Page Builder by SiteOrigin - Version 2.6.5

Version Description

  • 23 April 2018 =
  • Don't use mime_content_type for external layouts if it's not available. Just check file extensions.
  • Get correct ID for WooCommerce shop page to allow PB to render correctly.
  • Added image fallback url field for background images in row, cell and widget styles.
  • Temporarily remove Jetpack widgets requiring scripts for admin form, until we can reliably enqueue their scripts.
  • Remove loading indicator and display message when loading widget and style forms fail.
  • Allow setting margins around specific widgets.
Download this release

Release Info

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

Code changes from version 2.6.4 to 2.6.5

css/admin.css CHANGED
@@ -1598,6 +1598,7 @@
1598
  }
1599
  .so-panels-dialog .so-visual-styles {
1600
  margin: -15px;
 
1601
  /* All the field types */
1602
  }
1603
  .so-panels-dialog .so-visual-styles h3 {
@@ -1757,8 +1758,11 @@
1757
  color: #666;
1758
  text-decoration: none;
1759
  }
1760
- .so-panels-dialog .so-visual-styles .style-field-image .remove-image .remove-image {
1761
- color: #333;
 
 
 
1762
  }
1763
  .so-panels-dialog .so-visual-styles .style-field-checkbox label {
1764
  -webkit-user-select: none;
1598
  }
1599
  .so-panels-dialog .so-visual-styles {
1600
  margin: -15px;
1601
+ height: 100%;
1602
  /* All the field types */
1603
  }
1604
  .so-panels-dialog .so-visual-styles h3 {
1758
  color: #666;
1759
  text-decoration: none;
1760
  }
1761
+ .so-panels-dialog .so-visual-styles .style-field-image .remove-image.hidden {
1762
+ display: none;
1763
+ }
1764
+ .so-panels-dialog .so-visual-styles .style-field-image .image-fallback {
1765
+ margin-top: 4px;
1766
  }
1767
  .so-panels-dialog .so-visual-styles .style-field-checkbox label {
1768
  -webkit-user-select: none;
css/admin.min.css CHANGED
@@ -1 +1 @@
1
- @font-face{font-family:siteorigin-panels-icons;src:url(icons/panels-icons.eot);src:url(icons/panels-icons.eot) format("embedded-opentype"),url(icons/panels-icons.woff) format("woff"),url(icons/panels-icons.ttf) format("truetype"),url(icons/panels-icons.svg) format("svg");font-weight:400;font-style:normal}#so-panels-panels.attached-to-editor{margin-top:20px}#so-panels-panels.attached-to-editor .handlediv,#so-panels-panels.attached-to-editor .hndle{display:none!important}#so-panels-panels.attached-to-editor .inside{margin:0!important;padding:0!important}#so-panels-panels.attached-to-editor .so-toolbar .so-switch-to-standard{display:block}.siteorigin-panels-builder{position:relative}.siteorigin-panels-builder .so-tool-button{padding:6px 7px;text-decoration:none;line-height:1em;float:left;margin-right:2px;display:block;visibility:visible;position:relative;cursor:pointer;border:1px solid #bebebe;background:#eee;background:-o-linear-gradient(#f9f9f9,#eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#f9f9f9",endColorstr="#eeeeee",GradientType=0);box-shadow:0 1px 1px rgba(0,0,0,.04),inset 0 1px 0 hsla(0,0%,100%,.5);outline:none;border-radius:2px}.siteorigin-panels-builder .so-tool-button .so-panels-icon{font-size:12px}.siteorigin-panels-builder .so-tool-button span{display:inline-block;color:#666;text-shadow:0 1px 0 #fff;min-width:10px;text-align:center}.siteorigin-panels-builder .so-tool-button:hover{background:#fff}.siteorigin-panels-builder .so-tool-button:hover span{color:#444}.siteorigin-panels-builder .so-builder-toolbar{-ms-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #d0d0d0;background:#f5f5f5;line-height:1em;z-index:101;white-space:nowrap;overflow-x:hidden;position:relative;box-shadow:0 1px 1px rgba(0,0,0,.04);top:0;left:0;width:100%;padding:6px 9px;margin-top:0!important;zoom:1}.siteorigin-panels-builder .so-builder-toolbar:before{content:"";display:block}.siteorigin-panels-builder .so-builder-toolbar:after{content:"";display:table;clear:both}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button{display:inline-block;color:#666;padding:2px 10px 2px 8px}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button .so-button-text{margin:3px 0 2px;font-size:11px}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button .so-panels-icon{float:left;margin:3px 7px 2px 0;font-size:14px;color:#747474}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button:hover,.siteorigin-panels-builder .so-builder-toolbar .so-tool-button:hover .so-panels-icon{color:#444}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button.so-learn{background:#e5e5e5;background:-o-linear-gradient(#f6f6f6,#e5e5e5);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#f6f6f6",endColorstr="#e5e5e5",GradientType=0)}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button.so-learn:hover{background:#fff}.siteorigin-panels-builder .so-builder-toolbar .so-switch-to-standard{cursor:pointer;float:right;display:none;text-decoration:none;color:#666;padding:5px 6px;border-radius:2px;border:1px solid transparent;font-size:11px}.siteorigin-panels-builder .so-builder-toolbar .so-switch-to-standard:hover{background:#fafafa;border:1px solid #999;color:#444}.siteorigin-panels-builder .so-rows-container{padding:20px 15px 0}.siteorigin-panels-builder .so-rows-container .so-row-color-1.so-row-color{background-color:#cde2ec;border:1px solid #a4cadd}.siteorigin-panels-builder .so-rows-container .so-row-color-1.so-row-color.so-row-color-selected:before{background:#a8cdde}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-1 .so-cells .cell .cell-wrapper{background-color:#cde2ec}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-1 .so-cells .cell.cell-selected .cell-wrapper{background-color:#99c4d8}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-1 .so-cells .cell .resize-handle{background-color:#e7f1f6}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-1 .so-cells .cell .resize-handle:hover{background-color:#dcebf2}.siteorigin-panels-builder .so-rows-container .so-row-color-2.so-row-color{background-color:#f2c2be;border:1px solid #e9968f}.siteorigin-panels-builder .so-rows-container .so-row-color-2.so-row-color.so-row-color-selected:before{background:#ea9a93}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-2 .so-cells .cell .cell-wrapper{background-color:#f2c2be}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-2 .so-cells .cell.cell-selected .cell-wrapper{background-color:#e68a83}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-2 .so-cells .cell .resize-handle{background-color:#f8dedc}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-2 .so-cells .cell .resize-handle:hover{background-color:#f5d2cf}.siteorigin-panels-builder .so-rows-container .so-row-color-3.so-row-color{background-color:#d5ccdf;border:1px solid #b9aac9}.siteorigin-panels-builder .so-rows-container .so-row-color-3.so-row-color.so-row-color-selected:before{background:#bbadcb}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-3 .so-cells .cell .cell-wrapper{background-color:#d5ccdf}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-3 .so-cells .cell.cell-selected .cell-wrapper{background-color:#b1a0c3}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-3 .so-cells .cell .resize-handle{background-color:#e7e2ed}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-3 .so-cells .cell .resize-handle:hover{background-color:#dfd9e7}.siteorigin-panels-builder .so-rows-container .so-row-color-4.so-row-color{background-color:#cae7cd;border:1px solid #a3d6a9}.siteorigin-panels-builder .so-rows-container .so-row-color-4.so-row-color.so-row-color-selected:before{background:#a7d7ac}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-4 .so-cells .cell .cell-wrapper{background-color:#cae7cd}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-4 .so-cells .cell.cell-selected .cell-wrapper{background-color:#99d19f}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-4 .so-cells .cell .resize-handle{background-color:#e3f2e4}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-4 .so-cells .cell .resize-handle:hover{background-color:#d8edda}.siteorigin-panels-builder .so-rows-container .so-row-color-5.so-row-color{background-color:#e2dcb1;border:1px solid #d3ca88}.siteorigin-panels-builder .so-rows-container .so-row-color-5.so-row-color.so-row-color-selected:before{background:#d4cb8c}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-5 .so-cells .cell .cell-wrapper{background-color:#e2dcb1}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-5 .so-cells .cell.cell-selected .cell-wrapper{background-color:#cfc57d}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-5 .so-cells .cell .resize-handle{background-color:#ece8cb}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-5 .so-cells .cell .resize-handle:hover{background-color:#e8e3c0}.siteorigin-panels-builder .so-rows-container h3.so-row-label{display:inline-block;font-size:1em;font-weight:500;color:#474747;margin:0 0 0 4px;line-height:22px;float:left}.siteorigin-panels-builder .so-rows-container .so-row-toolbar{zoom:1;margin-bottom:4px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar:before{content:"";display:block}.siteorigin-panels-builder .so-rows-container .so-row-toolbar:after{content:"";display:table;clear:both}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button{-ms-box-sizing:border-box;box-sizing:border-box;padding:4px;float:right}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button .so-panels-icon{color:#777;font-size:11px;width:11px;height:11px;display:block}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button:hover .so-panels-icon{color:#555}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button.so-row-move{cursor:move}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper{visibility:hidden;opacity:0;transition:visibility 0s linear 75ms,opacity 75ms linear;z-index:101;right:-10px;top:100%;width:125px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a.so-row-delete{color:#a00}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a.so-row-delete:hover{color:#fff;background:#a00}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li.so-row-colors-container{display:flex;justify-content:space-around;padding:5px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li.so-row-colors-container .so-row-color{display:inline-block;cursor:pointer;position:relative;text-align:center;width:14px;height:14px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li.so-row-colors-container .so-row-color.so-row-color-selected:before{content:"";display:block;position:absolute;top:2px;bottom:2px;left:2px;right:2px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper:hover .so-dropdown-links-wrapper{visibility:visible;opacity:1;transition-delay:0s}.siteorigin-panels-builder .so-rows-container .ui-sortable-placeholder{visibility:visible!important;background:#f7f7f7;-ms-box-sizing:border-box;box-sizing:border-box}.siteorigin-panels-builder .so-rows-container .so-row-container{margin-bottom:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.siteorigin-panels-builder .so-rows-container .so-row-container.ui-sortable-helper{opacity:.9}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells{zoom:1;margin:0 -5px;position:relative}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells:before{content:"";display:block}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells:after{content:"";display:table;clear:both}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .ui-resizable-handle.ui-resizable-w{width:10px;left:-11px;cursor:col-resize;background:rgba(0,150,211,.25);transition:background .25s ease-in-out}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .ui-resizable-handle.ui-resizable-w:hover{background:rgba(0,150,211,.1)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell{-ms-box-sizing:border-box;box-sizing:border-box;float:left;position:relative;padding:0 5px}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell.so-first{margin-left:0}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell.so-last{margin-right:0}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .cell-wrapper{background:#e4eff4;padding:7px 7px 0;height:100%;min-height:63px;transition:background .25s ease-in-out 0s}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell.cell-selected .cell-wrapper{background-size:3px 3px}}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .cell-wrapper{-ms-box-sizing:border-box;box-sizing:border-box}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget{cursor:move;margin-bottom:7px;background:#f9f9fb;border:1px solid hsla(0,0%,100%,.75);max-height:49px;box-shadow:0 1px 1px rgba(0,0,0,.075);-ms-box-sizing:border-box;box-sizing:border-box}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-no-move{cursor:auto}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget:hover{border:1px solid hsla(0,0%,100%,.55);background:#fff;box-shadow:0 0 2px rgba(0,0,0,.1)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .so-widget-wrapper{padding:7px 8px;overflow:hidden;position:relative}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget h4{display:block;cursor:pointer;margin:0 15px 3px 0;font-weight:600;line-height:1.25em;color:#474747;text-shadow:0 1px 0 #fff;white-space:nowrap}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget h4 span{font-weight:400;display:inline-block;color:#999;text-shadow:0 1px 0 #fff;margin-left:12px;margin-right:5px;font-style:italic}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-no-edit h4{cursor:auto}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions{font-size:12px;position:absolute;top:5px;right:7px;cursor:pointer;padding:2px 2px 2px 15px;z-index:10}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions:hover{background:#feffff}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions:hover a{opacity:1}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions a{display:none;margin-right:3px;text-decoration:none}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions a.widget-delete{color:red}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions a.widget-delete:hover{color:#fff;background:red}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget:hover .title a{display:inline-block;opacity:.5}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.panel-being-dragged .title .actions{display:none}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget small{display:block;height:16px;overflow:hidden;color:#777}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .form{display:none}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only:hover{background:#f5f5f5;border:1px solid #a6bac1;box-shadow:none}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only:hover h4,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only:hover small,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only h4,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only small{opacity:.5}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered{background:#3a7096;border:1px solid #39618c;box-shadow:0 2px 2px rgba(0,0,0,.1)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered h4,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered small,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered span{color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.85)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered small{color:#eee}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget-sortable-highlight{border:1px solid rgba(0,0,0,.075);background:rgba(0,0,0,.025);-ms-box-sizing:border-box;box-sizing:border-box;height:49px;margin-bottom:7px;position:relative;box-shadow:inset 2px 2px 2px rgba(0,0,0,.01)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .resize-handle{z-index:100;position:absolute;top:0;width:10px;left:-5px;cursor:col-resize;background:#f6fafb;height:100%;transition:background .25s ease-in-out 0s}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell:first-child .resize-handle{display:none}.siteorigin-panels-builder .so-panels-welcome-message{text-align:center;padding:0 15px 20px;color:#555;line-height:1.8em}.siteorigin-panels-builder .so-panels-welcome-message .so-message-wrapper{padding:15px 10px;background:#f8f8f8;border:1px solid #e0e0e0}.siteorigin-panels-builder .so-panels-welcome-message .so-tool-button{font-size:inherit;display:inline-block;float:none;color:#666;padding:5px 10px;margin:0 3px}.siteorigin-panels-builder .so-panels-welcome-message .so-tool-button .so-panels-icon{color:#777;font-size:.8em}.siteorigin-panels-builder .so-panels-welcome-message .so-tip-wrapper{margin-top:15px;font-size:.95em}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar{padding:10px}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar>.so-tool-button{padding-right:2px}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar>.so-tool-button .so-panels-icon{font-size:14px}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar>.so-tool-button.so-learn,.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar>.so-tool-button span.so-button-text{display:none}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar .so-switch-to-standard,.siteorigin-panels-builder.so-display-narrow .widgets-container .so-widget .actions{display:none!important}.so-widget.ui-sortable-helper.widget-being-dragged{z-index:500002!important;opacity:.9;pointer-events:none;border:1px solid rgba(0,0,0,.35)!important;cursor:move;margin-bottom:7px;background:#f9f9fb;border:1px solid hsla(0,0%,100%,.75);max-height:49px;box-shadow:0 1px 1px rgba(0,0,0,.075);-ms-box-sizing:border-box;box-sizing:border-box}.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-no-move{cursor:auto}.so-widget.ui-sortable-helper.widget-being-dragged:hover{border:1px solid hsla(0,0%,100%,.55);background:#fff;box-shadow:0 0 2px rgba(0,0,0,.1)}.so-widget.ui-sortable-helper.widget-being-dragged .so-widget-wrapper{padding:7px 8px;overflow:hidden;position:relative}.so-widget.ui-sortable-helper.widget-being-dragged h4{display:block;cursor:pointer;margin:0 15px 3px 0;font-weight:600;line-height:1.25em;color:#474747;text-shadow:0 1px 0 #fff;white-space:nowrap}.so-widget.ui-sortable-helper.widget-being-dragged h4 span{font-weight:400;display:inline-block;color:#999;text-shadow:0 1px 0 #fff;margin-left:12px;margin-right:5px;font-style:italic}.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-no-edit h4{cursor:auto}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions{font-size:12px;position:absolute;top:5px;right:7px;cursor:pointer;padding:2px 2px 2px 15px;z-index:10}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions:hover{background:#feffff}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions:hover a{opacity:1}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions a{display:none;margin-right:3px;text-decoration:none}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions a.widget-delete{color:red}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions a.widget-delete:hover{color:#fff;background:red}.so-widget.ui-sortable-helper.widget-being-dragged:hover .title a{display:inline-block;opacity:.5}.so-widget.ui-sortable-helper.widget-being-dragged.panel-being-dragged .title .actions{display:none}.so-widget.ui-sortable-helper.widget-being-dragged small{display:block;height:16px;overflow:hidden;color:#777}.so-widget.ui-sortable-helper.widget-being-dragged .form{display:none}.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only,.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only:hover{background:#f5f5f5;border:1px solid #a6bac1;box-shadow:none}.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only:hover h4,.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only:hover small,.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only h4,.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only small{opacity:.5}.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered{background:#3a7096;border:1px solid #39618c;box-shadow:0 2px 2px rgba(0,0,0,.1)}.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered h4,.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered small,.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered span{color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.85)}.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered small{color:#eee}.widgets-holder-wrap .widget-inside .siteorigin-panels-builder .so-builder-container{padding-top:0}.widgets-holder-wrap .widget-inside .siteorigin-panels-builder .so-rows-container{padding:10px 0 0}.widgets-holder-wrap .widget-inside .siteorigin-panels-builder .so-builder-toolbar{padding-left:15px;padding-right:15px;margin:0 -15px}.so-panels-dialog .so-content,.so-panels-dialog .so-left-sidebar,.so-panels-dialog .so-overlay,.so-panels-dialog .so-right-sidebar,.so-panels-dialog .so-title-bar,.so-panels-dialog .so-toolbar{z-index:100001;position:fixed;-ms-box-sizing:border-box;box-sizing:border-box;padding:15px}.so-panels-dialog .so-content,.so-panels-dialog .so-left-sidebar,.so-panels-dialog .so-right-sidebar{overflow-y:auto}.so-panels-dialog .so-overlay{top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.5)}.so-panels-dialog .so-content{top:80px;left:30px;right:30px;bottom:88px;background-color:#fdfdfd;overflow-x:hidden;box-shadow:inset 0 2px 2px rgba(0,0,0,.03)}.so-panels-dialog .so-content>:first-child{margin-top:0}.so-panels-dialog .so-content>:last-child{margin-bottom:0}.so-panels-dialog .so-content .so-content-tabs>*{display:none}.so-panels-dialog .so-title-bar{left:30px;right:30px;top:30px;height:50px;background-color:#fafafa;border-bottom:1px solid #d8d8d8}.so-panels-dialog .so-title-bar h3.so-title{-ms-box-sizing:border-box;box-sizing:border-box;margin:-3px 150px 0 -3px;padding:5px 6px;display:block}.so-panels-dialog .so-title-bar h3.so-title.so-title-editable:focus,.so-panels-dialog .so-title-bar h3.so-title.so-title-editable:hover{outline:none;background-color:#f0f0f0}.so-panels-dialog .so-title-bar h3.so-title.so-title-editable:focus{margin-top:-4px;margin-left:-4px;border:1px solid #e4e4e4}.so-panels-dialog .so-title-bar input[type=text].so-edit-title{margin-top:-3px;margin-left:-3px;display:none;color:#23282d;font-size:1.3em;font-weight:600;border:none;box-shadow:none;background-color:#f0f0f0;padding:4px 5px}.so-panels-dialog .so-title-bar h3.so-parent-link{cursor:pointer;position:relative;float:left;margin:0 15px 0 0!important;padding:0 27px 0 0!important}.so-panels-dialog .so-title-bar h3.so-parent-link .so-separator{position:absolute;top:-15px;right:0;width:12px;height:50px;display:block;background:url(images/dialog-separator.png) no-repeat}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.so-panels-dialog .so-title-bar h3.so-parent-link .so-separator{background:url(images/dialog-separator@2x.png) no-repeat;background-size:cover}}.so-panels-dialog .so-title-bar a{cursor:pointer;position:absolute;box-sizing:border-box;width:50px;height:50px;display:block;top:0;right:0;transition:all .2s ease 0s;background:#fafafa;border-left:1px solid #d8d8d8;border-bottom:1px solid #d8d8d8}.so-panels-dialog .so-title-bar a:hover{background:#e9e9e9}.so-panels-dialog .so-title-bar a:hover .so-dialog-icon{color:#333}.so-panels-dialog .so-title-bar a .so-dialog-icon{position:absolute;top:50%;left:50%;text-decoration:none;width:20px;height:20px;margin-left:-10px;margin-top:-10px;color:#666;text-align:center}.so-panels-dialog .so-title-bar a .so-dialog-icon:before{font:400 20px/1em dashicons;top:7px;left:13px}.so-panels-dialog .so-title-bar a.so-close{right:0}.so-panels-dialog .so-title-bar a.so-close .so-dialog-icon:before{content:"\f335"}.so-panels-dialog .so-title-bar a.so-next{right:50px}.so-panels-dialog .so-title-bar a.so-next .so-dialog-icon:before{content:"\f345"}.so-panels-dialog .so-title-bar a.so-previous{right:100px}.so-panels-dialog .so-title-bar a.so-previous .so-dialog-icon:before{content:"\f341"}.so-panels-dialog .so-title-bar a.so-nav.so-disabled{cursor:default;pointer-events:none}.so-panels-dialog .so-title-bar a.so-nav.so-disabled .so-dialog-icon{color:#ddd}.so-panels-dialog .so-title-bar.so-has-icon{padding-left:45px}.so-panels-dialog .so-title-bar.so-has-icon .so-panels-icon{position:absolute;top:14.5px;left:14px;font-size:22px;line-height:22px;display:block;width:22px;height:22px;text-align:center;color:#666}.so-panels-dialog .so-toolbar{left:30px;right:30px;bottom:30px;height:58px;background-color:#fafafa;border-top:1px solid #d8d8d8;z-index:100002}.so-panels-dialog .so-toolbar .so-status{float:left;padding-top:6px;padding-bottom:6px;font-style:italic;color:#999;line-height:1em}.so-panels-dialog .so-toolbar .so-status.so-panels-loading{padding-left:26px;background-position:0}.so-panels-dialog .so-toolbar .so-status .dashicons-warning{color:#a00;vertical-align:middle;margin-right:7px;margin-top:-1px}.so-panels-dialog .so-toolbar .so-buttons{float:right}.so-panels-dialog .so-toolbar .so-buttons .action-buttons{position:absolute;left:15px;top:50%;margin-top:-.65em}.so-panels-dialog .so-toolbar .so-buttons .action-buttons a{cursor:pointer;display:inline;padding:.2em .5em;line-height:1em;margin-right:.5em;text-decoration:none}.so-panels-dialog .so-toolbar .so-buttons .action-buttons .so-delete{color:#a00}.so-panels-dialog .so-toolbar .so-buttons .action-buttons .so-delete:hover{background:#a00;color:#fff}.so-panels-dialog .so-toolbar .so-buttons .action-buttons .so-duplicate:hover{text-decoration:underline}.so-panels-dialog .so-left-sidebar,.so-panels-dialog .so-right-sidebar{background-color:#f3f3f3}.so-panels-dialog .so-left-sidebar{display:none;top:30px;left:30px;bottom:30px;width:290px;border-right:1px solid #d8d8d8}.so-panels-dialog .so-left-sidebar h4{margin:0 0 20px;font-size:18px}.so-panels-dialog .so-left-sidebar .so-sidebar-search{width:100%;padding:6px;margin-bottom:20px}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs{list-style:none;margin:0 -15px}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li{margin-bottom:0}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li a{padding:7px 16px;display:block;font-size:14px;text-decoration:none;box-shadow:none!important}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li a:hover{background:#fff}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li.tab-active a{color:#555;font-weight:700;background:#fff}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li.tab-active a:hover{background:#fff}.so-panels-dialog .so-right-sidebar{display:none;top:80px;right:30px;bottom:88px;width:290px;border-left:1px solid #d8d8d8}.so-panels-dialog .so-right-sidebar h3{color:#333}.so-panels-dialog .so-right-sidebar h3:first-child{margin-top:0}.so-panels-dialog .so-sidebar .form-field{margin-bottom:20px}.so-panels-dialog .so-sidebar .form-field label{font-weight:500;font-size:15px;display:block;margin-bottom:10px}.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-content,.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-title-bar,.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-toolbar{left:320px}.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-content{box-shadow:inset 2px 2px 2px rgba(0,0,0,.03)}.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-left-sidebar{display:block}.so-panels-dialog.so-panels-dialog-has-right-sidebar .so-content{right:320px}.so-panels-dialog.so-panels-dialog-has-right-sidebar .so-right-sidebar{display:block}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget{border-radius:2px;border:1px solid #ccc;cursor:pointer;padding:10px;background:#f9f9f9;box-shadow:0 1px 2px rgba(0,0,0,.075),inset 0 1px 0 #fff;margin-bottom:15px}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget:hover{border:1px solid #bbb;background:#fff}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget.so-current{border-color:#0074a2;background:#2ea2cc;cursor:auto;box-shadow:0 1px 2px rgba(0,0,0,.15),inset 0 1px 0 hsla(0,0%,100%,.2)}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget.so-current h3{color:#fff}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget.so-current small{color:#eee}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget.so-current:hover{border-color:#0074a2;background:#2ea2cc}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget:last-child{margin-bottom:0}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget h3{margin:0 0 7px;padding:0;height:1.2em;color:#222;font-size:14px}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget small{font-size:11px;line-height:1.25em;display:block;overflow:hidden;color:#888}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list{zoom:1;margin:0 -5px -10px;min-height:10px}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list:before{content:"";display:block}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list:after{content:"";display:table;clear:both}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type{-ms-user-select:none;-moz-user-select:-moz-none;-webkit-user-select:none;user-select:none;-ms-box-sizing:border-box;box-sizing:border-box;width:25%;padding:0 5px;margin-bottom:10px;float:left}@media (max-width:1280px){.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type{width:33.333%}}@media (max-width:960px){.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type{width:50%}}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type h3{margin:0 0 7px;padding:0;color:#222;font-size:14px}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type small{font-size:11px;min-height:2.5em;line-height:1.25em;display:block;overflow:hidden;color:#888}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type .widget-icon{font-size:20px;width:20px;height:20px;color:#666;float:left;margin:-1px .5em 0 0}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type-wrapper{border:1px solid #ccc;cursor:pointer;padding:10px;background:#f8f8f8;box-shadow:0 1px 2px rgba(0,0,0,.075)}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type-wrapper:hover{border:1px solid #bbb;background:#fff;box-shadow:0 2px 2px rgba(0,0,0,.075)}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form{zoom:1;padding:8px;border:1px solid #ccc;margin-bottom:20px;background:#f3f3f3}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form:before{content:"";display:block}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form:after{content:"";display:table;clear:both}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form button,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form input,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form select,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form span,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form strong{display:inline;margin:1px 5px;outline:none;box-shadow:none}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form button{margin-top:2px}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form label{display:inline}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview{margin:0 -6px;height:360px;position:relative;white-space:nowrap}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell-in,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell-weight{-ms-box-sizing:border-box;box-sizing:border-box}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell{display:inline-block;position:relative;padding:0 6px;cursor:pointer}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in{border:1px solid #bcccd2;min-height:360px;background:#e4eff4;position:relative}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in.cell-selected{background:#cae7f4 url(images/cell-selected.png) repeat;border-color:#9abcc7;box-shadow:0 0 5px rgba(0,0,0,.2)}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight-input{position:absolute;font-size:17px;font-weight:700;top:50%;left:50%;width:80px;text-align:center;color:#5e6d72;margin:-.95em 0 0 -40px;padding:10px 0;border:1px solid transparent;line-height:1.4em!important;overflow:hidden;cursor:pointer}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight-input:after,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight:after{content:"%"}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight-input:hover,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight:hover{background:#f6f6f6;border:1px solid #d0d0d0}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight-input{background:#f6f6f6;border:1px solid #d0d0d0;box-shadow:none}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .resize-handle{z-index:100;position:absolute;top:0;width:12px;left:-6px;cursor:col-resize;background:#e5f4fb;height:360px;transition:background .15s ease-in-out 0s}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .resize-handle.ui-draggable-dragging,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .resize-handle:hover{background:#b7e0f1}.so-panels-dialog.so-panels-dialog-history .so-left-sidebar{padding:0}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry{padding:10px;background:#f8f8f8;cursor:pointer;border-bottom:1px solid #ccc}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry h3{margin:0 0 .6em;font-size:12px;font-weight:700;color:#444;line-height:1em}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry .timesince{color:#999;font-size:11px;line-height:1em}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry:hover{background:#f0f0f0}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry.so-selected{background:#eee}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry .count{color:#999}.so-panels-dialog.so-panels-dialog-history .so-content{padding:0;overflow-y:hidden}.so-panels-dialog.so-panels-dialog-history .so-content form.history-form{display:none}.so-panels-dialog.so-panels-dialog-history .so-content iframe.siteorigin-panels-history-iframe{width:100%;height:100%}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content{padding-left:10px;padding-right:10px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-error-message{font-size:14px;border:1px solid #ccc;background:#f8f8f8;padding:15px 20px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .export-file-ui{padding:5px 15px;text-align:right}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui{padding:15px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .drag-drop-message{display:none}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui.has-drag-drop .drag-drop-message{display:block}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui p.drag-drop-message{font-size:1em;margin-bottom:0}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .drag-upload-area{display:block;-ms-box-sizing:border-box;box-sizing:border-box;padding:50px 30px;border:4px dashed #e0e0e0;text-align:center;transition:all .25s ease 0s}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .drag-upload-area.file-dragover{background-color:#f2f9fc;border-color:#0074a2}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .progress-bar{display:none;padding:2px;border:2px solid #2181b1;border-radius:2px;margin-top:20px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .progress-bar .progress-percent{height:14px;background-color:#358ebe;border-radius:1px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .file-browse-button{padding:12px 30px;height:auto}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-browse{background:#f3f3f3;border-bottom:1px solid #d0d0d0;margin:-15px -10px 15px;padding:15px;font-weight:700}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items-wrapper{display:flex;flex-flow:row wrap}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-no-results{margin:20px 0;padding:0 5px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{-ms-box-sizing:border-box;box-sizing:border-box;padding:6px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-directory-item-wrapper{display:flex;flex-flow:column nowrap;height:100%;box-sizing:border-box;padding:15px 10px;background:#f7f7f7;border:1px solid #d0d0d0;box-shadow:0 1px 1px rgba(0,0,0,.1)}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-title{font-size:15px;margin:0 0 13px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot{flex:3 auto;margin-bottom:10px;cursor:pointer}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot.so-loading{background-image:url(images/wpspin_light.gif);background-position:50%;background-repeat:no-repeat}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot.so-loading{background-image:url(images/wpspin_light-2x.gif);background-size:16px 16px}}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot img{display:block;width:100%;height:auto}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot .so-screenshot-wrapper{display:block;min-height:40px;background:gray;border:1px solid #d0d0d0}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-description{flex:1 auto;font-size:.9em;color:#666;margin-bottom:10px;max-height:60px;overflow:hidden}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom{flex:1 auto;position:relative;max-height:50px;margin:10px -10px -15px;background:#fcfcfc;border-top:1px solid #d0d0d0}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom .so-title{margin:0;padding:16px 10px;cursor:pointer;overflow:hidden;white-space:nowrap}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom .so-buttons{position:absolute;z-index:2;top:0;bottom:0;right:0;height:100%;visibility:hidden;-ms-box-sizing:border-box;box-sizing:border-box;padding:11px 10px 10px 15px;border-left:1px solid #d0d0d0;background:#f6f6f6;box-shadow:-1px 0 1px rgba(0,0,0,.05)}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item:hover .so-buttons{visibility:visible}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected{background-color:#e5f4fa}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-directory-item-wrapper{background:#deeef4;border-color:#9abcc7}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-bottom{background:#f8fdff;border-color:#bcccd2}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-bottom .so-title{color:#3e484c}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-bottom .so-buttons{background:#eaf2f6;border-color:#bcccd2}@media only screen and (min-width:1680px){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{width:20%}}@media only screen and (max-width:1679px) and (min-width:1280px){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{width:25%}}@media only screen and (max-width:1279px) and (min-width:1140px){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{width:33.333%}}@media only screen and (max-width:1139px){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{width:50%}}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-pages{margin-top:15px;padding:0 5px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-pages .button-disabled{pointer-events:none}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-toolbar .so-buttons select.so-layout-position{vertical-align:baseline}.so-panels-dialog .so-visual-styles{margin:-15px}.so-panels-dialog .so-visual-styles h3{line-height:1em;margin:0;padding:20px 15px;border-bottom:1px solid #ddd}.so-panels-dialog .so-visual-styles .style-section-head{background:#fff;padding:15px 10px;border-bottom:1px solid #ddd;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.so-panels-dialog .so-visual-styles .style-section-head h4{margin:0}.so-panels-dialog .so-visual-styles .style-section-fields{padding:15px;border-bottom:1px solid #ddd;background:#f7f7f7}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper{margin-bottom:20px}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper:last-child{margin-bottom:0}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper>label{font-weight:700;display:block;margin-bottom:3px}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper .style-field{zoom:1}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper .style-field:before{content:"";display:block}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper .style-field:after{content:"";display:table;clear:both}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper .style-field input{font-size:12px}.so-panels-dialog .so-visual-styles .style-input-wrapper{zoom:1}.so-panels-dialog .so-visual-styles .style-input-wrapper:before{content:"";display:block}.so-panels-dialog .so-visual-styles .style-input-wrapper:after{content:"";display:table;clear:both}.so-panels-dialog .so-visual-styles .style-input-wrapper input{max-width:100%}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-inputs{overflow:auto;margin:0 -3px 4px}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper{box-sizing:border-box;float:left;width:25%;padding:0 3px}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value{border-width:1px;display:block;max-width:100%}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value.measurement-top{box-shadow:inset 0 2px 1px rgba(0,115,170,.35)}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value.measurement-right{box-shadow:inset -3px 0 2px rgba(0,115,170,.35)}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value.measurement-bottom{box-shadow:inset 0 -2px 1px rgba(0,115,170,.35)}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value.measurement-left{box-shadow:inset 3px 0 2px rgba(0,115,170,.35)}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-unit-multiple{width:100%;display:block}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-unit-single{float:right;width:25%}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-value-single{float:left;width:72%}.so-panels-dialog .so-visual-styles .style-field-image .so-image-selector{display:inline-block;background-color:#f7f7f7;border:1px solid #ccc;height:28px;float:left;border-radius:3px;cursor:pointer;box-shadow:inset 0 1px #fff}.so-panels-dialog .so-visual-styles .style-field-image .so-image-selector .current-image{height:28px;width:28px;float:left;background:#fff;border-right:1px solid #ccc;background-size:cover;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:3px;border-top-left-radius:3px;background-clip:padding-box}.so-panels-dialog .so-visual-styles .style-field-image .so-image-selector .select-image{font-size:12px;line-height:28px;float:left;padding:0 8px;color:#555}.so-panels-dialog .so-visual-styles .style-field-image .remove-image{font-size:12px;margin-top:4px;margin-left:15px;display:inline-block;float:left;color:#666;text-decoration:none}.so-panels-dialog .so-visual-styles .style-field-image .remove-image .remove-image{color:#333}.so-panels-dialog .so-visual-styles .style-field-checkbox label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.so-panels-dialog .so-visual-styles .so-field-code{font-size:12px;font-family:Courier\ 10 Pitch,Courier,monospace}.so-panels-dialog .so-visual-styles .so-description{color:#999;font-size:12px;margin-top:5px;margin-bottom:0;font-style:italic;clear:both}.so-panels-dialog .so-visual-styles.so-cell-styles{margin-top:15px}.so-panels-dialog .so-content .siteorigin-panels-builder .so-builder-toolbar{border:1px solid #dedede}.so-panels-dialog .so-content .siteorigin-panels-builder .so-rows-container{padding:20px 0 0}.so-panels-dialog .so-content .siteorigin-panels-builder .so-panels-welcome-message{padding-left:0;padding-right:0}.so-panels-dialog .so-dropdown-wrapper input[type=button].button-primary{width:125px;height:28px}.so-panels-dialog .so-dropdown-wrapper .so-dropdown-links-wrapper{display:block;z-index:11;bottom:28px;width:125px}.so-panels-dialog .so-dropdown-wrapper .so-dropdown-links-wrapper.hidden{display:none}.wp-customizer .so-panels-dialog .so-content,.wp-customizer .so-panels-dialog .so-left-sidebar,.wp-customizer .so-panels-dialog .so-overlay,.wp-customizer .so-panels-dialog .so-right-sidebar,.wp-customizer .so-panels-dialog .so-title-bar,.wp-customizer .so-panels-dialog .so-toolbar{z-index:500001}.wp-customizer .so-panels-dialog .so-toolbar{z-index:500002}.so-panels-live-editor>div{position:fixed;z-index:99999;-ms-box-sizing:border-box;box-sizing:border-box}.so-panels-live-editor .live-editor-form{display:none}.so-panels-live-editor .live-editor-collapse{position:fixed;top:18px;left:10px;line-height:1em;cursor:pointer;z-index:100000}.so-panels-live-editor .live-editor-collapse .collapse-icon{float:left;margin:-4px 6px 0 0;border-radius:50%;width:20px;height:20px;overflow:hidden;transition:all .25s ease 0s}.so-panels-live-editor .live-editor-collapse .collapse-icon:before{display:block;content:"\f148";background:#eee;font:normal 20px/1 dashicons;speak:none;padding:0;-webkit-font-smoothing:antialiased}.so-panels-live-editor .live-editor-collapse:hover{color:#0073aa}.so-panels-live-editor .live-editor-collapse:hover .collapse-icon{box-shadow:0 0 3px rgba(30,140,190,.8)}.so-panels-live-editor .so-sidebar-tools{background:#eee;border-bottom:1px solid #ddd;border-right:1px solid #d0d0d0;top:0;left:0;height:46px;width:360px}.so-panels-live-editor .so-sidebar-tools .live-editor-close{margin:9px 10px 0 15px;float:right}.so-panels-live-editor .so-sidebar-tools .live-editor-mode{float:right;margin:9px 4px 0 0}.so-panels-live-editor .so-sidebar-tools .live-editor-mode .dashicons{font-size:30px;width:30px;height:30px;cursor:pointer;color:#999}.so-panels-live-editor .so-sidebar-tools .live-editor-mode .dashicons:hover{color:#666}.so-panels-live-editor .so-sidebar-tools .live-editor-mode.so-active .dashicons,.so-panels-live-editor .so-sidebar-tools .live-editor-mode.so-active .dashicons:hover{color:#0073aa}.so-panels-live-editor .so-sidebar{top:46px;left:0;bottom:0;width:360px;overflow-y:auto;background:#f7f7f7;border-right:1px solid #d0d0d0}.so-panels-live-editor .so-sidebar .siteorigin-panels-builder .so-rows-container{padding:10px 10px 0!important}.so-panels-live-editor .so-preview{top:0;right:0;bottom:0;left:360px;background-color:#191e23}.so-panels-live-editor .so-preview form{display:none}.so-panels-live-editor .so-preview iframe{float:left;width:100%;height:100%;margin:0 auto}.so-panels-live-editor .so-preview-overlay{display:none;opacity:.975;top:0;right:0;bottom:0;left:360px;background-color:#f4f4f4;cursor:wait}.so-panels-live-editor .so-preview-overlay .so-loading-container{opacity:.6;position:absolute;top:50%;width:200px;padding:2px;border-radius:5px;left:50%;margin-left:-104px;margin-top:-9px;border:2px solid #aaa}.so-panels-live-editor .so-preview-overlay .so-loading-container .so-loading-bar{width:50%;border-radius:3px;height:10px;background:#aaa}.so-panels-live-editor.so-collapsed .live-editor-collapse .collapse-icon{transform:rotate(180deg)}.so-panels-live-editor.so-collapsed .so-sidebar,.so-panels-live-editor.so-collapsed .so-sidebar-tools{display:none}.so-panels-live-editor.so-collapsed .so-preview,.so-panels-live-editor.so-collapsed .so-preview-overlay{left:0}.so-panels-live-editor.live-editor-mobile-mode .so-preview iframe{max-width:480px;max-height:640px;position:absolute;top:50%;left:50%;margin-left:-240px;margin-top:-320px}@media (max-width:840px){.so-panels-live-editor.live-editor-mobile-mode .so-preview iframe{position:static;margin-left:0;margin-top:0}}@media (max-height:640px){.so-panels-live-editor.live-editor-mobile-mode .so-preview iframe{position:static;margin-left:0;margin-top:0}}.so-panels-live-editor.live-editor-tablet-mode .so-preview iframe{position:absolute;max-width:768px;top:0;left:50%;margin-left:-384px}@media (max-width:1128px){.so-panels-live-editor.live-editor-tablet-mode .so-preview iframe{position:static;margin-left:0;margin-top:0}}.so-panels-loading{background-image:url(images/wpspin_light.gif);background-position:50%;background-repeat:no-repeat}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.so-panels-loading{background-image:url(images/wpspin_light-2x.gif);background-size:16px 16px}}#panels-home-page .switch{margin:0 10px 0 0;float:left;position:relative;display:inline-block;vertical-align:top;width:68px;height:24px;padding:3px;background-color:#fff;border-radius:24px;box-shadow:inset 0 -1px #fff,inset 0 1px 1px rgba(0,0,0,.05);cursor:pointer;background-image:linear-gradient(180deg,#eee,#fff 25px)}#panels-home-page .switch .switch-input{position:absolute;top:0;left:0;opacity:0}#panels-home-page .switch .switch-label{position:relative;display:block;height:inherit;font-size:12px;text-transform:uppercase;background:#eceeef;border-radius:inherit;box-shadow:inset 0 1px 2px rgba(0,0,0,.12),inset 0 0 2px rgba(0,0,0,.15);transition:.15s ease-out;transition-property:opacity background}#panels-home-page .switch .switch-label:after,#panels-home-page .switch .switch-label:before{position:absolute;top:50%;margin-top:-.5em;line-height:1;transition:inherit}#panels-home-page .switch .switch-label:before{content:attr(data-off);right:11px;color:#aaa;text-shadow:0 1px hsla(0,0%,100%,.5)}#panels-home-page .switch .switch-label:after{content:attr(data-on);left:13px;color:#fff;text-shadow:0 1px rgba(0,0,0,.2);opacity:0}#panels-home-page .switch .switch-input:checked~.switch-label{background:#47a8d8;box-shadow:inset 0 1px 2px rgba(0,0,0,.15),inset 0 0 3px rgba(0,0,0,.2)}#panels-home-page .switch .switch-input:checked~.switch-label:before{opacity:0}#panels-home-page .switch .switch-input:checked~.switch-label:after{opacity:1}#panels-home-page .switch .switch-handle{position:absolute;top:4px;left:4px;width:22px;height:22px;background:#fff;border-radius:12px;box-shadow:1px 1px 5px rgba(0,0,0,.2);background-image:linear-gradient(180deg,#fff 40%,#f0f0f0);transition:left .15s ease-out}#panels-home-page .switch .switch-handle:before{content:"";position:absolute;top:50%;left:50%;margin:-7px 0 0 -7px;width:14px;height:14px;background:#f9f9f9;border-radius:7px;box-shadow:inset 0 1px rgba(0,0,0,.02);background-image:linear-gradient(180deg,#eee,#fff)}#panels-home-page .switch .switch-input:checked~.switch-handle{left:48px;box-shadow:-1px 1px 5px rgba(0,0,0,.2)}#panels-home-page .switch .switch-green>.switch-input:checked~.switch-label{background:#4fb845}#panels-home-page #panels-view-as-page{display:inline-block;margin-left:50px}.siteorigin-panels-builder-form .siteorigin-panels-builder{border:1px solid #d0d0d0;background-color:#fff;margin:10px 0}.siteorigin-panels-builder-form .siteorigin-panels-builder.so-panels-loading{min-height:150px}.siteorigin-page-builder-widget .siteorigin-panels-display-builder{display:inline-block!important}.siteorigin-page-builder-widget .siteorigin-panels-no-builder{display:none!important}.so-panels-contextual-menu{border:1px solid silver;background:#f9f9f9;box-shadow:0 1px 1px rgba(0,0,0,.04);outline:none;border-radius:2px;position:absolute;width:180px;top:20px;left:20px;z-index:999999;display:none;overflow-y:auto}.so-panels-contextual-menu,.so-panels-contextual-menu *{font-size:12px}.so-panels-contextual-menu .so-section{border-bottom:1px solid silver}.so-panels-contextual-menu .so-section:last-child{border-bottom:none}.so-panels-contextual-menu .so-section h5{margin:0 0 5px;padding:8px 10px 5px;border-bottom:1px solid #d0d0d0;background:#f6f6f6}.so-panels-contextual-menu .so-section .so-search-wrapper{margin:-5px 0 5px;border-bottom:1px solid #d0d0d0;background:#f4f4f4}.so-panels-contextual-menu .so-section .so-search-wrapper input[type=text]{box-sizing:border-box;display:block;width:100%;margin:0;border:none;padding:5px 10px;background:#fbfbfb}.so-panels-contextual-menu .so-section .so-search-wrapper input[type=text]:active,.so-panels-contextual-menu .so-section .so-search-wrapper input[type=text]:focus{border:none;box-shadow:none;background:#fff}.so-panels-contextual-menu .so-section ul{margin:5px 0 0;padding:0 0 5px}.so-panels-contextual-menu .so-section ul li{cursor:pointer;margin:0;padding:4px 10px;line-height:1em}.so-panels-contextual-menu .so-section ul li.so-active,.so-panels-contextual-menu .so-section ul li:hover{background:#f0f0f0;color:#444}.so-panels-contextual-menu .so-section ul li.so-confirm{color:#a00}.so-panels-contextual-menu .so-section ul li.so-confirm.so-active,.so-panels-contextual-menu .so-section ul li.so-confirm:hover{background:#a00;color:#fff}.so-panels-contextual-menu .so-section ul li .dashicons{width:12px;height:12px;font-size:12px;margin:0;float:right;line-height:12px}.so-panels-contextual-menu .so-section .so-no-results{padding:0 10px 5px;display:none;font-style:italic}.so-dropdown-wrapper{position:relative;float:right}.so-dropdown-wrapper .so-dropdown-links-wrapper{position:absolute;padding:6px 0 0}.so-dropdown-wrapper .so-dropdown-links-wrapper ul{margin:0;border:1px solid silver;background:#f9f9f9;border-radius:2px;padding:4px 0;box-shadow:0 2px 2px rgba(0,0,0,.1)}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li{margin:0}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li:first-child{border-top-width:1px}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li a{display:block;padding:2px 8px;text-decoration:none;color:#666;font-size:11px;cursor:pointer;outline:0!important;box-shadow:none}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li a:hover{background:#f0f0f0;color:#444}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li a .dashicons{font-size:16px;margin:0;float:right;line-height:16px}.so-dropdown-wrapper .so-dropdown-links-wrapper .so-pointer{width:12px;height:6px;position:absolute;z-index:12;background:url(images/dropdown-pointer.png);background-size:12px 6px;top:1px;right:18px}.so-panels-icon{font-family:siteorigin-panels-icons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.so-panels-icon.so-panels-icon-add-row:before{content:"\e900"}.so-panels-icon.so-panels-icon-add-widget:before{content:"\e901"}.so-panels-icon.so-panels-icon-addons:before{content:"\e902"}.so-panels-icon.so-panels-icon-history:before{content:"\e903"}.so-panels-icon.so-panels-icon-layouts:before{content:"\e904"}.so-panels-icon.so-panels-icon-learn:before{content:"\e905"}.so-panels-icon.so-panels-icon-live-editor:before{content:"\e906"}.so-panels-icon.so-panels-icon-move:before{content:"\e907"}.so-panels-icon.so-panels-icon-settings:before{content:"\e908"}#post-status-info.for-siteorigin-panels{margin-top:-21px!important}
1
+ @font-face{font-family:siteorigin-panels-icons;src:url(icons/panels-icons.eot);src:url(icons/panels-icons.eot) format("embedded-opentype"),url(icons/panels-icons.woff) format("woff"),url(icons/panels-icons.ttf) format("truetype"),url(icons/panels-icons.svg) format("svg");font-weight:400;font-style:normal}#so-panels-panels.attached-to-editor{margin-top:20px}#so-panels-panels.attached-to-editor .handlediv,#so-panels-panels.attached-to-editor .hndle{display:none!important}#so-panels-panels.attached-to-editor .inside{margin:0!important;padding:0!important}#so-panels-panels.attached-to-editor .so-toolbar .so-switch-to-standard{display:block}.siteorigin-panels-builder{position:relative}.siteorigin-panels-builder .so-tool-button{padding:6px 7px;text-decoration:none;line-height:1em;float:left;margin-right:2px;display:block;visibility:visible;position:relative;cursor:pointer;border:1px solid #bebebe;background:#eee;background:-o-linear-gradient(#f9f9f9,#eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#f9f9f9",endColorstr="#eeeeee",GradientType=0);box-shadow:0 1px 1px rgba(0,0,0,.04),inset 0 1px 0 hsla(0,0%,100%,.5);outline:none;border-radius:2px}.siteorigin-panels-builder .so-tool-button .so-panels-icon{font-size:12px}.siteorigin-panels-builder .so-tool-button span{display:inline-block;color:#666;text-shadow:0 1px 0 #fff;min-width:10px;text-align:center}.siteorigin-panels-builder .so-tool-button:hover{background:#fff}.siteorigin-panels-builder .so-tool-button:hover span{color:#444}.siteorigin-panels-builder .so-builder-toolbar{-ms-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #d0d0d0;background:#f5f5f5;line-height:1em;z-index:101;white-space:nowrap;overflow-x:hidden;position:relative;box-shadow:0 1px 1px rgba(0,0,0,.04);top:0;left:0;width:100%;padding:6px 9px;margin-top:0!important;zoom:1}.siteorigin-panels-builder .so-builder-toolbar:before{content:"";display:block}.siteorigin-panels-builder .so-builder-toolbar:after{content:"";display:table;clear:both}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button{display:inline-block;color:#666;padding:2px 10px 2px 8px}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button .so-button-text{margin:3px 0 2px;font-size:11px}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button .so-panels-icon{float:left;margin:3px 7px 2px 0;font-size:14px;color:#747474}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button:hover,.siteorigin-panels-builder .so-builder-toolbar .so-tool-button:hover .so-panels-icon{color:#444}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button.so-learn{background:#e5e5e5;background:-o-linear-gradient(#f6f6f6,#e5e5e5);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#f6f6f6",endColorstr="#e5e5e5",GradientType=0)}.siteorigin-panels-builder .so-builder-toolbar .so-tool-button.so-learn:hover{background:#fff}.siteorigin-panels-builder .so-builder-toolbar .so-switch-to-standard{cursor:pointer;float:right;display:none;text-decoration:none;color:#666;padding:5px 6px;border-radius:2px;border:1px solid transparent;font-size:11px}.siteorigin-panels-builder .so-builder-toolbar .so-switch-to-standard:hover{background:#fafafa;border:1px solid #999;color:#444}.siteorigin-panels-builder .so-rows-container{padding:20px 15px 0}.siteorigin-panels-builder .so-rows-container .so-row-color-1.so-row-color{background-color:#cde2ec;border:1px solid #a4cadd}.siteorigin-panels-builder .so-rows-container .so-row-color-1.so-row-color.so-row-color-selected:before{background:#a8cdde}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-1 .so-cells .cell .cell-wrapper{background-color:#cde2ec}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-1 .so-cells .cell.cell-selected .cell-wrapper{background-color:#99c4d8}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-1 .so-cells .cell .resize-handle{background-color:#e7f1f6}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-1 .so-cells .cell .resize-handle:hover{background-color:#dcebf2}.siteorigin-panels-builder .so-rows-container .so-row-color-2.so-row-color{background-color:#f2c2be;border:1px solid #e9968f}.siteorigin-panels-builder .so-rows-container .so-row-color-2.so-row-color.so-row-color-selected:before{background:#ea9a93}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-2 .so-cells .cell .cell-wrapper{background-color:#f2c2be}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-2 .so-cells .cell.cell-selected .cell-wrapper{background-color:#e68a83}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-2 .so-cells .cell .resize-handle{background-color:#f8dedc}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-2 .so-cells .cell .resize-handle:hover{background-color:#f5d2cf}.siteorigin-panels-builder .so-rows-container .so-row-color-3.so-row-color{background-color:#d5ccdf;border:1px solid #b9aac9}.siteorigin-panels-builder .so-rows-container .so-row-color-3.so-row-color.so-row-color-selected:before{background:#bbadcb}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-3 .so-cells .cell .cell-wrapper{background-color:#d5ccdf}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-3 .so-cells .cell.cell-selected .cell-wrapper{background-color:#b1a0c3}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-3 .so-cells .cell .resize-handle{background-color:#e7e2ed}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-3 .so-cells .cell .resize-handle:hover{background-color:#dfd9e7}.siteorigin-panels-builder .so-rows-container .so-row-color-4.so-row-color{background-color:#cae7cd;border:1px solid #a3d6a9}.siteorigin-panels-builder .so-rows-container .so-row-color-4.so-row-color.so-row-color-selected:before{background:#a7d7ac}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-4 .so-cells .cell .cell-wrapper{background-color:#cae7cd}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-4 .so-cells .cell.cell-selected .cell-wrapper{background-color:#99d19f}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-4 .so-cells .cell .resize-handle{background-color:#e3f2e4}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-4 .so-cells .cell .resize-handle:hover{background-color:#d8edda}.siteorigin-panels-builder .so-rows-container .so-row-color-5.so-row-color{background-color:#e2dcb1;border:1px solid #d3ca88}.siteorigin-panels-builder .so-rows-container .so-row-color-5.so-row-color.so-row-color-selected:before{background:#d4cb8c}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-5 .so-cells .cell .cell-wrapper{background-color:#e2dcb1}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-5 .so-cells .cell.cell-selected .cell-wrapper{background-color:#cfc57d}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-5 .so-cells .cell .resize-handle{background-color:#ece8cb}.siteorigin-panels-builder .so-rows-container .so-row-container.so-row-color-5 .so-cells .cell .resize-handle:hover{background-color:#e8e3c0}.siteorigin-panels-builder .so-rows-container h3.so-row-label{display:inline-block;font-size:1em;font-weight:500;color:#474747;margin:0 0 0 4px;line-height:22px;float:left}.siteorigin-panels-builder .so-rows-container .so-row-toolbar{zoom:1;margin-bottom:4px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar:before{content:"";display:block}.siteorigin-panels-builder .so-rows-container .so-row-toolbar:after{content:"";display:table;clear:both}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button{-ms-box-sizing:border-box;box-sizing:border-box;padding:4px;float:right}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button .so-panels-icon{color:#777;font-size:11px;width:11px;height:11px;display:block}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button:hover .so-panels-icon{color:#555}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button.so-row-move{cursor:move}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper{visibility:hidden;opacity:0;transition:visibility 0s linear 75ms,opacity 75ms linear;z-index:101;right:-10px;top:100%;width:125px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a.so-row-delete{color:#a00}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a.so-row-delete:hover{color:#fff;background:#a00}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li.so-row-colors-container{display:flex;justify-content:space-around;padding:5px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li.so-row-colors-container .so-row-color{display:inline-block;cursor:pointer;position:relative;text-align:center;width:14px;height:14px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li.so-row-colors-container .so-row-color.so-row-color-selected:before{content:"";display:block;position:absolute;top:2px;bottom:2px;left:2px;right:2px}.siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper:hover .so-dropdown-links-wrapper{visibility:visible;opacity:1;transition-delay:0s}.siteorigin-panels-builder .so-rows-container .ui-sortable-placeholder{visibility:visible!important;background:#f7f7f7;-ms-box-sizing:border-box;box-sizing:border-box}.siteorigin-panels-builder .so-rows-container .so-row-container{margin-bottom:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.siteorigin-panels-builder .so-rows-container .so-row-container.ui-sortable-helper{opacity:.9}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells{zoom:1;margin:0 -5px;position:relative}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells:before{content:"";display:block}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells:after{content:"";display:table;clear:both}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .ui-resizable-handle.ui-resizable-w{width:10px;left:-11px;cursor:col-resize;background:rgba(0,150,211,.25);transition:background .25s ease-in-out}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .ui-resizable-handle.ui-resizable-w:hover{background:rgba(0,150,211,.1)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell{-ms-box-sizing:border-box;box-sizing:border-box;float:left;position:relative;padding:0 5px}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell.so-first{margin-left:0}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell.so-last{margin-right:0}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .cell-wrapper{background:#e4eff4;padding:7px 7px 0;height:100%;min-height:63px;transition:background .25s ease-in-out 0s}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell.cell-selected .cell-wrapper{background-size:3px 3px}}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .cell-wrapper{-ms-box-sizing:border-box;box-sizing:border-box}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget{cursor:move;margin-bottom:7px;background:#f9f9fb;border:1px solid hsla(0,0%,100%,.75);max-height:49px;box-shadow:0 1px 1px rgba(0,0,0,.075);-ms-box-sizing:border-box;box-sizing:border-box}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-no-move{cursor:auto}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget:hover{border:1px solid hsla(0,0%,100%,.55);background:#fff;box-shadow:0 0 2px rgba(0,0,0,.1)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .so-widget-wrapper{padding:7px 8px;overflow:hidden;position:relative}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget h4{display:block;cursor:pointer;margin:0 15px 3px 0;font-weight:600;line-height:1.25em;color:#474747;text-shadow:0 1px 0 #fff;white-space:nowrap}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget h4 span{font-weight:400;display:inline-block;color:#999;text-shadow:0 1px 0 #fff;margin-left:12px;margin-right:5px;font-style:italic}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-no-edit h4{cursor:auto}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions{font-size:12px;position:absolute;top:5px;right:7px;cursor:pointer;padding:2px 2px 2px 15px;z-index:10}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions:hover{background:#feffff}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions:hover a{opacity:1}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions a{display:none;margin-right:3px;text-decoration:none}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions a.widget-delete{color:red}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .title .actions a.widget-delete:hover{color:#fff;background:red}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget:hover .title a{display:inline-block;opacity:.5}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.panel-being-dragged .title .actions{display:none}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget small{display:block;height:16px;overflow:hidden;color:#777}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .form{display:none}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only:hover{background:#f5f5f5;border:1px solid #a6bac1;box-shadow:none}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only:hover h4,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only:hover small,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only h4,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-widget-read-only small{opacity:.5}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered{background:#3a7096;border:1px solid #39618c;box-shadow:0 2px 2px rgba(0,0,0,.1)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered h4,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered small,.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered span{color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.85)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered small{color:#eee}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget-sortable-highlight{border:1px solid rgba(0,0,0,.075);background:rgba(0,0,0,.025);-ms-box-sizing:border-box;box-sizing:border-box;height:49px;margin-bottom:7px;position:relative;box-shadow:inset 2px 2px 2px rgba(0,0,0,.01)}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .resize-handle{z-index:100;position:absolute;top:0;width:10px;left:-5px;cursor:col-resize;background:#f6fafb;height:100%;transition:background .25s ease-in-out 0s}.siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell:first-child .resize-handle{display:none}.siteorigin-panels-builder .so-panels-welcome-message{text-align:center;padding:0 15px 20px;color:#555;line-height:1.8em}.siteorigin-panels-builder .so-panels-welcome-message .so-message-wrapper{padding:15px 10px;background:#f8f8f8;border:1px solid #e0e0e0}.siteorigin-panels-builder .so-panels-welcome-message .so-tool-button{font-size:inherit;display:inline-block;float:none;color:#666;padding:5px 10px;margin:0 3px}.siteorigin-panels-builder .so-panels-welcome-message .so-tool-button .so-panels-icon{color:#777;font-size:.8em}.siteorigin-panels-builder .so-panels-welcome-message .so-tip-wrapper{margin-top:15px;font-size:.95em}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar{padding:10px}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar>.so-tool-button{padding-right:2px}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar>.so-tool-button .so-panels-icon{font-size:14px}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar>.so-tool-button.so-learn,.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar>.so-tool-button span.so-button-text{display:none}.siteorigin-panels-builder.so-display-narrow .so-builder-toolbar .so-switch-to-standard,.siteorigin-panels-builder.so-display-narrow .widgets-container .so-widget .actions{display:none!important}.so-widget.ui-sortable-helper.widget-being-dragged{z-index:500002!important;opacity:.9;pointer-events:none;border:1px solid rgba(0,0,0,.35)!important;cursor:move;margin-bottom:7px;background:#f9f9fb;border:1px solid hsla(0,0%,100%,.75);max-height:49px;box-shadow:0 1px 1px rgba(0,0,0,.075);-ms-box-sizing:border-box;box-sizing:border-box}.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-no-move{cursor:auto}.so-widget.ui-sortable-helper.widget-being-dragged:hover{border:1px solid hsla(0,0%,100%,.55);background:#fff;box-shadow:0 0 2px rgba(0,0,0,.1)}.so-widget.ui-sortable-helper.widget-being-dragged .so-widget-wrapper{padding:7px 8px;overflow:hidden;position:relative}.so-widget.ui-sortable-helper.widget-being-dragged h4{display:block;cursor:pointer;margin:0 15px 3px 0;font-weight:600;line-height:1.25em;color:#474747;text-shadow:0 1px 0 #fff;white-space:nowrap}.so-widget.ui-sortable-helper.widget-being-dragged h4 span{font-weight:400;display:inline-block;color:#999;text-shadow:0 1px 0 #fff;margin-left:12px;margin-right:5px;font-style:italic}.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-no-edit h4{cursor:auto}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions{font-size:12px;position:absolute;top:5px;right:7px;cursor:pointer;padding:2px 2px 2px 15px;z-index:10}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions:hover{background:#feffff}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions:hover a{opacity:1}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions a{display:none;margin-right:3px;text-decoration:none}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions a.widget-delete{color:red}.so-widget.ui-sortable-helper.widget-being-dragged .title .actions a.widget-delete:hover{color:#fff;background:red}.so-widget.ui-sortable-helper.widget-being-dragged:hover .title a{display:inline-block;opacity:.5}.so-widget.ui-sortable-helper.widget-being-dragged.panel-being-dragged .title .actions{display:none}.so-widget.ui-sortable-helper.widget-being-dragged small{display:block;height:16px;overflow:hidden;color:#777}.so-widget.ui-sortable-helper.widget-being-dragged .form{display:none}.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only,.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only:hover{background:#f5f5f5;border:1px solid #a6bac1;box-shadow:none}.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only:hover h4,.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only:hover small,.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only h4,.so-widget.ui-sortable-helper.widget-being-dragged.so-widget-read-only small{opacity:.5}.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered{background:#3a7096;border:1px solid #39618c;box-shadow:0 2px 2px rgba(0,0,0,.1)}.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered h4,.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered small,.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered span{color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.85)}.so-widget.ui-sortable-helper.widget-being-dragged.so-hovered small{color:#eee}.widgets-holder-wrap .widget-inside .siteorigin-panels-builder .so-builder-container{padding-top:0}.widgets-holder-wrap .widget-inside .siteorigin-panels-builder .so-rows-container{padding:10px 0 0}.widgets-holder-wrap .widget-inside .siteorigin-panels-builder .so-builder-toolbar{padding-left:15px;padding-right:15px;margin:0 -15px}.so-panels-dialog .so-content,.so-panels-dialog .so-left-sidebar,.so-panels-dialog .so-overlay,.so-panels-dialog .so-right-sidebar,.so-panels-dialog .so-title-bar,.so-panels-dialog .so-toolbar{z-index:100001;position:fixed;-ms-box-sizing:border-box;box-sizing:border-box;padding:15px}.so-panels-dialog .so-content,.so-panels-dialog .so-left-sidebar,.so-panels-dialog .so-right-sidebar{overflow-y:auto}.so-panels-dialog .so-overlay{top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.5)}.so-panels-dialog .so-content{top:80px;left:30px;right:30px;bottom:88px;background-color:#fdfdfd;overflow-x:hidden;box-shadow:inset 0 2px 2px rgba(0,0,0,.03)}.so-panels-dialog .so-content>:first-child{margin-top:0}.so-panels-dialog .so-content>:last-child{margin-bottom:0}.so-panels-dialog .so-content .so-content-tabs>*{display:none}.so-panels-dialog .so-title-bar{left:30px;right:30px;top:30px;height:50px;background-color:#fafafa;border-bottom:1px solid #d8d8d8}.so-panels-dialog .so-title-bar h3.so-title{-ms-box-sizing:border-box;box-sizing:border-box;margin:-3px 150px 0 -3px;padding:5px 6px;display:block}.so-panels-dialog .so-title-bar h3.so-title.so-title-editable:focus,.so-panels-dialog .so-title-bar h3.so-title.so-title-editable:hover{outline:none;background-color:#f0f0f0}.so-panels-dialog .so-title-bar h3.so-title.so-title-editable:focus{margin-top:-4px;margin-left:-4px;border:1px solid #e4e4e4}.so-panels-dialog .so-title-bar input[type=text].so-edit-title{margin-top:-3px;margin-left:-3px;display:none;color:#23282d;font-size:1.3em;font-weight:600;border:none;box-shadow:none;background-color:#f0f0f0;padding:4px 5px}.so-panels-dialog .so-title-bar h3.so-parent-link{cursor:pointer;position:relative;float:left;margin:0 15px 0 0!important;padding:0 27px 0 0!important}.so-panels-dialog .so-title-bar h3.so-parent-link .so-separator{position:absolute;top:-15px;right:0;width:12px;height:50px;display:block;background:url(images/dialog-separator.png) no-repeat}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.so-panels-dialog .so-title-bar h3.so-parent-link .so-separator{background:url(images/dialog-separator@2x.png) no-repeat;background-size:cover}}.so-panels-dialog .so-title-bar a{cursor:pointer;position:absolute;box-sizing:border-box;width:50px;height:50px;display:block;top:0;right:0;transition:all .2s ease 0s;background:#fafafa;border-left:1px solid #d8d8d8;border-bottom:1px solid #d8d8d8}.so-panels-dialog .so-title-bar a:hover{background:#e9e9e9}.so-panels-dialog .so-title-bar a:hover .so-dialog-icon{color:#333}.so-panels-dialog .so-title-bar a .so-dialog-icon{position:absolute;top:50%;left:50%;text-decoration:none;width:20px;height:20px;margin-left:-10px;margin-top:-10px;color:#666;text-align:center}.so-panels-dialog .so-title-bar a .so-dialog-icon:before{font:400 20px/1em dashicons;top:7px;left:13px}.so-panels-dialog .so-title-bar a.so-close{right:0}.so-panels-dialog .so-title-bar a.so-close .so-dialog-icon:before{content:"\f335"}.so-panels-dialog .so-title-bar a.so-next{right:50px}.so-panels-dialog .so-title-bar a.so-next .so-dialog-icon:before{content:"\f345"}.so-panels-dialog .so-title-bar a.so-previous{right:100px}.so-panels-dialog .so-title-bar a.so-previous .so-dialog-icon:before{content:"\f341"}.so-panels-dialog .so-title-bar a.so-nav.so-disabled{cursor:default;pointer-events:none}.so-panels-dialog .so-title-bar a.so-nav.so-disabled .so-dialog-icon{color:#ddd}.so-panels-dialog .so-title-bar.so-has-icon{padding-left:45px}.so-panels-dialog .so-title-bar.so-has-icon .so-panels-icon{position:absolute;top:14.5px;left:14px;font-size:22px;line-height:22px;display:block;width:22px;height:22px;text-align:center;color:#666}.so-panels-dialog .so-toolbar{left:30px;right:30px;bottom:30px;height:58px;background-color:#fafafa;border-top:1px solid #d8d8d8;z-index:100002}.so-panels-dialog .so-toolbar .so-status{float:left;padding-top:6px;padding-bottom:6px;font-style:italic;color:#999;line-height:1em}.so-panels-dialog .so-toolbar .so-status.so-panels-loading{padding-left:26px;background-position:0}.so-panels-dialog .so-toolbar .so-status .dashicons-warning{color:#a00;vertical-align:middle;margin-right:7px;margin-top:-1px}.so-panels-dialog .so-toolbar .so-buttons{float:right}.so-panels-dialog .so-toolbar .so-buttons .action-buttons{position:absolute;left:15px;top:50%;margin-top:-.65em}.so-panels-dialog .so-toolbar .so-buttons .action-buttons a{cursor:pointer;display:inline;padding:.2em .5em;line-height:1em;margin-right:.5em;text-decoration:none}.so-panels-dialog .so-toolbar .so-buttons .action-buttons .so-delete{color:#a00}.so-panels-dialog .so-toolbar .so-buttons .action-buttons .so-delete:hover{background:#a00;color:#fff}.so-panels-dialog .so-toolbar .so-buttons .action-buttons .so-duplicate:hover{text-decoration:underline}.so-panels-dialog .so-left-sidebar,.so-panels-dialog .so-right-sidebar{background-color:#f3f3f3}.so-panels-dialog .so-left-sidebar{display:none;top:30px;left:30px;bottom:30px;width:290px;border-right:1px solid #d8d8d8}.so-panels-dialog .so-left-sidebar h4{margin:0 0 20px;font-size:18px}.so-panels-dialog .so-left-sidebar .so-sidebar-search{width:100%;padding:6px;margin-bottom:20px}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs{list-style:none;margin:0 -15px}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li{margin-bottom:0}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li a{padding:7px 16px;display:block;font-size:14px;text-decoration:none;box-shadow:none!important}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li a:hover{background:#fff}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li.tab-active a{color:#555;font-weight:700;background:#fff}.so-panels-dialog .so-left-sidebar .so-sidebar-tabs li.tab-active a:hover{background:#fff}.so-panels-dialog .so-right-sidebar{display:none;top:80px;right:30px;bottom:88px;width:290px;border-left:1px solid #d8d8d8}.so-panels-dialog .so-right-sidebar h3{color:#333}.so-panels-dialog .so-right-sidebar h3:first-child{margin-top:0}.so-panels-dialog .so-sidebar .form-field{margin-bottom:20px}.so-panels-dialog .so-sidebar .form-field label{font-weight:500;font-size:15px;display:block;margin-bottom:10px}.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-content,.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-title-bar,.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-toolbar{left:320px}.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-content{box-shadow:inset 2px 2px 2px rgba(0,0,0,.03)}.so-panels-dialog.so-panels-dialog-has-left-sidebar .so-left-sidebar{display:block}.so-panels-dialog.so-panels-dialog-has-right-sidebar .so-content{right:320px}.so-panels-dialog.so-panels-dialog-has-right-sidebar .so-right-sidebar{display:block}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget{border-radius:2px;border:1px solid #ccc;cursor:pointer;padding:10px;background:#f9f9f9;box-shadow:0 1px 2px rgba(0,0,0,.075),inset 0 1px 0 #fff;margin-bottom:15px}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget:hover{border:1px solid #bbb;background:#fff}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget.so-current{border-color:#0074a2;background:#2ea2cc;cursor:auto;box-shadow:0 1px 2px rgba(0,0,0,.15),inset 0 1px 0 hsla(0,0%,100%,.2)}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget.so-current h3{color:#fff}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget.so-current small{color:#eee}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget.so-current:hover{border-color:#0074a2;background:#2ea2cc}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget:last-child{margin-bottom:0}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget h3{margin:0 0 7px;padding:0;height:1.2em;color:#222;font-size:14px}.so-panels-dialog.so-panels-dialog-edit-widget .so-left-sidebar .so-widgets .so-widget small{font-size:11px;line-height:1.25em;display:block;overflow:hidden;color:#888}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list{zoom:1;margin:0 -5px -10px;min-height:10px}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list:before{content:"";display:block}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list:after{content:"";display:table;clear:both}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type{-ms-user-select:none;-moz-user-select:-moz-none;-webkit-user-select:none;user-select:none;-ms-box-sizing:border-box;box-sizing:border-box;width:25%;padding:0 5px;margin-bottom:10px;float:left}@media (max-width:1280px){.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type{width:33.333%}}@media (max-width:960px){.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type{width:50%}}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type h3{margin:0 0 7px;padding:0;color:#222;font-size:14px}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type small{font-size:11px;min-height:2.5em;line-height:1.25em;display:block;overflow:hidden;color:#888}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type .widget-icon{font-size:20px;width:20px;height:20px;color:#666;float:left;margin:-1px .5em 0 0}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type-wrapper{border:1px solid #ccc;cursor:pointer;padding:10px;background:#f8f8f8;box-shadow:0 1px 2px rgba(0,0,0,.075)}.so-panels-dialog.so-panels-dialog-add-widget .widget-type-list .widget-type-wrapper:hover{border:1px solid #bbb;background:#fff;box-shadow:0 2px 2px rgba(0,0,0,.075)}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form{zoom:1;padding:8px;border:1px solid #ccc;margin-bottom:20px;background:#f3f3f3}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form:before{content:"";display:block}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form:after{content:"";display:table;clear:both}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form button,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form input,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form select,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form span,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form strong{display:inline;margin:1px 5px;outline:none;box-shadow:none}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form button{margin-top:2px}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-set-form label{display:inline}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview{margin:0 -6px;height:360px;position:relative;white-space:nowrap}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell-in,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell-weight{-ms-box-sizing:border-box;box-sizing:border-box}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell{display:inline-block;position:relative;padding:0 6px;cursor:pointer}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in{border:1px solid #bcccd2;min-height:360px;background:#e4eff4;position:relative}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in.cell-selected{background:#cae7f4 url(images/cell-selected.png) repeat;border-color:#9abcc7;box-shadow:0 0 5px rgba(0,0,0,.2)}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight-input{position:absolute;font-size:17px;font-weight:700;top:50%;left:50%;width:80px;text-align:center;color:#5e6d72;margin:-.95em 0 0 -40px;padding:10px 0;border:1px solid transparent;line-height:1.4em!important;overflow:hidden;cursor:pointer}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight-input:after,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight:after{content:"%"}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight-input:hover,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight:hover{background:#f6f6f6;border:1px solid #d0d0d0}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .preview-cell-in .preview-cell-weight-input{background:#f6f6f6;border:1px solid #d0d0d0;box-shadow:none}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .resize-handle{z-index:100;position:absolute;top:0;width:12px;left:-6px;cursor:col-resize;background:#e5f4fb;height:360px;transition:background .15s ease-in-out 0s}.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .resize-handle.ui-draggable-dragging,.so-panels-dialog.so-panels-dialog-row-edit .so-content .row-preview .preview-cell .resize-handle:hover{background:#b7e0f1}.so-panels-dialog.so-panels-dialog-history .so-left-sidebar{padding:0}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry{padding:10px;background:#f8f8f8;cursor:pointer;border-bottom:1px solid #ccc}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry h3{margin:0 0 .6em;font-size:12px;font-weight:700;color:#444;line-height:1em}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry .timesince{color:#999;font-size:11px;line-height:1em}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry:hover{background:#f0f0f0}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry.so-selected{background:#eee}.so-panels-dialog.so-panels-dialog-history .history-entries .history-entry .count{color:#999}.so-panels-dialog.so-panels-dialog-history .so-content{padding:0;overflow-y:hidden}.so-panels-dialog.so-panels-dialog-history .so-content form.history-form{display:none}.so-panels-dialog.so-panels-dialog-history .so-content iframe.siteorigin-panels-history-iframe{width:100%;height:100%}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content{padding-left:10px;padding-right:10px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-error-message{font-size:14px;border:1px solid #ccc;background:#f8f8f8;padding:15px 20px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .export-file-ui{padding:5px 15px;text-align:right}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui{padding:15px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .drag-drop-message{display:none}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui.has-drag-drop .drag-drop-message{display:block}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui p.drag-drop-message{font-size:1em;margin-bottom:0}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .drag-upload-area{display:block;-ms-box-sizing:border-box;box-sizing:border-box;padding:50px 30px;border:4px dashed #e0e0e0;text-align:center;transition:all .25s ease 0s}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .drag-upload-area.file-dragover{background-color:#f2f9fc;border-color:#0074a2}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .progress-bar{display:none;padding:2px;border:2px solid #2181b1;border-radius:2px;margin-top:20px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .progress-bar .progress-percent{height:14px;background-color:#358ebe;border-radius:1px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .file-browse-button{padding:12px 30px;height:auto}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-browse{background:#f3f3f3;border-bottom:1px solid #d0d0d0;margin:-15px -10px 15px;padding:15px;font-weight:700}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items-wrapper{display:flex;flex-flow:row wrap}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-no-results{margin:20px 0;padding:0 5px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{-ms-box-sizing:border-box;box-sizing:border-box;padding:6px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-directory-item-wrapper{display:flex;flex-flow:column nowrap;height:100%;box-sizing:border-box;padding:15px 10px;background:#f7f7f7;border:1px solid #d0d0d0;box-shadow:0 1px 1px rgba(0,0,0,.1)}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-title{font-size:15px;margin:0 0 13px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot{flex:3 auto;margin-bottom:10px;cursor:pointer}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot.so-loading{background-image:url(images/wpspin_light.gif);background-position:50%;background-repeat:no-repeat}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot.so-loading{background-image:url(images/wpspin_light-2x.gif);background-size:16px 16px}}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot img{display:block;width:100%;height:auto}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot .so-screenshot-wrapper{display:block;min-height:40px;background:gray;border:1px solid #d0d0d0}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-description{flex:1 auto;font-size:.9em;color:#666;margin-bottom:10px;max-height:60px;overflow:hidden}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom{flex:1 auto;position:relative;max-height:50px;margin:10px -10px -15px;background:#fcfcfc;border-top:1px solid #d0d0d0}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom .so-title{margin:0;padding:16px 10px;cursor:pointer;overflow:hidden;white-space:nowrap}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom .so-buttons{position:absolute;z-index:2;top:0;bottom:0;right:0;height:100%;visibility:hidden;-ms-box-sizing:border-box;box-sizing:border-box;padding:11px 10px 10px 15px;border-left:1px solid #d0d0d0;background:#f6f6f6;box-shadow:-1px 0 1px rgba(0,0,0,.05)}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item:hover .so-buttons{visibility:visible}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected{background-color:#e5f4fa}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-directory-item-wrapper{background:#deeef4;border-color:#9abcc7}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-bottom{background:#f8fdff;border-color:#bcccd2}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-bottom .so-title{color:#3e484c}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-bottom .so-buttons{background:#eaf2f6;border-color:#bcccd2}@media only screen and (min-width:1680px){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{width:20%}}@media only screen and (max-width:1679px) and (min-width:1280px){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{width:25%}}@media only screen and (max-width:1279px) and (min-width:1140px){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{width:33.333%}}@media only screen and (max-width:1139px){.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item{width:50%}}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-pages{margin-top:15px;padding:0 5px}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-pages .button-disabled{pointer-events:none}.so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-toolbar .so-buttons select.so-layout-position{vertical-align:baseline}.so-panels-dialog .so-visual-styles{margin:-15px;height:100%}.so-panels-dialog .so-visual-styles h3{line-height:1em;margin:0;padding:20px 15px;border-bottom:1px solid #ddd}.so-panels-dialog .so-visual-styles .style-section-head{background:#fff;padding:15px 10px;border-bottom:1px solid #ddd;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.so-panels-dialog .so-visual-styles .style-section-head h4{margin:0}.so-panels-dialog .so-visual-styles .style-section-fields{padding:15px;border-bottom:1px solid #ddd;background:#f7f7f7}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper{margin-bottom:20px}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper:last-child{margin-bottom:0}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper>label{font-weight:700;display:block;margin-bottom:3px}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper .style-field{zoom:1}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper .style-field:before{content:"";display:block}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper .style-field:after{content:"";display:table;clear:both}.so-panels-dialog .so-visual-styles .style-section-fields .style-field-wrapper .style-field input{font-size:12px}.so-panels-dialog .so-visual-styles .style-input-wrapper{zoom:1}.so-panels-dialog .so-visual-styles .style-input-wrapper:before{content:"";display:block}.so-panels-dialog .so-visual-styles .style-input-wrapper:after{content:"";display:table;clear:both}.so-panels-dialog .so-visual-styles .style-input-wrapper input{max-width:100%}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-inputs{overflow:auto;margin:0 -3px 4px}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper{box-sizing:border-box;float:left;width:25%;padding:0 3px}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value{border-width:1px;display:block;max-width:100%}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value.measurement-top{box-shadow:inset 0 2px 1px rgba(0,115,170,.35)}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value.measurement-right{box-shadow:inset -3px 0 2px rgba(0,115,170,.35)}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value.measurement-bottom{box-shadow:inset 0 -2px 1px rgba(0,115,170,.35)}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-wrapper .measurement-value.measurement-left{box-shadow:inset 3px 0 2px rgba(0,115,170,.35)}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-unit-multiple{width:100%;display:block}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-unit-single{float:right;width:25%}.so-panels-dialog .so-visual-styles .style-field-measurement .measurement-value-single{float:left;width:72%}.so-panels-dialog .so-visual-styles .style-field-image .so-image-selector{display:inline-block;background-color:#f7f7f7;border:1px solid #ccc;height:28px;float:left;border-radius:3px;cursor:pointer;box-shadow:inset 0 1px #fff}.so-panels-dialog .so-visual-styles .style-field-image .so-image-selector .current-image{height:28px;width:28px;float:left;background:#fff;border-right:1px solid #ccc;background-size:cover;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:3px;border-top-left-radius:3px;background-clip:padding-box}.so-panels-dialog .so-visual-styles .style-field-image .so-image-selector .select-image{font-size:12px;line-height:28px;float:left;padding:0 8px;color:#555}.so-panels-dialog .so-visual-styles .style-field-image .remove-image{font-size:12px;margin-top:4px;margin-left:15px;display:inline-block;float:left;color:#666;text-decoration:none}.so-panels-dialog .so-visual-styles .style-field-image .remove-image.hidden{display:none}.so-panels-dialog .so-visual-styles .style-field-image .image-fallback{margin-top:4px}.so-panels-dialog .so-visual-styles .style-field-checkbox label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.so-panels-dialog .so-visual-styles .so-field-code{font-size:12px;font-family:Courier\ 10 Pitch,Courier,monospace}.so-panels-dialog .so-visual-styles .so-description{color:#999;font-size:12px;margin-top:5px;margin-bottom:0;font-style:italic;clear:both}.so-panels-dialog .so-visual-styles.so-cell-styles{margin-top:15px}.so-panels-dialog .so-content .siteorigin-panels-builder .so-builder-toolbar{border:1px solid #dedede}.so-panels-dialog .so-content .siteorigin-panels-builder .so-rows-container{padding:20px 0 0}.so-panels-dialog .so-content .siteorigin-panels-builder .so-panels-welcome-message{padding-left:0;padding-right:0}.so-panels-dialog .so-dropdown-wrapper input[type=button].button-primary{width:125px;height:28px}.so-panels-dialog .so-dropdown-wrapper .so-dropdown-links-wrapper{display:block;z-index:11;bottom:28px;width:125px}.so-panels-dialog .so-dropdown-wrapper .so-dropdown-links-wrapper.hidden{display:none}.wp-customizer .so-panels-dialog .so-content,.wp-customizer .so-panels-dialog .so-left-sidebar,.wp-customizer .so-panels-dialog .so-overlay,.wp-customizer .so-panels-dialog .so-right-sidebar,.wp-customizer .so-panels-dialog .so-title-bar,.wp-customizer .so-panels-dialog .so-toolbar{z-index:500001}.wp-customizer .so-panels-dialog .so-toolbar{z-index:500002}.so-panels-live-editor>div{position:fixed;z-index:99999;-ms-box-sizing:border-box;box-sizing:border-box}.so-panels-live-editor .live-editor-form{display:none}.so-panels-live-editor .live-editor-collapse{position:fixed;top:18px;left:10px;line-height:1em;cursor:pointer;z-index:100000}.so-panels-live-editor .live-editor-collapse .collapse-icon{float:left;margin:-4px 6px 0 0;border-radius:50%;width:20px;height:20px;overflow:hidden;transition:all .25s ease 0s}.so-panels-live-editor .live-editor-collapse .collapse-icon:before{display:block;content:"\f148";background:#eee;font:normal 20px/1 dashicons;speak:none;padding:0;-webkit-font-smoothing:antialiased}.so-panels-live-editor .live-editor-collapse:hover{color:#0073aa}.so-panels-live-editor .live-editor-collapse:hover .collapse-icon{box-shadow:0 0 3px rgba(30,140,190,.8)}.so-panels-live-editor .so-sidebar-tools{background:#eee;border-bottom:1px solid #ddd;border-right:1px solid #d0d0d0;top:0;left:0;height:46px;width:360px}.so-panels-live-editor .so-sidebar-tools .live-editor-close{margin:9px 10px 0 15px;float:right}.so-panels-live-editor .so-sidebar-tools .live-editor-mode{float:right;margin:9px 4px 0 0}.so-panels-live-editor .so-sidebar-tools .live-editor-mode .dashicons{font-size:30px;width:30px;height:30px;cursor:pointer;color:#999}.so-panels-live-editor .so-sidebar-tools .live-editor-mode .dashicons:hover{color:#666}.so-panels-live-editor .so-sidebar-tools .live-editor-mode.so-active .dashicons,.so-panels-live-editor .so-sidebar-tools .live-editor-mode.so-active .dashicons:hover{color:#0073aa}.so-panels-live-editor .so-sidebar{top:46px;left:0;bottom:0;width:360px;overflow-y:auto;background:#f7f7f7;border-right:1px solid #d0d0d0}.so-panels-live-editor .so-sidebar .siteorigin-panels-builder .so-rows-container{padding:10px 10px 0!important}.so-panels-live-editor .so-preview{top:0;right:0;bottom:0;left:360px;background-color:#191e23}.so-panels-live-editor .so-preview form{display:none}.so-panels-live-editor .so-preview iframe{float:left;width:100%;height:100%;margin:0 auto}.so-panels-live-editor .so-preview-overlay{display:none;opacity:.975;top:0;right:0;bottom:0;left:360px;background-color:#f4f4f4;cursor:wait}.so-panels-live-editor .so-preview-overlay .so-loading-container{opacity:.6;position:absolute;top:50%;width:200px;padding:2px;border-radius:5px;left:50%;margin-left:-104px;margin-top:-9px;border:2px solid #aaa}.so-panels-live-editor .so-preview-overlay .so-loading-container .so-loading-bar{width:50%;border-radius:3px;height:10px;background:#aaa}.so-panels-live-editor.so-collapsed .live-editor-collapse .collapse-icon{transform:rotate(180deg)}.so-panels-live-editor.so-collapsed .so-sidebar,.so-panels-live-editor.so-collapsed .so-sidebar-tools{display:none}.so-panels-live-editor.so-collapsed .so-preview,.so-panels-live-editor.so-collapsed .so-preview-overlay{left:0}.so-panels-live-editor.live-editor-mobile-mode .so-preview iframe{max-width:480px;max-height:640px;position:absolute;top:50%;left:50%;margin-left:-240px;margin-top:-320px}@media (max-width:840px){.so-panels-live-editor.live-editor-mobile-mode .so-preview iframe{position:static;margin-left:0;margin-top:0}}@media (max-height:640px){.so-panels-live-editor.live-editor-mobile-mode .so-preview iframe{position:static;margin-left:0;margin-top:0}}.so-panels-live-editor.live-editor-tablet-mode .so-preview iframe{position:absolute;max-width:768px;top:0;left:50%;margin-left:-384px}@media (max-width:1128px){.so-panels-live-editor.live-editor-tablet-mode .so-preview iframe{position:static;margin-left:0;margin-top:0}}.so-panels-loading{background-image:url(images/wpspin_light.gif);background-position:50%;background-repeat:no-repeat}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.so-panels-loading{background-image:url(images/wpspin_light-2x.gif);background-size:16px 16px}}#panels-home-page .switch{margin:0 10px 0 0;float:left;position:relative;display:inline-block;vertical-align:top;width:68px;height:24px;padding:3px;background-color:#fff;border-radius:24px;box-shadow:inset 0 -1px #fff,inset 0 1px 1px rgba(0,0,0,.05);cursor:pointer;background-image:linear-gradient(180deg,#eee,#fff 25px)}#panels-home-page .switch .switch-input{position:absolute;top:0;left:0;opacity:0}#panels-home-page .switch .switch-label{position:relative;display:block;height:inherit;font-size:12px;text-transform:uppercase;background:#eceeef;border-radius:inherit;box-shadow:inset 0 1px 2px rgba(0,0,0,.12),inset 0 0 2px rgba(0,0,0,.15);transition:.15s ease-out;transition-property:opacity background}#panels-home-page .switch .switch-label:after,#panels-home-page .switch .switch-label:before{position:absolute;top:50%;margin-top:-.5em;line-height:1;transition:inherit}#panels-home-page .switch .switch-label:before{content:attr(data-off);right:11px;color:#aaa;text-shadow:0 1px hsla(0,0%,100%,.5)}#panels-home-page .switch .switch-label:after{content:attr(data-on);left:13px;color:#fff;text-shadow:0 1px rgba(0,0,0,.2);opacity:0}#panels-home-page .switch .switch-input:checked~.switch-label{background:#47a8d8;box-shadow:inset 0 1px 2px rgba(0,0,0,.15),inset 0 0 3px rgba(0,0,0,.2)}#panels-home-page .switch .switch-input:checked~.switch-label:before{opacity:0}#panels-home-page .switch .switch-input:checked~.switch-label:after{opacity:1}#panels-home-page .switch .switch-handle{position:absolute;top:4px;left:4px;width:22px;height:22px;background:#fff;border-radius:12px;box-shadow:1px 1px 5px rgba(0,0,0,.2);background-image:linear-gradient(180deg,#fff 40%,#f0f0f0);transition:left .15s ease-out}#panels-home-page .switch .switch-handle:before{content:"";position:absolute;top:50%;left:50%;margin:-7px 0 0 -7px;width:14px;height:14px;background:#f9f9f9;border-radius:7px;box-shadow:inset 0 1px rgba(0,0,0,.02);background-image:linear-gradient(180deg,#eee,#fff)}#panels-home-page .switch .switch-input:checked~.switch-handle{left:48px;box-shadow:-1px 1px 5px rgba(0,0,0,.2)}#panels-home-page .switch .switch-green>.switch-input:checked~.switch-label{background:#4fb845}#panels-home-page #panels-view-as-page{display:inline-block;margin-left:50px}.siteorigin-panels-builder-form .siteorigin-panels-builder{border:1px solid #d0d0d0;background-color:#fff;margin:10px 0}.siteorigin-panels-builder-form .siteorigin-panels-builder.so-panels-loading{min-height:150px}.siteorigin-page-builder-widget .siteorigin-panels-display-builder{display:inline-block!important}.siteorigin-page-builder-widget .siteorigin-panels-no-builder{display:none!important}.so-panels-contextual-menu{border:1px solid silver;background:#f9f9f9;box-shadow:0 1px 1px rgba(0,0,0,.04);outline:none;border-radius:2px;position:absolute;width:180px;top:20px;left:20px;z-index:999999;display:none;overflow-y:auto}.so-panels-contextual-menu,.so-panels-contextual-menu *{font-size:12px}.so-panels-contextual-menu .so-section{border-bottom:1px solid silver}.so-panels-contextual-menu .so-section:last-child{border-bottom:none}.so-panels-contextual-menu .so-section h5{margin:0 0 5px;padding:8px 10px 5px;border-bottom:1px solid #d0d0d0;background:#f6f6f6}.so-panels-contextual-menu .so-section .so-search-wrapper{margin:-5px 0 5px;border-bottom:1px solid #d0d0d0;background:#f4f4f4}.so-panels-contextual-menu .so-section .so-search-wrapper input[type=text]{box-sizing:border-box;display:block;width:100%;margin:0;border:none;padding:5px 10px;background:#fbfbfb}.so-panels-contextual-menu .so-section .so-search-wrapper input[type=text]:active,.so-panels-contextual-menu .so-section .so-search-wrapper input[type=text]:focus{border:none;box-shadow:none;background:#fff}.so-panels-contextual-menu .so-section ul{margin:5px 0 0;padding:0 0 5px}.so-panels-contextual-menu .so-section ul li{cursor:pointer;margin:0;padding:4px 10px;line-height:1em}.so-panels-contextual-menu .so-section ul li.so-active,.so-panels-contextual-menu .so-section ul li:hover{background:#f0f0f0;color:#444}.so-panels-contextual-menu .so-section ul li.so-confirm{color:#a00}.so-panels-contextual-menu .so-section ul li.so-confirm.so-active,.so-panels-contextual-menu .so-section ul li.so-confirm:hover{background:#a00;color:#fff}.so-panels-contextual-menu .so-section ul li .dashicons{width:12px;height:12px;font-size:12px;margin:0;float:right;line-height:12px}.so-panels-contextual-menu .so-section .so-no-results{padding:0 10px 5px;display:none;font-style:italic}.so-dropdown-wrapper{position:relative;float:right}.so-dropdown-wrapper .so-dropdown-links-wrapper{position:absolute;padding:6px 0 0}.so-dropdown-wrapper .so-dropdown-links-wrapper ul{margin:0;border:1px solid silver;background:#f9f9f9;border-radius:2px;padding:4px 0;box-shadow:0 2px 2px rgba(0,0,0,.1)}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li{margin:0}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li:first-child{border-top-width:1px}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li a{display:block;padding:2px 8px;text-decoration:none;color:#666;font-size:11px;cursor:pointer;outline:0!important;box-shadow:none}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li a:hover{background:#f0f0f0;color:#444}.so-dropdown-wrapper .so-dropdown-links-wrapper ul li a .dashicons{font-size:16px;margin:0;float:right;line-height:16px}.so-dropdown-wrapper .so-dropdown-links-wrapper .so-pointer{width:12px;height:6px;position:absolute;z-index:12;background:url(images/dropdown-pointer.png);background-size:12px 6px;top:1px;right:18px}.so-panels-icon{font-family:siteorigin-panels-icons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.so-panels-icon.so-panels-icon-add-row:before{content:"\e900"}.so-panels-icon.so-panels-icon-add-widget:before{content:"\e901"}.so-panels-icon.so-panels-icon-addons:before{content:"\e902"}.so-panels-icon.so-panels-icon-history:before{content:"\e903"}.so-panels-icon.so-panels-icon-layouts:before{content:"\e904"}.so-panels-icon.so-panels-icon-learn:before{content:"\e905"}.so-panels-icon.so-panels-icon-live-editor:before{content:"\e906"}.so-panels-icon.so-panels-icon-move:before{content:"\e907"}.so-panels-icon.so-panels-icon-settings:before{content:"\e908"}#post-status-info.for-siteorigin-panels{margin-top:-21px!important}
inc/admin-layouts.php CHANGED
@@ -90,17 +90,33 @@ class SiteOrigin_Panels_Admin_Layouts {
90
  }
91
 
92
  foreach ( $files as $file ) {
93
- // get file mime type
94
- $mime_type = mime_content_type( $file );
95
 
96
- // skip non text files.
97
- if ( strpos( $mime_type, 'text/' ) !== 0 ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  continue;
99
  }
100
 
101
  // get file contents
102
  $file_contents = file_get_contents( $file );
103
 
 
 
 
 
 
104
  // json decode
105
  $panels_data = json_decode( $file_contents, true );
106
 
90
  }
91
 
92
  foreach ( $files as $file ) {
 
 
93
 
94
+ if ( function_exists( 'mime_content_type' ) ) {
95
+ // get file mime type
96
+ $mime_type = mime_content_type( $file );
97
+
98
+ // Valid if text files.
99
+ $valid_file_type = strpos( $mime_type, 'text/' ) === 0;
100
+ } else {
101
+ // If `mime_content_type` isn't available, just check file extension.
102
+ $ext = pathinfo( $file, PATHINFO_EXTENSION );
103
+
104
+ // skip files which don't have a `.json` extension.
105
+ $valid_file_type = ! empty( $ext ) && $ext === 'json';
106
+ }
107
+
108
+ if ( ! $valid_file_type ) {
109
  continue;
110
  }
111
 
112
  // get file contents
113
  $file_contents = file_get_contents( $file );
114
 
115
+ // skip if file_get_contents fails
116
+ if ( $file_contents === false ) {
117
+ continue;
118
+ }
119
+
120
  // json decode
121
  $panels_data = json_decode( $file_contents, true );
122
 
inc/admin.php CHANGED
@@ -433,6 +433,9 @@ class SiteOrigin_Panels_Admin {
433
  'prebuiltDefaultScreenshot' => siteorigin_panels_url( 'css/images/prebuilt-default.png' ),
434
  'loadOnAttach' => siteorigin_panels_setting( 'load-on-attach' ),
435
  'siteoriginWidgetRegex' => str_replace( '*+', '*', get_shortcode_regex( array( 'siteorigin_widget' ) ) ),
 
 
 
436
  ) );
437
 
438
  $js_widgets = array();
@@ -700,6 +703,20 @@ class SiteOrigin_Panels_Admin {
700
 
701
  // Other plugins can manipulate the list of widgets. Possibly to add recommended widgets
702
  $widgets = apply_filters( 'siteorigin_panels_widgets', $widgets );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
703
 
704
  // Sort the widgets alphabetically
705
  uasort( $widgets, array( $this, 'widgets_sorter' ) );
@@ -908,7 +925,17 @@ class SiteOrigin_Panels_Admin {
908
  // Add all the information fields
909
  return $form;
910
  }
911
-
 
 
 
 
 
 
 
 
 
 
912
  function is_core_js_widget( $widget ) {
913
  $js_widgets = array(
914
  'WP_Widget_Custom_HTML',
@@ -969,13 +996,21 @@ class SiteOrigin_Panels_Admin {
969
  * Display a widget form with the provided data
970
  */
971
  function action_widget_form() {
972
- if ( empty( $_REQUEST['widget'] ) ) {
973
- wp_die();
974
- }
975
  if ( empty( $_REQUEST['_panelsnonce'] ) || ! wp_verify_nonce( $_REQUEST['_panelsnonce'], 'panels_action' ) ) {
976
- wp_die();
 
 
 
 
977
  }
978
-
 
 
 
 
 
 
 
979
  $request = array_map( 'stripslashes_deep', $_REQUEST );
980
 
981
  $widget_class = $request['widget'];
433
  'prebuiltDefaultScreenshot' => siteorigin_panels_url( 'css/images/prebuilt-default.png' ),
434
  'loadOnAttach' => siteorigin_panels_setting( 'load-on-attach' ),
435
  'siteoriginWidgetRegex' => str_replace( '*+', '*', get_shortcode_regex( array( 'siteorigin_widget' ) ) ),
436
+ 'forms' => array(
437
+ 'loadingFailed' => __( 'Unknown error. Failed to load the form. Please check your internet connection, contact your web site administrator, or try again later.', 'siteorigin-panels' ),
438
+ )
439
  ) );
440
 
441
  $js_widgets = array();
703
 
704
  // Other plugins can manipulate the list of widgets. Possibly to add recommended widgets
705
  $widgets = apply_filters( 'siteorigin_panels_widgets', $widgets );
706
+
707
+ // Exclude these temporarily, as they won't work until we have a reliable way to enqueue their admin form scripts.
708
+ $to_exclude = array(
709
+ 'Jetpack_Gallery_Widget',
710
+ 'WPCOM_Widget_GooglePlus_Badge',
711
+ 'Jetpack_Widget_Social_Icons',
712
+ 'Jetpack_Twitter_Timeline_Widget'
713
+ );
714
+
715
+ foreach ( $to_exclude as $widget_class ) {
716
+ if ( in_array( $widget_class, $widgets ) ) {
717
+ unset( $widgets[ $widget_class ] );
718
+ }
719
+ }
720
 
721
  // Sort the widgets alphabetically
722
  uasort( $widgets, array( $this, 'widgets_sorter' ) );
925
  // Add all the information fields
926
  return $form;
927
  }
928
+
929
+ /**
930
+ * Checks whether a widget is considered to be a JS widget. I.e. it needs to have scripts and/or styles enqueued for
931
+ * it's admin form to work.
932
+ *
933
+ * Can remove the whitelist of core widgets when all widgets are following a similar pattern.
934
+ *
935
+ * @param $widget The widget to be tested.
936
+ *
937
+ * @return bool Whether or not the widget is considered a JS widget.
938
+ */
939
  function is_core_js_widget( $widget ) {
940
  $js_widgets = array(
941
  'WP_Widget_Custom_HTML',
996
  * Display a widget form with the provided data
997
  */
998
  function action_widget_form() {
 
 
 
999
  if ( empty( $_REQUEST['_panelsnonce'] ) || ! wp_verify_nonce( $_REQUEST['_panelsnonce'], 'panels_action' ) ) {
1000
+ wp_die(
1001
+ __( 'The supplied nonce is invalid.', 'siteorigin-panels' ),
1002
+ __( 'Invalid nonce.', 'siteorigin-panels' ),
1003
+ 403
1004
+ );
1005
  }
1006
+ if ( empty( $_REQUEST['widget'] ) ) {
1007
+ wp_die(
1008
+ __( 'Please specify the type of widget form to be rendered.', 'siteorigin-panels' ),
1009
+ __( 'Missing widget type.', 'siteorigin-panels' ),
1010
+ 400
1011
+ );
1012
+ }
1013
+
1014
  $request = array_map( 'stripslashes_deep', $_REQUEST );
1015
 
1016
  $widget_class = $request['widget'];
inc/renderer.php CHANGED
@@ -95,6 +95,35 @@ class SiteOrigin_Panels_Renderer {
95
  str_replace( ',', '.', $calc_width ),
96
  )
97
  ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  }
99
 
100
  if (
@@ -240,6 +269,10 @@ class SiteOrigin_Panels_Renderer {
240
 
241
  if ( empty( $post_id ) ) {
242
  $post_id = get_the_ID();
 
 
 
 
243
  }
244
 
245
  global $siteorigin_panels_current_post;
@@ -409,6 +442,10 @@ class SiteOrigin_Panels_Renderer {
409
 
410
  if ( empty( $post_id ) ) {
411
  $post_id = get_the_ID();
 
 
 
 
412
  }
413
 
414
  $classes = array( 'so-panel' );
95
  str_replace( ',', '.', $calc_width ),
96
  )
97
  ) );
98
+
99
+ // Add in any widget specific CSS
100
+ foreach ( $cell['widgets'] as $wi => $widget ) {
101
+ $widget_style_data = ! empty( $widget['panels_info']['style'] ) ? $widget['panels_info']['style'] : array();
102
+ $widget_css = apply_filters(
103
+ 'siteorigin_panels_css_widget_css',
104
+ array(),
105
+ $widget_style_data,
106
+ $row,
107
+ $ri,
108
+ $cell,
109
+ $ci - 1,
110
+ $widget,
111
+ $wi,
112
+ $panels_data,
113
+ $post_id
114
+ );
115
+
116
+ $css->add_widget_css(
117
+ $post_id,
118
+ $ri,
119
+ $ci,
120
+ $wi,
121
+ '',
122
+ $widget_css,
123
+ 1920,
124
+ true
125
+ );
126
+ }
127
  }
128
 
129
  if (
269
 
270
  if ( empty( $post_id ) ) {
271
  $post_id = get_the_ID();
272
+
273
+ if ( class_exists( 'WooCommerce' ) && is_shop() ) {
274
+ $post_id = wc_get_page_id( 'shop' );
275
+ }
276
  }
277
 
278
  global $siteorigin_panels_current_post;
442
 
443
  if ( empty( $post_id ) ) {
444
  $post_id = get_the_ID();
445
+
446
+ if ( class_exists( 'WooCommerce' ) && is_shop() ) {
447
+ $post_id = wc_get_page_id( 'shop' );
448
+ }
449
  }
450
 
451
  $classes = array( 'so-panel' );
inc/styles-admin.php CHANGED
@@ -1,469 +1,493 @@
1
- <?php
2
-
3
- class SiteOrigin_Panels_Styles_Admin {
4
-
5
- function __construct() {
6
- add_action( 'wp_ajax_so_panels_style_form', array( $this, 'action_style_form' ) );
7
-
8
- add_filter( 'siteorigin_panels_data', array( $this, 'convert_data' ) );
9
- add_filter( 'siteorigin_panels_prebuilt_layout', array( $this, 'convert_data' ) );
10
- }
11
-
12
- public static function single() {
13
- static $single;
14
- return empty( $single ) ? $single = new self() : $single;
15
- }
16
-
17
- /**
18
- * Admin action for handling fetching the style fields
19
- */
20
- function action_style_form() {
21
- $type = $_REQUEST['type'];
22
- if ( ! in_array( $type, array( 'row', 'cell', 'widget' ) ) ) {
23
- exit();
24
- }
25
- if ( empty( $_GET['_panelsnonce'] ) || ! wp_verify_nonce( $_GET['_panelsnonce'], 'panels_action' ) ) {
26
- exit();
27
- }
28
-
29
- $current = isset( $_REQUEST['style'] ) ? $_REQUEST['style'] : array();
30
- $post_id = empty( $_REQUEST['postId'] ) ? 0 : $_REQUEST['postId'];
31
-
32
- $args = ! empty( $_POST['args'] ) ? json_decode( stripslashes( $_POST['args'] ), true ) : array();
33
-
34
- switch ( $type ) {
35
- case 'row':
36
- $this->render_styles_fields( 'row', '<h3>' . __( 'Row Styles', 'siteorigin-panels' ) . '</h3>', '', $current, $post_id, $args );
37
- break;
38
-
39
- case 'cell':
40
- $cell_number = isset( $args['index'] ) ? ' ' . ( intval( $args['index'] ) + 1 ) : '';
41
- $this->render_styles_fields( 'cell', '<h3>' . sprintf( __( 'Cell%s Styles', 'siteorigin-panels' ), $cell_number ) . '</h3>', '', $current, $post_id, $args );
42
- break;
43
-
44
- case 'widget':
45
- $this->render_styles_fields( 'widget', '<h3>' . __( 'Widget Styles', 'siteorigin-panels' ) . '</h3>', '', $current, $post_id, $args );
46
- break;
47
- }
48
-
49
- wp_die();
50
- }
51
-
52
- /**
53
- * Render all the style fields
54
- *
55
- * @param $section
56
- * @param string $before
57
- * @param string $after
58
- * @param array $current
59
- * @param int $post_id
60
- * @param array $args Arguments passed by the builder
61
- *
62
- * @return bool
63
- */
64
- function render_styles_fields( $section, $before = '', $after = '', $current = array(), $post_id = 0, $args = array() ) {
65
- $fields = array();
66
- $fields = apply_filters( 'siteorigin_panels_' . $section . '_style_fields', $fields, $post_id, $args );
67
- $fields = apply_filters( 'siteorigin_panels_general_style_fields', $fields, $post_id, $args );
68
- if ( empty( $fields ) ) {
69
- return false;
70
- }
71
-
72
- $groups = array(
73
- 'attributes' => array(
74
- 'name' => __( 'Attributes', 'siteorigin-panels' ),
75
- 'priority' => 5
76
- ),
77
- 'layout' => array(
78
- 'name' => __( 'Layout', 'siteorigin-panels' ),
79
- 'priority' => 10
80
- ),
81
- 'design' => array(
82
- 'name' => __( 'Design', 'siteorigin-panels' ),
83
- 'priority' => 15
84
- ),
85
- );
86
-
87
- // Check if we need a default group
88
- foreach ( $fields as $field_id => $field ) {
89
- if ( empty( $field['group'] ) || $field['group'] == 'theme' ) {
90
- if ( empty( $groups['theme'] ) ) {
91
- $groups['theme'] = array(
92
- 'name' => __( 'Theme', 'siteorigin-panels' ),
93
- 'priority' => 10
94
- );
95
- }
96
- $fields[ $field_id ]['group'] = 'theme';
97
- }
98
- }
99
- $groups = apply_filters( 'siteorigin_panels_' . $section . '_style_groups', $groups, $post_id, $args );
100
- $groups = apply_filters( 'siteorigin_panels_general_style_groups', $groups, $post_id, $args );
101
-
102
- // Sort the style fields and groups by priority
103
- uasort( $fields, array( $this, 'sort_fields' ) );
104
- uasort( $groups, array( $this, 'sort_fields' ) );
105
-
106
- echo $before;
107
-
108
- $group_counts = array();
109
- foreach ( $fields as $field_id => $field ) {
110
- if ( empty( $group_counts[ $field['group'] ] ) ) {
111
- $group_counts[ $field['group'] ] = 0;
112
- }
113
- $group_counts[ $field['group'] ] ++;
114
- }
115
-
116
- foreach ( $groups as $group_id => $group ) {
117
-
118
- if ( empty( $group_counts[ $group_id ] ) ) {
119
- continue;
120
- }
121
-
122
- ?>
123
- <div class="style-section-wrapper">
124
- <div class="style-section-head">
125
- <h4><?php echo esc_html( $group['name'] ) ?></h4>
126
- </div>
127
- <div class="style-section-fields" style="display: none">
128
- <?php
129
- foreach ( $fields as $field_id => $field ) {
130
- $default = isset( $field[ 'default' ] ) ? $field[ 'default' ] : false;
131
-
132
- if ( $field['group'] == $group_id ) {
133
- ?>
134
- <div class="style-field-wrapper">
135
- <label><?php echo $field['name'] ?></label>
136
- <div
137
- class="style-field style-field-<?php echo sanitize_html_class( $field['type'] ) ?>">
138
- <?php $this->render_style_field( $field, isset( $current[ $field_id ] ) ? $current[ $field_id ] : $default, $field_id ) ?>
139
- </div>
140
- </div>
141
- <?php
142
-
143
- }
144
-
145
- }
146
- ?>
147
- </div>
148
- </div>
149
- <?php
150
- }
151
-
152
- echo $after;
153
- }
154
-
155
- /**
156
- * Generate the style field
157
- *
158
- * @param array $field Everything needed to display the field
159
- * @param $current
160
- * @param $field_id
161
- */
162
- function render_style_field( $field, $current, $field_id ) {
163
- $field_name = 'style[' . $field_id . ']';
164
-
165
- echo '<div class="style-input-wrapper">';
166
- switch ( $field['type'] ) {
167
- case 'measurement' :
168
-
169
- if ( ! empty( $field['multiple'] ) ) {
170
- ?>
171
- <div class="measurement-inputs">
172
- <div class="measurement-wrapper">
173
- <input type="text" class="measurement-value measurement-top"
174
- placeholder="<?php _e( 'Top', 'siteorigin-panels' ) ?>"/>
175
- </div>
176
- <div class="measurement-wrapper">
177
- <input type="text" class="measurement-value measurement-right"
178
- placeholder="<?php _e( 'Right', 'siteorigin-panels' ) ?>"/>
179
- </div>
180
- <div class="measurement-wrapper">
181
- <input type="text" class="measurement-value measurement-bottom"
182
- placeholder="<?php _e( 'Bottom', 'siteorigin-panels' ) ?>"/>
183
- </div>
184
- <div class="measurement-wrapper">
185
- <input type="text" class="measurement-value measurement-left"
186
- placeholder="<?php _e( 'Left', 'siteorigin-panels' ) ?>"/>
187
- </div>
188
- </div>
189
- <?php
190
- } else {
191
- ?><input type="text" class="measurement-value measurement-value-single"/><?php
192
- }
193
-
194
- ?>
195
- <select
196
- class="measurement-unit measurement-unit-<?php echo ! empty( $field['multiple'] ) ? 'multiple' : 'single' ?>">
197
- <?php foreach ( $this->measurements_list() as $measurement ): ?>
198
- <option
199
- value="<?php echo esc_html( $measurement ) ?>"><?php echo esc_html( $measurement ) ?></option>
200
- <?php endforeach ?>
201
- </select>
202
- <input type="hidden" name="<?php echo esc_attr( $field_name ) ?>"
203
- value="<?php echo esc_attr( $current ) ?>"/>
204
- <?php
205
- break;
206
-
207
- case 'color' :
208
- ?>
209
- <input type="text" name="<?php echo esc_attr( $field_name ) ?>"
210
- value="<?php echo esc_attr( $current ) ?>" class="so-wp-color-field"/>
211
- <?php
212
- break;
213
-
214
- case 'image' :
215
- $image = false;
216
- if ( ! empty( $current ) ) {
217
- $image = SiteOrigin_Panels_Styles::get_attachment_image_src( $current, 'thumbnail' );
218
- }
219
-
220
- ?>
221
- <div class="so-image-selector">
222
- <div class="current-image" <?php if ( ! empty( $image ) ) {
223
- echo 'style="background-image: url(' . esc_url( $image[0] ) . ');"';
224
- } ?>>
225
- </div>
226
-
227
- <div class="select-image">
228
- <?php _e( 'Select Image', 'siteorigin-panels' ) ?>
229
- </div>
230
- <input type="hidden" name="<?php echo esc_attr( $field_name ) ?>"
231
- value="<?php echo intval( $current ) ?>"/>
232
- </div>
233
- <a href="#" class="remove-image"><?php _e( 'Remove', 'siteorigin-panels' ) ?></a>
234
- <?php
235
- break;
236
-
237
- case 'url' :
238
- case 'text' :
239
- ?><input type="text" name="<?php echo esc_attr( $field_name ) ?>"
240
- value="<?php echo esc_attr( $current ) ?>" class="widefat" /><?php
241
- break;
242
-
243
- case 'checkbox' :
244
- $current = (bool) $current;
245
- ?>
246
- <label class="so-checkbox-label">
247
- <input type="checkbox" name="<?php echo esc_attr( $field_name ) ?>" <?php checked( $current ) ?> />
248
- <?php echo esc_html( isset( $field['label'] ) ? $field['label'] : __( 'Enabled', 'siteorigin-panels' ) ) ?>
249
- </label>
250
- <?php
251
- break;
252
-
253
- case 'select' :
254
- ?>
255
- <select name="<?php echo esc_attr( $field_name ) ?>">
256
- <?php foreach ( $field['options'] as $k => $v ) : ?>
257
- <option
258
- value="<?php echo esc_attr( $k ) ?>" <?php selected( $current, $k ) ?>><?php echo esc_html( $v ) ?></option>
259
- <?php endforeach; ?>
260
- </select>
261
- <?php
262
- break;
263
-
264
- case 'textarea' :
265
- case 'code' :
266
- ?><textarea type="text" name="<?php echo esc_attr( $field_name ) ?>"
267
- class="widefat <?php if ( $field['type'] == 'code' ) {
268
- echo 'so-field-code';
269
- } ?>" rows="4"><?php echo esc_textarea( $current ) ?></textarea><?php
270
- break;
271
- }
272
-
273
- echo '</div>';
274
-
275
- if ( ! empty( $field['description'] ) ) {
276
- ?><p class="so-description"><?php echo wp_kses_post( $field['description'] ) ?></p><?php
277
- }
278
- }
279
-
280
- /**
281
- * Sanitize the style fields in panels_data
282
- *
283
- * @param $panels_data
284
- *
285
- * @return mixed
286
- */
287
- function sanitize_all( $panels_data ) {
288
- if ( ! empty( $panels_data['widgets'] ) ) {
289
- // Sanitize the widgets
290
- for ( $i = 0; $i < count( $panels_data['widgets'] ); $i ++ ) {
291
- if ( empty( $panels_data['widgets'][ $i ]['panels_info']['style'] ) ) {
292
- continue;
293
- }
294
- $panels_data['widgets'][ $i ]['panels_info']['style'] = $this->sanitize_style_fields( 'widget', $panels_data['widgets'][ $i ]['panels_info']['style'] );
295
- }
296
- }
297
-
298
- if ( ! empty( $panels_data['grids'] ) ) {
299
- // The rows
300
- for ( $i = 0; $i < count( $panels_data['grids'] ); $i ++ ) {
301
- if ( empty( $panels_data['grids'][ $i ]['style'] ) ) {
302
- continue;
303
- }
304
- $panels_data['grids'][ $i ]['style'] = $this->sanitize_style_fields( 'row', $panels_data['grids'][ $i ]['style'] );
305
- }
306
- }
307
-
308
- if ( ! empty( $panels_data['grid_cells'] ) ) {
309
- // And finally, the cells
310
- for ( $i = 0; $i < count( $panels_data['grid_cells'] ); $i ++ ) {
311
- if ( empty( $panels_data['grid_cells'][ $i ]['style'] ) ) {
312
- continue;
313
- }
314
- $panels_data['grid_cells'][ $i ]['style'] = $this->sanitize_style_fields( 'cell', $panels_data['grid_cells'][ $i ]['style'] );
315
- }
316
- }
317
-
318
- return $panels_data;
319
- }
320
-
321
- /**
322
- * Sanitize style fields.
323
- *
324
- * @param $section
325
- * @param $styles
326
- *
327
- * @return Sanitized styles
328
- */
329
- function sanitize_style_fields( $section, $styles ) {
330
- // Use the filter to get the fields for this section.
331
- if ( empty( $fields_cache[ $section ] ) ) {
332
- // This filter doesn't pass in the arguments $post_id and $args
333
- // Plugins looking to extend fields, should always add their fields if these are empty
334
- $fields_cache[ $section ] = array();
335
- $fields_cache[ $section ] = apply_filters( 'siteorigin_panels_' . $section . '_style_fields', $fields_cache[ $section ], false, false );
336
- $fields_cache[ $section ] = apply_filters( 'siteorigin_panels_general_style_fields', $fields_cache[ $section ], false, false );
337
- }
338
- $fields = $fields_cache[ $section ];
339
-
340
- $return = array();
341
- foreach ( $fields as $k => $field ) {
342
- // Skip this if no field type is set
343
- if ( empty( $field['type'] ) ) {
344
- continue;
345
- }
346
-
347
- // Handle the special case of a checkbox
348
- if ( $field['type'] == 'checkbox' ) {
349
- $return[ $k ] = ! empty( $styles[ $k ] ) ? true : '';
350
- continue;
351
- }
352
-
353
- // Ignore this if we don't even have a value for the style
354
- if ( ! isset( $styles[ $k ] ) || $styles[ $k ] == '' ) {
355
- continue;
356
- }
357
-
358
- switch ( $field['type'] ) {
359
- case 'color' :
360
- $color = $styles[ $k ];
361
- if ( preg_match( '|^#([A-Fa-f0-9]{3,8})$|', $color ) ) {
362
- $return[ $k ] = $color;
363
- } else {
364
- $return[ $k ] = '';
365
- }
366
- break;
367
- case 'image' :
368
- $return[ $k ] = ! empty( $styles[ $k ] ) ? sanitize_text_field( $styles[ $k ] ) : false;
369
- break;
370
- case 'url' :
371
- $return[ $k ] = esc_url_raw( $styles[ $k ] );
372
- break;
373
- case 'measurement' :
374
- $measurements = array_map( 'preg_quote', $this->measurements_list() );
375
- if ( ! empty( $field['multiple'] ) ) {
376
- if ( preg_match_all( '/(?:(-?[0-9\.,]+).*?(' . implode( '|', $measurements ) . ')+)/', $styles[ $k ], $match ) ) {
377
- $return[ $k ] = $styles[ $k ];
378
- } else {
379
- $return[ $k ] = '';
380
- }
381
- } else {
382
- if ( preg_match( '/([-?0-9\.,]+).*?(' . implode( '|', $measurements ) . ')/', $styles[ $k ], $match ) ) {
383
- $return[ $k ] = $match[1] . $match[2];
384
- } else {
385
- $return[ $k ] = '';
386
- }
387
- }
388
- break;
389
- case 'select' :
390
- if ( ! empty( $styles[ $k ] ) && in_array( $styles[ $k ], array_keys( $field['options'] ) ) ) {
391
- $return[ $k ] = $styles[ $k ];
392
- }
393
- break;
394
- default:
395
- // Just pass the value through.
396
- $return[ $k ] = $styles[ $k ];
397
- break;
398
-
399
- }
400
- }
401
-
402
- return $return;
403
- }
404
-
405
- /**
406
- * Convert the single string attribute of the grid style into an array.
407
- *
408
- * @param $panels_data
409
- *
410
- * @return mixed
411
- */
412
- function convert_data( $panels_data ) {
413
- if ( empty( $panels_data ) || empty( $panels_data['grids'] ) || ! is_array( $panels_data['grids'] ) ) {
414
- return $panels_data;
415
- }
416
-
417
- foreach( $panels_data['grids'] as & $grid ) {
418
- if ( ! is_array( $grid ) || empty( $grid ) || empty( $grid['style'] ) ) {
419
- continue;
420
- }
421
-
422
- if ( is_string( $grid['style'] ) ) {
423
- $grid['style'] = array(
424
- $grid['style']
425
- );
426
- }
427
- }
428
-
429
- return $panels_data;
430
- }
431
-
432
- /**
433
- * Get list of supported mesurements
434
- *
435
- * @return array
436
- */
437
- function measurements_list() {
438
- $measurements = array(
439
- 'px',
440
- '%',
441
- 'in',
442
- 'cm',
443
- 'mm',
444
- 'em',
445
- 'ex',
446
- 'pt',
447
- 'pc',
448
- 'rem'
449
- );
450
-
451
- // Allow themes and plugins to trim or enhance the list.
452
- return apply_filters( 'siteorigin_panels_style_get_measurements_list', $measurements );
453
- }
454
-
455
- /**
456
- * User sort function to sort by the priority key value.
457
- *
458
- * @param $a
459
- * @param $b
460
- *
461
- * @return int
462
- */
463
- static function sort_fields( $a, $b ) {
464
- return ( ( isset( $a['priority'] ) ? $a['priority'] : 10 ) > ( isset( $b['priority'] ) ? $b['priority'] : 10 ) ) ? 1 : - 1;
465
- }
466
- }
467
-
468
- // Initialise all the default styling
469
- SiteOrigin_Panels_Styles::single();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SiteOrigin_Panels_Styles_Admin {
4
+
5
+ function __construct() {
6
+ add_action( 'wp_ajax_so_panels_style_form', array( $this, 'action_style_form' ) );
7
+
8
+ add_filter( 'siteorigin_panels_data', array( $this, 'convert_data' ) );
9
+ add_filter( 'siteorigin_panels_prebuilt_layout', array( $this, 'convert_data' ) );
10
+ }
11
+
12
+ public static function single() {
13
+ static $single;
14
+ return empty( $single ) ? $single = new self() : $single;
15
+ }
16
+
17
+ /**
18
+ * Admin action for handling fetching the style fields
19
+ */
20
+ function action_style_form() {
21
+ if ( empty( $_REQUEST['_panelsnonce'] ) || ! wp_verify_nonce( $_REQUEST['_panelsnonce'], 'panels_action' ) ) {
22
+ wp_die(
23
+ __( 'The supplied nonce is invalid.', 'siteorigin-panels' ),
24
+ __( 'Invalid nonce.', 'siteorigin-panels' ),
25
+ 403
26
+ );
27
+ }
28
+
29
+ $type = $_REQUEST['type'];
30
+
31
+ if ( ! in_array( $type, array( 'row', 'cell', 'widget' ) ) ) {
32
+ wp_die(
33
+ __( 'Please specify the type of style form to be rendered.', 'siteorigin-panels' ),
34
+ __( 'Missing style form type.', 'siteorigin-panels' ),
35
+ 400
36
+ );
37
+ }
38
+
39
+ $current = isset( $_REQUEST['style'] ) ? $_REQUEST['style'] : array();
40
+ $post_id = empty( $_REQUEST['postId'] ) ? 0 : $_REQUEST['postId'];
41
+
42
+ $args = ! empty( $_POST['args'] ) ? json_decode( stripslashes( $_POST['args'] ), true ) : array();
43
+
44
+ switch ( $type ) {
45
+ case 'row':
46
+ $this->render_styles_fields( 'row', '<h3>' . __( 'Row Styles', 'siteorigin-panels' ) . '</h3>', '', $current, $post_id, $args );
47
+ break;
48
+
49
+ case 'cell':
50
+ $cell_number = isset( $args['index'] ) ? ' ' . ( intval( $args['index'] ) + 1 ) : '';
51
+ $this->render_styles_fields( 'cell', '<h3>' . sprintf( __( 'Cell%s Styles', 'siteorigin-panels' ), $cell_number ) . '</h3>', '', $current, $post_id, $args );
52
+ break;
53
+
54
+ case 'widget':
55
+ $this->render_styles_fields( 'widget', '<h3>' . __( 'Widget Styles', 'siteorigin-panels' ) . '</h3>', '', $current, $post_id, $args );
56
+ break;
57
+ }
58
+
59
+ wp_die();
60
+ }
61
+
62
+ /**
63
+ * Render all the style fields
64
+ *
65
+ * @param $section
66
+ * @param string $before
67
+ * @param string $after
68
+ * @param array $current
69
+ * @param int $post_id
70
+ * @param array $args Arguments passed by the builder
71
+ *
72
+ * @return bool
73
+ */
74
+ function render_styles_fields( $section, $before = '', $after = '', $current = array(), $post_id = 0, $args = array() ) {
75
+ $fields = array();
76
+ $fields = apply_filters( 'siteorigin_panels_' . $section . '_style_fields', $fields, $post_id, $args );
77
+ $fields = apply_filters( 'siteorigin_panels_general_style_fields', $fields, $post_id, $args );
78
+ if ( empty( $fields ) ) {
79
+ return false;
80
+ }
81
+
82
+ $groups = array(
83
+ 'attributes' => array(
84
+ 'name' => __( 'Attributes', 'siteorigin-panels' ),
85
+ 'priority' => 5
86
+ ),
87
+ 'layout' => array(
88
+ 'name' => __( 'Layout', 'siteorigin-panels' ),
89
+ 'priority' => 10
90
+ ),
91
+ 'design' => array(
92
+ 'name' => __( 'Design', 'siteorigin-panels' ),
93
+ 'priority' => 15
94
+ ),
95
+ );
96
+
97
+ // Check if we need a default group
98
+ foreach ( $fields as $field_id => $field ) {
99
+ if ( empty( $field['group'] ) || $field['group'] == 'theme' ) {
100
+ if ( empty( $groups['theme'] ) ) {
101
+ $groups['theme'] = array(
102
+ 'name' => __( 'Theme', 'siteorigin-panels' ),
103
+ 'priority' => 10
104
+ );
105
+ }
106
+ $fields[ $field_id ]['group'] = 'theme';
107
+ }
108
+ }
109
+ $groups = apply_filters( 'siteorigin_panels_' . $section . '_style_groups', $groups, $post_id, $args );
110
+ $groups = apply_filters( 'siteorigin_panels_general_style_groups', $groups, $post_id, $args );
111
+
112
+ // Sort the style fields and groups by priority
113
+ uasort( $fields, array( $this, 'sort_fields' ) );
114
+ uasort( $groups, array( $this, 'sort_fields' ) );
115
+
116
+ echo $before;
117
+
118
+ $group_counts = array();
119
+ foreach ( $fields as $field_id => $field ) {
120
+ if ( empty( $group_counts[ $field['group'] ] ) ) {
121
+ $group_counts[ $field['group'] ] = 0;
122
+ }
123
+ $group_counts[ $field['group'] ] ++;
124
+ }
125
+
126
+ foreach ( $groups as $group_id => $group ) {
127
+
128
+ if ( empty( $group_counts[ $group_id ] ) ) {
129
+ continue;
130
+ }
131
+
132
+ ?>
133
+ <div class="style-section-wrapper">
134
+ <div class="style-section-head">
135
+ <h4><?php echo esc_html( $group['name'] ) ?></h4>
136
+ </div>
137
+ <div class="style-section-fields" style="display: none">
138
+ <?php
139
+ foreach ( $fields as $field_id => $field ) {
140
+ $default = isset( $field[ 'default' ] ) ? $field[ 'default' ] : false;
141
+
142
+ if ( $field['group'] == $group_id ) {
143
+ ?>
144
+ <div class="style-field-wrapper">
145
+ <label><?php echo $field['name'] ?></label>
146
+ <div
147
+ class="style-field style-field-<?php echo sanitize_html_class( $field['type'] ) ?>">
148
+ <?php $this->render_style_field( $field, isset( $current[ $field_id ] ) ? $current[ $field_id ] : $default, $field_id, $current ) ?>
149
+ </div>
150
+ </div>
151
+ <?php
152
+
153
+ }
154
+
155
+ }
156
+ ?>
157
+ </div>
158
+ </div>
159
+ <?php
160
+ }
161
+
162
+ echo $after;
163
+ }
164
+
165
+ /**
166
+ * Generate the style field
167
+ *
168
+ * @param array $field Everything needed to display the field
169
+ * @param $current
170
+ * @param $field_id
171
+ * @param $current_styles
172
+ */
173
+ function render_style_field( $field, $current, $field_id, $current_styles ) {
174
+ $field_name = 'style[' . $field_id . ']';
175
+
176
+ echo '<div class="style-input-wrapper">';
177
+ switch ( $field['type'] ) {
178
+ case 'measurement' :
179
+
180
+ if ( ! empty( $field['multiple'] ) ) {
181
+ ?>
182
+ <div class="measurement-inputs">
183
+ <div class="measurement-wrapper">
184
+ <input type="text" class="measurement-value measurement-top"
185
+ placeholder="<?php _e( 'Top', 'siteorigin-panels' ) ?>"/>
186
+ </div>
187
+ <div class="measurement-wrapper">
188
+ <input type="text" class="measurement-value measurement-right"
189
+ placeholder="<?php _e( 'Right', 'siteorigin-panels' ) ?>"/>
190
+ </div>
191
+ <div class="measurement-wrapper">
192
+ <input type="text" class="measurement-value measurement-bottom"
193
+ placeholder="<?php _e( 'Bottom', 'siteorigin-panels' ) ?>"/>
194
+ </div>
195
+ <div class="measurement-wrapper">
196
+ <input type="text" class="measurement-value measurement-left"
197
+ placeholder="<?php _e( 'Left', 'siteorigin-panels' ) ?>"/>
198
+ </div>
199
+ </div>
200
+ <?php
201
+ } else {
202
+ ?><input type="text" class="measurement-value measurement-value-single"/><?php
203
+ }
204
+
205
+ ?>
206
+ <select
207
+ class="measurement-unit measurement-unit-<?php echo ! empty( $field['multiple'] ) ? 'multiple' : 'single' ?>">
208
+ <?php foreach ( $this->measurements_list() as $measurement ): ?>
209
+ <option
210
+ value="<?php echo esc_html( $measurement ) ?>"><?php echo esc_html( $measurement ) ?></option>
211
+ <?php endforeach ?>
212
+ </select>
213
+ <input type="hidden" name="<?php echo esc_attr( $field_name ) ?>"
214
+ value="<?php echo esc_attr( $current ) ?>"/>
215
+ <?php
216
+ break;
217
+
218
+ case 'color' :
219
+ ?>
220
+ <input type="text" name="<?php echo esc_attr( $field_name ) ?>"
221
+ value="<?php echo esc_attr( $current ) ?>" class="so-wp-color-field"/>
222
+ <?php
223
+ break;
224
+
225
+ case 'image' :
226
+ $image = false;
227
+ if ( ! empty( $current ) ) {
228
+ $image = SiteOrigin_Panels_Styles::get_attachment_image_src( $current, 'thumbnail' );
229
+ }
230
+
231
+ $fallback_url = $current_styles[ $field_id . '_fallback' ];
232
+ $fallback_field_name = 'style[' . $field_id . '_fallback]';
233
+
234
+ ?>
235
+ <div class="so-image-selector">
236
+ <div class="current-image" <?php if ( ! empty( $image ) ) {
237
+ echo 'style="background-image: url(' . esc_url( $image[0] ) . ');"';
238
+ } ?>>
239
+ </div>
240
+
241
+ <div class="select-image">
242
+ <?php _e( 'Select Image', 'siteorigin-panels' ) ?>
243
+ </div>
244
+ <input type="hidden" name="<?php echo esc_attr( $field_name ) ?>"
245
+ value="<?php echo intval( $current ) ?>"/>
246
+ </div>
247
+ <a href="#" class="remove-image<?php if ( empty( $current ) ) echo ' hidden' ?>"><?php _e( 'Remove', 'siteorigin-panels' ) ?></a>
248
+
249
+ <input type="text" value="<?php if ( $fallback_url !== 'false' ) echo esc_url( $fallback_url ) ?>"
250
+ placeholder="<?php esc_attr_e( 'External URL', 'siteorigin-panels' ) ?>"
251
+ name="<?php echo esc_attr( $fallback_field_name ) ?>"
252
+ class="image-fallback widefat" />
253
+ <?php
254
+ break;
255
+
256
+ case 'url' :
257
+ case 'text' :
258
+ ?><input type="text" name="<?php echo esc_attr( $field_name ) ?>"
259
+ value="<?php echo esc_attr( $current ) ?>" class="widefat" /><?php
260
+ break;
261
+
262
+ case 'checkbox' :
263
+ $current = (bool) $current;
264
+ ?>
265
+ <label class="so-checkbox-label">
266
+ <input type="checkbox" name="<?php echo esc_attr( $field_name ) ?>" <?php checked( $current ) ?> />
267
+ <?php echo esc_html( isset( $field['label'] ) ? $field['label'] : __( 'Enabled', 'siteorigin-panels' ) ) ?>
268
+ </label>
269
+ <?php
270
+ break;
271
+
272
+ case 'select' :
273
+ ?>
274
+ <select name="<?php echo esc_attr( $field_name ) ?>">
275
+ <?php foreach ( $field['options'] as $k => $v ) : ?>
276
+ <option
277
+ value="<?php echo esc_attr( $k ) ?>" <?php selected( $current, $k ) ?>><?php echo esc_html( $v ) ?></option>
278
+ <?php endforeach; ?>
279
+ </select>
280
+ <?php
281
+ break;
282
+
283
+ case 'textarea' :
284
+ case 'code' :
285
+ ?><textarea type="text" name="<?php echo esc_attr( $field_name ) ?>"
286
+ class="widefat <?php if ( $field['type'] == 'code' ) {
287
+ echo 'so-field-code';
288
+ } ?>" rows="4"><?php echo esc_textarea( $current ) ?></textarea><?php
289
+ break;
290
+ }
291
+
292
+ echo '</div>';
293
+
294
+ if ( ! empty( $field['description'] ) ) {
295
+ ?><p class="so-description"><?php echo wp_kses_post( $field['description'] ) ?></p><?php
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Sanitize the style fields in panels_data
301
+ *
302
+ * @param $panels_data
303
+ *
304
+ * @return mixed
305
+ */
306
+ function sanitize_all( $panels_data ) {
307
+ if ( ! empty( $panels_data['widgets'] ) ) {
308
+ // Sanitize the widgets
309
+ for ( $i = 0; $i < count( $panels_data['widgets'] ); $i ++ ) {
310
+ if ( empty( $panels_data['widgets'][ $i ]['panels_info']['style'] ) ) {
311
+ continue;
312
+ }
313
+ $panels_data['widgets'][ $i ]['panels_info']['style'] = $this->sanitize_style_fields( 'widget', $panels_data['widgets'][ $i ]['panels_info']['style'] );
314
+ }
315
+ }
316
+
317
+ if ( ! empty( $panels_data['grids'] ) ) {
318
+ // The rows
319
+ for ( $i = 0; $i < count( $panels_data['grids'] ); $i ++ ) {
320
+ if ( empty( $panels_data['grids'][ $i ]['style'] ) ) {
321
+ continue;
322
+ }
323
+ $panels_data['grids'][ $i ]['style'] = $this->sanitize_style_fields( 'row', $panels_data['grids'][ $i ]['style'] );
324
+ }
325
+ }
326
+
327
+ if ( ! empty( $panels_data['grid_cells'] ) ) {
328
+ // And finally, the cells
329
+ for ( $i = 0; $i < count( $panels_data['grid_cells'] ); $i ++ ) {
330
+ if ( empty( $panels_data['grid_cells'][ $i ]['style'] ) ) {
331
+ continue;
332
+ }
333
+ $panels_data['grid_cells'][ $i ]['style'] = $this->sanitize_style_fields( 'cell', $panels_data['grid_cells'][ $i ]['style'] );
334
+ }
335
+ }
336
+
337
+ return $panels_data;
338
+ }
339
+
340
+ /**
341
+ * Sanitize style fields.
342
+ *
343
+ * @param $section
344
+ * @param $styles
345
+ *
346
+ * @return Sanitized styles
347
+ */
348
+ function sanitize_style_fields( $section, $styles ) {
349
+ // Use the filter to get the fields for this section.
350
+ if ( empty( $fields_cache[ $section ] ) ) {
351
+ // This filter doesn't pass in the arguments $post_id and $args
352
+ // Plugins looking to extend fields, should always add their fields if these are empty
353
+ $fields_cache[ $section ] = array();
354
+ $fields_cache[ $section ] = apply_filters( 'siteorigin_panels_' . $section . '_style_fields', $fields_cache[ $section ], false, false );
355
+ $fields_cache[ $section ] = apply_filters( 'siteorigin_panels_general_style_fields', $fields_cache[ $section ], false, false );
356
+ }
357
+ $fields = $fields_cache[ $section ];
358
+
359
+ $return = array();
360
+ foreach ( $fields as $k => $field ) {
361
+ // Skip this if no field type is set
362
+ if ( empty( $field['type'] ) ) {
363
+ continue;
364
+ }
365
+
366
+ // Handle the special case of a checkbox
367
+ if ( $field['type'] == 'checkbox' ) {
368
+ $return[ $k ] = ! empty( $styles[ $k ] ) ? true : '';
369
+ continue;
370
+ }
371
+
372
+ // Ignore this if we don't even have a value for the style, unless 'image' field which might have a fallback.
373
+ if ( ! isset( $styles[ $k ] ) || ( $field['type'] != 'image' && $styles[ $k ] == '' ) ) {
374
+ continue;
375
+ }
376
+
377
+ switch ( $field['type'] ) {
378
+ case 'color' :
379
+ $color = $styles[ $k ];
380
+ if ( preg_match( '|^#([A-Fa-f0-9]{3,8})$|', $color ) ) {
381
+ $return[ $k ] = $color;
382
+ } else {
383
+ $return[ $k ] = '';
384
+ }
385
+ break;
386
+ case 'image' :
387
+ $return[ $k ] = ! empty( $styles[ $k ] ) ? sanitize_text_field( $styles[ $k ] ) : false;
388
+ $fallback_name = $k . '_fallback';
389
+ if ( $styles[ $k ] == '' && $styles[ $fallback_name ] == '' ) {
390
+ continue;
391
+ }
392
+ $return[ $fallback_name ] = ! empty( $styles[ $fallback_name ] ) ? esc_url_raw( $styles[ $fallback_name ] ) : false;
393
+ break;
394
+ case 'url' :
395
+ $return[ $k ] = esc_url_raw( $styles[ $k ] );
396
+ break;
397
+ case 'measurement' :
398
+ $measurements = array_map( 'preg_quote', $this->measurements_list() );
399
+ if ( ! empty( $field['multiple'] ) ) {
400
+ if ( preg_match_all( '/(?:(-?[0-9\.,]+).*?(' . implode( '|', $measurements ) . ')+)/', $styles[ $k ], $match ) ) {
401
+ $return[ $k ] = $styles[ $k ];
402
+ } else {
403
+ $return[ $k ] = '';
404
+ }
405
+ } else {
406
+ if ( preg_match( '/([-?0-9\.,]+).*?(' . implode( '|', $measurements ) . ')/', $styles[ $k ], $match ) ) {
407
+ $return[ $k ] = $match[1] . $match[2];
408
+ } else {
409
+ $return[ $k ] = '';
410
+ }
411
+ }
412
+ break;
413
+ case 'select' :
414
+ if ( ! empty( $styles[ $k ] ) && in_array( $styles[ $k ], array_keys( $field['options'] ) ) ) {
415
+ $return[ $k ] = $styles[ $k ];
416
+ }
417
+ break;
418
+ default:
419
+ // Just pass the value through.
420
+ $return[ $k ] = $styles[ $k ];
421
+ break;
422
+
423
+ }
424
+ }
425
+
426
+ return $return;
427
+ }
428
+
429
+ /**
430
+ * Convert the single string attribute of the grid style into an array.
431
+ *
432
+ * @param $panels_data
433
+ *
434
+ * @return mixed
435
+ */
436
+ function convert_data( $panels_data ) {
437
+ if ( empty( $panels_data ) || empty( $panels_data['grids'] ) || ! is_array( $panels_data['grids'] ) ) {
438
+ return $panels_data;
439
+ }
440
+
441
+ foreach( $panels_data['grids'] as & $grid ) {
442
+ if ( ! is_array( $grid ) || empty( $grid ) || empty( $grid['style'] ) ) {
443
+ continue;
444
+ }
445
+
446
+ if ( is_string( $grid['style'] ) ) {
447
+ $grid['style'] = array(
448
+ $grid['style']
449
+ );
450
+ }
451
+ }
452
+
453
+ return $panels_data;
454
+ }
455
+
456
+ /**
457
+ * Get list of supported mesurements
458
+ *
459
+ * @return array
460
+ */
461
+ function measurements_list() {
462
+ $measurements = array(
463
+ 'px',
464
+ '%',
465
+ 'in',
466
+ 'cm',
467
+ 'mm',
468
+ 'em',
469
+ 'ex',
470
+ 'pt',
471
+ 'pc',
472
+ 'rem'
473
+ );
474
+
475
+ // Allow themes and plugins to trim or enhance the list.
476
+ return apply_filters( 'siteorigin_panels_style_get_measurements_list', $measurements );
477
+ }
478
+
479
+ /**
480
+ * User sort function to sort by the priority key value.
481
+ *
482
+ * @param $a
483
+ * @param $b
484
+ *
485
+ * @return int
486
+ */
487
+ static function sort_fields( $a, $b ) {
488
+ return ( ( isset( $a['priority'] ) ? $a['priority'] : 10 ) > ( isset( $b['priority'] ) ? $b['priority'] : 10 ) ) ? 1 : - 1;
489
+ }
490
+ }
491
+
492
+ // Initialise all the default styling
493
+ SiteOrigin_Panels_Styles::single();
inc/styles.php CHANGED
@@ -1,672 +1,708 @@
1
- <?php
2
-
3
- /**
4
- * Class for handling all the default styling.
5
- *
6
- * Class SiteOrigin_Panels_Default_Styles
7
- */
8
- class SiteOrigin_Panels_Styles {
9
-
10
- public function __construct() {
11
- add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ), 5 );
12
-
13
- // Adding all the fields
14
- add_filter( 'siteorigin_panels_row_style_fields', array( $this, 'row_style_fields' ) );
15
- add_filter( 'siteorigin_panels_cell_style_fields', array( $this, 'cell_style_fields' ) );
16
- add_filter( 'siteorigin_panels_widget_style_fields', array( $this, 'widget_style_fields' ) );
17
-
18
- // Style wrapper attributes
19
- add_filter( 'siteorigin_panels_row_style_attributes', array( $this, 'general_style_attributes' ), 10, 2 );
20
- add_filter( 'siteorigin_panels_row_style_attributes', array( $this, 'row_style_attributes' ), 10, 2 );
21
- add_filter( 'siteorigin_panels_row_style_attributes', array( $this, 'vantage_row_style_attributes' ), 11, 2 );
22
- add_filter( 'siteorigin_panels_cell_style_attributes', array( $this, 'general_style_attributes' ), 10, 2 );
23
- add_filter( 'siteorigin_panels_widget_style_attributes', array( $this, 'general_style_attributes' ), 10, 2 );
24
-
25
- // Style wrapper CSS
26
- add_filter( 'siteorigin_panels_row_style_css', array( $this, 'general_style_css' ), 10, 2 );
27
- add_filter( 'siteorigin_panels_cell_style_css', array( $this, 'general_style_css' ), 10, 2 );
28
- add_filter( 'siteorigin_panels_widget_style_css', array( $this, 'general_style_css' ), 10, 2 );
29
-
30
- add_filter( 'siteorigin_panels_row_style_mobile_css', array( $this, 'general_style_mobile_css' ), 10, 2 );
31
- add_filter( 'siteorigin_panels_cell_style_mobile_css', array( $this, 'general_style_mobile_css' ), 10, 2 );
32
- add_filter( 'siteorigin_panels_widget_style_mobile_css', array( $this, 'general_style_mobile_css' ), 10, 2 );
33
-
34
- // Main filter to add any custom CSS.
35
- add_filter( 'siteorigin_panels_css_object', array( $this, 'filter_css_object' ), 10, 4 );
36
-
37
- // Filtering specific attributes
38
- add_filter( 'siteorigin_panels_css_row_margin_bottom', array( $this, 'filter_row_bottom_margin' ), 10, 2 );
39
- add_filter( 'siteorigin_panels_css_row_gutter', array( $this, 'filter_row_gutter' ), 10, 2 );
40
- }
41
-
42
- public static function single() {
43
- static $single;
44
- return empty( $single ) ? $single = new self() : $single;
45
- }
46
-
47
- static function register_scripts() {
48
- wp_register_script(
49
- 'siteorigin-panels-front-styles',
50
- siteorigin_panels_url( 'js/styling' . SITEORIGIN_PANELS_VERSION_SUFFIX . SITEORIGIN_PANELS_JS_SUFFIX . '.js' ),
51
- array( 'jquery' ),
52
- SITEORIGIN_PANELS_VERSION
53
- );
54
- wp_register_script(
55
- 'siteorigin-parallax',
56
- siteorigin_panels_url( 'js/siteorigin-parallax' . SITEORIGIN_PANELS_JS_SUFFIX . '.js' ),
57
- array( 'jquery' ),
58
- SITEORIGIN_PANELS_VERSION
59
- );
60
- wp_localize_script( 'siteorigin-panels-front-styles', 'panelsStyles', array(
61
- 'fullContainer' => apply_filters( 'siteorigin_panels_full_width_container', siteorigin_panels_setting( 'full-width-container' ) )
62
- ) );
63
- }
64
-
65
- /**
66
- * These are general styles that apply to all elements
67
- *
68
- * @param $label
69
- *
70
- * @return array
71
- */
72
- static function get_general_style_fields( $id, $label ) {
73
- $fields = array();
74
-
75
- // All the attribute fields
76
-
77
- $fields['id'] = array(
78
- 'name' => sprintf( __( '%s ID', 'siteorigin-panels' ), $label ),
79
- 'type' => 'text',
80
- 'group' => 'attributes',
81
- 'description' => sprintf( __( 'A custom ID used for this %s.', 'siteorigin-panels' ), strtolower( $label ) ),
82
- 'priority' => 4,
83
- );
84
-
85
- $fields['class'] = array(
86
- 'name' => sprintf( __( '%s Class', 'siteorigin-panels' ), $label ),
87
- 'type' => 'text',
88
- 'group' => 'attributes',
89
- 'description' => __( 'A CSS class', 'siteorigin-panels' ),
90
- 'priority' => 5,
91
- );
92
-
93
- $fields[ $id . '_css' ] = array(
94
- 'name' => __( 'CSS Styles', 'siteorigin-panels' ),
95
- 'type' => 'code',
96
- 'group' => 'attributes',
97
- 'description' => __( 'One style attribute per line.', 'siteorigin-panels' ),
98
- 'priority' => 10,
99
- );
100
-
101
- $fields[ 'mobile_css' ] = array(
102
- 'name' => __( 'Mobile CSS Styles', 'siteorigin-panels' ),
103
- 'type' => 'code',
104
- 'group' => 'attributes',
105
- 'description' => __( 'CSS applied when in mobile view.', 'siteorigin-panels' ),
106
- 'priority' => 11,
107
- );
108
-
109
- // The layout fields
110
-
111
- $fields['padding'] = array(
112
- 'name' => __( 'Padding', 'siteorigin-panels' ),
113
- 'type' => 'measurement',
114
- 'group' => 'layout',
115
- 'description' => sprintf( __( 'Padding around the entire %s.', 'siteorigin-panels' ), strtolower( $label ) ),
116
- 'priority' => 7,
117
- 'multiple' => true
118
- );
119
-
120
- $fields['mobile_padding'] = array(
121
- 'name' => __( 'Mobile Padding', 'siteorigin-panels' ),
122
- 'type' => 'measurement',
123
- 'group' => 'layout',
124
- 'description' => __( 'Padding when on mobile devices.', 'siteorigin-panels' ),
125
- 'priority' => 8,
126
- 'multiple' => true
127
- );
128
-
129
- // The general design fields
130
-
131
- $fields['background'] = array(
132
- 'name' => __( 'Background Color', 'siteorigin-panels' ),
133
- 'type' => 'color',
134
- 'group' => 'design',
135
- 'description' => sprintf( __( 'Background color of the %s.', 'siteorigin-panels' ), strtolower( $label ) ),
136
- 'priority' => 5,
137
- );
138
-
139
- $fields['background_image_attachment'] = array(
140
- 'name' => __( 'Background Image', 'siteorigin-panels' ),
141
- 'type' => 'image',
142
- 'group' => 'design',
143
- 'description' => sprintf( __( 'Background image of the %s.', 'siteorigin-panels' ), strtolower( $label ) ),
144
- 'priority' => 6,
145
- );
146
-
147
- $fields['background_display'] = array(
148
- 'name' => __( 'Background Image Display', 'siteorigin-panels' ),
149
- 'type' => 'select',
150
- 'group' => 'design',
151
- 'options' => array(
152
- 'tile' => __( 'Tiled Image', 'siteorigin-panels' ),
153
- 'cover' => __( 'Cover', 'siteorigin-panels' ),
154
- 'center' => __( 'Centered, with original size', 'siteorigin-panels' ),
155
- 'fixed' => __( 'Fixed', 'siteorigin-panels' ),
156
- 'parallax' => __( 'Parallax', 'siteorigin-panels' ),
157
- 'parallax-original' => __( 'Parallax (Original Size)', 'siteorigin-panels' ),
158
- ),
159
- 'description' => __( 'How the background image is displayed.', 'siteorigin-panels' ),
160
- 'priority' => 7,
161
- );
162
-
163
- $fields['border_color'] = array(
164
- 'name' => __( 'Border Color', 'siteorigin-panels' ),
165
- 'type' => 'color',
166
- 'group' => 'design',
167
- 'description' => sprintf( __( 'Border color of the %s.', 'siteorigin-panels' ), strtolower( $label ) ),
168
- 'priority' => 10,
169
- );
170
-
171
- return $fields;
172
- }
173
-
174
- /**
175
- * All the row styling fields
176
- *
177
- * @param $fields
178
- *
179
- * @return array
180
- */
181
- static function row_style_fields( $fields ) {
182
- // Add the general fields
183
- $fields = wp_parse_args( $fields, self::get_general_style_fields( 'row', __( 'Row', 'siteorigin-panels' ) ) );
184
-
185
- $fields['cell_class'] = array(
186
- 'name' => __( 'Cell Class', 'siteorigin-panels' ),
187
- 'type' => 'text',
188
- 'group' => 'attributes',
189
- 'description' => __( 'Class added to all cells in this row.', 'siteorigin-panels' ),
190
- 'priority' => 6,
191
- );
192
-
193
- // Add the layout fields
194
-
195
- $fields['bottom_margin'] = array(
196
- 'name' => __( 'Bottom Margin', 'siteorigin-panels' ),
197
- 'type' => 'measurement',
198
- 'group' => 'layout',
199
- 'description' => sprintf( __( 'Space below the row. Default is %spx.', 'siteorigin-panels' ), siteorigin_panels_setting( 'margin-bottom' ) ),
200
- 'priority' => 5,
201
- );
202
-
203
- $fields['gutter'] = array(
204
- 'name' => __( 'Gutter', 'siteorigin-panels' ),
205
- 'type' => 'measurement',
206
- 'group' => 'layout',
207
- 'description' => sprintf( __( 'Amount of space between cells. Default is %spx.', 'siteorigin-panels' ), siteorigin_panels_setting( 'margin-sides' ) ),
208
- 'priority' => 6,
209
- );
210
-
211
- $fields['row_stretch'] = array(
212
- 'name' => __( 'Row Layout', 'siteorigin-panels' ),
213
- 'type' => 'select',
214
- 'group' => 'layout',
215
- 'options' => array(
216
- '' => __( 'Standard', 'siteorigin-panels' ),
217
- 'full' => __( 'Full Width', 'siteorigin-panels' ),
218
- 'full-stretched' => __( 'Full Width Stretched', 'siteorigin-panels' ),
219
- ),
220
- 'priority' => 10,
221
- );
222
-
223
- $fields['collapse_behaviour'] = array(
224
- 'name' => __( 'Collapse Behaviour', 'siteorigin-panels' ),
225
- 'type' => 'select',
226
- 'group' => 'layout',
227
- 'options' => array(
228
- '' => __( 'Standard', 'siteorigin-panels' ),
229
- 'no_collapse' => __( 'No Collapse', 'siteorigin-panels' ),
230
- ),
231
- 'priority' => 15,
232
- );
233
-
234
- $fields['collapse_order'] = array(
235
- 'name' => __( 'Collapse Order', 'siteorigin-panels' ),
236
- 'type' => 'select',
237
- 'group' => 'layout',
238
- 'options' => array(
239
- '' => __( 'Default', 'siteorigin-panels' ),
240
- 'left-top' => __( 'Left on Top', 'siteorigin-panels' ),
241
- 'right-top' => __( 'Right on Top', 'siteorigin-panels' ),
242
- ),
243
- 'priority' => 16,
244
- );
245
-
246
- if ( siteorigin_panels_setting( 'legacy-layout' ) != 'always' ) {
247
- $fields['cell_alignment'] = array(
248
- 'name' => __( 'Cell Vertical Alignment', 'siteorigin-panels' ),
249
- 'type' => 'select',
250
- 'group' => 'layout',
251
- 'options' => array(
252
- 'flex-start' => __( 'Top', 'siteorigin-panels' ),
253
- 'center' => __( 'Center', 'siteorigin-panels' ),
254
- 'flex-end' => __( 'Bottom', 'siteorigin-panels' ),
255
- 'stretch' => __( 'Stretch', 'siteorigin-panels' ),
256
- ),
257
- 'priority' => 17,
258
- );
259
- }
260
-
261
- return $fields;
262
- }
263
-
264
- /**
265
- * All the cell styling fields
266
- *
267
- * @param $fields
268
- *
269
- * @return array
270
- */
271
- static function cell_style_fields( $fields ) {
272
- // Add the general fields
273
- $fields = wp_parse_args( $fields, self::get_general_style_fields( 'cell', __( 'Cell', 'siteorigin-panels' ) ) );
274
-
275
- $fields['vertical_alignment'] = array(
276
- 'name' => __( 'Vertical Alignment', 'siteorigin-panels' ),
277
- 'type' => 'select',
278
- 'group' => 'layout',
279
- 'options' => array(
280
- 'auto' => __( 'Use row setting', 'siteorigin-panels' ),
281
- 'flex-start' => __( 'Top', 'siteorigin-panels' ),
282
- 'center' => __( 'Center', 'siteorigin-panels' ),
283
- 'flex-end' => __( 'Bottom', 'siteorigin-panels' ),
284
- 'stretch' => __( 'Stretch', 'siteorigin-panels' ),
285
- ),
286
- 'priority' => 16,
287
- );
288
-
289
- $fields['font_color'] = array(
290
- 'name' => __( 'Font Color', 'siteorigin-panels' ),
291
- 'type' => 'color',
292
- 'group' => 'design',
293
- 'description' => __( 'Color of text inside this cell.', 'siteorigin-panels' ),
294
- 'priority' => 15,
295
- );
296
-
297
- $fields['link_color'] = array(
298
- 'name' => __( 'Links Color', 'siteorigin-panels' ),
299
- 'type' => 'color',
300
- 'group' => 'design',
301
- 'description' => __( 'Color of links inside this cell.', 'siteorigin-panels' ),
302
- 'priority' => 16,
303
- );
304
-
305
- return $fields;
306
- }
307
-
308
- /**
309
- * @param $fields
310
- *
311
- * @return array
312
- */
313
- static function widget_style_fields( $fields ) {
314
-
315
- // Add the general fields
316
- $fields = wp_parse_args( $fields, self::get_general_style_fields( 'widget', __( 'Widget', 'siteorigin-panels' ) ) );
317
-
318
- // How lets add the design fields
319
-
320
- $fields['font_color'] = array(
321
- 'name' => __( 'Font Color', 'siteorigin-panels' ),
322
- 'type' => 'color',
323
- 'group' => 'design',
324
- 'description' => __( 'Color of text inside this widget.', 'siteorigin-panels' ),
325
- 'priority' => 15,
326
- );
327
-
328
- $fields['link_color'] = array(
329
- 'name' => __( 'Links Color', 'siteorigin-panels' ),
330
- 'type' => 'color',
331
- 'group' => 'design',
332
- 'description' => __( 'Color of links inside this widget.', 'siteorigin-panels' ),
333
- 'priority' => 16,
334
- );
335
-
336
- return $fields;
337
- }
338
-
339
- /**
340
- * Style attributes that apply to rows, cells and widgets
341
- *
342
- * @param $attributes
343
- * @param $style
344
- *
345
- * @return array $attributes
346
- */
347
- static function general_style_attributes( $attributes, $style ){
348
- if ( ! empty( $style['class'] ) ) {
349
- if( ! is_array( $style['class'] ) ) {
350
- $style['class'] = explode( ' ', $style[ 'class' ] );
351
- }
352
- $attributes['class'] = array_merge( $attributes['class'], $style['class'] );
353
- }
354
-
355
- if ( ! empty( $style['background_display'] ) && ! empty( $style['background_image_attachment'] ) ) {
356
-
357
- $url = self::get_attachment_image_src( $style['background_image_attachment'], 'full' );
358
-
359
- if (
360
- ! empty( $url ) &&
361
- ( $style['background_display'] == 'parallax' || $style['background_display'] == 'parallax-original' )
362
- ) {
363
- wp_enqueue_script( 'siteorigin-parallax' );
364
- $parallax_args = array(
365
- 'backgroundUrl' => $url[0],
366
- 'backgroundSize' => array( $url[1], $url[2] ),
367
- 'backgroundSizing' => $style['background_display'] == 'parallax-original' ? 'original' : 'scaled',
368
- 'limitMotion' => siteorigin_panels_setting( 'parallax-motion' ) ? floatval( siteorigin_panels_setting( 'parallax-motion' ) ) : 'auto',
369
- );
370
- $attributes['data-siteorigin-parallax'] = json_encode( $parallax_args );
371
- }
372
- }
373
-
374
- if ( ! empty( $style['id'] ) ) {
375
- $attributes['id'] = sanitize_html_class( $style['id'] );
376
- }
377
-
378
- return $attributes;
379
- }
380
-
381
- static function row_style_attributes( $attributes, $style ) {
382
- if ( ! empty( $style['row_stretch'] ) ) {
383
- $attributes['class'][] = 'siteorigin-panels-stretch';
384
- $attributes['data-stretch-type'] = $style['row_stretch'];
385
- wp_enqueue_script( 'siteorigin-panels-front-styles' );
386
- }
387
-
388
- return $attributes;
389
- }
390
-
391
- static function vantage_row_style_attributes( $attributes, $style ) {
392
- if ( isset( $style['class'] ) && $style['class'] == 'wide-grey' && ! empty( $attributes['style'] ) ) {
393
- $attributes['style'] = preg_replace( '/padding-left: 1000px; padding-right: 1000px;/', '', $attributes['style'] );
394
- }
395
-
396
- return $attributes;
397
- }
398
-
399
- /**
400
- * Get the CSS styles that apply to all rows, cells and widgets
401
- *
402
- * @param $css
403
- * @param $style
404
- *
405
- * @return mixed
406
- */
407
- static function general_style_css( $css, $style ){
408
-
409
- if ( ! empty( $style['background'] ) ) {
410
- $css[ 'background-color' ] = $style['background'];
411
- }
412
-
413
- if ( ! empty( $style['background_display'] ) && ! empty( $style['background_image_attachment'] ) ) {
414
-
415
- $url = self::get_attachment_image_src( $style['background_image_attachment'], 'full' );
416
-
417
- if ( ! empty( $url ) ) {
418
- $css[ 'background-image' ] = 'url(' . $url[0] . ')';
419
-
420
- switch ( $style['background_display'] ) {
421
- case 'parallax':
422
- case 'parallax-original':
423
- $css[ 'background-position' ] = 'center center';
424
- $css[ 'background-repeat' ] = 'no-repeat';
425
- break;
426
- case 'tile':
427
- $css[ 'background-repeat' ] = 'repeat';
428
- break;
429
- case 'cover':
430
- $css[ 'background-position' ] = 'center center';
431
- $css[ 'background-size' ] = 'cover';
432
- break;
433
- case 'center':
434
- $css[ 'background-position' ] = 'center center';
435
- $css[ 'background-repeat' ] = 'no-repeat';
436
- break;
437
- case 'fixed':
438
- $css[ 'background-attachment' ] = 'fixed';
439
- $css[ 'background-position' ] = 'center center';
440
- $css[ 'background-size' ] = 'cover';
441
- break;
442
- }
443
- }
444
- }
445
-
446
- if ( ! empty( $style[ 'border_color' ] ) ) {
447
- $css[ 'border' ] = '1px solid ' . $style['border_color'];
448
- }
449
-
450
- if ( ! empty( $style[ 'font_color' ] ) ) {
451
- $css[ 'color' ] = $style['font_color'];
452
- }
453
-
454
- if( ! empty( $style[ 'padding' ] ) ) {
455
- $css['padding'] = $style[ 'padding' ];
456
- }
457
-
458
- // Find which key the CSS is stored in
459
- foreach( array( 'row_css', 'cell_css', 'widget_css', '' ) as $css_key ) {
460
- if( empty( $css_key ) || ! empty( $style[ $css_key ] ) ) {
461
- break;
462
- }
463
- }
464
- if ( ! empty( $css_key ) && ! empty( $style[ $css_key ] ) ) {
465
- preg_match_all( '/^([A-Za-z0-9\-]+?):(.+?);?$/m', $style[ $css_key ], $matches );
466
-
467
- if ( ! empty( $matches[0] ) ) {
468
- for ( $i = 0; $i < count( $matches[0] ); $i ++ ) {
469
- $css[ $matches[1][ $i ] ] = $matches[2][ $i ];
470
- }
471
- }
472
- }
473
-
474
- return $css;
475
- }
476
-
477
- /**
478
- * Get the mobile styling for rows, cells and widgets
479
- *
480
- * @param $css
481
- * @param $style
482
- *
483
- * @return mixed
484
- */
485
- static function general_style_mobile_css( $css, $style ){
486
- if( ! empty( $style['mobile_padding'] ) ) {
487
- $css['padding'] = $style[ 'mobile_padding' ];
488
- }
489
-
490
- if ( ! empty( $style['background_display'] ) && ! empty( $style['background_image_attachment'] ) && $style['background_display'] == 'fixed' ) {
491
- $css[ 'background-attachment' ] = 'scroll';
492
- }
493
-
494
- if ( ! empty( $style[ 'mobile_css' ] ) ) {
495
- preg_match_all( '/^([A-Za-z0-9\-]+?):(.+?);?$/m', $style[ 'mobile_css' ], $matches );
496
-
497
- if ( ! empty( $matches[0] ) ) {
498
- for ( $i = 0; $i < count( $matches[0] ); $i ++ ) {
499
- $css[ $matches[1][ $i ] ] = $matches[2][ $i ];
500
- }
501
- }
502
- }
503
-
504
- return $css;
505
- }
506
-
507
- /**
508
- * @param SiteOrigin_Panels_Css_Builder $css
509
- * @param $panels_data
510
- * @param $post_id
511
- *
512
- * @return mixed
513
- */
514
- static function filter_css_object( $css, $panels_data, $post_id, $layout ) {
515
- $mobile_width = siteorigin_panels_setting( 'mobile-width' );
516
- if( empty( $layout ) ) {
517
- return $css;
518
- }
519
-
520
- foreach( $layout as $ri => $row ) {
521
- if( empty( $row[ 'style' ] ) ) $row[ 'style' ] = array();
522
-
523
- $standard_css = apply_filters( 'siteorigin_panels_row_style_css', array(), $row['style'] );
524
- $mobile_css = apply_filters( 'siteorigin_panels_row_style_mobile_css', array(), $row['style'] );
525
-
526
- if ( ! empty( $standard_css ) ) {
527
- $css->add_row_css(
528
- $post_id,
529
- $ri,
530
- '> .panel-row-style',
531
- $standard_css
532
- );
533
- }
534
- if ( ! empty( $mobile_css ) ) {
535
- $css->add_row_css(
536
- $post_id,
537
- $ri,
538
- '> .panel-row-style',
539
- $mobile_css,
540
- $mobile_width
541
- );
542
- }
543
-
544
- // Add in flexbox alignment to the main row element
545
- if ( siteorigin_panels_setting( 'legacy-layout' ) != 'always' && ! SiteOrigin_Panels::is_legacy_browser() && ! empty( $row['style']['cell_alignment'] ) ) {
546
- $css->add_row_css(
547
- $post_id,
548
- $ri,
549
- array( '.panel-no-style', '.panel-has-style > .panel-row-style' ),
550
- array(
551
- '-webkit-align-items' => $row['style']['cell_alignment'],
552
- 'align-items' => $row['style']['cell_alignment'],
553
- )
554
- );
555
- }
556
-
557
- // Process the cells if there are any
558
- if( empty( $row[ 'cells' ] ) ) continue;
559
-
560
- foreach( $row[ 'cells' ] as $ci => $cell ) {
561
- if( empty( $cell[ 'style' ] ) ) $cell[ 'style' ] = array();
562
-
563
- $standard_css = apply_filters( 'siteorigin_panels_cell_style_css', array(), $cell['style'] );
564
- $mobile_css = apply_filters( 'siteorigin_panels_cell_style_mobile_css', array(), $cell['style'] );
565
-
566
- if ( ! empty( $standard_css ) ) {
567
- $css->add_cell_css(
568
- $post_id,
569
- $ri,
570
- $ci,
571
- '> .panel-cell-style',
572
- $standard_css
573
- );
574
- }
575
- if ( ! empty( $mobile_css ) ) {
576
- $css->add_cell_css(
577
- $post_id,
578
- $ri,
579
- $ci,
580
- '> .panel-cell-style',
581
- $mobile_css,
582
- $mobile_width
583
- );
584
- }
585
-
586
- if ( ! empty( $cell[ 'style' ]['vertical_alignment'] ) ) {
587
- $css->add_cell_css(
588
- $post_id,
589
- $ri,
590
- $ci,
591
- '',
592
- array(
593
- 'align-self' => $cell[ 'style' ]['vertical_alignment']
594
- )
595
- );
596
- }
597
-
598
- // Process the widgets if there are any
599
- if( empty( $cell[ 'widgets' ] ) ) continue;
600
-
601
- foreach( $cell['widgets'] as $wi => $widget ) {
602
- if ( empty( $widget['panels_info'] ) ) continue;
603
- if ( empty( $widget['panels_info']['style'] ) ) $widget['panels_info']['style'] = array();
604
-
605
- $standard_css = apply_filters( 'siteorigin_panels_widget_style_css', array(), $widget['panels_info']['style'] );
606
- $mobile_css = apply_filters( 'siteorigin_panels_widget_style_mobile_css', array(), $widget['panels_info']['style'] );
607
-
608
- if( ! empty( $standard_css ) ) {
609
- $css->add_widget_css(
610
- $post_id,
611
- $ri,
612
- $ci,
613
- $wi,
614
- '> .panel-widget-style',
615
- $standard_css
616
- );
617
- }
618
-
619
- if( ! empty( $mobile_css ) ) {
620
- $css->add_widget_css(
621
- $post_id,
622
- $ri,
623
- $ci,
624
- $wi,
625
- '> .panel-widget-style',
626
- $mobile_css,
627
- $mobile_width
628
- );
629
- }
630
-
631
- if ( ! empty( $widget['panels_info']['style']['link_color'] ) ) {
632
- $css->add_widget_css( $post_id, $ri, $ci, $wi, ' a', array(
633
- 'color' => $widget['panels_info']['style']['link_color']
634
- ) );
635
- }
636
- }
637
- }
638
- }
639
-
640
- return $css;
641
- }
642
-
643
- static function filter_row_bottom_margin( $margin, $grid ) {
644
- if ( ! empty( $grid['style']['bottom_margin'] ) ) {
645
- $margin = $grid['style']['bottom_margin'];
646
- }
647
-
648
- return $margin;
649
- }
650
-
651
- static function filter_row_gutter( $gutter, $grid ) {
652
- if ( ! empty( $grid['style']['gutter'] ) ) {
653
- $gutter = $grid['style']['gutter'];
654
- }
655
-
656
- return $gutter;
657
- }
658
-
659
- public static function get_attachment_image_src( $image, $size = 'full' ){
660
- if( empty( $image ) ) {
661
- return false;
662
- }
663
- else if( is_numeric( $image ) ) {
664
- return wp_get_attachment_image_src( $image, $size );
665
- }
666
- else if( is_string( $image ) ) {
667
- preg_match( '/(.*?)\#([0-9]+)x([0-9]+)$/', $image, $matches );
668
- return ! empty( $matches ) ? $matches : false;
669
- }
670
- }
671
-
672
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class for handling all the default styling.
5
+ *
6
+ * Class SiteOrigin_Panels_Default_Styles
7
+ */
8
+ class SiteOrigin_Panels_Styles {
9
+
10
+ public function __construct() {
11
+ add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ), 5 );
12
+
13
+ // Adding all the fields
14
+ add_filter( 'siteorigin_panels_row_style_fields', array( $this, 'row_style_fields' ) );
15
+ add_filter( 'siteorigin_panels_cell_style_fields', array( $this, 'cell_style_fields' ) );
16
+ add_filter( 'siteorigin_panels_widget_style_fields', array( $this, 'widget_style_fields' ) );
17
+
18
+ // Style wrapper attributes
19
+ add_filter( 'siteorigin_panels_row_style_attributes', array( $this, 'general_style_attributes' ), 10, 2 );
20
+ add_filter( 'siteorigin_panels_row_style_attributes', array( $this, 'row_style_attributes' ), 10, 2 );
21
+ add_filter( 'siteorigin_panels_row_style_attributes', array( $this, 'vantage_row_style_attributes' ), 11, 2 );
22
+ add_filter( 'siteorigin_panels_cell_style_attributes', array( $this, 'general_style_attributes' ), 10, 2 );
23
+ add_filter( 'siteorigin_panels_widget_style_attributes', array( $this, 'general_style_attributes' ), 10, 2 );
24
+
25
+ // Style wrapper CSS
26
+ add_filter( 'siteorigin_panels_row_style_css', array( $this, 'general_style_css' ), 10, 2 );
27
+ add_filter( 'siteorigin_panels_cell_style_css', array( $this, 'general_style_css' ), 10, 2 );
28
+ add_filter( 'siteorigin_panels_widget_style_css', array( $this, 'general_style_css' ), 10, 2 );
29
+
30
+ add_filter( 'siteorigin_panels_row_style_mobile_css', array( $this, 'general_style_mobile_css' ), 10, 2 );
31
+ add_filter( 'siteorigin_panels_cell_style_mobile_css', array( $this, 'general_style_mobile_css' ), 10, 2 );
32
+ add_filter( 'siteorigin_panels_widget_style_mobile_css', array( $this, 'general_style_mobile_css' ), 10, 2 );
33
+
34
+ // Main filter to add any custom CSS.
35
+ add_filter( 'siteorigin_panels_css_object', array( $this, 'filter_css_object' ), 10, 4 );
36
+
37
+ // Filtering specific attributes
38
+ add_filter( 'siteorigin_panels_css_row_margin_bottom', array( $this, 'filter_row_bottom_margin' ), 10, 2 );
39
+ add_filter( 'siteorigin_panels_css_row_gutter', array( $this, 'filter_row_gutter' ), 10, 2 );
40
+ add_filter( 'siteorigin_panels_css_widget_css', array( $this, 'filter_widget_style_css' ), 10, 2 );
41
+ }
42
+
43
+ public static function single() {
44
+ static $single;
45
+ return empty( $single ) ? $single = new self() : $single;
46
+ }
47
+
48
+ static function register_scripts() {
49
+ wp_register_script(
50
+ 'siteorigin-panels-front-styles',
51
+ siteorigin_panels_url( 'js/styling' . SITEORIGIN_PANELS_VERSION_SUFFIX . SITEORIGIN_PANELS_JS_SUFFIX . '.js' ),
52
+ array( 'jquery' ),
53
+ SITEORIGIN_PANELS_VERSION
54
+ );
55
+ wp_register_script(
56
+ 'siteorigin-parallax',
57
+ siteorigin_panels_url( 'js/siteorigin-parallax' . SITEORIGIN_PANELS_JS_SUFFIX . '.js' ),
58
+ array( 'jquery' ),
59
+ SITEORIGIN_PANELS_VERSION
60
+ );
61
+ wp_localize_script( 'siteorigin-panels-front-styles', 'panelsStyles', array(
62
+ 'fullContainer' => apply_filters( 'siteorigin_panels_full_width_container', siteorigin_panels_setting( 'full-width-container' ) )
63
+ ) );
64
+ }
65
+
66
+ /**
67
+ * These are general styles that apply to all elements
68
+ *
69
+ * @param $label
70
+ *
71
+ * @return array
72
+ */
73
+ static function get_general_style_fields( $id, $label ) {
74
+ $fields = array();
75
+
76
+ // All the attribute fields
77
+
78
+ $fields['id'] = array(
79
+ 'name' => sprintf( __( '%s ID', 'siteorigin-panels' ), $label ),
80
+ 'type' => 'text',
81
+ 'group' => 'attributes',
82
+ 'description' => sprintf( __( 'A custom ID used for this %s.', 'siteorigin-panels' ), strtolower( $label ) ),
83
+ 'priority' => 4,
84
+ );
85
+
86
+ $fields['class'] = array(
87
+ 'name' => sprintf( __( '%s Class', 'siteorigin-panels' ), $label ),
88
+ 'type' => 'text',
89
+ 'group' => 'attributes',
90
+ 'description' => __( 'A CSS class', 'siteorigin-panels' ),
91
+ 'priority' => 5,
92
+ );
93
+
94
+ $fields[ $id . '_css' ] = array(
95
+ 'name' => __( 'CSS Styles', 'siteorigin-panels' ),
96
+ 'type' => 'code',
97
+ 'group' => 'attributes',
98
+ 'description' => __( 'One style attribute per line.', 'siteorigin-panels' ),
99
+ 'priority' => 10,
100
+ );
101
+
102
+ $fields[ 'mobile_css' ] = array(
103
+ 'name' => __( 'Mobile CSS Styles', 'siteorigin-panels' ),
104
+ 'type' => 'code',
105
+ 'group' => 'attributes',
106
+ 'description' => __( 'CSS applied when in mobile view.', 'siteorigin-panels' ),
107
+ 'priority' => 11,
108
+ );
109
+
110
+ // The layout fields
111
+
112
+ $fields['padding'] = array(
113
+ 'name' => __( 'Padding', 'siteorigin-panels' ),
114
+ 'type' => 'measurement',
115
+ 'group' => 'layout',
116
+ 'description' => sprintf( __( 'Padding around the entire %s.', 'siteorigin-panels' ), strtolower( $label ) ),
117
+ 'priority' => 7,
118
+ 'multiple' => true
119
+ );
120
+
121
+ $fields['mobile_padding'] = array(
122
+ 'name' => __( 'Mobile Padding', 'siteorigin-panels' ),
123
+ 'type' => 'measurement',
124
+ 'group' => 'layout',
125
+ 'description' => __( 'Padding when on mobile devices.', 'siteorigin-panels' ),
126
+ 'priority' => 8,
127
+ 'multiple' => true
128
+ );
129
+
130
+ // The general design fields
131
+
132
+ $fields['background'] = array(
133
+ 'name' => __( 'Background Color', 'siteorigin-panels' ),
134
+ 'type' => 'color',
135
+ 'group' => 'design',
136
+ 'description' => sprintf( __( 'Background color of the %s.', 'siteorigin-panels' ), strtolower( $label ) ),
137
+ 'priority' => 5,
138
+ );
139
+
140
+ $fields['background_image_attachment'] = array(
141
+ 'name' => __( 'Background Image', 'siteorigin-panels' ),
142
+ 'type' => 'image',
143
+ 'group' => 'design',
144
+ 'description' => sprintf( __( 'Background image of the %s.', 'siteorigin-panels' ), strtolower( $label ) ),
145
+ 'priority' => 6,
146
+ );
147
+
148
+ $fields['background_display'] = array(
149
+ 'name' => __( 'Background Image Display', 'siteorigin-panels' ),
150
+ 'type' => 'select',
151
+ 'group' => 'design',
152
+ 'options' => array(
153
+ 'tile' => __( 'Tiled Image', 'siteorigin-panels' ),
154
+ 'cover' => __( 'Cover', 'siteorigin-panels' ),
155
+ 'center' => __( 'Centered, with original size', 'siteorigin-panels' ),
156
+ 'fixed' => __( 'Fixed', 'siteorigin-panels' ),
157
+ 'parallax' => __( 'Parallax', 'siteorigin-panels' ),
158
+ 'parallax-original' => __( 'Parallax (Original Size)', 'siteorigin-panels' ),
159
+ ),
160
+ 'description' => __( 'How the background image is displayed.', 'siteorigin-panels' ),
161
+ 'priority' => 7,
162
+ );
163
+
164
+ $fields['border_color'] = array(
165
+ 'name' => __( 'Border Color', 'siteorigin-panels' ),
166
+ 'type' => 'color',
167
+ 'group' => 'design',
168
+ 'description' => sprintf( __( 'Border color of the %s.', 'siteorigin-panels' ), strtolower( $label ) ),
169
+ 'priority' => 10,
170
+ );
171
+
172
+ return $fields;
173
+ }
174
+
175
+ /**
176
+ * All the row styling fields
177
+ *
178
+ * @param $fields
179
+ *
180
+ * @return array
181
+ */
182
+ static function row_style_fields( $fields ) {
183
+ // Add the general fields
184
+ $fields = wp_parse_args( $fields, self::get_general_style_fields( 'row', __( 'Row', 'siteorigin-panels' ) ) );
185
+
186
+ $fields['cell_class'] = array(
187
+ 'name' => __( 'Cell Class', 'siteorigin-panels' ),
188
+ 'type' => 'text',
189
+ 'group' => 'attributes',
190
+ 'description' => __( 'Class added to all cells in this row.', 'siteorigin-panels' ),
191
+ 'priority' => 6,
192
+ );
193
+
194
+ // Add the layout fields
195
+
196
+ $fields['bottom_margin'] = array(
197
+ 'name' => __( 'Bottom Margin', 'siteorigin-panels' ),
198
+ 'type' => 'measurement',
199
+ 'group' => 'layout',
200
+ 'description' => sprintf( __( 'Space below the row. Default is %spx.', 'siteorigin-panels' ), siteorigin_panels_setting( 'margin-bottom' ) ),
201
+ 'priority' => 5,
202
+ );
203
+
204
+ $fields['gutter'] = array(
205
+ 'name' => __( 'Gutter', 'siteorigin-panels' ),
206
+ 'type' => 'measurement',
207
+ 'group' => 'layout',
208
+ 'description' => sprintf( __( 'Amount of space between cells. Default is %spx.', 'siteorigin-panels' ), siteorigin_panels_setting( 'margin-sides' ) ),
209
+ 'priority' => 6,
210
+ );
211
+
212
+ $fields['row_stretch'] = array(
213
+ 'name' => __( 'Row Layout', 'siteorigin-panels' ),
214
+ 'type' => 'select',
215
+ 'group' => 'layout',
216
+ 'options' => array(
217
+ '' => __( 'Standard', 'siteorigin-panels' ),
218
+ 'full' => __( 'Full Width', 'siteorigin-panels' ),
219
+ 'full-stretched' => __( 'Full Width Stretched', 'siteorigin-panels' ),
220
+ ),
221
+ 'priority' => 10,
222
+ );
223
+
224
+ $fields['collapse_behaviour'] = array(
225
+ 'name' => __( 'Collapse Behaviour', 'siteorigin-panels' ),
226
+ 'type' => 'select',
227
+ 'group' => 'layout',
228
+ 'options' => array(
229
+ '' => __( 'Standard', 'siteorigin-panels' ),
230
+ 'no_collapse' => __( 'No Collapse', 'siteorigin-panels' ),
231
+ ),
232
+ 'priority' => 15,
233
+ );
234
+
235
+ $fields['collapse_order'] = array(
236
+ 'name' => __( 'Collapse Order', 'siteorigin-panels' ),
237
+ 'type' => 'select',
238
+ 'group' => 'layout',
239
+ 'options' => array(
240
+ '' => __( 'Default', 'siteorigin-panels' ),
241
+ 'left-top' => __( 'Left on Top', 'siteorigin-panels' ),
242
+ 'right-top' => __( 'Right on Top', 'siteorigin-panels' ),
243
+ ),
244
+ 'priority' => 16,
245
+ );
246
+
247
+ if ( siteorigin_panels_setting( 'legacy-layout' ) != 'always' ) {
248
+ $fields['cell_alignment'] = array(
249
+ 'name' => __( 'Cell Vertical Alignment', 'siteorigin-panels' ),
250
+ 'type' => 'select',
251
+ 'group' => 'layout',
252
+ 'options' => array(
253
+ 'flex-start' => __( 'Top', 'siteorigin-panels' ),
254
+ 'center' => __( 'Center', 'siteorigin-panels' ),
255
+ 'flex-end' => __( 'Bottom', 'siteorigin-panels' ),
256
+ 'stretch' => __( 'Stretch', 'siteorigin-panels' ),
257
+ ),
258
+ 'priority' => 17,
259
+ );
260
+ }
261
+
262
+ return $fields;
263
+ }
264
+
265
+ /**
266
+ * All the cell styling fields
267
+ *
268
+ * @param $fields
269
+ *
270
+ * @return array
271
+ */
272
+ static function cell_style_fields( $fields ) {
273
+ // Add the general fields
274
+ $fields = wp_parse_args( $fields, self::get_general_style_fields( 'cell', __( 'Cell', 'siteorigin-panels' ) ) );
275
+
276
+ $fields['vertical_alignment'] = array(
277
+ 'name' => __( 'Vertical Alignment', 'siteorigin-panels' ),
278
+ 'type' => 'select',
279
+ 'group' => 'layout',
280
+ 'options' => array(
281
+ 'auto' => __( 'Use row setting', 'siteorigin-panels' ),
282
+ 'flex-start' => __( 'Top', 'siteorigin-panels' ),
283
+ 'center' => __( 'Center', 'siteorigin-panels' ),
284
+ 'flex-end' => __( 'Bottom', 'siteorigin-panels' ),
285
+ 'stretch' => __( 'Stretch', 'siteorigin-panels' ),
286
+ ),
287
+ 'priority' => 16,
288
+ );
289
+
290
+ $fields['font_color'] = array(
291
+ 'name' => __( 'Font Color', 'siteorigin-panels' ),
292
+ 'type' => 'color',
293
+ 'group' => 'design',
294
+ 'description' => __( 'Color of text inside this cell.', 'siteorigin-panels' ),
295
+ 'priority' => 15,
296
+ );
297
+
298
+ $fields['link_color'] = array(
299
+ 'name' => __( 'Links Color', 'siteorigin-panels' ),
300
+ 'type' => 'color',
301
+ 'group' => 'design',
302
+ 'description' => __( 'Color of links inside this cell.', 'siteorigin-panels' ),
303
+ 'priority' => 16,
304
+ );
305
+
306
+ return $fields;
307
+ }
308
+
309
+ /**
310
+ * @param $fields
311
+ *
312
+ * @return array
313
+ */
314
+ static function widget_style_fields( $fields ) {
315
+
316
+ // Add the general fields
317
+ $fields = wp_parse_args( $fields, self::get_general_style_fields( 'widget', __( 'Widget', 'siteorigin-panels' ) ) );
318
+
319
+ $fields['margin'] = array(
320
+ 'name' => __( 'Margin', 'siteorigin-panels' ),
321
+ 'type' => 'measurement',
322
+ 'group' => 'layout',
323
+ 'description' => __( 'Margins around the widget.', 'siteorigin-panels' ),
324
+ 'priority' => 6,
325
+ 'multiple' => true
326
+ );
327
+
328
+ // How lets add the design fields
329
+
330
+ $fields['font_color'] = array(
331
+ 'name' => __( 'Font Color', 'siteorigin-panels' ),
332
+ 'type' => 'color',
333
+ 'group' => 'design',
334
+ 'description' => __( 'Color of text inside this widget.', 'siteorigin-panels' ),
335
+ 'priority' => 15,
336
+ );
337
+
338
+ $fields['link_color'] = array(
339
+ 'name' => __( 'Links Color', 'siteorigin-panels' ),
340
+ 'type' => 'color',
341
+ 'group' => 'design',
342
+ 'description' => __( 'Color of links inside this widget.', 'siteorigin-panels' ),
343
+ 'priority' => 16,
344
+ );
345
+
346
+ return $fields;
347
+ }
348
+
349
+ /**
350
+ * Style attributes that apply to rows, cells and widgets
351
+ *
352
+ * @param $attributes
353
+ * @param $style
354
+ *
355
+ * @return array $attributes
356
+ */
357
+ static function general_style_attributes( $attributes, $style ){
358
+ if ( ! empty( $style['class'] ) ) {
359
+ if( ! is_array( $style['class'] ) ) {
360
+ $style['class'] = explode( ' ', $style[ 'class' ] );
361
+ }
362
+ $attributes['class'] = array_merge( $attributes['class'], $style['class'] );
363
+ }
364
+
365
+ if ( ! empty( $style['background_display'] ) &&
366
+ ! empty( $style['background_image_attachment'] )
367
+ ) {
368
+
369
+ $url = self::get_attachment_image_src( $style['background_image_attachment'], 'full' );
370
+
371
+ if (
372
+ ! empty( $url ) &&
373
+ ( $style['background_display'] == 'parallax' || $style['background_display'] == 'parallax-original' )
374
+ ) {
375
+ wp_enqueue_script( 'siteorigin-parallax' );
376
+ $parallax_args = array(
377
+ 'backgroundUrl' => $url[0],
378
+ 'backgroundSize' => array( $url[1], $url[2] ),
379
+ 'backgroundSizing' => $style['background_display'] == 'parallax-original' ? 'original' : 'scaled',
380
+ 'limitMotion' => siteorigin_panels_setting( 'parallax-motion' ) ? floatval( siteorigin_panels_setting( 'parallax-motion' ) ) : 'auto',
381
+ );
382
+ $attributes['data-siteorigin-parallax'] = json_encode( $parallax_args );
383
+ }
384
+ }
385
+
386
+ if ( ! empty( $style['id'] ) ) {
387
+ $attributes['id'] = sanitize_html_class( $style['id'] );
388
+ }
389
+
390
+ return $attributes;
391
+ }
392
+
393
+ static function row_style_attributes( $attributes, $style ) {
394
+ if ( ! empty( $style['row_stretch'] ) ) {
395
+ $attributes['class'][] = 'siteorigin-panels-stretch';
396
+ $attributes['data-stretch-type'] = $style['row_stretch'];
397
+ wp_enqueue_script( 'siteorigin-panels-front-styles' );
398
+ }
399
+
400
+ return $attributes;
401
+ }
402
+
403
+ static function vantage_row_style_attributes( $attributes, $style ) {
404
+ if ( isset( $style['class'] ) && $style['class'] == 'wide-grey' && ! empty( $attributes['style'] ) ) {
405
+ $attributes['style'] = preg_replace( '/padding-left: 1000px; padding-right: 1000px;/', '', $attributes['style'] );
406
+ }
407
+
408
+ return $attributes;
409
+ }
410
+
411
+ /**
412
+ * Get the CSS styles that apply to all rows, cells and widgets
413
+ *
414
+ * @param $css
415
+ * @param $style
416
+ *
417
+ * @return mixed
418
+ */
419
+ static function general_style_css( $css, $style ){
420
+
421
+ if ( ! empty( $style['background'] ) ) {
422
+ $css[ 'background-color' ] = $style['background'];
423
+ }
424
+
425
+ if ( ! empty( $style['background_display'] ) &&
426
+ ! ( empty( $style['background_image_attachment'] ) && empty( $style['background_image_attachment_fallback'] ) )
427
+ ) {
428
+ $url = self::get_attachment_image_src( $style['background_image_attachment'], 'full' );
429
+
430
+ if ( empty( $url ) ) {
431
+ $url = $style['background_image_attachment_fallback'];
432
+ }
433
+
434
+ if ( ! empty( $url ) ) {
435
+ $css['background-image'] = 'url(' .( is_array( $url ) ? $url[0] : $url ) . ')';
436
+
437
+ switch ( $style['background_display'] ) {
438
+ case 'parallax':
439
+ case 'parallax-original':
440
+ $css[ 'background-position' ] = 'center center';
441
+ $css[ 'background-repeat' ] = 'no-repeat';
442
+ break;
443
+ case 'tile':
444
+ $css[ 'background-repeat' ] = 'repeat';
445
+ break;
446
+ case 'cover':
447
+ $css[ 'background-position' ] = 'center center';
448
+ $css[ 'background-size' ] = 'cover';
449
+ break;
450
+ case 'center':
451
+ $css[ 'background-position' ] = 'center center';
452
+ $css[ 'background-repeat' ] = 'no-repeat';
453
+ break;
454
+ case 'fixed':
455
+ $css[ 'background-attachment' ] = 'fixed';
456
+ $css[ 'background-position' ] = 'center center';
457
+ $css[ 'background-size' ] = 'cover';
458
+ break;
459
+ }
460
+ }
461
+ }
462
+
463
+ if ( ! empty( $style[ 'border_color' ] ) ) {
464
+ $css[ 'border' ] = '1px solid ' . $style['border_color'];
465
+ }
466
+
467
+ if ( ! empty( $style[ 'font_color' ] ) ) {
468
+ $css[ 'color' ] = $style['font_color'];
469
+ }
470
+
471
+ if( ! empty( $style[ 'padding' ] ) ) {
472
+ $css['padding'] = $style[ 'padding' ];
473
+ }
474
+
475
+ // Find which key the CSS is stored in
476
+ foreach( array( 'row_css', 'cell_css', 'widget_css', '' ) as $css_key ) {
477
+ if( empty( $css_key ) || ! empty( $style[ $css_key ] ) ) {
478
+ break;
479
+ }
480
+ }
481
+ if ( ! empty( $css_key ) && ! empty( $style[ $css_key ] ) ) {
482
+ preg_match_all( '/^([A-Za-z0-9\-]+?):(.+?);?$/m', $style[ $css_key ], $matches );
483
+
484
+ if ( ! empty( $matches[0] ) ) {
485
+ for ( $i = 0; $i < count( $matches[0] ); $i ++ ) {
486
+ $css[ $matches[1][ $i ] ] = $matches[2][ $i ];
487
+ }
488
+ }
489
+ }
490
+
491
+ return $css;
492
+ }
493
+
494
+ /**
495
+ * Get the mobile styling for rows, cells and widgets
496
+ *
497
+ * @param $css
498
+ * @param $style
499
+ *
500
+ * @return mixed
501
+ */
502
+ static function general_style_mobile_css( $css, $style ){
503
+ if( ! empty( $style['mobile_padding'] ) ) {
504
+ $css['padding'] = $style[ 'mobile_padding' ];
505
+ }
506
+
507
+ if ( ! empty( $style['background_display'] ) &&
508
+ $style['background_display'] == 'fixed' &&
509
+ ! ( empty( $style['background_image_attachment'] ) && empty( $style['background_image_attachment_fallback'] ) )
510
+ ) {
511
+ $css[ 'background-attachment' ] = 'scroll';
512
+ }
513
+
514
+ if ( ! empty( $style[ 'mobile_css' ] ) ) {
515
+ preg_match_all( '/^([A-Za-z0-9\-]+?):(.+?);?$/m', $style[ 'mobile_css' ], $matches );
516
+
517
+ if ( ! empty( $matches[0] ) ) {
518
+ for ( $i = 0; $i < count( $matches[0] ); $i ++ ) {
519
+ $css[ $matches[1][ $i ] ] = $matches[2][ $i ];
520
+ }
521
+ }
522
+ }
523
+
524
+ return $css;
525
+ }
526
+
527
+ /**
528
+ * @param SiteOrigin_Panels_Css_Builder $css
529
+ * @param $panels_data
530
+ * @param $post_id
531
+ *
532
+ * @return mixed
533
+ */
534
+ static function filter_css_object( $css, $panels_data, $post_id, $layout ) {
535
+ $mobile_width = siteorigin_panels_setting( 'mobile-width' );
536
+ if( empty( $layout ) ) {
537
+ return $css;
538
+ }
539
+
540
+ foreach( $layout as $ri => $row ) {
541
+ if( empty( $row[ 'style' ] ) ) $row[ 'style' ] = array();
542
+
543
+ $standard_css = apply_filters( 'siteorigin_panels_row_style_css', array(), $row['style'] );
544
+ $mobile_css = apply_filters( 'siteorigin_panels_row_style_mobile_css', array(), $row['style'] );
545
+
546
+ if ( ! empty( $standard_css ) ) {
547
+ $css->add_row_css(
548
+ $post_id,
549
+ $ri,
550
+ '> .panel-row-style',
551
+ $standard_css
552
+ );
553
+ }
554
+ if ( ! empty( $mobile_css ) ) {
555
+ $css->add_row_css(
556
+ $post_id,
557
+ $ri,
558
+ '> .panel-row-style',
559
+ $mobile_css,
560
+ $mobile_width
561
+ );
562
+ }
563
+
564
+ // Add in flexbox alignment to the main row element
565
+ if ( siteorigin_panels_setting( 'legacy-layout' ) != 'always' && ! SiteOrigin_Panels::is_legacy_browser() && ! empty( $row['style']['cell_alignment'] ) ) {
566
+ $css->add_row_css(
567
+ $post_id,
568
+ $ri,
569
+ array( '.panel-no-style', '.panel-has-style > .panel-row-style' ),
570
+ array(
571
+ '-webkit-align-items' => $row['style']['cell_alignment'],
572
+ 'align-items' => $row['style']['cell_alignment'],
573
+ )
574
+ );
575
+ }
576
+
577
+ // Process the cells if there are any
578
+ if( empty( $row[ 'cells' ] ) ) continue;
579
+
580
+ foreach( $row[ 'cells' ] as $ci => $cell ) {
581
+ if( empty( $cell[ 'style' ] ) ) $cell[ 'style' ] = array();
582
+
583
+ $standard_css = apply_filters( 'siteorigin_panels_cell_style_css', array(), $cell['style'] );
584
+ $mobile_css = apply_filters( 'siteorigin_panels_cell_style_mobile_css', array(), $cell['style'] );
585
+
586
+ if ( ! empty( $standard_css ) ) {
587
+ $css->add_cell_css(
588
+ $post_id,
589
+ $ri,
590
+ $ci,
591
+ '> .panel-cell-style',
592
+ $standard_css
593
+ );
594
+ }
595
+ if ( ! empty( $mobile_css ) ) {
596
+ $css->add_cell_css(
597
+ $post_id,
598
+ $ri,
599
+ $ci,
600
+ '> .panel-cell-style',
601
+ $mobile_css,
602
+ $mobile_width
603
+ );
604
+ }
605
+
606
+ if ( ! empty( $cell[ 'style' ]['vertical_alignment'] ) ) {
607
+ $css->add_cell_css(
608
+ $post_id,
609
+ $ri,
610
+ $ci,
611
+ '',
612
+ array(
613
+ 'align-self' => $cell[ 'style' ]['vertical_alignment']
614
+ )
615
+ );
616
+ }
617
+
618
+ // Process the widgets if there are any
619
+ if( empty( $cell[ 'widgets' ] ) ) continue;
620
+
621
+ foreach( $cell['widgets'] as $wi => $widget ) {
622
+ if ( empty( $widget['panels_info'] ) ) continue;
623
+ if ( empty( $widget['panels_info']['style'] ) ) $widget['panels_info']['style'] = array();
624
+
625
+ $standard_css = apply_filters( 'siteorigin_panels_widget_style_css', array(), $widget['panels_info']['style'] );
626
+ $mobile_css = apply_filters( 'siteorigin_panels_widget_style_mobile_css', array(), $widget['panels_info']['style'] );
627
+
628
+ if( ! empty( $standard_css ) ) {
629
+ $css->add_widget_css(
630
+ $post_id,
631
+ $ri,
632
+ $ci,
633
+ $wi,
634
+ '> .panel-widget-style',
635
+ $standard_css
636
+ );
637
+ }
638
+
639
+ if( ! empty( $mobile_css ) ) {
640
+ $css->add_widget_css(
641
+ $post_id,
642
+ $ri,
643
+ $ci,
644
+ $wi,
645
+ '> .panel-widget-style',
646
+ $mobile_css,
647
+ $mobile_width
648
+ );
649
+ }
650
+
651
+ if ( ! empty( $widget['panels_info']['style']['link_color'] ) ) {
652
+ $css->add_widget_css( $post_id, $ri, $ci, $wi, ' a', array(
653
+ 'color' => $widget['panels_info']['style']['link_color']
654
+ ) );
655
+ }
656
+ }
657
+ }
658
+ }
659
+
660
+ return $css;
661
+ }
662
+
663
+ static function filter_row_bottom_margin( $margin, $grid ) {
664
+ if ( ! empty( $grid['style']['bottom_margin'] ) ) {
665
+ $margin = $grid['style']['bottom_margin'];
666
+ }
667
+
668
+ return $margin;
669
+ }
670
+
671
+ static function filter_row_gutter( $gutter, $grid ) {
672
+ if ( ! empty( $grid['style']['gutter'] ) ) {
673
+ $gutter = $grid['style']['gutter'];
674
+ }
675
+
676
+ return $gutter;
677
+ }
678
+
679
+ /**
680
+ * Adds widget specific styles not included in the general style fields.
681
+ *
682
+ * @param $widget_css The CSS properties and values
683
+ * @param $widget_style_data The style settings as obtained from the style fields.
684
+ *
685
+ * @return mixed
686
+ */
687
+ static function filter_widget_style_css( $widget_css, $widget_style_data ) {
688
+ if ( ! empty( $widget_style_data['margin'] ) ) {
689
+ $widget_css['margin'] = $widget_style_data['margin'];
690
+ }
691
+
692
+ return $widget_css;
693
+ }
694
+
695
+ public static function get_attachment_image_src( $image, $size = 'full' ){
696
+ if( empty( $image ) ) {
697
+ return false;
698
+ }
699
+ else if( is_numeric( $image ) ) {
700
+ return wp_get_attachment_image_src( $image, $size );
701
+ }
702
+ else if( is_string( $image ) ) {
703
+ preg_match( '/(.*?)\#([0-9]+)x([0-9]+)$/', $image, $matches );
704
+ return ! empty( $matches ) ? $matches : false;
705
+ }
706
+ }
707
+
708
+ }
js/siteorigin-panels-263.min.js DELETED
@@ -1,4 +0,0 @@
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||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}})},{}],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()))break;e.destroy()}}})},{}],4:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.widget,initialize:function(){}})},{}],5:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({dialogClass:"so-panels-dialog-add-builder",render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-builder").html(),{})),this.$(".so-content .siteorigin-panels-builder").append(this.builder.$el)},initializeDialog:function(){var e=this;this.once("open_dialog_complete",function(){e.builder.initSortable()}),this.on("open_dialog_complete",function(){e.builder.trigger("builder_resize")})}})},{}],6:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({historyEntryTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-history-entry").html())),entries:{},currentEntry:null,revertEntry:null,selectedEntry:null,previewScrollTop:null,dialogClass:"so-panels-dialog-history",dialogIcon:"history",events:{"click .so-close":"closeDialog","click .so-restore":"restoreSelectedEntry"},initializeDialog:function(){this.entries=new s.collection.historyEntries,this.on("open_dialog",this.setCurrentEntry,this),this.on("open_dialog",this.renderHistoryEntries,this)},render:function(){var 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 input[name="live_editor_post_ID"]').val(this.builder.config.postId),this.$("form.history-form").submit()},restoreSelectedEntry:function(){return!this.$(".so-buttons .so-restore").hasClass("disabled")&&(this.currentEntry.get("data")===this.selectedEntry.get("data")?(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(s.helpers.utils.processTemplate(l("#siteorigin-panels-directory-items").html())),builder:null,dialogClass:"so-panels-dialog-prebuilt-layouts",dialogIcon:"layouts",layoutCache:{},currentTab:!1,directoryPage:1,events:{"click .so-close":"closeDialog","click .so-sidebar-tabs li a":"tabClickHandler","click .so-content .layout":"layoutClickHandler","keyup .so-sidebar-search":"searchHandler","click .so-screenshot, .so-title":"directoryItemClickHandler"},initializeDialog:function(){var e=this;this.on("open_dialog",function(){e.$(".so-sidebar-tabs li a").first().click(),e.$(".so-status").removeClass("so-panels-loading")}),this.on("button_click",this.toolbarButtonClick,this)},render:function(){this.renderDialog(this.parseDialogContent(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();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)}}}).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=l(this),s=t.builder.model.getPanelsData(),o=l('input[name="post_title"]').val();o||(o=l('input[name="post_ID"]').val()),s.name=o,i.find('input[name="panels_export_data"]').val(JSON.stringify(s))})},displayLayoutDirectory:function(e,t,i){var s=this,o=this.$(".so-content").empty().addClass("so-panels-loading");if(void 0===e&&(e=""),void 0===t&&(t=1),void 0===i&&(i="directory-siteorigin"),i.match("^directory-")&&!panelsOptions.directory_enabled)return o.removeClass("so-panels-loading").html(l("#siteorigin-panels-directory-enable").html()),void o.find(".so-panels-enable-directory").click(function(n){n.preventDefault(),l.get(panelsOptions.ajaxurl,{action:"so_panels_directory_enable"},function(){}),panelsOptions.directory_enabled=!0,o.addClass("so-panels-loading"),s.displayLayoutDirectory(e,t,i)});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");t<=1?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")},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){var i="";e.success?t.resolve(e.data):(i=e.data.message,t.reject(e.data)),this.setStatusMessage(i,!1,!e.success),this.updateButtonState(!0)}.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(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-row-cell-preview").html())),editableLabel:!0,events:{"click .so-close":"closeDialog","click .so-toolbar .so-save":"saveHandler","click .so-toolbar .so-insert":"insertHandler","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler","change .row-set-form > *":"setCellsFromForm","click .row-set-form button.set-row":"setCellsFromForm"},dialogIcon:"add-row",dialogClass:"so-panels-dialog-row-edit",styleType:"row",dialogType:"edit",row:{cells:null,style:{}},cellStylesCache:[],initializeDialog:function(){this.on("open_dialog",function(){_.isUndefined(this.model)||_.isEmpty(this.model.get("cells"))?this.setRowModel(null):this.setRowModel(this.model),this.regenerateRowPreview()},this),this.row={cells:new s.collection.cells([{weight:.5},{weight:.5}]),style:{}},this.dialogFormsLoaded=0;var e=this;this.on("form_loaded styles_loaded",function(){2===++this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})}),this.on("close_dialog",this.closeHandler),this.on("edit_label",function(e){if(e!==panelsOptions.loc.row.add&&e!==panelsOptions.loc.row.edit||(e=""),this.model.set("label",e),_.isEmpty(e)){var t="create"===this.dialogType?panelsOptions.loc.row.add:panelsOptions.loc.row.edit;this.$(".so-title").text(t)}}.bind(this))},setRowDialogType:function(e){this.dialogType=e},render:function(){var e="create"===this.dialogType?panelsOptions.loc.row.add:panelsOptions.loc.row.edit;this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-row").html(),{title:e,dialogType:this.dialogType}));var t=this.$(".so-title");this.model.has("label")&&!_.isEmpty(this.model.get("label"))&&t.text(this.model.get("label")),this.$(".so-edit-title").val(t.text()),this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("row",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this}),this.builder.supports("addRow")||this.$(".so-buttons .so-duplicate").remove(),this.builder.supports("deleteRow")||this.$(".so-buttons .so-delete").remove();var i=this.$(".so-sidebar.so-right-sidebar");return this.styles.attach(i),this.styles.on("styles_loaded",function(e){e?i.removeClass("so-panels-loading"):(i.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),i.remove())},this),i.addClass("so-panels-loading"),_.isUndefined(this.model)||(this.$('input[name="cells"].so-row-field').val(this.model.get("cells").length),this.model.has("ratio")&&this.$('select[name="ratio"].so-row-field').val(this.model.get("ratio")),this.model.has("ratio_direction")&&this.$('select[name="ratio_direction"].so-row-field').val(this.model.get("ratio_direction"))),this.$("input.so-row-field").keyup(function(){l(this).trigger("change")}),this},setRowModel:function(e){return this.model=e,_.isEmpty(this.model)?this:(this.row={cells:this.model.get("cells").clone(),style:{},ratio:this.model.get("ratio"),ratio_direction:this.model.get("ratio_direction")},this.$('input[name="cells"].so-row-field').val(this.model.get("cells").length),this.model.has("ratio")&&this.$('select[name="ratio"].so-row-field').val(this.model.get("ratio")),this.model.has("ratio_direction")&&this.$('select[name="ratio_direction"].so-row-field').val(this.model.get("ratio_direction")),this.clearCellStylesCache(),this)},regenerateRowPreview:function(){var e=this,t=this.$(".row-preview"),i=this.getSelectedCellIndex();t.empty();var s;this.row.cells.each(function(o,n){var a=l(this.cellPreviewTemplate({weight:o.get("weight")}));t.append(a),n==i&&a.find(".preview-cell-in").addClass("cell-selected");var r,d=a.prev();d.length&&(r=l('<div class="resize-handle"></div>'),r.appendTo(a).dblclick(function(){var t=e.row.cells.at(n-1),i=o.get("weight")+t.get("weight");o.set("weight",i/2),t.set("weight",i/2),e.scaleRowWidths()}),r.draggable({axis:"x",containment:t,start:function(e,t){var i=a.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:a.outerWidth(),left:6,height:a.outerHeight()});i.find(".resize-handle").remove();var s=d.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:d.outerWidth(),right:6,height:d.outerHeight()});s.find(".resize-handle").remove(),l(this).data({newCellClone:i,prevCellClone:s}),a.find("> .preview-cell-in").css("visibility","hidden"),d.find("> .preview-cell-in").css("visibility","hidden")},drag:function(i,s){var o=e.row.cells.at(n).get("weight"),a=e.row.cells.at(n-1).get("weight"),r=o-(s.position.left+6)/t.width(),d=a+(s.position.left+6)/t.width();s.helper.offset().left,t.offset().left;l(this).data("newCellClone").css("width",t.width()*r).find(".preview-cell-weight").html(Math.round(1e3*r)/10),l(this).data("prevCellClone").css("width",t.width()*d).find(".preview-cell-weight").html(Math.round(1e3*d)/10)},stop:function(i,s){l(this).data("newCellClone").remove(),l(this).data("prevCellClone").remove(),a.find(".preview-cell-in").css("visibility","visible"),d.find(".preview-cell-in").css("visibility","visible");var o=s.position.left+6,r=o/t.width(),c=e.row.cells.at(n),h=e.row.cells.at(n-1);c.get("weight")-r>.02&&h.get("weight")+r>.02&&(c.set("weight",c.get("weight")-r),h.set("weight",h.get("weight")+r)),e.scaleRowWidths(),s.helper.css("left",-6)}})),a.click(function(e){if(l(e.target).is(".preview-cell")||l(e.target).is(".preview-cell-in")){var t=l(e.target);t.closest(".row-preview").find(".preview-cell .preview-cell-in").removeClass("cell-selected"),t.addClass("cell-selected"),this.openSelectedCellStyles()}}.bind(this)),a.find(".preview-cell-weight").click(function(i){e.$(".resize-handle").css("pointer-event","none").draggable("disable"),t.find(".preview-cell-weight").each(function(){var i=jQuery(this).hide();l('<input type="text" class="preview-cell-weight-input no-user-interacted" />').val(parseFloat(i.html())).insertAfter(i).focus(function(){clearTimeout(s)}).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.at(t).get("weight"))/10)}),s=setTimeout(function(){if(0===t.find(".preview-cell-weight-input").length)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.each(function(e,t){e.set("weight",i[t])}),t.find(".preview-cell").each(function(t,i){var s=e.row.cells.at(t).get("weight");l(i).animate({width:Math.round(1e3*s)/10+"%"},250),l(i).find(".preview-cell-weight-input").val(Math.round(1e3*s)/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.openSelectedCellStyles(),this.trigger("form_loaded",this)},getSelectedCellIndex:function(){var e=-1;return this.$(".preview-cell .preview-cell-in").each(function(t,i){l(i).is(".cell-selected")&&(e=t)}),e},openSelectedCellStyles:function(){if(!_.isUndefined(this.cellStyles)){if(this.cellStyles.stylesLoaded){var e={};try{e=this.getFormValues(".so-sidebar .so-visual-styles.so-cell-styles").style}catch(e){console.log("Error retrieving cell styles - "+e.message)}this.cellStyles.model.set("style",e)}this.cellStyles.detach()}if(this.cellStyles=this.getSelectedCellStyles(),this.cellStyles){var t=this.$(".so-sidebar.so-right-sidebar");this.cellStyles.attach(t),this.cellStyles.stylesLoaded||(this.cellStyles.on("styles_loaded",function(){t.removeClass("so-panels-loading")},this),t.addClass("so-panels-loading"))}},getSelectedCellStyles:function(){var e=this.getSelectedCellIndex();if(e>-1){var t=this.cellStylesCache[e];t||(t=new s.view.styles,t.model=this.row.cells.at(e),t.render("cell",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this,index:e}),this.cellStylesCache[e]=t)}return t},clearCellStylesCache:function(){this.cellStylesCache.forEach(function(e){e.remove()}),this.cellStylesCache=[]},scaleRowWidths:function(){var e=this;this.$(".row-preview .preview-cell").each(function(t,i){var s=e.row.cells.at(t);l(i).css("width",100*s.get("weight")+"%").find(".preview-cell-weight").html(Math.round(1e3*s.get("weight"))/10)})},setCellsFromForm:function(){try{var e={cells:parseInt(this.$('.row-set-form input[name="cells"]').val()),ratio:parseFloat(this.$('.row-set-form select[name="ratio"]').val()),direction:this.$('.row-set-form select[name="ratio_direction"]').val()};_.isNaN(e.cells)&&(e.cells=1),isNaN(e.ratio)&&(e.ratio=1),e.cells<1?(e.cells=1,this.$('.row-set-form input[name="cells"]').val(e.cells)):e.cells>12&&(e.cells=12,this.$('.row-set-form input[name="cells"]').val(e.cells)),this.$('.row-set-form select[name="ratio"]').val(e.ratio);for(var t=[],i=this.row.cells.length!==e.cells,o=1,n=0;n<e.cells;n++)t.push(o),o*=e.ratio;var a=_.reduce(t,function(e,t){return e+t});if(t=_.map(t,function(e){return e/a}),t=_.filter(t,function(e){return e>.01}),"left"===e.direction&&(t=t.reverse()),this.row.cells=new s.collection.cells(this.row.cells.first(t.length)),_.each(t,function(e,t){var i=this.row.cells.at(t);i?i.set("weight",e):(i=new s.model.cell({weight:e,row:this.model}),this.row.cells.add(i))}.bind(this)),this.row.ratio=e.ratio,this.row.ratio_direction=e.direction,i)this.regenerateRowPreview();else{var r=this;this.$(".preview-cell").each(function(e,t){var i=r.row.cells.at(e).get("weight");l(t).animate({width:Math.round(1e3*i)/10+"%"},250),l(t).find(".preview-cell-weight").html(Math.round(1e3*i)/10)}),this.$(".preview-cell").css("overflow","visible"),setTimeout(function(){r.regenerateRowPreview()},260)}}catch(e){console.log("Error setting cells - "+e.message)}this.$(".row-set-form .so-button-row-set").removeClass("button-primary")},tabClickHandler:function(e){"#row-layout"===e.attr("href")?this.$(".so-panels-dialog").addClass("so-panels-dialog-has-right-sidebar"):this.$(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar")},updateModel:function(e){if(e=_.extend({refresh:!0,refreshArgs:null},e),_.isEmpty(this.model)||(this.model.setCells(this.row.cells),this.model.set("ratio",this.row.ratio),this.model.set("ratio_direction",this.row.ratio_direction)),!_.isUndefined(this.styles)&&this.styles.stylesLoaded){var t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles.so-row-styles").style}catch(e){console.log("Error retrieving row styles - "+e.message)}this.model.set("style",t)}if(!_.isUndefined(this.cellStyles)&&this.cellStyles.stylesLoaded){var t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles.so-cell-styles").style}catch(e){console.log("Error retrieving cell styles - "+e.message)}this.cellStyles.model.set("style",t)}e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},insertHandler:function(){this.builder.addHistoryEntry("row_added"),this.updateModel();var e=this.builder.getActiveCell({createCell:!1}),t={};return null!==e&&(t.at=this.builder.model.get("rows").indexOf(e.row)+1),this.model.collection=this.builder.model.get("rows"),this.builder.model.get("rows").add(this.model,t),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},saveHandler:function(){return this.builder.addHistoryEntry("row_edited"),this.updateModel(),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},deleteHandler:function(){return this.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.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.closeDialog({silent:!0}),!1},closeHandler:function(){this.clearCellStylesCache(),_.isUndefined(this.cellStyles)||(this.cellStyles=void 0)}})},{}],9:[function(e,t,i){var s=window.panels,l=jQuery,o=e("../view/widgets/js-widget");t.exports=s.view.dialog.extend({builder:null,sidebarWidgetTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-widget-sidebar-widget").html())),dialogClass:"so-panels-dialog-edit-widget",dialogIcon:"add-widget",widgetView:!1,savingWidget:!1,editableLabel:!0,events:{"click .so-close":"saveHandler","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler"},initializeDialog:function(){var e=this;this.model.on("change:values",this.handleChangeValues,this),this.model.on("destroy",this.remove,this),this.dialogFormsLoaded=0,this.on("form_loaded styles_loaded",function(){2===++this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})}),this.on("edit_label",function(e){e===panelsOptions.widgets[this.model.get("class")].title&&(e=""),this.model.set("label",e),_.isEmpty(e)&&this.$(".so-title").text(this.model.getWidgetField("title"))}.bind(this))},render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-widget").html(),{})),this.loadForm();var e=this.model.getWidgetField("title");this.$(".so-title .widget-name").html(e),this.$(".so-edit-title").val(e),this.builder.supports("addWidget")||this.$(".so-buttons .so-duplicate").remove(),this.builder.supports("deleteWidget")||this.$(".so-buttons .so-delete").remove(),this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("widget",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this});var t=this.$(".so-sidebar.so-right-sidebar");this.styles.attach(t),this.styles.on("styles_loaded",function(e){e?t.removeClass("so-panels-loading"):(t.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),t.remove())},this),t.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;do{if(widgetView=e.eq(--t).data("view"),!_.isUndefined(widgetView)&&!widgetView.model.get("read_only"))return widgetView.getEditDialog()}while(!_.isUndefined(widgetView)&&t>0);return!1},getNextDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t,i=e.index(this.widgetView.$el);if(i===e.length-1)return!1;do{if(t=e.eq(++i).data("view"),!_.isUndefined(t)&&!t.model.get("read_only"))return t.getEditDialog()}while(!_.isUndefined(t));return!1},loadForm:function(){if(this.$("> *").length){this.$(".so-content").addClass("so-panels-loading");var e={action:"so_panels_widget_form",widget:this.model.get("class"),instance:JSON.stringify(this.model.get("values")),raw:this.model.get("raw")};l.post(panelsOptions.ajaxurl,e,function(e){var t=e.replace(/{\$id}/g,this.model.cid),i=this.$(".so-content");i.removeClass("so-panels-loading").html(t),this.trigger("form_loaded",this),this.$(".panel-dialog").trigger("panelsopen"),this.on("close_dialog",this.updateModel,this),i.find("> .widget-content").length>0&&o.addWidget(i,this.model.widget_id)}.bind(this),"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(e){}this.model.set("style",i)}this.savingWidget=!1,e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},handleChangeValues:function(){this.savingWidget||this.loadForm()},saveHandler:function(){this.builder.addHistoryEntry("widget_edited"),this.closeDialog()},deleteHandler:function(){return this.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}})},{"../view/widgets/js-widget":31}],10:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({builder:null,widgetTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-widgets-widget").html())),filter:{},dialogClass:"so-panels-dialog-add-widget",dialogIcon:"add-widget",events:{"click .so-close":"closeDialog","click .widget-type":"widgetClickHandler","keyup .so-sidebar-search":"searchHandler"},initializeDialog:function(){this.on("open_dialog",function(){this.filter.search="",this.filterWidgets(this.filter)},this),this.on("open_dialog_complete",function(){this.$(".so-sidebar-search").val("").focus(),this.balanceWidgetHeights()}),this.on("tab_click",this.tabClickHandler,this)},render:function(){this.renderDialog(this.parseDialogContent(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){if(13===e.which){var t=this.$(".widget-type-list .widget-type:visible");1===t.length&&t.click()}else this.filter.search=l(e.target).val().trim(),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)||null!==o&&!_.isEmpty(_.intersection(e.groups,panelsOptions.widgets[s].groups)),t&&(_.isUndefined(e.search)||""===e.search||-1===o.title.toLowerCase().indexOf(e.search.toLowerCase())&&(t=!1)),t?i.show():i.hide()}),this.balanceWidgetHeights()},
2
- 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.get("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){t.exports={canCopyPaste:function(){return"undefined"!=typeof Storage&&panelsOptions.user},setModel:function(e){if(!this.canCopyPaste())return!1;var t=panels.helpers.serialize.serialize(e);return e instanceof panels.model.row?t.thingType="row-model":e instanceof panels.model.widget&&(t.thingType="widget-model"),localStorage["panels_clipboard_"+panelsOptions.user]=JSON.stringify(t),!0},isModel:function(e){if(!this.canCopyPaste())return!1;var t=localStorage["panels_clipboard_"+panelsOptions.user];return void 0!==t&&(t=JSON.parse(t),t.thingType&&t.thingType===e)},getModel:function(e){if(!this.canCopyPaste())return null;var t=localStorage["panels_clipboard_"+panelsOptions.user];return void 0!==t&&(t=JSON.parse(t),t.thingType&&t.thingType===e)?panels.helpers.serialize.unserialize(t,t.thingType,null):null}}},{}],12:[function(e,t,i){t.exports={lock:function(){if("hidden"!==jQuery("body").css("overflow")){var e=[self.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft,self.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop];jQuery("body").data({"scroll-position":e}).css("overflow","hidden"),_.isUndefined(e)||window.scrollTo(e[0],e[1])}},unlock:function(){if("hidden"===jQuery("body").css("overflow")&&!jQuery(".so-panels-dialog-wrapper").is(":visible")&&!jQuery(".so-panels-live-editor").is(":visible")){jQuery("body").css("overflow","visible");var e=jQuery("body").data("scroll-position");_.isUndefined(e)||window.scrollTo(e[0],e[1])}}}},{}],13:[function(e,t,i){t.exports={serialize:function(e){var t;if(e instanceof Backbone.Model){var i={};for(var s in e.attributes)if(e.attributes.hasOwnProperty(s)){if("builder"===s||"collection"===s)continue;t=e.attributes[s],t instanceof Backbone.Model||t instanceof Backbone.Collection?i[s]=this.serialize(t):i[s]=t}return i}if(e instanceof Backbone.Collection){for(var l=[],o=0;o<e.models.length;o++)t=e.models[o],t instanceof Backbone.Model||t instanceof Backbone.Collection?l.push(this.serialize(t)):l.push(t);return l}},unserialize:function(e,t,i){var s;switch(t){case"row-model":s=new panels.model.row,s.builder=i,s.set("style",e.style),s.setCells(this.unserialize(e.cells,"cell-collection",s));break;case"cell-model":s=new panels.model.cell,s.row=i,s.set("weight",e.weight),s.set("style",e.style),s.set("widgets",this.unserialize(e.widgets,"widget-collection",s));break;case"widget-model":s=new panels.model.widget,s.cell=i;for(var l in e)e.hasOwnProperty(l)&&s.set(l,e[l]);s.set("widget_id",panels.helpers.utils.generateUUID());break;case"cell-collection":s=new panels.collection.cells;for(var o=0;o<e.length;o++)s.push(this.unserialize(e[o],"cell-model",i));break;case"widget-collection":s=new panels.collection.widgets;for(var o=0;o<e.length;o++)s.push(this.unserialize(e[o],"widget-model",i));break;default:console.log("Unknown Thing - "+t)}return s}}},{}],14:[function(e,t,i){t.exports={generateUUID:function(){var e=(new Date).getTime();return window.performance&&"function"==typeof window.performance.now&&(e+=performance.now()),"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){var i=(e+16*Math.random())%16|0;return e=Math.floor(e/16),("x"==t?i:3&i|8).toString(16)})},processTemplate:function(e){return _.isUndefined(e)||_.isNull(e)?"":(e=e.replace(/{{%/g,"<%"),e=e.replace(/%}}/g,"%>"),e=e.trim())},selectElementContents:function(e){var t=document.createRange();t.selectNodeContents(e);var i=window.getSelection();i.removeAllRanges(),i.addRange(t)}}},{}],15:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=function(e){return this.each(function(){var t=jQuery(this),i=t.closest("form").find(".widget-id").val(),o=l.extend(!0,{},e);if(_.isUndefined(i)||!(i.indexOf("__i__")>-1)){var n=new s.model.builder,a=new s.view.builder({model:n,config:o}),r=t.closest(".so-panels-dialog-wrapper").data("view");_.isUndefined(r)||(r.on("close_dialog",function(){n.refreshPanelsData()}),r.on("open_dialog_complete",function(){a.trigger("builder_resize")}),r.model.on("destroy",function(){n.emptyRows().destroy()}),a.setDialogParents(panelsOptions.loc.layout_widget,r));var d=Boolean(t.closest(".widget-content").length);a.render().attach({container:t,dialog:d||"dialog"===t.data("mode"),type:t.data("type")}).setDataField(t.find("input.panels-data")),d||"dialog"===t.data("mode")?(a.setDialogParents(panelsOptions.loc.layout_widget,a.dialog),t.find(".siteorigin-panels-display-builder").click(function(e){e.preventDefault(),a.dialog.openDialog()})):t.find(".siteorigin-panels-display-builder").parent().remove(),l(document).trigger("panels_setup",a)}})}},{}],16:[function(e,t,i){var s={};window.panels=s,window.siteoriginPanels=s,s.helpers={},s.helpers.clipboard=e("./helpers/clipboard"),s.helpers.utils=e("./helpers/utils"),s.helpers.serialize=e("./helpers/serialize"),s.helpers.pageScroll=e("./helpers/page-scroll"),s.model={},s.model.widget=e("./model/widget"),s.model.cell=e("./model/cell"),s.model.row=e("./model/row"),s.model.builder=e("./model/builder"),s.model.historyEntry=e("./model/history-entry"),s.collection={},s.collection.widgets=e("./collection/widgets"),s.collection.cells=e("./collection/cells"),s.collection.rows=e("./collection/rows"),s.collection.historyEntries=e("./collection/history-entries"),s.view={},s.view.widget=e("./view/widget"),s.view.cell=e("./view/cell"),s.view.row=e("./view/row"),s.view.builder=e("./view/builder"),s.view.dialog=e("./view/dialog"),s.view.styles=e("./view/styles"),s.view.liveEditor=e("./view/live-editor"),s.dialog={},s.dialog.builder=e("./dialog/builder"),s.dialog.widgets=e("./dialog/widgets"),s.dialog.widget=e("./dialog/widget"),s.dialog.prebuilt=e("./dialog/prebuilt"),s.dialog.row=e("./dialog/row"),s.dialog.history=e("./dialog/history"),s.utils={},s.utils.menu=e("./utils/menu"),jQuery.fn.soPanelsSetupBuilderWidget=e("./jquery/setup-builder-widget"),jQuery(function(e){var t,i,s,l,o=e("#siteorigin-panels-metabox");if(s=e("form#post"),o.length&&s.length)t=o,i=o.find(".siteorigin-panels-data-field"),l={editorType:"tinyMCE",postId:e("#post_ID").val(),editorId:"#content",builderType:o.data("builder-type"),builderSupports:o.data("builder-supports"),loadOnAttach:panelsOptions.loadOnAttach&&1==e("#auto_draft").val(),loadLiveEditor:1==o.data("live-editor"),liveEditorPreview:t.data("preview-url")};else if(e(".siteorigin-panels-builder-form").length){var n=e(".siteorigin-panels-builder-form");t=n.find(".siteorigin-panels-builder-container"),i=n.find('input[name="panels_data"]'),s=n,l={editorType:"standalone",postId:n.data("post-id"),editorId:"#post_content",builderType:n.data("type"),builderSupports:n.data("builder-supports"),loadLiveEditor:!1,liveEditorPreview:n.data("preview-url")}}if(!_.isUndefined(t)){var a=window.siteoriginPanels,r=new a.model.builder,d=new a.view.builder({model:r,config:l});d.render().attach({container:t}).setDataField(i).attachToEditor(),s.submit(function(){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,"./helpers/clipboard":11,"./helpers/page-scroll":12,"./helpers/serialize":13,"./helpers/utils":14,"./jquery/setup-builder-widget":15,"./model/builder":17,"./model/cell":18,"./model/history-entry":19,"./model/row":20,"./model/widget":21,"./utils/menu":22,"./view/builder":23,"./view/cell":24,"./view/dialog":25,"./view/live-editor":26,"./view/row":27,"./view/styles":28,"./view/widget":29}],17:[function(e,t,i){t.exports=Backbone.Model.extend({layoutPosition:{BEFORE:"before",AFTER:"after",REPLACE:"replace"},rows:{},defaults:{data:{widgets:[],grids:[],grid_cells:[]}},initialize:function(){this.set("rows",new panels.collection.rows)},addRow:function(e,t,i){i=_.extend({noAnimate:!1},i);var s=new panels.collection.cells(t);e=_.extend({collection:this.get("rows"),cells:s},e);var l=new panels.model.row(e);return l.builder=this,this.get("rows").add(l,i),l},loadPanelsData:function(e,t){try{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(e.grid_cells[l]);var o=this;if(_.each(i,function(t,i){var s={};_.isUndefined(e.grids[i].style)||(s.style=e.grids[i].style),_.isUndefined(e.grids[i].ratio)||(s.ratio=e.grids[i].ratio),_.isUndefined(e.grids[i].ratio_direction)||(s.ratio_direction=e.grids[i].ratio_direction),_.isUndefined(e.grids[i].color_label)||(s.color_label=e.grids[i].color_label),_.isUndefined(e.grids[i].label)||(s.label=e.grids[i].label),o.addRow(s,t,{noAnimate:!0})}),_.isUndefined(e.widgets))return;_.each(e.widgets,function(e){var t=null;_.isUndefined(e.panels_info)?(t=e.info,delete e.info):(t=e.panels_info,delete e.panels_info);var i=o.get("rows").at(parseInt(t.grid)),s=i.get("cells").at(parseInt(t.cell)),l=new panels.model.widget({class:t.class,values:e});_.isUndefined(t.style)||l.set("style",t.style),_.isUndefined(t.read_only)||l.set("read_only",t.read_only),_.isUndefined(t.widget_id)?l.set("widget_id",panels.helpers.utils.generateUUID()):l.set("widget_id",t.widget_id),_.isUndefined(t.label)||l.set("label",t.label),l.cell=s,s.get("widgets").add(l,{noAnimate:!0})}),this.trigger("load_panels_data")}catch(e){console.log("Error loading data: "+e.message)}},concatPanelsData:function(e,t){if(_.isUndefined(t)||_.isUndefined(t.grids)||_.isEmpty(t.grids)||_.isUndefined(t.grid_cells)||_.isEmpty(t.grid_cells))return e;if(_.isUndefined(e)||_.isUndefined(e.grids)||_.isEmpty(e.grids))return t;var i=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.get("rows").each(function(i,s){i.get("cells").each(function(i,l){i.get("widgets").each(function(i,o){var n={class:i.get("class"),raw:i.get("raw"),grid:s,cell:l,id:t++,widget_id:i.get("widget_id"),style:i.get("style"),label:i.get("label")};_.isEmpty(n.widget_id)&&(n.widget_id=panels.helpers.utils.generateUUID());var a=_.extend(_.clone(i.get("values")),{panels_info:n});e.widgets.push(a)}),e.grid_cells.push({grid:s,index:l,weight:i.get("weight"),style:i.get("style")})}),e.grids.push({cells:i.get("cells").length,style:i.get("style"),ratio:i.get("ratio"),ratio_direction:i.get("ratio_direction"),color_label:i.get("color_label"),label:i.get("label")})}),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.get("rows").toArray(),"destroy"),this.get("rows").reset(),this},isValidLayoutPosition:function(e){return e===this.layoutPosition.BEFORE||e===this.layoutPosition.AFTER||e===this.layoutPosition.REPLACE},getPanelsDataFromHtml:function(e,t){var i=this,s=jQuery('<div id="wrapper">'+e+"</div>");if(s.find(".panel-layout .panel-grid").length){var l={grids:[],grid_cells:[],widgets:[]},o=new RegExp(panelsOptions.siteoriginWidgetRegex,"i"),n=function(){function e(e){return e&&"string"==typeof e&&(e=e.replace(/<script[^>]*>([\S\s]*?)<\/script>/gim,""),e=e.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gim,""),t.innerHTML=e,e=t.textContent,t.textContent=""),e}var t=document.createElement("div");return e}(),a=function(e){var t=e.find("div");if(!t.length)return e.html();var i;for(i=0;i<t.length-1&&jQuery.trim(t.eq(i).text())==jQuery.trim(t.eq(i+1).text());i++);var s=t.eq(i).find(".widget-title:header"),l="";return s.length&&(l=s.html(),s.remove()),{title:l,text:t.eq(i).html()}},r=s.find(".panel-layout").eq(0),d=function(e,t){return jQuery(t).closest(".panel-layout").is(r)};return s.find("> .panel-layout > .panel-grid").filter(d).each(function(e,s){var r=jQuery(s),c=r.find(".panel-grid-cell").filter(d);l.grids.push({cells:c.length,style:r.data("style"),ratio:r.data("ratio"),ratio_direction:r.data("ratio-direction"),color_label:r.data("color-label"),label:r.data("label")}),c.each(function(s,r){var c=jQuery(r),h=c.find(".so-panel").filter(d);l.grid_cells.push({grid:e,weight:_.isUndefined(c.data("weight"))?1:parseFloat(c.data("weight")),style:c.data("style")}),h.each(function(r,d){var c=jQuery(d),h=c.find(".panel-widget-style").length?c.find(".panel-widget-style").html():c.html(),u={grid:e,cell:s,style:c.data("style"),raw:!1,label:c.data("label")};h=h.trim();var p=o.exec(h);if(!_.isNull(p)&&""===h.replace(o,"").trim()){try{var g=/class="(.*?)"/.exec(p[3]),f=jQuery(p[5]),w=JSON.parse(n(f.val())),m=w.instance;u.class=g[1].replace(/\\\\+/g,"\\"),u.raw=!1,m.panels_info=u,l.widgets.push(m)}catch(e){u.class=t,l.widgets.push(_.extend(a(c),{filter:"1",type:"visual",panels_info:u}))}return!0}if(-1!==h.indexOf("panel-layout")){if(jQuery("<div>"+h+"</div>").find(".panel-layout .panel-grid").length)return u.class="SiteOrigin_Panels_Widgets_Layout",l.widgets.push({panels_data:i.getPanelsDataFromHtml(h,t),panels_info:u}),!0}return u.class=t,l.widgets.push(_.extend(a(c),{filter:"1",type:"visual",panels_info:u})),!0})})}),s.find(".panel-layout").remove(),s.find("style[data-panels-style-for-post]").remove(),s.html().replace(/^\s+|\s+$/gm,"").length&&(l.grids.push({cells:1,style:{}}),l.grid_cells.push({grid:l.grids.length-1,weight:1}),l.widgets.push({filter:"1",text:s.html().replace(/^\s+|\s+$/gm,""),title:"",type:"visual",panels_info:{class:t,raw:!1,grid:l.grids.length-1,cell:0}})),l}return{grid_cells:[{grid:0,weight:1}],grids:[{cells:1}],widgets:[{filter:"1",text:e,title:"",type:"visual",panels_info:{class:t,raw:!1,grid:0,cell:0}}]}}})},{}],18:[function(e,t,i){t.exports=Backbone.Model.extend({widgets:{},row:null,defaults:{weight:0,style:{}},indexes:null,initialize:function(){this.set("widgets",new panels.collection.widgets),this.on("destroy",this.onDestroy,this)},onDestroy:function(){_.invoke(this.get("widgets").toArray(),"destroy"),this.get("widgets").reset()},clone:function(e,t){_.isUndefined(e)&&(e=this.row),t=_.extend({cloneWidgets:!0},t);var i=new this.constructor(this.attributes);return i.set("collection",e.get("cells"),{silent:!0}),i.row=e,t.cloneWidgets&&this.get("widgets").each(function(e){i.get("widgets").add(e.clone(i,t),{silent:!0})}),i}})},{}],19:[function(e,t,i){t.exports=Backbone.Model.extend({defaults:{text:"",data:"",time:null,count:1}})},{}],20:[function(e,t,i){t.exports=Backbone.Model.extend({builder:null,defaults:{style:{}},indexes:null,initialize:function(){_.isEmpty(this.get("cells"))?this.set("cells",new panels.collection.cells):this.get("cells").each(function(e){e.row=this}.bind(this)),this.on("destroy",this.onDestroy,this)},setCells:function(e){var t=this.get("cells")||new panels.collection.cells,i=[];t.each(function(s,l){var o=e.at(l);if(o)s.set("weight",o.get("weight"));else{for(var n=t.at(e.length-1),a=s.get("widgets").models.slice(),r=0;r<a.length;r++)a[r].moveToCell(n,{silent:!1});i.push(s)}}),_.each(i,function(e){t.remove(e)}),e.length>t.length&&_.each(e.slice(t.length,e.length),function(e){e.set({collection:t}),e.row=this,t.add(e)}.bind(this)),this.reweightCells()},reweightCells:function(){var e=0,t=this.get("cells");t.each(function(t){e+=t.get("weight")}),t.each(function(t){t.set("weight",t.get("weight")/e)}),this.trigger("reweight_cells")},onDestroy:function(){_.invoke(this.get("cells").toArray(),"destroy"),this.get("cells").reset()},clone:function(e){_.isUndefined(e)&&(e=this.builder);var t=new this.constructor(this.attributes);t.set("collection",e.get("rows"),{silent:!0}),t.builder=e;var i=new panels.collection.cells;return this.get("cells").each(function(e){i.add(e.clone(t),{silent:!0})}),t.set("cells",i),t}})},{}],21:[function(e,t,i){t.exports=Backbone.Model.extend({cell:null,defaults:{class:null,missing:!1,values:{},raw:!1,style:{},read_only:!1,widget_id:""},indexes:null,initialize:function(){var e=this.get("class");!_.isUndefined(panelsOptions.widgets[e])&&panelsOptions.widgets[e].installed||this.set("missing",!0)},getWidgetField:function(e){return _.isUndefined(panelsOptions.widgets[this.get("class")])?"title"===e||"description"===e?panelsOptions.loc.missing_widget[e]:"":this.has("label")&&!_.isEmpty(this.get("label"))?this.get("label"):panelsOptions.widgets[this.get("class")][e]},moveToCell:function(e,t,i){return t=_.extend({silent:!0},t),this.cell=e,this.collection.remove(this,t),e.get("widgets").add(this,_.extend({at:i},t)),this.trigger("move_to_cell",e,i),this},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("widget_id",""),i.set("values",s,{silent:!0}),i.set("collection",e.get("widgets"),{silent:!0}),i.cell=e,i.isDuplicate=!0,i},getTitle:function(){var e=panelsOptions.widgets[this.get("class")];if(_.isUndefined(e))return this.get("class").replace(/_/g," ");if(!_.isUndefined(e.panels_title)&&!1===e.panels_title)return panelsOptions.widgets[this.get("class")].description;var t=this.get("values"),i=["title","text"];for(var s in t)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")}})},{}],22:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({wrapperTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-context-menu").html())),sectionTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-context-menu-section").html())),contexts:[],active:!1,events:{"keyup .so-search-wrapper input":"searchKeyUp"},initialize:function(){this.listenContextMenu(),this.render(),this.attach()},listenContextMenu:function(){var e=this;l(window).on("contextmenu",function(t){return e.active&&!e.isOverEl(e.$el,t)?(e.closeMenu(),e.active=!1,t.preventDefault(),!1):!!e.active||(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"),l(window).on("keyup",{menu:this},this.keyboardListen),l(window).on("click",{menu:this},this.clickOutsideListen),this.$el.css("max-height",l(window).height()-20),e.left+this.$el.outerWidth()+10>=l(window).width()&&(e.left=l(window).width()-this.$el.outerWidth()-10),e.left<=0&&(e.left=10),e.top+this.$el.outerHeight()-l(window).scrollTop()+10>=l(window).height()&&(e.top=l(window).height()+l(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"),l(window).off("keyup",this.keyboardListen),l(window).off("click",this.clickOutsideListen),this.active=!1,this.$el.empty().hide()},keyboardListen:function(e){var t=e.data.menu;switch(e.which){case 27:t.closeMenu()}},clickOutsideListen:function(e){var t=e.data.menu;3!==e.which&&t.$el.is(":visible")&&!t.isOverEl(t.$el,e)&&t.closeMenu()},addSection:function(e,t,i,s){var o=this;t=_.extend({display:5,defaultDisplay:!1,search:!0,sectionTitle:"",searchPlaceholder:"",titleKey:"title"},t);var n=l(this.sectionTemplate({settings:t,items:i})).attr("id","panels-menu-section-"+e);this.$el.append(n),n.find(".so-item:not(.so-confirm)").click(function(){var e=l(this);s(e.data("key")),o.closeMenu()}),n.find(".so-item.so-confirm").click(function(){var e=l(this);if(e.hasClass("so-confirming"))return s(e.data("key")),void o.closeMenu();e.data("original-text",e.html()).addClass("so-confirming").html('<span class="dashicons dashicons-yes"></span> '+panelsOptions.loc.dropdown_confirm),setTimeout(function(){e.removeClass("so-confirming"),e.html(e.data("original-text"))},2500)}),n.data("settings",t).find(".so-search-wrapper input").trigger("keyup"),this.active=!0},hasSection:function(e){return this.$el.find("#panels-menu-section-"+e).length>0},searchKeyUp:function(e){var t=l(e.currentTarget),i=t.closest(".so-section"),s=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=a-1<0?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(s.defaultDisplay){i.find(".so-item").hide();for(var r=0;r<s.defaultDisplay.length;r++)i.find('.so-item[data-key="'+s.defaultDisplay[r]+'"]').show()}else i.find(".so-item").show();else i.find(".so-item").hide().each(function(){var e=l(this);-1!==e.html().toLowerCase().indexOf(t.val().toLowerCase())&&e.show()});i.find(".so-item:visible:gt("+(s.display-1)+")").hide(),0===i.find(".so-item:visible").length&&""!==t.val()?i.find(".so-no-results").show():i.find(".so-no-results").hide()},isOverEl:function(e,t){var i=[[e.offset().left,e.offset().top],[e.offset().left+e.outerWidth(),e.offset().top+e.outerHeight()]];return t.pageX>=i[0][0]&&t.pageX<=i[1][0]&&t.pageY>=i[0][1]&&t.pageY<=i[1][1]}})},{}],23:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({config:{},template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder").html())),dialogs:{},rowsSortable:null,dataField:!1,currentData:"",attachedToEditor:!1,attachedVisible:!1,liveEditor:void 0,menu:!1,activeCell:null,events:{"click .so-tool-button.so-widget-add":"displayAddWidgetDialog","click .so-tool-button.so-row-add":"displayAddRowDialog","click .so-tool-button.so-prebuilt-add":"displayAddPrebuiltDialog","click .so-tool-button.so-history":"displayHistoryDialog","click .so-tool-button.so-live-editor":"displayLiveEditor"},rows:null,initialize:function(e){var t=this;return this.config=_.extend({loadLiveEditor:!1,builderSupports:{}},e.config),this.config.builderSupports=_.extend({addRow:!0,editRow:!0,deleteRow:!0,moveRow:!0,addWidget:!0,editWidget:!0,deleteWidget:!0,moveWidget:!0,prebuilt:!0,history:!0,liveEditor:!0,revertToEditor:!0},this.config.builderSupports),e.config.loadLiveEditor&&this.on("builder_live_editor_added",function(){this.displayLiveEditor()}),this.dialogs={widgets:new 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.get("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("hide_builder",this.handleHideBuilder,this),this.on("builder_rendered builder_resize",this.handleBuilderSizing,this),this.model.on("change:data load_panels_data",this.toggleWelcomeDisplay,this),this.on("display_builder",this.wrapEditorExpandAdjust,this),this.menu=new s.utils.menu({}),this.menu.on("activate_context",this.activateContextMenu,this),this.config.loadOnAttach&&this.on("builder_attached_to_editor",function(){this.displayAttachedBuilder({confirm:!1})},this),this},render:function(){return this.setElement(this.template()),this.$el.attr("id","siteorigin-panels-builder-"+this.cid).addClass("so-builder-container"),this.trigger("builder_rendered"),this},attach:function(e){e=_.extend({container:!1,dialog:!1},e),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.trigger("builder_attached"),this.supports("liveEditor")&&this.addLiveEditor(),this.supports("history")&&this.addHistoryBrowser();var t=this.$(".so-builder-toolbar"),i=this.$(".so-panels-welcome-message"),l=panelsOptions.loc.welcomeMessage,o=[];this.supports("addWidget")?o.push(l.addWidgetButton):t.find(".so-widget-add").hide(),this.supports("addRow")?o.push(l.addRowButton):t.find(".so-row-add").hide(),this.supports("prebuilt")?o.push(l.addPrebuiltButton):t.find(".so-prebuilt-add").hide();var n="";3===o.length?n=l.threeEnabled:2===o.length?n=l.twoEnabled:1===o.length?n=l.oneEnabled:0===o.length&&(n=l.addingDisabled);var a=_.template(s.helpers.utils.processTemplate(n)),r=a({items:o})+" "+l.docsMessage;return i.find(".so-message-wrapper").html(r),this},attachToEditor:function(){if("tinyMCE"!==this.config.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").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(e){t.displayAttachedBuilder({confirm:!0})&&e.preventDefault()})),this.supports("revertToEditor")&&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").show(),e.hide(),l(window).resize(),t.attachedVisible=!1,t.trigger("hide_builder"))}).show(),e.insertAfter("#wp-content-wrap").hide().addClass("attached-to-editor");var i=this.model.get("data");_.isEmpty(i.widgets)&&_.isEmpty(i.grids)&&this.supports("revertToEditor")||this.displayAttachedBuilder({confirm:!1});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.trigger("builder_attached_to_editor"),this},displayAttachedBuilder:function(e){if(e=_.extend({confirm:!0},e),e.confirm){var t="undefined"!=typeof tinyMCE&&tinyMCE.get("content");if(""!==(t&&_.isFunction(t.getContent)?t.getContent():l("textarea#content").val())&&!confirm(panelsOptions.loc.confirm_use_builder))return!1}return l("#wp-content-wrap").hide(),l("#editor-expand-toggle").on("change.editor-expand",function(){l(this).prop("checked")||l("#wp-content-wrap").hide()}),this.metabox.show().find("> .inside").show(),l(window).resize(),l(document).scroll(),this.attachedVisible=!0,this.trigger("display_builder"),!0},initSortable:function(){if(!this.supports("moveRow"))return this;var e=this;return 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,i){e.addHistoryEntry("row_moved");var s=l(i.item),o=s.data("view");e.model.get("rows").remove(o.model,{silent:!0}),e.model.get("rows").add(o.model,{silent:!0,at:s.index()}),o.trigger("move",s.index()),e.model.refreshPanelsData()}}),this},refreshSortable:function(){_.isNull(this.rowsSortable)||this.rowsSortable.sortable("refresh")},setDataField:function(e,t){if(t=_.extend({load:!0},t),this.dataField=e,this.dataField.data("builder",this),t.load&&""!==e.val()){var i=this.dataField.val();try{i=JSON.parse(i)}catch(e){i={}}this.model.loadPanelsData(i),this.currentData=i,this.toggleWelcomeDisplay()}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)),!1===i.noAnimate&&l.visualCreate(),this.refreshSortable(),l.resize()},displayAddWidgetDialog:function(){this.dialogs.widgets.openDialog()},displayAddRowDialog:function(){var e=new s.model.row,t=new s.collection.cells([{weight:.5},{weight:.5}]);t.each(function(t){t.row=e}),e.set("cells",t),e.builder=this.model,this.dialogs.row.setRowModel(e),this.dialogs.row.openDialog()},displayAddPrebuiltDialog:function(){this.dialogs.prebuilt.openDialog()},displayHistoryDialog:function(){this.dialogs.history.openDialog()},pasteRowHandler:function(){var e=s.helpers.clipboard.getModel("row-model");!_.isEmpty(e)&&e instanceof s.model.row&&(this.addHistoryEntry("row_pasted"),e.builder=this.model,this.model.get("rows").add(e,{at:this.model.get("rows").indexOf(this.model)+1}),this.model.refreshPanelsData())},getActiveCell:function(e){if(e=_.extend({createCell:!0},e),
3
- !this.model.get("rows").length){if(!e.createCell)return null;this.model.addRow({},[{weight:1}],{noAnimate:!0})}var t=this.activeCell;return _.isEmpty(t)||-1===this.model.get("rows").indexOf(t.model.row)?this.model.get("rows").last().get("cells").first():t.model},addLiveEditor:function(){return _.isEmpty(this.config.liveEditorPreview)?this:(this.liveEditor=new s.view.liveEditor({builder:this,previewUrl:this.config.liveEditorPreview}),this.liveEditor.hasPreviewUrl()&&this.$(".so-builder-toolbar .so-live-editor").show(),this.trigger("builder_live_editor_added"),this)},displayLiveEditor:function(){_.isUndefined(this.liveEditor)||this.liveEditor.open()},addHistoryBrowser:function(){if(_.isEmpty(this.config.liveEditorPreview))return this;this.dialogs.history=new 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)},supports:function(e){return"rowAction"===e?this.supports("addRow")||this.supports("editRow")||this.supports("deleteRow"):"widgetAction"===e?this.supports("addWidget")||this.supports("editWidget")||this.supports("deleteWidget"):!_.isUndefined(this.config.builderSupports[e])&&this.config.builderSupports[e]},handleContentChange:function(){if(panelsOptions.copy_content&&this.attachedToEditor&&this.$el.is(":visible")){var e=this.model.getPanelsData();_.isEmpty(e.widgets)||l.post(panelsOptions.ajaxurl,{action:"so_panels_builder_content",panels_data:JSON.stringify(e),post_id:this.config.postId},function(e){""!==e&&this.updateEditorContent(e)}.bind(this))}},updateEditorContent:function(e){if("tinyMCE"!==this.config.editorType||"undefined"==typeof tinyMCE||_.isNull(tinyMCE.get("content"))){l(this.config.editorId).val(e).trigger("change").trigger("keyup")}else{var t=tinyMCE.get("content");t.setContent(e),t.fire("change"),t.fire("keyup")}this.triggerYoastSeoChange()},triggerYoastSeoChange:function(){if(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="undefined"!=typeof tinyMCE&&tinyMCE.get("content"),t=e&&_.isFunction(e.getContent)?e.getContent():l("textarea#content").val();if((_.isEmpty(this.model.get("data"))||_.isEmpty(this.model.get("data").widgets)&&_.isEmpty(this.model.get("data").grids))&&""!==t){var i=panelsOptions.text_widget;if(_.isEmpty(i))return;this.model.loadPanelsData(this.model.getPanelsDataFromHtml(t,i)),this.model.trigger("change"),this.model.trigger("change:data")}l("#post-status-info").addClass("for-siteorigin-panels")},handleHideBuilder:function(){l("#post-status-info").show().removeClass("for-siteorigin-panels")},wrapEditorExpandAdjust:function(){try{for(var e,t=(l.hasData(window)&&l._data(window)).events.scroll,i=0;i<t.length;i++)if("editor-expand"===t[i].namespace){e=t[i],l(window).unbind("scroll",e.handler),l(window).bind("scroll",function(t){this.attachedVisible||e.handler(t)}.bind(this));break}}catch(e){return}},handleBuilderSizing:function(){var e=this.$el.width();return e?(e<480?this.$el.addClass("so-display-narrow"):this.$el.removeClass("so-display-narrow"),this):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.get("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(),o=l(".so-panels-dialog-wrapper:visible").sort(function(e,t){return l(e).zIndex()>l(t).zIndex()?1:-1}).last(),n=i.$el.closest(".so-panels-dialog-wrapper");if(i.$el.is(s)&&(0===o.length||o.is(n))){var a=l([]).add(i.$(".so-panels-welcome-message:visible")).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)}),r=a.last().data("view");void 0!==r&&void 0!==r.buildContextualMenu?r.buildContextualMenu(e,t):a.last().hasClass("so-panels-welcome-message")&&this.buildContextualMenu(e,t)}},buildContextualMenu:function(e,t){var i={};this.supports("addRow")&&(i.add_row={title:panelsOptions.loc.contextual.add_row}),s.helpers.clipboard.canCopyPaste()&&s.helpers.clipboard.isModel("row-model")&&this.supports("addRow")&&(i.paste_row={title:panelsOptions.loc.contextual.row_paste}),_.isEmpty(i)||t.addSection("builder-actions",{sectionTitle:panelsOptions.loc.contextual.row_actions,search:!1},i,function(e){switch(e){case"add_row":this.displayAddRowDialog();break;case"paste_row":this.pasteRowHandler()}}.bind(this))}})},{}],24:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-cell").html())),events:{"click .cell-wrapper":"handleCellClick"},row:null,widgetSortable:null,initialize:function(){this.model.get("widgets").on("add",this.onAddWidget,this)},render:function(){var e={weight:this.model.get("weight"),totalWeight:this.row.model.get("cells").totalWeight()};this.setElement(this.template(e)),this.$el.data("view",this);var t=this;return this.model.get("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(){if(!this.row.builder.supports("moveWidget"))return this;var e=this,t=e.row.builder.$el.attr("id");return 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),o=s.data("view"),n=s.closest(".cell").data("view");o.model.moveToCell(n.model,{},s.index()),o.cell=n,o.cell.row.builder.model.refreshPanelsData()},helper:function(e,t){var i=t.clone().css({width:t.outerWidth(),"z-index":1e4,position:"fixed"}).addClass("widget-being-dragged").appendTo("body");return t.outerWidth()>720&&i.animate({"margin-left":e.pageX-t.offset().left-240,width:480},"fast"),i}}),this},refreshSortable:function(){_.isNull(this.widgetSortable)||this.widgetSortable.sortable("refresh")},initResizable:function(){if(!this.row.builder.supports("editRow"))return this;var e,t=this.$(".resize-handle").css("position","absolute"),i=this.row.$el,s=this;return 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()}}),this},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)),!1===i.noAnimate&&l.visualCreate(),this.refreshSortable(),this.row.resize()},handleCellClick:function(e){this.row.builder.$el.find(".so-cells .cell").removeClass("cell-selected"),this.row.builder.activeCell!==this||this.model.get("widgets").length?(this.$el.addClass("cell-selected"),this.row.builder.activeCell=this):this.row.builder.activeCell=null},pasteHandler:function(){var e=s.helpers.clipboard.getModel("widget-model");!_.isEmpty(e)&&e instanceof s.model.widget&&(this.row.builder.addHistoryEntry("widget_pasted"),e.cell=this.model,this.model.get("widgets").add(e),this.row.builder.model.refreshPanelsData())},buildContextualMenu:function(e,t){var i=this;t.hasSection("add-widget-below")||t.addSection("add-widget-cell",{sectionTitle:panelsOptions.loc.contextual.add_widget_cell,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){i.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({class:e});t.cell=i.model,t.cell.get("widgets").add(t),i.row.builder.model.refreshPanelsData()});var l={};this.row.builder.supports("addWidget")&&s.helpers.clipboard.isModel("widget-model")&&(l.paste={title:panelsOptions.loc.contextual.cell_paste_widget}),_.isEmpty(l)||t.addSection("cell-actions",{sectionTitle:panelsOptions.loc.contextual.cell_actions,search:!1},l,function(e){switch(e){case"paste":this.pasteHandler()}this.row.builder.model.refreshPanelsData()}.bind(this)),this.row.buildContextualMenu(e,t)}})},{}],25:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({dialogTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog").html())),dialogTabTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-tab").html())),tabbed:!1,rendered:!1,builder:!1,className:"so-panels-dialog-wrapper",dialogClass:"",dialogIcon:"",parentDialog:!1,dialogOpen:!1,editableLabel:!1,events:{"click .so-close":"closeDialog","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext"},initialize:function(){this.once("open_dialog",this.render),this.once("open_dialog",this.attach),this.once("open_dialog",this.setDialogClass),this.trigger("initialize_dialog",this),_.isUndefined(this.initializeDialog)||this.initializeDialog()},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=l(_.template(s.helpers.utils.processTemplate(e))(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(e=_.extend({editableLabel:this.editableLabel,dialogIcon:this.dialogIcon},e),this.$el.html(this.dialogTemplate(e)).hide(),this.$el.data("view",this),this.$el.addClass("so-panels-dialog-wrapper"),!1!==this.parentDialog){var t=this,i=l('<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.$(".so-title-bar .so-title-editable").length&&this.initEditableLabel(),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=l(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 o=s.split("#")[1];t.$(".so-content .so-content-tabs .tab-"+o).show()}t.trigger("tab_click",i)}),this.$(".so-sidebar-tabs li a").first().click(),this},initToolbar:function(){this.$(".so-toolbar .so-buttons .so-toolbar-button").click(function(e){e.preventDefault(),this.trigger("button_click",l(e.currentTarget))}.bind(this)),this.$(".so-toolbar .so-buttons .so-dropdown-button").click(function(e){e.preventDefault();var t=l(e.currentTarget),i=t.siblings(".so-dropdown-links-wrapper");i.is(".hidden")?i.removeClass("hidden"):i.addClass("hidden")}.bind(this)),l("html").click(function(e){this.$(".so-dropdown-links-wrapper").not(".hidden").each(function(t,i){var s=l(i),o=l(e.target);0!==o.length&&(o.is(".so-needs-confirm")&&!o.is(".so-confirmed")||o.is(".so-dropdown-button"))||s.addClass("hidden")})}.bind(this))},initEditableLabel:function(){var e=this.$(".so-title-bar .so-title-editable");e.keypress(function(t){var i="keypress"===t.type&&13===t.keyCode;if(i){var s=l(":tabbable"),o=s.index(e);s.eq(o+1).focus(),window.getSelection().removeAllRanges()}return!i}).blur(function(){var t=e.text().replace(/^\s+|\s+$/gm,"");t!==e.data("original-value").replace(/^\s+|\s+$/gm,"")&&(e.text(t),this.trigger("edit_label",t))}.bind(this)),e.focus(function(){e.data("original-value",e.text()),s.helpers.utils.selectElementContents(this)})},setupDialog:function(){this.openDialog(),this.closeDialog()},refreshDialogNav:function(){this.$(".so-title-bar .so-nav").show().removeClass("so-disabled");var e=this.getNextDialog(),t=this.$(".so-title-bar .so-next"),i=this.getPrevDialog(),s=this.$(".so-title-bar .so-previous");null===e?t.hide():!1===e&&t.addClass("so-disabled"),null===i?s.hide():!1===i&&s.addClass("so-disabled")},openDialog:function(e){e=_.extend({silent:!1},e),e.silent||this.trigger("open_dialog"),this.dialogOpen=!0,this.refreshDialogNav(),s.helpers.pageScroll.lock(),l(window).on("keyup",this.keyboardListen),this.$el.show(),e.silent||(this.trigger("open_dialog_complete"),this.builder.trigger("open_dialog",this),l(document).trigger("open_dialog",this))},closeDialog:function(e){e=_.extend({silent:!1},e),e.silent||this.trigger("close_dialog"),this.dialogOpen=!1,this.$el.hide(),s.helpers.pageScroll.unlock(),l(window).off("keyup",this.keyboardListen),e.silent||(this.trigger("close_dialog_complete"),this.builder.trigger("close_dialog",this))},keyboardListen:function(e){27===e.which&&l(".so-panels-dialog-wrapper .so-close").trigger("click")},navToPrevious:function(){this.closeDialog();var e=this.getPrevDialog();null!==e&&!1!==e&&e.openDialog()},navToNext:function(){this.closeDialog();var e=this.getNextDialog();null!==e&&!1!==e&&e.openDialog()},getFormValues:function(e){_.isUndefined(e)&&(e=".so-content");var t,i=this.$(e),s={};return i.find("[name]").each(function(){var e=l(this);try{var i=/([A-Za-z_]+)\[(.*)\]/.exec(e.attr("name"));if(_.isEmpty(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=s,n=null,a=!!_.isString(e.attr("type"))&&e.attr("type").toLowerCase();if("checkbox"===a)n=e.is(":checked")?""===e.val()||e.val():null;else if("radio"===a){if(!e.is(":checked"))return;n=e.val()}else if("SELECT"===e.prop("tagName")){var r=e.find("option:selected");1===r.length?n=e.find("option:selected").val():r.length>1&&(n=_.map(e.find("option:selected"),function(e,t){return l(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(e){n=""}}if(null!==n)for(var d=0;d<t.length;d++)d===t.length-1?""===t[d]?o.push(n):o[t[d]]=n:(_.isUndefined(o[t[d]])&&(""===t[d+1]?o[t[d]]=[]:o[t[d]]={}),o=o[t[d]])}catch(t){console.log("Field ["+e.attr("name")+"] could not be processed and was skipped - "+t.message)}}),s},setStatusMessage:function(e,t,i){var s=i?'<span class="dashicons dashicons-warning"></span>'+e:e;this.$(".so-toolbar .so-status").html(s),!_.isUndefined(t)&&t?this.$(".so-toolbar .so-status").addClass("so-panels-loading"):this.$(".so-toolbar .so-status").removeClass("so-panels-loading")},setParent:function(e,t){this.parentDialog={text:e,dialog:t}}})},{}],26:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-live-editor").html())),previewScrollTop:0,loadTimes:[],previewFrameId:1,previewUrl:null,previewIframe:null,events:{"click .live-editor-close":"close","click .live-editor-collapse":"collapse","click .live-editor-mode":"mobileToggle"},initialize:function(e){e=_.extend({builder:!1,previewUrl:!1},e),_.isEmpty(e.previewUrl)&&(e.previewUrl=panelsOptions.ajaxurl+"&action=so_panels_live_editor_preview"),this.builder=e.builder,this.previewUrl=e.previewUrl,this.builder.model.on("refresh_panels_data",this.handleRefreshData,this),this.builder.model.on("load_panels_data",this.handleLoadData,this)},render:function(){this.setElement(this.template()),this.$el.hide();var e=this,t=!1;return l(document).mousedown(function(){t=!0}).mouseup(function(){t=!1}),this.$el.on("mouseenter",".so-widget-wrapper",function(){var i=l(this),s=i.data("live-editor-preview-widget");t||void 0===s||!s.length||e.$(".so-preview-overlay").is(":visible")||(e.highlightElement(s),e.scrollToElement(s))}),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")},open:function(){if(""===this.$el.html()&&this.render(),0===this.$el.closest("body").length&&this.attach(),s.helpers.pageScroll.lock(),this.$el.is(":visible"))return this;if(this.$el.show(),this.refreshPreview(this.builder.model.getPanelsData()),this.originalContainer=this.builder.$el.parent(),this.builder.$el.appendTo(this.$(".so-live-editor-builder")),this.builder.$(".so-tool-button.so-live-editor").hide(),this.builder.trigger("builder_resize"),"auto-draft"===l("#original_post_status").val()&&!this.autoSaved){var e=this;wp.autosave&&(""===l('#title[name="post_title"]').val()&&l('#title[name="post_title"]').val(panelsOptions.loc.draft).trigger("keydown"),l(document).one("heartbeat-tick.autosave",function(){e.autoSaved=!0,e.refreshPreview(e.builder.model.getPanelsData())}),wp.autosave.server.triggerSave())}},close:function(){if(!this.$el.is(":visible"))return this;this.$el.hide(),s.helpers.pageScroll.unlock(),this.builder.$el.appendTo(this.originalContainer),this.builder.$(".so-tool-button.so-live-editor").show(),this.builder.trigger("builder_resize")},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),this.previewIframe.contents().find("body").find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return 0===l(this).parents(".so-panel").length}).not(e).addClass("so-panels-faded"),e.removeClass("so-panels-faded").addClass("so-panels-highlighted")},resetHighlights:function(){var e=this.previewIframe.contents().find("body");this.resetHighlightTimeout=setTimeout(function(){e.find(".panel-grid .panel-grid-cell .so-panel").removeClass("so-panels-faded so-panels-highlighted")},100)},scrollToElement:function(e){this.$(".so-preview iframe")[0].contentWindow.liveEditorScrollTo(e)},handleRefreshData:function(e,t){if(!this.$el.is(":visible"))return this;this.refreshPreview(e)},handleLoadData:function(){if(!this.$el.is(":visible"))return this;this.refreshPreview(this.builder.model.getPanelsData())},refreshPreview:function(e){var t=this.loadTimes.length?_.reduce(this.loadTimes,function(e,t){return e+t},0)/this.loadTimes.length:1e3;_.isNull(this.previewIframe)||this.$(".so-preview-overlay").is(":visible")||(this.previewScrollTop=this.previewIframe.contents().scrollTop()),this.$(".so-preview-overlay").show(),this.$(".so-preview-overlay .so-loading-bar").clearQueue().css("width","0%").animate({width:"100%"},parseInt(t)+100),this.postToIframe({live_editor_panels_data:JSON.stringify(e),live_editor_post_ID:this.builder.config.postId},this.previewUrl,this.$(".so-preview")),this.previewIframe.data("load-start",(new Date).getTime())},postToIframe:function(e,t,i){_.isNull(this.previewIframe)||this.previewIframe.remove();var s="siteorigin-panels-live-preview-"+this.previewFrameId;this.previewIframe=l('<iframe src="javascript:false;" />').attr({id:s,name:s}).appendTo(i),this.setupPreviewFrame(this.previewIframe);var o=l('<form id="soPostToPreviewFrame" method="post" />').attr({id:s,target:this.previewIframe.attr("id"),action:t}).appendTo("body");return l.each(e,function(e,t){l('<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=l(this),i=e.contents();if(!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);var s=i.find("#pl-"+t.builder.config.postId);s.find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return l(this).closest(".panel-layout").is(s)}).each(function(e,i){var s=l(i),o=t.$(".so-live-editor-builder .so-widget-wrapper").eq(s.data("index"));o.data("live-editor-preview-widget",s),s.css({cursor:"pointer"}).mouseenter(function(){o.parent().addClass("so-hovered"),t.highlightElement(s)}).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=l(this);e.data("iframeready")||e.trigger("iframeready")})},hasPreviewUrl:function(){return""!==this.$("form.live-editor-form").attr("action")},mobileToggle:function(e){var t=l(e.currentTarget);this.$(".live-editor-mode").not(t).removeClass("so-active"),t.addClass("so-active"),this.$el.removeClass("live-editor-desktop-mode live-editor-tablet-mode live-editor-mobile-mode").addClass("live-editor-"+t.data("mode")+"-mode")}})},{}],27:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-row").html())),events:{"click .so-row-settings":"editSettingsHandler","click .so-row-duplicate":"duplicateHandler","click .so-row-delete":"confirmedDeleteHandler","click .so-row-color":"rowColorChangeHandler"},builder:null,dialog:null,initialize:function(){var e=this.model.get("cells");e.on("add",this.handleCellAdd,this),e.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 t=this;e.each(function(e){t.listenTo(e.get("widgets"),"add",t.resize)}),e.on("add",function(e){t.listenTo(e.get("widgets"),"add",t.resize)},this),this.model.on("change:label",this.onLabelChange,this)},render:function(){var e=this.model.has("color_label")?this.model.get("color_label"):1,t=this.model.has("label")?this.model.get("label"):"";this.setElement(this.template({rowColorLabel:e,rowLabel:t})),this.$el.data("view",this);var i=this;return this.model.get("cells").each(function(e){var t=new s.view.cell({model:e});t.row=i,t.render(),t.$el.appendTo(i.$(".so-cells"))}),this.builder.supports("rowAction")?(this.builder.supports("editRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-settings").parent().remove(),this.$el.addClass("so-row-no-edit")),this.builder.supports("addRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-duplicate").parent().remove(),this.$el.addClass("so-row-no-duplicate")),this.builder.supports("deleteRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-delete").parent().remove(),this.$el.addClass("so-row-no-delete"))):(this.$(".so-row-toolbar .so-dropdown-wrapper").remove(),this.$el.addClass("so-row-no-actions")),this.builder.supports("moveRow")||(this.$(".so-row-toolbar .so-row-move").remove(),this.$el.addClass("so-row-no-move")),l.trim(this.$(".so-row-toolbar").html()).length||this.$(".so-row-toolbar").remove(),this.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),this.$(".so-cells .resize-handle").css("height",0);var t=0;this.$(".so-cells .cell").each(function(){t=Math.max(t,l(this).height()),l(this).css("width",100*l(this).data("view").model.get("weight")+"%")}),this.$(".so-cells .cell-wrapper").css("min-height",Math.max(t,63)),this.$(".so-cells .resize-handle").css("height",this.$(".so-cells .cell-wrapper").outerHeight())}},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.builder.addHistoryEntry("row_deleted");var e=this;this.$el.fadeOut("normal",function(){e.model.destroy(),e.builder.model.refreshPanelsData()})},onLabelChange:function(e,t){0==this.$(".so-row-label").length?this.$(".so-row-toolbar").prepend('<h3 class="so-row-label">'+t+"</h3>"):this.$(".so-row-label").text(t)},duplicateHandler:function(){this.builder.addHistoryEntry("row_duplicated");var e=this.model.clone(this.builder.model);this.builder.model.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData()},copyHandler:function(){s.helpers.clipboard.setModel(this.model)},pasteHandler:function(){var e=s.helpers.clipboard.getModel("row-model");!_.isEmpty(e)&&e instanceof s.model.row&&(this.builder.addHistoryEntry("row_pasted"),e.builder=this.builder.model,this.builder.model.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData())},confirmedDeleteHandler:function(e){var t=l(e.target);if(t.hasClass("dashicons")&&(t=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(){if(this.builder.supports("editRow"))return null===this.dialog&&(this.dialog=new s.dialog.row,this.dialog.setBuilder(this.builder).setRowModel(this.model)),this.dialog.openDialog(),this},deleteHandler:function(){return this.model.destroy(),this},rowColorChangeHandler:function(e){this.$(".so-row-color").removeClass("so-row-color-selected");var t=l(e.target),i=t.data("color-label"),s=this.model.has("color_label")?this.model.get("color_label"):1;t.addClass("so-row-color-selected"),this.$el.removeClass("so-row-color-"+s),this.$el.addClass("so-row-color-"+i),this.model.set("color_label",i)},handleCellAdd:function(e){var t=new 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=[],l=1;l<5;l++)i.push({title:l+" "+panelsOptions.loc.contextual.column});this.builder.supports("addRow")&&t.addSection("add-row",{sectionTitle:panelsOptions.loc.contextual.add_row,search:!1},i,function(e){this.builder.addHistoryEntry("row_added");for(var t=Number(e)+1,i=[],l=0;l<t;l++)i.push({weight:100/t});var o=new s.model.row({collection:this.collection}),n=new s.collection.cells(i);n.each(function(e){e.row=o}),o.setCells(n),o.builder=this.builder.model,this.builder.model.get("rows").add(o,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData()}.bind(this));var o={};this.builder.supports("editRow")&&(o.edit={title:panelsOptions.loc.contextual.row_edit}),s.helpers.clipboard.canCopyPaste()&&(o.copy={title:panelsOptions.loc.contextual.row_copy},this.builder.supports("addRow")&&s.helpers.clipboard.isModel("row-model")&&(o.paste={title:panelsOptions.loc.contextual.row_paste})),this.builder.supports("addRow")&&(o.duplicate={title:panelsOptions.loc.contextual.row_duplicate}),this.builder.supports("deleteRow")&&(o.delete={title:panelsOptions.loc.contextual.row_delete,confirm:!0}),_.isEmpty(o)||t.addSection("row-actions",{sectionTitle:panelsOptions.loc.contextual.row_actions,search:!1},o,function(e){switch(e){case"edit":this.editSettingsHandler();break;case"copy":this.copyHandler();break;case"paste":this.pasteHandler();break;case"duplicate":this.duplicateHandler();break;case"delete":this.visualDestroyModel()}}.bind(this))}})},{}],28:[function(e,t,i){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 so-"+e+"-styles");var l={builderType:i.builderType};return"cell"===e&&(l.index=i.index),s.post(panelsOptions.ajaxurl,{action:"so_panels_style_form",type:e,style:this.model.get("style"),args:JSON.stringify(l),postId:t},function(e){this.$el.html(e),this.setupFields(),this.stylesLoaded=!0,this.trigger("styles_loaded",!_.isEmpty(e)),_.isNull(i.dialog)||i.dialog.trigger("styles_loaded",!_.isEmpty(e))}.bind(this)),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(e){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=s(this),t=e.find('input[type="text"]'),i=e.find("select"),l=e.find('input[type="hidden"]');t.focus(function(){s(this).select()});!function(e){if(""!==e){var o=/(?:([0-9\.,\-]+)(.*))+/,n=l.val().split(" "),a=[];for(var r in n){var d=o.exec(n[r]);_.isNull(d)||_.isUndefined(d[1])||_.isUndefined(d[2])||(a.push(d[1]),i.val(d[2]))}
4
- 1===t.length?t.val(a.join(" ")):(1===a.length?a=[a[0],a[0],a[0],a[0]]:2===a.length?a=[a[0],a[1],a[0],a[1]]:3===a.length&&(a=[a[0],a[1],a[2],a[1]]),t.each(function(e,t){s(t).val(a[e])}))}}(l.val());var o=function(e){if(1===t.length){var o=t.val().split(" ").filter(function(e){return""!==e}).map(function(e){return e+i.val()}).join(" ");l.val(o)}else{var n=s(e.target),a=[],r=[],d=[];t.each(function(e,t){var i=""!==s(t).val()?parseFloat(s(t).val()):null;a.push(i),null===i?r.push(e):d.push(e)}),3===r.length&&d[0]===t.index(n)&&(t.val(n.val()),a=[n.val(),n.val(),n.val(),n.val()]),JSON.stringify(a)===JSON.stringify([null,null,null,null])?l.val(""):l.val(a.map(function(e){return(null===e?0:e)+i.val()}).join(" "))}};t.change(o),i.change(o)})}})},{}],29:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-widget").html())),cell:null,dialog:null,events:{"click .widget-edit":"editHandler","click .title h4":"titleClickHandler","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),this.model.on("change:label",this.onLabelChange,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),this.cell.row.builder.supports("editWidget")&&!this.model.get("read_only")||(this.$(".actions .widget-edit").remove(),this.$el.addClass("so-widget-no-edit")),this.cell.row.builder.supports("addWidget")||(this.$(".actions .widget-duplicate").remove(),this.$el.addClass("so-widget-no-duplicate")),this.cell.row.builder.supports("deleteWidget")||(this.$(".actions .widget-delete").remove(),this.$el.addClass("so-widget-no-delete")),this.cell.row.builder.supports("moveWidget")||this.$el.addClass("so-widget-no-move"),l.trim(this.$(".actions").html()).length||this.$(".actions").remove(),this.model.get("read_only")&&this.$el.addClass("so-widget-read-only"),0===_.size(this.model.get("values"))||e.loadForm){var t=this.getEditDialog();t.once("form_loaded",t.saveWidget,t),t.setupDialog()}return this},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()},titleClickHandler:function(e){return!this.cell.row.builder.supports("editWidget")||this.model.get("read_only")?this:(this.editHandler(),this)},duplicateHandler:function(){this.cell.row.builder.addHistoryEntry("widget_duplicated");var e=this.model.clone(this.model.cell);return this.cell.model.get("widgets").add(e,{at:this.model.collection.indexOf(this.model)+1}),this.cell.row.builder.model.refreshPanelsData(),this},copyHandler:function(){s.helpers.clipboard.setModel(this.model)},deleteHandler:function(){return this.model.trigger("visual_destroy"),this},onModelChange:function(){this.$(".description").html(this.model.getTitle())},onLabelChange:function(e){this.$(".title > h4").text(e.getWidgetField("title"))},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.cell.row.builder.addHistoryEntry("widget_deleted");var e=this;return this.$el.fadeOut("fast",function(){e.cell.row.resize(),e.model.destroy(),e.cell.row.builder.model.refreshPanelsData(),e.remove()}),this},buildContextualMenu:function(e,t){this.cell.row.builder.supports("addWidget")&&t.addSection("add-widget-below",{sectionTitle:panelsOptions.loc.contextual.add_widget_below,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){this.cell.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({class:e});t.cell=this.cell.model,this.cell.model.get("widgets").add(t,{at:this.model.collection.indexOf(this.model)+1}),this.cell.row.builder.model.refreshPanelsData()}.bind(this));var i={};this.cell.row.builder.supports("editWidget")&&!this.model.get("read_only")&&(i.edit={title:panelsOptions.loc.contextual.widget_edit}),s.helpers.clipboard.canCopyPaste()&&(i.copy={title:panelsOptions.loc.contextual.widget_copy}),this.cell.row.builder.supports("addWidget")&&(i.duplicate={title:panelsOptions.loc.contextual.widget_duplicate}),this.cell.row.builder.supports("deleteWidget")&&(i.delete={title:panelsOptions.loc.contextual.widget_delete,confirm:!0}),_.isEmpty(i)||t.addSection("widget-actions",{sectionTitle:panelsOptions.loc.contextual.widget_actions,search:!1},i,function(e){switch(e){case"edit":this.editHandler();break;case"copy":this.copyHandler();break;case"duplicate":this.duplicateHandler();break;case"delete":this.visualDestroyModel()}}.bind(this)),this.cell.buildContextualMenu(e,t)}})},{}],30:[function(e,t,i){var s=jQuery,l={addWidget:function(e,t,i){var l=wp.customHtmlWidgets,o=s("<div></div>"),n=t.find(".widget-content:first");n.before(o);var a=new l.CustomHtmlWidgetControl({el:o,syncContainer:n});return a.initializeEditor(),a.editor.codemirror.refresh(),a}};t.exports=l},{}],31:[function(e,t,i){var s=e("./custom-html-widget"),l=e("./media-widget"),o=e("./text-widget"),n={CUSTOM_HTML:"custom_html",MEDIA_AUDIO:"media_audio",MEDIA_GALLERY:"media_gallery",MEDIA_IMAGE:"media_image",MEDIA_VIDEO:"media_video",TEXT:"text",addWidget:function(e,t){var i,n=e.find("> .id_base").val();switch(n){case this.CUSTOM_HTML:i=s;break;case this.MEDIA_AUDIO:case this.MEDIA_GALLERY:case this.MEDIA_IMAGE:case this.MEDIA_VIDEO:i=l;break;case this.TEXT:i=o}i.addWidget(n,e,t)}};t.exports=n},{"./custom-html-widget":30,"./media-widget":32,"./text-widget":33}],32:[function(e,t,i){var s=jQuery,l={addWidget:function(e,t,i){var l=wp.mediaWidgets,o=l.controlConstructors[e];if(o){var n=l.modelConstructors[e]||l.MediaWidgetModel,a=t.find("> .widget-content"),r=s('<div class="media-widget-control"></div>');a.before(r);var d={};a.find(".media-widget-instance-property").each(function(){var e=s(this);d[e.data("property")]=e.val()}),d.widget_id=i;var c=new n(d),h=new o({el:r,syncContainer:a,model:c});return h.render(),h}}};t.exports=l},{}],33:[function(e,t,i){var s=jQuery,l={addWidget:function(e,t,i){var l=wp.textWidgets,o={},n=t.find(".visual");if(n.length>0){if(!n.val())return null;var a=s("<div></div>"),r=t.find(".widget-content:first");r.before(a),o={el:a,syncContainer:r}}else o={el:t};var d=new l.TextWidgetControl(o);return d.initializeEditor(),d}};t.exports=l},{}]},{},[16]);
 
 
 
 
js/siteorigin-panels-264.js DELETED
@@ -1,7261 +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
-
25
- },{}],2:[function(require,module,exports){
26
- var panels = window.panels;
27
-
28
- module.exports = Backbone.Collection.extend( {
29
- model: panels.model.historyEntry,
30
-
31
- /**
32
- * The builder model
33
- */
34
- builder: null,
35
-
36
- /**
37
- * The maximum number of items in the history
38
- */
39
- maxSize: 12,
40
-
41
- initialize: function () {
42
- this.on( 'add', this.onAddEntry, this );
43
- },
44
-
45
- /**
46
- * Add an entry to the collection.
47
- *
48
- * @param text The text that defines the action taken to get to this
49
- * @param data
50
- */
51
- addEntry: function ( text, data ) {
52
-
53
- if ( _.isEmpty( data ) ) {
54
- data = this.builder.getPanelsData();
55
- }
56
-
57
- var entry = new panels.model.historyEntry( {
58
- text: text,
59
- data: JSON.stringify( data ),
60
- time: parseInt( new Date().getTime() / 1000 ),
61
- collection: this
62
- } );
63
-
64
- this.add( entry );
65
- },
66
-
67
- /**
68
- * Resize the collection so it's not bigger than this.maxSize
69
- */
70
- onAddEntry: function ( entry ) {
71
-
72
- if ( this.models.length > 1 ) {
73
- var lastEntry = this.at( this.models.length - 2 );
74
-
75
- if (
76
- (
77
- entry.get( 'text' ) === lastEntry.get( 'text' ) && entry.get( 'time' ) - lastEntry.get( 'time' ) < 15
78
- ) ||
79
- (
80
- entry.get( 'data' ) === lastEntry.get( 'data' )
81
- )
82
- ) {
83
- // If both entries have the same text and are within 20 seconds of each other, or have the same data, then remove most recent
84
- this.remove( entry );
85
- lastEntry.set( 'count', lastEntry.get( 'count' ) + 1 );
86
- }
87
- }
88
-
89
- // Make sure that there are not to many entries in this collection
90
- while ( this.models.length > this.maxSize ) {
91
- this.shift();
92
- }
93
- }
94
- } );
95
-
96
- },{}],3:[function(require,module,exports){
97
- var panels = window.panels;
98
-
99
- module.exports = Backbone.Collection.extend( {
100
- model: panels.model.row,
101
-
102
- /**
103
- * Destroy all the rows in this collection
104
- */
105
- empty: function () {
106
- var model;
107
- do {
108
- model = this.collection.first();
109
- if ( ! model ) {
110
- break;
111
- }
112
-
113
- model.destroy();
114
- } while ( true );
115
- }
116
-
117
- } );
118
-
119
- },{}],4:[function(require,module,exports){
120
- var panels = window.panels;
121
-
122
- module.exports = Backbone.Collection.extend( {
123
- model: panels.model.widget,
124
-
125
- initialize: function () {
126
-
127
- }
128
-
129
- } );
130
-
131
- },{}],5:[function(require,module,exports){
132
- var panels = window.panels, $ = jQuery;
133
-
134
- module.exports = panels.view.dialog.extend( {
135
- dialogClass: 'so-panels-dialog-add-builder',
136
-
137
- render: function () {
138
- // Render the dialog and attach it to the builder interface
139
- this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-builder' ).html(), {} ) );
140
- this.$( '.so-content .siteorigin-panels-builder' ).append( this.builder.$el );
141
- },
142
-
143
- initializeDialog: function () {
144
- var thisView = this;
145
- this.once( 'open_dialog_complete', function () {
146
- thisView.builder.initSortable();
147
- } );
148
-
149
- this.on( 'open_dialog_complete', function () {
150
- thisView.builder.trigger( 'builder_resize' );
151
- } );
152
- }
153
- } );
154
-
155
- },{}],6:[function(require,module,exports){
156
- var panels = window.panels, $ = jQuery;
157
-
158
- module.exports = panels.view.dialog.extend( {
159
-
160
- historyEntryTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-history-entry' ).html() ) ),
161
-
162
- entries: {},
163
- currentEntry: null,
164
- revertEntry: null,
165
- selectedEntry: null,
166
-
167
- previewScrollTop: null,
168
-
169
- dialogClass: 'so-panels-dialog-history',
170
- dialogIcon: 'history',
171
-
172
- events: {
173
- 'click .so-close': 'closeDialog',
174
- 'click .so-restore': 'restoreSelectedEntry'
175
- },
176
-
177
- initializeDialog: function () {
178
- this.entries = new panels.collection.historyEntries();
179
-
180
- this.on( 'open_dialog', this.setCurrentEntry, this );
181
- this.on( 'open_dialog', this.renderHistoryEntries, this );
182
- },
183
-
184
- render: function () {
185
- var thisView = this;
186
-
187
- // Render the dialog and attach it to the builder interface
188
- this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-history' ).html(), {} ) );
189
-
190
- this.$( 'iframe.siteorigin-panels-history-iframe' ).load( function () {
191
- var $$ = $( this );
192
- $$.show();
193
-
194
- $$.contents().scrollTop( thisView.previewScrollTop );
195
- } );
196
- },
197
-
198
- /**
199
- * Set the original entry. This should be set when creating the dialog.
200
- *
201
- * @param {panels.model.builder} builder
202
- */
203
- setRevertEntry: function ( builder ) {
204
- this.revertEntry = new panels.model.historyEntry( {
205
- data: JSON.stringify( builder.getPanelsData() ),
206
- time: parseInt( new Date().getTime() / 1000 )
207
- } );
208
- },
209
-
210
- /**
211
- * This is triggered when the dialog is opened.
212
- */
213
- setCurrentEntry: function () {
214
- this.currentEntry = new panels.model.historyEntry( {
215
- data: JSON.stringify( this.builder.model.getPanelsData() ),
216
- time: parseInt( new Date().getTime() / 1000 )
217
- } );
218
-
219
- this.selectedEntry = this.currentEntry;
220
- this.previewEntry( this.currentEntry );
221
- this.$( '.so-buttons .so-restore' ).addClass( 'disabled' );
222
- },
223
-
224
- /**
225
- * Render the history entries in the sidebar
226
- */
227
- renderHistoryEntries: function () {
228
- // Set up an interval that will display the time since every 10 seconds
229
- var thisView = this;
230
-
231
- var c = this.$( '.history-entries' ).empty();
232
-
233
- if ( this.currentEntry.get( 'data' ) !== this.revertEntry.get( 'data' ) || ! _.isEmpty( this.entries.models ) ) {
234
- $( this.historyEntryTemplate( {title: panelsOptions.loc.history.revert, count: 1} ) )
235
- .data( 'historyEntry', this.revertEntry )
236
- .prependTo( c );
237
- }
238
-
239
- // Now load all the entries in this.entries
240
- this.entries.each( function ( entry ) {
241
-
242
- var html = thisView.historyEntryTemplate( {
243
- title: panelsOptions.loc.history[entry.get( 'text' )],
244
- count: entry.get( 'count' )
245
- } );
246
-
247
- $( html )
248
- .data( 'historyEntry', entry )
249
- .prependTo( c );
250
- } );
251
-
252
-
253
- $( this.historyEntryTemplate( {title: panelsOptions.loc.history['current'], count: 1} ) )
254
- .data( 'historyEntry', this.currentEntry )
255
- .addClass( 'so-selected' )
256
- .prependTo( c );
257
-
258
- // Handle loading and selecting
259
- c.find( '.history-entry' ).click( function () {
260
- var $$ = jQuery( this );
261
- c.find( '.history-entry' ).not( $$ ).removeClass( 'so-selected' );
262
- $$.addClass( 'so-selected' );
263
-
264
- var entry = $$.data( 'historyEntry' );
265
-
266
- thisView.selectedEntry = entry;
267
-
268
- if ( thisView.selectedEntry.cid !== thisView.currentEntry.cid ) {
269
- thisView.$( '.so-buttons .so-restore' ).removeClass( 'disabled' );
270
- } else {
271
- thisView.$( '.so-buttons .so-restore' ).addClass( 'disabled' );
272
- }
273
-
274
- thisView.previewEntry( entry );
275
- } );
276
-
277
- this.updateEntryTimes();
278
- },
279
-
280
- /**
281
- * Preview an entry
282
- *
283
- * @param entry
284
- */
285
- previewEntry: function ( entry ) {
286
- var iframe = this.$( 'iframe.siteorigin-panels-history-iframe' );
287
- iframe.hide();
288
- this.previewScrollTop = iframe.contents().scrollTop();
289
-
290
- this.$( 'form.history-form input[name="live_editor_panels_data"]' ).val( entry.get( 'data' ) );
291
- this.$( 'form.history-form input[name="live_editor_post_ID"]' ).val( this.builder.config.postId );
292
- this.$( 'form.history-form' ).submit();
293
- },
294
-
295
- /**
296
- * Restore the current entry
297
- */
298
- restoreSelectedEntry: function () {
299
-
300
- if ( this.$( '.so-buttons .so-restore' ).hasClass( 'disabled' ) ) {
301
- return false;
302
- }
303
-
304
- if ( this.currentEntry.get( 'data' ) === this.selectedEntry.get( 'data' ) ) {
305
- this.closeDialog();
306
- return false;
307
- }
308
-
309
- // Add an entry for this restore event
310
- if ( this.selectedEntry.get( 'text' ) !== 'restore' ) {
311
- this.builder.addHistoryEntry( 'restore', this.builder.model.getPanelsData() );
312
- }
313
-
314
- this.builder.model.loadPanelsData( JSON.parse( this.selectedEntry.get( 'data' ) ) );
315
-
316
- this.closeDialog();
317
-
318
- return false;
319
- },
320
-
321
- /**
322
- * Update the entry times for the list of entries down the side
323
- */
324
- updateEntryTimes: function () {
325
- var thisView = this;
326
-
327
- this.$( '.history-entries .history-entry' ).each( function () {
328
- var $$ = jQuery( this );
329
-
330
- var time = $$.find( '.timesince' );
331
- var entry = $$.data( 'historyEntry' );
332
-
333
- time.html( thisView.timeSince( entry.get( 'time' ) ) );
334
- } );
335
- },
336
-
337
- /**
338
- * Gets the time since as a nice string.
339
- *
340
- * @param date
341
- */
342
- timeSince: function ( time ) {
343
- var diff = parseInt( new Date().getTime() / 1000 ) - time;
344
-
345
- var parts = [];
346
- var interval;
347
-
348
- // There are 3600 seconds in an hour
349
- if ( diff > 3600 ) {
350
- interval = Math.floor( diff / 3600 );
351
- if ( interval === 1 ) {
352
- parts.push( panelsOptions.loc.time.hour.replace( '%d', interval ) );
353
- } else {
354
- parts.push( panelsOptions.loc.time.hours.replace( '%d', interval ) );
355
- }
356
- diff -= interval * 3600;
357
- }
358
-
359
- // There are 60 seconds in a minute
360
- if ( diff > 60 ) {
361
- interval = Math.floor( diff / 60 );
362
- if ( interval === 1 ) {
363
- parts.push( panelsOptions.loc.time.minute.replace( '%d', interval ) );
364
- } else {
365
- parts.push( panelsOptions.loc.time.minutes.replace( '%d', interval ) );
366
- }
367
- diff -= interval * 60;
368
- }
369
-
370
- if ( diff > 0 ) {
371
- if ( diff === 1 ) {
372
- parts.push( panelsOptions.loc.time.second.replace( '%d', diff ) );
373
- } else {
374
- parts.push( panelsOptions.loc.time.seconds.replace( '%d', diff ) );
375
- }
376
- }
377
-
378
- // Return the amount of time ago
379
- return _.isEmpty( parts ) ? panelsOptions.loc.time.now : panelsOptions.loc.time.ago.replace( '%s', parts.slice( 0, 2 ).join( ', ' ) );
380
-
381
- }
382
-
383
- } );
384
-
385
- },{}],7:[function(require,module,exports){
386
- var panels = window.panels, $ = jQuery;
387
-
388
- module.exports = panels.view.dialog.extend( {
389
-
390
- directoryTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-directory-items' ).html() ) ),
391
-
392
- builder: null,
393
- dialogClass: 'so-panels-dialog-prebuilt-layouts',
394
- dialogIcon: 'layouts',
395
-
396
- layoutCache: {},
397
- currentTab: false,
398
- directoryPage: 1,
399
-
400
- events: {
401
- 'click .so-close': 'closeDialog',
402
- 'click .so-sidebar-tabs li a': 'tabClickHandler',
403
- 'click .so-content .layout': 'layoutClickHandler',
404
- 'keyup .so-sidebar-search': 'searchHandler',
405
-
406
- // The directory items
407
- 'click .so-screenshot, .so-title': 'directoryItemClickHandler'
408
- },
409
-
410
- /**
411
- * Initialize the prebuilt dialog.
412
- */
413
- initializeDialog: function () {
414
- var thisView = this;
415
-
416
- this.on( 'open_dialog', function () {
417
- thisView.$( '.so-sidebar-tabs li a' ).first().click();
418
- thisView.$( '.so-status' ).removeClass( 'so-panels-loading' );
419
- } );
420
-
421
- this.on( 'button_click', this.toolbarButtonClick, this );
422
- },
423
-
424
- /**
425
- * Render the prebuilt layouts dialog
426
- */
427
- render: function () {
428
- this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-prebuilt' ).html(), {} ) );
429
-
430
- this.initToolbar();
431
- },
432
-
433
- /**
434
- *
435
- * @param e
436
- * @return {boolean}
437
- */
438
- tabClickHandler: function ( e ) {
439
- e.preventDefault();
440
- // Reset selected item state when changing tabs
441
- this.selectedLayoutItem = null;
442
- this.uploadedLayout = null;
443
- this.updateButtonState( false );
444
-
445
- this.$( '.so-sidebar-tabs li' ).removeClass( 'tab-active' );
446
-
447
- var $$ = $( e.target );
448
- var tab = $$.attr( 'href' ).split( '#' )[1];
449
- $$.parent().addClass( 'tab-active' );
450
-
451
- var thisView = this;
452
-
453
- // Empty everything
454
- this.$( '.so-content' ).empty();
455
-
456
- thisView.currentTab = tab;
457
- if ( tab == 'import' ) {
458
- this.displayImportExport();
459
- } else {
460
- this.displayLayoutDirectory( '', 1, tab );
461
- }
462
-
463
- thisView.$( '.so-sidebar-search' ).val( '' );
464
- },
465
-
466
- /**
467
- * Display and setup the import/export form
468
- */
469
- displayImportExport: function () {
470
- var c = this.$( '.so-content' ).empty().removeClass( 'so-panels-loading' );
471
- c.html( $( '#siteorigin-panels-dialog-prebuilt-importexport' ).html() );
472
-
473
- var thisView = this;
474
- var uploadUi = thisView.$( '.import-upload-ui' ).hide();
475
-
476
- // Create the uploader
477
- var uploader = new plupload.Uploader( {
478
- runtimes: 'html5,silverlight,flash,html4',
479
-
480
- browse_button: uploadUi.find( '.file-browse-button' ).get( 0 ),
481
- container: uploadUi.get( 0 ),
482
- drop_element: uploadUi.find( '.drag-upload-area' ).get( 0 ),
483
-
484
- file_data_name: 'panels_import_data',
485
- multiple_queues: false,
486
- max_file_size: panelsOptions.plupload.max_file_size,
487
- url: panelsOptions.plupload.url,
488
- flash_swf_url: panelsOptions.plupload.flash_swf_url,
489
- silverlight_xap_url: panelsOptions.plupload.silverlight_xap_url,
490
- filters: [
491
- {title: panelsOptions.plupload.filter_title, extensions: 'json'}
492
- ],
493
-
494
- multipart_params: {
495
- action: 'so_panels_import_layout'
496
- },
497
-
498
- init: {
499
- PostInit: function ( uploader ) {
500
- if ( uploader.features.dragdrop ) {
501
- uploadUi.addClass( 'has-drag-drop' );
502
- }
503
- uploadUi.show().find( '.progress-precent' ).css( 'width', '0%' );
504
- },
505
- FilesAdded: function ( uploader ) {
506
- uploadUi.find( '.file-browse-button' ).blur();
507
- uploadUi.find( '.drag-upload-area' ).removeClass( 'file-dragover' );
508
- uploadUi.find( '.progress-bar' ).fadeIn( 'fast' );
509
- thisView.$( '.js-so-selected-file' ).text( panelsOptions.loc.prebuilt_loading );
510
- uploader.start();
511
- },
512
- UploadProgress: function ( uploader, file ) {
513
- uploadUi.find( '.progress-precent' ).css( 'width', file.percent + '%' );
514
- },
515
- FileUploaded: function ( uploader, file, response ) {
516
- var layout = JSON.parse( response.response );
517
- if ( ! _.isUndefined( layout.widgets ) ) {
518
-
519
- thisView.uploadedLayout = layout;
520
- uploadUi.find( '.progress-bar' ).hide();
521
- thisView.$( '.js-so-selected-file' ).text(
522
- panelsOptions.loc.ready_to_insert.replace( '%s', file.name )
523
- );
524
- thisView.updateButtonState( true );
525
- } else {
526
- alert( panelsOptions.plupload.error_message );
527
- }
528
- },
529
- Error: function () {
530
- alert( panelsOptions.plupload.error_message );
531
- }
532
- }
533
- } );
534
- uploader.init();
535
-
536
- // This is
537
- uploadUi.find( '.drag-upload-area' )
538
- .on( 'dragover', function () {
539
- $( this ).addClass( 'file-dragover' );
540
- } )
541
- .on( 'dragleave', function () {
542
- $( this ).removeClass( 'file-dragover' );
543
- } );
544
-
545
- // Handle exporting the file
546
- c.find( '.so-export' ).submit( function ( e ) {
547
- var $$ = $( this );
548
- var panelsData = thisView.builder.model.getPanelsData();
549
- var postName = $('input[name="post_title"]').val();
550
- if ( ! postName ) {
551
- postName = $('input[name="post_ID"]').val();
552
- }
553
- panelsData.name = postName;
554
- $$.find( 'input[name="panels_export_data"]' ).val( JSON.stringify( panelsData ) );
555
- } );
556
-
557
- },
558
-
559
- /**
560
- * Display the layout directory tab.
561
- *
562
- * @param query
563
- */
564
- displayLayoutDirectory: function ( search, page, type ) {
565
- var thisView = this;
566
- var c = this.$( '.so-content' ).empty().addClass( 'so-panels-loading' );
567
-
568
- if ( search === undefined ) {
569
- search = '';
570
- }
571
- if ( page === undefined ) {
572
- page = 1;
573
- }
574
- if ( type === undefined ) {
575
- type = 'directory-siteorigin';
576
- }
577
-
578
- if ( type.match('^directory-') && ! panelsOptions.directory_enabled ) {
579
- // Display the button to enable the prebuilt layout
580
- c.removeClass( 'so-panels-loading' ).html( $( '#siteorigin-panels-directory-enable' ).html() );
581
- c.find( '.so-panels-enable-directory' ).click( function ( e ) {
582
- e.preventDefault();
583
- // Sent the query to enable the directory, then enable the directory
584
- $.get(
585
- panelsOptions.ajaxurl,
586
- {action: 'so_panels_directory_enable'},
587
- function () {
588
-
589
- }
590
- );
591
-
592
- // Enable the layout directory
593
- panelsOptions.directory_enabled = true;
594
- c.addClass( 'so-panels-loading' );
595
- thisView.displayLayoutDirectory( search, page, type );
596
- } );
597
- return;
598
- }
599
-
600
- // Get all the items for the current query
601
- $.get(
602
- panelsOptions.ajaxurl,
603
- {
604
- action: 'so_panels_layouts_query',
605
- search: search,
606
- page: page,
607
- type: type,
608
- },
609
- function ( data ) {
610
- // Skip this if we're no longer viewing the layout directory
611
- if ( thisView.currentTab !== type ) {
612
- return;
613
- }
614
-
615
- // Add the directory items
616
- c.removeClass( 'so-panels-loading' ).html( thisView.directoryTemplate( data ) );
617
-
618
- // Lets setup the next and previous buttons
619
- var prev = c.find( '.so-previous' ), next = c.find( '.so-next' );
620
-
621
- if ( page <= 1 ) {
622
- prev.addClass( 'button-disabled' );
623
- } else {
624
- prev.click( function ( e ) {
625
- e.preventDefault();
626
- thisView.displayLayoutDirectory( search, page - 1, thisView.currentTab );
627
- } );
628
- }
629
-
630
- if ( page === data.max_num_pages || data.max_num_pages === 0 ) {
631
- next.addClass( 'button-disabled' );
632
- } else {
633
- next.click( function ( e ) {
634
- e.preventDefault();
635
- thisView.displayLayoutDirectory( search, page + 1, thisView.currentTab );
636
- } );
637
- }
638
-
639
- // Handle nice preloading of the screenshots
640
- c.find( '.so-screenshot' ).each( function () {
641
- var $$ = $( this ), $a = $$.find( '.so-screenshot-wrapper' );
642
- $a.css( 'height', ( $a.width() / 4 * 3 ) + 'px' ).addClass( 'so-loading' );
643
-
644
- if ( $$.data( 'src' ) !== '' ) {
645
- // Set the initial height
646
- var $img = $( '<img/>' ).attr( 'src', $$.data( 'src' ) ).load( function () {
647
- $a.removeClass( 'so-loading' ).css( 'height', 'auto' );
648
- $img.appendTo( $a ).hide().fadeIn( 'fast' );
649
- } );
650
- } else {
651
- $( '<img/>' ).attr( 'src', panelsOptions.prebuiltDefaultScreenshot ).appendTo( $a ).hide().fadeIn( 'fast' );
652
- }
653
-
654
- } );
655
-
656
- // Set the title
657
- c.find( '.so-directory-browse' ).html( data.title );
658
- },
659
- 'json'
660
- );
661
- },
662
-
663
- /**
664
- * Set the selected state for the clicked layout directory item and remove previously selected item.
665
- * Enable the toolbar buttons.
666
- */
667
- directoryItemClickHandler: function ( e ) {
668
- var $directoryItem = this.$( e.target ).closest( '.so-directory-item' );
669
- this.$( '.so-directory-items' ).find( '.selected' ).removeClass( 'selected' );
670
- $directoryItem.addClass( 'selected' );
671
- this.selectedLayoutItem = {lid: $directoryItem.data( 'layout-id' ), type: $directoryItem.data( 'layout-type' )};
672
- this.updateButtonState( true );
673
-
674
- },
675
-
676
- /**
677
- * Load a particular layout into the builder.
678
- *
679
- * @param id
680
- */
681
- toolbarButtonClick: function ( $button ) {
682
- if ( ! this.canAddLayout() ) {
683
- return false;
684
- }
685
- var position = $button.data( 'value' );
686
- if ( _.isUndefined( position ) ) {
687
- return false;
688
- }
689
- this.updateButtonState( false );
690
-
691
- if ( $button.hasClass( 'so-needs-confirm' ) && ! $button.hasClass( 'so-confirmed' ) ) {
692
- this.updateButtonState( true );
693
- if ( $button.hasClass( 'so-confirming' ) ) {
694
- return;
695
- }
696
- $button.addClass( 'so-confirming' );
697
- var originalText = $button.html();
698
- $button.html( '<span class="dashicons dashicons-yes"></span>' + $button.data( 'confirm' ) );
699
- setTimeout( function () {
700
- $button.removeClass( 'so-confirmed' ).html( originalText );
701
- }, 2500 );
702
- setTimeout( function () {
703
- $button.removeClass( 'so-confirming' );
704
- $button.addClass( 'so-confirmed' );
705
- }, 200 );
706
- return false;
707
- }
708
- this.addingLayout = true;
709
- if ( this.currentTab === 'import' ) {
710
- this.addLayoutToBuilder( this.uploadedLayout, position );
711
- } else {
712
- this.loadSelectedLayout().then( function ( layout ) {
713
- this.addLayoutToBuilder( layout, position );
714
- }.bind( this ) );
715
- }
716
- },
717
-
718
- canAddLayout: function () {
719
- return (
720
- this.selectedLayoutItem || this.uploadedLayout
721
- ) && ! this.addingLayout;
722
- },
723
-
724
- /**
725
- * Load the layout according to selectedLayoutItem.
726
- */
727
- loadSelectedLayout: function () {
728
- this.setStatusMessage( panelsOptions.loc.prebuilt_loading, true );
729
-
730
- var args = _.extend( this.selectedLayoutItem, {action: 'so_panels_get_layout'} );
731
- var deferredLayout = new $.Deferred();
732
-
733
- $.get(
734
- panelsOptions.ajaxurl,
735
- args,
736
- function ( layout ) {
737
- var msg = '';
738
- if ( ! layout.success ) {
739
- msg = layout.data.message;
740
- deferredLayout.reject( layout.data );
741
- } else {
742
- deferredLayout.resolve( layout.data );
743
- }
744
- this.setStatusMessage( msg, false, ! layout.success );
745
- this.updateButtonState( true );
746
- }.bind( this )
747
- );
748
- return deferredLayout.promise();
749
- },
750
-
751
- /**
752
- * Handle an update to the search
753
- */
754
- searchHandler: function ( e ) {
755
- if ( e.keyCode === 13 ) {
756
- this.displayLayoutDirectory( $( e.currentTarget ).val(), 1, this.currentTab );
757
- }
758
- },
759
-
760
- /**
761
- * Attempt to set the 'Insert' button's state according to the `enabled` argument, also checking whether the
762
- * requirements for inserting a layout have valid values.
763
- */
764
- updateButtonState: function ( enabled ) {
765
- enabled = enabled && (
766
- this.selectedLayoutItem || this.uploadedLayout
767
- );
768
- var $button = this.$( '.so-import-layout' );
769
- $button.prop( "disabled", ! enabled );
770
- if ( enabled ) {
771
- $button.removeClass( 'disabled' );
772
- } else {
773
- $button.addClass( 'disabled' );
774
- }
775
- },
776
-
777
- addLayoutToBuilder: function ( layout, position ) {
778
- this.builder.addHistoryEntry( 'prebuilt_loaded' );
779
- this.builder.model.loadPanelsData( layout, position );
780
- this.addingLayout = false;
781
- this.closeDialog();
782
- }
783
- } );
784
-
785
- },{}],8:[function(require,module,exports){
786
- var panels = window.panels, $ = jQuery;
787
-
788
- module.exports = panels.view.dialog.extend({
789
-
790
- cellPreviewTemplate: _.template( panels.helpers.utils.processTemplate( $('#siteorigin-panels-dialog-row-cell-preview').html() ) ),
791
-
792
- editableLabel: true,
793
-
794
- events: {
795
- 'click .so-close': 'closeDialog',
796
-
797
- // Toolbar buttons
798
- 'click .so-toolbar .so-save': 'saveHandler',
799
- 'click .so-toolbar .so-insert': 'insertHandler',
800
- 'click .so-toolbar .so-delete': 'deleteHandler',
801
- 'click .so-toolbar .so-duplicate': 'duplicateHandler',
802
-
803
- // Changing the row
804
- 'change .row-set-form > *': 'setCellsFromForm',
805
- 'click .row-set-form button.set-row': 'setCellsFromForm',
806
- },
807
-
808
- dialogIcon: 'add-row',
809
- dialogClass: 'so-panels-dialog-row-edit',
810
- styleType: 'row',
811
-
812
- dialogType: 'edit',
813
-
814
- /**
815
- * The current settings, not yet saved to the model
816
- */
817
- row: {
818
- // This will be a clone of cells collection.
819
- cells: null,
820
- // The style settings of the row
821
- style: {}
822
- },
823
-
824
- cellStylesCache: [],
825
-
826
- initializeDialog: function () {
827
- this.on('open_dialog', function () {
828
- if (!_.isUndefined(this.model) && !_.isEmpty(this.model.get('cells'))) {
829
- this.setRowModel(this.model);
830
- } else {
831
- this.setRowModel(null);
832
- }
833
-
834
- this.regenerateRowPreview();
835
- }, this);
836
-
837
- // This is the default row layout
838
- this.row = {
839
- cells: new panels.collection.cells([{weight: 0.5}, {weight: 0.5}]),
840
- style: {}
841
- };
842
-
843
- // Refresh panels data after both dialog form components are loaded
844
- this.dialogFormsLoaded = 0;
845
- var thisView = this;
846
- this.on('form_loaded styles_loaded', function () {
847
- this.dialogFormsLoaded++;
848
- if (this.dialogFormsLoaded === 2) {
849
- thisView.updateModel({
850
- refreshArgs: {
851
- silent: true
852
- }
853
- });
854
- }
855
- });
856
-
857
- this.on('close_dialog', this.closeHandler);
858
-
859
- this.on( 'edit_label', function ( text ) {
860
- // If text is set to default values, just clear it.
861
- if ( text === panelsOptions.loc.row.add || text === panelsOptions.loc.row.edit ) {
862
- text = '';
863
- }
864
- this.model.set( 'label', text );
865
- if ( _.isEmpty( text ) ) {
866
- var title = this.dialogType === 'create' ? panelsOptions.loc.row.add : panelsOptions.loc.row.edit;
867
- this.$( '.so-title').text( title );
868
- }
869
- }.bind( this ) );
870
- },
871
-
872
- /**
873
- *
874
- * @param dialogType Either "edit" or "create"
875
- */
876
- setRowDialogType: function (dialogType) {
877
- this.dialogType = dialogType;
878
- },
879
-
880
- /**
881
- * Render the new row dialog
882
- */
883
- render: function () {
884
- var title = this.dialogType === 'create' ? panelsOptions.loc.row.add : panelsOptions.loc.row.edit;
885
- this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-row' ).html(), {
886
- title: title,
887
- dialogType: this.dialogType
888
- } ) );
889
-
890
- var titleElt = this.$( '.so-title' );
891
-
892
- if ( this.model.has( 'label' ) && ! _.isEmpty( this.model.get( 'label' ) ) ) {
893
- titleElt.text( this.model.get( 'label' ) );
894
- }
895
- this.$( '.so-edit-title' ).val( titleElt.text() );
896
-
897
- // Now we need to attach the style window
898
- this.styles = new panels.view.styles();
899
- this.styles.model = this.model;
900
- this.styles.render('row', this.builder.config.postId, {
901
- builderType: this.builder.config.builderType,
902
- dialog: this
903
- });
904
-
905
- if (!this.builder.supports('addRow')) {
906
- this.$('.so-buttons .so-duplicate').remove();
907
- }
908
- if (!this.builder.supports('deleteRow')) {
909
- this.$('.so-buttons .so-delete').remove();
910
- }
911
-
912
- var $rightSidebar = this.$('.so-sidebar.so-right-sidebar');
913
- this.styles.attach($rightSidebar);
914
-
915
- // Handle the loading class
916
- this.styles.on('styles_loaded', function (hasStyles) {
917
- // If we have styles remove the loading spinner, else remove the whole empty sidebar.
918
- if (hasStyles) {
919
- $rightSidebar.removeClass('so-panels-loading');
920
- } else {
921
- $rightSidebar.closest('.so-panels-dialog').removeClass('so-panels-dialog-has-right-sidebar');
922
- $rightSidebar.remove();
923
- }
924
- }, this);
925
- $rightSidebar.addClass('so-panels-loading');
926
-
927
- if (!_.isUndefined(this.model)) {
928
- // Set the initial value of the
929
- this.$( 'input[name="cells"].so-row-field' ).val( this.model.get( 'cells' ).length );
930
- if ( this.model.has( 'ratio' ) ) {
931
- this.$( 'select[name="ratio"].so-row-field' ).val( this.model.get( 'ratio' ) );
932
- }
933
- if ( this.model.has( 'ratio_direction' ) ) {
934
- this.$( 'select[name="ratio_direction"].so-row-field' ).val( this.model.get( 'ratio_direction' ) );
935
- }
936
- }
937
-
938
- this.$('input.so-row-field').keyup(function () {
939
- $(this).trigger('change');
940
- });
941
-
942
- return this;
943
- },
944
-
945
- /**
946
- * Set the row model we'll be using for this dialog.
947
- *
948
- * @param model
949
- */
950
- setRowModel: function (model) {
951
- this.model = model;
952
-
953
- if (_.isEmpty(this.model)) {
954
- return this;
955
- }
956
-
957
- // Set the rows to be a copy of the model
958
- this.row = {
959
- cells: this.model.get('cells').clone(),
960
- style: {},
961
- ratio: this.model.get('ratio'),
962
- ratio_direction: this.model.get('ratio_direction'),
963
- };
964
-
965
- // Set the initial value of the cell field.
966
- this.$( 'input[name="cells"].so-row-field' ).val( this.model.get( 'cells' ).length );
967
- if ( this.model.has( 'ratio' ) ) {
968
- this.$( 'select[name="ratio"].so-row-field' ).val( this.model.get( 'ratio' ) );
969
- }
970
- if ( this.model.has( 'ratio_direction' ) ) {
971
- this.$( 'select[name="ratio_direction"].so-row-field' ).val( this.model.get( 'ratio_direction' ) );
972
- }
973
-
974
- this.clearCellStylesCache();
975
-
976
- return this;
977
- },
978
-
979
- /**
980
- * Regenerate the row preview and resizing interface.
981
- */
982
- regenerateRowPreview: function () {
983
- var thisDialog = this;
984
- var rowPreview = this.$('.row-preview');
985
-
986
- // If no selected cell, select the first cell.
987
- var selectedIndex = this.getSelectedCellIndex();
988
-
989
- rowPreview.empty();
990
-
991
- var timeout;
992
-
993
- // Represent the cells
994
- this.row.cells.each(function (cellModel, i) {
995
- var newCell = $(this.cellPreviewTemplate({weight: cellModel.get('weight')}));
996
- rowPreview.append(newCell);
997
-
998
- if(i == selectedIndex) {
999
- newCell.find('.preview-cell-in').addClass('cell-selected');
1000
- }
1001
-
1002
- var prevCell = newCell.prev();
1003
- var handle;
1004
-
1005
- if (prevCell.length) {
1006
- handle = $('<div class="resize-handle"></div>');
1007
- handle
1008
- .appendTo(newCell)
1009
- .dblclick(function () {
1010
- var prevCellModel = thisDialog.row.cells.at(i - 1);
1011
- var t = cellModel.get('weight') + prevCellModel.get('weight');
1012
- cellModel.set('weight', t / 2);
1013
- prevCellModel.set('weight', t / 2);
1014
- thisDialog.scaleRowWidths();
1015
- });
1016
-
1017
- handle.draggable({
1018
- axis: 'x',
1019
- containment: rowPreview,
1020
- start: function (e, ui) {
1021
-
1022
- // Create the clone for the current cell
1023
- var newCellClone = newCell.clone().appendTo(ui.helper).css({
1024
- position: 'absolute',
1025
- top: '0',
1026
- width: newCell.outerWidth(),
1027
- left: 6,
1028
- height: newCell.outerHeight()
1029
- });
1030
- newCellClone.find('.resize-handle').remove();
1031
-
1032
- // Create the clone for the previous cell
1033
- var prevCellClone = prevCell.clone().appendTo(ui.helper).css({
1034
- position: 'absolute',
1035
- top: '0',
1036
- width: prevCell.outerWidth(),
1037
- right: 6,
1038
- height: prevCell.outerHeight()
1039
- });
1040
- prevCellClone.find('.resize-handle').remove();
1041
-
1042
- $(this).data({
1043
- 'newCellClone': newCellClone,
1044
- 'prevCellClone': prevCellClone
1045
- });
1046
-
1047
- // Hide the
1048
- newCell.find('> .preview-cell-in').css('visibility', 'hidden');
1049
- prevCell.find('> .preview-cell-in').css('visibility', 'hidden');
1050
- },
1051
- drag: function (e, ui) {
1052
- // Calculate the new cell and previous cell widths as a percent
1053
- var cellWeight = thisDialog.row.cells.at(i).get('weight');
1054
- var prevCellWeight = thisDialog.row.cells.at(i - 1).get('weight');
1055
- var ncw = cellWeight - (
1056
- (
1057
- ui.position.left + 6
1058
- ) / rowPreview.width()
1059
- );
1060
- var pcw = prevCellWeight + (
1061
- (
1062
- ui.position.left + 6
1063
- ) / rowPreview.width()
1064
- );
1065
-
1066
- var helperLeft = ui.helper.offset().left - rowPreview.offset().left - 6;
1067
-
1068
- $(this).data('newCellClone').css('width', rowPreview.width() * ncw)
1069
- .find('.preview-cell-weight').html(Math.round(ncw * 1000) / 10);
1070
-
1071
- $(this).data('prevCellClone').css('width', rowPreview.width() * pcw)
1072
- .find('.preview-cell-weight').html(Math.round(pcw * 1000) / 10);
1073
- },
1074
- stop: function (e, ui) {
1075
- // Remove the clones
1076
- $(this).data('newCellClone').remove();
1077
- $(this).data('prevCellClone').remove();
1078
-
1079
- // Reshow the main cells
1080
- newCell.find('.preview-cell-in').css('visibility', 'visible');
1081
- prevCell.find('.preview-cell-in').css('visibility', 'visible');
1082
-
1083
- // Calculate the new cell weights
1084
- var offset = ui.position.left + 6;
1085
- var percent = offset / rowPreview.width();
1086
-
1087
- // Ignore this if any of the cells are below 2% in width.
1088
- var cellModel = thisDialog.row.cells.at(i);
1089
- var prevCellModel = thisDialog.row.cells.at(i - 1);
1090
- if (cellModel.get('weight') - percent > 0.02 && prevCellModel.get('weight') + percent > 0.02) {
1091
- cellModel.set('weight', cellModel.get('weight') - percent);
1092
- prevCellModel.set('weight', prevCellModel.get('weight') + percent);
1093
- }
1094
-
1095
- thisDialog.scaleRowWidths();
1096
- ui.helper.css('left', -6);
1097
- }
1098
- });
1099
- }
1100
-
1101
- newCell.click(function (event) {
1102
-
1103
- if ( ! ( $(event.target).is('.preview-cell') || $(event.target).is('.preview-cell-in') ) ) {
1104
- return;
1105
- }
1106
-
1107
- var cell = $(event.target);
1108
- cell.closest('.row-preview').find('.preview-cell .preview-cell-in').removeClass('cell-selected');
1109
- cell.addClass('cell-selected');
1110
-
1111
- this.openSelectedCellStyles();
1112
-
1113
- }.bind(this));
1114
-
1115
- // Make this row weight click editable
1116
- newCell.find('.preview-cell-weight').click(function (ci) {
1117
-
1118
- // Disable the draggable while entering values
1119
- thisDialog.$('.resize-handle').css('pointer-event', 'none').draggable('disable');
1120
-
1121
- rowPreview.find('.preview-cell-weight').each(function () {
1122
- var $$ = jQuery(this).hide();
1123
- $('<input type="text" class="preview-cell-weight-input no-user-interacted" />')
1124
- .val(parseFloat($$.html())).insertAfter($$)
1125
- .focus(function () {
1126
- clearTimeout(timeout);
1127
- })
1128
- .keyup(function (e) {
1129
- if (e.keyCode !== 9) {
1130
- // Only register the interaction if the user didn't press tab
1131
- $(this).removeClass('no-user-interacted');
1132
- }
1133
-
1134
- // Enter is clicked
1135
- if (e.keyCode === 13) {
1136
- e.preventDefault();
1137
- $(this).blur();
1138
- }
1139
- })
1140
- .keydown(function (e) {
1141
- if (e.keyCode === 9) {
1142
- e.preventDefault();
1143
-
1144
- // Tab will always cycle around the row inputs
1145
- var inputs = rowPreview.find('.preview-cell-weight-input');
1146
- var i = inputs.index($(this));
1147
- if (i === inputs.length - 1) {
1148
- inputs.eq(0).focus().select();
1149
- } else {
1150
- inputs.eq(i + 1).focus().select();
1151
- }
1152
- }
1153
- })
1154
- .blur(function () {
1155
- rowPreview.find('.preview-cell-weight-input').each(function (i, el) {
1156
- if (isNaN(parseFloat($(el).val()))) {
1157
- $(el).val(Math.floor(thisDialog.row.cells.at(i).get('weight') * 1000) / 10);
1158
- }
1159
- });
1160
-
1161
- timeout = setTimeout(function () {
1162
- // If there are no weight inputs, then skip this
1163
- if (rowPreview.find('.preview-cell-weight-input').length === 0) {
1164
- return false;
1165
- }
1166
-
1167
- // Go through all the inputs
1168
- var rowWeights = [],
1169
- rowChanged = [],
1170
- changedSum = 0,
1171
- unchangedSum = 0;
1172
-
1173
- rowPreview.find('.preview-cell-weight-input').each(function (i, el) {
1174
- var val = parseFloat($(el).val());
1175
- if (isNaN(val)) {
1176
- val = 1 / thisDialog.row.cells.length;
1177
- } else {
1178
- val = Math.round(val * 10) / 1000;
1179
- }
1180
-
1181
- // Check within 3 decimal points
1182
- var changed = !$(el).hasClass('no-user-interacted');
1183
-
1184
- rowWeights.push(val);
1185
- rowChanged.push(changed);
1186
-
1187
- if (changed) {
1188
- changedSum += val;
1189
- } else {
1190
- unchangedSum += val;
1191
- }
1192
- });
1193
-
1194
- if (changedSum > 0 && unchangedSum > 0 && (
1195
- 1 - changedSum
1196
- ) > 0) {
1197
- // Balance out the unchanged rows to occupy the weight left over by the changed sum
1198
- for (var i = 0; i < rowWeights.length; i++) {
1199
- if (!rowChanged[i]) {
1200
- rowWeights[i] = (
1201
- rowWeights[i] / unchangedSum
1202
- ) * (
1203
- 1 - changedSum
1204
- );
1205
- }
1206
- }
1207
- }
1208
-
1209
- // Last check to ensure total weight is 1
1210
- var sum = _.reduce(rowWeights, function (memo, num) {
1211
- return memo + num;
1212
- });
1213
- rowWeights = rowWeights.map(function (w) {
1214
- return w / sum;
1215
- });
1216
-
1217
- // Set the new cell weights and regenerate the preview.
1218
- if (Math.min.apply(Math, rowWeights) > 0.01) {
1219
- thisDialog.row.cells.each(function (cell, i) {
1220
- cell.set('weight', rowWeights[i]);
1221
- });
1222
- }
1223
-
1224
- // Now lets animate the cells into their new widths
1225
- rowPreview.find('.preview-cell').each(function (i, el) {
1226
- var cellWeight = thisDialog.row.cells.at(i).get('weight');
1227
- $(el).animate({'width': Math.round(cellWeight * 1000) / 10 + "%"}, 250);
1228
- $(el).find('.preview-cell-weight-input').val(Math.round(cellWeight * 1000) / 10);
1229
- });
1230
-
1231
- // So the draggable handle is not hidden.
1232
- rowPreview.find('.preview-cell').css('overflow', 'visible');
1233
-
1234
- setTimeout(function () {
1235
- thisDialog.regenerateRowPreview();
1236
- }, 260);
1237
-
1238
- }, 100);
1239
- })
1240
- .click(function () {
1241
- $(this).select();
1242
- });
1243
- });
1244
-
1245
- $(this).siblings('.preview-cell-weight-input').select();
1246
-
1247
- });
1248
-
1249
- }, this);
1250
-
1251
- this.openSelectedCellStyles();
1252
-
1253
- this.trigger('form_loaded', this);
1254
- },
1255
-
1256
- getSelectedCellIndex: function() {
1257
- var selectedIndex = -1;
1258
- this.$('.preview-cell .preview-cell-in').each(function(index, el) {
1259
- if($(el).is('.cell-selected')) {
1260
- selectedIndex = index;
1261
- }
1262
- });
1263
- return selectedIndex;
1264
- },
1265
-
1266
- openSelectedCellStyles: function() {
1267
- if (!_.isUndefined(this.cellStyles)) {
1268
- if (this.cellStyles.stylesLoaded) {
1269
- var style = {};
1270
- try {
1271
- style = this.getFormValues('.so-sidebar .so-visual-styles.so-cell-styles').style;
1272
- }
1273
- catch (err) {
1274
- console.log('Error retrieving cell styles - ' + err.message);
1275
- }
1276
-
1277
- this.cellStyles.model.set('style', style);
1278
- }
1279
- this.cellStyles.detach();
1280
- }
1281
-
1282
- this.cellStyles = this.getSelectedCellStyles();
1283
-
1284
- if ( this.cellStyles ) {
1285
- var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
1286
- this.cellStyles.attach( $rightSidebar );
1287
-
1288
- if ( !this.cellStyles.stylesLoaded ) {
1289
- this.cellStyles.on( 'styles_loaded', function () {
1290
- $rightSidebar.removeClass( 'so-panels-loading' );
1291
- }, this );
1292
- $rightSidebar.addClass( 'so-panels-loading' );
1293
- }
1294
- }
1295
- },
1296
-
1297
- getSelectedCellStyles: function () {
1298
- var cellIndex = this.getSelectedCellIndex();
1299
- if ( cellIndex > -1 ) {
1300
- var cellStyles = this.cellStylesCache[cellIndex];
1301
- if ( !cellStyles ) {
1302
- cellStyles = new panels.view.styles();
1303
- cellStyles.model = this.row.cells.at( cellIndex );
1304
- cellStyles.render( 'cell', this.builder.config.postId, {
1305
- builderType: this.builder.config.builderType,
1306
- dialog: this,
1307
- index: cellIndex,
1308
- } );
1309
- this.cellStylesCache[cellIndex] = cellStyles;
1310
- }
1311
- }
1312
-
1313
- return cellStyles;
1314
- },
1315
-
1316
- clearCellStylesCache: function () {
1317
- // Call remove() on all cell styles to remove data, event listeners etc.
1318
- this.cellStylesCache.forEach(function (cellStyles) {
1319
- cellStyles.remove();
1320
- });
1321
- this.cellStylesCache = [];
1322
- },
1323
-
1324
- /**
1325
- * Visually scale the row widths based on the cell weights
1326
- */
1327
- scaleRowWidths: function () {
1328
- var thisDialog = this;
1329
- this.$('.row-preview .preview-cell').each(function (i, el) {
1330
- var cell = thisDialog.row.cells.at(i);
1331
- $(el)
1332
- .css('width', cell.get('weight') * 100 + "%")
1333
- .find('.preview-cell-weight').html(Math.round(cell.get('weight') * 1000) / 10);
1334
- });
1335
- },
1336
-
1337
- /**
1338
- * Get the weights from the
1339
- */
1340
- setCellsFromForm: function () {
1341
-
1342
- try {
1343
- var f = {
1344
- 'cells': parseInt(this.$('.row-set-form input[name="cells"]').val()),
1345
- 'ratio': parseFloat(this.$('.row-set-form select[name="ratio"]').val()),
1346
- 'direction': this.$('.row-set-form select[name="ratio_direction"]').val()
1347
- };
1348
-
1349
- if (_.isNaN(f.cells)) {
1350
- f.cells = 1;
1351
- }
1352
- if (isNaN(f.ratio)) {
1353
- f.ratio = 1;
1354
- }
1355
- if (f.cells < 1) {
1356
- f.cells = 1;
1357
- this.$('.row-set-form input[name="cells"]').val(f.cells);
1358
- }
1359
- else if (f.cells > 12) {
1360
- f.cells = 12;
1361
- this.$('.row-set-form input[name="cells"]').val(f.cells);
1362
- }
1363
-
1364
- this.$('.row-set-form select[name="ratio"]').val(f.ratio);
1365
-
1366
- var cells = [];
1367
- var cellCountChanged = (
1368
- this.row.cells.length !== f.cells
1369
- );
1370
-
1371
- // Now, lets create some cells
1372
- var currentWeight = 1;
1373
- for (var i = 0; i < f.cells; i++) {
1374
- cells.push(currentWeight);
1375
- currentWeight *= f.ratio;
1376
- }
1377
-
1378
- // Now lets make sure that the row weights add up to 1
1379
-
1380
- var totalRowWeight = _.reduce(cells, function (memo, weight) {
1381
- return memo + weight;
1382
- });
1383
- cells = _.map(cells, function (cell) {
1384
- return cell / totalRowWeight;
1385
- });
1386
-
1387
- // Don't return cells that are too small
1388
- cells = _.filter(cells, function (cell) {
1389
- return cell > 0.01;
1390
- });
1391
-
1392
- if (f.direction === 'left') {
1393
- cells = cells.reverse();
1394
- }
1395
-
1396
- // Discard deleted cells.
1397
- this.row.cells = new panels.collection.cells(this.row.cells.first(cells.length));
1398
-
1399
- _.each(cells, function (cellWeight, index) {
1400
- var cell = this.row.cells.at(index);
1401
- if (!cell) {
1402
- cell = new panels.model.cell({weight: cellWeight, row: this.model});
1403
- this.row.cells.add(cell);
1404
- } else {
1405
- cell.set('weight', cellWeight);
1406
- }
1407
- }.bind(this));
1408
-
1409
- this.row.ratio = f.ratio;
1410
- this.row.ratio_direction = f.direction;
1411
-
1412
- if (cellCountChanged) {
1413
- this.regenerateRowPreview();
1414
- } else {
1415
- var thisDialog = this;
1416
-
1417
- // Now lets animate the cells into their new widths
1418
- this.$('.preview-cell').each(function (i, el) {
1419
- var cellWeight = thisDialog.row.cells.at(i).get('weight');
1420
- $(el).animate({'width': Math.round(cellWeight * 1000) / 10 + "%"}, 250);
1421
- $(el).find('.preview-cell-weight').html(Math.round(cellWeight * 1000) / 10);
1422
- });
1423
-
1424
- // So the draggable handle is not hidden.
1425
- this.$('.preview-cell').css('overflow', 'visible');
1426
-
1427
- setTimeout(function () {
1428
- thisDialog.regenerateRowPreview();
1429
- }, 260);
1430
- }
1431
- }
1432
- catch (err) {
1433
- console.log('Error setting cells - ' + err.message);
1434
- }
1435
-
1436
-
1437
- // Remove the button primary class
1438
- this.$('.row-set-form .so-button-row-set').removeClass('button-primary');
1439
- },
1440
-
1441
- /**
1442
- * Handle a click on the dialog left bar tab
1443
- */
1444
- tabClickHandler: function ($t) {
1445
- if ($t.attr('href') === '#row-layout') {
1446
- this.$('.so-panels-dialog').addClass('so-panels-dialog-has-right-sidebar');
1447
- } else {
1448
- this.$('.so-panels-dialog').removeClass('so-panels-dialog-has-right-sidebar');
1449
- }
1450
- },
1451
-
1452
- /**
1453
- * Update the current model with what we have in the dialog
1454
- */
1455
- updateModel: function (args) {
1456
- args = _.extend({
1457
- refresh: true,
1458
- refreshArgs: null
1459
- }, args);
1460
-
1461
- // Set the cells
1462
- if (!_.isEmpty(this.model)) {
1463
- this.model.setCells( this.row.cells );
1464
- this.model.set( 'ratio', this.row.ratio );
1465
- this.model.set( 'ratio_direction', this.row.ratio_direction );
1466
- }
1467
-
1468
- // Update the row styles if they've loaded
1469
- if (!_.isUndefined(this.styles) && this.styles.stylesLoaded) {
1470
- // This is an edit dialog, so there are styles
1471
- var style = {};
1472
- try {
1473
- style = this.getFormValues('.so-sidebar .so-visual-styles.so-row-styles').style;
1474
- }
1475
- catch (err) {
1476
- console.log('Error retrieving row styles - ' + err.message);
1477
- }
1478
-
1479
- this.model.set('style', style);
1480
- }
1481
-
1482
- // Update the cell styles if any are showing.
1483
- if (!_.isUndefined(this.cellStyles) && this.cellStyles.stylesLoaded) {
1484
-
1485
- var style = {};
1486
- try {
1487
- style = this.getFormValues('.so-sidebar .so-visual-styles.so-cell-styles').style;
1488
- }
1489
- catch (err) {
1490
- console.log('Error retrieving cell styles - ' + err.message);
1491
- }
1492
-
1493
- this.cellStyles.model.set('style', style);
1494
- }
1495
-
1496
- if (args.refresh) {
1497
- this.builder.model.refreshPanelsData(args.refreshArgs);
1498
- }
1499
- },
1500
-
1501
- /**
1502
- * Insert the new row
1503
- */
1504
- insertHandler: function () {
1505
- this.builder.addHistoryEntry('row_added');
1506
-
1507
- this.updateModel();
1508
-
1509
- var activeCell = this.builder.getActiveCell({
1510
- createCell: false,
1511
- });
1512
-
1513
- var options = {};
1514
- if (activeCell !== null) {
1515
- options.at = this.builder.model.get('rows').indexOf(activeCell.row) + 1;
1516
- }
1517
-
1518
- // Set up the model and add it to the builder
1519
- this.model.collection = this.builder.model.get('rows');
1520
- this.builder.model.get('rows').add(this.model, options);
1521
-
1522
- this.closeDialog();
1523
-
1524
- this.builder.model.refreshPanelsData();
1525
-
1526
- return false;
1527
- },
1528
-
1529
- /**
1530
- * We'll just save this model and close the dialog
1531
- */
1532
- saveHandler: function () {
1533
- this.builder.addHistoryEntry('row_edited');
1534
- this.updateModel();
1535
- this.closeDialog();
1536
-
1537
- this.builder.model.refreshPanelsData();
1538
-
1539
- return false;
1540
- },
1541
-
1542
- /**
1543
- * The user clicks delete, so trigger deletion on the row model
1544
- */
1545
- deleteHandler: function () {
1546
- // Trigger a destroy on the model that will happen with a visual indication to the user
1547
- this.model.trigger('visual_destroy');
1548
- this.closeDialog({silent: true});
1549
-
1550
- return false;
1551
- },
1552
-
1553
- /**
1554
- * Duplicate this row
1555
- */
1556
- duplicateHandler: function () {
1557
- this.builder.addHistoryEntry('row_duplicated');
1558
-
1559
- var duplicateRow = this.model.clone(this.builder.model);
1560
-
1561
- this.builder.model.get('rows').add( duplicateRow, {
1562
- at: this.builder.model.get('rows').indexOf(this.model) + 1
1563
- } );
1564
-
1565
- this.closeDialog({silent: true});
1566
-
1567
- return false;
1568
- },
1569
-
1570
- closeHandler: function() {
1571
- this.clearCellStylesCache();
1572
- if( ! _.isUndefined(this.cellStyles) ) {
1573
- this.cellStyles = undefined;
1574
- }
1575
- },
1576
-
1577
- });
1578
-
1579
- },{}],9:[function(require,module,exports){
1580
- var panels = window.panels, $ = jQuery;
1581
- var jsWidget = require( '../view/widgets/js-widget' );
1582
-
1583
- module.exports = panels.view.dialog.extend( {
1584
-
1585
- builder: null,
1586
- sidebarWidgetTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-widget-sidebar-widget' ).html() ) ),
1587
-
1588
- dialogClass: 'so-panels-dialog-edit-widget',
1589
- dialogIcon: 'add-widget',
1590
-
1591
- widgetView: false,
1592
- savingWidget: false,
1593
- editableLabel: true,
1594
-
1595
- events: {
1596
- 'click .so-close': 'saveHandler',
1597
- 'click .so-nav.so-previous': 'navToPrevious',
1598
- 'click .so-nav.so-next': 'navToNext',
1599
-
1600
- // Action handlers
1601
- 'click .so-toolbar .so-delete': 'deleteHandler',
1602
- 'click .so-toolbar .so-duplicate': 'duplicateHandler'
1603
- },
1604
-
1605
- initializeDialog: function () {
1606
- var thisView = this;
1607
- this.model.on( 'change:values', this.handleChangeValues, this );
1608
- this.model.on( 'destroy', this.remove, this );
1609
-
1610
- // Refresh panels data after both dialog form components are loaded
1611
- this.dialogFormsLoaded = 0;
1612
- this.on( 'form_loaded styles_loaded', function () {
1613
- this.dialogFormsLoaded ++;
1614
- if ( this.dialogFormsLoaded === 2 ) {
1615
- thisView.updateModel( {
1616
- refreshArgs: {
1617
- silent: true
1618
- }
1619
- } );
1620
- }
1621
- } );
1622
-
1623
- this.on( 'edit_label', function ( text ) {
1624
- // If text is set to default value, just clear it.
1625
- if ( text === panelsOptions.widgets[ this.model.get( 'class' ) ][ 'title' ] ) {
1626
- text = '';
1627
- }
1628
- this.model.set( 'label', text );
1629
- if ( _.isEmpty( text ) ) {
1630
- this.$( '.so-title' ).text( this.model.getWidgetField( 'title' ) );
1631
- }
1632
- }.bind( this ) );
1633
- },
1634
-
1635
- /**
1636
- * Render the widget dialog.
1637
- */
1638
- render: function () {
1639
- // Render the dialog and attach it to the builder interface
1640
- this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widget' ).html(), {} ) );
1641
- this.loadForm();
1642
-
1643
- var title = this.model.getWidgetField( 'title' );
1644
- this.$( '.so-title .widget-name' ).html( title );
1645
- this.$( '.so-edit-title' ).val( title );
1646
-
1647
- if( ! this.builder.supports( 'addWidget' ) ) {
1648
- this.$( '.so-buttons .so-duplicate' ).remove();
1649
- }
1650
- if( ! this.builder.supports( 'deleteWidget' ) ) {
1651
- this.$( '.so-buttons .so-delete' ).remove();
1652
- }
1653
-
1654
- // Now we need to attach the style window
1655
- this.styles = new panels.view.styles();
1656
- this.styles.model = this.model;
1657
- this.styles.render( 'widget', this.builder.config.postId, {
1658
- builderType: this.builder.config.builderType,
1659
- dialog: this
1660
- } );
1661
-
1662
- var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
1663
- this.styles.attach( $rightSidebar );
1664
-
1665
- // Handle the loading class
1666
- this.styles.on( 'styles_loaded', function ( hasStyles ) {
1667
- // If we have styles remove the loading spinner, else remove the whole empty sidebar.
1668
- if ( hasStyles ) {
1669
- $rightSidebar.removeClass( 'so-panels-loading' );
1670
- } else {
1671
- $rightSidebar.closest( '.so-panels-dialog' ).removeClass( 'so-panels-dialog-has-right-sidebar' );
1672
- $rightSidebar.remove();
1673
- }
1674
- }, this );
1675
- $rightSidebar.addClass( 'so-panels-loading' );
1676
- },
1677
-
1678
- /**
1679
- * Get the previous widget editing dialog by looking at the dom.
1680
- * @returns {*}
1681
- */
1682
- getPrevDialog: function () {
1683
- var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1684
- if ( widgets.length <= 1 ) {
1685
- return false;
1686
- }
1687
- var currentIndex = widgets.index( this.widgetView.$el );
1688
-
1689
- if ( currentIndex === 0 ) {
1690
- return false;
1691
- } else {
1692
- do {
1693
- widgetView = widgets.eq( --currentIndex ).data( 'view' );
1694
- if ( ! _.isUndefined( widgetView ) && ! widgetView.model.get( 'read_only' ) ) {
1695
- return widgetView.getEditDialog();
1696
- }
1697
- } while( ! _.isUndefined( widgetView ) && currentIndex > 0 );
1698
- }
1699
-
1700
- return false;
1701
- },
1702
-
1703
- /**
1704
- * Get the next widget editing dialog by looking at the dom.
1705
- * @returns {*}
1706
- */
1707
- getNextDialog: function () {
1708
- var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1709
- if ( widgets.length <= 1 ) {
1710
- return false;
1711
- }
1712
-
1713
- var currentIndex = widgets.index( this.widgetView.$el ), widgetView;
1714
-
1715
- if ( currentIndex === widgets.length - 1 ) {
1716
- return false;
1717
- } else {
1718
- do {
1719
- widgetView = widgets.eq( ++currentIndex ).data( 'view' );
1720
- if ( ! _.isUndefined( widgetView ) && ! widgetView.model.get( 'read_only' ) ) {
1721
- return widgetView.getEditDialog();
1722
- }
1723
- } while( ! _.isUndefined( widgetView ) );
1724
- }
1725
-
1726
- return false;
1727
- },
1728
-
1729
- /**
1730
- * Load the widget form from the server.
1731
- * This is called when rendering the dialog for the first time.
1732
- */
1733
- loadForm: function () {
1734
- // don't load the form if this dialog hasn't been rendered yet
1735
- if ( ! this.$( '> *' ).length ) {
1736
- return;
1737
- }
1738
-
1739
- this.$( '.so-content' ).addClass( 'so-panels-loading' );
1740
-
1741
- var data = {
1742
- 'action': 'so_panels_widget_form',
1743
- 'widget': this.model.get( 'class' ),
1744
- 'instance': JSON.stringify( this.model.get( 'values' ) ),
1745
- 'raw': this.model.get( 'raw' )
1746
- };
1747
-
1748
- $.post(
1749
- panelsOptions.ajaxurl,
1750
- data,
1751
- function ( result ) {
1752
- // Add in the CID of the widget model
1753
- var html = result.replace( /{\$id}/g, this.model.cid );
1754
-
1755
- // Load this content into the form
1756
- var $soContent = this.$( '.so-content' );
1757
- $soContent
1758
- .removeClass( 'so-panels-loading' )
1759
- .html( html );
1760
-
1761
- // Trigger all the necessary events
1762
- this.trigger( 'form_loaded', this );
1763
-
1764
- // For legacy compatibility, trigger a panelsopen event
1765
- this.$( '.panel-dialog' ).trigger( 'panelsopen' );
1766
-
1767
- // If the main dialog is closed from this point on, save the widget content
1768
- this.on( 'close_dialog', this.updateModel, this );
1769
-
1770
- var widgetContent = $soContent.find( '> .widget-content' );
1771
- // If there's a widget content wrapper, this is one of the new widgets in WP 4.8 which need some special
1772
- // handling in JS.
1773
- if ( widgetContent.length > 0 ) {
1774
- jsWidget.addWidget( $soContent, this.model.widget_id );
1775
- }
1776
-
1777
- }.bind( this ),
1778
- 'html'
1779
- );
1780
- },
1781
-
1782
- /**
1783
- * Save the widget from the form to the model
1784
- */
1785
- updateModel: function ( args ) {
1786
- args = _.extend( {
1787
- refresh: true,
1788
- refreshArgs: null
1789
- }, args );
1790
-
1791
- // Get the values from the form and assign the new values to the model
1792
- this.savingWidget = true;
1793
-
1794
- if ( ! this.model.get( 'missing' ) ) {
1795
- // Only get the values for non missing widgets.
1796
- var values = this.getFormValues();
1797
- if ( _.isUndefined( values.widgets ) ) {
1798
- values = {};
1799
- } else {
1800
- values = values.widgets;
1801
- values = values[Object.keys( values )[0]];
1802
- }
1803
-
1804
- this.model.setValues( values );
1805
- this.model.set( 'raw', true ); // We've saved from the widget form, so this is now raw
1806
- }
1807
-
1808
- if ( this.styles.stylesLoaded ) {
1809
- // If the styles view has loaded
1810
- var style = {};
1811
- try {
1812
- style = this.getFormValues( '.so-sidebar .so-visual-styles' ).style;
1813
- }
1814
- catch ( e ) {
1815
- }
1816
- this.model.set( 'style', style );
1817
- }
1818
-
1819
- this.savingWidget = false;
1820
-
1821
- if ( args.refresh ) {
1822
- this.builder.model.refreshPanelsData( args.refreshArgs );
1823
- }
1824
- },
1825
-
1826
- /**
1827
- *
1828
- */
1829
- handleChangeValues: function () {
1830
- if ( ! this.savingWidget ) {
1831
- // Reload the form when we've changed the model and we're not currently saving from the form
1832
- this.loadForm();
1833
- }
1834
- },
1835
-
1836
- /**
1837
- * Save a history entry for this widget. Called when the dialog is closed.
1838
- */
1839
- saveHandler: function () {
1840
- this.builder.addHistoryEntry( 'widget_edited' );
1841
- this.closeDialog();
1842
- },
1843
-
1844
- /**
1845
- * When the user clicks delete.
1846
- *
1847
- * @returns {boolean}
1848
- */
1849
- deleteHandler: function () {
1850
-
1851
- this.model.trigger( 'visual_destroy' );
1852
- this.closeDialog( {silent: true} );
1853
- this.builder.model.refreshPanelsData();
1854
-
1855
- return false;
1856
- },
1857
-
1858
- duplicateHandler: function () {
1859
- this.model.trigger( 'user_duplicate' );
1860
-
1861
- this.closeDialog( {silent: true} );
1862
- this.builder.model.refreshPanelsData();
1863
-
1864
- return false;
1865
- }
1866
-
1867
- } );
1868
-
1869
- },{"../view/widgets/js-widget":31}],10:[function(require,module,exports){
1870
- var panels = window.panels, $ = jQuery;
1871
-
1872
- module.exports = panels.view.dialog.extend( {
1873
-
1874
- builder: null,
1875
- widgetTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-widgets-widget' ).html() ) ),
1876
- filter: {},
1877
-
1878
- dialogClass: 'so-panels-dialog-add-widget',
1879
- dialogIcon: 'add-widget',
1880
-
1881
- events: {
1882
- 'click .so-close': 'closeDialog',
1883
- 'click .widget-type': 'widgetClickHandler',
1884
- 'keyup .so-sidebar-search': 'searchHandler'
1885
- },
1886
-
1887
- /**
1888
- * Initialize the widget adding dialog
1889
- */
1890
- initializeDialog: function () {
1891
-
1892
- this.on( 'open_dialog', function () {
1893
- this.filter.search = '';
1894
- this.filterWidgets( this.filter );
1895
- }, this );
1896
-
1897
- this.on( 'open_dialog_complete', function () {
1898
- // Clear the search and re-filter the widgets when we open the dialog
1899
- this.$( '.so-sidebar-search' ).val( '' ).focus();
1900
- this.balanceWidgetHeights();
1901
- } );
1902
-
1903
- // We'll implement a custom tab click handler
1904
- this.on( 'tab_click', this.tabClickHandler, this );
1905
- },
1906
-
1907
- render: function () {
1908
- // Render the dialog and attach it to the builder interface
1909
- this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widgets' ).html(), {} ) );
1910
-
1911
- // Add all the widgets
1912
- _.each( panelsOptions.widgets, function ( widget ) {
1913
- var $w = $( this.widgetTemplate( {
1914
- title: widget.title,
1915
- description: widget.description
1916
- } ) );
1917
-
1918
- if ( _.isUndefined( widget.icon ) ) {
1919
- widget.icon = 'dashicons dashicons-admin-generic';
1920
- }
1921
-
1922
- $( '<span class="widget-icon" />' ).addClass( widget.icon ).prependTo( $w.find( '.widget-type-wrapper' ) );
1923
-
1924
- $w.data( 'class', widget.class ).appendTo( this.$( '.widget-type-list' ) );
1925
- }, this );
1926
-
1927
- // Add the sidebar tabs
1928
- var tabs = this.$( '.so-sidebar-tabs' );
1929
- _.each( panelsOptions.widget_dialog_tabs, function ( tab ) {
1930
- $( this.dialogTabTemplate( {'title': tab.title} ) ).data( {
1931
- 'message': tab.message,
1932
- 'filter': tab.filter
1933
- } ).appendTo( tabs );
1934
- }, this );
1935
-
1936
- // We'll be using tabs, so initialize them
1937
- this.initTabs();
1938
-
1939
- var thisDialog = this;
1940
- $( window ).resize( function () {
1941
- thisDialog.balanceWidgetHeights();
1942
- } );
1943
- },
1944
-
1945
- /**
1946
- * Handle a tab being clicked
1947
- */
1948
- tabClickHandler: function ( $t ) {
1949
- // Get the filter from the tab, and filter the widgets
1950
- this.filter = $t.parent().data( 'filter' );
1951
- this.filter.search = this.$( '.so-sidebar-search' ).val();
1952
-
1953
- var message = $t.parent().data( 'message' );
1954
- if ( _.isEmpty( message ) ) {
1955
- message = '';
1956
- }
1957
-
1958
- this.$( '.so-toolbar .so-status' ).html( message );
1959
-
1960
- this.filterWidgets( this.filter );
1961
-
1962
- return false;
1963
- },
1964
-
1965
- /**
1966
- * Handle changes to the search value
1967
- */
1968
- searchHandler: function ( e ) {
1969
- if( e.which === 13 ) {
1970
- var visibleWidgets = this.$( '.widget-type-list .widget-type:visible' );
1971
- if( visibleWidgets.length === 1 ) {
1972
- visibleWidgets.click();
1973
- }
1974
- }
1975
- else {
1976
- this.filter.search = $( e.target ).val().trim();
1977
- this.filterWidgets( this.filter );
1978
- }
1979
- },
1980
-
1981
- /**
1982
- * Filter the widgets that we're displaying
1983
- * @param filter
1984
- */
1985
- filterWidgets: function ( filter ) {
1986
- if ( _.isUndefined( filter ) ) {
1987
- filter = {};
1988
- }
1989
-
1990
- if ( _.isUndefined( filter.groups ) ) {
1991
- filter.groups = '';
1992
- }
1993
-
1994
- this.$( '.widget-type-list .widget-type' ).each( function () {
1995
- var $$ = $( this ), showWidget;
1996
- var widgetClass = $$.data( 'class' );
1997
-
1998
- var widgetData = (
1999
- ! _.isUndefined( panelsOptions.widgets[widgetClass] )
2000
- ) ? panelsOptions.widgets[widgetClass] : null;
2001
-
2002
- if ( _.isEmpty( filter.groups ) ) {
2003
- // This filter doesn't specify groups, so show all
2004
- showWidget = true;
2005
- } else if ( widgetData !== null && ! _.isEmpty( _.intersection( filter.groups, panelsOptions.widgets[widgetClass].groups ) ) ) {
2006
- // This widget is in the filter group
2007
- showWidget = true;
2008
- } else {
2009
- // This widget is not in the filter group
2010
- showWidget = false;
2011
- }
2012
-
2013
- // This can probably be done with a more intelligent operator
2014
- if ( showWidget ) {
2015
-
2016
- if ( ! _.isUndefined( filter.search ) && filter.search !== '' ) {
2017
- // Check if the widget title contains the search term
2018
- if ( widgetData.title.toLowerCase().indexOf( filter.search.toLowerCase() ) === - 1 ) {
2019
- showWidget = false;
2020
- }
2021
- }
2022
-
2023
- }
2024
-
2025
- if ( showWidget ) {
2026
- $$.show();
2027
- } else {
2028
- $$.hide();
2029
- }
2030
- } );
2031
-
2032
- // Balance the tags after filtering
2033
- this.balanceWidgetHeights();
2034
- },
2035
-
2036
- /**
2037
- * Add the widget to the current builder
2038
- *
2039
- * @param e
2040
- */
2041
- widgetClickHandler: function ( e ) {
2042
- // Add the history entry
2043
- this.builder.addHistoryEntry( 'widget_added' );
2044
-
2045
- var $w = $( e.currentTarget );
2046
-
2047
- var widget = new panels.model.widget( {
2048
- class: $w.data( 'class' )
2049
- } );
2050
-
2051
- // Add the widget to the cell model
2052
- widget.cell = this.builder.getActiveCell();
2053
- widget.cell.get('widgets').add( widget );
2054
-
2055
- this.closeDialog();
2056
- this.builder.model.refreshPanelsData();
2057
- },
2058
-
2059
- /**
2060
- * Balance widgets in a given row so they have enqual height.
2061
- * @param e
2062
- */
2063
- balanceWidgetHeights: function ( e ) {
2064
- var widgetRows = [[]];
2065
- var previousWidget = null;
2066
-
2067
- // Work out how many widgets there are per row
2068
- var perRow = Math.round( this.$( '.widget-type' ).parent().width() / this.$( '.widget-type' ).width() );
2069
-
2070
- // Add clears to create balanced rows
2071
- this.$( '.widget-type' )
2072
- .css( 'clear', 'none' )
2073
- .filter( ':visible' )
2074
- .each( function ( i, el ) {
2075
- if ( i % perRow === 0 && i !== 0 ) {
2076
- $( el ).css( 'clear', 'both' );
2077
- }
2078
- } );
2079
-
2080
- // Group the widgets into rows
2081
- this.$( '.widget-type-wrapper' )
2082
- .css( 'height', 'auto' )
2083
- .filter( ':visible' )
2084
- .each( function ( i, el ) {
2085
- var $el = $( el );
2086
- if ( previousWidget !== null && previousWidget.position().top !== $el.position().top ) {
2087
- widgetRows[widgetRows.length] = [];
2088
- }
2089
- previousWidget = $el;
2090
- widgetRows[widgetRows.length - 1].push( $el );
2091
- } );
2092
-
2093
- // Balance the height of the widgets within the row.
2094
- _.each( widgetRows, function ( row, i ) {
2095
- var maxHeight = _.max( row.map( function ( el ) {
2096
- return el.height();
2097
- } ) );
2098
- // Set the height of each widget in the row
2099
- _.each( row, function ( el ) {
2100
- el.height( maxHeight );
2101
- } );
2102
-
2103
- } );
2104
- }
2105
- } );
2106
-
2107
- },{}],11:[function(require,module,exports){
2108
- module.exports = {
2109
- /**
2110
- * Check if we have copy paste available.
2111
- * @returns {boolean|*}
2112
- */
2113
- canCopyPaste: function(){
2114
- return typeof(Storage) !== "undefined" && panelsOptions.user;
2115
- },
2116
-
2117
- /**
2118
- * Set the model that we're going to store in the clipboard
2119
- */
2120
- setModel: function( model ){
2121
- if( ! this.canCopyPaste() ) {
2122
- return false;
2123
- }
2124
-
2125
- var serial = panels.helpers.serialize.serialize( model );
2126
- if( model instanceof panels.model.row ) {
2127
- serial.thingType = 'row-model';
2128
- } else if( model instanceof panels.model.widget ) {
2129
- serial.thingType = 'widget-model';
2130
- }
2131
-
2132
- // Store this in local storage
2133
- localStorage[ 'panels_clipboard_' + panelsOptions.user ] = JSON.stringify( serial );
2134
- return true;
2135
- },
2136
-
2137
- /**
2138
- * Check if the current model stored in the clipboard is the expected type
2139
- */
2140
- isModel: function( expected ){
2141
- if( ! this.canCopyPaste() ) {
2142
- return false;
2143
- }
2144
-
2145
- var clipboardObject = localStorage[ 'panels_clipboard_' + panelsOptions.user ];
2146
- if( clipboardObject !== undefined ) {
2147
- clipboardObject = JSON.parse(clipboardObject);
2148
- return clipboardObject.thingType && clipboardObject.thingType === expected;
2149
- }
2150
-
2151
- return false;
2152
- },
2153
-
2154
- /**
2155
- * Get the model currently stored in the clipboard
2156
- */
2157
- getModel: function( expected ){
2158
- if( ! this.canCopyPaste() ) {
2159
- return null;
2160
- }
2161
-
2162
- var clipboardObject = localStorage[ 'panels_clipboard_' + panelsOptions.user ];
2163
- if( clipboardObject !== undefined ) {
2164
- clipboardObject = JSON.parse( clipboardObject );
2165
- if( clipboardObject.thingType && clipboardObject.thingType === expected ) {
2166
- return panels.helpers.serialize.unserialize( clipboardObject, clipboardObject.thingType, null );
2167
- }
2168
- }
2169
-
2170
- return null;
2171
- },
2172
- };
2173
-
2174
- },{}],12:[function(require,module,exports){
2175
- module.exports = {
2176
- /**
2177
- * Lock window scrolling for the main overlay
2178
- */
2179
- lock: function () {
2180
- if ( jQuery( 'body' ).css( 'overflow' ) === 'hidden' ) {
2181
- return;
2182
- }
2183
-
2184
- // lock scroll position, but retain settings for later
2185
- var scrollPosition = [
2186
- self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
2187
- self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
2188
- ];
2189
-
2190
- jQuery( 'body' )
2191
- .data( {
2192
- 'scroll-position': scrollPosition
2193
- } )
2194
- .css( 'overflow', 'hidden' );
2195
-
2196
- if( ! _.isUndefined( scrollPosition ) ) {
2197
- window.scrollTo( scrollPosition[0], scrollPosition[1] );
2198
- }
2199
- },
2200
-
2201
- /**
2202
- * Unlock window scrolling
2203
- */
2204
- unlock: function () {
2205
- if ( jQuery( 'body' ).css( 'overflow' ) !== 'hidden' ) {
2206
- return;
2207
- }
2208
-
2209
- // Check that there are no more dialogs or a live editor
2210
- if ( ! jQuery( '.so-panels-dialog-wrapper' ).is( ':visible' ) && ! jQuery( '.so-panels-live-editor' ).is( ':visible' ) ) {
2211
- jQuery( 'body' ).css( 'overflow', 'visible' );
2212
- var scrollPosition = jQuery( 'body' ).data( 'scroll-position' );
2213
-
2214
- if( ! _.isUndefined( scrollPosition ) ) {
2215
- window.scrollTo( scrollPosition[0], scrollPosition[1] );
2216
- }
2217
- }
2218
- },
2219
- };
2220
-
2221
- },{}],13:[function(require,module,exports){
2222
- /*
2223
- This is a modified version of https://github.com/underdogio/backbone-serialize/
2224
- */
2225
-
2226
- /* global Backbone, module, panels */
2227
-
2228
- module.exports = {
2229
- serialize: function( thing ){
2230
- var val;
2231
-
2232
- if( thing instanceof Backbone.Model ) {
2233
- var retObj = {};
2234
- for ( var key in thing.attributes ) {
2235
- if (thing.attributes.hasOwnProperty( key ) ) {
2236
- // Skip these to avoid recursion
2237
- if( key === 'builder' || key === 'collection' ) { continue; }
2238
-
2239
- // If the value is a Model or a Collection, then serialize them as well
2240
- val = thing.attributes[key];
2241
- if ( val instanceof Backbone.Model || val instanceof Backbone.Collection ) {
2242
- retObj[key] = this.serialize( val );
2243
- } else {
2244
- // Otherwise, save the original value
2245
- retObj[key] = val;
2246
- }
2247
- }
2248
- }
2249
- return retObj;
2250
- }
2251
- else if( thing instanceof Backbone.Collection ) {
2252
- // Walk over all of our models
2253
- var retArr = [];
2254
-
2255
- for ( var i = 0; i < thing.models.length; i++ ) {
2256
- // If the model is serializable, then serialize it
2257
- val = thing.models[i];
2258
-
2259
- if ( val instanceof Backbone.Model || val instanceof Backbone.Collection ) {
2260
- retArr.push( this.serialize( val ) );
2261
- } else {
2262
- // Otherwise (it is an object), return it in its current form
2263
- retArr.push( val );
2264
- }
2265
- }
2266
-
2267
- // Return the serialized models
2268
- return retArr;
2269
- }
2270
- },
2271
-
2272
- unserialize: function( thing, thingType, parent ) {
2273
- var retObj;
2274
-
2275
- switch( thingType ) {
2276
- case 'row-model' :
2277
- retObj = new panels.model.row();
2278
- retObj.builder = parent;
2279
- retObj.set( 'style', thing.style );
2280
- retObj.setCells( this.unserialize( thing.cells, 'cell-collection', retObj ) );
2281
- break;
2282
-
2283
- case 'cell-model' :
2284
- retObj = new panels.model.cell();
2285
- retObj.row = parent;
2286
- retObj.set( 'weight', thing.weight );
2287
- retObj.set( 'style', thing.style );
2288
- retObj.set( 'widgets', this.unserialize( thing.widgets, 'widget-collection', retObj ) );
2289
- break;
2290
-
2291
- case 'widget-model' :
2292
- retObj = new panels.model.widget();
2293
- retObj.cell = parent;
2294
- for ( var key in thing ) {
2295
- if ( thing.hasOwnProperty( key ) ) {
2296
- retObj.set( key, thing[key] );
2297
- }
2298
- }
2299
- retObj.set( 'widget_id', panels.helpers.utils.generateUUID() );
2300
- break;
2301
-
2302
- case 'cell-collection':
2303
- retObj = new panels.collection.cells();
2304
- for( var i = 0; i < thing.length; i++ ) {
2305
- retObj.push( this.unserialize( thing[i], 'cell-model', parent ) );
2306
- }
2307
- break;
2308
-
2309
- case 'widget-collection':
2310
- retObj = new panels.collection.widgets();
2311
- for( var i = 0; i < thing.length; i++ ) {
2312
- retObj.push( this.unserialize( thing[i], 'widget-model', parent ) );
2313
- }
2314
- break;
2315
-
2316
- default:
2317
- console.log( 'Unknown Thing - ' + thingType );
2318
- break;
2319
- }
2320
-
2321
- return retObj;
2322
- }
2323
- };
2324
-
2325
- },{}],14:[function(require,module,exports){
2326
- module.exports = {
2327
-
2328
- generateUUID: function(){
2329
- var d = new Date().getTime();
2330
- if( window.performance && typeof window.performance.now === "function" ){
2331
- d += performance.now(); //use high-precision timer if available
2332
- }
2333
- var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace( /[xy]/g, function(c) {
2334
- var r = (d + Math.random()*16)%16 | 0;
2335
- d = Math.floor(d/16);
2336
- return ( c == 'x' ? r : (r&0x3|0x8) ).toString(16);
2337
- } );
2338
- return uuid;
2339
- },
2340
-
2341
- processTemplate: function ( s ) {
2342
- if ( _.isUndefined( s ) || _.isNull( s ) ) {
2343
- return '';
2344
- }
2345
- s = s.replace( /{{%/g, '<%' );
2346
- s = s.replace( /%}}/g, '%>' );
2347
- s = s.trim();
2348
- return s;
2349
- },
2350
-
2351
- // From this SO post: http://stackoverflow.com/questions/6139107/programmatically-select-text-in-a-contenteditable-html-element
2352
- selectElementContents: function( element ) {
2353
- var range = document.createRange();
2354
- range.selectNodeContents( element );
2355
- var sel = window.getSelection();
2356
- sel.removeAllRanges();
2357
- sel.addRange( range );
2358
- },
2359
-
2360
- }
2361
-
2362
- },{}],15:[function(require,module,exports){
2363
- /* global _, jQuery, panels */
2364
-
2365
- var panels = window.panels, $ = jQuery;
2366
-
2367
- module.exports = function ( config ) {
2368
-
2369
- return this.each( function () {
2370
- var $$ = jQuery( this );
2371
- var widgetId = $$.closest( 'form' ).find( '.widget-id' ).val();
2372
-
2373
- // Create a config for this specific widget
2374
- var thisConfig = $.extend(true, {}, config);
2375
-
2376
- // Exit if this isn't a real widget
2377
- if ( ! _.isUndefined( widgetId ) && widgetId.indexOf( '__i__' ) > - 1 ) {
2378
- return;
2379
- }
2380
-
2381
- // Create the main builder model
2382
- var builderModel = new panels.model.builder();
2383
-
2384
- // Now for the view to display the builder
2385
- var builderView = new panels.view.builder( {
2386
- model: builderModel,
2387
- config: thisConfig
2388
- } );
2389
-
2390
- // Save panels data when we close the dialog, if we're in a dialog
2391
- var dialog = $$.closest( '.so-panels-dialog-wrapper' ).data( 'view' );
2392
- if ( ! _.isUndefined( dialog ) ) {
2393
- dialog.on( 'close_dialog', function () {
2394
- builderModel.refreshPanelsData();
2395
- } );
2396
-
2397
- dialog.on( 'open_dialog_complete', function () {
2398
- // Make sure the new layout widget is always properly setup
2399
- builderView.trigger( 'builder_resize' );
2400
- } );
2401
-
2402
- dialog.model.on( 'destroy', function () {
2403
- // Destroy the builder
2404
- builderModel.emptyRows().destroy();
2405
- } );
2406
-
2407
- // Set the parent for all the sub dialogs
2408
- builderView.setDialogParents( panelsOptions.loc.layout_widget, dialog );
2409
- }
2410
-
2411
- // Basic setup for the builder
2412
- var isWidget = Boolean( $$.closest( '.widget-content' ).length );
2413
- builderView
2414
- .render()
2415
- .attach( {
2416
- container: $$,
2417
- dialog: isWidget || $$.data('mode') === 'dialog',
2418
- type: $$.data( 'type' )
2419
- } )
2420
- .setDataField( $$.find( 'input.panels-data' ) );
2421
-
2422
- if ( isWidget || $$.data('mode') === 'dialog' ) {
2423
- // Set up the dialog opening
2424
- builderView.setDialogParents( panelsOptions.loc.layout_widget, builderView.dialog );
2425
- $$.find( '.siteorigin-panels-display-builder' ).click( function ( e ) {
2426
- e.preventDefault();
2427
- builderView.dialog.openDialog();
2428
- } );
2429
- } else {
2430
- // Remove the dialog opener button, this is already being displayed in a page builder dialog.
2431
- $$.find( '.siteorigin-panels-display-builder' ).parent().remove();
2432
- }
2433
-
2434
- // Trigger a global jQuery event after we've setup the builder view
2435
- $( document ).trigger( 'panels_setup', builderView );
2436
- } );
2437
- };
2438
-
2439
- },{}],16:[function(require,module,exports){
2440
- /**
2441
- * Everything we need for SiteOrigin Page Builder.
2442
- *
2443
- * @copyright Greg Priday 2013 - 2016 - <https://siteorigin.com/>
2444
- * @license GPL 3.0 http://www.gnu.org/licenses/gpl.html
2445
- */
2446
-
2447
- /* global Backbone, _, jQuery, tinyMCE, panelsOptions, plupload, confirm, console, require */
2448
-
2449
- var panels = {};
2450
-
2451
- // Store everything globally
2452
- window.panels = panels;
2453
- window.siteoriginPanels = panels;
2454
-
2455
- // Helpers
2456
- panels.helpers = {};
2457
- panels.helpers.clipboard = require( './helpers/clipboard' );
2458
- panels.helpers.utils = require( './helpers/utils' );
2459
- panels.helpers.serialize = require( './helpers/serialize' );
2460
- panels.helpers.pageScroll = require( './helpers/page-scroll' );
2461
-
2462
- // The models
2463
- panels.model = {};
2464
- panels.model.widget = require( './model/widget' );
2465
- panels.model.cell = require( './model/cell' );
2466
- panels.model.row = require( './model/row' );
2467
- panels.model.builder = require( './model/builder' );
2468
- panels.model.historyEntry = require( './model/history-entry' );
2469
-
2470
- // The collections
2471
- panels.collection = {};
2472
- panels.collection.widgets = require( './collection/widgets' );
2473
- panels.collection.cells = require( './collection/cells' );
2474
- panels.collection.rows = require( './collection/rows' );
2475
- panels.collection.historyEntries = require( './collection/history-entries' );
2476
-
2477
- // The views
2478
- panels.view = {};
2479
- panels.view.widget = require( './view/widget' );
2480
- panels.view.cell = require( './view/cell' );
2481
- panels.view.row = require( './view/row' );
2482
- panels.view.builder = require( './view/builder' );
2483
- panels.view.dialog = require( './view/dialog' );
2484
- panels.view.styles = require( './view/styles' );
2485
- panels.view.liveEditor = require( './view/live-editor' );
2486
-
2487
- // The dialogs
2488
- panels.dialog = {};
2489
- panels.dialog.builder = require( './dialog/builder' );
2490
- panels.dialog.widgets = require( './dialog/widgets' );
2491
- panels.dialog.widget = require( './dialog/widget' );
2492
- panels.dialog.prebuilt = require( './dialog/prebuilt' );
2493
- panels.dialog.row = require( './dialog/row' );
2494
- panels.dialog.history = require( './dialog/history' );
2495
-
2496
- // The utils
2497
- panels.utils = {};
2498
- panels.utils.menu = require( './utils/menu' );
2499
-
2500
- // jQuery Plugins
2501
- jQuery.fn.soPanelsSetupBuilderWidget = require( './jquery/setup-builder-widget' );
2502
-
2503
-
2504
- // Set up Page Builder if we're on the main interface
2505
- jQuery( function ( $ ) {
2506
-
2507
- var container,
2508
- field,
2509
- form,
2510
- builderConfig;
2511
-
2512
- var $panelsMetabox = $( '#siteorigin-panels-metabox' );
2513
- form = $( 'form#post' );
2514
- if ( $panelsMetabox.length && form.length ) {
2515
- // This is usually the case when we're in the post edit interface
2516
- container = $panelsMetabox;
2517
- field = $panelsMetabox.find( '.siteorigin-panels-data-field' );
2518
-
2519
- builderConfig = {
2520
- editorType: 'tinyMCE',
2521
- postId: $( '#post_ID' ).val(),
2522
- editorId: '#content',
2523
- builderType: $panelsMetabox.data( 'builder-type' ),
2524
- builderSupports: $panelsMetabox.data( 'builder-supports' ),
2525
- loadOnAttach: panelsOptions.loadOnAttach && $( '#auto_draft' ).val() == 1,
2526
- loadLiveEditor: $panelsMetabox.data('live-editor') == 1,
2527
- liveEditorPreview: container.data('preview-url')
2528
- };
2529
- }
2530
- else if ( $( '.siteorigin-panels-builder-form' ).length ) {
2531
- // We're dealing with another interface like the custom home page interface
2532
- var $$ = $( '.siteorigin-panels-builder-form' );
2533
-
2534
- container = $$.find( '.siteorigin-panels-builder-container' );
2535
- field = $$.find( 'input[name="panels_data"]' );
2536
- form = $$;
2537
-
2538
- builderConfig = {
2539
- editorType: 'standalone',
2540
- postId: $$.data( 'post-id' ),
2541
- editorId: '#post_content',
2542
- builderType: $$.data( 'type' ),
2543
- builderSupports: $$.data( 'builder-supports' ),
2544
- loadLiveEditor: false,
2545
- liveEditorPreview: $$.data( 'preview-url' )
2546
- };
2547
- }
2548
-
2549
- if ( ! _.isUndefined( container ) ) {
2550
- // If we have a container, then set up the main builder
2551
- var panels = window.siteoriginPanels;
2552
-
2553
- // Create the main builder model
2554
- var builderModel = new panels.model.builder();
2555
-
2556
- // Now for the view to display the builder
2557
- var builderView = new panels.view.builder( {
2558
- model: builderModel,
2559
- config: builderConfig
2560
- } );
2561
-
2562
- // Set up the builder view
2563
- builderView
2564
- .render()
2565
- .attach( {
2566
- container: container
2567
- } )
2568
- .setDataField( field )
2569
- .attachToEditor();
2570
-
2571
- // When the form is submitted, update the panels data
2572
- form.submit( function () {
2573
- // Refresh the data
2574
- builderModel.refreshPanelsData();
2575
- } );
2576
-
2577
- container.removeClass( 'so-panels-loading' );
2578
-
2579
- // Trigger a global jQuery event after we've setup the builder view. Everything is accessible form there
2580
- $( document ).trigger( 'panels_setup', builderView, window.panels );
2581
- }
2582
-
2583
- // Setup new widgets when they're added in the standard widget interface
2584
- $( document ).on( 'widget-added', function ( e, widget ) {
2585
- $( widget ).find( '.siteorigin-page-builder-widget' ).soPanelsSetupBuilderWidget();
2586
- } );
2587
-
2588
- // Setup existing widgets on the page (for the widgets interface)
2589
- if ( ! $( 'body' ).hasClass( 'wp-customizer' ) ) {
2590
- $( function () {
2591
- $( '.siteorigin-page-builder-widget' ).soPanelsSetupBuilderWidget();
2592
- } );
2593
- }
2594
- } );
2595
-
2596
- },{"./collection/cells":1,"./collection/history-entries":2,"./collection/rows":3,"./collection/widgets":4,"./dialog/builder":5,"./dialog/history":6,"./dialog/prebuilt":7,"./dialog/row":8,"./dialog/widget":9,"./dialog/widgets":10,"./helpers/clipboard":11,"./helpers/page-scroll":12,"./helpers/serialize":13,"./helpers/utils":14,"./jquery/setup-builder-widget":15,"./model/builder":17,"./model/cell":18,"./model/history-entry":19,"./model/row":20,"./model/widget":21,"./utils/menu":22,"./view/builder":23,"./view/cell":24,"./view/dialog":25,"./view/live-editor":26,"./view/row":27,"./view/styles":28,"./view/widget":29}],17:[function(require,module,exports){
2597
- module.exports = Backbone.Model.extend({
2598
- layoutPosition: {
2599
- BEFORE: 'before',
2600
- AFTER: 'after',
2601
- REPLACE: 'replace',
2602
- },
2603
-
2604
- rows: {},
2605
-
2606
- defaults: {
2607
- 'data': {
2608
- 'widgets': [],
2609
- 'grids': [],
2610
- 'grid_cells': []
2611
- }
2612
- },
2613
-
2614
- initialize: function () {
2615
- // These are the main rows in the interface
2616
- this.set( 'rows', new panels.collection.rows() );
2617
- },
2618
-
2619
- /**
2620
- * Add a new row to this builder.
2621
- *
2622
- * @param attrs
2623
- * @param cells
2624
- * @param options
2625
- */
2626
- addRow: function (attrs, cells, options) {
2627
- options = _.extend({
2628
- noAnimate: false
2629
- }, options);
2630
-
2631
- var cellCollection = new panels.collection.cells(cells);
2632
-
2633
- attrs = _.extend({
2634
- collection: this.get('rows'),
2635
- cells: cellCollection,
2636
- }, attrs);
2637
-
2638
- // Create the actual row
2639
- var row = new panels.model.row(attrs);
2640
- row.builder = this;
2641
-
2642
- this.get('rows').add( row, options );
2643
-
2644
- return row;
2645
- },
2646
-
2647
- /**
2648
- * Load the panels data into the builder
2649
- *
2650
- * @param data Object the layout and widgets data to load.
2651
- * @param position string Where to place the new layout. Allowed options are 'before', 'after'. Anything else will
2652
- * cause the new layout to replace the old one.
2653
- */
2654
- loadPanelsData: function ( data, position ) {
2655
- try {
2656
- if ( position === this.layoutPosition.BEFORE ) {
2657
- data = this.concatPanelsData( data, this.getPanelsData() );
2658
- } else if ( position === this.layoutPosition.AFTER ) {
2659
- data = this.concatPanelsData( this.getPanelsData(), data );
2660
- }
2661
-
2662
- // Start by destroying any rows that currently exist. This will in turn destroy cells, widgets and all the associated views
2663
- this.emptyRows();
2664
-
2665
- // This will empty out the current rows and reload the builder data.
2666
- this.set( 'data', JSON.parse( JSON.stringify( data ) ), {silent: true} );
2667
-
2668
- var cit = 0;
2669
- var rows = [];
2670
-
2671
- if ( _.isUndefined( data.grid_cells ) ) {
2672
- this.trigger( 'load_panels_data' );
2673
- return;
2674
- }
2675
-
2676
- var gi;
2677
- for ( var ci = 0; ci < data.grid_cells.length; ci ++ ) {
2678
- gi = parseInt( data.grid_cells[ci].grid );
2679
- if ( _.isUndefined( rows[gi] ) ) {
2680
- rows[gi] = [];
2681
- }
2682
-
2683
- rows[gi].push( data.grid_cells[ci] );
2684
- }
2685
-
2686
- var builderModel = this;
2687
- _.each( rows, function ( row, i ) {
2688
- var rowAttrs = {};
2689
-
2690
- if ( ! _.isUndefined( data.grids[i].style ) ) {
2691
- rowAttrs.style = data.grids[i].style;
2692
- }
2693
-
2694
- if ( ! _.isUndefined( data.grids[i].ratio) ) {
2695
- rowAttrs.ratio = data.grids[i].ratio;
2696
- }
2697
-
2698
- if ( ! _.isUndefined( data.grids[i].ratio_direction) ) {
2699
- rowAttrs.ratio_direction = data.grids[i].ratio_direction
2700
- }
2701
-
2702
- if ( ! _.isUndefined( data.grids[i].color_label) ) {
2703
- rowAttrs.color_label = data.grids[i].color_label;
2704
- }
2705
-
2706
- if ( ! _.isUndefined( data.grids[i].label) ) {
2707
- rowAttrs.label = data.grids[i].label;
2708
- }
2709
- // This will create and add the row model and its cells
2710
- builderModel.addRow(rowAttrs, row, {noAnimate: true} );
2711
- } );
2712
-
2713
-
2714
- if ( _.isUndefined( data.widgets ) ) {
2715
- return;
2716
- }
2717
-
2718
- // Add the widgets
2719
- _.each( data.widgets, function ( widgetData ) {
2720
- var panels_info = null;
2721
- if ( ! _.isUndefined( widgetData.panels_info ) ) {
2722
- panels_info = widgetData.panels_info;
2723
- delete widgetData.panels_info;
2724
- } else {
2725
- panels_info = widgetData.info;
2726
- delete widgetData.info;
2727
- }
2728
-
2729
- var row = builderModel.get('rows').at( parseInt( panels_info.grid ) );
2730
- var cell = row.get('cells').at( parseInt( panels_info.cell ) );
2731
-
2732
- var newWidget = new panels.model.widget( {
2733
- class: panels_info.class,
2734
- values: widgetData
2735
- } );
2736
-
2737
- if ( ! _.isUndefined( panels_info.style ) ) {
2738
- newWidget.set( 'style', panels_info.style );
2739
- }
2740
-
2741
- if ( ! _.isUndefined( panels_info.read_only ) ) {
2742
- newWidget.set( 'read_only', panels_info.read_only );
2743
- }
2744
- if ( ! _.isUndefined( panels_info.widget_id ) ) {
2745
- newWidget.set( 'widget_id', panels_info.widget_id );
2746
- }
2747
- else {
2748
- newWidget.set( 'widget_id', panels.helpers.utils.generateUUID() );
2749
- }
2750
-
2751
- if ( ! _.isUndefined( panels_info.label ) ) {
2752
- newWidget.set( 'label', panels_info.label );
2753
- }
2754
-
2755
- newWidget.cell = cell;
2756
- cell.get('widgets').add( newWidget, { noAnimate: true } );
2757
- } );
2758
-
2759
- this.trigger( 'load_panels_data' );
2760
- }
2761
- catch ( err ) {
2762
- console.log( 'Error loading data: ' + err.message );
2763
-
2764
- }
2765
- },
2766
-
2767
- /**
2768
- * Concatenate the second set of Page Builder data to the first. There is some validation of input, but for the most
2769
- * part it's up to the caller to ensure the Page Builder data is well formed.
2770
- */
2771
- concatPanelsData: function ( panelsDataA, panelsDataB ) {
2772
-
2773
- if ( _.isUndefined( panelsDataB ) || _.isUndefined( panelsDataB.grids ) || _.isEmpty( panelsDataB.grids ) ||
2774
- _.isUndefined( panelsDataB.grid_cells ) || _.isEmpty( panelsDataB.grid_cells ) ) {
2775
- return panelsDataA;
2776
- }
2777
-
2778
- if ( _.isUndefined( panelsDataA ) || _.isUndefined( panelsDataA.grids ) || _.isEmpty( panelsDataA.grids ) ) {
2779
- return panelsDataB;
2780
- }
2781
-
2782
- var gridsBOffset = panelsDataA.grids.length;
2783
- var widgetsBOffset = ! _.isUndefined( panelsDataA.widgets ) ? panelsDataA.widgets.length : 0;
2784
- var newPanelsData = {grids: [], 'grid_cells': [], 'widgets': []};
2785
-
2786
- // Concatenate grids (rows)
2787
- newPanelsData.grids = panelsDataA.grids.concat( panelsDataB.grids );
2788
-
2789
- // Create a copy of panelsDataA grid_cells and widgets
2790
- if ( ! _.isUndefined( panelsDataA.grid_cells ) ) {
2791
- newPanelsData.grid_cells = panelsDataA.grid_cells.slice();
2792
- }
2793
- if ( ! _.isUndefined( panelsDataA.widgets ) ) {
2794
- newPanelsData.widgets = panelsDataA.widgets.slice();
2795
- }
2796
-
2797
- var i;
2798
- // Concatenate grid cells (row columns)
2799
- for ( i = 0; i < panelsDataB.grid_cells.length; i ++ ) {
2800
- var gridCellB = panelsDataB.grid_cells[i];
2801
- gridCellB.grid = parseInt( gridCellB.grid ) + gridsBOffset;
2802
- newPanelsData.grid_cells.push( gridCellB );
2803
- }
2804
-
2805
- // Concatenate widgets
2806
- if ( ! _.isUndefined( panelsDataB.widgets ) ) {
2807
- for ( i = 0; i < panelsDataB.widgets.length; i ++ ) {
2808
- var widgetB = panelsDataB.widgets[i];
2809
- widgetB.panels_info.grid = parseInt( widgetB.panels_info.grid ) + gridsBOffset;
2810
- widgetB.panels_info.id = parseInt( widgetB.panels_info.id ) + widgetsBOffset;
2811
- newPanelsData.widgets.push( widgetB );
2812
- }
2813
- }
2814
-
2815
- return newPanelsData;
2816
- },
2817
-
2818
- /**
2819
- * Convert the content of the builder into a object that represents the page builder data
2820
- */
2821
- getPanelsData: function () {
2822
-
2823
- var builder = this;
2824
-
2825
- var data = {
2826
- 'widgets': [],
2827
- 'grids': [],
2828
- 'grid_cells': []
2829
- };
2830
- var widgetId = 0;
2831
-
2832
- this.get('rows').each( function ( row, ri ) {
2833
-
2834
- row.get('cells').each( function ( cell, ci ) {
2835
-
2836
- cell.get('widgets').each( function ( widget, wi ) {
2837
- // Add the data for the widget, including the panels_info field.
2838
- var panels_info = {
2839
- class: widget.get( 'class' ),
2840
- raw: widget.get( 'raw' ),
2841
- grid: ri,
2842
- cell: ci,
2843
- // Strictly this should be an index
2844
- id: widgetId ++,
2845
- widget_id: widget.get( 'widget_id' ),
2846
- style: widget.get( 'style' ),
2847
- label: widget.get( 'label' ),
2848
- };
2849
-
2850
- if( _.isEmpty( panels_info.widget_id ) ) {
2851
- panels_info.widget_id = panels.helpers.utils.generateUUID();
2852
- }
2853
-
2854
- var values = _.extend( _.clone( widget.get( 'values' ) ), {
2855
- panels_info: panels_info
2856
- } );
2857
- data.widgets.push( values );
2858
- } );
2859
-
2860
- // Add the cell info
2861
- data.grid_cells.push( {
2862
- grid: ri,
2863
- index: ci,
2864
- weight: cell.get( 'weight' ),
2865
- style: cell.get( 'style' ),
2866
- } );
2867
-
2868
- } );
2869
-
2870
- data.grids.push( {
2871
- cells: row.get('cells').length,
2872
- style: row.get( 'style' ),
2873
- ratio: row.get('ratio'),
2874
- ratio_direction: row.get('ratio_direction'),
2875
- color_label: row.get( 'color_label' ),
2876
- label: row.get( 'label' ),
2877
- } );
2878
-
2879
- } );
2880
-
2881
- return data;
2882
-
2883
- },
2884
-
2885
- /**
2886
- * This will check all the current entries and refresh the panels data
2887
- */
2888
- refreshPanelsData: function ( args ) {
2889
- args = _.extend( {
2890
- silent: false
2891
- }, args );
2892
-
2893
- var oldData = this.get( 'data' );
2894
- var newData = this.getPanelsData();
2895
- this.set( 'data', newData, {silent: true} );
2896
-
2897
- if ( ! args.silent && JSON.stringify( newData ) !== JSON.stringify( oldData ) ) {
2898
- // The default change event doesn't trigger on deep changes, so we'll trigger our own
2899
- this.trigger( 'change' );
2900
- this.trigger( 'change:data' );
2901
- this.trigger( 'refresh_panels_data', newData, args );
2902
- }
2903
- },
2904
-
2905
- /**
2906
- * Empty all the rows and the cells/widgets they contain.
2907
- */
2908
- emptyRows: function () {
2909
- _.invoke( this.get('rows').toArray(), 'destroy' );
2910
- this.get('rows').reset();
2911
-
2912
- return this;
2913
- },
2914
-
2915
- isValidLayoutPosition: function ( position ) {
2916
- return position === this.layoutPosition.BEFORE ||
2917
- position === this.layoutPosition.AFTER ||
2918
- position === this.layoutPosition.REPLACE;
2919
- },
2920
-
2921
- /**
2922
- * Convert HTML into Panels Data
2923
- * @param html
2924
- */
2925
- getPanelsDataFromHtml: function( html, editorClass ){
2926
- var thisModel = this;
2927
- var $html = jQuery( '<div id="wrapper">' + html + '</div>' );
2928
-
2929
- if( $html.find('.panel-layout .panel-grid').length ) {
2930
- // This looks like Page Builder html, lets try parse it
2931
- var panels_data = {
2932
- grids: [],
2933
- grid_cells: [],
2934
- widgets: [],
2935
- };
2936
-
2937
- // The Regex object that'll match SiteOrigin widgets
2938
- var re = new RegExp( panelsOptions.siteoriginWidgetRegex , "i" );
2939
- var decodeEntities = (function() {
2940
- // this prevents any overhead from creating the object each time
2941
- var element = document.createElement('div');
2942
-
2943
- function decodeHTMLEntities (str) {
2944
- if(str && typeof str === 'string') {
2945
- // strip script/html tags
2946
- str = str.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '');
2947
- str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
2948
- element.innerHTML = str;
2949
- str = element.textContent;
2950
- element.textContent = '';
2951
- }
2952
-
2953
- return str;
2954
- }
2955
-
2956
- return decodeHTMLEntities;
2957
- })();
2958
-
2959
- // Remove all wrapping divs from a widget to get its html
2960
- var getTextWidgetContents = function( $el ){
2961
- var $divs = $el.find( 'div' );
2962
- if( ! $divs.length ) {
2963
- return $el.html();
2964
- }
2965
-
2966
- var i;
2967
- for( i = 0; i < $divs.length - 1; i++ ) {
2968
- if( jQuery.trim( $divs.eq(i).text() ) != jQuery.trim( $divs.eq(i+1).text() ) ) {
2969
- break;
2970
- }
2971
- }
2972
-
2973
- var title = $divs.eq( i ).find( '.widget-title:header' ),
2974
- titleText = '';
2975
-
2976
- if( title.length ) {
2977
- titleText = title.html();
2978
- title.remove();
2979
- }
2980
-
2981
- return {
2982
- title: titleText,
2983
- text: $divs.eq(i).html(),
2984
- };
2985
- };
2986
-
2987
- var $layout = $html.find( '.panel-layout' ).eq(0);
2988
- var filterNestedLayout = function( i, el ){
2989
- return jQuery( el ).closest( '.panel-layout' ).is( $layout );
2990
- };
2991
-
2992
- $html.find('> .panel-layout > .panel-grid').filter( filterNestedLayout ).each( function( ri, el ){
2993
- var $row = jQuery( el ),
2994
- $cells = $row.find( '.panel-grid-cell' ).filter( filterNestedLayout );
2995
-
2996
- panels_data.grids.push( {
2997
- cells: $cells.length,
2998
- style: $row.data( 'style' ),
2999
- ratio: $row.data( 'ratio' ),
3000
- ratio_direction: $row.data( 'ratio-direction' ),
3001
- color_label: $row.data( 'color-label' ),
3002
- label: $row.data( 'label' ),
3003
- } );
3004
-
3005
- $cells.each( function( ci, el ){
3006
- var $cell = jQuery( el ),
3007
- $widgets = $cell.find( '.so-panel' ).filter( filterNestedLayout );
3008
-
3009
- panels_data.grid_cells.push( {
3010
- grid: ri,
3011
- weight: ! _.isUndefined( $cell.data( 'weight' ) ) ? parseFloat( $cell.data( 'weight' ) ) : 1,
3012
- style: $cell.data( 'style' ),
3013
- } );
3014
-
3015
- $widgets.each( function( wi, el ){
3016
- var $widget = jQuery(el),
3017
- widgetContent = $widget.find('.panel-widget-style').length ? $widget.find('.panel-widget-style').html() : $widget.html(),
3018
- panels_info = {
3019
- grid: ri,
3020
- cell: ci,
3021
- style: $widget.data( 'style' ),
3022
- raw: false,
3023
- label: $widget.data( 'label' )
3024
- };
3025
-
3026
- widgetContent = widgetContent.trim();
3027
-
3028
- // Check if this is a SiteOrigin Widget
3029
- var match = re.exec( widgetContent );
3030
- if( ! _.isNull( match ) && widgetContent.replace( re, '' ).trim() === '' ) {
3031
- try {
3032
- var classMatch = /class="(.*?)"/.exec( match[3] ),
3033
- dataInput = jQuery( match[5] ),
3034
- data = JSON.parse( decodeEntities( dataInput.val( ) ) ),
3035
- newWidget = data.instance;
3036
-
3037
- panels_info.class = classMatch[1].replace( /\\\\+/g, '\\' );
3038
- panels_info.raw = false;
3039
-
3040
- newWidget.panels_info = panels_info;
3041
- panels_data.widgets.push( newWidget );
3042
- }
3043
- catch ( err ) {
3044
- // There was a problem, so treat this as a standard editor widget
3045
- panels_info.class = editorClass;
3046
- panels_data.widgets.push( _.extend( getTextWidgetContents( $widget ), {
3047
- filter: "1",
3048
- type: "visual",
3049
- panels_info: panels_info
3050
- } ) );
3051
- }
3052
-
3053
- // Continue
3054
- return true;
3055
- }
3056
- else if( widgetContent.indexOf( 'panel-layout' ) !== -1 ) {
3057
- // Check if this is a layout widget
3058
- var $widgetContent = jQuery( '<div>' + widgetContent + '</div>' );
3059
- if( $widgetContent.find('.panel-layout .panel-grid').length ) {
3060
- // This is a standard editor class widget
3061
- panels_info.class = 'SiteOrigin_Panels_Widgets_Layout';
3062
- panels_data.widgets.push( {
3063
- panels_data: thisModel.getPanelsDataFromHtml( widgetContent, editorClass ),
3064
- panels_info: panels_info
3065
- } );
3066
-
3067
- // continue
3068
- return true;
3069
- }
3070
- }
3071
-
3072
- // This is a standard editor class widget
3073
- panels_info.class = editorClass;
3074
- panels_data.widgets.push( _.extend( getTextWidgetContents( $widget ), {
3075
- filter: "1",
3076
- type: "visual",
3077
- panels_info: panels_info
3078
- } ) );
3079
- return true;
3080
- } );
3081
- } );
3082
- } );
3083
-
3084
- // Remove all the Page Builder content
3085
- $html.find('.panel-layout').remove();
3086
- $html.find('style[data-panels-style-for-post]').remove();
3087
-
3088
- // If there's anything left, add it to an editor widget at the end of panels_data
3089
- if( $html.html().replace(/^\s+|\s+$/gm,'').length ) {
3090
- panels_data.grids.push( {
3091
- cells: 1,
3092
- style: {},
3093
- } );
3094
- panels_data.grid_cells.push( {
3095
- grid: panels_data.grids.length - 1,
3096
- weight: 1,
3097
- } );
3098
- panels_data.widgets.push( {
3099
- filter: "1",
3100
- text: $html.html().replace(/^\s+|\s+$/gm,''),
3101
- title: "",
3102
- type: "visual",
3103
- panels_info: {
3104
- class: editorClass,
3105
- raw: false,
3106
- grid: panels_data.grids.length - 1,
3107
- cell: 0
3108
- }
3109
- } );
3110
- }
3111
-
3112
- return panels_data;
3113
- }
3114
- else {
3115
- // This is probably just old school post content
3116
- return {
3117
- grid_cells: [ { grid: 0, weight: 1 } ],
3118
- grids: [ { cells: 1 } ],
3119
- widgets: [
3120
- {
3121
- filter: "1",
3122
- text: html,
3123
- title: "",
3124
- type: "visual",
3125
- panels_info: {
3126
- class: editorClass,
3127
- raw: false,
3128
- grid: 0,
3129
- cell: 0
3130
- }
3131
- }
3132
- ]
3133
- };
3134
- }
3135
- }
3136
- } );
3137
-
3138
- },{}],18:[function(require,module,exports){
3139
- module.exports = Backbone.Model.extend( {
3140
- /* A collection of widgets */
3141
- widgets: {},
3142
-
3143
- /* The row this model belongs to */
3144
- row: null,
3145
-
3146
- defaults: {
3147
- weight: 0,
3148
- style: {}
3149
- },
3150
-
3151
- indexes: null,
3152
-
3153
- /**
3154
- * Set up the cell model
3155
- */
3156
- initialize: function () {
3157
- this.set( 'widgets', new panels.collection.widgets() );
3158
- this.on( 'destroy', this.onDestroy, this );
3159
- },
3160
-
3161
- /**
3162
- * Triggered when we destroy a cell
3163
- */
3164
- onDestroy: function () {
3165
- // Destroy all the widgets
3166
- _.invoke( this.get('widgets').toArray(), 'destroy' );
3167
- this.get('widgets').reset();
3168
- },
3169
-
3170
- /**
3171
- * Create a clone of the cell, along with all its widgets
3172
- */
3173
- clone: function ( row, cloneOptions ) {
3174
- if ( _.isUndefined( row ) ) {
3175
- row = this.row;
3176
- }
3177
- cloneOptions = _.extend( {cloneWidgets: true}, cloneOptions );
3178
-
3179
- var clone = new this.constructor( this.attributes );
3180
- clone.set( 'collection', row.get('cells'), {silent: true} );
3181
- clone.row = row;
3182
-
3183
- if ( cloneOptions.cloneWidgets ) {
3184
- // Now we're going add all the widgets that belong to this, to the clone
3185
- this.get('widgets').each( function ( widget ) {
3186
- clone.get('widgets').add( widget.clone( clone, cloneOptions ), {silent: true} );
3187
- } );
3188
- }
3189
-
3190
- return clone;
3191
- }
3192
-
3193
- } );
3194
-
3195
- },{}],19:[function(require,module,exports){
3196
- module.exports = Backbone.Model.extend( {
3197
- defaults: {
3198
- text: '',
3199
- data: '',
3200
- time: null,
3201
- count: 1
3202
- }
3203
- } );
3204
-
3205
- },{}],20:[function(require,module,exports){
3206
- module.exports = Backbone.Model.extend( {
3207
- /* The builder model */
3208
- builder: null,
3209
-
3210
- defaults: {
3211
- style: {}
3212
- },
3213
-
3214
- indexes: null,
3215
-
3216
- /**
3217
- * Initialize the row model
3218
- */
3219
- initialize: function () {
3220
- if ( _.isEmpty(this.get('cells') ) ) {
3221
- this.set('cells', new panels.collection.cells());
3222
- }
3223
- else {
3224
- // Make sure that the cells have this row set as their parent
3225
- this.get('cells').each( function( cell ){
3226
- cell.row = this;
3227
- }.bind( this ) );
3228
- }
3229
- this.on( 'destroy', this.onDestroy, this );
3230
- },
3231
-
3232
- /**
3233
- * Add cells to the model row
3234
- *
3235
- * @param newCells the updated collection of cell models
3236
- */
3237
- setCells: function ( newCells ) {
3238
- var currentCells = this.get('cells') || new panels.collection.cells();
3239
- var cellsToRemove = [];
3240
-
3241
- currentCells.each(function (cell, i) {
3242
- var newCell = newCells.at(i);
3243
- if(newCell) {
3244
- cell.set('weight', newCell.get('weight'));
3245
- } else {
3246
- var newParentCell = currentCells.at( newCells.length - 1 );
3247
-
3248
- // First move all the widgets to the new cell
3249
- var widgetsToMove = cell.get('widgets').models.slice();
3250
- for ( var j = 0; j < widgetsToMove.length; j++ ) {
3251
- widgetsToMove[j].moveToCell( newParentCell, { silent: false } );
3252
- }
3253
-
3254
- cellsToRemove.push(cell);
3255
- }
3256
- });
3257
-
3258
- _.each(cellsToRemove, function(cell) {
3259
- currentCells.remove(cell);
3260
- });
3261
-
3262
- if( newCells.length > currentCells.length) {
3263
- _.each(newCells.slice(currentCells.length, newCells.length), function (newCell) {
3264
- // TODO: make sure row and collection is set correctly when cell is created then we can just add new cells
3265
- newCell.set({collection: currentCells});
3266
- newCell.row = this;
3267
- currentCells.add(newCell);
3268
- }.bind(this));
3269
- }
3270
-
3271
- // Rescale the cells when we add or remove
3272
- this.reweightCells();
3273
- },
3274
-
3275
- /**
3276
- * Make sure that all the cell weights add up to 1
3277
- */
3278
- reweightCells: function () {
3279
- var totalWeight = 0;
3280
- var cells = this.get('cells');
3281
- cells.each( function ( cell ) {
3282
- totalWeight += cell.get( 'weight' );
3283
- } );
3284
-
3285
- cells.each( function ( cell ) {
3286
- cell.set( 'weight', cell.get( 'weight' ) / totalWeight );
3287
- } );
3288
-
3289
- // This is for the row view to hook into and resize
3290
- this.trigger( 'reweight_cells' );
3291
- },
3292
-
3293
- /**
3294
- * Triggered when the model is destroyed
3295
- */
3296
- onDestroy: function () {
3297
- // Also destroy all the cells
3298
- _.invoke( this.get('cells').toArray(), 'destroy' );
3299
- this.get('cells').reset();
3300
- },
3301
-
3302
- /**
3303
- * Create a clone of the row, along with all its cells
3304
- *
3305
- * @param {panels.model.builder} builder The builder model to attach this to.
3306
- *
3307
- * @return {panels.model.row} The cloned row.
3308
- */
3309
- clone: function ( builder ) {
3310
- if ( _.isUndefined( builder ) ) {
3311
- builder = this.builder;
3312
- }
3313
-
3314
- var clone = new this.constructor( this.attributes );
3315
- clone.set( 'collection', builder.get('rows'), {silent: true} );
3316
- clone.builder = builder;
3317
-
3318
- var cellClones = new panels.collection.cells();
3319
- this.get('cells').each( function ( cell ) {
3320
- cellClones.add( cell.clone( clone ), {silent: true} );
3321
- } );
3322
-
3323
- clone.set( 'cells', cellClones );
3324
-
3325
- return clone;
3326
- }
3327
- } );
3328
-
3329
- },{}],21:[function(require,module,exports){
3330
- /**
3331
- * Model for an instance of a widget
3332
- */
3333
- module.exports = Backbone.Model.extend( {
3334
-
3335
- cell: null,
3336
-
3337
- defaults: {
3338
- // The PHP Class of the widget
3339
- class: null,
3340
-
3341
- // Is this class missing? Missing widgets are a special case.
3342
- missing: false,
3343
-
3344
- // The values of the widget
3345
- values: {},
3346
-
3347
- // Have the current values been passed through the widgets update function
3348
- raw: false,
3349
-
3350
- // Visual style fields
3351
- style: {},
3352
-
3353
- read_only: false,
3354
- widget_id: '',
3355
- },
3356
-
3357
- indexes: null,
3358
-
3359
- initialize: function () {
3360
- var widgetClass = this.get( 'class' );
3361
- if ( _.isUndefined( panelsOptions.widgets[widgetClass] ) || ! panelsOptions.widgets[widgetClass].installed ) {
3362
- this.set( 'missing', true );
3363
- }
3364
- },
3365
-
3366
- /**
3367
- * @param field
3368
- * @returns {*}
3369
- */
3370
- getWidgetField: function ( field ) {
3371
- if ( _.isUndefined( panelsOptions.widgets[this.get( 'class' )] ) ) {
3372
- if ( field === 'title' || field === 'description' ) {
3373
- return panelsOptions.loc.missing_widget[field];
3374
- } else {
3375
- return '';
3376
- }
3377
- } else if ( this.has( 'label' ) && ! _.isEmpty( this.get( 'label' ) ) ) {
3378
- // Use the label instead of the actual widget title
3379
- return this.get( 'label' );
3380
- } else {
3381
- return panelsOptions.widgets[ this.get( 'class' ) ][ field ];
3382
- }
3383
- },
3384
-
3385
- /**
3386
- * Move this widget model to a new cell. Called by the views.
3387
- *
3388
- * @param panels.model.cell newCell
3389
- * @param object options The options passed to the
3390
- *
3391
- * @return boolean Indicating if the widget was moved into a different cell
3392
- */
3393
- moveToCell: function ( newCell, options, at ) {
3394
- options = _.extend( {
3395
- silent: true,
3396
- }, options );
3397
-
3398
- this.cell = newCell;
3399
- this.collection.remove( this, options );
3400
- newCell.get('widgets').add( this, _.extend( {
3401
- at: at
3402
- }, options ) );
3403
-
3404
- // This should be used by views to reposition everything.
3405
- this.trigger( 'move_to_cell', newCell, at );
3406
-
3407
- return this;
3408
- },
3409
-
3410
- /**
3411
- * Trigger an event on the model that indicates a user wants to edit it
3412
- */
3413
- triggerEdit: function () {
3414
- this.trigger( 'user_edit', this );
3415
- },
3416
-
3417
- /**
3418
- * Trigger an event on the widget that indicates a user wants to duplicate it
3419
- */
3420
- triggerDuplicate: function () {
3421
- this.trigger( 'user_duplicate', this );
3422
- },
3423
-
3424
- /**
3425
- * This is basically a wrapper for set that checks if we need to trigger a change
3426
- */
3427
- setValues: function ( values ) {
3428
- var hasChanged = false;
3429
- if ( JSON.stringify( values ) !== JSON.stringify( this.get( 'values' ) ) ) {
3430
- hasChanged = true;
3431
- }
3432
-
3433
- this.set( 'values', values, {silent: true} );
3434
-
3435
- if ( hasChanged ) {
3436
- // We'll trigger our own change events.
3437
- // NB: Must include the model being changed (i.e. `this`) as a workaround for a bug in Backbone 1.2.3
3438
- this.trigger( 'change', this );
3439
- this.trigger( 'change:values' );
3440
- }
3441
- },
3442
-
3443
- /**
3444
- * Create a clone of this widget attached to the given cell.
3445
- *
3446
- * @param {panels.model.cell} cell The cell model we're attaching this widget clone to.
3447
- * @returns {panels.model.widget}
3448
- */
3449
- clone: function ( cell, options ) {
3450
- if ( _.isUndefined( cell ) ) {
3451
- cell = this.cell;
3452
- }
3453
-
3454
- var clone = new this.constructor( this.attributes );
3455
-
3456
- // Create a deep clone of the original values
3457
- var cloneValues = JSON.parse( JSON.stringify( this.get( 'values' ) ) );
3458
-
3459
- // We want to exclude any fields that start with _ from the clone. Assuming these are internal.
3460
- var cleanClone = function ( vals ) {
3461
- _.each( vals, function ( el, i ) {
3462
- if ( _.isString( i ) && i[0] === '_' ) {
3463
- delete vals[i];
3464
- }
3465
- else if ( _.isObject( vals[i] ) ) {
3466
- cleanClone( vals[i] );
3467
- }
3468
- } );
3469
-
3470
- return vals;
3471
- };
3472
- cloneValues = cleanClone( cloneValues );
3473
-
3474
- if ( this.get( 'class' ) === "SiteOrigin_Panels_Widgets_Layout" ) {
3475
- // Special case of this being a layout widget, it needs a new ID
3476
- cloneValues.builder_id = Math.random().toString( 36 ).substr( 2 );
3477
- }
3478
-
3479
- clone.set( 'widget_id', '' );
3480
- clone.set( 'values', cloneValues, {silent: true} );
3481
- clone.set( 'collection', cell.get('widgets'), {silent: true} );
3482
- clone.cell = cell;
3483
-
3484
- // This is used to force a form reload later on
3485
- clone.isDuplicate = true;
3486
-
3487
- return clone;
3488
- },
3489
-
3490
- /**
3491
- * Gets the value that makes most sense as the title.
3492
- */
3493
- getTitle: function () {
3494
- var widgetData = panelsOptions.widgets[this.get( 'class' )];
3495
-
3496
- if ( _.isUndefined( widgetData ) ) {
3497
- return this.get( 'class' ).replace( /_/g, ' ' );
3498
- }
3499
- else if ( ! _.isUndefined( widgetData.panels_title ) ) {
3500
- // This means that the widget has told us which field it wants us to use as a title
3501
- if ( widgetData.panels_title === false ) {
3502
- return panelsOptions.widgets[this.get( 'class' )].description;
3503
- }
3504
- }
3505
-
3506
- var values = this.get( 'values' );
3507
-
3508
- // Create a list of fields to check for a title
3509
- var titleFields = ['title', 'text'];
3510
-
3511
- for ( var k in values ) {
3512
- if ( values.hasOwnProperty( k ) ) {
3513
- titleFields.push( k );
3514
- }
3515
- }
3516
-
3517
- titleFields = _.uniq( titleFields );
3518
-
3519
- for ( var i in titleFields ) {
3520
- if (
3521
- ! _.isUndefined( values[titleFields[i]] ) &&
3522
- _.isString( values[titleFields[i]] ) &&
3523
- values[titleFields[i]] !== '' &&
3524
- values[titleFields[i]] !== 'on' &&
3525
- titleFields[i][0] !== '_' && ! jQuery.isNumeric( values[titleFields[i]] )
3526
- ) {
3527
- var title = values[titleFields[i]];
3528
- title = title.replace( /<\/?[^>]+(>|$)/g, "" );
3529
- var parts = title.split( " " );
3530
- parts = parts.slice( 0, 20 );
3531
- return parts.join( ' ' );
3532
- }
3533
- }
3534
-
3535
- // If we still have nothing, then just return the widget description
3536
- return this.getWidgetField( 'description' );
3537
- }
3538
-
3539
- } );
3540
-
3541
- },{}],22:[function(require,module,exports){
3542
- var panels = window.panels, $ = jQuery;
3543
-
3544
- module.exports = Backbone.View.extend( {
3545
- wrapperTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-context-menu' ).html() ) ),
3546
- sectionTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-context-menu-section' ).html() ) ),
3547
-
3548
- contexts: [],
3549
- active: false,
3550
-
3551
- events: {
3552
- 'keyup .so-search-wrapper input': 'searchKeyUp'
3553
- },
3554
-
3555
- /**
3556
- * Intialize the context menu
3557
- */
3558
- initialize: function () {
3559
- this.listenContextMenu();
3560
- this.render();
3561
- this.attach();
3562
- },
3563
-
3564
- /**
3565
- * Listen for the right click context menu
3566
- */
3567
- listenContextMenu: function () {
3568
- var thisView = this;
3569
-
3570
- $( window ).on( 'contextmenu', function ( e ) {
3571
- if ( thisView.active && ! thisView.isOverEl( thisView.$el, e ) ) {
3572
- thisView.closeMenu();
3573
- thisView.active = false;
3574
- e.preventDefault();
3575
- return false;
3576
- }
3577
-
3578
- if ( thisView.active ) {
3579
- // Lets not double up on the context menu
3580
- return true;
3581
- }
3582
-
3583
- // Other components should listen to activate_context
3584
- thisView.active = false;
3585
- thisView.trigger( 'activate_context', e, thisView );
3586
-
3587
- if ( thisView.active ) {
3588
- // We don't want the default event to happen.
3589
- e.preventDefault();
3590
-
3591
- thisView.openMenu( {
3592
- left: e.pageX,
3593
- top: e.pageY
3594
- } );
3595
- }
3596
- } );
3597
- },
3598
-
3599
- render: function () {
3600
- this.setElement( this.wrapperTemplate() );
3601
- },
3602
-
3603
- attach: function () {
3604
- this.$el.appendTo( 'body' );
3605
- },
3606
-
3607
- /**
3608
- * Display the actual context menu.
3609
- *
3610
- * @param position
3611
- */
3612
- openMenu: function ( position ) {
3613
- this.trigger( 'open_menu' );
3614
-
3615
- // Start listening for situations when we should close the menu
3616
- $( window ).on( 'keyup', {menu: this}, this.keyboardListen );
3617
- $( window ).on( 'click', {menu: this}, this.clickOutsideListen );
3618
-
3619
- // Set the maximum height of the menu
3620
- this.$el.css( 'max-height', $( window ).height() - 20 );
3621
-
3622
- // Correct the left position
3623
- if ( position.left + this.$el.outerWidth() + 10 >= $( window ).width() ) {
3624
- position.left = $( window ).width() - this.$el.outerWidth() - 10;
3625
- }
3626
- if ( position.left <= 0 ) {
3627
- position.left = 10;
3628
- }
3629
-
3630
- // Check top position
3631
- if ( position.top + this.$el.outerHeight() - $( window ).scrollTop() + 10 >= $( window ).height() ) {
3632
- position.top = $( window ).height() + $( window ).scrollTop() - this.$el.outerHeight() - 10;
3633
- }
3634
- if ( position.left <= 0 ) {
3635
- position.left = 10;
3636
- }
3637
-
3638
- // position the contextual menu
3639
- this.$el.css( {
3640
- left: position.left + 1,
3641
- top: position.top + 1
3642
- } ).show();
3643
- this.$( '.so-search-wrapper input' ).focus();
3644
- },
3645
-
3646
- closeMenu: function () {
3647
- this.trigger( 'close_menu' );
3648
-
3649
- // Stop listening for situations when we should close the menu
3650
- $( window ).off( 'keyup', this.keyboardListen );
3651
- $( window ).off( 'click', this.clickOutsideListen );
3652
-
3653
- this.active = false;
3654
- this.$el.empty().hide();
3655
- },
3656
-
3657
- /**
3658
- * Keyboard events handler
3659
- */
3660
- keyboardListen: function ( e ) {
3661
- var menu = e.data.menu;
3662
-
3663
- switch ( e.which ) {
3664
- case 27:
3665
- menu.closeMenu();
3666
- break;
3667
- }
3668
- },
3669
-
3670
- /**
3671
- * Listen for a click outside the menu to close it.
3672
- * @param e
3673
- */
3674
- clickOutsideListen: function ( e ) {
3675
- var menu = e.data.menu;
3676
- if ( e.which !== 3 && menu.$el.is( ':visible' ) && ! menu.isOverEl( menu.$el, e ) ) {
3677
- menu.closeMenu();
3678
- }
3679
- },
3680
-
3681
- /**
3682
- * Add a new section to the contextual menu.
3683
- *
3684
- * @param settings
3685
- * @param items
3686
- * @param callback
3687
- */
3688
- addSection: function ( id, settings, items, callback ) {
3689
- var thisView = this;
3690
- settings = _.extend( {
3691
- display: 5,
3692
- defaultDisplay: false,
3693
- search: true,
3694
-
3695
- // All the labels
3696
- sectionTitle: '',
3697
- searchPlaceholder: '',
3698
-
3699
- // This is the key to be used in items for the title. Makes it easier to list objects
3700
- titleKey: 'title'
3701
- }, settings );
3702
-
3703
- // Create the new section
3704
- var section = $( this.sectionTemplate( {
3705
- settings: settings,
3706
- items: items
3707
- } ) ).attr( 'id', 'panels-menu-section-' + id );
3708
- this.$el.append( section );
3709
-
3710
- section.find( '.so-item:not(.so-confirm)' ).click( function () {
3711
- var $$ = $( this );
3712
- callback( $$.data( 'key' ) );
3713
- thisView.closeMenu();
3714
- } );
3715
-
3716
- section.find( '.so-item.so-confirm' ).click( function () {
3717
- var $$ = $( this );
3718
-
3719
- if ( $$.hasClass( 'so-confirming' ) ) {
3720
- callback( $$.data( 'key' ) );
3721
- thisView.closeMenu();
3722
- return;
3723
- }
3724
-
3725
- $$
3726
- .data( 'original-text', $$.html() )
3727
- .addClass( 'so-confirming' )
3728
- .html( '<span class="dashicons dashicons-yes"></span> ' + panelsOptions.loc.dropdown_confirm );
3729
-
3730
- setTimeout( function () {
3731
- $$.removeClass( 'so-confirming' );
3732
- $$.html( $$.data( 'original-text' ) );
3733
- }, 2500 );
3734
- } );
3735
-
3736
- section.data( 'settings', settings ).find( '.so-search-wrapper input' ).trigger( 'keyup' );
3737
-
3738
- this.active = true;
3739
- },
3740
-
3741
- /**
3742
- * Check if a section exists in the current menu.
3743
- *
3744
- * @param id
3745
- * @returns {boolean}
3746
- */
3747
- hasSection: function( id ){
3748
- return this.$el.find( '#panels-menu-section-' + id ).length > 0;
3749
- },
3750
-
3751
- /**
3752
- * Handle searching inside a section.
3753
- *
3754
- * @param e
3755
- * @returns {boolean}
3756
- */
3757
- searchKeyUp: function ( e ) {
3758
- var
3759
- $$ = $( e.currentTarget ),
3760
- section = $$.closest( '.so-section' ),
3761
- settings = section.data( 'settings' );
3762
-
3763
- if ( e.which === 38 || e.which === 40 ) {
3764
- // First, lets check if this is an up, down or enter press
3765
- var
3766
- items = section.find( 'ul li:visible' ),
3767
- activeItem = items.filter( '.so-active' ).eq( 0 );
3768
-
3769
- if ( activeItem.length ) {
3770
- items.removeClass( 'so-active' );
3771
-
3772
- var activeIndex = items.index( activeItem );
3773
-
3774
- if ( e.which === 38 ) {
3775
- if ( activeIndex - 1 < 0 ) {
3776
- activeItem = items.last();
3777
- } else {
3778
- activeItem = items.eq( activeIndex - 1 );
3779
- }
3780
- }
3781
- else if ( e.which === 40 ) {
3782
- if ( activeIndex + 1 >= items.length ) {
3783
- activeItem = items.first();
3784
- } else {
3785
- activeItem = items.eq( activeIndex + 1 );
3786
- }
3787
- }
3788
- }
3789
- else if ( e.which === 38 ) {
3790
- activeItem = items.last();
3791
- }
3792
- else if ( e.which === 40 ) {
3793
- activeItem = items.first();
3794
- }
3795
-
3796
- activeItem.addClass( 'so-active' );
3797
- return false;
3798
- }
3799
- if ( e.which === 13 ) {
3800
- if ( section.find( 'ul li:visible' ).length === 1 ) {
3801
- // We'll treat a single visible item as active when enter is clicked
3802
- section.find( 'ul li:visible' ).trigger( 'click' );
3803
- return false;
3804
- }
3805
- section.find( 'ul li.so-active:visible' ).trigger( 'click' );
3806
- return false;
3807
- }
3808
-
3809
- if ( $$.val() === '' ) {
3810
- // We'll display the defaultDisplay items
3811
- if ( settings.defaultDisplay ) {
3812
- section.find( '.so-item' ).hide();
3813
- for ( var i = 0; i < settings.defaultDisplay.length; i ++ ) {
3814
- section.find( '.so-item[data-key="' + settings.defaultDisplay[i] + '"]' ).show();
3815
- }
3816
- } else {
3817
- // We'll just display all the items
3818
- section.find( '.so-item' ).show();
3819
- }
3820
- } else {
3821
- section.find( '.so-item' ).hide().each( function () {
3822
- var item = $( this );
3823
- if ( item.html().toLowerCase().indexOf( $$.val().toLowerCase() ) !== - 1 ) {
3824
- item.show();
3825
- }
3826
- } );
3827
- }
3828
-
3829
- // Now, we'll only show the first settings.display visible items
3830
- section.find( '.so-item:visible:gt(' + (
3831
- settings.display - 1
3832
- ) + ')' ).hide();
3833
-
3834
-
3835
- if ( section.find( '.so-item:visible' ).length === 0 && $$.val() !== '' ) {
3836
- section.find( '.so-no-results' ).show();
3837
- } else {
3838
- section.find( '.so-no-results' ).hide();
3839
- }
3840
- },
3841
-
3842
- /**
3843
- * Check if the given mouse event is over the element
3844
- * @param el
3845
- * @param event
3846
- */
3847
- isOverEl: function ( el, event ) {
3848
- var elPos = [
3849
- [el.offset().left, el.offset().top],
3850
- [el.offset().left + el.outerWidth(), el.offset().top + el.outerHeight()]
3851
- ];
3852
-
3853
- // Return if this event is over the given element
3854
- return (
3855
- event.pageX >= elPos[0][0] && event.pageX <= elPos[1][0] &&
3856
- event.pageY >= elPos[0][1] && event.pageY <= elPos[1][1]
3857
- );
3858
- }
3859
-
3860
- } );
3861
-
3862
- },{}],23:[function(require,module,exports){
3863
- var panels = window.panels, $ = jQuery;
3864
-
3865
- module.exports = Backbone.View.extend( {
3866
-
3867
- // Config options
3868
- config: {},
3869
-
3870
- template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder' ).html() ) ),
3871
- dialogs: {},
3872
- rowsSortable: null,
3873
- dataField: false,
3874
- currentData: '',
3875
-
3876
- attachedToEditor: false,
3877
- attachedVisible: false,
3878
- liveEditor: undefined,
3879
- menu: false,
3880
-
3881
- activeCell: null,
3882
-
3883
- events: {
3884
- 'click .so-tool-button.so-widget-add': 'displayAddWidgetDialog',
3885
- 'click .so-tool-button.so-row-add': 'displayAddRowDialog',
3886
- 'click .so-tool-button.so-prebuilt-add': 'displayAddPrebuiltDialog',
3887
- 'click .so-tool-button.so-history': 'displayHistoryDialog',
3888
- 'click .so-tool-button.so-live-editor': 'displayLiveEditor'
3889
- },
3890
-
3891
- /* A row collection */
3892
- rows: null,
3893
-
3894
- /**
3895
- * Initialize the builder
3896
- */
3897
- initialize: function ( options ) {
3898
- var builder = this;
3899
-
3900
- this.config = _.extend( {
3901
- loadLiveEditor: false,
3902
- builderSupports: {}
3903
- }, options.config );
3904
-
3905
- // These are the actions that a user can perform in the builder
3906
- this.config.builderSupports = _.extend( {
3907
- addRow: true,
3908
- editRow: true,
3909
- deleteRow: true,
3910
- moveRow: true,
3911
- addWidget: true,
3912
- editWidget: true,
3913
- deleteWidget: true,
3914
- moveWidget: true,
3915
- prebuilt: true,
3916
- history: true,
3917
- liveEditor: true,
3918
- revertToEditor: true
3919
- }, this.config.builderSupports );
3920
-
3921
- // Automatically load the live editor as soon as it's ready
3922
- if ( options.config.loadLiveEditor ) {
3923
- this.on( 'builder_live_editor_added', function () {
3924
- this.displayLiveEditor();
3925
- } );
3926
- }
3927
-
3928
- // Now lets create all the dialog boxes that the main builder interface uses
3929
- this.dialogs = {
3930
- widgets: new panels.dialog.widgets(),
3931
- row: new panels.dialog.row(),
3932
- prebuilt: new panels.dialog.prebuilt()
3933
- };
3934
-
3935
- // Set the builder for each dialog and render it.
3936
- _.each( this.dialogs, function ( p, i, d ) {
3937
- d[ i ].setBuilder( builder );
3938
- } );
3939
-
3940
- this.dialogs.row.setRowDialogType( 'create' );
3941
-
3942
- // This handles a new row being added to the collection - we'll display it in the interface
3943
- this.model.get( 'rows' ).on( 'add', this.onAddRow, this );
3944
-
3945
- // Reflow the entire builder when ever the
3946
- $( window ).resize( function ( e ) {
3947
- if ( e.target === window ) {
3948
- builder.trigger( 'builder_resize' );
3949
- }
3950
- } );
3951
-
3952
- // When the data changes in the model, store it in the field
3953
- this.model.on( 'change:data load_panels_data', this.storeModelData, this );
3954
-
3955
- // Handle a content change
3956
- this.on( 'content_change', this.handleContentChange, this );
3957
- this.on( 'display_builder', this.handleDisplayBuilder, this );
3958
- this.on( 'hide_builder', this.handleHideBuilder, this );
3959
- this.on( 'builder_rendered builder_resize', this.handleBuilderSizing, this );
3960
- this.model.on( 'change:data load_panels_data', this.toggleWelcomeDisplay, this );
3961
-
3962
- this.on( 'display_builder', this.wrapEditorExpandAdjust, this );
3963
-
3964
- // Create the context menu for this builder
3965
- this.menu = new panels.utils.menu( {} );
3966
- this.menu.on( 'activate_context', this.activateContextMenu, this );
3967
-
3968
- if ( this.config.loadOnAttach ) {
3969
- this.on( 'builder_attached_to_editor', function () {
3970
- this.displayAttachedBuilder( { confirm: false } );
3971
- }, this );
3972
- }
3973
-
3974
-
3975
- return this;
3976
- },
3977
-
3978
- /**
3979
- * Render the builder interface.
3980
- *
3981
- * @return {panels.view.builder}
3982
- */
3983
- render: function () {
3984
- // this.$el.html( this.template() );
3985
- this.setElement( this.template() );
3986
- this.$el
3987
- .attr( 'id', 'siteorigin-panels-builder-' + this.cid )
3988
- .addClass( 'so-builder-container' );
3989
-
3990
- this.trigger( 'builder_rendered' );
3991
-
3992
- return this;
3993
- },
3994
-
3995
- /**
3996
- * Attach the builder to the given container
3997
- *
3998
- * @param container
3999
- * @returns {panels.view.builder}
4000
- */
4001
- attach: function ( options ) {
4002
-
4003
- options = _.extend( {
4004
- container: false,
4005
- dialog: false
4006
- }, options );
4007
-
4008
- if ( options.dialog ) {
4009
- // We're going to add this to a dialog
4010
- this.dialog = new panels.dialog.builder();
4011
- this.dialog.builder = this;
4012
- } else {
4013
- // Attach this in the standard way
4014
- this.$el.appendTo( options.container );
4015
- this.metabox = options.container.closest( '.postbox' );
4016
- this.initSortable();
4017
- this.trigger( 'attached_to_container', options.container );
4018
- }
4019
-
4020
- this.trigger( 'builder_attached' );
4021
-
4022
- // Add support for components we have
4023
-
4024
- if ( this.supports( 'liveEditor' ) ) {
4025
- this.addLiveEditor();
4026
- }
4027
- if ( this.supports( 'history' ) ) {
4028
- this.addHistoryBrowser();
4029
- }
4030
-
4031
- // Hide toolbar buttons we don't support
4032
- var toolbar = this.$( '.so-builder-toolbar' );
4033
- var welcomeMessageContainer = this.$( '.so-panels-welcome-message' );
4034
- var welcomeMessage = panelsOptions.loc.welcomeMessage;
4035
-
4036
- var supportedItems = [];
4037
-
4038
- if ( !this.supports( 'addWidget' ) ) {
4039
- toolbar.find( '.so-widget-add' ).hide();
4040
- } else {
4041
- supportedItems.push( welcomeMessage.addWidgetButton );
4042
- }
4043
- if ( !this.supports( 'addRow' ) ) {
4044
- toolbar.find( '.so-row-add' ).hide();
4045
- } else {
4046
- supportedItems.push( welcomeMessage.addRowButton );
4047
- }
4048
- if ( !this.supports( 'prebuilt' ) ) {
4049
- toolbar.find( '.so-prebuilt-add' ).hide();
4050
- } else {
4051
- supportedItems.push( welcomeMessage.addPrebuiltButton );
4052
- }
4053
-
4054
- var msg = '';
4055
- if ( supportedItems.length === 3 ) {
4056
- msg = welcomeMessage.threeEnabled;
4057
- } else if ( supportedItems.length === 2 ) {
4058
- msg = welcomeMessage.twoEnabled;
4059
- } else if ( supportedItems.length === 1 ) {
4060
- msg = welcomeMessage.oneEnabled;
4061
- } else if ( supportedItems.length === 0 ) {
4062
- msg = welcomeMessage.addingDisabled;
4063
- }
4064
-
4065
- var resTemplate = _.template( panels.helpers.utils.processTemplate( msg ) );
4066
- var msgHTML = resTemplate( { items: supportedItems } ) + ' ' + welcomeMessage.docsMessage;
4067
- welcomeMessageContainer.find( '.so-message-wrapper' ).html( msgHTML );
4068
-
4069
- return this;
4070
- },
4071
-
4072
- /**
4073
- * This will move the Page Builder meta box into the editor if we're in the post/page edit interface.
4074
- *
4075
- * @returns {panels.view.builder}
4076
- */
4077
- attachToEditor: function () {
4078
- if ( this.config.editorType !== 'tinyMCE' ) {
4079
- return this;
4080
- }
4081
-
4082
- this.attachedToEditor = true;
4083
- var metabox = this.metabox;
4084
- var thisView = this;
4085
-
4086
- // Handle switching between the page builder and other tabs
4087
- $( '#wp-content-wrap .wp-editor-tabs' )
4088
- .find( '.wp-switch-editor' )
4089
- .click( function ( e ) {
4090
- e.preventDefault();
4091
- $( '#wp-content-editor-container' ).show();
4092
-
4093
- // metabox.hide();
4094
- $( '#wp-content-wrap' ).removeClass( 'panels-active' );
4095
- $( '#content-resize-handle' ).show();
4096
-
4097
- // Make sure the word count is visible
4098
- thisView.trigger( 'hide_builder' );
4099
- } ).end()
4100
- .append(
4101
- $( '<a id="content-panels" class="hide-if-no-js wp-switch-editor switch-panels">' + metabox.find( '.hndle span' ).html() + '</a>' )
4102
- .click( function ( e ) {
4103
- if ( thisView.displayAttachedBuilder( { confirm: true } ) ) {
4104
- e.preventDefault();
4105
- }
4106
- } )
4107
- );
4108
-
4109
- // Switch back to the standard editor
4110
- if ( this.supports( 'revertToEditor' ) ) {
4111
- metabox.find( '.so-switch-to-standard' ).click( function ( e ) {
4112
- e.preventDefault();
4113
-
4114
- if ( !confirm( panelsOptions.loc.confirm_stop_builder ) ) {
4115
- return;
4116
- }
4117
-
4118
- // User is switching to the standard visual editor
4119
- thisView.addHistoryEntry( 'back_to_editor' );
4120
- thisView.model.loadPanelsData( false );
4121
-
4122
- // Switch back to the standard editor
4123
- $( '#wp-content-wrap' ).show();
4124
- metabox.hide();
4125
-
4126
- // Resize to trigger reflow of WordPress editor stuff
4127
- $( window ).resize();
4128
-
4129
- thisView.attachedVisible = false;
4130
- thisView.trigger( 'hide_builder' );
4131
- } ).show();
4132
- }
4133
-
4134
- // Move the panels box into a tab of the content editor
4135
- metabox.insertAfter( '#wp-content-wrap' ).hide().addClass( 'attached-to-editor' );
4136
-
4137
- // Switch to the Page Builder interface as soon as we load the page if there are widgets or the normal editor
4138
- // isn't supported.
4139
- var data = this.model.get( 'data' );
4140
- if ( !_.isEmpty( data.widgets ) || !_.isEmpty( data.grids ) || !this.supports( 'revertToEditor' ) ) {
4141
- this.displayAttachedBuilder( { confirm: false } );
4142
- }
4143
-
4144
- // We will also make this sticky if its attached to an editor.
4145
- var stickToolbar = function () {
4146
- var toolbar = thisView.$( '.so-builder-toolbar' );
4147
-
4148
- if ( thisView.$el.hasClass( 'so-display-narrow' ) ) {
4149
- // In this case, we don't want to stick the toolbar.
4150
- toolbar.css( {
4151
- top: 0,
4152
- left: 0,
4153
- width: '100%',
4154
- position: 'absolute'
4155
- } );
4156
- thisView.$el.css( 'padding-top', toolbar.outerHeight() );
4157
- return;
4158
- }
4159
-
4160
- var newTop = $( window ).scrollTop() - thisView.$el.offset().top;
4161
-
4162
- if ( $( '#wpadminbar' ).css( 'position' ) === 'fixed' ) {
4163
- newTop += $( '#wpadminbar' ).outerHeight();
4164
- }
4165
-
4166
- var limits = {
4167
- top: 0,
4168
- bottom: thisView.$el.outerHeight() - toolbar.outerHeight() + 20
4169
- };
4170
-
4171
- if ( newTop > limits.top && newTop < limits.bottom ) {
4172
- if ( toolbar.css( 'position' ) !== 'fixed' ) {
4173
- // The toolbar needs to stick to the top, over the interface
4174
- toolbar.css( {
4175
- top: $( '#wpadminbar' ).outerHeight(),
4176
- left: thisView.$el.offset().left,
4177
- width: thisView.$el.outerWidth(),
4178
- position: 'fixed'
4179
- } );
4180
- }
4181
- } else {
4182
- // The toolbar needs to be at the top or bottom of the interface
4183
- toolbar.css( {
4184
- top: Math.min( Math.max( newTop, 0 ), thisView.$el.outerHeight() - toolbar.outerHeight() + 20 ),
4185
- left: 0,
4186
- width: '100%',
4187
- position: 'absolute'
4188
- } );
4189
- }
4190
-
4191
- thisView.$el.css( 'padding-top', toolbar.outerHeight() );
4192
- };
4193
-
4194
- this.on( 'builder_resize', stickToolbar, this );
4195
- $( document ).scroll( stickToolbar );
4196
- stickToolbar();
4197
-
4198
- this.trigger( 'builder_attached_to_editor' );
4199
-
4200
- return this;
4201
- },
4202
-
4203
- /**
4204
- * Display the builder interface when attached to a WordPress editor
4205
- */
4206
- displayAttachedBuilder: function ( options ) {
4207
- options = _.extend( {
4208
- confirm: true
4209
- }, options );
4210
-
4211
- // Switch to the Page Builder interface
4212
-
4213
- if ( options.confirm ) {
4214
- var editor = typeof tinyMCE !== 'undefined' ? tinyMCE.get( 'content' ) : false;
4215
- var editorContent = ( editor && _.isFunction( editor.getContent ) ) ? editor.getContent() : $( 'textarea#content' ).val();
4216
-
4217
- if ( editorContent !== '' && !confirm( panelsOptions.loc.confirm_use_builder ) ) {
4218
- return false;
4219
- }
4220
- }
4221
-
4222
- // Hide the standard content editor
4223
- $( '#wp-content-wrap' ).hide();
4224
-
4225
-
4226
- $( '#editor-expand-toggle' ).on( 'change.editor-expand', function () {
4227
- if ( !$( this ).prop( 'checked' ) ) {
4228
- $( '#wp-content-wrap' ).hide();
4229
- }
4230
- } );
4231
-
4232
- // Show page builder and the inside div
4233
- this.metabox.show().find( '> .inside' ).show();
4234
-
4235
- // Triggers full refresh
4236
- $( window ).resize();
4237
- $( document ).scroll();
4238
-
4239
- // Make sure the word count is visible
4240
- this.attachedVisible = true;
4241
- this.trigger( 'display_builder' );
4242
-
4243
- return true;
4244
- },
4245
-
4246
- /**
4247
- * Initialize the row sortables
4248
- */
4249
- initSortable: function () {
4250
- if ( !this.supports( 'moveRow' ) ) {
4251
- return this;
4252
- }
4253
-
4254
- // Create the sortable for the rows
4255
- var builderView = this;
4256
-
4257
- this.rowsSortable = this.$( '.so-rows-container' ).sortable( {
4258
- appendTo: '#wpwrap',
4259
- items: '.so-row-container',
4260
- handle: '.so-row-move',
4261
- axis: 'y',
4262
- tolerance: 'pointer',
4263
- scroll: false,
4264
- stop: function ( e, ui ) {
4265
- builderView.addHistoryEntry( 'row_moved' );
4266
-
4267
- var $$ = $( ui.item ),
4268
- row = $$.data( 'view' );
4269
-
4270
- builderView.model.get( 'rows' ).remove( row.model, {
4271
- 'silent': true
4272
- } );
4273
- builderView.model.get( 'rows' ).add( row.model, {
4274
- 'silent': true,
4275
- 'at': $$.index()
4276
- } );
4277
-
4278
- row.trigger( 'move', $$.index() );
4279
-
4280
- builderView.model.refreshPanelsData();
4281
- }
4282
- } );
4283
-
4284
- return this;
4285
- },
4286
-
4287
- /**
4288
- * Refresh the row sortable
4289
- */
4290
- refreshSortable: function () {
4291
- // Refresh the sortable to account for the new row
4292
- if ( !_.isNull( this.rowsSortable ) ) {
4293
- this.rowsSortable.sortable( 'refresh' );
4294
- }
4295
- },
4296
-
4297
- /**
4298
- * Set the field that's used to store the data
4299
- * @param field
4300
- */
4301
- setDataField: function ( field, options ) {
4302
- options = _.extend( {
4303
- load: true
4304
- }, options );
4305
-
4306
- this.dataField = field;
4307
- this.dataField.data( 'builder', this );
4308
-
4309
- if ( options.load && field.val() !== '' ) {
4310
- var data = this.dataField.val();
4311
- try {
4312
- data = JSON.parse( data );
4313
- }
4314
- catch ( err ) {
4315
- data = {};
4316
- }
4317
-
4318
- this.model.loadPanelsData( data );
4319
- this.currentData = data;
4320
- this.toggleWelcomeDisplay();
4321
- }
4322
-
4323
- return this;
4324
- },
4325
-
4326
- /**
4327
- * Store the model data in the data html field set in this.setDataField.
4328
- */
4329
- storeModelData: function () {
4330
- var data = JSON.stringify( this.model.get( 'data' ) );
4331
-
4332
- if ( $( this.dataField ).val() !== data ) {
4333
- // If the data is different, set it and trigger a content_change event
4334
- $( this.dataField ).val( data );
4335
- $( this.dataField ).trigger( 'change' );
4336
- this.trigger( 'content_change' );
4337
- }
4338
- },
4339
-
4340
- /**
4341
- * HAndle the visual side of adding a new row to the builder.
4342
- *
4343
- * @param row
4344
- * @param collection
4345
- * @param options
4346
- */
4347
- onAddRow: function ( row, collection, options ) {
4348
- options = _.extend( { noAnimate: false }, options );
4349
- // Create a view for the row
4350
- var rowView = new panels.view.row( { model: row } );
4351
- rowView.builder = this;
4352
- rowView.render();
4353
-
4354
- // Attach the row elements to this builder
4355
- if ( _.isUndefined( options.at ) || collection.length <= 1 ) {
4356
- // Insert this at the end of the widgets container
4357
- rowView.$el.appendTo( this.$( '.so-rows-container' ) );
4358
- } else {
4359
- // We need to insert this at a specific position
4360
- rowView.$el.insertAfter(
4361
- this.$( '.so-rows-container .so-row-container' ).eq( options.at - 1 )
4362
- );
4363
- }
4364
-
4365
- if ( options.noAnimate === false ) {
4366
- rowView.visualCreate();
4367
- }
4368
-
4369
- this.refreshSortable();
4370
- rowView.resize();
4371
- },
4372
-
4373
- /**
4374
- * Display the dialog to add a new widget.
4375
- *
4376
- * @returns {boolean}
4377
- */
4378
- displayAddWidgetDialog: function () {
4379
- this.dialogs.widgets.openDialog();
4380
- },
4381
-
4382
- /**
4383
- * Display the dialog to add a new row.
4384
- */
4385
- displayAddRowDialog: function () {
4386
- var row = new panels.model.row();
4387
- var cells = new panels.collection.cells( [ { weight: 0.5 }, { weight: 0.5 } ] );
4388
- cells.each( function ( cell ) {
4389
- cell.row = row;
4390
- } );
4391
- row.set( 'cells', cells );
4392
- row.builder = this.model;
4393
-
4394
- this.dialogs.row.setRowModel( row );
4395
- this.dialogs.row.openDialog();
4396
- },
4397
-
4398
- /**
4399
- * Display the dialog to add prebuilt layouts.
4400
- *
4401
- * @returns {boolean}
4402
- */
4403
- displayAddPrebuiltDialog: function () {
4404
- this.dialogs.prebuilt.openDialog();
4405
- },
4406
-
4407
- /**
4408
- * Display the history dialog.
4409
- *
4410
- * @returns {boolean}
4411
- */
4412
- displayHistoryDialog: function () {
4413
- this.dialogs.history.openDialog();
4414
- },
4415
-
4416
- /**
4417
- * Handle pasting a row into the builder.
4418
- */
4419
- pasteRowHandler: function () {
4420
- var pastedModel = panels.helpers.clipboard.getModel( 'row-model' );
4421
-
4422
- if ( !_.isEmpty( pastedModel ) && pastedModel instanceof panels.model.row ) {
4423
- this.addHistoryEntry( 'row_pasted' );
4424
- pastedModel.builder = this.model;
4425
- this.model.get( 'rows' ).add( pastedModel, {
4426
- at: this.model.get( 'rows' ).indexOf( this.model ) + 1
4427
- } );
4428
- this.model.refreshPanelsData();
4429
- }
4430
- },
4431
-
4432
- /**
4433
- * Get the model for the currently selected cell
4434
- */
4435
- getActiveCell: function ( options ) {
4436
- options = _.extend( {
4437
- createCell: true,
4438
- }, options );
4439
-
4440
- if ( !this.model.get( 'rows' ).length ) {
4441
- // There aren't any rows yet
4442
- if ( options.createCell ) {
4443
- // Create a row with a single cell
4444
- this.model.addRow( {}, [ { weight: 1 } ], { noAnimate: true } );
4445
- } else {
4446
- return null;
4447
- }
4448
- }
4449
-
4450
- // Make sure the active cell isn't empty, and it's in a row that exists
4451
- var activeCell = this.activeCell;
4452
- if ( _.isEmpty( activeCell ) || this.model.get( 'rows' ).indexOf( activeCell.model.row ) === -1 ) {
4453
- return this.model.get( 'rows' ).last().get( 'cells' ).first();
4454
- } else {
4455
- return activeCell.model;
4456
- }
4457
- },
4458
-
4459
- /**
4460
- * Add a live editor to the builder
4461
- *
4462
- * @returns {panels.view.builder}
4463
- */
4464
- addLiveEditor: function () {
4465
- if ( _.isEmpty( this.config.liveEditorPreview ) ) {
4466
- return this;
4467
- }
4468
-
4469
- // Create the live editor and set the builder to this.
4470
- this.liveEditor = new panels.view.liveEditor( {
4471
- builder: this,
4472
- previewUrl: this.config.liveEditorPreview
4473
- } );
4474
-
4475
- // Display the live editor button in the toolbar
4476
- if ( this.liveEditor.hasPreviewUrl() ) {
4477
- this.$( '.so-builder-toolbar .so-live-editor' ).show();
4478
- }
4479
-
4480
- this.trigger( 'builder_live_editor_added' );
4481
-
4482
- return this;
4483
- },
4484
-
4485
- /**
4486
- * Show the current live editor
4487
- */
4488
- displayLiveEditor: function () {
4489
- if ( _.isUndefined( this.liveEditor ) ) {
4490
- return;
4491
- }
4492
-
4493
- this.liveEditor.open();
4494
- },
4495
-
4496
- /**
4497
- * Add the history browser.
4498
- *
4499
- * @return {panels.view.builder}
4500
- */
4501
- addHistoryBrowser: function () {
4502
- if ( _.isEmpty( this.config.liveEditorPreview ) ) {
4503
- return this;
4504
- }
4505
-
4506
- this.dialogs.history = new panels.dialog.history();
4507
- this.dialogs.history.builder = this;
4508
- this.dialogs.history.entries.builder = this.model;
4509
-
4510
- // Set the revert entry
4511
- this.dialogs.history.setRevertEntry( this.model );
4512
-
4513
- // Display the live editor button in the toolbar
4514
- this.$( '.so-builder-toolbar .so-history' ).show();
4515
- },
4516
-
4517
- /**
4518
- * Add an entry.
4519
- *
4520
- * @param text
4521
- * @param data
4522
- */
4523
- addHistoryEntry: function ( text, data ) {
4524
- if ( _.isUndefined( data ) ) {
4525
- data = null;
4526
- }
4527
-
4528
- if ( !_.isUndefined( this.dialogs.history ) ) {
4529
- this.dialogs.history.entries.addEntry( text, data );
4530
- }
4531
- },
4532
-
4533
- supports: function ( thing ) {
4534
-
4535
- if ( thing === 'rowAction' ) {
4536
- // Check if this supports any row action
4537
- return this.supports( 'addRow' ) || this.supports( 'editRow' ) || this.supports( 'deleteRow' );
4538
- } else if ( thing === 'widgetAction' ) {
4539
- // Check if this supports any widget action
4540
- return this.supports( 'addWidget' ) || this.supports( 'editWidget' ) || this.supports( 'deleteWidget' );
4541
- }
4542
-
4543
- return _.isUndefined( this.config.builderSupports[ thing ] ) ? false : this.config.builderSupports[ thing ];
4544
- },
4545
-
4546
- /**
4547
- * Handle a change of the content
4548
- */
4549
- handleContentChange: function () {
4550
-
4551
- // Make sure we actually need to copy content.
4552
- if ( panelsOptions.copy_content && this.attachedToEditor && this.$el.is( ':visible' ) ) {
4553
-
4554
- var panelsData = this.model.getPanelsData();
4555
- if ( !_.isEmpty( panelsData.widgets ) ) {
4556
- // We're going to create a copy of page builder content into the post content
4557
- $.post(
4558
- panelsOptions.ajaxurl,
4559
- {
4560
- action: 'so_panels_builder_content',
4561
- panels_data: JSON.stringify( panelsData ),
4562
- post_id: this.config.postId
4563
- },
4564
- function ( content ) {
4565
- if ( content !== '' ) {
4566
- this.updateEditorContent( content );
4567
- }
4568
- }.bind( this )
4569
- );
4570
- }
4571
- }
4572
- },
4573
-
4574
- /**
4575
- * Update editor content with the given content.
4576
- *
4577
- * @param content
4578
- */
4579
- updateEditorContent: function ( content ) {
4580
- // Switch back to the standard editor
4581
- if ( this.config.editorType !== 'tinyMCE' || typeof tinyMCE === 'undefined' || _.isNull( tinyMCE.get( "content" ) ) ) {
4582
- var $editor = $( this.config.editorId );
4583
- $editor.val( content ).trigger( 'change' ).trigger( 'keyup' );
4584
- } else {
4585
- var contentEd = tinyMCE.get( "content" );
4586
-
4587
- contentEd.setContent( content );
4588
-
4589
- contentEd.fire( 'change' );
4590
- contentEd.fire( 'keyup' );
4591
- }
4592
-
4593
- this.triggerYoastSeoChange();
4594
- },
4595
-
4596
- /**
4597
- * Trigger a change on Yoast SEO
4598
- */
4599
- triggerYoastSeoChange: function () {
4600
- if ( $( '#yoast_wpseo_focuskw_text_input' ).length ) {
4601
- var element = document.getElementById( 'yoast_wpseo_focuskw_text_input' ), event;
4602
-
4603
- if ( document.createEvent ) {
4604
- event = document.createEvent( "HTMLEvents" );
4605
- event.initEvent( "keyup", true, true );
4606
- } else {
4607
- event = document.createEventObject();
4608
- event.eventType = "keyup";
4609
- }
4610
-
4611
- event.eventName = "keyup";
4612
-
4613
- if ( document.createEvent ) {
4614
- element.dispatchEvent( event );
4615
- } else {
4616
- element.fireEvent( "on" + event.eventType, event );
4617
- }
4618
- }
4619
- },
4620
-
4621
- /**
4622
- * Handle displaying the builder
4623
- */
4624
- handleDisplayBuilder: function () {
4625
- var editor = typeof tinyMCE !== 'undefined' ? tinyMCE.get( 'content' ) : false;
4626
- var editorContent = ( editor && _.isFunction( editor.getContent ) ) ? editor.getContent() : $( 'textarea#content' ).val();
4627
-
4628
- if (
4629
- (
4630
- _.isEmpty( this.model.get( 'data' ) ) ||
4631
- ( _.isEmpty( this.model.get( 'data' ).widgets ) && _.isEmpty( this.model.get( 'data' ).grids ) )
4632
- ) &&
4633
- editorContent !== ''
4634
- ) {
4635
- var editorClass = panelsOptions.text_widget;
4636
- // There is a small chance a theme will have removed this, so check
4637
- if ( _.isEmpty( editorClass ) ) {
4638
- return;
4639
- }
4640
-
4641
- // Create the existing page content in a single widget
4642
- this.model.loadPanelsData( this.model.getPanelsDataFromHtml( editorContent, editorClass ) );
4643
- this.model.trigger( 'change' );
4644
- this.model.trigger( 'change:data' );
4645
- }
4646
-
4647
- $( '#post-status-info' ).addClass( 'for-siteorigin-panels' );
4648
- },
4649
-
4650
- handleHideBuilder: function () {
4651
- $( '#post-status-info' ).show().removeClass( 'for-siteorigin-panels' );
4652
- },
4653
-
4654
- wrapEditorExpandAdjust: function () {
4655
- try {
4656
- var events = ( $.hasData( window ) && $._data( window ) ).events.scroll,
4657
- event;
4658
-
4659
- for ( var i = 0; i < events.length; i++ ) {
4660
- if ( events[ i ].namespace === 'editor-expand' ) {
4661
- event = events[ i ];
4662
-
4663
- // Wrap the call
4664
- $( window ).unbind( 'scroll', event.handler );
4665
- $( window ).bind( 'scroll', function ( e ) {
4666
- if ( !this.attachedVisible ) {
4667
- event.handler( e );
4668
- }
4669
- }.bind( this ) );
4670
-
4671
- break;
4672
- }
4673
- }
4674
- }
4675
- catch ( e ) {
4676
- // We tried, we failed
4677
- return;
4678
- }
4679
- },
4680
-
4681
- /**
4682
- * Either add or remove the narrow class
4683
- * @returns {exports}
4684
- */
4685
- handleBuilderSizing: function () {
4686
- var width = this.$el.width();
4687
-
4688
- if ( !width ) {
4689
- return this;
4690
- }
4691
-
4692
- if ( width < 480 ) {
4693
- this.$el.addClass( 'so-display-narrow' );
4694
- } else {
4695
- this.$el.removeClass( 'so-display-narrow' );
4696
- }
4697
-
4698
- return this;
4699
- },
4700
-
4701
- /**
4702
- * Set the parent dialog for all the dialogs in this builder.
4703
- *
4704
- * @param text
4705
- * @param dialog
4706
- */
4707
- setDialogParents: function ( text, dialog ) {
4708
- _.each( this.dialogs, function ( p, i, d ) {
4709
- d[ i ].setParent( text, dialog );
4710
- } );
4711
-
4712
- // For any future dialogs
4713
- this.on( 'add_dialog', function ( newDialog ) {
4714
- newDialog.setParent( text, dialog );
4715
- }, this );
4716
- },
4717
-
4718
- /**
4719
- * This shows or hides the welcome display depending on whether there are any rows in the collection.
4720
- */
4721
- toggleWelcomeDisplay: function () {
4722
- if ( !this.model.get( 'rows' ).isEmpty() ) {
4723
- this.$( '.so-panels-welcome-message' ).hide();
4724
- } else {
4725
- this.$( '.so-panels-welcome-message' ).show();
4726
- }
4727
- },
4728
-
4729
- /**
4730
- * Activate the contextual menu
4731
- * @param e
4732
- * @param menu
4733
- */
4734
- activateContextMenu: function ( e, menu ) {
4735
- var builder = this;
4736
-
4737
- // Of all the visible builders, find the topmost
4738
- var topmostBuilder = $( '.siteorigin-panels-builder:visible' )
4739
- .sort( function ( a, b ) {
4740
- return $( a ).zIndex() > $( b ).zIndex() ? 1 : -1;
4741
- } )
4742
- .last();
4743
-
4744
- var topmostDialog = $( '.so-panels-dialog-wrapper:visible' )
4745
- .sort( function ( a, b ) {
4746
- return $( a ).zIndex() > $( b ).zIndex() ? 1 : -1;
4747
- } )
4748
- .last();
4749
-
4750
- var closestDialog = builder.$el.closest( '.so-panels-dialog-wrapper' );
4751
-
4752
- // Only run this if its element is the topmost builder, in the topmost dialog
4753
- if (
4754
- builder.$el.is( topmostBuilder ) &&
4755
- (
4756
- topmostDialog.length === 0 ||
4757
- topmostDialog.is( closestDialog )
4758
- )
4759
- ) {
4760
- // Get the element we're currently hovering over
4761
- var over = $( [] )
4762
- .add( builder.$( '.so-panels-welcome-message:visible' ) )
4763
- .add( builder.$( '.so-rows-container > .so-row-container' ) )
4764
- .add( builder.$( '.so-cells > .cell' ) )
4765
- .add( builder.$( '.cell-wrapper > .so-widget' ) )
4766
- .filter( function ( i ) {
4767
- return menu.isOverEl( $( this ), e );
4768
- } );
4769
-
4770
- var activeView = over.last().data( 'view' );
4771
- if ( activeView !== undefined && activeView.buildContextualMenu !== undefined ) {
4772
- // We'll pass this to the current active view so it can popular the contextual menu
4773
- activeView.buildContextualMenu( e, menu );
4774
- }
4775
- else if ( over.last().hasClass( 'so-panels-welcome-message' ) ) {
4776
- // The user opened the contextual menu on the welcome message
4777
- this.buildContextualMenu( e, menu );
4778
- }
4779
- }
4780
- },
4781
-
4782
- /**
4783
- * Build the contextual menu for the main builder - before any content has been added.
4784
- */
4785
- buildContextualMenu: function ( e, menu ) {
4786
- var actions = {};
4787
-
4788
- if ( this.supports( 'addRow' ) ) {
4789
- actions.add_row = { title: panelsOptions.loc.contextual.add_row };
4790
- }
4791
-
4792
- if ( panels.helpers.clipboard.canCopyPaste() ) {
4793
- if ( panels.helpers.clipboard.isModel( 'row-model' ) && this.supports( 'addRow' ) ) {
4794
- actions.paste_row = { title: panelsOptions.loc.contextual.row_paste };
4795
- }
4796
- }
4797
-
4798
- if ( !_.isEmpty( actions ) ) {
4799
- menu.addSection(
4800
- 'builder-actions',
4801
- {
4802
- sectionTitle: panelsOptions.loc.contextual.row_actions,
4803
- search: false,
4804
- },
4805
- actions,
4806
- function ( c ) {
4807
- switch ( c ) {
4808
- case 'add_row':
4809
- this.displayAddRowDialog();
4810
- break;
4811
-
4812
- case 'paste_row':
4813
- this.pasteRowHandler();
4814
- break;
4815
- }
4816
- }.bind( this )
4817
- );
4818
- }
4819
- },
4820
- } );
4821
-
4822
- },{}],24:[function(require,module,exports){
4823
- var panels = window.panels, $ = jQuery;
4824
-
4825
- module.exports = Backbone.View.extend( {
4826
- template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder-cell' ).html() ) ),
4827
- events: {
4828
- 'click .cell-wrapper': 'handleCellClick'
4829
- },
4830
-
4831
- /* The row view that this cell is a part of */
4832
- row: null,
4833
- widgetSortable: null,
4834
-
4835
- initialize: function () {
4836
- this.model.get('widgets').on( 'add', this.onAddWidget, this );
4837
- },
4838
-
4839
- /**
4840
- * Render the actual cell
4841
- */
4842
- render: function () {
4843
- var templateArgs = {
4844
- weight: this.model.get( 'weight' ),
4845
- totalWeight: this.row.model.get('cells').totalWeight()
4846
- };
4847
-
4848
- this.setElement( this.template( templateArgs ) );
4849
- this.$el.data( 'view', this );
4850
-
4851
- // Now lets render any widgets that are currently in the row
4852
- var thisView = this;
4853
- this.model.get('widgets').each( function ( widget ) {
4854
- var widgetView = new panels.view.widget( {model: widget} );
4855
- widgetView.cell = thisView;
4856
- widgetView.render();
4857
-
4858
- widgetView.$el.appendTo( thisView.$( '.widgets-container' ) );
4859
- } );
4860
-
4861
- this.initSortable();
4862
- this.initResizable();
4863
-
4864
- return this;
4865
- },
4866
-
4867
- /**
4868
- * Initialize the widget sortable
4869
- */
4870
- initSortable: function () {
4871
- if( ! this.row.builder.supports( 'moveWidget' ) ) {
4872
- return this;
4873
- }
4874
-
4875
- var cellView = this;
4876
-
4877
- // Go up the view hierarchy until we find the ID attribute
4878
- var builderID = cellView.row.builder.$el.attr( 'id' );
4879
-
4880
- // Create a widget sortable that's connected with all other cells
4881
- this.widgetSortable = this.$( '.widgets-container' ).sortable( {
4882
- placeholder: "so-widget-sortable-highlight",
4883
- connectWith: '#' + builderID + ' .so-cells .cell .widgets-container',
4884
- tolerance: 'pointer',
4885
- scroll: false,
4886
- over: function ( e, ui ) {
4887
- // This will make all the rows in the current builder resize
4888
- cellView.row.builder.trigger( 'widget_sortable_move' );
4889
- },
4890
- stop: function ( e, ui ) {
4891
- cellView.row.builder.addHistoryEntry( 'widget_moved' );
4892
-
4893
- var $$ = $( ui.item ),
4894
- widget = $$.data( 'view' ),
4895
- targetCell = $$.closest( '.cell' ).data( 'view' );
4896
-
4897
- // Move the model and the view to the new cell
4898
- widget.model.moveToCell( targetCell.model, {}, $$.index() );
4899
- widget.cell = targetCell;
4900
-
4901
- widget.cell.row.builder.model.refreshPanelsData();
4902
- },
4903
- helper: function ( e, el ) {
4904
- var helper = el.clone()
4905
- .css( {
4906
- 'width': el.outerWidth(),
4907
- 'z-index': 10000,
4908
- 'position': 'fixed'
4909
- } )
4910
- .addClass( 'widget-being-dragged' ).appendTo( 'body' );
4911
-
4912
- // Center the helper to the mouse cursor.
4913
- if ( el.outerWidth() > 720 ) {
4914
- helper.animate( {
4915
- 'margin-left': e.pageX - el.offset().left - (
4916
- 480 / 2
4917
- ),
4918
- 'width': 480
4919
- }, 'fast' );
4920
- }
4921
-
4922
- return helper;
4923
- }
4924
- } );
4925
-
4926
- return this;
4927
- },
4928
-
4929
- /**
4930
- * Refresh the widget sortable when a new widget is added
4931
- */
4932
- refreshSortable: function () {
4933
- if ( ! _.isNull( this.widgetSortable ) ) {
4934
- this.widgetSortable.sortable( 'refresh' );
4935
- }
4936
- },
4937
-
4938
- /**
4939
- * This will make the cell resizble
4940
- */
4941
- initResizable: function () {
4942
- if( ! this.row.builder.supports( 'editRow' ) ) {
4943
- return this;
4944
- }
4945
-
4946
- // var neighbor = this.$el.previous().data('view');
4947
- var handle = this.$( '.resize-handle' ).css( 'position', 'absolute' );
4948
- var container = this.row.$el;
4949
- var cellView = this;
4950
-
4951
- // The view of the cell to the left is stored when dragging starts.
4952
- var previousCell;
4953
-
4954
- handle.draggable( {
4955
- axis: 'x',
4956
- containment: container,
4957
- start: function ( e, ui ) {
4958
- // Set the containment to the cell parent
4959
- previousCell = cellView.$el.prev().data( 'view' );
4960
- if ( _.isUndefined( previousCell ) ) {
4961
- return;
4962
- }
4963
-
4964
- // Create the clone for the current cell
4965
- var newCellClone = cellView.$el.clone().appendTo( ui.helper ).css( {
4966
- position: 'absolute',
4967
- top: '0',
4968
- width: cellView.$el.outerWidth(),
4969
- left: 5,
4970
- height: cellView.$el.outerHeight()
4971
- } );
4972
- newCellClone.find( '.resize-handle' ).remove();
4973
-
4974
- // Create the clone for the previous cell
4975
- var prevCellClone = previousCell.$el.clone().appendTo( ui.helper ).css( {
4976
- position: 'absolute',
4977
- top: '0',
4978
- width: previousCell.$el.outerWidth(),
4979
- right: 5,
4980
- height: previousCell.$el.outerHeight()
4981
- } );
4982
- prevCellClone.find( '.resize-handle' ).remove();
4983
-
4984
- $( this ).data( {
4985
- 'newCellClone': newCellClone,
4986
- 'prevCellClone': prevCellClone
4987
- } );
4988
- },
4989
- drag: function ( e, ui ) {
4990
- // Calculate the new cell and previous cell widths as a percent
4991
- var containerWidth = cellView.row.$el.width() + 10;
4992
- var ncw = cellView.model.get( 'weight' ) - (
4993
- (
4994
- ui.position.left + handle.outerWidth() / 2
4995
- ) / containerWidth
4996
- );
4997
- var pcw = previousCell.model.get( 'weight' ) + (
4998
- (
4999
- ui.position.left + handle.outerWidth() / 2
5000
- ) / containerWidth
5001
- );
5002
-
5003
- $( this ).data( 'newCellClone' ).css( 'width', containerWidth * ncw )
5004
- .find( '.preview-cell-weight' ).html( Math.round( ncw * 1000 ) / 10 );
5005
-
5006
- $( this ).data( 'prevCellClone' ).css( 'width', containerWidth * pcw )
5007
- .find( '.preview-cell-weight' ).html( Math.round( pcw * 1000 ) / 10 );
5008
- },
5009
- stop: function ( e, ui ) {
5010
- // Remove the clones
5011
- $( this ).data( 'newCellClone' ).remove();
5012
- $( this ).data( 'prevCellClone' ).remove();
5013
-
5014
- var containerWidth = cellView.row.$el.width() + 10;
5015
- var ncw = cellView.model.get( 'weight' ) - (
5016
- (
5017
- ui.position.left + handle.outerWidth() / 2
5018
- ) / containerWidth
5019
- );
5020
- var pcw = previousCell.model.get( 'weight' ) + (
5021
- (
5022
- ui.position.left + handle.outerWidth() / 2
5023
- ) / containerWidth
5024
- );
5025
-
5026
- if ( ncw > 0.02 && pcw > 0.02 ) {
5027
- cellView.row.builder.addHistoryEntry( 'cell_resized' );
5028
- cellView.model.set( 'weight', ncw );
5029
- previousCell.model.set( 'weight', pcw );
5030
- cellView.row.resize();
5031
- }
5032
-
5033
- ui.helper.css( 'left', - handle.outerWidth() / 2 );
5034
-
5035
- // Refresh the panels data
5036
- cellView.row.builder.model.refreshPanelsData();
5037
- }
5038
- } );
5039
-
5040
- return this;
5041
- },
5042
-
5043
- /**
5044
- * This is triggered when ever a widget is added to the row collection.
5045
- *
5046
- * @param widget
5047
- */
5048
- onAddWidget: function ( widget, collection, options ) {
5049
- options = _.extend( {noAnimate: false}, options );
5050
-
5051
- // Create the view for the widget
5052
- var view = new panels.view.widget( {
5053
- model: widget
5054
- } );
5055
- view.cell = this;
5056
-
5057
- if ( _.isUndefined( widget.isDuplicate ) ) {
5058
- widget.isDuplicate = false;
5059
- }
5060
-
5061
- // Render and load the form if this is a duplicate
5062
- view.render( {
5063
- 'loadForm': widget.isDuplicate
5064
- } );
5065
-
5066
- if ( _.isUndefined( options.at ) || collection.length <= 1 ) {
5067
- // Insert this at the end of the widgets container
5068
- view.$el.appendTo( this.$( '.widgets-container' ) );
5069
- } else {
5070
- // We need to insert this at a specific position
5071
- view.$el.insertAfter(
5072
- this.$( '.widgets-container .so-widget' ).eq( options.at - 1 )
5073
- );
5074
- }
5075
-
5076
- if ( options.noAnimate === false ) {
5077
- // We need an animation
5078
- view.visualCreate();
5079
- }
5080
-
5081
- this.refreshSortable();
5082
- this.row.resize();
5083
- },
5084
-
5085
- /**
5086
- * Handle this cell being clicked on
5087
- *
5088
- * @param e
5089
- * @returns {boolean}
5090
- */
5091
- handleCellClick: function ( e ) {
5092
- // Remove all existing selected cell indication for this builder
5093
- this.row.builder.$el.find( '.so-cells .cell' ).removeClass( 'cell-selected' );
5094
-
5095
- if( this.row.builder.activeCell === this && ! this.model.get('widgets').length ) {
5096
- // This is a click on an empty cell
5097
- this.row.builder.activeCell = null;
5098
- }
5099
- else {
5100
- this.$el.addClass( 'cell-selected' );
5101
- this.row.builder.activeCell = this;
5102
- }
5103
- },
5104
-
5105
- /**
5106
- * Insert a widget from the clipboard
5107
- */
5108
- pasteHandler: function(){
5109
- var pastedModel = panels.helpers.clipboard.getModel( 'widget-model' );
5110
- if( ! _.isEmpty( pastedModel ) && pastedModel instanceof panels.model.widget ) {
5111
- this.row.builder.addHistoryEntry( 'widget_pasted' );
5112
- pastedModel.cell = this.model;
5113
- this.model.get('widgets').add( pastedModel );
5114
- this.row.builder.model.refreshPanelsData();
5115
- }
5116
- },
5117
-
5118
- /**
5119
- * Build up the contextual menu for a cell
5120
- *
5121
- * @param e
5122
- * @param menu
5123
- */
5124
- buildContextualMenu: function ( e, menu ) {
5125
- var thisView = this;
5126
-
5127
- if( ! menu.hasSection( 'add-widget-below' ) ) {
5128
- menu.addSection(
5129
- 'add-widget-cell',
5130
- {
5131
- sectionTitle: panelsOptions.loc.contextual.add_widget_cell,
5132
- searchPlaceholder: panelsOptions.loc.contextual.search_widgets,
5133
- defaultDisplay: panelsOptions.contextual.default_widgets
5134
- },
5135
- panelsOptions.widgets,
5136
- function ( c ) {
5137
- thisView.row.builder.addHistoryEntry( 'widget_added' );
5138
-
5139
- var widget = new panels.model.widget( {
5140
- class: c
5141
- } );
5142
-
5143
- // Add the widget to the cell model
5144
- widget.cell = thisView.model;
5145
- widget.cell.get('widgets').add( widget );
5146
-
5147
- thisView.row.builder.model.refreshPanelsData();
5148
- }
5149
- );
5150
- }
5151
-
5152
- var actions = {};
5153
- if ( this.row.builder.supports('addWidget') && panels.helpers.clipboard.isModel( 'widget-model' ) ) {
5154
- actions.paste = {title: panelsOptions.loc.contextual.cell_paste_widget};
5155
- }
5156
-
5157
- if( ! _.isEmpty( actions ) ) {
5158
- menu.addSection(
5159
- 'cell-actions',
5160
- {
5161
- sectionTitle: panelsOptions.loc.contextual.cell_actions,
5162
- search: false,
5163
- },
5164
- actions,
5165
- function ( c ) {
5166
- switch ( c ) {
5167
- case 'paste':
5168
- this.pasteHandler();
5169
- break;
5170
- }
5171
-
5172
- this.row.builder.model.refreshPanelsData();
5173
- }.bind( this )
5174
- );
5175
- }
5176
-
5177
- // Add the contextual menu for the parent row
5178
- this.row.buildContextualMenu( e, menu );
5179
- }
5180
- } );
5181
-
5182
- },{}],25:[function(require,module,exports){
5183
- var panels = window.panels, $ = jQuery;
5184
-
5185
- module.exports = Backbone.View.extend( {
5186
- dialogTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog' ).html() ) ),
5187
- dialogTabTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-tab' ).html() ) ),
5188
-
5189
- tabbed: false,
5190
- rendered: false,
5191
- builder: false,
5192
- className: 'so-panels-dialog-wrapper',
5193
- dialogClass: '',
5194
- dialogIcon: '',
5195
- parentDialog: false,
5196
- dialogOpen: false,
5197
- editableLabel: false,
5198
-
5199
- events: {
5200
- 'click .so-close': 'closeDialog',
5201
- 'click .so-nav.so-previous': 'navToPrevious',
5202
- 'click .so-nav.so-next': 'navToNext',
5203
- },
5204
-
5205
- initialize: function () {
5206
- // The first time this dialog is opened, render it
5207
- this.once( 'open_dialog', this.render );
5208
- this.once( 'open_dialog', this.attach );
5209
- this.once( 'open_dialog', this.setDialogClass );
5210
-
5211
- this.trigger( 'initialize_dialog', this );
5212
-
5213
- if ( ! _.isUndefined( this.initializeDialog ) ) {
5214
- this.initializeDialog();
5215
- }
5216
- },
5217
-
5218
- /**
5219
- * Returns the next dialog in the sequence. Should be overwritten by a child dialog.
5220
- * @returns {null}
5221
- */
5222
- getNextDialog: function () {
5223
- return null;
5224
- },
5225
-
5226
- /**
5227
- * Returns the previous dialog in this sequence. Should be overwritten by child dialog.
5228
- * @returns {null}
5229
- */
5230
- getPrevDialog: function () {
5231
- return null;
5232
- },
5233
-
5234
- /**
5235
- * Adds a dialog class to uniquely identify this dialog type
5236
- */
5237
- setDialogClass: function () {
5238
- if ( this.dialogClass !== '' ) {
5239
- this.$( '.so-panels-dialog' ).addClass( this.dialogClass );
5240
- }
5241
- },
5242
-
5243
- /**
5244
- * Set the builder that controls this dialog.
5245
- * @param {panels.view.builder} builder
5246
- */
5247
- setBuilder: function ( builder ) {
5248
- this.builder = builder;
5249
-
5250
- // Trigger an add dialog event on the builder so it can modify the dialog in any way
5251
- builder.trigger( 'add_dialog', this, this.builder );
5252
-
5253
- return this;
5254
- },
5255
-
5256
- /**
5257
- * Attach the dialog to the window
5258
- */
5259
- attach: function () {
5260
- this.$el.appendTo( 'body' );
5261
-
5262
- return this;
5263
- },
5264
-
5265
- /**
5266
- * Converts an HTML representation of the dialog into arguments for a dialog box
5267
- * @param html HTML for the dialog
5268
- * @param args Arguments passed to the template
5269
- * @returns {}
5270
- */
5271
- parseDialogContent: function ( html, args ) {
5272
- // Add a CID
5273
- args = _.extend( {cid: this.cid}, args );
5274
-
5275
-
5276
- var c = $( (
5277
- _.template( panels.helpers.utils.processTemplate( html ) )
5278
- )( args ) );
5279
- var r = {
5280
- title: c.find( '.title' ).html(),
5281
- buttons: c.find( '.buttons' ).html(),
5282
- content: c.find( '.content' ).html()
5283
- };
5284
-
5285
- if ( c.has( '.left-sidebar' ) ) {
5286
- r.left_sidebar = c.find( '.left-sidebar' ).html();
5287
- }
5288
-
5289
- if ( c.has( '.right-sidebar' ) ) {
5290
- r.right_sidebar = c.find( '.right-sidebar' ).html();
5291
- }
5292
-
5293
- return r;
5294
-
5295
- },
5296
-
5297
- /**
5298
- * Render the dialog and initialize the tabs
5299
- *
5300
- * @param attributes
5301
- * @returns {panels.view.dialog}
5302
- */
5303
- renderDialog: function ( attributes ) {
5304
- attributes = _.extend( {
5305
- editableLabel: this.editableLabel,
5306
- dialogIcon: this.dialogIcon,
5307
- }, attributes );
5308
-
5309
- this.$el.html( this.dialogTemplate( attributes ) ).hide();
5310
- this.$el.data( 'view', this );
5311
- this.$el.addClass( 'so-panels-dialog-wrapper' );
5312
-
5313
- if ( this.parentDialog !== false ) {
5314
- // Add a link to the parent dialog as a sort of crumbtrail.
5315
- var thisDialog = this;
5316
- var dialogParent = $( '<h3 class="so-parent-link"></h3>' ).html( this.parentDialog.text + '<div class="so-separator"></div>' );
5317
- dialogParent.click( function ( e ) {
5318
- e.preventDefault();
5319
- thisDialog.closeDialog();
5320
- thisDialog.parentDialog.openDialog();
5321
- } );
5322
- this.$( '.so-title-bar' ).prepend( dialogParent );
5323
- }
5324
-
5325
- if( this.$( '.so-title-bar .so-title-editable' ).length ) {
5326
- // Added here because .so-edit-title is only available after the template has been rendered.
5327
- this.initEditableLabel();
5328
- }
5329
-
5330
- return this;
5331
- },
5332
-
5333
- /**
5334
- * Initialize the sidebar tabs
5335
- */
5336
- initTabs: function () {
5337
- var tabs = this.$( '.so-sidebar-tabs li a' );
5338
-
5339
- if ( tabs.length === 0 ) {
5340
- return this;
5341
- }
5342
-
5343
- var thisDialog = this;
5344
- tabs.click( function ( e ) {
5345
- e.preventDefault();
5346
- var $$ = $( this );
5347
-
5348
- thisDialog.$( '.so-sidebar-tabs li' ).removeClass( 'tab-active' );
5349
- thisDialog.$( '.so-content .so-content-tabs > *' ).hide();
5350
-
5351
- $$.parent().addClass( 'tab-active' );
5352
-
5353
- var url = $$.attr( 'href' );
5354
- if ( ! _.isUndefined( url ) && url.charAt( 0 ) === '#' ) {
5355
- // Display the new tab
5356
- var tabName = url.split( '#' )[1];
5357
- thisDialog.$( '.so-content .so-content-tabs .tab-' + tabName ).show();
5358
- }
5359
-
5360
- // This lets other dialogs implement their own custom handlers
5361
- thisDialog.trigger( 'tab_click', $$ );
5362
-
5363
- } );
5364
-
5365
- // Trigger a click on the first tab
5366
- this.$( '.so-sidebar-tabs li a' ).first().click();
5367
- return this;
5368
- },
5369
-
5370
- initToolbar: function () {
5371
- // Trigger simplified click event for elements marked as toolbar buttons.
5372
- var buttons = this.$( '.so-toolbar .so-buttons .so-toolbar-button' );
5373
- buttons.click( function ( e ) {
5374
- e.preventDefault();
5375
-
5376
- this.trigger( 'button_click', $( e.currentTarget ) );
5377
- }.bind( this ) );
5378
-
5379
- // Handle showing and hiding the dropdown list items
5380
- var $dropdowns = this.$( '.so-toolbar .so-buttons .so-dropdown-button' );
5381
- $dropdowns.click( function ( e ) {
5382
- e.preventDefault();
5383
- var $dropdownButton = $( e.currentTarget );
5384
- var $dropdownList = $dropdownButton.siblings( '.so-dropdown-links-wrapper' );
5385
- if ( $dropdownList.is( '.hidden' ) ) {
5386
- $dropdownList.removeClass( 'hidden' );
5387
- } else {
5388
- $dropdownList.addClass( 'hidden' );
5389
- }
5390
-
5391
- }.bind( this ) );
5392
-
5393
- // Hide dropdown list on click anywhere, unless it's a dropdown option which requires confirmation in it's
5394
- // unconfirmed state.
5395
- $( 'html' ).click( function ( e ) {
5396
- this.$( '.so-dropdown-links-wrapper' ).not( '.hidden' ).each( function ( index, el ) {
5397
- var $dropdownList = $( el );
5398
- var $trgt = $( e.target );
5399
- if ( $trgt.length === 0 || !(
5400
- (
5401
- $trgt.is('.so-needs-confirm') && !$trgt.is('.so-confirmed')
5402
- ) || $trgt.is('.so-dropdown-button')
5403
- ) ) {
5404
- $dropdownList.addClass('hidden');
5405
- }
5406
- } );
5407
- }.bind( this ) );
5408
- },
5409
-
5410
- /**
5411
- * Initialize the editable dialog title
5412
- */
5413
- initEditableLabel: function(){
5414
- var $editElt = this.$( '.so-title-bar .so-title-editable' );
5415
-
5416
- $editElt.keypress( function ( event ) {
5417
- var enterPressed = event.type === 'keypress' && event.keyCode === 13;
5418
- if ( enterPressed ) {
5419
- // Need to make sure tab focus is on another element, otherwise pressing enter multiple times refocuses
5420
- // the element and allows newlines.
5421
- var tabbables = $( ':tabbable' );
5422
- var curTabIndex = tabbables.index( $editElt );
5423
- tabbables.eq( curTabIndex + 1 ).focus();
5424
- // After the above, we're somehow left with the first letter of text selected,
5425
- // so this removes the selection.
5426
- window.getSelection().removeAllRanges();
5427
- }
5428
- return !enterPressed;
5429
- } ).blur( function () {
5430
- var newValue = $editElt.text().replace( /^\s+|\s+$/gm, '' );
5431
- var oldValue = $editElt.data( 'original-value' ).replace( /^\s+|\s+$/gm, '' );
5432
- if ( newValue !== oldValue ) {
5433
- $editElt.text( newValue );
5434
- this.trigger( 'edit_label', newValue );
5435
- }
5436
-
5437
- }.bind( this ) );
5438
-
5439
- $editElt.focus( function() {
5440
- $editElt.data( 'original-value', $editElt.text() );
5441
- panels.helpers.utils.selectElementContents( this );
5442
- } );
5443
- },
5444
-
5445
- /**
5446
- * Quickly setup the dialog by opening and closing it.
5447
- */
5448
- setupDialog: function () {
5449
- this.openDialog();
5450
- this.closeDialog();
5451
- },
5452
-
5453
- /**
5454
- * Refresh the next and previous buttons.
5455
- */
5456
- refreshDialogNav: function () {
5457
- this.$( '.so-title-bar .so-nav' ).show().removeClass( 'so-disabled' );
5458
-
5459
- // Lets also hide the next and previous if we don't have a next and previous dialog
5460
- var nextDialog = this.getNextDialog();
5461
- var nextButton = this.$( '.so-title-bar .so-next' );
5462
-
5463
- var prevDialog = this.getPrevDialog();
5464
- var prevButton = this.$( '.so-title-bar .so-previous' );
5465
-
5466
- if ( nextDialog === null ) {
5467
- nextButton.hide();
5468
- }
5469
- else if ( nextDialog === false ) {
5470
- nextButton.addClass( 'so-disabled' );
5471
- }
5472
-
5473
- if ( prevDialog === null ) {
5474
- prevButton.hide();
5475
- }
5476
- else if ( prevDialog === false ) {
5477
- prevButton.addClass( 'so-disabled' );
5478
- }
5479
- },
5480
-
5481
- /**
5482
- * Open the dialog
5483
- */
5484
- openDialog: function ( options ) {
5485
- options = _.extend( {
5486
- silent: false
5487
- }, options );
5488
-
5489
- if ( ! options.silent ) {
5490
- this.trigger( 'open_dialog' );
5491
- }
5492
-
5493
- this.dialogOpen = true;
5494
-
5495
- this.refreshDialogNav();
5496
-
5497
- // Stop scrolling for the main body
5498
- panels.helpers.pageScroll.lock();
5499
-
5500
- // Start listen for keyboard keypresses.
5501
- $( window ).on( 'keyup', this.keyboardListen );
5502
-
5503
- this.$el.show();
5504
-
5505
- if ( ! options.silent ) {
5506
- // This triggers once everything is visible
5507
- this.trigger( 'open_dialog_complete' );
5508
- this.builder.trigger( 'open_dialog', this );
5509
- $( document ).trigger( 'open_dialog', this );
5510
- }
5511
- },
5512
-
5513
- /**
5514
- * Close the dialog
5515
- *
5516
- * @param e
5517
- * @returns {boolean}
5518
- */
5519
- closeDialog: function ( options ) {
5520
- options = _.extend( {
5521
- silent: false
5522
- }, options );
5523
-
5524
- if ( ! options.silent ) {
5525
- this.trigger( 'close_dialog' );
5526
- }
5527
-
5528
- this.dialogOpen = false;
5529
-
5530
- this.$el.hide();
5531
- panels.helpers.pageScroll.unlock();
5532
-
5533
- // Stop listen for keyboard keypresses.
5534
- $( window ).off( 'keyup', this.keyboardListen );
5535
-
5536
- if ( ! options.silent ) {
5537
- // This triggers once everything is hidden
5538
- this.trigger( 'close_dialog_complete' );
5539
- this.builder.trigger( 'close_dialog', this );
5540
- }
5541
- },
5542
-
5543
- /**
5544
- * Keyboard events handler
5545
- */
5546
- keyboardListen: function ( e ) {
5547
- // [Esc] to close
5548
- if ( e.which === 27 ) {
5549
- $( '.so-panels-dialog-wrapper .so-close' ).trigger( 'click' );
5550
- }
5551
- },
5552
-
5553
- /**
5554
- * Navigate to the previous dialog
5555
- */
5556
- navToPrevious: function () {
5557
- this.closeDialog();
5558
-
5559
- var prev = this.getPrevDialog();
5560
- if ( prev !== null && prev !== false ) {
5561
- prev.openDialog();
5562
- }
5563
- },
5564
-
5565
- /**
5566
- * Navigate to the next dialog
5567
- */
5568
- navToNext: function () {
5569
- this.closeDialog();
5570
-
5571
- var next = this.getNextDialog();
5572
- if ( next !== null && next !== false ) {
5573
- next.openDialog();
5574
- }
5575
- },
5576
-
5577
- /**
5578
- * Get the values from the form and convert them into a data array
5579
- */
5580
- getFormValues: function ( formSelector ) {
5581
- if ( _.isUndefined( formSelector ) ) {
5582
- formSelector = '.so-content';
5583
- }
5584
-
5585
- var $f = this.$( formSelector );
5586
-
5587
- var data = {}, parts;
5588
-
5589
- // Find all the named fields in the form
5590
- $f.find( '[name]' ).each( function () {
5591
- var $$ = $( this );
5592
-
5593
- try {
5594
-
5595
- var name = /([A-Za-z_]+)\[(.*)\]/.exec( $$.attr( 'name' ) );
5596
- if ( _.isEmpty( name ) ) {
5597
- return true;
5598
- }
5599
-
5600
- // Create an array with the parts of the name
5601
- if ( _.isUndefined( name[2] ) ) {
5602
- parts = $$.attr( 'name' );
5603
- } else {
5604
- parts = name[2].split( '][' );
5605
- parts.unshift( name[1] );
5606
- }
5607
-
5608
- parts = parts.map( function ( e ) {
5609
- if ( ! isNaN( parseFloat( e ) ) && isFinite( e ) ) {
5610
- return parseInt( e );
5611
- } else {
5612
- return e;
5613
- }
5614
- } );
5615
-
5616
- var sub = data;
5617
- var fieldValue = null;
5618
-
5619
- var fieldType = (
5620
- _.isString( $$.attr( 'type' ) ) ? $$.attr( 'type' ).toLowerCase() : false
5621
- );
5622
-
5623
- // First we need to get the value from the field
5624
- if ( fieldType === 'checkbox' ) {
5625
- if ( $$.is( ':checked' ) ) {
5626
- fieldValue = $$.val() !== '' ? $$.val() : true;
5627
- } else {
5628
- fieldValue = null;
5629
- }
5630
- }
5631
- else if ( fieldType === 'radio' ) {
5632
- if ( $$.is( ':checked' ) ) {
5633
- fieldValue = $$.val();
5634
- } else {
5635
- //skip over unchecked radios
5636
- return;
5637
- }
5638
- }
5639
- else if ( $$.prop( 'tagName' ) === 'SELECT' ) {
5640
- var selected = $$.find( 'option:selected' );
5641
-
5642
- if ( selected.length === 1 ) {
5643
- fieldValue = $$.find( 'option:selected' ).val();
5644
- }
5645
- else if ( selected.length > 1 ) {
5646
- // This is a mutli-select field
5647
- fieldValue = _.map( $$.find( 'option:selected' ), function ( n, i ) {
5648
- return $( n ).val();
5649
- } );
5650
- }
5651
-
5652
- } else {
5653
- // This is a fallback that will work for most fields
5654
- fieldValue = $$.val();
5655
- }
5656
-
5657
- // Now, we need to filter this value if necessary
5658
- if ( ! _.isUndefined( $$.data( 'panels-filter' ) ) ) {
5659
- switch ( $$.data( 'panels-filter' ) ) {
5660
- case 'json_parse':
5661
- // Attempt to parse the JSON value of this field
5662
- try {
5663
- fieldValue = JSON.parse( fieldValue );
5664
- }
5665
- catch ( err ) {
5666
- fieldValue = '';
5667
- }
5668
- break;
5669
- }
5670
- }
5671
-
5672
- // Now convert this into an array
5673
- if ( fieldValue !== null ) {
5674
- for ( var i = 0; i < parts.length; i ++ ) {
5675
- if ( i === parts.length - 1 ) {
5676
- if ( parts[i] === '' ) {
5677
- // This needs to be an array
5678
- sub.push( fieldValue );
5679
- } else {
5680
- sub[parts[i]] = fieldValue;
5681
- }
5682
- } else {
5683
- if ( _.isUndefined( sub[parts[i]] ) ) {
5684
- if ( parts[i + 1] === '' ) {
5685
- sub[parts[i]] = [];
5686
- } else {
5687
- sub[parts[i]] = {};
5688
- }
5689
- }
5690
- sub = sub[parts[i]];
5691
- }
5692
- }
5693
- }
5694
- }
5695
- catch ( error ) {
5696
- // Ignore this error, just log the message for debugging
5697
- console.log( 'Field [' + $$.attr('name') + '] could not be processed and was skipped - ' + error.message );
5698
- }
5699
-
5700
- } ); // End of each through input fields
5701
-
5702
- return data;
5703
- },
5704
-
5705
- /**
5706
- * Set a status message for the dialog
5707
- */
5708
- setStatusMessage: function ( message, loading, error ) {
5709
- var msg = error ? '<span class="dashicons dashicons-warning"></span>' + message : message;
5710
- this.$( '.so-toolbar .so-status' ).html( msg );
5711
- if ( ! _.isUndefined( loading ) && loading ) {
5712
- this.$( '.so-toolbar .so-status' ).addClass( 'so-panels-loading' );
5713
- } else {
5714
- this.$( '.so-toolbar .so-status' ).removeClass( 'so-panels-loading' );
5715
- }
5716
- },
5717
-
5718
- /**
5719
- * Set the parent after.
5720
- */
5721
- setParent: function ( text, dialog ) {
5722
- this.parentDialog = {
5723
- text: text,
5724
- dialog: dialog
5725
- };
5726
- }
5727
- } );
5728
-
5729
- },{}],26:[function(require,module,exports){
5730
- var panels = window.panels, $ = jQuery;
5731
-
5732
- module.exports = Backbone.View.extend( {
5733
- template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-live-editor' ).html() ) ),
5734
-
5735
- previewScrollTop: 0,
5736
- loadTimes: [],
5737
- previewFrameId: 1,
5738
-
5739
- previewUrl: null,
5740
- previewIframe: null,
5741
-
5742
- events: {
5743
- 'click .live-editor-close': 'close',
5744
- 'click .live-editor-collapse': 'collapse',
5745
- 'click .live-editor-mode': 'mobileToggle'
5746
- },
5747
-
5748
- initialize: function ( options ) {
5749
- options = _.extend( {
5750
- builder: false,
5751
- previewUrl: false,
5752
- }, options );
5753
-
5754
- if( _.isEmpty( options.previewUrl ) ) {
5755
- options.previewUrl = panelsOptions.ajaxurl + "&action=so_panels_live_editor_preview";
5756
- }
5757
-
5758
- this.builder = options.builder;
5759
- this.previewUrl = options.previewUrl;
5760
-
5761
- this.builder.model.on( 'refresh_panels_data', this.handleRefreshData, this );
5762
- this.builder.model.on( 'load_panels_data', this.handleLoadData, this );
5763
- },
5764
-
5765
- /**
5766
- * Render the live editor
5767
- */
5768
- render: function () {
5769
- this.setElement( this.template() );
5770
- this.$el.hide();
5771
- var thisView = this;
5772
-
5773
- var isMouseDown = false;
5774
-
5775
- $( document )
5776
- .mousedown( function () {
5777
- isMouseDown = true;
5778
- } )
5779
- .mouseup( function () {
5780
- isMouseDown = false;
5781
- } );
5782
-
5783
- // Handle highlighting the relevant widget in the live editor preview
5784
- this.$el.on( 'mouseenter', '.so-widget-wrapper', function () {
5785
- var $$ = $( this ),
5786
- previewWidget = $$.data( 'live-editor-preview-widget' );
5787
-
5788
- if ( ! isMouseDown && previewWidget !== undefined && previewWidget.length && ! thisView.$( '.so-preview-overlay' ).is( ':visible' ) ) {
5789
- thisView.highlightElement( previewWidget );
5790
- thisView.scrollToElement( previewWidget );
5791
- }
5792
- } );
5793
-
5794
- thisView.$el.on( 'mouseleave', '.so-widget-wrapper', function () {
5795
- thisView.resetHighlights();
5796
- } );
5797
-
5798
- thisView.builder.on( 'open_dialog', function () {
5799
- thisView.resetHighlights();
5800
- } );
5801
-
5802
- return this;
5803
- },
5804
-
5805
- /**
5806
- * Attach the live editor to the document
5807
- */
5808
- attach: function () {
5809
- this.$el.appendTo( 'body' );
5810
- },
5811
-
5812
- /**
5813
- * Display the live editor
5814
- */
5815
- open: function () {
5816
- if ( this.$el.html() === '' ) {
5817
- this.render();
5818
- }
5819
- if ( this.$el.closest( 'body' ).length === 0 ) {
5820
- this.attach();
5821
- }
5822
-
5823
- // Disable page scrolling
5824
- panels.helpers.pageScroll.lock();
5825
-
5826
- if ( this.$el.is( ':visible' ) ) {
5827
- return this;
5828
- }
5829
-
5830
- // Refresh the preview display
5831
- this.$el.show();
5832
- this.refreshPreview( this.builder.model.getPanelsData() );
5833
-
5834
- // Move the builder view into the Live Editor
5835
- this.originalContainer = this.builder.$el.parent();
5836
- this.builder.$el.appendTo( this.$( '.so-live-editor-builder' ) );
5837
- this.builder.$( '.so-tool-button.so-live-editor' ).hide();
5838
- this.builder.trigger( 'builder_resize' );
5839
-
5840
-
5841
- if( $('#original_post_status' ).val() === 'auto-draft' && ! this.autoSaved ) {
5842
- // The live editor requires a saved draft post, so we'll create one for auto-draft posts
5843
- var thisView = this;
5844
-
5845
- if ( wp.autosave ) {
5846
- // Set a temporary post title so the autosave triggers properly
5847
- if( $('#title[name="post_title"]' ).val() === '' ) {
5848
- $('#title[name="post_title"]' ).val( panelsOptions.loc.draft ).trigger('keydown');
5849
- }
5850
-
5851
- $( document ).one( 'heartbeat-tick.autosave', function(){
5852
- thisView.autoSaved = true;
5853
- thisView.refreshPreview( thisView.builder.model.getPanelsData() );
5854
- } );
5855
- wp.autosave.server.triggerSave();
5856
- }
5857
- }
5858
- },
5859
-
5860
- /**
5861
- * Close the live editor
5862
- */
5863
- close: function () {
5864
- if ( ! this.$el.is( ':visible' ) ) {
5865
- return this;
5866
- }
5867
-
5868
- this.$el.hide();
5869
- panels.helpers.pageScroll.unlock();
5870
-
5871
- // Move the builder back to its original container
5872
- this.builder.$el.appendTo( this.originalContainer );
5873
- this.builder.$( '.so-tool-button.so-live-editor' ).show();
5874
- this.builder.trigger( 'builder_resize' );
5875
- },
5876
-
5877
- /**
5878
- * Collapse the live editor
5879
- */
5880
- collapse: function () {
5881
- this.$el.toggleClass( 'so-collapsed' );
5882
-
5883
- var text = this.$( '.live-editor-collapse span' );
5884
- text.html( text.data( this.$el.hasClass( 'so-collapsed' ) ? 'expand' : 'collapse' ) );
5885
- },
5886
-
5887
- /**
5888
- * Create an overlay in the preview.
5889
- *
5890
- * @param over
5891
- * @return {*|Object} The item we're hovering over.
5892
- */
5893
- highlightElement: function ( over ) {
5894
- if( ! _.isUndefined( this.resetHighlightTimeout ) ) {
5895
- clearTimeout( this.resetHighlightTimeout );
5896
- }
5897
-
5898
- // Remove any old overlays
5899
-
5900
- var body = this.previewIframe.contents().find( 'body' );
5901
- body.find( '.panel-grid .panel-grid-cell .so-panel' )
5902
- .filter( function () {
5903
- // Filter to only include non nested
5904
- return $( this ).parents( '.so-panel' ).length === 0;
5905
- } )
5906
- .not( over )
5907
- .addClass( 'so-panels-faded' );
5908
-
5909
- over.removeClass( 'so-panels-faded' ).addClass( 'so-panels-highlighted' );
5910
- },
5911
-
5912
- /**
5913
- * Reset highlights in the live preview
5914
- */
5915
- resetHighlights: function() {
5916
-
5917
- var body = this.previewIframe.contents().find( 'body' );
5918
- this.resetHighlightTimeout = setTimeout( function(){
5919
- body.find( '.panel-grid .panel-grid-cell .so-panel' )
5920
- .removeClass( 'so-panels-faded so-panels-highlighted' );
5921
- }, 100 );
5922
- },
5923
-
5924
- /**
5925
- * Scroll over an element in the live preview
5926
- * @param over
5927
- */
5928
- scrollToElement: function( over ) {
5929
- var contentWindow = this.$( '.so-preview iframe' )[0].contentWindow;
5930
- contentWindow.liveEditorScrollTo( over );
5931
- },
5932
-
5933
- handleRefreshData: function ( newData, args ) {
5934
- if ( ! this.$el.is( ':visible' ) ) {
5935
- return this;
5936
- }
5937
-
5938
- this.refreshPreview( newData );
5939
- },
5940
-
5941
- handleLoadData: function () {
5942
- if ( ! this.$el.is( ':visible' ) ) {
5943
- return this;
5944
- }
5945
-
5946
- this.refreshPreview( this.builder.model.getPanelsData() );
5947
- },
5948
-
5949
- /**
5950
- * Refresh the Live Editor preview.
5951
- * @returns {exports}
5952
- */
5953
- refreshPreview: function ( data ) {
5954
- var loadTimePrediction = this.loadTimes.length ?
5955
- _.reduce( this.loadTimes, function ( memo, num ) {
5956
- return memo + num;
5957
- }, 0 ) / this.loadTimes.length : 1000;
5958
-
5959
- // Store the last preview iframe position
5960
- if( ! _.isNull( this.previewIframe ) ) {
5961
- if ( ! this.$( '.so-preview-overlay' ).is( ':visible' ) ) {
5962
- this.previewScrollTop = this.previewIframe.contents().scrollTop();
5963
- }
5964
- }
5965
-
5966
- // Add a loading bar
5967
- this.$( '.so-preview-overlay' ).show();
5968
- this.$( '.so-preview-overlay .so-loading-bar' )
5969
- .clearQueue()
5970
- .css( 'width', '0%' )
5971
- .animate( {width: '100%'}, parseInt( loadTimePrediction ) + 100 );
5972
-
5973
-
5974
- this.postToIframe(
5975
- {
5976
- live_editor_panels_data: JSON.stringify( data ),
5977
- live_editor_post_ID: this.builder.config.postId
5978
- },
5979
- this.previewUrl,
5980
- this.$('.so-preview')
5981
- );
5982
-
5983
- this.previewIframe.data( 'load-start', new Date().getTime() );
5984
- },
5985
-
5986
- /**
5987
- * Use a temporary form to post data to an iframe.
5988
- *
5989
- * @param data The data to send
5990
- * @param url The preview URL
5991
- * @param target The target iframe
5992
- */
5993
- postToIframe: function( data, url, target ){
5994
- // Store the old preview
5995
-
5996
- if( ! _.isNull( this.previewIframe ) ) {
5997
- this.previewIframe.remove();
5998
- }
5999
-
6000
- var iframeId = 'siteorigin-panels-live-preview-' + this.previewFrameId;
6001
-
6002
- // Remove the old preview frame
6003
- this.previewIframe = $('<iframe src="javascript:false;" />')
6004
- .attr( {
6005
- 'id' : iframeId,
6006
- 'name' : iframeId,
6007
- } )
6008
- .appendTo( target )
6009
-
6010
- this.setupPreviewFrame( this.previewIframe );
6011
-
6012
- // We can use a normal POST form submit
6013
- var tempForm = $('<form id="soPostToPreviewFrame" method="post" />')
6014
- .attr( {
6015
- id: iframeId,
6016
- target: this.previewIframe.attr('id'),
6017
- action: url
6018
- } )
6019
- .appendTo( 'body' );
6020
-
6021
- $.each( data, function( name, value ){
6022
- $('<input type="hidden" />')
6023
- .attr( {
6024
- name: name,
6025
- value: value
6026
- } )
6027
- .appendTo( tempForm );
6028
- } );
6029
-
6030
- tempForm
6031
- .submit()
6032
- .remove();
6033
-
6034
- this.previewFrameId++;
6035
-
6036
- return this.previewIframe;
6037
- },
6038
-
6039
- /**
6040
- * Do all the basic setup for the preview Iframe element
6041
- * @param iframe
6042
- */
6043
- setupPreviewFrame: function( iframe ){
6044
- var thisView = this;
6045
- iframe
6046
- .data( 'iframeready', false )
6047
- .on( 'iframeready', function () {
6048
- var $$ = $( this ),
6049
- $iframeContents = $$.contents();
6050
-
6051
- if( $$.data( 'iframeready' ) ) {
6052
- // Skip this if the iframeready function has already run
6053
- return;
6054
- }
6055
-
6056
- $$.data( 'iframeready', true );
6057
-
6058
- if ( $$.data( 'load-start' ) !== undefined ) {
6059
- thisView.loadTimes.unshift( new Date().getTime() - $$.data( 'load-start' ) );
6060
-
6061
- if ( ! _.isEmpty( thisView.loadTimes ) ) {
6062
- thisView.loadTimes = thisView.loadTimes.slice( 0, 4 );
6063
- }
6064
- }
6065
-
6066
- setTimeout( function(){
6067
- // Scroll to the correct position
6068
- $iframeContents.scrollTop( thisView.previewScrollTop );
6069
- thisView.$( '.so-preview-overlay' ).hide();
6070
- }, 100 );
6071
-
6072
-
6073
- // Lets find all the first level grids. This is to account for the Page Builder layout widget.
6074
- var layoutWrapper = $iframeContents.find( '#pl-' + thisView.builder.config.postId );
6075
- layoutWrapper.find( '.panel-grid .panel-grid-cell .so-panel' )
6076
- .filter( function () {
6077
- // Filter to only include non nested
6078
- return $( this ).closest( '.panel-layout' ).is( layoutWrapper );
6079
- } )
6080
- .each( function ( i, el ) {
6081
- var $$ = $( el );
6082
- var widgetEdit = thisView.$( '.so-live-editor-builder .so-widget-wrapper' ).eq( $$.data( 'index' ) );
6083
- widgetEdit.data( 'live-editor-preview-widget', $$ );
6084
-
6085
- $$
6086
- .css( {
6087
- 'cursor': 'pointer'
6088
- } )
6089
- .mouseenter( function () {
6090
- widgetEdit.parent().addClass( 'so-hovered' );
6091
- thisView.highlightElement( $$ );
6092
- } )
6093
- .mouseleave( function () {
6094
- widgetEdit.parent().removeClass( 'so-hovered' );
6095
- thisView.resetHighlights();
6096
- } )
6097
- .click( function ( e ) {
6098
- e.preventDefault();
6099
- // When we click a widget, send that click to the form
6100
- widgetEdit.find( '.title h4' ).click();
6101
- } );
6102
- } );
6103
-
6104
- // Prevent default clicks inside the preview iframe
6105
- $iframeContents.find( "a" ).css( {'pointer-events': 'none'} ).click( function ( e ) {
6106
- e.preventDefault();
6107
- } );
6108
-
6109
- } )
6110
- .on( 'load', function(){
6111
- var $$ = $( this );
6112
- if( ! $$.data( 'iframeready' ) ) {
6113
- $$.trigger('iframeready');
6114
- }
6115
- } );
6116
- },
6117
-
6118
- /**
6119
- * Return true if the live editor has a valid preview URL.
6120
- * @return {boolean}
6121
- */
6122
- hasPreviewUrl: function () {
6123
- return this.$( 'form.live-editor-form' ).attr( 'action' ) !== '';
6124
- },
6125
-
6126
- /**
6127
- * Toggle the size of the preview iframe to simulate mobile devices.
6128
- * @param e
6129
- */
6130
- mobileToggle: function( e ){
6131
- var button = $( e.currentTarget );
6132
- this.$('.live-editor-mode' ).not( button ).removeClass('so-active');
6133
- button.addClass( 'so-active' );
6134
-
6135
- this.$el
6136
- .removeClass( 'live-editor-desktop-mode live-editor-tablet-mode live-editor-mobile-mode' )
6137
- .addClass( 'live-editor-' + button.data( 'mode' ) + '-mode' );
6138
-
6139
- }
6140
- } );
6141
-
6142
- },{}],27:[function(require,module,exports){
6143
- var panels = window.panels, $ = jQuery;
6144
-
6145
- module.exports = Backbone.View.extend( {
6146
- template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder-row' ).html() ) ),
6147
-
6148
- events: {
6149
- 'click .so-row-settings': 'editSettingsHandler',
6150
- 'click .so-row-duplicate': 'duplicateHandler',
6151
- 'click .so-row-delete': 'confirmedDeleteHandler',
6152
- 'click .so-row-color': 'rowColorChangeHandler',
6153
- },
6154
-
6155
- builder: null,
6156
- dialog: null,
6157
-
6158
- /**
6159
- * Initialize the row view
6160
- */
6161
- initialize: function () {
6162
-
6163
- var rowCells = this.model.get('cells');
6164
- rowCells.on( 'add', this.handleCellAdd, this );
6165
- rowCells.on( 'remove', this.handleCellRemove, this );
6166
- this.model.on( 'reweight_cells', this.resize, this );
6167
-
6168
- this.model.on( 'destroy', this.onModelDestroy, this );
6169
- this.model.on( 'visual_destroy', this.visualDestroyModel, this );
6170
-
6171
- var thisView = this;
6172
- rowCells.each( function ( cell ) {
6173
- thisView.listenTo( cell.get('widgets'), 'add', thisView.resize );
6174
- } );
6175
-
6176
- // When ever a new cell is added, listen to it for new widgets
6177
- rowCells.on( 'add', function ( cell ) {
6178
- thisView.listenTo( cell.get('widgets'), 'add', thisView.resize );
6179
- }, this );
6180
-
6181
- this.model.on( 'change:label', this.onLabelChange, this );
6182
- },
6183
-
6184
- /**
6185
- * Render the row.
6186
- *
6187
- * @returns {panels.view.row}
6188
- */
6189
- render: function () {
6190
- var rowColorLabel = this.model.has( 'color_label' ) ? this.model.get( 'color_label' ) : 1;
6191
- var rowLabel = this.model.has( 'label' ) ? this.model.get( 'label' ) : '';
6192
- this.setElement( this.template( { rowColorLabel: rowColorLabel, rowLabel: rowLabel } ) );
6193
- this.$el.data( 'view', this );
6194
-
6195
- // Create views for the cells in this row
6196
- var thisView = this;
6197
- this.model.get('cells').each( function ( cell ) {
6198
- var cellView = new panels.view.cell( {
6199
- model: cell
6200
- } );
6201
- cellView.row = thisView;
6202
- cellView.render();
6203
- cellView.$el.appendTo( thisView.$( '.so-cells' ) );
6204
- } );
6205
-
6206
- // Remove any unsupported actions
6207
- if( ! this.builder.supports( 'rowAction' ) ) {
6208
- this.$('.so-row-toolbar .so-dropdown-wrapper' ).remove();
6209
- this.$el.addClass('so-row-no-actions');
6210
- }
6211
- else {
6212
- if( ! this.builder.supports( 'editRow' ) ) {
6213
- this.$('.so-row-toolbar .so-dropdown-links-wrapper .so-row-settings' ).parent().remove();
6214
- this.$el.addClass('so-row-no-edit');
6215
- }
6216
- if( ! this.builder.supports( 'addRow' ) ) {
6217
- this.$('.so-row-toolbar .so-dropdown-links-wrapper .so-row-duplicate' ).parent().remove();
6218
- this.$el.addClass('so-row-no-duplicate');
6219
- }
6220
- if( ! this.builder.supports( 'deleteRow' ) ) {
6221
- this.$('.so-row-toolbar .so-dropdown-links-wrapper .so-row-delete' ).parent().remove();
6222
- this.$el.addClass('so-row-no-delete');
6223
- }
6224
- }
6225
- if( ! this.builder.supports( 'moveRow' ) ) {
6226
- this.$('.so-row-toolbar .so-row-move' ).remove();
6227
- this.$el.addClass('so-row-no-move');
6228
- }
6229
- if( !$.trim( this.$('.so-row-toolbar').html() ).length ) {
6230
- this.$('.so-row-toolbar' ).remove();
6231
- }
6232
-
6233
- // Resize the rows when ever the widget sortable moves
6234
- this.builder.on( 'widget_sortable_move', this.resize, this );
6235
- this.builder.on( 'builder_resize', this.resize, this );
6236
-
6237
- this.resize();
6238
-
6239
- return this;
6240
- },
6241
-
6242
- /**
6243
- * Give a visual indication of the creation of this row
6244
- */
6245
- visualCreate: function () {
6246
- this.$el.hide().fadeIn( 'fast' );
6247
- },
6248
-
6249
- /**
6250
- * Visually resize the row so that all cell heights are the same and the widths so that they balance to 100%
6251
- *
6252
- * @param e
6253
- */
6254
- resize: function ( e ) {
6255
- // Don't resize this
6256
- if ( ! this.$el.is( ':visible' ) ) {
6257
- return;
6258
- }
6259
-
6260
- // Reset everything to have an automatic height
6261
- this.$( '.so-cells .cell-wrapper' ).css( 'min-height', 0 );
6262
- this.$( '.so-cells .resize-handle' ).css( 'height', 0 );
6263
-
6264
- // We'll tie the values to the row view, to prevent issue with values going to different rows
6265
- var height = 0;
6266
- this.$( '.so-cells .cell' ).each( function () {
6267
- height = Math.max(
6268
- height,
6269
- $( this ).height()
6270
- );
6271
-
6272
- $( this ).css(
6273
- 'width',
6274
- ( $( this ).data( 'view' ).model.get( 'weight' ) * 100) + "%"
6275
- );
6276
- } );
6277
-
6278
- // Resize all the grids and cell wrappers
6279
- this.$( '.so-cells .cell-wrapper' ).css( 'min-height', Math.max( height, 63 ) );
6280
- this.$( '.so-cells .resize-handle' ).css( 'height', this.$( '.so-cells .cell-wrapper' ).outerHeight() );
6281
- },
6282
-
6283
- /**
6284
- * Remove the view from the dom.
6285
- */
6286
- onModelDestroy: function () {
6287
- this.remove();
6288
- },
6289
-
6290
- /**
6291
- * Fade out the view and destroy the model
6292
- */
6293
- visualDestroyModel: function () {
6294
- this.builder.addHistoryEntry( 'row_deleted' );
6295
- var thisView = this;
6296
- this.$el.fadeOut( 'normal', function () {
6297
- thisView.model.destroy();
6298
- thisView.builder.model.refreshPanelsData();
6299
- } );
6300
- },
6301
-
6302
- onLabelChange: function( model, text ) {
6303
- if ( this.$('.so-row-label').length == 0 ) {
6304
- this.$( '.so-row-toolbar' ).prepend( '<h3 class="so-row-label">' + text + '</h3>' );
6305
- } else {
6306
- this.$('.so-row-label').text( text );
6307
- }
6308
- },
6309
-
6310
- /**
6311
- * Duplicate this row.
6312
- *
6313
- * @return {boolean}
6314
- */
6315
- duplicateHandler: function () {
6316
- this.builder.addHistoryEntry( 'row_duplicated' );
6317
-
6318
- var duplicateRow = this.model.clone( this.builder.model );
6319
-
6320
- this.builder.model.get('rows').add( duplicateRow, {
6321
- at: this.builder.model.get('rows').indexOf( this.model ) + 1
6322
- } );
6323
-
6324
- this.builder.model.refreshPanelsData();
6325
- },
6326
-
6327
- /**
6328
- * Copy the row to a localStorage
6329
- */
6330
- copyHandler: function(){
6331
- panels.helpers.clipboard.setModel( this.model );
6332
- },
6333
-
6334
- /**
6335
- * Create a new row and insert it
6336
- */
6337
- pasteHandler: function(){
6338
- var pastedModel = panels.helpers.clipboard.getModel( 'row-model' );
6339
-
6340
- if( ! _.isEmpty( pastedModel ) && pastedModel instanceof panels.model.row ) {
6341
- this.builder.addHistoryEntry( 'row_pasted' );
6342
- pastedModel.builder = this.builder.model;
6343
- this.builder.model.get('rows').add( pastedModel, {
6344
- at: this.builder.model.get('rows').indexOf( this.model ) + 1
6345
- } );
6346
- this.builder.model.refreshPanelsData();
6347
- }
6348
- },
6349
-
6350
- /**
6351
- * Handles deleting the row with a confirmation.
6352
- */
6353
- confirmedDeleteHandler: function ( e ) {
6354
- var $$ = $( e.target );
6355
-
6356
- // The user clicked on the dashicon
6357
- if ( $$.hasClass( 'dashicons' ) ) {
6358
- $$ = $.parent();
6359
- }
6360
-
6361
- if ( $$.hasClass( 'so-confirmed' ) ) {
6362
- this.visualDestroyModel();
6363
- } else {
6364
- var originalText = $$.html();
6365
-
6366
- $$.addClass( 'so-confirmed' ).html(
6367
- '<span class="dashicons dashicons-yes"></span>' + panelsOptions.loc.dropdown_confirm
6368
- );
6369
-
6370
- setTimeout( function () {
6371
- $$.removeClass( 'so-confirmed' ).html( originalText );
6372
- }, 2500 );
6373
- }
6374
- },
6375
-
6376
- /**
6377
- * Handle displaying the settings dialog
6378
- */
6379
- editSettingsHandler: function () {
6380
- if ( ! this.builder.supports( 'editRow' ) ) {
6381
- return;
6382
- }
6383
- // Lets open up an instance of the settings dialog
6384
- if ( this.dialog === null ) {
6385
- // Create the dialog
6386
- this.dialog = new panels.dialog.row();
6387
- this.dialog.setBuilder( this.builder ).setRowModel( this.model );
6388
- }
6389
-
6390
- this.dialog.openDialog();
6391
-
6392
- return this;
6393
- },
6394
-
6395
- /**
6396
- * Handle deleting this entire row.
6397
- */
6398
- deleteHandler: function () {
6399
- this.model.destroy();
6400
- return this;
6401
- },
6402
-
6403
- /**
6404
- * Change the row background color.
6405
- */
6406
- rowColorChangeHandler: function ( event ) {
6407
- this.$( '.so-row-color' ).removeClass( 'so-row-color-selected' );
6408
- var clickedColorElem = $( event.target );
6409
- var newColorLabel = clickedColorElem.data( 'color-label' );
6410
- var oldColorLabel = this.model.has( 'color_label' ) ? this.model.get( 'color_label' ) : 1;
6411
- clickedColorElem.addClass( 'so-row-color-selected' );
6412
- this.$el.removeClass( 'so-row-color-' + oldColorLabel );
6413
- this.$el.addClass( 'so-row-color-' + newColorLabel );
6414
- this.model.set( 'color_label', newColorLabel );
6415
- },
6416
-
6417
- /**
6418
- * Handle a new cell being added to this row view. For now we'll assume the new cell is always last
6419
- */
6420
- handleCellAdd: function ( cell ) {
6421
- var cellView = new panels.view.cell( {
6422
- model: cell
6423
- } );
6424
- cellView.row = this;
6425
- cellView.render();
6426
- cellView.$el.appendTo( this.$( '.so-cells' ) );
6427
- },
6428
-
6429
- /**
6430
- * Handle a cell being removed from this row view
6431
- */
6432
- handleCellRemove: function ( cell ) {
6433
- // Find the view that ties in to the cell we're removing
6434
- this.$( '.so-cells > .cell' ).each( function () {
6435
- var view = $( this ).data( 'view' );
6436
- if ( _.isUndefined( view ) ) {
6437
- return;
6438
- }
6439
-
6440
- if ( view.model.cid === cell.cid ) {
6441
- // Remove this view
6442
- view.remove();
6443
- }
6444
- } );
6445
- },
6446
-
6447
- /**
6448
- * Build up the contextual menu for a row
6449
- *
6450
- * @param e
6451
- * @param menu
6452
- */
6453
- buildContextualMenu: function ( e, menu ) {
6454
- var options = [];
6455
- for ( var i = 1; i < 5; i ++ ) {
6456
- options.push( {
6457
- title: i + ' ' + panelsOptions.loc.contextual.column
6458
- } );
6459
- }
6460
-
6461
- if( this.builder.supports( 'addRow' ) ) {
6462
- menu.addSection(
6463
- 'add-row',
6464
- {
6465
- sectionTitle: panelsOptions.loc.contextual.add_row,
6466
- search: false
6467
- },
6468
- options,
6469
- function ( c ) {
6470
- this.builder.addHistoryEntry( 'row_added' );
6471
-
6472
- var columns = Number( c ) + 1;
6473
- var weights = [];
6474
- for ( var i = 0; i < columns; i ++ ) {
6475
- weights.push( {weight: 100 / columns } );
6476
- }
6477
-
6478
- // Create the actual row
6479
- var newRow = new panels.model.row( {
6480
- collection: this.collection
6481
- } );
6482
-
6483
- var cells = new panels.collection.cells(weights);
6484
- cells.each(function (cell) {
6485
- cell.row = newRow;
6486
- });
6487
- newRow.setCells(cells);
6488
- newRow.builder = this.builder.model;
6489
-
6490
- this.builder.model.get('rows').add( newRow, {
6491
- at: this.builder.model.get('rows').indexOf( this.model ) + 1
6492
- } );
6493
-
6494
- this.builder.model.refreshPanelsData();
6495
- }.bind( this )
6496
- );
6497
- }
6498
-
6499
- var actions = {};
6500
-
6501
- if( this.builder.supports( 'editRow' ) ) {
6502
- actions.edit = { title: panelsOptions.loc.contextual.row_edit };
6503
- }
6504
-
6505
- // Copy and paste functions
6506
- if ( panels.helpers.clipboard.canCopyPaste() ) {
6507
- actions.copy = { title: panelsOptions.loc.contextual.row_copy };
6508
- if ( this.builder.supports( 'addRow' ) && panels.helpers.clipboard.isModel( 'row-model' ) ) {
6509
- actions.paste = { title: panelsOptions.loc.contextual.row_paste };
6510
- }
6511
- }
6512
-
6513
- if( this.builder.supports( 'addRow' ) ) {
6514
- actions.duplicate = { title: panelsOptions.loc.contextual.row_duplicate };
6515
- }
6516
-
6517
- if( this.builder.supports( 'deleteRow' ) ) {
6518
- actions.delete = { title: panelsOptions.loc.contextual.row_delete, confirm: true };
6519
- }
6520
-
6521
- if( ! _.isEmpty( actions ) ) {
6522
- menu.addSection(
6523
- 'row-actions',
6524
- {
6525
- sectionTitle: panelsOptions.loc.contextual.row_actions,
6526
- search: false,
6527
- },
6528
- actions,
6529
- function ( c ) {
6530
- switch ( c ) {
6531
- case 'edit':
6532
- this.editSettingsHandler();
6533
- break;
6534
- case 'copy':
6535
- this.copyHandler();
6536
- break;
6537
- case 'paste':
6538
- this.pasteHandler();
6539
- break;
6540
- case 'duplicate':
6541
- this.duplicateHandler();
6542
- break;
6543
- case 'delete':
6544
- this.visualDestroyModel();
6545
- break;
6546
- }
6547
- }.bind( this )
6548
- );
6549
- }
6550
- },
6551
- } );
6552
-
6553
- },{}],28:[function(require,module,exports){
6554
- var panels = window.panels, $ = jQuery;
6555
-
6556
- module.exports = Backbone.View.extend( {
6557
-
6558
- stylesLoaded: false,
6559
-
6560
- initialize: function () {
6561
-
6562
- },
6563
-
6564
- /**
6565
- * Render the visual styles object.
6566
- *
6567
- * @param type
6568
- * @param postId
6569
- */
6570
- render: function ( stylesType, postId, args ) {
6571
- if ( _.isUndefined( stylesType ) ) {
6572
- return;
6573
- }
6574
-
6575
- // Add in the default args
6576
- args = _.extend( {
6577
- builderType: '',
6578
- dialog: null
6579
- }, args );
6580
-
6581
- this.$el.addClass( 'so-visual-styles so-' + stylesType + '-styles' );
6582
-
6583
- var postArgs = {
6584
- builderType: args.builderType
6585
- };
6586
-
6587
- if ( stylesType === 'cell') {
6588
- postArgs.index = args.index;
6589
- }
6590
-
6591
- // Load the form
6592
- $.post(
6593
- panelsOptions.ajaxurl,
6594
- {
6595
- action: 'so_panels_style_form',
6596
- type: stylesType,
6597
- style: this.model.get( 'style' ),
6598
- args: JSON.stringify( postArgs ),
6599
- postId: postId
6600
- },
6601
- function ( response ) {
6602
- this.$el.html( response );
6603
- this.setupFields();
6604
- this.stylesLoaded = true;
6605
- this.trigger( 'styles_loaded', ! _.isEmpty( response ) );
6606
- if ( ! _.isNull( args.dialog ) ) {
6607
- args.dialog.trigger( 'styles_loaded', ! _.isEmpty( response ) );
6608
- }
6609
- }.bind(this)
6610
- );
6611
-
6612
- return this;
6613
- },
6614
-
6615
- /**
6616
- * Attach the style view to the DOM.
6617
- *
6618
- * @param wrapper
6619
- */
6620
- attach: function ( wrapper ) {
6621
- wrapper.append( this.$el );
6622
- },
6623
-
6624
- /**
6625
- * Detach the styles view from the DOM
6626
- */
6627
- detach: function () {
6628
- this.$el.detach();
6629
- },
6630
-
6631
- /**
6632
- * Setup all the fields
6633
- */
6634
- setupFields: function () {
6635
-
6636
- // Set up the sections as collapsible
6637
- this.$( '.style-section-wrapper' ).each( function () {
6638
- var $s = $( this );
6639
-
6640
- $s.find( '.style-section-head' ).click( function ( e ) {
6641
- e.preventDefault();
6642
- $s.find( '.style-section-fields' ).slideToggle( 'fast' );
6643
- } );
6644
- } );
6645
-
6646
- // Set up the color fields
6647
- if ( ! _.isUndefined( $.fn.wpColorPicker ) ) {
6648
- if ( _.isObject( panelsOptions.wpColorPickerOptions.palettes ) && ! $.isArray( panelsOptions.wpColorPickerOptions.palettes ) ) {
6649
- panelsOptions.wpColorPickerOptions.palettes = $.map( panelsOptions.wpColorPickerOptions.palettes, function ( el ) {
6650
- return el;
6651
- } );
6652
- }
6653
- this.$( '.so-wp-color-field' ).wpColorPicker( panelsOptions.wpColorPickerOptions );
6654
- }
6655
-
6656
- // Set up the image select fields
6657
- this.$( '.style-field-image' ).each( function () {
6658
- var frame = null;
6659
- var $s = $( this );
6660
-
6661
- $s.find( '.so-image-selector' ).click( function ( e ) {
6662
- e.preventDefault();
6663
-
6664
- if ( frame === null ) {
6665
- // Create the media frame.
6666
- frame = wp.media( {
6667
- // Set the title of the modal.
6668
- title: 'choose',
6669
-
6670
- // Tell the modal to show only images.
6671
- library: {
6672
- type: 'image'
6673
- },
6674
-
6675
- // Customize the submit button.
6676
- button: {
6677
- // Set the text of the button.
6678
- text: 'Done',
6679
- close: true
6680
- }
6681
- } );
6682
-
6683
- frame.on( 'select', function () {
6684
- var attachment = frame.state().get( 'selection' ).first().attributes;
6685
-
6686
- var url = attachment.url;
6687
- if ( ! _.isUndefined( attachment.sizes ) ) {
6688
- try {
6689
- url = attachment.sizes.thumbnail.url;
6690
- }
6691
- catch ( e ) {
6692
- // We'll use the full image instead
6693
- url = attachment.sizes.full.url;
6694
- }
6695
- }
6696
- $s.find( '.current-image' ).css( 'background-image', 'url(' + url + ')' );
6697
-
6698
- // Store the ID
6699
- $s.find( 'input' ).val( attachment.id )
6700
- } );
6701
- }
6702
-
6703
- frame.open();
6704
-
6705
- } );
6706
-
6707
- // Handle clicking on remove
6708
- $s.find( '.remove-image' ).click( function ( e ) {
6709
- e.preventDefault();
6710
- $s.find( '.current-image' ).css( 'background-image', 'none' );
6711
- $s.find( 'input' ).val( '' );
6712
- } );
6713
- } );
6714
-
6715
- // Set up all the measurement fields
6716
- this.$( '.style-field-measurement' ).each( function () {
6717
- var $$ = $( this );
6718
-
6719
- var text = $$.find( 'input[type="text"]' );
6720
- var unit = $$.find( 'select' );
6721
- var hidden = $$.find( 'input[type="hidden"]' );
6722
-
6723
- text.focus( function(){
6724
- $(this).select();
6725
- } );
6726
-
6727
- /**
6728
- * Load value into the visible input fields.
6729
- * @param value
6730
- */
6731
- var loadValue = function( value ) {
6732
- if( value === '' ) {
6733
- return;
6734
- }
6735
-
6736
- var re = /(?:([0-9\.,\-]+)(.*))+/;
6737
- var valueList = hidden.val().split( ' ' );
6738
- var valueListValue = [];
6739
- for ( var i in valueList ) {
6740
- var match = re.exec( valueList[i] );
6741
- if ( ! _.isNull( match ) && ! _.isUndefined( match[1] ) && ! _.isUndefined( match[2] ) ) {
6742
- valueListValue.push( match[1] );
6743
- unit.val( match[2] );
6744
- }
6745
- }
6746
-
6747
- if( text.length === 1 ) {
6748
- // This is a single input text field
6749
- text.val( valueListValue.join( ' ' ) );
6750
- }
6751
- else {
6752
- // We're dealing with a multiple field
6753
- if( valueListValue.length === 1 ) {
6754
- valueListValue = [ valueListValue[0], valueListValue[0], valueListValue[0], valueListValue[0] ];
6755
- }
6756
- else if( valueListValue.length === 2 ) {
6757
- valueListValue = [ valueListValue[0], valueListValue[1], valueListValue[0], valueListValue[1] ];
6758
- }
6759
- else if( valueListValue.length === 3 ) {
6760
- valueListValue = [ valueListValue[0], valueListValue[1], valueListValue[2], valueListValue[1] ];
6761
- }
6762
-
6763
- // Store this in the visible fields
6764
- text.each( function( i, el ) {
6765
- $( el ).val( valueListValue[i] );
6766
- } );
6767
- }
6768
- };
6769
- loadValue( hidden.val() );
6770
-
6771
- /**
6772
- * Set value of the hidden field based on inputs
6773
- */
6774
- var setValue = function( e ){
6775
- var i;
6776
-
6777
- if( text.length === 1 ) {
6778
- // We're dealing with a single measurement
6779
- var fullString = text
6780
- .val()
6781
- .split( ' ' )
6782
- .filter( function ( value ) {
6783
- return value !== '';
6784
- } )
6785
- .map( function ( value ) {
6786
- return value + unit.val();
6787
- } )
6788
- .join( ' ' );
6789
- hidden.val( fullString );
6790
- }
6791
- else {
6792
- var target = $( e.target ),
6793
- valueList = [],
6794
- emptyIndex = [],
6795
- fullIndex = [];
6796
-
6797
- text.each( function( i, el ) {
6798
- var value = $( el ).val( ) !== '' ? parseFloat( $( el ).val( ) ) : null;
6799
- valueList.push( value );
6800
-
6801
- if( value === null ) {
6802
- emptyIndex.push( i );
6803
- }
6804
- else {
6805
- fullIndex.push( i );
6806
- }
6807
- } );
6808
-
6809
- if( emptyIndex.length === 3 && fullIndex[0] === text.index( target ) ) {
6810
- text.val( target.val() );
6811
- valueList = [ target.val(), target.val(), target.val(), target.val() ];
6812
- }
6813
-
6814
- if( JSON.stringify( valueList ) === JSON.stringify( [ null, null, null, null ] ) ) {
6815
- hidden.val('');
6816
- }
6817
- else {
6818
- hidden.val( valueList.map( function( k ){
6819
- return ( k === null ? 0 : k ) + unit.val();
6820
- } ).join( ' ' ) );
6821
- }
6822
- }
6823
- };
6824
-
6825
- // Set the value when ever anything changes
6826
- text.change( setValue );
6827
- unit.change( setValue );
6828
- } );
6829
- }
6830
-
6831
- } );
6832
-
6833
- },{}],29:[function(require,module,exports){
6834
- var panels = window.panels, $ = jQuery;
6835
-
6836
- module.exports = Backbone.View.extend( {
6837
- template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder-widget' ).html() ) ),
6838
-
6839
- // The cell view that this widget belongs to
6840
- cell: null,
6841
-
6842
- // The edit dialog
6843
- dialog: null,
6844
-
6845
- events: {
6846
- 'click .widget-edit': 'editHandler',
6847
- 'click .title h4': 'titleClickHandler',
6848
- 'click .actions .widget-duplicate': 'duplicateHandler',
6849
- 'click .actions .widget-delete': 'deleteHandler'
6850
- },
6851
-
6852
- /**
6853
- * Initialize the widget
6854
- */
6855
- initialize: function () {
6856
- this.model.on( 'user_edit', this.editHandler, this ); // When a user wants to edit the widget model
6857
- this.model.on( 'user_duplicate', this.duplicateHandler, this ); // When a user wants to duplicate the widget model
6858
- this.model.on( 'destroy', this.onModelDestroy, this );
6859
- this.model.on( 'visual_destroy', this.visualDestroyModel, this );
6860
-
6861
- this.model.on( 'change:values', this.onModelChange, this );
6862
- this.model.on( 'change:label', this.onLabelChange, this );
6863
- },
6864
-
6865
- /**
6866
- * Render the widget
6867
- */
6868
- render: function ( options ) {
6869
- options = _.extend( {'loadForm': false}, options );
6870
-
6871
- this.setElement( this.template( {
6872
- title: this.model.getWidgetField( 'title' ),
6873
- description: this.model.getTitle()
6874
- } ) );
6875
-
6876
- this.$el.data( 'view', this );
6877
-
6878
- // Remove any unsupported actions
6879
- if( ! this.cell.row.builder.supports( 'editWidget' ) || this.model.get( 'read_only' ) ) {
6880
- this.$( '.actions .widget-edit' ).remove();
6881
- this.$el.addClass('so-widget-no-edit');
6882
- }
6883
- if( ! this.cell.row.builder.supports( 'addWidget' ) ) {
6884
- this.$( '.actions .widget-duplicate' ).remove();
6885
- this.$el.addClass('so-widget-no-duplicate');
6886
- }
6887
- if( ! this.cell.row.builder.supports( 'deleteWidget' ) ) {
6888
- this.$( '.actions .widget-delete' ).remove();
6889
- this.$el.addClass('so-widget-no-delete');
6890
- }
6891
- if( ! this.cell.row.builder.supports( 'moveWidget' ) ) {
6892
- this.$el.addClass('so-widget-no-move');
6893
- }
6894
- if( !$.trim( this.$('.actions').html() ).length ) {
6895
- this.$( '.actions' ).remove();
6896
- }
6897
-
6898
- if( this.model.get( 'read_only' ) ) {
6899
- this.$el.addClass('so-widget-read-only');
6900
- }
6901
-
6902
- if ( _.size( this.model.get( 'values' ) ) === 0 || options.loadForm ) {
6903
- // If this widget doesn't have a value, create a form and save it
6904
- var dialog = this.getEditDialog();
6905
-
6906
- // Save the widget as soon as the form is loaded
6907
- dialog.once( 'form_loaded', dialog.saveWidget, dialog );
6908
-
6909
- // Setup the dialog to load the form
6910
- dialog.setupDialog();
6911
- }
6912
-
6913
- return this;
6914
- },
6915
-
6916
- /**
6917
- * Display an animation that implies creation using a visual animation
6918
- */
6919
- visualCreate: function () {
6920
- this.$el.hide().fadeIn( 'fast' );
6921
- },
6922
-
6923
- /**
6924
- * Get the dialog view of the form that edits this widget
6925
- *
6926
- * @returns {null}
6927
- */
6928
- getEditDialog: function () {
6929
- if ( this.dialog === null ) {
6930
- this.dialog = new panels.dialog.widget( {
6931
- model: this.model
6932
- } );
6933
- this.dialog.setBuilder( this.cell.row.builder );
6934
-
6935
- // Store the widget view
6936
- this.dialog.widgetView = this;
6937
- }
6938
- return this.dialog;
6939
- },
6940
-
6941
- /**
6942
- * Handle clicking on edit widget.
6943
- *
6944
- * @returns {boolean}
6945
- */
6946
- editHandler: function () {
6947
- // Create a new dialog for editing this
6948
- this.getEditDialog().openDialog();
6949
- },
6950
-
6951
- titleClickHandler: function( event ){
6952
- if ( ! this.cell.row.builder.supports( 'editWidget' ) || this.model.get( 'read_only' ) ) {
6953
- return this;
6954
- }
6955
- this.editHandler();
6956
- return this;
6957
- },
6958
-
6959
- /**
6960
- * Handle clicking on duplicate.
6961
- *
6962
- * @returns {boolean}
6963
- */
6964
- duplicateHandler: function () {
6965
- // Add the history entry
6966
- this.cell.row.builder.addHistoryEntry( 'widget_duplicated' );
6967
-
6968
- // Create the new widget and connect it to the widget collection for the current row
6969
- var newWidget = this.model.clone( this.model.cell );
6970
-
6971
- this.cell.model.get('widgets').add( newWidget, {
6972
- // Add this after the existing model
6973
- at: this.model.collection.indexOf( this.model ) + 1
6974
- } );
6975
-
6976
- this.cell.row.builder.model.refreshPanelsData();
6977
- return this;
6978
- },
6979
-
6980
- /**
6981
- * Copy the row to a cookie based clipboard
6982
- */
6983
- copyHandler: function(){
6984
- panels.helpers.clipboard.setModel( this.model );
6985
- },
6986
-
6987
- /**
6988
- * Handle clicking on delete.
6989
- *
6990
- * @returns {boolean}
6991
- */
6992
- deleteHandler: function () {
6993
- this.model.trigger( 'visual_destroy' );
6994
- return this;
6995
- },
6996
-
6997
- onModelChange: function () {
6998
- // Update the description when ever the model changes
6999
- this.$( '.description' ).html( this.model.getTitle() );
7000
- },
7001
-
7002
- onLabelChange: function( model ) {
7003
- this.$( '.title > h4' ).text( model.getWidgetField( 'title' ) );
7004
- },
7005
-
7006
- /**
7007
- * When the model is destroyed, fade it out
7008
- */
7009
- onModelDestroy: function () {
7010
- this.remove();
7011
- },
7012
-
7013
- /**
7014
- * Visually destroy a model
7015
- */
7016
- visualDestroyModel: function () {
7017
- // Add the history entry
7018
- this.cell.row.builder.addHistoryEntry( 'widget_deleted' );
7019
-
7020
- var thisView = this;
7021
- this.$el.fadeOut( 'fast', function () {
7022
- thisView.cell.row.resize();
7023
- thisView.model.destroy();
7024
- thisView.cell.row.builder.model.refreshPanelsData();
7025
- thisView.remove();
7026
- } );
7027
-
7028
- return this;
7029
- },
7030
-
7031
- /**
7032
- * Build up the contextual menu for a widget
7033
- *
7034
- * @param e
7035
- * @param menu
7036
- */
7037
- buildContextualMenu: function ( e, menu ) {
7038
- if( this.cell.row.builder.supports( 'addWidget' ) ) {
7039
- menu.addSection(
7040
- 'add-widget-below',
7041
- {
7042
- sectionTitle: panelsOptions.loc.contextual.add_widget_below,
7043
- searchPlaceholder: panelsOptions.loc.contextual.search_widgets,
7044
- defaultDisplay: panelsOptions.contextual.default_widgets
7045
- },
7046
- panelsOptions.widgets,
7047
- function ( c ) {
7048
- this.cell.row.builder.addHistoryEntry( 'widget_added' );
7049
-
7050
- var widget = new panels.model.widget( {
7051
- class: c
7052
- } );
7053
- widget.cell = this.cell.model;
7054
-
7055
- // Insert the new widget below
7056
- this.cell.model.get('widgets').add( widget, {
7057
- // Add this after the existing model
7058
- at: this.model.collection.indexOf( this.model ) + 1
7059
- } );
7060
-
7061
- this.cell.row.builder.model.refreshPanelsData();
7062
- }.bind( this )
7063
- );
7064
- }
7065
-
7066
- var actions = {};
7067
-
7068
- if( this.cell.row.builder.supports( 'editWidget' ) && ! this.model.get( 'read_only' ) ) {
7069
- actions.edit = { title: panelsOptions.loc.contextual.widget_edit };
7070
- }
7071
-
7072
- // Copy and paste functions
7073
- if ( panels.helpers.clipboard.canCopyPaste() ) {
7074
- actions.copy = {title: panelsOptions.loc.contextual.widget_copy};
7075
- }
7076
-
7077
- if( this.cell.row.builder.supports( 'addWidget' ) ) {
7078
- actions.duplicate = { title: panelsOptions.loc.contextual.widget_duplicate };
7079
- }
7080
-
7081
- if( this.cell.row.builder.supports( 'deleteWidget' ) ) {
7082
- actions.delete = { title: panelsOptions.loc.contextual.widget_delete, confirm: true };
7083
- }
7084
-
7085
- if( ! _.isEmpty( actions ) ) {
7086
- menu.addSection(
7087
- 'widget-actions',
7088
- {
7089
- sectionTitle: panelsOptions.loc.contextual.widget_actions,
7090
- search: false,
7091
- },
7092
- actions,
7093
- function ( c ) {
7094
- switch ( c ) {
7095
- case 'edit':
7096
- this.editHandler();
7097
- break;
7098
- case 'copy':
7099
- this.copyHandler();
7100
- break;
7101
- case 'duplicate':
7102
- this.duplicateHandler();
7103
- break;
7104
- case 'delete':
7105
- this.visualDestroyModel();
7106
- break;
7107
- }
7108
- }.bind( this )
7109
- );
7110
- }
7111
-
7112
- // Lets also add the contextual menu for the entire row
7113
- this.cell.buildContextualMenu( e, menu );
7114
- }
7115
-
7116
- } );
7117
-
7118
- },{}],30:[function(require,module,exports){
7119
- var $ = jQuery;
7120
-
7121
- var customHtmlWidget = {
7122
- addWidget: function( idBase, widgetContainer, widgetId ) {
7123
- var component = wp.customHtmlWidgets;
7124
-
7125
- var fieldContainer = $( '<div></div>' );
7126
- var syncContainer = widgetContainer.find( '.widget-content:first' );
7127
- syncContainer.before( fieldContainer );
7128
-
7129
- var widgetControl = new component.CustomHtmlWidgetControl( {
7130
- el: fieldContainer,
7131
- syncContainer: syncContainer,
7132
- } );
7133
-
7134
- widgetControl.initializeEditor();
7135
-
7136
- // HACK: To ensure CodeMirror resize for the gutter.
7137
- widgetControl.editor.codemirror.refresh();
7138
-
7139
- return widgetControl;
7140
- }
7141
- };
7142
-
7143
- module.exports = customHtmlWidget;
7144
-
7145
- },{}],31:[function(require,module,exports){
7146
- var customHtmlWidget = require( './custom-html-widget' );
7147
- var mediaWidget = require( './media-widget' );
7148
- var textWidget = require( './text-widget' );
7149
-
7150
- var jsWidget = {
7151
- CUSTOM_HTML: 'custom_html',
7152
- MEDIA_AUDIO: 'media_audio',
7153
- MEDIA_GALLERY: 'media_gallery',
7154
- MEDIA_IMAGE: 'media_image',
7155
- MEDIA_VIDEO: 'media_video',
7156
- TEXT: 'text',
7157
-
7158
- addWidget: function( widgetContainer, widgetId ) {
7159
- var idBase = widgetContainer.find( '> .id_base' ).val();
7160
- var widget;
7161
-
7162
- switch ( idBase ) {
7163
- case this.CUSTOM_HTML:
7164
- widget = customHtmlWidget;
7165
- break;
7166
- case this.MEDIA_AUDIO:
7167
- case this.MEDIA_GALLERY:
7168
- case this.MEDIA_IMAGE:
7169
- case this.MEDIA_VIDEO:
7170
- widget = mediaWidget;
7171
- break;
7172
- case this.TEXT:
7173
- widget = textWidget;
7174
- break
7175
- }
7176
-
7177
- widget.addWidget( idBase, widgetContainer, widgetId );
7178
- },
7179
- };
7180
-
7181
- module.exports = jsWidget;
7182
-
7183
- },{"./custom-html-widget":30,"./media-widget":32,"./text-widget":33}],32:[function(require,module,exports){
7184
- var $ = jQuery;
7185
-
7186
- var mediaWidget = {
7187
- addWidget: function( idBase, widgetContainer, widgetId ) {
7188
- var component = wp.mediaWidgets;
7189
-
7190
- var ControlConstructor = component.controlConstructors[ idBase ];
7191
- if ( ! ControlConstructor ) {
7192
- return;
7193
- }
7194
-
7195
- var ModelConstructor = component.modelConstructors[ idBase ] || component.MediaWidgetModel;
7196
- var syncContainer = widgetContainer.find( '> .widget-content' );
7197
- var controlContainer = $( '<div class="media-widget-control"></div>' );
7198
- syncContainer.before( controlContainer );
7199
-
7200
- var modelAttributes = {};
7201
- syncContainer.find( '.media-widget-instance-property' ).each( function() {
7202
- var input = $( this );
7203
- modelAttributes[ input.data( 'property' ) ] = input.val();
7204
- });
7205
- modelAttributes.widget_id = widgetId;
7206
-
7207
- var widgetModel = new ModelConstructor( modelAttributes );
7208
-
7209
- var widgetControl = new ControlConstructor({
7210
- el: controlContainer,
7211
- syncContainer: syncContainer,
7212
- model: widgetModel,
7213
- });
7214
-
7215
- widgetControl.render();
7216
-
7217
- return widgetControl;
7218
- }
7219
- };
7220
-
7221
- module.exports = mediaWidget;
7222
-
7223
- },{}],33:[function(require,module,exports){
7224
- var $ = jQuery;
7225
-
7226
- var textWidget = {
7227
- addWidget: function( idBase, widgetContainer, widgetId ) {
7228
- var component = wp.textWidgets;
7229
-
7230
- var options = {};
7231
- var visualField = widgetContainer.find( '.visual' );
7232
- // 'visual' field and syncContainer were introduced together in 4.8.1
7233
- if ( visualField.length > 0 ) {
7234
- // If 'visual' field has no value it's a legacy text widget.
7235
- if ( ! visualField.val() ) {
7236
- return null;
7237
- }
7238
-
7239
- var fieldContainer = $( '<div></div>' );
7240
- var syncContainer = widgetContainer.find( '.widget-content:first' );
7241
- syncContainer.before( fieldContainer );
7242
-
7243
- options = {
7244
- el: fieldContainer,
7245
- syncContainer: syncContainer,
7246
- };
7247
- } else {
7248
- options = { el: widgetContainer };
7249
- }
7250
-
7251
- var widgetControl = new component.TextWidgetControl( options );
7252
-
7253
- widgetControl.initializeEditor();
7254
-
7255
- return widgetControl;
7256
- }
7257
- };
7258
-
7259
- module.exports = textWidget;
7260
-
7261
- },{}]},{},[16]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/siteorigin-panels-264.min.js DELETED
@@ -1,4 +0,0 @@
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||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}})},{}],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()))break;e.destroy()}}})},{}],4:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.widget,initialize:function(){}})},{}],5:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({dialogClass:"so-panels-dialog-add-builder",render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-builder").html(),{})),this.$(".so-content .siteorigin-panels-builder").append(this.builder.$el)},initializeDialog:function(){var e=this;this.once("open_dialog_complete",function(){e.builder.initSortable()}),this.on("open_dialog_complete",function(){e.builder.trigger("builder_resize")})}})},{}],6:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({historyEntryTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-history-entry").html())),entries:{},currentEntry:null,revertEntry:null,selectedEntry:null,previewScrollTop:null,dialogClass:"so-panels-dialog-history",dialogIcon:"history",events:{"click .so-close":"closeDialog","click .so-restore":"restoreSelectedEntry"},initializeDialog:function(){this.entries=new s.collection.historyEntries,this.on("open_dialog",this.setCurrentEntry,this),this.on("open_dialog",this.renderHistoryEntries,this)},render:function(){var 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 input[name="live_editor_post_ID"]').val(this.builder.config.postId),this.$("form.history-form").submit()},restoreSelectedEntry:function(){return!this.$(".so-buttons .so-restore").hasClass("disabled")&&(this.currentEntry.get("data")===this.selectedEntry.get("data")?(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(s.helpers.utils.processTemplate(l("#siteorigin-panels-directory-items").html())),builder:null,dialogClass:"so-panels-dialog-prebuilt-layouts",dialogIcon:"layouts",layoutCache:{},currentTab:!1,directoryPage:1,events:{"click .so-close":"closeDialog","click .so-sidebar-tabs li a":"tabClickHandler","click .so-content .layout":"layoutClickHandler","keyup .so-sidebar-search":"searchHandler","click .so-screenshot, .so-title":"directoryItemClickHandler"},initializeDialog:function(){var e=this;this.on("open_dialog",function(){e.$(".so-sidebar-tabs li a").first().click(),e.$(".so-status").removeClass("so-panels-loading")}),this.on("button_click",this.toolbarButtonClick,this)},render:function(){this.renderDialog(this.parseDialogContent(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();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)}}}).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=l(this),s=t.builder.model.getPanelsData(),o=l('input[name="post_title"]').val();o||(o=l('input[name="post_ID"]').val()),s.name=o,i.find('input[name="panels_export_data"]').val(JSON.stringify(s))})},displayLayoutDirectory:function(e,t,i){var s=this,o=this.$(".so-content").empty().addClass("so-panels-loading");if(void 0===e&&(e=""),void 0===t&&(t=1),void 0===i&&(i="directory-siteorigin"),i.match("^directory-")&&!panelsOptions.directory_enabled)return o.removeClass("so-panels-loading").html(l("#siteorigin-panels-directory-enable").html()),void o.find(".so-panels-enable-directory").click(function(n){n.preventDefault(),l.get(panelsOptions.ajaxurl,{action:"so_panels_directory_enable"},function(){}),panelsOptions.directory_enabled=!0,o.addClass("so-panels-loading"),s.displayLayoutDirectory(e,t,i)});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");t<=1?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")},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){var i="";e.success?t.resolve(e.data):(i=e.data.message,t.reject(e.data)),this.setStatusMessage(i,!1,!e.success),this.updateButtonState(!0)}.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(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-row-cell-preview").html())),editableLabel:!0,events:{"click .so-close":"closeDialog","click .so-toolbar .so-save":"saveHandler","click .so-toolbar .so-insert":"insertHandler","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler","change .row-set-form > *":"setCellsFromForm","click .row-set-form button.set-row":"setCellsFromForm"},dialogIcon:"add-row",dialogClass:"so-panels-dialog-row-edit",styleType:"row",dialogType:"edit",row:{cells:null,style:{}},cellStylesCache:[],initializeDialog:function(){this.on("open_dialog",function(){_.isUndefined(this.model)||_.isEmpty(this.model.get("cells"))?this.setRowModel(null):this.setRowModel(this.model),this.regenerateRowPreview()},this),this.row={cells:new s.collection.cells([{weight:.5},{weight:.5}]),style:{}},this.dialogFormsLoaded=0;var e=this;this.on("form_loaded styles_loaded",function(){2===++this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})}),this.on("close_dialog",this.closeHandler),this.on("edit_label",function(e){if(e!==panelsOptions.loc.row.add&&e!==panelsOptions.loc.row.edit||(e=""),this.model.set("label",e),_.isEmpty(e)){var t="create"===this.dialogType?panelsOptions.loc.row.add:panelsOptions.loc.row.edit;this.$(".so-title").text(t)}}.bind(this))},setRowDialogType:function(e){this.dialogType=e},render:function(){var e="create"===this.dialogType?panelsOptions.loc.row.add:panelsOptions.loc.row.edit;this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-row").html(),{title:e,dialogType:this.dialogType}));var t=this.$(".so-title");this.model.has("label")&&!_.isEmpty(this.model.get("label"))&&t.text(this.model.get("label")),this.$(".so-edit-title").val(t.text()),this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("row",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this}),this.builder.supports("addRow")||this.$(".so-buttons .so-duplicate").remove(),this.builder.supports("deleteRow")||this.$(".so-buttons .so-delete").remove();var i=this.$(".so-sidebar.so-right-sidebar");return this.styles.attach(i),this.styles.on("styles_loaded",function(e){e?i.removeClass("so-panels-loading"):(i.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),i.remove())},this),i.addClass("so-panels-loading"),_.isUndefined(this.model)||(this.$('input[name="cells"].so-row-field').val(this.model.get("cells").length),this.model.has("ratio")&&this.$('select[name="ratio"].so-row-field').val(this.model.get("ratio")),this.model.has("ratio_direction")&&this.$('select[name="ratio_direction"].so-row-field').val(this.model.get("ratio_direction"))),this.$("input.so-row-field").keyup(function(){l(this).trigger("change")}),this},setRowModel:function(e){return this.model=e,_.isEmpty(this.model)?this:(this.row={cells:this.model.get("cells").clone(),style:{},ratio:this.model.get("ratio"),ratio_direction:this.model.get("ratio_direction")},this.$('input[name="cells"].so-row-field').val(this.model.get("cells").length),this.model.has("ratio")&&this.$('select[name="ratio"].so-row-field').val(this.model.get("ratio")),this.model.has("ratio_direction")&&this.$('select[name="ratio_direction"].so-row-field').val(this.model.get("ratio_direction")),this.clearCellStylesCache(),this)},regenerateRowPreview:function(){var e=this,t=this.$(".row-preview"),i=this.getSelectedCellIndex();t.empty();var s;this.row.cells.each(function(o,n){var a=l(this.cellPreviewTemplate({weight:o.get("weight")}));t.append(a),n==i&&a.find(".preview-cell-in").addClass("cell-selected");var r,d=a.prev();d.length&&(r=l('<div class="resize-handle"></div>'),r.appendTo(a).dblclick(function(){var t=e.row.cells.at(n-1),i=o.get("weight")+t.get("weight");o.set("weight",i/2),t.set("weight",i/2),e.scaleRowWidths()}),r.draggable({axis:"x",containment:t,start:function(e,t){var i=a.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:a.outerWidth(),left:6,height:a.outerHeight()});i.find(".resize-handle").remove();var s=d.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:d.outerWidth(),right:6,height:d.outerHeight()});s.find(".resize-handle").remove(),l(this).data({newCellClone:i,prevCellClone:s}),a.find("> .preview-cell-in").css("visibility","hidden"),d.find("> .preview-cell-in").css("visibility","hidden")},drag:function(i,s){var o=e.row.cells.at(n).get("weight"),a=e.row.cells.at(n-1).get("weight"),r=o-(s.position.left+6)/t.width(),d=a+(s.position.left+6)/t.width();s.helper.offset().left,t.offset().left;l(this).data("newCellClone").css("width",t.width()*r).find(".preview-cell-weight").html(Math.round(1e3*r)/10),l(this).data("prevCellClone").css("width",t.width()*d).find(".preview-cell-weight").html(Math.round(1e3*d)/10)},stop:function(i,s){l(this).data("newCellClone").remove(),l(this).data("prevCellClone").remove(),a.find(".preview-cell-in").css("visibility","visible"),d.find(".preview-cell-in").css("visibility","visible");var o=s.position.left+6,r=o/t.width(),c=e.row.cells.at(n),h=e.row.cells.at(n-1);c.get("weight")-r>.02&&h.get("weight")+r>.02&&(c.set("weight",c.get("weight")-r),h.set("weight",h.get("weight")+r)),e.scaleRowWidths(),s.helper.css("left",-6)}})),a.click(function(e){if(l(e.target).is(".preview-cell")||l(e.target).is(".preview-cell-in")){var t=l(e.target);t.closest(".row-preview").find(".preview-cell .preview-cell-in").removeClass("cell-selected"),t.addClass("cell-selected"),this.openSelectedCellStyles()}}.bind(this)),a.find(".preview-cell-weight").click(function(i){e.$(".resize-handle").css("pointer-event","none").draggable("disable"),t.find(".preview-cell-weight").each(function(){var i=jQuery(this).hide();l('<input type="text" class="preview-cell-weight-input no-user-interacted" />').val(parseFloat(i.html())).insertAfter(i).focus(function(){clearTimeout(s)}).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.at(t).get("weight"))/10)}),s=setTimeout(function(){if(0===t.find(".preview-cell-weight-input").length)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.each(function(e,t){e.set("weight",i[t])}),t.find(".preview-cell").each(function(t,i){var s=e.row.cells.at(t).get("weight");l(i).animate({width:Math.round(1e3*s)/10+"%"},250),l(i).find(".preview-cell-weight-input").val(Math.round(1e3*s)/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.openSelectedCellStyles(),this.trigger("form_loaded",this)},getSelectedCellIndex:function(){var e=-1;return this.$(".preview-cell .preview-cell-in").each(function(t,i){l(i).is(".cell-selected")&&(e=t)}),e},openSelectedCellStyles:function(){if(!_.isUndefined(this.cellStyles)){if(this.cellStyles.stylesLoaded){var e={};try{e=this.getFormValues(".so-sidebar .so-visual-styles.so-cell-styles").style}catch(e){console.log("Error retrieving cell styles - "+e.message)}this.cellStyles.model.set("style",e)}this.cellStyles.detach()}if(this.cellStyles=this.getSelectedCellStyles(),this.cellStyles){var t=this.$(".so-sidebar.so-right-sidebar");this.cellStyles.attach(t),this.cellStyles.stylesLoaded||(this.cellStyles.on("styles_loaded",function(){t.removeClass("so-panels-loading")},this),t.addClass("so-panels-loading"))}},getSelectedCellStyles:function(){var e=this.getSelectedCellIndex();if(e>-1){var t=this.cellStylesCache[e];t||(t=new s.view.styles,t.model=this.row.cells.at(e),t.render("cell",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this,index:e}),this.cellStylesCache[e]=t)}return t},clearCellStylesCache:function(){this.cellStylesCache.forEach(function(e){e.remove()}),this.cellStylesCache=[]},scaleRowWidths:function(){var e=this;this.$(".row-preview .preview-cell").each(function(t,i){var s=e.row.cells.at(t);l(i).css("width",100*s.get("weight")+"%").find(".preview-cell-weight").html(Math.round(1e3*s.get("weight"))/10)})},setCellsFromForm:function(){try{var e={cells:parseInt(this.$('.row-set-form input[name="cells"]').val()),ratio:parseFloat(this.$('.row-set-form select[name="ratio"]').val()),direction:this.$('.row-set-form select[name="ratio_direction"]').val()};_.isNaN(e.cells)&&(e.cells=1),isNaN(e.ratio)&&(e.ratio=1),e.cells<1?(e.cells=1,this.$('.row-set-form input[name="cells"]').val(e.cells)):e.cells>12&&(e.cells=12,this.$('.row-set-form input[name="cells"]').val(e.cells)),this.$('.row-set-form select[name="ratio"]').val(e.ratio);for(var t=[],i=this.row.cells.length!==e.cells,o=1,n=0;n<e.cells;n++)t.push(o),o*=e.ratio;var a=_.reduce(t,function(e,t){return e+t});if(t=_.map(t,function(e){return e/a}),t=_.filter(t,function(e){return e>.01}),"left"===e.direction&&(t=t.reverse()),this.row.cells=new s.collection.cells(this.row.cells.first(t.length)),_.each(t,function(e,t){var i=this.row.cells.at(t);i?i.set("weight",e):(i=new s.model.cell({weight:e,row:this.model}),this.row.cells.add(i))}.bind(this)),this.row.ratio=e.ratio,this.row.ratio_direction=e.direction,i)this.regenerateRowPreview();else{var r=this;this.$(".preview-cell").each(function(e,t){var i=r.row.cells.at(e).get("weight");l(t).animate({width:Math.round(1e3*i)/10+"%"},250),l(t).find(".preview-cell-weight").html(Math.round(1e3*i)/10)}),this.$(".preview-cell").css("overflow","visible"),setTimeout(function(){r.regenerateRowPreview()},260)}}catch(e){console.log("Error setting cells - "+e.message)}this.$(".row-set-form .so-button-row-set").removeClass("button-primary")},tabClickHandler:function(e){"#row-layout"===e.attr("href")?this.$(".so-panels-dialog").addClass("so-panels-dialog-has-right-sidebar"):this.$(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar")},updateModel:function(e){if(e=_.extend({refresh:!0,refreshArgs:null},e),_.isEmpty(this.model)||(this.model.setCells(this.row.cells),this.model.set("ratio",this.row.ratio),this.model.set("ratio_direction",this.row.ratio_direction)),!_.isUndefined(this.styles)&&this.styles.stylesLoaded){var t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles.so-row-styles").style}catch(e){console.log("Error retrieving row styles - "+e.message)}this.model.set("style",t)}if(!_.isUndefined(this.cellStyles)&&this.cellStyles.stylesLoaded){var t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles.so-cell-styles").style}catch(e){console.log("Error retrieving cell styles - "+e.message)}this.cellStyles.model.set("style",t)}e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},insertHandler:function(){this.builder.addHistoryEntry("row_added"),this.updateModel();var e=this.builder.getActiveCell({createCell:!1}),t={};return null!==e&&(t.at=this.builder.model.get("rows").indexOf(e.row)+1),this.model.collection=this.builder.model.get("rows"),this.builder.model.get("rows").add(this.model,t),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},saveHandler:function(){return this.builder.addHistoryEntry("row_edited"),this.updateModel(),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},deleteHandler:function(){return this.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.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.closeDialog({silent:!0}),!1},closeHandler:function(){this.clearCellStylesCache(),_.isUndefined(this.cellStyles)||(this.cellStyles=void 0)}})},{}],9:[function(e,t,i){var s=window.panels,l=jQuery,o=e("../view/widgets/js-widget");t.exports=s.view.dialog.extend({builder:null,sidebarWidgetTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-widget-sidebar-widget").html())),dialogClass:"so-panels-dialog-edit-widget",dialogIcon:"add-widget",widgetView:!1,savingWidget:!1,editableLabel:!0,events:{"click .so-close":"saveHandler","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler"},initializeDialog:function(){var e=this;this.model.on("change:values",this.handleChangeValues,this),this.model.on("destroy",this.remove,this),this.dialogFormsLoaded=0,this.on("form_loaded styles_loaded",function(){2===++this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})}),this.on("edit_label",function(e){e===panelsOptions.widgets[this.model.get("class")].title&&(e=""),this.model.set("label",e),_.isEmpty(e)&&this.$(".so-title").text(this.model.getWidgetField("title"))}.bind(this))},render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-widget").html(),{})),this.loadForm();var e=this.model.getWidgetField("title");this.$(".so-title .widget-name").html(e),this.$(".so-edit-title").val(e),this.builder.supports("addWidget")||this.$(".so-buttons .so-duplicate").remove(),this.builder.supports("deleteWidget")||this.$(".so-buttons .so-delete").remove(),this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("widget",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this});var t=this.$(".so-sidebar.so-right-sidebar");this.styles.attach(t),this.styles.on("styles_loaded",function(e){e?t.removeClass("so-panels-loading"):(t.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),t.remove())},this),t.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;do{if(widgetView=e.eq(--t).data("view"),!_.isUndefined(widgetView)&&!widgetView.model.get("read_only"))return widgetView.getEditDialog()}while(!_.isUndefined(widgetView)&&t>0);return!1},getNextDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t,i=e.index(this.widgetView.$el);if(i===e.length-1)return!1;do{if(t=e.eq(++i).data("view"),!_.isUndefined(t)&&!t.model.get("read_only"))return t.getEditDialog()}while(!_.isUndefined(t));return!1},loadForm:function(){if(this.$("> *").length){this.$(".so-content").addClass("so-panels-loading");var e={action:"so_panels_widget_form",widget:this.model.get("class"),instance:JSON.stringify(this.model.get("values")),raw:this.model.get("raw")};l.post(panelsOptions.ajaxurl,e,function(e){var t=e.replace(/{\$id}/g,this.model.cid),i=this.$(".so-content");i.removeClass("so-panels-loading").html(t),this.trigger("form_loaded",this),this.$(".panel-dialog").trigger("panelsopen"),this.on("close_dialog",this.updateModel,this),i.find("> .widget-content").length>0&&o.addWidget(i,this.model.widget_id)}.bind(this),"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(e){}this.model.set("style",i)}this.savingWidget=!1,e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},handleChangeValues:function(){this.savingWidget||this.loadForm()},saveHandler:function(){this.builder.addHistoryEntry("widget_edited"),this.closeDialog()},deleteHandler:function(){return this.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}})},{"../view/widgets/js-widget":31}],10:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({builder:null,widgetTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-widgets-widget").html())),filter:{},dialogClass:"so-panels-dialog-add-widget",dialogIcon:"add-widget",events:{"click .so-close":"closeDialog","click .widget-type":"widgetClickHandler","keyup .so-sidebar-search":"searchHandler"},initializeDialog:function(){this.on("open_dialog",function(){this.filter.search="",this.filterWidgets(this.filter)},this),this.on("open_dialog_complete",function(){this.$(".so-sidebar-search").val("").focus(),this.balanceWidgetHeights()}),this.on("tab_click",this.tabClickHandler,this)},render:function(){this.renderDialog(this.parseDialogContent(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){if(13===e.which){var t=this.$(".widget-type-list .widget-type:visible");1===t.length&&t.click()}else this.filter.search=l(e.target).val().trim(),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)||null!==o&&!_.isEmpty(_.intersection(e.groups,panelsOptions.widgets[s].groups)),t&&(_.isUndefined(e.search)||""===e.search||-1===o.title.toLowerCase().indexOf(e.search.toLowerCase())&&(t=!1)),t?i.show():i.hide()}),this.balanceWidgetHeights()},
2
- 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.get("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){t.exports={canCopyPaste:function(){return"undefined"!=typeof Storage&&panelsOptions.user},setModel:function(e){if(!this.canCopyPaste())return!1;var t=panels.helpers.serialize.serialize(e);return e instanceof panels.model.row?t.thingType="row-model":e instanceof panels.model.widget&&(t.thingType="widget-model"),localStorage["panels_clipboard_"+panelsOptions.user]=JSON.stringify(t),!0},isModel:function(e){if(!this.canCopyPaste())return!1;var t=localStorage["panels_clipboard_"+panelsOptions.user];return void 0!==t&&(t=JSON.parse(t),t.thingType&&t.thingType===e)},getModel:function(e){if(!this.canCopyPaste())return null;var t=localStorage["panels_clipboard_"+panelsOptions.user];return void 0!==t&&(t=JSON.parse(t),t.thingType&&t.thingType===e)?panels.helpers.serialize.unserialize(t,t.thingType,null):null}}},{}],12:[function(e,t,i){t.exports={lock:function(){if("hidden"!==jQuery("body").css("overflow")){var e=[self.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft,self.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop];jQuery("body").data({"scroll-position":e}).css("overflow","hidden"),_.isUndefined(e)||window.scrollTo(e[0],e[1])}},unlock:function(){if("hidden"===jQuery("body").css("overflow")&&!jQuery(".so-panels-dialog-wrapper").is(":visible")&&!jQuery(".so-panels-live-editor").is(":visible")){jQuery("body").css("overflow","visible");var e=jQuery("body").data("scroll-position");_.isUndefined(e)||window.scrollTo(e[0],e[1])}}}},{}],13:[function(e,t,i){t.exports={serialize:function(e){var t;if(e instanceof Backbone.Model){var i={};for(var s in e.attributes)if(e.attributes.hasOwnProperty(s)){if("builder"===s||"collection"===s)continue;t=e.attributes[s],t instanceof Backbone.Model||t instanceof Backbone.Collection?i[s]=this.serialize(t):i[s]=t}return i}if(e instanceof Backbone.Collection){for(var l=[],o=0;o<e.models.length;o++)t=e.models[o],t instanceof Backbone.Model||t instanceof Backbone.Collection?l.push(this.serialize(t)):l.push(t);return l}},unserialize:function(e,t,i){var s;switch(t){case"row-model":s=new panels.model.row,s.builder=i,s.set("style",e.style),s.setCells(this.unserialize(e.cells,"cell-collection",s));break;case"cell-model":s=new panels.model.cell,s.row=i,s.set("weight",e.weight),s.set("style",e.style),s.set("widgets",this.unserialize(e.widgets,"widget-collection",s));break;case"widget-model":s=new panels.model.widget,s.cell=i;for(var l in e)e.hasOwnProperty(l)&&s.set(l,e[l]);s.set("widget_id",panels.helpers.utils.generateUUID());break;case"cell-collection":s=new panels.collection.cells;for(var o=0;o<e.length;o++)s.push(this.unserialize(e[o],"cell-model",i));break;case"widget-collection":s=new panels.collection.widgets;for(var o=0;o<e.length;o++)s.push(this.unserialize(e[o],"widget-model",i));break;default:console.log("Unknown Thing - "+t)}return s}}},{}],14:[function(e,t,i){t.exports={generateUUID:function(){var e=(new Date).getTime();return window.performance&&"function"==typeof window.performance.now&&(e+=performance.now()),"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){var i=(e+16*Math.random())%16|0;return e=Math.floor(e/16),("x"==t?i:3&i|8).toString(16)})},processTemplate:function(e){return _.isUndefined(e)||_.isNull(e)?"":(e=e.replace(/{{%/g,"<%"),e=e.replace(/%}}/g,"%>"),e=e.trim())},selectElementContents:function(e){var t=document.createRange();t.selectNodeContents(e);var i=window.getSelection();i.removeAllRanges(),i.addRange(t)}}},{}],15:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=function(e){return this.each(function(){var t=jQuery(this),i=t.closest("form").find(".widget-id").val(),o=l.extend(!0,{},e);if(_.isUndefined(i)||!(i.indexOf("__i__")>-1)){var n=new s.model.builder,a=new s.view.builder({model:n,config:o}),r=t.closest(".so-panels-dialog-wrapper").data("view");_.isUndefined(r)||(r.on("close_dialog",function(){n.refreshPanelsData()}),r.on("open_dialog_complete",function(){a.trigger("builder_resize")}),r.model.on("destroy",function(){n.emptyRows().destroy()}),a.setDialogParents(panelsOptions.loc.layout_widget,r));var d=Boolean(t.closest(".widget-content").length);a.render().attach({container:t,dialog:d||"dialog"===t.data("mode"),type:t.data("type")}).setDataField(t.find("input.panels-data")),d||"dialog"===t.data("mode")?(a.setDialogParents(panelsOptions.loc.layout_widget,a.dialog),t.find(".siteorigin-panels-display-builder").click(function(e){e.preventDefault(),a.dialog.openDialog()})):t.find(".siteorigin-panels-display-builder").parent().remove(),l(document).trigger("panels_setup",a)}})}},{}],16:[function(e,t,i){var s={};window.panels=s,window.siteoriginPanels=s,s.helpers={},s.helpers.clipboard=e("./helpers/clipboard"),s.helpers.utils=e("./helpers/utils"),s.helpers.serialize=e("./helpers/serialize"),s.helpers.pageScroll=e("./helpers/page-scroll"),s.model={},s.model.widget=e("./model/widget"),s.model.cell=e("./model/cell"),s.model.row=e("./model/row"),s.model.builder=e("./model/builder"),s.model.historyEntry=e("./model/history-entry"),s.collection={},s.collection.widgets=e("./collection/widgets"),s.collection.cells=e("./collection/cells"),s.collection.rows=e("./collection/rows"),s.collection.historyEntries=e("./collection/history-entries"),s.view={},s.view.widget=e("./view/widget"),s.view.cell=e("./view/cell"),s.view.row=e("./view/row"),s.view.builder=e("./view/builder"),s.view.dialog=e("./view/dialog"),s.view.styles=e("./view/styles"),s.view.liveEditor=e("./view/live-editor"),s.dialog={},s.dialog.builder=e("./dialog/builder"),s.dialog.widgets=e("./dialog/widgets"),s.dialog.widget=e("./dialog/widget"),s.dialog.prebuilt=e("./dialog/prebuilt"),s.dialog.row=e("./dialog/row"),s.dialog.history=e("./dialog/history"),s.utils={},s.utils.menu=e("./utils/menu"),jQuery.fn.soPanelsSetupBuilderWidget=e("./jquery/setup-builder-widget"),jQuery(function(e){var t,i,s,l,o=e("#siteorigin-panels-metabox");if(s=e("form#post"),o.length&&s.length)t=o,i=o.find(".siteorigin-panels-data-field"),l={editorType:"tinyMCE",postId:e("#post_ID").val(),editorId:"#content",builderType:o.data("builder-type"),builderSupports:o.data("builder-supports"),loadOnAttach:panelsOptions.loadOnAttach&&1==e("#auto_draft").val(),loadLiveEditor:1==o.data("live-editor"),liveEditorPreview:t.data("preview-url")};else if(e(".siteorigin-panels-builder-form").length){var n=e(".siteorigin-panels-builder-form");t=n.find(".siteorigin-panels-builder-container"),i=n.find('input[name="panels_data"]'),s=n,l={editorType:"standalone",postId:n.data("post-id"),editorId:"#post_content",builderType:n.data("type"),builderSupports:n.data("builder-supports"),loadLiveEditor:!1,liveEditorPreview:n.data("preview-url")}}if(!_.isUndefined(t)){var a=window.siteoriginPanels,r=new a.model.builder,d=new a.view.builder({model:r,config:l});d.render().attach({container:t}).setDataField(i).attachToEditor(),s.submit(function(){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,"./helpers/clipboard":11,"./helpers/page-scroll":12,"./helpers/serialize":13,"./helpers/utils":14,"./jquery/setup-builder-widget":15,"./model/builder":17,"./model/cell":18,"./model/history-entry":19,"./model/row":20,"./model/widget":21,"./utils/menu":22,"./view/builder":23,"./view/cell":24,"./view/dialog":25,"./view/live-editor":26,"./view/row":27,"./view/styles":28,"./view/widget":29}],17:[function(e,t,i){t.exports=Backbone.Model.extend({layoutPosition:{BEFORE:"before",AFTER:"after",REPLACE:"replace"},rows:{},defaults:{data:{widgets:[],grids:[],grid_cells:[]}},initialize:function(){this.set("rows",new panels.collection.rows)},addRow:function(e,t,i){i=_.extend({noAnimate:!1},i);var s=new panels.collection.cells(t);e=_.extend({collection:this.get("rows"),cells:s},e);var l=new panels.model.row(e);return l.builder=this,this.get("rows").add(l,i),l},loadPanelsData:function(e,t){try{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(e.grid_cells[l]);var o=this;if(_.each(i,function(t,i){var s={};_.isUndefined(e.grids[i].style)||(s.style=e.grids[i].style),_.isUndefined(e.grids[i].ratio)||(s.ratio=e.grids[i].ratio),_.isUndefined(e.grids[i].ratio_direction)||(s.ratio_direction=e.grids[i].ratio_direction),_.isUndefined(e.grids[i].color_label)||(s.color_label=e.grids[i].color_label),_.isUndefined(e.grids[i].label)||(s.label=e.grids[i].label),o.addRow(s,t,{noAnimate:!0})}),_.isUndefined(e.widgets))return;_.each(e.widgets,function(e){var t=null;_.isUndefined(e.panels_info)?(t=e.info,delete e.info):(t=e.panels_info,delete e.panels_info);var i=o.get("rows").at(parseInt(t.grid)),s=i.get("cells").at(parseInt(t.cell)),l=new panels.model.widget({class:t.class,values:e});_.isUndefined(t.style)||l.set("style",t.style),_.isUndefined(t.read_only)||l.set("read_only",t.read_only),_.isUndefined(t.widget_id)?l.set("widget_id",panels.helpers.utils.generateUUID()):l.set("widget_id",t.widget_id),_.isUndefined(t.label)||l.set("label",t.label),l.cell=s,s.get("widgets").add(l,{noAnimate:!0})}),this.trigger("load_panels_data")}catch(e){console.log("Error loading data: "+e.message)}},concatPanelsData:function(e,t){if(_.isUndefined(t)||_.isUndefined(t.grids)||_.isEmpty(t.grids)||_.isUndefined(t.grid_cells)||_.isEmpty(t.grid_cells))return e;if(_.isUndefined(e)||_.isUndefined(e.grids)||_.isEmpty(e.grids))return t;var i=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.get("rows").each(function(i,s){i.get("cells").each(function(i,l){i.get("widgets").each(function(i,o){var n={class:i.get("class"),raw:i.get("raw"),grid:s,cell:l,id:t++,widget_id:i.get("widget_id"),style:i.get("style"),label:i.get("label")};_.isEmpty(n.widget_id)&&(n.widget_id=panels.helpers.utils.generateUUID());var a=_.extend(_.clone(i.get("values")),{panels_info:n});e.widgets.push(a)}),e.grid_cells.push({grid:s,index:l,weight:i.get("weight"),style:i.get("style")})}),e.grids.push({cells:i.get("cells").length,style:i.get("style"),ratio:i.get("ratio"),ratio_direction:i.get("ratio_direction"),color_label:i.get("color_label"),label:i.get("label")})}),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.get("rows").toArray(),"destroy"),this.get("rows").reset(),this},isValidLayoutPosition:function(e){return e===this.layoutPosition.BEFORE||e===this.layoutPosition.AFTER||e===this.layoutPosition.REPLACE},getPanelsDataFromHtml:function(e,t){var i=this,s=jQuery('<div id="wrapper">'+e+"</div>");if(s.find(".panel-layout .panel-grid").length){var l={grids:[],grid_cells:[],widgets:[]},o=new RegExp(panelsOptions.siteoriginWidgetRegex,"i"),n=function(){function e(e){return e&&"string"==typeof e&&(e=e.replace(/<script[^>]*>([\S\s]*?)<\/script>/gim,""),e=e.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gim,""),t.innerHTML=e,e=t.textContent,t.textContent=""),e}var t=document.createElement("div");return e}(),a=function(e){var t=e.find("div");if(!t.length)return e.html();var i;for(i=0;i<t.length-1&&jQuery.trim(t.eq(i).text())==jQuery.trim(t.eq(i+1).text());i++);var s=t.eq(i).find(".widget-title:header"),l="";return s.length&&(l=s.html(),s.remove()),{title:l,text:t.eq(i).html()}},r=s.find(".panel-layout").eq(0),d=function(e,t){return jQuery(t).closest(".panel-layout").is(r)};return s.find("> .panel-layout > .panel-grid").filter(d).each(function(e,s){var r=jQuery(s),c=r.find(".panel-grid-cell").filter(d);l.grids.push({cells:c.length,style:r.data("style"),ratio:r.data("ratio"),ratio_direction:r.data("ratio-direction"),color_label:r.data("color-label"),label:r.data("label")}),c.each(function(s,r){var c=jQuery(r),h=c.find(".so-panel").filter(d);l.grid_cells.push({grid:e,weight:_.isUndefined(c.data("weight"))?1:parseFloat(c.data("weight")),style:c.data("style")}),h.each(function(r,d){var c=jQuery(d),h=c.find(".panel-widget-style").length?c.find(".panel-widget-style").html():c.html(),u={grid:e,cell:s,style:c.data("style"),raw:!1,label:c.data("label")};h=h.trim();var p=o.exec(h);if(!_.isNull(p)&&""===h.replace(o,"").trim()){try{var g=/class="(.*?)"/.exec(p[3]),f=jQuery(p[5]),w=JSON.parse(n(f.val())),m=w.instance;u.class=g[1].replace(/\\\\+/g,"\\"),u.raw=!1,m.panels_info=u,l.widgets.push(m)}catch(e){u.class=t,l.widgets.push(_.extend(a(c),{filter:"1",type:"visual",panels_info:u}))}return!0}if(-1!==h.indexOf("panel-layout")){if(jQuery("<div>"+h+"</div>").find(".panel-layout .panel-grid").length)return u.class="SiteOrigin_Panels_Widgets_Layout",l.widgets.push({panels_data:i.getPanelsDataFromHtml(h,t),panels_info:u}),!0}return u.class=t,l.widgets.push(_.extend(a(c),{filter:"1",type:"visual",panels_info:u})),!0})})}),s.find(".panel-layout").remove(),s.find("style[data-panels-style-for-post]").remove(),s.html().replace(/^\s+|\s+$/gm,"").length&&(l.grids.push({cells:1,style:{}}),l.grid_cells.push({grid:l.grids.length-1,weight:1}),l.widgets.push({filter:"1",text:s.html().replace(/^\s+|\s+$/gm,""),title:"",type:"visual",panels_info:{class:t,raw:!1,grid:l.grids.length-1,cell:0}})),l}return{grid_cells:[{grid:0,weight:1}],grids:[{cells:1}],widgets:[{filter:"1",text:e,title:"",type:"visual",panels_info:{class:t,raw:!1,grid:0,cell:0}}]}}})},{}],18:[function(e,t,i){t.exports=Backbone.Model.extend({widgets:{},row:null,defaults:{weight:0,style:{}},indexes:null,initialize:function(){this.set("widgets",new panels.collection.widgets),this.on("destroy",this.onDestroy,this)},onDestroy:function(){_.invoke(this.get("widgets").toArray(),"destroy"),this.get("widgets").reset()},clone:function(e,t){_.isUndefined(e)&&(e=this.row),t=_.extend({cloneWidgets:!0},t);var i=new this.constructor(this.attributes);return i.set("collection",e.get("cells"),{silent:!0}),i.row=e,t.cloneWidgets&&this.get("widgets").each(function(e){i.get("widgets").add(e.clone(i,t),{silent:!0})}),i}})},{}],19:[function(e,t,i){t.exports=Backbone.Model.extend({defaults:{text:"",data:"",time:null,count:1}})},{}],20:[function(e,t,i){t.exports=Backbone.Model.extend({builder:null,defaults:{style:{}},indexes:null,initialize:function(){_.isEmpty(this.get("cells"))?this.set("cells",new panels.collection.cells):this.get("cells").each(function(e){e.row=this}.bind(this)),this.on("destroy",this.onDestroy,this)},setCells:function(e){var t=this.get("cells")||new panels.collection.cells,i=[];t.each(function(s,l){var o=e.at(l);if(o)s.set("weight",o.get("weight"));else{for(var n=t.at(e.length-1),a=s.get("widgets").models.slice(),r=0;r<a.length;r++)a[r].moveToCell(n,{silent:!1});i.push(s)}}),_.each(i,function(e){t.remove(e)}),e.length>t.length&&_.each(e.slice(t.length,e.length),function(e){e.set({collection:t}),e.row=this,t.add(e)}.bind(this)),this.reweightCells()},reweightCells:function(){var e=0,t=this.get("cells");t.each(function(t){e+=t.get("weight")}),t.each(function(t){t.set("weight",t.get("weight")/e)}),this.trigger("reweight_cells")},onDestroy:function(){_.invoke(this.get("cells").toArray(),"destroy"),this.get("cells").reset()},clone:function(e){_.isUndefined(e)&&(e=this.builder);var t=new this.constructor(this.attributes);t.set("collection",e.get("rows"),{silent:!0}),t.builder=e;var i=new panels.collection.cells;return this.get("cells").each(function(e){i.add(e.clone(t),{silent:!0})}),t.set("cells",i),t}})},{}],21:[function(e,t,i){t.exports=Backbone.Model.extend({cell:null,defaults:{class:null,missing:!1,values:{},raw:!1,style:{},read_only:!1,widget_id:""},indexes:null,initialize:function(){var e=this.get("class");!_.isUndefined(panelsOptions.widgets[e])&&panelsOptions.widgets[e].installed||this.set("missing",!0)},getWidgetField:function(e){return _.isUndefined(panelsOptions.widgets[this.get("class")])?"title"===e||"description"===e?panelsOptions.loc.missing_widget[e]:"":this.has("label")&&!_.isEmpty(this.get("label"))?this.get("label"):panelsOptions.widgets[this.get("class")][e]},moveToCell:function(e,t,i){return t=_.extend({silent:!0},t),this.cell=e,this.collection.remove(this,t),e.get("widgets").add(this,_.extend({at:i},t)),this.trigger("move_to_cell",e,i),this},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("widget_id",""),i.set("values",s,{silent:!0}),i.set("collection",e.get("widgets"),{silent:!0}),i.cell=e,i.isDuplicate=!0,i},getTitle:function(){var e=panelsOptions.widgets[this.get("class")];if(_.isUndefined(e))return this.get("class").replace(/_/g," ");if(!_.isUndefined(e.panels_title)&&!1===e.panels_title)return panelsOptions.widgets[this.get("class")].description;var t=this.get("values"),i=["title","text"];for(var s in t)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")}})},{}],22:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({wrapperTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-context-menu").html())),sectionTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-context-menu-section").html())),contexts:[],active:!1,events:{"keyup .so-search-wrapper input":"searchKeyUp"},initialize:function(){this.listenContextMenu(),this.render(),this.attach()},listenContextMenu:function(){var e=this;l(window).on("contextmenu",function(t){return e.active&&!e.isOverEl(e.$el,t)?(e.closeMenu(),e.active=!1,t.preventDefault(),!1):!!e.active||(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"),l(window).on("keyup",{menu:this},this.keyboardListen),l(window).on("click",{menu:this},this.clickOutsideListen),this.$el.css("max-height",l(window).height()-20),e.left+this.$el.outerWidth()+10>=l(window).width()&&(e.left=l(window).width()-this.$el.outerWidth()-10),e.left<=0&&(e.left=10),e.top+this.$el.outerHeight()-l(window).scrollTop()+10>=l(window).height()&&(e.top=l(window).height()+l(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"),l(window).off("keyup",this.keyboardListen),l(window).off("click",this.clickOutsideListen),this.active=!1,this.$el.empty().hide()},keyboardListen:function(e){var t=e.data.menu;switch(e.which){case 27:t.closeMenu()}},clickOutsideListen:function(e){var t=e.data.menu;3!==e.which&&t.$el.is(":visible")&&!t.isOverEl(t.$el,e)&&t.closeMenu()},addSection:function(e,t,i,s){var o=this;t=_.extend({display:5,defaultDisplay:!1,search:!0,sectionTitle:"",searchPlaceholder:"",titleKey:"title"},t);var n=l(this.sectionTemplate({settings:t,items:i})).attr("id","panels-menu-section-"+e);this.$el.append(n),n.find(".so-item:not(.so-confirm)").click(function(){var e=l(this);s(e.data("key")),o.closeMenu()}),n.find(".so-item.so-confirm").click(function(){var e=l(this);if(e.hasClass("so-confirming"))return s(e.data("key")),void o.closeMenu();e.data("original-text",e.html()).addClass("so-confirming").html('<span class="dashicons dashicons-yes"></span> '+panelsOptions.loc.dropdown_confirm),setTimeout(function(){e.removeClass("so-confirming"),e.html(e.data("original-text"))},2500)}),n.data("settings",t).find(".so-search-wrapper input").trigger("keyup"),this.active=!0},hasSection:function(e){return this.$el.find("#panels-menu-section-"+e).length>0},searchKeyUp:function(e){var t=l(e.currentTarget),i=t.closest(".so-section"),s=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=a-1<0?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(s.defaultDisplay){i.find(".so-item").hide();for(var r=0;r<s.defaultDisplay.length;r++)i.find('.so-item[data-key="'+s.defaultDisplay[r]+'"]').show()}else i.find(".so-item").show();else i.find(".so-item").hide().each(function(){var e=l(this);-1!==e.html().toLowerCase().indexOf(t.val().toLowerCase())&&e.show()});i.find(".so-item:visible:gt("+(s.display-1)+")").hide(),0===i.find(".so-item:visible").length&&""!==t.val()?i.find(".so-no-results").show():i.find(".so-no-results").hide()},isOverEl:function(e,t){var i=[[e.offset().left,e.offset().top],[e.offset().left+e.outerWidth(),e.offset().top+e.outerHeight()]];return t.pageX>=i[0][0]&&t.pageX<=i[1][0]&&t.pageY>=i[0][1]&&t.pageY<=i[1][1]}})},{}],23:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({config:{},template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder").html())),dialogs:{},rowsSortable:null,dataField:!1,currentData:"",attachedToEditor:!1,attachedVisible:!1,liveEditor:void 0,menu:!1,activeCell:null,events:{"click .so-tool-button.so-widget-add":"displayAddWidgetDialog","click .so-tool-button.so-row-add":"displayAddRowDialog","click .so-tool-button.so-prebuilt-add":"displayAddPrebuiltDialog","click .so-tool-button.so-history":"displayHistoryDialog","click .so-tool-button.so-live-editor":"displayLiveEditor"},rows:null,initialize:function(e){var t=this;return this.config=_.extend({loadLiveEditor:!1,builderSupports:{}},e.config),this.config.builderSupports=_.extend({addRow:!0,editRow:!0,deleteRow:!0,moveRow:!0,addWidget:!0,editWidget:!0,deleteWidget:!0,moveWidget:!0,prebuilt:!0,history:!0,liveEditor:!0,revertToEditor:!0},this.config.builderSupports),e.config.loadLiveEditor&&this.on("builder_live_editor_added",function(){this.displayLiveEditor()}),this.dialogs={widgets:new 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.get("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("hide_builder",this.handleHideBuilder,this),this.on("builder_rendered builder_resize",this.handleBuilderSizing,this),this.model.on("change:data load_panels_data",this.toggleWelcomeDisplay,this),this.on("display_builder",this.wrapEditorExpandAdjust,this),this.menu=new s.utils.menu({}),this.menu.on("activate_context",this.activateContextMenu,this),this.config.loadOnAttach&&this.on("builder_attached_to_editor",function(){this.displayAttachedBuilder({confirm:!1})},this),this},render:function(){return this.setElement(this.template()),this.$el.attr("id","siteorigin-panels-builder-"+this.cid).addClass("so-builder-container"),this.trigger("builder_rendered"),this},attach:function(e){e=_.extend({container:!1,dialog:!1},e),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.trigger("builder_attached"),this.supports("liveEditor")&&this.addLiveEditor(),this.supports("history")&&this.addHistoryBrowser();var t=this.$(".so-builder-toolbar"),i=this.$(".so-panels-welcome-message"),l=panelsOptions.loc.welcomeMessage,o=[];this.supports("addWidget")?o.push(l.addWidgetButton):t.find(".so-widget-add").hide(),this.supports("addRow")?o.push(l.addRowButton):t.find(".so-row-add").hide(),this.supports("prebuilt")?o.push(l.addPrebuiltButton):t.find(".so-prebuilt-add").hide();var n="";3===o.length?n=l.threeEnabled:2===o.length?n=l.twoEnabled:1===o.length?n=l.oneEnabled:0===o.length&&(n=l.addingDisabled);var a=_.template(s.helpers.utils.processTemplate(n)),r=a({items:o})+" "+l.docsMessage;return i.find(".so-message-wrapper").html(r),this},attachToEditor:function(){if("tinyMCE"!==this.config.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").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(e){t.displayAttachedBuilder({confirm:!0})&&e.preventDefault()})),this.supports("revertToEditor")&&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").show(),e.hide(),l(window).resize(),t.attachedVisible=!1,t.trigger("hide_builder"))}).show(),e.insertAfter("#wp-content-wrap").hide().addClass("attached-to-editor");var i=this.model.get("data");_.isEmpty(i.widgets)&&_.isEmpty(i.grids)&&this.supports("revertToEditor")||this.displayAttachedBuilder({confirm:!1});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.trigger("builder_attached_to_editor"),this},displayAttachedBuilder:function(e){if(e=_.extend({confirm:!0},e),e.confirm){var t="undefined"!=typeof tinyMCE&&tinyMCE.get("content");if(""!==(t&&_.isFunction(t.getContent)?t.getContent():l("textarea#content").val())&&!confirm(panelsOptions.loc.confirm_use_builder))return!1}return l("#wp-content-wrap").hide(),l("#editor-expand-toggle").on("change.editor-expand",function(){l(this).prop("checked")||l("#wp-content-wrap").hide()}),this.metabox.show().find("> .inside").show(),l(window).resize(),l(document).scroll(),this.attachedVisible=!0,this.trigger("display_builder"),!0},initSortable:function(){if(!this.supports("moveRow"))return this;var e=this;return 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,i){e.addHistoryEntry("row_moved");var s=l(i.item),o=s.data("view");e.model.get("rows").remove(o.model,{silent:!0}),e.model.get("rows").add(o.model,{silent:!0,at:s.index()}),o.trigger("move",s.index()),e.model.refreshPanelsData()}}),this},refreshSortable:function(){_.isNull(this.rowsSortable)||this.rowsSortable.sortable("refresh")},setDataField:function(e,t){if(t=_.extend({load:!0},t),this.dataField=e,this.dataField.data("builder",this),t.load&&""!==e.val()){var i=this.dataField.val();try{i=JSON.parse(i)}catch(e){i={}}this.model.loadPanelsData(i),this.currentData=i,this.toggleWelcomeDisplay()}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)),!1===i.noAnimate&&l.visualCreate(),this.refreshSortable(),l.resize()},displayAddWidgetDialog:function(){this.dialogs.widgets.openDialog()},displayAddRowDialog:function(){var e=new s.model.row,t=new s.collection.cells([{weight:.5},{weight:.5}]);t.each(function(t){t.row=e}),e.set("cells",t),e.builder=this.model,this.dialogs.row.setRowModel(e),this.dialogs.row.openDialog()},displayAddPrebuiltDialog:function(){this.dialogs.prebuilt.openDialog()},displayHistoryDialog:function(){this.dialogs.history.openDialog()},pasteRowHandler:function(){var e=s.helpers.clipboard.getModel("row-model");!_.isEmpty(e)&&e instanceof s.model.row&&(this.addHistoryEntry("row_pasted"),e.builder=this.model,this.model.get("rows").add(e,{at:this.model.get("rows").indexOf(this.model)+1}),this.model.refreshPanelsData())},getActiveCell:function(e){if(e=_.extend({createCell:!0},e),
3
- !this.model.get("rows").length){if(!e.createCell)return null;this.model.addRow({},[{weight:1}],{noAnimate:!0})}var t=this.activeCell;return _.isEmpty(t)||-1===this.model.get("rows").indexOf(t.model.row)?this.model.get("rows").last().get("cells").first():t.model},addLiveEditor:function(){return _.isEmpty(this.config.liveEditorPreview)?this:(this.liveEditor=new s.view.liveEditor({builder:this,previewUrl:this.config.liveEditorPreview}),this.liveEditor.hasPreviewUrl()&&this.$(".so-builder-toolbar .so-live-editor").show(),this.trigger("builder_live_editor_added"),this)},displayLiveEditor:function(){_.isUndefined(this.liveEditor)||this.liveEditor.open()},addHistoryBrowser:function(){if(_.isEmpty(this.config.liveEditorPreview))return this;this.dialogs.history=new 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)},supports:function(e){return"rowAction"===e?this.supports("addRow")||this.supports("editRow")||this.supports("deleteRow"):"widgetAction"===e?this.supports("addWidget")||this.supports("editWidget")||this.supports("deleteWidget"):!_.isUndefined(this.config.builderSupports[e])&&this.config.builderSupports[e]},handleContentChange:function(){if(panelsOptions.copy_content&&this.attachedToEditor&&this.$el.is(":visible")){var e=this.model.getPanelsData();_.isEmpty(e.widgets)||l.post(panelsOptions.ajaxurl,{action:"so_panels_builder_content",panels_data:JSON.stringify(e),post_id:this.config.postId},function(e){""!==e&&this.updateEditorContent(e)}.bind(this))}},updateEditorContent:function(e){if("tinyMCE"!==this.config.editorType||"undefined"==typeof tinyMCE||_.isNull(tinyMCE.get("content"))){l(this.config.editorId).val(e).trigger("change").trigger("keyup")}else{var t=tinyMCE.get("content");t.setContent(e),t.fire("change"),t.fire("keyup")}this.triggerYoastSeoChange()},triggerYoastSeoChange:function(){if(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="undefined"!=typeof tinyMCE&&tinyMCE.get("content"),t=e&&_.isFunction(e.getContent)?e.getContent():l("textarea#content").val();if((_.isEmpty(this.model.get("data"))||_.isEmpty(this.model.get("data").widgets)&&_.isEmpty(this.model.get("data").grids))&&""!==t){var i=panelsOptions.text_widget;if(_.isEmpty(i))return;this.model.loadPanelsData(this.model.getPanelsDataFromHtml(t,i)),this.model.trigger("change"),this.model.trigger("change:data")}l("#post-status-info").addClass("for-siteorigin-panels")},handleHideBuilder:function(){l("#post-status-info").show().removeClass("for-siteorigin-panels")},wrapEditorExpandAdjust:function(){try{for(var e,t=(l.hasData(window)&&l._data(window)).events.scroll,i=0;i<t.length;i++)if("editor-expand"===t[i].namespace){e=t[i],l(window).unbind("scroll",e.handler),l(window).bind("scroll",function(t){this.attachedVisible||e.handler(t)}.bind(this));break}}catch(e){return}},handleBuilderSizing:function(){var e=this.$el.width();return e?(e<480?this.$el.addClass("so-display-narrow"):this.$el.removeClass("so-display-narrow"),this):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.get("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(),o=l(".so-panels-dialog-wrapper:visible").sort(function(e,t){return l(e).zIndex()>l(t).zIndex()?1:-1}).last(),n=i.$el.closest(".so-panels-dialog-wrapper");if(i.$el.is(s)&&(0===o.length||o.is(n))){var a=l([]).add(i.$(".so-panels-welcome-message:visible")).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)}),r=a.last().data("view");void 0!==r&&void 0!==r.buildContextualMenu?r.buildContextualMenu(e,t):a.last().hasClass("so-panels-welcome-message")&&this.buildContextualMenu(e,t)}},buildContextualMenu:function(e,t){var i={};this.supports("addRow")&&(i.add_row={title:panelsOptions.loc.contextual.add_row}),s.helpers.clipboard.canCopyPaste()&&s.helpers.clipboard.isModel("row-model")&&this.supports("addRow")&&(i.paste_row={title:panelsOptions.loc.contextual.row_paste}),_.isEmpty(i)||t.addSection("builder-actions",{sectionTitle:panelsOptions.loc.contextual.row_actions,search:!1},i,function(e){switch(e){case"add_row":this.displayAddRowDialog();break;case"paste_row":this.pasteRowHandler()}}.bind(this))}})},{}],24:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-cell").html())),events:{"click .cell-wrapper":"handleCellClick"},row:null,widgetSortable:null,initialize:function(){this.model.get("widgets").on("add",this.onAddWidget,this)},render:function(){var e={weight:this.model.get("weight"),totalWeight:this.row.model.get("cells").totalWeight()};this.setElement(this.template(e)),this.$el.data("view",this);var t=this;return this.model.get("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(){if(!this.row.builder.supports("moveWidget"))return this;var e=this,t=e.row.builder.$el.attr("id");return 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),o=s.data("view"),n=s.closest(".cell").data("view");o.model.moveToCell(n.model,{},s.index()),o.cell=n,o.cell.row.builder.model.refreshPanelsData()},helper:function(e,t){var i=t.clone().css({width:t.outerWidth(),"z-index":1e4,position:"fixed"}).addClass("widget-being-dragged").appendTo("body");return t.outerWidth()>720&&i.animate({"margin-left":e.pageX-t.offset().left-240,width:480},"fast"),i}}),this},refreshSortable:function(){_.isNull(this.widgetSortable)||this.widgetSortable.sortable("refresh")},initResizable:function(){if(!this.row.builder.supports("editRow"))return this;var e,t=this.$(".resize-handle").css("position","absolute"),i=this.row.$el,s=this;return 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()}}),this},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)),!1===i.noAnimate&&l.visualCreate(),this.refreshSortable(),this.row.resize()},handleCellClick:function(e){this.row.builder.$el.find(".so-cells .cell").removeClass("cell-selected"),this.row.builder.activeCell!==this||this.model.get("widgets").length?(this.$el.addClass("cell-selected"),this.row.builder.activeCell=this):this.row.builder.activeCell=null},pasteHandler:function(){var e=s.helpers.clipboard.getModel("widget-model");!_.isEmpty(e)&&e instanceof s.model.widget&&(this.row.builder.addHistoryEntry("widget_pasted"),e.cell=this.model,this.model.get("widgets").add(e),this.row.builder.model.refreshPanelsData())},buildContextualMenu:function(e,t){var i=this;t.hasSection("add-widget-below")||t.addSection("add-widget-cell",{sectionTitle:panelsOptions.loc.contextual.add_widget_cell,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){i.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({class:e});t.cell=i.model,t.cell.get("widgets").add(t),i.row.builder.model.refreshPanelsData()});var l={};this.row.builder.supports("addWidget")&&s.helpers.clipboard.isModel("widget-model")&&(l.paste={title:panelsOptions.loc.contextual.cell_paste_widget}),_.isEmpty(l)||t.addSection("cell-actions",{sectionTitle:panelsOptions.loc.contextual.cell_actions,search:!1},l,function(e){switch(e){case"paste":this.pasteHandler()}this.row.builder.model.refreshPanelsData()}.bind(this)),this.row.buildContextualMenu(e,t)}})},{}],25:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({dialogTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog").html())),dialogTabTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-tab").html())),tabbed:!1,rendered:!1,builder:!1,className:"so-panels-dialog-wrapper",dialogClass:"",dialogIcon:"",parentDialog:!1,dialogOpen:!1,editableLabel:!1,events:{"click .so-close":"closeDialog","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext"},initialize:function(){this.once("open_dialog",this.render),this.once("open_dialog",this.attach),this.once("open_dialog",this.setDialogClass),this.trigger("initialize_dialog",this),_.isUndefined(this.initializeDialog)||this.initializeDialog()},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=l(_.template(s.helpers.utils.processTemplate(e))(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(e=_.extend({editableLabel:this.editableLabel,dialogIcon:this.dialogIcon},e),this.$el.html(this.dialogTemplate(e)).hide(),this.$el.data("view",this),this.$el.addClass("so-panels-dialog-wrapper"),!1!==this.parentDialog){var t=this,i=l('<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.$(".so-title-bar .so-title-editable").length&&this.initEditableLabel(),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=l(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 o=s.split("#")[1];t.$(".so-content .so-content-tabs .tab-"+o).show()}t.trigger("tab_click",i)}),this.$(".so-sidebar-tabs li a").first().click(),this},initToolbar:function(){this.$(".so-toolbar .so-buttons .so-toolbar-button").click(function(e){e.preventDefault(),this.trigger("button_click",l(e.currentTarget))}.bind(this)),this.$(".so-toolbar .so-buttons .so-dropdown-button").click(function(e){e.preventDefault();var t=l(e.currentTarget),i=t.siblings(".so-dropdown-links-wrapper");i.is(".hidden")?i.removeClass("hidden"):i.addClass("hidden")}.bind(this)),l("html").click(function(e){this.$(".so-dropdown-links-wrapper").not(".hidden").each(function(t,i){var s=l(i),o=l(e.target);0!==o.length&&(o.is(".so-needs-confirm")&&!o.is(".so-confirmed")||o.is(".so-dropdown-button"))||s.addClass("hidden")})}.bind(this))},initEditableLabel:function(){var e=this.$(".so-title-bar .so-title-editable");e.keypress(function(t){var i="keypress"===t.type&&13===t.keyCode;if(i){var s=l(":tabbable"),o=s.index(e);s.eq(o+1).focus(),window.getSelection().removeAllRanges()}return!i}).blur(function(){var t=e.text().replace(/^\s+|\s+$/gm,"");t!==e.data("original-value").replace(/^\s+|\s+$/gm,"")&&(e.text(t),this.trigger("edit_label",t))}.bind(this)),e.focus(function(){e.data("original-value",e.text()),s.helpers.utils.selectElementContents(this)})},setupDialog:function(){this.openDialog(),this.closeDialog()},refreshDialogNav:function(){this.$(".so-title-bar .so-nav").show().removeClass("so-disabled");var e=this.getNextDialog(),t=this.$(".so-title-bar .so-next"),i=this.getPrevDialog(),s=this.$(".so-title-bar .so-previous");null===e?t.hide():!1===e&&t.addClass("so-disabled"),null===i?s.hide():!1===i&&s.addClass("so-disabled")},openDialog:function(e){e=_.extend({silent:!1},e),e.silent||this.trigger("open_dialog"),this.dialogOpen=!0,this.refreshDialogNav(),s.helpers.pageScroll.lock(),l(window).on("keyup",this.keyboardListen),this.$el.show(),e.silent||(this.trigger("open_dialog_complete"),this.builder.trigger("open_dialog",this),l(document).trigger("open_dialog",this))},closeDialog:function(e){e=_.extend({silent:!1},e),e.silent||this.trigger("close_dialog"),this.dialogOpen=!1,this.$el.hide(),s.helpers.pageScroll.unlock(),l(window).off("keyup",this.keyboardListen),e.silent||(this.trigger("close_dialog_complete"),this.builder.trigger("close_dialog",this))},keyboardListen:function(e){27===e.which&&l(".so-panels-dialog-wrapper .so-close").trigger("click")},navToPrevious:function(){this.closeDialog();var e=this.getPrevDialog();null!==e&&!1!==e&&e.openDialog()},navToNext:function(){this.closeDialog();var e=this.getNextDialog();null!==e&&!1!==e&&e.openDialog()},getFormValues:function(e){_.isUndefined(e)&&(e=".so-content");var t,i=this.$(e),s={};return i.find("[name]").each(function(){var e=l(this);try{var i=/([A-Za-z_]+)\[(.*)\]/.exec(e.attr("name"));if(_.isEmpty(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=s,n=null,a=!!_.isString(e.attr("type"))&&e.attr("type").toLowerCase();if("checkbox"===a)n=e.is(":checked")?""===e.val()||e.val():null;else if("radio"===a){if(!e.is(":checked"))return;n=e.val()}else if("SELECT"===e.prop("tagName")){var r=e.find("option:selected");1===r.length?n=e.find("option:selected").val():r.length>1&&(n=_.map(e.find("option:selected"),function(e,t){return l(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(e){n=""}}if(null!==n)for(var d=0;d<t.length;d++)d===t.length-1?""===t[d]?o.push(n):o[t[d]]=n:(_.isUndefined(o[t[d]])&&(""===t[d+1]?o[t[d]]=[]:o[t[d]]={}),o=o[t[d]])}catch(t){console.log("Field ["+e.attr("name")+"] could not be processed and was skipped - "+t.message)}}),s},setStatusMessage:function(e,t,i){var s=i?'<span class="dashicons dashicons-warning"></span>'+e:e;this.$(".so-toolbar .so-status").html(s),!_.isUndefined(t)&&t?this.$(".so-toolbar .so-status").addClass("so-panels-loading"):this.$(".so-toolbar .so-status").removeClass("so-panels-loading")},setParent:function(e,t){this.parentDialog={text:e,dialog:t}}})},{}],26:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-live-editor").html())),previewScrollTop:0,loadTimes:[],previewFrameId:1,previewUrl:null,previewIframe:null,events:{"click .live-editor-close":"close","click .live-editor-collapse":"collapse","click .live-editor-mode":"mobileToggle"},initialize:function(e){e=_.extend({builder:!1,previewUrl:!1},e),_.isEmpty(e.previewUrl)&&(e.previewUrl=panelsOptions.ajaxurl+"&action=so_panels_live_editor_preview"),this.builder=e.builder,this.previewUrl=e.previewUrl,this.builder.model.on("refresh_panels_data",this.handleRefreshData,this),this.builder.model.on("load_panels_data",this.handleLoadData,this)},render:function(){this.setElement(this.template()),this.$el.hide();var e=this,t=!1;return l(document).mousedown(function(){t=!0}).mouseup(function(){t=!1}),this.$el.on("mouseenter",".so-widget-wrapper",function(){var i=l(this),s=i.data("live-editor-preview-widget");t||void 0===s||!s.length||e.$(".so-preview-overlay").is(":visible")||(e.highlightElement(s),e.scrollToElement(s))}),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")},open:function(){if(""===this.$el.html()&&this.render(),0===this.$el.closest("body").length&&this.attach(),s.helpers.pageScroll.lock(),this.$el.is(":visible"))return this;if(this.$el.show(),this.refreshPreview(this.builder.model.getPanelsData()),this.originalContainer=this.builder.$el.parent(),this.builder.$el.appendTo(this.$(".so-live-editor-builder")),this.builder.$(".so-tool-button.so-live-editor").hide(),this.builder.trigger("builder_resize"),"auto-draft"===l("#original_post_status").val()&&!this.autoSaved){var e=this;wp.autosave&&(""===l('#title[name="post_title"]').val()&&l('#title[name="post_title"]').val(panelsOptions.loc.draft).trigger("keydown"),l(document).one("heartbeat-tick.autosave",function(){e.autoSaved=!0,e.refreshPreview(e.builder.model.getPanelsData())}),wp.autosave.server.triggerSave())}},close:function(){if(!this.$el.is(":visible"))return this;this.$el.hide(),s.helpers.pageScroll.unlock(),this.builder.$el.appendTo(this.originalContainer),this.builder.$(".so-tool-button.so-live-editor").show(),this.builder.trigger("builder_resize")},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),this.previewIframe.contents().find("body").find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return 0===l(this).parents(".so-panel").length}).not(e).addClass("so-panels-faded"),e.removeClass("so-panels-faded").addClass("so-panels-highlighted")},resetHighlights:function(){var e=this.previewIframe.contents().find("body");this.resetHighlightTimeout=setTimeout(function(){e.find(".panel-grid .panel-grid-cell .so-panel").removeClass("so-panels-faded so-panels-highlighted")},100)},scrollToElement:function(e){this.$(".so-preview iframe")[0].contentWindow.liveEditorScrollTo(e)},handleRefreshData:function(e,t){if(!this.$el.is(":visible"))return this;this.refreshPreview(e)},handleLoadData:function(){if(!this.$el.is(":visible"))return this;this.refreshPreview(this.builder.model.getPanelsData())},refreshPreview:function(e){var t=this.loadTimes.length?_.reduce(this.loadTimes,function(e,t){return e+t},0)/this.loadTimes.length:1e3;_.isNull(this.previewIframe)||this.$(".so-preview-overlay").is(":visible")||(this.previewScrollTop=this.previewIframe.contents().scrollTop()),this.$(".so-preview-overlay").show(),this.$(".so-preview-overlay .so-loading-bar").clearQueue().css("width","0%").animate({width:"100%"},parseInt(t)+100),this.postToIframe({live_editor_panels_data:JSON.stringify(e),live_editor_post_ID:this.builder.config.postId},this.previewUrl,this.$(".so-preview")),this.previewIframe.data("load-start",(new Date).getTime())},postToIframe:function(e,t,i){_.isNull(this.previewIframe)||this.previewIframe.remove();var s="siteorigin-panels-live-preview-"+this.previewFrameId;this.previewIframe=l('<iframe src="javascript:false;" />').attr({id:s,name:s}).appendTo(i),this.setupPreviewFrame(this.previewIframe);var o=l('<form id="soPostToPreviewFrame" method="post" />').attr({id:s,target:this.previewIframe.attr("id"),action:t}).appendTo("body");return l.each(e,function(e,t){l('<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=l(this),i=e.contents();if(!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);var s=i.find("#pl-"+t.builder.config.postId);s.find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return l(this).closest(".panel-layout").is(s)}).each(function(e,i){var s=l(i),o=t.$(".so-live-editor-builder .so-widget-wrapper").eq(s.data("index"));o.data("live-editor-preview-widget",s),s.css({cursor:"pointer"}).mouseenter(function(){o.parent().addClass("so-hovered"),t.highlightElement(s)}).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=l(this);e.data("iframeready")||e.trigger("iframeready")})},hasPreviewUrl:function(){return""!==this.$("form.live-editor-form").attr("action")},mobileToggle:function(e){var t=l(e.currentTarget);this.$(".live-editor-mode").not(t).removeClass("so-active"),t.addClass("so-active"),this.$el.removeClass("live-editor-desktop-mode live-editor-tablet-mode live-editor-mobile-mode").addClass("live-editor-"+t.data("mode")+"-mode")}})},{}],27:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-row").html())),events:{"click .so-row-settings":"editSettingsHandler","click .so-row-duplicate":"duplicateHandler","click .so-row-delete":"confirmedDeleteHandler","click .so-row-color":"rowColorChangeHandler"},builder:null,dialog:null,initialize:function(){var e=this.model.get("cells");e.on("add",this.handleCellAdd,this),e.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 t=this;e.each(function(e){t.listenTo(e.get("widgets"),"add",t.resize)}),e.on("add",function(e){t.listenTo(e.get("widgets"),"add",t.resize)},this),this.model.on("change:label",this.onLabelChange,this)},render:function(){var e=this.model.has("color_label")?this.model.get("color_label"):1,t=this.model.has("label")?this.model.get("label"):"";this.setElement(this.template({rowColorLabel:e,rowLabel:t})),this.$el.data("view",this);var i=this;return this.model.get("cells").each(function(e){var t=new s.view.cell({model:e});t.row=i,t.render(),t.$el.appendTo(i.$(".so-cells"))}),this.builder.supports("rowAction")?(this.builder.supports("editRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-settings").parent().remove(),this.$el.addClass("so-row-no-edit")),this.builder.supports("addRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-duplicate").parent().remove(),this.$el.addClass("so-row-no-duplicate")),this.builder.supports("deleteRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-delete").parent().remove(),this.$el.addClass("so-row-no-delete"))):(this.$(".so-row-toolbar .so-dropdown-wrapper").remove(),this.$el.addClass("so-row-no-actions")),this.builder.supports("moveRow")||(this.$(".so-row-toolbar .so-row-move").remove(),this.$el.addClass("so-row-no-move")),l.trim(this.$(".so-row-toolbar").html()).length||this.$(".so-row-toolbar").remove(),this.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),this.$(".so-cells .resize-handle").css("height",0);var t=0;this.$(".so-cells .cell").each(function(){t=Math.max(t,l(this).height()),l(this).css("width",100*l(this).data("view").model.get("weight")+"%")}),this.$(".so-cells .cell-wrapper").css("min-height",Math.max(t,63)),this.$(".so-cells .resize-handle").css("height",this.$(".so-cells .cell-wrapper").outerHeight())}},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.builder.addHistoryEntry("row_deleted");var e=this;this.$el.fadeOut("normal",function(){e.model.destroy(),e.builder.model.refreshPanelsData()})},onLabelChange:function(e,t){0==this.$(".so-row-label").length?this.$(".so-row-toolbar").prepend('<h3 class="so-row-label">'+t+"</h3>"):this.$(".so-row-label").text(t)},duplicateHandler:function(){this.builder.addHistoryEntry("row_duplicated");var e=this.model.clone(this.builder.model);this.builder.model.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData()},copyHandler:function(){s.helpers.clipboard.setModel(this.model)},pasteHandler:function(){var e=s.helpers.clipboard.getModel("row-model");!_.isEmpty(e)&&e instanceof s.model.row&&(this.builder.addHistoryEntry("row_pasted"),e.builder=this.builder.model,this.builder.model.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData())},confirmedDeleteHandler:function(e){var t=l(e.target);if(t.hasClass("dashicons")&&(t=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(){if(this.builder.supports("editRow"))return null===this.dialog&&(this.dialog=new s.dialog.row,this.dialog.setBuilder(this.builder).setRowModel(this.model)),this.dialog.openDialog(),this},deleteHandler:function(){return this.model.destroy(),this},rowColorChangeHandler:function(e){this.$(".so-row-color").removeClass("so-row-color-selected");var t=l(e.target),i=t.data("color-label"),s=this.model.has("color_label")?this.model.get("color_label"):1;t.addClass("so-row-color-selected"),this.$el.removeClass("so-row-color-"+s),this.$el.addClass("so-row-color-"+i),this.model.set("color_label",i)},handleCellAdd:function(e){var t=new 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=[],l=1;l<5;l++)i.push({title:l+" "+panelsOptions.loc.contextual.column});this.builder.supports("addRow")&&t.addSection("add-row",{sectionTitle:panelsOptions.loc.contextual.add_row,search:!1},i,function(e){this.builder.addHistoryEntry("row_added");for(var t=Number(e)+1,i=[],l=0;l<t;l++)i.push({weight:100/t});var o=new s.model.row({collection:this.collection}),n=new s.collection.cells(i);n.each(function(e){e.row=o}),o.setCells(n),o.builder=this.builder.model,this.builder.model.get("rows").add(o,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData()}.bind(this));var o={};this.builder.supports("editRow")&&(o.edit={title:panelsOptions.loc.contextual.row_edit}),s.helpers.clipboard.canCopyPaste()&&(o.copy={title:panelsOptions.loc.contextual.row_copy},this.builder.supports("addRow")&&s.helpers.clipboard.isModel("row-model")&&(o.paste={title:panelsOptions.loc.contextual.row_paste})),this.builder.supports("addRow")&&(o.duplicate={title:panelsOptions.loc.contextual.row_duplicate}),this.builder.supports("deleteRow")&&(o.delete={title:panelsOptions.loc.contextual.row_delete,confirm:!0}),_.isEmpty(o)||t.addSection("row-actions",{sectionTitle:panelsOptions.loc.contextual.row_actions,search:!1},o,function(e){switch(e){case"edit":this.editSettingsHandler();break;case"copy":this.copyHandler();break;case"paste":this.pasteHandler();break;case"duplicate":this.duplicateHandler();break;case"delete":this.visualDestroyModel()}}.bind(this))}})},{}],28:[function(e,t,i){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 so-"+e+"-styles");var l={builderType:i.builderType};return"cell"===e&&(l.index=i.index),s.post(panelsOptions.ajaxurl,{action:"so_panels_style_form",type:e,style:this.model.get("style"),args:JSON.stringify(l),postId:t},function(e){this.$el.html(e),this.setupFields(),this.stylesLoaded=!0,this.trigger("styles_loaded",!_.isEmpty(e)),_.isNull(i.dialog)||i.dialog.trigger("styles_loaded",!_.isEmpty(e))}.bind(this)),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(e){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=s(this),t=e.find('input[type="text"]'),i=e.find("select"),l=e.find('input[type="hidden"]');t.focus(function(){s(this).select()});!function(e){if(""!==e){var o=/(?:([0-9\.,\-]+)(.*))+/,n=l.val().split(" "),a=[];for(var r in n){var d=o.exec(n[r]);_.isNull(d)||_.isUndefined(d[1])||_.isUndefined(d[2])||(a.push(d[1]),i.val(d[2]))}
4
- 1===t.length?t.val(a.join(" ")):(1===a.length?a=[a[0],a[0],a[0],a[0]]:2===a.length?a=[a[0],a[1],a[0],a[1]]:3===a.length&&(a=[a[0],a[1],a[2],a[1]]),t.each(function(e,t){s(t).val(a[e])}))}}(l.val());var o=function(e){if(1===t.length){var o=t.val().split(" ").filter(function(e){return""!==e}).map(function(e){return e+i.val()}).join(" ");l.val(o)}else{var n=s(e.target),a=[],r=[],d=[];t.each(function(e,t){var i=""!==s(t).val()?parseFloat(s(t).val()):null;a.push(i),null===i?r.push(e):d.push(e)}),3===r.length&&d[0]===t.index(n)&&(t.val(n.val()),a=[n.val(),n.val(),n.val(),n.val()]),JSON.stringify(a)===JSON.stringify([null,null,null,null])?l.val(""):l.val(a.map(function(e){return(null===e?0:e)+i.val()}).join(" "))}};t.change(o),i.change(o)})}})},{}],29:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-widget").html())),cell:null,dialog:null,events:{"click .widget-edit":"editHandler","click .title h4":"titleClickHandler","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),this.model.on("change:label",this.onLabelChange,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),this.cell.row.builder.supports("editWidget")&&!this.model.get("read_only")||(this.$(".actions .widget-edit").remove(),this.$el.addClass("so-widget-no-edit")),this.cell.row.builder.supports("addWidget")||(this.$(".actions .widget-duplicate").remove(),this.$el.addClass("so-widget-no-duplicate")),this.cell.row.builder.supports("deleteWidget")||(this.$(".actions .widget-delete").remove(),this.$el.addClass("so-widget-no-delete")),this.cell.row.builder.supports("moveWidget")||this.$el.addClass("so-widget-no-move"),l.trim(this.$(".actions").html()).length||this.$(".actions").remove(),this.model.get("read_only")&&this.$el.addClass("so-widget-read-only"),0===_.size(this.model.get("values"))||e.loadForm){var t=this.getEditDialog();t.once("form_loaded",t.saveWidget,t),t.setupDialog()}return this},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()},titleClickHandler:function(e){return!this.cell.row.builder.supports("editWidget")||this.model.get("read_only")?this:(this.editHandler(),this)},duplicateHandler:function(){this.cell.row.builder.addHistoryEntry("widget_duplicated");var e=this.model.clone(this.model.cell);return this.cell.model.get("widgets").add(e,{at:this.model.collection.indexOf(this.model)+1}),this.cell.row.builder.model.refreshPanelsData(),this},copyHandler:function(){s.helpers.clipboard.setModel(this.model)},deleteHandler:function(){return this.model.trigger("visual_destroy"),this},onModelChange:function(){this.$(".description").html(this.model.getTitle())},onLabelChange:function(e){this.$(".title > h4").text(e.getWidgetField("title"))},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.cell.row.builder.addHistoryEntry("widget_deleted");var e=this;return this.$el.fadeOut("fast",function(){e.cell.row.resize(),e.model.destroy(),e.cell.row.builder.model.refreshPanelsData(),e.remove()}),this},buildContextualMenu:function(e,t){this.cell.row.builder.supports("addWidget")&&t.addSection("add-widget-below",{sectionTitle:panelsOptions.loc.contextual.add_widget_below,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){this.cell.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({class:e});t.cell=this.cell.model,this.cell.model.get("widgets").add(t,{at:this.model.collection.indexOf(this.model)+1}),this.cell.row.builder.model.refreshPanelsData()}.bind(this));var i={};this.cell.row.builder.supports("editWidget")&&!this.model.get("read_only")&&(i.edit={title:panelsOptions.loc.contextual.widget_edit}),s.helpers.clipboard.canCopyPaste()&&(i.copy={title:panelsOptions.loc.contextual.widget_copy}),this.cell.row.builder.supports("addWidget")&&(i.duplicate={title:panelsOptions.loc.contextual.widget_duplicate}),this.cell.row.builder.supports("deleteWidget")&&(i.delete={title:panelsOptions.loc.contextual.widget_delete,confirm:!0}),_.isEmpty(i)||t.addSection("widget-actions",{sectionTitle:panelsOptions.loc.contextual.widget_actions,search:!1},i,function(e){switch(e){case"edit":this.editHandler();break;case"copy":this.copyHandler();break;case"duplicate":this.duplicateHandler();break;case"delete":this.visualDestroyModel()}}.bind(this)),this.cell.buildContextualMenu(e,t)}})},{}],30:[function(e,t,i){var s=jQuery,l={addWidget:function(e,t,i){var l=wp.customHtmlWidgets,o=s("<div></div>"),n=t.find(".widget-content:first");n.before(o);var a=new l.CustomHtmlWidgetControl({el:o,syncContainer:n});return a.initializeEditor(),a.editor.codemirror.refresh(),a}};t.exports=l},{}],31:[function(e,t,i){var s=e("./custom-html-widget"),l=e("./media-widget"),o=e("./text-widget"),n={CUSTOM_HTML:"custom_html",MEDIA_AUDIO:"media_audio",MEDIA_GALLERY:"media_gallery",MEDIA_IMAGE:"media_image",MEDIA_VIDEO:"media_video",TEXT:"text",addWidget:function(e,t){var i,n=e.find("> .id_base").val();switch(n){case this.CUSTOM_HTML:i=s;break;case this.MEDIA_AUDIO:case this.MEDIA_GALLERY:case this.MEDIA_IMAGE:case this.MEDIA_VIDEO:i=l;break;case this.TEXT:i=o}i.addWidget(n,e,t)}};t.exports=n},{"./custom-html-widget":30,"./media-widget":32,"./text-widget":33}],32:[function(e,t,i){var s=jQuery,l={addWidget:function(e,t,i){var l=wp.mediaWidgets,o=l.controlConstructors[e];if(o){var n=l.modelConstructors[e]||l.MediaWidgetModel,a=t.find("> .widget-content"),r=s('<div class="media-widget-control"></div>');a.before(r);var d={};a.find(".media-widget-instance-property").each(function(){var e=s(this);d[e.data("property")]=e.val()}),d.widget_id=i;var c=new n(d),h=new o({el:r,syncContainer:a,model:c});return h.render(),h}}};t.exports=l},{}],33:[function(e,t,i){var s=jQuery,l={addWidget:function(e,t,i){var l=wp.textWidgets,o={},n=t.find(".visual");if(n.length>0){if(!n.val())return null;var a=s("<div></div>"),r=t.find(".widget-content:first");r.before(a),o={el:a,syncContainer:r}}else o={el:t};var d=new l.TextWidgetControl(o);return d.initializeEditor(),d}};t.exports=l},{}]},{},[16]);
 
 
 
 
js/{siteorigin-panels-263.js → siteorigin-panels-265.js} RENAMED
@@ -910,19 +910,16 @@ module.exports = panels.view.dialog.extend({
910
  }
911
 
912
  var $rightSidebar = this.$('.so-sidebar.so-right-sidebar');
913
- this.styles.attach($rightSidebar);
914
 
915
  // Handle the loading class
916
  this.styles.on('styles_loaded', function (hasStyles) {
917
- // If we have styles remove the loading spinner, else remove the whole empty sidebar.
918
- if (hasStyles) {
919
- $rightSidebar.removeClass('so-panels-loading');
920
- } else {
921
  $rightSidebar.closest('.so-panels-dialog').removeClass('so-panels-dialog-has-right-sidebar');
922
  $rightSidebar.remove();
923
  }
924
  }, this);
925
- $rightSidebar.addClass('so-panels-loading');
926
 
927
  if (!_.isUndefined(this.model)) {
928
  // Set the initial value of the
@@ -1284,13 +1281,6 @@ module.exports = panels.view.dialog.extend({
1284
  if ( this.cellStyles ) {
1285
  var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
1286
  this.cellStyles.attach( $rightSidebar );
1287
-
1288
- if ( !this.cellStyles.stylesLoaded ) {
1289
- this.cellStyles.on( 'styles_loaded', function () {
1290
- $rightSidebar.removeClass( 'so-panels-loading' );
1291
- }, this );
1292
- $rightSidebar.addClass( 'so-panels-loading' );
1293
- }
1294
  }
1295
  },
1296
 
@@ -1577,419 +1567,425 @@ module.exports = panels.view.dialog.extend({
1577
  });
1578
 
1579
  },{}],9:[function(require,module,exports){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1580
  var panels = window.panels, $ = jQuery;
1581
- var jsWidget = require( '../view/widgets/js-widget' );
1582
 
1583
  module.exports = panels.view.dialog.extend( {
1584
 
1585
  builder: null,
1586
- sidebarWidgetTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-widget-sidebar-widget' ).html() ) ),
1587
-
1588
- dialogClass: 'so-panels-dialog-edit-widget',
1589
- dialogIcon: 'add-widget',
1590
 
1591
- widgetView: false,
1592
- savingWidget: false,
1593
- editableLabel: true,
1594
 
1595
  events: {
1596
- 'click .so-close': 'saveHandler',
1597
- 'click .so-nav.so-previous': 'navToPrevious',
1598
- 'click .so-nav.so-next': 'navToNext',
1599
-
1600
- // Action handlers
1601
- 'click .so-toolbar .so-delete': 'deleteHandler',
1602
- 'click .so-toolbar .so-duplicate': 'duplicateHandler'
1603
  },
1604
 
 
 
 
1605
  initializeDialog: function () {
1606
- var thisView = this;
1607
- this.model.on( 'change:values', this.handleChangeValues, this );
1608
- this.model.on( 'destroy', this.remove, this );
1609
 
1610
- // Refresh panels data after both dialog form components are loaded
1611
- this.dialogFormsLoaded = 0;
1612
- this.on( 'form_loaded styles_loaded', function () {
1613
- this.dialogFormsLoaded ++;
1614
- if ( this.dialogFormsLoaded === 2 ) {
1615
- thisView.updateModel( {
1616
- refreshArgs: {
1617
- silent: true
1618
- }
1619
- } );
1620
- }
1621
  } );
1622
 
1623
- this.on( 'edit_label', function ( text ) {
1624
- // If text is set to default value, just clear it.
1625
- if ( text === panelsOptions.widgets[ this.model.get( 'class' ) ][ 'title' ] ) {
1626
- text = '';
1627
- }
1628
- this.model.set( 'label', text );
1629
- if ( _.isEmpty( text ) ) {
1630
- this.$( '.so-title' ).text( this.model.getWidgetField( 'title' ) );
1631
- }
1632
- }.bind( this ) );
1633
  },
1634
 
1635
- /**
1636
- * Render the widget dialog.
1637
- */
1638
  render: function () {
1639
  // Render the dialog and attach it to the builder interface
1640
- this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widget' ).html(), {} ) );
1641
- this.loadForm();
1642
 
1643
- var title = this.model.getWidgetField( 'title' );
1644
- this.$( '.so-title .widget-name' ).html( title );
1645
- this.$( '.so-edit-title' ).val( title );
 
 
 
1646
 
1647
- if( ! this.builder.supports( 'addWidget' ) ) {
1648
- this.$( '.so-buttons .so-duplicate' ).remove();
1649
- }
1650
- if( ! this.builder.supports( 'deleteWidget' ) ) {
1651
- this.$( '.so-buttons .so-delete' ).remove();
1652
- }
1653
 
1654
- // Now we need to attach the style window
1655
- this.styles = new panels.view.styles();
1656
- this.styles.model = this.model;
1657
- this.styles.render( 'widget', this.builder.config.postId, {
1658
- builderType: this.builder.config.builderType,
1659
- dialog: this
1660
- } );
1661
 
1662
- var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
1663
- this.styles.attach( $rightSidebar );
1664
 
1665
- // Handle the loading class
1666
- this.styles.on( 'styles_loaded', function ( hasStyles ) {
1667
- // If we have styles remove the loading spinner, else remove the whole empty sidebar.
1668
- if ( hasStyles ) {
1669
- $rightSidebar.removeClass( 'so-panels-loading' );
1670
- } else {
1671
- $rightSidebar.closest( '.so-panels-dialog' ).removeClass( 'so-panels-dialog-has-right-sidebar' );
1672
- $rightSidebar.remove();
1673
- }
1674
  }, this );
1675
- $rightSidebar.addClass( 'so-panels-loading' );
 
 
 
 
 
 
 
1676
  },
1677
 
1678
  /**
1679
- * Get the previous widget editing dialog by looking at the dom.
1680
- * @returns {*}
1681
  */
1682
- getPrevDialog: function () {
1683
- var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1684
- if ( widgets.length <= 1 ) {
1685
- return false;
1686
- }
1687
- var currentIndex = widgets.index( this.widgetView.$el );
1688
 
1689
- if ( currentIndex === 0 ) {
1690
- return false;
1691
- } else {
1692
- do {
1693
- widgetView = widgets.eq( --currentIndex ).data( 'view' );
1694
- if ( ! _.isUndefined( widgetView ) && ! widgetView.model.get( 'read_only' ) ) {
1695
- return widgetView.getEditDialog();
1696
- }
1697
- } while( ! _.isUndefined( widgetView ) && currentIndex > 0 );
1698
  }
1699
 
 
 
 
 
1700
  return false;
1701
  },
1702
 
1703
  /**
1704
- * Get the next widget editing dialog by looking at the dom.
1705
- * @returns {*}
1706
  */
1707
- getNextDialog: function () {
1708
- var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1709
- if ( widgets.length <= 1 ) {
1710
- return false;
 
 
1711
  }
1712
-
1713
- var currentIndex = widgets.index( this.widgetView.$el ), widgetView;
1714
-
1715
- if ( currentIndex === widgets.length - 1 ) {
1716
- return false;
1717
- } else {
1718
- do {
1719
- widgetView = widgets.eq( ++currentIndex ).data( 'view' );
1720
- if ( ! _.isUndefined( widgetView ) && ! widgetView.model.get( 'read_only' ) ) {
1721
- return widgetView.getEditDialog();
1722
- }
1723
- } while( ! _.isUndefined( widgetView ) );
1724
  }
1725
-
1726
- return false;
1727
  },
1728
 
1729
  /**
1730
- * Load the widget form from the server.
1731
- * This is called when rendering the dialog for the first time.
1732
  */
1733
- loadForm: function () {
1734
- // don't load the form if this dialog hasn't been rendered yet
1735
- if ( ! this.$( '> *' ).length ) {
1736
- return;
1737
  }
1738
 
1739
- this.$( '.so-content' ).addClass( 'so-panels-loading' );
1740
-
1741
- var data = {
1742
- 'action': 'so_panels_widget_form',
1743
- 'widget': this.model.get( 'class' ),
1744
- 'instance': JSON.stringify( this.model.get( 'values' ) ),
1745
- 'raw': this.model.get( 'raw' )
1746
- };
1747
-
1748
- $.post(
1749
- panelsOptions.ajaxurl,
1750
- data,
1751
- function ( result ) {
1752
- // Add in the CID of the widget model
1753
- var html = result.replace( /{\$id}/g, this.model.cid );
1754
-
1755
- // Load this content into the form
1756
- var $soContent = this.$( '.so-content' );
1757
- $soContent
1758
- .removeClass( 'so-panels-loading' )
1759
- .html( html );
1760
-
1761
- // Trigger all the necessary events
1762
- this.trigger( 'form_loaded', this );
1763
-
1764
- // For legacy compatibility, trigger a panelsopen event
1765
- this.$( '.panel-dialog' ).trigger( 'panelsopen' );
1766
-
1767
- // If the main dialog is closed from this point on, save the widget content
1768
- this.on( 'close_dialog', this.updateModel, this );
1769
-
1770
- var widgetContent = $soContent.find( '> .widget-content' );
1771
- // If there's a widget content wrapper, this is one of the new widgets in WP 4.8 which need some special
1772
- // handling in JS.
1773
- if ( widgetContent.length > 0 ) {
1774
- jsWidget.addWidget( $soContent, this.model.widget_id );
1775
- }
1776
-
1777
- }.bind( this ),
1778
- 'html'
1779
- );
1780
- },
1781
-
1782
- /**
1783
- * Save the widget from the form to the model
1784
- */
1785
- updateModel: function ( args ) {
1786
- args = _.extend( {
1787
- refresh: true,
1788
- refreshArgs: null
1789
- }, args );
1790
-
1791
- // Get the values from the form and assign the new values to the model
1792
- this.savingWidget = true;
1793
-
1794
- if ( ! this.model.get( 'missing' ) ) {
1795
- // Only get the values for non missing widgets.
1796
- var values = this.getFormValues();
1797
- if ( _.isUndefined( values.widgets ) ) {
1798
- values = {};
1799
- } else {
1800
- values = values.widgets;
1801
- values = values[Object.keys( values )[0]];
1802
- }
1803
-
1804
- this.model.setValues( values );
1805
- this.model.set( 'raw', true ); // We've saved from the widget form, so this is now raw
1806
- }
1807
-
1808
- if ( this.styles.stylesLoaded ) {
1809
- // If the styles view has loaded
1810
- var style = {};
1811
- try {
1812
- style = this.getFormValues( '.so-sidebar .so-visual-styles' ).style;
1813
- }
1814
- catch ( e ) {
1815
- }
1816
- this.model.set( 'style', style );
1817
- }
1818
-
1819
- this.savingWidget = false;
1820
-
1821
- if ( args.refresh ) {
1822
- this.builder.model.refreshPanelsData( args.refreshArgs );
1823
- }
1824
- },
1825
-
1826
- /**
1827
- *
1828
- */
1829
- handleChangeValues: function () {
1830
- if ( ! this.savingWidget ) {
1831
- // Reload the form when we've changed the model and we're not currently saving from the form
1832
- this.loadForm();
1833
- }
1834
- },
1835
-
1836
- /**
1837
- * Save a history entry for this widget. Called when the dialog is closed.
1838
- */
1839
- saveHandler: function () {
1840
- this.builder.addHistoryEntry( 'widget_edited' );
1841
- this.closeDialog();
1842
- },
1843
-
1844
- /**
1845
- * When the user clicks delete.
1846
- *
1847
- * @returns {boolean}
1848
- */
1849
- deleteHandler: function () {
1850
-
1851
- this.model.trigger( 'visual_destroy' );
1852
- this.closeDialog( {silent: true} );
1853
- this.builder.model.refreshPanelsData();
1854
-
1855
- return false;
1856
- },
1857
-
1858
- duplicateHandler: function () {
1859
- this.model.trigger( 'user_duplicate' );
1860
-
1861
- this.closeDialog( {silent: true} );
1862
- this.builder.model.refreshPanelsData();
1863
-
1864
- return false;
1865
- }
1866
-
1867
- } );
1868
-
1869
- },{"../view/widgets/js-widget":31}],10:[function(require,module,exports){
1870
- var panels = window.panels, $ = jQuery;
1871
-
1872
- module.exports = panels.view.dialog.extend( {
1873
-
1874
- builder: null,
1875
- widgetTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-widgets-widget' ).html() ) ),
1876
- filter: {},
1877
-
1878
- dialogClass: 'so-panels-dialog-add-widget',
1879
- dialogIcon: 'add-widget',
1880
-
1881
- events: {
1882
- 'click .so-close': 'closeDialog',
1883
- 'click .widget-type': 'widgetClickHandler',
1884
- 'keyup .so-sidebar-search': 'searchHandler'
1885
- },
1886
-
1887
- /**
1888
- * Initialize the widget adding dialog
1889
- */
1890
- initializeDialog: function () {
1891
-
1892
- this.on( 'open_dialog', function () {
1893
- this.filter.search = '';
1894
- this.filterWidgets( this.filter );
1895
- }, this );
1896
-
1897
- this.on( 'open_dialog_complete', function () {
1898
- // Clear the search and re-filter the widgets when we open the dialog
1899
- this.$( '.so-sidebar-search' ).val( '' ).focus();
1900
- this.balanceWidgetHeights();
1901
- } );
1902
-
1903
- // We'll implement a custom tab click handler
1904
- this.on( 'tab_click', this.tabClickHandler, this );
1905
- },
1906
-
1907
- render: function () {
1908
- // Render the dialog and attach it to the builder interface
1909
- this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widgets' ).html(), {} ) );
1910
-
1911
- // Add all the widgets
1912
- _.each( panelsOptions.widgets, function ( widget ) {
1913
- var $w = $( this.widgetTemplate( {
1914
- title: widget.title,
1915
- description: widget.description
1916
- } ) );
1917
-
1918
- if ( _.isUndefined( widget.icon ) ) {
1919
- widget.icon = 'dashicons dashicons-admin-generic';
1920
- }
1921
-
1922
- $( '<span class="widget-icon" />' ).addClass( widget.icon ).prependTo( $w.find( '.widget-type-wrapper' ) );
1923
-
1924
- $w.data( 'class', widget.class ).appendTo( this.$( '.widget-type-list' ) );
1925
- }, this );
1926
-
1927
- // Add the sidebar tabs
1928
- var tabs = this.$( '.so-sidebar-tabs' );
1929
- _.each( panelsOptions.widget_dialog_tabs, function ( tab ) {
1930
- $( this.dialogTabTemplate( {'title': tab.title} ) ).data( {
1931
- 'message': tab.message,
1932
- 'filter': tab.filter
1933
- } ).appendTo( tabs );
1934
- }, this );
1935
-
1936
- // We'll be using tabs, so initialize them
1937
- this.initTabs();
1938
-
1939
- var thisDialog = this;
1940
- $( window ).resize( function () {
1941
- thisDialog.balanceWidgetHeights();
1942
- } );
1943
- },
1944
-
1945
- /**
1946
- * Handle a tab being clicked
1947
- */
1948
- tabClickHandler: function ( $t ) {
1949
- // Get the filter from the tab, and filter the widgets
1950
- this.filter = $t.parent().data( 'filter' );
1951
- this.filter.search = this.$( '.so-sidebar-search' ).val();
1952
-
1953
- var message = $t.parent().data( 'message' );
1954
- if ( _.isEmpty( message ) ) {
1955
- message = '';
1956
- }
1957
-
1958
- this.$( '.so-toolbar .so-status' ).html( message );
1959
-
1960
- this.filterWidgets( this.filter );
1961
-
1962
- return false;
1963
- },
1964
-
1965
- /**
1966
- * Handle changes to the search value
1967
- */
1968
- searchHandler: function ( e ) {
1969
- if( e.which === 13 ) {
1970
- var visibleWidgets = this.$( '.widget-type-list .widget-type:visible' );
1971
- if( visibleWidgets.length === 1 ) {
1972
- visibleWidgets.click();
1973
- }
1974
- }
1975
- else {
1976
- this.filter.search = $( e.target ).val().trim();
1977
- this.filterWidgets( this.filter );
1978
- }
1979
- },
1980
-
1981
- /**
1982
- * Filter the widgets that we're displaying
1983
- * @param filter
1984
- */
1985
- filterWidgets: function ( filter ) {
1986
- if ( _.isUndefined( filter ) ) {
1987
- filter = {};
1988
- }
1989
-
1990
- if ( _.isUndefined( filter.groups ) ) {
1991
- filter.groups = '';
1992
- }
1993
 
1994
  this.$( '.widget-type-list .widget-type' ).each( function () {
1995
  var $$ = $( this ), showWidget;
@@ -3860,964 +3856,964 @@ module.exports = Backbone.View.extend( {
3860
  } );
3861
 
3862
  },{}],23:[function(require,module,exports){
3863
- var panels = window.panels, $ = jQuery;
3864
-
3865
- module.exports = Backbone.View.extend( {
3866
-
3867
- // Config options
3868
- config: {},
3869
-
3870
- template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder' ).html() ) ),
3871
- dialogs: {},
3872
- rowsSortable: null,
3873
- dataField: false,
3874
- currentData: '',
3875
-
3876
- attachedToEditor: false,
3877
- attachedVisible: false,
3878
- liveEditor: undefined,
3879
- menu: false,
3880
-
3881
- activeCell: null,
3882
-
3883
- events: {
3884
- 'click .so-tool-button.so-widget-add': 'displayAddWidgetDialog',
3885
- 'click .so-tool-button.so-row-add': 'displayAddRowDialog',
3886
- 'click .so-tool-button.so-prebuilt-add': 'displayAddPrebuiltDialog',
3887
- 'click .so-tool-button.so-history': 'displayHistoryDialog',
3888
- 'click .so-tool-button.so-live-editor': 'displayLiveEditor'
3889
- },
3890
-
3891
- /* A row collection */
3892
- rows: null,
3893
-
3894
- /**
3895
- * Initialize the builder
3896
- */
3897
- initialize: function ( options ) {
3898
- var builder = this;
3899
-
3900
- this.config = _.extend( {
3901
- loadLiveEditor: false,
3902
- builderSupports: {}
3903
- }, options.config );
3904
-
3905
- // These are the actions that a user can perform in the builder
3906
- this.config.builderSupports = _.extend( {
3907
- addRow: true,
3908
- editRow: true,
3909
- deleteRow: true,
3910
- moveRow: true,
3911
- addWidget: true,
3912
- editWidget: true,
3913
- deleteWidget: true,
3914
- moveWidget: true,
3915
- prebuilt: true,
3916
- history: true,
3917
- liveEditor: true,
3918
- revertToEditor: true
3919
- }, this.config.builderSupports );
3920
-
3921
- // Automatically load the live editor as soon as it's ready
3922
- if ( options.config.loadLiveEditor ) {
3923
- this.on( 'builder_live_editor_added', function () {
3924
- this.displayLiveEditor();
3925
- } );
3926
- }
3927
-
3928
- // Now lets create all the dialog boxes that the main builder interface uses
3929
- this.dialogs = {
3930
- widgets: new panels.dialog.widgets(),
3931
- row: new panels.dialog.row(),
3932
- prebuilt: new panels.dialog.prebuilt()
3933
- };
3934
-
3935
- // Set the builder for each dialog and render it.
3936
- _.each( this.dialogs, function ( p, i, d ) {
3937
- d[ i ].setBuilder( builder );
3938
- } );
3939
-
3940
- this.dialogs.row.setRowDialogType( 'create' );
3941
-
3942
- // This handles a new row being added to the collection - we'll display it in the interface
3943
- this.model.get( 'rows' ).on( 'add', this.onAddRow, this );
3944
-
3945
- // Reflow the entire builder when ever the
3946
- $( window ).resize( function ( e ) {
3947
- if ( e.target === window ) {
3948
- builder.trigger( 'builder_resize' );
3949
- }
3950
- } );
3951
-
3952
- // When the data changes in the model, store it in the field
3953
- this.model.on( 'change:data load_panels_data', this.storeModelData, this );
3954
-
3955
- // Handle a content change
3956
- this.on( 'content_change', this.handleContentChange, this );
3957
- this.on( 'display_builder', this.handleDisplayBuilder, this );
3958
- this.on( 'hide_builder', this.handleHideBuilder, this );
3959
- this.on( 'builder_rendered builder_resize', this.handleBuilderSizing, this );
3960
- this.model.on( 'change:data load_panels_data', this.toggleWelcomeDisplay, this );
3961
-
3962
- this.on( 'display_builder', this.wrapEditorExpandAdjust, this );
3963
-
3964
- // Create the context menu for this builder
3965
- this.menu = new panels.utils.menu( {} );
3966
- this.menu.on( 'activate_context', this.activateContextMenu, this );
3967
-
3968
- if ( this.config.loadOnAttach ) {
3969
- this.on( 'builder_attached_to_editor', function () {
3970
- this.displayAttachedBuilder( { confirm: false } );
3971
- }, this );
3972
- }
3973
-
3974
-
3975
- return this;
3976
- },
3977
-
3978
- /**
3979
- * Render the builder interface.
3980
- *
3981
- * @return {panels.view.builder}
3982
- */
3983
- render: function () {
3984
- // this.$el.html( this.template() );
3985
- this.setElement( this.template() );
3986
- this.$el
3987
- .attr( 'id', 'siteorigin-panels-builder-' + this.cid )
3988
- .addClass( 'so-builder-container' );
3989
-
3990
- this.trigger( 'builder_rendered' );
3991
-
3992
- return this;
3993
- },
3994
-
3995
- /**
3996
- * Attach the builder to the given container
3997
- *
3998
- * @param container
3999
- * @returns {panels.view.builder}
4000
- */
4001
- attach: function ( options ) {
4002
-
4003
- options = _.extend( {
4004
- container: false,
4005
- dialog: false
4006
- }, options );
4007
-
4008
- if ( options.dialog ) {
4009
- // We're going to add this to a dialog
4010
- this.dialog = new panels.dialog.builder();
4011
- this.dialog.builder = this;
4012
- } else {
4013
- // Attach this in the standard way
4014
- this.$el.appendTo( options.container );
4015
- this.metabox = options.container.closest( '.postbox' );
4016
- this.initSortable();
4017
- this.trigger( 'attached_to_container', options.container );
4018
- }
4019
-
4020
- this.trigger( 'builder_attached' );
4021
-
4022
- // Add support for components we have
4023
-
4024
- if ( this.supports( 'liveEditor' ) ) {
4025
- this.addLiveEditor();
4026
- }
4027
- if ( this.supports( 'history' ) ) {
4028
- this.addHistoryBrowser();
4029
- }
4030
-
4031
- // Hide toolbar buttons we don't support
4032
- var toolbar = this.$( '.so-builder-toolbar' );
4033
- var welcomeMessageContainer = this.$( '.so-panels-welcome-message' );
4034
- var welcomeMessage = panelsOptions.loc.welcomeMessage;
4035
-
4036
- var supportedItems = [];
4037
-
4038
- if ( !this.supports( 'addWidget' ) ) {
4039
- toolbar.find( '.so-widget-add' ).hide();
4040
- } else {
4041
- supportedItems.push( welcomeMessage.addWidgetButton );
4042
- }
4043
- if ( !this.supports( 'addRow' ) ) {
4044
- toolbar.find( '.so-row-add' ).hide();
4045
- } else {
4046
- supportedItems.push( welcomeMessage.addRowButton );
4047
- }
4048
- if ( !this.supports( 'prebuilt' ) ) {
4049
- toolbar.find( '.so-prebuilt-add' ).hide();
4050
- } else {
4051
- supportedItems.push( welcomeMessage.addPrebuiltButton );
4052
- }
4053
-
4054
- var msg = '';
4055
- if ( supportedItems.length === 3 ) {
4056
- msg = welcomeMessage.threeEnabled;
4057
- } else if ( supportedItems.length === 2 ) {
4058
- msg = welcomeMessage.twoEnabled;
4059
- } else if ( supportedItems.length === 1 ) {
4060
- msg = welcomeMessage.oneEnabled;
4061
- } else if ( supportedItems.length === 0 ) {
4062
- msg = welcomeMessage.addingDisabled;
4063
- }
4064
-
4065
- var resTemplate = _.template( panels.helpers.utils.processTemplate( msg ) );
4066
- var msgHTML = resTemplate( { items: supportedItems } ) + ' ' + welcomeMessage.docsMessage;
4067
- welcomeMessageContainer.find( '.so-message-wrapper' ).html( msgHTML );
4068
-
4069
- return this;
4070
- },
4071
-
4072
- /**
4073
- * This will move the Page Builder meta box into the editor if we're in the post/page edit interface.
4074
- *
4075
- * @returns {panels.view.builder}
4076
- */
4077
- attachToEditor: function () {
4078
- if ( this.config.editorType !== 'tinyMCE' ) {
4079
- return this;
4080
- }
4081
-
4082
- this.attachedToEditor = true;
4083
- var metabox = this.metabox;
4084
- var thisView = this;
4085
-
4086
- // Handle switching between the page builder and other tabs
4087
- $( '#wp-content-wrap .wp-editor-tabs' )
4088
- .find( '.wp-switch-editor' )
4089
- .click( function ( e ) {
4090
- e.preventDefault();
4091
- $( '#wp-content-editor-container' ).show();
4092
-
4093
- // metabox.hide();
4094
- $( '#wp-content-wrap' ).removeClass( 'panels-active' );
4095
- $( '#content-resize-handle' ).show();
4096
-
4097
- // Make sure the word count is visible
4098
- thisView.trigger( 'hide_builder' );
4099
- } ).end()
4100
- .append(
4101
- $( '<a id="content-panels" class="hide-if-no-js wp-switch-editor switch-panels">' + metabox.find( '.hndle span' ).html() + '</a>' )
4102
- .click( function ( e ) {
4103
- if ( thisView.displayAttachedBuilder( { confirm: true } ) ) {
4104
- e.preventDefault();
4105
- }
4106
- } )
4107
- );
4108
-
4109
- // Switch back to the standard editor
4110
- if ( this.supports( 'revertToEditor' ) ) {
4111
- metabox.find( '.so-switch-to-standard' ).click( function ( e ) {
4112
- e.preventDefault();
4113
-
4114
- if ( !confirm( panelsOptions.loc.confirm_stop_builder ) ) {
4115
- return;
4116
- }
4117
-
4118
- // User is switching to the standard visual editor
4119
- thisView.addHistoryEntry( 'back_to_editor' );
4120
- thisView.model.loadPanelsData( false );
4121
-
4122
- // Switch back to the standard editor
4123
- $( '#wp-content-wrap' ).show();
4124
- metabox.hide();
4125
-
4126
- // Resize to trigger reflow of WordPress editor stuff
4127
- $( window ).resize();
4128
-
4129
- thisView.attachedVisible = false;
4130
- thisView.trigger( 'hide_builder' );
4131
- } ).show();
4132
- }
4133
-
4134
- // Move the panels box into a tab of the content editor
4135
- metabox.insertAfter( '#wp-content-wrap' ).hide().addClass( 'attached-to-editor' );
4136
-
4137
- // Switch to the Page Builder interface as soon as we load the page if there are widgets or the normal editor
4138
- // isn't supported.
4139
- var data = this.model.get( 'data' );
4140
- if ( !_.isEmpty( data.widgets ) || !_.isEmpty( data.grids ) || !this.supports( 'revertToEditor' ) ) {
4141
- this.displayAttachedBuilder( { confirm: false } );
4142
- }
4143
-
4144
- // We will also make this sticky if its attached to an editor.
4145
- var stickToolbar = function () {
4146
- var toolbar = thisView.$( '.so-builder-toolbar' );
4147
-
4148
- if ( thisView.$el.hasClass( 'so-display-narrow' ) ) {
4149
- // In this case, we don't want to stick the toolbar.
4150
- toolbar.css( {
4151
- top: 0,
4152
- left: 0,
4153
- width: '100%',
4154
- position: 'absolute'
4155
- } );
4156
- thisView.$el.css( 'padding-top', toolbar.outerHeight() );
4157
- return;
4158
- }
4159
-
4160
- var newTop = $( window ).scrollTop() - thisView.$el.offset().top;
4161
-
4162
- if ( $( '#wpadminbar' ).css( 'position' ) === 'fixed' ) {
4163
- newTop += $( '#wpadminbar' ).outerHeight();
4164
- }
4165
-
4166
- var limits = {
4167
- top: 0,
4168
- bottom: thisView.$el.outerHeight() - toolbar.outerHeight() + 20
4169
- };
4170
-
4171
- if ( newTop > limits.top && newTop < limits.bottom ) {
4172
- if ( toolbar.css( 'position' ) !== 'fixed' ) {
4173
- // The toolbar needs to stick to the top, over the interface
4174
- toolbar.css( {
4175
- top: $( '#wpadminbar' ).outerHeight(),
4176
- left: thisView.$el.offset().left,
4177
- width: thisView.$el.outerWidth(),
4178
- position: 'fixed'
4179
- } );
4180
- }
4181
- } else {
4182
- // The toolbar needs to be at the top or bottom of the interface
4183
- toolbar.css( {
4184
- top: Math.min( Math.max( newTop, 0 ), thisView.$el.outerHeight() - toolbar.outerHeight() + 20 ),
4185
- left: 0,
4186
- width: '100%',
4187
- position: 'absolute'
4188
- } );
4189
- }
4190
-
4191
- thisView.$el.css( 'padding-top', toolbar.outerHeight() );
4192
- };
4193
-
4194
- this.on( 'builder_resize', stickToolbar, this );
4195
- $( document ).scroll( stickToolbar );
4196
- stickToolbar();
4197
-
4198
- this.trigger( 'builder_attached_to_editor' );
4199
-
4200
- return this;
4201
- },
4202
-
4203
- /**
4204
- * Display the builder interface when attached to a WordPress editor
4205
- */
4206
- displayAttachedBuilder: function ( options ) {
4207
- options = _.extend( {
4208
- confirm: true
4209
- }, options );
4210
-
4211
- // Switch to the Page Builder interface
4212
-
4213
- if ( options.confirm ) {
4214
- var editor = typeof tinyMCE !== 'undefined' ? tinyMCE.get( 'content' ) : false;
4215
- var editorContent = ( editor && _.isFunction( editor.getContent ) ) ? editor.getContent() : $( 'textarea#content' ).val();
4216
-
4217
- if ( editorContent !== '' && !confirm( panelsOptions.loc.confirm_use_builder ) ) {
4218
- return false;
4219
- }
4220
- }
4221
-
4222
- // Hide the standard content editor
4223
- $( '#wp-content-wrap' ).hide();
4224
-
4225
-
4226
- $( '#editor-expand-toggle' ).on( 'change.editor-expand', function () {
4227
- if ( !$( this ).prop( 'checked' ) ) {
4228
- $( '#wp-content-wrap' ).hide();
4229
- }
4230
- } );
4231
-
4232
- // Show page builder and the inside div
4233
- this.metabox.show().find( '> .inside' ).show();
4234
-
4235
- // Triggers full refresh
4236
- $( window ).resize();
4237
- $( document ).scroll();
4238
-
4239
- // Make sure the word count is visible
4240
- this.attachedVisible = true;
4241
- this.trigger( 'display_builder' );
4242
-
4243
- return true;
4244
- },
4245
-
4246
- /**
4247
- * Initialize the row sortables
4248
- */
4249
- initSortable: function () {
4250
- if ( !this.supports( 'moveRow' ) ) {
4251
- return this;
4252
- }
4253
-
4254
- // Create the sortable for the rows
4255
- var builderView = this;
4256
-
4257
- this.rowsSortable = this.$( '.so-rows-container' ).sortable( {
4258
- appendTo: '#wpwrap',
4259
- items: '.so-row-container',
4260
- handle: '.so-row-move',
4261
- axis: 'y',
4262
- tolerance: 'pointer',
4263
- scroll: false,
4264
- stop: function ( e, ui ) {
4265
- builderView.addHistoryEntry( 'row_moved' );
4266
-
4267
- var $$ = $( ui.item ),
4268
- row = $$.data( 'view' );
4269
-
4270
- builderView.model.get( 'rows' ).remove( row.model, {
4271
- 'silent': true
4272
- } );
4273
- builderView.model.get( 'rows' ).add( row.model, {
4274
- 'silent': true,
4275
- 'at': $$.index()
4276
- } );
4277
-
4278
- row.trigger( 'move', $$.index() );
4279
-
4280
- builderView.model.refreshPanelsData();
4281
- }
4282
- } );
4283
-
4284
- return this;
4285
- },
4286
-
4287
- /**
4288
- * Refresh the row sortable
4289
- */
4290
- refreshSortable: function () {
4291
- // Refresh the sortable to account for the new row
4292
- if ( !_.isNull( this.rowsSortable ) ) {
4293
- this.rowsSortable.sortable( 'refresh' );
4294
- }
4295
- },
4296
-
4297
- /**
4298
- * Set the field that's used to store the data
4299
- * @param field
4300
- */
4301
- setDataField: function ( field, options ) {
4302
- options = _.extend( {
4303
- load: true
4304
- }, options );
4305
-
4306
- this.dataField = field;
4307
- this.dataField.data( 'builder', this );
4308
-
4309
- if ( options.load && field.val() !== '' ) {
4310
- var data = this.dataField.val();
4311
- try {
4312
- data = JSON.parse( data );
4313
- }
4314
- catch ( err ) {
4315
- data = {};
4316
- }
4317
-
4318
- this.model.loadPanelsData( data );
4319
- this.currentData = data;
4320
- this.toggleWelcomeDisplay();
4321
- }
4322
-
4323
- return this;
4324
- },
4325
-
4326
- /**
4327
- * Store the model data in the data html field set in this.setDataField.
4328
- */
4329
- storeModelData: function () {
4330
- var data = JSON.stringify( this.model.get( 'data' ) );
4331
-
4332
- if ( $( this.dataField ).val() !== data ) {
4333
- // If the data is different, set it and trigger a content_change event
4334
- $( this.dataField ).val( data );
4335
- $( this.dataField ).trigger( 'change' );
4336
- this.trigger( 'content_change' );
4337
- }
4338
- },
4339
-
4340
- /**
4341
- * HAndle the visual side of adding a new row to the builder.
4342
- *
4343
- * @param row
4344
- * @param collection
4345
- * @param options
4346
- */
4347
- onAddRow: function ( row, collection, options ) {
4348
- options = _.extend( { noAnimate: false }, options );
4349
- // Create a view for the row
4350
- var rowView = new panels.view.row( { model: row } );
4351
- rowView.builder = this;
4352
- rowView.render();
4353
-
4354
- // Attach the row elements to this builder
4355
- if ( _.isUndefined( options.at ) || collection.length <= 1 ) {
4356
- // Insert this at the end of the widgets container
4357
- rowView.$el.appendTo( this.$( '.so-rows-container' ) );
4358
- } else {
4359
- // We need to insert this at a specific position
4360
- rowView.$el.insertAfter(
4361
- this.$( '.so-rows-container .so-row-container' ).eq( options.at - 1 )
4362
- );
4363
- }
4364
-
4365
- if ( options.noAnimate === false ) {
4366
- rowView.visualCreate();
4367
- }
4368
-
4369
- this.refreshSortable();
4370
- rowView.resize();
4371
- },
4372
-
4373
- /**
4374
- * Display the dialog to add a new widget.
4375
- *
4376
- * @returns {boolean}
4377
- */
4378
- displayAddWidgetDialog: function () {
4379
- this.dialogs.widgets.openDialog();
4380
- },
4381
-
4382
- /**
4383
- * Display the dialog to add a new row.
4384
- */
4385
- displayAddRowDialog: function () {
4386
- var row = new panels.model.row();
4387
- var cells = new panels.collection.cells( [ { weight: 0.5 }, { weight: 0.5 } ] );
4388
- cells.each( function ( cell ) {
4389
- cell.row = row;
4390
- } );
4391
- row.set( 'cells', cells );
4392
- row.builder = this.model;
4393
-
4394
- this.dialogs.row.setRowModel( row );
4395
- this.dialogs.row.openDialog();
4396
- },
4397
-
4398
- /**
4399
- * Display the dialog to add prebuilt layouts.
4400
- *
4401
- * @returns {boolean}
4402
- */
4403
- displayAddPrebuiltDialog: function () {
4404
- this.dialogs.prebuilt.openDialog();
4405
- },
4406
-
4407
- /**
4408
- * Display the history dialog.
4409
- *
4410
- * @returns {boolean}
4411
- */
4412
- displayHistoryDialog: function () {
4413
- this.dialogs.history.openDialog();
4414
- },
4415
-
4416
- /**
4417
- * Handle pasting a row into the builder.
4418
- */
4419
- pasteRowHandler: function () {
4420
- var pastedModel = panels.helpers.clipboard.getModel( 'row-model' );
4421
-
4422
- if ( !_.isEmpty( pastedModel ) && pastedModel instanceof panels.model.row ) {
4423
- this.addHistoryEntry( 'row_pasted' );
4424
- pastedModel.builder = this.model;
4425
- this.model.get( 'rows' ).add( pastedModel, {
4426
- at: this.model.get( 'rows' ).indexOf( this.model ) + 1
4427
- } );
4428
- this.model.refreshPanelsData();
4429
- }
4430
- },
4431
-
4432
- /**
4433
- * Get the model for the currently selected cell
4434
- */
4435
- getActiveCell: function ( options ) {
4436
- options = _.extend( {
4437
- createCell: true,
4438
- }, options );
4439
-
4440
- if ( !this.model.get( 'rows' ).length ) {
4441
- // There aren't any rows yet
4442
- if ( options.createCell ) {
4443
- // Create a row with a single cell
4444
- this.model.addRow( {}, [ { weight: 1 } ], { noAnimate: true } );
4445
- } else {
4446
- return null;
4447
- }
4448
- }
4449
-
4450
- // Make sure the active cell isn't empty, and it's in a row that exists
4451
- var activeCell = this.activeCell;
4452
- if ( _.isEmpty( activeCell ) || this.model.get( 'rows' ).indexOf( activeCell.model.row ) === -1 ) {
4453
- return this.model.get( 'rows' ).last().get( 'cells' ).first();
4454
- } else {
4455
- return activeCell.model;
4456
- }
4457
- },
4458
-
4459
- /**
4460
- * Add a live editor to the builder
4461
- *
4462
- * @returns {panels.view.builder}
4463
- */
4464
- addLiveEditor: function () {
4465
- if ( _.isEmpty( this.config.liveEditorPreview ) ) {
4466
- return this;
4467
- }
4468
-
4469
- // Create the live editor and set the builder to this.
4470
- this.liveEditor = new panels.view.liveEditor( {
4471
- builder: this,
4472
- previewUrl: this.config.liveEditorPreview
4473
- } );
4474
-
4475
- // Display the live editor button in the toolbar
4476
- if ( this.liveEditor.hasPreviewUrl() ) {
4477
- this.$( '.so-builder-toolbar .so-live-editor' ).show();
4478
- }
4479
-
4480
- this.trigger( 'builder_live_editor_added' );
4481
-
4482
- return this;
4483
- },
4484
-
4485
- /**
4486
- * Show the current live editor
4487
- */
4488
- displayLiveEditor: function () {
4489
- if ( _.isUndefined( this.liveEditor ) ) {
4490
- return;
4491
- }
4492
-
4493
- this.liveEditor.open();
4494
- },
4495
-
4496
- /**
4497
- * Add the history browser.
4498
- *
4499
- * @return {panels.view.builder}
4500
- */
4501
- addHistoryBrowser: function () {
4502
- if ( _.isEmpty( this.config.liveEditorPreview ) ) {
4503
- return this;
4504
- }
4505
-
4506
- this.dialogs.history = new panels.dialog.history();
4507
- this.dialogs.history.builder = this;
4508
- this.dialogs.history.entries.builder = this.model;
4509
-
4510
- // Set the revert entry
4511
- this.dialogs.history.setRevertEntry( this.model );
4512
-
4513
- // Display the live editor button in the toolbar
4514
- this.$( '.so-builder-toolbar .so-history' ).show();
4515
- },
4516
-
4517
- /**
4518
- * Add an entry.
4519
- *
4520
- * @param text
4521
- * @param data
4522
- */
4523
- addHistoryEntry: function ( text, data ) {
4524
- if ( _.isUndefined( data ) ) {
4525
- data = null;
4526
- }
4527
-
4528
- if ( !_.isUndefined( this.dialogs.history ) ) {
4529
- this.dialogs.history.entries.addEntry( text, data );
4530
- }
4531
- },
4532
-
4533
- supports: function ( thing ) {
4534
-
4535
- if ( thing === 'rowAction' ) {
4536
- // Check if this supports any row action
4537
- return this.supports( 'addRow' ) || this.supports( 'editRow' ) || this.supports( 'deleteRow' );
4538
- } else if ( thing === 'widgetAction' ) {
4539
- // Check if this supports any widget action
4540
- return this.supports( 'addWidget' ) || this.supports( 'editWidget' ) || this.supports( 'deleteWidget' );
4541
- }
4542
-
4543
- return _.isUndefined( this.config.builderSupports[ thing ] ) ? false : this.config.builderSupports[ thing ];
4544
- },
4545
-
4546
- /**
4547
- * Handle a change of the content
4548
- */
4549
- handleContentChange: function () {
4550
-
4551
- // Make sure we actually need to copy content.
4552
- if ( panelsOptions.copy_content && this.attachedToEditor && this.$el.is( ':visible' ) ) {
4553
-
4554
- var panelsData = this.model.getPanelsData();
4555
- if ( !_.isEmpty( panelsData.widgets ) ) {
4556
- // We're going to create a copy of page builder content into the post content
4557
- $.post(
4558
- panelsOptions.ajaxurl,
4559
- {
4560
- action: 'so_panels_builder_content',
4561
- panels_data: JSON.stringify( panelsData ),
4562
- post_id: this.config.postId
4563
- },
4564
- function ( content ) {
4565
- if ( content !== '' ) {
4566
- this.updateEditorContent( content );
4567
- }
4568
- }.bind( this )
4569
- );
4570
- }
4571
- }
4572
- },
4573
-
4574
- /**
4575
- * Update editor content with the given content.
4576
- *
4577
- * @param content
4578
- */
4579
- updateEditorContent: function ( content ) {
4580
- // Switch back to the standard editor
4581
- if ( this.config.editorType !== 'tinyMCE' || typeof tinyMCE === 'undefined' || _.isNull( tinyMCE.get( "content" ) ) ) {
4582
- var $editor = $( this.config.editorId );
4583
- $editor.val( content ).trigger( 'change' ).trigger( 'keyup' );
4584
- } else {
4585
- var contentEd = tinyMCE.get( "content" );
4586
-
4587
- contentEd.setContent( content );
4588
-
4589
- contentEd.fire( 'change' );
4590
- contentEd.fire( 'keyup' );
4591
- }
4592
-
4593
- this.triggerYoastSeoChange();
4594
- },
4595
-
4596
- /**
4597
- * Trigger a change on Yoast SEO
4598
- */
4599
- triggerYoastSeoChange: function () {
4600
- if ( $( '#yoast_wpseo_focuskw_text_input' ).length ) {
4601
- var element = document.getElementById( 'yoast_wpseo_focuskw_text_input' ), event;
4602
-
4603
- if ( document.createEvent ) {
4604
- event = document.createEvent( "HTMLEvents" );
4605
- event.initEvent( "keyup", true, true );
4606
- } else {
4607
- event = document.createEventObject();
4608
- event.eventType = "keyup";
4609
- }
4610
-
4611
- event.eventName = "keyup";
4612
-
4613
- if ( document.createEvent ) {
4614
- element.dispatchEvent( event );
4615
- } else {
4616
- element.fireEvent( "on" + event.eventType, event );
4617
- }
4618
- }
4619
- },
4620
-
4621
- /**
4622
- * Handle displaying the builder
4623
- */
4624
- handleDisplayBuilder: function () {
4625
- var editor = typeof tinyMCE !== 'undefined' ? tinyMCE.get( 'content' ) : false;
4626
- var editorContent = ( editor && _.isFunction( editor.getContent ) ) ? editor.getContent() : $( 'textarea#content' ).val();
4627
-
4628
- if (
4629
- (
4630
- _.isEmpty( this.model.get( 'data' ) ) ||
4631
- ( _.isEmpty( this.model.get( 'data' ).widgets ) && _.isEmpty( this.model.get( 'data' ).grids ) )
4632
- ) &&
4633
- editorContent !== ''
4634
- ) {
4635
- var editorClass = panelsOptions.text_widget;
4636
- // There is a small chance a theme will have removed this, so check
4637
- if ( _.isEmpty( editorClass ) ) {
4638
- return;
4639
- }
4640
-
4641
- // Create the existing page content in a single widget
4642
- this.model.loadPanelsData( this.model.getPanelsDataFromHtml( editorContent, editorClass ) );
4643
- this.model.trigger( 'change' );
4644
- this.model.trigger( 'change:data' );
4645
- }
4646
-
4647
- $( '#post-status-info' ).addClass( 'for-siteorigin-panels' );
4648
- },
4649
-
4650
- handleHideBuilder: function () {
4651
- $( '#post-status-info' ).show().removeClass( 'for-siteorigin-panels' );
4652
- },
4653
-
4654
- wrapEditorExpandAdjust: function () {
4655
- try {
4656
- var events = ( $.hasData( window ) && $._data( window ) ).events.scroll,
4657
- event;
4658
-
4659
- for ( var i = 0; i < events.length; i++ ) {
4660
- if ( events[ i ].namespace === 'editor-expand' ) {
4661
- event = events[ i ];
4662
-
4663
- // Wrap the call
4664
- $( window ).unbind( 'scroll', event.handler );
4665
- $( window ).bind( 'scroll', function ( e ) {
4666
- if ( !this.attachedVisible ) {
4667
- event.handler( e );
4668
- }
4669
- }.bind( this ) );
4670
-
4671
- break;
4672
- }
4673
- }
4674
- }
4675
- catch ( e ) {
4676
- // We tried, we failed
4677
- return;
4678
- }
4679
- },
4680
-
4681
- /**
4682
- * Either add or remove the narrow class
4683
- * @returns {exports}
4684
- */
4685
- handleBuilderSizing: function () {
4686
- var width = this.$el.width();
4687
-
4688
- if ( !width ) {
4689
- return this;
4690
- }
4691
-
4692
- if ( width < 480 ) {
4693
- this.$el.addClass( 'so-display-narrow' );
4694
- } else {
4695
- this.$el.removeClass( 'so-display-narrow' );
4696
- }
4697
-
4698
- return this;
4699
- },
4700
-
4701
- /**
4702
- * Set the parent dialog for all the dialogs in this builder.
4703
- *
4704
- * @param text
4705
- * @param dialog
4706
- */
4707
- setDialogParents: function ( text, dialog ) {
4708
- _.each( this.dialogs, function ( p, i, d ) {
4709
- d[ i ].setParent( text, dialog );
4710
- } );
4711
-
4712
- // For any future dialogs
4713
- this.on( 'add_dialog', function ( newDialog ) {
4714
- newDialog.setParent( text, dialog );
4715
- }, this );
4716
- },
4717
-
4718
- /**
4719
- * This shows or hides the welcome display depending on whether there are any rows in the collection.
4720
- */
4721
- toggleWelcomeDisplay: function () {
4722
- if ( !this.model.get( 'rows' ).isEmpty() ) {
4723
- this.$( '.so-panels-welcome-message' ).hide();
4724
- } else {
4725
- this.$( '.so-panels-welcome-message' ).show();
4726
- }
4727
- },
4728
-
4729
- /**
4730
- * Activate the contextual menu
4731
- * @param e
4732
- * @param menu
4733
- */
4734
- activateContextMenu: function ( e, menu ) {
4735
- var builder = this;
4736
-
4737
- // Of all the visible builders, find the topmost
4738
- var topmostBuilder = $( '.siteorigin-panels-builder:visible' )
4739
- .sort( function ( a, b ) {
4740
- return $( a ).zIndex() > $( b ).zIndex() ? 1 : -1;
4741
- } )
4742
- .last();
4743
-
4744
- var topmostDialog = $( '.so-panels-dialog-wrapper:visible' )
4745
- .sort( function ( a, b ) {
4746
- return $( a ).zIndex() > $( b ).zIndex() ? 1 : -1;
4747
- } )
4748
- .last();
4749
-
4750
- var closestDialog = builder.$el.closest( '.so-panels-dialog-wrapper' );
4751
-
4752
- // Only run this if its element is the topmost builder, in the topmost dialog
4753
- if (
4754
- builder.$el.is( topmostBuilder ) &&
4755
- (
4756
- topmostDialog.length === 0 ||
4757
- topmostDialog.is( closestDialog )
4758
- )
4759
- ) {
4760
- // Get the element we're currently hovering over
4761
- var over = $( [] )
4762
- .add( builder.$( '.so-panels-welcome-message:visible' ) )
4763
- .add( builder.$( '.so-rows-container > .so-row-container' ) )
4764
- .add( builder.$( '.so-cells > .cell' ) )
4765
- .add( builder.$( '.cell-wrapper > .so-widget' ) )
4766
- .filter( function ( i ) {
4767
- return menu.isOverEl( $( this ), e );
4768
- } );
4769
-
4770
- var activeView = over.last().data( 'view' );
4771
- if ( activeView !== undefined && activeView.buildContextualMenu !== undefined ) {
4772
- // We'll pass this to the current active view so it can popular the contextual menu
4773
- activeView.buildContextualMenu( e, menu );
4774
- }
4775
- else if ( over.last().hasClass( 'so-panels-welcome-message' ) ) {
4776
- // The user opened the contextual menu on the welcome message
4777
- this.buildContextualMenu( e, menu );
4778
- }
4779
- }
4780
- },
4781
-
4782
- /**
4783
- * Build the contextual menu for the main builder - before any content has been added.
4784
- */
4785
- buildContextualMenu: function ( e, menu ) {
4786
- var actions = {};
4787
-
4788
- if ( this.supports( 'addRow' ) ) {
4789
- actions.add_row = { title: panelsOptions.loc.contextual.add_row };
4790
- }
4791
-
4792
- if ( panels.helpers.clipboard.canCopyPaste() ) {
4793
- if ( panels.helpers.clipboard.isModel( 'row-model' ) && this.supports( 'addRow' ) ) {
4794
- actions.paste_row = { title: panelsOptions.loc.contextual.row_paste };
4795
- }
4796
- }
4797
-
4798
- if ( !_.isEmpty( actions ) ) {
4799
- menu.addSection(
4800
- 'builder-actions',
4801
- {
4802
- sectionTitle: panelsOptions.loc.contextual.row_actions,
4803
- search: false,
4804
- },
4805
- actions,
4806
- function ( c ) {
4807
- switch ( c ) {
4808
- case 'add_row':
4809
- this.displayAddRowDialog();
4810
- break;
4811
-
4812
- case 'paste_row':
4813
- this.pasteRowHandler();
4814
- break;
4815
- }
4816
- }.bind( this )
4817
- );
4818
- }
4819
- },
4820
- } );
4821
 
4822
  },{}],24:[function(require,module,exports){
4823
  var panels = window.panels, $ = jQuery;
@@ -6551,284 +6547,301 @@ module.exports = Backbone.View.extend( {
6551
  } );
6552
 
6553
  },{}],28:[function(require,module,exports){
6554
- var panels = window.panels, $ = jQuery;
6555
-
6556
- module.exports = Backbone.View.extend( {
6557
-
6558
- stylesLoaded: false,
6559
-
6560
- initialize: function () {
6561
-
6562
- },
6563
-
6564
- /**
6565
- * Render the visual styles object.
6566
- *
6567
- * @param type
6568
- * @param postId
6569
- */
6570
- render: function ( stylesType, postId, args ) {
6571
- if ( _.isUndefined( stylesType ) ) {
6572
- return;
6573
- }
6574
-
6575
- // Add in the default args
6576
- args = _.extend( {
6577
- builderType: '',
6578
- dialog: null
6579
- }, args );
6580
-
6581
- this.$el.addClass( 'so-visual-styles so-' + stylesType + '-styles' );
6582
-
6583
- var postArgs = {
6584
- builderType: args.builderType
6585
- };
6586
-
6587
- if ( stylesType === 'cell') {
6588
- postArgs.index = args.index;
6589
- }
6590
-
6591
- // Load the form
6592
- $.post(
6593
- panelsOptions.ajaxurl,
6594
- {
6595
- action: 'so_panels_style_form',
6596
- type: stylesType,
6597
- style: this.model.get( 'style' ),
6598
- args: JSON.stringify( postArgs ),
6599
- postId: postId
6600
- },
6601
- function ( response ) {
6602
- this.$el.html( response );
6603
- this.setupFields();
6604
- this.stylesLoaded = true;
6605
- this.trigger( 'styles_loaded', ! _.isEmpty( response ) );
6606
- if ( ! _.isNull( args.dialog ) ) {
6607
- args.dialog.trigger( 'styles_loaded', ! _.isEmpty( response ) );
6608
- }
6609
- }.bind(this)
6610
- );
6611
-
6612
- return this;
6613
- },
6614
-
6615
- /**
6616
- * Attach the style view to the DOM.
6617
- *
6618
- * @param wrapper
6619
- */
6620
- attach: function ( wrapper ) {
6621
- wrapper.append( this.$el );
6622
- },
6623
-
6624
- /**
6625
- * Detach the styles view from the DOM
6626
- */
6627
- detach: function () {
6628
- this.$el.detach();
6629
- },
6630
-
6631
- /**
6632
- * Setup all the fields
6633
- */
6634
- setupFields: function () {
6635
-
6636
- // Set up the sections as collapsible
6637
- this.$( '.style-section-wrapper' ).each( function () {
6638
- var $s = $( this );
6639
-
6640
- $s.find( '.style-section-head' ).click( function ( e ) {
6641
- e.preventDefault();
6642
- $s.find( '.style-section-fields' ).slideToggle( 'fast' );
6643
- } );
6644
- } );
6645
-
6646
- // Set up the color fields
6647
- if ( ! _.isUndefined( $.fn.wpColorPicker ) ) {
6648
- if ( _.isObject( panelsOptions.wpColorPickerOptions.palettes ) && ! $.isArray( panelsOptions.wpColorPickerOptions.palettes ) ) {
6649
- panelsOptions.wpColorPickerOptions.palettes = $.map( panelsOptions.wpColorPickerOptions.palettes, function ( el ) {
6650
- return el;
6651
- } );
6652
- }
6653
- this.$( '.so-wp-color-field' ).wpColorPicker( panelsOptions.wpColorPickerOptions );
6654
- }
6655
-
6656
- // Set up the image select fields
6657
- this.$( '.style-field-image' ).each( function () {
6658
- var frame = null;
6659
- var $s = $( this );
6660
-
6661
- $s.find( '.so-image-selector' ).click( function ( e ) {
6662
- e.preventDefault();
6663
-
6664
- if ( frame === null ) {
6665
- // Create the media frame.
6666
- frame = wp.media( {
6667
- // Set the title of the modal.
6668
- title: 'choose',
6669
-
6670
- // Tell the modal to show only images.
6671
- library: {
6672
- type: 'image'
6673
- },
6674
-
6675
- // Customize the submit button.
6676
- button: {
6677
- // Set the text of the button.
6678
- text: 'Done',
6679
- close: true
6680
- }
6681
- } );
6682
-
6683
- frame.on( 'select', function () {
6684
- var attachment = frame.state().get( 'selection' ).first().attributes;
6685
-
6686
- var url = attachment.url;
6687
- if ( ! _.isUndefined( attachment.sizes ) ) {
6688
- try {
6689
- url = attachment.sizes.thumbnail.url;
6690
- }
6691
- catch ( e ) {
6692
- // We'll use the full image instead
6693
- url = attachment.sizes.full.url;
6694
- }
6695
- }
6696
- $s.find( '.current-image' ).css( 'background-image', 'url(' + url + ')' );
6697
-
6698
- // Store the ID
6699
- $s.find( 'input' ).val( attachment.id )
6700
- } );
6701
- }
6702
-
6703
- frame.open();
6704
-
6705
- } );
6706
-
6707
- // Handle clicking on remove
6708
- $s.find( '.remove-image' ).click( function ( e ) {
6709
- e.preventDefault();
6710
- $s.find( '.current-image' ).css( 'background-image', 'none' );
6711
- $s.find( 'input' ).val( '' );
6712
- } );
6713
- } );
6714
-
6715
- // Set up all the measurement fields
6716
- this.$( '.style-field-measurement' ).each( function () {
6717
- var $$ = $( this );
6718
-
6719
- var text = $$.find( 'input[type="text"]' );
6720
- var unit = $$.find( 'select' );
6721
- var hidden = $$.find( 'input[type="hidden"]' );
6722
-
6723
- text.focus( function(){
6724
- $(this).select();
6725
- } );
6726
-
6727
- /**
6728
- * Load value into the visible input fields.
6729
- * @param value
6730
- */
6731
- var loadValue = function( value ) {
6732
- if( value === '' ) {
6733
- return;
6734
- }
6735
-
6736
- var re = /(?:([0-9\.,\-]+)(.*))+/;
6737
- var valueList = hidden.val().split( ' ' );
6738
- var valueListValue = [];
6739
- for ( var i in valueList ) {
6740
- var match = re.exec( valueList[i] );
6741
- if ( ! _.isNull( match ) && ! _.isUndefined( match[1] ) && ! _.isUndefined( match[2] ) ) {
6742
- valueListValue.push( match[1] );
6743
- unit.val( match[2] );
6744
- }
6745
- }
6746
-
6747
- if( text.length === 1 ) {
6748
- // This is a single input text field
6749
- text.val( valueListValue.join( ' ' ) );
6750
- }
6751
- else {
6752
- // We're dealing with a multiple field
6753
- if( valueListValue.length === 1 ) {
6754
- valueListValue = [ valueListValue[0], valueListValue[0], valueListValue[0], valueListValue[0] ];
6755
- }
6756
- else if( valueListValue.length === 2 ) {
6757
- valueListValue = [ valueListValue[0], valueListValue[1], valueListValue[0], valueListValue[1] ];
6758
- }
6759
- else if( valueListValue.length === 3 ) {
6760
- valueListValue = [ valueListValue[0], valueListValue[1], valueListValue[2], valueListValue[1] ];
6761
- }
6762
-
6763
- // Store this in the visible fields
6764
- text.each( function( i, el ) {
6765
- $( el ).val( valueListValue[i] );
6766
- } );
6767
- }
6768
- };
6769
- loadValue( hidden.val() );
6770
-
6771
- /**
6772
- * Set value of the hidden field based on inputs
6773
- */
6774
- var setValue = function( e ){
6775
- var i;
6776
-
6777
- if( text.length === 1 ) {
6778
- // We're dealing with a single measurement
6779
- var fullString = text
6780
- .val()
6781
- .split( ' ' )
6782
- .filter( function ( value ) {
6783
- return value !== '';
6784
- } )
6785
- .map( function ( value ) {
6786
- return value + unit.val();
6787
- } )
6788
- .join( ' ' );
6789
- hidden.val( fullString );
6790
- }
6791
- else {
6792
- var target = $( e.target ),
6793
- valueList = [],
6794
- emptyIndex = [],
6795
- fullIndex = [];
6796
-
6797
- text.each( function( i, el ) {
6798
- var value = $( el ).val( ) !== '' ? parseFloat( $( el ).val( ) ) : null;
6799
- valueList.push( value );
6800
-
6801
- if( value === null ) {
6802
- emptyIndex.push( i );
6803
- }
6804
- else {
6805
- fullIndex.push( i );
6806
- }
6807
- } );
6808
-
6809
- if( emptyIndex.length === 3 && fullIndex[0] === text.index( target ) ) {
6810
- text.val( target.val() );
6811
- valueList = [ target.val(), target.val(), target.val(), target.val() ];
6812
- }
6813
-
6814
- if( JSON.stringify( valueList ) === JSON.stringify( [ null, null, null, null ] ) ) {
6815
- hidden.val('');
6816
- }
6817
- else {
6818
- hidden.val( valueList.map( function( k ){
6819
- return ( k === null ? 0 : k ) + unit.val();
6820
- } ).join( ' ' ) );
6821
- }
6822
- }
6823
- };
6824
-
6825
- // Set the value when ever anything changes
6826
- text.change( setValue );
6827
- unit.change( setValue );
6828
- } );
6829
- }
6830
-
6831
- } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6832
 
6833
  },{}],29:[function(require,module,exports){
6834
  var panels = window.panels, $ = jQuery;
910
  }
911
 
912
  var $rightSidebar = this.$('.so-sidebar.so-right-sidebar');
913
+ this.styles.attach( $rightSidebar );
914
 
915
  // Handle the loading class
916
  this.styles.on('styles_loaded', function (hasStyles) {
917
+ // If we don't have styles remove the empty sidebar.
918
+ if ( ! hasStyles ) {
 
 
919
  $rightSidebar.closest('.so-panels-dialog').removeClass('so-panels-dialog-has-right-sidebar');
920
  $rightSidebar.remove();
921
  }
922
  }, this);
 
923
 
924
  if (!_.isUndefined(this.model)) {
925
  // Set the initial value of the
1281
  if ( this.cellStyles ) {
1282
  var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
1283
  this.cellStyles.attach( $rightSidebar );
 
 
 
 
 
 
 
1284
  }
1285
  },
1286
 
1567
  });
1568
 
1569
  },{}],9:[function(require,module,exports){
1570
+ var panels = window.panels, $ = jQuery;
1571
+ var jsWidget = require( '../view/widgets/js-widget' );
1572
+
1573
+ module.exports = panels.view.dialog.extend( {
1574
+
1575
+ builder: null,
1576
+ sidebarWidgetTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-widget-sidebar-widget' ).html() ) ),
1577
+
1578
+ dialogClass: 'so-panels-dialog-edit-widget',
1579
+ dialogIcon: 'add-widget',
1580
+
1581
+ widgetView: false,
1582
+ savingWidget: false,
1583
+ editableLabel: true,
1584
+
1585
+ events: {
1586
+ 'click .so-close': 'saveHandler',
1587
+ 'click .so-nav.so-previous': 'navToPrevious',
1588
+ 'click .so-nav.so-next': 'navToNext',
1589
+
1590
+ // Action handlers
1591
+ 'click .so-toolbar .so-delete': 'deleteHandler',
1592
+ 'click .so-toolbar .so-duplicate': 'duplicateHandler'
1593
+ },
1594
+
1595
+ initializeDialog: function () {
1596
+ var thisView = this;
1597
+ this.model.on( 'change:values', this.handleChangeValues, this );
1598
+ this.model.on( 'destroy', this.remove, this );
1599
+
1600
+ // Refresh panels data after both dialog form components are loaded
1601
+ this.dialogFormsLoaded = 0;
1602
+ this.on( 'form_loaded styles_loaded', function () {
1603
+ this.dialogFormsLoaded ++;
1604
+ if ( this.dialogFormsLoaded === 2 ) {
1605
+ thisView.updateModel( {
1606
+ refreshArgs: {
1607
+ silent: true
1608
+ }
1609
+ } );
1610
+ }
1611
+ } );
1612
+
1613
+ this.on( 'edit_label', function ( text ) {
1614
+ // If text is set to default value, just clear it.
1615
+ if ( text === panelsOptions.widgets[ this.model.get( 'class' ) ][ 'title' ] ) {
1616
+ text = '';
1617
+ }
1618
+ this.model.set( 'label', text );
1619
+ if ( _.isEmpty( text ) ) {
1620
+ this.$( '.so-title' ).text( this.model.getWidgetField( 'title' ) );
1621
+ }
1622
+ }.bind( this ) );
1623
+ },
1624
+
1625
+ /**
1626
+ * Render the widget dialog.
1627
+ */
1628
+ render: function () {
1629
+ // Render the dialog and attach it to the builder interface
1630
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widget' ).html(), {} ) );
1631
+ this.loadForm();
1632
+
1633
+ var title = this.model.getWidgetField( 'title' );
1634
+ this.$( '.so-title .widget-name' ).html( title );
1635
+ this.$( '.so-edit-title' ).val( title );
1636
+
1637
+ if( ! this.builder.supports( 'addWidget' ) ) {
1638
+ this.$( '.so-buttons .so-duplicate' ).remove();
1639
+ }
1640
+ if( ! this.builder.supports( 'deleteWidget' ) ) {
1641
+ this.$( '.so-buttons .so-delete' ).remove();
1642
+ }
1643
+
1644
+ // Now we need to attach the style window
1645
+ this.styles = new panels.view.styles();
1646
+ this.styles.model = this.model;
1647
+ this.styles.render( 'widget', this.builder.config.postId, {
1648
+ builderType: this.builder.config.builderType,
1649
+ dialog: this
1650
+ } );
1651
+
1652
+ var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
1653
+ this.styles.attach( $rightSidebar );
1654
+
1655
+ // Handle the loading class
1656
+ this.styles.on( 'styles_loaded', function ( hasStyles ) {
1657
+ // If we don't have styles remove the empty sidebar.
1658
+ if ( ! hasStyles ) {
1659
+ $rightSidebar.closest( '.so-panels-dialog' ).removeClass( 'so-panels-dialog-has-right-sidebar' );
1660
+ $rightSidebar.remove();
1661
+ }
1662
+ }, this );
1663
+ },
1664
+
1665
+ /**
1666
+ * Get the previous widget editing dialog by looking at the dom.
1667
+ * @returns {*}
1668
+ */
1669
+ getPrevDialog: function () {
1670
+ var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1671
+ if ( widgets.length <= 1 ) {
1672
+ return false;
1673
+ }
1674
+ var currentIndex = widgets.index( this.widgetView.$el );
1675
+
1676
+ if ( currentIndex === 0 ) {
1677
+ return false;
1678
+ } else {
1679
+ do {
1680
+ widgetView = widgets.eq( --currentIndex ).data( 'view' );
1681
+ if ( ! _.isUndefined( widgetView ) && ! widgetView.model.get( 'read_only' ) ) {
1682
+ return widgetView.getEditDialog();
1683
+ }
1684
+ } while( ! _.isUndefined( widgetView ) && currentIndex > 0 );
1685
+ }
1686
+
1687
+ return false;
1688
+ },
1689
+
1690
+ /**
1691
+ * Get the next widget editing dialog by looking at the dom.
1692
+ * @returns {*}
1693
+ */
1694
+ getNextDialog: function () {
1695
+ var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1696
+ if ( widgets.length <= 1 ) {
1697
+ return false;
1698
+ }
1699
+
1700
+ var currentIndex = widgets.index( this.widgetView.$el ), widgetView;
1701
+
1702
+ if ( currentIndex === widgets.length - 1 ) {
1703
+ return false;
1704
+ } else {
1705
+ do {
1706
+ widgetView = widgets.eq( ++currentIndex ).data( 'view' );
1707
+ if ( ! _.isUndefined( widgetView ) && ! widgetView.model.get( 'read_only' ) ) {
1708
+ return widgetView.getEditDialog();
1709
+ }
1710
+ } while( ! _.isUndefined( widgetView ) );
1711
+ }
1712
+
1713
+ return false;
1714
+ },
1715
+
1716
+ /**
1717
+ * Load the widget form from the server.
1718
+ * This is called when rendering the dialog for the first time.
1719
+ */
1720
+ loadForm: function () {
1721
+ // don't load the form if this dialog hasn't been rendered yet
1722
+ if ( ! this.$( '> *' ).length ) {
1723
+ return;
1724
+ }
1725
+
1726
+ this.$( '.so-content' ).addClass( 'so-panels-loading' );
1727
+
1728
+ var data = {
1729
+ 'action': 'so_panels_widget_form',
1730
+ 'widget': this.model.get( 'class' ),
1731
+ 'instance': JSON.stringify( this.model.get( 'values' ) ),
1732
+ 'raw': this.model.get( 'raw' )
1733
+ };
1734
+
1735
+ var $soContent = this.$( '.so-content' );
1736
+
1737
+ $.post( panelsOptions.ajaxurl, data, null, 'html' )
1738
+ .done( function ( result ) {
1739
+ // Add in the CID of the widget model
1740
+ var html = result.replace( /{\$id}/g, this.model.cid );
1741
+
1742
+ // Load this content into the form
1743
+ $soContent
1744
+ .removeClass( 'so-panels-loading' )
1745
+ .html( html );
1746
+
1747
+ // Trigger all the necessary events
1748
+ this.trigger( 'form_loaded', this );
1749
+
1750
+ // For legacy compatibility, trigger a panelsopen event
1751
+ this.$( '.panel-dialog' ).trigger( 'panelsopen' );
1752
+
1753
+ // If the main dialog is closed from this point on, save the widget content
1754
+ this.on( 'close_dialog', this.updateModel, this );
1755
+
1756
+ var widgetContent = $soContent.find( '> .widget-content' );
1757
+ // If there's a widget content wrapper, this is one of the new widgets in WP 4.8 which need some special
1758
+ // handling in JS.
1759
+ if ( widgetContent.length > 0 ) {
1760
+ jsWidget.addWidget( $soContent, this.model.widget_id );
1761
+ }
1762
+
1763
+ }.bind( this ) )
1764
+ .fail( function ( error ) {
1765
+ var html;
1766
+ if ( error && error.responseText ) {
1767
+ html = error.responseText;
1768
+ } else {
1769
+ html = panelsOptions.forms.loadingFailed;
1770
+ }
1771
+
1772
+ $soContent
1773
+ .removeClass( 'so-panels-loading' )
1774
+ .html( html );
1775
+ } );
1776
+ },
1777
+
1778
+ /**
1779
+ * Save the widget from the form to the model
1780
+ */
1781
+ updateModel: function ( args ) {
1782
+ args = _.extend( {
1783
+ refresh: true,
1784
+ refreshArgs: null
1785
+ }, args );
1786
+
1787
+ // Get the values from the form and assign the new values to the model
1788
+ this.savingWidget = true;
1789
+
1790
+ if ( ! this.model.get( 'missing' ) ) {
1791
+ // Only get the values for non missing widgets.
1792
+ var values = this.getFormValues();
1793
+ if ( _.isUndefined( values.widgets ) ) {
1794
+ values = {};
1795
+ } else {
1796
+ values = values.widgets;
1797
+ values = values[Object.keys( values )[0]];
1798
+ }
1799
+
1800
+ this.model.setValues( values );
1801
+ this.model.set( 'raw', true ); // We've saved from the widget form, so this is now raw
1802
+ }
1803
+
1804
+ if ( this.styles.stylesLoaded ) {
1805
+ // If the styles view has loaded
1806
+ var style = {};
1807
+ try {
1808
+ style = this.getFormValues( '.so-sidebar .so-visual-styles' ).style;
1809
+ }
1810
+ catch ( e ) {
1811
+ }
1812
+ this.model.set( 'style', style );
1813
+ }
1814
+
1815
+ this.savingWidget = false;
1816
+
1817
+ if ( args.refresh ) {
1818
+ this.builder.model.refreshPanelsData( args.refreshArgs );
1819
+ }
1820
+ },
1821
+
1822
+ /**
1823
+ *
1824
+ */
1825
+ handleChangeValues: function () {
1826
+ if ( ! this.savingWidget ) {
1827
+ // Reload the form when we've changed the model and we're not currently saving from the form
1828
+ this.loadForm();
1829
+ }
1830
+ },
1831
+
1832
+ /**
1833
+ * Save a history entry for this widget. Called when the dialog is closed.
1834
+ */
1835
+ saveHandler: function () {
1836
+ this.builder.addHistoryEntry( 'widget_edited' );
1837
+ this.closeDialog();
1838
+ },
1839
+
1840
+ /**
1841
+ * When the user clicks delete.
1842
+ *
1843
+ * @returns {boolean}
1844
+ */
1845
+ deleteHandler: function () {
1846
+
1847
+ this.model.trigger( 'visual_destroy' );
1848
+ this.closeDialog( {silent: true} );
1849
+ this.builder.model.refreshPanelsData();
1850
+
1851
+ return false;
1852
+ },
1853
+
1854
+ duplicateHandler: function () {
1855
+ this.model.trigger( 'user_duplicate' );
1856
+
1857
+ this.closeDialog( {silent: true} );
1858
+ this.builder.model.refreshPanelsData();
1859
+
1860
+ return false;
1861
+ }
1862
+
1863
+ } );
1864
+
1865
+ },{"../view/widgets/js-widget":31}],10:[function(require,module,exports){
1866
  var panels = window.panels, $ = jQuery;
 
1867
 
1868
  module.exports = panels.view.dialog.extend( {
1869
 
1870
  builder: null,
1871
+ widgetTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-widgets-widget' ).html() ) ),
1872
+ filter: {},
 
 
1873
 
1874
+ dialogClass: 'so-panels-dialog-add-widget',
1875
+ dialogIcon: 'add-widget',
 
1876
 
1877
  events: {
1878
+ 'click .so-close': 'closeDialog',
1879
+ 'click .widget-type': 'widgetClickHandler',
1880
+ 'keyup .so-sidebar-search': 'searchHandler'
 
 
 
 
1881
  },
1882
 
1883
+ /**
1884
+ * Initialize the widget adding dialog
1885
+ */
1886
  initializeDialog: function () {
 
 
 
1887
 
1888
+ this.on( 'open_dialog', function () {
1889
+ this.filter.search = '';
1890
+ this.filterWidgets( this.filter );
1891
+ }, this );
1892
+
1893
+ this.on( 'open_dialog_complete', function () {
1894
+ // Clear the search and re-filter the widgets when we open the dialog
1895
+ this.$( '.so-sidebar-search' ).val( '' ).focus();
1896
+ this.balanceWidgetHeights();
 
 
1897
  } );
1898
 
1899
+ // We'll implement a custom tab click handler
1900
+ this.on( 'tab_click', this.tabClickHandler, this );
 
 
 
 
 
 
 
 
1901
  },
1902
 
 
 
 
1903
  render: function () {
1904
  // Render the dialog and attach it to the builder interface
1905
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widgets' ).html(), {} ) );
 
1906
 
1907
+ // Add all the widgets
1908
+ _.each( panelsOptions.widgets, function ( widget ) {
1909
+ var $w = $( this.widgetTemplate( {
1910
+ title: widget.title,
1911
+ description: widget.description
1912
+ } ) );
1913
 
1914
+ if ( _.isUndefined( widget.icon ) ) {
1915
+ widget.icon = 'dashicons dashicons-admin-generic';
1916
+ }
 
 
 
1917
 
1918
+ $( '<span class="widget-icon" />' ).addClass( widget.icon ).prependTo( $w.find( '.widget-type-wrapper' ) );
 
 
 
 
 
 
1919
 
1920
+ $w.data( 'class', widget.class ).appendTo( this.$( '.widget-type-list' ) );
1921
+ }, this );
1922
 
1923
+ // Add the sidebar tabs
1924
+ var tabs = this.$( '.so-sidebar-tabs' );
1925
+ _.each( panelsOptions.widget_dialog_tabs, function ( tab ) {
1926
+ $( this.dialogTabTemplate( {'title': tab.title} ) ).data( {
1927
+ 'message': tab.message,
1928
+ 'filter': tab.filter
1929
+ } ).appendTo( tabs );
 
 
1930
  }, this );
1931
+
1932
+ // We'll be using tabs, so initialize them
1933
+ this.initTabs();
1934
+
1935
+ var thisDialog = this;
1936
+ $( window ).resize( function () {
1937
+ thisDialog.balanceWidgetHeights();
1938
+ } );
1939
  },
1940
 
1941
  /**
1942
+ * Handle a tab being clicked
 
1943
  */
1944
+ tabClickHandler: function ( $t ) {
1945
+ // Get the filter from the tab, and filter the widgets
1946
+ this.filter = $t.parent().data( 'filter' );
1947
+ this.filter.search = this.$( '.so-sidebar-search' ).val();
 
 
1948
 
1949
+ var message = $t.parent().data( 'message' );
1950
+ if ( _.isEmpty( message ) ) {
1951
+ message = '';
 
 
 
 
 
 
1952
  }
1953
 
1954
+ this.$( '.so-toolbar .so-status' ).html( message );
1955
+
1956
+ this.filterWidgets( this.filter );
1957
+
1958
  return false;
1959
  },
1960
 
1961
  /**
1962
+ * Handle changes to the search value
 
1963
  */
1964
+ searchHandler: function ( e ) {
1965
+ if( e.which === 13 ) {
1966
+ var visibleWidgets = this.$( '.widget-type-list .widget-type:visible' );
1967
+ if( visibleWidgets.length === 1 ) {
1968
+ visibleWidgets.click();
1969
+ }
1970
  }
1971
+ else {
1972
+ this.filter.search = $( e.target ).val().trim();
1973
+ this.filterWidgets( this.filter );
 
 
 
 
 
 
 
 
 
1974
  }
 
 
1975
  },
1976
 
1977
  /**
1978
+ * Filter the widgets that we're displaying
1979
+ * @param filter
1980
  */
1981
+ filterWidgets: function ( filter ) {
1982
+ if ( _.isUndefined( filter ) ) {
1983
+ filter = {};
 
1984
  }
1985
 
1986
+ if ( _.isUndefined( filter.groups ) ) {
1987
+ filter.groups = '';
1988
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1989
 
1990
  this.$( '.widget-type-list .widget-type' ).each( function () {
1991
  var $$ = $( this ), showWidget;
3856
  } );
3857
 
3858
  },{}],23:[function(require,module,exports){
3859
+ var panels = window.panels, $ = jQuery;
3860
+
3861
+ module.exports = Backbone.View.extend( {
3862
+
3863
+ // Config options
3864
+ config: {},
3865
+
3866
+ template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder' ).html() ) ),
3867
+ dialogs: {},
3868
+ rowsSortable: null,
3869
+ dataField: false,
3870
+ currentData: '',
3871
+
3872
+ attachedToEditor: false,
3873
+ attachedVisible: false,
3874
+ liveEditor: undefined,
3875
+ menu: false,
3876
+
3877
+ activeCell: null,
3878
+
3879
+ events: {
3880
+ 'click .so-tool-button.so-widget-add': 'displayAddWidgetDialog',
3881
+ 'click .so-tool-button.so-row-add': 'displayAddRowDialog',
3882
+ 'click .so-tool-button.so-prebuilt-add': 'displayAddPrebuiltDialog',
3883
+ 'click .so-tool-button.so-history': 'displayHistoryDialog',
3884
+ 'click .so-tool-button.so-live-editor': 'displayLiveEditor'
3885
+ },
3886
+
3887
+ /* A row collection */
3888
+ rows: null,
3889
+
3890
+ /**
3891
+ * Initialize the builder
3892
+ */
3893
+ initialize: function ( options ) {
3894
+ var builder = this;
3895
+
3896
+ this.config = _.extend( {
3897
+ loadLiveEditor: false,
3898
+ builderSupports: {}
3899
+ }, options.config );
3900
+
3901
+ // These are the actions that a user can perform in the builder
3902
+ this.config.builderSupports = _.extend( {
3903
+ addRow: true,
3904
+ editRow: true,
3905
+ deleteRow: true,
3906
+ moveRow: true,
3907
+ addWidget: true,
3908
+ editWidget: true,
3909
+ deleteWidget: true,
3910
+ moveWidget: true,
3911
+ prebuilt: true,
3912
+ history: true,
3913
+ liveEditor: true,
3914
+ revertToEditor: true
3915
+ }, this.config.builderSupports );
3916
+
3917
+ // Automatically load the live editor as soon as it's ready
3918
+ if ( options.config.loadLiveEditor ) {
3919
+ this.on( 'builder_live_editor_added', function () {
3920
+ this.displayLiveEditor();
3921
+ } );
3922
+ }
3923
+
3924
+ // Now lets create all the dialog boxes that the main builder interface uses
3925
+ this.dialogs = {
3926
+ widgets: new panels.dialog.widgets(),
3927
+ row: new panels.dialog.row(),
3928
+ prebuilt: new panels.dialog.prebuilt()
3929
+ };
3930
+
3931
+ // Set the builder for each dialog and render it.
3932
+ _.each( this.dialogs, function ( p, i, d ) {
3933
+ d[ i ].setBuilder( builder );
3934
+ } );
3935
+
3936
+ this.dialogs.row.setRowDialogType( 'create' );
3937
+
3938
+ // This handles a new row being added to the collection - we'll display it in the interface
3939
+ this.model.get( 'rows' ).on( 'add', this.onAddRow, this );
3940
+
3941
+ // Reflow the entire builder when ever the
3942
+ $( window ).resize( function ( e ) {
3943
+ if ( e.target === window ) {
3944
+ builder.trigger( 'builder_resize' );
3945
+ }
3946
+ } );
3947
+
3948
+ // When the data changes in the model, store it in the field
3949
+ this.model.on( 'change:data load_panels_data', this.storeModelData, this );
3950
+
3951
+ // Handle a content change
3952
+ this.on( 'content_change', this.handleContentChange, this );
3953
+ this.on( 'display_builder', this.handleDisplayBuilder, this );
3954
+ this.on( 'hide_builder', this.handleHideBuilder, this );
3955
+ this.on( 'builder_rendered builder_resize', this.handleBuilderSizing, this );
3956
+ this.model.on( 'change:data load_panels_data', this.toggleWelcomeDisplay, this );
3957
+
3958
+ this.on( 'display_builder', this.wrapEditorExpandAdjust, this );
3959
+
3960
+ // Create the context menu for this builder
3961
+ this.menu = new panels.utils.menu( {} );
3962
+ this.menu.on( 'activate_context', this.activateContextMenu, this );
3963
+
3964
+ if ( this.config.loadOnAttach ) {
3965
+ this.on( 'builder_attached_to_editor', function () {
3966
+ this.displayAttachedBuilder( { confirm: false } );
3967
+ }, this );
3968
+ }
3969
+
3970
+
3971
+ return this;
3972
+ },
3973
+
3974
+ /**
3975
+ * Render the builder interface.
3976
+ *
3977
+ * @return {panels.view.builder}
3978
+ */
3979
+ render: function () {
3980
+ // this.$el.html( this.template() );
3981
+ this.setElement( this.template() );
3982
+ this.$el
3983
+ .attr( 'id', 'siteorigin-panels-builder-' + this.cid )
3984
+ .addClass( 'so-builder-container' );
3985
+
3986
+ this.trigger( 'builder_rendered' );
3987
+
3988
+ return this;
3989
+ },
3990
+
3991
+ /**
3992
+ * Attach the builder to the given container
3993
+ *
3994
+ * @param container
3995
+ * @returns {panels.view.builder}
3996
+ */
3997
+ attach: function ( options ) {
3998
+
3999
+ options = _.extend( {
4000
+ container: false,
4001
+ dialog: false
4002
+ }, options );
4003
+
4004
+ if ( options.dialog ) {
4005
+ // We're going to add this to a dialog
4006
+ this.dialog = new panels.dialog.builder();
4007
+ this.dialog.builder = this;
4008
+ } else {
4009
+ // Attach this in the standard way
4010
+ this.$el.appendTo( options.container );
4011
+ this.metabox = options.container.closest( '.postbox' );
4012
+ this.initSortable();
4013
+ this.trigger( 'attached_to_container', options.container );
4014
+ }
4015
+
4016
+ this.trigger( 'builder_attached' );
4017
+
4018
+ // Add support for components we have
4019
+
4020
+ if ( this.supports( 'liveEditor' ) ) {
4021
+ this.addLiveEditor();
4022
+ }
4023
+ if ( this.supports( 'history' ) ) {
4024
+ this.addHistoryBrowser();
4025
+ }
4026
+
4027
+ // Hide toolbar buttons we don't support
4028
+ var toolbar = this.$( '.so-builder-toolbar' );
4029
+ var welcomeMessageContainer = this.$( '.so-panels-welcome-message' );
4030
+ var welcomeMessage = panelsOptions.loc.welcomeMessage;
4031
+
4032
+ var supportedItems = [];
4033
+
4034
+ if ( !this.supports( 'addWidget' ) ) {
4035
+ toolbar.find( '.so-widget-add' ).hide();
4036
+ } else {
4037
+ supportedItems.push( welcomeMessage.addWidgetButton );
4038
+ }
4039
+ if ( !this.supports( 'addRow' ) ) {
4040
+ toolbar.find( '.so-row-add' ).hide();
4041
+ } else {
4042
+ supportedItems.push( welcomeMessage.addRowButton );
4043
+ }
4044
+ if ( !this.supports( 'prebuilt' ) ) {
4045
+ toolbar.find( '.so-prebuilt-add' ).hide();
4046
+ } else {
4047
+ supportedItems.push( welcomeMessage.addPrebuiltButton );
4048
+ }
4049
+
4050
+ var msg = '';
4051
+ if ( supportedItems.length === 3 ) {
4052
+ msg = welcomeMessage.threeEnabled;
4053
+ } else if ( supportedItems.length === 2 ) {
4054
+ msg = welcomeMessage.twoEnabled;
4055
+ } else if ( supportedItems.length === 1 ) {
4056
+ msg = welcomeMessage.oneEnabled;
4057
+ } else if ( supportedItems.length === 0 ) {
4058
+ msg = welcomeMessage.addingDisabled;
4059
+ }
4060
+
4061
+ var resTemplate = _.template( panels.helpers.utils.processTemplate( msg ) );
4062
+ var msgHTML = resTemplate( { items: supportedItems } ) + ' ' + welcomeMessage.docsMessage;
4063
+ welcomeMessageContainer.find( '.so-message-wrapper' ).html( msgHTML );
4064
+
4065
+ return this;
4066
+ },
4067
+
4068
+ /**
4069
+ * This will move the Page Builder meta box into the editor if we're in the post/page edit interface.
4070
+ *
4071
+ * @returns {panels.view.builder}
4072
+ */
4073
+ attachToEditor: function () {
4074
+ if ( this.config.editorType !== 'tinyMCE' ) {
4075
+ return this;
4076
+ }
4077
+
4078
+ this.attachedToEditor = true;
4079
+ var metabox = this.metabox;
4080
+ var thisView = this;
4081
+
4082
+ // Handle switching between the page builder and other tabs
4083
+ $( '#wp-content-wrap .wp-editor-tabs' )
4084
+ .find( '.wp-switch-editor' )
4085
+ .click( function ( e ) {
4086
+ e.preventDefault();
4087
+ $( '#wp-content-editor-container' ).show();
4088
+
4089
+ // metabox.hide();
4090
+ $( '#wp-content-wrap' ).removeClass( 'panels-active' );
4091
+ $( '#content-resize-handle' ).show();
4092
+
4093
+ // Make sure the word count is visible
4094
+ thisView.trigger( 'hide_builder' );
4095
+ } ).end()
4096
+ .append(
4097
+ $( '<a id="content-panels" class="hide-if-no-js wp-switch-editor switch-panels">' + metabox.find( '.hndle span' ).html() + '</a>' )
4098
+ .click( function ( e ) {
4099
+ if ( thisView.displayAttachedBuilder( { confirm: true } ) ) {
4100
+ e.preventDefault();
4101
+ }
4102
+ } )
4103
+ );
4104
+
4105
+ // Switch back to the standard editor
4106
+ if ( this.supports( 'revertToEditor' ) ) {
4107
+ metabox.find( '.so-switch-to-standard' ).click( function ( e ) {
4108
+ e.preventDefault();
4109
+
4110
+ if ( !confirm( panelsOptions.loc.confirm_stop_builder ) ) {
4111
+ return;
4112
+ }
4113
+
4114
+ // User is switching to the standard visual editor
4115
+ thisView.addHistoryEntry( 'back_to_editor' );
4116
+ thisView.model.loadPanelsData( false );
4117
+
4118
+ // Switch back to the standard editor
4119
+ $( '#wp-content-wrap' ).show();
4120
+ metabox.hide();
4121
+
4122
+ // Resize to trigger reflow of WordPress editor stuff
4123
+ $( window ).resize();
4124
+
4125
+ thisView.attachedVisible = false;
4126
+ thisView.trigger( 'hide_builder' );
4127
+ } ).show();
4128
+ }
4129
+
4130
+ // Move the panels box into a tab of the content editor
4131
+ metabox.insertAfter( '#wp-content-wrap' ).hide().addClass( 'attached-to-editor' );
4132
+
4133
+ // Switch to the Page Builder interface as soon as we load the page if there are widgets or the normal editor
4134
+ // isn't supported.
4135
+ var data = this.model.get( 'data' );
4136
+ if ( !_.isEmpty( data.widgets ) || !_.isEmpty( data.grids ) || !this.supports( 'revertToEditor' ) ) {
4137
+ this.displayAttachedBuilder( { confirm: false } );
4138
+ }
4139
+
4140
+ // We will also make this sticky if its attached to an editor.
4141
+ var stickToolbar = function () {
4142
+ var toolbar = thisView.$( '.so-builder-toolbar' );
4143
+
4144
+ if ( thisView.$el.hasClass( 'so-display-narrow' ) ) {
4145
+ // In this case, we don't want to stick the toolbar.
4146
+ toolbar.css( {
4147
+ top: 0,
4148
+ left: 0,
4149
+ width: '100%',
4150
+ position: 'absolute'
4151
+ } );
4152
+ thisView.$el.css( 'padding-top', toolbar.outerHeight() );
4153
+ return;
4154
+ }
4155
+
4156
+ var newTop = $( window ).scrollTop() - thisView.$el.offset().top;
4157
+
4158
+ if ( $( '#wpadminbar' ).css( 'position' ) === 'fixed' ) {
4159
+ newTop += $( '#wpadminbar' ).outerHeight();
4160
+ }
4161
+
4162
+ var limits = {
4163
+ top: 0,
4164
+ bottom: thisView.$el.outerHeight() - toolbar.outerHeight() + 20
4165
+ };
4166
+
4167
+ if ( newTop > limits.top && newTop < limits.bottom ) {
4168
+ if ( toolbar.css( 'position' ) !== 'fixed' ) {
4169
+ // The toolbar needs to stick to the top, over the interface
4170
+ toolbar.css( {
4171
+ top: $( '#wpadminbar' ).outerHeight(),
4172
+ left: thisView.$el.offset().left,
4173
+ width: thisView.$el.outerWidth(),
4174
+ position: 'fixed'
4175
+ } );
4176
+ }
4177
+ } else {
4178
+ // The toolbar needs to be at the top or bottom of the interface
4179
+ toolbar.css( {
4180
+ top: Math.min( Math.max( newTop, 0 ), thisView.$el.outerHeight() - toolbar.outerHeight() + 20 ),
4181
+ left: 0,
4182
+ width: '100%',
4183
+ position: 'absolute'
4184
+ } );
4185
+ }
4186
+
4187
+ thisView.$el.css( 'padding-top', toolbar.outerHeight() );
4188
+ };
4189
+
4190
+ this.on( 'builder_resize', stickToolbar, this );
4191
+ $( document ).scroll( stickToolbar );
4192
+ stickToolbar();
4193
+
4194
+ this.trigger( 'builder_attached_to_editor' );
4195
+
4196
+ return this;
4197
+ },
4198
+
4199
+ /**
4200
+ * Display the builder interface when attached to a WordPress editor
4201
+ */
4202
+ displayAttachedBuilder: function ( options ) {
4203
+ options = _.extend( {
4204
+ confirm: true
4205
+ }, options );
4206
+
4207
+ // Switch to the Page Builder interface
4208
+
4209
+ if ( options.confirm ) {
4210
+ var editor = typeof tinyMCE !== 'undefined' ? tinyMCE.get( 'content' ) : false;
4211
+ var editorContent = ( editor && _.isFunction( editor.getContent ) ) ? editor.getContent() : $( 'textarea#content' ).val();
4212
+
4213
+ if ( editorContent !== '' && !confirm( panelsOptions.loc.confirm_use_builder ) ) {
4214
+ return false;
4215
+ }
4216
+ }
4217
+
4218
+ // Hide the standard content editor
4219
+ $( '#wp-content-wrap' ).hide();
4220
+
4221
+
4222
+ $( '#editor-expand-toggle' ).on( 'change.editor-expand', function () {
4223
+ if ( !$( this ).prop( 'checked' ) ) {
4224
+ $( '#wp-content-wrap' ).hide();
4225
+ }
4226
+ } );
4227
+
4228
+ // Show page builder and the inside div
4229
+ this.metabox.show().find( '> .inside' ).show();
4230
+
4231
+ // Triggers full refresh
4232
+ $( window ).resize();
4233
+ $( document ).scroll();
4234
+
4235
+ // Make sure the word count is visible
4236
+ this.attachedVisible = true;
4237
+ this.trigger( 'display_builder' );
4238
+
4239
+ return true;
4240
+ },
4241
+
4242
+ /**
4243
+ * Initialize the row sortables
4244
+ */
4245
+ initSortable: function () {
4246
+ if ( !this.supports( 'moveRow' ) ) {
4247
+ return this;
4248
+ }
4249
+
4250
+ // Create the sortable for the rows
4251
+ var builderView = this;
4252
+
4253
+ this.rowsSortable = this.$( '.so-rows-container' ).sortable( {
4254
+ appendTo: '#wpwrap',
4255
+ items: '.so-row-container',
4256
+ handle: '.so-row-move',
4257
+ axis: 'y',
4258
+ tolerance: 'pointer',
4259
+ scroll: false,
4260
+ stop: function ( e, ui ) {
4261
+ builderView.addHistoryEntry( 'row_moved' );
4262
+
4263
+ var $$ = $( ui.item ),
4264
+ row = $$.data( 'view' );
4265
+
4266
+ builderView.model.get( 'rows' ).remove( row.model, {
4267
+ 'silent': true
4268
+ } );
4269
+ builderView.model.get( 'rows' ).add( row.model, {
4270
+ 'silent': true,
4271
+ 'at': $$.index()
4272
+ } );
4273
+
4274
+ row.trigger( 'move', $$.index() );
4275
+
4276
+ builderView.model.refreshPanelsData();
4277
+ }
4278
+ } );
4279
+
4280
+ return this;
4281
+ },
4282
+
4283
+ /**
4284
+ * Refresh the row sortable
4285
+ */
4286
+ refreshSortable: function () {
4287
+ // Refresh the sortable to account for the new row
4288
+ if ( !_.isNull( this.rowsSortable ) ) {
4289
+ this.rowsSortable.sortable( 'refresh' );
4290
+ }
4291
+ },
4292
+
4293
+ /**
4294
+ * Set the field that's used to store the data
4295
+ * @param field
4296
+ */
4297
+ setDataField: function ( field, options ) {
4298
+ options = _.extend( {
4299
+ load: true
4300
+ }, options );
4301
+
4302
+ this.dataField = field;
4303
+ this.dataField.data( 'builder', this );
4304
+
4305
+ if ( options.load && field.val() !== '' ) {
4306
+ var data = this.dataField.val();
4307
+ try {
4308
+ data = JSON.parse( data );
4309
+ }
4310
+ catch ( err ) {
4311
+ data = {};
4312
+ }
4313
+
4314
+ this.model.loadPanelsData( data );
4315
+ this.currentData = data;
4316
+ this.toggleWelcomeDisplay();
4317
+ }
4318
+
4319
+ return this;
4320
+ },
4321
+
4322
+ /**
4323
+ * Store the model data in the data html field set in this.setDataField.
4324
+ */
4325
+ storeModelData: function () {
4326
+ var data = JSON.stringify( this.model.get( 'data' ) );
4327
+
4328
+ if ( $( this.dataField ).val() !== data ) {
4329
+ // If the data is different, set it and trigger a content_change event
4330
+ $( this.dataField ).val( data );
4331
+ $( this.dataField ).trigger( 'change' );
4332
+ this.trigger( 'content_change' );
4333
+ }
4334
+ },
4335
+
4336
+ /**
4337
+ * HAndle the visual side of adding a new row to the builder.
4338
+ *
4339
+ * @param row
4340
+ * @param collection
4341
+ * @param options
4342
+ */
4343
+ onAddRow: function ( row, collection, options ) {
4344
+ options = _.extend( { noAnimate: false }, options );
4345
+ // Create a view for the row
4346
+ var rowView = new panels.view.row( { model: row } );
4347
+ rowView.builder = this;
4348
+ rowView.render();
4349
+
4350
+ // Attach the row elements to this builder
4351
+ if ( _.isUndefined( options.at ) || collection.length <= 1 ) {
4352
+ // Insert this at the end of the widgets container
4353
+ rowView.$el.appendTo( this.$( '.so-rows-container' ) );
4354
+ } else {
4355
+ // We need to insert this at a specific position
4356
+ rowView.$el.insertAfter(
4357
+ this.$( '.so-rows-container .so-row-container' ).eq( options.at - 1 )
4358
+ );
4359
+ }
4360
+
4361
+ if ( options.noAnimate === false ) {
4362
+ rowView.visualCreate();
4363
+ }
4364
+
4365
+ this.refreshSortable();
4366
+ rowView.resize();
4367
+ },
4368
+
4369
+ /**
4370
+ * Display the dialog to add a new widget.
4371
+ *
4372
+ * @returns {boolean}
4373
+ */
4374
+ displayAddWidgetDialog: function () {
4375
+ this.dialogs.widgets.openDialog();
4376
+ },
4377
+
4378
+ /**
4379
+ * Display the dialog to add a new row.
4380
+ */
4381
+ displayAddRowDialog: function () {
4382
+ var row = new panels.model.row();
4383
+ var cells = new panels.collection.cells( [ { weight: 0.5 }, { weight: 0.5 } ] );
4384
+ cells.each( function ( cell ) {
4385
+ cell.row = row;
4386
+ } );
4387
+ row.set( 'cells', cells );
4388
+ row.builder = this.model;
4389
+
4390
+ this.dialogs.row.setRowModel( row );
4391
+ this.dialogs.row.openDialog();
4392
+ },
4393
+
4394
+ /**
4395
+ * Display the dialog to add prebuilt layouts.
4396
+ *
4397
+ * @returns {boolean}
4398
+ */
4399
+ displayAddPrebuiltDialog: function () {
4400
+ this.dialogs.prebuilt.openDialog();
4401
+ },
4402
+
4403
+ /**
4404
+ * Display the history dialog.
4405
+ *
4406
+ * @returns {boolean}
4407
+ */
4408
+ displayHistoryDialog: function () {
4409
+ this.dialogs.history.openDialog();
4410
+ },
4411
+
4412
+ /**
4413
+ * Handle pasting a row into the builder.
4414
+ */
4415
+ pasteRowHandler: function () {
4416
+ var pastedModel = panels.helpers.clipboard.getModel( 'row-model' );
4417
+
4418
+ if ( !_.isEmpty( pastedModel ) && pastedModel instanceof panels.model.row ) {
4419
+ this.addHistoryEntry( 'row_pasted' );
4420
+ pastedModel.builder = this.model;
4421
+ this.model.get( 'rows' ).add( pastedModel, {
4422
+ at: this.model.get( 'rows' ).indexOf( this.model ) + 1
4423
+ } );
4424
+ this.model.refreshPanelsData();
4425
+ }
4426
+ },
4427
+
4428
+ /**
4429
+ * Get the model for the currently selected cell
4430
+ */
4431
+ getActiveCell: function ( options ) {
4432
+ options = _.extend( {
4433
+ createCell: true,
4434
+ }, options );
4435
+
4436
+ if ( !this.model.get( 'rows' ).length ) {
4437
+ // There aren't any rows yet
4438
+ if ( options.createCell ) {
4439
+ // Create a row with a single cell
4440
+ this.model.addRow( {}, [ { weight: 1 } ], { noAnimate: true } );
4441
+ } else {
4442
+ return null;
4443
+ }
4444
+ }
4445
+
4446
+ // Make sure the active cell isn't empty, and it's in a row that exists
4447
+ var activeCell = this.activeCell;
4448
+ if ( _.isEmpty( activeCell ) || this.model.get( 'rows' ).indexOf( activeCell.model.row ) === -1 ) {
4449
+ return this.model.get( 'rows' ).last().get( 'cells' ).first();
4450
+ } else {
4451
+ return activeCell.model;
4452
+ }
4453
+ },
4454
+
4455
+ /**
4456
+ * Add a live editor to the builder
4457
+ *
4458
+ * @returns {panels.view.builder}
4459
+ */
4460
+ addLiveEditor: function () {
4461
+ if ( _.isEmpty( this.config.liveEditorPreview ) ) {
4462
+ return this;
4463
+ }
4464
+
4465
+ // Create the live editor and set the builder to this.
4466
+ this.liveEditor = new panels.view.liveEditor( {
4467
+ builder: this,
4468
+ previewUrl: this.config.liveEditorPreview
4469
+ } );
4470
+
4471
+ // Display the live editor button in the toolbar
4472
+ if ( this.liveEditor.hasPreviewUrl() ) {
4473
+ this.$( '.so-builder-toolbar .so-live-editor' ).show();
4474
+ }
4475
+
4476
+ this.trigger( 'builder_live_editor_added' );
4477
+
4478
+ return this;
4479
+ },
4480
+
4481
+ /**
4482
+ * Show the current live editor
4483
+ */
4484
+ displayLiveEditor: function () {
4485
+ if ( _.isUndefined( this.liveEditor ) ) {
4486
+ return;
4487
+ }
4488
+
4489
+ this.liveEditor.open();
4490
+ },
4491
+
4492
+ /**
4493
+ * Add the history browser.
4494
+ *
4495
+ * @return {panels.view.builder}
4496
+ */
4497
+ addHistoryBrowser: function () {
4498
+ if ( _.isEmpty( this.config.liveEditorPreview ) ) {
4499
+ return this;
4500
+ }
4501
+
4502
+ this.dialogs.history = new panels.dialog.history();
4503
+ this.dialogs.history.builder = this;
4504
+ this.dialogs.history.entries.builder = this.model;
4505
+
4506
+ // Set the revert entry
4507
+ this.dialogs.history.setRevertEntry( this.model );
4508
+
4509
+ // Display the live editor button in the toolbar
4510
+ this.$( '.so-builder-toolbar .so-history' ).show();
4511
+ },
4512
+
4513
+ /**
4514
+ * Add an entry.
4515
+ *
4516
+ * @param text
4517
+ * @param data
4518
+ */
4519
+ addHistoryEntry: function ( text, data ) {
4520
+ if ( _.isUndefined( data ) ) {
4521
+ data = null;
4522
+ }
4523
+
4524
+ if ( !_.isUndefined( this.dialogs.history ) ) {
4525
+ this.dialogs.history.entries.addEntry( text, data );
4526
+ }
4527
+ },
4528
+
4529
+ supports: function ( thing ) {
4530
+
4531
+ if ( thing === 'rowAction' ) {
4532
+ // Check if this supports any row action
4533
+ return this.supports( 'addRow' ) || this.supports( 'editRow' ) || this.supports( 'deleteRow' );
4534
+ } else if ( thing === 'widgetAction' ) {
4535
+ // Check if this supports any widget action
4536
+ return this.supports( 'addWidget' ) || this.supports( 'editWidget' ) || this.supports( 'deleteWidget' );
4537
+ }
4538
+
4539
+ return _.isUndefined( this.config.builderSupports[ thing ] ) ? false : this.config.builderSupports[ thing ];
4540
+ },
4541
+
4542
+ /**
4543
+ * Handle a change of the content
4544
+ */
4545
+ handleContentChange: function () {
4546
+
4547
+ // Make sure we actually need to copy content.
4548
+ if ( panelsOptions.copy_content && this.attachedToEditor && this.$el.is( ':visible' ) ) {
4549
+
4550
+ var panelsData = this.model.getPanelsData();
4551
+ if ( !_.isEmpty( panelsData.widgets ) ) {
4552
+ // We're going to create a copy of page builder content into the post content
4553
+ $.post(
4554
+ panelsOptions.ajaxurl,
4555
+ {
4556
+ action: 'so_panels_builder_content',
4557
+ panels_data: JSON.stringify( panelsData ),
4558
+ post_id: this.config.postId
4559
+ },
4560
+ function ( content ) {
4561
+ if ( content !== '' ) {
4562
+ this.updateEditorContent( content );
4563
+ }
4564
+ }.bind( this )
4565
+ );
4566
+ }
4567
+ }
4568
+ },
4569
+
4570
+ /**
4571
+ * Update editor content with the given content.
4572
+ *
4573
+ * @param content
4574
+ */
4575
+ updateEditorContent: function ( content ) {
4576
+ // Switch back to the standard editor
4577
+ if ( this.config.editorType !== 'tinyMCE' || typeof tinyMCE === 'undefined' || _.isNull( tinyMCE.get( "content" ) ) ) {
4578
+ var $editor = $( this.config.editorId );
4579
+ $editor.val( content ).trigger( 'change' ).trigger( 'keyup' );
4580
+ } else {
4581
+ var contentEd = tinyMCE.get( "content" );
4582
+
4583
+ contentEd.setContent( content );
4584
+
4585
+ contentEd.fire( 'change' );
4586
+ contentEd.fire( 'keyup' );
4587
+ }
4588
+
4589
+ this.triggerYoastSeoChange();
4590
+ },
4591
+
4592
+ /**
4593
+ * Trigger a change on Yoast SEO
4594
+ */
4595
+ triggerYoastSeoChange: function () {
4596
+ if ( $( '#yoast_wpseo_focuskw_text_input' ).length ) {
4597
+ var element = document.getElementById( 'yoast_wpseo_focuskw_text_input' ), event;
4598
+
4599
+ if ( document.createEvent ) {
4600
+ event = document.createEvent( "HTMLEvents" );
4601
+ event.initEvent( "keyup", true, true );
4602
+ } else {
4603
+ event = document.createEventObject();
4604
+ event.eventType = "keyup";
4605
+ }
4606
+
4607
+ event.eventName = "keyup";
4608
+
4609
+ if ( document.createEvent ) {
4610
+ element.dispatchEvent( event );
4611
+ } else {
4612
+ element.fireEvent( "on" + event.eventType, event );
4613
+ }
4614
+ }
4615
+ },
4616
+
4617
+ /**
4618
+ * Handle displaying the builder
4619
+ */
4620
+ handleDisplayBuilder: function () {
4621
+ var editor = typeof tinyMCE !== 'undefined' ? tinyMCE.get( 'content' ) : false;
4622
+ var editorContent = ( editor && _.isFunction( editor.getContent ) ) ? editor.getContent() : $( 'textarea#content' ).val();
4623
+
4624
+ if (
4625
+ (
4626
+ _.isEmpty( this.model.get( 'data' ) ) ||
4627
+ ( _.isEmpty( this.model.get( 'data' ).widgets ) && _.isEmpty( this.model.get( 'data' ).grids ) )
4628
+ ) &&
4629
+ editorContent !== ''
4630
+ ) {
4631
+ var editorClass = panelsOptions.text_widget;
4632
+ // There is a small chance a theme will have removed this, so check
4633
+ if ( _.isEmpty( editorClass ) ) {
4634
+ return;
4635
+ }
4636
+
4637
+ // Create the existing page content in a single widget
4638
+ this.model.loadPanelsData( this.model.getPanelsDataFromHtml( editorContent, editorClass ) );
4639
+ this.model.trigger( 'change' );
4640
+ this.model.trigger( 'change:data' );
4641
+ }
4642
+
4643
+ $( '#post-status-info' ).addClass( 'for-siteorigin-panels' );
4644
+ },
4645
+
4646
+ handleHideBuilder: function () {
4647
+ $( '#post-status-info' ).show().removeClass( 'for-siteorigin-panels' );
4648
+ },
4649
+
4650
+ wrapEditorExpandAdjust: function () {
4651
+ try {
4652
+ var events = ( $.hasData( window ) && $._data( window ) ).events.scroll,
4653
+ event;
4654
+
4655
+ for ( var i = 0; i < events.length; i++ ) {
4656
+ if ( events[ i ].namespace === 'editor-expand' ) {
4657
+ event = events[ i ];
4658
+
4659
+ // Wrap the call
4660
+ $( window ).unbind( 'scroll', event.handler );
4661
+ $( window ).bind( 'scroll', function ( e ) {
4662
+ if ( !this.attachedVisible ) {
4663
+ event.handler( e );
4664
+ }
4665
+ }.bind( this ) );
4666
+
4667
+ break;
4668
+ }
4669
+ }
4670
+ }
4671
+ catch ( e ) {
4672
+ // We tried, we failed
4673
+ return;
4674
+ }
4675
+ },
4676
+
4677
+ /**
4678
+ * Either add or remove the narrow class
4679
+ * @returns {exports}
4680
+ */
4681
+ handleBuilderSizing: function () {
4682
+ var width = this.$el.width();
4683
+
4684
+ if ( !width ) {
4685
+ return this;
4686
+ }
4687
+
4688
+ if ( width < 480 ) {
4689
+ this.$el.addClass( 'so-display-narrow' );
4690
+ } else {
4691
+ this.$el.removeClass( 'so-display-narrow' );
4692
+ }
4693
+
4694
+ return this;
4695
+ },
4696
+
4697
+ /**
4698
+ * Set the parent dialog for all the dialogs in this builder.
4699
+ *
4700
+ * @param text
4701
+ * @param dialog
4702
+ */
4703
+ setDialogParents: function ( text, dialog ) {
4704
+ _.each( this.dialogs, function ( p, i, d ) {
4705
+ d[ i ].setParent( text, dialog );
4706
+ } );
4707
+
4708
+ // For any future dialogs
4709
+ this.on( 'add_dialog', function ( newDialog ) {
4710
+ newDialog.setParent( text, dialog );
4711
+ }, this );
4712
+ },
4713
+
4714
+ /**
4715
+ * This shows or hides the welcome display depending on whether there are any rows in the collection.
4716
+ */
4717
+ toggleWelcomeDisplay: function () {
4718
+ if ( !this.model.get( 'rows' ).isEmpty() ) {
4719
+ this.$( '.so-panels-welcome-message' ).hide();
4720
+ } else {
4721
+ this.$( '.so-panels-welcome-message' ).show();
4722
+ }
4723
+ },
4724
+
4725
+ /**
4726
+ * Activate the contextual menu
4727
+ * @param e
4728
+ * @param menu
4729
+ */
4730
+ activateContextMenu: function ( e, menu ) {
4731
+ var builder = this;
4732
+
4733
+ // Of all the visible builders, find the topmost
4734
+ var topmostBuilder = $( '.siteorigin-panels-builder:visible' )
4735
+ .sort( function ( a, b ) {
4736
+ return $( a ).zIndex() > $( b ).zIndex() ? 1 : -1;
4737
+ } )
4738
+ .last();
4739
+
4740
+ var topmostDialog = $( '.so-panels-dialog-wrapper:visible' )
4741
+ .sort( function ( a, b ) {
4742
+ return $( a ).zIndex() > $( b ).zIndex() ? 1 : -1;
4743
+ } )
4744
+ .last();
4745
+
4746
+ var closestDialog = builder.$el.closest( '.so-panels-dialog-wrapper' );
4747
+
4748
+ // Only run this if its element is the topmost builder, in the topmost dialog
4749
+ if (
4750
+ builder.$el.is( topmostBuilder ) &&
4751
+ (
4752
+ topmostDialog.length === 0 ||
4753
+ topmostDialog.is( closestDialog )
4754
+ )
4755
+ ) {
4756
+ // Get the element we're currently hovering over
4757
+ var over = $( [] )
4758
+ .add( builder.$( '.so-panels-welcome-message:visible' ) )
4759
+ .add( builder.$( '.so-rows-container > .so-row-container' ) )
4760
+ .add( builder.$( '.so-cells > .cell' ) )
4761
+ .add( builder.$( '.cell-wrapper > .so-widget' ) )
4762
+ .filter( function ( i ) {
4763
+ return menu.isOverEl( $( this ), e );
4764
+ } );
4765
+
4766
+ var activeView = over.last().data( 'view' );
4767
+ if ( activeView !== undefined && activeView.buildContextualMenu !== undefined ) {
4768
+ // We'll pass this to the current active view so it can popular the contextual menu
4769
+ activeView.buildContextualMenu( e, menu );
4770
+ }
4771
+ else if ( over.last().hasClass( 'so-panels-welcome-message' ) ) {
4772
+ // The user opened the contextual menu on the welcome message
4773
+ this.buildContextualMenu( e, menu );
4774
+ }
4775
+ }
4776
+ },
4777
+
4778
+ /**
4779
+ * Build the contextual menu for the main builder - before any content has been added.
4780
+ */
4781
+ buildContextualMenu: function ( e, menu ) {
4782
+ var actions = {};
4783
+
4784
+ if ( this.supports( 'addRow' ) ) {
4785
+ actions.add_row = { title: panelsOptions.loc.contextual.add_row };
4786
+ }
4787
+
4788
+ if ( panels.helpers.clipboard.canCopyPaste() ) {
4789
+ if ( panels.helpers.clipboard.isModel( 'row-model' ) && this.supports( 'addRow' ) ) {
4790
+ actions.paste_row = { title: panelsOptions.loc.contextual.row_paste };
4791
+ }
4792
+ }
4793
+
4794
+ if ( !_.isEmpty( actions ) ) {
4795
+ menu.addSection(
4796
+ 'builder-actions',
4797
+ {
4798
+ sectionTitle: panelsOptions.loc.contextual.row_actions,
4799
+ search: false,
4800
+ },
4801
+ actions,
4802
+ function ( c ) {
4803
+ switch ( c ) {
4804
+ case 'add_row':
4805
+ this.displayAddRowDialog();
4806
+ break;
4807
+
4808
+ case 'paste_row':
4809
+ this.pasteRowHandler();
4810
+ break;
4811
+ }
4812
+ }.bind( this )
4813
+ );
4814
+ }
4815
+ },
4816
+ } );
4817
 
4818
  },{}],24:[function(require,module,exports){
4819
  var panels = window.panels, $ = jQuery;
6547
  } );
6548
 
6549
  },{}],28:[function(require,module,exports){
6550
+ var panels = window.panels, $ = jQuery;
6551
+
6552
+ module.exports = Backbone.View.extend( {
6553
+
6554
+ stylesLoaded: false,
6555
+
6556
+ initialize: function () {
6557
+
6558
+ },
6559
+
6560
+ /**
6561
+ * Render the visual styles object.
6562
+ *
6563
+ * @param type
6564
+ * @param postId
6565
+ */
6566
+ render: function ( stylesType, postId, args ) {
6567
+ if ( _.isUndefined( stylesType ) ) {
6568
+ return;
6569
+ }
6570
+
6571
+ // Add in the default args
6572
+ args = _.extend( {
6573
+ builderType: '',
6574
+ dialog: null
6575
+ }, args );
6576
+
6577
+ this.$el.addClass( 'so-visual-styles so-' + stylesType + '-styles so-panels-loading' );
6578
+
6579
+ var postArgs = {
6580
+ builderType: args.builderType
6581
+ };
6582
+
6583
+ if ( stylesType === 'cell') {
6584
+ postArgs.index = args.index;
6585
+ }
6586
+
6587
+ // Load the form
6588
+ $.post(
6589
+ panelsOptions.ajaxurl,
6590
+ {
6591
+ action: 'so_panels_style_form',
6592
+ type: stylesType,
6593
+ style: this.model.get( 'style' ),
6594
+ args: JSON.stringify( postArgs ),
6595
+ postId: postId
6596
+ },
6597
+ null,
6598
+ 'html'
6599
+ ).done( function ( response ) {
6600
+ this.$el.html( response );
6601
+ this.setupFields();
6602
+ this.stylesLoaded = true;
6603
+ this.trigger( 'styles_loaded', !_.isEmpty( response ) );
6604
+ if ( !_.isNull( args.dialog ) ) {
6605
+ args.dialog.trigger( 'styles_loaded', !_.isEmpty( response ) );
6606
+ }
6607
+ }.bind( this ) )
6608
+ .fail( function ( error ) {
6609
+ var html;
6610
+ if ( error && error.responseText ) {
6611
+ html = error.responseText;
6612
+ } else {
6613
+ html = panelsOptions.forms.loadingFailed;
6614
+ }
6615
+
6616
+ this.$el.html( html );
6617
+ }.bind( this ) )
6618
+ .always( function () {
6619
+ this.$el.removeClass( 'so-panels-loading' );
6620
+ }.bind( this ) );
6621
+
6622
+ return this;
6623
+ },
6624
+
6625
+ /**
6626
+ * Attach the style view to the DOM.
6627
+ *
6628
+ * @param wrapper
6629
+ */
6630
+ attach: function ( wrapper ) {
6631
+ wrapper.append( this.$el );
6632
+ },
6633
+
6634
+ /**
6635
+ * Detach the styles view from the DOM
6636
+ */
6637
+ detach: function () {
6638
+ this.$el.detach();
6639
+ },
6640
+
6641
+ /**
6642
+ * Setup all the fields
6643
+ */
6644
+ setupFields: function () {
6645
+
6646
+ // Set up the sections as collapsible
6647
+ this.$( '.style-section-wrapper' ).each( function () {
6648
+ var $s = $( this );
6649
+
6650
+ $s.find( '.style-section-head' ).click( function ( e ) {
6651
+ e.preventDefault();
6652
+ $s.find( '.style-section-fields' ).slideToggle( 'fast' );
6653
+ } );
6654
+ } );
6655
+
6656
+ // Set up the color fields
6657
+ if ( ! _.isUndefined( $.fn.wpColorPicker ) ) {
6658
+ if ( _.isObject( panelsOptions.wpColorPickerOptions.palettes ) && ! $.isArray( panelsOptions.wpColorPickerOptions.palettes ) ) {
6659
+ panelsOptions.wpColorPickerOptions.palettes = $.map( panelsOptions.wpColorPickerOptions.palettes, function ( el ) {
6660
+ return el;
6661
+ } );
6662
+ }
6663
+ this.$( '.so-wp-color-field' ).wpColorPicker( panelsOptions.wpColorPickerOptions );
6664
+ }
6665
+
6666
+ // Set up the image select fields
6667
+ this.$( '.style-field-image' ).each( function () {
6668
+ var frame = null;
6669
+ var $s = $( this );
6670
+
6671
+ $s.find( '.so-image-selector' ).click( function ( e ) {
6672
+ e.preventDefault();
6673
+
6674
+ if ( frame === null ) {
6675
+ // Create the media frame.
6676
+ frame = wp.media( {
6677
+ // Set the title of the modal.
6678
+ title: 'choose',
6679
+
6680
+ // Tell the modal to show only images.
6681
+ library: {
6682
+ type: 'image'
6683
+ },
6684
+
6685
+ // Customize the submit button.
6686
+ button: {
6687
+ // Set the text of the button.
6688
+ text: 'Done',
6689
+ close: true
6690
+ }
6691
+ } );
6692
+
6693
+ frame.on( 'select', function () {
6694
+ var attachment = frame.state().get( 'selection' ).first().attributes;
6695
+
6696
+ var url = attachment.url;
6697
+ if ( ! _.isUndefined( attachment.sizes ) ) {
6698
+ try {
6699
+ url = attachment.sizes.thumbnail.url;
6700
+ }
6701
+ catch ( e ) {
6702
+ // We'll use the full image instead
6703
+ url = attachment.sizes.full.url;
6704
+ }
6705
+ }
6706
+ $s.find( '.current-image' ).css( 'background-image', 'url(' + url + ')' );
6707
+
6708
+ // Store the ID
6709
+ $s.find( '.so-image-selector > input' ).val( attachment.id );
6710
+
6711
+ $s.find( '.remove-image' ).removeClass( 'hidden' );
6712
+ } );
6713
+ }
6714
+
6715
+ frame.open();
6716
+
6717
+ } );
6718
+
6719
+ // Handle clicking on remove
6720
+ $s.find( '.remove-image' ).click( function ( e ) {
6721
+ e.preventDefault();
6722
+ $s.find( '.current-image' ).css( 'background-image', 'none' );
6723
+ $s.find( '.so-image-selector > input' ).val( '' );
6724
+ $s.find( '.remove-image' ).addClass( 'hidden' );
6725
+ } );
6726
+ } );
6727
+
6728
+ // Set up all the measurement fields
6729
+ this.$( '.style-field-measurement' ).each( function () {
6730
+ var $$ = $( this );
6731
+
6732
+ var text = $$.find( 'input[type="text"]' );
6733
+ var unit = $$.find( 'select' );
6734
+ var hidden = $$.find( 'input[type="hidden"]' );
6735
+
6736
+ text.focus( function(){
6737
+ $(this).select();
6738
+ } );
6739
+
6740
+ /**
6741
+ * Load value into the visible input fields.
6742
+ * @param value
6743
+ */
6744
+ var loadValue = function( value ) {
6745
+ if( value === '' ) {
6746
+ return;
6747
+ }
6748
+
6749
+ var re = /(?:([0-9\.,\-]+)(.*))+/;
6750
+ var valueList = hidden.val().split( ' ' );
6751
+ var valueListValue = [];
6752
+ for ( var i in valueList ) {
6753
+ var match = re.exec( valueList[i] );
6754
+ if ( ! _.isNull( match ) && ! _.isUndefined( match[1] ) && ! _.isUndefined( match[2] ) ) {
6755
+ valueListValue.push( match[1] );
6756
+ unit.val( match[2] );
6757
+ }
6758
+ }
6759
+
6760
+ if( text.length === 1 ) {
6761
+ // This is a single input text field
6762
+ text.val( valueListValue.join( ' ' ) );
6763
+ }
6764
+ else {
6765
+ // We're dealing with a multiple field
6766
+ if( valueListValue.length === 1 ) {
6767
+ valueListValue = [ valueListValue[0], valueListValue[0], valueListValue[0], valueListValue[0] ];
6768
+ }
6769
+ else if( valueListValue.length === 2 ) {
6770
+ valueListValue = [ valueListValue[0], valueListValue[1], valueListValue[0], valueListValue[1] ];
6771
+ }
6772
+ else if( valueListValue.length === 3 ) {
6773
+ valueListValue = [ valueListValue[0], valueListValue[1], valueListValue[2], valueListValue[1] ];
6774
+ }
6775
+
6776
+ // Store this in the visible fields
6777
+ text.each( function( i, el ) {
6778
+ $( el ).val( valueListValue[i] );
6779
+ } );
6780
+ }
6781
+ };
6782
+ loadValue( hidden.val() );
6783
+
6784
+ /**
6785
+ * Set value of the hidden field based on inputs
6786
+ */
6787
+ var setValue = function( e ){
6788
+ var i;
6789
+
6790
+ if( text.length === 1 ) {
6791
+ // We're dealing with a single measurement
6792
+ var fullString = text
6793
+ .val()
6794
+ .split( ' ' )
6795
+ .filter( function ( value ) {
6796
+ return value !== '';
6797
+ } )
6798
+ .map( function ( value ) {
6799
+ return value + unit.val();
6800
+ } )
6801
+ .join( ' ' );
6802
+ hidden.val( fullString );
6803
+ }
6804
+ else {
6805
+ var target = $( e.target ),
6806
+ valueList = [],
6807
+ emptyIndex = [],
6808
+ fullIndex = [];
6809
+
6810
+ text.each( function( i, el ) {
6811
+ var value = $( el ).val( ) !== '' ? parseFloat( $( el ).val( ) ) : null;
6812
+ valueList.push( value );
6813
+
6814
+ if( value === null ) {
6815
+ emptyIndex.push( i );
6816
+ }
6817
+ else {
6818
+ fullIndex.push( i );
6819
+ }
6820
+ } );
6821
+
6822
+ if( emptyIndex.length === 3 && fullIndex[0] === text.index( target ) ) {
6823
+ text.val( target.val() );
6824
+ valueList = [ target.val(), target.val(), target.val(), target.val() ];
6825
+ }
6826
+
6827
+ if( JSON.stringify( valueList ) === JSON.stringify( [ null, null, null, null ] ) ) {
6828
+ hidden.val('');
6829
+ }
6830
+ else {
6831
+ hidden.val( valueList.map( function( k ){
6832
+ return ( k === null ? 0 : k ) + unit.val();
6833
+ } ).join( ' ' ) );
6834
+ }
6835
+ }
6836
+ };
6837
+
6838
+ // Set the value when ever anything changes
6839
+ text.change( setValue );
6840
+ unit.change( setValue );
6841
+ } );
6842
+ }
6843
+
6844
+ } );
6845
 
6846
  },{}],29:[function(require,module,exports){
6847
  var panels = window.panels, $ = jQuery;
js/siteorigin-panels-265.min.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
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||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}})},{}],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()))break;e.destroy()}}})},{}],4:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.widget,initialize:function(){}})},{}],5:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({dialogClass:"so-panels-dialog-add-builder",render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-builder").html(),{})),this.$(".so-content .siteorigin-panels-builder").append(this.builder.$el)},initializeDialog:function(){var e=this;this.once("open_dialog_complete",function(){e.builder.initSortable()}),this.on("open_dialog_complete",function(){e.builder.trigger("builder_resize")})}})},{}],6:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({historyEntryTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-history-entry").html())),entries:{},currentEntry:null,revertEntry:null,selectedEntry:null,previewScrollTop:null,dialogClass:"so-panels-dialog-history",dialogIcon:"history",events:{"click .so-close":"closeDialog","click .so-restore":"restoreSelectedEntry"},initializeDialog:function(){this.entries=new s.collection.historyEntries,this.on("open_dialog",this.setCurrentEntry,this),this.on("open_dialog",this.renderHistoryEntries,this)},render:function(){var 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 input[name="live_editor_post_ID"]').val(this.builder.config.postId),this.$("form.history-form").submit()},restoreSelectedEntry:function(){return!this.$(".so-buttons .so-restore").hasClass("disabled")&&(this.currentEntry.get("data")===this.selectedEntry.get("data")?(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(s.helpers.utils.processTemplate(l("#siteorigin-panels-directory-items").html())),builder:null,dialogClass:"so-panels-dialog-prebuilt-layouts",dialogIcon:"layouts",layoutCache:{},currentTab:!1,directoryPage:1,events:{"click .so-close":"closeDialog","click .so-sidebar-tabs li a":"tabClickHandler","click .so-content .layout":"layoutClickHandler","keyup .so-sidebar-search":"searchHandler","click .so-screenshot, .so-title":"directoryItemClickHandler"},initializeDialog:function(){var e=this;this.on("open_dialog",function(){e.$(".so-sidebar-tabs li a").first().click(),e.$(".so-status").removeClass("so-panels-loading")}),this.on("button_click",this.toolbarButtonClick,this)},render:function(){this.renderDialog(this.parseDialogContent(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();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)}}}).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=l(this),s=t.builder.model.getPanelsData(),o=l('input[name="post_title"]').val();o||(o=l('input[name="post_ID"]').val()),s.name=o,i.find('input[name="panels_export_data"]').val(JSON.stringify(s))})},displayLayoutDirectory:function(e,t,i){var s=this,o=this.$(".so-content").empty().addClass("so-panels-loading");if(void 0===e&&(e=""),void 0===t&&(t=1),void 0===i&&(i="directory-siteorigin"),i.match("^directory-")&&!panelsOptions.directory_enabled)return o.removeClass("so-panels-loading").html(l("#siteorigin-panels-directory-enable").html()),void o.find(".so-panels-enable-directory").click(function(n){n.preventDefault(),l.get(panelsOptions.ajaxurl,{action:"so_panels_directory_enable"},function(){}),panelsOptions.directory_enabled=!0,o.addClass("so-panels-loading"),s.displayLayoutDirectory(e,t,i)});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");t<=1?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")},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){var i="";e.success?t.resolve(e.data):(i=e.data.message,t.reject(e.data)),this.setStatusMessage(i,!1,!e.success),this.updateButtonState(!0)}.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(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-row-cell-preview").html())),editableLabel:!0,events:{"click .so-close":"closeDialog","click .so-toolbar .so-save":"saveHandler","click .so-toolbar .so-insert":"insertHandler","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler","change .row-set-form > *":"setCellsFromForm","click .row-set-form button.set-row":"setCellsFromForm"},dialogIcon:"add-row",dialogClass:"so-panels-dialog-row-edit",styleType:"row",dialogType:"edit",row:{cells:null,style:{}},cellStylesCache:[],initializeDialog:function(){this.on("open_dialog",function(){_.isUndefined(this.model)||_.isEmpty(this.model.get("cells"))?this.setRowModel(null):this.setRowModel(this.model),this.regenerateRowPreview()},this),this.row={cells:new s.collection.cells([{weight:.5},{weight:.5}]),style:{}},this.dialogFormsLoaded=0;var e=this;this.on("form_loaded styles_loaded",function(){2===++this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})}),this.on("close_dialog",this.closeHandler),this.on("edit_label",function(e){if(e!==panelsOptions.loc.row.add&&e!==panelsOptions.loc.row.edit||(e=""),this.model.set("label",e),_.isEmpty(e)){var t="create"===this.dialogType?panelsOptions.loc.row.add:panelsOptions.loc.row.edit;this.$(".so-title").text(t)}}.bind(this))},setRowDialogType:function(e){this.dialogType=e},render:function(){var e="create"===this.dialogType?panelsOptions.loc.row.add:panelsOptions.loc.row.edit;this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-row").html(),{title:e,dialogType:this.dialogType}));var t=this.$(".so-title");this.model.has("label")&&!_.isEmpty(this.model.get("label"))&&t.text(this.model.get("label")),this.$(".so-edit-title").val(t.text()),this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("row",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this}),this.builder.supports("addRow")||this.$(".so-buttons .so-duplicate").remove(),this.builder.supports("deleteRow")||this.$(".so-buttons .so-delete").remove();var i=this.$(".so-sidebar.so-right-sidebar");return this.styles.attach(i),this.styles.on("styles_loaded",function(e){e||(i.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),i.remove())},this),_.isUndefined(this.model)||(this.$('input[name="cells"].so-row-field').val(this.model.get("cells").length),this.model.has("ratio")&&this.$('select[name="ratio"].so-row-field').val(this.model.get("ratio")),this.model.has("ratio_direction")&&this.$('select[name="ratio_direction"].so-row-field').val(this.model.get("ratio_direction"))),this.$("input.so-row-field").keyup(function(){l(this).trigger("change")}),this},setRowModel:function(e){return this.model=e,_.isEmpty(this.model)?this:(this.row={cells:this.model.get("cells").clone(),style:{},ratio:this.model.get("ratio"),ratio_direction:this.model.get("ratio_direction")},this.$('input[name="cells"].so-row-field').val(this.model.get("cells").length),this.model.has("ratio")&&this.$('select[name="ratio"].so-row-field').val(this.model.get("ratio")),this.model.has("ratio_direction")&&this.$('select[name="ratio_direction"].so-row-field').val(this.model.get("ratio_direction")),this.clearCellStylesCache(),this)},regenerateRowPreview:function(){var e=this,t=this.$(".row-preview"),i=this.getSelectedCellIndex();t.empty();var s;this.row.cells.each(function(o,n){var a=l(this.cellPreviewTemplate({weight:o.get("weight")}));t.append(a),n==i&&a.find(".preview-cell-in").addClass("cell-selected");var r,d=a.prev();d.length&&(r=l('<div class="resize-handle"></div>'),r.appendTo(a).dblclick(function(){var t=e.row.cells.at(n-1),i=o.get("weight")+t.get("weight");o.set("weight",i/2),t.set("weight",i/2),e.scaleRowWidths()}),r.draggable({axis:"x",containment:t,start:function(e,t){var i=a.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:a.outerWidth(),left:6,height:a.outerHeight()});i.find(".resize-handle").remove();var s=d.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:d.outerWidth(),right:6,height:d.outerHeight()});s.find(".resize-handle").remove(),l(this).data({newCellClone:i,prevCellClone:s}),a.find("> .preview-cell-in").css("visibility","hidden"),d.find("> .preview-cell-in").css("visibility","hidden")},drag:function(i,s){var o=e.row.cells.at(n).get("weight"),a=e.row.cells.at(n-1).get("weight"),r=o-(s.position.left+6)/t.width(),d=a+(s.position.left+6)/t.width();s.helper.offset().left,t.offset().left;l(this).data("newCellClone").css("width",t.width()*r).find(".preview-cell-weight").html(Math.round(1e3*r)/10),l(this).data("prevCellClone").css("width",t.width()*d).find(".preview-cell-weight").html(Math.round(1e3*d)/10)},stop:function(i,s){l(this).data("newCellClone").remove(),l(this).data("prevCellClone").remove(),a.find(".preview-cell-in").css("visibility","visible"),d.find(".preview-cell-in").css("visibility","visible");var o=s.position.left+6,r=o/t.width(),c=e.row.cells.at(n),h=e.row.cells.at(n-1);c.get("weight")-r>.02&&h.get("weight")+r>.02&&(c.set("weight",c.get("weight")-r),h.set("weight",h.get("weight")+r)),e.scaleRowWidths(),s.helper.css("left",-6)}})),a.click(function(e){if(l(e.target).is(".preview-cell")||l(e.target).is(".preview-cell-in")){var t=l(e.target);t.closest(".row-preview").find(".preview-cell .preview-cell-in").removeClass("cell-selected"),t.addClass("cell-selected"),this.openSelectedCellStyles()}}.bind(this)),a.find(".preview-cell-weight").click(function(i){e.$(".resize-handle").css("pointer-event","none").draggable("disable"),t.find(".preview-cell-weight").each(function(){var i=jQuery(this).hide();l('<input type="text" class="preview-cell-weight-input no-user-interacted" />').val(parseFloat(i.html())).insertAfter(i).focus(function(){clearTimeout(s)}).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.at(t).get("weight"))/10)}),s=setTimeout(function(){if(0===t.find(".preview-cell-weight-input").length)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.each(function(e,t){e.set("weight",i[t])}),t.find(".preview-cell").each(function(t,i){var s=e.row.cells.at(t).get("weight");l(i).animate({width:Math.round(1e3*s)/10+"%"},250),l(i).find(".preview-cell-weight-input").val(Math.round(1e3*s)/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.openSelectedCellStyles(),this.trigger("form_loaded",this)},getSelectedCellIndex:function(){var e=-1;return this.$(".preview-cell .preview-cell-in").each(function(t,i){l(i).is(".cell-selected")&&(e=t)}),e},openSelectedCellStyles:function(){if(!_.isUndefined(this.cellStyles)){if(this.cellStyles.stylesLoaded){var e={};try{e=this.getFormValues(".so-sidebar .so-visual-styles.so-cell-styles").style}catch(e){console.log("Error retrieving cell styles - "+e.message)}this.cellStyles.model.set("style",e)}this.cellStyles.detach()}if(this.cellStyles=this.getSelectedCellStyles(),this.cellStyles){var t=this.$(".so-sidebar.so-right-sidebar");this.cellStyles.attach(t)}},getSelectedCellStyles:function(){var e=this.getSelectedCellIndex();if(e>-1){var t=this.cellStylesCache[e];t||(t=new s.view.styles,t.model=this.row.cells.at(e),t.render("cell",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this,index:e}),this.cellStylesCache[e]=t)}return t},clearCellStylesCache:function(){this.cellStylesCache.forEach(function(e){e.remove()}),this.cellStylesCache=[]},scaleRowWidths:function(){var e=this;this.$(".row-preview .preview-cell").each(function(t,i){var s=e.row.cells.at(t);l(i).css("width",100*s.get("weight")+"%").find(".preview-cell-weight").html(Math.round(1e3*s.get("weight"))/10)})},setCellsFromForm:function(){try{var e={cells:parseInt(this.$('.row-set-form input[name="cells"]').val()),ratio:parseFloat(this.$('.row-set-form select[name="ratio"]').val()),direction:this.$('.row-set-form select[name="ratio_direction"]').val()};_.isNaN(e.cells)&&(e.cells=1),isNaN(e.ratio)&&(e.ratio=1),e.cells<1?(e.cells=1,this.$('.row-set-form input[name="cells"]').val(e.cells)):e.cells>12&&(e.cells=12,this.$('.row-set-form input[name="cells"]').val(e.cells)),this.$('.row-set-form select[name="ratio"]').val(e.ratio);for(var t=[],i=this.row.cells.length!==e.cells,o=1,n=0;n<e.cells;n++)t.push(o),o*=e.ratio;var a=_.reduce(t,function(e,t){return e+t});if(t=_.map(t,function(e){return e/a}),t=_.filter(t,function(e){return e>.01}),"left"===e.direction&&(t=t.reverse()),this.row.cells=new s.collection.cells(this.row.cells.first(t.length)),_.each(t,function(e,t){var i=this.row.cells.at(t);i?i.set("weight",e):(i=new s.model.cell({weight:e,row:this.model}),this.row.cells.add(i))}.bind(this)),this.row.ratio=e.ratio,this.row.ratio_direction=e.direction,i)this.regenerateRowPreview();else{var r=this;this.$(".preview-cell").each(function(e,t){var i=r.row.cells.at(e).get("weight");l(t).animate({width:Math.round(1e3*i)/10+"%"},250),l(t).find(".preview-cell-weight").html(Math.round(1e3*i)/10)}),this.$(".preview-cell").css("overflow","visible"),setTimeout(function(){r.regenerateRowPreview()},260)}}catch(e){console.log("Error setting cells - "+e.message)}this.$(".row-set-form .so-button-row-set").removeClass("button-primary")},tabClickHandler:function(e){"#row-layout"===e.attr("href")?this.$(".so-panels-dialog").addClass("so-panels-dialog-has-right-sidebar"):this.$(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar")},updateModel:function(e){if(e=_.extend({refresh:!0,refreshArgs:null},e),_.isEmpty(this.model)||(this.model.setCells(this.row.cells),this.model.set("ratio",this.row.ratio),this.model.set("ratio_direction",this.row.ratio_direction)),!_.isUndefined(this.styles)&&this.styles.stylesLoaded){var t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles.so-row-styles").style}catch(e){console.log("Error retrieving row styles - "+e.message)}this.model.set("style",t)}if(!_.isUndefined(this.cellStyles)&&this.cellStyles.stylesLoaded){var t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles.so-cell-styles").style}catch(e){console.log("Error retrieving cell styles - "+e.message)}this.cellStyles.model.set("style",t)}e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},insertHandler:function(){this.builder.addHistoryEntry("row_added"),this.updateModel();var e=this.builder.getActiveCell({createCell:!1}),t={};return null!==e&&(t.at=this.builder.model.get("rows").indexOf(e.row)+1),this.model.collection=this.builder.model.get("rows"),this.builder.model.get("rows").add(this.model,t),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},saveHandler:function(){return this.builder.addHistoryEntry("row_edited"),this.updateModel(),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},deleteHandler:function(){return this.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.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.closeDialog({silent:!0}),!1},closeHandler:function(){this.clearCellStylesCache(),_.isUndefined(this.cellStyles)||(this.cellStyles=void 0)}})},{}],9:[function(e,t,i){var s=window.panels,l=jQuery,o=e("../view/widgets/js-widget");t.exports=s.view.dialog.extend({builder:null,sidebarWidgetTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-widget-sidebar-widget").html())),dialogClass:"so-panels-dialog-edit-widget",dialogIcon:"add-widget",widgetView:!1,savingWidget:!1,editableLabel:!0,events:{"click .so-close":"saveHandler","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler"},initializeDialog:function(){var e=this;this.model.on("change:values",this.handleChangeValues,this),this.model.on("destroy",this.remove,this),this.dialogFormsLoaded=0,this.on("form_loaded styles_loaded",function(){2===++this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})}),this.on("edit_label",function(e){e===panelsOptions.widgets[this.model.get("class")].title&&(e=""),this.model.set("label",e),_.isEmpty(e)&&this.$(".so-title").text(this.model.getWidgetField("title"))}.bind(this))},render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-widget").html(),{})),this.loadForm();var e=this.model.getWidgetField("title");this.$(".so-title .widget-name").html(e),this.$(".so-edit-title").val(e),this.builder.supports("addWidget")||this.$(".so-buttons .so-duplicate").remove(),this.builder.supports("deleteWidget")||this.$(".so-buttons .so-delete").remove(),this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("widget",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this});var t=this.$(".so-sidebar.so-right-sidebar");this.styles.attach(t),this.styles.on("styles_loaded",function(e){e||(t.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),t.remove())},this)},getPrevDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t=e.index(this.widgetView.$el);if(0===t)return!1;do{if(widgetView=e.eq(--t).data("view"),!_.isUndefined(widgetView)&&!widgetView.model.get("read_only"))return widgetView.getEditDialog()}while(!_.isUndefined(widgetView)&&t>0);return!1},getNextDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t,i=e.index(this.widgetView.$el);if(i===e.length-1)return!1;do{if(t=e.eq(++i).data("view"),!_.isUndefined(t)&&!t.model.get("read_only"))return t.getEditDialog()}while(!_.isUndefined(t));return!1},loadForm:function(){if(this.$("> *").length){this.$(".so-content").addClass("so-panels-loading");var e={action:"so_panels_widget_form",widget:this.model.get("class"),instance:JSON.stringify(this.model.get("values")),raw:this.model.get("raw")},t=this.$(".so-content");l.post(panelsOptions.ajaxurl,e,null,"html").done(function(e){var i=e.replace(/{\$id}/g,this.model.cid);t.removeClass("so-panels-loading").html(i),this.trigger("form_loaded",this),this.$(".panel-dialog").trigger("panelsopen"),this.on("close_dialog",this.updateModel,this),t.find("> .widget-content").length>0&&o.addWidget(t,this.model.widget_id)}.bind(this)).fail(function(e){var i;i=e&&e.responseText?e.responseText:panelsOptions.forms.loadingFailed,t.removeClass("so-panels-loading").html(i)})}},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(e){}this.model.set("style",i)}this.savingWidget=!1,e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},handleChangeValues:function(){this.savingWidget||this.loadForm()},saveHandler:function(){this.builder.addHistoryEntry("widget_edited"),this.closeDialog()},deleteHandler:function(){return this.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}})},{"../view/widgets/js-widget":31}],10:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({builder:null,widgetTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-widgets-widget").html())),filter:{},dialogClass:"so-panels-dialog-add-widget",dialogIcon:"add-widget",events:{"click .so-close":"closeDialog","click .widget-type":"widgetClickHandler","keyup .so-sidebar-search":"searchHandler"},initializeDialog:function(){this.on("open_dialog",function(){this.filter.search="",this.filterWidgets(this.filter)},this),this.on("open_dialog_complete",function(){this.$(".so-sidebar-search").val("").focus(),this.balanceWidgetHeights()}),this.on("tab_click",this.tabClickHandler,this)},render:function(){this.renderDialog(this.parseDialogContent(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){if(13===e.which){var t=this.$(".widget-type-list .widget-type:visible");1===t.length&&t.click()}else this.filter.search=l(e.target).val().trim(),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)||null!==o&&!_.isEmpty(_.intersection(e.groups,panelsOptions.widgets[s].groups)),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")})
2
+ ;i.cell=this.builder.getActiveCell(),i.cell.get("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){t.exports={canCopyPaste:function(){return"undefined"!=typeof Storage&&panelsOptions.user},setModel:function(e){if(!this.canCopyPaste())return!1;var t=panels.helpers.serialize.serialize(e);return e instanceof panels.model.row?t.thingType="row-model":e instanceof panels.model.widget&&(t.thingType="widget-model"),localStorage["panels_clipboard_"+panelsOptions.user]=JSON.stringify(t),!0},isModel:function(e){if(!this.canCopyPaste())return!1;var t=localStorage["panels_clipboard_"+panelsOptions.user];return void 0!==t&&(t=JSON.parse(t),t.thingType&&t.thingType===e)},getModel:function(e){if(!this.canCopyPaste())return null;var t=localStorage["panels_clipboard_"+panelsOptions.user];return void 0!==t&&(t=JSON.parse(t),t.thingType&&t.thingType===e)?panels.helpers.serialize.unserialize(t,t.thingType,null):null}}},{}],12:[function(e,t,i){t.exports={lock:function(){if("hidden"!==jQuery("body").css("overflow")){var e=[self.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft,self.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop];jQuery("body").data({"scroll-position":e}).css("overflow","hidden"),_.isUndefined(e)||window.scrollTo(e[0],e[1])}},unlock:function(){if("hidden"===jQuery("body").css("overflow")&&!jQuery(".so-panels-dialog-wrapper").is(":visible")&&!jQuery(".so-panels-live-editor").is(":visible")){jQuery("body").css("overflow","visible");var e=jQuery("body").data("scroll-position");_.isUndefined(e)||window.scrollTo(e[0],e[1])}}}},{}],13:[function(e,t,i){t.exports={serialize:function(e){var t;if(e instanceof Backbone.Model){var i={};for(var s in e.attributes)if(e.attributes.hasOwnProperty(s)){if("builder"===s||"collection"===s)continue;t=e.attributes[s],t instanceof Backbone.Model||t instanceof Backbone.Collection?i[s]=this.serialize(t):i[s]=t}return i}if(e instanceof Backbone.Collection){for(var l=[],o=0;o<e.models.length;o++)t=e.models[o],t instanceof Backbone.Model||t instanceof Backbone.Collection?l.push(this.serialize(t)):l.push(t);return l}},unserialize:function(e,t,i){var s;switch(t){case"row-model":s=new panels.model.row,s.builder=i,s.set("style",e.style),s.setCells(this.unserialize(e.cells,"cell-collection",s));break;case"cell-model":s=new panels.model.cell,s.row=i,s.set("weight",e.weight),s.set("style",e.style),s.set("widgets",this.unserialize(e.widgets,"widget-collection",s));break;case"widget-model":s=new panels.model.widget,s.cell=i;for(var l in e)e.hasOwnProperty(l)&&s.set(l,e[l]);s.set("widget_id",panels.helpers.utils.generateUUID());break;case"cell-collection":s=new panels.collection.cells;for(var o=0;o<e.length;o++)s.push(this.unserialize(e[o],"cell-model",i));break;case"widget-collection":s=new panels.collection.widgets;for(var o=0;o<e.length;o++)s.push(this.unserialize(e[o],"widget-model",i));break;default:console.log("Unknown Thing - "+t)}return s}}},{}],14:[function(e,t,i){t.exports={generateUUID:function(){var e=(new Date).getTime();return window.performance&&"function"==typeof window.performance.now&&(e+=performance.now()),"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){var i=(e+16*Math.random())%16|0;return e=Math.floor(e/16),("x"==t?i:3&i|8).toString(16)})},processTemplate:function(e){return _.isUndefined(e)||_.isNull(e)?"":(e=e.replace(/{{%/g,"<%"),e=e.replace(/%}}/g,"%>"),e=e.trim())},selectElementContents:function(e){var t=document.createRange();t.selectNodeContents(e);var i=window.getSelection();i.removeAllRanges(),i.addRange(t)}}},{}],15:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=function(e){return this.each(function(){var t=jQuery(this),i=t.closest("form").find(".widget-id").val(),o=l.extend(!0,{},e);if(_.isUndefined(i)||!(i.indexOf("__i__")>-1)){var n=new s.model.builder,a=new s.view.builder({model:n,config:o}),r=t.closest(".so-panels-dialog-wrapper").data("view");_.isUndefined(r)||(r.on("close_dialog",function(){n.refreshPanelsData()}),r.on("open_dialog_complete",function(){a.trigger("builder_resize")}),r.model.on("destroy",function(){n.emptyRows().destroy()}),a.setDialogParents(panelsOptions.loc.layout_widget,r));var d=Boolean(t.closest(".widget-content").length);a.render().attach({container:t,dialog:d||"dialog"===t.data("mode"),type:t.data("type")}).setDataField(t.find("input.panels-data")),d||"dialog"===t.data("mode")?(a.setDialogParents(panelsOptions.loc.layout_widget,a.dialog),t.find(".siteorigin-panels-display-builder").click(function(e){e.preventDefault(),a.dialog.openDialog()})):t.find(".siteorigin-panels-display-builder").parent().remove(),l(document).trigger("panels_setup",a)}})}},{}],16:[function(e,t,i){var s={};window.panels=s,window.siteoriginPanels=s,s.helpers={},s.helpers.clipboard=e("./helpers/clipboard"),s.helpers.utils=e("./helpers/utils"),s.helpers.serialize=e("./helpers/serialize"),s.helpers.pageScroll=e("./helpers/page-scroll"),s.model={},s.model.widget=e("./model/widget"),s.model.cell=e("./model/cell"),s.model.row=e("./model/row"),s.model.builder=e("./model/builder"),s.model.historyEntry=e("./model/history-entry"),s.collection={},s.collection.widgets=e("./collection/widgets"),s.collection.cells=e("./collection/cells"),s.collection.rows=e("./collection/rows"),s.collection.historyEntries=e("./collection/history-entries"),s.view={},s.view.widget=e("./view/widget"),s.view.cell=e("./view/cell"),s.view.row=e("./view/row"),s.view.builder=e("./view/builder"),s.view.dialog=e("./view/dialog"),s.view.styles=e("./view/styles"),s.view.liveEditor=e("./view/live-editor"),s.dialog={},s.dialog.builder=e("./dialog/builder"),s.dialog.widgets=e("./dialog/widgets"),s.dialog.widget=e("./dialog/widget"),s.dialog.prebuilt=e("./dialog/prebuilt"),s.dialog.row=e("./dialog/row"),s.dialog.history=e("./dialog/history"),s.utils={},s.utils.menu=e("./utils/menu"),jQuery.fn.soPanelsSetupBuilderWidget=e("./jquery/setup-builder-widget"),jQuery(function(e){var t,i,s,l,o=e("#siteorigin-panels-metabox");if(s=e("form#post"),o.length&&s.length)t=o,i=o.find(".siteorigin-panels-data-field"),l={editorType:"tinyMCE",postId:e("#post_ID").val(),editorId:"#content",builderType:o.data("builder-type"),builderSupports:o.data("builder-supports"),loadOnAttach:panelsOptions.loadOnAttach&&1==e("#auto_draft").val(),loadLiveEditor:1==o.data("live-editor"),liveEditorPreview:t.data("preview-url")};else if(e(".siteorigin-panels-builder-form").length){var n=e(".siteorigin-panels-builder-form");t=n.find(".siteorigin-panels-builder-container"),i=n.find('input[name="panels_data"]'),s=n,l={editorType:"standalone",postId:n.data("post-id"),editorId:"#post_content",builderType:n.data("type"),builderSupports:n.data("builder-supports"),loadLiveEditor:!1,liveEditorPreview:n.data("preview-url")}}if(!_.isUndefined(t)){var a=window.siteoriginPanels,r=new a.model.builder,d=new a.view.builder({model:r,config:l});d.render().attach({container:t}).setDataField(i).attachToEditor(),s.submit(function(){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,"./helpers/clipboard":11,"./helpers/page-scroll":12,"./helpers/serialize":13,"./helpers/utils":14,"./jquery/setup-builder-widget":15,"./model/builder":17,"./model/cell":18,"./model/history-entry":19,"./model/row":20,"./model/widget":21,"./utils/menu":22,"./view/builder":23,"./view/cell":24,"./view/dialog":25,"./view/live-editor":26,"./view/row":27,"./view/styles":28,"./view/widget":29}],17:[function(e,t,i){t.exports=Backbone.Model.extend({layoutPosition:{BEFORE:"before",AFTER:"after",REPLACE:"replace"},rows:{},defaults:{data:{widgets:[],grids:[],grid_cells:[]}},initialize:function(){this.set("rows",new panels.collection.rows)},addRow:function(e,t,i){i=_.extend({noAnimate:!1},i);var s=new panels.collection.cells(t);e=_.extend({collection:this.get("rows"),cells:s},e);var l=new panels.model.row(e);return l.builder=this,this.get("rows").add(l,i),l},loadPanelsData:function(e,t){try{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(e.grid_cells[l]);var o=this;if(_.each(i,function(t,i){var s={};_.isUndefined(e.grids[i].style)||(s.style=e.grids[i].style),_.isUndefined(e.grids[i].ratio)||(s.ratio=e.grids[i].ratio),_.isUndefined(e.grids[i].ratio_direction)||(s.ratio_direction=e.grids[i].ratio_direction),_.isUndefined(e.grids[i].color_label)||(s.color_label=e.grids[i].color_label),_.isUndefined(e.grids[i].label)||(s.label=e.grids[i].label),o.addRow(s,t,{noAnimate:!0})}),_.isUndefined(e.widgets))return;_.each(e.widgets,function(e){var t=null;_.isUndefined(e.panels_info)?(t=e.info,delete e.info):(t=e.panels_info,delete e.panels_info);var i=o.get("rows").at(parseInt(t.grid)),s=i.get("cells").at(parseInt(t.cell)),l=new panels.model.widget({class:t.class,values:e});_.isUndefined(t.style)||l.set("style",t.style),_.isUndefined(t.read_only)||l.set("read_only",t.read_only),_.isUndefined(t.widget_id)?l.set("widget_id",panels.helpers.utils.generateUUID()):l.set("widget_id",t.widget_id),_.isUndefined(t.label)||l.set("label",t.label),l.cell=s,s.get("widgets").add(l,{noAnimate:!0})}),this.trigger("load_panels_data")}catch(e){console.log("Error loading data: "+e.message)}},concatPanelsData:function(e,t){if(_.isUndefined(t)||_.isUndefined(t.grids)||_.isEmpty(t.grids)||_.isUndefined(t.grid_cells)||_.isEmpty(t.grid_cells))return e;if(_.isUndefined(e)||_.isUndefined(e.grids)||_.isEmpty(e.grids))return t;var i=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.get("rows").each(function(i,s){i.get("cells").each(function(i,l){i.get("widgets").each(function(i,o){var n={class:i.get("class"),raw:i.get("raw"),grid:s,cell:l,id:t++,widget_id:i.get("widget_id"),style:i.get("style"),label:i.get("label")};_.isEmpty(n.widget_id)&&(n.widget_id=panels.helpers.utils.generateUUID());var a=_.extend(_.clone(i.get("values")),{panels_info:n});e.widgets.push(a)}),e.grid_cells.push({grid:s,index:l,weight:i.get("weight"),style:i.get("style")})}),e.grids.push({cells:i.get("cells").length,style:i.get("style"),ratio:i.get("ratio"),ratio_direction:i.get("ratio_direction"),color_label:i.get("color_label"),label:i.get("label")})}),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.get("rows").toArray(),"destroy"),this.get("rows").reset(),this},isValidLayoutPosition:function(e){return e===this.layoutPosition.BEFORE||e===this.layoutPosition.AFTER||e===this.layoutPosition.REPLACE},getPanelsDataFromHtml:function(e,t){var i=this,s=jQuery('<div id="wrapper">'+e+"</div>");if(s.find(".panel-layout .panel-grid").length){var l={grids:[],grid_cells:[],widgets:[]},o=new RegExp(panelsOptions.siteoriginWidgetRegex,"i"),n=function(){function e(e){return e&&"string"==typeof e&&(e=e.replace(/<script[^>]*>([\S\s]*?)<\/script>/gim,""),e=e.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gim,""),t.innerHTML=e,e=t.textContent,t.textContent=""),e}var t=document.createElement("div");return e}(),a=function(e){var t=e.find("div");if(!t.length)return e.html();var i;for(i=0;i<t.length-1&&jQuery.trim(t.eq(i).text())==jQuery.trim(t.eq(i+1).text());i++);var s=t.eq(i).find(".widget-title:header"),l="";return s.length&&(l=s.html(),s.remove()),{title:l,text:t.eq(i).html()}},r=s.find(".panel-layout").eq(0),d=function(e,t){return jQuery(t).closest(".panel-layout").is(r)};return s.find("> .panel-layout > .panel-grid").filter(d).each(function(e,s){var r=jQuery(s),c=r.find(".panel-grid-cell").filter(d);l.grids.push({cells:c.length,style:r.data("style"),ratio:r.data("ratio"),ratio_direction:r.data("ratio-direction"),color_label:r.data("color-label"),label:r.data("label")}),c.each(function(s,r){var c=jQuery(r),h=c.find(".so-panel").filter(d);l.grid_cells.push({grid:e,weight:_.isUndefined(c.data("weight"))?1:parseFloat(c.data("weight")),style:c.data("style")}),h.each(function(r,d){var c=jQuery(d),h=c.find(".panel-widget-style").length?c.find(".panel-widget-style").html():c.html(),u={grid:e,cell:s,style:c.data("style"),raw:!1,label:c.data("label")};h=h.trim();var p=o.exec(h);if(!_.isNull(p)&&""===h.replace(o,"").trim()){try{var g=/class="(.*?)"/.exec(p[3]),f=jQuery(p[5]),w=JSON.parse(n(f.val())),m=w.instance;u.class=g[1].replace(/\\\\+/g,"\\"),u.raw=!1,m.panels_info=u,l.widgets.push(m)}catch(e){u.class=t,l.widgets.push(_.extend(a(c),{filter:"1",type:"visual",panels_info:u}))}return!0}if(-1!==h.indexOf("panel-layout")){if(jQuery("<div>"+h+"</div>").find(".panel-layout .panel-grid").length)return u.class="SiteOrigin_Panels_Widgets_Layout",l.widgets.push({panels_data:i.getPanelsDataFromHtml(h,t),panels_info:u}),!0}return u.class=t,l.widgets.push(_.extend(a(c),{filter:"1",type:"visual",panels_info:u})),!0})})}),s.find(".panel-layout").remove(),s.find("style[data-panels-style-for-post]").remove(),s.html().replace(/^\s+|\s+$/gm,"").length&&(l.grids.push({cells:1,style:{}}),l.grid_cells.push({grid:l.grids.length-1,weight:1}),l.widgets.push({filter:"1",text:s.html().replace(/^\s+|\s+$/gm,""),title:"",type:"visual",panels_info:{class:t,raw:!1,grid:l.grids.length-1,cell:0}})),l}return{grid_cells:[{grid:0,weight:1}],grids:[{cells:1}],widgets:[{filter:"1",text:e,title:"",type:"visual",panels_info:{class:t,raw:!1,grid:0,cell:0}}]}}})},{}],18:[function(e,t,i){t.exports=Backbone.Model.extend({widgets:{},row:null,defaults:{weight:0,style:{}},indexes:null,initialize:function(){this.set("widgets",new panels.collection.widgets),this.on("destroy",this.onDestroy,this)},onDestroy:function(){_.invoke(this.get("widgets").toArray(),"destroy"),this.get("widgets").reset()},clone:function(e,t){_.isUndefined(e)&&(e=this.row),t=_.extend({cloneWidgets:!0},t);var i=new this.constructor(this.attributes);return i.set("collection",e.get("cells"),{silent:!0}),i.row=e,t.cloneWidgets&&this.get("widgets").each(function(e){i.get("widgets").add(e.clone(i,t),{silent:!0})}),i}})},{}],19:[function(e,t,i){t.exports=Backbone.Model.extend({defaults:{text:"",data:"",time:null,count:1}})},{}],20:[function(e,t,i){t.exports=Backbone.Model.extend({builder:null,defaults:{style:{}},indexes:null,initialize:function(){_.isEmpty(this.get("cells"))?this.set("cells",new panels.collection.cells):this.get("cells").each(function(e){e.row=this}.bind(this)),this.on("destroy",this.onDestroy,this)},setCells:function(e){var t=this.get("cells")||new panels.collection.cells,i=[];t.each(function(s,l){var o=e.at(l);if(o)s.set("weight",o.get("weight"));else{for(var n=t.at(e.length-1),a=s.get("widgets").models.slice(),r=0;r<a.length;r++)a[r].moveToCell(n,{silent:!1});i.push(s)}}),_.each(i,function(e){t.remove(e)}),e.length>t.length&&_.each(e.slice(t.length,e.length),function(e){e.set({collection:t}),e.row=this,t.add(e)}.bind(this)),this.reweightCells()},reweightCells:function(){var e=0,t=this.get("cells");t.each(function(t){e+=t.get("weight")}),t.each(function(t){t.set("weight",t.get("weight")/e)}),this.trigger("reweight_cells")},onDestroy:function(){_.invoke(this.get("cells").toArray(),"destroy"),this.get("cells").reset()},clone:function(e){_.isUndefined(e)&&(e=this.builder);var t=new this.constructor(this.attributes);t.set("collection",e.get("rows"),{silent:!0}),t.builder=e;var i=new panels.collection.cells;return this.get("cells").each(function(e){i.add(e.clone(t),{silent:!0})}),t.set("cells",i),t}})},{}],21:[function(e,t,i){t.exports=Backbone.Model.extend({cell:null,defaults:{class:null,missing:!1,values:{},raw:!1,style:{},read_only:!1,widget_id:""},indexes:null,initialize:function(){var e=this.get("class");!_.isUndefined(panelsOptions.widgets[e])&&panelsOptions.widgets[e].installed||this.set("missing",!0)},getWidgetField:function(e){return _.isUndefined(panelsOptions.widgets[this.get("class")])?"title"===e||"description"===e?panelsOptions.loc.missing_widget[e]:"":this.has("label")&&!_.isEmpty(this.get("label"))?this.get("label"):panelsOptions.widgets[this.get("class")][e]},moveToCell:function(e,t,i){return t=_.extend({silent:!0},t),this.cell=e,this.collection.remove(this,t),e.get("widgets").add(this,_.extend({at:i},t)),this.trigger("move_to_cell",e,i),this},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("widget_id",""),i.set("values",s,{silent:!0}),i.set("collection",e.get("widgets"),{silent:!0}),i.cell=e,i.isDuplicate=!0,i},getTitle:function(){var e=panelsOptions.widgets[this.get("class")];if(_.isUndefined(e))return this.get("class").replace(/_/g," ");if(!_.isUndefined(e.panels_title)&&!1===e.panels_title)return panelsOptions.widgets[this.get("class")].description;var t=this.get("values"),i=["title","text"];for(var s in t)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")}})},{}],22:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({wrapperTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-context-menu").html())),sectionTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-context-menu-section").html())),contexts:[],active:!1,events:{"keyup .so-search-wrapper input":"searchKeyUp"},initialize:function(){this.listenContextMenu(),this.render(),this.attach()},listenContextMenu:function(){var e=this;l(window).on("contextmenu",function(t){return e.active&&!e.isOverEl(e.$el,t)?(e.closeMenu(),e.active=!1,t.preventDefault(),!1):!!e.active||(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"),l(window).on("keyup",{menu:this},this.keyboardListen),l(window).on("click",{menu:this},this.clickOutsideListen),this.$el.css("max-height",l(window).height()-20),e.left+this.$el.outerWidth()+10>=l(window).width()&&(e.left=l(window).width()-this.$el.outerWidth()-10),e.left<=0&&(e.left=10),e.top+this.$el.outerHeight()-l(window).scrollTop()+10>=l(window).height()&&(e.top=l(window).height()+l(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"),l(window).off("keyup",this.keyboardListen),l(window).off("click",this.clickOutsideListen),this.active=!1,this.$el.empty().hide()},keyboardListen:function(e){var t=e.data.menu;switch(e.which){case 27:t.closeMenu()}},clickOutsideListen:function(e){var t=e.data.menu;3!==e.which&&t.$el.is(":visible")&&!t.isOverEl(t.$el,e)&&t.closeMenu()},addSection:function(e,t,i,s){var o=this;t=_.extend({display:5,defaultDisplay:!1,search:!0,sectionTitle:"",searchPlaceholder:"",titleKey:"title"},t);var n=l(this.sectionTemplate({settings:t,items:i})).attr("id","panels-menu-section-"+e);this.$el.append(n),n.find(".so-item:not(.so-confirm)").click(function(){var e=l(this);s(e.data("key")),o.closeMenu()}),n.find(".so-item.so-confirm").click(function(){var e=l(this);if(e.hasClass("so-confirming"))return s(e.data("key")),void o.closeMenu();e.data("original-text",e.html()).addClass("so-confirming").html('<span class="dashicons dashicons-yes"></span> '+panelsOptions.loc.dropdown_confirm),setTimeout(function(){e.removeClass("so-confirming"),e.html(e.data("original-text"))},2500)}),n.data("settings",t).find(".so-search-wrapper input").trigger("keyup"),this.active=!0},hasSection:function(e){return this.$el.find("#panels-menu-section-"+e).length>0},searchKeyUp:function(e){var t=l(e.currentTarget),i=t.closest(".so-section"),s=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=a-1<0?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(s.defaultDisplay){i.find(".so-item").hide();for(var r=0;r<s.defaultDisplay.length;r++)i.find('.so-item[data-key="'+s.defaultDisplay[r]+'"]').show()}else i.find(".so-item").show();else i.find(".so-item").hide().each(function(){var e=l(this);-1!==e.html().toLowerCase().indexOf(t.val().toLowerCase())&&e.show()});i.find(".so-item:visible:gt("+(s.display-1)+")").hide(),0===i.find(".so-item:visible").length&&""!==t.val()?i.find(".so-no-results").show():i.find(".so-no-results").hide()},isOverEl:function(e,t){var i=[[e.offset().left,e.offset().top],[e.offset().left+e.outerWidth(),e.offset().top+e.outerHeight()]];return t.pageX>=i[0][0]&&t.pageX<=i[1][0]&&t.pageY>=i[0][1]&&t.pageY<=i[1][1]}})},{}],23:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({config:{},template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder").html())),dialogs:{},rowsSortable:null,dataField:!1,currentData:"",attachedToEditor:!1,attachedVisible:!1,liveEditor:void 0,menu:!1,activeCell:null,events:{"click .so-tool-button.so-widget-add":"displayAddWidgetDialog","click .so-tool-button.so-row-add":"displayAddRowDialog","click .so-tool-button.so-prebuilt-add":"displayAddPrebuiltDialog","click .so-tool-button.so-history":"displayHistoryDialog","click .so-tool-button.so-live-editor":"displayLiveEditor"},rows:null,initialize:function(e){var t=this;return this.config=_.extend({loadLiveEditor:!1,builderSupports:{}},e.config),this.config.builderSupports=_.extend({addRow:!0,editRow:!0,deleteRow:!0,moveRow:!0,addWidget:!0,editWidget:!0,deleteWidget:!0,moveWidget:!0,prebuilt:!0,history:!0,liveEditor:!0,revertToEditor:!0},this.config.builderSupports),e.config.loadLiveEditor&&this.on("builder_live_editor_added",function(){this.displayLiveEditor()}),this.dialogs={widgets:new 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.get("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("hide_builder",this.handleHideBuilder,this),this.on("builder_rendered builder_resize",this.handleBuilderSizing,this),this.model.on("change:data load_panels_data",this.toggleWelcomeDisplay,this),this.on("display_builder",this.wrapEditorExpandAdjust,this),this.menu=new s.utils.menu({}),this.menu.on("activate_context",this.activateContextMenu,this),this.config.loadOnAttach&&this.on("builder_attached_to_editor",function(){this.displayAttachedBuilder({confirm:!1})},this),this},render:function(){return this.setElement(this.template()),this.$el.attr("id","siteorigin-panels-builder-"+this.cid).addClass("so-builder-container"),this.trigger("builder_rendered"),this},attach:function(e){e=_.extend({container:!1,dialog:!1},e),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.trigger("builder_attached"),this.supports("liveEditor")&&this.addLiveEditor(),this.supports("history")&&this.addHistoryBrowser();var t=this.$(".so-builder-toolbar"),i=this.$(".so-panels-welcome-message"),l=panelsOptions.loc.welcomeMessage,o=[];this.supports("addWidget")?o.push(l.addWidgetButton):t.find(".so-widget-add").hide(),this.supports("addRow")?o.push(l.addRowButton):t.find(".so-row-add").hide(),this.supports("prebuilt")?o.push(l.addPrebuiltButton):t.find(".so-prebuilt-add").hide();var n="";3===o.length?n=l.threeEnabled:2===o.length?n=l.twoEnabled:1===o.length?n=l.oneEnabled:0===o.length&&(n=l.addingDisabled);var a=_.template(s.helpers.utils.processTemplate(n)),r=a({items:o})+" "+l.docsMessage;return i.find(".so-message-wrapper").html(r),this},attachToEditor:function(){if("tinyMCE"!==this.config.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").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(e){t.displayAttachedBuilder({confirm:!0})&&e.preventDefault()})),this.supports("revertToEditor")&&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").show(),e.hide(),l(window).resize(),t.attachedVisible=!1,t.trigger("hide_builder"))}).show(),e.insertAfter("#wp-content-wrap").hide().addClass("attached-to-editor");var i=this.model.get("data");_.isEmpty(i.widgets)&&_.isEmpty(i.grids)&&this.supports("revertToEditor")||this.displayAttachedBuilder({confirm:!1});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.trigger("builder_attached_to_editor"),this},displayAttachedBuilder:function(e){if(e=_.extend({confirm:!0},e),e.confirm){var t="undefined"!=typeof tinyMCE&&tinyMCE.get("content");if(""!==(t&&_.isFunction(t.getContent)?t.getContent():l("textarea#content").val())&&!confirm(panelsOptions.loc.confirm_use_builder))return!1}return l("#wp-content-wrap").hide(),l("#editor-expand-toggle").on("change.editor-expand",function(){l(this).prop("checked")||l("#wp-content-wrap").hide()}),this.metabox.show().find("> .inside").show(),l(window).resize(),l(document).scroll(),this.attachedVisible=!0,this.trigger("display_builder"),!0},initSortable:function(){if(!this.supports("moveRow"))return this;var e=this;return 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,i){e.addHistoryEntry("row_moved");var s=l(i.item),o=s.data("view");e.model.get("rows").remove(o.model,{silent:!0}),e.model.get("rows").add(o.model,{silent:!0,at:s.index()}),o.trigger("move",s.index()),e.model.refreshPanelsData()}}),this},refreshSortable:function(){_.isNull(this.rowsSortable)||this.rowsSortable.sortable("refresh")},setDataField:function(e,t){if(t=_.extend({load:!0},t),this.dataField=e,this.dataField.data("builder",this),t.load&&""!==e.val()){var i=this.dataField.val();try{i=JSON.parse(i)}catch(e){i={}}this.model.loadPanelsData(i),this.currentData=i,this.toggleWelcomeDisplay()}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)),!1===i.noAnimate&&l.visualCreate(),this.refreshSortable(),l.resize()},displayAddWidgetDialog:function(){this.dialogs.widgets.openDialog()},displayAddRowDialog:function(){var e=new s.model.row,t=new s.collection.cells([{weight:.5},{weight:.5}]);t.each(function(t){t.row=e}),e.set("cells",t),e.builder=this.model,this.dialogs.row.setRowModel(e),this.dialogs.row.openDialog()},displayAddPrebuiltDialog:function(){this.dialogs.prebuilt.openDialog()},displayHistoryDialog:function(){this.dialogs.history.openDialog()},pasteRowHandler:function(){var e=s.helpers.clipboard.getModel("row-model");!_.isEmpty(e)&&e instanceof s.model.row&&(this.addHistoryEntry("row_pasted"),e.builder=this.model,this.model.get("rows").add(e,{at:this.model.get("rows").indexOf(this.model)+1}),this.model.refreshPanelsData())},getActiveCell:function(e){if(e=_.extend({createCell:!0},e),!this.model.get("rows").length){if(!e.createCell)return null;this.model.addRow({},[{weight:1}],{noAnimate:!0})}var t=this.activeCell
3
+ ;return _.isEmpty(t)||-1===this.model.get("rows").indexOf(t.model.row)?this.model.get("rows").last().get("cells").first():t.model},addLiveEditor:function(){return _.isEmpty(this.config.liveEditorPreview)?this:(this.liveEditor=new s.view.liveEditor({builder:this,previewUrl:this.config.liveEditorPreview}),this.liveEditor.hasPreviewUrl()&&this.$(".so-builder-toolbar .so-live-editor").show(),this.trigger("builder_live_editor_added"),this)},displayLiveEditor:function(){_.isUndefined(this.liveEditor)||this.liveEditor.open()},addHistoryBrowser:function(){if(_.isEmpty(this.config.liveEditorPreview))return this;this.dialogs.history=new 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)},supports:function(e){return"rowAction"===e?this.supports("addRow")||this.supports("editRow")||this.supports("deleteRow"):"widgetAction"===e?this.supports("addWidget")||this.supports("editWidget")||this.supports("deleteWidget"):!_.isUndefined(this.config.builderSupports[e])&&this.config.builderSupports[e]},handleContentChange:function(){if(panelsOptions.copy_content&&this.attachedToEditor&&this.$el.is(":visible")){var e=this.model.getPanelsData();_.isEmpty(e.widgets)||l.post(panelsOptions.ajaxurl,{action:"so_panels_builder_content",panels_data:JSON.stringify(e),post_id:this.config.postId},function(e){""!==e&&this.updateEditorContent(e)}.bind(this))}},updateEditorContent:function(e){if("tinyMCE"!==this.config.editorType||"undefined"==typeof tinyMCE||_.isNull(tinyMCE.get("content"))){l(this.config.editorId).val(e).trigger("change").trigger("keyup")}else{var t=tinyMCE.get("content");t.setContent(e),t.fire("change"),t.fire("keyup")}this.triggerYoastSeoChange()},triggerYoastSeoChange:function(){if(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="undefined"!=typeof tinyMCE&&tinyMCE.get("content"),t=e&&_.isFunction(e.getContent)?e.getContent():l("textarea#content").val();if((_.isEmpty(this.model.get("data"))||_.isEmpty(this.model.get("data").widgets)&&_.isEmpty(this.model.get("data").grids))&&""!==t){var i=panelsOptions.text_widget;if(_.isEmpty(i))return;this.model.loadPanelsData(this.model.getPanelsDataFromHtml(t,i)),this.model.trigger("change"),this.model.trigger("change:data")}l("#post-status-info").addClass("for-siteorigin-panels")},handleHideBuilder:function(){l("#post-status-info").show().removeClass("for-siteorigin-panels")},wrapEditorExpandAdjust:function(){try{for(var e,t=(l.hasData(window)&&l._data(window)).events.scroll,i=0;i<t.length;i++)if("editor-expand"===t[i].namespace){e=t[i],l(window).unbind("scroll",e.handler),l(window).bind("scroll",function(t){this.attachedVisible||e.handler(t)}.bind(this));break}}catch(e){return}},handleBuilderSizing:function(){var e=this.$el.width();return e?(e<480?this.$el.addClass("so-display-narrow"):this.$el.removeClass("so-display-narrow"),this):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.get("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(),o=l(".so-panels-dialog-wrapper:visible").sort(function(e,t){return l(e).zIndex()>l(t).zIndex()?1:-1}).last(),n=i.$el.closest(".so-panels-dialog-wrapper");if(i.$el.is(s)&&(0===o.length||o.is(n))){var a=l([]).add(i.$(".so-panels-welcome-message:visible")).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)}),r=a.last().data("view");void 0!==r&&void 0!==r.buildContextualMenu?r.buildContextualMenu(e,t):a.last().hasClass("so-panels-welcome-message")&&this.buildContextualMenu(e,t)}},buildContextualMenu:function(e,t){var i={};this.supports("addRow")&&(i.add_row={title:panelsOptions.loc.contextual.add_row}),s.helpers.clipboard.canCopyPaste()&&s.helpers.clipboard.isModel("row-model")&&this.supports("addRow")&&(i.paste_row={title:panelsOptions.loc.contextual.row_paste}),_.isEmpty(i)||t.addSection("builder-actions",{sectionTitle:panelsOptions.loc.contextual.row_actions,search:!1},i,function(e){switch(e){case"add_row":this.displayAddRowDialog();break;case"paste_row":this.pasteRowHandler()}}.bind(this))}})},{}],24:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-cell").html())),events:{"click .cell-wrapper":"handleCellClick"},row:null,widgetSortable:null,initialize:function(){this.model.get("widgets").on("add",this.onAddWidget,this)},render:function(){var e={weight:this.model.get("weight"),totalWeight:this.row.model.get("cells").totalWeight()};this.setElement(this.template(e)),this.$el.data("view",this);var t=this;return this.model.get("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(){if(!this.row.builder.supports("moveWidget"))return this;var e=this,t=e.row.builder.$el.attr("id");return 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),o=s.data("view"),n=s.closest(".cell").data("view");o.model.moveToCell(n.model,{},s.index()),o.cell=n,o.cell.row.builder.model.refreshPanelsData()},helper:function(e,t){var i=t.clone().css({width:t.outerWidth(),"z-index":1e4,position:"fixed"}).addClass("widget-being-dragged").appendTo("body");return t.outerWidth()>720&&i.animate({"margin-left":e.pageX-t.offset().left-240,width:480},"fast"),i}}),this},refreshSortable:function(){_.isNull(this.widgetSortable)||this.widgetSortable.sortable("refresh")},initResizable:function(){if(!this.row.builder.supports("editRow"))return this;var e,t=this.$(".resize-handle").css("position","absolute"),i=this.row.$el,s=this;return 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()}}),this},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)),!1===i.noAnimate&&l.visualCreate(),this.refreshSortable(),this.row.resize()},handleCellClick:function(e){this.row.builder.$el.find(".so-cells .cell").removeClass("cell-selected"),this.row.builder.activeCell!==this||this.model.get("widgets").length?(this.$el.addClass("cell-selected"),this.row.builder.activeCell=this):this.row.builder.activeCell=null},pasteHandler:function(){var e=s.helpers.clipboard.getModel("widget-model");!_.isEmpty(e)&&e instanceof s.model.widget&&(this.row.builder.addHistoryEntry("widget_pasted"),e.cell=this.model,this.model.get("widgets").add(e),this.row.builder.model.refreshPanelsData())},buildContextualMenu:function(e,t){var i=this;t.hasSection("add-widget-below")||t.addSection("add-widget-cell",{sectionTitle:panelsOptions.loc.contextual.add_widget_cell,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){i.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({class:e});t.cell=i.model,t.cell.get("widgets").add(t),i.row.builder.model.refreshPanelsData()});var l={};this.row.builder.supports("addWidget")&&s.helpers.clipboard.isModel("widget-model")&&(l.paste={title:panelsOptions.loc.contextual.cell_paste_widget}),_.isEmpty(l)||t.addSection("cell-actions",{sectionTitle:panelsOptions.loc.contextual.cell_actions,search:!1},l,function(e){switch(e){case"paste":this.pasteHandler()}this.row.builder.model.refreshPanelsData()}.bind(this)),this.row.buildContextualMenu(e,t)}})},{}],25:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({dialogTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog").html())),dialogTabTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-tab").html())),tabbed:!1,rendered:!1,builder:!1,className:"so-panels-dialog-wrapper",dialogClass:"",dialogIcon:"",parentDialog:!1,dialogOpen:!1,editableLabel:!1,events:{"click .so-close":"closeDialog","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext"},initialize:function(){this.once("open_dialog",this.render),this.once("open_dialog",this.attach),this.once("open_dialog",this.setDialogClass),this.trigger("initialize_dialog",this),_.isUndefined(this.initializeDialog)||this.initializeDialog()},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=l(_.template(s.helpers.utils.processTemplate(e))(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(e=_.extend({editableLabel:this.editableLabel,dialogIcon:this.dialogIcon},e),this.$el.html(this.dialogTemplate(e)).hide(),this.$el.data("view",this),this.$el.addClass("so-panels-dialog-wrapper"),!1!==this.parentDialog){var t=this,i=l('<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.$(".so-title-bar .so-title-editable").length&&this.initEditableLabel(),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=l(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 o=s.split("#")[1];t.$(".so-content .so-content-tabs .tab-"+o).show()}t.trigger("tab_click",i)}),this.$(".so-sidebar-tabs li a").first().click(),this},initToolbar:function(){this.$(".so-toolbar .so-buttons .so-toolbar-button").click(function(e){e.preventDefault(),this.trigger("button_click",l(e.currentTarget))}.bind(this)),this.$(".so-toolbar .so-buttons .so-dropdown-button").click(function(e){e.preventDefault();var t=l(e.currentTarget),i=t.siblings(".so-dropdown-links-wrapper");i.is(".hidden")?i.removeClass("hidden"):i.addClass("hidden")}.bind(this)),l("html").click(function(e){this.$(".so-dropdown-links-wrapper").not(".hidden").each(function(t,i){var s=l(i),o=l(e.target);0!==o.length&&(o.is(".so-needs-confirm")&&!o.is(".so-confirmed")||o.is(".so-dropdown-button"))||s.addClass("hidden")})}.bind(this))},initEditableLabel:function(){var e=this.$(".so-title-bar .so-title-editable");e.keypress(function(t){var i="keypress"===t.type&&13===t.keyCode;if(i){var s=l(":tabbable"),o=s.index(e);s.eq(o+1).focus(),window.getSelection().removeAllRanges()}return!i}).blur(function(){var t=e.text().replace(/^\s+|\s+$/gm,"");t!==e.data("original-value").replace(/^\s+|\s+$/gm,"")&&(e.text(t),this.trigger("edit_label",t))}.bind(this)),e.focus(function(){e.data("original-value",e.text()),s.helpers.utils.selectElementContents(this)})},setupDialog:function(){this.openDialog(),this.closeDialog()},refreshDialogNav:function(){this.$(".so-title-bar .so-nav").show().removeClass("so-disabled");var e=this.getNextDialog(),t=this.$(".so-title-bar .so-next"),i=this.getPrevDialog(),s=this.$(".so-title-bar .so-previous");null===e?t.hide():!1===e&&t.addClass("so-disabled"),null===i?s.hide():!1===i&&s.addClass("so-disabled")},openDialog:function(e){e=_.extend({silent:!1},e),e.silent||this.trigger("open_dialog"),this.dialogOpen=!0,this.refreshDialogNav(),s.helpers.pageScroll.lock(),l(window).on("keyup",this.keyboardListen),this.$el.show(),e.silent||(this.trigger("open_dialog_complete"),this.builder.trigger("open_dialog",this),l(document).trigger("open_dialog",this))},closeDialog:function(e){e=_.extend({silent:!1},e),e.silent||this.trigger("close_dialog"),this.dialogOpen=!1,this.$el.hide(),s.helpers.pageScroll.unlock(),l(window).off("keyup",this.keyboardListen),e.silent||(this.trigger("close_dialog_complete"),this.builder.trigger("close_dialog",this))},keyboardListen:function(e){27===e.which&&l(".so-panels-dialog-wrapper .so-close").trigger("click")},navToPrevious:function(){this.closeDialog();var e=this.getPrevDialog();null!==e&&!1!==e&&e.openDialog()},navToNext:function(){this.closeDialog();var e=this.getNextDialog();null!==e&&!1!==e&&e.openDialog()},getFormValues:function(e){_.isUndefined(e)&&(e=".so-content");var t,i=this.$(e),s={};return i.find("[name]").each(function(){var e=l(this);try{var i=/([A-Za-z_]+)\[(.*)\]/.exec(e.attr("name"));if(_.isEmpty(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=s,n=null,a=!!_.isString(e.attr("type"))&&e.attr("type").toLowerCase();if("checkbox"===a)n=e.is(":checked")?""===e.val()||e.val():null;else if("radio"===a){if(!e.is(":checked"))return;n=e.val()}else if("SELECT"===e.prop("tagName")){var r=e.find("option:selected");1===r.length?n=e.find("option:selected").val():r.length>1&&(n=_.map(e.find("option:selected"),function(e,t){return l(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(e){n=""}}if(null!==n)for(var d=0;d<t.length;d++)d===t.length-1?""===t[d]?o.push(n):o[t[d]]=n:(_.isUndefined(o[t[d]])&&(""===t[d+1]?o[t[d]]=[]:o[t[d]]={}),o=o[t[d]])}catch(t){console.log("Field ["+e.attr("name")+"] could not be processed and was skipped - "+t.message)}}),s},setStatusMessage:function(e,t,i){var s=i?'<span class="dashicons dashicons-warning"></span>'+e:e;this.$(".so-toolbar .so-status").html(s),!_.isUndefined(t)&&t?this.$(".so-toolbar .so-status").addClass("so-panels-loading"):this.$(".so-toolbar .so-status").removeClass("so-panels-loading")},setParent:function(e,t){this.parentDialog={text:e,dialog:t}}})},{}],26:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-live-editor").html())),previewScrollTop:0,loadTimes:[],previewFrameId:1,previewUrl:null,previewIframe:null,events:{"click .live-editor-close":"close","click .live-editor-collapse":"collapse","click .live-editor-mode":"mobileToggle"},initialize:function(e){e=_.extend({builder:!1,previewUrl:!1},e),_.isEmpty(e.previewUrl)&&(e.previewUrl=panelsOptions.ajaxurl+"&action=so_panels_live_editor_preview"),this.builder=e.builder,this.previewUrl=e.previewUrl,this.builder.model.on("refresh_panels_data",this.handleRefreshData,this),this.builder.model.on("load_panels_data",this.handleLoadData,this)},render:function(){this.setElement(this.template()),this.$el.hide();var e=this,t=!1;return l(document).mousedown(function(){t=!0}).mouseup(function(){t=!1}),this.$el.on("mouseenter",".so-widget-wrapper",function(){var i=l(this),s=i.data("live-editor-preview-widget");t||void 0===s||!s.length||e.$(".so-preview-overlay").is(":visible")||(e.highlightElement(s),e.scrollToElement(s))}),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")},open:function(){if(""===this.$el.html()&&this.render(),0===this.$el.closest("body").length&&this.attach(),s.helpers.pageScroll.lock(),this.$el.is(":visible"))return this;if(this.$el.show(),this.refreshPreview(this.builder.model.getPanelsData()),this.originalContainer=this.builder.$el.parent(),this.builder.$el.appendTo(this.$(".so-live-editor-builder")),this.builder.$(".so-tool-button.so-live-editor").hide(),this.builder.trigger("builder_resize"),"auto-draft"===l("#original_post_status").val()&&!this.autoSaved){var e=this;wp.autosave&&(""===l('#title[name="post_title"]').val()&&l('#title[name="post_title"]').val(panelsOptions.loc.draft).trigger("keydown"),l(document).one("heartbeat-tick.autosave",function(){e.autoSaved=!0,e.refreshPreview(e.builder.model.getPanelsData())}),wp.autosave.server.triggerSave())}},close:function(){if(!this.$el.is(":visible"))return this;this.$el.hide(),s.helpers.pageScroll.unlock(),this.builder.$el.appendTo(this.originalContainer),this.builder.$(".so-tool-button.so-live-editor").show(),this.builder.trigger("builder_resize")},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),this.previewIframe.contents().find("body").find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return 0===l(this).parents(".so-panel").length}).not(e).addClass("so-panels-faded"),e.removeClass("so-panels-faded").addClass("so-panels-highlighted")},resetHighlights:function(){var e=this.previewIframe.contents().find("body");this.resetHighlightTimeout=setTimeout(function(){e.find(".panel-grid .panel-grid-cell .so-panel").removeClass("so-panels-faded so-panels-highlighted")},100)},scrollToElement:function(e){this.$(".so-preview iframe")[0].contentWindow.liveEditorScrollTo(e)},handleRefreshData:function(e,t){if(!this.$el.is(":visible"))return this;this.refreshPreview(e)},handleLoadData:function(){if(!this.$el.is(":visible"))return this;this.refreshPreview(this.builder.model.getPanelsData())},refreshPreview:function(e){var t=this.loadTimes.length?_.reduce(this.loadTimes,function(e,t){return e+t},0)/this.loadTimes.length:1e3;_.isNull(this.previewIframe)||this.$(".so-preview-overlay").is(":visible")||(this.previewScrollTop=this.previewIframe.contents().scrollTop()),this.$(".so-preview-overlay").show(),this.$(".so-preview-overlay .so-loading-bar").clearQueue().css("width","0%").animate({width:"100%"},parseInt(t)+100),this.postToIframe({live_editor_panels_data:JSON.stringify(e),live_editor_post_ID:this.builder.config.postId},this.previewUrl,this.$(".so-preview")),this.previewIframe.data("load-start",(new Date).getTime())},postToIframe:function(e,t,i){_.isNull(this.previewIframe)||this.previewIframe.remove();var s="siteorigin-panels-live-preview-"+this.previewFrameId;this.previewIframe=l('<iframe src="javascript:false;" />').attr({id:s,name:s}).appendTo(i),this.setupPreviewFrame(this.previewIframe);var o=l('<form id="soPostToPreviewFrame" method="post" />').attr({id:s,target:this.previewIframe.attr("id"),action:t}).appendTo("body");return l.each(e,function(e,t){l('<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=l(this),i=e.contents();if(!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);var s=i.find("#pl-"+t.builder.config.postId);s.find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return l(this).closest(".panel-layout").is(s)}).each(function(e,i){var s=l(i),o=t.$(".so-live-editor-builder .so-widget-wrapper").eq(s.data("index"));o.data("live-editor-preview-widget",s),s.css({cursor:"pointer"}).mouseenter(function(){o.parent().addClass("so-hovered"),t.highlightElement(s)}).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=l(this);e.data("iframeready")||e.trigger("iframeready")})},hasPreviewUrl:function(){return""!==this.$("form.live-editor-form").attr("action")},mobileToggle:function(e){var t=l(e.currentTarget);this.$(".live-editor-mode").not(t).removeClass("so-active"),t.addClass("so-active"),this.$el.removeClass("live-editor-desktop-mode live-editor-tablet-mode live-editor-mobile-mode").addClass("live-editor-"+t.data("mode")+"-mode")}})},{}],27:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-row").html())),events:{"click .so-row-settings":"editSettingsHandler","click .so-row-duplicate":"duplicateHandler","click .so-row-delete":"confirmedDeleteHandler","click .so-row-color":"rowColorChangeHandler"},builder:null,dialog:null,initialize:function(){var e=this.model.get("cells");e.on("add",this.handleCellAdd,this),e.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 t=this;e.each(function(e){t.listenTo(e.get("widgets"),"add",t.resize)}),e.on("add",function(e){t.listenTo(e.get("widgets"),"add",t.resize)},this),this.model.on("change:label",this.onLabelChange,this)},render:function(){var e=this.model.has("color_label")?this.model.get("color_label"):1,t=this.model.has("label")?this.model.get("label"):"";this.setElement(this.template({rowColorLabel:e,rowLabel:t})),this.$el.data("view",this);var i=this;return this.model.get("cells").each(function(e){var t=new s.view.cell({model:e});t.row=i,t.render(),t.$el.appendTo(i.$(".so-cells"))}),this.builder.supports("rowAction")?(this.builder.supports("editRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-settings").parent().remove(),this.$el.addClass("so-row-no-edit")),this.builder.supports("addRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-duplicate").parent().remove(),this.$el.addClass("so-row-no-duplicate")),this.builder.supports("deleteRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-delete").parent().remove(),this.$el.addClass("so-row-no-delete"))):(this.$(".so-row-toolbar .so-dropdown-wrapper").remove(),this.$el.addClass("so-row-no-actions")),this.builder.supports("moveRow")||(this.$(".so-row-toolbar .so-row-move").remove(),this.$el.addClass("so-row-no-move")),l.trim(this.$(".so-row-toolbar").html()).length||this.$(".so-row-toolbar").remove(),this.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),this.$(".so-cells .resize-handle").css("height",0);var t=0;this.$(".so-cells .cell").each(function(){t=Math.max(t,l(this).height()),l(this).css("width",100*l(this).data("view").model.get("weight")+"%")}),this.$(".so-cells .cell-wrapper").css("min-height",Math.max(t,63)),this.$(".so-cells .resize-handle").css("height",this.$(".so-cells .cell-wrapper").outerHeight())}},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.builder.addHistoryEntry("row_deleted");var e=this;this.$el.fadeOut("normal",function(){e.model.destroy(),e.builder.model.refreshPanelsData()})},onLabelChange:function(e,t){0==this.$(".so-row-label").length?this.$(".so-row-toolbar").prepend('<h3 class="so-row-label">'+t+"</h3>"):this.$(".so-row-label").text(t)},duplicateHandler:function(){this.builder.addHistoryEntry("row_duplicated");var e=this.model.clone(this.builder.model);this.builder.model.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData()},copyHandler:function(){s.helpers.clipboard.setModel(this.model)},pasteHandler:function(){var e=s.helpers.clipboard.getModel("row-model");!_.isEmpty(e)&&e instanceof s.model.row&&(this.builder.addHistoryEntry("row_pasted"),e.builder=this.builder.model,this.builder.model.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData())},confirmedDeleteHandler:function(e){var t=l(e.target);if(t.hasClass("dashicons")&&(t=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(){if(this.builder.supports("editRow"))return null===this.dialog&&(this.dialog=new s.dialog.row,this.dialog.setBuilder(this.builder).setRowModel(this.model)),this.dialog.openDialog(),this},deleteHandler:function(){return this.model.destroy(),this},rowColorChangeHandler:function(e){this.$(".so-row-color").removeClass("so-row-color-selected");var t=l(e.target),i=t.data("color-label"),s=this.model.has("color_label")?this.model.get("color_label"):1;t.addClass("so-row-color-selected"),this.$el.removeClass("so-row-color-"+s),this.$el.addClass("so-row-color-"+i),this.model.set("color_label",i)},handleCellAdd:function(e){var t=new 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=[],l=1;l<5;l++)i.push({title:l+" "+panelsOptions.loc.contextual.column});this.builder.supports("addRow")&&t.addSection("add-row",{sectionTitle:panelsOptions.loc.contextual.add_row,search:!1},i,function(e){this.builder.addHistoryEntry("row_added");for(var t=Number(e)+1,i=[],l=0;l<t;l++)i.push({weight:100/t});var o=new s.model.row({collection:this.collection}),n=new s.collection.cells(i);n.each(function(e){e.row=o}),o.setCells(n),o.builder=this.builder.model,this.builder.model.get("rows").add(o,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData()}.bind(this));var o={};this.builder.supports("editRow")&&(o.edit={title:panelsOptions.loc.contextual.row_edit}),s.helpers.clipboard.canCopyPaste()&&(o.copy={title:panelsOptions.loc.contextual.row_copy},this.builder.supports("addRow")&&s.helpers.clipboard.isModel("row-model")&&(o.paste={title:panelsOptions.loc.contextual.row_paste})),this.builder.supports("addRow")&&(o.duplicate={title:panelsOptions.loc.contextual.row_duplicate}),this.builder.supports("deleteRow")&&(o.delete={title:panelsOptions.loc.contextual.row_delete,confirm:!0}),_.isEmpty(o)||t.addSection("row-actions",{sectionTitle:panelsOptions.loc.contextual.row_actions,search:!1},o,function(e){switch(e){case"edit":this.editSettingsHandler();break;case"copy":this.copyHandler();break;case"paste":this.pasteHandler();break;case"duplicate":this.duplicateHandler();break;case"delete":this.visualDestroyModel()}}.bind(this))}})},{}],28:[function(e,t,i){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 so-"+e+"-styles so-panels-loading");var l={builderType:i.builderType};return"cell"===e&&(l.index=i.index),s.post(panelsOptions.ajaxurl,{action:"so_panels_style_form",type:e,style:this.model.get("style"),args:JSON.stringify(l),postId:t},null,"html").done(function(e){this.$el.html(e),this.setupFields(),this.stylesLoaded=!0,this.trigger("styles_loaded",!_.isEmpty(e)),_.isNull(i.dialog)||i.dialog.trigger("styles_loaded",!_.isEmpty(e))}.bind(this)).fail(function(e){var t;t=e&&e.responseText?e.responseText:panelsOptions.forms.loadingFailed,this.$el.html(t)}.bind(this)).always(function(){this.$el.removeClass("so-panels-loading")}.bind(this)),this}},attach:function(e){e.append(this.$el)},detach:function(){this.$el.detach()},setupFields:function(){this.$(".style-section-wrapper").each(function(){var 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(e){s=i.sizes.full.url}t.find(".current-image").css("background-image","url("+s+")"),t.find(".so-image-selector > input").val(i.id),t.find(".remove-image").removeClass("hidden")})),e.open()}),t.find(".remove-image").click(function(e){e.preventDefault(),t.find(".current-image").css("background-image","none"),t.find(".so-image-selector > input").val(""),t.find(".remove-image").addClass("hidden")})}),this.$(".style-field-measurement").each(function(){var e=s(this),t=e.find('input[type="text"]'),i=e.find("select"),l=e.find('input[type="hidden"]');t.focus(function(){s(this).select()});!function(e){if(""!==e){
4
+ var o=/(?:([0-9\.,\-]+)(.*))+/,n=l.val().split(" "),a=[];for(var r in n){var d=o.exec(n[r]);_.isNull(d)||_.isUndefined(d[1])||_.isUndefined(d[2])||(a.push(d[1]),i.val(d[2]))}1===t.length?t.val(a.join(" ")):(1===a.length?a=[a[0],a[0],a[0],a[0]]:2===a.length?a=[a[0],a[1],a[0],a[1]]:3===a.length&&(a=[a[0],a[1],a[2],a[1]]),t.each(function(e,t){s(t).val(a[e])}))}}(l.val());var o=function(e){if(1===t.length){var o=t.val().split(" ").filter(function(e){return""!==e}).map(function(e){return e+i.val()}).join(" ");l.val(o)}else{var n=s(e.target),a=[],r=[],d=[];t.each(function(e,t){var i=""!==s(t).val()?parseFloat(s(t).val()):null;a.push(i),null===i?r.push(e):d.push(e)}),3===r.length&&d[0]===t.index(n)&&(t.val(n.val()),a=[n.val(),n.val(),n.val(),n.val()]),JSON.stringify(a)===JSON.stringify([null,null,null,null])?l.val(""):l.val(a.map(function(e){return(null===e?0:e)+i.val()}).join(" "))}};t.change(o),i.change(o)})}})},{}],29:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-widget").html())),cell:null,dialog:null,events:{"click .widget-edit":"editHandler","click .title h4":"titleClickHandler","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),this.model.on("change:label",this.onLabelChange,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),this.cell.row.builder.supports("editWidget")&&!this.model.get("read_only")||(this.$(".actions .widget-edit").remove(),this.$el.addClass("so-widget-no-edit")),this.cell.row.builder.supports("addWidget")||(this.$(".actions .widget-duplicate").remove(),this.$el.addClass("so-widget-no-duplicate")),this.cell.row.builder.supports("deleteWidget")||(this.$(".actions .widget-delete").remove(),this.$el.addClass("so-widget-no-delete")),this.cell.row.builder.supports("moveWidget")||this.$el.addClass("so-widget-no-move"),l.trim(this.$(".actions").html()).length||this.$(".actions").remove(),this.model.get("read_only")&&this.$el.addClass("so-widget-read-only"),0===_.size(this.model.get("values"))||e.loadForm){var t=this.getEditDialog();t.once("form_loaded",t.saveWidget,t),t.setupDialog()}return this},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()},titleClickHandler:function(e){return!this.cell.row.builder.supports("editWidget")||this.model.get("read_only")?this:(this.editHandler(),this)},duplicateHandler:function(){this.cell.row.builder.addHistoryEntry("widget_duplicated");var e=this.model.clone(this.model.cell);return this.cell.model.get("widgets").add(e,{at:this.model.collection.indexOf(this.model)+1}),this.cell.row.builder.model.refreshPanelsData(),this},copyHandler:function(){s.helpers.clipboard.setModel(this.model)},deleteHandler:function(){return this.model.trigger("visual_destroy"),this},onModelChange:function(){this.$(".description").html(this.model.getTitle())},onLabelChange:function(e){this.$(".title > h4").text(e.getWidgetField("title"))},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.cell.row.builder.addHistoryEntry("widget_deleted");var e=this;return this.$el.fadeOut("fast",function(){e.cell.row.resize(),e.model.destroy(),e.cell.row.builder.model.refreshPanelsData(),e.remove()}),this},buildContextualMenu:function(e,t){this.cell.row.builder.supports("addWidget")&&t.addSection("add-widget-below",{sectionTitle:panelsOptions.loc.contextual.add_widget_below,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){this.cell.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({class:e});t.cell=this.cell.model,this.cell.model.get("widgets").add(t,{at:this.model.collection.indexOf(this.model)+1}),this.cell.row.builder.model.refreshPanelsData()}.bind(this));var i={};this.cell.row.builder.supports("editWidget")&&!this.model.get("read_only")&&(i.edit={title:panelsOptions.loc.contextual.widget_edit}),s.helpers.clipboard.canCopyPaste()&&(i.copy={title:panelsOptions.loc.contextual.widget_copy}),this.cell.row.builder.supports("addWidget")&&(i.duplicate={title:panelsOptions.loc.contextual.widget_duplicate}),this.cell.row.builder.supports("deleteWidget")&&(i.delete={title:panelsOptions.loc.contextual.widget_delete,confirm:!0}),_.isEmpty(i)||t.addSection("widget-actions",{sectionTitle:panelsOptions.loc.contextual.widget_actions,search:!1},i,function(e){switch(e){case"edit":this.editHandler();break;case"copy":this.copyHandler();break;case"duplicate":this.duplicateHandler();break;case"delete":this.visualDestroyModel()}}.bind(this)),this.cell.buildContextualMenu(e,t)}})},{}],30:[function(e,t,i){var s=jQuery,l={addWidget:function(e,t,i){var l=wp.customHtmlWidgets,o=s("<div></div>"),n=t.find(".widget-content:first");n.before(o);var a=new l.CustomHtmlWidgetControl({el:o,syncContainer:n});return a.initializeEditor(),a.editor.codemirror.refresh(),a}};t.exports=l},{}],31:[function(e,t,i){var s=e("./custom-html-widget"),l=e("./media-widget"),o=e("./text-widget"),n={CUSTOM_HTML:"custom_html",MEDIA_AUDIO:"media_audio",MEDIA_GALLERY:"media_gallery",MEDIA_IMAGE:"media_image",MEDIA_VIDEO:"media_video",TEXT:"text",addWidget:function(e,t){var i,n=e.find("> .id_base").val();switch(n){case this.CUSTOM_HTML:i=s;break;case this.MEDIA_AUDIO:case this.MEDIA_GALLERY:case this.MEDIA_IMAGE:case this.MEDIA_VIDEO:i=l;break;case this.TEXT:i=o}i.addWidget(n,e,t)}};t.exports=n},{"./custom-html-widget":30,"./media-widget":32,"./text-widget":33}],32:[function(e,t,i){var s=jQuery,l={addWidget:function(e,t,i){var l=wp.mediaWidgets,o=l.controlConstructors[e];if(o){var n=l.modelConstructors[e]||l.MediaWidgetModel,a=t.find("> .widget-content"),r=s('<div class="media-widget-control"></div>');a.before(r);var d={};a.find(".media-widget-instance-property").each(function(){var e=s(this);d[e.data("property")]=e.val()}),d.widget_id=i;var c=new n(d),h=new o({el:r,syncContainer:a,model:c});return h.render(),h}}};t.exports=l},{}],33:[function(e,t,i){var s=jQuery,l={addWidget:function(e,t,i){var l=wp.textWidgets,o={},n=t.find(".visual");if(n.length>0){if(!n.val())return null;var a=s("<div></div>"),r=t.find(".widget-content:first");r.before(a),o={el:a,syncContainer:r}}else o={el:t};var d=new l.TextWidgetControl(o);return d.initializeEditor(),d}};t.exports=l},{}]},{},[16]);
js/styling-264.js DELETED
@@ -1,59 +0,0 @@
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
-
16
- // Reset all the styles associated with row stretching
17
- $$.css( {
18
- 'margin-left': 0,
19
- 'margin-right': 0,
20
- 'padding-left': 0,
21
- 'padding-right': 0
22
- } );
23
-
24
- var leftSpace = $$.offset().left - fullContainer.offset().left,
25
- rightSpace = fullContainer.outerWidth() - leftSpace - $$.parent().outerWidth();
26
-
27
- $$.css( {
28
- 'margin-left': - leftSpace,
29
- 'margin-right': - rightSpace,
30
- 'padding-left': $$.data( 'stretch-type' ) === 'full' ? leftSpace : 0,
31
- 'padding-right': $$.data( 'stretch-type' ) === 'full' ? rightSpace : 0
32
- } );
33
-
34
- var cells = $$.find( '> .panel-grid-cell' );
35
-
36
- if ( $$.data( 'stretch-type' ) === 'full-stretched' && cells.length === 1 ) {
37
- cells.css( {
38
- 'padding-left': 0,
39
- 'padding-right': 0
40
- } );
41
- }
42
-
43
- $$.css( {
44
- 'border-left': 0,
45
- 'border-right': 0
46
- } );
47
- } );
48
-
49
- if ( $( '.siteorigin-panels-stretch.panel-row-style' ).length ) {
50
- $( window ).trigger( 'panelsStretchRows' );
51
- }
52
- }
53
- $( window ).on( 'resize load', stretchFullWidthRows );
54
- stretchFullWidthRows();
55
-
56
- // This should have been done in the footer, but run it here just incase.
57
- $( 'body' ).removeClass( 'siteorigin-panels-before-js' );
58
-
59
- } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/styling-264.min.js DELETED
@@ -1 +0,0 @@
1
- jQuery(function(t){var e=t(panelsStyles.fullContainer);0===e.length&&(e=t("body"));var r=function(){t(".siteorigin-panels-stretch.panel-row-style").each(function(){var r=t(this);r.css({"margin-left":0,"margin-right":0,"padding-left":0,"padding-right":0});var i=r.offset().left-e.offset().left,n=e.outerWidth()-i-r.parent().outerWidth();r.css({"margin-left":-i,"margin-right":-n,"padding-left":"full"===r.data("stretch-type")?i:0,"padding-right":"full"===r.data("stretch-type")?n:0});var a=r.find("> .panel-grid-cell");"full-stretched"===r.data("stretch-type")&&1===a.length&&a.css({"padding-left":0,"padding-right":0}),r.css({"border-left":0,"border-right":0})}),t(".siteorigin-panels-stretch.panel-row-style").length&&t(window).trigger("panelsStretchRows")};t(window).on("resize load",r),r(),t("body").removeClass("siteorigin-panels-before-js")});
 
js/{styling-263.js → styling-265.js} RENAMED
File without changes
js/{styling-263.min.js → styling-265.min.js} RENAMED
File without changes
lang/siteorigin-panels.pot CHANGED
@@ -17,35 +17,35 @@ msgstr ""
17
  "X-Poedit-SearchPathExcluded-0: *.js\n"
18
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
 
20
- #: tmp/inc/admin-layouts.php:79, tmp/inc/admin-layouts.php:405
21
  msgid "Layouts Directory"
22
  msgstr ""
23
 
24
- #: tmp/inc/admin-layouts.php:333
25
  msgid "Invalid request."
26
  msgstr ""
27
 
28
- #: tmp/inc/admin-layouts.php:363
29
  msgid "Theme Defined Layouts"
30
  msgstr ""
31
 
32
- #: tmp/inc/admin-layouts.php:505
33
  msgid "Clone %s"
34
  msgstr ""
35
 
36
- #: tmp/inc/admin-layouts.php:581
37
  msgid " - Results For:"
38
  msgstr ""
39
 
40
- #: tmp/inc/admin-layouts.php:647
41
  msgid "Missing layout ID or no such layout exists"
42
  msgstr ""
43
 
44
- #: tmp/inc/admin-layouts.php:739
45
  msgid "There was a problem fetching the layout. Please try again later."
46
  msgstr ""
47
 
48
- #: tmp/inc/admin-widget-dialog.php:197, tmp/widgets/widgets.php:164
49
  msgid "Widgets Bundle"
50
  msgstr ""
51
 
@@ -97,7 +97,7 @@ msgstr ""
97
  msgid "Addons"
98
  msgstr ""
99
 
100
- #: tmp/inc/admin.php:285, tmp/inc/admin.php:1013, tmp/inc/admin.php:2035, tmp/inc/admin.php:2045, tmp/inc/settings.php:389, tmp/tpl/js-templates.php:399
101
  msgid "Page Builder"
102
  msgstr ""
103
 
@@ -325,7 +325,7 @@ msgstr ""
325
  msgid "New Row"
326
  msgstr ""
327
 
328
- #: tmp/inc/admin.php:815, tmp/inc/admin.php:831, tmp/inc/styles.php:183, tmp/tpl/js-templates.php:137
329
  msgid "Row"
330
  msgstr ""
331
 
@@ -345,7 +345,7 @@ msgstr ""
345
  msgid "Add a {{%= items[0] %}}, {{%= items[1] %}} or {{%= items[2] %}} to get started."
346
  msgstr ""
347
 
348
- #: tmp/inc/admin.php:829, tmp/inc/styles.php:316, tmp/tpl/js-templates.php:135
349
  msgid "Widget"
350
  msgstr ""
351
 
@@ -369,103 +369,123 @@ msgstr ""
369
  msgid "Error uploading or importing file."
370
  msgstr ""
371
 
372
- #: tmp/inc/admin.php:1175, tmp/inc/home.php:26
 
 
 
 
373
  msgid "Home Page"
374
  msgstr ""
375
 
376
- #: tmp/inc/admin.php:1363
377
  msgid "Untitled Widget"
378
  msgstr ""
379
 
380
- #: tmp/inc/admin.php:1693
381
  msgid "You need to install 1{%1$s} to use the widget 2{%2$s}."
382
  msgstr ""
383
 
384
- #: tmp/inc/admin.php:1705
385
  msgid "Save and reload this page to start using the widget after you've installed it."
386
  msgstr ""
387
 
388
- #: tmp/inc/admin.php:1737
389
  msgid "The widget 1{%1$s} is not available. Please try locate and install the missing plugin. Post on the 2{support forums} if you need help."
390
  msgstr ""
391
 
392
- #: tmp/inc/admin.php:2069
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  msgid "%s Widgets"
394
  msgstr ""
395
 
396
- #: tmp/inc/admin.php:2161
397
  msgid "12 Page Builder Tips"
398
  msgstr ""
399
 
400
- #: tmp/inc/admin.php:2167
401
  msgid "Sign up to our newsletter and we'll send you this free Page Builder video course."
402
  msgstr ""
403
 
404
- #: tmp/inc/admin.php:2169
405
  msgid "12 tips that'll help you get the most out of Page Builder."
406
  msgstr ""
407
 
408
- #: tmp/inc/admin.php:2171
409
  msgid "Watch the video to find out more, then sign up below to get started."
410
  msgstr ""
411
 
412
- #: tmp/inc/admin.php:2173, tmp/inc/admin.php:2193
413
  msgid "We'll email you a confirmation. You can unsubscribe at any time."
414
  msgstr ""
415
 
416
- #: tmp/inc/admin.php:2181
417
  msgid "Free Page Builder Addons"
418
  msgstr ""
419
 
420
- #: tmp/inc/admin.php:2187
421
  msgid "The free animations addon allows you to add beautiful animations to Page Builder elements."
422
  msgstr ""
423
 
424
- #: tmp/inc/admin.php:2189
425
  msgid "Sign up to our newsletter and we'll send you the addon as a free gift."
426
  msgstr ""
427
 
428
- #: tmp/inc/admin.php:2191
429
  msgid "Plus, we'll send you even more powerful addons, for as long as you're subscribed."
430
  msgstr ""
431
 
432
- #: tmp/inc/admin.php:2223
433
  msgid "Watch Intro Video"
434
  msgstr ""
435
 
436
- #: tmp/inc/admin.php:2225
437
  msgid "Loaded from Vimeo Servers"
438
  msgstr ""
439
 
440
- #: tmp/inc/admin.php:2227
441
  msgid "Please enter a valid email address."
442
  msgstr ""
443
 
444
- #: tmp/inc/admin.php:2231
445
  msgid "Your Name"
446
  msgstr ""
447
 
448
- #: tmp/inc/admin.php:2233
449
  msgid "Your Email"
450
  msgstr ""
451
 
452
- #: tmp/inc/admin.php:2235
453
  msgid "Sign Up"
454
  msgstr ""
455
 
456
- #: tmp/inc/admin.php:2237, tmp/tpl/js-templates.php:477
457
  msgid "Close"
458
  msgstr ""
459
 
460
- #: tmp/inc/admin.php:2259
461
  msgid "Get a lightbox addon for SiteOrigin widgets"
462
  msgstr ""
463
 
464
- #: tmp/inc/admin.php:2267
465
  msgid "Get the row, cell and widget animations addon"
466
  msgstr ""
467
 
468
- #: tmp/inc/admin.php:2275
469
  msgid "Get premium email support for SiteOrigin Page Builder"
470
  msgstr ""
471
 
@@ -633,7 +653,7 @@ msgstr ""
633
  msgid "Display recommend widgets in Page Builder add widget dialog."
634
  msgstr ""
635
 
636
- #: tmp/inc/settings.php:657, tmp/inc/styles-admin.php:78
637
  msgid "Layout"
638
  msgstr ""
639
 
@@ -741,271 +761,291 @@ msgstr ""
741
  msgid "Include styles into your Post Content. This keeps page layouts, even when Page Builder is deactivated."
742
  msgstr ""
743
 
744
- #: tmp/inc/settings.php:925, tmp/inc/styles-admin.php:248
745
  msgid "Enabled"
746
  msgstr ""
747
 
748
- #: tmp/inc/styles-admin.php:36
 
 
 
 
 
 
 
 
749
  msgid "Row Styles"
750
  msgstr ""
751
 
752
- #: tmp/inc/styles-admin.php:41
753
  msgid "Cell%s Styles"
754
  msgstr ""
755
 
756
- #: tmp/inc/styles-admin.php:45
757
  msgid "Widget Styles"
758
  msgstr ""
759
 
760
- #: tmp/inc/styles-admin.php:74
761
  msgid "Attributes"
762
  msgstr ""
763
 
764
- #: tmp/inc/styles-admin.php:82
765
  msgid "Design"
766
  msgstr ""
767
 
768
- #: tmp/inc/styles-admin.php:92
769
  msgid "Theme"
770
  msgstr ""
771
 
772
- #: tmp/inc/styles-admin.php:174, tmp/inc/styles.php:252, tmp/inc/styles.php:281
773
  msgid "Top"
774
  msgstr ""
775
 
776
- #: tmp/inc/styles-admin.php:178, tmp/widgets/widgets/button/button.php:30
777
  msgid "Right"
778
  msgstr ""
779
 
780
- #: tmp/inc/styles-admin.php:182, tmp/inc/styles.php:254, tmp/inc/styles.php:283
781
  msgid "Bottom"
782
  msgstr ""
783
 
784
- #: tmp/inc/styles-admin.php:186, tmp/widgets/widgets/button/button.php:29
785
  msgid "Left"
786
  msgstr ""
787
 
788
- #: tmp/inc/styles-admin.php:228
789
  msgid "Select Image"
790
  msgstr ""
791
 
792
- #: tmp/inc/styles-admin.php:233
793
  msgid "Remove"
794
  msgstr ""
795
 
796
- #: tmp/inc/styles.php:78
 
 
 
 
797
  msgid "%s ID"
798
  msgstr ""
799
 
800
- #: tmp/inc/styles.php:81
801
  msgid "A custom ID used for this %s."
802
  msgstr ""
803
 
804
- #: tmp/inc/styles.php:86
805
  msgid "%s Class"
806
  msgstr ""
807
 
808
- #: tmp/inc/styles.php:89
809
  msgid "A CSS class"
810
  msgstr ""
811
 
812
- #: tmp/inc/styles.php:94
813
  msgid "CSS Styles"
814
  msgstr ""
815
 
816
- #: tmp/inc/styles.php:97
817
  msgid "One style attribute per line."
818
  msgstr ""
819
 
820
- #: tmp/inc/styles.php:102
821
  msgid "Mobile CSS Styles"
822
  msgstr ""
823
 
824
- #: tmp/inc/styles.php:105
825
  msgid "CSS applied when in mobile view."
826
  msgstr ""
827
 
828
- #: tmp/inc/styles.php:112
829
  msgid "Padding"
830
  msgstr ""
831
 
832
- #: tmp/inc/styles.php:115
833
  msgid "Padding around the entire %s."
834
  msgstr ""
835
 
836
- #: tmp/inc/styles.php:121
837
  msgid "Mobile Padding"
838
  msgstr ""
839
 
840
- #: tmp/inc/styles.php:124
841
  msgid "Padding when on mobile devices."
842
  msgstr ""
843
 
844
- #: tmp/inc/styles.php:132
845
  msgid "Background Color"
846
  msgstr ""
847
 
848
- #: tmp/inc/styles.php:135
849
  msgid "Background color of the %s."
850
  msgstr ""
851
 
852
- #: tmp/inc/styles.php:140
853
  msgid "Background Image"
854
  msgstr ""
855
 
856
- #: tmp/inc/styles.php:143
857
  msgid "Background image of the %s."
858
  msgstr ""
859
 
860
- #: tmp/inc/styles.php:148
861
  msgid "Background Image Display"
862
  msgstr ""
863
 
864
- #: tmp/inc/styles.php:152
865
  msgid "Tiled Image"
866
  msgstr ""
867
 
868
- #: tmp/inc/styles.php:153
869
  msgid "Cover"
870
  msgstr ""
871
 
872
- #: tmp/inc/styles.php:154
873
  msgid "Centered, with original size"
874
  msgstr ""
875
 
876
- #: tmp/inc/styles.php:155
877
  msgid "Fixed"
878
  msgstr ""
879
 
880
- #: tmp/inc/styles.php:156
881
  msgid "Parallax"
882
  msgstr ""
883
 
884
- #: tmp/inc/styles.php:157
885
  msgid "Parallax (Original Size)"
886
  msgstr ""
887
 
888
- #: tmp/inc/styles.php:159
889
  msgid "How the background image is displayed."
890
  msgstr ""
891
 
892
- #: tmp/inc/styles.php:164
893
  msgid "Border Color"
894
  msgstr ""
895
 
896
- #: tmp/inc/styles.php:167
897
  msgid "Border color of the %s."
898
  msgstr ""
899
 
900
- #: tmp/inc/styles.php:186
901
  msgid "Cell Class"
902
  msgstr ""
903
 
904
- #: tmp/inc/styles.php:189
905
  msgid "Class added to all cells in this row."
906
  msgstr ""
907
 
908
- #: tmp/inc/styles.php:196
909
  msgid "Bottom Margin"
910
  msgstr ""
911
 
912
- #: tmp/inc/styles.php:199
913
  msgid "Space below the row. Default is %spx."
914
  msgstr ""
915
 
916
- #: tmp/inc/styles.php:204
917
  msgid "Gutter"
918
  msgstr ""
919
 
920
- #: tmp/inc/styles.php:207
921
  msgid "Amount of space between cells. Default is %spx."
922
  msgstr ""
923
 
924
- #: tmp/inc/styles.php:212
925
  msgid "Row Layout"
926
  msgstr ""
927
 
928
- #: tmp/inc/styles.php:216, tmp/inc/styles.php:228
929
  msgid "Standard"
930
  msgstr ""
931
 
932
- #: tmp/inc/styles.php:217
933
  msgid "Full Width"
934
  msgstr ""
935
 
936
- #: tmp/inc/styles.php:218
937
  msgid "Full Width Stretched"
938
  msgstr ""
939
 
940
- #: tmp/inc/styles.php:224
941
  msgid "Collapse Behaviour"
942
  msgstr ""
943
 
944
- #: tmp/inc/styles.php:229
945
  msgid "No Collapse"
946
  msgstr ""
947
 
948
- #: tmp/inc/styles.php:235
949
  msgid "Collapse Order"
950
  msgstr ""
951
 
952
- #: tmp/inc/styles.php:239, tmp/inc/widgets/post-loop.php:295, tmp/widgets/widgets.php:635, tmp/widgets/widgets.php:757
953
  msgid "Default"
954
  msgstr ""
955
 
956
- #: tmp/inc/styles.php:240
957
  msgid "Left on Top"
958
  msgstr ""
959
 
960
- #: tmp/inc/styles.php:241
961
  msgid "Right on Top"
962
  msgstr ""
963
 
964
- #: tmp/inc/styles.php:248
965
  msgid "Cell Vertical Alignment"
966
  msgstr ""
967
 
968
- #: tmp/inc/styles.php:253, tmp/inc/styles.php:282, tmp/widgets/widgets/button/button.php:31
969
  msgid "Center"
970
  msgstr ""
971
 
972
- #: tmp/inc/styles.php:255, tmp/inc/styles.php:284
973
  msgid "Stretch"
974
  msgstr ""
975
 
976
- #: tmp/inc/styles.php:273
977
  msgid "Cell"
978
  msgstr ""
979
 
980
- #: tmp/inc/styles.php:276
981
  msgid "Vertical Alignment"
982
  msgstr ""
983
 
984
- #: tmp/inc/styles.php:280
985
  msgid "Use row setting"
986
  msgstr ""
987
 
988
- #: tmp/inc/styles.php:290, tmp/inc/styles.php:321
989
  msgid "Font Color"
990
  msgstr ""
991
 
992
- #: tmp/inc/styles.php:293
993
  msgid "Color of text inside this cell."
994
  msgstr ""
995
 
996
- #: tmp/inc/styles.php:298, tmp/inc/styles.php:329
997
  msgid "Links Color"
998
  msgstr ""
999
 
1000
- #: tmp/inc/styles.php:301
1001
  msgid "Color of links inside this cell."
1002
  msgstr ""
1003
 
1004
- #: tmp/inc/styles.php:324
 
 
 
 
 
 
 
 
1005
  msgid "Color of text inside this widget."
1006
  msgstr ""
1007
 
1008
- #: tmp/inc/styles.php:332
1009
  msgid "Color of links inside this widget."
1010
  msgstr ""
1011
 
@@ -1029,7 +1069,7 @@ msgstr ""
1029
  msgid "Displays content from the current post."
1030
  msgstr ""
1031
 
1032
- #: tmp/inc/widgets/post-content.php:60, tmp/inc/widgets/post-loop.php:269, tmp/widgets/widgets.php:608, tmp/widgets/widgets.php:783
1033
  msgid "None"
1034
  msgstr ""
1035
 
@@ -1069,51 +1109,51 @@ msgstr ""
1069
  msgid "More Link"
1070
  msgstr ""
1071
 
1072
- #: tmp/inc/widgets/post-loop.php:253, tmp/widgets/widgets.php:594
1073
  msgid "Post Type"
1074
  msgstr ""
1075
 
1076
- #: tmp/inc/widgets/post-loop.php:262, tmp/widgets/widgets.php:601
1077
  msgid "Posts Per Page"
1078
  msgstr ""
1079
 
1080
- #: tmp/inc/widgets/post-loop.php:267, tmp/widgets/widgets.php:606
1081
  msgid "Order By"
1082
  msgstr ""
1083
 
1084
- #: tmp/inc/widgets/post-loop.php:270, tmp/widgets/widgets.php:609
1085
  msgid "Post ID"
1086
  msgstr ""
1087
 
1088
- #: tmp/inc/widgets/post-loop.php:271, tmp/widgets/widgets.php:610
1089
  msgid "Author"
1090
  msgstr ""
1091
 
1092
- #: tmp/inc/widgets/post-loop.php:272, tmp/inc/widgets/post-loop.php:273, tmp/widgets/widgets.php:611, tmp/widgets/widgets.php:612, tmp/widgets/widgets/testimonial/testimonial.php:15
1093
  msgid "Name"
1094
  msgstr ""
1095
 
1096
- #: tmp/inc/widgets/post-loop.php:274, tmp/widgets/widgets.php:613
1097
  msgid "Date"
1098
  msgstr ""
1099
 
1100
- #: tmp/inc/widgets/post-loop.php:275, tmp/widgets/widgets.php:614
1101
  msgid "Modified"
1102
  msgstr ""
1103
 
1104
- #: tmp/inc/widgets/post-loop.php:276, tmp/widgets/widgets.php:615
1105
  msgid "Parent"
1106
  msgstr ""
1107
 
1108
- #: tmp/inc/widgets/post-loop.php:277, tmp/widgets/widgets.php:616
1109
  msgid "Random"
1110
  msgstr ""
1111
 
1112
- #: tmp/inc/widgets/post-loop.php:278, tmp/widgets/widgets.php:617
1113
  msgid "Comment Count"
1114
  msgstr ""
1115
 
1116
- #: tmp/inc/widgets/post-loop.php:279, tmp/widgets/widgets.php:618
1117
  msgid "Menu Order"
1118
  msgstr ""
1119
 
@@ -1121,31 +1161,31 @@ msgstr ""
1121
  msgid "Post In Order"
1122
  msgstr ""
1123
 
1124
- #: tmp/inc/widgets/post-loop.php:285, tmp/widgets/widgets.php:624
1125
  msgid "Order"
1126
  msgstr ""
1127
 
1128
- #: tmp/inc/widgets/post-loop.php:287, tmp/widgets/widgets.php:627
1129
  msgid "Descending"
1130
  msgstr ""
1131
 
1132
- #: tmp/inc/widgets/post-loop.php:288, tmp/widgets/widgets.php:626
1133
  msgid "Ascending"
1134
  msgstr ""
1135
 
1136
- #: tmp/inc/widgets/post-loop.php:293, tmp/widgets/widgets.php:633
1137
  msgid "Sticky Posts"
1138
  msgstr ""
1139
 
1140
- #: tmp/inc/widgets/post-loop.php:296, tmp/widgets/widgets.php:636
1141
  msgid "Ignore Sticky"
1142
  msgstr ""
1143
 
1144
- #: tmp/inc/widgets/post-loop.php:297, tmp/widgets/widgets.php:637
1145
  msgid "Exclude Sticky"
1146
  msgstr ""
1147
 
1148
- #: tmp/inc/widgets/post-loop.php:298, tmp/widgets/widgets.php:638
1149
  msgid "Only Sticky"
1150
  msgstr ""
1151
 
@@ -1153,7 +1193,7 @@ msgstr ""
1153
  msgid "Additional "
1154
  msgstr ""
1155
 
1156
- #: tmp/inc/widgets/post-loop.php:310, tmp/widgets/widgets.php:648
1157
  msgid "Additional query arguments. See 1{query_posts}."
1158
  msgstr ""
1159
 
@@ -1173,15 +1213,15 @@ msgstr ""
1173
  msgid "Save Settings"
1174
  msgstr ""
1175
 
1176
- #: tmp/siteorigin-panels.php:611
1177
  msgid "Read More"
1178
  msgstr ""
1179
 
1180
- #: tmp/siteorigin-panels.php:731
1181
  msgid "Edit Home Page"
1182
  msgstr ""
1183
 
1184
- #: tmp/siteorigin-panels.php:771, tmp/tpl/js-templates.php:67, tmp/tpl/js-templates.php:71
1185
  msgid "Live Editor"
1186
  msgstr ""
1187
 
@@ -1401,139 +1441,139 @@ msgstr ""
1401
  msgid "No Results"
1402
  msgstr ""
1403
 
1404
- #: tmp/widgets/widgets.php:161
1405
  msgid "This is a legacy widget. "
1406
  msgstr ""
1407
 
1408
- #: tmp/widgets/widgets.php:162
1409
  msgid "Ideally you should move to using widgets from the SiteOrigin Widgets Bundle instead. "
1410
  msgstr ""
1411
 
1412
- #: tmp/widgets/widgets.php:163
1413
  msgid "It'll be moved to a separate plugin after Page Builder 2.6 is released. "
1414
  msgstr ""
1415
 
1416
- #: tmp/widgets/widgets.php:220
1417
  msgid "Style"
1418
  msgstr ""
1419
 
1420
- #: tmp/widgets/widgets.php:244
1421
  msgid "%s Style"
1422
  msgstr ""
1423
 
1424
- #: tmp/widgets/widgets.php:644
1425
  msgid "Additional Arguments"
1426
  msgstr ""
1427
 
1428
- #: tmp/widgets/widgets.php:705
1429
  msgid "Gallery (PB)"
1430
  msgstr ""
1431
 
1432
- #: tmp/widgets/widgets.php:707
1433
  msgid "Displays a gallery."
1434
  msgstr ""
1435
 
1436
- #: tmp/widgets/widgets.php:746
1437
  msgid "Gallery Images"
1438
  msgstr ""
1439
 
1440
- #: tmp/widgets/widgets.php:747
1441
  msgid "edit gallery"
1442
  msgstr ""
1443
 
1444
- #: tmp/widgets/widgets.php:751
1445
  msgid "Comma separated attachment IDs. Defaults to all current page's attachments."
1446
  msgstr ""
1447
 
1448
- #: tmp/widgets/widgets.php:755
1449
  msgid "Image Size"
1450
  msgstr ""
1451
 
1452
- #: tmp/widgets/widgets.php:758
1453
  msgid "Large"
1454
  msgstr ""
1455
 
1456
- #: tmp/widgets/widgets.php:759
1457
  msgid "Medium"
1458
  msgstr ""
1459
 
1460
- #: tmp/widgets/widgets.php:760
1461
  msgid "Thumbnail"
1462
  msgstr ""
1463
 
1464
- #: tmp/widgets/widgets.php:761
1465
  msgid "Full"
1466
  msgstr ""
1467
 
1468
- #: tmp/widgets/widgets.php:769
1469
  msgid "Gallery Type"
1470
  msgstr ""
1471
 
1472
- #: tmp/widgets/widgets.php:774
1473
  msgid "Columns"
1474
  msgstr ""
1475
 
1476
- #: tmp/widgets/widgets.php:779
1477
  msgid "Link To"
1478
  msgstr ""
1479
 
1480
- #: tmp/widgets/widgets.php:781
1481
  msgid "Attachment Page"
1482
  msgstr ""
1483
 
1484
- #: tmp/widgets/widgets.php:782
1485
  msgid "File"
1486
  msgstr ""
1487
 
1488
- #: tmp/widgets/widgets.php:800
1489
  msgid "Image (PB)"
1490
  msgstr ""
1491
 
1492
- #: tmp/widgets/widgets.php:802
1493
  msgid "Displays a simple image."
1494
  msgstr ""
1495
 
1496
- #: tmp/widgets/widgets.php:835, tmp/widgets/widgets/animated-image/animated-image.php:15
1497
  msgid "Image URL"
1498
  msgstr ""
1499
 
1500
- #: tmp/widgets/widgets.php:839, tmp/widgets/widgets/button/button.php:19
1501
  msgid "Destination URL"
1502
  msgstr ""
1503
 
1504
- #: tmp/widgets/widgets.php:853
1505
  msgid "Embedded Video (PB)"
1506
  msgstr ""
1507
 
1508
- #: tmp/widgets/widgets.php:855
1509
  msgid "Embeds a video."
1510
  msgstr ""
1511
 
1512
- #: tmp/widgets/widgets.php:893
1513
  msgid "Video"
1514
  msgstr ""
1515
 
1516
- #: tmp/widgets/widgets.php:909
1517
  msgid "Self Hosted Video (PB)"
1518
  msgstr ""
1519
 
1520
- #: tmp/widgets/widgets.php:911
1521
  msgid "A self hosted video player."
1522
  msgstr ""
1523
 
1524
- #: tmp/widgets/widgets.php:953
1525
  msgid "Video URL"
1526
  msgstr ""
1527
 
1528
- #: tmp/widgets/widgets.php:957
1529
  msgid "Poster URL"
1530
  msgstr ""
1531
 
1532
- #: tmp/widgets/widgets.php:959
1533
  msgid "An image that displays before the video starts playing."
1534
  msgstr ""
1535
 
1536
- #: tmp/widgets/widgets.php:964
1537
  msgid "Auto Play Video"
1538
  msgstr ""
1539
 
17
  "X-Poedit-SearchPathExcluded-0: *.js\n"
18
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
 
20
+ #: tmp/inc/admin-layouts.php:79, tmp/inc/admin-layouts.php:437
21
  msgid "Layouts Directory"
22
  msgstr ""
23
 
24
+ #: tmp/inc/admin-layouts.php:365
25
  msgid "Invalid request."
26
  msgstr ""
27
 
28
+ #: tmp/inc/admin-layouts.php:395
29
  msgid "Theme Defined Layouts"
30
  msgstr ""
31
 
32
+ #: tmp/inc/admin-layouts.php:537
33
  msgid "Clone %s"
34
  msgstr ""
35
 
36
+ #: tmp/inc/admin-layouts.php:613
37
  msgid " - Results For:"
38
  msgstr ""
39
 
40
+ #: tmp/inc/admin-layouts.php:679
41
  msgid "Missing layout ID or no such layout exists"
42
  msgstr ""
43
 
44
+ #: tmp/inc/admin-layouts.php:771
45
  msgid "There was a problem fetching the layout. Please try again later."
46
  msgstr ""
47
 
48
+ #: tmp/inc/admin-widget-dialog.php:197, tmp/widgets/widgets.php:327
49
  msgid "Widgets Bundle"
50
  msgstr ""
51
 
97
  msgid "Addons"
98
  msgstr ""
99
 
100
+ #: tmp/inc/admin.php:285, tmp/inc/admin.php:1019, tmp/inc/admin.php:2105, tmp/inc/admin.php:2115, tmp/inc/settings.php:389, tmp/tpl/js-templates.php:399
101
  msgid "Page Builder"
102
  msgstr ""
103
 
325
  msgid "New Row"
326
  msgstr ""
327
 
328
+ #: tmp/inc/admin.php:815, tmp/inc/admin.php:831, tmp/inc/styles.php:367, tmp/tpl/js-templates.php:137
329
  msgid "Row"
330
  msgstr ""
331
 
345
  msgid "Add a {{%= items[0] %}}, {{%= items[1] %}} or {{%= items[2] %}} to get started."
346
  msgstr ""
347
 
348
+ #: tmp/inc/admin.php:829, tmp/inc/styles.php:633, tmp/tpl/js-templates.php:135
349
  msgid "Widget"
350
  msgstr ""
351
 
369
  msgid "Error uploading or importing file."
370
  msgstr ""
371
 
372
+ #: tmp/inc/admin.php:873
373
+ msgid "Unknown error. Failed to load the form. Please check your internet connection, contact your web site administrator, or try again later."
374
+ msgstr ""
375
+
376
+ #: tmp/inc/admin.php:1181, tmp/inc/home.php:26
377
  msgid "Home Page"
378
  msgstr ""
379
 
380
+ #: tmp/inc/admin.php:1369
381
  msgid "Untitled Widget"
382
  msgstr ""
383
 
384
+ #: tmp/inc/admin.php:1727
385
  msgid "You need to install 1{%1$s} to use the widget 2{%2$s}."
386
  msgstr ""
387
 
388
+ #: tmp/inc/admin.php:1739
389
  msgid "Save and reload this page to start using the widget after you've installed it."
390
  msgstr ""
391
 
392
+ #: tmp/inc/admin.php:1771
393
  msgid "The widget 1{%1$s} is not available. Please try locate and install the missing plugin. Post on the 2{support forums} if you need help."
394
  msgstr ""
395
 
396
+ #: tmp/inc/admin.php:2001, tmp/inc/styles-admin.php:45
397
+ msgid "The supplied nonce is invalid."
398
+ msgstr ""
399
+
400
+ #: tmp/inc/admin.php:2003, tmp/inc/styles-admin.php:47
401
+ msgid "Invalid nonce."
402
+ msgstr ""
403
+
404
+ #: tmp/inc/admin.php:2015
405
+ msgid "Please specify the type of widget form to be rendered."
406
+ msgstr ""
407
+
408
+ #: tmp/inc/admin.php:2017
409
+ msgid "Missing widget type."
410
+ msgstr ""
411
+
412
+ #: tmp/inc/admin.php:2139
413
  msgid "%s Widgets"
414
  msgstr ""
415
 
416
+ #: tmp/inc/admin.php:2231
417
  msgid "12 Page Builder Tips"
418
  msgstr ""
419
 
420
+ #: tmp/inc/admin.php:2237
421
  msgid "Sign up to our newsletter and we'll send you this free Page Builder video course."
422
  msgstr ""
423
 
424
+ #: tmp/inc/admin.php:2239
425
  msgid "12 tips that'll help you get the most out of Page Builder."
426
  msgstr ""
427
 
428
+ #: tmp/inc/admin.php:2241
429
  msgid "Watch the video to find out more, then sign up below to get started."
430
  msgstr ""
431
 
432
+ #: tmp/inc/admin.php:2243, tmp/inc/admin.php:2263
433
  msgid "We'll email you a confirmation. You can unsubscribe at any time."
434
  msgstr ""
435
 
436
+ #: tmp/inc/admin.php:2251
437
  msgid "Free Page Builder Addons"
438
  msgstr ""
439
 
440
+ #: tmp/inc/admin.php:2257
441
  msgid "The free animations addon allows you to add beautiful animations to Page Builder elements."
442
  msgstr ""
443
 
444
+ #: tmp/inc/admin.php:2259
445
  msgid "Sign up to our newsletter and we'll send you the addon as a free gift."
446
  msgstr ""
447
 
448
+ #: tmp/inc/admin.php:2261
449
  msgid "Plus, we'll send you even more powerful addons, for as long as you're subscribed."
450
  msgstr ""
451
 
452
+ #: tmp/inc/admin.php:2293
453
  msgid "Watch Intro Video"
454
  msgstr ""
455
 
456
+ #: tmp/inc/admin.php:2295
457
  msgid "Loaded from Vimeo Servers"
458
  msgstr ""
459
 
460
+ #: tmp/inc/admin.php:2297
461
  msgid "Please enter a valid email address."
462
  msgstr ""
463
 
464
+ #: tmp/inc/admin.php:2301
465
  msgid "Your Name"
466
  msgstr ""
467
 
468
+ #: tmp/inc/admin.php:2303
469
  msgid "Your Email"
470
  msgstr ""
471
 
472
+ #: tmp/inc/admin.php:2305
473
  msgid "Sign Up"
474
  msgstr ""
475
 
476
+ #: tmp/inc/admin.php:2307, tmp/tpl/js-templates.php:477
477
  msgid "Close"
478
  msgstr ""
479
 
480
+ #: tmp/inc/admin.php:2329
481
  msgid "Get a lightbox addon for SiteOrigin widgets"
482
  msgstr ""
483
 
484
+ #: tmp/inc/admin.php:2337
485
  msgid "Get the row, cell and widget animations addon"
486
  msgstr ""
487
 
488
+ #: tmp/inc/admin.php:2345
489
  msgid "Get premium email support for SiteOrigin Page Builder"
490
  msgstr ""
491
 
653
  msgid "Display recommend widgets in Page Builder add widget dialog."
654
  msgstr ""
655
 
656
+ #: tmp/inc/settings.php:657, tmp/inc/styles-admin.php:175
657
  msgid "Layout"
658
  msgstr ""
659
 
761
  msgid "Include styles into your Post Content. This keeps page layouts, even when Page Builder is deactivated."
762
  msgstr ""
763
 
764
+ #: tmp/inc/settings.php:925, tmp/inc/styles-admin.php:533
765
  msgid "Enabled"
766
  msgstr ""
767
 
768
+ #: tmp/inc/styles-admin.php:65
769
+ msgid "Please specify the type of style form to be rendered."
770
+ msgstr ""
771
+
772
+ #: tmp/inc/styles-admin.php:67
773
+ msgid "Missing style form type."
774
+ msgstr ""
775
+
776
+ #: tmp/inc/styles-admin.php:91
777
  msgid "Row Styles"
778
  msgstr ""
779
 
780
+ #: tmp/inc/styles-admin.php:101
781
  msgid "Cell%s Styles"
782
  msgstr ""
783
 
784
+ #: tmp/inc/styles-admin.php:109
785
  msgid "Widget Styles"
786
  msgstr ""
787
 
788
+ #: tmp/inc/styles-admin.php:167
789
  msgid "Attributes"
790
  msgstr ""
791
 
792
+ #: tmp/inc/styles-admin.php:183
793
  msgid "Design"
794
  msgstr ""
795
 
796
+ #: tmp/inc/styles-admin.php:203
797
  msgid "Theme"
798
  msgstr ""
799
 
800
+ #: tmp/inc/styles-admin.php:369, tmp/inc/styles.php:505, tmp/inc/styles.php:563
801
  msgid "Top"
802
  msgstr ""
803
 
804
+ #: tmp/inc/styles-admin.php:377, tmp/widgets/widgets/button/button.php:30
805
  msgid "Right"
806
  msgstr ""
807
 
808
+ #: tmp/inc/styles-admin.php:385, tmp/inc/styles.php:509, tmp/inc/styles.php:567
809
  msgid "Bottom"
810
  msgstr ""
811
 
812
+ #: tmp/inc/styles-admin.php:393, tmp/widgets/widgets/button/button.php:29
813
  msgid "Left"
814
  msgstr ""
815
 
816
+ #: tmp/inc/styles-admin.php:483
817
  msgid "Select Image"
818
  msgstr ""
819
 
820
+ #: tmp/inc/styles-admin.php:493
821
  msgid "Remove"
822
  msgstr ""
823
 
824
+ #: tmp/inc/styles-admin.php:499
825
+ msgid "External URL"
826
+ msgstr ""
827
+
828
+ #: tmp/inc/styles.php:157
829
  msgid "%s ID"
830
  msgstr ""
831
 
832
+ #: tmp/inc/styles.php:163
833
  msgid "A custom ID used for this %s."
834
  msgstr ""
835
 
836
+ #: tmp/inc/styles.php:173
837
  msgid "%s Class"
838
  msgstr ""
839
 
840
+ #: tmp/inc/styles.php:179
841
  msgid "A CSS class"
842
  msgstr ""
843
 
844
+ #: tmp/inc/styles.php:189
845
  msgid "CSS Styles"
846
  msgstr ""
847
 
848
+ #: tmp/inc/styles.php:195
849
  msgid "One style attribute per line."
850
  msgstr ""
851
 
852
+ #: tmp/inc/styles.php:205
853
  msgid "Mobile CSS Styles"
854
  msgstr ""
855
 
856
+ #: tmp/inc/styles.php:211
857
  msgid "CSS applied when in mobile view."
858
  msgstr ""
859
 
860
+ #: tmp/inc/styles.php:225
861
  msgid "Padding"
862
  msgstr ""
863
 
864
+ #: tmp/inc/styles.php:231
865
  msgid "Padding around the entire %s."
866
  msgstr ""
867
 
868
+ #: tmp/inc/styles.php:243
869
  msgid "Mobile Padding"
870
  msgstr ""
871
 
872
+ #: tmp/inc/styles.php:249
873
  msgid "Padding when on mobile devices."
874
  msgstr ""
875
 
876
+ #: tmp/inc/styles.php:265
877
  msgid "Background Color"
878
  msgstr ""
879
 
880
+ #: tmp/inc/styles.php:271
881
  msgid "Background color of the %s."
882
  msgstr ""
883
 
884
+ #: tmp/inc/styles.php:281
885
  msgid "Background Image"
886
  msgstr ""
887
 
888
+ #: tmp/inc/styles.php:287
889
  msgid "Background image of the %s."
890
  msgstr ""
891
 
892
+ #: tmp/inc/styles.php:297
893
  msgid "Background Image Display"
894
  msgstr ""
895
 
896
+ #: tmp/inc/styles.php:305
897
  msgid "Tiled Image"
898
  msgstr ""
899
 
900
+ #: tmp/inc/styles.php:307
901
  msgid "Cover"
902
  msgstr ""
903
 
904
+ #: tmp/inc/styles.php:309
905
  msgid "Centered, with original size"
906
  msgstr ""
907
 
908
+ #: tmp/inc/styles.php:311
909
  msgid "Fixed"
910
  msgstr ""
911
 
912
+ #: tmp/inc/styles.php:313
913
  msgid "Parallax"
914
  msgstr ""
915
 
916
+ #: tmp/inc/styles.php:315
917
  msgid "Parallax (Original Size)"
918
  msgstr ""
919
 
920
+ #: tmp/inc/styles.php:319
921
  msgid "How the background image is displayed."
922
  msgstr ""
923
 
924
+ #: tmp/inc/styles.php:329
925
  msgid "Border Color"
926
  msgstr ""
927
 
928
+ #: tmp/inc/styles.php:335
929
  msgid "Border color of the %s."
930
  msgstr ""
931
 
932
+ #: tmp/inc/styles.php:373
933
  msgid "Cell Class"
934
  msgstr ""
935
 
936
+ #: tmp/inc/styles.php:379
937
  msgid "Class added to all cells in this row."
938
  msgstr ""
939
 
940
+ #: tmp/inc/styles.php:393
941
  msgid "Bottom Margin"
942
  msgstr ""
943
 
944
+ #: tmp/inc/styles.php:399
945
  msgid "Space below the row. Default is %spx."
946
  msgstr ""
947
 
948
+ #: tmp/inc/styles.php:409
949
  msgid "Gutter"
950
  msgstr ""
951
 
952
+ #: tmp/inc/styles.php:415
953
  msgid "Amount of space between cells. Default is %spx."
954
  msgstr ""
955
 
956
+ #: tmp/inc/styles.php:425
957
  msgid "Row Layout"
958
  msgstr ""
959
 
960
+ #: tmp/inc/styles.php:433, tmp/inc/styles.php:457
961
  msgid "Standard"
962
  msgstr ""
963
 
964
+ #: tmp/inc/styles.php:435
965
  msgid "Full Width"
966
  msgstr ""
967
 
968
+ #: tmp/inc/styles.php:437
969
  msgid "Full Width Stretched"
970
  msgstr ""
971
 
972
+ #: tmp/inc/styles.php:449
973
  msgid "Collapse Behaviour"
974
  msgstr ""
975
 
976
+ #: tmp/inc/styles.php:459
977
  msgid "No Collapse"
978
  msgstr ""
979
 
980
+ #: tmp/inc/styles.php:471
981
  msgid "Collapse Order"
982
  msgstr ""
983
 
984
+ #: tmp/inc/styles.php:479, tmp/inc/widgets/post-loop.php:295, tmp/widgets/widgets.php:1269, tmp/widgets/widgets.php:1513
985
  msgid "Default"
986
  msgstr ""
987
 
988
+ #: tmp/inc/styles.php:481
989
  msgid "Left on Top"
990
  msgstr ""
991
 
992
+ #: tmp/inc/styles.php:483
993
  msgid "Right on Top"
994
  msgstr ""
995
 
996
+ #: tmp/inc/styles.php:497
997
  msgid "Cell Vertical Alignment"
998
  msgstr ""
999
 
1000
+ #: tmp/inc/styles.php:507, tmp/inc/styles.php:565, tmp/widgets/widgets/button/button.php:31
1001
  msgid "Center"
1002
  msgstr ""
1003
 
1004
+ #: tmp/inc/styles.php:511, tmp/inc/styles.php:569
1005
  msgid "Stretch"
1006
  msgstr ""
1007
 
1008
+ #: tmp/inc/styles.php:547
1009
  msgid "Cell"
1010
  msgstr ""
1011
 
1012
+ #: tmp/inc/styles.php:553
1013
  msgid "Vertical Alignment"
1014
  msgstr ""
1015
 
1016
+ #: tmp/inc/styles.php:561
1017
  msgid "Use row setting"
1018
  msgstr ""
1019
 
1020
+ #: tmp/inc/styles.php:581, tmp/inc/styles.php:661
1021
  msgid "Font Color"
1022
  msgstr ""
1023
 
1024
+ #: tmp/inc/styles.php:587
1025
  msgid "Color of text inside this cell."
1026
  msgstr ""
1027
 
1028
+ #: tmp/inc/styles.php:597, tmp/inc/styles.php:677
1029
  msgid "Links Color"
1030
  msgstr ""
1031
 
1032
+ #: tmp/inc/styles.php:603
1033
  msgid "Color of links inside this cell."
1034
  msgstr ""
1035
 
1036
+ #: tmp/inc/styles.php:639
1037
+ msgid "Margin"
1038
+ msgstr ""
1039
+
1040
+ #: tmp/inc/styles.php:645
1041
+ msgid "Margins around the widget."
1042
+ msgstr ""
1043
+
1044
+ #: tmp/inc/styles.php:667
1045
  msgid "Color of text inside this widget."
1046
  msgstr ""
1047
 
1048
+ #: tmp/inc/styles.php:683
1049
  msgid "Color of links inside this widget."
1050
  msgstr ""
1051
 
1069
  msgid "Displays content from the current post."
1070
  msgstr ""
1071
 
1072
+ #: tmp/inc/widgets/post-content.php:60, tmp/inc/widgets/post-loop.php:269, tmp/widgets/widgets.php:1215, tmp/widgets/widgets.php:1565
1073
  msgid "None"
1074
  msgstr ""
1075
 
1109
  msgid "More Link"
1110
  msgstr ""
1111
 
1112
+ #: tmp/inc/widgets/post-loop.php:253, tmp/widgets/widgets.php:1187
1113
  msgid "Post Type"
1114
  msgstr ""
1115
 
1116
+ #: tmp/inc/widgets/post-loop.php:262, tmp/widgets/widgets.php:1201
1117
  msgid "Posts Per Page"
1118
  msgstr ""
1119
 
1120
+ #: tmp/inc/widgets/post-loop.php:267, tmp/widgets/widgets.php:1211
1121
  msgid "Order By"
1122
  msgstr ""
1123
 
1124
+ #: tmp/inc/widgets/post-loop.php:270, tmp/widgets/widgets.php:1217
1125
  msgid "Post ID"
1126
  msgstr ""
1127
 
1128
+ #: tmp/inc/widgets/post-loop.php:271, tmp/widgets/widgets.php:1219
1129
  msgid "Author"
1130
  msgstr ""
1131
 
1132
+ #: tmp/inc/widgets/post-loop.php:272, tmp/inc/widgets/post-loop.php:273, tmp/widgets/widgets.php:1221, tmp/widgets/widgets.php:1223, tmp/widgets/widgets/testimonial/testimonial.php:15
1133
  msgid "Name"
1134
  msgstr ""
1135
 
1136
+ #: tmp/inc/widgets/post-loop.php:274, tmp/widgets/widgets.php:1225
1137
  msgid "Date"
1138
  msgstr ""
1139
 
1140
+ #: tmp/inc/widgets/post-loop.php:275, tmp/widgets/widgets.php:1227
1141
  msgid "Modified"
1142
  msgstr ""
1143
 
1144
+ #: tmp/inc/widgets/post-loop.php:276, tmp/widgets/widgets.php:1229
1145
  msgid "Parent"
1146
  msgstr ""
1147
 
1148
+ #: tmp/inc/widgets/post-loop.php:277, tmp/widgets/widgets.php:1231
1149
  msgid "Random"
1150
  msgstr ""
1151
 
1152
+ #: tmp/inc/widgets/post-loop.php:278, tmp/widgets/widgets.php:1233
1153
  msgid "Comment Count"
1154
  msgstr ""
1155
 
1156
+ #: tmp/inc/widgets/post-loop.php:279, tmp/widgets/widgets.php:1235
1157
  msgid "Menu Order"
1158
  msgstr ""
1159
 
1161
  msgid "Post In Order"
1162
  msgstr ""
1163
 
1164
+ #: tmp/inc/widgets/post-loop.php:285, tmp/widgets/widgets.php:1247
1165
  msgid "Order"
1166
  msgstr ""
1167
 
1168
+ #: tmp/inc/widgets/post-loop.php:287, tmp/widgets/widgets.php:1253
1169
  msgid "Descending"
1170
  msgstr ""
1171
 
1172
+ #: tmp/inc/widgets/post-loop.php:288, tmp/widgets/widgets.php:1251
1173
  msgid "Ascending"
1174
  msgstr ""
1175
 
1176
+ #: tmp/inc/widgets/post-loop.php:293, tmp/widgets/widgets.php:1265
1177
  msgid "Sticky Posts"
1178
  msgstr ""
1179
 
1180
+ #: tmp/inc/widgets/post-loop.php:296, tmp/widgets/widgets.php:1271
1181
  msgid "Ignore Sticky"
1182
  msgstr ""
1183
 
1184
+ #: tmp/inc/widgets/post-loop.php:297, tmp/widgets/widgets.php:1273
1185
  msgid "Exclude Sticky"
1186
  msgstr ""
1187
 
1188
+ #: tmp/inc/widgets/post-loop.php:298, tmp/widgets/widgets.php:1275
1189
  msgid "Only Sticky"
1190
  msgstr ""
1191
 
1193
  msgid "Additional "
1194
  msgstr ""
1195
 
1196
+ #: tmp/inc/widgets/post-loop.php:310, tmp/widgets/widgets.php:1295
1197
  msgid "Additional query arguments. See 1{query_posts}."
1198
  msgstr ""
1199
 
1213
  msgid "Save Settings"
1214
  msgstr ""
1215
 
1216
+ #: tmp/siteorigin-panels.php:623
1217
  msgid "Read More"
1218
  msgstr ""
1219
 
1220
+ #: tmp/siteorigin-panels.php:755
1221
  msgid "Edit Home Page"
1222
  msgstr ""
1223
 
1224
+ #: tmp/siteorigin-panels.php:795, tmp/tpl/js-templates.php:67, tmp/tpl/js-templates.php:71
1225
  msgid "Live Editor"
1226
  msgstr ""
1227
 
1441
  msgid "No Results"
1442
  msgstr ""
1443
 
1444
+ #: tmp/widgets/widgets.php:321
1445
  msgid "This is a legacy widget. "
1446
  msgstr ""
1447
 
1448
+ #: tmp/widgets/widgets.php:323
1449
  msgid "Ideally you should move to using widgets from the SiteOrigin Widgets Bundle instead. "
1450
  msgstr ""
1451
 
1452
+ #: tmp/widgets/widgets.php:325
1453
  msgid "It'll be moved to a separate plugin after Page Builder 2.6 is released. "
1454
  msgstr ""
1455
 
1456
+ #: tmp/widgets/widgets.php:439
1457
  msgid "Style"
1458
  msgstr ""
1459
 
1460
+ #: tmp/widgets/widgets.php:487
1461
  msgid "%s Style"
1462
  msgstr ""
1463
 
1464
+ #: tmp/widgets/widgets.php:1287
1465
  msgid "Additional Arguments"
1466
  msgstr ""
1467
 
1468
+ #: tmp/widgets/widgets.php:1409
1469
  msgid "Gallery (PB)"
1470
  msgstr ""
1471
 
1472
+ #: tmp/widgets/widgets.php:1413
1473
  msgid "Displays a gallery."
1474
  msgstr ""
1475
 
1476
+ #: tmp/widgets/widgets.php:1491
1477
  msgid "Gallery Images"
1478
  msgstr ""
1479
 
1480
+ #: tmp/widgets/widgets.php:1493
1481
  msgid "edit gallery"
1482
  msgstr ""
1483
 
1484
+ #: tmp/widgets/widgets.php:1501
1485
  msgid "Comma separated attachment IDs. Defaults to all current page's attachments."
1486
  msgstr ""
1487
 
1488
+ #: tmp/widgets/widgets.php:1509
1489
  msgid "Image Size"
1490
  msgstr ""
1491
 
1492
+ #: tmp/widgets/widgets.php:1515
1493
  msgid "Large"
1494
  msgstr ""
1495
 
1496
+ #: tmp/widgets/widgets.php:1517
1497
  msgid "Medium"
1498
  msgstr ""
1499
 
1500
+ #: tmp/widgets/widgets.php:1519
1501
  msgid "Thumbnail"
1502
  msgstr ""
1503
 
1504
+ #: tmp/widgets/widgets.php:1521
1505
  msgid "Full"
1506
  msgstr ""
1507
 
1508
+ #: tmp/widgets/widgets.php:1537
1509
  msgid "Gallery Type"
1510
  msgstr ""
1511
 
1512
+ #: tmp/widgets/widgets.php:1547
1513
  msgid "Columns"
1514
  msgstr ""
1515
 
1516
+ #: tmp/widgets/widgets.php:1557
1517
  msgid "Link To"
1518
  msgstr ""
1519
 
1520
+ #: tmp/widgets/widgets.php:1561
1521
  msgid "Attachment Page"
1522
  msgstr ""
1523
 
1524
+ #: tmp/widgets/widgets.php:1563
1525
  msgid "File"
1526
  msgstr ""
1527
 
1528
+ #: tmp/widgets/widgets.php:1599
1529
  msgid "Image (PB)"
1530
  msgstr ""
1531
 
1532
+ #: tmp/widgets/widgets.php:1603
1533
  msgid "Displays a simple image."
1534
  msgstr ""
1535
 
1536
+ #: tmp/widgets/widgets.php:1669, tmp/widgets/widgets/animated-image/animated-image.php:15
1537
  msgid "Image URL"
1538
  msgstr ""
1539
 
1540
+ #: tmp/widgets/widgets.php:1677, tmp/widgets/widgets/button/button.php:19
1541
  msgid "Destination URL"
1542
  msgstr ""
1543
 
1544
+ #: tmp/widgets/widgets.php:1705
1545
  msgid "Embedded Video (PB)"
1546
  msgstr ""
1547
 
1548
+ #: tmp/widgets/widgets.php:1709
1549
  msgid "Embeds a video."
1550
  msgstr ""
1551
 
1552
+ #: tmp/widgets/widgets.php:1785
1553
  msgid "Video"
1554
  msgstr ""
1555
 
1556
+ #: tmp/widgets/widgets.php:1817
1557
  msgid "Self Hosted Video (PB)"
1558
  msgstr ""
1559
 
1560
+ #: tmp/widgets/widgets.php:1821
1561
  msgid "A self hosted video player."
1562
  msgstr ""
1563
 
1564
+ #: tmp/widgets/widgets.php:1905
1565
  msgid "Video URL"
1566
  msgstr ""
1567
 
1568
+ #: tmp/widgets/widgets.php:1913
1569
  msgid "Poster URL"
1570
  msgstr ""
1571
 
1572
+ #: tmp/widgets/widgets.php:1917
1573
  msgid "An image that displays before the video starts playing."
1574
  msgstr ""
1575
 
1576
+ #: tmp/widgets/widgets.php:1927
1577
  msgid "Auto Play Video"
1578
  msgstr ""
1579
 
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Page Builder by SiteOrigin ===
2
  Tags: page builder, responsive, widget, widgets, builder, page, admin, gallery, content, cms, pages, post, css, layout, grid
3
  Requires at least: 4.4
4
- Tested up to: 4.9.5
5
- Stable tag: 2.6.4
6
- Build time: 2018-04-04T19:32:31+02:00
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl.html
9
  Donate link: https://siteorigin.com/downloads/contribution/
@@ -96,6 +96,14 @@ We've tried to ensure that Page Builder is compatible with most plugin widgets.
96
 
97
  == Changelog ==
98
 
 
 
 
 
 
 
 
 
99
  = 2.6.4 - 4 April 2018 =
100
  * Only call widget `enqueue_admin_scripts` function for WP core JS widgets.
101
 
1
  === Page Builder by SiteOrigin ===
2
  Tags: page builder, responsive, widget, widgets, builder, page, admin, gallery, content, cms, pages, post, css, layout, grid
3
  Requires at least: 4.4
4
+ Tested up to: 4.9
5
+ Stable tag: 2.6.5
6
+ Build time: 2018-04-23T10:13:48+02:00
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl.html
9
  Donate link: https://siteorigin.com/downloads/contribution/
96
 
97
  == Changelog ==
98
 
99
+ = 2.6.5 - 23 April 2018 =
100
+ * Don't use `mime_content_type` for external layouts if it's not available. Just check file extensions.
101
+ * Get correct ID for WooCommerce shop page to allow PB to render correctly.
102
+ * Added image fallback url field for background images in row, cell and widget styles.
103
+ * Temporarily remove Jetpack widgets requiring scripts for admin form, until we can reliably enqueue their scripts.
104
+ * Remove loading indicator and display message when loading widget and style forms fail.
105
+ * Allow setting margins around specific widgets.
106
+
107
  = 2.6.4 - 4 April 2018 =
108
  * Only call widget `enqueue_admin_scripts` function for WP core JS widgets.
109
 
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.6.4
7
  Author: SiteOrigin
8
  Author URI: https://siteorigin.com
9
  License: GPL3
@@ -11,12 +11,12 @@ License URI: http://www.gnu.org/licenses/gpl.html
11
  Donate link: http://siteorigin.com/page-builder/#donate
12
  */
13
 
14
- define( 'SITEORIGIN_PANELS_VERSION', '2.6.4' );
15
  if ( ! defined( 'SITEORIGIN_PANELS_JS_SUFFIX' ) ) {
16
  define( 'SITEORIGIN_PANELS_JS_SUFFIX', '.min' );
17
  }
18
  define( 'SITEORIGIN_PANELS_CSS_SUFFIX', '.min' );
19
- define( 'SITEORIGIN_PANELS_VERSION_SUFFIX', '-264' );
20
 
21
  require_once plugin_dir_path( __FILE__ ) . 'inc/functions.php';
22
 
@@ -65,6 +65,7 @@ class SiteOrigin_Panels {
65
 
66
  // We need to generate fresh post content
67
  add_filter( 'the_content', array( $this, 'generate_post_content' ) );
 
68
  add_filter( 'wp_enqueue_scripts', array( $this, 'generate_post_css' ) );
69
 
70
  // Content cache has been removed. SiteOrigin_Panels_Cache_Renderer just deletes any existing caches.
@@ -275,6 +276,11 @@ class SiteOrigin_Panels {
275
  }
276
 
277
  $post_id = get_the_ID();
 
 
 
 
 
278
  // If we're viewing a preview make sure we load and render the autosave post's meta.
279
  if ( $preview ) {
280
  $preview_post = wp_get_post_autosave( $post_id, get_current_user_id() );
@@ -320,9 +326,15 @@ class SiteOrigin_Panels {
320
  * Generate CSS for the current post
321
  */
322
  public function generate_post_css() {
323
- if( is_singular() && get_post_meta( get_the_ID(), 'panels_data', true ) ) {
 
 
 
 
 
 
324
  $renderer = SiteOrigin_Panels::renderer();
325
- $renderer->add_inline_css( get_the_ID(), $renderer->generate_css( get_the_ID() ) );
326
  }
327
  }
328
 
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.6.5
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.6.5' );
15
  if ( ! defined( 'SITEORIGIN_PANELS_JS_SUFFIX' ) ) {
16
  define( 'SITEORIGIN_PANELS_JS_SUFFIX', '.min' );
17
  }
18
  define( 'SITEORIGIN_PANELS_CSS_SUFFIX', '.min' );
19
+ define( 'SITEORIGIN_PANELS_VERSION_SUFFIX', '-265' );
20
 
21
  require_once plugin_dir_path( __FILE__ ) . 'inc/functions.php';
22
 
65
 
66
  // We need to generate fresh post content
67
  add_filter( 'the_content', array( $this, 'generate_post_content' ) );
68
+ add_filter( 'woocommerce_format_content', array( $this, 'generate_post_content' ) );
69
  add_filter( 'wp_enqueue_scripts', array( $this, 'generate_post_css' ) );
70
 
71
  // Content cache has been removed. SiteOrigin_Panels_Cache_Renderer just deletes any existing caches.
276
  }
277
 
278
  $post_id = get_the_ID();
279
+
280
+ if ( class_exists( 'WooCommerce' ) && is_shop() ) {
281
+ $post_id = wc_get_page_id( 'shop' );
282
+ }
283
+
284
  // If we're viewing a preview make sure we load and render the autosave post's meta.
285
  if ( $preview ) {
286
  $preview_post = wp_get_post_autosave( $post_id, get_current_user_id() );
326
  * Generate CSS for the current post
327
  */
328
  public function generate_post_css() {
329
+ $post_id = get_the_ID();
330
+
331
+ if ( class_exists( 'WooCommerce' ) && is_shop() ) {
332
+ $post_id = wc_get_page_id( 'shop' );
333
+ }
334
+
335
+ if( is_singular() && get_post_meta( $post_id, 'panels_data', true ) ) {
336
  $renderer = SiteOrigin_Panels::renderer();
337
+ $renderer->add_inline_css( $post_id, $renderer->generate_css( $post_id ) );
338
  }
339
  }
340
 
widgets/lib/lessc.inc.php CHANGED
@@ -1,3473 +1,3473 @@
1
- <?php
2
-
3
- /**
4
- * lessphp v0.3.9
5
- * http://leafo.net/lessphp
6
- *
7
- * LESS css compiler, adapted from http://lesscss.org
8
- *
9
- * Copyright 2012, Leaf Corcoran <leafot@gmail.com>
10
- * Licensed under MIT or GPLv3, see LICENSE
11
- */
12
-
13
-
14
- /**
15
- * The less compiler and parser.
16
- *
17
- * Converting LESS to CSS is a three stage process. The incoming file is parsed
18
- * by `lessc_parser` into a syntax tree, then it is compiled into another tree
19
- * representing the CSS structure by `lessc`. The CSS tree is fed into a
20
- * formatter, like `lessc_formatter` which then outputs CSS as a string.
21
- *
22
- * During the first compile, all values are *reduced*, which means that their
23
- * types are brought to the lowest form before being dump as strings. This
24
- * handles math equations, variable dereferences, and the like.
25
- *
26
- * The `parse` function of `lessc` is the entry point.
27
- *
28
- * In summary:
29
- *
30
- * The `lessc` class creates an intstance of the parser, feeds it LESS code,
31
- * then transforms the resulting tree to a CSS tree. This class also holds the
32
- * evaluation context, such as all available mixins and variables at any given
33
- * time.
34
- *
35
- * The `lessc_parser` class is only concerned with parsing its input.
36
- *
37
- * The `lessc_formatter` takes a CSS tree, and dumps it to a formatted string,
38
- * handling things like indentation.
39
- */
40
- class lessc {
41
- static public $VERSION = "v0.3.9";
42
- static protected $TRUE = array("keyword", "true");
43
- static protected $FALSE = array("keyword", "false");
44
-
45
- protected $libFunctions = array();
46
- protected $registeredVars = array();
47
- protected $preserveComments = false;
48
-
49
- public $vPrefix = '@'; // prefix of abstract properties
50
- public $mPrefix = '$'; // prefix of abstract blocks
51
- public $parentSelector = '&';
52
-
53
- public $importDisabled = false;
54
- public $importDir = '';
55
-
56
- protected $numberPrecision = null;
57
-
58
- // set to the parser that generated the current line when compiling
59
- // so we know how to create error messages
60
- protected $sourceParser = null;
61
- protected $sourceLoc = null;
62
-
63
- static public $defaultValue = array("keyword", "");
64
-
65
- static protected $nextImportId = 0; // uniquely identify imports
66
-
67
- // attempts to find the path of an import url, returns null for css files
68
- protected function findImport($url) {
69
- foreach ((array)$this->importDir as $dir) {
70
- $full = $dir.(substr($dir, -1) != '/' ? '/' : '').$url;
71
- if ($this->fileExists($file = $full.'.less') || $this->fileExists($file = $full)) {
72
- return $file;
73
- }
74
- }
75
-
76
- return null;
77
- }
78
-
79
- protected function fileExists($name) {
80
- return is_file($name);
81
- }
82
-
83
- static public function compressList($items, $delim) {
84
- if (!isset($items[1]) && isset($items[0])) return $items[0];
85
- else return array('list', $delim, $items);
86
- }
87
-
88
- static public function preg_quote($what) {
89
- return preg_quote($what, '/');
90
- }
91
-
92
- protected function tryImport($importPath, $parentBlock, $out) {
93
- if ($importPath[0] == "function" && $importPath[1] == "url") {
94
- $importPath = $this->flattenList($importPath[2]);
95
- }
96
-
97
- $str = $this->coerceString($importPath);
98
- if ($str === null) return false;
99
-
100
- $url = $this->compileValue($this->lib_e($str));
101
-
102
- // don't import if it ends in css
103
- if (substr_compare($url, '.css', -4, 4) === 0) return false;
104
-
105
- $realPath = $this->findImport($url);
106
- if ($realPath === null) return false;
107
-
108
- if ($this->importDisabled) {
109
- return array(false, "/* import disabled */");
110
- }
111
-
112
- $this->addParsedFile($realPath);
113
- $parser = $this->makeParser($realPath);
114
- $root = $parser->parse(file_get_contents($realPath));
115
-
116
- // set the parents of all the block props
117
- foreach ($root->props as $prop) {
118
- if ($prop[0] == "block") {
119
- $prop[1]->parent = $parentBlock;
120
- }
121
- }
122
-
123
- // copy mixins into scope, set their parents
124
- // bring blocks from import into current block
125
- // TODO: need to mark the source parser these came from this file
126
- foreach ($root->children as $childName => $child) {
127
- if (isset($parentBlock->children[$childName])) {
128
- $parentBlock->children[$childName] = array_merge(
129
- $parentBlock->children[$childName],
130
- $child);
131
- } else {
132
- $parentBlock->children[$childName] = $child;
133
- }
134
- }
135
-
136
- $pi = pathinfo($realPath);
137
- $dir = $pi["dirname"];
138
-
139
- list($top, $bottom) = $this->sortProps($root->props, true);
140
- $this->compileImportedProps($top, $parentBlock, $out, $parser, $dir);
141
-
142
- return array(true, $bottom, $parser, $dir);
143
- }
144
-
145
- protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir) {
146
- $oldSourceParser = $this->sourceParser;
147
-
148
- $oldImport = $this->importDir;
149
-
150
- // TODO: this is because the importDir api is stupid
151
- $this->importDir = (array)$this->importDir;
152
- array_unshift($this->importDir, $importDir);
153
-
154
- foreach ($props as $prop) {
155
- $this->compileProp($prop, $block, $out);
156
- }
157
-
158
- $this->importDir = $oldImport;
159
- $this->sourceParser = $oldSourceParser;
160
- }
161
-
162
- /**
163
- * Recursively compiles a block.
164
- *
165
- * A block is analogous to a CSS block in most cases. A single LESS document
166
- * is encapsulated in a block when parsed, but it does not have parent tags
167
- * so all of it's children appear on the root level when compiled.
168
- *
169
- * Blocks are made up of props and children.
170
- *
171
- * Props are property instructions, array tuples which describe an action
172
- * to be taken, eg. write a property, set a variable, mixin a block.
173
- *
174
- * The children of a block are just all the blocks that are defined within.
175
- * This is used to look up mixins when performing a mixin.
176
- *
177
- * Compiling the block involves pushing a fresh environment on the stack,
178
- * and iterating through the props, compiling each one.
179
- *
180
- * See lessc::compileProp()
181
- *
182
- */
183
- protected function compileBlock($block) {
184
- switch ($block->type) {
185
- case "root":
186
- $this->compileRoot($block);
187
- break;
188
- case null:
189
- $this->compileCSSBlock($block);
190
- break;
191
- case "media":
192
- $this->compileMedia($block);
193
- break;
194
- case "directive":
195
- $name = "@" . $block->name;
196
- if (!empty($block->value)) {
197
- $name .= " " . $this->compileValue($this->reduce($block->value));
198
- }
199
-
200
- $this->compileNestedBlock($block, array($name));
201
- break;
202
- default:
203
- $this->throwError("unknown block type: $block->type\n");
204
- }
205
- }
206
-
207
- protected function compileCSSBlock($block) {
208
- $env = $this->pushEnv();
209
-
210
- $selectors = $this->compileSelectors($block->tags);
211
- $env->selectors = $this->multiplySelectors($selectors);
212
- $out = $this->makeOutputBlock(null, $env->selectors);
213
-
214
- $this->scope->children[] = $out;
215
- $this->compileProps($block, $out);
216
-
217
- $block->scope = $env; // mixins carry scope with them!
218
- $this->popEnv();
219
- }
220
-
221
- protected function compileMedia($media) {
222
- $env = $this->pushEnv($media);
223
- $parentScope = $this->mediaParent($this->scope);
224
-
225
- $query = $this->compileMediaQuery($this->multiplyMedia($env));
226
-
227
- $this->scope = $this->makeOutputBlock($media->type, array($query));
228
- $parentScope->children[] = $this->scope;
229
-
230
- $this->compileProps($media, $this->scope);
231
-
232
- if (count($this->scope->lines) > 0) {
233
- $orphanSelelectors = $this->findClosestSelectors();
234
- if (!is_null($orphanSelelectors)) {
235
- $orphan = $this->makeOutputBlock(null, $orphanSelelectors);
236
- $orphan->lines = $this->scope->lines;
237
- array_unshift($this->scope->children, $orphan);
238
- $this->scope->lines = array();
239
- }
240
- }
241
-
242
- $this->scope = $this->scope->parent;
243
- $this->popEnv();
244
- }
245
-
246
- protected function mediaParent($scope) {
247
- while (!empty($scope->parent)) {
248
- if (!empty($scope->type) && $scope->type != "media") {
249
- break;
250
- }
251
- $scope = $scope->parent;
252
- }
253
-
254
- return $scope;
255
- }
256
-
257
- protected function compileNestedBlock($block, $selectors) {
258
- $this->pushEnv($block);
259
- $this->scope = $this->makeOutputBlock($block->type, $selectors);
260
- $this->scope->parent->children[] = $this->scope;
261
-
262
- $this->compileProps($block, $this->scope);
263
-
264
- $this->scope = $this->scope->parent;
265
- $this->popEnv();
266
- }
267
-
268
- protected function compileRoot($root) {
269
- $this->pushEnv();
270
- $this->scope = $this->makeOutputBlock($root->type);
271
- $this->compileProps($root, $this->scope);
272
- $this->popEnv();
273
- }
274
-
275
- protected function compileProps($block, $out) {
276
- foreach ($this->sortProps($block->props) as $prop) {
277
- $this->compileProp($prop, $block, $out);
278
- }
279
- }
280
-
281
- protected function sortProps($props, $split = false) {
282
- $vars = array();
283
- $imports = array();
284
- $other = array();
285
-
286
- foreach ($props as $prop) {
287
- switch ($prop[0]) {
288
- case "assign":
289
- if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) {
290
- $vars[] = $prop;
291
- } else {
292
- $other[] = $prop;
293
- }
294
- break;
295
- case "import":
296
- $id = self::$nextImportId++;
297
- $prop[] = $id;
298
- $imports[] = $prop;
299
- $other[] = array("import_mixin", $id);
300
- break;
301
- default:
302
- $other[] = $prop;
303
- }
304
- }
305
-
306
- if ($split) {
307
- return array(array_merge($vars, $imports), $other);
308
- } else {
309
- return array_merge($vars, $imports, $other);
310
- }
311
- }
312
-
313
- protected function compileMediaQuery($queries) {
314
- $compiledQueries = array();
315
- foreach ($queries as $query) {
316
- $parts = array();
317
- foreach ($query as $q) {
318
- switch ($q[0]) {
319
- case "mediaType":
320
- $parts[] = implode(" ", array_slice($q, 1));
321
- break;
322
- case "mediaExp":
323
- if (isset($q[2])) {
324
- $parts[] = "($q[1]: " .
325
- $this->compileValue($this->reduce($q[2])) . ")";
326
- } else {
327
- $parts[] = "($q[1])";
328
- }
329
- break;
330
- case "variable":
331
- $parts[] = $this->compileValue($this->reduce($q));
332
- break;
333
- }
334
- }
335
-
336
- if (count($parts) > 0) {
337
- $compiledQueries[] = implode(" and ", $parts);
338
- }
339
- }
340
-
341
- $out = "@media";
342
- if (!empty($parts)) {
343
- $out .= " " .
344
- implode($this->formatter->selectorSeparator, $compiledQueries);
345
- }
346
- return $out;
347
- }
348
-
349
- protected function multiplyMedia($env, $childQueries = null) {
350
- if (is_null($env) ||
351
- !empty($env->block->type) && $env->block->type != "media")
352
- {
353
- return $childQueries;
354
- }
355
-
356
- // plain old block, skip
357
- if (empty($env->block->type)) {
358
- return $this->multiplyMedia($env->parent, $childQueries);
359
- }
360
-
361
- $out = array();
362
- $queries = $env->block->queries;
363
- if (is_null($childQueries)) {
364
- $out = $queries;
365
- } else {
366
- foreach ($queries as $parent) {
367
- foreach ($childQueries as $child) {
368
- $out[] = array_merge($parent, $child);
369
- }
370
- }
371
- }
372
-
373
- return $this->multiplyMedia($env->parent, $out);
374
- }
375
-
376
- protected function expandParentSelectors(&$tag, $replace) {
377
- $parts = explode("$&$", $tag);
378
- $count = 0;
379
- foreach ($parts as &$part) {
380
- $part = str_replace($this->parentSelector, $replace, $part, $c);
381
- $count += $c;
382
- }
383
- $tag = implode($this->parentSelector, $parts);
384
- return $count;
385
- }
386
-
387
- protected function findClosestSelectors() {
388
- $env = $this->env;
389
- $selectors = null;
390
- while ($env !== null) {
391
- if (isset($env->selectors)) {
392
- $selectors = $env->selectors;
393
- break;
394
- }
395
- $env = $env->parent;
396
- }
397
-
398
- return $selectors;
399
- }
400
-
401
-
402
- // multiply $selectors against the nearest selectors in env
403
- protected function multiplySelectors($selectors) {
404
- // find parent selectors
405
-
406
- $parentSelectors = $this->findClosestSelectors();
407
- if (is_null($parentSelectors)) {
408
- // kill parent reference in top level selector
409
- foreach ($selectors as &$s) {
410
- $this->expandParentSelectors($s, "");
411
- }
412
-
413
- return $selectors;
414
- }
415
-
416
- $out = array();
417
- foreach ($parentSelectors as $parent) {
418
- foreach ($selectors as $child) {
419
- $count = $this->expandParentSelectors($child, $parent);
420
-
421
- // don't prepend the parent tag if & was used
422
- if ($count > 0) {
423
- $out[] = trim($child);
424
- } else {
425
- $out[] = trim($parent . ' ' . $child);
426
- }
427
- }
428
- }
429
-
430
- return $out;
431
- }
432
-
433
- // reduces selector expressions
434
- protected function compileSelectors($selectors) {
435
- $out = array();
436
-
437
- foreach ($selectors as $s) {
438
- if (is_array($s)) {
439
- list(, $value) = $s;
440
- $out[] = trim($this->compileValue($this->reduce($value)));
441
- } else {
442
- $out[] = $s;
443
- }
444
- }
445
-
446
- return $out;
447
- }
448
-
449
- protected function eq($left, $right) {
450
- return $left == $right;
451
- }
452
-
453
- protected function patternMatch($block, $callingArgs) {
454
- // match the guards if it has them
455
- // any one of the groups must have all its guards pass for a match
456
- if (!empty($block->guards)) {
457
- $groupPassed = false;
458
- foreach ($block->guards as $guardGroup) {
459
- foreach ($guardGroup as $guard) {
460
- $this->pushEnv();
461
- $this->zipSetArgs($block->args, $callingArgs);
462
-
463
- $negate = false;
464
- if ($guard[0] == "negate") {
465
- $guard = $guard[1];
466
- $negate = true;
467
- }
468
-
469
- $passed = $this->reduce($guard) == self::$TRUE;
470
- if ($negate) $passed = !$passed;
471
-
472
- $this->popEnv();
473
-
474
- if ($passed) {
475
- $groupPassed = true;
476
- } else {
477
- $groupPassed = false;
478
- break;
479
- }
480
- }
481
-
482
- if ($groupPassed) break;
483
- }
484
-
485
- if (!$groupPassed) {
486
- return false;
487
- }
488
- }
489
-
490
- $numCalling = count($callingArgs);
491
-
492
- if (empty($block->args)) {
493
- return $block->isVararg || $numCalling == 0;
494
- }
495
-
496
- $i = -1; // no args
497
- // try to match by arity or by argument literal
498
- foreach ($block->args as $i => $arg) {
499
- switch ($arg[0]) {
500
- case "lit":
501
- if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i])) {
502
- return false;
503
- }
504
- break;
505
- case "arg":
506
- // no arg and no default value
507
- if (!isset($callingArgs[$i]) && !isset($arg[2])) {
508
- return false;
509
- }
510
- break;
511
- case "rest":
512
- $i--; // rest can be empty
513
- break 2;
514
- }
515
- }
516
-
517
- if ($block->isVararg) {
518
- return true; // not having enough is handled above
519
- } else {
520
- $numMatched = $i + 1;
521
- // greater than becuase default values always match
522
- return $numMatched >= $numCalling;
523
- }
524
- }
525
-
526
- protected function patternMatchAll($blocks, $callingArgs) {
527
- $matches = null;
528
- foreach ($blocks as $block) {
529
- if ($this->patternMatch($block, $callingArgs)) {
530
- $matches[] = $block;
531
- }
532
- }
533
-
534
- return $matches;
535
- }
536
-
537
- // attempt to find blocks matched by path and args
538
- protected function findBlocks($searchIn, $path, $args, $seen=array()) {
539
- if ($searchIn == null) return null;
540
- if (isset($seen[$searchIn->id])) return null;
541
- $seen[$searchIn->id] = true;
542
-
543
- $name = $path[0];
544
-
545
- if (isset($searchIn->children[$name])) {
546
- $blocks = $searchIn->children[$name];
547
- if (count($path) == 1) {
548
- $matches = $this->patternMatchAll($blocks, $args);
549
- if (!empty($matches)) {
550
- // This will return all blocks that match in the closest
551
- // scope that has any matching block, like lessjs
552
- return $matches;
553
- }
554
- } else {
555
- $matches = array();
556
- foreach ($blocks as $subBlock) {
557
- $subMatches = $this->findBlocks($subBlock,
558
- array_slice($path, 1), $args, $seen);
559
-
560
- if (!is_null($subMatches)) {
561
- foreach ($subMatches as $sm) {
562
- $matches[] = $sm;
563
- }
564
- }
565
- }
566
-
567
- return count($matches) > 0 ? $matches : null;
568
- }
569
- }
570
-
571
- if ($searchIn->parent === $searchIn) return null;
572
- return $this->findBlocks($searchIn->parent, $path, $args, $seen);
573
- }
574
-
575
- // sets all argument names in $args to either the default value
576
- // or the one passed in through $values
577
- protected function zipSetArgs($args, $values) {
578
- $i = 0;
579
- $assignedValues = array();
580
- foreach ($args as $a) {
581
- if ($a[0] == "arg") {
582
- if ($i < count($values) && !is_null($values[$i])) {
583
- $value = $values[$i];
584
- } elseif (isset($a[2])) {
585
- $value = $a[2];
586
- } else $value = null;
587
-
588
- $value = $this->reduce($value);
589
- $this->set($a[1], $value);
590
- $assignedValues[] = $value;
591
- }
592
- $i++;
593
- }
594
-
595
- // check for a rest
596
- $last = end($args);
597
- if ($last[0] == "rest") {
598
- $rest = array_slice($values, count($args) - 1);
599
- $this->set($last[1], $this->reduce(array("list", " ", $rest)));
600
- }
601
-
602
- $this->env->arguments = $assignedValues;
603
- }
604
-
605
- // compile a prop and update $lines or $blocks appropriately
606
- protected function compileProp($prop, $block, $out) {
607
- // set error position context
608
- $this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;
609
-
610
- switch ($prop[0]) {
611
- case 'assign':
612
- list(, $name, $value) = $prop;
613
- if ($name[0] == $this->vPrefix) {
614
- $this->set($name, $value);
615
- } else {
616
- $out->lines[] = $this->formatter->property($name,
617
- $this->compileValue($this->reduce($value)));
618
- }
619
- break;
620
- case 'block':
621
- list(, $child) = $prop;
622
- $this->compileBlock($child);
623
- break;
624
- case 'mixin':
625
- list(, $path, $args, $suffix) = $prop;
626
-
627
- $args = array_map(array($this, "reduce"), (array)$args);
628
- $mixins = $this->findBlocks($block, $path, $args);
629
-
630
- if ($mixins === null) {
631
- // fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n");
632
- break; // throw error here??
633
- }
634
-
635
- foreach ($mixins as $mixin) {
636
- $haveScope = false;
637
- if (isset($mixin->parent->scope)) {
638
- $haveScope = true;
639
- $mixinParentEnv = $this->pushEnv();
640
- $mixinParentEnv->storeParent = $mixin->parent->scope;
641
- }
642
-
643
- $haveArgs = false;
644
- if (isset($mixin->args)) {
645
- $haveArgs = true;
646
- $this->pushEnv();
647
- $this->zipSetArgs($mixin->args, $args);
648
- }
649
-
650
- $oldParent = $mixin->parent;
651
- if ($mixin != $block) $mixin->parent = $block;
652
-
653
- foreach ($this->sortProps($mixin->props) as $subProp) {
654
- if ($suffix !== null &&
655
- $subProp[0] == "assign" &&
656
- is_string($subProp[1]) &&
657
- $subProp[1]{0} != $this->vPrefix)
658
- {
659
- $subProp[2] = array(
660
- 'list', ' ',
661
- array($subProp[2], array('keyword', $suffix))
662
- );
663
- }
664
-
665
- $this->compileProp($subProp, $mixin, $out);
666
- }
667
-
668
- $mixin->parent = $oldParent;
669
-
670
- if ($haveArgs) $this->popEnv();
671
- if ($haveScope) $this->popEnv();
672
- }
673
-
674
- break;
675
- case 'raw':
676
- $out->lines[] = $prop[1];
677
- break;
678
- case "directive":
679
- list(, $name, $value) = $prop;
680
- $out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';';
681
- break;
682
- case "comment":
683
- $out->lines[] = $prop[1];
684
- break;
685
- case "import";
686
- list(, $importPath, $importId) = $prop;
687
- $importPath = $this->reduce($importPath);
688
-
689
- if (!isset($this->env->imports)) {
690
- $this->env->imports = array();
691
- }
692
-
693
- $result = $this->tryImport($importPath, $block, $out);
694
-
695
- $this->env->imports[$importId] = $result === false ?
696
- array(false, "@import " . $this->compileValue($importPath).";") :
697
- $result;
698
-
699
- break;
700
- case "import_mixin":
701
- list(,$importId) = $prop;
702
- $import = $this->env->imports[$importId];
703
- if ($import[0] === false) {
704
- $out->lines[] = $import[1];
705
- } else {
706
- list(, $bottom, $parser, $importDir) = $import;
707
- $this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
708
- }
709
-
710
- break;
711
- default:
712
- $this->throwError("unknown op: {$prop[0]}\n");
713
- }
714
- }
715
-
716
-
717
- /**
718
- * Compiles a primitive value into a CSS property value.
719
- *
720
- * Values in lessphp are typed by being wrapped in arrays, their format is
721
- * typically:
722
- *
723
- * array(type, contents [, additional_contents]*)
724
- *
725
- * The input is expected to be reduced. This function will not work on
726
- * things like expressions and variables.
727
- */
728
- protected function compileValue($value) {
729
- switch ($value[0]) {
730
- case 'list':
731
- // [1] - delimiter
732
- // [2] - array of values
733
- return implode($value[1], array_map(array($this, 'compileValue'), $value[2]));
734
- case 'raw_color':
735
- if (!empty($this->formatter->compressColors)) {
736
- return $this->compileValue($this->coerceColor($value));
737
- }
738
- return $value[1];
739
- case 'keyword':
740
- // [1] - the keyword
741
- return $value[1];
742
- case 'number':
743
- list(, $num, $unit) = $value;
744
- // [1] - the number
745
- // [2] - the unit
746
- if ($this->numberPrecision !== null) {
747
- $num = round($num, $this->numberPrecision);
748
- }
749
- return $num . $unit;
750
- case 'string':
751
- // [1] - contents of string (includes quotes)
752
- list(, $delim, $content) = $value;
753
- foreach ($content as &$part) {
754
- if (is_array($part)) {
755
- $part = $this->compileValue($part);
756
- }
757
- }
758
- return $delim . implode($content) . $delim;
759
- case 'color':
760
- // [1] - red component (either number or a %)
761
- // [2] - green component
762
- // [3] - blue component
763
- // [4] - optional alpha component
764
- list(, $r, $g, $b) = $value;
765
- $r = round($r);
766
- $g = round($g);
767
- $b = round($b);
768
-
769
- if (count($value) == 5 && $value[4] != 1) { // rgba
770
- return 'rgba('.$r.','.$g.','.$b.','.$value[4].')';
771
- }
772
-
773
- $h = sprintf("#%02x%02x%02x", $r, $g, $b);
774
-
775
- if (!empty($this->formatter->compressColors)) {
776
- // Converting hex color to short notation (e.g. #003399 to #039)
777
- if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) {
778
- $h = '#' . $h[1] . $h[3] . $h[5];
779
- }
780
- }
781
-
782
- return $h;
783
-
784
- case 'function':
785
- list(, $name, $args) = $value;
786
- return $name.'('.$this->compileValue($args).')';
787
- default: // assumed to be unit
788
- $this->throwError("unknown value type: $value[0]");
789
- }
790
- }
791
-
792
- protected function lib_isnumber($value) {
793
- return $this->toBool($value[0] == "number");
794
- }
795
-
796
- protected function lib_isstring($value) {
797
- return $this->toBool($value[0] == "string");
798
- }
799
-
800
- protected function lib_iscolor($value) {
801
- return $this->toBool($this->coerceColor($value));
802
- }
803
-
804
- protected function lib_iskeyword($value) {
805
- return $this->toBool($value[0] == "keyword");
806
- }
807
-
808
- protected function lib_ispixel($value) {
809
- return $this->toBool($value[0] == "number" && $value[2] == "px");
810
- }
811
-
812
- protected function lib_ispercentage($value) {
813
- return $this->toBool($value[0] == "number" && $value[2] == "%");
814
- }
815
-
816
- protected function lib_isem($value) {
817
- return $this->toBool($value[0] == "number" && $value[2] == "em");
818
- }
819
-
820
- protected function lib_isrem($value) {
821
- return $this->toBool($value[0] == "number" && $value[2] == "rem");
822
- }
823
-
824
- protected function lib_rgbahex($color) {
825
- $color = $this->coerceColor($color);
826
- if (is_null($color))
827
- $this->throwError("color expected for rgbahex");
828
-
829
- return sprintf("#%02x%02x%02x%02x",
830
- isset($color[4]) ? $color[4]*255 : 255,
831
- $color[1],$color[2], $color[3]);
832
- }
833
-
834
- protected function lib_argb($color){
835
- return $this->lib_rgbahex($color);
836
- }
837
-
838
- // utility func to unquote a string
839
- protected function lib_e($arg) {
840
- switch ($arg[0]) {
841
- case "list":
842
- $items = $arg[2];
843
- if (isset($items[0])) {
844
- return $this->lib_e($items[0]);
845
- }
846
- return self::$defaultValue;
847
- case "string":
848
- $arg[1] = "";
849
- return $arg;
850
- case "keyword":
851
- return $arg;
852
- default:
853
- return array("keyword", $this->compileValue($arg));
854
- }
855
- }
856
-
857
- protected function lib__sprintf($args) {
858
- if ($args[0] != "list") return $args;
859
- $values = $args[2];
860
- $string = array_shift($values);
861
- $template = $this->compileValue($this->lib_e($string));
862
-
863
- $i = 0;
864
- if (preg_match_all('/%[dsa]/', $template, $m)) {
865
- foreach ($m[0] as $match) {
866
- $val = isset($values[$i]) ?
867
- $this->reduce($values[$i]) : array('keyword', '');
868
-
869
- // lessjs compat, renders fully expanded color, not raw color
870
- if ($color = $this->coerceColor($val)) {
871
- $val = $color;
872
- }
873
-
874
- $i++;
875
- $rep = $this->compileValue($this->lib_e($val));
876
- $template = preg_replace('/'.self::preg_quote($match).'/',
877
- $rep, $template, 1);
878
- }
879
- }
880
-
881
- $d = $string[0] == "string" ? $string[1] : '"';
882
- return array("string", $d, array($template));
883
- }
884
-
885
- protected function lib_floor($arg) {
886
- $value = $this->assertNumber($arg);
887
- return array("number", floor($value), $arg[2]);
888
- }
889
-
890
- protected function lib_ceil($arg) {
891
- $value = $this->assertNumber($arg);
892
- return array("number", ceil($value), $arg[2]);
893
- }
894
-
895
- protected function lib_round($arg) {
896
- $value = $this->assertNumber($arg);
897
- return array("number", round($value), $arg[2]);
898
- }
899
-
900
- protected function lib_unit($arg) {
901
- if ($arg[0] == "list") {
902
- list($number, $newUnit) = $arg[2];
903
- return array("number", $this->assertNumber($number),
904
- $this->compileValue($this->lib_e($newUnit)));
905
- } else {
906
- return array("number", $this->assertNumber($arg), "");
907
- }
908
- }
909
-
910
- /**
911
- * Helper function to get arguments for color manipulation functions.
912
- * takes a list that contains a color like thing and a percentage
913
- */
914
- protected function colorArgs($args) {
915
- if ($args[0] != 'list' || count($args[2]) < 2) {
916
- return array(array('color', 0, 0, 0), 0);
917
- }
918
- list($color, $delta) = $args[2];
919
- $color = $this->assertColor($color);
920
- $delta = floatval($delta[1]);
921
-
922
- return array($color, $delta);
923
- }
924
-
925
- protected function lib_darken($args) {
926
- list($color, $delta) = $this->colorArgs($args);
927
-
928
- $hsl = $this->toHSL($color);
929
- $hsl[3] = $this->clamp($hsl[3] - $delta, 100);
930
- return $this->toRGB($hsl);
931
- }
932
-
933
- protected function lib_lighten($args) {
934
- list($color, $delta) = $this->colorArgs($args);
935
-
936
- $hsl = $this->toHSL($color);
937
- $hsl[3] = $this->clamp($hsl[3] + $delta, 100);
938
- return $this->toRGB($hsl);
939
- }
940
-
941
- protected function lib_saturate($args) {
942
- list($color, $delta) = $this->colorArgs($args);
943
-
944
- $hsl = $this->toHSL($color);
945
- $hsl[2] = $this->clamp($hsl[2] + $delta, 100);
946
- return $this->toRGB($hsl);
947
- }
948
-
949
- protected function lib_desaturate($args) {
950
- list($color, $delta) = $this->colorArgs($args);
951
-
952
- $hsl = $this->toHSL($color);
953
- $hsl[2] = $this->clamp($hsl[2] - $delta, 100);
954
- return $this->toRGB($hsl);
955
- }
956
-
957
- protected function lib_spin($args) {
958
- list($color, $delta) = $this->colorArgs($args);
959
-
960
- $hsl = $this->toHSL($color);
961
-
962
- $hsl[1] = $hsl[1] + $delta % 360;
963
- if ($hsl[1] < 0) $hsl[1] += 360;
964
-
965
- return $this->toRGB($hsl);
966
- }
967
-
968
- protected function lib_fadeout($args) {
969
- list($color, $delta) = $this->colorArgs($args);
970
- $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta/100);
971
- return $color;
972
- }
973
-
974
- protected function lib_fadein($args) {
975
- list($color, $delta) = $this->colorArgs($args);
976
- $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta/100);
977
- return $color;
978
- }
979
-
980
- protected function lib_hue($color) {
981
- $hsl = $this->toHSL($this->assertColor($color));
982
- return round($hsl[1]);
983
- }
984
-
985
- protected function lib_saturation($color) {
986
- $hsl = $this->toHSL($this->assertColor($color));
987
- return round($hsl[2]);
988
- }
989
-
990
- protected function lib_lightness($color) {
991
- $hsl = $this->toHSL($this->assertColor($color));
992
- return round($hsl[3]);
993
- }
994
-
995
- // get the alpha of a color
996
- // defaults to 1 for non-colors or colors without an alpha
997
- protected function lib_alpha($value) {
998
- if (!is_null($color = $this->coerceColor($value))) {
999
- return isset($color[4]) ? $color[4] : 1;
1000
- }
1001
- }
1002
-
1003
- // set the alpha of the color
1004
- protected function lib_fade($args) {
1005
- list($color, $alpha) = $this->colorArgs($args);
1006
- $color[4] = $this->clamp($alpha / 100.0);
1007
- return $color;
1008
- }
1009
-
1010
- protected function lib_percentage($arg) {
1011
- $num = $this->assertNumber($arg);
1012
- return array("number", $num*100, "%");
1013
- }
1014
-
1015
- // mixes two colors by weight
1016
- // mix(@color1, @color2, @weight);
1017
- // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
1018
- protected function lib_mix($args) {
1019
- if ($args[0] != "list" || count($args[2]) < 3)
1020
- $this->throwError("mix expects (color1, color2, weight)");
1021
-
1022
- list($first, $second, $weight) = $args[2];
1023
- $first = $this->assertColor($first);
1024
- $second = $this->assertColor($second);
1025
-
1026
- $first_a = $this->lib_alpha($first);
1027
- $second_a = $this->lib_alpha($second);
1028
- $weight = $weight[1] / 100.0;
1029
-
1030
- $w = $weight * 2 - 1;
1031
- $a = $first_a - $second_a;
1032
-
1033
- $w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0;
1034
- $w2 = 1.0 - $w1;
1035
-
1036
- $new = array('color',
1037
- $w1 * $first[1] + $w2 * $second[1],
1038
- $w1 * $first[2] + $w2 * $second[2],
1039
- $w1 * $first[3] + $w2 * $second[3],
1040
- );
1041
-
1042
- if ($first_a != 1.0 || $second_a != 1.0) {
1043
- $new[] = $first_a * $weight + $second_a * ($weight - 1);
1044
- }
1045
-
1046
- return $this->fixColor($new);
1047
- }
1048
-
1049
- protected function lib_contrast($args) {
1050
- if ($args[0] != 'list' || count($args[2]) < 3) {
1051
- return array(array('color', 0, 0, 0), 0);
1052
- }
1053
-
1054
- list($inputColor, $darkColor, $lightColor) = $args[2];
1055
-
1056
- $inputColor = $this->assertColor($inputColor);
1057
- $darkColor = $this->assertColor($darkColor);
1058
- $lightColor = $this->assertColor($lightColor);
1059
- $hsl = $this->toHSL($inputColor);
1060
-
1061
- if ($hsl[3] > 50) {
1062
- return $darkColor;
1063
- }
1064
-
1065
- return $lightColor;
1066
- }
1067
-
1068
- protected function assertColor($value, $error = "expected color value") {
1069
- $color = $this->coerceColor($value);
1070
- if (is_null($color)) $this->throwError($error);
1071
- return $color;
1072
- }
1073
-
1074
- protected function assertNumber($value, $error = "expecting number") {
1075
- if ($value[0] == "number") return $value[1];
1076
- $this->throwError($error);
1077
- }
1078
-
1079
- protected function toHSL($color) {
1080
- if ($color[0] == 'hsl') return $color;
1081
-
1082
- $r = $color[1] / 255;
1083
- $g = $color[2] / 255;
1084
- $b = $color[3] / 255;
1085
-
1086
- $min = min($r, $g, $b);
1087
- $max = max($r, $g, $b);
1088
-
1089
- $L = ($min + $max) / 2;
1090
- if ($min == $max) {
1091
- $S = $H = 0;
1092
- } else {
1093
- if ($L < 0.5)
1094
- $S = ($max - $min)/($max + $min);
1095
- else
1096
- $S = ($max - $min)/(2.0 - $max - $min);
1097
-
1098
- if ($r == $max) $H = ($g - $b)/($max - $min);
1099
- elseif ($g == $max) $H = 2.0 + ($b - $r)/($max - $min);
1100
- elseif ($b == $max) $H = 4.0 + ($r - $g)/($max - $min);
1101
-
1102
- }
1103
-
1104
- $out = array('hsl',
1105
- ($H < 0 ? $H + 6 : $H)*60,
1106
- $S*100,
1107
- $L*100,
1108
- );
1109
-
1110
- if (count($color) > 4) $out[] = $color[4]; // copy alpha
1111
- return $out;
1112
- }
1113
-
1114
- protected function toRGB_helper($comp, $temp1, $temp2) {
1115
- if ($comp < 0) $comp += 1.0;
1116
- elseif ($comp > 1) $comp -= 1.0;
1117
-
1118
- if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp;
1119
- if (2 * $comp < 1) return $temp2;
1120
- if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1)*((2/3) - $comp) * 6;
1121
-
1122
- return $temp1;
1123
- }
1124
-
1125
- /**
1126
- * Converts a hsl array into a color value in rgb.
1127
- * Expects H to be in range of 0 to 360, S and L in 0 to 100
1128
- */
1129
- protected function toRGB($color) {
1130
- if ($color[0] == 'color') return $color;
1131
-
1132
- $H = $color[1] / 360;
1133
- $S = $color[2] / 100;
1134
- $L = $color[3] / 100;
1135
-
1136
- if ($S == 0) {
1137
- $r = $g = $b = $L;
1138
- } else {
1139
- $temp2 = $L < 0.5 ?
1140
- $L*(1.0 + $S) :
1141
- $L + $S - $L * $S;
1142
-
1143
- $temp1 = 2.0 * $L - $temp2;
1144
-
1145
- $r = $this->toRGB_helper($H + 1/3, $temp1, $temp2);
1146
- $g = $this->toRGB_helper($H, $temp1, $temp2);
1147
- $b = $this->toRGB_helper($H - 1/3, $temp1, $temp2);
1148
- }
1149
-
1150
- // $out = array('color', round($r*255), round($g*255), round($b*255));
1151
- $out = array('color', $r*255, $g*255, $b*255);
1152
- if (count($color) > 4) $out[] = $color[4]; // copy alpha
1153
- return $out;
1154
- }
1155
-
1156
- protected function clamp($v, $max = 1, $min = 0) {
1157
- return min($max, max($min, $v));
1158
- }
1159
-
1160
- /**
1161
- * Convert the rgb, rgba, hsl color literals of function type
1162
- * as returned by the parser into values of color type.
1163
- */
1164
- protected function funcToColor($func) {
1165
- $fname = $func[1];
1166
- if ($func[2][0] != 'list') return false; // need a list of arguments
1167
- $rawComponents = $func[2][2];
1168
-
1169
- if ($fname == 'hsl' || $fname == 'hsla') {
1170
- $hsl = array('hsl');
1171
- $i = 0;
1172
- foreach ($rawComponents as $c) {
1173
- $val = $this->reduce($c);
1174
- $val = isset($val[1]) ? floatval($val[1]) : 0;
1175
-
1176
- if ($i == 0) $clamp = 360;
1177
- elseif ($i < 3) $clamp = 100;
1178
- else $clamp = 1;
1179
-
1180
- $hsl[] = $this->clamp($val, $clamp);
1181
- $i++;
1182
- }
1183
-
1184
- while (count($hsl) < 4) $hsl[] = 0;
1185
- return $this->toRGB($hsl);
1186
-
1187
- } elseif ($fname == 'rgb' || $fname == 'rgba') {
1188
- $components = array();
1189
- $i = 1;
1190
- foreach ($rawComponents as $c) {
1191
- $c = $this->reduce($c);
1192
- if ($i < 4) {
1193
- if ($c[0] == "number" && $c[2] == "%") {
1194
- $components[] = 255 * ($c[1] / 100);
1195
- } else {
1196
- $components[] = floatval($c[1]);
1197
- }
1198
- } elseif ($i == 4) {
1199
- if ($c[0] == "number" && $c[2] == "%") {
1200
- $components[] = 1.0 * ($c[1] / 100);
1201
- } else {
1202
- $components[] = floatval($c[1]);
1203
- }
1204
- } else break;
1205
-
1206
- $i++;
1207
- }
1208
- while (count($components) < 3) $components[] = 0;
1209
- array_unshift($components, 'color');
1210
- return $this->fixColor($components);
1211
- }
1212
-
1213
- return false;
1214
- }
1215
-
1216
- protected function reduce($value, $forExpression = false) {
1217
- switch ($value[0]) {
1218
- case "interpolate":
1219
- $reduced = $this->reduce($value[1]);
1220
- $var = $this->compileValue($reduced);
1221
- $res = $this->reduce(array("variable", $this->vPrefix . $var));
1222
-
1223
- if (empty($value[2])) $res = $this->lib_e($res);
1224
-
1225
- return $res;
1226
- case "variable":
1227
- $key = $value[1];
1228
- if (is_array($key)) {
1229
- $key = $this->reduce($key);
1230
- $key = $this->vPrefix . $this->compileValue($this->lib_e($key));
1231
- }
1232
-
1233
- $seen =& $this->env->seenNames;
1234
-
1235
- if (!empty($seen[$key])) {
1236
- $this->throwError("infinite loop detected: $key");
1237
- }
1238
-
1239
- $seen[$key] = true;
1240
- $out = $this->reduce($this->get($key, self::$defaultValue));
1241
- $seen[$key] = false;
1242
- return $out;
1243
- case "list":
1244
- foreach ($value[2] as &$item) {
1245
- $item = $this->reduce($item, $forExpression);
1246
- }
1247
- return $value;
1248
- case "expression":
1249
- return $this->evaluate($value);
1250
- case "string":
1251
- foreach ($value[2] as &$part) {
1252
- if (is_array($part)) {
1253
- $strip = $part[0] == "variable";
1254
- $part = $this->reduce($part);
1255
- if ($strip) $part = $this->lib_e($part);
1256
- }
1257
- }
1258
- return $value;
1259
- case "escape":
1260
- list(,$inner) = $value;
1261
- return $this->lib_e($this->reduce($inner));
1262
- case "function":
1263
- $color = $this->funcToColor($value);
1264
- if ($color) return $color;
1265
-
1266
- list(, $name, $args) = $value;
1267
- if ($name == "%") $name = "_sprintf";
1268
- $f = isset($this->libFunctions[$name]) ?
1269
- $this->libFunctions[$name] : array($this, 'lib_'.$name);
1270
-
1271
- if (is_callable($f)) {
1272
- if ($args[0] == 'list')
1273
- $args = self::compressList($args[2], $args[1]);
1274
-
1275
- $ret = call_user_func($f, $this->reduce($args, true), $this);
1276
-
1277
- if (is_null($ret)) {
1278
- return array("string", "", array(
1279
- $name, "(", $args, ")"
1280
- ));
1281
- }
1282
-
1283
- // convert to a typed value if the result is a php primitive
1284
- if (is_numeric($ret)) $ret = array('number', $ret, "");
1285
- elseif (!is_array($ret)) $ret = array('keyword', $ret);
1286
-
1287
- return $ret;
1288
- }
1289
-
1290
- // plain function, reduce args
1291
- $value[2] = $this->reduce($value[2]);
1292
- return $value;
1293
- case "unary":
1294
- list(, $op, $exp) = $value;
1295
- $exp = $this->reduce($exp);
1296
-
1297
- if ($exp[0] == "number") {
1298
- switch ($op) {
1299
- case "+":
1300
- return $exp;
1301
- case "-":
1302
- $exp[1] *= -1;
1303
- return $exp;
1304
- }
1305
- }
1306
- return array("string", "", array($op, $exp));
1307
- }
1308
-
1309
- if ($forExpression) {
1310
- switch ($value[0]) {
1311
- case "keyword":
1312
- if ($color = $this->coerceColor($value)) {
1313
- return $color;
1314
- }
1315
- break;
1316
- case "raw_color":
1317
- return $this->coerceColor($value);
1318
- }
1319
- }
1320
-
1321
- return $value;
1322
- }
1323
-
1324
-
1325
- // coerce a value for use in color operation
1326
- protected function coerceColor($value) {
1327
- switch($value[0]) {
1328
- case 'color': return $value;
1329
- case 'raw_color':
1330
- $c = array("color", 0, 0, 0);
1331
- $colorStr = substr($value[1], 1);
1332
- $num = hexdec($colorStr);
1333
- $width = strlen($colorStr) == 3 ? 16 : 256;
1334
-
1335
- for ($i = 3; $i > 0; $i--) { // 3 2 1
1336
- $t = $num % $width;
1337
- $num /= $width;
1338
-
1339
- $c[$i] = $t * (256/$width) + $t * floor(16/$width);
1340
- }
1341
-
1342
- return $c;
1343
- case 'keyword':
1344
- $name = $value[1];
1345
- if (isset(self::$cssColors[$name])) {
1346
- $rgba = explode(',', self::$cssColors[$name]);
1347
-
1348
- if(isset($rgba[3]))
1349
- return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
1350
-
1351
- return array('color', $rgba[0], $rgba[1], $rgba[2]);
1352
- }
1353
- return null;
1354
- }
1355
- }
1356
-
1357
- // make something string like into a string
1358
- protected function coerceString($value) {
1359
- switch ($value[0]) {
1360
- case "string":
1361
- return $value;
1362
- case "keyword":
1363
- return array("string", "", array($value[1]));
1364
- }
1365
- return null;
1366
- }
1367
-
1368
- // turn list of length 1 into value type
1369
- protected function flattenList($value) {
1370
- if ($value[0] == "list" && count($value[2]) == 1) {
1371
- return $this->flattenList($value[2][0]);
1372
- }
1373
- return $value;
1374
- }
1375
-
1376
- protected function toBool($a) {
1377
- if ($a) return self::$TRUE;
1378
- else return self::$FALSE;
1379
- }
1380
-
1381
- // evaluate an expression
1382
- protected function evaluate($exp) {
1383
- list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;
1384
-
1385
- $left = $this->reduce($left, true);
1386
- $right = $this->reduce($right, true);
1387
-
1388
- if ($leftColor = $this->coerceColor($left)) {
1389
- $left = $leftColor;
1390
- }
1391
-
1392
- if ($rightColor = $this->coerceColor($right)) {
1393
- $right = $rightColor;
1394
- }
1395
-
1396
- $ltype = $left[0];
1397
- $rtype = $right[0];
1398
-
1399
- // operators that work on all types
1400
- if ($op == "and") {
1401
- return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
1402
- }
1403
-
1404
- if ($op == "=") {
1405
- return $this->toBool($this->eq($left, $right) );
1406
- }
1407
-
1408
- if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) {
1409
- return $str;
1410
- }
1411
-
1412
- // type based operators
1413
- $fname = "op_${ltype}_${rtype}";
1414
- if (is_callable(array($this, $fname))) {
1415
- $out = $this->$fname($op, $left, $right);
1416
- if (!is_null($out)) return $out;
1417
- }
1418
-
1419
- // make the expression look it did before being parsed
1420
- $paddedOp = $op;
1421
- if ($whiteBefore) $paddedOp = " " . $paddedOp;
1422
- if ($whiteAfter) $paddedOp .= " ";
1423
-
1424
- return array("string", "", array($left, $paddedOp, $right));
1425
- }
1426
-
1427
- protected function stringConcatenate($left, $right) {
1428
- if ($strLeft = $this->coerceString($left)) {
1429
- if ($right[0] == "string") {
1430
- $right[1] = "";
1431
- }
1432
- $strLeft[2][] = $right;
1433
- return $strLeft;
1434
- }
1435
-
1436
- if ($strRight = $this->coerceString($right)) {
1437
- array_unshift($strRight[2], $left);
1438
- return $strRight;
1439
- }
1440
- }
1441
-
1442
-
1443
- // make sure a color's components don't go out of bounds
1444
- protected function fixColor($c) {
1445
- foreach (range(1, 3) as $i) {
1446
- if ($c[$i] < 0) $c[$i] = 0;
1447
- if ($c[$i] > 255) $c[$i] = 255;
1448
- }
1449
-
1450
- return $c;
1451
- }
1452
-
1453
- protected function op_number_color($op, $lft, $rgt) {
1454
- if ($op == '+' || $op == '*') {
1455
- return $this->op_color_number($op, $rgt, $lft);
1456
- }
1457
- }
1458
-
1459
- protected function op_color_number($op, $lft, $rgt) {
1460
- if ($rgt[0] == '%') $rgt[1] /= 100;
1461
-
1462
- return $this->op_color_color($op, $lft,
1463
- array_fill(1, count($lft) - 1, $rgt[1]));
1464
- }
1465
-
1466
- protected function op_color_color($op, $left, $right) {
1467
- $out = array('color');
1468
- $max = count($left) > count($right) ? count($left) : count($right);
1469
- foreach (range(1, $max - 1) as $i) {
1470
- $lval = isset($left[$i]) ? $left[$i] : 0;
1471
- $rval = isset($right[$i]) ? $right[$i] : 0;
1472
- switch ($op) {
1473
- case '+':
1474
- $out[] = $lval + $rval;
1475
- break;
1476
- case '-':
1477
- $out[] = $lval - $rval;
1478
- break;
1479
- case '*':
1480
- $out[] = $lval * $rval;
1481
- break;
1482
- case '%':
1483
- $out[] = $lval % $rval;
1484
- break;
1485
- case '/':
1486
- if ($rval == 0) $this->throwError("evaluate error: can't divide by zero");
1487
- $out[] = $lval / $rval;
1488
- break;
1489
- default:
1490
- $this->throwError('evaluate error: color op number failed on op '.$op);
1491
- }
1492
- }
1493
- return $this->fixColor($out);
1494
- }
1495
-
1496
- function lib_red($color){
1497
- $color = $this->coerceColor($color);
1498
- if (is_null($color)) {
1499
- $this->throwError('color expected for red()');
1500
- }
1501
-
1502
- return $color[1];
1503
- }
1504
-
1505
- function lib_green($color){
1506
- $color = $this->coerceColor($color);
1507
- if (is_null($color)) {
1508
- $this->throwError('color expected for green()');
1509
- }
1510
-
1511
- return $color[2];
1512
- }
1513
-
1514
- function lib_blue($color){
1515
- $color = $this->coerceColor($color);
1516
- if (is_null($color)) {
1517
- $this->throwError('color expected for blue()');
1518
- }
1519
-
1520
- return $color[3];
1521
- }
1522
-
1523
-
1524
- // operator on two numbers
1525
- protected function op_number_number($op, $left, $right) {
1526
- $unit = empty($left[2]) ? $right[2] : $left[2];
1527
-
1528
- $value = 0;
1529
- switch ($op) {
1530
- case '+':
1531
- $value = $left[1] + $right[1];
1532
- break;
1533
- case '*':
1534
- $value = $left[1] * $right[1];
1535
- break;
1536
- case '-':
1537
- $value = $left[1] - $right[1];
1538
- break;
1539
- case '%':
1540
- $value = $left[1] % $right[1];
1541
- break;
1542
- case '/':
1543
- if ($right[1] == 0) $this->throwError('parse error: divide by zero');
1544
- $value = $left[1] / $right[1];
1545
- break;
1546
- case '<':
1547
- return $this->toBool($left[1] < $right[1]);
1548
- case '>':
1549
- return $this->toBool($left[1] > $right[1]);
1550
- case '>=':
1551
- return $this->toBool($left[1] >= $right[1]);
1552
- case '=<':
1553
- return $this->toBool($left[1] <= $right[1]);
1554
- default:
1555
- $this->throwError('parse error: unknown number operator: '.$op);
1556
- }
1557
-
1558
- return array("number", $value, $unit);
1559
- }
1560
-
1561
-
1562
- /* environment functions */
1563
-
1564
- protected function makeOutputBlock($type, $selectors = null) {
1565
- $b = new stdclass;
1566
- $b->lines = array();
1567
- $b->children = array();
1568
- $b->selectors = $selectors;
1569
- $b->type = $type;
1570
- $b->parent = $this->scope;
1571
- return $b;
1572
- }
1573
-
1574
- // the state of execution
1575
- protected function pushEnv($block = null) {
1576
- $e = new stdclass;
1577
- $e->parent = $this->env;
1578
- $e->store = array();
1579
- $e->block = $block;
1580
-
1581
- $this->env = $e;
1582
- return $e;
1583
- }
1584
-
1585
- // pop something off the stack
1586
- protected function popEnv() {
1587
- $old = $this->env;
1588
- $this->env = $this->env->parent;
1589
- return $old;
1590
- }
1591
-
1592
- // set something in the current env
1593
- protected function set($name, $value) {
1594
- $this->env->store[$name] = $value;
1595
- }
1596
-
1597
-
1598
- // get the highest occurrence entry for a name
1599
- protected function get($name, $default=null) {
1600
- $current = $this->env;
1601
-
1602
- $isArguments = $name == $this->vPrefix . 'arguments';
1603
- while ($current) {
1604
- if ($isArguments && isset($current->arguments)) {
1605
- return array('list', ' ', $current->arguments);
1606
- }
1607
-
1608
- if (isset($current->store[$name]))
1609
- return $current->store[$name];
1610
- else {
1611
- $current = isset($current->storeParent) ?
1612
- $current->storeParent : $current->parent;
1613
- }
1614
- }
1615
-
1616
- return $default;
1617
- }
1618
-
1619
- // inject array of unparsed strings into environment as variables
1620
- protected function injectVariables($args) {
1621
- $this->pushEnv();
1622
- $parser = new lessc_parser($this, __METHOD__);
1623
- foreach ($args as $name => $strValue) {
1624
- if ($name{0} != '@') $name = '@'.$name;
1625
- $parser->count = 0;
1626
- $parser->buffer = (string)$strValue;
1627
- if (!$parser->propertyValue($value)) {
1628
- throw new Exception("failed to parse passed in variable $name: $strValue");
1629
- }
1630
-
1631
- $this->set($name, $value);
1632
- }
1633
- }
1634
-
1635
- /**
1636
- * Initialize any static state, can initialize parser for a file
1637
- * $opts isn't used yet
1638
- */
1639
- public function __construct($fname = null) {
1640
- if ($fname !== null) {
1641
- // used for deprecated parse method
1642
- $this->_parseFile = $fname;
1643
- }
1644
- }
1645
-
1646
- public function compile($string, $name = null) {
1647
- $locale = setlocale(LC_NUMERIC, 0);
1648
- setlocale(LC_NUMERIC, "C");
1649
-
1650
- $this->parser = $this->makeParser($name);
1651
- $root = $this->parser->parse($string);
1652
-
1653
- $this->env = null;
1654
- $this->scope = null;
1655
-
1656
- $this->formatter = $this->newFormatter();
1657
-
1658
- if (!empty($this->registeredVars)) {
1659
- $this->injectVariables($this->registeredVars);
1660
- }
1661
-
1662
- $this->sourceParser = $this->parser; // used for error messages
1663
- $this->compileBlock($root);
1664
-
1665
- ob_start();
1666
- $this->formatter->block($this->scope);
1667
- $out = ob_get_clean();
1668
- setlocale(LC_NUMERIC, $locale);
1669
- return $out;
1670
- }
1671
-
1672
- public function compileFile($fname, $outFname = null) {
1673
- if (!is_readable($fname)) {
1674
- throw new Exception('load error: failed to find '.$fname);
1675
- }
1676
-
1677
- $pi = pathinfo($fname);
1678
-
1679
- $oldImport = $this->importDir;
1680
-
1681
- $this->importDir = (array)$this->importDir;
1682
- $this->importDir[] = $pi['dirname'].'/';
1683
-
1684
- $this->allParsedFiles = array();
1685
- $this->addParsedFile($fname);
1686
-
1687
- $out = $this->compile(file_get_contents($fname), $fname);
1688
-
1689
- $this->importDir = $oldImport;
1690
-
1691
- if ($outFname !== null) {
1692
- return file_put_contents($outFname, $out);
1693
- }
1694
-
1695
- return $out;
1696
- }
1697
-
1698
- // compile only if changed input has changed or output doesn't exist
1699
- public function checkedCompile($in, $out) {
1700
- if (!is_file($out) || filemtime($in) > filemtime($out)) {
1701
- $this->compileFile($in, $out);
1702
- return true;
1703
- }
1704
- return false;
1705
- }
1706
-
1707
- /**
1708
- * Execute lessphp on a .less file or a lessphp cache structure
1709
- *
1710
- * The lessphp cache structure contains information about a specific
1711
- * less file having been parsed. It can be used as a hint for future
1712
- * calls to determine whether or not a rebuild is required.
1713
- *
1714
- * The cache structure contains two important keys that may be used
1715
- * externally:
1716
- *
1717
- * compiled: The final compiled CSS
1718
- * updated: The time (in seconds) the CSS was last compiled
1719
- *
1720
- * The cache structure is a plain-ol' PHP associative array and can
1721
- * be serialized and unserialized without a hitch.
1722
- *
1723
- * @param mixed $in Input
1724
- * @param bool $force Force rebuild?
1725
- * @return array lessphp cache structure
1726
- */
1727
- public function cachedCompile($in, $force = false) {
1728
- // assume no root
1729
- $root = null;
1730
-
1731
- if (is_string($in)) {
1732
- $root = $in;
1733
- } elseif (is_array($in) and isset($in['root'])) {
1734
- if ($force or ! isset($in['files'])) {
1735
- // If we are forcing a recompile or if for some reason the
1736
- // structure does not contain any file information we should
1737
- // specify the root to trigger a rebuild.
1738
- $root = $in['root'];
1739
- } elseif (isset($in['files']) and is_array($in['files'])) {
1740
- foreach ($in['files'] as $fname => $ftime ) {
1741
- if (!file_exists($fname) or filemtime($fname) > $ftime) {
1742
- // One of the files we knew about previously has changed
1743
- // so we should look at our incoming root again.
1744
- $root = $in['root'];
1745
- break;
1746
- }
1747
- }
1748
- }
1749
- } else {
1750
- // TODO: Throw an exception? We got neither a string nor something
1751
- // that looks like a compatible lessphp cache structure.
1752
- return null;
1753
- }
1754
-
1755
- if ($root !== null) {
1756
- // If we have a root value which means we should rebuild.
1757
- $out = array();
1758
- $out['root'] = $root;
1759
- $out['compiled'] = $this->compileFile($root);
1760
- $out['files'] = $this->allParsedFiles();
1761
- $out['updated'] = time();
1762
- return $out;
1763
- } else {
1764
- // No changes, pass back the structure
1765
- // we were given initially.
1766
- return $in;
1767
- }
1768
-
1769
- }
1770
-
1771
- // parse and compile buffer
1772
- // This is deprecated
1773
- public function parse($str = null, $initialVariables = null) {
1774
- if (is_array($str)) {
1775
- $initialVariables = $str;
1776
- $str = null;
1777
- }
1778
-
1779
- $oldVars = $this->registeredVars;
1780
- if ($initialVariables !== null) {
1781
- $this->setVariables($initialVariables);
1782
- }
1783
-
1784
- if ($str == null) {
1785
- if (empty($this->_parseFile)) {
1786
- throw new exception("nothing to parse");
1787
- }
1788
-
1789
- $out = $this->compileFile($this->_parseFile);
1790
- } else {
1791
- $out = $this->compile($str);
1792
- }
1793
-
1794
- $this->registeredVars = $oldVars;
1795
- return $out;
1796
- }
1797
-
1798
- protected function makeParser($name) {
1799
- $parser = new lessc_parser($this, $name);
1800
- $parser->writeComments = $this->preserveComments;
1801
-
1802
- return $parser;
1803
- }
1804
-
1805
- public function setFormatter($name) {
1806
- $this->formatterName = $name;
1807
- }
1808
-
1809
- protected function newFormatter() {
1810
- $className = "lessc_formatter_lessjs";
1811
- if (!empty($this->formatterName)) {
1812
- if (!is_string($this->formatterName))
1813
- return $this->formatterName;
1814
- $className = "lessc_formatter_$this->formatterName";
1815
- }
1816
-
1817
- return new $className;
1818
- }
1819
-
1820
- public function setPreserveComments($preserve) {
1821
- $this->preserveComments = $preserve;
1822
- }
1823
-
1824
- public function registerFunction($name, $func) {
1825
- $this->libFunctions[$name] = $func;
1826
- }
1827
-
1828
- public function unregisterFunction($name) {
1829
- unset($this->libFunctions[$name]);
1830
- }
1831
-
1832
- public function setVariables($variables) {
1833
- $this->registeredVars = array_merge($this->registeredVars, $variables);
1834
- }
1835
-
1836
- public function unsetVariable($name) {
1837
- unset($this->registeredVars[$name]);
1838
- }
1839
-
1840
- public function setImportDir($dirs) {
1841
- $this->importDir = (array)$dirs;
1842
- }
1843
-
1844
- public function addImportDir($dir) {
1845
- $this->importDir = (array)$this->importDir;
1846
- $this->importDir[] = $dir;
1847
- }
1848
-
1849
- public function allParsedFiles() {
1850
- return $this->allParsedFiles;
1851
- }
1852
-
1853
- protected function addParsedFile($file) {
1854
- $this->allParsedFiles[realpath($file)] = filemtime($file);
1855
- }
1856
-
1857
- /**
1858
- * Uses the current value of $this->count to show line and line number
1859
- */
1860
- protected function throwError($msg = null) {
1861
- if ($this->sourceLoc >= 0) {
1862
- $this->sourceParser->throwError($msg, $this->sourceLoc);
1863
- }
1864
- throw new exception($msg);
1865
- }
1866
-
1867
- // compile file $in to file $out if $in is newer than $out
1868
- // returns true when it compiles, false otherwise
1869
- public static function ccompile($in, $out, $less = null) {
1870
- if ($less === null) {
1871
- $less = new self;
1872
- }
1873
- return $less->checkedCompile($in, $out);
1874
- }
1875
-
1876
- public static function cexecute($in, $force = false, $less = null) {
1877
- if ($less === null) {
1878
- $less = new self;
1879
- }
1880
- return $less->cachedCompile($in, $force);
1881
- }
1882
-
1883
- static protected $cssColors = array(
1884
- 'aliceblue' => '240,248,255',
1885
- 'antiquewhite' => '250,235,215',
1886
- 'aqua' => '0,255,255',
1887
- 'aquamarine' => '127,255,212',
1888
- 'azure' => '240,255,255',
1889
- 'beige' => '245,245,220',
1890
- 'bisque' => '255,228,196',
1891
- 'black' => '0,0,0',
1892
- 'blanchedalmond' => '255,235,205',
1893
- 'blue' => '0,0,255',
1894
- 'blueviolet' => '138,43,226',
1895
- 'brown' => '165,42,42',
1896
- 'burlywood' => '222,184,135',
1897
- 'cadetblue' => '95,158,160',
1898
- 'chartreuse' => '127,255,0',
1899
- 'chocolate' => '210,105,30',
1900
- 'coral' => '255,127,80',
1901
- 'cornflowerblue' => '100,149,237',
1902
- 'cornsilk' => '255,248,220',
1903
- 'crimson' => '220,20,60',
1904
- 'cyan' => '0,255,255',
1905
- 'darkblue' => '0,0,139',
1906
- 'darkcyan' => '0,139,139',
1907
- 'darkgoldenrod' => '184,134,11',
1908
- 'darkgray' => '169,169,169',
1909
- 'darkgreen' => '0,100,0',
1910
- 'darkgrey' => '169,169,169',
1911
- 'darkkhaki' => '189,183,107',
1912
- 'darkmagenta' => '139,0,139',
1913
- 'darkolivegreen' => '85,107,47',
1914
- 'darkorange' => '255,140,0',
1915
- 'darkorchid' => '153,50,204',
1916
- 'darkred' => '139,0,0',
1917
- 'darksalmon' => '233,150,122',
1918
- 'darkseagreen' => '143,188,143',
1919
- 'darkslateblue' => '72,61,139',
1920
- 'darkslategray' => '47,79,79',
1921
- 'darkslategrey' => '47,79,79',
1922
- 'darkturquoise' => '0,206,209',
1923
- 'darkviolet' => '148,0,211',
1924
- 'deeppink' => '255,20,147',
1925
- 'deepskyblue' => '0,191,255',
1926
- 'dimgray' => '105,105,105',
1927
- 'dimgrey' => '105,105,105',
1928
- 'dodgerblue' => '30,144,255',
1929
- 'firebrick' => '178,34,34',
1930
- 'floralwhite' => '255,250,240',
1931
- 'forestgreen' => '34,139,34',
1932
- 'fuchsia' => '255,0,255',
1933
- 'gainsboro' => '220,220,220',
1934
- 'ghostwhite' => '248,248,255',
1935
- 'gold' => '255,215,0',
1936
- 'goldenrod' => '218,165,32',
1937
- 'gray' => '128,128,128',
1938
- 'green' => '0,128,0',
1939
- 'greenyellow' => '173,255,47',
1940
- 'grey' => '128,128,128',
1941
- 'honeydew' => '240,255,240',
1942
- 'hotpink' => '255,105,180',
1943
- 'indianred' => '205,92,92',
1944
- 'indigo' => '75,0,130',
1945
- 'ivory' => '255,255,240',
1946
- 'khaki' => '240,230,140',
1947
- 'lavender' => '230,230,250',
1948
- 'lavenderblush' => '255,240,245',
1949
- 'lawngreen' => '124,252,0',
1950
- 'lemonchiffon' => '255,250,205',
1951
- 'lightblue' => '173,216,230',
1952
- 'lightcoral' => '240,128,128',
1953
- 'lightcyan' => '224,255,255',
1954
- 'lightgoldenrodyellow' => '250,250,210',
1955
- 'lightgray' => '211,211,211',
1956
- 'lightgreen' => '144,238,144',
1957
- 'lightgrey' => '211,211,211',
1958
- 'lightpink' => '255,182,193',
1959
- 'lightsalmon' => '255,160,122',
1960
- 'lightseagreen' => '32,178,170',
1961
- 'lightskyblue' => '135,206,250',
1962
- 'lightslategray' => '119,136,153',
1963
- 'lightslategrey' => '119,136,153',
1964
- 'lightsteelblue' => '176,196,222',
1965
- 'lightyellow' => '255,255,224',
1966
- 'lime' => '0,255,0',
1967
- 'limegreen' => '50,205,50',
1968
- 'linen' => '250,240,230',
1969
- 'magenta' => '255,0,255',
1970
- 'maroon' => '128,0,0',
1971
- 'mediumaquamarine' => '102,205,170',
1972
- 'mediumblue' => '0,0,205',
1973
- 'mediumorchid' => '186,85,211',
1974
- 'mediumpurple' => '147,112,219',
1975
- 'mediumseagreen' => '60,179,113',
1976
- 'mediumslateblue' => '123,104,238',
1977
- 'mediumspringgreen' => '0,250,154',
1978
- 'mediumturquoise' => '72,209,204',
1979
- 'mediumvioletred' => '199,21,133',
1980
- 'midnightblue' => '25,25,112',
1981
- 'mintcream' => '245,255,250',
1982
- 'mistyrose' => '255,228,225',
1983
- 'moccasin' => '255,228,181',
1984
- 'navajowhite' => '255,222,173',
1985
- 'navy' => '0,0,128',
1986
- 'oldlace' => '253,245,230',
1987
- 'olive' => '128,128,0',
1988
- 'olivedrab' => '107,142,35',
1989
- 'orange' => '255,165,0',
1990
- 'orangered' => '255,69,0',
1991
- 'orchid' => '218,112,214',
1992
- 'palegoldenrod' => '238,232,170',
1993
- 'palegreen' => '152,251,152',
1994
- 'paleturquoise' => '175,238,238',
1995
- 'palevioletred' => '219,112,147',
1996
- 'papayawhip' => '255,239,213',
1997
- 'peachpuff' => '255,218,185',
1998
- 'peru' => '205,133,63',
1999
- 'pink' => '255,192,203',
2000
- 'plum' => '221,160,221',
2001
- 'powderblue' => '176,224,230',
2002
- 'purple' => '128,0,128',
2003
- 'red' => '255,0,0',
2004
- 'rosybrown' => '188,143,143',
2005
- 'royalblue' => '65,105,225',
2006
- 'saddlebrown' => '139,69,19',
2007
- 'salmon' => '250,128,114',
2008
- 'sandybrown' => '244,164,96',
2009
- 'seagreen' => '46,139,87',
2010
- 'seashell' => '255,245,238',
2011
- 'sienna' => '160,82,45',
2012
- 'silver' => '192,192,192',
2013
- 'skyblue' => '135,206,235',
2014
- 'slateblue' => '106,90,205',
2015
- 'slategray' => '112,128,144',
2016
- 'slategrey' => '112,128,144',
2017
- 'snow' => '255,250,250',
2018
- 'springgreen' => '0,255,127',
2019
- 'steelblue' => '70,130,180',
2020
- 'tan' => '210,180,140',
2021
- 'teal' => '0,128,128',
2022
- 'thistle' => '216,191,216',
2023
- 'tomato' => '255,99,71',
2024
- 'transparent' => '0,0,0,0',
2025
- 'turquoise' => '64,224,208',
2026
- 'violet' => '238,130,238',
2027
- 'wheat' => '245,222,179',
2028
- 'white' => '255,255,255',
2029
- 'whitesmoke' => '245,245,245',
2030
- 'yellow' => '255,255,0',
2031
- 'yellowgreen' => '154,205,50'
2032
- );
2033
- }
2034
-
2035
- // responsible for taking a string of LESS code and converting it into a
2036
- // syntax tree
2037
- class lessc_parser {
2038
- static protected $nextBlockId = 0; // used to uniquely identify blocks
2039
-
2040
- static protected $precedence = array(
2041
- '=<' => 0,
2042
- '>=' => 0,
2043
- '=' => 0,
2044
- '<' => 0,
2045
- '>' => 0,
2046
-
2047
- '+' => 1,
2048
- '-' => 1,
2049
- '*' => 2,
2050
- '/' => 2,
2051
- '%' => 2,
2052
- );
2053
-
2054
- static protected $whitePattern;
2055
- static protected $commentMulti;
2056
-
2057
- static protected $commentSingle = "//";
2058
- static protected $commentMultiLeft = "/*";
2059
- static protected $commentMultiRight = "*/";
2060
-
2061
- // regex string to match any of the operators
2062
- static protected $operatorString;
2063
-
2064
- // these properties will supress division unless it's inside parenthases
2065
- static protected $supressDivisionProps =
2066
- array('/border-radius$/i', '/^font$/i');
2067
-
2068
- protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document");
2069
- protected $lineDirectives = array("charset");
2070
-
2071
- /**
2072
- * if we are in parens we can be more liberal with whitespace around
2073
- * operators because it must evaluate to a single value and thus is less
2074
- * ambiguous.
2075
- *
2076
- * Consider:
2077
- * property1: 10 -5; // is two numbers, 10 and -5
2078
- * property2: (10 -5); // should evaluate to 5
2079
- */
2080
- protected $inParens = false;
2081
-
2082
- // caches preg escaped literals
2083
- static protected $literalCache = array();
2084
-
2085
- public function __construct($lessc, $sourceName = null) {
2086
- $this->eatWhiteDefault = true;
2087
- // reference to less needed for vPrefix, mPrefix, and parentSelector
2088
- $this->lessc = $lessc;
2089
-
2090
- $this->sourceName = $sourceName; // name used for error messages
2091
-
2092
- $this->writeComments = false;
2093
-
2094
- if (!self::$operatorString) {
2095
- self::$operatorString =
2096
- '('.implode('|', array_map(array('lessc', 'preg_quote'),
2097
- array_keys(self::$precedence))).')';
2098
-
2099
- $commentSingle = lessc::preg_quote(self::$commentSingle);
2100
- $commentMultiLeft = lessc::preg_quote(self::$commentMultiLeft);
2101
- $commentMultiRight = lessc::preg_quote(self::$commentMultiRight);
2102
-
2103
- self::$commentMulti = $commentMultiLeft.'.*?'.$commentMultiRight;
2104
- self::$whitePattern = '/'.$commentSingle.'[^\n]*\s*|('.self::$commentMulti.')\s*|\s+/Ais';
2105
- }
2106
- }
2107
-
2108
- public function parse($buffer) {
2109
- $this->count = 0;
2110
- $this->line = 1;
2111
-
2112
- $this->env = null; // block stack
2113
- $this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer);
2114
- $this->pushSpecialBlock("root");
2115
- $this->eatWhiteDefault = true;
2116
- $this->seenComments = array();
2117
-
2118
- // trim whitespace on head
2119
- // if (preg_match('/^\s+/', $this->buffer, $m)) {
2120
- // $this->line += substr_count($m[0], "\n");
2121
- // $this->buffer = ltrim($this->buffer);
2122
- // }
2123
- $this->whitespace();
2124
-
2125
- // parse the entire file
2126
- $lastCount = $this->count;
2127
- while (false !== $this->parseChunk());
2128
-
2129
- if ($this->count != strlen($this->buffer))
2130
- $this->throwError();
2131
-
2132
- // TODO report where the block was opened
2133
- if (!is_null($this->env->parent))
2134
- throw new exception('parse error: unclosed block');
2135
-
2136
- return $this->env;
2137
- }
2138
-
2139
- /**
2140
- * Parse a single chunk off the head of the buffer and append it to the
2141
- * current parse environment.
2142
- * Returns false when the buffer is empty, or when there is an error.
2143
- *
2144
- * This function is called repeatedly until the entire document is
2145
- * parsed.
2146
- *
2147
- * This parser is most similar to a recursive descent parser. Single
2148
- * functions represent discrete grammatical rules for the language, and
2149
- * they are able to capture the text that represents those rules.
2150
- *
2151
- * Consider the function lessc::keyword(). (all parse functions are
2152
- * structured the same)
2153
- *
2154
- * The function takes a single reference argument. When calling the
2155
- * function it will attempt to match a keyword on the head of the buffer.
2156
- * If it is successful, it will place the keyword in the referenced
2157
- * argument, advance the position in the buffer, and return true. If it
2158
- * fails then it won't advance the buffer and it will return false.
2159
- *
2160
- * All of these parse functions are powered by lessc::match(), which behaves
2161
- * the same way, but takes a literal regular expression. Sometimes it is
2162
- * more convenient to use match instead of creating a new function.
2163
- *
2164
- * Because of the format of the functions, to parse an entire string of
2165
- * grammatical rules, you can chain them together using &&.
2166
- *
2167
- * But, if some of the rules in the chain succeed before one fails, then
2168
- * the buffer position will be left at an invalid state. In order to
2169
- * avoid this, lessc::seek() is used to remember and set buffer positions.
2170
- *
2171
- * Before parsing a chain, use $s = $this->seek() to remember the current
2172
- * position into $s. Then if a chain fails, use $this->seek($s) to
2173
- * go back where we started.
2174
- */
2175
- protected function parseChunk() {
2176
- if (empty($this->buffer)) return false;
2177
- $s = $this->seek();
2178
-
2179
- // setting a property
2180
- if ($this->keyword($key) && $this->assign() &&
2181
- $this->propertyValue($value, $key) && $this->end())
2182
- {
2183
- $this->append(array('assign', $key, $value), $s);
2184
- return true;
2185
- } else {
2186
- $this->seek($s);
2187
- }
2188
-
2189
-
2190
- // look for special css blocks
2191
- if ($this->literal('@', false)) {
2192
- $this->count--;
2193
-
2194
- // media
2195
- if ($this->literal('@media')) {
2196
- if (($this->mediaQueryList($mediaQueries) || true)
2197
- && $this->literal('{'))
2198
- {
2199
- $media = $this->pushSpecialBlock("media");
2200
- $media->queries = is_null($mediaQueries) ? array() : $mediaQueries;
2201
- return true;
2202
- } else {
2203
- $this->seek($s);
2204
- return false;
2205
- }
2206
- }
2207
-
2208
- if ($this->literal("@", false) && $this->keyword($dirName)) {
2209
- if ($this->isDirective($dirName, $this->blockDirectives)) {
2210
- if (($this->openString("{", $dirValue, null, array(";")) || true) &&
2211
- $this->literal("{"))
2212
- {
2213
- $dir = $this->pushSpecialBlock("directive");
2214
- $dir->name = $dirName;
2215
- if (isset($dirValue)) $dir->value = $dirValue;
2216
- return true;
2217
- }
2218
- } elseif ($this->isDirective($dirName, $this->lineDirectives)) {
2219
- if ($this->propertyValue($dirValue) && $this->end()) {
2220
- $this->append(array("directive", $dirName, $dirValue));
2221
- return true;
2222
- }
2223
- }
2224
- }
2225
-
2226
- $this->seek($s);
2227
- }
2228
-
2229
- // setting a variable
2230
- if ($this->variable($var) && $this->assign() &&
2231
- $this->propertyValue($value) && $this->end())
2232
- {
2233
- $this->append(array('assign', $var, $value), $s);
2234
- return true;
2235
- } else {
2236
- $this->seek($s);
2237
- }
2238
-
2239
- if ($this->import($importValue)) {
2240
- $this->append($importValue, $s);
2241
- return true;
2242
- }
2243
-
2244
- // opening parametric mixin
2245
- if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg) &&
2246
- ($this->guards($guards) || true) &&
2247
- $this->literal('{'))
2248
- {
2249
- $block = $this->pushBlock($this->fixTags(array($tag)));
2250
- $block->args = $args;
2251
- $block->isVararg = $isVararg;
2252
- if (!empty($guards)) $block->guards = $guards;
2253
- return true;
2254
- } else {
2255
- $this->seek($s);
2256
- }
2257
-
2258
- // opening a simple block
2259
- if ($this->tags($tags) && $this->literal('{')) {
2260
- $tags = $this->fixTags($tags);
2261
- $this->pushBlock($tags);
2262
- return true;
2263
- } else {
2264
- $this->seek($s);
2265
- }
2266
-
2267
- // closing a block
2268
- if ($this->literal('}', false)) {
2269
- try {
2270
- $block = $this->pop();
2271
- } catch (exception $e) {
2272
- $this->seek($s);
2273
- $this->throwError($e->getMessage());
2274
- }
2275
-
2276
- $hidden = false;
2277
- if (is_null($block->type)) {
2278
- $hidden = true;
2279
- if (!isset($block->args)) {
2280
- foreach ($block->tags as $tag) {
2281
- if (!is_string($tag) || $tag{0} != $this->lessc->mPrefix) {
2282
- $hidden = false;
2283
- break;
2284
- }
2285
- }
2286
- }
2287
-
2288
- foreach ($block->tags as $tag) {
2289
- if (is_string($tag)) {
2290
- $this->env->children[$tag][] = $block;
2291
- }
2292
- }
2293
- }
2294
-
2295
- if (!$hidden) {
2296
- $this->append(array('block', $block), $s);
2297
- }
2298
-
2299
- // this is done here so comments aren't bundled into he block that
2300
- // was just closed
2301
- $this->whitespace();
2302
- return true;
2303
- }
2304
-
2305
- // mixin
2306
- if ($this->mixinTags($tags) &&
2307
- ($this->argumentValues($argv) || true) &&
2308
- ($this->keyword($suffix) || true) && $this->end())
2309
- {
2310
- $tags = $this->fixTags($tags);
2311
- $this->append(array('mixin', $tags, $argv, $suffix), $s);
2312
- return true;
2313
- } else {
2314
- $this->seek($s);
2315
- }
2316
-
2317
- // spare ;
2318
- if ($this->literal(';')) return true;
2319
-
2320
- return false; // got nothing, throw error
2321
- }
2322
-
2323
- protected function isDirective($dirname, $directives) {
2324
- // TODO: cache pattern in parser
2325
- $pattern = implode("|",
2326
- array_map(array("lessc", "preg_quote"), $directives));
2327
- $pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i';
2328
-
2329
- return preg_match($pattern, $dirname);
2330
- }
2331
-
2332
- protected function fixTags($tags) {
2333
- // move @ tags out of variable namespace
2334
- foreach ($tags as &$tag) {
2335
- if ($tag{0} == $this->lessc->vPrefix)
2336
- $tag[0] = $this->lessc->mPrefix;
2337
- }
2338
- return $tags;
2339
- }
2340
-
2341
- // a list of expressions
2342
- protected function expressionList(&$exps) {
2343
- $values = array();
2344
-
2345
- while ($this->expression($exp)) {
2346
- $values[] = $exp;
2347
- }
2348
-
2349
- if (count($values) == 0) return false;
2350
-
2351
- $exps = lessc::compressList($values, ' ');
2352
- return true;
2353
- }
2354
-
2355
- /**
2356
- * Attempt to consume an expression.
2357
- * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
2358
- */
2359
- protected function expression(&$out) {
2360
- if ($this->value($lhs)) {
2361
- $out = $this->expHelper($lhs, 0);
2362
-
2363
- // look for / shorthand
2364
- if (!empty($this->env->supressedDivision)) {
2365
- unset($this->env->supressedDivision);
2366
- $s = $this->seek();
2367
- if ($this->literal("/") && $this->value($rhs)) {
2368
- $out = array("list", "",
2369
- array($out, array("keyword", "/"), $rhs));
2370
- } else {
2371
- $this->seek($s);
2372
- }
2373
- }
2374
-
2375
- return true;
2376
- }
2377
- return false;
2378
- }
2379
-
2380
- /**
2381
- * recursively parse infix equation with $lhs at precedence $minP
2382
- */
2383
- protected function expHelper($lhs, $minP) {
2384
- $this->inExp = true;
2385
- $ss = $this->seek();
2386
-
2387
- while (true) {
2388
- $whiteBefore = isset($this->buffer[$this->count - 1]) &&
2389
- ctype_space($this->buffer[$this->count - 1]);
2390
-
2391
- // If there is whitespace before the operator, then we require
2392
- // whitespace after the operator for it to be an expression
2393
- $needWhite = $whiteBefore && !$this->inParens;
2394
-
2395
- if ($this->match(self::$operatorString.($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) {
2396
- if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) {
2397
- foreach (self::$supressDivisionProps as $pattern) {
2398
- if (preg_match($pattern, $this->env->currentProperty)) {
2399
- $this->env->supressedDivision = true;
2400
- break 2;
2401
- }
2402
- }
2403
- }
2404
-
2405
-
2406
- $whiteAfter = isset($this->buffer[$this->count - 1]) &&
2407
- ctype_space($this->buffer[$this->count - 1]);
2408
-
2409
- if (!$this->value($rhs)) break;
2410
-
2411
- // peek for next operator to see what to do with rhs
2412
- if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]]) {
2413
- $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]);
2414
- }
2415
-
2416
- $lhs = array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter);
2417
- $ss = $this->seek();
2418
-
2419
- continue;
2420
- }
2421
-
2422
- break;
2423
- }
2424
-
2425
- $this->seek($ss);
2426
-
2427
- return $lhs;
2428
- }
2429
-
2430
- // consume a list of values for a property
2431
- public function propertyValue(&$value, $keyName = null) {
2432
- $values = array();
2433
-
2434
- if ($keyName !== null) $this->env->currentProperty = $keyName;
2435
-
2436
- $s = null;
2437
- while ($this->expressionList($v)) {
2438
- $values[] = $v;
2439
- $s = $this->seek();
2440
- if (!$this->literal(',')) break;
2441
- }
2442
-
2443
- if ($s) $this->seek($s);
2444
-
2445
- if ($keyName !== null) unset($this->env->currentProperty);
2446
-
2447
- if (count($values) == 0) return false;
2448
-
2449
- $value = lessc::compressList($values, ', ');
2450
- return true;
2451
- }
2452
-
2453
- protected function parenValue(&$out) {
2454
- $s = $this->seek();
2455
-
2456
- // speed shortcut
2457
- if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") {
2458
- return false;
2459
- }
2460
-
2461
- $inParens = $this->inParens;
2462
- if ($this->literal("(") &&
2463
- ($this->inParens = true) && $this->expression($exp) &&
2464
- $this->literal(")"))
2465
- {
2466
- $out = $exp;
2467
- $this->inParens = $inParens;
2468
- return true;
2469
- } else {
2470
- $this->inParens = $inParens;
2471
- $this->seek($s);
2472
- }
2473
-
2474
- return false;
2475
- }
2476
-
2477
- // a single value
2478
- protected function value(&$value) {
2479
- $s = $this->seek();
2480
-
2481
- // speed shortcut
2482
- if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") {
2483
- // negation
2484
- if ($this->literal("-", false) &&
2485
- (($this->variable($inner) && $inner = array("variable", $inner)) ||
2486
- $this->unit($inner) ||
2487
- $this->parenValue($inner)))
2488
- {
2489
- $value = array("unary", "-", $inner);
2490
- return true;
2491
- } else {
2492
- $this->seek($s);
2493
- }
2494
- }
2495
-
2496
- if ($this->parenValue($value)) return true;
2497
- if ($this->unit($value)) return true;
2498
- if ($this->color($value)) return true;
2499
- if ($this->func($value)) return true;
2500
- if ($this->_string($value)) return true;
2501
-
2502
- if ($this->keyword($word)) {
2503
- $value = array('keyword', $word);
2504
- return true;
2505
- }
2506
-
2507
- // try a variable
2508
- if ($this->variable($var)) {
2509
- $value = array('variable', $var);
2510
- return true;
2511
- }
2512
-
2513
- // unquote string (should this work on any type?
2514
- if ($this->literal("~") && $this->_string($str)) {
2515
- $value = array("escape", $str);
2516
- return true;
2517
- } else {
2518
- $this->seek($s);
2519
- }
2520
-
2521
- // css hack: \0
2522
- if ($this->literal('\\') && $this->match('([0-9]+)', $m)) {
2523
- $value = array('keyword', '\\'.$m[1]);
2524
- return true;
2525
- } else {
2526
- $this->seek($s);
2527
- }
2528
-
2529
- return false;
2530
- }
2531
-
2532
- // an import statement
2533
- protected function import(&$out) {
2534
- $s = $this->seek();
2535
- if (!$this->literal('@import')) return false;
2536
-
2537
- // @import "something.css" media;
2538
- // @import url("something.css") media;
2539
- // @import url(something.css) media;
2540
-
2541
- if ($this->propertyValue($value)) {
2542
- $out = array("import", $value);
2543
- return true;
2544
- }
2545
- }
2546
-
2547
- protected function mediaQueryList(&$out) {
2548
- if ($this->genericList($list, "mediaQuery", ",", false)) {
2549
- $out = $list[2];
2550
- return true;
2551
- }
2552
- return false;
2553
- }
2554
-
2555
- protected function mediaQuery(&$out) {
2556
- $s = $this->seek();
2557
-
2558
- $expressions = null;
2559
- $parts = array();
2560
-
2561
- if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) {
2562
- $prop = array("mediaType");
2563
- if (isset($only)) $prop[] = "only";
2564
- if (isset($not)) $prop[] = "not";
2565
- $prop[] = $mediaType;
2566
- $parts[] = $prop;
2567
- } else {
2568
- $this->seek($s);
2569
- }
2570
-
2571
-
2572
- if (!empty($mediaType) && !$this->literal("and")) {
2573
- // ~
2574
- } else {
2575
- $this->genericList($expressions, "mediaExpression", "and", false);
2576
- if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]);
2577
- }
2578
-
2579
- if (count($parts) == 0) {
2580
- $this->seek($s);
2581
- return false;
2582
- }
2583
-
2584
- $out = $parts;
2585
- return true;
2586
- }
2587
-
2588
- protected function mediaExpression(&$out) {
2589
- $s = $this->seek();
2590
- $value = null;
2591
- if ($this->literal("(") &&
2592
- $this->keyword($feature) &&
2593
- ($this->literal(":") && $this->expression($value) || true) &&
2594
- $this->literal(")"))
2595
- {
2596
- $out = array("mediaExp", $feature);
2597
- if ($value) $out[] = $value;
2598
- return true;
2599
- } elseif ($this->variable($variable)) {
2600
- $out = array('variable', $variable);
2601
- return true;
2602
- }
2603
-
2604
- $this->seek($s);
2605
- return false;
2606
- }
2607
-
2608
- // an unbounded string stopped by $end
2609
- protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null) {
2610
- $oldWhite = $this->eatWhiteDefault;
2611
- $this->eatWhiteDefault = false;
2612
-
2613
- $stop = array("'", '"', "@{", $end);
2614
- $stop = array_map(array("lessc", "preg_quote"), $stop);
2615
- // $stop[] = self::$commentMulti;
2616
-
2617
- if (!is_null($rejectStrs)) {
2618
- $stop = array_merge($stop, $rejectStrs);
2619
- }
2620
-
2621
- $patt = '(.*?)('.implode("|", $stop).')';
2622
-
2623
- $nestingLevel = 0;
2624
-
2625
- $content = array();
2626
- while ($this->match($patt, $m, false)) {
2627
- if (!empty($m[1])) {
2628
- $content[] = $m[1];
2629
- if ($nestingOpen) {
2630
- $nestingLevel += substr_count($m[1], $nestingOpen);
2631
- }
2632
- }
2633
-
2634
- $tok = $m[2];
2635
-
2636
- $this->count-= strlen($tok);
2637
- if ($tok == $end) {
2638
- if ($nestingLevel == 0) {
2639
- break;
2640
- } else {
2641
- $nestingLevel--;
2642
- }
2643
- }
2644
-
2645
- if (($tok == "'" || $tok == '"') && $this->_string($str)) {
2646
- $content[] = $str;
2647
- continue;
2648
- }
2649
-
2650
- if ($tok == "@{" && $this->interpolation($inter)) {
2651
- $content[] = $inter;
2652
- continue;
2653
- }
2654
-
2655
- if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {
2656
- $ount = null;
2657
- break;
2658
- }
2659
-
2660
- $content[] = $tok;
2661
- $this->count+= strlen($tok);
2662
- }
2663
-
2664
- $this->eatWhiteDefault = $oldWhite;
2665
-
2666
- if (count($content) == 0) return false;
2667
-
2668
- // trim the end
2669
- if (is_string(end($content))) {
2670
- $content[count($content) - 1] = rtrim(end($content));
2671
- }
2672
-
2673
- $out = array("string", "", $content);
2674
- return true;
2675
- }
2676
-
2677
- protected function _string(&$out) {
2678
- $s = $this->seek();
2679
- if ($this->literal('"', false)) {
2680
- $delim = '"';
2681
- } elseif ($this->literal("'", false)) {
2682
- $delim = "'";
2683
- } else {
2684
- return false;
2685
- }
2686
-
2687
- $content = array();
2688
-
2689
- // look for either ending delim , escape, or string interpolation
2690
- $patt = '([^\n]*?)(@\{|\\\\|' .
2691
- lessc::preg_quote($delim).')';
2692
-
2693
- $oldWhite = $this->eatWhiteDefault;
2694
- $this->eatWhiteDefault = false;
2695
-
2696
- while ($this->match($patt, $m, false)) {
2697
- $content[] = $m[1];
2698
- if ($m[2] == "@{") {
2699
- $this->count -= strlen($m[2]);
2700
- if ($this->interpolation($inter, false)) {
2701
- $content[] = $inter;
2702
- } else {
2703
- $this->count += strlen($m[2]);
2704
- $content[] = "@{"; // ignore it
2705
- }
2706
- } elseif ($m[2] == '\\') {
2707
- $content[] = $m[2];
2708
- if ($this->literal($delim, false)) {
2709
- $content[] = $delim;
2710
- }
2711
- } else {
2712
- $this->count -= strlen($delim);
2713
- break; // delim
2714
- }
2715
- }
2716
-
2717
- $this->eatWhiteDefault = $oldWhite;
2718
-
2719
- if ($this->literal($delim)) {
2720
- $out = array("string", $delim, $content);
2721
- return true;
2722
- }
2723
-
2724
- $this->seek($s);
2725
- return false;
2726
- }
2727
-
2728
- protected function interpolation(&$out) {
2729
- $oldWhite = $this->eatWhiteDefault;
2730
- $this->eatWhiteDefault = true;
2731
-
2732
- $s = $this->seek();
2733
- if ($this->literal("@{") &&
2734
- $this->openString("}", $interp, null, array("'", '"', ";")) &&
2735
- $this->literal("}", false))
2736
- {
2737
- $out = array("interpolate", $interp);
2738
- $this->eatWhiteDefault = $oldWhite;
2739
- if ($this->eatWhiteDefault) $this->whitespace();
2740
- return true;
2741
- }
2742
-
2743
- $this->eatWhiteDefault = $oldWhite;
2744
- $this->seek($s);
2745
- return false;
2746
- }
2747
-
2748
- protected function unit(&$unit) {
2749
- // speed shortcut
2750
- if (isset($this->buffer[$this->count])) {
2751
- $char = $this->buffer[$this->count];
2752
- if (!ctype_digit($char) && $char != ".") return false;
2753
- }
2754
-
2755
- if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) {
2756
- $unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]);
2757
- return true;
2758
- }
2759
- return false;
2760
- }
2761
-
2762
- // a # color
2763
- protected function color(&$out) {
2764
- if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) {
2765
- if (strlen($m[1]) > 7) {
2766
- $out = array("string", "", array($m[1]));
2767
- } else {
2768
- $out = array("raw_color", $m[1]);
2769
- }
2770
- return true;
2771
- }
2772
-
2773
- return false;
2774
- }
2775
-
2776
- // consume a list of property values delimited by ; and wrapped in ()
2777
- protected function argumentValues(&$args, $delim = ',') {
2778
- $s = $this->seek();
2779
- if (!$this->literal('(')) return false;
2780
-
2781
- $values = array();
2782
- while (true) {
2783
- if ($this->expressionList($value)) $values[] = $value;
2784
- if (!$this->literal($delim)) break;
2785
- else {
2786
- if ($value == null) $values[] = null;
2787
- $value = null;
2788
- }
2789
- }
2790
-
2791
- if (!$this->literal(')')) {
2792
- $this->seek($s);
2793
- return false;
2794
- }
2795
-
2796
- $args = $values;
2797
- return true;
2798
- }
2799
-
2800
- // consume an argument definition list surrounded by ()
2801
- // each argument is a variable name with optional value
2802
- // or at the end a ... or a variable named followed by ...
2803
- protected function argumentDef(&$args, &$isVararg, $delim = ',') {
2804
- $s = $this->seek();
2805
- if (!$this->literal('(')) return false;
2806
-
2807
- $values = array();
2808
-
2809
- $isVararg = false;
2810
- while (true) {
2811
- if ($this->literal("...")) {
2812
- $isVararg = true;
2813
- break;
2814
- }
2815
-
2816
- if ($this->variable($vname)) {
2817
- $arg = array("arg", $vname);
2818
- $ss = $this->seek();
2819
- if ($this->assign() && $this->expressionList($value)) {
2820
- $arg[] = $value;
2821
- } else {
2822
- $this->seek($ss);
2823
- if ($this->literal("...")) {
2824
- $arg[0] = "rest";
2825
- $isVararg = true;
2826
- }
2827
- }
2828
- $values[] = $arg;
2829
- if ($isVararg) break;
2830
- continue;
2831
- }
2832
-
2833
- if ($this->value($literal)) {
2834
- $values[] = array("lit", $literal);
2835
- }
2836
-
2837
- if (!$this->literal($delim)) break;
2838
- }
2839
-
2840
- if (!$this->literal(')')) {
2841
- $this->seek($s);
2842
- return false;
2843
- }
2844
-
2845
- $args = $values;
2846
-
2847
- return true;
2848
- }
2849
-
2850
- // consume a list of tags
2851
- // this accepts a hanging delimiter
2852
- protected function tags(&$tags, $simple = false, $delim = ',') {
2853
- $tags = array();
2854
- while ($this->tag($tt, $simple)) {
2855
- $tags[] = $tt;
2856
- if (!$this->literal($delim)) break;
2857
- }
2858
- if (count($tags) == 0) return false;
2859
-
2860
- return true;
2861
- }
2862
-
2863
- // list of tags of specifying mixin path
2864
- // optionally separated by > (lazy, accepts extra >)
2865
- protected function mixinTags(&$tags) {
2866
- $s = $this->seek();
2867
- $tags = array();
2868
- while ($this->tag($tt, true)) {
2869
- $tags[] = $tt;
2870
- $this->literal(">");
2871
- }
2872
-
2873
- if (count($tags) == 0) return false;
2874
-
2875
- return true;
2876
- }
2877
-
2878
- // a bracketed value (contained within in a tag definition)
2879
- protected function tagBracket(&$value) {
2880
- // speed shortcut
2881
- if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
2882
- return false;
2883
- }
2884
-
2885
- $s = $this->seek();
2886
- if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false)) {
2887
- $value = '['.$c.']';
2888
- // whitespace?
2889
- if ($this->whitespace()) $value .= " ";
2890
-
2891
- // escape parent selector, (yuck)
2892
- $value = str_replace($this->lessc->parentSelector, "$&$", $value);
2893
- return true;
2894
- }
2895
-
2896
- $this->seek($s);
2897
- return false;
2898
- }
2899
-
2900
- protected function tagExpression(&$value) {
2901
- $s = $this->seek();
2902
- if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
2903
- $value = array('exp', $exp);
2904
- return true;
2905
- }
2906
-
2907
- $this->seek($s);
2908
- return false;
2909
- }
2910
-
2911
- // a space separated list of selectors
2912
- protected function tag(&$tag, $simple = false) {
2913
- if ($simple)
2914
- $chars = '^@,:;{}\][>\(\) "\'';
2915
- else
2916
- $chars = '^@,;{}["\'';
2917
-
2918
- $s = $this->seek();
2919
-
2920
- if (!$simple && $this->tagExpression($tag)) {
2921
- return true;
2922
- }
2923
-
2924
- $hasExpression = false;
2925
- $parts = array();
2926
- while ($this->tagBracket($first)) $parts[] = $first;
2927
-
2928
- $oldWhite = $this->eatWhiteDefault;
2929
- $this->eatWhiteDefault = false;
2930
-
2931
- while (true) {
2932
- if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) {
2933
- $parts[] = $m[1];
2934
- if ($simple) break;
2935
-
2936
- while ($this->tagBracket($brack)) {
2937
- $parts[] = $brack;
2938
- }
2939
- continue;
2940
- }
2941
-
2942
- if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") {
2943
- if ($this->interpolation($interp)) {
2944
- $hasExpression = true;
2945
- $interp[2] = true; // don't unescape
2946
- $parts[] = $interp;
2947
- continue;
2948
- }
2949
-
2950
- if ($this->literal("@")) {
2951
- $parts[] = "@";
2952
- continue;
2953
- }
2954
- }
2955
-
2956
- if ($this->unit($unit)) { // for keyframes
2957
- $parts[] = $unit[1];
2958
- $parts[] = $unit[2];
2959
- continue;
2960
- }
2961
-
2962
- break;
2963
- }
2964
-
2965
- $this->eatWhiteDefault = $oldWhite;
2966
- if (!$parts) {
2967
- $this->seek($s);
2968
- return false;
2969
- }
2970
-
2971
- if ($hasExpression) {
2972
- $tag = array("exp", array("string", "", $parts));
2973
- } else {
2974
- $tag = trim(implode($parts));
2975
- }
2976
-
2977
- $this->whitespace();
2978
- return true;
2979
- }
2980
-
2981
- // a css function
2982
- protected function func(&$func) {
2983
- $s = $this->seek();
2984
-
2985
- if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('(')) {
2986
- $fname = $m[1];
2987
-
2988
- $sPreArgs = $this->seek();
2989
-
2990
- $args = array();
2991
- while (true) {
2992
- $ss = $this->seek();
2993
- // this ugly nonsense is for ie filter properties
2994
- if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) {
2995
- $args[] = array("string", "", array($name, "=", $value));
2996
- } else {
2997
- $this->seek($ss);
2998
- if ($this->expressionList($value)) {
2999
- $args[] = $value;
3000
- }
3001
- }
3002
-
3003
- if (!$this->literal(',')) break;
3004
- }
3005
- $args = array('list', ',', $args);
3006
-
3007
- if ($this->literal(')')) {
3008
- $func = array('function', $fname, $args);
3009
- return true;
3010
- } elseif ($fname == 'url') {
3011
- // couldn't parse and in url? treat as string
3012
- $this->seek($sPreArgs);
3013
- if ($this->openString(")", $string) && $this->literal(")")) {
3014
- $func = array('function', $fname, $string);
3015
- return true;
3016
- }
3017
- }
3018
- }
3019
-
3020
- $this->seek($s);
3021
- return false;
3022
- }
3023
-
3024
- // consume a less variable
3025
- protected function variable(&$name) {
3026
- $s = $this->seek();
3027
- if ($this->literal($this->lessc->vPrefix, false) &&
3028
- ($this->variable($sub) || $this->keyword($name)))
3029
- {
3030
- if (!empty($sub)) {
3031
- $name = array('variable', $sub);
3032
- } else {
3033
- $name = $this->lessc->vPrefix.$name;
3034
- }
3035
- return true;
3036
- }
3037
-
3038
- $name = null;
3039
- $this->seek($s);
3040
- return false;
3041
- }
3042
-
3043
- /**
3044
- * Consume an assignment operator
3045
- * Can optionally take a name that will be set to the current property name
3046
- */
3047
- protected function assign($name = null) {
3048
- if ($name) $this->currentProperty = $name;
3049
- return $this->literal(':') || $this->literal('=');
3050
- }
3051
-
3052
- // consume a keyword
3053
- protected function keyword(&$word) {
3054
- if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) {
3055
- $word = $m[1];
3056
- return true;
3057
- }
3058
- return false;
3059
- }
3060
-
3061
- // consume an end of statement delimiter
3062
- protected function end() {
3063
- if ($this->literal(';')) {
3064
- return true;
3065
- } elseif ($this->count == strlen($this->buffer) || $this->buffer{$this->count} == '}') {
3066
- // if there is end of file or a closing block next then we don't need a ;
3067
- return true;
3068
- }
3069
- return false;
3070
- }
3071
-
3072
- protected function guards(&$guards) {
3073
- $s = $this->seek();
3074
-
3075
- if (!$this->literal("when")) {
3076
- $this->seek($s);
3077
- return false;
3078
- }
3079
-
3080
- $guards = array();
3081
-
3082
- while ($this->guardGroup($g)) {
3083
- $guards[] = $g;
3084
- if (!$this->literal(",")) break;
3085
- }
3086
-
3087
- if (count($guards) == 0) {
3088
- $guards = null;
3089
- $this->seek($s);
3090
- return false;
3091
- }
3092
-
3093
- return true;
3094
- }
3095
-
3096
- // a bunch of guards that are and'd together
3097
- // TODO rename to guardGroup
3098
- protected function guardGroup(&$guardGroup) {
3099
- $s = $this->seek();
3100
- $guardGroup = array();
3101
- while ($this->guard($guard)) {
3102
- $guardGroup[] = $guard;
3103
- if (!$this->literal("and")) break;
3104
- }
3105
-
3106
- if (count($guardGroup) == 0) {
3107
- $guardGroup = null;
3108
- $this->seek($s);
3109
- return false;
3110
- }
3111
-
3112
- return true;
3113
- }
3114
-
3115
- protected function guard(&$guard) {
3116
- $s = $this->seek();
3117
- $negate = $this->literal("not");
3118
-
3119
- if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
3120
- $guard = $exp;
3121
- if ($negate) $guard = array("negate", $guard);
3122
- return true;
3123
- }
3124
-
3125
- $this->seek($s);
3126
- return false;
3127
- }
3128
-
3129
- /* raw parsing functions */
3130
-
3131
- protected function literal($what, $eatWhitespace = null) {
3132
- if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
3133
-
3134
- // shortcut on single letter
3135
- if (!isset($what[1]) && isset($this->buffer[$this->count])) {
3136
- if ($this->buffer[$this->count] == $what) {
3137
- if (!$eatWhitespace) {
3138
- $this->count++;
3139
- return true;
3140
- }
3141
- // goes below...
3142
- } else {
3143
- return false;
3144
- }
3145
- }
3146
-
3147
- if (!isset(self::$literalCache[$what])) {
3148
- self::$literalCache[$what] = lessc::preg_quote($what);
3149
- }
3150
-
3151
- return $this->match(self::$literalCache[$what], $m, $eatWhitespace);
3152
- }
3153
-
3154
- protected function genericList(&$out, $parseItem, $delim="", $flatten=true) {
3155
- $s = $this->seek();
3156
- $items = array();
3157
- while ($this->$parseItem($value)) {
3158
- $items[] = $value;
3159
- if ($delim) {
3160
- if (!$this->literal($delim)) break;
3161
- }
3162
- }
3163
-
3164
- if (count($items) == 0) {
3165
- $this->seek($s);
3166
- return false;
3167
- }
3168
-
3169
- if ($flatten && count($items) == 1) {
3170
- $out = $items[0];
3171
- } else {
3172
- $out = array("list", $delim, $items);
3173
- }
3174
-
3175
- return true;
3176
- }
3177
-
3178
-
3179
- // advance counter to next occurrence of $what
3180
- // $until - don't include $what in advance
3181
- // $allowNewline, if string, will be used as valid char set
3182
- protected function to($what, &$out, $until = false, $allowNewline = false) {
3183
- if (is_string($allowNewline)) {
3184
- $validChars = $allowNewline;
3185
- } else {
3186
- $validChars = $allowNewline ? "." : "[^\n]";
3187
- }
3188
- if (!$this->match('('.$validChars.'*?)'.lessc::preg_quote($what), $m, !$until)) return false;
3189
- if ($until) $this->count -= strlen($what); // give back $what
3190
- $out = $m[1];
3191
- return true;
3192
- }
3193
-
3194
- // try to match something on head of buffer
3195
- protected function match($regex, &$out, $eatWhitespace = null) {
3196
- if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
3197
-
3198
- $r = '/'.$regex.($eatWhitespace && !$this->writeComments ? '\s*' : '').'/Ais';
3199
- if (preg_match($r, $this->buffer, $out, null, $this->count)) {
3200
- $this->count += strlen($out[0]);
3201
- if ($eatWhitespace && $this->writeComments) $this->whitespace();
3202
- return true;
3203
- }
3204
- return false;
3205
- }
3206
-
3207
- // match some whitespace
3208
- protected function whitespace() {
3209
- if ($this->writeComments) {
3210
- $gotWhite = false;
3211
- while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) {
3212
- if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
3213
- $this->append(array("comment", $m[1]));
3214
- $this->commentsSeen[$this->count] = true;
3215
- }
3216
- $this->count += strlen($m[0]);
3217
- $gotWhite = true;
3218
- }
3219
- return $gotWhite;
3220
- } else {
3221
- $this->match("", $m);
3222
- return strlen($m[0]) > 0;
3223
- }
3224
- }
3225
-
3226
- // match something without consuming it
3227
- protected function peek($regex, &$out = null, $from=null) {
3228
- if (is_null($from)) $from = $this->count;
3229
- $r = '/'.$regex.'/Ais';
3230
- $result = preg_match($r, $this->buffer, $out, null, $from);
3231
-
3232
- return $result;
3233
- }
3234
-
3235
- // seek to a spot in the buffer or return where we are on no argument
3236
- protected function seek($where = null) {
3237
- if ($where === null) return $this->count;
3238
- else $this->count = $where;
3239
- return true;
3240
- }
3241
-
3242
- /* misc functions */
3243
-
3244
- public function throwError($msg = "parse error", $count = null) {
3245
- $count = is_null($count) ? $this->count : $count;
3246
-
3247
- $line = $this->line +
3248
- substr_count(substr($this->buffer, 0, $count), "\n");
3249
-
3250
- if (!empty($this->sourceName)) {
3251
- $loc = "$this->sourceName on line $line";
3252
- } else {
3253
- $loc = "line: $line";
3254
- }
3255
-
3256
- // TODO this depends on $this->count
3257
- if ($this->peek("(.*?)(\n|$)", $m, $count)) {
3258
- throw new exception("$msg: failed at `$m[1]` $loc");
3259
- } else {
3260
- throw new exception("$msg: $loc");
3261
- }
3262
- }
3263
-
3264
- protected function pushBlock($selectors=null, $type=null) {
3265
- $b = new stdclass;
3266
- $b->parent = $this->env;
3267
-
3268
- $b->type = $type;
3269
- $b->id = self::$nextBlockId++;
3270
-
3271
- $b->isVararg = false; // TODO: kill me from here
3272
- $b->tags = $selectors;
3273
-
3274
- $b->props = array();
3275
- $b->children = array();
3276
-
3277
- $this->env = $b;
3278
- return $b;
3279
- }
3280
-
3281
- // push a block that doesn't multiply tags
3282
- protected function pushSpecialBlock($type) {
3283
- return $this->pushBlock(null, $type);
3284
- }
3285
-
3286
- // append a property to the current block
3287
- protected function append($prop, $pos = null) {
3288
- if ($pos !== null) $prop[-1] = $pos;
3289
- $this->env->props[] = $prop;
3290
- }
3291
-
3292
- // pop something off the stack
3293
- protected function pop() {
3294
- $old = $this->env;
3295
- $this->env = $this->env->parent;
3296
- return $old;
3297
- }
3298
-
3299
- // remove comments from $text
3300
- // todo: make it work for all functions, not just url
3301
- protected function removeComments($text) {
3302
- $look = array(
3303
- 'url(', '//', '/*', '"', "'"
3304
- );
3305
-
3306
- $out = '';
3307
- $min = null;
3308
- while (true) {
3309
- // find the next item
3310
- foreach ($look as $token) {
3311
- $pos = strpos($text, $token);
3312
- if ($pos !== false) {
3313
- if (!isset($min) || $pos < $min[1]) $min = array($token, $pos);
3314
- }
3315
- }
3316
-
3317
- if (is_null($min)) break;
3318
-
3319
- $count = $min[1];
3320
- $skip = 0;
3321
- $newlines = 0;
3322
- switch ($min[0]) {
3323
- case 'url(':
3324
- if (preg_match('/url\(.*?\)/', $text, $m, 0, $count))
3325
- $count += strlen($m[0]) - strlen($min[0]);
3326
- break;
3327
- case '"':
3328
- case "'":
3329
- if (preg_match('/'.$min[0].'.*?'.$min[0].'/', $text, $m, 0, $count))
3330
- $count += strlen($m[0]) - 1;
3331
- break;
3332
- case '//':
3333
- $skip = strpos($text, "\n", $count);
3334
- if ($skip === false) $skip = strlen($text) - $count;
3335
- else $skip -= $count;
3336
- break;
3337
- case '/*':
3338
- if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) {
3339
- $skip = strlen($m[0]);
3340
- $newlines = substr_count($m[0], "\n");
3341
- }
3342
- break;
3343
- }
3344
-
3345
- if ($skip == 0) $count += strlen($min[0]);
3346
-
3347
- $out .= substr($text, 0, $count).str_repeat("\n", $newlines);
3348
- $text = substr($text, $count + $skip);
3349
-
3350
- $min = null;
3351
- }
3352
-
3353
- return $out.$text;
3354
- }
3355
-
3356
- }
3357
-
3358
- class lessc_formatter_classic {
3359
- public $indentChar = " ";
3360
-
3361
- public $break = "\n";
3362
- public $open = " {";
3363
- public $close = "}";
3364
- public $selectorSeparator = ", ";
3365
- public $assignSeparator = ":";
3366
-
3367
- public $openSingle = " { ";
3368
- public $closeSingle = " }";
3369
-
3370
- public $disableSingle = false;
3371
- public $breakSelectors = false;
3372
-
3373
- public $compressColors = false;
3374
-
3375
- public function __construct() {
3376
- $this->indentLevel = 0;
3377
- }
3378
-
3379
- public function indentStr($n = 0) {
3380
- return str_repeat($this->indentChar, max($this->indentLevel + $n, 0));
3381
- }
3382
-
3383
- public function property($name, $value) {
3384
- return $name . $this->assignSeparator . $value . ";";
3385
- }
3386
-
3387
- protected function isEmpty($block) {
3388
- if (empty($block->lines)) {
3389
- foreach ($block->children as $child) {
3390
- if (!$this->isEmpty($child)) return false;
3391
- }
3392
-
3393
- return true;
3394
- }
3395
- return false;
3396
- }
3397
-
3398
- public function block($block) {
3399
- if ($this->isEmpty($block)) return;
3400
-
3401
- $inner = $pre = $this->indentStr();
3402
-
3403
- $isSingle = !$this->disableSingle &&
3404
- is_null($block->type) && count($block->lines) == 1;
3405
-
3406
- if (!empty($block->selectors)) {
3407
- $this->indentLevel++;
3408
-
3409
- if ($this->breakSelectors) {
3410
- $selectorSeparator = $this->selectorSeparator . $this->break . $pre;
3411
- } else {
3412
- $selectorSeparator = $this->selectorSeparator;
3413
- }
3414
-
3415
- echo $pre .
3416
- implode($selectorSeparator, $block->selectors);
3417
- if ($isSingle) {
3418
- echo $this->openSingle;
3419
- $inner = "";
3420
- } else {
3421
- echo $this->open . $this->break;
3422
- $inner = $this->indentStr();
3423
- }
3424
-
3425
- }
3426
-
3427
- if (!empty($block->lines)) {
3428
- $glue = $this->break.$inner;
3429
- echo $inner . implode($glue, $block->lines);
3430
- if (!$isSingle && !empty($block->children)) {
3431
- echo $this->break;
3432
- }
3433
- }
3434
-
3435
- foreach ($block->children as $child) {
3436
- $this->block($child);
3437
- }
3438
-
3439
- if (!empty($block->selectors)) {
3440
- if (!$isSingle && empty($block->children)) echo $this->break;
3441
-
3442
- if ($isSingle) {
3443
- echo $this->closeSingle . $this->break;
3444
- } else {
3445
- echo $pre . $this->close . $this->break;
3446
- }
3447
-
3448
- $this->indentLevel--;
3449
- }
3450
- }
3451
- }
3452
-
3453
- class lessc_formatter_compressed extends lessc_formatter_classic {
3454
- public $disableSingle = true;
3455
- public $open = "{";
3456
- public $selectorSeparator = ",";
3457
- public $assignSeparator = ":";
3458
- public $break = "";
3459
- public $compressColors = true;
3460
-
3461
- public function indentStr($n = 0) {
3462
- return "";
3463
- }
3464
- }
3465
-
3466
- class lessc_formatter_lessjs extends lessc_formatter_classic {
3467
- public $disableSingle = true;
3468
- public $breakSelectors = true;
3469
- public $assignSeparator = ": ";
3470
- public $selectorSeparator = ",";
3471
- }
3472
-
3473
-
1
+ <?php
2
+
3
+ /**
4
+ * lessphp v0.3.9
5
+ * http://leafo.net/lessphp
6
+ *
7
+ * LESS css compiler, adapted from http://lesscss.org
8
+ *
9
+ * Copyright 2012, Leaf Corcoran <leafot@gmail.com>
10
+ * Licensed under MIT or GPLv3, see LICENSE
11
+ */
12
+
13
+
14
+ /**
15
+ * The less compiler and parser.
16
+ *
17
+ * Converting LESS to CSS is a three stage process. The incoming file is parsed
18
+ * by `lessc_parser` into a syntax tree, then it is compiled into another tree
19
+ * representing the CSS structure by `lessc`. The CSS tree is fed into a
20
+ * formatter, like `lessc_formatter` which then outputs CSS as a string.
21
+ *
22
+ * During the first compile, all values are *reduced*, which means that their
23
+ * types are brought to the lowest form before being dump as strings. This
24
+ * handles math equations, variable dereferences, and the like.
25
+ *
26
+ * The `parse` function of `lessc` is the entry point.
27
+ *
28
+ * In summary:
29
+ *
30
+ * The `lessc` class creates an intstance of the parser, feeds it LESS code,
31
+ * then transforms the resulting tree to a CSS tree. This class also holds the
32
+ * evaluation context, such as all available mixins and variables at any given
33
+ * time.
34
+ *
35
+ * The `lessc_parser` class is only concerned with parsing its input.
36
+ *
37
+ * The `lessc_formatter` takes a CSS tree, and dumps it to a formatted string,
38
+ * handling things like indentation.
39
+ */
40
+ class lessc {
41
+ static public $VERSION = "v0.3.9";
42
+ static protected $TRUE = array("keyword", "true");
43
+ static protected $FALSE = array("keyword", "false");
44
+
45
+ protected $libFunctions = array();
46
+ protected $registeredVars = array();
47
+ protected $preserveComments = false;
48
+
49
+ public $vPrefix = '@'; // prefix of abstract properties
50
+ public $mPrefix = '$'; // prefix of abstract blocks
51
+ public $parentSelector = '&';
52
+
53
+ public $importDisabled = false;
54
+ public $importDir = '';
55
+
56
+ protected $numberPrecision = null;
57
+
58
+ // set to the parser that generated the current line when compiling
59
+ // so we know how to create error messages
60
+ protected $sourceParser = null;
61
+ protected $sourceLoc = null;
62
+
63
+ static public $defaultValue = array("keyword", "");
64
+
65
+ static protected $nextImportId = 0; // uniquely identify imports
66
+
67
+ // attempts to find the path of an import url, returns null for css files
68
+ protected function findImport($url) {
69
+ foreach ((array)$this->importDir as $dir) {
70
+ $full = $dir.(substr($dir, -1) != '/' ? '/' : '').$url;
71
+ if ($this->fileExists($file = $full.'.less') || $this->fileExists($file = $full)) {
72
+ return $file;
73
+ }
74
+ }
75
+
76
+ return null;
77
+ }
78
+
79
+ protected function fileExists($name) {
80
+ return is_file($name);
81
+ }
82
+
83
+ static public function compressList($items, $delim) {
84
+ if (!isset($items[1]) && isset($items[0])) return $items[0];
85
+ else return array('list', $delim, $items);
86
+ }
87
+
88
+ static public function preg_quote($what) {
89
+ return preg_quote($what, '/');
90
+ }
91
+
92
+ protected function tryImport($importPath, $parentBlock, $out) {
93
+ if ($importPath[0] == "function" && $importPath[1] == "url") {
94
+ $importPath = $this->flattenList($importPath[2]);
95
+ }
96
+
97
+ $str = $this->coerceString($importPath);
98
+ if ($str === null) return false;
99
+
100
+ $url = $this->compileValue($this->lib_e($str));
101
+
102
+ // don't import if it ends in css
103
+ if (substr_compare($url, '.css', -4, 4) === 0) return false;
104
+
105
+ $realPath = $this->findImport($url);
106
+ if ($realPath === null) return false;
107
+
108
+ if ($this->importDisabled) {
109
+ return array(false, "/* import disabled */");
110
+ }
111
+
112
+ $this->addParsedFile($realPath);
113
+ $parser = $this->makeParser($realPath);
114
+ $root = $parser->parse(file_get_contents($realPath));
115
+
116
+ // set the parents of all the block props
117
+ foreach ($root->props as $prop) {
118
+ if ($prop[0] == "block") {
119
+ $prop[1]->parent = $parentBlock;
120
+ }
121
+ }
122
+
123
+ // copy mixins into scope, set their parents
124
+ // bring blocks from import into current block
125
+ // TODO: need to mark the source parser these came from this file
126
+ foreach ($root->children as $childName => $child) {
127
+ if (isset($parentBlock->children[$childName])) {
128
+ $parentBlock->children[$childName] = array_merge(
129
+ $parentBlock->children[$childName],
130
+ $child);
131
+ } else {
132
+ $parentBlock->children[$childName] = $child;
133
+ }
134
+ }
135
+
136
+ $pi = pathinfo($realPath);
137
+ $dir = $pi["dirname"];
138
+
139
+ list($top, $bottom) = $this->sortProps($root->props, true);
140
+ $this->compileImportedProps($top, $parentBlock, $out, $parser, $dir);
141
+
142
+ return array(true, $bottom, $parser, $dir);
143
+ }
144
+
145
+ protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir) {
146
+ $oldSourceParser = $this->sourceParser;
147
+
148
+ $oldImport = $this->importDir;
149
+
150
+ // TODO: this is because the importDir api is stupid
151
+ $this->importDir = (array)$this->importDir;
152
+ array_unshift($this->importDir, $importDir);
153
+
154
+ foreach ($props as $prop) {
155
+ $this->compileProp($prop, $block, $out);
156
+ }
157
+
158
+ $this->importDir = $oldImport;
159
+ $this->sourceParser = $oldSourceParser;
160
+ }
161
+
162
+ /**
163
+ * Recursively compiles a block.
164
+ *
165
+ * A block is analogous to a CSS block in most cases. A single LESS document
166
+ * is encapsulated in a block when parsed, but it does not have parent tags
167
+ * so all of it's children appear on the root level when compiled.
168
+ *
169
+ * Blocks are made up of props and children.
170
+ *
171
+ * Props are property instructions, array tuples which describe an action
172
+ * to be taken, eg. write a property, set a variable, mixin a block.
173
+ *
174
+ * The children of a block are just all the blocks that are defined within.
175
+ * This is used to look up mixins when performing a mixin.
176
+ *
177
+ * Compiling the block involves pushing a fresh environment on the stack,
178
+ * and iterating through the props, compiling each one.
179
+ *
180
+ * See lessc::compileProp()
181
+ *
182
+ */
183
+ protected function compileBlock($block) {
184
+ switch ($block->type) {
185
+ case "root":
186
+ $this->compileRoot($block);
187
+ break;
188
+ case null:
189
+ $this->compileCSSBlock($block);
190
+ break;
191
+ case "media":
192
+ $this->compileMedia($block);
193
+ break;
194
+ case "directive":
195
+ $name = "@" . $block->name;
196
+ if (!empty($block->value)) {
197
+ $name .= " " . $this->compileValue($this->reduce($block->value));
198
+ }
199
+
200
+ $this->compileNestedBlock($block, array($name));
201
+ break;
202
+ default:
203
+ $this->throwError("unknown block type: $block->type\n");
204
+ }
205
+ }
206
+
207
+ protected function compileCSSBlock($block) {
208
+ $env = $this->pushEnv();
209
+
210
+ $selectors = $this->compileSelectors($block->tags);
211
+ $env->selectors = $this->multiplySelectors($selectors);
212
+ $out = $this->makeOutputBlock(null, $env->selectors);
213
+
214
+ $this->scope->children[] = $out;
215
+ $this->compileProps($block, $out);
216
+
217
+ $block->scope = $env; // mixins carry scope with them!
218
+ $this->popEnv();
219
+ }
220
+
221
+ protected function compileMedia($media) {
222
+ $env = $this->pushEnv($media);
223
+ $parentScope = $this->mediaParent($this->scope);
224
+
225
+ $query = $this->compileMediaQuery($this->multiplyMedia($env));
226
+
227
+ $this->scope = $this->makeOutputBlock($media->type, array($query));
228
+ $parentScope->children[] = $this->scope;
229
+
230
+ $this->compileProps($media, $this->scope);
231
+
232
+ if (count($this->scope->lines) > 0) {
233
+ $orphanSelelectors = $this->findClosestSelectors();
234
+ if (!is_null($orphanSelelectors)) {
235
+ $orphan = $this->makeOutputBlock(null, $orphanSelelectors);
236
+ $orphan->lines = $this->scope->lines;
237
+ array_unshift($this->scope->children, $orphan);
238
+ $this->scope->lines = array();
239
+ }
240
+ }
241
+
242
+ $this->scope = $this->scope->parent;
243
+ $this->popEnv();
244
+ }
245
+
246
+ protected function mediaParent($scope) {
247
+ while (!empty($scope->parent)) {
248
+ if (!empty($scope->type) && $scope->type != "media") {
249
+ break;
250
+ }
251
+ $scope = $scope->parent;
252
+ }
253
+
254
+ return $scope;
255
+ }
256
+
257
+ protected function compileNestedBlock($block, $selectors) {
258
+ $this->pushEnv($block);
259
+ $this->scope = $this->makeOutputBlock($block->type, $selectors);
260
+ $this->scope->parent->children[] = $this->scope;
261
+
262
+ $this->compileProps($block, $this->scope);
263
+
264
+ $this->scope = $this->scope->parent;
265
+ $this->popEnv();
266
+ }
267
+
268
+ protected function compileRoot($root) {
269
+ $this->pushEnv();
270
+ $this->scope = $this->makeOutputBlock($root->type);
271
+ $this->compileProps($root, $this->scope);
272
+ $this->popEnv();
273
+ }
274
+
275
+ protected function compileProps($block, $out) {
276
+ foreach ($this->sortProps($block->props) as $prop) {
277
+ $this->compileProp($prop, $block, $out);
278
+ }
279
+ }
280
+
281
+ protected function sortProps($props, $split = false) {
282
+ $vars = array();
283
+ $imports = array();
284
+ $other = array();
285
+
286
+ foreach ($props as $prop) {
287
+ switch ($prop[0]) {
288
+ case "assign":
289
+ if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) {
290
+ $vars[] = $prop;
291
+ } else {
292
+ $other[] = $prop;
293
+ }
294
+ break;
295
+ case "import":
296
+ $id = self::$nextImportId++;
297
+ $prop[] = $id;
298
+ $imports[] = $prop;
299
+ $other[] = array("import_mixin", $id);
300
+ break;
301
+ default:
302
+ $other[] = $prop;
303
+ }
304
+ }
305
+
306
+ if ($split) {
307
+ return array(array_merge($vars, $imports), $other);
308
+ } else {
309
+ return array_merge($vars, $imports, $other);
310
+ }
311
+ }
312
+
313
+ protected function compileMediaQuery($queries) {
314
+ $compiledQueries = array();
315
+ foreach ($queries as $query) {
316
+ $parts = array();
317
+ foreach ($query as $q) {
318
+ switch ($q[0]) {
319
+ case "mediaType":
320
+ $parts[] = implode(" ", array_slice($q, 1));
321
+ break;
322
+ case "mediaExp":
323
+ if (isset($q[2])) {
324
+ $parts[] = "($q[1]: " .
325
+ $this->compileValue($this->reduce($q[2])) . ")";
326
+ } else {
327
+ $parts[] = "($q[1])";
328
+ }
329
+ break;
330
+ case "variable":
331
+ $parts[] = $this->compileValue($this->reduce($q));
332
+ break;
333
+ }
334
+ }
335
+
336
+ if (count($parts) > 0) {
337
+ $compiledQueries[] = implode(" and ", $parts);
338
+ }
339
+ }
340
+
341
+ $out = "@media";
342
+ if (!empty($parts)) {
343
+ $out .= " " .
344
+ implode($this->formatter->selectorSeparator, $compiledQueries);
345
+ }
346
+ return $out;
347
+ }
348
+
349
+ protected function multiplyMedia($env, $childQueries = null) {
350
+ if (is_null($env) ||
351
+ !empty($env->block->type) && $env->block->type != "media")
352
+ {
353
+ return $childQueries;
354
+ }
355
+
356
+ // plain old block, skip
357
+ if (empty($env->block->type)) {
358
+ return $this->multiplyMedia($env->parent, $childQueries);
359
+ }
360
+
361
+ $out = array();
362
+ $queries = $env->block->queries;
363
+ if (is_null($childQueries)) {
364
+ $out = $queries;
365
+ } else {
366
+ foreach ($queries as $parent) {
367
+ foreach ($childQueries as $child) {
368
+ $out[] = array_merge($parent, $child);
369
+ }
370
+ }
371
+ }
372
+
373
+ return $this->multiplyMedia($env->parent, $out);
374
+ }
375
+
376
+ protected function expandParentSelectors(&$tag, $replace) {
377
+ $parts = explode("$&$", $tag);
378
+ $count = 0;
379
+ foreach ($parts as &$part) {
380
+ $part = str_replace($this->parentSelector, $replace, $part, $c);
381
+ $count += $c;
382
+ }
383
+ $tag = implode($this->parentSelector, $parts);
384
+ return $count;
385
+ }
386
+
387
+ protected function findClosestSelectors() {
388
+ $env = $this->env;
389
+ $selectors = null;
390
+ while ($env !== null) {
391
+ if (isset($env->selectors)) {
392
+ $selectors = $env->selectors;
393
+ break;
394
+ }
395
+ $env = $env->parent;
396
+ }
397
+
398
+ return $selectors;
399
+ }
400
+
401
+
402
+ // multiply $selectors against the nearest selectors in env
403
+ protected function multiplySelectors($selectors) {
404
+ // find parent selectors
405
+
406
+ $parentSelectors = $this->findClosestSelectors();
407
+ if (is_null($parentSelectors)) {
408
+ // kill parent reference in top level selector
409
+ foreach ($selectors as &$s) {
410
+ $this->expandParentSelectors($s, "");
411
+ }
412
+
413
+ return $selectors;
414
+ }
415
+
416
+ $out = array();
417
+ foreach ($parentSelectors as $parent) {
418
+ foreach ($selectors as $child) {
419
+ $count = $this->expandParentSelectors($child, $parent);
420
+
421
+ // don't prepend the parent tag if & was used
422
+ if ($count > 0) {
423
+ $out[] = trim($child);
424
+ } else {
425
+ $out[] = trim($parent . ' ' . $child);
426
+ }
427
+ }
428
+ }
429
+
430
+ return $out;
431
+ }
432
+
433
+ // reduces selector expressions
434
+ protected function compileSelectors($selectors) {
435
+ $out = array();
436
+
437
+ foreach ($selectors as $s) {
438
+ if (is_array($s)) {
439
+ list(, $value) = $s;
440
+ $out[] = trim($this->compileValue($this->reduce($value)));
441
+ } else {
442
+ $out[] = $s;
443
+ }
444
+ }
445
+
446
+ return $out;
447
+ }
448
+
449
+ protected function eq($left, $right) {
450
+ return $left == $right;
451
+ }
452
+
453
+ protected function patternMatch($block, $callingArgs) {
454
+ // match the guards if it has them
455
+ // any one of the groups must have all its guards pass for a match
456
+ if (!empty($block->guards)) {
457
+ $groupPassed = false;
458
+ foreach ($block->guards as $guardGroup) {
459
+ foreach ($guardGroup as $guard) {
460
+ $this->pushEnv();
461
+ $this->zipSetArgs($block->args, $callingArgs);
462
+
463
+ $negate = false;
464
+ if ($guard[0] == "negate") {
465
+ $guard = $guard[1];
466
+ $negate = true;
467
+ }
468
+
469
+ $passed = $this->reduce($guard) == self::$TRUE;
470
+ if ($negate) $passed = !$passed;
471
+
472
+ $this->popEnv();
473
+
474
+ if ($passed) {
475
+ $groupPassed = true;
476
+ } else {
477
+ $groupPassed = false;
478
+ break;
479
+ }
480
+ }
481
+
482
+ if ($groupPassed) break;
483
+ }
484
+
485
+ if (!$groupPassed) {
486
+ return false;
487
+ }
488
+ }
489
+
490
+ $numCalling = count($callingArgs);
491
+
492
+ if (empty($block->args)) {
493
+ return $block->isVararg || $numCalling == 0;
494
+ }
495
+
496
+ $i = -1; // no args
497
+ // try to match by arity or by argument literal
498
+ foreach ($block->args as $i => $arg) {
499
+ switch ($arg[0]) {
500
+ case "lit":
501
+ if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i])) {
502
+ return false;
503
+ }
504
+ break;
505
+ case "arg":
506
+ // no arg and no default value
507
+ if (!isset($callingArgs[$i]) && !isset($arg[2])) {
508
+ return false;
509
+ }
510
+ break;
511
+ case "rest":
512
+ $i--; // rest can be empty
513
+ break 2;
514
+ }
515
+ }
516
+
517
+ if ($block->isVararg) {
518
+ return true; // not having enough is handled above
519
+ } else {
520
+ $numMatched = $i + 1;
521
+ // greater than becuase default values always match
522
+ return $numMatched >= $numCalling;
523
+ }
524
+ }
525
+
526
+ protected function patternMatchAll($blocks, $callingArgs) {
527
+ $matches = null;
528
+ foreach ($blocks as $block) {
529
+ if ($this->patternMatch($block, $callingArgs)) {
530
+ $matches[] = $block;
531
+ }
532
+ }
533
+
534
+ return $matches;
535
+ }
536
+
537
+ // attempt to find blocks matched by path and args
538
+ protected function findBlocks($searchIn, $path, $args, $seen=array()) {
539
+ if ($searchIn == null) return null;
540
+ if (isset($seen[$searchIn->id])) return null;
541
+ $seen[$searchIn->id] = true;
542
+
543
+ $name = $path[0];
544
+
545
+ if (isset($searchIn->children[$name])) {
546
+ $blocks = $searchIn->children[$name];
547
+ if (count($path) == 1) {
548
+ $matches = $this->patternMatchAll($blocks, $args);
549
+ if (!empty($matches)) {
550
+ // This will return all blocks that match in the closest
551
+ // scope that has any matching block, like lessjs
552
+ return $matches;
553
+ }
554
+ } else {
555
+ $matches = array();
556
+ foreach ($blocks as $subBlock) {
557
+ $subMatches = $this->findBlocks($subBlock,
558
+ array_slice($path, 1), $args, $seen);
559
+
560
+ if (!is_null($subMatches)) {
561
+ foreach ($subMatches as $sm) {
562
+ $matches[] = $sm;
563
+ }
564
+ }
565
+ }
566
+
567
+ return count($matches) > 0 ? $matches : null;
568
+ }
569
+ }
570
+
571
+ if ($searchIn->parent === $searchIn) return null;
572
+ return $this->findBlocks($searchIn->parent, $path, $args, $seen);
573
+ }
574
+
575
+ // sets all argument names in $args to either the default value
576
+ // or the one passed in through $values
577
+ protected function zipSetArgs($args, $values) {
578
+ $i = 0;
579
+ $assignedValues = array();
580
+ foreach ($args as $a) {
581
+ if ($a[0] == "arg") {
582
+ if ($i < count($values) && !is_null($values[$i])) {
583
+ $value = $values[$i];
584
+ } elseif (isset($a[2])) {
585
+ $value = $a[2];
586
+ } else $value = null;
587
+
588
+ $value = $this->reduce($value);
589
+ $this->set($a[1], $value);
590
+ $assignedValues[] = $value;
591
+ }
592
+ $i++;
593
+ }
594
+
595
+ // check for a rest
596
+ $last = end($args);
597
+ if ($last[0] == "rest") {
598
+ $rest = array_slice($values, count($args) - 1);
599
+ $this->set($last[1], $this->reduce(array("list", " ", $rest)));
600
+ }
601
+
602
+ $this->env->arguments = $assignedValues;
603
+ }
604
+
605
+ // compile a prop and update $lines or $blocks appropriately
606
+ protected function compileProp($prop, $block, $out) {
607
+ // set error position context
608
+ $this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;
609
+
610
+ switch ($prop[0]) {
611
+ case 'assign':
612
+ list(, $name, $value) = $prop;
613
+ if ($name[0] == $this->vPrefix) {
614
+ $this->set($name, $value);
615
+ } else {
616
+ $out->lines[] = $this->formatter->property($name,
617
+ $this->compileValue($this->reduce($value)));
618
+ }
619
+ break;
620
+ case 'block':
621
+ list(, $child) = $prop;
622
+ $this->compileBlock($child);
623
+ break;
624
+ case 'mixin':
625
+ list(, $path, $args, $suffix) = $prop;
626
+
627
+ $args = array_map(array($this, "reduce"), (array)$args);
628
+ $mixins = $this->findBlocks($block, $path, $args);
629
+
630
+ if ($mixins === null) {
631
+ // fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n");
632
+ break; // throw error here??
633
+ }
634
+
635
+ foreach ($mixins as $mixin) {
636
+ $haveScope = false;
637
+ if (isset($mixin->parent->scope)) {
638
+ $haveScope = true;
639
+ $mixinParentEnv = $this->pushEnv();
640
+ $mixinParentEnv->storeParent = $mixin->parent->scope;
641
+ }
642
+
643
+ $haveArgs = false;
644
+ if (isset($mixin->args)) {
645
+ $haveArgs = true;
646
+ $this->pushEnv();
647
+ $this->zipSetArgs($mixin->args, $args);
648
+ }
649
+
650
+ $oldParent = $mixin->parent;
651
+ if ($mixin != $block) $mixin->parent = $block;
652
+
653
+ foreach ($this->sortProps($mixin->props) as $subProp) {
654
+ if ($suffix !== null &&
655
+ $subProp[0] == "assign" &&
656
+ is_string($subProp[1]) &&
657
+ $subProp[1]{0} != $this->vPrefix)
658
+ {
659
+ $subProp[2] = array(
660
+ 'list', ' ',
661
+ array($subProp[2], array('keyword', $suffix))
662
+ );
663
+ }
664
+
665
+ $this->compileProp($subProp, $mixin, $out);
666
+ }
667
+
668
+ $mixin->parent = $oldParent;
669
+
670
+ if ($haveArgs) $this->popEnv();
671
+ if ($haveScope) $this->popEnv();
672
+ }
673
+
674
+ break;
675
+ case 'raw':
676
+ $out->lines[] = $prop[1];
677
+ break;
678
+ case "directive":
679
+ list(, $name, $value) = $prop;
680
+ $out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';';
681
+ break;
682
+ case "comment":
683
+ $out->lines[] = $prop[1];
684
+ break;
685
+ case "import";
686
+ list(, $importPath, $importId) = $prop;
687
+ $importPath = $this->reduce($importPath);
688
+
689
+ if (!isset($this->env->imports)) {
690
+ $this->env->imports = array();
691
+ }
692
+
693
+ $result = $this->tryImport($importPath, $block, $out);
694
+
695
+ $this->env->imports[$importId] = $result === false ?
696
+ array(false, "@import " . $this->compileValue($importPath).";") :
697
+ $result;
698
+
699
+ break;
700
+ case "import_mixin":
701
+ list(,$importId) = $prop;
702
+ $import = $this->env->imports[$importId];
703
+ if ($import[0] === false) {
704
+ $out->lines[] = $import[1];
705
+ } else {
706
+ list(, $bottom, $parser, $importDir) = $import;
707
+ $this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
708
+ }
709
+
710
+ break;
711
+ default:
712
+ $this->throwError("unknown op: {$prop[0]}\n");
713
+ }
714
+ }
715
+
716
+
717
+ /**
718
+ * Compiles a primitive value into a CSS property value.
719
+ *
720
+ * Values in lessphp are typed by being wrapped in arrays, their format is
721
+ * typically:
722
+ *
723
+ * array(type, contents [, additional_contents]*)
724
+ *
725
+ * The input is expected to be reduced. This function will not work on
726
+ * things like expressions and variables.
727
+ */
728
+ protected function compileValue($value) {
729
+ switch ($value[0]) {
730
+ case 'list':
731
+ // [1] - delimiter
732
+ // [2] - array of values
733
+ return implode($value[1], array_map(array($this, 'compileValue'), $value[2]));
734
+ case 'raw_color':
735
+ if (!empty($this->formatter->compressColors)) {
736
+ return $this->compileValue($this->coerceColor($value));
737
+ }
738
+ return $value[1];
739
+ case 'keyword':
740
+ // [1] - the keyword
741
+ return $value[1];
742
+ case 'number':
743
+ list(, $num, $unit) = $value;
744
+ // [1] - the number
745
+ // [2] - the unit
746
+ if ($this->numberPrecision !== null) {
747
+ $num = round($num, $this->numberPrecision);
748
+ }
749
+ return $num . $unit;
750
+ case 'string':
751
+ // [1] - contents of string (includes quotes)
752
+ list(, $delim, $content) = $value;
753
+ foreach ($content as &$part) {
754
+ if (is_array($part)) {
755
+ $part = $this->compileValue($part);
756
+ }
757
+ }
758
+ return $delim . implode($content) . $delim;
759
+ case 'color':
760
+ // [1] - red component (either number or a %)
761
+ // [2] - green component
762
+ // [3] - blue component
763
+ // [4] - optional alpha component
764
+ list(, $r, $g, $b) = $value;
765
+ $r = round($r);
766
+ $g = round($g);
767
+ $b = round($b);
768
+
769
+ if (count($value) == 5 && $value[4] != 1) { // rgba
770
+ return 'rgba('.$r.','.$g.','.$b.','.$value[4].')';
771
+ }
772
+
773
+ $h = sprintf("#%02x%02x%02x", $r, $g, $b);
774
+
775
+ if (!empty($this->formatter->compressColors)) {
776
+ // Converting hex color to short notation (e.g. #003399 to #039)
777
+ if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) {
778
+ $h = '#' . $h[1] . $h[3] . $h[5];
779
+ }
780
+ }
781
+
782
+ return $h;
783
+
784
+ case 'function':
785
+ list(, $name, $args) = $value;
786
+ return $name.'('.$this->compileValue($args).')';
787
+ default: // assumed to be unit
788
+ $this->throwError("unknown value type: $value[0]");
789
+ }
790
+ }
791
+
792
+ protected function lib_isnumber($value) {
793
+ return $this->toBool($value[0] == "number");
794
+ }
795
+
796
+ protected function lib_isstring($value) {
797
+ return $this->toBool($value[0] == "string");
798
+ }
799
+
800
+ protected function lib_iscolor($value) {
801
+ return $this->toBool($this->coerceColor($value));
802
+ }
803
+
804
+ protected function lib_iskeyword($value) {
805
+ return $this->toBool($value[0] == "keyword");
806
+ }
807
+
808
+ protected function lib_ispixel($value) {
809
+ return $this->toBool($value[0] == "number" && $value[2] == "px");
810
+ }
811
+
812
+ protected function lib_ispercentage($value) {
813
+ return $this->toBool($value[0] == "number" && $value[2] == "%");
814
+ }
815
+
816
+ protected function lib_isem($value) {
817
+ return $this->toBool($value[0] == "number" && $value[2] == "em");
818
+ }
819
+
820
+ protected function lib_isrem($value) {
821
+ return $this->toBool($value[0] == "number" && $value[2] == "rem");
822
+ }
823
+
824
+ protected function lib_rgbahex($color) {
825
+ $color = $this->coerceColor($color);
826
+ if (is_null($color))
827
+ $this->throwError("color expected for rgbahex");
828
+
829
+ return sprintf("#%02x%02x%02x%02x",
830
+ isset($color[4]) ? $color[4]*255 : 255,
831
+ $color[1],$color[2], $color[3]);
832
+ }
833
+
834
+ protected function lib_argb($color){
835
+ return $this->lib_rgbahex($color);
836
+ }
837
+
838
+ // utility func to unquote a string
839
+ protected function lib_e($arg) {
840
+ switch ($arg[0]) {
841
+ case "list":
842
+ $items = $arg[2];
843
+ if (isset($items[0])) {
844
+ return $this->lib_e($items[0]);
845
+ }
846
+ return self::$defaultValue;
847
+ case "string":
848
+ $arg[1] = "";
849
+ return $arg;
850
+ case "keyword":
851
+ return $arg;
852
+ default:
853
+ return array("keyword", $this->compileValue($arg));
854
+ }
855
+ }
856
+
857
+ protected function lib__sprintf($args) {
858
+ if ($args[0] != "list") return $args;
859
+ $values = $args[2];
860
+ $string = array_shift($values);
861
+ $template = $this->compileValue($this->lib_e($string));
862
+
863
+ $i = 0;
864
+ if (preg_match_all('/%[dsa]/', $template, $m)) {
865
+ foreach ($m[0] as $match) {
866
+ $val = isset($values[$i]) ?
867
+ $this->reduce($values[$i]) : array('keyword', '');
868
+
869
+ // lessjs compat, renders fully expanded color, not raw color
870
+ if ($color = $this->coerceColor($val)) {
871
+ $val = $color;
872
+ }
873
+
874
+ $i++;
875
+ $rep = $this->compileValue($this->lib_e($val));
876
+ $template = preg_replace('/'.self::preg_quote($match).'/',
877
+ $rep, $template, 1);
878
+ }
879
+ }
880
+
881
+ $d = $string[0] == "string" ? $string[1] : '"';
882
+ return array("string", $d, array($template));
883
+ }
884
+
885
+ protected function lib_floor($arg) {
886
+ $value = $this->assertNumber($arg);
887
+ return array("number", floor($value), $arg[2]);
888
+ }
889
+
890
+ protected function lib_ceil($arg) {
891
+ $value = $this->assertNumber($arg);
892
+ return array("number", ceil($value), $arg[2]);
893
+ }
894
+
895
+ protected function lib_round($arg) {
896
+ $value = $this->assertNumber($arg);
897
+ return array("number", round($value), $arg[2]);
898
+ }
899
+
900
+ protected function lib_unit($arg) {
901
+ if ($arg[0] == "list") {
902
+ list($number, $newUnit) = $arg[2];
903
+ return array("number", $this->assertNumber($number),
904
+ $this->compileValue($this->lib_e($newUnit)));
905
+ } else {
906
+ return array("number", $this->assertNumber($arg), "");
907
+ }
908
+ }
909
+
910
+ /**
911
+ * Helper function to get arguments for color manipulation functions.
912
+ * takes a list that contains a color like thing and a percentage
913
+ */
914
+ protected function colorArgs($args) {
915
+ if ($args[0] != 'list' || count($args[2]) < 2) {
916
+ return array(array('color', 0, 0, 0), 0);
917
+ }
918
+ list($color, $delta) = $args[2];
919
+ $color = $this->assertColor($color);
920
+ $delta = floatval($delta[1]);
921
+
922
+ return array($color, $delta);
923
+ }
924
+
925
+ protected function lib_darken($args) {
926
+ list($color, $delta) = $this->colorArgs($args);
927
+
928
+ $hsl = $this->toHSL($color);
929
+ $hsl[3] = $this->clamp($hsl[3] - $delta, 100);
930
+ return $this->toRGB($hsl);
931
+ }
932
+
933
+ protected function lib_lighten($args) {
934
+ list($color, $delta) = $this->colorArgs($args);
935
+
936
+ $hsl = $this->toHSL($color);
937
+ $hsl[3] = $this->clamp($hsl[3] + $delta, 100);
938
+ return $this->toRGB($hsl);
939
+ }
940
+
941
+ protected function lib_saturate($args) {
942
+ list($color, $delta) = $this->colorArgs($args);
943
+
944
+ $hsl = $this->toHSL($color);
945
+ $hsl[2] = $this->clamp($hsl[2] + $delta, 100);
946
+ return $this->toRGB($hsl);
947
+ }
948
+
949
+ protected function lib_desaturate($args) {
950
+ list($color, $delta) = $this->colorArgs($args);
951
+
952
+ $hsl = $this->toHSL($color);
953
+ $hsl[2] = $this->clamp($hsl[2] - $delta, 100);
954
+ return $this->toRGB($hsl);
955
+ }
956
+
957
+ protected function lib_spin($args) {
958
+ list($color, $delta) = $this->colorArgs($args);
959
+
960
+ $hsl = $this->toHSL($color);
961
+
962
+ $hsl[1] = $hsl[1] + $delta % 360;
963
+ if ($hsl[1] < 0) $hsl[1] += 360;
964
+
965
+ return $this->toRGB($hsl);
966
+ }
967
+
968
+ protected function lib_fadeout($args) {
969
+ list($color, $delta) = $this->colorArgs($args);
970
+ $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta/100);
971
+ return $color;
972
+ }
973
+
974
+ protected function lib_fadein($args) {
975
+ list($color, $delta) = $this->colorArgs($args);
976
+ $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta/100);
977
+ return $color;
978
+ }
979
+
980
+ protected function lib_hue($color) {
981
+ $hsl = $this->toHSL($this->assertColor($color));
982
+ return round($hsl[1]);
983
+ }
984
+
985
+ protected function lib_saturation($color) {
986
+ $hsl = $this->toHSL($this->assertColor($color));
987
+ return round($hsl[2]);
988
+ }
989
+
990
+ protected function lib_lightness($color) {
991
+ $hsl = $this->toHSL($this->assertColor($color));
992
+ return round($hsl[3]);
993
+ }
994
+
995
+ // get the alpha of a color
996
+ // defaults to 1 for non-colors or colors without an alpha
997
+ protected function lib_alpha($value) {
998
+ if (!is_null($color = $this->coerceColor($value))) {
999
+ return isset($color[4]) ? $color[4] : 1;
1000
+ }
1001
+ }
1002
+
1003
+ // set the alpha of the color
1004
+ protected function lib_fade($args) {
1005
+ list($color, $alpha) = $this->colorArgs($args);
1006
+ $color[4] = $this->clamp($alpha / 100.0);
1007
+ return $color;
1008
+ }
1009
+
1010
+ protected function lib_percentage($arg) {
1011
+ $num = $this->assertNumber($arg);
1012
+ return array("number", $num*100, "%");
1013
+ }
1014
+
1015
+ // mixes two colors by weight
1016
+ // mix(@color1, @color2, @weight);
1017
+ // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
1018
+ protected function lib_mix($args) {
1019
+ if ($args[0] != "list" || count($args[2]) < 3)
1020
+ $this->throwError("mix expects (color1, color2, weight)");
1021
+
1022
+ list($first, $second, $weight) = $args[2];
1023
+ $first = $this->assertColor($first);
1024
+ $second = $this->assertColor($second);
1025
+
1026
+ $first_a = $this->lib_alpha($first);
1027
+ $second_a = $this->lib_alpha($second);
1028
+ $weight = $weight[1] / 100.0;
1029
+
1030
+ $w = $weight * 2 - 1;
1031
+ $a = $first_a - $second_a;
1032
+
1033
+ $w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0;
1034
+ $w2 = 1.0 - $w1;
1035
+
1036
+ $new = array('color',
1037
+ $w1 * $first[1] + $w2 * $second[1],
1038
+ $w1 * $first[2] + $w2 * $second[2],
1039
+ $w1 * $first[3] + $w2 * $second[3],
1040
+ );
1041
+
1042
+ if ($first_a != 1.0 || $second_a != 1.0) {
1043
+ $new[] = $first_a * $weight + $second_a * ($weight - 1);
1044
+ }
1045
+
1046
+ return $this->fixColor($new);
1047
+ }
1048
+
1049
+ protected function lib_contrast($args) {
1050
+ if ($args[0] != 'list' || count($args[2]) < 3) {
1051
+ return array(array('color', 0, 0, 0), 0);
1052
+ }
1053
+
1054
+ list($inputColor, $darkColor, $lightColor) = $args[2];
1055
+
1056
+ $inputColor = $this->assertColor($inputColor);
1057
+ $darkColor = $this->assertColor($darkColor);
1058
+ $lightColor = $this->assertColor($lightColor);
1059
+ $hsl = $this->toHSL($inputColor);
1060
+
1061
+ if ($hsl[3] > 50) {
1062
+ return $darkColor;
1063
+ }
1064
+
1065
+ return $lightColor;
1066
+ }
1067
+
1068
+ protected function assertColor($value, $error = "expected color value") {
1069
+ $color = $this->coerceColor($value);
1070
+ if (is_null($color)) $this->throwError($error);
1071
+ return $color;
1072
+ }
1073
+
1074
+ protected function assertNumber($value, $error = "expecting number") {
1075
+ if ($value[0] == "number") return $value[1];
1076
+ $this->throwError($error);
1077
+ }
1078
+
1079
+ protected function toHSL($color) {
1080
+ if ($color[0] == 'hsl') return $color;
1081
+
1082
+ $r = $color[1] / 255;
1083
+ $g = $color[2] / 255;
1084
+ $b = $color[3] / 255;
1085
+
1086
+ $min = min($r, $g, $b);
1087
+ $max = max($r, $g, $b);
1088
+
1089
+ $L = ($min + $max) / 2;
1090
+ if ($min == $max) {
1091
+ $S = $H = 0;
1092
+ } else {
1093
+ if ($L < 0.5)
1094
+ $S = ($max - $min)/($max + $min);
1095
+ else
1096
+ $S = ($max - $min)/(2.0 - $max - $min);
1097
+
1098
+ if ($r == $max) $H = ($g - $b)/($max - $min);
1099
+ elseif ($g == $max) $H = 2.0 + ($b - $r)/($max - $min);
1100
+ elseif ($b == $max) $H = 4.0 + ($r - $g)/($max - $min);
1101
+
1102
+ }
1103
+
1104
+ $out = array('hsl',
1105
+ ($H < 0 ? $H + 6 : $H)*60,
1106
+ $S*100,
1107
+ $L*100,
1108
+ );
1109
+
1110
+ if (count($color) > 4) $out[] = $color[4]; // copy alpha
1111
+ return $out;
1112
+ }
1113
+
1114
+ protected function toRGB_helper($comp, $temp1, $temp2) {
1115
+ if ($comp < 0) $comp += 1.0;
1116
+ elseif ($comp > 1) $comp -= 1.0;
1117
+
1118
+ if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp;
1119
+ if (2 * $comp < 1) return $temp2;
1120
+ if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1)*((2/3) - $comp) * 6;
1121
+
1122
+ return $temp1;
1123
+ }
1124
+
1125
+ /**
1126
+ * Converts a hsl array into a color value in rgb.
1127
+ * Expects H to be in range of 0 to 360, S and L in 0 to 100
1128
+ */
1129
+ protected function toRGB($color) {
1130
+ if ($color[0] == 'color') return $color;
1131
+
1132
+ $H = $color[1] / 360;
1133
+ $S = $color[2] / 100;
1134
+ $L = $color[3] / 100;
1135
+
1136
+ if ($S == 0) {
1137
+ $r = $g = $b = $L;
1138
+ } else {
1139
+ $temp2 = $L < 0.5 ?
1140
+ $L*(1.0 + $S) :
1141
+ $L + $S - $L * $S;
1142
+
1143
+ $temp1 = 2.0 * $L - $temp2;
1144
+
1145
+ $r = $this->toRGB_helper($H + 1/3, $temp1, $temp2);
1146
+ $g = $this->toRGB_helper($H, $temp1, $temp2);
1147
+ $b = $this->toRGB_helper($H - 1/3, $temp1, $temp2);
1148
+ }
1149
+
1150
+ // $out = array('color', round($r*255), round($g*255), round($b*255));
1151
+ $out = array('color', $r*255, $g*255, $b*255);
1152
+ if (count($color) > 4) $out[] = $color[4]; // copy alpha
1153
+ return $out;
1154
+ }
1155
+
1156
+ protected function clamp($v, $max = 1, $min = 0) {
1157
+ return min($max, max($min, $v));
1158
+ }
1159
+
1160
+ /**
1161
+ * Convert the rgb, rgba, hsl color literals of function type
1162
+ * as returned by the parser into values of color type.
1163
+ */
1164
+ protected function funcToColor($func) {
1165
+ $fname = $func[1];
1166
+ if ($func[2][0] != 'list') return false; // need a list of arguments
1167
+ $rawComponents = $func[2][2];
1168
+
1169
+ if ($fname == 'hsl' || $fname == 'hsla') {
1170
+ $hsl = array('hsl');
1171
+ $i = 0;
1172
+ foreach ($rawComponents as $c) {
1173
+ $val = $this->reduce($c);
1174
+ $val = isset($val[1]) ? floatval($val[1]) : 0;
1175
+
1176
+ if ($i == 0) $clamp = 360;
1177
+ elseif ($i < 3) $clamp = 100;
1178
+ else $clamp = 1;
1179
+
1180
+ $hsl[] = $this->clamp($val, $clamp);
1181
+ $i++;
1182
+ }
1183
+
1184
+ while (count($hsl) < 4) $hsl[] = 0;
1185
+ return $this->toRGB($hsl);
1186
+
1187
+ } elseif ($fname == 'rgb' || $fname == 'rgba') {
1188
+ $components = array();
1189
+ $i = 1;
1190
+ foreach ($rawComponents as $c) {
1191
+ $c = $this->reduce($c);
1192
+ if ($i < 4) {
1193
+ if ($c[0] == "number" && $c[2] == "%") {
1194
+ $components[] = 255 * ($c[1] / 100);
1195
+ } else {
1196
+ $components[] = floatval($c[1]);
1197
+ }
1198
+ } elseif ($i == 4) {
1199
+ if ($c[0] == "number" && $c[2] == "%") {
1200
+ $components[] = 1.0 * ($c[1] / 100);
1201
+ } else {
1202
+ $components[] = floatval($c[1]);
1203
+ }
1204
+ } else break;
1205
+
1206
+ $i++;
1207
+ }
1208
+ while (count($components) < 3) $components[] = 0;
1209
+ array_unshift($components, 'color');
1210
+ return $this->fixColor($components);
1211
+ }
1212
+
1213
+ return false;
1214
+ }
1215
+
1216
+ protected function reduce($value, $forExpression = false) {
1217
+ switch ($value[0]) {
1218
+ case "interpolate":
1219
+ $reduced = $this->reduce($value[1]);
1220
+ $var = $this->compileValue($reduced);
1221
+ $res = $this->reduce(array("variable", $this->vPrefix . $var));
1222
+
1223
+ if (empty($value[2])) $res = $this->lib_e($res);
1224
+
1225
+ return $res;
1226
+ case "variable":
1227
+ $key = $value[1];
1228
+ if (is_array($key)) {
1229
+ $key = $this->reduce($key);
1230
+ $key = $this->vPrefix . $this->compileValue($this->lib_e($key));
1231
+ }
1232
+
1233
+ $seen =& $this->env->seenNames;
1234
+
1235
+ if (!empty($seen[$key])) {
1236
+ $this->throwError("infinite loop detected: $key");
1237
+ }
1238
+
1239
+ $seen[$key] = true;
1240
+ $out = $this->reduce($this->get($key, self::$defaultValue));
1241
+ $seen[$key] = false;
1242
+ return $out;
1243
+ case "list":
1244
+ foreach ($value[2] as &$item) {
1245
+ $item = $this->reduce($item, $forExpression);
1246
+ }
1247
+ return $value;
1248
+ case "expression":
1249
+ return $this->evaluate($value);
1250
+ case "string":
1251
+ foreach ($value[2] as &$part) {
1252
+ if (is_array($part)) {
1253
+ $strip = $part[0] == "variable";
1254
+ $part = $this->reduce($part);
1255
+ if ($strip) $part = $this->lib_e($part);
1256
+ }
1257
+ }
1258
+ return $value;
1259
+ case "escape":
1260
+ list(,$inner) = $value;
1261
+ return $this->lib_e($this->reduce($inner));
1262
+ case "function":
1263
+ $color = $this->funcToColor($value);
1264
+ if ($color) return $color;
1265
+
1266
+ list(, $name, $args) = $value;
1267
+ if ($name == "%") $name = "_sprintf";
1268
+ $f = isset($this->libFunctions[$name]) ?
1269
+ $this->libFunctions[$name] : array($this, 'lib_'.$name);
1270
+
1271
+ if (is_callable($f)) {
1272
+ if ($args[0] == 'list')
1273
+ $args = self::compressList($args[2], $args[1]);
1274
+
1275
+ $ret = call_user_func($f, $this->reduce($args, true), $this);
1276
+
1277
+ if (is_null($ret)) {
1278
+ return array("string", "", array(
1279
+ $name, "(", $args, ")"
1280
+ ));
1281
+ }
1282
+
1283
+ // convert to a typed value if the result is a php primitive
1284
+ if (is_numeric($ret)) $ret = array('number', $ret, "");
1285
+ elseif (!is_array($ret)) $ret = array('keyword', $ret);
1286
+
1287
+ return $ret;
1288
+ }
1289
+
1290
+ // plain function, reduce args
1291
+ $value[2] = $this->reduce($value[2]);
1292
+ return $value;
1293
+ case "unary":
1294
+ list(, $op, $exp) = $value;
1295
+ $exp = $this->reduce($exp);
1296
+
1297
+ if ($exp[0] == "number") {
1298
+ switch ($op) {
1299
+ case "+":
1300
+ return $exp;
1301
+ case "-":
1302
+ $exp[1] *= -1;
1303
+ return $exp;
1304
+ }
1305
+ }
1306
+ return array("string", "", array($op, $exp));
1307
+ }
1308
+
1309
+ if ($forExpression) {
1310
+ switch ($value[0]) {
1311
+ case "keyword":
1312
+ if ($color = $this->coerceColor($value)) {
1313
+ return $color;
1314
+ }
1315
+ break;
1316
+ case "raw_color":
1317
+ return $this->coerceColor($value);
1318
+ }
1319
+ }
1320
+
1321
+ return $value;
1322
+ }
1323
+
1324
+
1325
+ // coerce a value for use in color operation
1326
+ protected function coerceColor($value) {
1327
+ switch($value[0]) {
1328
+ case 'color': return $value;
1329
+ case 'raw_color':
1330
+ $c = array("color", 0, 0, 0);
1331
+ $colorStr = substr($value[1], 1);
1332
+ $num = hexdec($colorStr);
1333
+ $width = strlen($colorStr) == 3 ? 16 : 256;
1334
+
1335
+ for ($i = 3; $i > 0; $i--) { // 3 2 1
1336
+ $t = $num % $width;
1337
+ $num /= $width;
1338
+
1339
+ $c[$i] = $t * (256/$width) + $t * floor(16/$width);
1340
+ }
1341
+
1342
+ return $c;
1343
+ case 'keyword':
1344
+ $name = $value[1];
1345
+ if (isset(self::$cssColors[$name])) {
1346
+ $rgba = explode(',', self::$cssColors[$name]);
1347
+
1348
+ if(isset($rgba[3]))
1349
+ return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
1350
+
1351
+ return array('color', $rgba[0], $rgba[1], $rgba[2]);
1352
+ }
1353
+ return null;
1354
+ }
1355
+ }
1356
+
1357
+ // make something string like into a string
1358
+ protected function coerceString($value) {
1359
+ switch ($value[0]) {
1360
+ case "string":
1361
+ return $value;
1362
+ case "keyword":
1363
+ return array("string", "", array($value[1]));
1364
+ }
1365
+ return null;
1366
+ }
1367
+
1368
+ // turn list of length 1 into value type
1369
+ protected function flattenList($value) {
1370
+ if ($value[0] == "list" && count($value[2]) == 1) {
1371
+ return $this->flattenList($value[2][0]);
1372
+ }
1373
+ return $value;
1374
+ }
1375
+
1376
+ protected function toBool($a) {
1377
+ if ($a) return self::$TRUE;
1378
+ else return self::$FALSE;
1379
+ }
1380
+
1381
+ // evaluate an expression
1382
+ protected function evaluate($exp) {
1383
+ list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;
1384
+
1385
+ $left = $this->reduce($left, true);
1386
+ $right = $this->reduce($right, true);
1387
+
1388
+ if ($leftColor = $this->coerceColor($left)) {
1389
+ $left = $leftColor;
1390
+ }
1391
+
1392
+ if ($rightColor = $this->coerceColor($right)) {
1393
+ $right = $rightColor;
1394
+ }
1395
+
1396
+ $ltype = $left[0];
1397
+ $rtype = $right[0];
1398
+
1399
+ // operators that work on all types
1400
+ if ($op == "and") {
1401
+ return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
1402
+ }
1403
+
1404
+ if ($op == "=") {
1405
+ return $this->toBool($this->eq($left, $right) );
1406
+ }
1407
+
1408
+ if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) {
1409
+ return $str;
1410
+ }
1411
+
1412
+ // type based operators
1413
+ $fname = "op_${ltype}_${rtype}";
1414
+ if (is_callable(array($this, $fname))) {
1415
+ $out = $this->$fname($op, $left, $right);
1416
+ if (!is_null($out)) return $out;
1417
+ }
1418
+
1419
+ // make the expression look it did before being parsed
1420
+ $paddedOp = $op;
1421
+ if ($whiteBefore) $paddedOp = " " . $paddedOp;
1422
+ if ($whiteAfter) $paddedOp .= " ";
1423
+
1424
+ return array("string", "", array($left, $paddedOp, $right));
1425
+ }
1426
+
1427
+ protected function stringConcatenate($left, $right) {
1428
+ if ($strLeft = $this->coerceString($left)) {
1429
+ if ($right[0] == "string") {
1430
+ $right[1] = "";
1431
+ }
1432
+ $strLeft[2][] = $right;
1433
+ return $strLeft;
1434
+ }
1435
+
1436
+ if ($strRight = $this->coerceString($right)) {
1437
+ array_unshift($strRight[2], $left);
1438
+ return $strRight;
1439
+ }
1440
+ }
1441
+
1442
+
1443
+ // make sure a color's components don't go out of bounds
1444
+ protected function fixColor($c) {
1445
+ foreach (range(1, 3) as $i) {
1446
+ if ($c[$i] < 0) $c[$i] = 0;
1447
+ if ($c[$i] > 255) $c[$i] = 255;
1448
+ }
1449
+
1450
+ return $c;
1451
+ }
1452
+
1453
+ protected function op_number_color($op, $lft, $rgt) {
1454
+ if ($op == '+' || $op == '*') {
1455
+ return $this->op_color_number($op, $rgt, $lft);
1456
+ }
1457
+ }
1458
+
1459
+ protected function op_color_number($op, $lft, $rgt) {
1460
+ if ($rgt[0] == '%') $rgt[1] /= 100;
1461
+
1462
+ return $this->op_color_color($op, $lft,
1463
+ array_fill(1, count($lft) - 1, $rgt[1]));
1464
+ }
1465
+
1466
+ protected function op_color_color($op, $left, $right) {
1467
+ $out = array('color');
1468
+ $max = count($left) > count($right) ? count($left) : count($right);
1469
+ foreach (range(1, $max - 1) as $i) {
1470
+ $lval = isset($left[$i]) ? $left[$i] : 0;
1471
+ $rval = isset($right[$i]) ? $right[$i] : 0;
1472
+ switch ($op) {
1473
+ case '+':
1474
+ $out[] = $lval + $rval;
1475
+ break;
1476
+ case '-':
1477
+ $out[] = $lval - $rval;
1478
+ break;
1479
+ case '*':
1480
+ $out[] = $lval * $rval;
1481
+ break;
1482
+ case '%':
1483
+ $out[] = $lval % $rval;
1484
+ break;
1485
+ case '/':
1486
+ if ($rval == 0) $this->throwError("evaluate error: can't divide by zero");
1487
+ $out[] = $lval / $rval;
1488
+ break;
1489
+ default:
1490
+ $this->throwError('evaluate error: color op number failed on op '.$op);
1491
+ }
1492
+ }
1493
+ return $this->fixColor($out);
1494
+ }
1495
+
1496
+ function lib_red($color){
1497
+ $color = $this->coerceColor($color);
1498
+ if (is_null($color)) {
1499
+ $this->throwError('color expected for red()');
1500
+ }
1501
+
1502
+ return $color[1];
1503
+ }
1504
+
1505
+ function lib_green($color){
1506
+ $color = $this->coerceColor($color);
1507
+ if (is_null($color)) {
1508
+ $this->throwError('color expected for green()');
1509
+ }
1510
+
1511
+ return $color[2];
1512
+ }
1513
+
1514
+ function lib_blue($color){
1515
+ $color = $this->coerceColor($color);
1516
+ if (is_null($color)) {
1517
+ $this->throwError('color expected for blue()');
1518
+ }
1519
+
1520
+ return $color[3];
1521
+ }
1522
+
1523
+
1524
+ // operator on two numbers
1525
+ protected function op_number_number($op, $left, $right) {
1526
+ $unit = empty($left[2]) ? $right[2] : $left[2];
1527
+
1528
+ $value = 0;
1529
+ switch ($op) {
1530
+ case '+':
1531
+ $value = $left[1] + $right[1];
1532
+ break;
1533
+ case '*':
1534
+ $value = $left[1] * $right[1];
1535
+ break;
1536
+ case '-':
1537
+ $value = $left[1] - $right[1];
1538
+ break;
1539
+ case '%':
1540
+ $value = $left[1] % $right[1];
1541
+ break;
1542
+ case '/':
1543
+ if ($right[1] == 0) $this->throwError('parse error: divide by zero');
1544
+ $value = $left[1] / $right[1];
1545
+ break;
1546
+ case '<':
1547
+ return $this->toBool($left[1] < $right[1]);
1548
+ case '>':
1549
+ return $this->toBool($left[1] > $right[1]);
1550
+ case '>=':
1551
+ return $this->toBool($left[1] >= $right[1]);
1552
+ case '=<':
1553
+ return $this->toBool($left[1] <= $right[1]);
1554
+ default:
1555
+ $this->throwError('parse error: unknown number operator: '.$op);
1556
+ }
1557
+
1558
+ return array("number", $value, $unit);
1559
+ }
1560
+
1561
+
1562
+ /* environment functions */
1563
+
1564
+ protected function makeOutputBlock($type, $selectors = null) {
1565
+ $b = new stdclass;
1566
+ $b->lines = array();
1567
+ $b->children = array();
1568
+ $b->selectors = $selectors;
1569
+ $b->type = $type;
1570
+ $b->parent = $this->scope;
1571
+ return $b;
1572
+ }
1573
+
1574
+ // the state of execution
1575
+ protected function pushEnv($block = null) {
1576
+ $e = new stdclass;
1577
+ $e->parent = $this->env;
1578
+ $e->store = array();
1579
+ $e->block = $block;
1580
+
1581
+ $this->env = $e;
1582
+ return $e;
1583
+ }
1584
+
1585
+ // pop something off the stack
1586
+ protected function popEnv() {
1587
+ $old = $this->env;
1588
+ $this->env = $this->env->parent;
1589
+ return $old;
1590
+ }
1591
+
1592
+ // set something in the current env
1593
+ protected function set($name, $value) {
1594
+ $this->env->store[$name] = $value;
1595
+ }
1596
+
1597
+
1598
+ // get the highest occurrence entry for a name
1599
+ protected function get($name, $default=null) {
1600
+ $current = $this->env;
1601
+
1602
+ $isArguments = $name == $this->vPrefix . 'arguments';
1603
+ while ($current) {
1604
+ if ($isArguments && isset($current->arguments)) {
1605
+ return array('list', ' ', $current->arguments);
1606
+ }
1607
+
1608
+ if (isset($current->store[$name]))
1609
+ return $current->store[$name];
1610
+ else {
1611
+ $current = isset($current->storeParent) ?
1612
+ $current->storeParent : $current->parent;
1613
+ }
1614
+ }
1615
+
1616
+ return $default;
1617
+ }
1618
+
1619
+ // inject array of unparsed strings into environment as variables
1620
+ protected function injectVariables($args) {
1621
+ $this->pushEnv();
1622
+ $parser = new lessc_parser($this, __METHOD__);
1623
+ foreach ($args as $name => $strValue) {
1624
+ if ($name{0} != '@') $name = '@'.$name;
1625
+ $parser->count = 0;
1626
+ $parser->buffer = (string)$strValue;
1627
+ if (!$parser->propertyValue($value)) {
1628
+ throw new Exception("failed to parse passed in variable $name: $strValue");
1629
+ }
1630
+
1631
+ $this->set($name, $value);
1632
+ }
1633
+ }
1634
+
1635
+ /**
1636
+ * Initialize any static state, can initialize parser for a file
1637
+ * $opts isn't used yet
1638
+ */
1639
+ public function __construct($fname = null) {
1640
+ if ($fname !== null) {
1641
+ // used for deprecated parse method
1642
+ $this->_parseFile = $fname;
1643
+ }
1644
+ }
1645
+
1646
+ public function compile($string, $name = null) {
1647
+ $locale = setlocale(LC_NUMERIC, 0);
1648
+ setlocale(LC_NUMERIC, "C");
1649
+
1650
+ $this->parser = $this->makeParser($name);
1651
+ $root = $this->parser->parse($string);
1652
+
1653
+ $this->env = null;
1654
+ $this->scope = null;
1655
+
1656
+ $this->formatter = $this->newFormatter();
1657
+
1658
+ if (!empty($this->registeredVars)) {
1659
+ $this->injectVariables($this->registeredVars);
1660
+ }
1661
+
1662
+ $this->sourceParser = $this->parser; // used for error messages
1663
+ $this->compileBlock($root);
1664
+
1665
+ ob_start();
1666
+ $this->formatter->block($this->scope);
1667
+ $out = ob_get_clean();
1668
+ setlocale(LC_NUMERIC, $locale);
1669
+ return $out;
1670
+ }
1671
+
1672
+ public function compileFile($fname, $outFname = null) {
1673
+ if (!is_readable($fname)) {
1674
+ throw new Exception('load error: failed to find '.$fname);
1675
+ }
1676
+
1677
+ $pi = pathinfo($fname);
1678
+
1679
+ $oldImport = $this->importDir;
1680
+
1681
+ $this->importDir = (array)$this->importDir;
1682
+ $this->importDir[] = $pi['dirname'].'/';
1683
+
1684
+ $this->allParsedFiles = array();
1685
+ $this->addParsedFile($fname);
1686
+
1687
+ $out = $this->compile(file_get_contents($fname), $fname);
1688
+
1689
+ $this->importDir = $oldImport;
1690
+
1691
+ if ($outFname !== null) {
1692
+ return file_put_contents($outFname, $out);
1693
+ }
1694
+
1695
+ return $out;
1696
+ }
1697
+
1698
+ // compile only if changed input has changed or output doesn't exist
1699
+ public function checkedCompile($in, $out) {
1700
+ if (!is_file($out) || filemtime($in) > filemtime($out)) {
1701
+ $this->compileFile($in, $out);
1702
+ return true;
1703
+ }
1704
+ return false;
1705
+ }
1706
+
1707
+ /**
1708
+ * Execute lessphp on a .less file or a lessphp cache structure
1709
+ *
1710
+ * The lessphp cache structure contains information about a specific
1711
+ * less file having been parsed. It can be used as a hint for future
1712
+ * calls to determine whether or not a rebuild is required.
1713
+ *
1714
+ * The cache structure contains two important keys that may be used
1715
+ * externally:
1716
+ *
1717
+ * compiled: The final compiled CSS
1718
+ * updated: The time (in seconds) the CSS was last compiled
1719
+ *
1720
+ * The cache structure is a plain-ol' PHP associative array and can
1721
+ * be serialized and unserialized without a hitch.
1722
+ *
1723
+ * @param mixed $in Input
1724
+ * @param bool $force Force rebuild?
1725
+ * @return array lessphp cache structure
1726
+ */
1727
+ public function cachedCompile($in, $force = false) {
1728
+ // assume no root
1729
+ $root = null;
1730
+
1731
+ if (is_string($in)) {
1732
+ $root = $in;
1733
+ } elseif (is_array($in) and isset($in['root'])) {
1734
+ if ($force or ! isset($in['files'])) {
1735
+ // If we are forcing a recompile or if for some reason the
1736
+ // structure does not contain any file information we should
1737
+ // specify the root to trigger a rebuild.
1738
+ $root = $in['root'];
1739
+ } elseif (isset($in['files']) and is_array($in['files'])) {
1740
+ foreach ($in['files'] as $fname => $ftime ) {
1741
+ if (!file_exists($fname) or filemtime($fname) > $ftime) {
1742
+ // One of the files we knew about previously has changed
1743
+ // so we should look at our incoming root again.
1744
+ $root = $in['root'];
1745
+ break;
1746
+ }
1747
+ }
1748
+ }
1749
+ } else {
1750
+ // TODO: Throw an exception? We got neither a string nor something
1751
+ // that looks like a compatible lessphp cache structure.
1752
+ return null;
1753
+ }
1754
+
1755
+ if ($root !== null) {
1756
+ // If we have a root value which means we should rebuild.
1757
+ $out = array();
1758
+ $out['root'] = $root;
1759
+ $out['compiled'] = $this->compileFile($root);
1760
+ $out['files'] = $this->allParsedFiles();
1761
+ $out['updated'] = time();
1762
+ return $out;
1763
+ } else {
1764
+ // No changes, pass back the structure
1765
+ // we were given initially.
1766
+ return $in;
1767
+ }
1768
+
1769
+ }
1770
+
1771
+ // parse and compile buffer
1772
+ // This is deprecated
1773
+ public function parse($str = null, $initialVariables = null) {
1774
+ if (is_array($str)) {
1775
+ $initialVariables = $str;
1776
+ $str = null;
1777
+ }
1778
+
1779
+ $oldVars = $this->registeredVars;
1780
+ if ($initialVariables !== null) {
1781
+ $this->setVariables($initialVariables);
1782
+ }
1783
+
1784
+ if ($str == null) {
1785
+ if (empty($this->_parseFile)) {
1786
+ throw new exception("nothing to parse");
1787
+ }
1788
+
1789
+ $out = $this->compileFile($this->_parseFile);
1790
+ } else {
1791
+ $out = $this->compile($str);
1792
+ }
1793
+
1794
+ $this->registeredVars = $oldVars;
1795
+ return $out;
1796
+ }
1797
+
1798
+ protected function makeParser($name) {
1799
+ $parser = new lessc_parser($this, $name);
1800
+ $parser->writeComments = $this->preserveComments;
1801
+
1802
+ return $parser;
1803
+ }
1804
+
1805
+ public function setFormatter($name) {
1806
+ $this->formatterName = $name;
1807
+ }
1808
+
1809
+ protected function newFormatter() {
1810
+ $className = "lessc_formatter_lessjs";
1811
+ if (!empty($this->formatterName)) {
1812
+ if (!is_string($this->formatterName))
1813
+ return $this->formatterName;
1814
+ $className = "lessc_formatter_$this->formatterName";
1815
+ }
1816
+
1817
+ return new $className;
1818
+ }
1819
+
1820
+ public function setPreserveComments($preserve) {
1821
+ $this->preserveComments = $preserve;
1822
+ }
1823
+
1824
+ public function registerFunction($name, $func) {
1825
+ $this->libFunctions[$name] = $func;
1826
+ }
1827
+
1828
+ public function unregisterFunction($name) {
1829
+ unset($this->libFunctions[$name]);
1830
+ }
1831
+
1832
+ public function setVariables($variables) {
1833
+ $this->registeredVars = array_merge($this->registeredVars, $variables);
1834
+ }
1835
+
1836
+ public function unsetVariable($name) {
1837
+ unset($this->registeredVars[$name]);
1838
+ }
1839
+
1840
+ public function setImportDir($dirs) {
1841
+ $this->importDir = (array)$dirs;
1842
+ }
1843
+
1844
+ public function addImportDir($dir) {
1845
+ $this->importDir = (array)$this->importDir;
1846
+ $this->importDir[] = $dir;
1847
+ }
1848
+
1849
+ public function allParsedFiles() {
1850
+ return $this->allParsedFiles;
1851
+ }
1852
+
1853
+ protected function addParsedFile($file) {
1854
+ $this->allParsedFiles[realpath($file)] = filemtime($file);
1855
+ }
1856
+
1857
+ /**
1858
+ * Uses the current value of $this->count to show line and line number
1859
+ */
1860
+ protected function throwError($msg = null) {
1861
+ if ($this->sourceLoc >= 0) {
1862
+ $this->sourceParser->throwError($msg, $this->sourceLoc);
1863
+ }
1864
+ throw new exception($msg);
1865
+ }
1866
+
1867
+ // compile file $in to file $out if $in is newer than $out
1868
+ // returns true when it compiles, false otherwise
1869
+ public static function ccompile($in, $out, $less = null) {
1870
+ if ($less === null) {
1871
+ $less = new self;
1872
+ }
1873
+ return $less->checkedCompile($in, $out);
1874
+ }
1875
+
1876
+ public static function cexecute($in, $force = false, $less = null) {
1877
+ if ($less === null) {
1878
+ $less = new self;
1879
+ }
1880
+ return $less->cachedCompile($in, $force);
1881
+ }
1882
+
1883
+ static protected $cssColors = array(
1884
+ 'aliceblue' => '240,248,255',
1885
+ 'antiquewhite' => '250,235,215',
1886
+ 'aqua' => '0,255,255',
1887
+ 'aquamarine' => '127,255,212',
1888
+ 'azure' => '240,255,255',
1889
+ 'beige' => '245,245,220',
1890
+ 'bisque' => '255,228,196',
1891
+ 'black' => '0,0,0',
1892
+ 'blanchedalmond' => '255,235,205',
1893
+ 'blue' => '0,0,255',
1894
+ 'blueviolet' => '138,43,226',
1895
+ 'brown' => '165,42,42',
1896
+ 'burlywood' => '222,184,135',
1897
+ 'cadetblue' => '95,158,160',
1898
+ 'chartreuse' => '127,255,0',
1899
+ 'chocolate' => '210,105,30',
1900
+ 'coral' => '255,127,80',
1901
+ 'cornflowerblue' => '100,149,237',
1902
+ 'cornsilk' => '255,248,220',
1903
+ 'crimson' => '220,20,60',
1904
+ 'cyan' => '0,255,255',
1905
+ 'darkblue' => '0,0,139',
1906
+ 'darkcyan' => '0,139,139',
1907
+ 'darkgoldenrod' => '184,134,11',
1908
+ 'darkgray' => '169,169,169',
1909
+ 'darkgreen' => '0,100,0',
1910
+ 'darkgrey' => '169,169,169',
1911
+ 'darkkhaki' => '189,183,107',
1912
+ 'darkmagenta' => '139,0,139',
1913
+ 'darkolivegreen' => '85,107,47',
1914
+ 'darkorange' => '255,140,0',
1915
+ 'darkorchid' => '153,50,204',
1916
+ 'darkred' => '139,0,0',
1917
+ 'darksalmon' => '233,150,122',
1918
+ 'darkseagreen' => '143,188,143',
1919
+ 'darkslateblue' => '72,61,139',
1920
+ 'darkslategray' => '47,79,79',
1921
+ 'darkslategrey' => '47,79,79',
1922
+ 'darkturquoise' => '0,206,209',
1923
+ 'darkviolet' => '148,0,211',
1924
+ 'deeppink' => '255,20,147',
1925
+ 'deepskyblue' => '0,191,255',
1926
+ 'dimgray' => '105,105,105',
1927
+ 'dimgrey' => '105,105,105',
1928
+ 'dodgerblue' => '30,144,255',
1929
+ 'firebrick' => '178,34,34',
1930
+ 'floralwhite' => '255,250,240',
1931
+ 'forestgreen' => '34,139,34',
1932
+ 'fuchsia' => '255,0,255',
1933
+ 'gainsboro' => '220,220,220',
1934
+ 'ghostwhite' => '248,248,255',
1935
+ 'gold' => '255,215,0',
1936
+ 'goldenrod' => '218,165,32',
1937
+ 'gray' => '128,128,128',
1938
+ 'green' => '0,128,0',
1939
+ 'greenyellow' => '173,255,47',
1940
+ 'grey' => '128,128,128',
1941
+ 'honeydew' => '240,255,240',
1942
+ 'hotpink' => '255,105,180',
1943
+ 'indianred' => '205,92,92',
1944
+ 'indigo' => '75,0,130',
1945
+ 'ivory' => '255,255,240',
1946
+ 'khaki' => '240,230,140',
1947
+ 'lavender' => '230,230,250',
1948
+ 'lavenderblush' => '255,240,245',
1949
+ 'lawngreen' => '124,252,0',
1950
+ 'lemonchiffon' => '255,250,205',
1951
+ 'lightblue' => '173,216,230',
1952
+ 'lightcoral' => '240,128,128',
1953
+ 'lightcyan' => '224,255,255',
1954
+ 'lightgoldenrodyellow' => '250,250,210',
1955
+ 'lightgray' => '211,211,211',
1956
+ 'lightgreen' => '144,238,144',
1957
+ 'lightgrey' => '211,211,211',
1958
+ 'lightpink' => '255,182,193',
1959
+ 'lightsalmon' => '255,160,122',
1960
+ 'lightseagreen' => '32,178,170',
1961
+ 'lightskyblue' => '135,206,250',
1962
+ 'lightslategray' => '119,136,153',
1963
+ 'lightslategrey' => '119,136,153',
1964
+ 'lightsteelblue' => '176,196,222',
1965
+ 'lightyellow' => '255,255,224',
1966
+ 'lime' => '0,255,0',
1967
+ 'limegreen' => '50,205,50',
1968
+ 'linen' => '250,240,230',
1969
+ 'magenta' => '255,0,255',
1970
+ 'maroon' => '128,0,0',
1971
+ 'mediumaquamarine' => '102,205,170',
1972
+ 'mediumblue' => '0,0,205',
1973
+ 'mediumorchid' => '186,85,211',
1974
+ 'mediumpurple' => '147,112,219',
1975
+ 'mediumseagreen' => '60,179,113',
1976
+ 'mediumslateblue' => '123,104,238',
1977
+ 'mediumspringgreen' => '0,250,154',
1978
+ 'mediumturquoise' => '72,209,204',
1979
+ 'mediumvioletred' => '199,21,133',
1980
+ 'midnightblue' => '25,25,112',
1981
+ 'mintcream' => '245,255,250',
1982
+ 'mistyrose' => '255,228,225',
1983
+ 'moccasin' => '255,228,181',
1984
+ 'navajowhite' => '255,222,173',
1985
+ 'navy' => '0,0,128',
1986
+ 'oldlace' => '253,245,230',
1987
+ 'olive' => '128,128,0',
1988
+ 'olivedrab' => '107,142,35',
1989
+ 'orange' => '255,165,0',
1990
+ 'orangered' => '255,69,0',
1991
+ 'orchid' => '218,112,214',
1992
+ 'palegoldenrod' => '238,232,170',
1993
+ 'palegreen' => '152,251,152',
1994
+ 'paleturquoise' => '175,238,238',
1995
+ 'palevioletred' => '219,112,147',
1996
+ 'papayawhip' => '255,239,213',
1997
+ 'peachpuff' => '255,218,185',
1998
+ 'peru' => '205,133,63',
1999
+ 'pink' => '255,192,203',
2000
+ 'plum' => '221,160,221',
2001
+ 'powderblue' => '176,224,230',
2002
+ 'purple' => '128,0,128',
2003
+ 'red' => '255,0,0',
2004
+ 'rosybrown' => '188,143,143',
2005
+ 'royalblue' => '65,105,225',
2006
+ 'saddlebrown' => '139,69,19',
2007
+ 'salmon' => '250,128,114',
2008
+ 'sandybrown' => '244,164,96',
2009
+ 'seagreen' => '46,139,87',
2010
+ 'seashell' => '255,245,238',
2011
+ 'sienna' => '160,82,45',
2012
+ 'silver' => '192,192,192',
2013
+ 'skyblue' => '135,206,235',
2014
+ 'slateblue' => '106,90,205',
2015
+ 'slategray' => '112,128,144',
2016
+ 'slategrey' => '112,128,144',
2017
+ 'snow' => '255,250,250',
2018
+ 'springgreen' => '0,255,127',
2019
+ 'steelblue' => '70,130,180',
2020
+ 'tan' => '210,180,140',
2021
+ 'teal' => '0,128,128',
2022
+ 'thistle' => '216,191,216',
2023
+ 'tomato' => '255,99,71',
2024
+ 'transparent' => '0,0,0,0',
2025
+ 'turquoise' => '64,224,208',
2026
+ 'violet' => '238,130,238',
2027
+ 'wheat' => '245,222,179',
2028
+ 'white' => '255,255,255',
2029
+ 'whitesmoke' => '245,245,245',
2030
+ 'yellow' => '255,255,0',
2031
+ 'yellowgreen' => '154,205,50'
2032
+ );
2033
+ }
2034
+
2035
+ // responsible for taking a string of LESS code and converting it into a
2036
+ // syntax tree
2037
+ class lessc_parser {
2038
+ static protected $nextBlockId = 0; // used to uniquely identify blocks
2039
+
2040
+ static protected $precedence = array(
2041
+ '=<' => 0,
2042
+ '>=' => 0,
2043
+ '=' => 0,
2044
+ '<' => 0,
2045
+ '>' => 0,
2046
+
2047
+ '+' => 1,
2048
+ '-' => 1,
2049
+ '*' => 2,
2050
+ '/' => 2,
2051
+ '%' => 2,
2052
+ );
2053
+
2054
+ static protected $whitePattern;
2055
+ static protected $commentMulti;
2056
+
2057
+ static protected $commentSingle = "//";
2058
+ static protected $commentMultiLeft = "/*";
2059
+ static protected $commentMultiRight = "*/";
2060
+
2061
+ // regex string to match any of the operators
2062
+ static protected $operatorString;
2063
+
2064
+ // these properties will supress division unless it's inside parenthases
2065
+ static protected $supressDivisionProps =
2066
+ array('/border-radius$/i', '/^font$/i');
2067
+
2068
+ protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document");
2069
+ protected $lineDirectives = array("charset");
2070
+
2071
+ /**
2072
+ * if we are in parens we can be more liberal with whitespace around
2073
+ * operators because it must evaluate to a single value and thus is less
2074
+ * ambiguous.
2075
+ *
2076
+ * Consider:
2077
+ * property1: 10 -5; // is two numbers, 10 and -5
2078
+ * property2: (10 -5); // should evaluate to 5
2079
+ */
2080
+ protected $inParens = false;
2081
+
2082
+ // caches preg escaped literals
2083
+ static protected $literalCache = array();
2084
+
2085
+ public function __construct($lessc, $sourceName = null) {
2086
+ $this->eatWhiteDefault = true;
2087
+ // reference to less needed for vPrefix, mPrefix, and parentSelector
2088
+ $this->lessc = $lessc;
2089
+
2090
+ $this->sourceName = $sourceName; // name used for error messages
2091
+
2092
+ $this->writeComments = false;
2093
+
2094
+ if (!self::$operatorString) {
2095
+ self::$operatorString =
2096
+ '('.implode('|', array_map(array('lessc', 'preg_quote'),
2097
+ array_keys(self::$precedence))).')';
2098
+
2099
+ $commentSingle = lessc::preg_quote(self::$commentSingle);
2100
+ $commentMultiLeft = lessc::preg_quote(self::$commentMultiLeft);
2101
+ $commentMultiRight = lessc::preg_quote(self::$commentMultiRight);
2102
+
2103
+ self::$commentMulti = $commentMultiLeft.'.*?'.$commentMultiRight;
2104
+ self::$whitePattern = '/'.$commentSingle.'[^\n]*\s*|('.self::$commentMulti.')\s*|\s+/Ais';
2105
+ }
2106
+ }
2107
+
2108
+ public function parse($buffer) {
2109
+ $this->count = 0;
2110
+ $this->line = 1;
2111
+
2112
+ $this->env = null; // block stack
2113
+ $this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer);
2114
+ $this->pushSpecialBlock("root");
2115
+ $this->eatWhiteDefault = true;
2116
+ $this->seenComments = array();
2117
+
2118
+ // trim whitespace on head
2119
+ // if (preg_match('/^\s+/', $this->buffer, $m)) {
2120
+ // $this->line += substr_count($m[0], "\n");
2121
+ // $this->buffer = ltrim($this->buffer);
2122
+ // }
2123
+ $this->whitespace();
2124
+
2125
+ // parse the entire file
2126
+ $lastCount = $this->count;
2127
+ while (false !== $this->parseChunk());
2128
+
2129
+ if ($this->count != strlen($this->buffer))
2130
+ $this->throwError();
2131
+
2132
+ // TODO report where the block was opened
2133
+ if (!is_null($this->env->parent))
2134
+ throw new exception('parse error: unclosed block');
2135
+
2136
+ return $this->env;
2137
+ }
2138
+
2139
+ /**
2140
+ * Parse a single chunk off the head of the buffer and append it to the
2141
+ * current parse environment.
2142
+ * Returns false when the buffer is empty, or when there is an error.
2143
+ *
2144
+ * This function is called repeatedly until the entire document is
2145
+ * parsed.
2146
+ *
2147
+ * This parser is most similar to a recursive descent parser. Single
2148
+ * functions represent discrete grammatical rules for the language, and
2149
+ * they are able to capture the text that represents those rules.
2150
+ *
2151
+ * Consider the function lessc::keyword(). (all parse functions are
2152
+ * structured the same)
2153
+ *
2154
+ * The function takes a single reference argument. When calling the
2155
+ * function it will attempt to match a keyword on the head of the buffer.
2156
+ * If it is successful, it will place the keyword in the referenced
2157
+ * argument, advance the position in the buffer, and return true. If it
2158
+ * fails then it won't advance the buffer and it will return false.
2159
+ *
2160
+ * All of these parse functions are powered by lessc::match(), which behaves
2161
+ * the same way, but takes a literal regular expression. Sometimes it is
2162
+ * more convenient to use match instead of creating a new function.
2163
+ *
2164
+ * Because of the format of the functions, to parse an entire string of
2165
+ * grammatical rules, you can chain them together using &&.
2166
+ *
2167
+ * But, if some of the rules in the chain succeed before one fails, then
2168
+ * the buffer position will be left at an invalid state. In order to
2169
+ * avoid this, lessc::seek() is used to remember and set buffer positions.
2170
+ *
2171
+ * Before parsing a chain, use $s = $this->seek() to remember the current
2172
+ * position into $s. Then if a chain fails, use $this->seek($s) to
2173
+ * go back where we started.
2174
+ */
2175
+ protected function parseChunk() {
2176
+ if (empty($this->buffer)) return false;
2177
+ $s = $this->seek();
2178
+
2179
+ // setting a property
2180
+ if ($this->keyword($key) && $this->assign() &&
2181
+ $this->propertyValue($value, $key) && $this->end())
2182
+ {
2183
+ $this->append(array('assign', $key, $value), $s);
2184
+ return true;
2185
+ } else {
2186
+ $this->seek($s);
2187
+ }
2188
+
2189
+
2190
+ // look for special css blocks
2191
+ if ($this->literal('@', false)) {
2192
+ $this->count--;
2193
+
2194
+ // media
2195
+ if ($this->literal('@media')) {
2196
+ if (($this->mediaQueryList($mediaQueries) || true)
2197
+ && $this->literal('{'))
2198
+ {
2199
+ $media = $this->pushSpecialBlock("media");
2200
+ $media->queries = is_null($mediaQueries) ? array() : $mediaQueries;
2201
+ return true;
2202
+ } else {
2203
+ $this->seek($s);
2204
+ return false;
2205
+ }
2206
+ }
2207
+
2208
+ if ($this->literal("@", false) && $this->keyword($dirName)) {
2209
+ if ($this->isDirective($dirName, $this->blockDirectives)) {
2210
+ if (($this->openString("{", $dirValue, null, array(";")) || true) &&
2211
+ $this->literal("{"))
2212
+ {
2213
+ $dir = $this->pushSpecialBlock("directive");
2214
+ $dir->name = $dirName;
2215
+ if (isset($dirValue)) $dir->value = $dirValue;
2216
+ return true;
2217
+ }
2218
+ } elseif ($this->isDirective($dirName, $this->lineDirectives)) {
2219
+ if ($this->propertyValue($dirValue) && $this->end()) {
2220
+ $this->append(array("directive", $dirName, $dirValue));
2221
+ return true;
2222
+ }
2223
+ }
2224
+ }
2225
+
2226
+ $this->seek($s);
2227
+ }
2228
+
2229
+ // setting a variable
2230
+ if ($this->variable($var) && $this->assign() &&
2231
+ $this->propertyValue($value) && $this->end())
2232
+ {
2233
+ $this->append(array('assign', $var, $value), $s);
2234
+ return true;
2235
+ } else {
2236
+ $this->seek($s);
2237
+ }
2238
+
2239
+ if ($this->import($importValue)) {
2240
+ $this->append($importValue, $s);
2241
+ return true;
2242
+ }
2243
+
2244
+ // opening parametric mixin
2245
+ if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg) &&
2246
+ ($this->guards($guards) || true) &&
2247
+ $this->literal('{'))
2248
+ {
2249
+ $block = $this->pushBlock($this->fixTags(array($tag)));
2250
+ $block->args = $args;
2251
+ $block->isVararg = $isVararg;
2252
+ if (!empty($guards)) $block->guards = $guards;
2253
+ return true;
2254
+ } else {
2255
+ $this->seek($s);
2256
+ }
2257
+
2258
+ // opening a simple block
2259
+ if ($this->tags($tags) && $this->literal('{')) {
2260
+ $tags = $this->fixTags($tags);
2261
+ $this->pushBlock($tags);
2262
+ return true;
2263
+ } else {
2264
+ $this->seek($s);
2265
+ }
2266
+
2267
+ // closing a block
2268
+ if ($this->literal('}', false)) {
2269
+ try {
2270
+ $block = $this->pop();
2271
+ } catch (exception $e) {
2272
+ $this->seek($s);
2273
+ $this->throwError($e->getMessage());
2274
+ }
2275
+
2276
+ $hidden = false;
2277
+ if (is_null($block->type)) {
2278
+ $hidden = true;
2279
+ if (!isset($block->args)) {
2280
+ foreach ($block->tags as $tag) {
2281
+ if (!is_string($tag) || $tag{0} != $this->lessc->mPrefix) {
2282
+ $hidden = false;
2283
+ break;
2284
+ }
2285
+ }
2286
+ }
2287
+
2288
+ foreach ($block->tags as $tag) {
2289
+ if (is_string($tag)) {
2290
+ $this->env->children[$tag][] = $block;
2291
+ }
2292
+ }
2293
+ }
2294
+
2295
+ if (!$hidden) {
2296
+ $this->append(array('block', $block), $s);
2297
+ }
2298
+
2299
+ // this is done here so comments aren't bundled into he block that
2300
+ // was just closed
2301
+ $this->whitespace();
2302
+ return true;
2303
+ }
2304
+
2305
+ // mixin
2306
+ if ($this->mixinTags($tags) &&
2307
+ ($this->argumentValues($argv) || true) &&
2308
+ ($this->keyword($suffix) || true) && $this->end())
2309
+ {
2310
+ $tags = $this->fixTags($tags);
2311
+ $this->append(array('mixin', $tags, $argv, $suffix), $s);
2312
+ return true;
2313
+ } else {
2314
+ $this->seek($s);
2315
+ }
2316
+
2317
+ // spare ;
2318
+ if ($this->literal(';')) return true;
2319
+
2320
+ return false; // got nothing, throw error
2321
+ }
2322
+
2323
+ protected function isDirective($dirname, $directives) {
2324
+ // TODO: cache pattern in parser
2325
+ $pattern = implode("|",
2326
+ array_map(array("lessc", "preg_quote"), $directives));
2327
+ $pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i';
2328
+
2329
+ return preg_match($pattern, $dirname);
2330
+ }
2331
+
2332
+ protected function fixTags($tags) {
2333
+ // move @ tags out of variable namespace
2334
+ foreach ($tags as &$tag) {
2335
+ if ($tag{0} == $this->lessc->vPrefix)
2336
+ $tag[0] = $this->lessc->mPrefix;
2337
+ }
2338
+ return $tags;
2339
+ }
2340
+
2341
+ // a list of expressions
2342
+ protected function expressionList(&$exps) {
2343
+ $values = array();
2344
+
2345
+ while ($this->expression($exp)) {
2346
+ $values[] = $exp;
2347
+ }
2348
+
2349
+ if (count($values) == 0) return false;
2350
+
2351
+ $exps = lessc::compressList($values, ' ');
2352
+ return true;
2353
+ }
2354
+
2355
+ /**
2356
+ * Attempt to consume an expression.
2357
+ * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
2358
+ */
2359
+ protected function expression(&$out) {
2360
+ if ($this->value($lhs)) {
2361
+ $out = $this->expHelper($lhs, 0);
2362
+
2363
+ // look for / shorthand
2364
+ if (!empty($this->env->supressedDivision)) {
2365
+ unset($this->env->supressedDivision);
2366
+ $s = $this->seek();
2367
+ if ($this->literal("/") && $this->value($rhs)) {
2368
+ $out = array("list", "",
2369
+ array($out, array("keyword", "/"), $rhs));
2370
+ } else {
2371
+ $this->seek($s);
2372
+ }
2373
+ }
2374
+
2375
+ return true;
2376
+ }
2377
+ return false;
2378
+ }
2379
+
2380
+ /**
2381
+ * recursively parse infix equation with $lhs at precedence $minP
2382
+ */
2383
+ protected function expHelper($lhs, $minP) {
2384
+ $this->inExp = true;
2385
+ $ss = $this->seek();
2386
+
2387
+ while (true) {
2388
+ $whiteBefore = isset($this->buffer[$this->count - 1]) &&
2389
+ ctype_space($this->buffer[$this->count - 1]);
2390
+
2391
+ // If there is whitespace before the operator, then we require
2392
+ // whitespace after the operator for it to be an expression
2393
+ $needWhite = $whiteBefore && !$this->inParens;
2394
+
2395
+ if ($this->match(self::$operatorString.($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) {
2396
+ if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) {
2397
+ foreach (self::$supressDivisionProps as $pattern) {
2398
+ if (preg_match($pattern, $this->env->currentProperty)) {
2399
+ $this->env->supressedDivision = true;
2400
+ break 2;
2401
+ }
2402
+ }
2403
+ }
2404
+
2405
+
2406
+ $whiteAfter = isset($this->buffer[$this->count - 1]) &&
2407
+ ctype_space($this->buffer[$this->count - 1]);
2408
+
2409
+ if (!$this->value($rhs)) break;
2410
+
2411
+ // peek for next operator to see what to do with rhs
2412
+ if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]]) {
2413
+ $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]);
2414
+ }
2415
+
2416
+ $lhs = array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter);
2417
+ $ss = $this->seek();
2418
+
2419
+ continue;
2420
+ }
2421
+
2422
+ break;
2423
+ }
2424
+
2425
+ $this->seek($ss);
2426
+
2427
+ return $lhs;
2428
+ }
2429
+
2430
+ // consume a list of values for a property
2431
+ public function propertyValue(&$value, $keyName = null) {
2432
+ $values = array();
2433
+
2434
+ if ($keyName !== null) $this->env->currentProperty = $keyName;
2435
+
2436
+ $s = null;
2437
+ while ($this->expressionList($v)) {
2438
+ $values[] = $v;
2439
+ $s = $this->seek();
2440
+ if (!$this->literal(',')) break;
2441
+ }
2442
+
2443
+ if ($s) $this->seek($s);
2444
+
2445
+ if ($keyName !== null) unset($this->env->currentProperty);
2446
+
2447
+ if (count($values) == 0) return false;
2448
+
2449
+ $value = lessc::compressList($values, ', ');
2450
+ return true;
2451
+ }
2452
+
2453
+ protected function parenValue(&$out) {
2454
+ $s = $this->seek();
2455
+
2456
+ // speed shortcut
2457
+ if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") {
2458
+ return false;
2459
+ }
2460
+
2461
+ $inParens = $this->inParens;
2462
+ if ($this->literal("(") &&
2463
+ ($this->inParens = true) && $this->expression($exp) &&
2464
+ $this->literal(")"))
2465
+ {
2466
+ $out = $exp;
2467
+ $this->inParens = $inParens;
2468
+ return true;
2469
+ } else {
2470
+ $this->inParens = $inParens;
2471
+ $this->seek($s);
2472
+ }
2473
+
2474
+ return false;
2475
+ }
2476
+
2477
+ // a single value
2478
+ protected function value(&$value) {
2479
+ $s = $this->seek();
2480
+
2481
+ // speed shortcut
2482
+ if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") {
2483
+ // negation
2484
+ if ($this->literal("-", false) &&
2485
+ (($this->variable($inner) && $inner = array("variable", $inner)) ||
2486
+ $this->unit($inner) ||
2487
+ $this->parenValue($inner)))
2488
+ {
2489
+ $value = array("unary", "-", $inner);
2490
+ return true;
2491
+ } else {
2492
+ $this->seek($s);
2493
+ }
2494
+ }
2495
+
2496
+ if ($this->parenValue($value)) return true;
2497
+ if ($this->unit($value)) return true;
2498
+ if ($this->color($value)) return true;
2499
+ if ($this->func($value)) return true;
2500
+ if ($this->_string($value)) return true;
2501
+
2502
+ if ($this->keyword($word)) {
2503
+ $value = array('keyword', $word);
2504
+ return true;
2505
+ }
2506
+
2507
+ // try a variable
2508
+ if ($this->variable($var)) {
2509
+ $value = array('variable', $var);
2510
+ return true;
2511
+ }
2512
+
2513
+ // unquote string (should this work on any type?
2514
+ if ($this->literal("~") && $this->_string($str)) {
2515
+ $value = array("escape", $str);
2516
+ return true;
2517
+ } else {
2518
+ $this->seek($s);
2519
+ }
2520
+
2521
+ // css hack: \0
2522
+ if ($this->literal('\\') && $this->match('([0-9]+)', $m)) {
2523
+ $value = array('keyword', '\\'.$m[1]);
2524
+ return true;
2525
+ } else {
2526
+ $this->seek($s);
2527
+ }
2528
+
2529
+ return false;
2530
+ }
2531
+
2532
+ // an import statement
2533
+ protected function import(&$out) {
2534
+ $s = $this->seek();
2535
+ if (!$this->literal('@import')) return false;
2536
+
2537
+ // @import "something.css" media;
2538
+ // @import url("something.css") media;
2539
+ // @import url(something.css) media;
2540
+
2541
+ if ($this->propertyValue($value)) {
2542
+ $out = array("import", $value);
2543
+ return true;
2544
+ }
2545
+ }
2546
+
2547
+ protected function mediaQueryList(&$out) {
2548
+ if ($this->genericList($list, "mediaQuery", ",", false)) {
2549
+ $out = $list[2];
2550
+ return true;
2551
+ }
2552
+ return false;
2553
+ }
2554
+
2555
+ protected function mediaQuery(&$out) {
2556
+ $s = $this->seek();
2557
+
2558
+ $expressions = null;
2559
+ $parts = array();
2560
+
2561
+ if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) {
2562
+ $prop = array("mediaType");
2563
+ if (isset($only)) $prop[] = "only";
2564
+ if (isset($not)) $prop[] = "not";
2565
+ $prop[] = $mediaType;
2566
+ $parts[] = $prop;
2567
+ } else {
2568
+ $this->seek($s);
2569
+ }
2570
+
2571
+
2572
+ if (!empty($mediaType) && !$this->literal("and")) {
2573
+ // ~
2574
+ } else {
2575
+ $this->genericList($expressions, "mediaExpression", "and", false);
2576
+ if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]);
2577
+ }
2578
+
2579
+ if (count($parts) == 0) {
2580
+ $this->seek($s);
2581
+ return false;
2582
+ }
2583
+
2584
+ $out = $parts;
2585
+ return true;
2586
+ }
2587
+
2588
+ protected function mediaExpression(&$out) {
2589
+ $s = $this->seek();
2590
+ $value = null;
2591
+ if ($this->literal("(") &&
2592
+ $this->keyword($feature) &&
2593
+ ($this->literal(":") && $this->expression($value) || true) &&
2594
+ $this->literal(")"))
2595
+ {
2596
+ $out = array("mediaExp", $feature);
2597
+ if ($value) $out[] = $value;
2598
+ return true;
2599
+ } elseif ($this->variable($variable)) {
2600
+ $out = array('variable', $variable);
2601
+ return true;
2602
+ }
2603
+
2604
+ $this->seek($s);
2605
+ return false;
2606
+ }
2607
+
2608
+ // an unbounded string stopped by $end
2609
+ protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null) {
2610
+ $oldWhite = $this->eatWhiteDefault;
2611
+ $this->eatWhiteDefault = false;
2612
+
2613
+ $stop = array("'", '"', "@{", $end);
2614
+ $stop = array_map(array("lessc", "preg_quote"), $stop);
2615
+ // $stop[] = self::$commentMulti;
2616
+
2617
+ if (!is_null($rejectStrs)) {
2618
+ $stop = array_merge($stop, $rejectStrs);
2619
+ }
2620
+
2621
+ $patt = '(.*?)('.implode("|", $stop).')';
2622
+
2623
+ $nestingLevel = 0;
2624
+
2625
+ $content = array();
2626
+ while ($this->match($patt, $m, false)) {
2627
+ if (!empty($m[1])) {
2628
+ $content[] = $m[1];
2629
+ if ($nestingOpen) {
2630
+ $nestingLevel += substr_count($m[1], $nestingOpen);
2631
+ }
2632
+ }
2633
+
2634
+ $tok = $m[2];
2635
+
2636
+ $this->count-= strlen($tok);
2637
+ if ($tok == $end) {
2638
+ if ($nestingLevel == 0) {
2639
+ break;
2640
+ } else {
2641
+ $nestingLevel--;
2642
+ }
2643
+ }
2644
+
2645
+ if (($tok == "'" || $tok == '"') && $this->_string($str)) {
2646
+ $content[] = $str;
2647
+ continue;
2648
+ }
2649
+
2650
+ if ($tok == "@{" && $this->interpolation($inter)) {
2651
+ $content[] = $inter;
2652
+ continue;
2653
+ }
2654
+
2655
+ if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {
2656
+ $ount = null;
2657
+ break;
2658
+ }
2659
+
2660
+ $content[] = $tok;
2661
+ $this->count+= strlen($tok);
2662
+ }
2663
+
2664
+ $this->eatWhiteDefault = $oldWhite;
2665
+
2666
+ if (count($content) == 0) return false;
2667
+
2668
+ // trim the end
2669
+ if (is_string(end($content))) {
2670
+ $content[count($content) - 1] = rtrim(end($content));
2671
+ }
2672
+
2673
+ $out = array("string", "", $content);
2674
+ return true;
2675
+ }
2676
+
2677
+ protected function _string(&$out) {
2678
+ $s = $this->seek();
2679
+ if ($this->literal('"', false)) {
2680
+ $delim = '"';
2681
+ } elseif ($this->literal("'", false)) {
2682
+ $delim = "'";
2683
+ } else {
2684
+ return false;
2685
+ }
2686
+
2687
+ $content = array();
2688
+
2689
+ // look for either ending delim , escape, or string interpolation
2690
+ $patt = '([^\n]*?)(@\{|\\\\|' .
2691
+ lessc::preg_quote($delim).')';
2692
+
2693
+ $oldWhite = $this->eatWhiteDefault;
2694
+ $this->eatWhiteDefault = false;
2695
+
2696
+ while ($this->match($patt, $m, false)) {
2697
+ $content[] = $m[1];
2698
+ if ($m[2] == "@{") {
2699
+ $this->count -= strlen($m[2]);
2700
+ if ($this->interpolation($inter, false)) {
2701
+ $content[] = $inter;
2702
+ } else {
2703
+ $this->count += strlen($m[2]);
2704
+ $content[] = "@{"; // ignore it
2705
+ }
2706
+ } elseif ($m[2] == '\\') {
2707
+ $content[] = $m[2];
2708
+ if ($this->literal($delim, false)) {
2709
+ $content[] = $delim;
2710
+ }
2711
+ } else {
2712
+ $this->count -= strlen($delim);
2713
+ break; // delim
2714
+ }
2715
+ }
2716
+
2717
+ $this->eatWhiteDefault = $oldWhite;
2718
+
2719
+ if ($this->literal($delim)) {
2720
+ $out = array("string", $delim, $content);
2721
+ return true;
2722
+ }
2723
+
2724
+ $this->seek($s);
2725
+ return false;
2726
+ }
2727
+
2728
+ protected function interpolation(&$out) {
2729
+ $oldWhite = $this->eatWhiteDefault;
2730
+ $this->eatWhiteDefault = true;
2731
+
2732
+ $s = $this->seek();
2733
+ if ($this->literal("@{") &&
2734
+ $this->openString("}", $interp, null, array("'", '"', ";")) &&
2735
+ $this->literal("}", false))
2736
+ {
2737
+ $out = array("interpolate", $interp);
2738
+ $this->eatWhiteDefault = $oldWhite;
2739
+ if ($this->eatWhiteDefault) $this->whitespace();
2740
+ return true;
2741
+ }
2742
+
2743
+ $this->eatWhiteDefault = $oldWhite;
2744
+ $this->seek($s);
2745
+ return false;
2746
+ }
2747
+
2748
+ protected function unit(&$unit) {
2749
+ // speed shortcut
2750
+ if (isset($this->buffer[$this->count])) {
2751
+ $char = $this->buffer[$this->count];
2752
+ if (!ctype_digit($char) && $char != ".") return false;
2753
+ }
2754
+
2755
+ if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) {
2756
+ $unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]);
2757
+ return true;
2758
+ }
2759
+ return false;
2760
+ }
2761
+
2762
+ // a # color
2763
+ protected function color(&$out) {
2764
+ if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) {
2765
+ if (strlen($m[1]) > 7) {
2766
+ $out = array("string", "", array($m[1]));
2767
+ } else {
2768
+ $out = array("raw_color", $m[1]);
2769
+ }
2770
+ return true;
2771
+ }
2772
+
2773
+ return false;
2774
+ }
2775
+
2776
+ // consume a list of property values delimited by ; and wrapped in ()
2777
+ protected function argumentValues(&$args, $delim = ',') {
2778
+ $s = $this->seek();
2779
+ if (!$this->literal('(')) return false;
2780
+
2781
+ $values = array();
2782
+ while (true) {
2783
+ if ($this->expressionList($value)) $values[] = $value;
2784
+ if (!$this->literal($delim)) break;
2785
+ else {
2786
+ if ($value == null) $values[] = null;
2787
+ $value = null;
2788
+ }
2789
+ }
2790
+
2791
+ if (!$this->literal(')')) {
2792
+ $this->seek($s);
2793
+ return false;
2794
+ }
2795
+
2796
+ $args = $values;
2797
+ return true;
2798
+ }
2799
+
2800
+ // consume an argument definition list surrounded by ()
2801
+ // each argument is a variable name with optional value
2802
+ // or at the end a ... or a variable named followed by ...
2803
+ protected function argumentDef(&$args, &$isVararg, $delim = ',') {
2804
+ $s = $this->seek();
2805
+ if (!$this->literal('(')) return false;
2806
+
2807
+ $values = array();
2808
+
2809
+ $isVararg = false;
2810
+ while (true) {
2811
+ if ($this->literal("...")) {
2812
+ $isVararg = true;
2813
+ break;
2814
+ }
2815
+
2816
+ if ($this->variable($vname)) {
2817
+ $arg = array("arg", $vname);
2818
+ $ss = $this->seek();
2819
+ if ($this->assign() && $this->expressionList($value)) {
2820
+ $arg[] = $value;
2821
+ } else {
2822
+ $this->seek($ss);
2823
+ if ($this->literal("...")) {
2824
+ $arg[0] = "rest";
2825
+ $isVararg = true;
2826
+ }
2827
+ }
2828
+ $values[] = $arg;
2829
+ if ($isVararg) break;
2830
+ continue;
2831
+ }
2832
+
2833
+ if ($this->value($literal)) {
2834
+ $values[] = array("lit", $literal);
2835
+ }
2836
+
2837
+ if (!$this->literal($delim)) break;
2838
+ }
2839
+
2840
+ if (!$this->literal(')')) {
2841
+ $this->seek($s);
2842
+ return false;
2843
+ }
2844
+
2845
+ $args = $values;
2846
+
2847
+ return true;
2848
+ }
2849
+
2850
+ // consume a list of tags
2851
+ // this accepts a hanging delimiter
2852
+ protected function tags(&$tags, $simple = false, $delim = ',') {
2853
+ $tags = array();
2854
+ while ($this->tag($tt, $simple)) {
2855
+ $tags[] = $tt;
2856
+ if (!$this->literal($delim)) break;
2857
+ }
2858
+ if (count($tags) == 0) return false;
2859
+
2860
+ return true;
2861
+ }
2862
+
2863
+ // list of tags of specifying mixin path
2864
+ // optionally separated by > (lazy, accepts extra >)
2865
+ protected function mixinTags(&$tags) {
2866
+ $s = $this->seek();
2867
+ $tags = array();
2868
+ while ($this->tag($tt, true)) {
2869
+ $tags[] = $tt;
2870
+ $this->literal(">");
2871
+ }
2872
+
2873
+ if (count($tags) == 0) return false;
2874
+
2875
+ return true;
2876
+ }
2877
+
2878
+ // a bracketed value (contained within in a tag definition)
2879
+ protected function tagBracket(&$value) {
2880
+ // speed shortcut
2881
+ if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
2882
+ return false;
2883
+ }
2884
+
2885
+ $s = $this->seek();
2886
+ if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false)) {
2887
+ $value = '['.$c.']';
2888
+ // whitespace?
2889
+ if ($this->whitespace()) $value .= " ";
2890
+
2891
+ // escape parent selector, (yuck)
2892
+ $value = str_replace($this->lessc->parentSelector, "$&$", $value);
2893
+ return true;
2894
+ }
2895
+
2896
+ $this->seek($s);
2897
+ return false;
2898
+ }
2899
+
2900
+ protected function tagExpression(&$value) {
2901
+ $s = $this->seek();
2902
+ if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
2903
+ $value = array('exp', $exp);
2904
+ return true;
2905
+ }
2906
+
2907
+ $this->seek($s);
2908
+ return false;
2909
+ }
2910
+
2911
+ // a space separated list of selectors
2912
+ protected function tag(&$tag, $simple = false) {
2913
+ if ($simple)
2914
+ $chars = '^@,:;{}\][>\(\) "\'';
2915
+ else
2916
+ $chars = '^@,;{}["\'';
2917
+
2918
+ $s = $this->seek();
2919
+
2920
+ if (!$simple && $this->tagExpression($tag)) {
2921
+ return true;
2922
+ }
2923
+
2924
+ $hasExpression = false;
2925
+ $parts = array();
2926
+ while ($this->tagBracket($first)) $parts[] = $first;
2927
+
2928
+ $oldWhite = $this->eatWhiteDefault;
2929
+ $this->eatWhiteDefault = false;
2930
+
2931
+ while (true) {
2932
+ if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) {
2933
+ $parts[] = $m[1];
2934
+ if ($simple) break;
2935
+
2936
+ while ($this->tagBracket($brack)) {
2937
+ $parts[] = $brack;
2938
+ }
2939
+ continue;
2940
+ }
2941
+
2942
+ if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") {
2943
+ if ($this->interpolation($interp)) {
2944
+ $hasExpression = true;
2945
+ $interp[2] = true; // don't unescape
2946
+ $parts[] = $interp;
2947
+ continue;
2948
+ }
2949
+
2950
+ if ($this->literal("@")) {
2951
+ $parts[] = "@";
2952
+ continue;
2953
+ }
2954
+ }
2955
+
2956
+ if ($this->unit($unit)) { // for keyframes
2957
+ $parts[] = $unit[1];
2958
+ $parts[] = $unit[2];
2959
+ continue;
2960
+ }
2961
+
2962
+ break;
2963
+ }
2964
+
2965
+ $this->eatWhiteDefault = $oldWhite;
2966
+ if (!$parts) {
2967
+ $this->seek($s);
2968
+ return false;
2969
+ }
2970
+
2971
+ if ($hasExpression) {
2972
+ $tag = array("exp", array("string", "", $parts));
2973
+ } else {
2974
+ $tag = trim(implode($parts));
2975
+ }
2976
+
2977
+ $this->whitespace();
2978
+ return true;
2979
+ }
2980
+
2981
+ // a css function
2982
+ protected function func(&$func) {
2983
+ $s = $this->seek();
2984
+
2985
+ if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('(')) {
2986
+ $fname = $m[1];
2987
+
2988
+ $sPreArgs = $this->seek();
2989
+
2990
+ $args = array();
2991
+ while (true) {
2992
+ $ss = $this->seek();
2993
+ // this ugly nonsense is for ie filter properties
2994
+ if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) {
2995
+ $args[] = array("string", "", array($name, "=", $value));
2996
+ } else {
2997
+ $this->seek($ss);
2998
+ if ($this->expressionList($value)) {
2999
+ $args[] = $value;
3000
+ }
3001
+ }
3002
+
3003
+ if (!$this->literal(',')) break;
3004
+ }
3005
+ $args = array('list', ',', $args);
3006
+
3007
+ if ($this->literal(')')) {
3008
+ $func = array('function', $fname, $args);
3009
+ return true;
3010
+ } elseif ($fname == 'url') {
3011
+ // couldn't parse and in url? treat as string
3012
+ $this->seek($sPreArgs);
3013
+ if ($this->openString(")", $string) && $this->literal(")")) {
3014
+ $func = array('function', $fname, $string);
3015
+ return true;
3016
+ }
3017
+ }
3018
+ }
3019
+
3020
+ $this->seek($s);
3021
+ return false;
3022
+ }
3023
+
3024
+ // consume a less variable
3025
+ protected function variable(&$name) {
3026
+ $s = $this->seek();
3027
+ if ($this->literal($this->lessc->vPrefix, false) &&
3028
+ ($this->variable($sub) || $this->keyword($name)))
3029
+ {
3030
+ if (!empty($sub)) {
3031
+ $name = array('variable', $sub);
3032
+ } else {
3033
+ $name = $this->lessc->vPrefix.$name;
3034
+ }
3035
+ return true;
3036
+ }
3037
+
3038
+ $name = null;
3039
+ $this->seek($s);
3040
+ return false;
3041
+ }
3042
+
3043
+ /**
3044
+ * Consume an assignment operator
3045
+ * Can optionally take a name that will be set to the current property name
3046
+ */
3047
+ protected function assign($name = null) {
3048
+ if ($name) $this->currentProperty = $name;
3049
+ return $this->literal(':') || $this->literal('=');
3050
+ }
3051
+
3052
+ // consume a keyword
3053
+ protected function keyword(&$word) {
3054
+ if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) {
3055
+ $word = $m[1];
3056
+ return true;
3057
+ }
3058
+ return false;
3059
+ }
3060
+
3061
+ // consume an end of statement delimiter
3062
+ protected function end() {
3063
+ if ($this->literal(';')) {
3064
+ return true;
3065
+ } elseif ($this->count == strlen($this->buffer) || $this->buffer{$this->count} == '}') {
3066
+ // if there is end of file or a closing block next then we don't need a ;
3067
+ return true;
3068
+ }
3069
+ return false;
3070
+ }
3071
+
3072
+ protected function guards(&$guards) {
3073
+ $s = $this->seek();
3074
+
3075
+ if (!$this->literal("when")) {
3076
+ $this->seek($s);
3077
+ return false;
3078
+ }
3079
+
3080
+ $guards = array();
3081
+
3082
+ while ($this->guardGroup($g)) {
3083
+ $guards[] = $g;
3084
+ if (!$this->literal(",")) break;
3085
+ }
3086
+
3087
+ if (count($guards) == 0) {
3088
+ $guards = null;
3089
+ $this->seek($s);
3090
+ return false;
3091
+ }
3092
+
3093
+ return true;
3094
+ }
3095
+
3096
+ // a bunch of guards that are and'd together
3097
+ // TODO rename to guardGroup
3098
+ protected function guardGroup(&$guardGroup) {
3099
+ $s = $this->seek();
3100
+ $guardGroup = array();
3101
+ while ($this->guard($guard)) {
3102
+ $guardGroup[] = $guard;
3103
+ if (!$this->literal("and")) break;
3104
+ }
3105
+
3106
+ if (count($guardGroup) == 0) {
3107
+ $guardGroup = null;
3108
+ $this->seek($s);
3109
+ return false;
3110
+ }
3111
+
3112
+ return true;
3113
+ }
3114
+
3115
+ protected function guard(&$guard) {
3116
+ $s = $this->seek();
3117
+ $negate = $this->literal("not");
3118
+
3119
+ if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
3120
+ $guard = $exp;
3121
+ if ($negate) $guard = array("negate", $guard);
3122
+ return true;
3123
+ }
3124
+
3125
+ $this->seek($s);
3126
+ return false;
3127
+ }
3128
+
3129
+ /* raw parsing functions */
3130
+
3131
+ protected function literal($what, $eatWhitespace = null) {
3132
+ if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
3133
+
3134
+ // shortcut on single letter
3135
+ if (!isset($what[1]) && isset($this->buffer[$this->count])) {
3136
+ if ($this->buffer[$this->count] == $what) {
3137
+ if (!$eatWhitespace) {
3138
+ $this->count++;
3139
+ return true;
3140
+ }
3141
+ // goes below...
3142
+ } else {
3143
+ return false;
3144
+ }
3145
+ }
3146
+
3147
+ if (!isset(self::$literalCache[$what])) {
3148
+ self::$literalCache[$what] = lessc::preg_quote($what);
3149
+ }
3150
+
3151
+ return $this->match(self::$literalCache[$what], $m, $eatWhitespace);
3152
+ }
3153
+
3154
+ protected function genericList(&$out, $parseItem, $delim="", $flatten=true) {
3155
+ $s = $this->seek();
3156
+ $items = array();
3157
+ while ($this->$parseItem($value)) {
3158
+ $items[] = $value;
3159
+ if ($delim) {
3160
+ if (!$this->literal($delim)) break;
3161
+ }
3162
+ }
3163
+
3164
+ if (count($items) == 0) {
3165
+ $this->seek($s);
3166
+ return false;
3167
+ }
3168
+
3169
+ if ($flatten && count($items) == 1) {
3170
+ $out = $items[0];
3171
+ } else {
3172
+ $out = array("list", $delim, $items);
3173
+ }
3174
+
3175
+ return true;
3176
+ }
3177
+
3178
+
3179
+ // advance counter to next occurrence of $what
3180
+ // $until - don't include $what in advance
3181
+ // $allowNewline, if string, will be used as valid char set
3182
+ protected function to($what, &$out, $until = false, $allowNewline = false) {
3183
+ if (is_string($allowNewline)) {
3184
+ $validChars = $allowNewline;
3185
+ } else {
3186
+ $validChars = $allowNewline ? "." : "[^\n]";
3187
+ }
3188
+ if (!$this->match('('.$validChars.'*?)'.lessc::preg_quote($what), $m, !$until)) return false;
3189
+ if ($until) $this->count -= strlen($what); // give back $what
3190
+ $out = $m[1];
3191
+ return true;
3192
+ }
3193
+
3194
+ // try to match something on head of buffer
3195
+ protected function match($regex, &$out, $eatWhitespace = null) {
3196
+ if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
3197
+
3198
+ $r = '/'.$regex.($eatWhitespace && !$this->writeComments ? '\s*' : '').'/Ais';
3199
+ if (preg_match($r, $this->buffer, $out, null, $this->count)) {
3200
+ $this->count += strlen($out[0]);
3201
+ if ($eatWhitespace && $this->writeComments) $this->whitespace();
3202
+ return true;
3203
+ }
3204
+ return false;
3205
+ }
3206
+
3207
+ // match some whitespace
3208
+ protected function whitespace() {
3209
+ if ($this->writeComments) {
3210
+ $gotWhite = false;
3211
+ while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) {
3212
+ if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
3213
+ $this->append(array("comment", $m[1]));
3214
+ $this->commentsSeen[$this->count] = true;
3215
+ }
3216
+ $this->count += strlen($m[0]);
3217
+ $gotWhite = true;
3218
+ }
3219
+ return $gotWhite;
3220
+ } else {
3221
+ $this->match("", $m);
3222
+ return strlen($m[0]) > 0;
3223
+ }
3224
+ }
3225
+
3226
+ // match something without consuming it
3227
+ protected function peek($regex, &$out = null, $from=null) {
3228
+ if (is_null($from)) $from = $this->count;
3229
+ $r = '/'.$regex.'/Ais';
3230
+ $result = preg_match($r, $this->buffer, $out, null, $from);
3231
+
3232
+ return $result;
3233
+ }
3234
+
3235
+ // seek to a spot in the buffer or return where we are on no argument
3236
+ protected function seek($where = null) {
3237
+ if ($where === null) return $this->count;
3238
+ else $this->count = $where;
3239
+ return true;
3240
+ }
3241
+
3242
+ /* misc functions */
3243
+
3244
+ public function throwError($msg = "parse error", $count = null) {
3245
+ $count = is_null($count) ? $this->count : $count;
3246
+
3247
+ $line = $this->line +
3248
+ substr_count(substr($this->buffer, 0, $count), "\n");
3249
+
3250
+ if (!empty($this->sourceName)) {
3251
+ $loc = "$this->sourceName on line $line";
3252
+ } else {
3253
+ $loc = "line: $line";
3254
+ }
3255
+
3256
+ // TODO this depends on $this->count
3257
+ if ($this->peek("(.*?)(\n|$)", $m, $count)) {
3258
+ throw new exception("$msg: failed at `$m[1]` $loc");
3259
+ } else {
3260
+ throw new exception("$msg: $loc");
3261
+ }
3262
+ }
3263
+
3264
+ protected function pushBlock($selectors=null, $type=null) {
3265
+ $b = new stdclass;
3266
+ $b->parent = $this->env;
3267
+
3268
+ $b->type = $type;
3269
+ $b->id = self::$nextBlockId++;
3270
+
3271
+ $b->isVararg = false; // TODO: kill me from here
3272
+ $b->tags = $selectors;
3273
+
3274
+ $b->props = array();
3275
+ $b->children = array();
3276
+
3277
+ $this->env = $b;
3278
+ return $b;
3279
+ }
3280
+
3281
+ // push a block that doesn't multiply tags
3282
+ protected function pushSpecialBlock($type) {
3283
+ return $this->pushBlock(null, $type);
3284
+ }
3285
+
3286
+ // append a property to the current block
3287
+ protected function append($prop, $pos = null) {
3288
+ if ($pos !== null) $prop[-1] = $pos;
3289
+ $this->env->props[] = $prop;
3290
+ }
3291
+
3292
+ // pop something off the stack
3293
+ protected function pop() {
3294
+ $old = $this->env;
3295
+ $this->env = $this->env->parent;
3296
+ return $old;
3297
+ }
3298
+
3299
+ // remove comments from $text
3300
+ // todo: make it work for all functions, not just url
3301
+ protected function removeComments($text) {
3302
+ $look = array(
3303
+ 'url(', '//', '/*', '"', "'"
3304
+ );
3305
+
3306
+ $out = '';
3307
+ $min = null;
3308
+ while (true) {
3309
+ // find the next item
3310
+ foreach ($look as $token) {
3311
+ $pos = strpos($text, $token);
3312
+ if ($pos !== false) {
3313
+ if (!isset($min) || $pos < $min[1]) $min = array($token, $pos);
3314
+ }
3315
+ }
3316
+
3317
+ if (is_null($min)) break;
3318
+
3319
+ $count = $min[1];
3320
+ $skip = 0;
3321
+ $newlines = 0;
3322
+ switch ($min[0]) {
3323
+ case 'url(':
3324
+ if (preg_match('/url\(.*?\)/', $text, $m, 0, $count))
3325
+ $count += strlen($m[0]) - strlen($min[0]);
3326
+ break;
3327
+ case '"':
3328
+ case "'":
3329
+ if (preg_match('/'.$min[0].'.*?'.$min[0].'/', $text, $m, 0, $count))
3330
+ $count += strlen($m[0]) - 1;
3331
+ break;
3332
+ case '//':
3333
+ $skip = strpos($text, "\n", $count);
3334
+ if ($skip === false) $skip = strlen($text) - $count;
3335
+ else $skip -= $count;
3336
+ break;
3337
+ case '/*':
3338
+ if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) {
3339
+ $skip = strlen($m[0]);
3340
+ $newlines = substr_count($m[0], "\n");
3341
+ }
3342
+ break;
3343
+ }
3344
+
3345
+ if ($skip == 0) $count += strlen($min[0]);
3346
+
3347
+ $out .= substr($text, 0, $count).str_repeat("\n", $newlines);
3348
+ $text = substr($text, $count + $skip);
3349
+
3350
+ $min = null;
3351
+ }
3352
+
3353
+ return $out.$text;
3354
+ }
3355
+
3356
+ }
3357
+
3358
+ class lessc_formatter_classic {
3359
+ public $indentChar = " ";
3360
+
3361
+ public $break = "\n";
3362
+ public $open = " {";
3363
+ public $close = "}";
3364
+ public $selectorSeparator = ", ";
3365
+ public $assignSeparator = ":";
3366
+
3367
+ public $openSingle = " { ";
3368
+ public $closeSingle = " }";
3369
+
3370
+ public $disableSingle = false;
3371
+ public $breakSelectors = false;
3372
+
3373
+ public $compressColors = false;
3374
+
3375
+ public function __construct() {
3376
+ $this->indentLevel = 0;
3377
+ }
3378
+
3379
+ public function indentStr($n = 0) {
3380
+ return str_repeat($this->indentChar, max($this->indentLevel + $n, 0));
3381
+ }
3382
+
3383
+ public function property($name, $value) {
3384
+ return $name . $this->assignSeparator . $value . ";";
3385
+ }
3386
+
3387
+ protected function isEmpty($block) {
3388
+ if (empty($block->lines)) {
3389
+ foreach ($block->children as $child) {
3390
+ if (!$this->isEmpty($child)) return false;
3391
+ }
3392
+
3393
+ return true;
3394
+ }
3395
+ return false;
3396
+ }
3397
+
3398
+ public function block($block) {
3399
+ if ($this->isEmpty($block)) return;
3400
+
3401
+ $inner = $pre = $this->indentStr();
3402
+
3403
+ $isSingle = !$this->disableSingle &&
3404
+ is_null($block->type) && count($block->lines) == 1;
3405
+
3406
+ if (!empty($block->selectors)) {
3407
+ $this->indentLevel++;
3408
+
3409
+ if ($this->breakSelectors) {
3410
+ $selectorSeparator = $this->selectorSeparator . $this->break . $pre;
3411
+ } else {
3412
+ $selectorSeparator = $this->selectorSeparator;
3413
+ }
3414
+
3415
+ echo $pre .
3416
+ implode($selectorSeparator, $block->selectors);
3417
+ if ($isSingle) {
3418
+ echo $this->openSingle;
3419
+ $inner = "";
3420
+ } else {
3421
+ echo $this->open . $this->break;
3422
+ $inner = $this->indentStr();
3423
+ }
3424
+
3425
+ }
3426
+
3427
+ if (!empty($block->lines)) {
3428
+ $glue = $this->break.$inner;
3429
+ echo $inner . implode($glue, $block->lines);
3430
+ if (!$isSingle && !empty($block->children)) {
3431
+ echo $this->break;
3432
+ }
3433
+ }
3434
+
3435
+ foreach ($block->children as $child) {
3436
+ $this->block($child);
3437
+ }
3438
+
3439
+ if (!empty($block->selectors)) {
3440
+ if (!$isSingle && empty($block->children)) echo $this->break;
3441
+
3442
+ if ($isSingle) {
3443
+ echo $this->closeSingle . $this->break;
3444
+ } else {
3445
+ echo $pre . $this->close . $this->break;
3446
+ }
3447
+
3448
+ $this->indentLevel--;
3449
+ }
3450
+ }
3451
+ }
3452
+
3453
+ class lessc_formatter_compressed extends lessc_formatter_classic {
3454
+ public $disableSingle = true;
3455
+ public $open = "{";
3456
+ public $selectorSeparator = ",";
3457
+ public $assignSeparator = ":";
3458
+ public $break = "";
3459
+ public $compressColors = true;
3460
+
3461
+ public function indentStr($n = 0) {
3462
+ return "";
3463
+ }
3464
+ }
3465
+
3466
+ class lessc_formatter_lessjs extends lessc_formatter_classic {
3467
+ public $disableSingle = true;
3468
+ public $breakSelectors = true;
3469
+ public $assignSeparator = ": ";
3470
+ public $selectorSeparator = ",";
3471
+ }
3472
+
3473
+
widgets/widgets.php CHANGED
@@ -1,1011 +1,1011 @@
1
- <?php
2
- // Include all the basic widgets
3
- include plugin_dir_path(__FILE__) . '/less/functions.php';
4
-
5
- /**
6
- * Include all the widget files and register their widgets
7
- */
8
- function origin_widgets_init(){
9
- foreach(glob(plugin_dir_path(__FILE__).'/widgets/*/*.php') as $file) {
10
- include_once ($file);
11
-
12
- $p = pathinfo($file);
13
- $class = $p['filename'];
14
- $class = str_replace('-', ' ', $class);
15
- $class = ucwords($class);
16
- $class = str_replace(' ', '_', $class);
17
-
18
- $class = 'SiteOrigin_Panels_Widget_'.$class;
19
- if( class_exists($class) ) register_widget($class);
20
- }
21
- }
22
- add_action('widgets_init', 'origin_widgets_init');
23
-
24
- function origin_widgets_enqueue($prefix){
25
- if($prefix == 'widgets.php') wp_enqueue_script('origin-widgets-admin-script', plugin_dir_url( __FILE__ ).'js/admin.js', array('jquery'), SITEORIGIN_PANELS_VERSION);
26
- }
27
- add_action('admin_enqueue_scripts', 'origin_widgets_enqueue');
28
-
29
- function origin_widgets_generate_css($class, $style, $preset, $version = null){
30
- $widget = new $class();
31
- if( !is_subclass_of($widget, 'SiteOrigin_Panels_Widget') ) return '';
32
- if(empty($version)) $version = SITEORIGIN_PANELS_VERSION;
33
-
34
- $id = str_replace('_', '', strtolower(str_replace('SiteOrigin_Panels_Widget_', '', $class)));
35
- $key = strtolower($id.'-'.$style.'-'. $preset.'-'.str_replace('.', '', $version));
36
-
37
- $css = get_site_transient('origin_wcss:'.$key);
38
- if($css === false || ( defined('SITEORIGIN_PANELS_NOCACHE') && SITEORIGIN_PANELS_NOCACHE ) ) {
39
-
40
- // Recreate the CSS
41
- $css = "/* Regenerate Cache */\n\n" ;
42
- $css .= $widget->create_css($style, $preset);
43
- $css = preg_replace('#/\*.*?\*/#s', '', $css);
44
- $css = preg_replace('/\s*([{}|:;,])\s+/', '$1', $css);
45
- $css = preg_replace('/\s\s+(.*)/', '$1', $css);
46
- $css = str_replace(';}', '}', $css);
47
-
48
- set_site_transient('origin_wcss:'.$key, $css, 86400);
49
- }
50
-
51
- return $css;
52
- }
53
-
54
- function origin_widgets_footer_css(){
55
- global $origin_widgets_generated_css;
56
- if( !empty( $origin_widgets_generated_css ) ) {
57
- echo '<style type="text/css">';
58
- foreach( $origin_widgets_generated_css as $id => $css ) {
59
- if( empty($css) ) continue;
60
- echo $css;
61
- $origin_widgets_generated_css[$id] = '';
62
- }
63
- echo '</style>';
64
- }
65
- }
66
- add_action('wp_head', 'origin_widgets_footer_css');
67
- add_action('wp_footer', 'origin_widgets_footer_css');
68
-
69
- /**
70
- * Class SiteOrigin_Panels_Widget
71
- */
72
- abstract class SiteOrigin_Panels_Widget extends WP_Widget{
73
- public $form_args;
74
- protected $demo;
75
- protected $origin_id;
76
- public $sub_widgets;
77
-
78
- private $styles;
79
-
80
- /**
81
- * Create the widget
82
- *
83
- * @param string $name Name for the widget displayed on the configuration page.
84
- * @param array $widget_options Optional Passed to wp_register_sidebar_widget()
85
- * - description: shown on the configuration page
86
- * - classname
87
- * @param array $control_options Optional Passed to wp_register_widget_control()
88
- * - width: required if more than 250px
89
- * - height: currently not used but may be needed in the future
90
- * @param array $form Form arguments.
91
- * @param array $demo Values for the demo of the page builder widget.
92
- * @internal param string $id_base
93
- */
94
- function __construct($name, $widget_options = array(), $control_options = array(), $form = array(), $demo = array()){
95
- $id_base = str_replace('SiteOrigin_Panels_Widget_', '', get_class($this));
96
- $id_base = strtolower(str_replace('_', '-', $id_base));
97
-
98
- parent::__construct('origin_'.$id_base, $name, $widget_options, $control_options);
99
- $this->origin_id = $id_base;
100
-
101
- $this->form_args = $form;
102
- $this->demo = $demo;
103
- $this->styles = array();
104
- $this->sub_widgets = array();
105
- }
106
-
107
- /**
108
- * Update the widget and save the new CSS.
109
- *
110
- * @param array $old
111
- * @param array $new
112
- * @return array
113
- */
114
- function update($new, $old) {
115
-
116
- // We wont clear cache if this is a preview
117
- if( !is_preview() ){
118
- // Remove the old CSS file
119
- if(!empty($old['origin_style'])) {
120
- list($style, $preset) = explode(':', $old['origin_style']);
121
- $this->clear_css_cache($style, $preset);
122
- }
123
-
124
- // Clear the cache for all sub widgets
125
- if(!empty($this->sub_widgets)){
126
- global $wp_widget_factory;
127
- foreach($this->sub_widgets as $id => $sub) {
128
- if(empty($old['origin_style_'.$id])) continue;
129
- $the_widget = $wp_widget_factory->widgets[$sub[1]];
130
- list($style, $preset) = explode(':', $old['origin_style_'.$id]);
131
-
132
- $the_widget->clear_css_cache($style, $preset);
133
- }
134
- }
135
-
136
-
137
-
138
- }
139
-
140
- foreach($this->form_args as $field_id => $field_args) {
141
- if($field_args['type'] == 'checkbox') {
142
- $new[$field_id] = !empty($new[$field_id]);
143
- }
144
- }
145
-
146
- return $new;
147
- }
148
-
149
- /**
150
- * Display the form for the widget. Auto generated from form array.
151
- *
152
- * @param array $instance
153
- * @return string|void
154
- */
155
- public function form($instance){
156
-
157
- ?>
158
- <div style="margin-bottom: 20px;">
159
- <strong>
160
- <?php
161
- _e( 'This is a legacy widget. ', 'siteorigin-panels' );
162
- _e( 'Ideally you should move to using widgets from the SiteOrigin Widgets Bundle instead. ', 'siteorigin-panels' );
163
- _e( "It'll be moved to a separate plugin after Page Builder 2.6 is released. ", 'siteorigin-panels' );
164
- echo '<a href="https://siteorigin.com/widgets-bundle/" target="_blank" rel="noopener noreferrer">' . __( 'Widgets Bundle', 'siteorigin-panels' ) . '</a>';
165
- ?>
166
- </strong>
167
- </div>
168
- <?php
169
-
170
- foreach($this->form_args as $field_id => $field_args) {
171
- if(isset($field_args['default']) && !isset($instance[$field_id])) {
172
- $instance[$field_id] = $field_args['default'];
173
- }
174
- if(!isset($instance[$field_id])) $instance[$field_id] = false;
175
-
176
- ?><p><label for="<?php echo $this->get_field_id( $field_id ); ?>"><?php echo esc_html($field_args['label']) ?></label><?php
177
-
178
- if($field_args['type'] != 'checkbox') echo '<br />';
179
-
180
- switch($field_args['type']) {
181
- case 'text' :
182
- ?><input type="text" class="widefat" id="<?php echo $this->get_field_id( $field_id ); ?>" name="<?php echo $this->get_field_name( $field_id ); ?>" value="<?php echo esc_attr($instance[$field_id]) ?>" /><?php
183
- break;
184
- case 'textarea' :
185
- if(empty($field_args['height'])) $field_args['height'] = 6;
186
- ?><textarea class="widefat" id="<?php echo $this->get_field_id( $field_id ); ?>" name="<?php echo $this->get_field_name( $field_id ); ?>" rows="<?php echo intval($field_args['height']) ?>"><?php echo esc_textarea($instance[$field_id]) ?></textarea><?php
187
- break;
188
- case 'number' :
189
- ?><input type="number" class="small-text" id="<?php echo $this->get_field_id( $field_id ); ?>" name="<?php echo $this->get_field_name( $field_id ); ?>" value="<?php echo floatval($instance[$field_id]) ?>" /><?php
190
- break;
191
- case 'checkbox' :
192
- ?><input type="checkbox" class="small-text" id="<?php echo $this->get_field_id( $field_id ); ?>" name="<?php echo $this->get_field_name( $field_id ); ?>" <?php checked(!empty($instance[$field_id])) ?>/><?php
193
- break;
194
- case 'select' :
195
- ?>
196
- <select id="<?php echo $this->get_field_id( $field_id ); ?>" name="<?php echo $this->get_field_name( $field_id ); ?>">
197
- <?php foreach($field_args['options'] as $k => $v) : ?>
198
- <option value="<?php echo esc_attr($k) ?>" <?php selected($instance[$field_id], $k) ?>><?php echo esc_html($v) ?></option>
199
- <?php endforeach; ?>
200
- </select>
201
- <?php
202
- break;
203
- }
204
- if(!empty($field_args['description'])) echo '<small class="description">'.esc_html($field_args['description']).'</small>';
205
-
206
- ?></p><?php
207
- }
208
-
209
- if(!isset($instance['origin_style'])) {
210
- $instance['origin_style'] = !empty($this->widget_options['default_style']) ? $this->widget_options['default_style'] : false;
211
- }
212
-
213
- do_action('siteorigin_panels_widget_before_styles', $this, $instance);
214
-
215
- // Now, lets add the style options.
216
- $styles = $this->get_styles();
217
- if( !empty( $styles ) ) {
218
- ?>
219
- <p>
220
- <label for="<?php echo $this->get_field_id('origin_style') ?>"><?php _e('Style', 'siteorigin-panels') ?></label>
221
- <select name="<?php echo $this->get_field_name('origin_style') ?>" id="<?php echo $this->get_field_id('origin_style') ?>">
222
- <?php foreach($this->get_styles() as $style_id => $style_info) : $presets = $this->get_style_presets($style_id); ?>
223
- <?php if(!empty($presets)) : foreach($presets as $preset_id => $preset) : ?>
224
- <option value="<?php echo esc_attr($style_id.':'.$preset_id) ?>" <?php selected($style_id.':'.$preset_id, $instance['origin_style']) ?>>
225
- <?php echo esc_html($style_info['Name'] . ' - ' . ucwords( str_replace( '_', ' ', $preset_id ) ) ) ?>
226
- </option>
227
- <?php endforeach; endif; ?>
228
- <?php endforeach ?>
229
- </select>
230
- </p>
231
- <?php
232
- }
233
-
234
- do_action('siteorigin_panels_widget_before_substyles', $this, $instance);
235
-
236
- foreach($this->sub_widgets as $id => $sub) {
237
- global $wp_widget_factory;
238
- $the_widget = $wp_widget_factory->widgets[$sub[1]];
239
-
240
- if(!isset($instance['origin_style_'.$id])) $instance['origin_style_'.$id] = !empty($this->widget_options['default_style_'.$id]) ? $this->widget_options['default_style_'.$id] : false;
241
-
242
- ?>
243
- <p>
244
- <label for="<?php echo $this->get_field_id('origin_style_'.$id) ?>"><?php printf(__('%s Style', 'siteorigin-panels'), $sub[0]) ?></label>
245
- <select name="<?php echo $this->get_field_name('origin_style_'.$id) ?>" id="<?php echo $this->get_field_id('origin_style_'.$id) ?>">
246
- <?php foreach($the_widget->get_styles() as $style_id => $style_info) : $presets = $the_widget->get_style_presets($style_id); ?>
247
- <?php if(!empty($presets)) : foreach($presets as $preset_id => $preset) : ?>
248
- <option value="<?php echo esc_attr($style_id.':'.$preset_id) ?>" <?php selected($style_id.':'.$preset_id, $instance['origin_style_'.$id]) ?>>
249
- <?php echo esc_html($style_info['Name'].' - ' . ucwords( str_replace( '_', ' ', $preset_id ) ) ) ?>
250
- </option>
251
- <?php endforeach; endif; ?>
252
- <?php endforeach ?>
253
- </select>
254
- </p>
255
- <?php
256
- }
257
-
258
- do_action('siteorigin_panels_widget_after_styles', $this, $instance);
259
- }
260
-
261
- /**
262
- * Render the widget.
263
- *
264
- * @param array $args
265
- * @param array $instance
266
- * @return bool|void
267
- */
268
- function widget($args, $instance){
269
-
270
- // Set up defaults for all the widget args
271
- foreach($this->form_args as $field_id => $field_args) {
272
- if(isset($field_args['default']) && !isset($instance[$field_id])) {
273
- $instance[$field_id] = $field_args['default'];
274
- }
275
- if(!isset($instance[$field_id])) $instance[$field_id] = false;
276
- }
277
-
278
- // Filter the title
279
- if(!empty($instance['title'])) {
280
- $instance['title'] = apply_filters('widget_title', $instance['title'], $instance, $this->id_base);
281
- }
282
-
283
- if(!empty($instance['origin_style'])) {
284
- list($style, $preset) = explode(':', $instance['origin_style']);
285
- $style = sanitize_file_name($style);
286
- $preset = sanitize_file_name($preset);
287
-
288
- $data = $this->get_style_data($style);
289
- $template = $data['Template'];
290
- }
291
- else {
292
- $style = 'default';
293
- $preset = 'default';
294
- }
295
-
296
- if(empty($template)) $template = 'default';
297
-
298
- $template_file = false;
299
- $paths = $this->get_widget_paths();
300
-
301
- foreach($paths as $path) {
302
- if(file_exists($path.'/'.$this->origin_id.'/tpl/'.$template.'.php')) {
303
- $template_file = $path.'/'.$this->origin_id.'/tpl/'.$template.'.php';
304
- break;
305
- }
306
- }
307
- if(empty($template_file)) {
308
- echo $args['before_widget'];
309
- echo 'Template not found';
310
- echo $args['after_widget'];
311
- return false;
312
- }
313
-
314
- // Dynamically generate the CSS
315
- global $origin_widgets_generated_css;
316
- if( empty($origin_widgets_generated_css) ) {
317
- $origin_widgets_generated_css = array();
318
- }
319
-
320
- if(!empty($instance['origin_style'])) {
321
- $filename = $this->origin_id.'-'.$style.'-'.$preset;
322
- if( !isset($origin_widgets_generated_css[$filename]) ) {
323
- $origin_widgets_generated_css[$filename] = origin_widgets_generate_css(get_class($this), $style, $preset);
324
- }
325
- }
326
-
327
- if(method_exists($this, 'enqueue_scripts')) {
328
- $this->enqueue_scripts();
329
- }
330
-
331
- $widget_classes = apply_filters('siteorigin_widgets_classes', array(
332
- 'origin-widget',
333
- 'origin-widget-'.$this->origin_id,
334
- 'origin-widget-'.$this->origin_id.'-'. $style .'-' . $preset,
335
- ), $instance);
336
-
337
- if(method_exists($this, 'widget_classes')) {
338
- $widget_classes = $this->widget_classes(array(
339
- 'origin-widget',
340
- 'origin-widget-'.$this->origin_id,
341
- 'origin-widget-'.$this->origin_id.'-'. $style .'-' . $preset,
342
- ), $instance);
343
- }
344
-
345
- echo $args['before_widget'];
346
- echo '<div class="'.esc_attr(implode(' ', $widget_classes) ).'">';
347
- include $template_file;
348
- echo '</div>';
349
- echo $args['after_widget'];
350
- }
351
-
352
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
353
- // Extra functions specific to a SiteOrigin widget.
354
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
355
-
356
- /**
357
- * A sub widget is a widget that's style is required by this widget
358
- *
359
- * @param $id
360
- * @param $instance
361
- */
362
- function sub_widget($id, $instance){
363
- $sub = $this->sub_widgets[$id];
364
- global $wp_widget_factory;
365
- $the_widget = $wp_widget_factory->widgets[$sub[1]];
366
- $the_widget->widget(array('before_widget' => '', 'after_widget' => ''), $instance);
367
- }
368
-
369
- /**
370
- * Get the CSS for the given style and preset
371
- *
372
- * @param $style
373
- * @param $preset
374
- * @return string
375
- */
376
- function create_css($style, $preset) {
377
- $paths = $this->get_widget_paths();
378
- $style_file = false;
379
-
380
- // Find the file - exit if it can't be found.
381
- foreach($paths as $path) {
382
- if(file_exists($path.'/'.$this->origin_id.'/styles/'.$style.'.less')) {
383
- $style_file = $path.'/'.$this->origin_id.'/styles/'.$style.'.less';
384
- break;
385
- }
386
- }
387
- if(empty($style_file)) return '';
388
-
389
- if( !class_exists('lessc') ) include plugin_dir_path(__FILE__) . 'lib/lessc.inc.php';
390
-
391
- foreach($this->get_widget_folders() as $folder => $folder_url) {
392
- $filename = rtrim($folder, '/') . '/' . $this->origin_id.'/styles/'.$style.'.less';
393
- if(file_exists($filename)) {
394
- $less = file_get_contents($filename);
395
- break;
396
- }
397
- }
398
- // Add in the mixins
399
- $less = str_replace(
400
- '@import "../../../less/mixins";',
401
- "\n\n".file_get_contents(plugin_dir_path(__FILE__).'less/mixins.less'),
402
- $less
403
- );
404
-
405
- // Apply the preset variables to the LESS file
406
- $presets = $this->get_style_presets($style);
407
- if(!empty($presets[$preset]) && is_array($presets[$preset])){
408
- foreach($presets[$preset] as $k => $v) {
409
- $less = preg_replace('/@'.preg_quote($k).':(.*);/', '@'.$k.': '.$v.';', $less);
410
- }
411
- }
412
-
413
- // Scope the CSS with the wrapper we'll be adding
414
- $less = '.origin-widget.origin-widget-'.$this->origin_id.'-'.$style.'-'.$preset.' {' . $less . '}';
415
- $lc = new lessc();
416
- $lc->setPreserveComments(false);
417
-
418
- $lc->registerFunction('lumlighten', 'origin_widgets_less_lumlighten');
419
- $lc->registerFunction('lumdarken', 'origin_widgets_less_lumdarken');
420
- $lc->registerFunction('texture', 'origin_widgets_less_texture');
421
- $lc->registerFunction('widgetimage', 'origin_widgets_less_widgetimage');
422
-
423
- // Create the CSS
424
- return $lc->compile($less);
425
- }
426
-
427
- /**
428
- * Removes a CSS file
429
- *
430
- * @param $style
431
- * @param $preset
432
- */
433
- function clear_css_cache($style, $preset){
434
- $filename = $this->origin_id.'-'.$style.'-'.$preset;
435
- delete_site_transient('origin_widgets_css_cache:'.$filename);
436
- }
437
-
438
- /**
439
- * Get all the paths where we'll look for widgets.
440
- *
441
- * @return array
442
- */
443
- function get_widget_paths(){
444
- static $paths = array();
445
-
446
- if(empty($paths)) {
447
- $paths = array_keys($this->get_widget_folders());
448
- }
449
-
450
- return $paths;
451
- }
452
-
453
- /**
454
- * Get all the folders where we'll look for widgets
455
- *
456
- * @return mixed|void
457
- */
458
- static function get_widget_folders(){
459
- static $folders = array();
460
-
461
- if(empty($folders)) {
462
- $folders = array(
463
- get_stylesheet_directory().'/widgets' => get_stylesheet_directory_uri().'/widgets/widgets',
464
- get_template_directory().'/widgets' => get_template_directory_uri().'/widgets',
465
- plugin_dir_path( __FILE__ ) . 'widgets' => plugin_dir_url( __FILE__ ).'widgets',
466
- );
467
- $folders = apply_filters('siteorigin_widget_folders', $folders);
468
- }
469
-
470
- return $folders;
471
- }
472
-
473
- /**
474
- * Get all the folders where we'll look for widget images
475
- *
476
- * @return mixed|void
477
- */
478
- static function get_image_folders(){
479
- static $folders = array();
480
- if(empty($folders)) {
481
- $folders = array(
482
- get_stylesheet_directory().'/widgets/img' => get_stylesheet_directory_uri().'/widgets/img',
483
- get_template_directory().'/widgets/img' => get_template_directory_uri().'/widgets/img',
484
- plugin_dir_path( __FILE__ ) . 'img' => plugin_dir_url( __FILE__ ) . 'img',
485
- );
486
- $folders = apply_filters('siteorigin_widget_image_folders', $folders);
487
- }
488
-
489
- return $folders;
490
- }
491
-
492
- /**
493
- * Get all the styles for this widget.
494
- *
495
- * @return array
496
- */
497
- public function get_styles(){
498
- if( empty( $this->styles ) ) {
499
- // We can add extra paths here
500
- foreach($this->get_widget_paths() as $path) {
501
- if(!is_dir($path)) continue;
502
-
503
- $files = glob($path.'/'.$this->origin_id.'/styles/*.less');
504
- if(!empty($files)) {
505
- foreach(glob($path.'/'.$this->origin_id.'/styles/*.less') as $file) {
506
- $p = pathinfo($file);
507
- $this->styles[$p['filename']] = $this->get_style_data($p['filename']);
508
- }
509
- }
510
- }
511
- }
512
-
513
- return $this->styles;
514
- }
515
-
516
- /**
517
- * Get the presets for a given style
518
- *
519
- * @param $style_id
520
- * @return mixed|void
521
- */
522
- public function get_style_presets($style_id) {
523
-
524
- $presets = array();
525
-
526
- foreach($this->get_widget_folders() as $folder => $folder_uri) {
527
- $filename = rtrim($folder, '/') . '/' . $this->origin_id.'/presets/'.sanitize_file_name($style_id).'.php';
528
-
529
- if(file_exists($filename)) {
530
- // This file should register a filter that adds the presets
531
- $new_presets = include($filename);
532
- $presets = array_merge($presets, $new_presets);
533
- }
534
- }
535
-
536
-
537
- return apply_filters('origin_widget_presets_'.$this->origin_id.'_'.$style_id, $presets);
538
- }
539
-
540
- /**
541
- * Get data for the style.
542
- *
543
- * @param $name
544
- * @return array
545
- */
546
- public function get_style_data($name) {
547
- $paths = $this->get_widget_paths();
548
-
549
- foreach($paths as $path) {
550
- $filename = $path.'/'.$this->origin_id.'/styles/'.sanitize_file_name($name).'.less';
551
- if(!file_exists($filename)) continue;
552
-
553
- $data = get_file_data($filename, array(
554
- 'Name' => 'Name',
555
- 'Template' => 'Template',
556
- 'Author' => 'Author',
557
- 'Author URI' => 'Author URI',
558
- ), 'origin_widget');
559
- return $data;
560
- }
561
- return false;
562
- }
563
-
564
- /**
565
- * Render a demo of the widget.
566
- *
567
- * @param array $args
568
- */
569
- function render_demo($args = array()){
570
- $this->widget($args, $this->demo);
571
- }
572
-
573
- /**
574
- * Register a widget that we'll be using inside this widget.
575
- *
576
- * @param $id
577
- * @param $name
578
- * @param $class
579
- */
580
- function add_sub_widget($id, $name, $class){
581
- $this->sub_widgets[$id] = array($name, $class);
582
- }
583
-
584
- /**
585
- * Add the fields required to query the posts.
586
- */
587
- function add_post_query_fields(){
588
- // Add the posts type field
589
- $post_types = get_post_types(array('public' => true));
590
- $post_types = array_values($post_types);
591
- $this->form_args['query_post_type'] = array(
592
- 'type' => 'select',
593
- 'options' => $post_types,
594
- 'label' => __('Post Type', 'siteorigin-panels')
595
- );
596
-
597
- // Add the posts per page field
598
- $this->form_args['query_posts_per_page'] = array(
599
- 'type' => 'number',
600
- 'default' => 10,
601
- 'label' => __('Posts Per Page', 'siteorigin-panels'),
602
- );
603
-
604
- $this->form_args['query_orderby'] = array(
605
- 'type' => 'select',
606
- 'label' => __('Order By', 'siteorigin-panels'),
607
- 'options' => array(
608
- 'none' => __('None', 'siteorigin-panels'),
609
- 'ID' => __('Post ID', 'siteorigin-panels'),
610
- 'author' => __('Author', 'siteorigin-panels'),
611
- 'name' => __('Name', 'siteorigin-panels'),
612
- 'name' => __('Name', 'siteorigin-panels'),
613
- 'date' => __('Date', 'siteorigin-panels'),
614
- 'modified' => __('Modified', 'siteorigin-panels'),
615
- 'parent' => __('Parent', 'siteorigin-panels'),
616
- 'rand' => __('Random', 'siteorigin-panels'),
617
- 'comment_count' => __('Comment Count', 'siteorigin-panels'),
618
- 'menu_order' => __('Menu Order', 'siteorigin-panels'),
619
- )
620
- );
621
-
622
- $this->form_args['query_order'] = array(
623
- 'type' => 'select',
624
- 'label' => __('Order', 'siteorigin-panels'),
625
- 'options' => array(
626
- 'ASC' => __('Ascending', 'siteorigin-panels'),
627
- 'DESC' => __('Descending', 'siteorigin-panels'),
628
- )
629
- );
630
-
631
- $this->form_args['query_sticky'] = array(
632
- 'type' => 'select',
633
- 'label' => __('Sticky Posts', 'siteorigin-panels'),
634
- 'options' => array(
635
- '' => __('Default', 'siteorigin-panels'),
636
- 'ignore' => __('Ignore Sticky', 'siteorigin-panels'),
637
- 'exclude' => __('Exclude Sticky', 'siteorigin-panels'),
638
- 'only' => __('Only Sticky', 'siteorigin-panels'),
639
- )
640
- );
641
-
642
- $this->form_args['query_additional'] = array(
643
- 'type' => 'text',
644
- 'label' => __('Additional Arguments', 'siteorigin-panels'),
645
- 'description' => preg_replace(
646
- '/1\{ *(.*?) *\}/',
647
- '<a href="http://codex.wordpress.org/Function_Reference/query_posts">$1</a>',
648
- __('Additional query arguments. See 1{query_posts}.', 'siteorigin-panels')
649
- )
650
- );
651
- }
652
-
653
- /**
654
- * Get all the posts for the current query
655
- *
656
- * @param $instance
657
- * @return WP_Query
658
- */
659
- static function get_query_posts($instance) {
660
- $query_args = array();
661
- foreach($instance as $k => $v){
662
- if(strpos($k, 'query_') === 0) {
663
- $query_args[preg_replace('/query_/', '', $k, 1)] = $v;
664
- }
665
- }
666
- $query = $query_args;
667
- unset($query['additional']);
668
- unset($query['sticky']);
669
-
670
- // Add the additional arguments
671
- $query = wp_parse_args($query_args['additional'], $query);
672
-
673
- // Add the sticky posts if required
674
- switch($query_args['sticky']){
675
- case 'ignore' :
676
- $query['ignore_sticky_posts'] = 1;
677
- break;
678
- case 'only' :
679
- $query['post__in'] = get_option( 'sticky_posts' );
680
- break;
681
- case 'exclude' :
682
- $query['post__not_in'] = get_option( 'sticky_posts' );
683
- break;
684
- }
685
-
686
- // Add the current page
687
- global $wp_query;
688
- $query['paged'] = $wp_query->get('paged');
689
-
690
- return new WP_Query($query);
691
- }
692
- }
693
-
694
- // All the standard bundled widgets
695
-
696
- /**
697
- * A gallery widget
698
- *
699
- * Class SiteOrigin_Panels_Widgets_Gallery
700
- */
701
- class SiteOrigin_Panels_Widgets_Gallery extends WP_Widget {
702
- function __construct() {
703
- parent::__construct(
704
- 'siteorigin-panels-gallery',
705
- __( 'Gallery (PB)', 'siteorigin-panels' ),
706
- array(
707
- 'description' => __( 'Displays a gallery.', 'siteorigin-panels' ),
708
- )
709
- );
710
- }
711
-
712
- function widget( $args, $instance ) {
713
- echo $args['before_widget'];
714
-
715
- $shortcode_attr = array();
716
- foreach($instance as $k => $v){
717
- if(empty($v)) continue;
718
- $shortcode_attr[] = $k.'="'.esc_attr($v).'"';
719
- }
720
-
721
- echo do_shortcode('[gallery '.implode(' ', $shortcode_attr).']');
722
-
723
- echo $args['after_widget'];
724
- }
725
-
726
- function update( $new, $old ) {
727
- return $new;
728
- }
729
-
730
- function form( $instance ) {
731
- global $_wp_additional_image_sizes;
732
-
733
- $types = apply_filters('siteorigin_panels_gallery_types', array());
734
-
735
- $instance = wp_parse_args($instance, array(
736
- 'ids' => '',
737
- 'size' => apply_filters('siteorigin_panels_gallery_default_size', ''),
738
- 'type' => apply_filters('siteorigin_panels_gallery_default_type', ''),
739
- 'columns' => 3,
740
- 'link' => '',
741
-
742
- ));
743
-
744
- ?>
745
- <p>
746
- <label for="<?php echo $this->get_field_id( 'ids' ) ?>"><?php _e( 'Gallery Images', 'siteorigin-panels' ) ?></label>
747
- <a href="#" onclick="return false;" class="so-gallery-widget-select-attachments hidden"><?php _e('edit gallery', 'siteorigin-panels') ?></a>
748
- <input type="text" class="widefat" value="<?php echo esc_attr($instance['ids']) ?>" name="<?php echo $this->get_field_name('ids') ?>" />
749
- </p>
750
- <p class="description">
751
- <?php _e("Comma separated attachment IDs. Defaults to all current page's attachments.", 'siteorigin-panels') ?>
752
- </p>
753
-
754
- <p>
755
- <label for="<?php echo $this->get_field_id( 'size' ) ?>"><?php _e( 'Image Size', 'siteorigin-panels' ) ?></label>
756
- <select name="<?php echo $this->get_field_name( 'size' ) ?>" id="<?php echo $this->get_field_id( 'size' ) ?>">
757
- <option value="" <?php selected(empty($instance['size'])) ?>><?php esc_html_e('Default', 'siteorigin-panels') ?></option>
758
- <option value="large" <?php selected('large', $instance['size']) ?>><?php esc_html_e( 'Large', 'siteorigin-panels' ) ?></option>
759
- <option value="medium" <?php selected('medium', $instance['size']) ?>><?php esc_html_e( 'Medium', 'siteorigin-panels' ) ?></option>
760
- <option value="thumbnail" <?php selected('thumbnail', $instance['size']) ?>><?php esc_html_e( 'Thumbnail', 'siteorigin-panels' ) ?></option>
761
- <option value="full" <?php selected('full', $instance['size']) ?>><?php esc_html_e( 'Full', 'siteorigin-panels' ) ?></option>
762
- <?php if(!empty($_wp_additional_image_sizes)) : foreach ( $_wp_additional_image_sizes as $name => $info ) : ?>
763
- <option value="<?php echo esc_attr( $name ) ?>" <?php selected($name, $instance['size']) ?>><?php echo esc_html( $name ) ?></option>
764
- <?php endforeach; endif; ?>
765
- </select>
766
- </p>
767
-
768
- <p>
769
- <label for="<?php echo $this->get_field_id( 'type' ) ?>"><?php _e( 'Gallery Type', 'siteorigin-panels' ) ?></label>
770
- <input type="text" class="regular" value="<?php echo esc_attr($instance['type']) ?>" name="<?php echo $this->get_field_name('type') ?>" />
771
- </p>
772
-
773
- <p>
774
- <label for="<?php echo $this->get_field_id( 'columns' ) ?>"><?php _e( 'Columns', 'siteorigin-panels' ) ?></label>
775
- <input type="text" class="regular" value="<?php echo esc_attr($instance['columns']) ?>" name="<?php echo $this->get_field_name('columns') ?>" />
776
- </p>
777
-
778
- <p>
779
- <label for="<?php echo $this->get_field_id( 'link' ) ?>"><?php _e( 'Link To', 'siteorigin-panels' ) ?></label>
780
- <select name="<?php echo $this->get_field_name( 'link' ) ?>" id="<?php echo $this->get_field_id( 'link' ) ?>">
781
- <option value="" <?php selected('', $instance['link']) ?>><?php esc_html_e('Attachment Page', 'siteorigin-panels') ?></option>
782
- <option value="file" <?php selected('file', $instance['link']) ?>><?php esc_html_e('File', 'siteorigin-panels') ?></option>
783
- <option value="none" <?php selected('none', $instance['link']) ?>><?php esc_html_e('None', 'siteorigin-panels') ?></option>
784
- </select>
785
- </p>
786
-
787
- <?php
788
- }
789
- }
790
-
791
- /**
792
- * An image widget
793
- *
794
- * Class SiteOrigin_Panels_Widgets_Image
795
- */
796
- class SiteOrigin_Panels_Widgets_Image extends WP_Widget {
797
- function __construct() {
798
- parent::__construct(
799
- 'siteorigin-panels-image',
800
- __( 'Image (PB)', 'siteorigin-panels' ),
801
- array(
802
- 'description' => __( 'Displays a simple image.', 'siteorigin-panels' ),
803
- )
804
- );
805
- }
806
-
807
- /**
808
- * @param array $args
809
- * @param array $instance
810
- */
811
- function widget( $args, $instance ) {
812
- echo $args['before_widget'];
813
- if(!empty($instance['href'])) echo '<a href="' . $instance['href'] . '">';
814
- echo '<img src="'.esc_url($instance['src']).'" />';
815
- if(!empty($instance['href'])) echo '</a>';
816
- echo $args['after_widget'];
817
- }
818
-
819
- function update($new, $old){
820
- $new = wp_parse_args($new, array(
821
- 'src' => '',
822
- 'href' => '',
823
- ));
824
- return $new;
825
- }
826
-
827
- function form( $instance ) {
828
- $instance = wp_parse_args($instance, array(
829
- 'src' => '',
830
- 'href' => '',
831
- ));
832
-
833
- ?>
834
- <p>
835
- <label for="<?php echo $this->get_field_id( 'src' ) ?>"><?php _e( 'Image URL', 'siteorigin-panels' ) ?></label>
836
- <input type="text" class="widefat" id="<?php echo $this->get_field_id( 'src' ) ?>" name="<?php echo $this->get_field_name( 'src' ) ?>" value="<?php echo esc_attr($instance['src']) ?>" />
837
- </p>
838
- <p>
839
- <label for="<?php echo $this->get_field_id( 'href' ) ?>"><?php _e( 'Destination URL', 'siteorigin-panels' ) ?></label>
840
- <input type="text" class="widefat" id="<?php echo $this->get_field_id( 'href' ) ?>" name="<?php echo $this->get_field_name( 'href' ) ?>" value="<?php echo esc_attr($instance['href']) ?>" />
841
- </p>
842
- <?php
843
- }
844
- }
845
-
846
- /**
847
- * A widget that lets you embed video.
848
- */
849
- class SiteOrigin_Panels_Widgets_EmbeddedVideo extends WP_Widget {
850
- function __construct() {
851
- parent::__construct(
852
- 'siteorigin-panels-embedded-video',
853
- __( 'Embedded Video (PB)', 'siteorigin-panels' ),
854
- array(
855
- 'description' => __( 'Embeds a video.', 'siteorigin-panels' ),
856
- )
857
- );
858
- }
859
-
860
- /**
861
- * Display the video using
862
- *
863
- * @param array $args
864
- * @param array $instance
865
- */
866
- function widget( $args, $instance ) {
867
- $embed = new WP_Embed();
868
-
869
- if(!wp_script_is('fitvids'))
870
- wp_enqueue_script('fitvids', plugin_dir_url( __FILE__ ) . 'js/jquery.fitvids.js', array('jquery'), SITEORIGIN_PANELS_VERSION);
871
-
872
- if(!wp_script_is('siteorigin-panels-embedded-video'))
873
- wp_enqueue_script('siteorigin-panels-embedded-video', plugin_dir_url( __FILE__ ).'js/embedded-video.js', array('jquery', 'fitvids'), SITEORIGIN_PANELS_VERSION);
874
-
875
- echo $args['before_widget'];
876
- ?><div class="siteorigin-fitvids"><?php echo $embed->run_shortcode( '[embed]' . $instance['video'] . '[/embed]' ) ?></div><?php
877
- echo $args['after_widget'];
878
- }
879
-
880
- /**
881
- * Display the embedded video form.
882
- *
883
- * @param array $instance
884
- * @return string|void
885
- */
886
- function form( $instance ) {
887
- $instance = wp_parse_args( $instance, array(
888
- 'video' => '',
889
- ) );
890
-
891
- ?>
892
- <p>
893
- <label for="<?php echo $this->get_field_id( 'video' ) ?>"><?php _e( 'Video', 'siteorigin-panels' ) ?></label>
894
- <input type="text" class="widefat" name="<?php echo $this->get_field_name( 'video' ) ?>" id="<?php echo $this->get_field_id( 'video' ) ?>" value="<?php echo esc_attr( $instance['video'] ) ?>" />
895
- </p>
896
- <?php
897
- }
898
-
899
- function update( $new, $old ) {
900
- $new['video'] = str_replace( 'https://', 'http://', $new['video'] );
901
- return $new;
902
- }
903
- }
904
-
905
- class SiteOrigin_Panels_Widgets_Video extends WP_Widget {
906
- function __construct() {
907
- parent::__construct(
908
- 'siteorigin-panels-video',
909
- __( 'Self Hosted Video (PB)', 'siteorigin-panels' ),
910
- array(
911
- 'description' => __( 'A self hosted video player.', 'siteorigin-panels' ),
912
- )
913
- );
914
- }
915
-
916
- function widget( $args, $instance ) {
917
- if ( empty($instance['url']) ) return;
918
- if ( !function_exists('wp_video_shortcode') ) return;
919
-
920
- $instance = wp_parse_args($instance, array(
921
- 'url' => '',
922
- 'poster' => '',
923
- 'autoplay' => false,
924
- ));
925
-
926
- echo $args['before_widget'];
927
- echo wp_video_shortcode( array(
928
- 'src' => $instance['url'],
929
- 'poster' => $instance['poster'],
930
- 'autoplay' => $instance['autoplay'],
931
- ) );
932
- echo $args['after_widget'];
933
- }
934
-
935
- function update( $new, $old ) {
936
- $new['url'] = esc_url_raw( $new['url'] );
937
- $new['poster'] = esc_url_raw( $new['poster'] );
938
- $new['autoplay'] = !empty($new['autoplay']) ? 1 : 0;
939
- return $new;
940
- }
941
-
942
- function form( $instance ) {
943
- $instance = wp_parse_args($instance, array(
944
- 'url' => '',
945
- 'poster' => '',
946
- 'skin' => 'siteorigin',
947
- 'ratio' => 1.777,
948
- 'autoplay' => false,
949
- ));
950
-
951
- ?>
952
- <p>
953
- <label for="<?php echo $this->get_field_id('url') ?>"><?php _e('Video URL', 'siteorigin-panels') ?></label>
954
- <input id="<?php echo $this->get_field_id('url') ?>" name="<?php echo $this->get_field_name('url') ?>" type="text" class="widefat" value="<?php echo esc_attr($instance['url']) ?>" />
955
- </p>
956
- <p>
957
- <label for="<?php echo $this->get_field_id('poster') ?>"><?php _e('Poster URL', 'siteorigin-panels') ?></label>
958
- <input id="<?php echo $this->get_field_id('poster') ?>" name="<?php echo $this->get_field_name('poster') ?>" type="text" class="widefat" value="<?php echo esc_attr($instance['poster']) ?>" />
959
- <small class="description"><?php _e('An image that displays before the video starts playing.', 'siteorigin-panels') ?></small>
960
- </p>
961
- <p>
962
- <label for="<?php echo $this->get_field_id('autoplay') ?>">
963
- <input id="<?php echo $this->get_field_id('autoplay') ?>" name="<?php echo $this->get_field_name('autoplay') ?>" type="checkbox" value="1" <?php checked($instance['autoplay']) ?> />
964
- <?php _e('Auto Play Video', 'siteorigin-panels') ?>
965
- </label>
966
- </p>
967
- <?php
968
- }
969
- }
970
-
971
- /**
972
- * A shortcode for self hosted video.
973
- *
974
- * @param array $atts
975
- * @return string
976
- */
977
- function siteorigin_panels_video_shortcode($atts){
978
- /**
979
- * @var string $url
980
- * @var string $poster
981
- * @var string $skin
982
- */
983
- $instance = shortcode_atts( array(
984
- 'url' => '',
985
- 'src' => '',
986
- 'poster' => '',
987
- 'skin' => 'siteorigin',
988
- 'ratio' => 1.777,
989
- 'autoplay' => 0,
990
- ), $atts );
991
-
992
- if(!empty($instance['src'])) $instance['url'] = $instance['src'];
993
- if(empty($instance['url'])) return;
994
-
995
- ob_start();
996
- the_widget('SiteOrigin_Panels_Widgets_Video', $instance);
997
- return ob_get_clean();
998
-
999
- }
1000
- add_shortcode('self_video', 'siteorigin_panels_video_shortcode');
1001
-
1002
- /**
1003
- * Register the widgets.
1004
- */
1005
- function siteorigin_panels_widgets_init(){
1006
- register_widget('SiteOrigin_Panels_Widgets_Gallery');
1007
- register_widget('SiteOrigin_Panels_Widgets_Image');
1008
- register_widget('SiteOrigin_Panels_Widgets_EmbeddedVideo');
1009
- register_widget('SiteOrigin_Panels_Widgets_Video');
1010
- }
1011
- add_action('widgets_init', 'siteorigin_panels_widgets_init');
1
+ <?php
2
+ // Include all the basic widgets
3
+ include plugin_dir_path(__FILE__) . '/less/functions.php';
4
+
5
+ /**
6
+ * Include all the widget files and register their widgets
7
+ */
8
+ function origin_widgets_init(){
9
+ foreach(glob(plugin_dir_path(__FILE__).'/widgets/*/*.php') as $file) {
10
+ include_once ($file);
11
+
12
+ $p = pathinfo($file);
13
+ $class = $p['filename'];
14
+ $class = str_replace('-', ' ', $class);
15
+ $class = ucwords($class);
16
+ $class = str_replace(' ', '_', $class);
17
+
18
+ $class = 'SiteOrigin_Panels_Widget_'.$class;
19
+ if( class_exists($class) ) register_widget($class);
20
+ }
21
+ }
22
+ add_action('widgets_init', 'origin_widgets_init');
23
+
24
+ function origin_widgets_enqueue($prefix){
25
+ if($prefix == 'widgets.php') wp_enqueue_script('origin-widgets-admin-script', plugin_dir_url( __FILE__ ).'js/admin.js', array('jquery'), SITEORIGIN_PANELS_VERSION);
26
+ }
27
+ add_action('admin_enqueue_scripts', 'origin_widgets_enqueue');
28
+
29
+ function origin_widgets_generate_css($class, $style, $preset, $version = null){
30
+ $widget = new $class();
31
+ if( !is_subclass_of($widget, 'SiteOrigin_Panels_Widget') ) return '';
32
+ if(empty($version)) $version = SITEORIGIN_PANELS_VERSION;
33
+
34
+ $id = str_replace('_', '', strtolower(str_replace('SiteOrigin_Panels_Widget_', '', $class)));
35
+ $key = strtolower($id.'-'.$style.'-'. $preset.'-'.str_replace('.', '', $version));
36
+
37
+ $css = get_site_transient('origin_wcss:'.$key);
38
+ if($css === false || ( defined('SITEORIGIN_PANELS_NOCACHE') && SITEORIGIN_PANELS_NOCACHE ) ) {
39
+
40
+ // Recreate the CSS
41
+ $css = "/* Regenerate Cache */\n\n" ;
42
+ $css .= $widget->create_css($style, $preset);
43
+ $css = preg_replace('#/\*.*?\*/#s', '', $css);
44
+ $css = preg_replace('/\s*([{}|:;,])\s+/', '$1', $css);
45
+ $css = preg_replace('/\s\s+(.*)/', '$1', $css);
46
+ $css = str_replace(';}', '}', $css);
47
+
48
+ set_site_transient('origin_wcss:'.$key, $css, 86400);
49
+ }
50
+
51
+ return $css;
52
+ }
53
+
54
+ function origin_widgets_footer_css(){
55
+ global $origin_widgets_generated_css;
56
+ if( !empty( $origin_widgets_generated_css ) ) {
57
+ echo '<style type="text/css">';
58
+ foreach( $origin_widgets_generated_css as $id => $css ) {
59
+ if( empty($css) ) continue;
60
+ echo $css;
61
+ $origin_widgets_generated_css[$id] = '';
62
+ }
63
+ echo '</style>';
64
+ }
65
+ }
66
+ add_action('wp_head', 'origin_widgets_footer_css');
67
+ add_action('wp_footer', 'origin_widgets_footer_css');
68
+
69
+ /**
70
+ * Class SiteOrigin_Panels_Widget
71
+ */
72
+ abstract class SiteOrigin_Panels_Widget extends WP_Widget{
73
+ public $form_args;
74
+ protected $demo;
75
+ protected $origin_id;
76
+ public $sub_widgets;
77
+
78
+ private $styles;
79
+
80
+ /**
81
+ * Create the widget
82
+ *
83
+ * @param string $name Name for the widget displayed on the configuration page.
84
+ * @param array $widget_options Optional Passed to wp_register_sidebar_widget()
85
+ * - description: shown on the configuration page
86
+ * - classname
87
+ * @param array $control_options Optional Passed to wp_register_widget_control()
88
+ * - width: required if more than 250px
89
+ * - height: currently not used but may be needed in the future
90
+ * @param array $form Form arguments.
91
+ * @param array $demo Values for the demo of the page builder widget.
92
+ * @internal param string $id_base
93
+ */
94
+ function __construct($name, $widget_options = array(), $control_options = array(), $form = array(), $demo = array()){
95
+ $id_base = str_replace('SiteOrigin_Panels_Widget_', '', get_class($this));
96
+ $id_base = strtolower(str_replace('_', '-', $id_base));
97
+
98
+ parent::__construct('origin_'.$id_base, $name, $widget_options, $control_options);
99
+ $this->origin_id = $id_base;
100
+
101
+ $this->form_args = $form;
102
+ $this->demo = $demo;
103
+ $this->styles = array();
104
+ $this->sub_widgets = array();
105
+ }
106
+
107
+ /**
108
+ * Update the widget and save the new CSS.
109
+ *
110
+ * @param array $old
111
+ * @param array $new
112
+ * @return array
113
+ */
114
+ function update($new, $old) {
115
+
116
+ // We wont clear cache if this is a preview
117
+ if( !is_preview() ){
118
+ // Remove the