mirror of https://github.com/artf/grapesjs.git
256 changed files with 19595 additions and 6156 deletions
@ -1,5 +1,5 @@ |
|||
language: node_js |
|||
node_js: |
|||
- "4.0" |
|||
- "5.6" |
|||
before_script: |
|||
- npm run build |
|||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -1,52 +1,17 @@ |
|||
define(function () { |
|||
return { |
|||
|
|||
// Style prefix
|
|||
stylePrefix : 'am-', |
|||
|
|||
// Default assets
|
|||
assets : [], |
|||
|
|||
// Indicates which storage to use. Available: local | remote
|
|||
storageType : 'local', |
|||
|
|||
// The name that will be used to identify assets inside storage.
|
|||
// If empty will be used: prefix + 'assets'
|
|||
storageName : 'assets', |
|||
|
|||
// Where store remote assets
|
|||
urlStore : 'http://localhost/assets/store', |
|||
|
|||
// Where fetch remote assets
|
|||
urlLoad : 'http://localhost/assets/load', |
|||
|
|||
// Custom parameters to pass with set request
|
|||
paramsStore : {}, |
|||
assets: [], |
|||
|
|||
// Custom parameters to pass with get request
|
|||
paramsLoad : {}, |
|||
|
|||
// Callback before request
|
|||
beforeSend : function(jqXHR,settings){}, |
|||
|
|||
// Callback after request
|
|||
onComplete : function(jqXHR,status){}, |
|||
// Style prefix
|
|||
stylePrefix: 'am-', |
|||
|
|||
// Url where uploads will be send
|
|||
urlUpload : 'http://localhost/assets/upload', |
|||
upload: 'http://localhost/assets/upload', |
|||
|
|||
// Text on upload input
|
|||
uploadText : 'Drop files here or click to upload', |
|||
|
|||
// Disable upload input
|
|||
disableUpload : false, |
|||
|
|||
// Store assets data where the new one is added or deleted
|
|||
storeOnChange : true, |
|||
|
|||
// It could be useful avoid to send other requests, for saving assets,
|
|||
// after each upload because the uploader script has already done it
|
|||
storeAfterUpload : false, |
|||
uploadText: 'Drop files here or click to upload', |
|||
|
|||
}; |
|||
}); |
|||
@ -1,74 +1,222 @@ |
|||
/** |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [getAll](#getall) |
|||
* * [remove](#remove) |
|||
* * [store](#store) |
|||
* * [load](#load) |
|||
* |
|||
* Before using this methods you should get first the module from the editor instance, in this way: |
|||
* |
|||
* ```js
|
|||
* var assetManager = editor.AssetManager; |
|||
* ``` |
|||
* |
|||
* @module AssetManager |
|||
* @param {Object} config Configurations |
|||
* @param {Array<Object>} [config.assets=[]] Default assets |
|||
* @param {String} [config.uploadText='Drop files here or click to upload'] Upload text |
|||
* @param {String} [config.upload=''] Where to send upload data. Expects as return a JSON with asset/s object |
|||
* as: {data: [{src:'...'}, {src:'...'}]} |
|||
* @return {this} |
|||
* @example |
|||
* ... |
|||
* { |
|||
* assets: [ |
|||
* {src:'path/to/image.png'}, |
|||
* ... |
|||
* ], |
|||
* upload: 'http://dropbox/path', // Set to false to disable it
|
|||
* uploadText: 'Drop files here or click to upload', |
|||
* } |
|||
*/ |
|||
define(function(require) { |
|||
/** |
|||
* @class AssetManager |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
var AssetManager = function(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Assets = require('./model/Assets'), |
|||
AssetsView = require('./view/AssetsView'), |
|||
FileUpload = require('./view/FileUploader'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.assets = new Assets(c.assets); |
|||
var obj = { |
|||
collection : this.assets, |
|||
config : c, |
|||
}; |
|||
|
|||
this.am = new AssetsView(obj); |
|||
this.fu = new FileUpload(obj); |
|||
}; |
|||
return function() { |
|||
var c = {}, |
|||
Assets = require('./model/Assets'), |
|||
AssetsView = require('./view/AssetsView'), |
|||
FileUpload = require('./view/FileUploader'), |
|||
assets, am, fu; |
|||
|
|||
return { |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'AssetManager', |
|||
|
|||
/** |
|||
* Mandatory for the storage manager |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
storageKey: 'assets', |
|||
|
|||
/** |
|||
* Initialize module |
|||
* @param {Object} config Configurations |
|||
* @private |
|||
*/ |
|||
init: function(config){ |
|||
c = config || {}; |
|||
var defaults = require('./config/config'); |
|||
|
|||
AssetManager.prototype = { |
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
var ppfx = c.pStylePrefix; |
|||
if(ppfx) |
|||
c.stylePrefix = ppfx + c.stylePrefix; |
|||
|
|||
assets = new Assets(c.assets); |
|||
var obj = { |
|||
collection: assets, |
|||
config: c, |
|||
}; |
|||
am = new AssetsView(obj); |
|||
fu = new FileUpload(obj); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Get collection of assets |
|||
* Add new asset/s to the collection. URLs are supposed to be unique |
|||
* @param {string|Object|Array<string>|Array<Object>} asset URL strings or an objects representing the resource. |
|||
* @return {Model} |
|||
* @example |
|||
* // In case of strings, would be interpreted as images
|
|||
* assetManager.add('http://img.jpg'); |
|||
* assetManager.add(['http://img.jpg', './path/to/img.png']); |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
getAssets : function(){ |
|||
return this.assets; |
|||
* // Using objects you could indicate the type and other meta informations
|
|||
* assetManager.add({ |
|||
* src: 'http://img.jpg', |
|||
* //type: 'image', //image is default
|
|||
* height: 300, |
|||
* width: 200, |
|||
* }); |
|||
* assetManager.add([{ |
|||
* src: 'http://img.jpg', |
|||
* },{ |
|||
* src: './path/to/img.png', |
|||
* }]); |
|||
*/ |
|||
add: function(asset){ |
|||
return assets.add(asset); |
|||
}, |
|||
|
|||
/** |
|||
* Set new target |
|||
* @param {Object} m Model |
|||
* |
|||
* @return void |
|||
* */ |
|||
setTarget : function(m){ |
|||
this.am.collection.target = m; |
|||
* Returns the asset by URL |
|||
* @param {string} src URL of the asset |
|||
* @return {Object} Object representing the asset |
|||
* @example |
|||
* var asset = assetManager.get('http://img.jpg'); |
|||
*/ |
|||
get: function(src){ |
|||
return assets.where({src: src})[0]; |
|||
}, |
|||
|
|||
/** |
|||
* Set callback after asset was selected |
|||
* @param {Object} f Callback function |
|||
* Return all assets |
|||
* @return {Collection} |
|||
*/ |
|||
getAll: function(){ |
|||
return assets; |
|||
}, |
|||
|
|||
/** |
|||
* Remove the asset by its URL |
|||
* @param {string} src URL of the asset |
|||
* @return {this} |
|||
* @example |
|||
* assetManager.remove('http://img.jpg'); |
|||
*/ |
|||
remove: function(src){ |
|||
var asset = this.get(src); |
|||
this.getAll().remove(asset); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Store assets data to the selected storage |
|||
* @param {Boolean} noStore If true, won't store |
|||
* @return {Object} Data to store |
|||
* @example |
|||
* var assets = assetManager.store(); |
|||
*/ |
|||
store: function(noStore){ |
|||
var obj = {}; |
|||
var assets = JSON.stringify(this.getAll().toJSON()); |
|||
obj[this.storageKey] = assets; |
|||
if(!noStore && c.stm) |
|||
c.stm.store(obj); |
|||
return obj; |
|||
}, |
|||
|
|||
/** |
|||
* Load data from the passed object, if the object is empty will try to fetch them |
|||
* autonomously from the storage manager. |
|||
* The fetched data will be added to the collection |
|||
* @param {Object} data Object of data to load |
|||
* @return {Object} Loaded assets |
|||
* @example |
|||
* var assets = assetManager.load(); |
|||
* // The format below will be used by the editor model
|
|||
* // to load automatically all the stuff
|
|||
* var assets = assetManager.load({ |
|||
* assets: [...] |
|||
* }); |
|||
* |
|||
* @return void |
|||
* */ |
|||
onSelect : function(f){ |
|||
this.am.collection.onSelect = f; |
|||
*/ |
|||
load: function(data){ |
|||
var d = data || ''; |
|||
var name = this.storageKey; |
|||
if(!d && c.stm) |
|||
d = c.stm.load(name); |
|||
var assets = []; |
|||
try{ |
|||
assets = JSON.parse(d[name]); |
|||
}catch(err){} |
|||
this.getAll().add(assets); |
|||
return assets; |
|||
}, |
|||
|
|||
/** |
|||
* Render |
|||
* @param {Boolean} f Force to render |
|||
* Render assets |
|||
* @param {Boolean} f Force to render, otherwise cached version will be returned |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
render : function(f){ |
|||
render: function(f){ |
|||
if(!this.rendered || f) |
|||
this.rendered = this.am.render().$el.add(this.fu.render().$el); |
|||
this.rendered = am.render().$el.add(fu.render().$el); |
|||
return this.rendered; |
|||
}, |
|||
}; |
|||
|
|||
return AssetManager; |
|||
//-------
|
|||
|
|||
/** |
|||
* Set new target |
|||
* @param {Object} m Model |
|||
* @private |
|||
* */ |
|||
setTarget: function(m){ |
|||
am.collection.target = m; |
|||
}, |
|||
|
|||
/** |
|||
* Set callback after asset was selected |
|||
* @param {Object} f Callback function |
|||
* @private |
|||
* */ |
|||
onSelect: function(f){ |
|||
am.collection.onSelect = f; |
|||
}, |
|||
|
|||
}; |
|||
}; |
|||
}); |
|||
@ -1,36 +1,31 @@ |
|||
define(['backbone'], |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class Asset |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
return Backbone.Model.extend({ |
|||
|
|||
idAttribute: 'src', |
|||
|
|||
defaults: { |
|||
type: 'none', //Type of the asset
|
|||
src: '', //Location
|
|||
type: '', |
|||
src: '', |
|||
}, |
|||
|
|||
initialize: function(options) { |
|||
this.options = options || {}; |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* Get filename of the asset |
|||
* |
|||
* @return {String} |
|||
* Get filename of the asset |
|||
* @return {string} |
|||
* @private |
|||
* */ |
|||
getFilename: function(){ |
|||
return this.get('src').split('/').pop(); |
|||
return this.get('src').split('/').pop(); |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* Get extension of the asset |
|||
* |
|||
* @return {String} |
|||
* Get extension of the asset |
|||
* @return {string} |
|||
* @private |
|||
* */ |
|||
getExtension: function(){ |
|||
return this.getFilename().split('.').pop(); |
|||
return this.getFilename().split('.').pop(); |
|||
}, |
|||
|
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,18 +1,13 @@ |
|||
define(['backbone', './Asset'], |
|||
define(['backbone', './Asset'], |
|||
function (Backbone, Asset) { |
|||
/** |
|||
* @class AssetImage |
|||
* */ |
|||
return Asset.extend({ |
|||
|
|||
defaults: _.extend({},Asset.prototype.defaults, |
|||
{ |
|||
type: 'image', |
|||
unitDim: 'px', |
|||
height: 0, |
|||
width: 0, |
|||
} |
|||
), |
|||
|
|||
return Asset.extend({ |
|||
|
|||
defaults: _.extend({}, Asset.prototype.defaults, { |
|||
type: 'image', |
|||
unitDim: 'px', |
|||
height: 0, |
|||
width: 0, |
|||
}), |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,11 +1,67 @@ |
|||
define(['backbone','./Asset'], |
|||
function (Backbone, Asset) { |
|||
/** |
|||
* @class Assets |
|||
* */ |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Asset, |
|||
|
|||
define(['backbone', './Asset', './AssetImage'], |
|||
function (Backbone, Asset, AssetImage) { |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: AssetImage, |
|||
|
|||
initialize: function(models, opt){ |
|||
|
|||
this.model = function(attrs, options) { |
|||
var model; |
|||
switch(attrs.type){ |
|||
default: |
|||
model = new AssetImage(attrs, options); |
|||
} |
|||
return model; |
|||
}; |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* Add new image asset to the collection |
|||
* @param {string} url URL of the image |
|||
* @param {Object} opts Options |
|||
* @return {this} |
|||
* @private |
|||
*/ |
|||
addImg: function(url, opts){ |
|||
this.add({ |
|||
type: 'image', |
|||
src: url, |
|||
}, opts); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Prevent inserting assets with the same 'src' |
|||
* Seems like idAttribute is not working with dynamic model assignament |
|||
* @private |
|||
*/ |
|||
add: function(models, opt) { |
|||
var mods = []; |
|||
models = models instanceof Array ? models : [models]; |
|||
|
|||
for (var i = 0, len = models.length; i < len; i++) { |
|||
var model = models[i]; |
|||
|
|||
if(typeof model === 'string') |
|||
model = {src: model, type: 'image'}; |
|||
|
|||
if(!model || !model.src) |
|||
continue; |
|||
|
|||
var found = this.where({src: model.src}); |
|||
|
|||
if(!found.length) |
|||
mods.push(model); |
|||
} |
|||
|
|||
if(mods.length == 1) |
|||
mods = mods[0]; |
|||
|
|||
return Backbone.Collection.prototype.add.apply(this, [mods, opt]); |
|||
}, |
|||
|
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -0,0 +1,15 @@ |
|||
<div class="<%= pfx %>assets-cont"> |
|||
<div class="<%= pfx %>assets-header"> |
|||
<form id="login-form" class="<%= pfx %>add-asset"> |
|||
<input class="<%= ppfx %>input" placeholder="http://path/to/the/image.jpg" /> |
|||
<button class="<%= ppfx %>btn-prim">Add image</button> |
|||
<div style="clear:both"></div> |
|||
</form> |
|||
<div class="<%= pfx %>dips" style="display:none"> |
|||
<button class="fa fa-th <%= ppfx %>btnt"></button> |
|||
<button class="fa fa-th-list <%= ppfx %>btnt"></button> |
|||
</div> |
|||
</div> |
|||
<div class="<%= pfx %>assets"></div> |
|||
<div style="clear:both"></div> |
|||
</div> |
|||
@ -0,0 +1,7 @@ |
|||
define(function () { |
|||
return { |
|||
|
|||
'blocks': [], |
|||
|
|||
}; |
|||
}); |
|||
@ -0,0 +1,122 @@ |
|||
/** |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [getAll](#getall) |
|||
* * [render](#render) |
|||
* |
|||
* Block manager helps managing various, draggable, piece of contents that could be easily reused inside templates. |
|||
* |
|||
* Before using methods you should get first the module from the editor instance, in this way: |
|||
* |
|||
* ```js
|
|||
* var blockManager = editor.BlockManager; |
|||
* ``` |
|||
* |
|||
* @module BlockManager |
|||
* @param {Object} config Configurations |
|||
* @param {Array<Object>} [config.blocks=[]] Default blocks |
|||
* @example |
|||
* ... |
|||
* { |
|||
* blocks: [ |
|||
* {id:'h1-block' label: 'Heading', content:'<h1>...</h1>'}, |
|||
* ... |
|||
* ], |
|||
* } |
|||
* ... |
|||
*/ |
|||
define(function(require) { |
|||
|
|||
return function() { |
|||
var c = {}, |
|||
defaults = require('./config/config'), |
|||
Blocks = require('./model/Blocks'), |
|||
BlocksView = require('./view/BlocksView'); |
|||
var blocks, view; |
|||
|
|||
return { |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'BlockManager', |
|||
|
|||
/** |
|||
* Initialize module. Automatically called with a new instance of the editor |
|||
* @param {Object} config Configurations |
|||
* @return {this} |
|||
* @private |
|||
*/ |
|||
init: function(config) { |
|||
c = config || {}; |
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
blocks = new Blocks(c.blocks); |
|||
view = new BlocksView({ collection: blocks }, c); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Add new block to the collection. |
|||
* @param {string} id Block id |
|||
* @param {Object} opts Options |
|||
* @param {string} opts.label Name of the block |
|||
* @param {string} opts.content HTML content |
|||
* @param {Object} [opts.attributes={}] Block attributes |
|||
* @return {Block} Added block |
|||
* @example |
|||
* blockManager.add('h1-block', { |
|||
* label: 'Heading', |
|||
* content: '<h1>Put your title here</h1>', |
|||
* attributes: { |
|||
* title: 'Insert h1 block' |
|||
* } |
|||
* }); |
|||
*/ |
|||
add: function(id, opts){ |
|||
var obj = opts || {}; |
|||
obj.id = id; |
|||
return blocks.add(obj); |
|||
}, |
|||
|
|||
/** |
|||
* Return block by id |
|||
* @param {string} id Block id |
|||
* @example |
|||
* var block = blockManager.get('h1-block'); |
|||
* console.log(JSON.stringify(block)); |
|||
* // {label: 'Heading', content: '<h1>Put your ...', ...}
|
|||
*/ |
|||
get: function(id){ |
|||
return blocks.get(id); |
|||
}, |
|||
|
|||
/** |
|||
* Return all blocks |
|||
* @return {Collection} |
|||
* @example |
|||
* var blocks = blockManager.getAll(); |
|||
* console.log(JSON.stringify(blocks)); |
|||
* // [{label: 'Heading', content: '<h1>Put your ...'}, ...]
|
|||
*/ |
|||
getAll: function(){ |
|||
return blocks; |
|||
}, |
|||
|
|||
/** |
|||
* Render blocks |
|||
* @return {HTMLElement} |
|||
*/ |
|||
render: function(){ |
|||
return view.render().el; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
|
|||
}); |
|||
@ -0,0 +1,13 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
|
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
label: '', |
|||
content: '', |
|||
attributes: {}, |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,9 @@ |
|||
define(['backbone','./Block'], |
|||
function (Backbone, Block) { |
|||
|
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Block, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,48 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
|
|||
return Backbone.View.extend({ |
|||
|
|||
events: { |
|||
mousedown: 'onDrag' |
|||
}, |
|||
|
|||
initialize: function(o, config) { |
|||
_.bindAll(this, 'onDrop'); |
|||
this.config = config || {}; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.listenTo(this.model, 'destroy', this.remove); |
|||
this.doc = $(document); |
|||
}, |
|||
|
|||
/** |
|||
* Start block dragging |
|||
* @private |
|||
*/ |
|||
onDrag: function(){ |
|||
if(!this.config.getSorter) |
|||
return; |
|||
var sorter = this.config.getSorter(); |
|||
//this.config.dragHelper(this.el.cloneNode(1));
|
|||
sorter.startSort(this.el); |
|||
sorter.setDropContent(this.model.get('content')); |
|||
this.doc.on('mouseup', this.onDrop); |
|||
}, |
|||
|
|||
/** |
|||
* Drop block |
|||
* @private |
|||
*/ |
|||
onDrop: function(){ |
|||
this.doc.off('mouseup', this.onDrop); |
|||
this.config.getSorter().endMove(); |
|||
}, |
|||
|
|||
render: function() { |
|||
this.el.innerHTML = this.model.get('label'); |
|||
this.$el.addClass(this.ppfx + 'block'); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,140 @@ |
|||
define(['backbone', './BlockView'], |
|||
function(Backbone, BlockView) { |
|||
|
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(opts, config) { |
|||
_.bindAll(this, 'getSorter', 'onDrag', 'onDrop', 'dragHelper', 'moveHelper'); |
|||
this.config = config || {}; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.listenTo(this.collection, 'add', this.addTo); |
|||
this.em = this.config.em; |
|||
this.tac = 'test-tac'; |
|||
|
|||
if(this.em){ |
|||
this.config.getSorter = this.getSorter; |
|||
this.config.dragHelper = this.dragHelper; |
|||
this.canvas = this.em.get('Canvas'); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Get sorter |
|||
* @private |
|||
*/ |
|||
getSorter: function(){ |
|||
if(!this.em) |
|||
return; |
|||
if(!this.sorter){ |
|||
var utils = this.em.get('Utils'); |
|||
var canvas = this.canvas; |
|||
this.sorter = new utils.Sorter({ |
|||
container: canvas.getBody(), |
|||
placer: canvas.getPlacerEl(), |
|||
containerSel: '*', |
|||
itemSel: '*', |
|||
pfx: this.ppfx, |
|||
onStart: this.onDrag, |
|||
onEndMove: this.onDrop, |
|||
document: canvas.getFrameEl().contentDocument, |
|||
direction: 'a', |
|||
wmargin: 1, |
|||
nested: 1, |
|||
em: this.em |
|||
}); |
|||
} |
|||
return this.sorter; |
|||
}, |
|||
/* |
|||
updateOffset: function(){ |
|||
if(!this.sorter) |
|||
return; |
|||
var sorter = this.sorter; |
|||
var offDim = this.canvas.getOffset(); |
|||
sorter.offTop = offDim.top; |
|||
sorter.offLeft = offDim.left; |
|||
}, |
|||
*/ |
|||
/** |
|||
* Callback when block is on drag |
|||
* @private |
|||
*/ |
|||
onDrag: function(){ |
|||
this.em.stopDefault(); |
|||
this.em.get('Canvas').getBody().style.cursor = 'grabbing'; |
|||
document.body.style.cursor = 'grabbing'; |
|||
}, |
|||
|
|||
dragHelper: function(el){ |
|||
el.className += ' ' + this.ppfx + 'bdrag'; |
|||
this.helper = el; |
|||
document.body.appendChild(el); |
|||
$(this.em.get('Canvas').getBody()).on('mousemove', this.moveHelper); |
|||
$(document).on('mousemove', this.moveHelper); |
|||
}, |
|||
|
|||
moveHelper: function(e){ |
|||
this.helper.style.left = e.pageX + 'px'; |
|||
this.helper.style.top = e.pageY + 'px'; |
|||
}, |
|||
|
|||
/** |
|||
* Callback when block is dropped |
|||
* @private |
|||
*/ |
|||
onDrop: function(model){ |
|||
this.em.runDefault(); |
|||
this.em.get('Canvas').getBody().style.cursor = ''; |
|||
document.body.style.cursor = ''; |
|||
if(model && model.get('activeOnRender')){ |
|||
model.trigger('active'); |
|||
model.set('activeOnRender', 0); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Add new model to the collection |
|||
* @param {Model} model |
|||
* @private |
|||
* */ |
|||
addTo: function(model){ |
|||
this.add(model); |
|||
}, |
|||
|
|||
/** |
|||
* Render new model inside the view |
|||
* @param {Model} model |
|||
* @param {Object} fragment Fragment collection |
|||
* @private |
|||
* */ |
|||
add: function(model, fragment){ |
|||
var frag = fragment || null; |
|||
var view = new BlockView({ |
|||
model: model, |
|||
attributes: model.get('attributes'), |
|||
}, this.config); |
|||
var rendered = view.render().el; |
|||
|
|||
if(frag) |
|||
frag.appendChild(rendered); |
|||
else |
|||
this.$el.append(rendered); |
|||
}, |
|||
|
|||
|
|||
|
|||
render: function() { |
|||
var frag = document.createDocumentFragment(); |
|||
this.$el.empty(); |
|||
|
|||
this.collection.each(function(model){ |
|||
this.add(model, frag); |
|||
}, this); |
|||
|
|||
this.$el.append(frag); |
|||
this.$el.addClass(this.ppfx + 'blocks-c'); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -1,10 +1,10 @@ |
|||
define(function () { |
|||
return { |
|||
|
|||
stylePrefix : 'cv-', |
|||
|
|||
|
|||
stylePrefix: 'cv-', |
|||
|
|||
// Coming soon
|
|||
rulers : false, |
|||
|
|||
rulers: false, |
|||
|
|||
}; |
|||
}); |
|||
@ -1,60 +1,185 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class Canvas |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* @class Canvas} |
|||
* */ |
|||
var Canvas = function(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Canvas = require('./model/Canvas'), |
|||
CanvasView = require('./view/CanvasView'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.canvas = new Canvas(config); |
|||
var obj = { |
|||
model : this.canvas, |
|||
config : c, |
|||
}; |
|||
|
|||
this.CanvasView = new CanvasView(obj); |
|||
}; |
|||
|
|||
Canvas.prototype = { |
|||
return function() { |
|||
var c = {}, |
|||
defaults = require('./config/config'), |
|||
Canvas = require('./model/Canvas'), |
|||
CanvasView = require('./view/CanvasView'); |
|||
var canvas; |
|||
|
|||
return { |
|||
|
|||
/** |
|||
* Used inside RTE |
|||
* @private |
|||
*/ |
|||
getCanvasView: function() { |
|||
return CanvasView; |
|||
}, |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'Canvas', |
|||
|
|||
/** |
|||
* Initialize module. Automatically called with a new instance of the editor |
|||
* @param {Object} config Configurations |
|||
*/ |
|||
init: function(config) { |
|||
c = config || {}; |
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
var ppfx = c.pStylePrefix; |
|||
if(ppfx) |
|||
c.stylePrefix = ppfx + c.stylePrefix; |
|||
|
|||
canvas = new Canvas(config); |
|||
CanvasView = new CanvasView({ |
|||
model: canvas, |
|||
config: c, |
|||
}); |
|||
|
|||
var cm = c.em.get('DomComponents'); |
|||
if(cm) |
|||
this.setWrapper(cm); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Add wrapper |
|||
* @param {Object} wrp Wrapper |
|||
* |
|||
* |
|||
* */ |
|||
setWrapper : function(wrp) |
|||
{ |
|||
this.canvas.set('wrapper', wrp); |
|||
setWrapper: function(wrp) { |
|||
canvas.set('wrapper', wrp); |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* Get wrapper |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
getWrapper : function() |
|||
{ |
|||
return this.canvas.get('wrapper').getComponent(); |
|||
* Returns canvas element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getElement: function(){ |
|||
return CanvasView.el; |
|||
}, |
|||
|
|||
/** |
|||
* Returns frame element of the canvas |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getFrameEl: function(){ |
|||
return CanvasView.frame.el; |
|||
}, |
|||
|
|||
/** |
|||
* Returns body element of the frame |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getBody: function(){ |
|||
return CanvasView.frame.el.contentDocument.body; |
|||
}, |
|||
|
|||
/** |
|||
* Returns body wrapper element of the frame |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getWrapperEl: function(){ |
|||
return this.getBody().querySelector('#wrapper'); |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* Returns element containing canvas tools |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getToolsEl: function(){ |
|||
return CanvasView.toolsEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns highlighter element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getHighlighter: function(){ |
|||
return CanvasView.hlEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns badge element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getBadgeEl: function(){ |
|||
return CanvasView.badgeEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns placer element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getPlacerEl: function(){ |
|||
return CanvasView.placerEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns ghost element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getGhostEl: function(){ |
|||
return CanvasView.ghostEl; |
|||
}, |
|||
|
|||
/** |
|||
* Render canvas |
|||
* */ |
|||
render : function() |
|||
{ |
|||
return this.CanvasView.render().$el; |
|||
render: function() { |
|||
return CanvasView.render().el; |
|||
}, |
|||
|
|||
/** |
|||
* Get frame position |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getOffset: function() { |
|||
var frameOff = this.offset(this.getFrameEl()); |
|||
var canvasOff = this.offset(this.getElement()); |
|||
return { |
|||
top: frameOff.top - canvasOff.top, |
|||
left: frameOff.left - canvasOff.left |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Get the offset of the element |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
offset: function(el){ |
|||
var rect = el.getBoundingClientRect(); |
|||
return { |
|||
top: rect.top + document.body.scrollTop, |
|||
left: rect.left + document.body.scrollLeft |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Returns wrapper element |
|||
* @return {HTMLElement} |
|||
* ???? |
|||
*/ |
|||
getFrameWrapperEl: function(){ |
|||
return CanvasView.frame.getWrapper(); |
|||
}, |
|||
}; |
|||
}; |
|||
|
|||
return Canvas; |
|||
|
|||
}); |
|||
@ -1,14 +1,18 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
/** |
|||
* @class Canvas |
|||
* */ |
|||
define(['backbone', './Frame'], |
|||
function(Backbone, Frame){ |
|||
|
|||
return Backbone.Model.extend({ |
|||
|
|||
|
|||
defaults :{ |
|||
wrapper : '', |
|||
rulers : false, |
|||
frame: '', |
|||
wrapper: '', |
|||
rulers: false, |
|||
}, |
|||
|
|||
|
|||
initialize: function(config) { |
|||
var conf = this.conf || {}; |
|||
this.set('frame', new Frame(conf.frame)); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -0,0 +1,14 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
|
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
wrapper: '', |
|||
width: '', |
|||
height: '', |
|||
attributes: {}, |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -1,25 +1,159 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
define(['backbone','./FrameView'], |
|||
function(Backbone, FrameView) { |
|||
/** |
|||
* @class CanvasView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
//id: 'canvas',
|
|||
|
|||
|
|||
initialize: function(o) { |
|||
this.config = o.config; |
|||
_.bindAll(this, 'renderBody', 'onFrameScroll', 'clearOff'); |
|||
this.config = o.config || {}; |
|||
this.em = this.config.em || {}; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.className = this.config.stylePrefix + 'canvas'; |
|||
this.listenTo(this.em, 'change:canvasOffset', this.clearOff); |
|||
this.frame = new FrameView({ |
|||
model: this.model.get('frame'), |
|||
config: this.config |
|||
}); |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* Update tools position |
|||
* @private |
|||
*/ |
|||
onFrameScroll: function(){ |
|||
var u = 'px'; |
|||
var body = this.frame.el.contentDocument.body; |
|||
this.toolsEl.style.top = '-' + body.scrollTop + u; |
|||
this.toolsEl.style.left = '-' + body.scrollLeft + u; |
|||
}, |
|||
|
|||
/** |
|||
* Render inside frame's body |
|||
* @private |
|||
*/ |
|||
renderBody: function(){ |
|||
var wrap = this.model.get('frame').get('wrapper'); |
|||
if(wrap){ |
|||
var body = this.frame.$el.contents().find('body'); |
|||
var cssc = this.config.em.get('CssComposer'); |
|||
var conf = this.config.em.get('Config'); |
|||
body.append(wrap.render()).append(cssc.render()); |
|||
var protCss = conf.protectedCss; |
|||
var frameCss = '.' + this.ppfx + 'dashed *{outline: 1px dashed rgba(170,170,170,0.7); outline-offset: -2px}' + |
|||
'.' + this.ppfx + 'comp-selected{outline: 3px solid #3b97e3 !important}' + |
|||
'.' + this.ppfx + 'no-select{user-select: none; -webkit-user-select:none; -moz-user-select: none}'+ |
|||
'.' + this.ppfx + 'freezed{opacity: 0.5; pointer-events: none}' + |
|||
'.' + this.ppfx + 'plh-image{background:#f5f5f5; border:none; height:50px; width:50px; display:block; outline:3px solid #ffca6f; cursor:pointer}'; |
|||
if(protCss) |
|||
body.append('<style>' + frameCss + protCss + '</style>'); |
|||
this.config.em.trigger('loaded'); |
|||
this.frame.el.contentWindow.onscroll = this.onFrameScroll; |
|||
this.frame.udpateOffset(); |
|||
|
|||
// When the iframe is focused the event dispatcher is not the same so
|
|||
// I need to delegate all events to the parent document
|
|||
var doc = document; |
|||
var fdoc = this.frame.el.contentDocument; |
|||
fdoc.addEventListener('keydown', function(e){ |
|||
doc.dispatchEvent(new KeyboardEvent(e.type, e)); |
|||
}); |
|||
fdoc.addEventListener('keyup', function(e){ |
|||
doc.dispatchEvent(new KeyboardEvent(e.type, e)); |
|||
}); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Get the offset of the element |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
*/ |
|||
offset: function(el){ |
|||
var rect = el.getBoundingClientRect(); |
|||
var docBody = el.ownerDocument.body; |
|||
return { |
|||
top: rect.top + docBody.scrollTop, |
|||
left: rect.left + docBody.scrollLeft |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Cleare cached offsets |
|||
* @private |
|||
*/ |
|||
clearOff: function(){ |
|||
this.frmOff = null; |
|||
this.cvsOff = null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns element's data info |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getElementPos: function(el){ |
|||
if(!this.frmOff) |
|||
this.frmOff = this.offset(this.frame.el); |
|||
if(!this.cvsOff) |
|||
this.cvsOff = this.offset(this.el); |
|||
var eo = this.offset(el); |
|||
var top = eo.top + this.frmOff.top - this.cvsOff.top; |
|||
var left = eo.left + this.frmOff.left - this.cvsOff.left; |
|||
return { |
|||
top: top, |
|||
left: left, |
|||
height: el.offsetHeight, |
|||
width: el.offsetWidth |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Returns position data of the canvas element |
|||
* @return {Object} obj Position object |
|||
*/ |
|||
getPosition: function() { |
|||
var bEl = this.frame.el.contentDocument.body; |
|||
var fo = this.frmOff; |
|||
var co = this.cvsOff; |
|||
return { |
|||
top: fo.top + bEl.scrollTop - co.top, |
|||
left: fo.left + bEl.scrollLeft - co.left |
|||
}; |
|||
}, |
|||
|
|||
|
|||
render: function() { |
|||
this.wrapper = this.model.get('wrapper'); |
|||
|
|||
if(this.wrapper && typeof this.wrapper.render == 'function'){ |
|||
this.$el.append( this.wrapper.render() ); |
|||
this.model.get('frame').set('wrapper', this.wrapper); |
|||
this.$el.append(this.frame.render().el); |
|||
var frame = this.frame; |
|||
frame.el.onload = this.renderBody; |
|||
} |
|||
this.$el.attr({class: this.className, id: this.config.canvasId}); |
|||
this.toolsEl = $('<div>', { id: this.ppfx + 'tools' }).get(0); |
|||
this.hlEl = $('<div>', { class: this.ppfx + 'highlighter' }).get(0); |
|||
this.badgeEl = $('<div>', {class: this.ppfx + 'badge'}).get(0); |
|||
this.placerEl = $('<div>', {class: this.ppfx + 'placeholder'}).get(0); |
|||
this.placerIntEl = $('<div>', {class: this.ppfx + 'placeholder-int'}).get(0); |
|||
this.ghostEl = $('<div>', {class: this.ppfx + 'ghost'}).get(0); |
|||
this.placerEl.appendChild(this.placerIntEl); |
|||
this.toolsEl.appendChild(this.hlEl); |
|||
this.toolsEl.appendChild(this.badgeEl); |
|||
this.toolsEl.appendChild(this.placerEl); |
|||
this.toolsEl.appendChild(this.ghostEl); |
|||
this.$el.append(this.toolsEl); |
|||
var rte = this.em.get('rte'); |
|||
|
|||
if(rte) |
|||
this.toolsEl.appendChild(rte.render()); |
|||
|
|||
this.$el.attr({class: this.className}); |
|||
return this; |
|||
}, |
|||
|
|||
|
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
@ -0,0 +1,54 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
/** |
|||
* @class CanvasView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
tagName: 'iframe', |
|||
|
|||
attributes: { |
|||
src: 'about:blank' |
|||
}, |
|||
|
|||
initialize: function(o) { |
|||
_.bindAll(this, 'udpateOffset'); |
|||
this.config = o.config || {}; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.em = this.config.em; |
|||
this.motionsEv = 'transitionend oTransitionEnd transitionend webkitTransitionEnd'; |
|||
this.listenTo(this.em, 'change:device', this.updateWidth); |
|||
}, |
|||
|
|||
/** |
|||
* Update width of the frame |
|||
* @private |
|||
*/ |
|||
updateWidth: function(model){ |
|||
var device = this.em.getDeviceModel(); |
|||
this.el.style.width = device ? device.get('width') : ''; |
|||
this.udpateOffset(); |
|||
this.$el.on(this.motionsEv, this.udpateOffset); |
|||
}, |
|||
|
|||
udpateOffset: function(){ |
|||
var offset = this.em.get('Canvas').getOffset(); |
|||
this.em.set('canvasOffset', offset); |
|||
this.$el.off(this.motionsEv, this.udpateOffset); |
|||
}, |
|||
|
|||
getBody: function(){ |
|||
this.$el.contents().find('body'); |
|||
}, |
|||
|
|||
getWrapper: function(){ |
|||
return this.$el.contents().find('body > div'); |
|||
}, |
|||
|
|||
render: function() { |
|||
this.$el.attr({class: this.ppfx + 'frame'}); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -1,63 +0,0 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class ClassManager |
|||
* @param {Object} config Configurations |
|||
* |
|||
* */ |
|||
var ClassManager = function(config) |
|||
{ |
|||
var c = config || {}, |
|||
def = require('./config/config'); |
|||
this.ClassTags = require('./model/ClassTags'); |
|||
this.ClassTagsView = require('./view/ClassTagsView'); |
|||
|
|||
for (var name in def) { |
|||
if (!(name in c)) |
|||
c[name] = def[name]; |
|||
} |
|||
|
|||
this.classes = new this.ClassTags(c.defaults); |
|||
this.config = c; |
|||
}; |
|||
|
|||
ClassManager.prototype = { |
|||
|
|||
/** |
|||
* Add new class to collection only if it's not already exists |
|||
* @param {String} name Class name |
|||
* |
|||
* @return {Object} Model class |
|||
* */ |
|||
addClass: function(name){ |
|||
var label = name; |
|||
var c = this.getClass(name); |
|||
if(!c) |
|||
return this.classes.add({name: name, label: label}); |
|||
return c; |
|||
}, |
|||
|
|||
/** |
|||
* Get class by its name |
|||
* @param {String} id Class name |
|||
* |
|||
* @return {Object|null} |
|||
* */ |
|||
getClass : function(id) { |
|||
var res = this.classes.where({name: id}); |
|||
return res.length ? res[0] : null; |
|||
}, |
|||
|
|||
/** |
|||
* Get collection of classes |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
getClasses : function() { |
|||
return this.classes; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
return ClassManager; |
|||
|
|||
}); |
|||
@ -1,29 +0,0 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class ClassTag |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
label: '', |
|||
name: '', |
|||
active: true, |
|||
}, |
|||
|
|||
initialize: function(){ |
|||
this.set('name', this.escapeName(this.get('name'))); |
|||
}, |
|||
|
|||
/** |
|||
* Escape string |
|||
* @param {String} name |
|||
* |
|||
* @return {String} |
|||
*/ |
|||
escapeName: function(name) { |
|||
return name.toLowerCase().replace(/([^a-z0-9\w]+)/gi, '-'); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -1,11 +0,0 @@ |
|||
define(['backbone','./ClassTag'], |
|||
function (Backbone, ClassTag) { |
|||
/** |
|||
* @class ClassTags |
|||
* */ |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: ClassTag, |
|||
|
|||
}); |
|||
}); |
|||
@ -1,3 +0,0 @@ |
|||
<span id="<%= pfx %>checkbox" class="fa"></span> |
|||
<span id="<%= pfx %>tag-label"><%= label %></span> |
|||
<span id="<%= pfx %>close">⨯</span> |
|||
@ -1,254 +1,225 @@ |
|||
/** |
|||
* - [addGenerator](#addgenerator) |
|||
* - [getGenerator](#getgenerator) |
|||
* - [getGenerators](#getgenerators) |
|||
* - [addViewer](#addviewer) |
|||
* - [getViewer](#getviewer) |
|||
* - [getViewers](#getviewers) |
|||
* - [updateViewer](#updateviewer) |
|||
* - [getCode](#getcode) |
|||
* |
|||
* |
|||
* Before using methods you should get first the module from the editor instance, in this way: |
|||
* |
|||
* ```js
|
|||
* var codeManager = editor.CodeManager; |
|||
* ``` |
|||
* |
|||
* @module CodeManager |
|||
*/ |
|||
define(function(require) { |
|||
/** |
|||
* @class CodeManager |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function CodeManager(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
gInterface = require('./model/GeneratorInterface'), |
|||
gHtml = require('./model/HtmlGenerator'), |
|||
gCss = require('./model/CssGenerator'), |
|||
gJson = require('./model/JsonGenerator'), |
|||
eInterface = require('./model/EditorInterface'), |
|||
eCM = require('./model/CodeMirrorEditor'), |
|||
editorView = require('./view/EditorView'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.gi = new gInterface(); |
|||
this.generators = {}; |
|||
this.defaultGenerators = {}; |
|||
this.currentGenerator = null; |
|||
|
|||
this.ei = new eInterface(); |
|||
this.editors = {}; |
|||
this.defaultEditors = {}; |
|||
this.currentEditor = null; |
|||
|
|||
var geHtml = new gHtml(), |
|||
geCss = new gCss(), |
|||
geJson = new gJson(), |
|||
edCM = new eCM(); |
|||
|
|||
this.defaultGenerators[geHtml.getId()] = geHtml; |
|||
this.defaultGenerators[geCss.getId()] = geCss; |
|||
this.defaultGenerators[geJson.getId()] = geJson; |
|||
|
|||
this.defaultEditors[edCM.getId()] = edCM; |
|||
|
|||
this.EditorView = editorView; |
|||
this.config = c; |
|||
} |
|||
|
|||
CodeManager.prototype = { |
|||
|
|||
/** |
|||
* Add new code generator |
|||
* @param {GeneratorInterface} generator |
|||
* |
|||
* @return this |
|||
* */ |
|||
addGenerator : function(generator) |
|||
{ |
|||
// Check interface implementation
|
|||
for (var method in this.gi) |
|||
if(!generator[method]){ |
|||
console.warn("addGenerator: method '"+ method +"' was not found"); |
|||
return; |
|||
} |
|||
var CodeManager = function() { |
|||
|
|||
var id = generator.getId(); |
|||
this.generators[id] = generator; |
|||
var c = {}, |
|||
defaults = require('./config/config'), |
|||
gHtml = require('./model/HtmlGenerator'), |
|||
gCss = require('./model/CssGenerator'), |
|||
gJson = require('./model/JsonGenerator'), |
|||
eCM = require('./model/CodeMirrorEditor'), |
|||
editorView = require('./view/EditorView'); |
|||
|
|||
if(!this.currentGenerator) |
|||
this.currentGenerator = id; |
|||
var generators = {}, |
|||
defGenerators = {}, |
|||
viewers = {}, |
|||
defViewers = {}; |
|||
|
|||
return this; |
|||
return { |
|||
|
|||
getConfig: function() { |
|||
return c; |
|||
}, |
|||
|
|||
/** |
|||
* Returns generator |
|||
* @param {String}|{Integer} id Generator ID |
|||
* |
|||
* @return {GeneratorInterface}|null |
|||
* */ |
|||
getGenerator : function(id) |
|||
{ |
|||
if(id && this.generators[id]) |
|||
generator = this.generators[id]; |
|||
config: c, |
|||
|
|||
return generator ? generator : null; |
|||
}, |
|||
EditorView: editorView, |
|||
|
|||
/** |
|||
* Returns generators |
|||
* |
|||
* @return {Array} |
|||
* */ |
|||
getGenerators : function() |
|||
{ |
|||
return this.generators; |
|||
}, |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'CodeManager', |
|||
|
|||
/** |
|||
* Initialize module. Automatically called with a new instance of the editor |
|||
* @param {Object} config Configurations |
|||
*/ |
|||
init: function(config) { |
|||
c = config || {}; |
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
var ppfx = c.pStylePrefix; |
|||
if(ppfx) |
|||
c.stylePrefix = ppfx + c.stylePrefix; |
|||
|
|||
defGenerators.html = new gHtml(); |
|||
defGenerators.css = new gCss(); |
|||
defGenerators.json = new gJson(); |
|||
|
|||
defViewers.CodeMirror = new eCM(); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Callback on load |
|||
*/ |
|||
onLoad: function(){ |
|||
this.loadDefaultGenerators().loadDefaultViewers(); |
|||
}, |
|||
|
|||
/** |
|||
* Get current generator |
|||
* |
|||
* @return {GeneratorInterface} |
|||
* Add new code generator to the collection |
|||
* @param {string} id Code generator ID |
|||
* @param {Object} generator Code generator wrapper |
|||
* @param {Function} generator.build Function that builds the code |
|||
* @return {this} |
|||
* @example |
|||
* codeManager.addGenerator('html7',{ |
|||
* build: function(model){ |
|||
* return 'myCode'; |
|||
* } |
|||
* }); |
|||
* */ |
|||
getCurrentGenerator : function() |
|||
{ |
|||
if(!this.currentGenerator) |
|||
this.loadDefaultGenerators(); |
|||
return this.getGenerator(this.currentGenerator); |
|||
addGenerator: function(id, generator) { |
|||
generators[id] = generator; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Set current generator |
|||
* @param {Integer} id Generator ID |
|||
* |
|||
* @return this |
|||
* Get code generator by id |
|||
* @param {string} id Code generator ID |
|||
* @return {Object|null} |
|||
* @example |
|||
* var generator = codeManager.getGenerator('html7'); |
|||
* generator.build = function(model){ |
|||
* //extend
|
|||
* }; |
|||
* */ |
|||
setCurrentGenerator : function(id) |
|||
{ |
|||
this.currentGenerator = id; |
|||
return this; |
|||
getGenerator: function(id) { |
|||
return generators[id] || null; |
|||
}, |
|||
|
|||
/** |
|||
* Load default generators |
|||
* |
|||
* @return this |
|||
* Returns all code generators |
|||
* @return {Array<Object>} |
|||
* */ |
|||
loadDefaultGenerators : function() |
|||
{ |
|||
for (var id in this.defaultGenerators) { |
|||
this.addGenerator(this.defaultGenerators[id]); |
|||
} |
|||
|
|||
return this; |
|||
getGenerators: function() { |
|||
return generators; |
|||
}, |
|||
|
|||
/** |
|||
* Add new editor |
|||
* @param {EditorInterface} editor |
|||
* |
|||
* @return this |
|||
* Add new code viewer |
|||
* @param {string} id Code viewer ID |
|||
* @param {Object} viewer Code viewer wrapper |
|||
* @param {Function} viewer.init Set element on which viewer will be displayed |
|||
* @param {Function} viewer.setContent Set content to the viewer |
|||
* @return {this} |
|||
* @example |
|||
* codeManager.addViewer('ace',{ |
|||
* init: function(el){ |
|||
* var ace = require('ace-editor'); |
|||
* this.editor = ace.edit(el.id); |
|||
* }, |
|||
* setContent: function(code){ |
|||
* this.editor.setValue(code); |
|||
* } |
|||
* }); |
|||
* */ |
|||
addEditor : function(editor) |
|||
{ |
|||
// Check interface implementation
|
|||
for (var method in this.ei) |
|||
if(!editor[method]){ |
|||
console.warn("addEditor: method '"+ method +"' was not found"); |
|||
return; |
|||
} |
|||
|
|||
var id = editor.getId(); |
|||
this.editors[id] = editor; |
|||
|
|||
if(!this.currentEditor) |
|||
this.currentEditor = id; |
|||
|
|||
addViewer: function(id, viewer) { |
|||
viewers[id] = viewer; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns editor |
|||
* @param {String}|{Integer} id Editor ID |
|||
* |
|||
* @return {EditorInterface}|null |
|||
* Get code viewer by id |
|||
* @param {string} id Code viewer ID |
|||
* @return {Object|null} |
|||
* @example |
|||
* var viewer = codeManager.getViewer('ace'); |
|||
* */ |
|||
getEditor : function(id) |
|||
{ |
|||
if(id && this.editors[id]) |
|||
editor = this.editors[id]; |
|||
|
|||
return editor ? editor : null; |
|||
getViewer: function(id) { |
|||
return viewers[id] || null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns editors |
|||
* |
|||
* @return {Array} |
|||
* Returns all code viewers |
|||
* @return {Array<Object>} |
|||
* */ |
|||
getEditors : function() |
|||
{ |
|||
return this.editors; |
|||
getViewers: function() { |
|||
return viewers; |
|||
}, |
|||
|
|||
/** |
|||
* Get current editor |
|||
* |
|||
* @return {EditorInterface} |
|||
* Update code viewer content |
|||
* @param {Object} viewer Viewer instance |
|||
* @param {string} code Code string |
|||
* @example |
|||
* var AceViewer = codeManager.getViewer('ace'); |
|||
* // ...
|
|||
* var viewer = AceViewer.init(el); |
|||
* // ...
|
|||
* codeManager.updateViewer(AceViewer, 'code'); |
|||
* */ |
|||
getCurrentEditor : function() |
|||
{ |
|||
if(!this.currentEditor) |
|||
this.loadDefaultEditors(); |
|||
return this.getEditor(this.currentEditor); |
|||
updateViewer: function(viewer, code) { |
|||
viewer.setContent(code); |
|||
}, |
|||
|
|||
/** |
|||
* Set current editor |
|||
* @param {Integer} id Editor ID |
|||
* |
|||
* @return this |
|||
* Get code from model |
|||
* @param {Object} model Any kind of model that will be passed to the build method of generator |
|||
* @param {string} genId Code generator id |
|||
* @param {Object} [opt] Options |
|||
* @return {string} |
|||
* @example |
|||
* var codeStr = codeManager.getCode(model, 'html'); |
|||
* */ |
|||
setCurrentEditor : function(id) |
|||
{ |
|||
this.currentEditor = id; |
|||
return this; |
|||
getCode: function(model, genId, opt) { |
|||
var generator = this.getGenerator(genId); |
|||
return generator ? generator.build(model, opt) : ''; |
|||
}, |
|||
|
|||
/** |
|||
* Load default editors |
|||
* |
|||
* @return this |
|||
* Load default code generators |
|||
* @return {this} |
|||
* @private |
|||
* */ |
|||
loadDefaultEditors : function() |
|||
{ |
|||
for (var id in this.defaultEditors) { |
|||
this.addEditor(this.defaultEditors[id]); |
|||
} |
|||
loadDefaultGenerators: function() { |
|||
for (var id in defGenerators) |
|||
this.addGenerator(id, defGenerators[id]); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Get code by name |
|||
* @param {Backbone.Model} model Model |
|||
* @param {String}|{Integer} v Id of code generator |
|||
* |
|||
* @return {String}|null |
|||
* Load default code viewers |
|||
* @return {this} |
|||
* @private |
|||
* */ |
|||
getCode : function(model, v, em) |
|||
{ |
|||
var id = v || this.currentGenerator, |
|||
generator = this.generators[id]; |
|||
return generator ? generator.build(model, em) : null; |
|||
}, |
|||
loadDefaultViewers: function() { |
|||
for (var id in defViewers) |
|||
this.addViewer(id, defViewers[id]); |
|||
|
|||
/** |
|||
* Update editor content |
|||
* @param {EditorInteface} editor Editor |
|||
* @param {String} code Code value |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateEditor : function(editor, code) |
|||
{ |
|||
editor.setContent(code); |
|||
return this; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
|
|||
return CodeManager; |
|||
|
|||
}); |
|||
@ -1,31 +0,0 @@ |
|||
define(function() { |
|||
/** |
|||
* @class EditorInterface |
|||
* */ |
|||
function EditorInterface() {} |
|||
|
|||
EditorInterface.prototype = { |
|||
|
|||
/** |
|||
* Get id |
|||
* |
|||
* @return {String}|{Integer} |
|||
* */ |
|||
getId : function(){}, |
|||
|
|||
/** |
|||
* Set content |
|||
* @param {String} str |
|||
* |
|||
* */ |
|||
setContent : function(str){}, |
|||
|
|||
/** |
|||
* Init editor |
|||
* @param {Object} el DOM element |
|||
* */ |
|||
init : function(el){}, |
|||
}; |
|||
|
|||
return EditorInterface; |
|||
}); |
|||
@ -1,26 +0,0 @@ |
|||
define(function() { |
|||
/** |
|||
* @class GeneratorInterface |
|||
* */ |
|||
function GeneratorInterface() {} |
|||
|
|||
GeneratorInterface.prototype = { |
|||
|
|||
/** |
|||
* Get id |
|||
* |
|||
* @return {String}|{Integer} |
|||
* */ |
|||
getId : function(){}, |
|||
|
|||
/** |
|||
* Generate code from model |
|||
* @param {Backbone.Model} model |
|||
* |
|||
* @return {String} |
|||
* */ |
|||
build : function(model){}, |
|||
}; |
|||
|
|||
return GeneratorInterface; |
|||
}); |
|||
@ -0,0 +1,86 @@ |
|||
define(function() { |
|||
|
|||
return { |
|||
/** |
|||
* Check if fullscreen mode is enabled |
|||
* @return {Boolean} |
|||
*/ |
|||
isEnabled: function(){ |
|||
var d = document; |
|||
if(d.fullscreenElement || d.webkitFullscreenElement || d.mozFullScreenElement) |
|||
return 1; |
|||
else |
|||
return 0; |
|||
}, |
|||
|
|||
/** |
|||
* Enable fullscreen mode and return browser prefix |
|||
* @param {HTMLElement} el |
|||
* @return {string} |
|||
*/ |
|||
enable: function(el){ |
|||
var pfx = ''; |
|||
if (el.requestFullscreen) |
|||
el.requestFullscreen(); |
|||
else if (el.webkitRequestFullscreen) { |
|||
pfx = 'webkit'; |
|||
el.webkitRequestFullscreen(); |
|||
}else if (el.mozRequestFullScreen) { |
|||
pfx = 'moz'; |
|||
el.mozRequestFullScreen(); |
|||
}else if (el.msRequestFullscreen) |
|||
el.msRequestFullscreen(); |
|||
else |
|||
console.warn('Fullscreen not supported'); |
|||
return pfx; |
|||
}, |
|||
|
|||
/** |
|||
* Disable fullscreen mode |
|||
*/ |
|||
disable: function(){ |
|||
var d = document; |
|||
if (d.exitFullscreen) |
|||
d.exitFullscreen(); |
|||
else if (d.webkitExitFullscreen) |
|||
d.webkitExitFullscreen(); |
|||
else if (d.mozCancelFullScreen) |
|||
d.mozCancelFullScreen(); |
|||
else if (d.msExitFullscreen) |
|||
d.msExitFullscreen(); |
|||
}, |
|||
|
|||
/** |
|||
* Triggered when the state of the fullscreen is changed. Inside detects if |
|||
* it's enabled |
|||
* @param {strinf} pfx Browser prefix |
|||
* @param {Event} e |
|||
*/ |
|||
fsChanged: function(pfx, e){ |
|||
var d = document; |
|||
var ev = (pfx || '') + 'fullscreenchange'; |
|||
if(!this.isEnabled()){ |
|||
this.stop(null, this.sender); |
|||
document.removeEventListener(ev, this.fsChanged); |
|||
} |
|||
}, |
|||
|
|||
run: function(editor, sender){ |
|||
this.sender = sender; |
|||
var pfx = this.enable(editor.getContainer()); |
|||
this.fsChanged = this.fsChanged.bind(this, pfx); |
|||
document.addEventListener(pfx + 'fullscreenchange', this.fsChanged); |
|||
if(editor) |
|||
editor.trigger('change:canvasOffset'); |
|||
}, |
|||
|
|||
stop: function(editor, sender){ |
|||
if(sender && sender.set) |
|||
sender.set('active', false); |
|||
this.disable(); |
|||
if(editor) |
|||
editor.trigger('change:canvasOffset'); |
|||
} |
|||
|
|||
}; |
|||
}); |
|||
@ -1,185 +1,113 @@ |
|||
define(['backbone', './SelectComponent','./SelectPosition'], |
|||
function(Backbone, SelectComponent, SelectPosition) { |
|||
/** |
|||
* @class MoveComponent |
|||
* */ |
|||
return _.extend({},SelectComponent, SelectPosition,{ |
|||
|
|||
return _.extend({}, SelectPosition, SelectComponent, { |
|||
|
|||
init: function(o){ |
|||
SelectComponent.init.apply(this, arguments); |
|||
_.bindAll(this,'startMove','onMove','endMove','rollback','selectingPosition','itemLeft'); |
|||
this.opt = o; |
|||
this.hoverClass = this.pfx + 'hover-move'; |
|||
this.badgeClass = this.pfx + 'badge-yellow'; |
|||
this.noSelClass = this.pfx + 'no-select'; |
|||
_.bindAll(this, 'initSorter','rollback', 'onEndMove'); |
|||
this.opt = o; |
|||
this.hoverClass = this.ppfx + 'highlighter-warning'; |
|||
this.badgeClass = this.ppfx + 'badge-warning'; |
|||
this.noSelClass = this.ppfx + 'no-select'; |
|||
}, |
|||
|
|||
enable: function(){ |
|||
this.canvasTop = this.$canvas.offset().top; |
|||
this.canvasLeft = this.$canvas.offset().left; |
|||
this.$el.css('cursor','move'); |
|||
this.$el.on('mousedown', this.startMove); |
|||
this.startSelectComponent(); |
|||
|
|||
//Avoid strange moving behavior
|
|||
this.$el.addClass(this.noSelClass); |
|||
SelectComponent.enable.apply(this, arguments); |
|||
this.getBadgeEl().addClass(this.badgeClass); |
|||
this.getHighlighterEl().addClass(this.hoverClass); |
|||
var wp = this.$wrapper; |
|||
wp.css('cursor','move'); |
|||
wp.on('mousedown', this.initSorter); |
|||
|
|||
// Avoid strange moving behavior
|
|||
wp.addClass(this.noSelClass); |
|||
}, |
|||
|
|||
/** |
|||
* Hover command |
|||
* @param {Object} e |
|||
* Overwrite for doing nothing |
|||
* @private |
|||
*/ |
|||
onHover: function(e) |
|||
{ |
|||
e.stopPropagation(); |
|||
toggleClipboard: function(){}, |
|||
|
|||
var $this = $(e.target); |
|||
if($this.data('model').get('movable')){ //Show badge if possible
|
|||
$this.addClass(this.hoverClass); |
|||
this.attachBadge(e.target); |
|||
} |
|||
}, |
|||
|
|||
/** Say what to do after the component was selected |
|||
* - Method from selectComponent |
|||
* @param Event |
|||
* @param Object Selected element |
|||
* */ |
|||
onSelect: function(e,el){}, |
|||
|
|||
/** Picking component to move |
|||
* @param event |
|||
/** |
|||
* Delegate sorting |
|||
* @param {Event} e |
|||
* @private |
|||
* */ |
|||
startMove: function(e, el){ |
|||
this.moved = false; |
|||
if( !$(e.target).data('model').get('movable') ){ return; } //In case the component selected is not movable
|
|||
this.$el.off('mousedown', this.startMove); |
|||
this.stopSelectComponent(e); |
|||
this.$selectedEl = $(e.target); |
|||
this.freezeComponent(this.$selectedEl); |
|||
this.helperObj = $('<div>', {class: "tempComp"}).css({ //HELPER gray box
|
|||
top : (e.pageY - this.canvasTop) + this.$canvas.scrollTop(), |
|||
left: (e.pageX - this.canvasLeft) + this.$canvas.scrollLeft(), |
|||
width: $(e.target).width(), |
|||
height: $(e.target).height(), |
|||
position : 'absolute', |
|||
'pointer-events': 'none', //disable events for the element
|
|||
}).data('helper',1).appendTo(this.$el); |
|||
|
|||
this.startSelectPosition(); |
|||
|
|||
this.$el.on('mousemove',this.onMove); |
|||
$(document).on('mouseup',this.endMove); |
|||
$(document).on('keypress',this.rollback); |
|||
}, |
|||
|
|||
/** During move |
|||
* @param event */ |
|||
onMove: function(e){ |
|||
this.moved = true; |
|||
var relativeY = (e.pageY - this.canvasTop) + this.$canvas.scrollTop(); |
|||
var relativeX = (e.pageX - this.canvasLeft) + this.$canvas.scrollLeft(); |
|||
this.helperObj[0].style.top = (relativeY)+'px'; |
|||
this.helperObj[0].style.left = (relativeX)+'px'; |
|||
initSorter: function(e){ |
|||
var el = $(e.target).data('model'); |
|||
if(!el.get('draggable')) |
|||
return; |
|||
// Avoid badge showing on move
|
|||
this.cacheEl = null; |
|||
this.startSelectPosition(e.target, this.frameEl.contentDocument); |
|||
this.sorter.onEndMove = this.onEndMove.bind(this); |
|||
this.stopSelectComponent(); |
|||
this.$wrapper.off('mousedown', this.initSorter); |
|||
this.getContentWindow().on('keydown', this.rollback); |
|||
}, |
|||
|
|||
/** Leave component |
|||
* @param event */ |
|||
endMove: function(e){ |
|||
this.$el.off('mousemove',this.onMove); |
|||
$(document).off('mouseup', this.endMove); |
|||
$(document).off('keypress', this.rollback); |
|||
this.helperObj.remove(); |
|||
|
|||
this.removePositionPlaceholder(); |
|||
this.stopSelectPosition(); |
|||
|
|||
//this.highlightComponent(e,el) after end of move
|
|||
if(this.moved) |
|||
this.move(null, this.$selectedEl, this.posIndex, this.posMethod); |
|||
this.unfreezeComponent(this.$selectedEl); |
|||
/** |
|||
* Callback after sorting |
|||
* @private |
|||
*/ |
|||
onEndMove: function(){ |
|||
this.enable(); |
|||
this.getContentWindow().off('keydown', this.rollback); |
|||
}, |
|||
|
|||
/** Move component to new position |
|||
* @param object Component to move |
|||
* @param object Target component |
|||
* @param int Indicates the position inside the collection |
|||
* @param string Before of after component |
|||
* |
|||
* @return void |
|||
* */ |
|||
move: function(target, el, posIndex, posMethod){ |
|||
var index = posIndex || 0; |
|||
var model = el.data("model"); |
|||
var collection = model.collection; |
|||
|
|||
var targetCollection = this.posTargetCollection; |
|||
var targetModel = this.posTargetModel; |
|||
|
|||
if(targetCollection && targetModel.get('droppable')){ |
|||
var modelTemp = targetCollection.add({css:{}}, { at: index }); |
|||
var modelRemoved = collection.remove(model); |
|||
targetCollection.add(modelRemoved, { at: index }); |
|||
targetCollection.remove(modelTemp);//{ avoidStore: 1 }
|
|||
}else |
|||
console.warn("Invalid target position"); |
|||
}, |
|||
|
|||
/** Make component untouchable |
|||
* @param object Component |
|||
* @return void |
|||
* */ |
|||
freezeComponent: function($component){ |
|||
$component.css({'pointer-events':'none'}); |
|||
$component.addClass('freezed'); |
|||
}, |
|||
|
|||
/** Make component touchable |
|||
* @param object Component |
|||
* @return void |
|||
/** |
|||
* Say what to do after the component was selected (selectComponent) |
|||
* @param {Event} e |
|||
* @param {Object} Selected element |
|||
* @private |
|||
* */ |
|||
unfreezeComponent: function($component){ |
|||
$component.css({'pointer-events':'auto'}); |
|||
$component.removeClass('freezed'); |
|||
}, |
|||
onSelect: function(e,el){}, |
|||
|
|||
/** Used to bring the previous situation before start moving the component |
|||
* @param Event |
|||
* @param Bool Indicates if rollback in anycase |
|||
* @return void |
|||
/** |
|||
* Used to bring the previous situation before start moving the component |
|||
* @param {Event} e |
|||
* @param {Boolean} Indicates if rollback in anycase |
|||
* @private |
|||
* */ |
|||
rollback: function(e, force){ |
|||
var key = e.which || e.keyCode; |
|||
if(key == this.opt.ESCAPE_KEY || force){ |
|||
this.moved = false; |
|||
this.endMove(); |
|||
this.sorter.moved = false; |
|||
this.sorter.endMove(); |
|||
} |
|||
return; |
|||
}, |
|||
|
|||
/** Closing method |
|||
* */ |
|||
last: function(){ |
|||
this.placeholder.remove(); |
|||
this.placeholderStart.remove(); |
|||
this.helperObj.remove(); |
|||
this.$el.off('mousemove',this.move); |
|||
$(document).off('mouseup', this.endMove); |
|||
$(document).off('keypress', this.rollback); |
|||
/** |
|||
* Returns badge element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getBadgeEl: function(){ |
|||
if(!this.$badge) |
|||
this.$badge = $(this.getBadge()); |
|||
return this.$badge; |
|||
}, |
|||
|
|||
/* Run method */ |
|||
run: function(){ |
|||
this.enable(); |
|||
/** |
|||
* Returns highlighter element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getHighlighterEl: function(){ |
|||
if(!this.$hl) |
|||
this.$hl = $(this.canvas.getHighlighter()); |
|||
return this.$hl; |
|||
}, |
|||
|
|||
/* Stop method */ |
|||
stop: function(){ |
|||
this.stopSelectComponent(); |
|||
this.$el.css('cursor','');//changes back aspect of the cursor
|
|||
this.$el.unbind();//removes all attached events
|
|||
this.$el.removeClass(this.noSelClass); |
|||
SelectComponent.stop.apply(this, arguments); |
|||
this.getBadgeEl().removeClass(this.badgeClass); |
|||
this.getHighlighterEl().removeClass(this.hoverClass); |
|||
var wp = this.$wrapper; |
|||
wp.css('cursor', '').unbind().removeClass(this.noSelClass); |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,28 @@ |
|||
define(function() { |
|||
|
|||
return { |
|||
|
|||
run: function(editor, sender) { |
|||
var config = editor.Config; |
|||
var pfx = config.stylePrefix; |
|||
var bm = editor.BlockManager; |
|||
if(!this.blocks){ |
|||
this.blocks = $('<div/>').get(0); |
|||
this.blocks.appendChild(bm.render()); |
|||
var panels = editor.Panels; |
|||
if(!panels.getPanel('views-container')) |
|||
panelC = panels.addPanel({id: 'views-container'}); |
|||
else |
|||
panelC = panels.getPanel('views-container'); |
|||
panelC.set('appendContent', this.blocks).trigger('change:appendContent'); |
|||
} |
|||
|
|||
this.blocks.style.display = 'block'; |
|||
}, |
|||
|
|||
stop: function() { |
|||
if(this.blocks) |
|||
this.blocks.style.display = 'none'; |
|||
} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,32 @@ |
|||
define(function() { |
|||
|
|||
return { |
|||
|
|||
run: function(editor, sender) { |
|||
var config = editor.Config; |
|||
var pfx = config.stylePrefix; |
|||
var tm = editor.TraitManager; |
|||
if(!this.obj){ |
|||
var tmView = tm.getTraitsViewer(); |
|||
var confTm = tm.getConfig(); |
|||
this.obj = $('<div/>') |
|||
.append('<div class="'+pfx+'traits-label">' + confTm.labelContainer + '</div>') |
|||
.get(0); |
|||
this.obj.appendChild(tmView.render().el); |
|||
var panels = editor.Panels; |
|||
if(!panels.getPanel('views-container')) |
|||
panelC = panels.addPanel({id: 'views-container'}); |
|||
else |
|||
panelC = panels.getPanel('views-container'); |
|||
panelC.set('appendContent', this.obj).trigger('change:appendContent'); |
|||
} |
|||
|
|||
this.obj.style.display = 'block'; |
|||
}, |
|||
|
|||
stop: function() { |
|||
if(this.obj) |
|||
this.obj.style.display = 'none'; |
|||
} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,54 @@ |
|||
define(function() { |
|||
|
|||
return { |
|||
|
|||
getPanels: function(editor){ |
|||
if(!this.panels) |
|||
this.panels = editor.Panels.getPanelsEl(); |
|||
return this.panels; |
|||
}, |
|||
|
|||
run: function(editor, sender) { |
|||
if(sender) |
|||
sender.set('active',false); |
|||
editor.stopCommand('sw-visibility'); |
|||
var that = this; |
|||
var panels = this.getPanels(editor); |
|||
var canvas = editor.Canvas.getElement(); |
|||
var editorEl = editor.getEl(); |
|||
var pfx = editor.Config.stylePrefix; |
|||
if(!this.helper) { |
|||
this.helper = document.createElement('span'); |
|||
this.helper.className = pfx + 'off-prv fa fa-eye-slash'; |
|||
editorEl.appendChild(this.helper); |
|||
this.helper.onclick = function(){ |
|||
that.stop(editor); |
|||
}; |
|||
} |
|||
this.helper.style.display = 'inline-block'; |
|||
|
|||
panels.style.display = 'none'; |
|||
var canvasS = canvas.style; |
|||
canvasS.width = '100%'; |
|||
canvasS.height = '100%'; |
|||
canvasS.top = '0'; |
|||
canvasS.left = '0'; |
|||
canvasS.padding = '0'; |
|||
canvasS.margin = '0'; |
|||
editor.trigger('change:canvasOffset'); |
|||
}, |
|||
|
|||
stop: function(editor, sender) { |
|||
var panels = this.getPanels(editor); |
|||
editor.runCommand('sw-visibility'); |
|||
editor.getModel().runDefault(); |
|||
panels.style.display = 'block'; |
|||
var canvas = editor.Canvas.getElement(); |
|||
canvas.setAttribute('style', ''); |
|||
if(this.helper) { |
|||
this.helper.style.display = 'none'; |
|||
} |
|||
editor.trigger('change:canvasOffset'); |
|||
} |
|||
}; |
|||
}); |
|||
@ -1,59 +0,0 @@ |
|||
define(['backbone', 'jqueryUi', './MoveComponent'], |
|||
function(Backbone, jqueryUi, MoveComponent) { |
|||
/** |
|||
* @class ResizeComponent |
|||
* */ |
|||
return _.extend({}, MoveComponent,{ |
|||
|
|||
enable: function(){ |
|||
var $this = this; |
|||
this.startSelectComponent(); |
|||
this.$el.find('*').resizable({ |
|||
containment: 'parent', |
|||
start: function(event,ui){ |
|||
ui.element[0].style.height = ui.element.height()+'px'; |
|||
ui.element.css({'min-height':'', 'min-width':'' }); |
|||
}, |
|||
stop: function(event,ui){ |
|||
ui.element.css('overflow','auto'); |
|||
$this.updateModel(ui); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* Update model of resized element |
|||
* @param object Component model |
|||
* */ |
|||
updateModel: function(el){ |
|||
var um = 'px', |
|||
model = el.element.data("model"), |
|||
style = _.clone(model.get('style')); |
|||
delete style['min-height']; |
|||
delete style['min-width']; |
|||
style.height = el.size.height + um; |
|||
style.width = el.size.width + um; |
|||
style.overflow = 'auto'; |
|||
model.set('style', style); |
|||
}, |
|||
|
|||
/** |
|||
* Run method |
|||
* */ |
|||
run: function(){ |
|||
this.enable(); |
|||
this.active = true; |
|||
}, |
|||
|
|||
/** |
|||
* Stop method |
|||
* */ |
|||
stop: function(){ |
|||
this.stopSelectComponent(); |
|||
this.$el.find('.ui-resizable').resizable("destroy"); |
|||
this.$el.unbind();//removes all attached events
|
|||
this.active = false; |
|||
} |
|||
}); |
|||
}); |
|||
@ -1,205 +1,302 @@ |
|||
define(function() { |
|||
/** |
|||
* @class SelectComponent |
|||
* @private |
|||
* */ |
|||
return { |
|||
|
|||
init: function(o){ |
|||
_.bindAll(this, 'onHover', 'onOut', 'onClick'); |
|||
_.bindAll(this, 'onHover', 'onOut', 'onClick', 'onKeyPress'); |
|||
}, |
|||
|
|||
enable: function() |
|||
{ |
|||
_.bindAll(this,'copyComp','pasteComp'); |
|||
var confMain = this.config.em.get('Config'); |
|||
|
|||
enable: function() { |
|||
_.bindAll(this, 'copyComp', 'pasteComp', 'onFrameScroll'); |
|||
this.frameOff = this.canvasOff = this.adjScroll = null; |
|||
var config = this.config.em.get('Config'); |
|||
this.startSelectComponent(); |
|||
if(confMain.copyPaste){ |
|||
this.toggleClipboard(config.copyPaste); |
|||
}, |
|||
|
|||
/** |
|||
* Toggle clipboard function |
|||
* @param {Boolean} active |
|||
* @return {this} |
|||
* @private |
|||
*/ |
|||
toggleClipboard: function(active){ |
|||
var en = active || 0; |
|||
if(en){ |
|||
key('⌘+c, ctrl+c', this.copyComp); |
|||
key('⌘+v, ctrl+v', this.pasteComp); |
|||
}else{ |
|||
key.unbind('⌘+c, ctrl+c'); |
|||
key.unbind('⌘+v, ctrl+v'); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Copy component to clipboard |
|||
* Copy component to the clipboard |
|||
* @private |
|||
*/ |
|||
copyComp: function() |
|||
{ |
|||
var sel = this.editorModel.get('selectedComponent'); |
|||
|
|||
if(sel && sel.get('copyable')) |
|||
this.editorModel.set('clipboard', sel); |
|||
copyComp: function() { |
|||
var el = this.editorModel.get('selectedComponent'); |
|||
if(el && el.get('copyable')) |
|||
this.editorModel.set('clipboard', el); |
|||
}, |
|||
|
|||
/** |
|||
* Paste component from clipboard |
|||
* @private |
|||
*/ |
|||
pasteComp: function() |
|||
{ |
|||
var clp = this.editorModel.get('clipboard'), |
|||
sel = this.editorModel.get('selectedComponent'); |
|||
if(clp && sel && sel.collection){ |
|||
var index = sel.collection.indexOf(sel), |
|||
clone = clp.clone(); |
|||
sel.collection.add(clone, { at: index + 1 }); |
|||
} |
|||
pasteComp: function() { |
|||
var clp = this.editorModel.get('clipboard'), |
|||
sel = this.editorModel.get('selectedComponent'); |
|||
if(clp && sel && sel.collection){ |
|||
var index = sel.collection.indexOf(sel), |
|||
clone = clp.clone(); |
|||
sel.collection.add(clone, { at: index + 1 }); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Start select component event |
|||
* @private |
|||
* */ |
|||
startSelectComponent: function() { |
|||
this.selEl = $(this.getCanvasBody()).find('*'); |
|||
this.selEl.on('mouseover', this.onHover) |
|||
.on('mouseout', this.onOut) |
|||
.on('click', this.onClick); |
|||
var cw = this.getContentWindow(); |
|||
cw.on('scroll', this.onFrameScroll); |
|||
cw.on('keydown', this.onKeyPress); |
|||
}, |
|||
|
|||
/** |
|||
* Stop select component event |
|||
* @private |
|||
* */ |
|||
stopSelectComponent: function() { |
|||
if(this.selEl) |
|||
this.selEl.trigger('mouseout').off('mouseover', this.onHover) |
|||
.off('mouseout', this.onOut) |
|||
.off('click', this.onClick); |
|||
this.selEl = null; |
|||
var cw = this.getContentWindow(); |
|||
cw.off('scroll', this.onFrameScroll); |
|||
cw.off('keydown', this.onKeyPress); |
|||
}, |
|||
|
|||
/** Start select component event |
|||
* @return void |
|||
/** |
|||
* On key press event |
|||
* @private |
|||
* */ |
|||
startSelectComponent: function(){ |
|||
var that = this; |
|||
this.$el.find('*') |
|||
.on('mouseover',this.onHover) |
|||
.on('mouseout', this.onOut) |
|||
.on('click', this.onClick); |
|||
this.selEl = this.$el.find('*'); |
|||
onKeyPress: function(e) { |
|||
var key = e.which || e.keyCode; |
|||
var comp = this.editorModel.get('selectedComponent'); |
|||
var focused = this.frameEl.contentDocument.activeElement.tagName !== 'BODY'; |
|||
if(key == 8 || key == 46) { |
|||
if(!focused) |
|||
e.preventDefault(); |
|||
if(comp && !focused){ |
|||
if(!comp.get('removable')) |
|||
return; |
|||
comp.set('status',''); |
|||
comp.destroy(); |
|||
this.hideBadge(); |
|||
this.clean(); |
|||
this.editorModel.set('selectedComponent',null); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Hover command |
|||
* @param {Object} e |
|||
* @private |
|||
*/ |
|||
onHover: function(e) |
|||
{ |
|||
onHover: function(e) { |
|||
e.stopPropagation(); |
|||
$(e.target).addClass(this.hoverClass); |
|||
this.attachBadge(e.target); |
|||
var trg = e.target; |
|||
// Adjust tools scroll top
|
|||
if(!this.adjScroll){ |
|||
this.adjScroll = 1; |
|||
this.onFrameScroll(e); |
|||
} |
|||
var pos = this.getElementPos(trg); |
|||
this.updateBadge(trg, pos); |
|||
this.updateHighlighter(trg, pos); |
|||
}, |
|||
|
|||
/** |
|||
* Out command |
|||
* @param {Object} e |
|||
* @private |
|||
*/ |
|||
onOut: function(e) |
|||
{ |
|||
onOut: function(e) { |
|||
e.stopPropagation(); |
|||
$(e.target).removeClass(this.hoverClass); |
|||
if(this.badge) |
|||
this.badge.css({ left: -10000, top:-10000 }); |
|||
this.hideBadge(); |
|||
if(this.hl) |
|||
this.hl.css({ left: -10000, top:-10000 }); |
|||
}, |
|||
|
|||
/** |
|||
* Hover command |
|||
* @param {Object} e |
|||
* @private |
|||
*/ |
|||
onClick: function(e) |
|||
{ |
|||
var s = $(e.target).data('model').get('stylable'); |
|||
onClick: function(e) { |
|||
var m = $(e.target).data('model'); |
|||
if(!m) |
|||
return; |
|||
var s = m.get('stylable'); |
|||
if(!(s instanceof Array) && !s) |
|||
return; |
|||
this.onSelect(e, e.target); |
|||
}, |
|||
|
|||
/** Stop select component event |
|||
* @param Event |
|||
* @return void |
|||
/** |
|||
* Update badge for the component |
|||
* @param {Object} Component |
|||
* @param {Object} pos Position object |
|||
* @private |
|||
* */ |
|||
stopSelectComponent: function(e){ |
|||
if(this.selEl) |
|||
this.selEl.trigger('mouseout').off('mouseover mouseout click'); |
|||
this.selEl = null; |
|||
updateBadge: function(el, pos) { |
|||
var $el = $(el); |
|||
this.cacheEl = el; |
|||
var model = $el.data("model"); |
|||
if(!model || !model.get('badgable')) |
|||
return; |
|||
var badge = this.getBadge(); |
|||
badge.innerHTML = model.getName(); |
|||
var bStyle = badge.style; |
|||
var u = 'px'; |
|||
bStyle.display = 'block'; |
|||
var canvasPos = this.canvas.getCanvasView().getPosition(); |
|||
var badgeH = badge ? badge.offsetHeight : 0; |
|||
var badgeW = badge ? badge.offsetWidth : 0; |
|||
var top = pos.top - badgeH < canvasPos.top ? canvasPos.top : pos.top - badgeH; |
|||
var left = pos.left + badgeW < canvasPos.left ? canvasPos.left : pos.left; |
|||
bStyle.top = top + u; |
|||
bStyle.left = left + u; |
|||
}, |
|||
|
|||
/** |
|||
* Update highlighter element |
|||
* @param {HTMLElement} el |
|||
* @param {Object} pos Position object |
|||
* @private |
|||
*/ |
|||
updateHighlighter: function(el, pos){ |
|||
if(!this.hl) |
|||
this.hl = $(this.canvas.getHighlighter()); |
|||
this.hl.css({ |
|||
left: pos.left, |
|||
top: pos.top, |
|||
height: pos.height, |
|||
width: pos.width |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* Say what to do after the component was selected |
|||
* @param {Object} e |
|||
* @param {Object} el |
|||
* @param {Object} e |
|||
* @param {Object} el |
|||
* @private |
|||
* */ |
|||
onSelect: function(e, el) |
|||
{ |
|||
onSelect: function(e, el) { |
|||
e.stopPropagation(); |
|||
var md = this.editorModel.get('selectedComponent'); |
|||
if(md) |
|||
md.set('status',''); |
|||
var nMd = $(el).data('model'); |
|||
this.cleanPrevious(md); |
|||
var $el = $(el); |
|||
var nMd = $el.data('model'); |
|||
if(nMd){ |
|||
this.editorModel.set('selectedComponent', nMd); |
|||
nMd.set('status','selected'); |
|||
} |
|||
}, |
|||
|
|||
/** Removes all highlighting effects on components |
|||
* @return void |
|||
/** |
|||
* Removes all highlighting effects on components |
|||
* @private |
|||
* */ |
|||
clean: function(){ |
|||
this.$el.find('*').removeClass(this.hoverClass); |
|||
clean: function() { |
|||
if(this.selEl) |
|||
this.selEl.removeClass(this.hoverClass); |
|||
}, |
|||
|
|||
/** Attach badge to component |
|||
* @param Object Component |
|||
* @return void |
|||
* */ |
|||
attachBadge: function(el){ |
|||
var model = $(el).data("model"); |
|||
if(!model || !model.get('badgable')) |
|||
return; |
|||
if(!this.badge) |
|||
this.createBadge(); |
|||
var badgeH = this.badge.outerHeight(); |
|||
this.updateBadgeLabel(model); |
|||
var $el = $(el); |
|||
if(!this.wrapper) |
|||
this.wrapper = this.$wrapper; |
|||
if(!this.wrapperTop) |
|||
this.wrapperTop = this.wrapper.offset() ? this.wrapper.offset().top : 0; |
|||
if(!this.wrapperLeft) |
|||
this.wrapperLeft= this.wrapper.offset() ? this.wrapper.offset().left : 0; |
|||
var relativeT = ($el.offset().top - this.wrapperTop) + this.wrapper.scrollTop(); |
|||
var relativeL = ($el.offset().left- this.wrapperLeft) + this.wrapper.scrollLeft(); |
|||
if( (relativeT-badgeH) > this.wrapperTop) //If it's possible set badge to top
|
|||
relativeT -= badgeH; |
|||
this.badge.css({ left: relativeL, top:relativeT }); |
|||
}, |
|||
|
|||
/** Create badge for the component |
|||
* @return void |
|||
* */ |
|||
createBadge: function (){ |
|||
this.badge = $('<div>', {class: this.badgeClass + " no-dots"}).appendTo(this.$wrapper); |
|||
/** |
|||
* Returns badge element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getBadge: function(){ |
|||
return this.canvas.getBadgeEl(); |
|||
}, |
|||
|
|||
/** Remove badge |
|||
* @return void |
|||
* */ |
|||
removeBadge: function (){ |
|||
if(this.badge){ |
|||
this.badge.remove(); |
|||
delete this.badge; |
|||
} |
|||
/** |
|||
* On frame scroll callback |
|||
* @private |
|||
*/ |
|||
onFrameScroll: function(e){ |
|||
var el = this.cacheEl; |
|||
if(el) |
|||
this.updateBadge(el, this.getElementPos(el)); |
|||
}, |
|||
|
|||
/** Updates badge label |
|||
* @param Object Model |
|||
* @return void |
|||
/** |
|||
* Returns element's data info |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getElementPos: function(el, badge){ |
|||
return this.canvas.getCanvasView().getElementPos(el); |
|||
}, |
|||
|
|||
/** |
|||
* Hide badge |
|||
* @private |
|||
* */ |
|||
updateBadgeLabel: function (model){ |
|||
hideBadge: function () { |
|||
this.getBadge().style.display = 'none'; |
|||
}, |
|||
|
|||
/** |
|||
* Clean previous model from different states |
|||
* @param {Component} model |
|||
* @private |
|||
*/ |
|||
cleanPrevious: function(model) { |
|||
if(model) |
|||
this.badge.html( model.getName() ); |
|||
model.set({ |
|||
status: '', |
|||
state: '', |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* Run method |
|||
* */ |
|||
run: function(em, sender){ |
|||
* Returns content window |
|||
* @private |
|||
*/ |
|||
getContentWindow: function(){ |
|||
if(!this.contWindow) |
|||
this.contWindow = $(this.frameEl.contentWindow); |
|||
return this.contWindow; |
|||
}, |
|||
|
|||
run: function(em, sender) { |
|||
this.enable(); |
|||
this.render(); |
|||
}, |
|||
|
|||
/** |
|||
* Stop method |
|||
* */ |
|||
stop: function(){ |
|||
var sel = this.editorModel.get('selectedComponent'); |
|||
if(sel) |
|||
sel.set('status',''); |
|||
this.$el.unbind(); //removes all attached events
|
|||
this.removeBadge(); |
|||
stop: function() { |
|||
this.stopSelectComponent(); |
|||
this.cleanPrevious(this.em.get('selectedComponent')); |
|||
this.clean(); |
|||
this.$el.find('*').unbind('mouseover').unbind('mouseout').unbind('click'); |
|||
this.editorModel.set('selectedComponent',null); |
|||
key.unbind('⌘+c, ctrl+c'); |
|||
key.unbind('⌘+v, ctrl+v'); |
|||
this.em.set('selectedComponent', null); |
|||
this.toggleClipboard(); |
|||
this.hideBadge(); |
|||
} |
|||
}; |
|||
}); |
|||
}); |
|||
|
|||
@ -1,368 +1,102 @@ |
|||
define(function() { |
|||
/** |
|||
* @class SelectPosition |
|||
* */ |
|||
|
|||
return { |
|||
|
|||
init: function(opt) { |
|||
_.bindAll(this,'selectingPosition','itemLeft'); |
|||
this.config = opt; |
|||
}, |
|||
|
|||
/** |
|||
* Returns position placeholder |
|||
* |
|||
* @return {Object} Placeholder |
|||
* */ |
|||
getPositionPlaceholder: function() |
|||
{ |
|||
return this.$plh; |
|||
}, |
|||
|
|||
/** |
|||
* Creates position placeholder |
|||
* |
|||
* @return {Object} Placeholder |
|||
* */ |
|||
createPositionPlaceholder: function() |
|||
{ |
|||
this.$plh = $('<div>', { class: this.plhClass + " no-dots" }) |
|||
.css({'pointer-events':'none'}).data('helper',1); |
|||
this.$plh.append( $('<div>', { class: this.plhClass + "-int no-dots" } ) ); |
|||
this.$plh.appendTo( this.$wrapper ); |
|||
return this.$plh; |
|||
}, |
|||
|
|||
enable: function() |
|||
{ |
|||
this.startSelectPosition(); |
|||
}, |
|||
|
|||
/** |
|||
|
|||
/** |
|||
* Start select position event |
|||
* |
|||
* @return void |
|||
* @param {HTMLElement} trg |
|||
* @private |
|||
* */ |
|||
startSelectPosition: function() |
|||
{ |
|||
startSelectPosition: function(trg, doc) { |
|||
this.isPointed = false; |
|||
this.$wrapper.on('mousemove', this.selectingPosition); |
|||
}, |
|||
|
|||
/** |
|||
var utils = this.editorModel.get('Utils'); |
|||
if(utils && !this.sorter) |
|||
this.sorter = new utils.Sorter({ |
|||
container: this.getCanvasBody(), |
|||
placer: this.canvas.getPlacerEl(), |
|||
containerSel: '*', |
|||
itemSel: '*', |
|||
pfx: this.ppfx, |
|||
direction: 'a', |
|||
document: doc, |
|||
wmargin: 1, |
|||
nested: 1, |
|||
em: this.editorModel, |
|||
}); |
|||
this.sorter.startSort(trg); |
|||
}, |
|||
|
|||
/** |
|||
* Get frame position |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getOffsetDim: function() { |
|||
var frameOff = this.offset(this.canvas.getFrameEl()); |
|||
var canvasOff = this.offset(this.canvas.getElement()); |
|||
var top = frameOff.top - canvasOff.top; |
|||
var left = frameOff.left - canvasOff.left; |
|||
return { top: top, left: left }; |
|||
}, |
|||
|
|||
/** |
|||
* Stop select position event |
|||
* @return void |
|||
* @private |
|||
* */ |
|||
stopSelectPosition: function() |
|||
{ |
|||
this.$wrapper.off('mousemove',this.selectingPosition); |
|||
stopSelectPosition: function() { |
|||
this.posTargetCollection = null; |
|||
this.posIndex = this.posMethod=='after' && this.cDim.length!==0 ? this.posIndex + 1 : this.posIndex; //Normalize
|
|||
if(this.sorter){ |
|||
this.sorter.moved = 0; |
|||
this.sorter.endMove(); |
|||
} |
|||
if(this.cDim){ |
|||
this.posIsLastEl = this.cDim.length!==0 && this.posMethod=='after' && this.posIndex==this.cDim.length; |
|||
this.posTargetEl = (this.cDim.length===0 ? $(this.outsideElem) : |
|||
this.posTargetEl = (this.cDim.length===0 ? $(this.outsideElem) : |
|||
(!this.posIsLastEl && this.cDim[this.posIndex] ? $(this.cDim[this.posIndex][5]).parent() : $(this.outsideElem) )); |
|||
this.posTargetModel = this.posTargetEl.data("model"); |
|||
this.posTargetCollection = this.posTargetEl.data("model-comp"); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* During event |
|||
* @param {Object} e Event |
|||
* */ |
|||
selectingPosition: function(e) |
|||
{ |
|||
this.isPointed = true; |
|||
|
|||
if(!this.wp){ |
|||
this.$wp = this.$wrapper; |
|||
this.wp = this.$wp[0]; |
|||
} |
|||
var wpO = this.$wp.offset(); |
|||
this.wpT = wpO.top; |
|||
this.wpL = wpO.left; |
|||
this.wpScT = this.$wp.scrollTop(); |
|||
this.wpScL = this.$wp.scrollLeft(); |
|||
|
|||
if(!this.$plh) |
|||
this.createPositionPlaceholder(); |
|||
|
|||
this.rY = (e.pageY - this.wpT) + this.wpScT; |
|||
this.rX = (e.pageX - this.wpL) + this.wpScL; |
|||
|
|||
this.entered(e); |
|||
this.updatePosition(this.rX, this.rY); |
|||
var actualPos = this.posIndex + ':' + this.posMethod; //save globally the new index
|
|||
|
|||
if(!this.lastPos || (this.lastPos != actualPos)){ //If there is a significant changes with mouse
|
|||
this.updatePositionPlaceholder(this.posIndex, this.posMethod); |
|||
this.lastPos = actualPos; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Search where to put placeholder |
|||
* @param {Integer} posX X position of the mouse |
|||
* @param {Integer} posY Y position of the mouse |
|||
* |
|||
* @retun void |
|||
* */ |
|||
updatePosition: function( posX, posY ){ |
|||
this.posMethod = "before"; |
|||
this.posIndex = 0; |
|||
var leftLimit = 0, xLimit = 0, dimRight = 0, yLimit = 0, xCenter = 0, yCenter = 0, dimDown = 0, dim = 0; |
|||
for(var i = 0; i < this.cDim.length; i++){ |
|||
dim = this.cDim[i]; |
|||
dimDown = dim[0] + dim[2]; |
|||
yCenter = dim[0] + (dim[2] / 2); //Horizontal center
|
|||
xCenter = dim[1] + (dim[3] / 2); //Vertical center
|
|||
dimRight = dim[1] + dim[3]; |
|||
if( (xLimit && dim[1] > xLimit) || (yLimit && yCenter > yLimit) || |
|||
(leftLimit && dimRight < leftLimit)) //No need with this one if over the limit
|
|||
continue; |
|||
if(!dim[4]){ //If it's not inFlow (like float element)
|
|||
if( posY < dimDown) |
|||
yLimit = dimDown; |
|||
if( posX < xCenter){ //If mouse lefter than center
|
|||
xLimit = xCenter; |
|||
this.posMethod = "before"; |
|||
}else{ |
|||
leftLimit = xCenter; |
|||
this.posMethod = "after"; |
|||
} |
|||
this.posIndex = i; |
|||
}else{ |
|||
this.posIndex = i; |
|||
if( posY < yCenter ){ //If mouse upper than center
|
|||
this.posMethod = "before"; //Should place helper before
|
|||
break; //No need to continue under inFlow element
|
|||
}else |
|||
this.posMethod = "after"; |
|||
} |
|||
} |
|||
if(this.posIndex == (this.cDim.length) && this.posMethod == 'after' ){ |
|||
this.posIndex--; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Updates the position of the placeholder |
|||
* @param {Integer} index Index of the nearest child |
|||
* @param {String} method Before or after position |
|||
* |
|||
* @return void |
|||
* */ |
|||
updatePositionPlaceholder: function(index, method){ |
|||
var t = 0, l = 0, w = 0, h = 0, |
|||
marg = 2, |
|||
un = 'px', |
|||
margI = 5, |
|||
plh = this.$plh[0]; |
|||
if( this.cDim[index] ){ |
|||
var elDim = this.cDim[index]; |
|||
if(!elDim[4]){ |
|||
w = 'auto'; |
|||
t = elDim[0] + marg; |
|||
h = elDim[2] - (marg * 2) + un; |
|||
l = (method == 'before') ? (elDim[1] - marg) : (elDim[1] + elDim[3] - marg); |
|||
}else{ |
|||
w = elDim[3] + un; |
|||
t = (method == 'before') ? (elDim[0] - marg) : (elDim[0] + elDim[2] - marg); |
|||
l = elDim[1]; |
|||
h = 'auto'; |
|||
} |
|||
//t -= this.wpScT;
|
|||
//l -= this.wpScL;
|
|||
}else{ |
|||
if(this.$targetEl){ |
|||
var trg = this.$targetEl[0], |
|||
$eO = this.$targetEl.offset(); |
|||
t = $eO.top - this.wpT + this.wpScT + margI; |
|||
l = $eO.left - this.wpL + this.wpScL + margI; |
|||
w = (parseInt(trg.offsetWidth) - margI * 2) + un; |
|||
h = 'auto'; |
|||
} |
|||
} |
|||
|
|||
plh.style.top = t + un; |
|||
plh.style.left = l + un; |
|||
if(w) |
|||
plh.style.width = w; |
|||
if(h) |
|||
plh.style.height = h; |
|||
}, |
|||
|
|||
/** |
|||
* Track inside which element pointer entered |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
entered: function(e){ |
|||
if( (!this.outsideElem || this.outsideElem != e.target) ){ //If I'm in the new element
|
|||
this.outsideElem = e.target; //Set the element in which it's actually inside
|
|||
this.$targetEl = $(e.target); |
|||
$(this.outsideElem).on('mouseleave',this.itemLeft); |
|||
this.cDim = this.getChildrenDim(); |
|||
this.dimT = this.getTargetDim(e); |
|||
if( this.nearToBorders(e) && (e.target.parentNode!=this.wp.parentNode) ) //Avoid flickering
|
|||
this.cDim = this.getChildrenDim(e.target.parentNode); |
|||
}else if( this.nearToBorders(e) && (e.target.parentNode!=this.wp.parentNode) ){ //Near to borders and parent is not the canvas
|
|||
this.cDim = this.getChildrenDim(e.target.parentNode); |
|||
}else if( !(this.nearToBorders(e)) ){ |
|||
this.cDim = this.getChildrenDim(); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Check if pointer is near to the borders of the target |
|||
* @param {Object} e Event |
|||
* |
|||
* @return {Integer} |
|||
* */ |
|||
nearToBorders: function(e){ |
|||
var m = 7; //Limit in pixels for be near
|
|||
if(!this.dimT) |
|||
return; |
|||
var dimT = this.dimT; |
|||
if(dimT[2] < 40) |
|||
m = 5; |
|||
if( ((dimT[0] + m) > this.rY) || (this.rY > (dimT[0] + dimT[2] - m)) || |
|||
((dimT[1] + m) > this.rX) || (this.rX > (dimT[1] + dimT[3] - m)) ) //Check if the pointer is near
|
|||
return 1; |
|||
else |
|||
return 0; |
|||
}, |
|||
|
|||
/** |
|||
* Check if pointer is near to the float component |
|||
* |
|||
* @return {Integer} |
|||
* */ |
|||
nearToFloat: function() |
|||
{ |
|||
var index = this.posIndex; |
|||
var isLastEl = this.posIsLastEl; |
|||
if(this.cDim.length !== 0 && ( |
|||
(!isLastEl && !this.cDim[index][4]) || |
|||
(this.cDim[index-1] && !this.cDim[index-1][4]) || |
|||
(isLastEl && !this.cDim[index-1][4]) ) ) |
|||
return 1; |
|||
else |
|||
return 0; |
|||
}, |
|||
|
|||
/** |
|||
* Returns dimension of the taget |
|||
* @param {Object} e Event |
|||
* |
|||
* @return {Array} |
|||
* */ |
|||
getTargetDim: function(e) |
|||
{ |
|||
var elT = e.target, |
|||
$el = $(elT); |
|||
return [ elT.offsetTop, elT.offsetLeft, $el.outerHeight(), $el.outerWidth() ]; |
|||
}, |
|||
|
|||
/** |
|||
* Returns children and their dimensions of the target element, |
|||
* excluding text nodes and the move placeholder |
|||
* @param {Object} el Element |
|||
* |
|||
* @return {Array} |
|||
* */ |
|||
getChildrenDim: function(el) |
|||
{ |
|||
var dim = []; |
|||
var elToPars = el || this.outsideElem; |
|||
var isInFlow = this.isInFlow; //Assign method for make it work inside $.each
|
|||
var $this = this; //Store context
|
|||
$(elToPars.childNodes).each(function(){ |
|||
var $el = $(this); |
|||
if(this.nodeName != '#text' && !$el.data('helper') ){ //Ignore text nodes and helpers
|
|||
dim.push( [ this.offsetTop, this.offsetLeft, $el.outerHeight(), $el.outerWidth(), isInFlow($this, this), this ] ); |
|||
} |
|||
}); |
|||
return dim; |
|||
}, |
|||
|
|||
/** |
|||
* Track when I go ouside of the element (basically when the target changes) |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
itemLeft: function(e) |
|||
{ |
|||
$(this.outsideElem).off('mouseleave',this.itemLeft); |
|||
this.outsideElem = null; |
|||
this.$targetEl = null; |
|||
this.lastPos = null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns true if the elements is in flow, or better is not in flow where |
|||
* for example the component is with float:left |
|||
* @param {Object} $this Context |
|||
* @param {Object} elm Element |
|||
* |
|||
* @return {Boolean} |
|||
* */ |
|||
isInFlow: function($this, elm) |
|||
{ |
|||
var $elm = $(elm), ch = -1; |
|||
if(!$elm.length) |
|||
return false; |
|||
if( ($elm.height() < ch) || !$this.okProps($elm) ) |
|||
return false; |
|||
return true; |
|||
}, |
|||
|
|||
/** |
|||
* Returns true only if the element follow the standard flow |
|||
* @param {Object} $elm Element |
|||
* |
|||
* @return {Boolean} |
|||
* */ |
|||
okProps: function($elm) |
|||
{ |
|||
if ($elm.css('float')!=='none') |
|||
return false; |
|||
switch($elm.css('position')) { |
|||
case 'static': case 'relative': break; |
|||
default: return false; |
|||
} |
|||
switch ($elm.css('display')) { |
|||
case 'block': case 'list-item': case 'table': return true; |
|||
} |
|||
return false; |
|||
|
|||
/** |
|||
* Enabel select position |
|||
* @private |
|||
*/ |
|||
enable: function() { |
|||
this.startSelectPosition(); |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* Removes position placeholder |
|||
* |
|||
* @param void |
|||
* */ |
|||
removePositionPlaceholder: function() |
|||
{ |
|||
if(this.$plh && this.$plh.length) |
|||
this.$plh.remove(); |
|||
this.$plh = null; |
|||
* Check if the pointer is near to the float component |
|||
* @param {number} index |
|||
* @param {string} method |
|||
* @param {Array<Array>} dims |
|||
* @return {Boolean} |
|||
* @private |
|||
* */ |
|||
nearFloat: function(index, method, dims) { |
|||
var i = index || 0; |
|||
var m = method || 'before'; |
|||
var len = dims.length; |
|||
var isLast = len !== 0 && m == 'after' && i == len; |
|||
if(len !== 0 && ( |
|||
(!isLast && !dims[i][4]) || |
|||
(dims[i-1] && !dims[i-1][4]) || |
|||
(isLast && !dims[i-1][4]) ) ) |
|||
return 1; |
|||
return 0; |
|||
}, |
|||
|
|||
/* Run method */ |
|||
run: function(){ |
|||
|
|||
|
|||
run: function() { |
|||
this.enable(); |
|||
}, |
|||
|
|||
/* Stop method */ |
|||
stop: function(){ |
|||
this.removePositionPlaceholder(); |
|||
|
|||
stop: function() { |
|||
this.stopSelectPosition(); |
|||
this.$wrapper.css('cursor','');//changes back aspect of the cursor
|
|||
this.$wrapper.unbind();//removes all attached events
|
|||
this.$wrapper.css('cursor',''); |
|||
this.$wrapper.unbind(); |
|||
} |
|||
}; |
|||
}); |
|||
@ -1,17 +1,13 @@ |
|||
define(function() { |
|||
/** |
|||
* @class SwitchVisibility |
|||
* */ |
|||
return { |
|||
|
|||
run: function() |
|||
{ |
|||
this.$canvas.addClass(this.pfx + 'dashed'); |
|||
|
|||
run: function(ed) { |
|||
ed.Canvas.getBody().className = this.ppfx + 'dashed'; |
|||
}, |
|||
|
|||
stop: function() |
|||
{ |
|||
this.$canvas.removeClass(this.pfx + 'dashed'); |
|||
|
|||
stop: function(ed) { |
|||
ed.Canvas.getBody().className = ""; |
|||
} |
|||
|
|||
}; |
|||
}); |
|||
@ -1,106 +1,258 @@ |
|||
/** |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [getAll](#getall) |
|||
* * [load](#load) |
|||
* * [store](#store) |
|||
* |
|||
* This module contains and manage CSS rules for the template inside the canvas |
|||
* Before using the methods you should get first the module from the editor instance, in this way: |
|||
* |
|||
* ```js
|
|||
* var cssComposer = editor.CssComposer; |
|||
* ``` |
|||
* |
|||
* @module CssComposer |
|||
* @param {Object} config Configurations |
|||
* @param {string|Array<Object>} [config.rules=[]] CSS string or an array of rule objects |
|||
* @example |
|||
* ... |
|||
* CssComposer: { |
|||
* rules: '.myClass{ color: red}', |
|||
* } |
|||
*/ |
|||
define(function(require) { |
|||
/** |
|||
* @class CssComposer |
|||
* @param {Object} config Configurations |
|||
* |
|||
* */ |
|||
var CssComposer = function(config) |
|||
{ |
|||
var c = config || {}, |
|||
def = require('./config/config'), |
|||
CssRule = require('./model/CssRule'), |
|||
CssRules = require('./model/CssRules'), |
|||
Selectors = require('./model/Selectors'), |
|||
CssRulesView = require('./view/CssRulesView'); |
|||
|
|||
for (var name in def) { |
|||
if (!(name in c)) |
|||
c[name] = def[name]; |
|||
} |
|||
|
|||
var rules = new CssRules(c.defaults, c), |
|||
rulesView = new CssRulesView({ |
|||
collection: rules, |
|||
config: c, |
|||
}); |
|||
return function() { |
|||
var c = {}, |
|||
defaults = require('./config/config'), |
|||
CssRule = require('./model/CssRule'), |
|||
CssRules = require('./model/CssRules'), |
|||
Selectors = require('./model/Selectors'), |
|||
CssRulesView = require('./view/CssRulesView'); |
|||
|
|||
var rules, rulesView; |
|||
|
|||
return { |
|||
|
|||
Selectors: Selectors, |
|||
|
|||
/** |
|||
* Create new rule and return it. Don't add it to the collection |
|||
* @param {Array} selectors Array of selectors |
|||
* @param {String} state Css rule state |
|||
* @param {String} width For which device this style is oriented |
|||
* |
|||
* @return {Object} |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'CssComposer', |
|||
|
|||
/** |
|||
* Mandatory for the storage manager |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
storageKey: function(){ |
|||
var keys = []; |
|||
var smc = (c.stm && c.stm.getConfig()) || {}; |
|||
if(smc.storeCss) |
|||
keys.push('css'); |
|||
if(smc.storeStyles) |
|||
keys.push('styles'); |
|||
return keys; |
|||
}, |
|||
|
|||
/** |
|||
* Initializes module. Automatically called with a new instance of the editor |
|||
* @param {Object} config Configurations |
|||
* @private |
|||
*/ |
|||
init: function(config) { |
|||
c = config || {}; |
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
var ppfx = c.pStylePrefix; |
|||
if(ppfx) |
|||
c.stylePrefix = ppfx + c.stylePrefix; |
|||
|
|||
var elStyle = (c.em && c.em.config.style) || ''; |
|||
c.rules = elStyle || c.rules; |
|||
|
|||
c.sm = c.em; // TODO Refactor
|
|||
rules = new CssRules([], c); |
|||
rules.add(c.rules); |
|||
|
|||
rulesView = new CssRulesView({ |
|||
collection: rules, |
|||
config: c, |
|||
}); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* On load callback |
|||
* @private |
|||
*/ |
|||
onLoad: function(){ |
|||
if(c.stm && c.stm.getConfig().autoload) |
|||
this.load(); |
|||
|
|||
if(c.stm && c.stm.isAutosave()) |
|||
c.em.listenRules(this.getAll()); |
|||
}, |
|||
|
|||
/** |
|||
* Load data from the passed object, if the object is empty will try to fetch them |
|||
* autonomously from the storage manager. |
|||
* The fetched data will be added to the collection |
|||
* @param {Object} data Object of data to load |
|||
* @return {Object} Loaded rules |
|||
*/ |
|||
load: function(data){ |
|||
var d = data || ''; |
|||
if(!d && c.stm) |
|||
d = c.em.getCacheLoad(); |
|||
var obj = ''; |
|||
if(d.style){ |
|||
try{ |
|||
obj = JSON.parse(d.style); |
|||
}catch(err){} |
|||
}else if(d.css) |
|||
obj = c.em.get('Parser').parseCss(d.css); |
|||
|
|||
if(obj) |
|||
rules.reset(obj); |
|||
return obj; |
|||
}, |
|||
|
|||
/** |
|||
* Store data to the selected storage |
|||
* @param {Boolean} noStore If true, won't store |
|||
* @return {Object} Data to store |
|||
*/ |
|||
store: function(noStore){ |
|||
if(!c.stm) |
|||
return; |
|||
var obj = {}; |
|||
var keys = this.storageKey(); |
|||
if(keys.indexOf('css') >= 0) |
|||
obj.css = c.em.getCss(); |
|||
if(keys.indexOf('styles') >= 0) |
|||
obj.styles = JSON.stringify(rules); |
|||
if(!noStore) |
|||
c.stm.store(obj); |
|||
return obj; |
|||
}, |
|||
|
|||
/** |
|||
* Add new rule to the collection, if not yet exists with the same selectors |
|||
* @param {Array<Selector>} selectors Array of selectors |
|||
* @param {String} state Css rule state |
|||
* @param {String} width For which device this style is oriented |
|||
* @return {Model} |
|||
* @example |
|||
* var sm = editor.SelectorManager; |
|||
* var sel1 = sm.add('myClass1'); |
|||
* var sel2 = sm.add('myClass2'); |
|||
* var rule = cssComposer.add([sel1, sel2], 'hover'); |
|||
* rule.set('style', { |
|||
* width: '100px', |
|||
* color: '#fff', |
|||
* }); |
|||
* */ |
|||
newRule: function(selectors, state, width) { |
|||
add: function(selectors, state, width) { |
|||
var s = state || ''; |
|||
var w = width || ''; |
|||
var rule = new CssRule({ |
|||
state: s, |
|||
maxWidth: w, |
|||
}); |
|||
rule.get('selectors').add(selectors); |
|||
return rule; |
|||
var rule = this.get(selectors, s, w); |
|||
if(rule) |
|||
return rule; |
|||
else{ |
|||
rule = new CssRule({ |
|||
state: s, |
|||
maxWidth: w, |
|||
}); |
|||
rule.get('selectors').add(selectors); |
|||
rules.add(rule); |
|||
return rule; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Add new rule to the collection if not yet exists |
|||
* @param {Object} rule |
|||
* |
|||
* @return {Object} |
|||
* Get the rule |
|||
* @param {Array<Selector>} selectors Array of selectors |
|||
* @param {String} state Css rule state |
|||
* @param {String} width For which device this style is oriented |
|||
* @return {Model|null} |
|||
* @example |
|||
* var sm = editor.SelectorManager; |
|||
* var sel1 = sm.add('myClass1'); |
|||
* var sel2 = sm.add('myClass2'); |
|||
* var rule = cssComposer.get([sel1, sel2], 'hover'); |
|||
* // Update the style
|
|||
* rule.set('style', { |
|||
* width: '300px', |
|||
* color: '#000', |
|||
* }); |
|||
* */ |
|||
addRule: function(rule){ |
|||
var models = rule.get('selectors').models; |
|||
var r = this.getRule(models, rule.get('state'), rule.get('maxWidth')); |
|||
if(!r) |
|||
r = rules.add(rule); |
|||
return r; |
|||
get: function(selectors, state, width) { |
|||
var rule = null; |
|||
rules.each(function(m){ |
|||
if(rule) |
|||
return; |
|||
if(m.compare(selectors, state, width)) |
|||
rule = m; |
|||
}); |
|||
return rule; |
|||
}, |
|||
|
|||
/** |
|||
* Get class by its name |
|||
* @param {Array} selectors Array of selectors |
|||
* @param {String} state Css rule state |
|||
* @param {String} width For which device this style is oriented |
|||
* |
|||
* @return {Object|null} |
|||
* Get the collection of rules |
|||
* @return {Collection} |
|||
* */ |
|||
getRule : function(selectors, state, width) { |
|||
fRule = null; |
|||
rules.each(function(rule){ |
|||
if(fRule) |
|||
return; |
|||
if(rule.compare(selectors, state, width)) |
|||
fRule = rule; |
|||
}, this); |
|||
return fRule; |
|||
getAll: function() { |
|||
return rules; |
|||
}, |
|||
|
|||
/** |
|||
* Get collection of css rules |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
getRules : function() { |
|||
return rules; |
|||
* Add a raw collection of rule objects |
|||
* This method overrides styles, in case, of already defined rule |
|||
* @param {Array<Object>} data Array of rule objects |
|||
* @return {Array<Model>} |
|||
* @private |
|||
*/ |
|||
addCollection: function(data){ |
|||
var result = []; |
|||
var d = data instanceof Array ? data : [data]; |
|||
for(var i = 0, l = d.length; i < l; i++){ |
|||
var rule = d[i] || {}; |
|||
if(!rule.selectors) |
|||
continue; |
|||
var sm = c.em && c.em.get('SelectorManager'); |
|||
if(!sm) |
|||
console.warn('Selector Manager not found'); |
|||
var sl = rule.selectors; |
|||
var sels = sl instanceof Array ? sl : [sl]; |
|||
var newSels = []; |
|||
for(var j = 0, le = sels.length; j < le; j++){ |
|||
var selec = sm.add(sels[j]); |
|||
newSels.push(selec); |
|||
} |
|||
var model = this.add(newSels, rule.state, rule.width); |
|||
model.set('style', rule.style || {}); |
|||
result.push(model); |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Render block of CSS rules |
|||
* |
|||
* @return {Object} |
|||
* Render the block of CSS rules |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
render: function(){ |
|||
render: function() { |
|||
return rulesView.render().el; |
|||
} |
|||
|
|||
}; |
|||
}; |
|||
|
|||
return CssComposer; |
|||
|
|||
}); |
|||
}); |
|||
|
|||
File diff suppressed because it is too large
@ -0,0 +1,9 @@ |
|||
define(function () { |
|||
return { |
|||
|
|||
devices: [], |
|||
|
|||
deviceLabel: 'Device', |
|||
|
|||
}; |
|||
}); |
|||
@ -0,0 +1,115 @@ |
|||
/** |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [getAll](#getall) |
|||
* |
|||
* Before using methods you should get first the module from the editor instance, in this way: |
|||
* |
|||
* ```js
|
|||
* var deviceManager = editor.DeviceManager; |
|||
* ``` |
|||
* |
|||
* @module DeviceManager |
|||
*/ |
|||
define(function(require) { |
|||
|
|||
return function() { |
|||
var c = {}, |
|||
defaults = require('./config/config'), |
|||
Devices = require('./model/Devices'), |
|||
DevicesView = require('./view/DevicesView'); |
|||
var devices, view; |
|||
|
|||
return { |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'DeviceManager', |
|||
|
|||
/** |
|||
* Initialize module. Automatically called with a new instance of the editor |
|||
* @param {Object} config Configurations |
|||
* @param {Array<Object>} [config.devices=[]] Default devices |
|||
* @example |
|||
* ... |
|||
* { |
|||
* devices: [ |
|||
* {name: 'Desktop', width: ''} |
|||
* {name: 'Tablet', width: '991px'} |
|||
* ], |
|||
* } |
|||
* ... |
|||
* @return {this} |
|||
*/ |
|||
init: function(config) { |
|||
c = config || {}; |
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
devices = new Devices(c.devices); |
|||
view = new DevicesView({ |
|||
collection: devices, |
|||
config: c |
|||
}); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Add new device to the collection. URLs are supposed to be unique |
|||
* @param {string} name Device name |
|||
* @param {string} width Width of the device |
|||
* @param {Object} opts Custom options |
|||
* @return {Device} Added device |
|||
* @example |
|||
* deviceManager.add('Tablet', '900px'); |
|||
*/ |
|||
add: function(name, width, opts){ |
|||
var obj = opts || {}; |
|||
obj.name = name; |
|||
obj.width = width; |
|||
return devices.add(obj); |
|||
}, |
|||
|
|||
/** |
|||
* Return device by name |
|||
* @param {string} name Name of the device |
|||
* @example |
|||
* var device = deviceManager.get('Tablet'); |
|||
* console.log(JSON.stringify(device)); |
|||
* // {name: 'Tablet', width: '900px'}
|
|||
*/ |
|||
get: function(name){ |
|||
return devices.get(name); |
|||
}, |
|||
|
|||
/** |
|||
* Return all devices |
|||
* @return {Collection} |
|||
* @example |
|||
* var devices = deviceManager.getAll(); |
|||
* console.log(JSON.stringify(devices)); |
|||
* // [{name: 'Desktop', width: ''}, ...]
|
|||
*/ |
|||
getAll: function(){ |
|||
return devices; |
|||
}, |
|||
|
|||
/** |
|||
* Render devices |
|||
* @return {string} HTML string |
|||
* @private |
|||
*/ |
|||
render: function(){ |
|||
return view.render().el; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
|
|||
}); |
|||
@ -0,0 +1,14 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
|
|||
return Backbone.Model.extend({ |
|||
|
|||
idAttribute: 'name', |
|||
|
|||
defaults :{ |
|||
name: '', |
|||
width: '', |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,9 @@ |
|||
define(['backbone','./Device'], |
|||
function (Backbone, Device) { |
|||
|
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Device, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,10 @@ |
|||
<div class="<%= ppfx %>device-label"><%= deviceLabel %></div> |
|||
<div class="<%= ppfx %>field <%= ppfx %>select"> |
|||
<span id="<%= ppfx %>input-holder"> |
|||
<select class="<%= ppfx %>devices"></select> |
|||
</span> |
|||
<div class="<%= ppfx %>sel-arrow"> |
|||
<div class="<%= ppfx %>d-s-arrow"></div> |
|||
</div> |
|||
</div> |
|||
<button style="display:none" class="<%= ppfx %>add-trasp">+</button> |
|||
@ -0,0 +1,82 @@ |
|||
define(['backbone', 'text!./../template/devices.html'], |
|||
function(Backbone, devicesTemplate) { |
|||
|
|||
return Backbone.View.extend({ |
|||
|
|||
template: _.template(devicesTemplate), |
|||
|
|||
events: { |
|||
'change': 'updateDevice' |
|||
}, |
|||
|
|||
initialize: function(o) { |
|||
this.config = o.config || {}; |
|||
this.em = this.config.em; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.events['click .' + this.ppfx + 'add-trasp'] = this.startAdd; |
|||
this.listenTo(this.em, 'change:device', this.updateSelect); |
|||
this.delegateEvents(); |
|||
}, |
|||
|
|||
/** |
|||
* Start adding new device |
|||
* @return {[type]} [description] |
|||
* @private |
|||
*/ |
|||
startAdd: function(){}, |
|||
|
|||
/** |
|||
* Update device of the editor |
|||
* @private |
|||
*/ |
|||
updateDevice: function(){ |
|||
var em = this.em; |
|||
if(em){ |
|||
var devEl = this.devicesEl; |
|||
var val = devEl ? devEl.val() : ''; |
|||
em.set('device', val); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Update select value on device update |
|||
* @private |
|||
*/ |
|||
updateSelect: function(){ |
|||
var em = this.em; |
|||
var devEl = this.devicesEl; |
|||
if(em && em.getDeviceModel && devEl){ |
|||
var device = em.getDeviceModel(); |
|||
var name = device ? device.get('name') : ''; |
|||
devEl.val(name); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Return devices options |
|||
* @return {string} String of options |
|||
* @private |
|||
*/ |
|||
getOptions: function(){ |
|||
var result = ''; |
|||
this.collection.each(function(device){ |
|||
var name = device.get('name'); |
|||
result += '<option value="' + name+ '">' + name + '</option>'; |
|||
}); |
|||
return result; |
|||
}, |
|||
|
|||
render: function() { |
|||
var pfx = this.ppfx; |
|||
this.$el.html(this.template({ |
|||
ppfx: pfx, |
|||
deviceLabel: this.config.deviceLabel |
|||
})); |
|||
this.devicesEl = this.$el.find('.' + pfx + 'devices'); |
|||
this.devicesEl.append(this.getOptions()); |
|||
this.el.className = pfx + 'devices-c'; |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -1,89 +1,288 @@ |
|||
/** |
|||
* |
|||
* * [getWrapper](#getwrapper) |
|||
* * [getComponents](#getcomponents) |
|||
* * [addComponent](#addcomponent) |
|||
* * [clear](#clear) |
|||
* * [load](#load) |
|||
* * [store](#store) |
|||
* * [render](#render) |
|||
* |
|||
* With this module is possible to manage components inside the canvas. |
|||
* Before using methods you should get first the module from the editor instance, in this way: |
|||
* |
|||
* ```js
|
|||
* var domComponents = editor.DomComponents; |
|||
* ``` |
|||
* |
|||
* @module DomComponents |
|||
* @param {Object} config Configurations |
|||
* @param {string|Array<Object>} [config.components=[]] HTML string or an array of possible components |
|||
* @example |
|||
* ... |
|||
* domComponents: { |
|||
* components: '<div>Hello world!</div>', |
|||
* } |
|||
* // Or
|
|||
* domComponents: { |
|||
* components: [ |
|||
* { tagName: 'span', style: {color: 'red'}, content: 'Hello'}, |
|||
* { style: {width: '100px', content: 'world!'}} |
|||
* ], |
|||
* } |
|||
* ... |
|||
*/ |
|||
define(function(require) { |
|||
/** |
|||
* @class Components |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function Components(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Component = require('./model/Component'), |
|||
ComponentText = require('./model/ComponentText'), |
|||
ComponentImage = require('./model/ComponentImage'), |
|||
ComponentView = require('./view/ComponentView'), |
|||
ComponentImageView = require('./view/ComponentImageView'), |
|||
|
|||
return function (){ |
|||
var c = {}, |
|||
defaults = require('./config/config'), |
|||
Component = require('./model/Component'), |
|||
ComponentText = require('./model/ComponentText'), |
|||
ComponentImage = require('./model/ComponentImage'), |
|||
ComponentLink = require('./model/ComponentLink'), |
|||
ComponentView = require('./view/ComponentView'), |
|||
ComponentImageView = require('./view/ComponentImageView'), |
|||
ComponentTextView = require('./view/ComponentTextView'); |
|||
ComponentLinkView = require('./view/ComponentLinkView'); |
|||
var component, componentView; |
|||
|
|||
// Set default options
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
return { |
|||
|
|||
if(!c.wrapper.attributes) |
|||
c.wrapper.attributes = {}; |
|||
c.wrapper.attributes.id = 'wrapper'; |
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'DomComponents', |
|||
|
|||
// If there is no components try to append defaults
|
|||
if(!c.wrapper.components.length && c.defaults.length){ |
|||
c.wrapper.components = c.defaults; |
|||
} |
|||
/** |
|||
* Mandatory for the storage manager |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
storageKey: function(){ |
|||
var keys = []; |
|||
var smc = (c.stm && c.stm.getConfig()) || {}; |
|||
if(smc.storeHtml) |
|||
keys.push('html'); |
|||
if(smc.storeComponents) |
|||
keys.push('components'); |
|||
return keys; |
|||
}, |
|||
|
|||
if(!c.wrapper.style) |
|||
c.wrapper.style = {}; |
|||
/** |
|||
* Initialize module. Called on a new instance of the editor with configurations passed |
|||
* inside 'domComponents' field |
|||
* @param {Object} config Configurations |
|||
* @private |
|||
*/ |
|||
init: function(config) { |
|||
c = config || {}; |
|||
if(c.em) |
|||
c.components = c.em.config.components || c.components; |
|||
|
|||
c.wrapper.style.position = 'relative'; |
|||
this.component = new Component(c.wrapper, { sm: c.em }); |
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
var obj = { |
|||
model: this.component, |
|||
config: c, |
|||
}; |
|||
var ppfx = c.pStylePrefix; |
|||
if(ppfx) |
|||
c.stylePrefix = ppfx + c.stylePrefix; |
|||
|
|||
// Load dependencies
|
|||
if(c.em){ |
|||
c.rte = c.em.get('rte') || ''; |
|||
c.modal = c.em.get('Modal') || ''; |
|||
c.am = c.em.get('AssetManager') || ''; |
|||
} |
|||
|
|||
component = new Component(c.wrapper, { sm: c.em, config: c }); |
|||
component.set({ attributes: {id: 'wrapper'}}); |
|||
component.get('components').add(c.components); |
|||
componentView = new ComponentView({ |
|||
model: component, |
|||
config: c, |
|||
}); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* On load callback |
|||
* @private |
|||
*/ |
|||
onLoad: function(){ |
|||
if(c.stm && c.stm.getConfig().autoload) |
|||
this.load(); |
|||
|
|||
if(c.stm && c.stm.isAutosave()){ |
|||
c.em.initUndoManager(); |
|||
c.em.initChildrenComp(this.getWrapper()); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Load components from the passed object, if the object is empty will try to fetch them |
|||
* autonomously from the selected storage |
|||
* The fetched data will be added to the collection |
|||
* @param {Object} data Object of data to load |
|||
* @return {Object} Loaded data |
|||
*/ |
|||
load: function(data){ |
|||
var d = data || ''; |
|||
if(!d && c.stm) |
|||
d = c.em.getCacheLoad(); |
|||
var obj = ''; |
|||
if(d.components){ |
|||
try{ |
|||
obj = JSON.parse(d.components); |
|||
}catch(err){} |
|||
}else if(d.html) |
|||
obj = d.html; |
|||
|
|||
this.c = c; |
|||
this.ComponentView = new ComponentView(obj); |
|||
} |
|||
if(obj) |
|||
this.getComponents().reset(obj); |
|||
return obj; |
|||
}, |
|||
|
|||
Components.prototype = { |
|||
/** |
|||
* Store components on the selected storage |
|||
* @param {Boolean} noStore If true, won't store |
|||
* @return {Object} Data to store |
|||
*/ |
|||
store: function(noStore){ |
|||
if(!c.stm) |
|||
return; |
|||
var obj = {}; |
|||
var keys = this.storageKey(); |
|||
if(keys.indexOf('html') >= 0) |
|||
obj.html = c.em.getHtml(); |
|||
if(keys.indexOf('components') >= 0) |
|||
obj.components = JSON.stringify(c.em.getComponents()); |
|||
if(!noStore) |
|||
c.stm.store(obj); |
|||
return obj; |
|||
}, |
|||
|
|||
/** |
|||
* Returns main wrapper which will contain all new components |
|||
* |
|||
* Returns privately the main wrapper |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getComponent : function(){ |
|||
return this.component; |
|||
return component; |
|||
}, |
|||
|
|||
/** |
|||
* Returns main wrapper which will contain all new components |
|||
* |
|||
* @return {Object} |
|||
* Returns root component inside the canvas. Something like <body> inside HTML page |
|||
* The wrapper doesn't differ from the original Component Model |
|||
* @return {Component} Root Component |
|||
* @example |
|||
* // Change background of the wrapper and set some attribute
|
|||
* var wrapper = domComponents.getWrapper(); |
|||
* wrapper.set('style', {'background-color': 'red'}); |
|||
* wrapper.set('attributes', {'title': 'Hello!'}); |
|||
*/ |
|||
getWrapper: function(){ |
|||
return this.getComponent(); |
|||
}, |
|||
|
|||
/** |
|||
* Returns children from the wrapper |
|||
* |
|||
* @return {Object} |
|||
* Returns wrapper's children collection. Once you have the collection you can |
|||
* add other Components(Models) inside. Each component can have several nested |
|||
* components inside and you can nest them as more as you wish. |
|||
* @return {Components} Collection of components |
|||
* @example |
|||
* // Let's add some component
|
|||
* var wrapperChildren = domComponents.getComponents(); |
|||
* var comp1 = wrapperChildren.add({ |
|||
* style: { 'background-color': 'red'} |
|||
* }); |
|||
* var comp2 = wrapperChildren.add({ |
|||
* tagName: 'span', |
|||
* attributes: { title: 'Hello!'} |
|||
* }); |
|||
* // Now let's add an other one inside first component
|
|||
* // First we have to get the collection inside. Each
|
|||
* // component has 'components' property
|
|||
* var comp1Children = comp1.get('components'); |
|||
* // Procede as before. You could also add multiple objects
|
|||
* comp1Children.add([ |
|||
* { style: { 'background-color': 'blue'}}, |
|||
* { style: { height: '100px', width: '100px'}} |
|||
* ]); |
|||
* // Remove comp2
|
|||
* wrapperChildren.remove(comp2); |
|||
*/ |
|||
getComponents: function(){ |
|||
return this.getWrapper().get('components'); |
|||
}, |
|||
|
|||
/** |
|||
* Render and returns wrapper |
|||
* |
|||
* @return {Object} |
|||
* Add new components to the wrapper's children. It's the same |
|||
* as 'domComponents.getComponents().add(...)' |
|||
* @param {Object|Component|Array<Object>} component Component/s to add |
|||
* @param {string} [component.tagName='div'] Tag name |
|||
* @param {string} [component.type=''] Type of the component. Available: ''(default), 'text', 'image' |
|||
* @param {boolean} [component.removable=true] If component is removable |
|||
* @param {boolean} [component.draggable=true] If is possible to move the component around the structure |
|||
* @param {boolean} [component.droppable=true] If is possible to drop inside other components |
|||
* @param {boolean} [component.badgable=true] If the badge is visible when the component is selected |
|||
* @param {boolean} [component.stylable=true] If is possible to style component |
|||
* @param {boolean} [component.copyable=true] If is possible to copy&paste the component |
|||
* @param {string} [component.content=''] String inside component |
|||
* @param {Object} [component.style={}] Style object |
|||
* @param {Object} [component.attributes={}] Attribute object |
|||
* @return {Component|Array<Component>} Component/s added |
|||
* @example |
|||
* // Example of a new component with some extra property
|
|||
* var comp1 = domComponents.addComponent({ |
|||
* tagName: 'div', |
|||
* removable: true, // Can't remove it
|
|||
* draggable: true, // Can't move it
|
|||
* copyable: true, // Disable copy/past
|
|||
* content: 'Content text', // Text inside component
|
|||
* style: { color: 'red'}, |
|||
* attributes: { title: 'here' } |
|||
* }); |
|||
*/ |
|||
render : function(){ |
|||
return this.ComponentView.render().el; |
|||
addComponent: function(component){ |
|||
return this.getComponents().add(component); |
|||
}, |
|||
}; |
|||
|
|||
return Components; |
|||
}); |
|||
/** |
|||
* Render and returns wrapper element with all components inside. |
|||
* Once the wrapper is rendered, and it's what happens when you init the editor, |
|||
* the all new components will be added automatically and property changes are all |
|||
* updated immediately |
|||
* @return {HTMLElement} |
|||
*/ |
|||
render: function(){ |
|||
return componentView.render().el; |
|||
}, |
|||
|
|||
/** |
|||
* Remove all components |
|||
* @return {this} |
|||
*/ |
|||
clear: function(){ |
|||
var c = this.getComponents(); |
|||
for(var i = 0, len = c.length; i < len; i++) |
|||
c.pop(); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Set components |
|||
* @param {Object|string} components HTML string or components model |
|||
* @return {this} |
|||
* @private |
|||
*/ |
|||
setComponents: function(components){ |
|||
this.clear().addComponent(components); |
|||
}, |
|||
|
|||
}; |
|||
}; |
|||
}); |
|||
|
|||
@ -1,14 +1,13 @@ |
|||
define(['./Component'], |
|||
define(['./Component'], |
|||
function (Component) { |
|||
/** |
|||
* @class ComponentImage |
|||
* */ |
|||
return Component.extend({ |
|||
|
|||
|
|||
return Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
src : '', |
|||
droppable : false, |
|||
src: '', |
|||
droppable: false, |
|||
traits: ['alt'], |
|||
}), |
|||
|
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -0,0 +1,13 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
|
|||
return Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
tagName: 'a', |
|||
droppable: false, |
|||
traits: ['title', 'href', 'target'], |
|||
}), |
|||
|
|||
}); |
|||
}); |
|||
@ -1,14 +1,12 @@ |
|||
define(['./Component'], |
|||
define(['./Component'], |
|||
function (Component) { |
|||
/** |
|||
* @class ComponentText |
|||
* */ |
|||
return Component.extend({ |
|||
|
|||
|
|||
return Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
content : '', |
|||
droppable : false, |
|||
}), |
|||
|
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -0,0 +1,15 @@ |
|||
define(['backbone', './ComponentView'], |
|||
function (Backbone, ComponentView) { |
|||
|
|||
return ComponentView.extend({ |
|||
|
|||
events: { |
|||
'click': 'onClick', |
|||
}, |
|||
|
|||
onClick: function(e) { |
|||
e.preventDefault(); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,68 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
|
|||
return Backbone.View.extend({ |
|||
|
|||
itemView: '', |
|||
|
|||
// Defines the View per type
|
|||
itemsView: '', |
|||
|
|||
itemType: 'type', |
|||
|
|||
initialize: function(opts, config) { |
|||
this.config = config || {}; |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* Add new model to the collection |
|||
* @param {Model} model |
|||
* @private |
|||
* */ |
|||
addTo: function(model){ |
|||
this.add(model); |
|||
}, |
|||
|
|||
/** |
|||
* Render new model inside the view |
|||
* @param {Model} model |
|||
* @param {Object} fragment Fragment collection |
|||
* @private |
|||
* */ |
|||
add: function(model, fragment){ |
|||
var frag = fragment || null; |
|||
var itemView = this.itemView; |
|||
if(this.itemsView){ |
|||
var typeField = model.get(this.itemType); |
|||
itemView = this.itemsView[typeField]; |
|||
} |
|||
var view = new itemView({ |
|||
model: model, |
|||
config: this.config |
|||
}, this.config); |
|||
var rendered = view.render().el; |
|||
|
|||
if(frag) |
|||
frag.appendChild(rendered); |
|||
else |
|||
this.$el.append(rendered); |
|||
}, |
|||
|
|||
|
|||
|
|||
render: function() { |
|||
var frag = document.createDocumentFragment(); |
|||
this.$el.empty(); |
|||
|
|||
if(this.collection.length) |
|||
this.collection.each(function(model){ |
|||
this.add(model, frag); |
|||
}, this); |
|||
|
|||
this.$el.append(frag); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -1,72 +1,183 @@ |
|||
define(function () { |
|||
var config = { |
|||
var blkStyle = '.blk-row::after{ content: ""; clear: both; display: block;} .blk-row{padding: 10px;}'; |
|||
return { |
|||
|
|||
// Style prefix
|
|||
stylePrefix: 'wte-', |
|||
stylePrefix: 'gjs-', |
|||
|
|||
// Prefix to use inside local storage name
|
|||
storagePrefix: 'wte-', |
|||
//TEMP
|
|||
components: '', |
|||
|
|||
// Editor ID. Useful in case of multiple editors on the same page
|
|||
id : '', |
|||
// Enable/Disable possibility to copy(ctrl + c) & paste(ctrl + v) components
|
|||
copyPaste: true, |
|||
|
|||
// Where render the editor
|
|||
container : '', |
|||
// Enable/Disable undo manager
|
|||
undoManager: true, |
|||
|
|||
idCanvas : 'canvas', |
|||
// Height for the editor container
|
|||
height: '900px', |
|||
|
|||
idCanvasOverlay : 'canvas-overlay', |
|||
// Width for the editor container
|
|||
width: '100%', |
|||
|
|||
idWrapper : 'wrapper', |
|||
// The css that could only be seen (for instance, inside the code viewer)
|
|||
protectedCss: '*{box-sizing: border-box;}body{margin:0;height:100%}#wrapper{min-height:100%; overflow:auto}', |
|||
|
|||
// Enable/Disable possibility to copy(ctrl + c) & paste(ctrl + v) components
|
|||
copyPaste : true, |
|||
// Default command
|
|||
defaultCommand: 'select-comp', |
|||
|
|||
// Enable/Disable undo manager
|
|||
undoManager : true, |
|||
// If true render a select of available devices
|
|||
showDevices: 1, |
|||
|
|||
//Indicates which storage to use. Available: local | remote | none
|
|||
storageType : 'local', |
|||
// Dom element
|
|||
el: '', |
|||
|
|||
//Configurations for Asset Manager
|
|||
assetManager : {}, |
|||
assetManager: {}, |
|||
|
|||
//Configurations for Canvas
|
|||
canvas : {}, |
|||
canvas: {}, |
|||
|
|||
//Configurations for Style Manager
|
|||
styleManager : {}, |
|||
styleManager: {}, |
|||
|
|||
//Configurations for Layers
|
|||
layers : {}, |
|||
layers: {}, |
|||
|
|||
//Configurations for Storage Manager
|
|||
storageManager : {}, |
|||
storageManager: {}, |
|||
|
|||
//Configurations for Rich Text Editor
|
|||
rte : {}, |
|||
rte: {}, |
|||
|
|||
//Configurations for Components
|
|||
components : {}, |
|||
//Configurations for DomComponents
|
|||
domComponents: {}, |
|||
|
|||
//Configurations for Modal Dialog
|
|||
modal : {}, |
|||
modal: {}, |
|||
|
|||
//Configurations for Code Manager
|
|||
codeManager : {}, |
|||
codeManager: {}, |
|||
|
|||
//Configurations for Panels
|
|||
panels : {}, |
|||
panels: {}, |
|||
|
|||
//Configurations for Commands
|
|||
commands : {}, |
|||
|
|||
//Configurations for Class Manager
|
|||
classManager : {}, |
|||
commands: {}, |
|||
|
|||
//Configurations for Css Composer
|
|||
cssComposer : {}, |
|||
cssComposer: {}, |
|||
|
|||
//Configurations for Selector Manager
|
|||
selectorManager: {}, |
|||
|
|||
//Configurations for Device Manager
|
|||
deviceManager: { |
|||
'devices': [{ |
|||
name: 'Desktop', |
|||
width: '', |
|||
},{ |
|||
name: 'Tablet', |
|||
width: '992px', |
|||
},{ |
|||
name: 'Mobile landscape', |
|||
width: '768px', |
|||
},{ |
|||
name: 'Mobile portrait', |
|||
width: '480px', |
|||
}], |
|||
}, |
|||
|
|||
//Configurations for Block Manager
|
|||
blockManager: { |
|||
'blocks': [{ |
|||
id: 'b1', |
|||
label: '1 Block', |
|||
content: '<div class="blk-row"><div class="blk1"></div></div><style>'+ blkStyle +'.blk1{width: 100%;padding: 10px;min-height: 75px;}</style>', |
|||
attributes: {class:'gjs-fonts gjs-f-b1'} |
|||
},{ |
|||
id: 'b2', |
|||
label: '2 Blocks', |
|||
content: '<div class="blk-row"><div class="blk2"></div><div class="blk2"></div></div><style>'+ blkStyle +'.blk2{float: left;width: 50%;padding: 10px;min-height: 75px;}</style>', |
|||
attributes: {class:'gjs-fonts gjs-f-b2'} |
|||
},{ |
|||
id: 'b3', |
|||
label: '3 Blocks', |
|||
content: '<div class="blk-row"><div class="blk3"></div><div class="blk3"></div><div class="blk3"></div></div><style>'+ blkStyle +'.blk3{float: left;width: 33.3333%;padding: 10px;min-height: 75px;}</style>', |
|||
attributes: {class:'gjs-fonts gjs-f-b3'} |
|||
},{ |
|||
id: 'b4', |
|||
label: '3/7 Block', |
|||
content: '<div class="blk-row"><div class="blk37l"></div><div class="blk37r"></div></div></div><style>'+ blkStyle +'.blk37l{float: left;width: 30%;padding: 10px;min-height: 75px;}.blk37r{float: left;width: 70%;padding: 10px;min-height: 75px;}</style>', |
|||
attributes: {class:'gjs-fonts gjs-f-b37'} |
|||
},{ |
|||
id: 'hero', |
|||
label: 'Hero section', |
|||
content: '<header class="header-banner"> <div class="container-width">'+ |
|||
'<div class="logo-container"><div class="logo">GrapesJS</div></div>'+ |
|||
'<nav class="navbar">'+ |
|||
'<div class="menu-item">BUILDER</div><div class="menu-item">TEMPLATE</div><div class="menu-item">WEB</div>'+ |
|||
'</nav><div class="clearfix"></div>'+ |
|||
'<div class="lead-title">Build your templates without coding</div>'+ |
|||
'<div class="lead-btn">Try it now</div></div></header>', |
|||
attributes: {class:'gjs-fonts gjs-f-hero'} |
|||
},{ |
|||
id: 'h1p', |
|||
label: 'Text section', |
|||
content: '<h1 class="heading">Insert title here</h1><p class="paragraph">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</p>', |
|||
attributes: {class:'gjs-fonts gjs-f-h1p'} |
|||
},{ |
|||
id: '3ba', |
|||
label: 'Badges', |
|||
content: '<div class="badges">'+ |
|||
'<div class="badge">'+ |
|||
'<div class="badge-header"></div>'+ |
|||
'<img class="badge-avatar" src="img/team1.jpg">'+ |
|||
'<div class="badge-body">'+ |
|||
'<div class="badge-name">Adam Smith</div><div class="badge-role">CEO</div><div class="badge-desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</div>'+ |
|||
'</div>'+ |
|||
'<div class="badge-foot"><span class="badge-link">f</span><span class="badge-link">t</span><span class="badge-link">ln</span></div>'+ |
|||
'</div>'+ |
|||
'<div class="badge">'+ |
|||
'<div class="badge-header"></div>'+ |
|||
'<img class="badge-avatar" src="img/team2.jpg">'+ |
|||
'<div class="badge-body">'+ |
|||
'<div class="badge-name">John Black</div><div class="badge-role">Software Engineer</div><div class="badge-desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</div>'+ |
|||
'</div>'+ |
|||
'<div class="badge-foot"><span class="badge-link">f</span><span class="badge-link">t</span><span class="badge-link">ln</span></div>'+ |
|||
'</div>'+ |
|||
'<div class="badge">'+ |
|||
'<div class="badge-header"></div>'+ |
|||
'<img class="badge-avatar" src="img/team3.jpg">'+ |
|||
'<div class="badge-body">'+ |
|||
'<div class="badge-name">Jessica White</div><div class="badge-role">Web Designer</div><div class="badge-desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</div>'+ |
|||
'</div>'+ |
|||
'<div class="badge-foot"><span class="badge-link">f</span><span class="badge-link">t</span><span class="badge-link">ln</span>'+ |
|||
'</div>'+ |
|||
'</div></div>', |
|||
attributes: {class:'gjs-fonts gjs-f-3ba'} |
|||
},{ |
|||
id: 'text', |
|||
label: 'Text', |
|||
attributes: {class:'gjs-fonts gjs-f-text'}, |
|||
content: { |
|||
type:'text', |
|||
content:'Insert your text here', |
|||
style: {padding: '10px' }, |
|||
activeOnRender: 1 |
|||
}, |
|||
},{ |
|||
id: 'image', |
|||
label: 'Image', |
|||
attributes: {class:'gjs-fonts gjs-f-image'}, |
|||
content: { type:'image', activeOnRender: 1}, |
|||
},{ |
|||
id: 'quo', |
|||
label: 'Quote', |
|||
content: '<blockquote class="quote">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</blockquote>', |
|||
attributes: {class:'gjs-fonts gjs-f-quo'} |
|||
}], |
|||
}, |
|||
|
|||
}; |
|||
return config; |
|||
}); |
|||
}); |
|||
|
|||
@ -1,39 +1,402 @@ |
|||
/** |
|||
* |
|||
* * [getConfig](#getconfig) |
|||
* * [getHtml](#gethtml) |
|||
* * [getCss](#getcss) |
|||
* * [getComponents](#getcomponents) |
|||
* * [setComponents](#setcomponents) |
|||
* * [getStyle](#getstyle) |
|||
* * [setStyle](#setstyle) |
|||
* * [getSelected](#getselected) |
|||
* * [setDevice](#setdevice) |
|||
* * [getDevice](#getdevice) |
|||
* * [runCommand](#runcommand) |
|||
* * [stopCommand](#stopcommand) |
|||
* * [store](#store) |
|||
* * [load](#load) |
|||
* * [getContainer](#getcontainer) |
|||
* * [on](#on) |
|||
* * [trigger](#trigger) |
|||
* * [render](#render) |
|||
* |
|||
* Editor class contains the top level API which you'll probably use to custom the editor or extend it with plugins. |
|||
* You get the Editor instance on init method |
|||
* |
|||
* ```js
|
|||
* var editor = grapesjs.init({...}); |
|||
* ``` |
|||
* Available events |
|||
* #run:{commandName} |
|||
* #stop:{commandName} |
|||
* #load - When the editor is loaded |
|||
* |
|||
* @module Editor |
|||
* @param {Object} config Configurations |
|||
* @param {string} config.container='' Selector for the editor container, eg. '#myEditor' |
|||
* @param {string|Array<Object>} [config.components=''] HTML string or object of components |
|||
* @param {string|Array<Object>} [config.style=''] CSS string or object of rules |
|||
* @param {Boolean} [config.fromElement=false] If true, will fetch HTML and CSS from selected container |
|||
* @param {Boolean} [config.copyPaste=true] Enable/Disable the possibility to copy(ctrl + c) & paste(ctrl + v) components |
|||
* @param {Boolean} [config.undoManager=true] Enable/Disable undo manager |
|||
* @param {Boolean} [config.autorender=true] If true renders editor on init |
|||
* @param {Boolean} [config.noticeOnUnload=true] Enable/Disable alert message before unload the page |
|||
* @param {string} [config.height='900px'] Height for the editor container |
|||
* @param {string} [config.width='100%'] Width for the editor container |
|||
* @param {Object} [config.storage={}] Storage manager configuration, see the relative documentation |
|||
* @param {Object} [config.styleManager={}] Style manager configuration, see the relative documentation |
|||
* @param {Object} [config.commands={}] Commands configuration, see the relative documentation |
|||
* @param {Object} [config.domComponents={}] Components configuration, see the relative documentation |
|||
* @param {Object} [config.panels={}] Panels configuration, see the relative documentation |
|||
* @param {Object} [config.showDevices=true] If true render a select of available devices inside style manager panel |
|||
* @param {string} [config.defaultCommand='select-comp'] Command to execute when no other command is running |
|||
* @param {Array} [config.plugins=[]] Array of plugins to execute on start |
|||
* @param {Object} [config.pluginsOpts={}] Custom options for plugins |
|||
* @example |
|||
* var editor = grapesjs.init({ |
|||
* container : '#gjs', |
|||
* components: '<div class="txt-red">Hello world!</div>', |
|||
* style: '.txt-red{color: red}', |
|||
* }); |
|||
*/ |
|||
define(function (require){ |
|||
/** |
|||
* @class Grapes |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
var Grapes = function(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Editor = require('./model/Editor'), |
|||
EditorView = require('./view/EditorView'); |
|||
|
|||
var Editor = function(config) { |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
EditorModel = require('./model/Editor'), |
|||
EditorView = require('./view/EditorView'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
c.pStylePrefix = c.stylePrefix; |
|||
|
|||
this.editor = new Editor(c); |
|||
var obj = { |
|||
model : this.editor, |
|||
config : c, |
|||
}; |
|||
var em = new EditorModel(c); |
|||
|
|||
this.editorView = new EditorView(obj); |
|||
}; |
|||
var editorView = new EditorView({ |
|||
model: em, |
|||
config: c, |
|||
}); |
|||
|
|||
Grapes.prototype = { |
|||
return { |
|||
|
|||
render : function() |
|||
{ |
|||
return this.editorView.render().$el; |
|||
} |
|||
/** |
|||
* @property {EditorModel} |
|||
* @private |
|||
*/ |
|||
editor: em, |
|||
|
|||
/** |
|||
* @property {DomComponents} |
|||
*/ |
|||
DomComponents: em.get('DomComponents'), |
|||
|
|||
/** |
|||
* @property {CssComposer} |
|||
*/ |
|||
CssComposer: em.get('CssComposer'), |
|||
|
|||
/** |
|||
* @property {StorageManager} |
|||
*/ |
|||
StorageManager: em.get('StorageManager'), |
|||
|
|||
/** |
|||
* @property {AssetManager} |
|||
*/ |
|||
AssetManager: em.get('AssetManager'), |
|||
|
|||
/** |
|||
* @property {BlockManager} |
|||
*/ |
|||
BlockManager: em.get('BlockManager'), |
|||
|
|||
/** |
|||
* @property {TraitManager} |
|||
*/ |
|||
TraitManager: em.get('TraitManager'), |
|||
|
|||
/** |
|||
* @property {SelectorManager} |
|||
*/ |
|||
SelectorManager: em.get('SelectorManager'), |
|||
|
|||
/** |
|||
* @property {CodeManager} |
|||
*/ |
|||
CodeManager: em.get('CodeManager'), |
|||
|
|||
/** |
|||
* @property {Commands} |
|||
*/ |
|||
Commands: em.get('Commands'), |
|||
|
|||
/** |
|||
* @property {Modal} |
|||
*/ |
|||
Modal: em.get('Modal'), |
|||
|
|||
/** |
|||
* @property {Panels} |
|||
*/ |
|||
Panels: em.get('Panels'), |
|||
|
|||
/** |
|||
* @property {StyleManager} |
|||
*/ |
|||
StyleManager: em.get('StyleManager'), |
|||
|
|||
/** |
|||
* @property {Canvas} |
|||
*/ |
|||
Canvas: em.get('Canvas'), |
|||
|
|||
/** |
|||
* @property {UndoManager} |
|||
*/ |
|||
UndoManager: em.get('UndoManager'), |
|||
|
|||
/** |
|||
* @property {DeviceManager} |
|||
*/ |
|||
DeviceManager: em.get('DeviceManager'), |
|||
|
|||
/** |
|||
* @property {RichTextEditor} |
|||
*/ |
|||
RichTextEditor: em.get('rte'), |
|||
|
|||
/** |
|||
* @property {Utils} |
|||
*/ |
|||
Utils: em.get('Utils'), |
|||
|
|||
/** |
|||
* @property {Utils} |
|||
*/ |
|||
Config: em.get('Config'), |
|||
|
|||
/** |
|||
* Initialize editor model |
|||
* @return {this} |
|||
* @private |
|||
*/ |
|||
init: function(){ |
|||
em.init(this); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns configuration object |
|||
* @return {Object} |
|||
*/ |
|||
getConfig: function(){ |
|||
return c; |
|||
}, |
|||
|
|||
/** |
|||
* Returns HTML built inside canvas |
|||
* @return {string} HTML string |
|||
*/ |
|||
getHtml: function(){ |
|||
return em.getHtml(); |
|||
}, |
|||
|
|||
/** |
|||
* Returns CSS built inside canvas |
|||
* @return {string} CSS string |
|||
*/ |
|||
getCss: function(){ |
|||
return em.getCss(); |
|||
}, |
|||
|
|||
/** |
|||
* Returns components in JSON format object |
|||
* @return {Object} |
|||
*/ |
|||
getComponents: function(){ |
|||
return em.get('DomComponents').getComponents(); |
|||
}, |
|||
|
|||
/** |
|||
* Set components inside editor's canvas. This method overrides actual components |
|||
* @param {Array<Object>|Object|string} components HTML string or components model |
|||
* @return {this} |
|||
* @example |
|||
* editor.setComponents('<div class="cls">New component</div>'); |
|||
* // or
|
|||
* editor.setComponents({ |
|||
* type: 'text', |
|||
* classes:['cls'], |
|||
* content: 'New component' |
|||
* }); |
|||
*/ |
|||
setComponents: function(components){ |
|||
em.setComponents(components); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns style in JSON format object |
|||
* @return {Object} |
|||
*/ |
|||
getStyle: function(){ |
|||
return em.get('CssComposer').getAll(); |
|||
}, |
|||
|
|||
/** |
|||
* Set style inside editor's canvas. This method overrides actual style |
|||
* @param {Array<Object>|Object|string} style CSS string or style model |
|||
* @return {this} |
|||
* @example |
|||
* editor.setStyle('.cls{color: red}'); |
|||
* //or
|
|||
* editor.setStyle({ |
|||
* selectors: ['cls'] |
|||
* style: { color: 'red' } |
|||
* }); |
|||
*/ |
|||
setStyle: function(style){ |
|||
em.setStyle(style); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns selected component, if there is one |
|||
* @return {grapesjs.Component} |
|||
*/ |
|||
getSelected: function(){ |
|||
return em.getSelected(); |
|||
}, |
|||
|
|||
/** |
|||
* Set device to the editor. If the device exists it will |
|||
* change the canvas to the proper width |
|||
* @return {this} |
|||
* @example |
|||
* editor.setDevice('Tablet'); |
|||
*/ |
|||
setDevice: function(name){ |
|||
return em.set('device', name); |
|||
}, |
|||
|
|||
/** |
|||
* Return the actual active device |
|||
* @return {string} Device name |
|||
* @example |
|||
* var device = editor.getDevice(); |
|||
* console.log(device); |
|||
* // 'Tablet'
|
|||
*/ |
|||
getDevice: function(){ |
|||
return em.get('device'); |
|||
}, |
|||
|
|||
/** |
|||
* Execute command |
|||
* @param {string} id Command ID |
|||
* @param {Object} options Custom options |
|||
* @example |
|||
* editor.runCommand('myCommand', {someValue: 1}); |
|||
*/ |
|||
runCommand: function(id, options) { |
|||
var command = em.get('Commands').get(id); |
|||
|
|||
if(command){ |
|||
command.run(this, this, options); |
|||
this.trigger('run:' + id); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Stop the command if stop method was provided |
|||
* @param {string} id Command ID |
|||
* @param {Object} options Custom options |
|||
* @example |
|||
* editor.stopCommand('myCommand', {someValue: 1}); |
|||
*/ |
|||
stopCommand: function(id, options) { |
|||
var command = em.get('Commands').get(id); |
|||
|
|||
if(command){ |
|||
command.stop(this, this, options); |
|||
this.trigger('stop:' + id); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Store data to the current storage |
|||
* @return {Object} Stored data |
|||
*/ |
|||
store: function(){ |
|||
return em.store(); |
|||
}, |
|||
|
|||
/** |
|||
* Load data from the current storage |
|||
* @return {Object} Stored data |
|||
*/ |
|||
load: function(){ |
|||
return em.load(); |
|||
}, |
|||
|
|||
/** |
|||
* Returns container element. The one which was indicated as 'container' on init method |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getContainer: function(){ |
|||
return c.el; |
|||
}, |
|||
|
|||
/** |
|||
* Attach event |
|||
* @param {string} event Event name |
|||
* @param {Function} callback Callback function |
|||
* @return {this} |
|||
*/ |
|||
on: function(event, callback){ |
|||
return em.on(event, callback); |
|||
}, |
|||
|
|||
/** |
|||
* Trigger event |
|||
* @param {string} event Event to trigger |
|||
* @return {this} |
|||
*/ |
|||
trigger: function(event){ |
|||
return em.trigger(event); |
|||
}, |
|||
|
|||
/** |
|||
* Returns editor element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getEl: function(){ |
|||
return editorView.el; |
|||
}, |
|||
|
|||
/** |
|||
* Returns editor model |
|||
* @return {Model} |
|||
* @private |
|||
*/ |
|||
getModel: function(){ |
|||
return em; |
|||
}, |
|||
|
|||
/** |
|||
* Render editor |
|||
* @return {HTMLElement} |
|||
*/ |
|||
render: function() { |
|||
return editorView.render().el; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
|
|||
return Grapes; |
|||
}); |
|||
return Editor; |
|||
}); |
|||
|
|||
@ -1,41 +1,41 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
/** |
|||
* @class EditorView |
|||
* */ |
|||
|
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function() { |
|||
this.cv = this.model.get('Canvas'); |
|||
this.pn = this.model.get('Panels'); |
|||
this.css = this.model.get('CssComposer'); |
|||
this.className = this.model.config.stylePrefix + 'editor'; |
|||
this.conf = this.model.config; |
|||
this.className = this.conf.stylePrefix + 'editor'; |
|||
this.model.on('loaded', function(){ |
|||
this.pn.active(); |
|||
this.model.runDefault(); |
|||
this.model.trigger('load'); |
|||
}, this); |
|||
}, |
|||
|
|||
render: function(){ |
|||
var conf = this.conf; |
|||
this.$el.empty(); |
|||
this.$cont = $(conf.el || ('body ' + conf.container)); |
|||
|
|||
this.$cont = $('body ' + this.model.config.container); |
|||
|
|||
this.model.set('$editor', this.$el); |
|||
if(conf.width) |
|||
this.$cont.css('width', conf.width); |
|||
|
|||
if(this.cv) |
|||
this.$el.append(this.cv.render()); |
|||
if(conf.height) |
|||
this.$cont.css('height', conf.height); |
|||
|
|||
if(this.pn) |
|||
this.$el.append(this.pn.render()); |
|||
// Canvas
|
|||
this.$el.append(this.model.get('Canvas').render()); |
|||
|
|||
if(this.css) |
|||
this.$el.append(this.css.render()); |
|||
// Panels
|
|||
this.$el.append(this.pn.render()); |
|||
|
|||
this.$el.attr('class', this.className); |
|||
|
|||
this.$cont.html(this.$el); |
|||
|
|||
if(this.pn) |
|||
this.pn.active(); |
|||
|
|||
return this; |
|||
} |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
@ -0,0 +1,37 @@ |
|||
define(function () { |
|||
return { |
|||
// If true renders editor on init
|
|||
autorender: 1, |
|||
|
|||
// Where init the editor
|
|||
container: '', |
|||
|
|||
// HTML string or object of components
|
|||
components: '', |
|||
|
|||
// CSS string or object of rules
|
|||
style: '', |
|||
|
|||
// If true, will fetch HTML and CSS from selected container
|
|||
fromElement: 0, |
|||
|
|||
// ---
|
|||
// Enable/Disable the possibility to copy(ctrl + c) & paste(ctrl + v) components
|
|||
copyPaste: true, |
|||
|
|||
// Enable/Disable undo manager
|
|||
undoManager: true, |
|||
|
|||
// Show an alert before unload the page
|
|||
noticeOnUnload: true, |
|||
|
|||
// Storage Manager
|
|||
storageManager: {}, |
|||
|
|||
// Array of plugins to init
|
|||
plugins: [], |
|||
|
|||
// Custom options for plugins
|
|||
pluginsOpts: {} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,79 @@ |
|||
define(function (require) { |
|||
|
|||
return function(config) { |
|||
|
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Editor = require('editor/main'), |
|||
PluginManager = require('PluginManager'); |
|||
|
|||
var plugins = new PluginManager(); |
|||
var editors = []; |
|||
|
|||
return { |
|||
|
|||
plugins: plugins, |
|||
|
|||
/** |
|||
* Initializes an editor based on passed options |
|||
* @param {Object} config Configuration object |
|||
* @param {string} config.container Selector which indicates where render the editor |
|||
* @param {Object|string} config.components='' HTML string or Component model in JSON format |
|||
* @param {Object|string} config.style='' CSS string or CSS model in JSON format |
|||
* @param {Boolean} [config.fromElement=false] If true, will fetch HTML and CSS from selected container |
|||
* @param {Boolean} [config.copyPaste=true] Enable/Disable the possibility to copy(ctrl+c) & paste(ctrl+v) components |
|||
* @param {Boolean} [config.undoManager=true] Enable/Disable undo manager |
|||
* @param {Array} [config.plugins=[]] Array of plugins to execute on start |
|||
* @return {grapesjs.Editor} GrapesJS editor instance |
|||
* @example |
|||
* var editor = grapesjs.init({ |
|||
* container: '#myeditor', |
|||
* components: '<article class="hello">Hello world</article>', |
|||
* style: '.hello{color: red}', |
|||
* }) |
|||
*/ |
|||
init: function(config) { |
|||
var c = config || {}; |
|||
var els = c.container; |
|||
|
|||
// Set default options
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
if(!els) |
|||
throw new Error("'container' is required"); |
|||
|
|||
if(c.noticeOnUnload) |
|||
window.onbeforeunload = function(e) { |
|||
return 1; |
|||
}; |
|||
|
|||
c.el = document.querySelector(els); |
|||
var editor = new Editor(c).init(); |
|||
|
|||
// Execute all plugins
|
|||
var plugs = plugins.getAll(); |
|||
for (var id in plugs){ |
|||
// Check if plugin is requested
|
|||
if(c.plugins.indexOf(id) < 0) |
|||
continue; |
|||
|
|||
var opts = c.pluginsOpts[id] || {}; |
|||
var plug = plugins.get(id); |
|||
plug(editor, opts); |
|||
} |
|||
|
|||
if(c.autorender) |
|||
editor.render(); |
|||
|
|||
editors.push(editor); |
|||
return editor; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}(); |
|||
|
|||
}); |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue