Browse Source

Merge branch 'scroll-to-view' into dev

pull/1130/head
Artur Arseniev 9 years ago
parent
commit
6f57773d37
  1. 2
      dist/css/grapes.min.css
  2. 33
      src/canvas/index.js
  3. 4
      src/canvas/view/CanvasView.js
  4. 24
      src/dom_components/index.js
  5. 29
      src/dom_components/view/ComponentView.js
  6. 13
      src/navigator/config/config.js
  7. 8
      src/navigator/index.js
  8. 16
      src/navigator/view/ItemView.js
  9. 4
      src/styles/scss/_gjs_layers.scss
  10. 16
      src/utils/mixins.js

2
dist/css/grapes.min.css

File diff suppressed because one or more lines are too long

33
src/canvas/index.js

@ -1,4 +1,4 @@
import { on, off, hasDnd } from 'utils/mixins';
import { on, off, hasDnd, getElement } from 'utils/mixins';
import Droppable from 'utils/Droppable';
module.exports = () => {
@ -86,6 +86,14 @@ module.exports = () => {
return CanvasView.frame.el;
},
/**
* Returns the frame document
* @return {HTMLElement}
*/
getDocument() {
return this.getFrameEl().contentDocument;
},
/**
* Returns body element of the frame
* @return {HTMLElement}
@ -342,6 +350,29 @@ module.exports = () => {
return this.getFrameEl().contentDocument.activeElement.tagName !== 'BODY';
},
/**
* Scroll canvas to the element if it's not visible. The scrolling is
* executed via `scrollIntoView` API and options of this method are
* passed to it. For instance, you can scroll smoothly with
* `{ behavior: 'smooth' }`. You can also force the scroll
* @param {HTMLElement|Component} el
* @param {Object} [opts={}] Options, same as options for `scrollIntoView`
* @example
* const selected = editor.getSelected();
* // Scroll smoothly (this behavior can be polyfilled)
* cv.scrollTo(selected, { behavior: 'smooth' });
* // Force the scroll, even if the element is alredy visible
* cv.scrollTo(selected, { force: true });
*/
scrollTo(el, opts = {}) {
const elem = getElement(el);
const cv = this.getCanvasView();
if (!cv.isElInViewport(elem) || opts.force) {
elem.scrollIntoView(opts);
}
},
/**
* Start autoscroll
*/

4
src/canvas/view/CanvasView.js

@ -1,4 +1,4 @@
import { on, off } from 'utils/mixins';
import { on, off, getElement } from 'utils/mixins';
const FrameView = require('./FrameView');
const $ = Backbone.$;
@ -23,7 +23,7 @@ module.exports = Backbone.View.extend({
* @return {Boolean}
*/
isElInViewport(el) {
const rect = el.getBoundingClientRect();
const rect = getElement(el).getBoundingClientRect();
const frameRect = this.getFrameOffset(1);
const rTop = rect.top;
const rLeft = rect.left;

24
src/dom_components/index.js

@ -32,6 +32,8 @@
* }
* ...
*/
import { isEmpty } from 'underscore';
module.exports = () => {
var c = {};
let em;
@ -190,6 +192,7 @@ module.exports = () => {
c.am = em.get('AssetManager') || '';
em.get('Parser').compTypes = componentTypes;
em.on('change:selectedComponent', this.componentChanged, this);
em.on('change:componentHovered', this.componentHovered, this);
}
// Build wrapper
@ -525,6 +528,27 @@ module.exports = () => {
});
model && model.set('status', 'selected');
},
/**
* Triggered when the component is hovered
* @private
*/
componentHovered() {
const em = c.em;
const model = em.get('componentHovered');
const previous = em.previous('componentHovered');
const state = 'hovered';
// Deselect the previous component
previous &&
previous.get('status') == state &&
previous.set({
status: '',
state: ''
});
model && isEmpty(model.get('status')) && model.set('status', state);
}
};
};

29
src/dom_components/view/ComponentView.js

