mirror of https://github.com/artf/grapesjs.git
17 changed files with 805 additions and 101 deletions
@ -0,0 +1,31 @@ |
|||
define(function() { |
|||
return { |
|||
|
|||
run: function(editor, sender, opts) { |
|||
var el = (opts && opts.el) || ''; |
|||
var canvas = editor.Canvas; |
|||
var canvasResizer = this.canvasResizer; |
|||
var options = opts.options || {}; |
|||
|
|||
// Create the resizer for the canvas if not yet created
|
|||
if(!canvasResizer) { |
|||
var canvasView = canvas.getCanvasView(); |
|||
options.prefix = editor.getConfig().stylePrefix; |
|||
options.appendTo = canvas.getResizerEl(); |
|||
options.posFetcher = canvasView.getElementPos.bind(canvasView); |
|||
options.mousePosFetcher = canvas.getMouseRelativePos; |
|||
this.canvasResizer = editor.Utils.Resizer.init(options); |
|||
canvasResizer = this.canvasResizer; |
|||
} |
|||
|
|||
canvasResizer.setOptions(options); |
|||
canvasResizer.focus(el); |
|||
}, |
|||
|
|||
stop: function() { |
|||
if(this.canvasResizer) |
|||
this.canvasResizer.blur(); |
|||
}, |
|||
|
|||
}; |
|||
}); |
|||
@ -0,0 +1,392 @@ |
|||
define(function(require) { |
|||
|
|||
var defaults = { |
|||
// Function which returns custom X and Y coordinates of the mouse
|
|||
mousePosFetcher: null, |
|||
// Indicates custom target updating strategy
|
|||
updateTarget: null, |
|||
// Function which gets HTMLElement as an arg and returns it relative position
|
|||
posFetcher: null, |
|||
onStart: null, |
|||
onMove: null, |
|||
onEnd: null, |
|||
tl: 1, |
|||
tc: 1, |
|||
tr: 1, |
|||
cl: 1, |
|||
cr: 1, |
|||
bl: 1, |
|||
bc: 1, |
|||
br: 1, |
|||
}; |
|||
|
|||
var createHandler = function (name, opts) { |
|||
var pfx = opts.prefix || ''; |
|||
var el = this.document.createElement('i'); |
|||
el.className = pfx + 'resizer-h ' + pfx + 'resizer-h-' + name; |
|||
el.setAttribute('data-' + pfx + 'handler', name); |
|||
return el; |
|||
}; |
|||
|
|||
var getBoundingRect = function(el, win) { |
|||
var w = win || window; |
|||
var rect = el.getBoundingClientRect(); |
|||
return { |
|||
left: rect.left + w.pageXOffset, |
|||
top: rect.top + w.pageYOffset, |
|||
width: rect.width, |
|||
height: rect.height |
|||
}; |
|||
}; |
|||
|
|||
return { |
|||
|
|||
/** |
|||
* Init the Resizer with options |
|||
* @param {Object} options |
|||
*/ |
|||
init: function(options) { |
|||
var opts = options || {}; |
|||
var pfx = opts.prefix || ''; |
|||
var appendTo = opts.appendTo || document.body; |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in opts)) |
|||
opts[name] = defaults[name]; |
|||
} |
|||
|
|||
var container = document.createElement('div'); |
|||
container.className = pfx + 'resizer-c'; |
|||
appendTo.appendChild(container); |
|||
|
|||
// Create handlers
|
|||
var handlers = { |
|||
tl: opts.tl ? createHandler('tl', opts) : '', |
|||
tc: opts.tc ? createHandler('tc', opts) : '', |
|||
tr: opts.tr ? createHandler('tr', opts) : '', |
|||
cl: opts.cl ? createHandler('cl', opts) : '', |
|||
cr: opts.cr ? createHandler('cr', opts) : '', |
|||
bl: opts.bl ? createHandler('bl', opts) : '', |
|||
bc: opts.bc ? createHandler('bc', opts) : '', |
|||
br: opts.br ? createHandler('br', opts) : '', |
|||
}; |
|||
|
|||
for (var n in handlers) { |
|||
if(handlers[n]) |
|||
container.appendChild(handlers[n]); |
|||
} |
|||
|
|||
this.container = container; |
|||
this.handlers = handlers; |
|||
this.opts = opts; |
|||
this.handleKeyDown = this.handleKeyDown.bind(this); |
|||
this.handleMouseDown = this.handleMouseDown.bind(this); |
|||
this.move = this.move.bind(this); |
|||
this.stop = this.stop.bind(this); |
|||
this.mousePosFetcher = opts.mousePosFetcher; |
|||
this.updateTarget = opts.updateTarget; |
|||
this.posFetcher = opts.posFetcher; |
|||
this.onStart = opts.onStart; |
|||
this.onMove = opts.onMove; |
|||
this.onEnd = opts.onEnd; |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Update options |
|||
* @param {Object} options |
|||
*/ |
|||
setOptions: function (options) { |
|||
var opts = options || {}; |
|||
|
|||
for (var opt in opts) { |
|||
if(opt in defaults) { |
|||
this[opt] = opts[opt]; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Detects if the passed element is a resize handler |
|||
* @param {HTMLElement} el |
|||
* @return {Boolean} |
|||
*/ |
|||
isHandler: function(el) { |
|||
var handlers = this.handlers; |
|||
|
|||
for (var n in handlers) { |
|||
if (handlers[n] === el) return true; |
|||
} |
|||
|
|||
return false; |
|||
}, |
|||
|
|||
/** |
|||
* Returns the focused element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getFocusedEl: function() { |
|||
return this.el; |
|||
}, |
|||
|
|||
/** |
|||
* Returns documents |
|||
*/ |
|||
getDocumentEl: function() { |
|||
if (!this.$doc) { |
|||
this.$doc = $([this.el.ownerDocument, document]); |
|||
} |
|||
return this.$doc; |
|||
}, |
|||
|
|||
/** |
|||
* Return element position |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
*/ |
|||
getElementPos: function (el) { |
|||
var posFetcher = this.posFetcher || ''; |
|||
return posFetcher ? posFetcher(el) : getBoundingRect(el); |
|||
}, |
|||
|
|||
/** |
|||
* Focus resizer on the element, attaches handlers to it |
|||
* @param {HTMLElement} el |
|||
*/ |
|||
focus: function(el) { |
|||
// Avoid focusing on already focused element
|
|||
if (el && el === this.el) { |
|||
return; |
|||
} |
|||
|
|||
this.el = el; |
|||
var rect = this.getElementPos(el); |
|||
var container = this.container; |
|||
var contStyle = container.style; |
|||
var unit = 'px'; |
|||
contStyle.left = rect.left + unit; |
|||
contStyle.top = rect.top + unit; |
|||
contStyle.width = rect.width + unit; |
|||
contStyle.height = rect.height + unit; |
|||
this.container.style.display = 'block'; |
|||
|
|||
this.getDocumentEl().on('mousedown', this.handleMouseDown); |
|||
}, |
|||
|
|||
/** |
|||
* Blur from element |
|||
*/ |
|||
blur: function () { |
|||
this.container.style.display = 'none'; |
|||
if(this.el) { |
|||
var doc = $([this.el.ownerDocument, document]); |
|||
this.getDocumentEl().off('mousedown', this.handleMouseDown); |
|||
this.el = null; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Start resizing |
|||
* @param {Event} e |
|||
*/ |
|||
start: function(e) { |
|||
//Right or middel click
|
|||
if (e.button !== 0) { |
|||
return; |
|||
} |
|||
e.preventDefault(); |
|||
e.stopPropagation(); |
|||
var opts = this.opts || {}; |
|||
var attrName = 'data-' + opts.prefix + 'handler'; |
|||
var rect = this.getElementPos(this.el); |
|||
this.handlerAttr = e.target.getAttribute(attrName); |
|||
this.clickedHandler = e.target; |
|||
this.startDim = { |
|||
t: rect.top, |
|||
l: rect.left, |
|||
w: rect.width, |
|||
h: rect.height, |
|||
}; |
|||
this.rectDim = { |
|||
t: rect.top, |
|||
l: rect.left, |
|||
w: rect.width, |
|||
h: rect.height, |
|||
}; |
|||
this.startPos = { |
|||
x: e.clientX, |
|||
y: e.clientY |
|||
}; |
|||
|
|||
// Listen events
|
|||
var doc = this.getDocumentEl(); |
|||
doc.on('mousemove', this.move); |
|||
doc.on('keydown', this.handleKeyDown); |
|||
doc.on('mouseup', this.stop); |
|||
this.move(e); |
|||
|
|||
// Start callback
|
|||
if(typeof this.onStart === 'function') { |
|||
this.onStart(e); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* While resizing |
|||
* @param {Event} e |
|||
*/ |
|||
move: function(e) { |
|||
var mouseFetch = this.mousePosFetcher; |
|||
var currentPos = mouseFetch ? mouseFetch(e) : { |
|||
x: e.clientX, |
|||
y: e.clientY |
|||
}; |
|||
|
|||
this.currentPos = currentPos; |
|||
this.delta = { |
|||
x: currentPos.x - this.startPos.x, |
|||
y: currentPos.y - this.startPos.y |
|||
}; |
|||
this.keys = { |
|||
shift: e.shiftKey, |
|||
ctrl: e.ctrlKey, |
|||
alt: e.altKey |
|||
}; |
|||
//console.log('move resizer ', this.currentPos);
|
|||
|
|||
this.rectDim = this.calc(this); |
|||
this.updateRect(0); |
|||
|
|||
// Move callback
|
|||
if(typeof this.onMove === 'function') { |
|||
this.onMove(e); |
|||
} |
|||
|
|||
// In case the mouse button was released outside of the window
|
|||
if (e.which === 0) { |
|||
this.stop(e); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Stop resizing |
|||
* @param {Event} e |
|||
*/ |
|||
stop: function(e) { |
|||
var doc = this.getDocumentEl(); |
|||
doc.off('mousemove', this.move); |
|||
doc.off('keydown', this.handleKeyDown); |
|||
doc.off('mouseup', this.stop); |
|||
this.updateRect(1); |
|||
|
|||
// Stop callback
|
|||
if(typeof this.onEnd === 'function') { |
|||
this.onEnd(e); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Update rect |
|||
*/ |
|||
updateRect: function(store) { |
|||
var elStyle = this.el.style; |
|||
var conStyle = this.container.style; |
|||
var rect = this.rectDim; |
|||
|
|||
// Use custom updating strategy if requested
|
|||
if (typeof this.updateTarget === 'function') { |
|||
this.updateTarget(this.el, rect, store); |
|||
} else { |
|||
elStyle.width = rect.w + 'px'; |
|||
elStyle.height = rect.h + 'px'; |
|||
//elStyle.top = rect.top + 'px';
|
|||
//elStyle.left = rect.left + 'px';
|
|||
} |
|||
|
|||
var rectEl = this.getElementPos(this.el); |
|||
var unit = 'px'; |
|||
conStyle.left = rectEl.left + unit; |
|||
conStyle.top = rectEl.top + unit; |
|||
conStyle.width = rectEl.width + unit; |
|||
conStyle.height = rectEl.height + unit; |
|||
}, |
|||
|
|||
/** |
|||
* Handle ESC key |
|||
* @param {Event} e |
|||
*/ |
|||
handleKeyDown: function (e) { |
|||
if (e.keyCode === 27) { |
|||
// Rollback to initial dimensions
|
|||
this.rectDim = this.startDim; |
|||
this.stop(e); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Handle mousedown to check if it's possible to start resizing |
|||
* @param {Event} e |
|||
*/ |
|||
handleMouseDown: function(e) { |
|||
var el = e.target; |
|||
if (this.isHandler(el)) { |
|||
this.start(e); |
|||
}else if(el !== this.el){ |
|||
this.blur(); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* All positioning logic |
|||
* @return {Object} |
|||
*/ |
|||
calc: function(data) { |
|||
var startDim = this.startDim; |
|||
var box = { |
|||
t: 0, |
|||
l: 0, |
|||
w: startDim.w, |
|||
h: startDim.h |
|||
}; |
|||
|
|||
if (!data) |
|||
return; |
|||
|
|||
var attr = data.handlerAttr; |
|||
if (~attr.indexOf('r')) { |
|||
box.w = Math.max(32, startDim.w + data.delta.x); |
|||
} |
|||
if (~attr.indexOf('b')) { |
|||
box.h = Math.max(32, startDim.h + data.delta.y); |
|||
} |
|||
if (~attr.indexOf('l')) { |
|||
box.w = Math.max(32, startDim.w - data.delta.x); |
|||
} |
|||
if (~attr.indexOf('t')) { |
|||
box.h = Math.max(32, startDim.h - data.delta.y); |
|||
} |
|||
|
|||
// Enforce aspect ratio (unless shift key is being held)
|
|||
if (attr.indexOf('c') < 0 && data.keys.shift) { |
|||
var ratio = startDim.w / startDim.h; |
|||
if (box.w / box.h > ratio) { |
|||
box.h = Math.round(box.w / ratio); |
|||
} else { |
|||
box.w = Math.round(box.h * ratio); |
|||
} |
|||
} |
|||
|
|||
if (~attr.indexOf('l')) { |
|||
box.l = startDim.w - box.w; |
|||
} |
|||
if (~attr.indexOf('t')) { |
|||
box.t = startDim.h - box.h; |
|||
} |
|||
|
|||
return box; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}); |
|||
@ -0,0 +1,168 @@ |
|||
.#{$cv-prefix}canvas { |
|||
background-color: rgba(0, 0, 0, 0.15); |
|||
box-sizing: border-box; |
|||
position: absolute; |
|||
width: (100% - $leftWidth); |
|||
height: 100%; |
|||
bottom: 0; |
|||
left: 0; |
|||
overflow: hidden; |
|||
padding-top: 40px; |
|||
z-index: 1; |
|||
|
|||
> iframe { |
|||
height: 100%; |
|||
outline: medium none; |
|||
width: 100%; |
|||
border: none; |
|||
margin: 0 auto; |
|||
display: block; |
|||
} |
|||
|
|||
.#{$app-prefix}ghost { |
|||
display: none; |
|||
pointer-events: none; |
|||
background-color: #5b5b5b; |
|||
border: 2px dashed #ccc; |
|||
position: absolute; |
|||
z-index: 10; |
|||
|
|||
@include opacity(0.55); |
|||
} |
|||
|
|||
.#{$app-prefix}highlighter, |
|||
.#{$app-prefix}highlighter-sel { |
|||
position: absolute; |
|||
outline: 1px solid $colorBlue; |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.#{$app-prefix}highlighter-warning { |
|||
outline: 3px solid $colorYell; |
|||
} |
|||
|
|||
.#{$app-prefix}highlighter-sel { |
|||
outline: 3px solid $colorBlue; |
|||
} |
|||
|
|||
##{$app-prefix}tools { |
|||
width: 100%; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
outline: none; |
|||
} |
|||
|
|||
/* This simulate body behaviour */ |
|||
> div:first-child { |
|||
background-color: #fff; |
|||
position: relative; |
|||
height: 100%; |
|||
overflow: auto; |
|||
width: 100%; |
|||
} |
|||
} |
|||
|
|||
.#{$cv-prefix}canvas * { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.#{$app-prefix}frame { |
|||
transition: width 0.35s ease; |
|||
} |
|||
|
|||
.#{$app-prefix}toolbar { |
|||
position: absolute; |
|||
background-color: $colorBlue; |
|||
color: white; |
|||
z-index: 10; |
|||
} |
|||
|
|||
.#{$app-prefix}toolbar-item { |
|||
padding: 5px 7px; |
|||
font-size: 0.8rem; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-c { |
|||
@extend .#{$app-prefix}no-pointer-events; |
|||
|
|||
position: absolute; |
|||
z-index: 9; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-h { |
|||
pointer-events: all; |
|||
position: absolute; |
|||
border: 3px solid $colorBlue; |
|||
width: 10px; |
|||
height: 10px; |
|||
background-color: white; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-h-tl { |
|||
top: 0; |
|||
left: 0; |
|||
cursor: nwse-resize; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-h-tr { |
|||
top: 0; |
|||
right: 0; |
|||
cursor: nesw-resize; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-h-tc { |
|||
top: 0; |
|||
margin: 0 auto; |
|||
left: 0; |
|||
right: 0; |
|||
cursor: ns-resize; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-h-cl { |
|||
left: 0; |
|||
margin: auto 0; |
|||
top: 0; |
|||
bottom: 0; |
|||
cursor: ew-resize; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-h-cr { |
|||
margin: auto 0; |
|||
top: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
cursor: ew-resize; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-h-bl { |
|||
bottom: 0; |
|||
left: 0; |
|||
cursor: nesw-resize; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-h-bc { |
|||
bottom: 0; |
|||
margin: 0 auto; |
|||
left: 0; |
|||
right: 0; |
|||
cursor: ns-resize; |
|||
} |
|||
|
|||
.#{$app-prefix}resizer-h-br { |
|||
bottom: 0; |
|||
right: 0; |
|||
cursor: nwse-resize; |
|||
} |
|||
|
|||
.btn-cl { |
|||
@include opacity(0.3); |
|||
|
|||
font-size: 25px; |
|||
cursor: pointer; |
|||
|
|||
&:hover { |
|||
@include opacity(0.7); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue