diff --git a/src/editor/model/Editor.js b/src/editor/model/Editor.js index e9c8795bc..7ffbe18c3 100644 --- a/src/editor/model/Editor.js +++ b/src/editor/model/Editor.js @@ -12,7 +12,8 @@ define([ 'RichTextEditor', 'DomComponents', 'ClassManager', - 'Panels'], + 'Panels', + 'Utils'], function( Backbone, UndoManager, @@ -27,7 +28,8 @@ define([ RichTextEditor, DomComponents, ClassManager, - Panels + Panels, + Utils ){ return Backbone.Model.extend({ @@ -58,10 +60,18 @@ define([ this.initCanvas(); this.initUndoManager(); this.initCssComposer(); + this.initUtils(); this.on('change:selectedComponent', this.componentSelected, this); }, + /** + * Initialize Utils + * */ + initUtils: function() { + this.set('Utils', new Utils()); + }, + /** * Initialize Css Composer * */ diff --git a/src/style_manager/model/Layer.js b/src/style_manager/model/Layer.js index 56f648e05..394170285 100644 --- a/src/style_manager/model/Layer.js +++ b/src/style_manager/model/Layer.js @@ -4,7 +4,7 @@ define(['backbone'], return Backbone.Model.extend({ defaults: { - name: '', + index: '', active: true, value: '', preview: false, diff --git a/src/style_manager/model/Layers.js b/src/style_manager/model/Layers.js index 977c577f7..16833fefc 100644 --- a/src/style_manager/model/Layers.js +++ b/src/style_manager/model/Layers.js @@ -5,5 +5,21 @@ define([ 'backbone', './Layer'], model: Layer, + initialize: function(){ + this.idx = 1; + this.on('add', this.onAdd); + this.on('reset', this.onReset); + }, + + onAdd: function(model, c, opts){ + //console.log(opts); + if(!opts.noIncrement) + model.set('index', this.idx++); + }, + + onReset: function(){ + this.idx = 1; + }, + }); }); diff --git a/src/style_manager/view/LayerView.js b/src/style_manager/view/LayerView.js index d745009d7..6cfe582bb 100644 --- a/src/style_manager/view/LayerView.js +++ b/src/style_manager/view/LayerView.js @@ -16,16 +16,17 @@ define(['backbone', 'text!./../templates/layer.html'], this.config = o.config || {}; this.pfx = this.config.stylePrefix || ''; this.className = this.pfx + 'layer'; + this.sorter = o.sorter || null; this.listenTo(this.model, 'destroy remove', this.remove); this.listenTo(this.model, 'change:value', this.valueChanged); this.listenTo(this.model, 'change:props', this.showProps); this.events['click #' + this.pfx + 'close-layer'] = 'remove'; - //this.events['mousedown > #' + this.pfx + 'move'] = 'initSorter'; + this.events['mousedown > #' + this.pfx + 'move'] = 'initSorter'; if( !this.model.get('preview') ){ this.$el.addClass(this.pfx + 'no-preview'); } - + this.$el.data('model', this.model); this.delegateEvents(); }, @@ -35,7 +36,7 @@ define(['backbone', 'text!./../templates/layer.html'], * */ initSorter: function(e){ if(this.sorter) - this.sorter.startMove(this); + this.sorter.startSort(this.el); }, /** @@ -121,7 +122,8 @@ define(['backbone', 'text!./../templates/layer.html'], Backbone.View.prototype.remove.apply(this, arguments); - if(this.model.collection) + //--- + if(this.model.collection.contains(this.model)) this.model.collection.remove(this.model); if(this.stackModel && this.stackModel.set){ @@ -162,8 +164,7 @@ define(['backbone', 'text!./../templates/layer.html'], render : function(){ var i = this.getIndex(); this.$el.html( this.template({ - label: 'Layer ' + i, - name: this.model.get('name'), + label: 'Layer ' + this.model.get('index'), pfx: this.pfx, })); this.$el.attr('class', this.className); diff --git a/src/style_manager/view/LayersView.js b/src/style_manager/view/LayersView.js index 0c7529d81..93161b900 100644 --- a/src/style_manager/view/LayersView.js +++ b/src/style_manager/view/LayersView.js @@ -6,14 +6,26 @@ define(['backbone','./LayerView'], return Backbone.View.extend({ initialize: function(o) { - this.config = o.config; + this.config = o.config || {}; this.stackModel = o.stackModel; - this.preview = o.preview; - this.pfx = this.config.stylePrefix; + this.preview = o.preview; + this.pfx = this.config.stylePrefix || ''; this.className = this.pfx + 'layers'; - this.listenTo( this.collection, 'add', this.addTo ); + this.listenTo( this.collection, 'add', this.addTo); this.listenTo( this.collection, 'deselectAll', this.deselectAll ); - this.listenTo( this.collection, 'reset', this.render ); + this.listenTo( this.collection, 'reset', this.render); + + var em = this.config.target || ''; + var utils = em ? em.get('Utils') : ''; + + this.sorter = utils ? new utils.Sorter({ + container: this.el, + containerSel: '.' + this.pfx + 'layers', + itemSel: '.' + this.pfx + 'layer', + pfx: 'wte-', + }) : ''; + + this.$el.data('collection', this.collection); }, /** @@ -23,19 +35,21 @@ define(['backbone','./LayerView'], * @return Object * */ addTo: function(model){ - this.addToCollection(model); + var i = this.collection.indexOf(model); + this.addToCollection(model, null, i); }, /** * Add new object to collection * @param Object Model * @param Object Fragment collection + * @param {number} index Index of append * * @return Object Object created * */ - addToCollection: function(model, fragmentEl){ - var fragment = fragmentEl || null; - var viewObject = LayerView; + addToCollection: function(model, fragmentEl, index){ + var fragment = fragmentEl || null; + var viewObject = LayerView; if(typeof this.preview !== 'undefined'){ model.set('preview', this.preview); @@ -45,13 +59,28 @@ define(['backbone','./LayerView'], model: model, stackModel: this.stackModel, config: this.config, + sorter: this.sorter }); var rendered = view.render().el; if(fragment){ fragment.appendChild( rendered ); }else{ - this.$el.append(rendered); + if(typeof index != 'undefined'){ + var method = 'before'; + // If the added model is the last of collection + // need to change the logic of append + if(this.$el.children().length == index){ + index--; + method = 'after'; + } + // In case the added is new in the collection index will be -1 + if(index < 0){ + this.$el.append(rendered); + }else + this.$el.children().eq(index)[method](rendered); + }else + this.$el.append(rendered); } return rendered; diff --git a/src/style_manager/view/PropertyStackView.js b/src/style_manager/view/PropertyStackView.js index 94f2582d7..f80764737 100644 --- a/src/style_manager/view/PropertyStackView.js +++ b/src/style_manager/view/PropertyStackView.js @@ -163,7 +163,9 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack },this); } this.$props.detach(); - this.getLayers().reset(n); + var layers = this.getLayers(); + layers.reset(); + layers.add(n); this.refreshValue(); this.model.set({stackIndex: null}, {silent: true}); }, diff --git a/src/utils/Sorter.js b/src/utils/Sorter.js index 7059f4eca..aed7d3b59 100644 --- a/src/utils/Sorter.js +++ b/src/utils/Sorter.js @@ -6,21 +6,18 @@ define(['backbone'], initialize: function(opt) { _.bindAll(this,'startSort','onMove','endMove','rollback'); var o = opt || {}; - this.config = o.config || {}; - this.pfx = this.config.stylePrefix || ''; - this.itemClass = '.' + this.pfx + this.config.itemClass; - this.itemsClass = '.' + this.pfx + this.config.itemsClass; - this.setElement('.'+this.pfx+this.config.containerId); - this.elT = 0; this.elL = 0; this.borderOffset = o.borderOffset || 10; this.freezeClass = o.freezeClass || 'freezed'; - this.el = document.querySelector(o.container); + var el = o.container; + this.el = typeof el === 'string' ? document.querySelector(o.container) : el; this.$el = $(this.el); - this.containerSel = 'div'; - this.itemSel = 'div'; + this.containerSel = o.containerSel || 'div'; + this.itemSel = o.itemSel || 'div'; + this.nested = o.nested || 0; + this.pfx = o.pfx || ''; }, /** @@ -44,6 +41,8 @@ define(['backbone'], * @return {Element|null} */ closest: function(el, selector){ + if(!el) + return; var elem = el.parentNode; while (elem && elem.nodeType === 1) { if (this.matches(elem, selector)) @@ -74,10 +73,10 @@ define(['backbone'], var pfx = this.pfx; var el = document.createElement('div'); var ins = document.createElement('div'); - el.id = pfx + 'placeholder'; + el.className = pfx + 'placeholder'; el.style.display = 'none'; el.style['pointer-events'] = 'none'; - ins.id = pfx + "plh-int"; + ins.className = pfx + "placeholder-int"; el.appendChild(ins); return el; }, @@ -88,16 +87,16 @@ define(['backbone'], * */ startSort: function(trg){ this.moved = 0; - this.eV = trg.el || trg; + this.eV = trg; + + if(!this.matches(trg, this.itemSel + ',' + this.containerSel)) + this.eV = this.closest(trg, this.itemSel); // Create placeholder if not exists if(!this.plh){ this.plh = this.createPlaceholder(); this.el.appendChild(this.plh); } - //freeze el.. add this.freezeClass - - //callback onStart this.$el.on('mousemove',this.onMove); $(document).on('mouseup',this.endMove); @@ -126,12 +125,12 @@ define(['backbone'], var dims = this.dimsFromTarget(e.target, this.rX, this.rY); var pos = this.findPosition(dims, this.rX, this.rY); - var actualPos = pos.index + ':' + pos.method; // If there is a significant changes with the pointer - if(!this.lastPos || (this.lastPos != actualPos)){ + if( !this.lastPos || + (this.lastPos.index != pos.index || this.lastPos.method != pos.method)){ this.movePlaceholder(this.plh, dims, pos, this.prevTargetDim); - this.lastPos = actualPos; + this.lastPos = pos; } //callback onMove @@ -144,9 +143,13 @@ define(['backbone'], * */ getChildrenDim: function(elem){ var dims = []; + if(!elem) + return dims; var ch = elem.children; //TODO filter match for (var i = 0, len = ch.length; i < len; i++) { var el = ch[i]; + if(!this.matches(el, this.itemSel)) + continue; var dim = this.getDim(el); dim.push(true); //TODO check if in flow, now only for vertical elements dim.push(el); @@ -175,9 +178,12 @@ define(['backbone'], dimsFromTarget: function(target, rX, rY){ var dims = []; - if(!this.matches(target, this.itemSel)) + if(!this.matches(target, this.itemSel + ',' + this.containerSel)) target = this.closest(target, this.itemSel); + if(!target) + return dims; + // Check if the target is different from the previous one if(this.prevTarget){ if(this.prevTarget != target){ @@ -187,10 +193,10 @@ define(['backbone'], // New target encountered if(!this.prevTarget){ - var parent = this.closest(target, this.containerSel); + this.targetP = this.closest(target, this.containerSel); this.prevTarget = target; this.prevTargetDim = this.getDim(target); - this.cacheDimsP = this.getChildrenDim(parent); + this.cacheDimsP = this.getChildrenDim(this.targetP); this.cacheDims = this.getChildrenDim(target); } @@ -198,10 +204,15 @@ define(['backbone'], if(this.prevTarget == target) dims = this.cacheDims; + // Target when I will drop element to sort + this.target = this.prevTarget; // Generally also on every new target the poiner enters near // to borders, so have to to check always - if(this.nearBorders(this.prevTargetDim, rX, rY)) + if(this.nearBorders(this.prevTargetDim, rX, rY) || + (!this.nested && !this.cacheDims.length)){ dims = this.cacheDimsP; + this.target = this.targetP; + } return dims; }, @@ -310,6 +321,10 @@ define(['backbone'], l = elDim[1]; } }else{ + if(!this.nested){ + plh.style.display = 'none'; + return; + } if(trgDim){ t = trgDim[0] + margI + 17; l = trgDim[1] + margI * 7; @@ -334,12 +349,9 @@ define(['backbone'], this.$el.off('mousemove', this.onMove); $(document).off('mouseup', this.endMove); $(document).off('keypress', this.rollback); - //this.eV.unfreeze(); - //this.$plh.hide(); + this.plh.style.display = 'none'; if(this.moved) - this.move(this.$targetEl, this.$sel, this.posIndex, this.posMethod); - //this.itemLeft(); // Do I need to reset all cached stuff? - //callback onMove + this.move(this.target, this.eV, this.lastPos); }, /** @@ -351,26 +363,17 @@ define(['backbone'], * * @return void * */ - move: function(target, el, posIndex, method){ - //this.eV - var trg = target|| this.$targetEl; - trg = trg || this.$backupEl; - if(!trg) - return; - var index = posIndex || 0; - var model = el.data("model"); - var collection = model.collection; - var targetModel = trg.data('model'); - var targetCollection = targetModel.collection; - - if(!this.cDim.length) - targetCollection = targetModel.get('components'); - - if(targetCollection && targetModel.get('droppable')){ - index = method == 'after' ? index + 1 : index; - var modelTemp = targetCollection.add({style:{}}, { at: index}); - var modelRemoved = collection.remove(model, { silent:false }); - targetCollection.add(modelRemoved, { at: index, silent:false }); + move: function(dst, src, pos){ + var index = pos.index; + var model = $(src).data('model'); + var collection = model.collection; + var targetCollection = $(dst).data('collection'); + + if(targetCollection){// && targetModel.get('droppable') + index = pos.method === 'after' ? index + 1 : index; + var modelTemp = targetCollection.add({}, {at: index, noIncrement: 1}); + var modelRemoved = model.collection.remove(model); + targetCollection.add(modelRemoved, {at: index, noIncrement: 1}); targetCollection.remove(modelTemp); }else console.warn("Invalid target position"); @@ -378,16 +381,13 @@ define(['backbone'], /** * Rollback to previous situation - * @param Event - * @param Bool Indicates if rollback in anycase - * @return void + * @param {Event} + * @param {Bool} Indicates if rollback in anycase * */ - rollback: function(e, force){ + rollback: function(e){ var key = e.which || e.keyCode; - if(key == 27 || force){ - this.moved = false; + if(key == 27) this.endMove(); - } return; }, diff --git a/styles/css/main.css b/styles/css/main.css index 1242ef154..3d6c4c903 100644 --- a/styles/css/main.css +++ b/styles/css/main.css @@ -2720,10 +2720,11 @@ ol.example li.placeholder:before { .wte-com-badge-yellow { background-color: #ffca6f; } -.wte-com-placeholder { - position: absolute; } +.wte-placeholder, .wte-com-placeholder { + position: absolute; + z-index: 10; } -.wte-com-placeholder-int { +.wte-placeholder-int, .wte-com-placeholder-int { background-color: #62c462; height: 100%; width: 100%; @@ -3218,7 +3219,7 @@ ol.example li.placeholder:before { .wte-sm-layer > #wte-sm-move { opacity: 0.3; filter: alpha(opacity=30); - cursor: pointer; + cursor: move; font-size: 12px; float: left; margin: 0 5px 0 0; } diff --git a/styles/scss/main.scss b/styles/scss/main.scss index 7374cb650..4c1b1a282 100644 --- a/styles/scss/main.scss +++ b/styles/scss/main.scss @@ -188,10 +188,11 @@ ol.example li.placeholder:before {position: absolute;} @extend .#{$com-prefix}badge; background-color: $colorYell; } -.#{$com-prefix}placeholder{ +.#{$app-prefix}placeholder, .#{$com-prefix}placeholder{ position: absolute; + z-index: 10; } -.#{$com-prefix}placeholder-int{ +.#{$app-prefix}placeholder-int, .#{$com-prefix}placeholder-int{ background-color: $colorGreen; height: 100%; width: 100%; pointer-events: 'none'; @@ -742,7 +743,7 @@ $arrowColor: darken($fontColor,24%); /*b1b1b1*/ } .#{$sm-prefix}layer > ##{$sm-prefix}move { @include opacity(0.3); - cursor: pointer; + cursor: move; font-size: 12px; float: left; margin: 0 5px 0 0; diff --git a/test/specs/style_manager/model/Models.js b/test/specs/style_manager/model/Models.js index c46855419..ecbc18b8b 100644 --- a/test/specs/style_manager/model/Models.js +++ b/test/specs/style_manager/model/Models.js @@ -118,8 +118,8 @@ define([path + 'Sector', delete obj; }); - it('Has name property', function() { - obj.has('name').should.equal(true); + it('Has index property', function() { + obj.has('index').should.equal(true); }); it('Is active', function() { @@ -144,6 +144,25 @@ define([path + 'Sector', obj.should.be.ok; }); + it('Init index on add', function() { + var model = obj.add({}); + model.get('index').should.equal(1); + }); + + it('Increment index', function() { + var model = obj.add({}); + var model2 = obj.add({}); + model2.get('index').should.equal(2); + }); + + it('Cache index', function() { + var model = obj.add({}); + var model2 = obj.add({}); + obj.remove(model2); + var model3 = obj.add({}); + model3.get('index').should.equal(3); + }); + }); } diff --git a/test/specs/utils/Sorter.js b/test/specs/utils/Sorter.js index a1c5327c4..d98578cec 100644 --- a/test/specs/utils/Sorter.js +++ b/test/specs/utils/Sorter.js @@ -47,7 +47,7 @@ define([path + 'Sorter',], }); it('Creates placeholder', function() { - obj.createPlaceholder().id.should.equal('placeholder'); + obj.createPlaceholder().className.should.equal('placeholder'); }); describe('Closest method', function() { @@ -267,6 +267,10 @@ define([path + 'Sorter',], it.skip('movePlaceholder', function() { }); + it.skip('move', function() { + obj.move(el).should.equal('test'); + }); + }); });