@ -98,15 +98,18 @@ module.exports = Backbone.View.extend({
* @param {Event} e
* @private
* */
updateStatus(e) {
var el = this.el;
var status = this.model.get('status');
var pfx = this.pfx;
var ppfx = this.ppfx;
var selectedCls = pfx + 'selected';
var selectedParentCls = selectedCls + '-parent';
var freezedCls = `${ppfx}freezed`;
this.$el.removeClass(`${selectedCls} ${selectedParentCls} ${freezedCls}`);
updateStatus(opts = {}) {
const em = this.em;
const el = this.el;
const status = this.model.get('status');
const pfx = this.pfx;
const ppfx = this.ppfx;
const selectedCls = `${pfx}selected`;
const selectedParentCls = `${selectedCls}-parent`;
const freezedCls = `${ppfx}freezed`;
const hoveredCls = `${ppfx}hovered`;
const toRemove = [selectedCls, selectedParentCls, freezedCls, hoveredCls];
this.$el.removeClass(toRemove.join(' '));
var actualCls = el.getAttribute('class') || '';
var cls = '';
@ -123,13 +126,13 @@ module.exports = Backbone.View.extend({
case 'freezed-selected':
cls = `${actualCls} ${freezedCls} ${selectedCls}`;
break;
case 'hovered':
cls = !opts.avoidHover ? `${actualCls} ${hoveredCls}` : '';
break;
}
cls = cls.trim();
if (cls) {
el.setAttribute('class', cls);
}
cls && el.setAttribute('class', cls);
},
/**

13
src/navigator/config/config.js

@ -18,5 +18,16 @@ module.exports = {
showWrapper: 1,
// Show hovered components in canvas
showHover: 1
showHover: 1,
// Scroll to selected component in Canvas when it's selected in Layers
// true, false or `scrollIntoView`-like options
scrollCanvas: { behavior: 'smooth' },
// Scroll to selected component in Layers when it's selected in Canvas
// true, false or `scrollIntoView`-like options
scrollLayers: 1,
// Highlight when a layer component is hovered
highlightHover: 1
};

8
src/navigator/index.js

@ -63,10 +63,11 @@ module.exports = () => {
* Triggered when the selected component is changed
* @private
*/
componentChanged(e, md, opts = {}) {
componentChanged(selected, opts = {}) {
if (opts.fromLayers) return;
const opened = em.get('opened');
const model = em.getSelected();
const scroll = config.scrollLayers;
let parent = model && model.collection ? model.collection.parent : null;
for (let cid in opened) opened[cid].set('open', 0);
@ -75,6 +76,11 @@ module.exports = () => {
opened[parent.cid] = parent;
parent = parent.collection ? parent.collection.parent : null;
}
if (model && scroll) {
const el = model.viewLayer && model.viewLayer.el;
el && el.scrollIntoView(scroll);
}
},
render() {

16
src/navigator/view/ItemView.js

@ -82,6 +82,7 @@ module.exports = require('backbone').View.extend({
this.clsNoChild = `${pfx}layer-no-chld`;
this.$el.data('model', model);
this.$el.data('collection', components);
model.viewLayer = this;
},
getVisibilityEl() {
@ -196,7 +197,14 @@ module.exports = require('backbone').View.extend({
*/
handleSelect(e) {
e.stopPropagation();
this.em && this.em.setSelected(this.model, { fromLayers: 1 });
const { em, config } = this;
if (em) {
const model = this.model;
em.setSelected(model, { fromLayers: 1 });
const scroll = config.scrollCanvas;
scroll && em.get('Canvas').scrollTo(model, scroll);
}
},
/**
@ -242,7 +250,11 @@ module.exports = require('backbone').View.extend({
* @param Event
* */
updateStatus(e) {
ComponentView.prototype.updateStatus.apply(this, arguments);
ComponentView.prototype.updateStatus.apply(this, [
{
avoidHover: !this.config.highlightHover
}
]);
},
/**

4
src/styles/scss/_gjs_layers.scss

@ -90,6 +90,10 @@
top: 0;
}
&.#{$nv-prefix}hovered .#{$nv-prefix}layer-title {
background-color: rgba(255, 255, 255, 0.015);
}
&.#{$nv-prefix}selected .#{$nv-prefix}layer-title {
background-color: rgba(255, 255, 255, 0.1);
}

16
src/utils/mixins.js

@ -1,4 +1,4 @@
import { omit, keys, isUndefined } from 'underscore';
import { omit, keys, isUndefined, isElement } from 'underscore';
const elProt = window.Element.prototype;
const matches =
@ -97,6 +97,19 @@ const hasDnd = em => {
);
};
/**
* Ensure to fetch the element from the input argument
* @param {HTMLElement|Component} el Component or HTML element
* @return {HTMLElement}
*/
const getElement = el => {
if (isElement(el)) {
return el;
} else if (el.getEl) {
return el.getEl();
}
};
export {
on,
off,
@ -104,6 +117,7 @@ export {
upFirst,
matches,
camelCase,
getElement,
shallowDiff,
normalizeFloat,
getUnitFromValue

Loading…
Cancel
Save