From c59312370047429953597651f905b43468eecbc2 Mon Sep 17 00:00:00 2001 From: Sam Georges Date: Sat, 24 May 2014 15:18:59 +1000 Subject: [PATCH] Components can now be dragged on to a page or layout --- modules/cms/assets/css/october.components.css | 75 ++++-- modules/cms/assets/js/october.cmspage.js | 3 + .../cms/assets/js/october.dragcomponents.js | 238 ++++++++++++++++++ .../cms/assets/less/october.components.less | 24 +- modules/cms/controllers/Index.php | 1 + .../partials/_component_list.htm | 6 +- 6 files changed, 321 insertions(+), 26 deletions(-) create mode 100644 modules/cms/assets/js/october.dragcomponents.js diff --git a/modules/cms/assets/css/october.components.css b/modules/cms/assets/css/october.components.css index 97e1e4f92..a04c54b9c 100644 --- a/modules/cms/assets/css/october.components.css +++ b/modules/cms/assets/css/october.components.css @@ -1,26 +1,35 @@ -div.control-componentlist div.components div.layout-cell, -.component-list .components div.layout-cell { +.draggable-component-item, +.component-list .components div.layout-cell, +div.control-componentlist div.components div.layout-cell { font-size: 11px; cursor: pointer; background: #ffffff; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } -div.control-componentlist div.components div.layout-cell:hover, -.component-list .components div.layout-cell:hover { +.draggable-component-item:hover, +.component-list .components div.layout-cell:hover, +div.control-componentlist div.components div.layout-cell:hover { background: #3382b6; } -div.control-componentlist div.components div.layout-cell > div, -.component-list .components div.layout-cell > div { +.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; } -div.control-componentlist div.components div.layout-cell > div:hover, -.component-list .components div.layout-cell > div:hover { +.draggable-component-item > div:hover, +.component-list .components div.layout-cell > div:hover, +div.control-componentlist div.components div.layout-cell > div:hover { color: #ffffff; } -div.control-componentlist div.components div.layout-cell > div:before, -.component-list .components div.layout-cell > div:before { +.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; @@ -28,8 +37,9 @@ div.control-componentlist div.components div.layout-cell > div:before, opacity: 0.7; filter: alpha(opacity=70); } -div.control-componentlist div.components div.layout-cell > div:after, -.component-list .components div.layout-cell > div:after { +.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; @@ -48,31 +58,50 @@ div.control-componentlist div.components div.layout-cell > div:after, *margin-right: .3em; content: "\f12e"; } -div.control-componentlist div.components div.layout-cell > div:hover:after, -.component-list .components div.layout-cell > div:hover:after { +.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: #3382b6; } -div.control-componentlist div.components div.layout-cell > div span, -.component-list .components div.layout-cell > div span { +.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; } -div.control-componentlist div.components div.layout-cell > div span.name, -.component-list .components div.layout-cell > div span.name { +.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: 12px; } -div.control-componentlist div.components div.layout-cell > div span.description, -.component-list .components div.layout-cell > div span.description { +.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: 100; 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; +} div.control-componentlist { position: relative; background-color: #2c3e50; @@ -172,6 +201,12 @@ div.control-componentlist div.components div.layout-cell.adding > div { -ms-transform: translate(0, -100px) !important; transform: translate(0, -100px) !important; } +.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; } diff --git a/modules/cms/assets/js/october.cmspage.js b/modules/cms/assets/js/october.cmspage.js index 78ba6323e..bbebea2d2 100644 --- a/modules/cms/assets/js/october.cmspage.js +++ b/modules/cms/assets/js/october.cmspage.js @@ -509,6 +509,9 @@ counter++ } + // Set the last alias used so dragComponents can use it + $('input[name="component_aliases[]"]', $(this)).val(alias) + $componentContainer.addClass($iconInput.val()) $iconInput.remove() $componentContainer.attr('data-inspectable', '') diff --git a/modules/cms/assets/js/october.dragcomponents.js b/modules/cms/assets/js/october.dragcomponents.js new file mode 100644 index 000000000..630af0837 --- /dev/null +++ b/modules/cms/assets/js/october.dragcomponents.js @@ -0,0 +1,238 @@ +/* + * 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, + $clone, + $editorArea, + $editor, + adjX = 0, + adjY = 0, + dragging = false, + startPos, + editorPos + + $el.mousedown(function(event){ + startDrag(event) + return false + }) + + $el.on('touchstart', function(event){ + var touchEvent = event.originalEvent; + if (touchEvent.touches.length == 1) { + startDrag(touchEvent.touches[0]) + event.stopPropagation() + } + }) + + function initDrag(event) { + $el.addClass(self.options.placeholderClass) + $clone.show() + $editorArea = $('[data-control="codeeditor"]:visible') + if (!$editorArea.length) return + + $editor = $editorArea.codeEditor('getEditorObject') + $editor.focus() + + $editor.on('mousemove', function (event) { + editorPos = event.getDocumentPosition() + $editor.clearSelection() + $editor.moveCursorToPosition(editorPos) + }); + } + + /* + * 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.touch) { + $(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) + }) + } + + /* + * 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() { + if (collision($clone, $editorArea)) { + + // Add the component to the page + $el.click() + + // Can only attach to page or layouts + var $componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist .layout') + if (!$componentList.length || !$editor) + return; + + // Inject {% component %} tag + var alias = $('input[name="component_aliases[]"]', $el).val() + $editor.insert("{% component '" + alias + "' %}") + } + + $editor.removeAllListeners('mousemove') + $editor.blur() + } + + function collision($div1, $div2) { + if (!$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); diff --git a/modules/cms/assets/less/october.components.less b/modules/cms/assets/less/october.components.less index 99db706fb..2e95c26ff 100644 --- a/modules/cms/assets/less/october.components.less +++ b/modules/cms/assets/less/october.components.less @@ -9,6 +9,7 @@ @color-component-text: #475354; @color-component-hover-bg: #3382b6; @color-component-hover-text: #ffffff; +@color-component-placeholder: #e0e0e0; @color-group-bg: #f1f3f4; .component-lego-icon() { @@ -26,10 +27,13 @@ .icon(@puzzle-piece); } -div.control-componentlist div.components div.layout-cell, .component-list .components div.layout-cell { +.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; @@ -82,6 +86,15 @@ div.control-componentlist div.components div.layout-cell, .component-list .compo } } } + + &.placeholder > div { + background: @color-component-placeholder; + color: @color-component-placeholder; + &:before, &:after { + color: @color-component-placeholder !important; + text-shadow: none !important; + } + } } div.control-componentlist { @@ -199,13 +212,18 @@ div.control-componentlist { } } +.draggable-component-item { + 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;} + span.alias { display: none; } + a.remove { display: none; } &:last-child > div { border-right: none; diff --git a/modules/cms/controllers/Index.php b/modules/cms/controllers/Index.php index eac9b9e99..82a85edbf 100644 --- a/modules/cms/controllers/Index.php +++ b/modules/cms/controllers/Index.php @@ -77,6 +77,7 @@ class Index extends Controller } $this->addJs('/modules/cms/assets/js/october.cmspage.js'); + $this->addJs('/modules/cms/assets/js/october.dragcomponents.js'); $this->addCss('/modules/cms/assets/css/october.components.css'); // Preload Ace editor modes explicitly, because they could be changed dynamically diff --git a/modules/cms/widgets/componentlist/partials/_component_list.htm b/modules/cms/widgets/componentlist/partials/_component_list.htm index 7b92ed484..f95cd295c 100644 --- a/modules/cms/widgets/componentlist/partials/_component_list.htm +++ b/modules/cms/widgets/componentlist/partials/_component_list.htm @@ -1,10 +1,10 @@
- $component): ?> + $component): ?> 0 && ($index % 2) == 0): ?>
@@ -15,7 +15,7 @@
-
+
title) ?> description) ?>