feat: VivesPOS landing on Winter CMS 1.2 — theme + plugin + Dockerfile
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
- Base: wintercms/winter branch 1.2 (full framework) - Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS - Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication - Partials: hero (offline-first), features, modes (offline/nube toggle), screenshots, pricing (3 planes), comparison, FAQ, CTA - Plugin VivesPOS.Site with ContactForm - Dockerfile: PHP 8.2 Apache, port 80, healthcheck - Added winter/wn-pages, blog, sitemap, seo plugins - Active theme set to vivespos
This commit is contained in:
10
modules/cms/assets/css/themelogs/template-diff.css
Normal file
10
modules/cms/assets/css/themelogs/template-diff.css
Normal file
@@ -0,0 +1,10 @@
|
||||
del {
|
||||
text-decoration: none;
|
||||
color: #b30000;
|
||||
background: #fadad7;
|
||||
}
|
||||
ins {
|
||||
background: #eaf2c2;
|
||||
color: #406619;
|
||||
text-decoration: none;
|
||||
}
|
||||
104
modules/cms/assets/css/winter.components.css
Normal file
104
modules/cms/assets/css/winter.components.css
Normal file
@@ -0,0 +1,104 @@
|
||||
.draggable-component-item,
|
||||
.component-list .components div.layout-cell,
|
||||
div.control-componentlist div.components div.layout-cell{font-size:11px;cursor:pointer;background:#fff;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||
.draggable-component-item:hover,
|
||||
.component-list .components div.layout-cell:hover,
|
||||
div.control-componentlist div.components div.layout-cell:hover{background:#6cc551}
|
||||
.draggable-component-item>div,
|
||||
.component-list .components div.layout-cell>div,
|
||||
div.control-componentlist div.components div.layout-cell>div{white-space:normal;color:#475354;position:relative;border-right:1px solid #ECF0F1}
|
||||
.draggable-component-item>div:before,
|
||||
.component-list .components div.layout-cell>div:before,
|
||||
div.control-componentlist div.components div.layout-cell>div:before{position:absolute;font-size:16px;left:15px;top:7px;opacity:0.7;filter:alpha(opacity=70)}
|
||||
.draggable-component-item>div:hover,
|
||||
.component-list .components div.layout-cell>div:hover,
|
||||
div.control-componentlist div.components div.layout-cell>div:hover{color:#fff}
|
||||
.draggable-component-item>div:hover:before,
|
||||
.component-list .components div.layout-cell>div:hover:before,
|
||||
div.control-componentlist div.components div.layout-cell>div:hover:before{opacity:1;filter:alpha(opacity=100)}
|
||||
.draggable-component-item>div:after,
|
||||
.component-list .components div.layout-cell>div:after,
|
||||
div.control-componentlist div.components div.layout-cell>div:after{position:absolute;font-size:37px;top:1px;z-index:50;color:#fff;text-shadow:0 0 1px #475354;width:12px;overflow:hidden;text-indent:-25px;right:-12px;font-family:"Font Awesome 6 Free";font-weight:900;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-style:normal;font-variant:normal;text-rendering:auto;content:"\f12e"}
|
||||
.draggable-component-item>div:hover:after,
|
||||
.component-list .components div.layout-cell>div:hover:after,
|
||||
div.control-componentlist div.components div.layout-cell>div:hover:after{text-shadow:none;color:#6cc551}
|
||||
.draggable-component-item>div span,
|
||||
.component-list .components div.layout-cell>div span,
|
||||
div.control-componentlist div.components div.layout-cell>div span{display:block}
|
||||
.draggable-component-item>div span.name,
|
||||
.component-list .components div.layout-cell>div span.name,
|
||||
div.control-componentlist div.components div.layout-cell>div span.name{white-space:nowrap;padding:8px 15px 0;font-weight:400;line-height:20px;font-size:13px}
|
||||
.draggable-component-item>div span.description,
|
||||
.component-list .components div.layout-cell>div span.description,
|
||||
div.control-componentlist div.components div.layout-cell>div span.description{padding:0 15px 10px;margin-top:8px;font-weight:400;font-size:11px;line-height:150%}
|
||||
.draggable-component-item.placeholder>div,
|
||||
.component-list .components div.layout-cell.placeholder>div,
|
||||
div.control-componentlist div.components div.layout-cell.placeholder>div{background:#e0e0e0;color:#e0e0e0}
|
||||
.draggable-component-item.placeholder>div:before,
|
||||
.component-list .components div.layout-cell.placeholder>div:before,
|
||||
div.control-componentlist div.components div.layout-cell.placeholder>div:before,
|
||||
.draggable-component-item.placeholder>div:after,
|
||||
.component-list .components div.layout-cell.placeholder>div:after,
|
||||
div.control-componentlist div.components div.layout-cell.placeholder>div:after{color:#e0e0e0 !important;text-shadow:none !important}
|
||||
[data-field-name="components"] + .control-tabs.primary-tabs{margin-top:-10px}
|
||||
div.control-componentlist{position:relative;padding:0;-webkit-transition:all 0.3s ease;transition:all 0.3s ease}
|
||||
div.control-componentlist.droppable{background-color:#79cbe1}
|
||||
div.control-componentlist.has-components{padding:0 20px 20px}
|
||||
div.control-componentlist div.layout{width:auto}
|
||||
div.control-componentlist div.components div.layout-cell.error-component{background:#e01346}
|
||||
div.control-componentlist div.components div.layout-cell.error-component>div{color:#fff}
|
||||
div.control-componentlist div.components div.layout-cell.error-component>div:after{color:#e01346}
|
||||
div.control-componentlist div.components div.layout-cell.warning-component{background:#ffc107}
|
||||
div.control-componentlist div.components div.layout-cell.warning-component>div{color:#343a40}
|
||||
div.control-componentlist div.components div.layout-cell.warning-component>div:after{color:#ffc107}
|
||||
div.control-componentlist div.components div.layout-cell:first-child{border-bottom-left-radius:3px;border-top-left-radius:3px}
|
||||
div.control-componentlist div.components div.layout-cell:last-child{margin-right:0;border-bottom-right-radius:3px;border-top-right-radius:3px}
|
||||
div.control-componentlist div.components div.layout-cell:last-child>div{border-right:none}
|
||||
div.control-componentlist div.components div.layout-cell:last-child>div:after{display:none}
|
||||
div.control-componentlist div.components div.layout-cell:nth-child(2n)>div:after{top:auto;bottom:5px}
|
||||
div.control-componentlist div.components div.layout-cell:first-child>div.popover-highlight{border-bottom-left-radius:3px;border-top-left-radius:3px}
|
||||
div.control-componentlist div.components div.layout-cell:last-child>div.popover-highlight{border-bottom-right-radius:3px;border-top-right-radius:3px}
|
||||
div.control-componentlist div.components div.layout-cell>div{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0);-webkit-transition:-webkit-transform 0.2s;-moz-transition:-moz-transform 0.2s;-o-transition:-o-transform 0.2s;transition:transform 0.2s;max-width:250px;min-width:170px}
|
||||
div.control-componentlist div.components div.layout-cell>div.popover-highlight{border-right-color:rgba(0,0,0,0);background:#fff !important;color:#475354 !important}
|
||||
div.control-componentlist div.components div.layout-cell>div.popover-highlight:before{opacity:0.7;filter:alpha(opacity=70)}
|
||||
div.control-componentlist div.components div.layout-cell>div.popover-highlight:after{color:#fff;text-shadow:none}
|
||||
div.control-componentlist div.components div.layout-cell>div.popover-highlight a.remove{display:none}
|
||||
div.control-componentlist div.components div.layout-cell>div span.name{padding-left:38px}
|
||||
div.control-componentlist div.components div.layout-cell>div span.description{padding-bottom:35px}
|
||||
div.control-componentlist div.components div.layout-cell>div span.alias{padding:0 15px;font-weight:500;position:absolute;width:100%;bottom:10px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
|
||||
div.control-componentlist div.components div.layout-cell>div span.alias:before{margin-right:4px;opacity:0.55;filter:alpha(opacity=55)}
|
||||
div.control-componentlist div.components div.layout-cell>div a.remove{position:absolute;display:inline-block;top:1px;right:5px;color:#000;font-size:17px;font-weight:bold;opacity:0.3;filter:alpha(opacity=30)}
|
||||
div.control-componentlist div.components div.layout-cell>div a.remove:hover{opacity:0.5;filter:alpha(opacity=50);text-decoration:none}
|
||||
div.control-componentlist div.components div.layout-cell.adding>div{-webkit-transform:translate(0,-100px) !important;-ms-transform:translate(0,-100px) !important;transform:translate(0,-100px) !important}
|
||||
.draggable-component-item{opacity:0.6;filter:alpha(opacity=60)}
|
||||
.draggable-component-item span.alias{display:none}
|
||||
.draggable-component-item a.remove{display:none}
|
||||
.component-list .components div.layout div.layout-row div.layout-cell{border-top:1px solid #ECF0F1}
|
||||
.component-list .components div.layout div.layout-row div.layout-cell span.alias{display:none}
|
||||
.component-list .components div.layout div.layout-row div.layout-cell a.remove{display:none}
|
||||
.component-list .components div.layout div.layout-row div.layout-cell:last-child>div{border-right:none}
|
||||
.component-list .components div.layout div.layout-row div.layout-cell:last-child>div:after{display:none}
|
||||
.component-list .components div.layout div.layout-row div.layout-cell>div:before{position:absolute;font-size:37px;top:1px;z-index:50;color:#fff;text-shadow:0 0 1px #475354;width:12px;overflow:hidden;text-indent:-25px;right:-12px;font-family:"Font Awesome 6 Free";font-weight:900;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-style:normal;font-variant:normal;text-rendering:auto;content:"\f12e";-webkit-transform:rotate(-90deg);-ms-transform:rotate(-90deg);transform:rotate(-90deg);opacity:1;filter:alpha(opacity=100);left:auto;top:-17px;right:15px}
|
||||
.component-list .components div.layout div.layout-row div.layout-cell>div:hover:before{text-shadow:none;color:#6cc551}
|
||||
.component-list .components div.layout div.layout-row:first-child div.layout-cell>div:before{display:none}
|
||||
.component-list .components div.layout.single div.layout-row>div.layout-cell>div{border-right:none}
|
||||
.component-list .components div.layout.single div.layout-row>div.layout-cell>div:before{display:block;right:55.5%}
|
||||
.control-filelist.component-list ul li div.group{background:#f1f3f4;border-top:1px solid #e6ebed;padding:10px 15px 10px 10px;position:relative;cursor:pointer}
|
||||
.control-filelist.component-list ul li div.group h4{text-transform:uppercase;font-size:14px;margin-top:3px}
|
||||
.control-filelist.component-list ul li div.group h4 a{padding-left:33px}
|
||||
.control-filelist.component-list ul li div.group h4 a:before{left:0}
|
||||
.control-filelist.component-list ul li div.group h4 a:after{display:none}
|
||||
.control-filelist.component-list ul li div.group span.description{display:block;font-size:13px;padding-left:33px;color:#8f8f8f}
|
||||
.control-filelist.component-list ul li div.group i{position:absolute;left:22px;top:21px;font-size:16px;opacity:0.7;filter:alpha(opacity=70);color:#405261}
|
||||
.touch div.control-componentlist div.components div.layout-cell>div:hover,
|
||||
.touch div.control-componentlist div.components div.layout-cell>div:active,
|
||||
.touch div.control-componentlist div.components div.layout-cell>div:active:focus{background:#fff;color:#475354}
|
||||
.touch div.control-componentlist div.components div.layout-cell>div:hover:after,
|
||||
.touch div.control-componentlist div.components div.layout-cell>div:active:after,
|
||||
.touch div.control-componentlist div.components div.layout-cell>div:active:focus:after{text-shadow:0 0 1px #475354 !important;color:#fff !important}
|
||||
body.drag div.control-componentlist div.components div.layout-cell>div,
|
||||
body.drag div.control-componentlist div.components div.layout-cell>div:hover,
|
||||
body.drag div.control-componentlist div.components div.layout-cell>div:active{background:#fff;color:#475354}
|
||||
body.drag div.control-componentlist div.components div.layout-cell>div:after,
|
||||
body.drag div.control-componentlist div.components div.layout-cell>div:hover:after,
|
||||
body.drag div.control-componentlist div.components div.layout-cell>div:active:after{text-shadow:0 0 1px #475354 !important;color:#fff !important}
|
||||
33
modules/cms/assets/css/winter.theme-selector.css
Normal file
33
modules/cms/assets/css/winter.theme-selector.css
Normal file
@@ -0,0 +1,33 @@
|
||||
.theme-selector-layout .layout-cell{padding:24px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
|
||||
.theme-selector-layout .theme-thumbnail{width:288px;background:#ecf0f1;border-top:1px solid #e3e7e9}
|
||||
.theme-selector-layout .theme-thumbnail img{opacity:0.6;filter:alpha(opacity=60);width:240px}
|
||||
.theme-selector-layout .theme-description{border-top:1px solid #f2f3f4}
|
||||
.theme-selector-layout .theme-description h3,
|
||||
.theme-selector-layout .theme-description p{opacity:0.6;filter:alpha(opacity=60)}
|
||||
.theme-selector-layout .theme-description h3{margin:0 0 25px 0;font-size:28px;color:#2b3e50;display:inline-block}
|
||||
.theme-selector-layout .theme-description p.author{font-size:13px;display:inline-block;color:#808c8d}
|
||||
.theme-selector-layout .theme-description p.description{color:#2b3e50;font-size:14px;line-height:180%;margin-bottom:30px}
|
||||
.theme-selector-layout .theme-description .controls .btn>i{margin-right:5px;font-size:16px;position:relative;top:1px}
|
||||
.theme-selector-layout .theme-description .controls .btn>i.icon-star{color:#f1a84e}
|
||||
.theme-selector-layout .theme-description .controls .dropdown{display:inline-block}
|
||||
.theme-selector-layout .layout-row.active .theme-thumbnail{background:#bdc3c7;border-top-color:#bdc3c7}
|
||||
.theme-selector-layout .layout-row.active .thumbnail-container{position:relative}
|
||||
.theme-selector-layout .layout-row.active .thumbnail-container:after{content:'';display:block;width:0;height:0;border-top:14px solid transparent;border-bottom:14px solid transparent;border-left:15px solid #bdc3c7;position:absolute;right:-35px;top:50%;margin-top:-14px}
|
||||
.theme-selector-layout .layout-row.active .theme-description h3,
|
||||
.theme-selector-layout .layout-row:hover .theme-description h3,
|
||||
.theme-selector-layout .layout-row.active .theme-description p,
|
||||
.theme-selector-layout .layout-row:hover .theme-description p{opacity:1;filter:alpha(opacity=100)}
|
||||
.theme-selector-layout .layout-row.active .theme-thumbnail img,
|
||||
.theme-selector-layout .layout-row:hover .theme-thumbnail img{opacity:1;filter:alpha(opacity=100)}
|
||||
.theme-selector-layout .layout-row:first-child .theme-description,
|
||||
.theme-selector-layout .layout-row.links .theme-description,
|
||||
.theme-selector-layout .layout-row:first-child .theme-thumbnail,
|
||||
.theme-selector-layout .layout-row.links .theme-thumbnail{border-top:none}
|
||||
.theme-selector-layout .layout-row.links .theme-thumbnail{border-bottom:1px solid #e3e7e9}
|
||||
.theme-selector-layout .layout-row.links .theme-description{border-bottom:1px solid #f2f3f4}
|
||||
.theme-selector-layout .create-new-theme{margin-bottom:10px}
|
||||
.theme-selector-layout .create-new-theme,
|
||||
.theme-selector-layout .find-more-themes{background:#ecf0f1;color:#2b3e50;text-decoration:none;display:block;padding:20px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
|
||||
.theme-selector-layout .create-new-theme:hover,
|
||||
.theme-selector-layout .find-more-themes:hover{background:#2da7c7;color:white}
|
||||
@media (max-width:768px){.theme-selector-layout .layout-cell,.theme-selector-layout .layout-row{display:block!important;width:auto!important;height:auto!important}.theme-selector-layout .theme-thumbnail img{width:100%}.theme-selector-layout .layout-row.links .theme-thumbnail{background:transparent;padding:0}}
|
||||
27
modules/cms/assets/images/cms-icon.svg
Normal file
27
modules/cms/assets/images/cms-icon.svg
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="65px" height="64px" viewBox="0 0 65 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<!-- Generator: Sketch 3.4.4 (17249) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>cms-icon</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="Group" sketch:type="MSLayerGroup">
|
||||
<path d="M0.754,3.84 C0.754,1.719 2.473,0 4.594,0 L32.754,0 L48.754,13.44 L48.754,60.16 C48.754,62.281 47.035,64 44.914,64 L4.594,64 C2.473,64 0.754,62.281 0.754,60.16 L0.754,3.84 Z" id="Fill-637" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M32.754,0 L32.754,9.6 C32.754,11.721 34.473,13.44 36.594,13.44 L48.754,13.44 L32.754,0 Z" id="Fill-638" fill="#F0F1F1" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M29.754,47 L39.754,47 C40.305,47 40.754,46.552 40.754,46 L40.754,41 C40.754,40.448 40.305,40 39.754,40 L29.754,40 C29.203,40 28.754,40.448 28.754,41 L28.754,46 C28.754,46.552 29.203,47 29.754,47" id="Fill-639" fill="#E2E4E5" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M29.754,40 C29.203,40 28.754,40.448 28.754,41 L28.754,46 C28.754,46.552 29.203,47 29.754,47 L39.754,47 C40.305,47 40.754,46.552 40.754,46 L40.754,41 C40.754,40.448 40.305,40 39.754,40 L29.754,40 Z M39.754,49 L29.754,49 C28.1,49 26.754,47.654 26.754,46 L26.754,41 C26.754,39.346 28.1,38 29.754,38 L39.754,38 C41.408,38 42.754,39.346 42.754,41 L42.754,46 C42.754,47.654 41.408,49 39.754,49 L39.754,49 Z" id="Fill-640" fill="#B6BCBD" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M7.754,47 L17.754,47 C18.305,47 18.754,46.552 18.754,46 L18.754,41 C18.754,40.448 18.305,40 17.754,40 L7.754,40 C7.203,40 6.754,40.448 6.754,41 L6.754,46 C6.754,46.552 7.203,47 7.754,47" id="Fill-641" fill="#E2E4E5" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M7.754,40 C7.203,40 6.754,40.448 6.754,41 L6.754,46 C6.754,46.552 7.203,47 7.754,47 L17.754,47 C18.305,47 18.754,46.552 18.754,46 L18.754,41 C18.754,40.448 18.305,40 17.754,40 L7.754,40 Z M17.754,49 L7.754,49 C6.1,49 4.754,47.654 4.754,46 L4.754,41 C4.754,39.346 6.1,38 7.754,38 L17.754,38 C19.408,38 20.754,39.346 20.754,41 L20.754,46 C20.754,47.654 19.408,49 17.754,49 L17.754,49 Z" id="Fill-642" fill="#B6BCBD" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M18.754,27 L28.754,27 C29.305,27 29.754,26.552 29.754,26 L29.754,21 C29.754,20.448 29.305,20 28.754,20 L18.754,20 C18.203,20 17.754,20.448 17.754,21 L17.754,26 C17.754,26.552 18.203,27 18.754,27" id="Fill-643" fill="#9CE5F4" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M28.026,29 L25.768,29 L30.482,38 L32.74,38 L28.026,29 Z" id="Fill-644" fill="#CFD3D4" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M19.482,29 L14.768,38 L17.026,38 L21.74,29 L19.482,29 Z" id="Fill-645" fill="#CFD3D4" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M18.754,20 C18.203,20 17.754,20.448 17.754,21 L17.754,26 C17.754,26.552 18.203,27 18.754,27 L28.754,27 C29.305,27 29.754,26.552 29.754,26 L29.754,21 C29.754,20.448 29.305,20 28.754,20 L18.754,20 Z M28.754,29 L18.754,29 C17.1,29 15.754,27.654 15.754,26 L15.754,21 C15.754,19.346 17.1,18 18.754,18 L28.754,18 C30.408,18 31.754,19.346 31.754,21 L31.754,26 C31.754,27.654 30.408,29 28.754,29 L28.754,29 Z" id="Fill-646" fill="#40C9E7" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M61.8979,34.4983 L40.6949,58.4653 L34.8179,59.6753 C34.6479,58.8573 34.2249,58.0823 33.5509,57.4863 C32.8769,56.8893 32.0559,56.5643 31.2229,56.4953 L31.7069,50.5143 L52.9099,26.5473 L61.8979,34.4983 Z" id="Fill-647" fill="#F4D0A1" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M61.8692,34.4729 C61.8852,34.4869 61.8862,34.5109 61.8722,34.5269 L41.1512,57.9499 C41.1182,57.9879 41.0652,57.9479 41.0892,57.9029 C41.7392,56.7029 41.5032,55.1759 40.4362,54.2309 C39.3092,53.2349 37.6512,53.2359 36.5312,54.1689 C36.4992,54.1959 36.4562,54.1589 36.4792,54.1229 C37.2692,52.8979 37.0682,51.2519 35.9422,50.2549 C34.8622,49.3009 33.2942,49.2619 32.1802,50.0819 C32.1442,50.1089 32.1032,50.0669 32.1332,50.0339 L52.8852,26.5759 C52.8992,26.5599 52.9232,26.5589 52.9392,26.5729 L61.8692,34.4729 Z" id="Fill-648" fill="#059BBF" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M61.8979,34.4983 L52.9099,26.5473 L54.2349,25.0493 L63.2229,33.0003 L61.8979,34.4983 Z" id="Fill-649" fill="#FACB1B" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M62.7497,24.5706 L62.6597,24.4916 C60.2027,22.3176 56.4487,22.5476 54.2747,25.0046 L54.2357,25.0496 L63.2227,33.0006 L63.2627,32.9556 C65.4367,30.4986 65.2067,26.7446 62.7497,24.5706" id="Fill-650" fill="#F89392" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M61.8728,34.5266 L41.1258,57.9796 C41.0948,58.0136 41.0478,57.9776 41.0698,57.9376 C41.7438,56.7326 41.5138,55.1846 40.4358,54.2306 C39.3118,53.2366 37.6588,53.2356 36.5388,54.1626 C36.5198,54.1786 36.4978,54.1546 36.5138,54.1366 L57.3788,30.5516 C57.3928,30.5356 57.4168,30.5336 57.4328,30.5476 L61.8698,34.4736 C61.8848,34.4866 61.8868,34.5106 61.8728,34.5266" id="Fill-651" fill="#0484AB" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M34.8181,59.6754 L30.9001,60.4824 L31.2231,56.4954 C32.0561,56.5644 32.8771,56.8894 33.5511,57.4864 C34.2251,58.0824 34.6481,58.8574 34.8181,59.6754" id="Fill-652" fill="#3E3E3F" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
BIN
modules/cms/assets/images/default-theme-preview.png
Normal file
BIN
modules/cms/assets/images/default-theme-preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
113
modules/cms/assets/js/themelogs/template-diff.js
Normal file
113
modules/cms/assets/js/themelogs/template-diff.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Template Diff plugin
|
||||
*
|
||||
* Data attributes:
|
||||
* - data-plugin="template-diff" - enables the plugin on an element
|
||||
*
|
||||
* JavaScript API:
|
||||
* $('pre').templateDiff({ option: 'value' })
|
||||
*
|
||||
* Dependences:
|
||||
* - jsdiff (diff.js)
|
||||
*/
|
||||
|
||||
+function ($) { "use strict";
|
||||
|
||||
// TEMPALTE DIFF CLASS DEFINITION
|
||||
// ============================
|
||||
|
||||
var TemplateDiff = function(element, options) {
|
||||
this.options = options
|
||||
this.$el = $(element)
|
||||
|
||||
// Init
|
||||
this.init()
|
||||
}
|
||||
|
||||
TemplateDiff.DEFAULTS = {
|
||||
oldFieldName: null,
|
||||
newFieldName: null,
|
||||
contentTag: '',
|
||||
diffType: 'lines' // chars, words, lines
|
||||
}
|
||||
|
||||
TemplateDiff.prototype.init = function() {
|
||||
var
|
||||
oldValue = $('[data-field-name="'+this.options.oldFieldName+'"] .form-control '+this.options.contentTag).html(),
|
||||
newValue = $('[data-field-name="'+this.options.newFieldName+'"] .form-control '+this.options.contentTag).html()
|
||||
|
||||
oldValue = $('<div />').html(oldValue).text()
|
||||
newValue = $('<div />').html(newValue).text()
|
||||
|
||||
this.diffStrings(oldValue, newValue)
|
||||
}
|
||||
|
||||
TemplateDiff.prototype.diffStrings = function(oldValue, newValue) {
|
||||
var result = this.$el.get(0)
|
||||
var diffType = 'diff' + this.options.diffType[0].toUpperCase() + this.options.diffType.slice(1)
|
||||
var diff = JsDiff[diffType](oldValue, newValue)
|
||||
var fragment = document.createDocumentFragment();
|
||||
for (var i=0; i < diff.length; i++) {
|
||||
|
||||
if (diff[i].added && diff[i + 1] && diff[i + 1].removed) {
|
||||
var swap = diff[i];
|
||||
diff[i] = diff[i + 1];
|
||||
diff[i + 1] = swap;
|
||||
}
|
||||
|
||||
var node;
|
||||
if (diff[i].removed) {
|
||||
node = document.createElement('del');
|
||||
node.appendChild(document.createTextNode(diff[i].value));
|
||||
}
|
||||
else if (diff[i].added) {
|
||||
node = document.createElement('ins');
|
||||
node.appendChild(document.createTextNode(diff[i].value));
|
||||
}
|
||||
else {
|
||||
node = document.createTextNode(diff[i].value);
|
||||
}
|
||||
fragment.appendChild(node);
|
||||
}
|
||||
|
||||
result.textContent = '';
|
||||
result.appendChild(fragment);
|
||||
}
|
||||
|
||||
// TEMPALTE DIFF PLUGIN DEFINITION
|
||||
// ============================
|
||||
|
||||
var old = $.fn.templateDiff
|
||||
|
||||
$.fn.templateDiff = function (option) {
|
||||
var args = Array.prototype.slice.call(arguments, 1), result
|
||||
this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('oc.example')
|
||||
var options = $.extend({}, TemplateDiff.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('oc.example', (data = new TemplateDiff(this, options)))
|
||||
if (typeof option == 'string') result = data[option].apply(data, args)
|
||||
if (typeof result != 'undefined') return false
|
||||
})
|
||||
|
||||
return result ? result : this
|
||||
}
|
||||
|
||||
$.fn.templateDiff.Constructor = TemplateDiff
|
||||
|
||||
// TEMPALTE DIFF NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.templateDiff.noConflict = function () {
|
||||
$.fn.templateDiff = old
|
||||
return this
|
||||
}
|
||||
|
||||
// TEMPALTE DIFF DATA-API
|
||||
// ===============
|
||||
|
||||
$(document).render(function () {
|
||||
$('[data-plugin="template-diff"]').templateDiff()
|
||||
});
|
||||
|
||||
}(window.jQuery);
|
||||
701
modules/cms/assets/js/winter.cmspage.js
Normal file
701
modules/cms/assets/js/winter.cmspage.js
Normal file
@@ -0,0 +1,701 @@
|
||||
/*
|
||||
* Scripts for the CMS page.
|
||||
*/
|
||||
+function ($) { "use strict";
|
||||
|
||||
var Base = $.wn.foundation.base,
|
||||
BaseProto = Base.prototype
|
||||
|
||||
var CmsPage = function() {
|
||||
|
||||
Base.call(this)
|
||||
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
|
||||
this.init()
|
||||
this.widgets = Snowboard['backend.ui.widgetHandler']()
|
||||
}
|
||||
|
||||
CmsPage.prototype = Object.create(BaseProto)
|
||||
CmsPage.prototype.constructor = CmsPage
|
||||
|
||||
CmsPage.prototype.init = function() {
|
||||
$(document).ready(this.proxy(this.registerHandlers))
|
||||
}
|
||||
|
||||
CmsPage.prototype.updateTemplateList = function(type) {
|
||||
var $form = $('#cms-side-panel form[data-template-type='+type+']'),
|
||||
templateList = type + 'List'
|
||||
|
||||
$form.request(templateList + '::onUpdate', {
|
||||
complete: function() {
|
||||
$('button[data-control=delete-template]', $form).trigger('oc.triggerOn.update')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.registerHandlers = function() {
|
||||
var $document = $(document),
|
||||
$masterTabs = $('#cms-master-tabs')
|
||||
|
||||
$masterTabs.on('closed.oc.tab', this.proxy(this.onTabClosed))
|
||||
$masterTabs.on('beforeClose.oc.tab', this.proxy(this.onBeforeTabClose))
|
||||
$masterTabs.on('oc.beforeRequest', this.proxy(this.onBeforeRequest))
|
||||
$masterTabs.on('shown.bs.tab', this.proxy(this.onTabShown))
|
||||
$masterTabs.on('initTab.oc.tab', this.proxy(this.onInitTab))
|
||||
$masterTabs.on('afterAllClosed.oc.tab', this.proxy(this.onAfterAllTabsClosed))
|
||||
|
||||
$(window).on('ajaxInvalidField', this.proxy(this.ajaxInvalidField))
|
||||
$document.on('open.oc.list', '#cms-side-panel', this.proxy(this.onOpenDocument))
|
||||
$document.on('ajaxUpdate', '[data-control=filelist], [data-control=assetlist]', this.proxy(this.onAjaxUpdate))
|
||||
$document.on('ajaxError', '#cms-master-tabs form', this.proxy(this.onAjaxError))
|
||||
$document.on('ajaxSuccess', '#cms-master-tabs form', this.proxy(this.onAjaxSuccess))
|
||||
$document.on('click', '#cms-side-panel form button[data-control=create-template], #cms-side-panel form li a[data-control=create-template]', this.proxy(this.onCreateTemplateClick))
|
||||
$document.on('click', '#cms-side-panel form button[data-control=delete-template]', this.proxy(this.onDeleteTemplateClick))
|
||||
$document.on('showing.oc.inspector', '[data-inspectable]', this.proxy(this.onInspectorShowing))
|
||||
$document.on('hidden.oc.inspector', '[data-inspectable]', this.proxy(this.onInspectorHidden))
|
||||
$document.on('hiding.oc.inspector', '[data-inspectable]', this.proxy(this.onInspectorHiding))
|
||||
$document.on('click', '#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist a.remove', this.proxy(this.onComponentRemove))
|
||||
$document.on('click', '#cms-component-list [data-component]', this.proxy(this.onComponentClick))
|
||||
|
||||
// Watch for PHP editors
|
||||
window.Snowboard.on('backend.formwidget.codeeditor.create', this.proxy(this.onCodeEditorCreate));
|
||||
}
|
||||
|
||||
// EVENT HANDLERS
|
||||
// ============================
|
||||
|
||||
CmsPage.prototype.onOpenDocument = function(event) {
|
||||
/*
|
||||
* Open a document when it's clicked in the sidebar
|
||||
*/
|
||||
|
||||
var $item = $(event.relatedTarget),
|
||||
$form = $item.closest('[data-template-type]'),
|
||||
data = {
|
||||
type: $form.data('template-type'),
|
||||
theme: $item.data('item-theme'),
|
||||
path: $item.data('item-path')
|
||||
},
|
||||
tabId = data.type + '-' + data.theme + '-' + data.path
|
||||
|
||||
if (data.type == 'asset' && $item.data('editable') === undefined)
|
||||
return true
|
||||
|
||||
if ($form.length == 0)
|
||||
return false
|
||||
|
||||
/*
|
||||
* Find if the tab is already opened
|
||||
*/
|
||||
if ($('#cms-master-tabs').data('oc.tab').goTo(tabId))
|
||||
return false
|
||||
|
||||
/*
|
||||
* Open a new tab
|
||||
*/
|
||||
$.wn.stripeLoadIndicator.show()
|
||||
|
||||
$form.request('onOpenTemplate', {
|
||||
data: data
|
||||
}).done(function(data) {
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
$('#cms-master-tabs').ocTab('addTab', data.tabTitle, data.tab, tabId, $form.data('type-icon'))
|
||||
}).always(function() {
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
CmsPage.prototype.ajaxInvalidField = function(ev, element, name, messages, isFirst) {
|
||||
/*
|
||||
* Detect invalid fields, uncollapse the panel
|
||||
*/
|
||||
if (!isFirst)
|
||||
return
|
||||
|
||||
ev.preventDefault()
|
||||
|
||||
var $el = $(element),
|
||||
$panel = $el.closest('.form-tabless-fields.collapsed'),
|
||||
$primaryPanel = $el.closest('.control-tabs.primary-tabs.collapsed')
|
||||
|
||||
if ($panel.length > 0)
|
||||
$panel.removeClass('collapsed')
|
||||
|
||||
if ($primaryPanel.length > 0) {
|
||||
$primaryPanel.removeClass('collapsed')
|
||||
|
||||
var pane = $primaryPanel.closest('.tab-pane'),
|
||||
$secondaryPanel = $('.control-tabs.secondary-tabs', pane)
|
||||
|
||||
$secondaryPanel.removeClass('primary-collapsed')
|
||||
}
|
||||
|
||||
$el.focus()
|
||||
}
|
||||
|
||||
CmsPage.prototype.onTabClosed = function(ev) {
|
||||
this.updateModifiedCounter()
|
||||
|
||||
if ($('> div.tab-content > div.tab-pane', '#cms-master-tabs').length == 0)
|
||||
this.setPageTitle('')
|
||||
}
|
||||
|
||||
CmsPage.prototype.onBeforeTabClose = function(ev) {
|
||||
if ($.fn.table !== undefined)
|
||||
$('[data-control=table]', ev.relatedTarget).table('dispose')
|
||||
|
||||
$.wn.foundation.controlUtils.disposeControls(ev.relatedTarget.get(0))
|
||||
}
|
||||
|
||||
CmsPage.prototype.onBeforeRequest = function(ev) {
|
||||
var $form = $(ev.target)
|
||||
|
||||
if ($('.components .layout-cell.error-component', $form).length > 0) {
|
||||
if (!confirm('The form contains unknown components. Their properties will be lost on save. Do you want to save the form?'))
|
||||
ev.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
CmsPage.prototype.onTabShown = function(ev) {
|
||||
/*
|
||||
* Listen for the tabs "shown" event to track the current template in the list
|
||||
*/
|
||||
|
||||
var $target = $(ev.target)
|
||||
|
||||
if ($target.closest('[data-control=tab]').attr('id') != 'cms-master-tabs')
|
||||
return
|
||||
|
||||
var dataId = $target.closest('li').attr('data-tab-id'),
|
||||
title = $target.attr('title'),
|
||||
$sidePanel = $('#cms-side-panel')
|
||||
|
||||
if (title)
|
||||
this.setPageTitle(title)
|
||||
|
||||
$sidePanel.find('[data-control=filelist]').fileList('markActive', dataId)
|
||||
$sidePanel.find('form').trigger('oc.list.setActiveItem', [dataId])
|
||||
}
|
||||
|
||||
CmsPage.prototype.onInitTab = function(ev, data) {
|
||||
/*
|
||||
* Listen for the tabs "initTab" event to inject extra controls to the tab
|
||||
*/
|
||||
|
||||
if ($(ev.target).attr('id') != 'cms-master-tabs')
|
||||
return
|
||||
|
||||
var $collapseIcon = $('<a href="javascript:;" class="tab-collapse-icon tabless"><i class="icon-chevron-up"></i></a>'),
|
||||
$panel = $('.form-tabless-fields', data.pane)
|
||||
|
||||
$panel.append($collapseIcon);
|
||||
|
||||
$collapseIcon.click(function(){
|
||||
$panel.toggleClass('collapsed')
|
||||
|
||||
if (typeof(localStorage) !== 'undefined')
|
||||
localStorage.ocCmsTablessCollapsed = $panel.hasClass('collapsed') ? 1 : 0
|
||||
|
||||
window.setTimeout(function(){
|
||||
$(window).trigger('oc.updateUi')
|
||||
}, 500)
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
var $primaryCollapseIcon = $('<a href="javascript:;" class="tab-collapse-icon primary"><i class="icon-chevron-down"></i></a>'),
|
||||
$primaryPanel = $('.control-tabs.primary-tabs', data.pane),
|
||||
$secondaryPanel = $('.control-tabs.secondary-tabs', data.pane)
|
||||
|
||||
if ($primaryPanel.length > 0) {
|
||||
$secondaryPanel.append($primaryCollapseIcon);
|
||||
|
||||
$primaryCollapseIcon.click(function(){
|
||||
$primaryPanel.toggleClass('collapsed')
|
||||
$secondaryPanel.toggleClass('primary-collapsed')
|
||||
$(window).trigger('oc.updateUi')
|
||||
if (typeof(localStorage) !== 'undefined')
|
||||
localStorage.ocCmsPrimaryCollapsed = $primaryPanel.hasClass('collapsed') ? 1 : 0
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof(localStorage) !== 'undefined') {
|
||||
if (!$('a', data.tab).hasClass('new-template') && localStorage.ocCmsTablessCollapsed == 1)
|
||||
$panel.addClass('collapsed')
|
||||
|
||||
if (localStorage.ocCmsPrimaryCollapsed == 1) {
|
||||
$primaryPanel.addClass('collapsed')
|
||||
$secondaryPanel.addClass('primary-collapsed')
|
||||
}
|
||||
}
|
||||
|
||||
var $componentListFormGroup = $('.control-componentlist', data.pane).closest('.form-group')
|
||||
if ($primaryPanel.length > 0)
|
||||
$primaryPanel.before($componentListFormGroup)
|
||||
else
|
||||
$secondaryPanel.parent().before($componentListFormGroup)
|
||||
|
||||
$componentListFormGroup.removeClass()
|
||||
$componentListFormGroup.addClass('layout-row min-size')
|
||||
this.updateComponentListClass(data.pane)
|
||||
|
||||
var $form = $('form', data.pane),
|
||||
self = this
|
||||
|
||||
$form.on('changed.oc.changeMonitor', function() {
|
||||
$panel.trigger('modified.oc.tab')
|
||||
$panel.find('[data-control=commit-button]').addClass('hide');
|
||||
$panel.find('[data-control=reset-button]').addClass('hide');
|
||||
self.updateModifiedCounter()
|
||||
})
|
||||
|
||||
$form.on('unchanged.oc.changeMonitor', function() {
|
||||
$panel.trigger('unmodified.oc.tab')
|
||||
self.updateModifiedCounter()
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.onCodeEditorCreate = function (widget, editor) {
|
||||
const $form = $(widget.element.closest('form'));
|
||||
|
||||
if (widget.config.get('language') === 'php') {
|
||||
let value = widget.getValue();
|
||||
|
||||
// If no PHP tag at the start, prepend one
|
||||
if (!/^<\?php\s*/.test(value)) {
|
||||
widget.setValue('<?php\n' + value);
|
||||
}
|
||||
|
||||
// Verify the editor has at least 2 lines before hiding line 1
|
||||
const lineCount = widget.getModel().getLineCount();
|
||||
if (lineCount >= 2) {
|
||||
// Only hide line 1 if it contains just the PHP open tag
|
||||
const firstLine = widget.getModel().getLineContent(1);
|
||||
if (/^<\?php\s*$/.test(firstLine)) {
|
||||
widget.fromLine(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add codelens and action to customise component templates
|
||||
const templateCommand = editor.addCommand(
|
||||
0,
|
||||
function (command, range, name) {
|
||||
$form.request('onExpandMarkupToken', {
|
||||
data: {
|
||||
tokenType: 'component',
|
||||
tokenName: name,
|
||||
},
|
||||
success: function (data) {
|
||||
if (data.result) {
|
||||
widget.replace(range, data.result)
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
widget.addCodeLens(
|
||||
'twig',
|
||||
function (model, token) {
|
||||
// Find component tags
|
||||
const lenses = [];
|
||||
const matches = model.findMatches('\\{%\\scomponent\\s[\'"]([^\'"]+)[\'"][^%]*\\s%\\}', true, true, false, null, true);
|
||||
|
||||
matches.forEach((match) => {
|
||||
const name = match.matches[1] ?? 'unknown';
|
||||
lenses.push({
|
||||
range: match.range,
|
||||
id: 'component-' + name + '-lens',
|
||||
command: {
|
||||
title: 'Customize template',
|
||||
id: templateCommand,
|
||||
arguments: [match.range, name]
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
lenses: lenses,
|
||||
dispose: function () {
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
CmsPage.prototype.onAfterAllTabsClosed = function(ev) {
|
||||
var $sidePanel = $('#cms-side-panel')
|
||||
|
||||
$sidePanel.find('[data-control=filelist]').fileList('markActive', null)
|
||||
$sidePanel.find('form').trigger('oc.list.setActiveItem', [null])
|
||||
}
|
||||
|
||||
CmsPage.prototype.onAjaxUpdate = function(ev) {
|
||||
var dataId = $('#cms-master-tabs .nav-tabs li.active').attr('data-tab-id'),
|
||||
$sidePanel = $('#cms-side-panel')
|
||||
|
||||
$sidePanel.find('[data-control=filelist]').fileList('markActive', dataId)
|
||||
$sidePanel.find('form').trigger('oc.list.setActiveItem', [dataId])
|
||||
}
|
||||
|
||||
CmsPage.prototype.onAjaxSuccess = function(ev, context, data) {
|
||||
var element = ev.target
|
||||
|
||||
// Update the visibilities of the commit & reset buttons
|
||||
$('[data-control=commit-button]', element).toggleClass('hide', !data.canCommit)
|
||||
$('[data-control=reset-button]', element).toggleClass('hide', !data.canReset)
|
||||
|
||||
if (data.templatePath !== undefined) {
|
||||
$('input[name=templatePath]', element).val(data.templatePath)
|
||||
$('input[name=templateMtime]', element).val(data.templateMtime)
|
||||
$('[data-control=delete-button]', element).removeClass('hide')
|
||||
$('[data-control=preview-button]', element).removeClass('hide')
|
||||
|
||||
if (data.pageUrl !== undefined)
|
||||
$('[data-control=preview-button]', element).attr('href', data.pageUrl)
|
||||
}
|
||||
|
||||
if (data.tabTitle !== undefined) {
|
||||
$('#cms-master-tabs').ocTab('updateTitle', $(element).closest('.tab-pane'), data.tabTitle)
|
||||
this.setPageTitle(data.tabTitle)
|
||||
}
|
||||
|
||||
var tabId = $('input[name=templateType]', element).val() + '-'
|
||||
+ $('input[name=theme]', element).val() + '-'
|
||||
+ $('input[name=templatePath]', element).val();
|
||||
|
||||
$('#cms-master-tabs').ocTab('updateIdentifier', $(element).closest('.tab-pane'), tabId)
|
||||
|
||||
var templateType = $('input[name=templateType]', element).val()
|
||||
if (templateType.length > 0) {
|
||||
$.wn.cmsPage.updateTemplateList(templateType)
|
||||
|
||||
if (templateType == 'layout')
|
||||
this.updateLayouts(element)
|
||||
}
|
||||
|
||||
if (context.handler == 'onSave' && (!data['X_WINTER_ERROR_FIELDS'] && !data['X_WINTER_ERROR_MESSAGE'])) {
|
||||
$(element).trigger('unchange.oc.changeMonitor')
|
||||
}
|
||||
|
||||
// Reload the form if the server has requested it
|
||||
if (data.forceReload) {
|
||||
this.reloadForm(element)
|
||||
}
|
||||
}
|
||||
|
||||
CmsPage.prototype.onAjaxError = function(ev, context, message, data, jqXHR) {
|
||||
if (context.handler == 'onSave') {
|
||||
if (jqXHR.responseText == 'mtime-mismatch') {
|
||||
ev.preventDefault()
|
||||
this.handleMtimeMismatch(ev.target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CmsPage.prototype.onCreateTemplateClick = function(ev) {
|
||||
var $form = $(ev.target).closest('[data-template-type]'),
|
||||
type = $form.data('template-type'),
|
||||
tabId = type + Math.random(),
|
||||
self = this
|
||||
|
||||
$.wn.stripeLoadIndicator.show()
|
||||
|
||||
$form.request('onCreateTemplate', {
|
||||
data: {type: type}
|
||||
}).done(function(data) {
|
||||
$('#cms-master-tabs').ocTab('addTab', data.tabTitle, data.tab, tabId, $form.data('type-icon') + ' new-template')
|
||||
$('#layout-side-panel').trigger('close.oc.sidePanel')
|
||||
self.setPageTitle(data.tabTitle)
|
||||
}).always(function(){
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.onDeleteTemplateClick = function(ev) {
|
||||
var $el = $(ev.currentTarget),
|
||||
$form = $el.closest('form'),
|
||||
templateType = $form.data('template-type'),
|
||||
self = this
|
||||
|
||||
if (!confirm($el.data('confirmation')))
|
||||
return
|
||||
|
||||
$.wn.stripeLoadIndicator.show()
|
||||
|
||||
$form.request('onDeleteTemplates', {
|
||||
data: {type: templateType}
|
||||
}).done(function(data) {
|
||||
var tabs = $('#cms-master-tabs').data('oc.tab');
|
||||
$.each(data.deleted, function(index, path){
|
||||
var
|
||||
tabId = templateType + '-' + data.theme + '-' + path,
|
||||
tab = tabs.findByIdentifier(tabId)
|
||||
|
||||
$('#cms-master-tabs').ocTab('closeTab', tab, true)
|
||||
})
|
||||
|
||||
if (data.error !== undefined && $.type(data.error) === 'string' && data.error.length)
|
||||
$.wn.flashMsg({text: data.error, 'class': 'error'})
|
||||
}).always(function(){
|
||||
self.updateTemplateList(templateType)
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.onInspectorShowing = function(ev, data) {
|
||||
var $dragScroll = $(ev.currentTarget).closest('[data-control="toolbar"]').data('oc.dragScroll')
|
||||
if ($dragScroll) {
|
||||
$dragScroll.goToElement(ev.currentTarget, data.callback)
|
||||
} else {
|
||||
data.callback();
|
||||
}
|
||||
|
||||
ev.stopPropagation()
|
||||
}
|
||||
|
||||
CmsPage.prototype.onInspectorHidden = function(ev) {
|
||||
var element = ev.target,
|
||||
values = JSON.parse($('[data-inspector-values]', element).val())
|
||||
|
||||
$('[name="component_aliases[]"]', element).val(values['oc.alias'])
|
||||
$('span.alias', element).text(values['oc.alias'])
|
||||
}
|
||||
|
||||
CmsPage.prototype.onInspectorHiding = function(ev, values) {
|
||||
var element = ev.target,
|
||||
values = JSON.parse($('[data-inspector-values]', element).val()),
|
||||
alias = values['oc.alias'],
|
||||
$componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist .layout'),
|
||||
$cell = $(ev.target).parent()
|
||||
|
||||
$('div.layout-cell', $componentList).each(function(){
|
||||
if ($cell.get(0) == this)
|
||||
return true
|
||||
|
||||
var $input = $('input[name="component_aliases[]"]', this)
|
||||
|
||||
if ($input.val() == alias) {
|
||||
ev.preventDefault()
|
||||
alert('The component alias "'+alias+'" is already used.')
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.onComponentRemove = function(ev) {
|
||||
var element = ev.currentTarget
|
||||
|
||||
$(element).trigger('change')
|
||||
var pane = $(element).closest('.tab-pane'),
|
||||
component = $(element).closest('div.layout-cell')
|
||||
|
||||
/*
|
||||
* Remove any {% component %} tags in the editor for this component
|
||||
*/
|
||||
var editor = $('[data-control=codeeditor]', pane)
|
||||
if (editor.length) {
|
||||
var alias = $('input[name="component_aliases[]"]', component).val().replace(/^@/, ''),
|
||||
codeEditor = this.widgets.getWidget(editor.get(0))
|
||||
|
||||
codeEditor.replace(new RegExp('\\{% +component +\'' + alias + '\'.*?%\\}'), '');
|
||||
}
|
||||
|
||||
component.remove()
|
||||
$(window).trigger('oc.updateUi')
|
||||
|
||||
this.updateComponentListClass(pane)
|
||||
return false
|
||||
}
|
||||
|
||||
CmsPage.prototype.onComponentClick = function(ev) {
|
||||
/*
|
||||
* Determine if a page or layout is open in the master tabs
|
||||
*/
|
||||
|
||||
var $componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist .layout')
|
||||
if ($componentList.length == 0) {
|
||||
alert('Components can be added only to pages, partials and layouts.')
|
||||
return;
|
||||
}
|
||||
|
||||
var $component = $(ev.currentTarget).clone(),
|
||||
$iconInput = $component.find('[data-component-icon]'),
|
||||
$componentContainer = $('.layout-relative', $component),
|
||||
$configInput = $component.find('[data-inspector-config]'),
|
||||
$aliasInput = $component.find('[data-component-default-alias]'),
|
||||
$valuesInput = $component.find('[data-inspector-values]'),
|
||||
$nameInput = $component.find('[data-component-name]'),
|
||||
$classInput = $component.find('[data-inspector-class]'),
|
||||
alias = $aliasInput.val(),
|
||||
originalAlias = alias,
|
||||
counter = 2,
|
||||
existingAliases = []
|
||||
|
||||
$('div.layout-cell input[name="component_aliases[]"]', $componentList).each(function(){
|
||||
existingAliases.push($(this).val())
|
||||
})
|
||||
|
||||
while($.inArray(alias, existingAliases) !== -1) {
|
||||
alias = originalAlias + counter
|
||||
counter++
|
||||
}
|
||||
|
||||
// Set the last alias used so dragComponents can use it
|
||||
$('input[name="component_aliases[]"]', $(ev.currentTarget)).val(alias)
|
||||
|
||||
$component.attr('data-component-attached', true)
|
||||
$componentContainer.addClass($iconInput.val())
|
||||
$iconInput.remove()
|
||||
|
||||
$componentContainer.attr({
|
||||
'data-inspectable': '',
|
||||
'data-inspector-title': $component.find('span.name').text(),
|
||||
'data-inspector-description': $component.find('span.description').text(),
|
||||
'data-inspector-config': $configInput.val(),
|
||||
'data-inspector-class': $classInput.val()
|
||||
})
|
||||
|
||||
$configInput.remove()
|
||||
$('input[name="component_names[]"]', $component).val($nameInput.val())
|
||||
$nameInput.remove()
|
||||
$('input[name="component_aliases[]"]', $component).val(alias)
|
||||
$component.find('span.alias').text(alias)
|
||||
$valuesInput.val($valuesInput.val().replace('--alias--', alias))
|
||||
$aliasInput.remove()
|
||||
|
||||
$component.addClass('adding')
|
||||
$componentList.append($component)
|
||||
$componentList.closest('[data-control="toolbar"]').data('oc.dragScroll').goToElement($component)
|
||||
$component.removeClass('adding')
|
||||
$component.trigger('change')
|
||||
|
||||
this.updateComponentListClass($component.closest('.tab-pane'))
|
||||
|
||||
$(window).trigger('oc.updateUi')
|
||||
}
|
||||
|
||||
// INTERNAL METHODS
|
||||
// ============================
|
||||
|
||||
CmsPage.prototype.updateComponentListClass = function(pane) {
|
||||
var $componentList = $('.control-componentlist', pane),
|
||||
$primaryPanel = $('.control-tabs.primary-tabs', pane),
|
||||
$primaryTabContainer = $('.nav-tabs', $primaryPanel),
|
||||
hasComponents = $('.layout', $componentList).children(':not(.hidden)').length > 0
|
||||
|
||||
$primaryTabContainer.toggleClass('component-area', hasComponents)
|
||||
$componentList.toggleClass('has-components', hasComponents)
|
||||
}
|
||||
|
||||
CmsPage.prototype.updateModifiedCounter = function() {
|
||||
var counters = {
|
||||
page: { menu: 'pages', count: 0 },
|
||||
partial: { menu: 'partials', count: 0 },
|
||||
layout: { menu: 'layouts', count: 0 },
|
||||
content: { menu: 'content', count: 0 },
|
||||
asset: { menu: 'assets', count: 0}
|
||||
}
|
||||
|
||||
$('> div.tab-content > div.tab-pane[data-modified]', '#cms-master-tabs').each(function(){
|
||||
var inputType = $('> form > input[name=templateType]', this).val()
|
||||
counters[inputType].count++
|
||||
})
|
||||
|
||||
$.each(counters, function(type, data){
|
||||
$.wn.sideNav.setCounter('cms/' + data.menu, data.count);
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.handleMtimeMismatch = function(form) {
|
||||
var $form = $(form)
|
||||
$form.popup({ handler: 'onOpenConcurrencyResolveForm' })
|
||||
|
||||
var popup = $form.data('oc.popup'),
|
||||
self = this
|
||||
|
||||
$(popup.$content).on('click', 'button[data-action=reload]', function(){
|
||||
popup.hide()
|
||||
self.reloadForm(form)
|
||||
})
|
||||
|
||||
$(popup.$content).on('click', 'button[data-action=save]', function(){
|
||||
popup.hide()
|
||||
|
||||
$('input[name=templateForceSave]', $form).val(1)
|
||||
$('a[data-request=onSave]', $form).trigger('click')
|
||||
$('input[name=templateForceSave]', $form).val(0)
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.reloadForm = function(form) {
|
||||
var
|
||||
$form = $(form),
|
||||
data = {
|
||||
type: $('[name=templateType]', $form).val(),
|
||||
theme: $('[name=theme]', $form).val(),
|
||||
path: $('[name=templatePath]', $form).val(),
|
||||
},
|
||||
tabId = data.type + '-' + data.theme + '-' + data.path,
|
||||
tabs = $('#cms-master-tabs').data('oc.tab'),
|
||||
tab = tabs.findByIdentifier(tabId),
|
||||
self = this
|
||||
|
||||
/*
|
||||
* Update tab
|
||||
*/
|
||||
|
||||
$.wn.stripeLoadIndicator.show()
|
||||
|
||||
$form.request('onOpenTemplate', {
|
||||
data: data
|
||||
}).done(function(data) {
|
||||
$('#cms-master-tabs').ocTab('updateTab', tab, data.tabTitle, data.tab)
|
||||
$('#cms-master-tabs').ocTab('unmodifyTab', tab)
|
||||
self.updateModifiedCounter()
|
||||
}).always(function() {
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
alert(jqXHR.responseText.length ? jqXHR.responseText : jqXHR.statusText)
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.setPageTitle = function(title) {
|
||||
if (title.length)
|
||||
$.wn.layout.setPageTitle(title + ' | ')
|
||||
else
|
||||
$.wn.layout.setPageTitle(title)
|
||||
}
|
||||
|
||||
CmsPage.prototype.updateLayouts = function(form) {
|
||||
$(form).request('onGetTemplateList', {
|
||||
success: function(data) {
|
||||
$('#cms-master-tabs > .tab-content select[name="settings[layout]"]').each(function(){
|
||||
var
|
||||
$select = $(this),
|
||||
value = $select.val()
|
||||
|
||||
$select.find('option').remove()
|
||||
$.each(data.layouts, function(layoutFile, layoutName){
|
||||
$select.append($('<option>').attr('value', layoutFile).text(layoutName))
|
||||
})
|
||||
$select.trigger('pause.oc.changeMonitor')
|
||||
$select.val(value)
|
||||
$select.trigger('change')
|
||||
$select.trigger('resume.oc.changeMonitor')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$.wn.cmsPage = new CmsPage();
|
||||
}(window.jQuery);
|
||||
260
modules/cms/assets/js/winter.dragcomponents.js
Normal file
260
modules/cms/assets/js/winter.dragcomponents.js
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* DragComponents plugin
|
||||
*
|
||||
* Data attributes:
|
||||
* - data-control="dragcomponents" - enables the plugin on an element
|
||||
* - data-option="value" - an option with a value
|
||||
*
|
||||
* JavaScript API:
|
||||
* $('a#someElement').dragComponents({ option: 'value' })
|
||||
*
|
||||
* Dependences:
|
||||
* - Some other plugin (filename.js)
|
||||
*/
|
||||
|
||||
+function ($) { "use strict";
|
||||
|
||||
// DRAGCOMPONENTS CLASS DEFINITION
|
||||
// ============================
|
||||
|
||||
var DragComponents = function(element, options) {
|
||||
var self = this
|
||||
this.options = options
|
||||
this.$el = $(element)
|
||||
|
||||
var $el = this.$el,
|
||||
widgets = Snowboard['backend.ui.widgetHandler'](),
|
||||
$clone,
|
||||
$editorArea,
|
||||
$editor,
|
||||
$componentList,
|
||||
adjX = 0,
|
||||
adjY = 0,
|
||||
dragging = false,
|
||||
startPos,
|
||||
editorPos
|
||||
|
||||
$el.mousedown(function(event){
|
||||
if ($el.data('component-attached')) return
|
||||
|
||||
startDrag(event)
|
||||
return false
|
||||
})
|
||||
|
||||
$el.on('touchstart', function(event){
|
||||
if ($el.data('component-attached')) return
|
||||
|
||||
var touchEvent = event.originalEvent;
|
||||
if (touchEvent.touches.length == 1) {
|
||||
startDrag(touchEvent.touches[0])
|
||||
event.stopPropagation()
|
||||
}
|
||||
})
|
||||
|
||||
function initDrag(event) {
|
||||
$componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist')
|
||||
$el.addClass(self.options.placeholderClass)
|
||||
$clone.show()
|
||||
$editorArea = $('#cms-master-tabs > div.tab-content > .tab-pane.active [data-control="codeeditor"]')
|
||||
if (!$editorArea.length) {
|
||||
return
|
||||
}
|
||||
|
||||
$editor = widgets.getWidget($editorArea.get(0));
|
||||
if (!$editor || !$editor.getEditor()) return;
|
||||
$editor.getEditor().focus();
|
||||
editorPos = $editor.getEditor().onMouseMove((event) => {
|
||||
if (event.target && event.target.position) {
|
||||
$editor.getEditor().setPosition(event.target.position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal event, drag has started
|
||||
*/
|
||||
function startDrag(event) {
|
||||
|
||||
startPos = $el.offset()
|
||||
$clone = $el.clone().appendTo($(document.body))
|
||||
|
||||
$clone
|
||||
.css({
|
||||
zIndex: '99999',
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none'
|
||||
})
|
||||
.addClass('draggable-component-item')
|
||||
.width($el.width())
|
||||
.height($el.height())
|
||||
.hide()
|
||||
|
||||
var objX = (event.pageX - startPos.left),
|
||||
objY = (event.pageY - startPos.top)
|
||||
|
||||
$clone.data('dragComponents', { x: objX, y: objY })
|
||||
|
||||
if (Modernizr.touchevents) {
|
||||
$(window).on('touchmove.oc.dragcomponents', function(event){
|
||||
var touchEvent = event.originalEvent
|
||||
moveDrag(touchEvent.touches[0])
|
||||
event.preventDefault()
|
||||
})
|
||||
|
||||
$(window).on('touchend.oc.dragcomponents', function(event) {
|
||||
stopDrag()
|
||||
})
|
||||
}
|
||||
else {
|
||||
$(window).on('mousemove.oc.dragcomponents', function(event){
|
||||
moveDrag(event)
|
||||
$(document.body).addClass(self.options.dragClass)
|
||||
return false
|
||||
})
|
||||
|
||||
$(window).on('mouseup.oc.dragcomponents', function(mouseUpEvent){
|
||||
var isClick = event.pageX == mouseUpEvent.pageX && event.pageY == mouseUpEvent.pageY
|
||||
stopDrag(isClick)
|
||||
return false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal event, drag is active
|
||||
*/
|
||||
function moveDrag(event) {
|
||||
if (!dragging) {
|
||||
dragging = true
|
||||
initDrag(event)
|
||||
}
|
||||
|
||||
adjY = $(window).scrollTop()
|
||||
adjX = $(window).scrollLeft()
|
||||
var offset = $clone.data('dragComponents')
|
||||
$clone.css({
|
||||
left: (event.pageX - adjX - offset.x),
|
||||
top: (event.pageY - adjY - offset.y)
|
||||
})
|
||||
|
||||
if (collision($clone, $componentList))
|
||||
$componentList.addClass('droppable')
|
||||
else
|
||||
$componentList.removeClass('droppable')
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal event, drag has ended
|
||||
*/
|
||||
function stopDrag(click) {
|
||||
dragging = false
|
||||
|
||||
if (click)
|
||||
$(document.body).removeClass(self.options.dragClass)
|
||||
|
||||
$el.removeClass(self.options.placeholderClass)
|
||||
$(window)
|
||||
.off('mousemove.oc.dragcomponents mouseup.oc.dragcomponents')
|
||||
.removeData('dragComponents')
|
||||
|
||||
if (!click)
|
||||
finishDrag()
|
||||
|
||||
$clone.remove()
|
||||
|
||||
window.setTimeout(function(){
|
||||
if (!click) {
|
||||
$(document.body).removeClass(self.options.dragClass)
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
function finishDrag() {
|
||||
// Dragged to the code editor
|
||||
if (collision($clone, $editorArea)) {
|
||||
// Add the component to the page
|
||||
$el.click()
|
||||
|
||||
// Can only attach to page or layouts
|
||||
if ($componentList.length && $editor && $editor.getEditor()) {
|
||||
// Inject {% component %} tag
|
||||
var alias = $('input[name="component_aliases[]"]', $el).val()
|
||||
$editor.insert("{% component '" + alias + "' %}")
|
||||
}
|
||||
}
|
||||
// Dragged to the component list
|
||||
else if (collision($clone, $componentList)) {
|
||||
// Add the component to the page
|
||||
$el.click()
|
||||
}
|
||||
|
||||
if (editorPos) {
|
||||
editorPos.dispose();
|
||||
}
|
||||
|
||||
if ($componentList.length) {
|
||||
$componentList.removeClass('droppable')
|
||||
}
|
||||
}
|
||||
|
||||
function collision($div1, $div2) {
|
||||
if (!$div1 || !$div2 || !$div1.length || !$div2.length)
|
||||
return false
|
||||
|
||||
var x1 = $div1.offset().left,
|
||||
y1 = $div1.offset().top,
|
||||
h1 = $div1.outerHeight(true),
|
||||
w1 = $div1.outerWidth(true),
|
||||
b1 = y1 + h1,
|
||||
r1 = x1 + w1,
|
||||
x2 = $div2.offset().left,
|
||||
y2 = $div2.offset().top,
|
||||
h2 = $div2.outerHeight(true),
|
||||
w2 = $div2.outerWidth(true),
|
||||
b2 = y2 + h2,
|
||||
r2 = x2 + w2
|
||||
|
||||
return !(b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DragComponents.DEFAULTS = {
|
||||
dragClass: 'drag',
|
||||
placeholderClass: 'placeholder'
|
||||
}
|
||||
|
||||
// DRAGCOMPONENTS PLUGIN DEFINITION
|
||||
// ============================
|
||||
|
||||
var old = $.fn.dragComponents
|
||||
|
||||
$.fn.dragComponents = function (option) {
|
||||
var args = Array.prototype.slice.call(arguments, 1)
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('oc.dragcomponents')
|
||||
var options = $.extend({}, DragComponents.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('oc.dragcomponents', (data = new DragComponents(this, options)))
|
||||
else if (typeof option == 'string') data[option].apply(data, args)
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.dragComponents.Constructor = DragComponents
|
||||
|
||||
// DRAGCOMPONENTS NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.dragComponents.noConflict = function () {
|
||||
$.fn.dragComponents = old
|
||||
return this
|
||||
}
|
||||
|
||||
// DRAGCOMPONENTS DATA-API
|
||||
// ===============
|
||||
|
||||
$(document).on('mouseenter.oc.dragcomponents', '[data-control="dragcomponent"]', function() {
|
||||
$(this).dragComponents()
|
||||
});
|
||||
|
||||
}(window.jQuery);
|
||||
183
modules/cms/assets/js/winter.tokenexpander.js
Normal file
183
modules/cms/assets/js/winter.tokenexpander.js
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Token Expander plugin
|
||||
* Locates Twig tokens and replaces them with potential content inside.
|
||||
*
|
||||
* JavaScript API:
|
||||
* $('#codeEditor').tokenExpander({ option: 'value' })
|
||||
*
|
||||
* Dependences:
|
||||
* - Code Edtior (codeeditor.js)
|
||||
*/
|
||||
|
||||
+function ($) { "use strict";
|
||||
|
||||
// TOKEN EXPANDER CLASS DEFINITION
|
||||
// ============================
|
||||
|
||||
var TokenExpander = function(element, options) {
|
||||
this.options = options
|
||||
this.$el = $(element)
|
||||
|
||||
// Public properties
|
||||
this.something = false
|
||||
|
||||
// Init
|
||||
this.init()
|
||||
}
|
||||
|
||||
TokenExpander.DEFAULTS = {
|
||||
option: 'default'
|
||||
}
|
||||
|
||||
TokenExpander.prototype.init = function() {
|
||||
|
||||
this.$editor = this.$el.codeEditor('getEditorObject')
|
||||
this.$selection = this.$editor.getSelection()
|
||||
this.$session = this.$editor.getSession()
|
||||
this.tokenName = null
|
||||
this.tokenValue = null
|
||||
this.tokenDefinition = null
|
||||
this.tokenRange = null
|
||||
|
||||
this.$selection.on('changeCursor', $.proxy(this.cursorChange, this))
|
||||
}
|
||||
|
||||
TokenExpander.prototype.cursorChange = function(event) {
|
||||
|
||||
var cursor = this.$selection.getCursor(),
|
||||
word = this.getActiveWord(cursor).toLowerCase()
|
||||
|
||||
if (word == 'component') {
|
||||
this.handleCursorOnToken(cursor, word)
|
||||
}
|
||||
else if (this.tokenName) {
|
||||
this.tokenName = null
|
||||
this.tokenValue = null
|
||||
this.tokenDefinition = null
|
||||
this.tokenRange = null
|
||||
|
||||
this.$el.trigger('hide.oc.tokenexpander')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TokenExpander.prototype.handleCursorOnToken = function(cursor, token) {
|
||||
var line = this.$session.getLine(cursor.row),
|
||||
definition = this.getTwigTokenDefinition(token, line, cursor.column)
|
||||
|
||||
if (definition) {
|
||||
|
||||
var value = this.getTwigTokenValue(token, definition[0])
|
||||
|
||||
if (value) {
|
||||
if (!this.tokenName)
|
||||
this.$el.trigger('show.oc.tokenexpander')
|
||||
|
||||
this.tokenName = token
|
||||
this.tokenValue = value
|
||||
this.tokenDefinition = definition
|
||||
this.tokenRange = this.$selection.getRange() // Used only for its row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback must return a promise object
|
||||
*/
|
||||
TokenExpander.prototype.expandToken = function(callback) {
|
||||
var $editor = this.$editor,
|
||||
$session = this.$session,
|
||||
definition = this.tokenDefinition,
|
||||
range = this.tokenRange
|
||||
|
||||
$editor.setReadOnly(true)
|
||||
|
||||
callback(this.tokenName, this.tokenValue)
|
||||
.done(function(data){
|
||||
range.setStart(range.start.row, definition[1])
|
||||
range.setEnd(range.end.row, definition[2])
|
||||
$session.replace(range, data.result)
|
||||
})
|
||||
.always(function(){
|
||||
$editor.setReadOnly(false)
|
||||
})
|
||||
}
|
||||
|
||||
TokenExpander.prototype.getTwigTokenValue = function(tokenName, tokenString) {
|
||||
|
||||
var regex = new RegExp("^{%\\s*"+tokenName+"\\s(['"+'"'+"])([^"+'"'+"']+)(?:\\1)[^(?:%})]+%}$", "i"),
|
||||
regexMatch = regex.exec(tokenString)
|
||||
|
||||
if (regexMatch && regexMatch[2])
|
||||
return regexMatch[2]
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of [tokenString, startPos, endPos] or null
|
||||
* Eg: ['{% component "thing" %}', 0, 23]
|
||||
*/
|
||||
TokenExpander.prototype.getTwigTokenDefinition = function(token, str, pos, filter) {
|
||||
|
||||
if (!filter)
|
||||
filter = 0
|
||||
|
||||
var filteredStr = str.substring(filter),
|
||||
regex = new RegExp("{%\\s*"+token+"\\s[^(?:%})]+%}", "i"),
|
||||
regexMatch = regex.exec(filteredStr)
|
||||
|
||||
if (regexMatch) {
|
||||
var start = str.indexOf(regexMatch[0], filter),
|
||||
end = start + regexMatch[0].length
|
||||
|
||||
// Win!
|
||||
if (start < pos && end > pos)
|
||||
return [regexMatch[0], start, end]
|
||||
|
||||
// Try again
|
||||
return this.getTwigTokenDefinition(token, str, pos, end)
|
||||
}
|
||||
|
||||
// Fail
|
||||
return null
|
||||
}
|
||||
|
||||
TokenExpander.prototype.getActiveWord = function(cursor) {
|
||||
var $session = this.$session,
|
||||
wordRange = $session.getWordRange(cursor.row, cursor.column),
|
||||
word = $session.getTextRange(wordRange)
|
||||
|
||||
return word
|
||||
}
|
||||
|
||||
// TOKEN EXPANDER PLUGIN DEFINITION
|
||||
// ============================
|
||||
|
||||
var old = $.fn.tokenExpander
|
||||
|
||||
$.fn.tokenExpander = function (option) {
|
||||
var args = Array.prototype.slice.call(arguments, 1), regexMatch
|
||||
this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('oc.tokenexpander')
|
||||
var options = $.extend({}, TokenExpander.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('oc.tokenexpander', (data = new TokenExpander(this, options)))
|
||||
if (typeof option == 'string') regexMatch = data[option].apply(data, args)
|
||||
if (typeof regexMatch != 'undefined') return false
|
||||
})
|
||||
|
||||
return regexMatch ? regexMatch : this
|
||||
}
|
||||
|
||||
$.fn.tokenExpander.Constructor = TokenExpander
|
||||
|
||||
// TOKEN EXPANDER NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.tokenExpander.noConflict = function () {
|
||||
$.fn.tokenExpander = old
|
||||
return this
|
||||
}
|
||||
|
||||
}(window.jQuery);
|
||||
406
modules/cms/assets/less/winter.components.less
Normal file
406
modules/cms/assets/less/winter.components.less
Normal file
@@ -0,0 +1,406 @@
|
||||
@import "../../../backend/assets/less/core/boot.less";
|
||||
|
||||
//
|
||||
// Component list
|
||||
// --------------------------------------------------
|
||||
|
||||
@color-component-list-bg: @brand-secondary;
|
||||
@color-component-bg: #ffffff;
|
||||
@color-component-text: #475354;
|
||||
@color-component-hover-bg: @brand-accent;
|
||||
@color-component-hover-text: #ffffff;
|
||||
@color-component-placeholder: #e0e0e0;
|
||||
@color-group-bg: #f1f3f4;
|
||||
@color-error-component-bg: @brand-danger;
|
||||
@color-error-component-text: #ffffff;
|
||||
@color-warning-component-bg: #ffc107;
|
||||
@color-warning-component-text: #343a40;
|
||||
|
||||
.component-lego-icon() {
|
||||
position: absolute;
|
||||
font-size: 37px;
|
||||
top: 1px;
|
||||
z-index: 50;
|
||||
color: @color-component-bg;
|
||||
text-shadow: 0 0 1px @color-component-text;
|
||||
width: 12px;
|
||||
overflow: hidden;
|
||||
text-indent: -25px;
|
||||
right: -12px;
|
||||
|
||||
.icon(@puzzle-piece);
|
||||
}
|
||||
|
||||
.draggable-component-item,
|
||||
.component-list .components div.layout-cell,
|
||||
div.control-componentlist div.components div.layout-cell {
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
background: @color-component-bg;
|
||||
.user-select(none);
|
||||
|
||||
&:hover {
|
||||
background: @color-component-hover-bg;
|
||||
}
|
||||
|
||||
> div {
|
||||
white-space: normal;
|
||||
color: @color-component-text;
|
||||
position: relative;
|
||||
border-right: 1px solid @color-panel-light;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
font-size: 16px;
|
||||
left: 15px;
|
||||
top: 7px;
|
||||
.opacity(0.7);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @color-component-hover-text;
|
||||
&:before {
|
||||
.opacity(1);
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
.component-lego-icon();
|
||||
}
|
||||
|
||||
&:hover:after {
|
||||
text-shadow: none;
|
||||
color: @color-component-hover-bg;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
|
||||
&.name {
|
||||
white-space: nowrap;
|
||||
padding: 8px 15px 0;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
font-size: @font-size-base - 1;
|
||||
}
|
||||
|
||||
&.description {
|
||||
padding: 0 15px 10px;
|
||||
margin-top: 8px;
|
||||
font-weight: 400;
|
||||
font-size: @font-size-base - 3;
|
||||
line-height: 150%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.placeholder > div {
|
||||
background: @color-component-placeholder;
|
||||
color: @color-component-placeholder;
|
||||
&:before, &:after {
|
||||
color: @color-component-placeholder !important;
|
||||
text-shadow: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce the double standard padding, since the tabs have padding
|
||||
// at the top and the components field has padding at the bottom.
|
||||
[data-field-name="components"] + .control-tabs.primary-tabs {
|
||||
margin-top: -(@padding-standard / 2);
|
||||
}
|
||||
|
||||
div.control-componentlist {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
.transition(all 0.3s ease);
|
||||
|
||||
&.droppable {
|
||||
background-color: lighten(@color-component-list-bg, 20%);
|
||||
}
|
||||
|
||||
&.has-components {
|
||||
padding: 0 @padding-standard @padding-standard;
|
||||
}
|
||||
|
||||
div.layout {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
div.components {
|
||||
div.layout-cell {
|
||||
&.error-component {
|
||||
background: @color-error-component-bg;
|
||||
|
||||
> div {
|
||||
color: @color-error-component-text;
|
||||
|
||||
&:after {
|
||||
color: @color-error-component-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.warning-component {
|
||||
background: @color-warning-component-bg;
|
||||
|
||||
> div {
|
||||
color: @color-warning-component-text;
|
||||
|
||||
&:after {
|
||||
color: @color-warning-component-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
.border-left-radius(3px);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
.border-right-radius(3px);
|
||||
|
||||
> div {
|
||||
border-right: none;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2n) > div:after {
|
||||
top: auto;
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
> div.popover-highlight {
|
||||
.border-left-radius(3px);
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
> div.popover-highlight {
|
||||
.border-right-radius(3px);
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
.translate(0, 0);
|
||||
.transition-transform(0.2s);
|
||||
|
||||
max-width: 250px;
|
||||
min-width: 170px;
|
||||
|
||||
&.popover-highlight {
|
||||
border-right-color: rgba(0,0,0,0);
|
||||
background: @color-component-bg!important;
|
||||
color: @color-component-text!important;
|
||||
&:before {
|
||||
.opacity(0.7);
|
||||
}
|
||||
|
||||
&:after {
|
||||
color: @color-component-bg;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
a.remove {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
&.name {
|
||||
padding-left: 38px;
|
||||
}
|
||||
|
||||
&.description {
|
||||
padding-bottom: 35px;
|
||||
}
|
||||
|
||||
&.alias {
|
||||
padding: 0 15px;
|
||||
font-weight: 500;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 10px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
|
||||
&:before {
|
||||
margin-right: 4px;
|
||||
.opacity(0.55);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.remove {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
top: 1px;
|
||||
right: 5px;
|
||||
color: @close-color;
|
||||
font-size: 17px;
|
||||
font-weight: @close-font-weight;
|
||||
.opacity(.3);
|
||||
|
||||
&:hover {
|
||||
.opacity(.5);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.adding > div {
|
||||
.translate(0, -100px)!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.draggable-component-item {
|
||||
.opacity(.6);
|
||||
span.alias { display: none; }
|
||||
a.remove { display: none; }
|
||||
}
|
||||
|
||||
.component-list .components {
|
||||
div.layout {
|
||||
div.layout-row {
|
||||
div.layout-cell {
|
||||
border-top: 1px solid @color-panel-light;
|
||||
span.alias { display: none; }
|
||||
a.remove { display: none; }
|
||||
|
||||
&:last-child > div {
|
||||
border-right: none;
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
&:before {
|
||||
.component-lego-icon();
|
||||
.rotate(-90deg);
|
||||
.opacity(1);
|
||||
left: auto;
|
||||
top: -17px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
&:hover:before {
|
||||
text-shadow: none;
|
||||
color: @color-component-hover-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
div.layout-cell {
|
||||
> div {
|
||||
&:before {display: none;}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.layout.single {
|
||||
div.layout-row > div.layout-cell > div {
|
||||
border-right: none;
|
||||
&:before {
|
||||
display: block;
|
||||
right: 55.5%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.control-filelist.component-list {
|
||||
ul li {
|
||||
div.group {
|
||||
background: @color-group-bg;
|
||||
border-top: 1px solid darken(@color-panel-light, 2%);
|
||||
padding: 10px 15px 10px 10px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
h4 {
|
||||
text-transform: uppercase;
|
||||
font-size: 14px;
|
||||
margin-top: 3px;
|
||||
|
||||
a {
|
||||
padding-left: 33px;
|
||||
|
||||
&:before {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span.description {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
padding-left: 33px;
|
||||
color: @color-text-description;
|
||||
}
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
left: 22px;
|
||||
top: 21px;
|
||||
font-size: 16px;
|
||||
.opacity(0.7);
|
||||
color: @color-text-title;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.disable-component-list-hover() {
|
||||
background: @color-component-bg;
|
||||
color: @color-component-text;
|
||||
|
||||
&:after {
|
||||
text-shadow: 0 0 1px @color-component-text!important;
|
||||
color: @color-component-bg!important;
|
||||
}
|
||||
}
|
||||
|
||||
.touch {
|
||||
div.control-componentlist div.components div.layout-cell {
|
||||
> div:hover, > div:active, > div:active:focus {
|
||||
.disable-component-list-hover();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modifies the color of the tab background when components are present
|
||||
// this is no longer required since the colors are the same! :-) -sg
|
||||
// .fancy-layout {
|
||||
// .control-tabs, &.control-tabs {
|
||||
// &.primary-tabs {
|
||||
// > div > ul.nav-tabs {
|
||||
// &.component-area {
|
||||
// background: @color-component-list-bg;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
body.drag div.control-componentlist div.components div.layout-cell {
|
||||
> div, > div:hover, > div:active {
|
||||
.disable-component-list-hover();
|
||||
}
|
||||
}
|
||||
160
modules/cms/assets/less/winter.theme-selector.less
Normal file
160
modules/cms/assets/less/winter.theme-selector.less
Normal file
@@ -0,0 +1,160 @@
|
||||
@import "../../../backend/assets/less/core/boot.less";
|
||||
|
||||
.theme-selector-layout {
|
||||
.layout-cell {
|
||||
padding: 24px;
|
||||
.box-sizing(border-box);
|
||||
}
|
||||
|
||||
.theme-thumbnail {
|
||||
width: 288px;
|
||||
background: #ecf0f1;
|
||||
border-top: 1px solid #e3e7e9;
|
||||
|
||||
img {
|
||||
.opacity(0.6);
|
||||
width: 240px;
|
||||
}
|
||||
}
|
||||
|
||||
.theme-description {
|
||||
border-top: 1px solid #f2f3f4;
|
||||
|
||||
h3, p {
|
||||
.opacity(0.6);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0 0 25px 0;
|
||||
font-size: 28px;
|
||||
color: #2b3e50;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
p.author {
|
||||
font-size: 13px;
|
||||
display: inline-block;
|
||||
color: #808c8d;
|
||||
}
|
||||
|
||||
p.description {
|
||||
color: #2b3e50;
|
||||
font-size: 14px;
|
||||
line-height: 180%;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.controls {
|
||||
.btn > i {
|
||||
margin-right: 5px;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
|
||||
&.icon-star {
|
||||
color: #f1a84e;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layout-row.active {
|
||||
.theme-thumbnail {
|
||||
background: #bdc3c7;
|
||||
border-top-color: #bdc3c7;
|
||||
}
|
||||
|
||||
.thumbnail-container {
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
.triangle(right, 15px, 28px, #bdc3c7);
|
||||
position: absolute;
|
||||
right: -35px;
|
||||
top: 50%;
|
||||
margin-top: -14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layout-row {
|
||||
&.active, &:hover {
|
||||
.theme-description {
|
||||
h3, p {
|
||||
.opacity(1);
|
||||
}
|
||||
}
|
||||
|
||||
.theme-thumbnail {
|
||||
img {
|
||||
.opacity(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child, &.links {
|
||||
.theme-description, .theme-thumbnail {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.links {
|
||||
.theme-thumbnail {
|
||||
border-bottom: 1px solid #e3e7e9;
|
||||
}
|
||||
.theme-description {
|
||||
border-bottom: 1px solid #f2f3f4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.create-new-theme {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.create-new-theme,
|
||||
.find-more-themes {
|
||||
background: #ecf0f1;
|
||||
color: #2b3e50;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
padding: 20px;
|
||||
.border-radius(4px);
|
||||
|
||||
&:hover {
|
||||
background: @link-color;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Screen specific
|
||||
//
|
||||
|
||||
@media (max-width: @screen-sm) {
|
||||
.theme-selector-layout {
|
||||
.layout-cell, .layout-row {
|
||||
display: block!important;
|
||||
width: auto!important;
|
||||
height: auto!important;
|
||||
}
|
||||
|
||||
.theme-thumbnail {
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-row.links {
|
||||
.theme-thumbnail {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1407
modules/cms/assets/vendor/jsdiff/diff.js
vendored
Normal file
1407
modules/cms/assets/vendor/jsdiff/diff.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user