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