mirror of https://github.com/artf/grapesjs.git
345 changed files with 20218 additions and 29374 deletions
@ -1,252 +0,0 @@ |
|||
module.exports = function(grunt) { |
|||
|
|||
var appPath = 'src', |
|||
buildPath = 'dist', |
|||
stylePath = 'styles', |
|||
configPath = 'config/require-config.js', |
|||
port = grunt.option('port') || 8000; |
|||
|
|||
grunt.loadNpmTasks('grunt-contrib-requirejs'); |
|||
grunt.loadNpmTasks('grunt-contrib-connect'); |
|||
grunt.loadNpmTasks('grunt-contrib-uglify'); |
|||
grunt.loadNpmTasks('grunt-contrib-cssmin'); |
|||
grunt.loadNpmTasks('grunt-contrib-jshint'); |
|||
grunt.loadNpmTasks('grunt-contrib-concat'); |
|||
grunt.loadNpmTasks('grunt-contrib-watch'); |
|||
grunt.loadNpmTasks('grunt-contrib-clean'); |
|||
grunt.loadNpmTasks('grunt-contrib-copy'); |
|||
grunt.loadNpmTasks('grunt-bowercopy'); |
|||
grunt.loadNpmTasks('grunt-mocha'); |
|||
grunt.loadNpmTasks('grunt-sass'); |
|||
|
|||
grunt.initConfig({ |
|||
appDir: appPath, |
|||
builtDir: buildPath, |
|||
styleDir: stylePath, |
|||
pkg: grunt.file.readJSON("package.json"), |
|||
|
|||
requirejs:{ |
|||
compile:{ |
|||
options: { |
|||
mainConfigFile: '<%= appDir %>/' + configPath, |
|||
appDir: '<%= appDir %>', |
|||
dir: '<%= builtDir %>', |
|||
baseUrl: './', |
|||
name: 'main', |
|||
include: ["./../node_modules/almond/almond"], |
|||
removeCombined: true, |
|||
findNestedDependencies: true, |
|||
keepBuildDir: true, |
|||
inlineText: true, |
|||
optimize: 'none', |
|||
wrap: { |
|||
start: "(function (root, factory) {"+ |
|||
"if (typeof define === 'function' && define.amd)"+ |
|||
"define([], factory);"+ |
|||
"else if(typeof exports === 'object' && typeof module === 'object')"+ |
|||
"module.exports = factory();"+ |
|||
"else "+ |
|||
"root.<%= pkg.name %> = root.GrapesJS = factory();"+ |
|||
"}(this, function () {", |
|||
end: "return require('grapesjs/main'); }));" |
|||
}, |
|||
|
|||
paths: { |
|||
"jquery": "wrappers/jquery", |
|||
} |
|||
|
|||
} |
|||
} |
|||
}, |
|||
|
|||
jshint: { |
|||
all: [ |
|||
'Gruntfile.js', |
|||
'<%= appDir %>/**/*.js', |
|||
] |
|||
}, |
|||
|
|||
uglify: { |
|||
options: { |
|||
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> */\n' |
|||
}, |
|||
build:{ |
|||
files: { |
|||
'<%= builtDir %>/grapes.min.js': ['<%= builtDir %>/main.js'] |
|||
} |
|||
} |
|||
}, |
|||
|
|||
sass: { |
|||
dist: { |
|||
files: [{ |
|||
expand: true, |
|||
cwd: '<%= styleDir %>/scss', |
|||
src: ['**/*.scss'], |
|||
dest: '<%= styleDir %>/css', |
|||
ext: '.css' |
|||
}] |
|||
} |
|||
}, |
|||
|
|||
cssmin: { |
|||
target: { |
|||
files: [{ |
|||
expand: true, |
|||
flatten: true, |
|||
src: [ |
|||
'<%= styleDir %>/css/main.css', |
|||
'node_modules/codemirror/lib/codemirror.css', |
|||
'node_modules/codemirror/theme/hopscotch.css' |
|||
], |
|||
dest: '<%= builtDir %>', |
|||
ext: '.min.css' |
|||
}] |
|||
} |
|||
}, |
|||
|
|||
concat: { |
|||
css: { |
|||
src: ['<%= builtDir %>/*.min.css'], |
|||
dest: '<%= builtDir %>/css/grapes.min.css' |
|||
} |
|||
}, |
|||
|
|||
mocha: { |
|||
test: { |
|||
src: ['test/index.html'], |
|||
options: { log: true, }, |
|||
}, |
|||
}, |
|||
|
|||
connect: { |
|||
server: { |
|||
options: { |
|||
port: port, |
|||
open: true |
|||
} |
|||
}, |
|||
}, |
|||
/* |
|||
bowercopy: { |
|||
options: { |
|||
srcPrefix: 'bower_components' |
|||
}, |
|||
scripts: { |
|||
options: { |
|||
destPrefix: 'vendor' |
|||
}, |
|||
files: { |
|||
'almond/almond.js' : 'almond/almond.js', |
|||
'jquery/jquery.js' : 'jquery/dist/jquery.min.js', |
|||
'underscore/underscore.js' : 'underscore/underscore-min.js', |
|||
'backbone/backbone.js' : 'backbone/backbone-min.js', |
|||
'backbone-undo/backbone-undo.js' : 'Backbone.Undo/Backbone.Undo.js', |
|||
'keymaster/keymaster.js' : 'keymaster/keymaster.js', |
|||
'require/require.js' : 'requirejs/require.js', |
|||
'require-text/text.js' : 'requirejs-text/text.js', |
|||
'spectrum/spectrum.js' : 'spectrum/spectrum.js', |
|||
'codemirror' : 'codemirror', |
|||
'codemirror-formatting' : 'codemirror-formatting/formatting.js', |
|||
'mocha' : 'mocha', |
|||
'chai' : 'chai/chai.js', |
|||
'sinon' : 'sinonjs/sinon.js', |
|||
}, |
|||
} |
|||
}, |
|||
*/ |
|||
watch: { |
|||
script: { |
|||
files: [ '<%= appDir %>/**/*.js' ], |
|||
tasks: ['jshint'] |
|||
}, |
|||
css: { |
|||
files: '**/*.scss', |
|||
tasks: ['sass'] |
|||
}, |
|||
test: { |
|||
files: ['test/specs/**/*.js'], |
|||
tasks: ['mocha'], |
|||
//options: { livereload: true }, //default port 35729
|
|||
} |
|||
}, |
|||
|
|||
clean: { |
|||
all: ["<%= builtDir %>/*", "!<%= builtDir %>/grapes.min.js", "!<%= builtDir %>/css"] |
|||
}, |
|||
|
|||
copy: { |
|||
fonts: { |
|||
cwd: '<%= styleDir %>/fonts', |
|||
src: '**/*', |
|||
dest: '<%= builtDir %>/fonts', |
|||
expand: true |
|||
} |
|||
} |
|||
|
|||
}); |
|||
|
|||
/** |
|||
* Have to copy require configs cause r.js will try to load them from the path indicated inside |
|||
* main.js file. This is the only way I have found to do it |
|||
* */ |
|||
grunt.registerTask('before-rjs', function() { |
|||
if(grunt.file.exists(buildPath)) |
|||
grunt.file.delete(buildPath); |
|||
grunt.file.mkdir(buildPath); |
|||
grunt.file.copy(appPath + '/' + configPath, buildPath + '/' + appPath + '/' + configPath); |
|||
}); |
|||
|
|||
grunt.registerTask('webfont-custom', function() { |
|||
var dir = './styles/fonts/'; |
|||
var destName = 'main-fonts'; |
|||
var donePromise = this.async(); |
|||
var svg2ttf = { |
|||
cmd: 'svg2ttf', |
|||
args: [dir + destName + '.svg', dir + destName + '.ttf'], |
|||
}; |
|||
var ttf2woff = { |
|||
cmd: 'ttf2woff', |
|||
args: [dir + destName + '.ttf', dir + destName + '.woff'], |
|||
}; |
|||
var ttf2woff2 = { |
|||
cmd: 'cat', |
|||
//args: [dir + destName + '.ttf', dir + destName + '.woff2'],
|
|||
args: [dir + destName + '.ttf', '|', 'ttf2woff2', '>>', dir + destName + '.woff2'], |
|||
}; |
|||
var ttf2eot = { |
|||
cmd: 'ttf2eot', |
|||
args: [dir + destName + '.ttf', dir + destName + '.eot'], |
|||
}; |
|||
grunt.util.spawn(svg2ttf, function done(error, result, code) { |
|||
grunt.log.ok('.ttf file created'); |
|||
|
|||
grunt.util.spawn(ttf2woff, function done(error, result, code) { |
|||
grunt.log.ok('.woff file created'); |
|||
|
|||
grunt.util.spawn(ttf2eot, function done(error, result, code) { |
|||
grunt.log.ok('.eot file created'); |
|||
donePromise(); |
|||
/* |
|||
grunt.util.spawn(ttf2woff2, function done(error, result, code) { |
|||
grunt.log.ok('.woff2 file created'); |
|||
donePromise(); |
|||
}); |
|||
*/ |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
grunt.registerTask('dev', ['connect', 'watch']); |
|||
|
|||
grunt.registerTask('test', ['jshint', 'mocha']); |
|||
|
|||
grunt.registerTask('build:fonts', ['webfont-custom']); |
|||
|
|||
grunt.registerTask('build', ['jshint', 'sass', 'before-rjs', 'requirejs', 'uglify', 'cssmin', 'concat', 'clean', 'copy']); |
|||
|
|||
grunt.registerTask('default', ['dev']); |
|||
|
|||
}; |
|||
@ -1,53 +0,0 @@ |
|||
{ |
|||
"name": "grapesjs", |
|||
"description": "Open source Web Template Editor", |
|||
"version": "0.5.41", |
|||
"author": "Artur Arseniev", |
|||
"homepage": "http://grapesjs.com", |
|||
"main": [ |
|||
"dist/grapes.min.js", |
|||
"dist/grapes.min.css" |
|||
], |
|||
"keywords": [ |
|||
"grapes", |
|||
"wte", |
|||
"web template editor", |
|||
"site builder", |
|||
"newsletter builder", |
|||
"wysiwyg", |
|||
"template", |
|||
"editor" |
|||
], |
|||
"license": "BSD-3-Clause", |
|||
"ignore": [ |
|||
"**/.*", |
|||
"styles", |
|||
"src", |
|||
"test", |
|||
"Gruntfile.js", |
|||
"index.html", |
|||
"README.md", |
|||
"package.json" |
|||
], |
|||
"dependencies": { |
|||
"jquery": "~2.2.0" |
|||
}, |
|||
"devDependencies": { |
|||
"mocha": "~2.3.4", |
|||
"chai": "~3.4.2", |
|||
"sinonjs": "~1.17.1", |
|||
"backbone": "~1.2.3", |
|||
"Backbone.Undo": "~0.2.5", |
|||
"keymaster": "~1.6.3", |
|||
"requirejs": "~2.1.22", |
|||
"requirejs-text": "~2.0.14", |
|||
"spectrum": "~1.8.0", |
|||
"underscore": "~1.8.3", |
|||
"codemirror": "~5.10.0", |
|||
"codemirror-formatting": "*", |
|||
"almond": "~0.3.1" |
|||
}, |
|||
"resolutions": { |
|||
"backbone": "~1.2.3" |
|||
} |
|||
} |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,18 +1,16 @@ |
|||
define(function () { |
|||
return { |
|||
// Default assets
|
|||
assets: [], |
|||
module.exports = { |
|||
// Default assets
|
|||
assets: [], |
|||
|
|||
// Style prefix
|
|||
stylePrefix: 'am-', |
|||
// Style prefix
|
|||
stylePrefix: 'am-', |
|||
|
|||
// Url where uploads will be send, set false to disable upload
|
|||
upload: 'http://localhost/assets/upload', |
|||
// Url where uploads will be send, set false to disable upload
|
|||
upload: 'http://localhost/assets/upload', |
|||
|
|||
// Text on upload input
|
|||
uploadText: 'Drop files here or click to upload', |
|||
// Text on upload input
|
|||
uploadText: 'Drop files here or click to upload', |
|||
|
|||
// Label for the add button
|
|||
addBtnText: 'Add image', |
|||
}; |
|||
}); |
|||
// Label for the add button
|
|||
addBtnText: 'Add image', |
|||
}; |
|||
|
|||
@ -0,0 +1,239 @@ |
|||
/** |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [getAll](#getall) |
|||
* * [remove](#remove) |
|||
* * [store](#store) |
|||
* * [load](#load) |
|||
* * [onClick](#onClick) |
|||
* * [onDblClick](#onDblClick) |
|||
* |
|||
* 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.addBtnText='Add image'] Text for the add button |
|||
* @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', |
|||
* } |
|||
*/ |
|||
|
|||
module.exports = () => { |
|||
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(config) { |
|||
c = config || {}; |
|||
var defaults = require('./config/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; |
|||
|
|||
assets = new Assets(c.assets); |
|||
var obj = { |
|||
collection: assets, |
|||
config: c, |
|||
}; |
|||
am = new AssetsView(obj); |
|||
fu = new FileUpload(obj); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* 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']); |
|||
* |
|||
* // 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(asset) { |
|||
return assets.add(asset); |
|||
}, |
|||
|
|||
/** |
|||
* 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(src) { |
|||
return assets.where({src})[0]; |
|||
}, |
|||
|
|||
/** |
|||
* Return all assets |
|||
* @return {Collection} |
|||
*/ |
|||
getAll() { |
|||
return assets; |
|||
}, |
|||
|
|||
/** |
|||
* Remove the asset by its URL |
|||
* @param {string} src URL of the asset |
|||
* @return {this} |
|||
* @example |
|||
* assetManager.remove('http://img.jpg'); |
|||
*/ |
|||
remove(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(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: [...] |
|||
* }); |
|||
* |
|||
*/ |
|||
load(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 assets |
|||
* @param {Boolean} f Force to render, otherwise cached version will be returned |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
render(f) { |
|||
if(!this.rendered || f) |
|||
this.rendered = am.render().$el.add(fu.render().$el); |
|||
return this.rendered; |
|||
}, |
|||
|
|||
//-------
|
|||
|
|||
/** |
|||
* Set new target |
|||
* @param {Object} m Model |
|||
* @private |
|||
* */ |
|||
setTarget(m) { |
|||
am.collection.target = m; |
|||
}, |
|||
|
|||
/** |
|||
* Set callback after asset was selected |
|||
* @param {Object} f Callback function |
|||
* @private |
|||
* */ |
|||
onSelect(f) { |
|||
am.collection.onSelect = f; |
|||
}, |
|||
|
|||
/** |
|||
* Set callback to fire when the asset is clicked |
|||
* @param {function} func |
|||
*/ |
|||
onClick(func) { |
|||
c.onClick = func; |
|||
}, |
|||
|
|||
/** |
|||
* Set callback to fire when the asset is double clicked |
|||
* @param {function} func |
|||
*/ |
|||
onDblClick(func) { |
|||
c.onDblClick = func; |
|||
}, |
|||
|
|||
}; |
|||
}; |
|||
@ -1,241 +0,0 @@ |
|||
/** |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [getAll](#getall) |
|||
* * [remove](#remove) |
|||
* * [store](#store) |
|||
* * [load](#load) |
|||
* * [onClick](#onClick) |
|||
* * [onDblClick](#onDblClick) |
|||
* |
|||
* 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.addBtnText='Add image'] Text for the add button |
|||
* @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) { |
|||
|
|||
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'); |
|||
|
|||
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; |
|||
}, |
|||
|
|||
/** |
|||
* 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']); |
|||
* |
|||
* // 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); |
|||
}, |
|||
|
|||
/** |
|||
* 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]; |
|||
}, |
|||
|
|||
/** |
|||
* 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: [...] |
|||
* }); |
|||
* |
|||
*/ |
|||
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 assets |
|||
* @param {Boolean} f Force to render, otherwise cached version will be returned |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
render: function(f){ |
|||
if(!this.rendered || f) |
|||
this.rendered = am.render().$el.add(fu.render().$el); |
|||
return this.rendered; |
|||
}, |
|||
|
|||
//-------
|
|||
|
|||
/** |
|||
* 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; |
|||
}, |
|||
|
|||
/** |
|||
* Set callback to fire when the asset is clicked |
|||
* @param {function} func |
|||
*/ |
|||
onClick: function(func) { |
|||
c.onClick = func; |
|||
}, |
|||
|
|||
/** |
|||
* Set callback to fire when the asset is double clicked |
|||
* @param {function} func |
|||
*/ |
|||
onDblClick: function(func) { |
|||
c.onDblClick = func; |
|||
}, |
|||
|
|||
}; |
|||
}; |
|||
}); |
|||
@ -1,31 +1,30 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
return Backbone.Model.extend({ |
|||
var Backbone = require('backbone'); |
|||
|
|||
idAttribute: 'src', |
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
type: '', |
|||
src: '', |
|||
}, |
|||
idAttribute: 'src', |
|||
|
|||
/** |
|||
* Get filename of the asset |
|||
* @return {string} |
|||
* @private |
|||
* */ |
|||
getFilename: function(){ |
|||
return this.get('src').split('/').pop(); |
|||
}, |
|||
defaults: { |
|||
type: '', |
|||
src: '', |
|||
}, |
|||
|
|||
/** |
|||
* Get extension of the asset |
|||
* @return {string} |
|||
* @private |
|||
* */ |
|||
getExtension: function(){ |
|||
return this.getFilename().split('.').pop(); |
|||
}, |
|||
/** |
|||
* Get filename of the asset |
|||
* @return {string} |
|||
* @private |
|||
* */ |
|||
getFilename() { |
|||
return this.get('src').split('/').pop(); |
|||
}, |
|||
|
|||
/** |
|||
* Get extension of the asset |
|||
* @return {string} |
|||
* @private |
|||
* */ |
|||
getExtension() { |
|||
return this.getFilename().split('.').pop(); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,13 +1,13 @@ |
|||
define(['backbone', './Asset'], |
|||
function (Backbone, Asset) { |
|||
return Asset.extend({ |
|||
var Backbone = require('backbone'); |
|||
var Asset = require('./Asset'); |
|||
|
|||
defaults: _.extend({}, Asset.prototype.defaults, { |
|||
type: 'image', |
|||
unitDim: 'px', |
|||
height: 0, |
|||
width: 0, |
|||
}), |
|||
module.exports = Asset.extend({ |
|||
|
|||
defaults: _.extend({}, Asset.prototype.defaults, { |
|||
type: 'image', |
|||
unitDim: 'px', |
|||
height: 0, |
|||
width: 0, |
|||
}), |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,67 +1,68 @@ |
|||
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]); |
|||
}, |
|||
|
|||
|
|||
}); |
|||
var Backbone = require('backbone'); |
|||
var Asset = require('./Asset'); |
|||
var AssetImage = require('./AssetImage'); |
|||
|
|||
module.exports = Backbone.Collection.extend({ |
|||
|
|||
model: AssetImage, |
|||
|
|||
initialize(models, opt) { |
|||
|
|||
this.model = (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(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(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]); |
|||
}, |
|||
|
|||
|
|||
}); |
|||
|
|||
@ -1,10 +0,0 @@ |
|||
<div id="<%= pfx %>preview-cont"> |
|||
<div id="<%= pfx %>preview" style="background-image: url(<%= src %>);"></div> |
|||
<div id="<%= pfx %>preview-bg" class="<%= ppfx %>checker-bg"></div> |
|||
</div> |
|||
<div id="<%= pfx %>meta"> |
|||
<div id="<%= pfx %>name"><%= name %></div> |
|||
<div id="<%= pfx %>dimensions"><%= dim %></div> |
|||
</div> |
|||
<div id="<%= pfx %>close">⨯</div> |
|||
<div style="clear:both"></div> |
|||
@ -1,17 +0,0 @@ |
|||
<div class="<%= pfx %>assets-cont"> |
|||
<div class="<%= pfx %>assets-header"> |
|||
<form class="<%= pfx %>add-asset"> |
|||
<div class="<%= ppfx %>field <%= pfx %>add-field"> |
|||
<input placeholder="http://path/to/the/image.jpg"/> |
|||
</div> |
|||
<button class="<%= ppfx %>btn-prim"><%= btnText %></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> |
|||
@ -1,5 +0,0 @@ |
|||
<form> |
|||
<div id="<%= pfx %>title"><%= title %></div> |
|||
<input type="file" id="<%= uploadId %>" name="file" accept="image/*" <%= disabled ? 'disabled' : '' %> multiple/> |
|||
<div style="clear:both;"></div> |
|||
</form> |
|||
@ -1,97 +1,108 @@ |
|||
define(['./AssetView','text!./../template/assetImage.html'], |
|||
function (AssetView, assetTemplate) { |
|||
return AssetView.extend({ |
|||
var AssetView = require('./AssetView'); |
|||
var assetTemplate = ` |
|||
<div id="<%= pfx %>preview-cont"> |
|||
<div id="<%= pfx %>preview" style="background-image: url(<%= src %>);"></div> |
|||
<div id="<%= pfx %>preview-bg" class="<%= ppfx %>checker-bg"></div> |
|||
</div> |
|||
<div id="<%= pfx %>meta"> |
|||
<div id="<%= pfx %>name"><%= name %></div> |
|||
<div id="<%= pfx %>dimensions"><%= dim %></div> |
|||
</div> |
|||
<div id="<%= pfx %>close">⨯</div> |
|||
<div style="clear:both"></div> |
|||
`;
|
|||
|
|||
events:{ |
|||
'click': 'handleClick', |
|||
'dblclick': 'handleDblClick', |
|||
}, |
|||
module.exports = AssetView.extend({ |
|||
|
|||
template: _.template(assetTemplate), |
|||
events:{ |
|||
'click': 'handleClick', |
|||
'dblclick': 'handleDblClick', |
|||
}, |
|||
|
|||
initialize: function(o) { |
|||
AssetView.prototype.initialize.apply(this, arguments); |
|||
this.className += ' ' + this.pfx + 'asset-image'; |
|||
this.events['click #' + this.pfx + 'close'] = 'removeItem'; |
|||
this.delegateEvents(); |
|||
}, |
|||
template: _.template(assetTemplate), |
|||
|
|||
/** |
|||
* Trigger when the asset is clicked |
|||
* @private |
|||
* */ |
|||
handleClick: function() { |
|||
var onClick = this.config.onClick; |
|||
var model = this.model; |
|||
model.collection.trigger('deselectAll'); |
|||
this.$el.addClass(this.pfx + 'highlight'); |
|||
initialize(o) { |
|||
AssetView.prototype.initialize.apply(this, arguments); |
|||
this.className += ' ' + this.pfx + 'asset-image'; |
|||
this.events['click #' + this.pfx + 'close'] = 'removeItem'; |
|||
this.delegateEvents(); |
|||
}, |
|||
|
|||
if (typeof onClick === 'function') { |
|||
onClick(model); |
|||
} else { |
|||
this.updateTarget(model.get('src')); |
|||
} |
|||
}, |
|||
/** |
|||
* Trigger when the asset is clicked |
|||
* @private |
|||
* */ |
|||
handleClick() { |
|||
var onClick = this.config.onClick; |
|||
var model = this.model; |
|||
model.collection.trigger('deselectAll'); |
|||
this.$el.addClass(this.pfx + 'highlight'); |
|||
|
|||
/** |
|||
* Trigger when the asset is double clicked |
|||
* @private |
|||
* */ |
|||
handleDblClick: function() { |
|||
var onDblClick = this.config.onDblClick; |
|||
var model = this.model; |
|||
if (typeof onClick === 'function') { |
|||
onClick(model); |
|||
} else { |
|||
this.updateTarget(model.get('src')); |
|||
} |
|||
}, |
|||
|
|||
if (typeof onDblClick === 'function') { |
|||
onDblClick(model); |
|||
} else { |
|||
this.updateTarget(model.get('src')); |
|||
} |
|||
/** |
|||
* Trigger when the asset is double clicked |
|||
* @private |
|||
* */ |
|||
handleDblClick() { |
|||
var onDblClick = this.config.onDblClick; |
|||
var model = this.model; |
|||
|
|||
var onSelect = model.collection.onSelect; |
|||
if(typeof onSelect == 'function'){ |
|||
onSelect(this.model); |
|||
} |
|||
}, |
|||
if (typeof onDblClick === 'function') { |
|||
onDblClick(model); |
|||
} else { |
|||
this.updateTarget(model.get('src')); |
|||
} |
|||
|
|||
/** |
|||
* Update target if exists |
|||
* @param {String} v Value |
|||
* @private |
|||
* */ |
|||
updateTarget: function(v){ |
|||
var target = this.model.collection.target; |
|||
if(target && target.set) { |
|||
var attr = _.clone( target.get('attributes') ); |
|||
target.set('attributes', attr ); |
|||
target.set('src', v ); |
|||
} |
|||
}, |
|||
var onSelect = model.collection.onSelect; |
|||
if(typeof onSelect == 'function'){ |
|||
onSelect(this.model); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Remove asset from collection |
|||
* @private |
|||
* */ |
|||
removeItem: function(e){ |
|||
e.stopPropagation(); |
|||
this.model.collection.remove(this.model); |
|||
}, |
|||
/** |
|||
* Update target if exists |
|||
* @param {String} v Value |
|||
* @private |
|||
* */ |
|||
updateTarget(v) { |
|||
var target = this.model.collection.target; |
|||
if(target && target.set) { |
|||
var attr = _.clone( target.get('attributes') ); |
|||
target.set('attributes', attr ); |
|||
target.set('src', v ); |
|||
} |
|||
}, |
|||
|
|||
render : function(){ |
|||
var name = this.model.get('name'), |
|||
dim = this.model.get('width') && this.model.get('height') ? |
|||
this.model.get('width')+' x '+this.model.get('height') : ''; |
|||
name = name ? name : this.model.get('src').split("/").pop(); |
|||
name = name && name.length > 30 ? name.substring(0, 30)+'...' : name; |
|||
dim = dim ? dim + (this.model.get('unitDim') ? this.model.get('unitDim') : ' px' ) : ''; |
|||
this.$el.html( this.template({ |
|||
name: name, |
|||
src: this.model.get('src'), |
|||
dim: dim, |
|||
pfx: this.pfx, |
|||
ppfx: this.ppfx |
|||
})); |
|||
this.$el.attr('class', this.className); |
|||
return this; |
|||
}, |
|||
}); |
|||
/** |
|||
* Remove asset from collection |
|||
* @private |
|||
* */ |
|||
removeItem(e) { |
|||
e.stopPropagation(); |
|||
this.model.collection.remove(this.model); |
|||
}, |
|||
|
|||
render() { |
|||
var name = this.model.get('name'), |
|||
dim = this.model.get('width') && this.model.get('height') ? |
|||
this.model.get('width')+' x '+this.model.get('height') : ''; |
|||
name = name ? name : this.model.get('src').split("/").pop(); |
|||
name = name && name.length > 30 ? name.substring(0, 30)+'...' : name; |
|||
dim = dim ? dim + (this.model.get('unitDim') ? this.model.get('unitDim') : ' px' ) : ''; |
|||
this.$el.html( this.template({ |
|||
name, |
|||
src: this.model.get('src'), |
|||
dim, |
|||
pfx: this.pfx, |
|||
ppfx: this.ppfx |
|||
})); |
|||
this.$el.attr('class', this.className); |
|||
return this; |
|||
}, |
|||
}); |
|||
|
|||
@ -1,14 +1,12 @@ |
|||
define(['backbone'], function (Backbone) { |
|||
|
|||
return Backbone.View.extend({ |
|||
initialize: function(o) { |
|||
this.options = o; |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix || ''; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.className = this.pfx + 'asset'; |
|||
this.listenTo( this.model, 'destroy remove', this.remove); |
|||
}, |
|||
}); |
|||
var Backbone = require('backbone'); |
|||
|
|||
module.exports = Backbone.View.extend({ |
|||
initialize(o) { |
|||
this.options = o; |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix || ''; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.className = this.pfx + 'asset'; |
|||
this.listenTo( this.model, 'destroy remove', this.remove); |
|||
}, |
|||
}); |
|||
|
|||
@ -1,131 +1,153 @@ |
|||
define(['backbone', './AssetView', './AssetImageView', './FileUploader', 'text!./../template/assets.html'], |
|||
function (Backbone, AssetView, AssetImageView, FileUploader, assetsTemplate) { |
|||
return Backbone.View.extend({ |
|||
|
|||
template: _.template(assetsTemplate), |
|||
|
|||
initialize: function(o) { |
|||
this.options = o; |
|||
this.config = o.config; |
|||
this.pfx = this.config.stylePrefix || ''; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.listenTo( this.collection, 'add', this.addToAsset ); |
|||
this.listenTo( this.collection, 'deselectAll', this.deselectAll ); |
|||
this.className = this.pfx + 'assets'; |
|||
|
|||
this.events = {}; |
|||
this.events.submit = 'addFromStr'; |
|||
this.delegateEvents(); |
|||
}, |
|||
|
|||
/** |
|||
* Add new asset to the collection via string |
|||
* @param {Event} e Event object |
|||
* @return {this} |
|||
* @private |
|||
*/ |
|||
addFromStr: function(e){ |
|||
e.preventDefault(); |
|||
|
|||
var input = this.getInputUrl(); |
|||
|
|||
var url = input.value.trim(); |
|||
|
|||
if(!url) |
|||
return; |
|||
|
|||
this.collection.addImg(url, {at: 0}); |
|||
|
|||
this.getAssetsEl().scrollTop = 0; |
|||
input.value = ''; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns assets element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getAssetsEl: function(){ |
|||
//if(!this.assets) // Not able to cache as after the rerender it losses the ref
|
|||
this.assets = this.el.querySelector('.' + this.pfx + 'assets'); |
|||
return this.assets; |
|||
}, |
|||
|
|||
/** |
|||
* Returns input url element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getInputUrl: function(){ |
|||
if(!this.inputUrl || !this.inputUrl.value) |
|||
this.inputUrl = this.el.querySelector('.'+this.pfx+'add-asset input'); |
|||
return this.inputUrl; |
|||
}, |
|||
|
|||
/** |
|||
* Add asset to collection |
|||
* @private |
|||
* */ |
|||
addToAsset: function(model){ |
|||
this.addAsset(model); |
|||
}, |
|||
|
|||
/** |
|||
* Add new asset to collection |
|||
* @param Object Model |
|||
* @param Object Fragment collection |
|||
* @return Object Object created |
|||
* @private |
|||
* */ |
|||
addAsset: function(model, fragmentEl){ |
|||
var fragment = fragmentEl || null; |
|||
var viewObject = AssetView; |
|||
|
|||
if(model.get('type').indexOf("image") > -1) |
|||
viewObject = AssetImageView; |
|||
|
|||
var view = new viewObject({ |
|||
model : model, |
|||
config : this.config, |
|||
}); |
|||
var rendered = view.render().el; |
|||
|
|||
if(fragment){ |
|||
fragment.appendChild( rendered ); |
|||
}else{ |
|||
var assetsEl = this.getAssetsEl(); |
|||
if(assetsEl) |
|||
assetsEl.insertBefore(rendered, assetsEl.firstChild); |
|||
} |
|||
|
|||
return rendered; |
|||
}, |
|||
|
|||
/** |
|||
* Deselect all assets |
|||
* @private |
|||
* */ |
|||
deselectAll: function(){ |
|||
this.$el.find('.' + this.pfx + 'highlight').removeClass(this.pfx + 'highlight'); |
|||
}, |
|||
|
|||
render: function() { |
|||
var fragment = document.createDocumentFragment(); |
|||
this.$el.empty(); |
|||
|
|||
this.collection.each(function(model){ |
|||
this.addAsset(model, fragment); |
|||
},this); |
|||
|
|||
this.$el.html(this.template({ |
|||
pfx: this.pfx, |
|||
ppfx: this.ppfx, |
|||
btnText: this.config.addBtnText, |
|||
})); |
|||
|
|||
this.$el.find('.'+this.pfx + 'assets').append(fragment); |
|||
return this; |
|||
} |
|||
}); |
|||
var Backbone = require('backbone'); |
|||
var AssetView = require('./AssetView'); |
|||
var AssetImageView = require('./AssetImageView'); |
|||
var FileUploader = require('./FileUploader'); |
|||
var assetsTemplate = ` |
|||
<div class="<%= pfx %>assets-cont"> |
|||
<div class="<%= pfx %>assets-header"> |
|||
<form class="<%= pfx %>add-asset"> |
|||
<div class="<%= ppfx %>field <%= pfx %>add-field"> |
|||
<input placeholder="http://path/to/the/image.jpg"/> |
|||
</div> |
|||
<button class="<%= ppfx %>btn-prim"><%= btnText %></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> |
|||
|
|||
`;
|
|||
|
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
template: _.template(assetsTemplate), |
|||
|
|||
initialize(o) { |
|||
this.options = o; |
|||
this.config = o.config; |
|||
this.pfx = this.config.stylePrefix || ''; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.listenTo( this.collection, 'add', this.addToAsset ); |
|||
this.listenTo( this.collection, 'deselectAll', this.deselectAll ); |
|||
this.className = this.pfx + 'assets'; |
|||
|
|||
this.events = {}; |
|||
this.events.submit = 'addFromStr'; |
|||
this.delegateEvents(); |
|||
}, |
|||
|
|||
/** |
|||
* Add new asset to the collection via string |
|||
* @param {Event} e Event object |
|||
* @return {this} |
|||
* @private |
|||
*/ |
|||
addFromStr(e) { |
|||
e.preventDefault(); |
|||
|
|||
var input = this.getInputUrl(); |
|||
|
|||
var url = input.value.trim(); |
|||
|
|||
if(!url) |
|||
return; |
|||
|
|||
this.collection.addImg(url, {at: 0}); |
|||
|
|||
this.getAssetsEl().scrollTop = 0; |
|||
input.value = ''; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns assets element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getAssetsEl() { |
|||
//if(!this.assets) // Not able to cache as after the rerender it losses the ref
|
|||
this.assets = this.el.querySelector('.' + this.pfx + 'assets'); |
|||
return this.assets; |
|||
}, |
|||
|
|||
/** |
|||
* Returns input url element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getInputUrl() { |
|||
if(!this.inputUrl || !this.inputUrl.value) |
|||
this.inputUrl = this.el.querySelector('.'+this.pfx+'add-asset input'); |
|||
return this.inputUrl; |
|||
}, |
|||
|
|||
/** |
|||
* Add asset to collection |
|||
* @private |
|||
* */ |
|||
addToAsset(model) { |
|||
this.addAsset(model); |
|||
}, |
|||
|
|||
/** |
|||
* Add new asset to collection |
|||
* @param Object Model |
|||
* @param Object Fragment collection |
|||
* @return Object Object created |
|||
* @private |
|||
* */ |
|||
addAsset(model, fragmentEl) { |
|||
var fragment = fragmentEl || null; |
|||
var viewObject = AssetView; |
|||
|
|||
if(model.get('type').indexOf("image") > -1) |
|||
viewObject = AssetImageView; |
|||
|
|||
var view = new viewObject({ |
|||
model, |
|||
config : this.config, |
|||
}); |
|||
var rendered = view.render().el; |
|||
|
|||
if(fragment){ |
|||
fragment.appendChild( rendered ); |
|||
}else{ |
|||
var assetsEl = this.getAssetsEl(); |
|||
if(assetsEl) |
|||
assetsEl.insertBefore(rendered, assetsEl.firstChild); |
|||
} |
|||
|
|||
return rendered; |
|||
}, |
|||
|
|||
/** |
|||
* Deselect all assets |
|||
* @private |
|||
* */ |
|||
deselectAll() { |
|||
this.$el.find('.' + this.pfx + 'highlight').removeClass(this.pfx + 'highlight'); |
|||
}, |
|||
|
|||
render() { |
|||
var fragment = document.createDocumentFragment(); |
|||
this.$el.empty(); |
|||
|
|||
this.collection.each(function(model){ |
|||
this.addAsset(model, fragment); |
|||
},this); |
|||
|
|||
this.$el.html(this.template({ |
|||
pfx: this.pfx, |
|||
ppfx: this.ppfx, |
|||
btnText: this.config.addBtnText, |
|||
})); |
|||
|
|||
this.$el.find('.'+this.pfx + 'assets').append(fragment); |
|||
return this; |
|||
} |
|||
}); |
|||
|
|||
@ -1,97 +1,103 @@ |
|||
define(['backbone', 'text!./../template/fileUploader.html'], |
|||
function (Backbone, fileUploaderTemplate) { |
|||
return Backbone.View.extend({ |
|||
var Backbone = require('backbone'); |
|||
var fileUploaderTemplate = ` |
|||
<form> |
|||
<div id="<%= pfx %>title"><%= title %></div> |
|||
<input type="file" id="<%= uploadId %>" name="file" accept="image/*" <%= disabled ? 'disabled' : '' %> multiple/> |
|||
<div style="clear:both;"></div> |
|||
</form> |
|||
`;
|
|||
|
|||
template: _.template(fileUploaderTemplate), |
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
events: {}, |
|||
template: _.template(fileUploaderTemplate), |
|||
|
|||
initialize: function(o) { |
|||
this.options = o || {}; |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix || ''; |
|||
this.target = this.collection || {}; |
|||
this.uploadId = this.pfx + 'uploadFile'; |
|||
this.disabled = !this.config.upload; |
|||
this.events['change #' + this.uploadId] = 'uploadFile'; |
|||
this.delegateEvents(); |
|||
}, |
|||
events: {}, |
|||
|
|||
/** |
|||
* Upload files |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
uploadFile : function(e){ |
|||
var files = e.dataTransfer ? e.dataTransfer.files : e.target.files, |
|||
formData = new FormData(); |
|||
for (var i = 0; i < files.length; i++) { |
|||
formData.append('files[]', files[i]); |
|||
} |
|||
var target = this.target; |
|||
$.ajax({ |
|||
url : this.config.upload, |
|||
type : 'POST', |
|||
data : formData, |
|||
beforeSend : this.config.beforeSend, |
|||
complete : this.config.onComplete, |
|||
xhrFields : { |
|||
onprogress: function (e) { |
|||
if (e.lengthComputable) { |
|||
/*var result = e.loaded / e.total * 100 + '%';*/ |
|||
} |
|||
}, |
|||
onload: function (e) { |
|||
//progress.value = 100;
|
|||
} |
|||
}, |
|||
cache: false, contentType: false, processData: false |
|||
}).done(function(data){ |
|||
target.add(data.data); |
|||
}).always(function(){ |
|||
//turnOff loading
|
|||
}); |
|||
}, |
|||
initialize(o) { |
|||
this.options = o || {}; |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix || ''; |
|||
this.target = this.collection || {}; |
|||
this.uploadId = this.pfx + 'uploadFile'; |
|||
this.disabled = !this.config.upload; |
|||
this.events['change #' + this.uploadId] = 'uploadFile'; |
|||
this.delegateEvents(); |
|||
}, |
|||
|
|||
/** |
|||
* Make input file droppable |
|||
* @private |
|||
* */ |
|||
initDrop: function(){ |
|||
var that = this; |
|||
if(!this.uploadForm){ |
|||
this.uploadForm = this.$el.find('form').get(0); |
|||
if( 'draggable' in this.uploadForm ){ |
|||
var uploadFile = this.uploadFile; |
|||
this.uploadForm.ondragover = function(){ |
|||
this.className = that.pfx + 'hover'; |
|||
return false; |
|||
}; |
|||
this.uploadForm.ondragleave = function(){ |
|||
this.className = ''; |
|||
return false; |
|||
}; |
|||
this.uploadForm.ondrop = function(e){ |
|||
this.className = ''; |
|||
e.preventDefault(); |
|||
that.uploadFile(e); |
|||
return; |
|||
}; |
|||
} |
|||
} |
|||
}, |
|||
/** |
|||
* Upload files |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
uploadFile(e) { |
|||
var files = e.dataTransfer ? e.dataTransfer.files : e.target.files, |
|||
formData = new FormData(); |
|||
for (var i = 0; i < files.length; i++) { |
|||
formData.append('files[]', files[i]); |
|||
} |
|||
var target = this.target; |
|||
$.ajax({ |
|||
url : this.config.upload, |
|||
type : 'POST', |
|||
data : formData, |
|||
beforeSend : this.config.beforeSend, |
|||
complete : this.config.onComplete, |
|||
xhrFields : { |
|||
onprogress(e) { |
|||
if (e.lengthComputable) { |
|||
/*var result = e.loaded / e.total * 100 + '%';*/ |
|||
} |
|||
}, |
|||
onload(e) { |
|||
//progress.value = 100;
|
|||
} |
|||
}, |
|||
cache: false, contentType: false, processData: false |
|||
}).done(data => { |
|||
target.add(data.data); |
|||
}).always(() => { |
|||
//turnOff loading
|
|||
}); |
|||
}, |
|||
|
|||
render : function(){ |
|||
this.$el.html( this.template({ |
|||
title: this.config.uploadText, |
|||
uploadId: this.uploadId, |
|||
disabled: this.disabled, |
|||
pfx: this.pfx |
|||
}) ); |
|||
this.initDrop(); |
|||
this.$el.attr('class', this.pfx + 'file-uploader'); |
|||
return this; |
|||
}, |
|||
/** |
|||
* Make input file droppable |
|||
* @private |
|||
* */ |
|||
initDrop() { |
|||
var that = this; |
|||
if(!this.uploadForm){ |
|||
this.uploadForm = this.$el.find('form').get(0); |
|||
if( 'draggable' in this.uploadForm ){ |
|||
var uploadFile = this.uploadFile; |
|||
this.uploadForm.ondragover = function(){ |
|||
this.className = that.pfx + 'hover'; |
|||
return false; |
|||
}; |
|||
this.uploadForm.ondragleave = function(){ |
|||
this.className = ''; |
|||
return false; |
|||
}; |
|||
this.uploadForm.ondrop = function(e){ |
|||
this.className = ''; |
|||
e.preventDefault(); |
|||
that.uploadFile(e); |
|||
return; |
|||
}; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
render() { |
|||
this.$el.html( this.template({ |
|||
title: this.config.uploadText, |
|||
uploadId: this.uploadId, |
|||
disabled: this.disabled, |
|||
pfx: this.pfx |
|||
}) ); |
|||
this.initDrop(); |
|||
this.$el.attr('class', this.pfx + 'file-uploader'); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,7 +1,5 @@ |
|||
define(function () { |
|||
return { |
|||
module.exports = { |
|||
|
|||
'blocks': [], |
|||
'blocks': [], |
|||
|
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
@ -0,0 +1,118 @@ |
|||
/** |
|||
* * [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>'}, |
|||
* ... |
|||
* ], |
|||
* } |
|||
* ... |
|||
*/ |
|||
module.exports = () => { |
|||
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(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(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(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() { |
|||
return blocks; |
|||
}, |
|||
|
|||
/** |
|||
* Render blocks |
|||
* @return {HTMLElement} |
|||
*/ |
|||
render() { |
|||
return view.render().el; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
@ -1,122 +0,0 @@ |
|||
/** |
|||
* * [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; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
|
|||
}); |
|||
@ -1,13 +1,11 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
var Backbone = require('backbone'); |
|||
|
|||
return Backbone.Model.extend({ |
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
label: '', |
|||
content: '', |
|||
attributes: {}, |
|||
}, |
|||
defaults :{ |
|||
label: '', |
|||
content: '', |
|||
attributes: {}, |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
@ -1,9 +1,6 @@ |
|||
define(['backbone','./Block'], |
|||
function (Backbone, Block) { |
|||
var Backbone = require('backbone'); |
|||
var Block = require('./Block'); |
|||
|
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Block, |
|||
|
|||
}); |
|||
module.exports = Backbone.Collection.extend({ |
|||
model: Block, |
|||
}); |
|||
|
|||
@ -1,50 +1,48 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
var Backbone = require('backbone'); |
|||
|
|||
return Backbone.View.extend({ |
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
events: { |
|||
mousedown: 'onDrag' |
|||
}, |
|||
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); |
|||
}, |
|||
initialize(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(e) { |
|||
if(!this.config.getSorter) |
|||
return; |
|||
this.config.em.refreshCanvas(); |
|||
var sorter = this.config.getSorter(); |
|||
sorter.setDragHelper(this.el, e); |
|||
sorter.startSort(this.el); |
|||
sorter.setDropContent(this.model.get('content')); |
|||
this.doc.on('mouseup', this.onDrop); |
|||
}, |
|||
/** |
|||
* Start block dragging |
|||
* @private |
|||
*/ |
|||
onDrag(e) { |
|||
if(!this.config.getSorter) |
|||
return; |
|||
this.config.em.refreshCanvas(); |
|||
var sorter = this.config.getSorter(); |
|||
sorter.setDragHelper(this.el, e); |
|||
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(); |
|||
}, |
|||
/** |
|||
* Drop block |
|||
* @private |
|||
*/ |
|||
onDrop() { |
|||
this.doc.off('mouseup', this.onDrop); |
|||
this.config.getSorter().endMove(); |
|||
}, |
|||
|
|||
render: function() { |
|||
var className = this.ppfx + 'block'; |
|||
this.$el.addClass(className); |
|||
this.el.innerHTML = '<div class="' + className + '-label">' + this.model.get('label') + '</div>'; |
|||
return this; |
|||
}, |
|||
render() { |
|||
var className = this.ppfx + 'block'; |
|||
this.$el.addClass(className); |
|||
this.el.innerHTML = '<div class="' + className + '-label">' + this.model.get('label') + '</div>'; |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,121 +1,120 @@ |
|||
define(['backbone', './BlockView'], |
|||
function(Backbone, BlockView) { |
|||
|
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(opts, config) { |
|||
_.bindAll(this, 'getSorter', 'onDrag', 'onDrop'); |
|||
this.config = config || {}; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.listenTo(this.collection, 'add', this.addTo); |
|||
this.em = this.config.em; |
|||
this.tac = 'test-tac'; |
|||
this.grabbingCls = this.ppfx + 'grabbing'; |
|||
|
|||
if(this.em){ |
|||
this.config.getSorter = this.getSorter; |
|||
this.canvas = this.em.get('Canvas'); |
|||
var Backbone = require('backbone'); |
|||
var BlockView = require('./BlockView'); |
|||
|
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
initialize(opts, config) { |
|||
_.bindAll(this, 'getSorter', 'onDrag', 'onDrop'); |
|||
this.config = config || {}; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.listenTo(this.collection, 'add', this.addTo); |
|||
this.em = this.config.em; |
|||
this.tac = 'test-tac'; |
|||
this.grabbingCls = this.ppfx + 'grabbing'; |
|||
|
|||
if(this.em){ |
|||
this.config.getSorter = this.getSorter; |
|||
this.canvas = this.em.get('Canvas'); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Get sorter |
|||
* @private |
|||
*/ |
|||
getSorter() { |
|||
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, |
|||
canvasRelative: 1, |
|||
}); |
|||
} |
|||
return this.sorter; |
|||
}, |
|||
|
|||
/** |
|||
* Callback when block is on drag |
|||
* @private |
|||
*/ |
|||
onDrag() { |
|||
this.em.stopDefault(); |
|||
}, |
|||
|
|||
/** |
|||
* Callback when block is dropped |
|||
* @private |
|||
*/ |
|||
onDrop(model) { |
|||
this.em.runDefault(); |
|||
|
|||
if (model && model.get) { |
|||
if(model.get('activeOnRender')) { |
|||
model.trigger('active'); |
|||
model.set('activeOnRender', 0); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 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, |
|||
canvasRelative: 1, |
|||
}); |
|||
} |
|||
return this.sorter; |
|||
}, |
|||
|
|||
/** |
|||
* Callback when block is on drag |
|||
* @private |
|||
*/ |
|||
onDrag: function(){ |
|||
this.em.stopDefault(); |
|||
}, |
|||
|
|||
/** |
|||
* Callback when block is dropped |
|||
* @private |
|||
*/ |
|||
onDrop: function(model){ |
|||
this.em.runDefault(); |
|||
|
|||
if (model && model.get) { |
|||
if(model.get('activeOnRender')) { |
|||
model.trigger('active'); |
|||
model.set('activeOnRender', 0); |
|||
} |
|||
|
|||
// Register all its components (eg. for the Undo Manager)
|
|||
this.em.initChildrenComp(model); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 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; |
|||
}, |
|||
|
|||
}); |
|||
|
|||
// Register all its components (eg. for the Undo Manager)
|
|||
this.em.initChildrenComp(model); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Add new model to the collection |
|||
* @param {Model} model |
|||
* @private |
|||
* */ |
|||
addTo(model) { |
|||
this.add(model); |
|||
}, |
|||
|
|||
/** |
|||
* Render new model inside the view |
|||
* @param {Model} model |
|||
* @param {Object} fragment Fragment collection |
|||
* @private |
|||
* */ |
|||
add(model, fragment) { |
|||
var frag = fragment || null; |
|||
var view = new BlockView({ |
|||
model, |
|||
attributes: model.get('attributes'), |
|||
}, this.config); |
|||
var rendered = view.render().el; |
|||
|
|||
if(frag) |
|||
frag.appendChild(rendered); |
|||
else |
|||
this.$el.append(rendered); |
|||
}, |
|||
|
|||
|
|||
|
|||
render() { |
|||
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,16 +1,14 @@ |
|||
define(function () { |
|||
return { |
|||
module.exports = { |
|||
|
|||
stylePrefix: 'cv-', |
|||
stylePrefix: 'cv-', |
|||
|
|||
// Coming soon
|
|||
rulers: false, |
|||
// Coming soon
|
|||
rulers: false, |
|||
|
|||
/* |
|||
* append scripts in head of iframe before renderBody content |
|||
* need to manually maintain the same scripts in cms's render template |
|||
*/ |
|||
scripts: [] |
|||
/* |
|||
* append scripts in head of iframe before renderBody content |
|||
* need to manually maintain the same scripts in cms's render template |
|||
*/ |
|||
scripts: [] |
|||
|
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
@ -0,0 +1,325 @@ |
|||
module.exports = () => { |
|||
var c = {}, |
|||
defaults = require('./config/config'), |
|||
Canvas = require('./model/Canvas'), |
|||
CanvasView = require('./view/CanvasView'); |
|||
var canvas; |
|||
|
|||
return { |
|||
|
|||
/** |
|||
* Used inside RTE |
|||
* @private |
|||
*/ |
|||
getCanvasView() { |
|||
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(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(wrp) { |
|||
canvas.set('wrapper', wrp); |
|||
}, |
|||
|
|||
/** |
|||
* Returns canvas element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getElement() { |
|||
return CanvasView.el; |
|||
}, |
|||
|
|||
/** |
|||
* Returns frame element of the canvas |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getFrameEl() { |
|||
return CanvasView.frame.el; |
|||
}, |
|||
|
|||
/** |
|||
* Returns body element of the frame |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getBody() { |
|||
return CanvasView.frame.el.contentDocument.body; |
|||
}, |
|||
|
|||
/** |
|||
* Returns body wrapper element of the frame |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getWrapperEl() { |
|||
return this.getBody().querySelector('#wrapper'); |
|||
}, |
|||
|
|||
/** |
|||
* Returns element containing canvas tools |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getToolsEl() { |
|||
return CanvasView.toolsEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns highlighter element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getHighlighter() { |
|||
return CanvasView.hlEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns badge element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getBadgeEl() { |
|||
return CanvasView.badgeEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns placer element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getPlacerEl() { |
|||
return CanvasView.placerEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns ghost element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getGhostEl() { |
|||
return CanvasView.ghostEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns toolbar element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getToolbarEl() { |
|||
return CanvasView.toolbarEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns resizer element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getResizerEl() { |
|||
return CanvasView.resizerEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns offset viewer element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getOffsetViewerEl() { |
|||
return CanvasView.offsetEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns fixed offset viewer element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getFixedOffsetViewerEl() { |
|||
return CanvasView.fixedOffsetEl; |
|||
}, |
|||
|
|||
/** |
|||
* Render canvas |
|||
* */ |
|||
render() { |
|||
return CanvasView.render().el; |
|||
}, |
|||
|
|||
/** |
|||
* Get frame position |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getOffset() { |
|||
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(el) { |
|||
var rect = el.getBoundingClientRect(); |
|||
return { |
|||
top: rect.top + document.body.scrollTop, |
|||
left: rect.left + document.body.scrollLeft |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Get element position relative to the canvas |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
*/ |
|||
getElementPos(el) { |
|||
return CanvasView.getElementPos(el); |
|||
}, |
|||
|
|||
/** |
|||
* This method comes handy when you need to attach something like toolbars |
|||
* to elements inside the canvas, dealing with all relative position, |
|||
* offsets, etc. and returning as result the object with positions which are |
|||
* viewable by the user (when the canvas is scrolled the top edge of the element |
|||
* is not viewable by the user anymore so the new top edge is the one of the canvas) |
|||
* |
|||
* The target should be visible before being passed here as invisible elements |
|||
* return empty string as width |
|||
* @param {HTMLElement} target The target in this case could be the toolbar |
|||
* @param {HTMLElement} element The element on which I'd attach the toolbar |
|||
* @param {Object} options Custom options |
|||
* @param {Boolean} options.toRight Set to true if you want the toolbar attached to the right |
|||
* @return {Object} |
|||
*/ |
|||
getTargetToElementDim(target, element, options) { |
|||
var opts = options || {}; |
|||
var canvasPos = CanvasView.getPosition(); |
|||
var pos = opts.elPos || CanvasView.getElementPos(element); |
|||
var toRight = options.toRight || 0; |
|||
var targetHeight = opts.targetHeight || target.offsetHeight; |
|||
var targetWidth = opts.targetWidth || target.offsetWidth; |
|||
var eventToTrigger = opts.event || null; |
|||
|
|||
var elTop = pos.top - targetHeight; |
|||
var elLeft = pos.left; |
|||
elLeft += toRight ? pos.width : 0; |
|||
elLeft = toRight ? (elLeft - targetWidth) : elLeft; |
|||
|
|||
var leftPos = elLeft < canvasPos.left ? canvasPos.left : elLeft; |
|||
var topPos = elTop < canvasPos.top ? canvasPos.top : elTop; |
|||
topPos = topPos > (pos.top + pos.height) ? (pos.top + pos.height) : topPos; |
|||
|
|||
var result = { |
|||
top: topPos, |
|||
left: leftPos, |
|||
elementTop: pos.top, |
|||
elementLeft: pos.left, |
|||
elementWidth: pos.width, |
|||
elementHeight: pos.height, |
|||
targetWidth: target.offsetWidth, |
|||
targetHeight: target.offsetHeight, |
|||
canvasTop: canvasPos.top, |
|||
canvasLeft: canvasPos.left, |
|||
}; |
|||
|
|||
// In this way I can catch data and also change the position strategy
|
|||
if(eventToTrigger && c.em) { |
|||
c.em.trigger(eventToTrigger, result); |
|||
} |
|||
|
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Instead of simply returning e.clientX and e.clientY this function |
|||
* calculates also the offset based on the canvas. This is helpful when you |
|||
* need to get X and Y position while moving between the editor area and |
|||
* canvas area, which is in the iframe |
|||
* @param {Event} e |
|||
* @return {Object} |
|||
*/ |
|||
getMouseRelativePos(e, options) { |
|||
var opts = options || {}; |
|||
var addTop = 0; |
|||
var addLeft = 0; |
|||
var subWinOffset = opts.subWinOffset; |
|||
var doc = e.target.ownerDocument; |
|||
var win = doc.defaultView || doc.parentWindow; |
|||
var frame = win.frameElement; |
|||
var yOffset = subWinOffset ? win.pageYOffset : 0; |
|||
var xOffset = subWinOffset ? win.pageXOffset : 0; |
|||
|
|||
if (frame) { |
|||
var frameRect = frame.getBoundingClientRect(); |
|||
addTop = frameRect.top || 0; |
|||
addLeft = frameRect.left || 0; |
|||
} |
|||
|
|||
return { |
|||
y: e.clientY + addTop - yOffset, |
|||
x: e.clientX + addLeft - xOffset, |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* X and Y mouse position relative to the canvas |
|||
* @param {Event} e |
|||
* @return {Object} |
|||
*/ |
|||
getMouseRelativeCanvas(e, options) { |
|||
var opts = options || {}; |
|||
var frame = this.getFrameEl(); |
|||
var body = this.getBody(); |
|||
var addTop = frame.offsetTop || 0; |
|||
var addLeft = frame.offsetLeft || 0; |
|||
var yOffset = body.scrollTop || 0; |
|||
var xOffset = body.scrollLeft || 0; |
|||
|
|||
return { |
|||
y: e.clientY + addTop + yOffset, |
|||
x: e.clientX + addLeft + xOffset, |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Returns wrapper element |
|||
* @return {HTMLElement} |
|||
* ???? |
|||
*/ |
|||
getFrameWrapperEl() { |
|||
return CanvasView.frame.getWrapper(); |
|||
}, |
|||
}; |
|||
}; |
|||
@ -1,329 +0,0 @@ |
|||
define(function(require) { |
|||
|
|||
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) { |
|||
canvas.set('wrapper', wrp); |
|||
}, |
|||
|
|||
/** |
|||
* 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; |
|||
}, |
|||
|
|||
/** |
|||
* Returns toolbar element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getToolbarEl: function() { |
|||
return CanvasView.toolbarEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns resizer element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getResizerEl: function() { |
|||
return CanvasView.resizerEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns offset viewer element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getOffsetViewerEl: function() { |
|||
return CanvasView.offsetEl; |
|||
}, |
|||
|
|||
/** |
|||
* Returns fixed offset viewer element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getFixedOffsetViewerEl: function() { |
|||
return CanvasView.fixedOffsetEl; |
|||
}, |
|||
|
|||
/** |
|||
* Render canvas |
|||
* */ |
|||
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 |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Get element position relative to the canvas |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
*/ |
|||
getElementPos: function(el) { |
|||
return CanvasView.getElementPos(el); |
|||
}, |
|||
|
|||
/** |
|||
* This method comes handy when you need to attach something like toolbars |
|||
* to elements inside the canvas, dealing with all relative position, |
|||
* offsets, etc. and returning as result the object with positions which are |
|||
* viewable by the user (when the canvas is scrolled the top edge of the element |
|||
* is not viewable by the user anymore so the new top edge is the one of the canvas) |
|||
* |
|||
* The target should be visible before being passed here as invisible elements |
|||
* return empty string as width |
|||
* @param {HTMLElement} target The target in this case could be the toolbar |
|||
* @param {HTMLElement} element The element on which I'd attach the toolbar |
|||
* @param {Object} options Custom options |
|||
* @param {Boolean} options.toRight Set to true if you want the toolbar attached to the right |
|||
* @return {Object} |
|||
*/ |
|||
getTargetToElementDim: function (target, element, options) { |
|||
var opts = options || {}; |
|||
var canvasPos = CanvasView.getPosition(); |
|||
var pos = opts.elPos || CanvasView.getElementPos(element); |
|||
var toRight = options.toRight || 0; |
|||
var targetHeight = opts.targetHeight || target.offsetHeight; |
|||
var targetWidth = opts.targetWidth || target.offsetWidth; |
|||
var eventToTrigger = opts.event || null; |
|||
|
|||
var elTop = pos.top - targetHeight; |
|||
var elLeft = pos.left; |
|||
elLeft += toRight ? pos.width : 0; |
|||
elLeft = toRight ? (elLeft - targetWidth) : elLeft; |
|||
|
|||
var leftPos = elLeft < canvasPos.left ? canvasPos.left : elLeft; |
|||
var topPos = elTop < canvasPos.top ? canvasPos.top : elTop; |
|||
topPos = topPos > (pos.top + pos.height) ? (pos.top + pos.height) : topPos; |
|||
|
|||
var result = { |
|||
top: topPos, |
|||
left: leftPos, |
|||
elementTop: pos.top, |
|||
elementLeft: pos.left, |
|||
elementWidth: pos.width, |
|||
elementHeight: pos.height, |
|||
targetWidth: target.offsetWidth, |
|||
targetHeight: target.offsetHeight, |
|||
canvasTop: canvasPos.top, |
|||
canvasLeft: canvasPos.left, |
|||
}; |
|||
|
|||
// In this way I can catch data and also change the position strategy
|
|||
if(eventToTrigger && c.em) { |
|||
c.em.trigger(eventToTrigger, result); |
|||
} |
|||
|
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Instead of simply returning e.clientX and e.clientY this function |
|||
* calculates also the offset based on the canvas. This is helpful when you |
|||
* need to get X and Y position while moving between the editor area and |
|||
* canvas area, which is in the iframe |
|||
* @param {Event} e |
|||
* @return {Object} |
|||
*/ |
|||
getMouseRelativePos: function (e, options) { |
|||
var opts = options || {}; |
|||
var addTop = 0; |
|||
var addLeft = 0; |
|||
var subWinOffset = opts.subWinOffset; |
|||
var doc = e.target.ownerDocument; |
|||
var win = doc.defaultView || doc.parentWindow; |
|||
var frame = win.frameElement; |
|||
var yOffset = subWinOffset ? win.pageYOffset : 0; |
|||
var xOffset = subWinOffset ? win.pageXOffset : 0; |
|||
|
|||
if (frame) { |
|||
var frameRect = frame.getBoundingClientRect(); |
|||
addTop = frameRect.top || 0; |
|||
addLeft = frameRect.left || 0; |
|||
} |
|||
|
|||
return { |
|||
y: e.clientY + addTop - yOffset, |
|||
x: e.clientX + addLeft - xOffset, |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* X and Y mouse position relative to the canvas |
|||
* @param {Event} e |
|||
* @return {Object} |
|||
*/ |
|||
getMouseRelativeCanvas: function (e, options) { |
|||
var opts = options || {}; |
|||
var frame = this.getFrameEl(); |
|||
var body = this.getBody(); |
|||
var addTop = frame.offsetTop || 0; |
|||
var addLeft = frame.offsetLeft || 0; |
|||
var yOffset = body.scrollTop || 0; |
|||
var xOffset = body.scrollLeft || 0; |
|||
|
|||
return { |
|||
y: e.clientY + addTop + yOffset, |
|||
x: e.clientX + addLeft + xOffset, |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Returns wrapper element |
|||
* @return {HTMLElement} |
|||
* ???? |
|||
*/ |
|||
getFrameWrapperEl: function(){ |
|||
return CanvasView.frame.getWrapper(); |
|||
}, |
|||
}; |
|||
}; |
|||
|
|||
}); |
|||
@ -1,18 +1,17 @@ |
|||
define(['backbone', './Frame'], |
|||
function(Backbone, Frame){ |
|||
var Backbone = require('backbone'); |
|||
var Frame = require('./Frame'); |
|||
|
|||
return Backbone.Model.extend({ |
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
frame: '', |
|||
wrapper: '', |
|||
rulers: false, |
|||
}, |
|||
defaults :{ |
|||
frame: '', |
|||
wrapper: '', |
|||
rulers: false, |
|||
}, |
|||
|
|||
initialize: function(config) { |
|||
var conf = this.conf || {}; |
|||
this.set('frame', new Frame(conf.frame)); |
|||
}, |
|||
initialize(config) { |
|||
var conf = this.conf || {}; |
|||
this.set('frame', new Frame(conf.frame)); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
@ -1,14 +1,12 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
var Backbone = require('backbone'); |
|||
|
|||
return Backbone.Model.extend({ |
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
wrapper: '', |
|||
width: '', |
|||
height: '', |
|||
attributes: {}, |
|||
}, |
|||
defaults :{ |
|||
wrapper: '', |
|||
width: '', |
|||
height: '', |
|||
attributes: {}, |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
@ -1,269 +1,266 @@ |
|||
define(['backbone','./FrameView'], |
|||
function(Backbone, FrameView) { |
|||
/** |
|||
* @class CanvasView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
var Backbone = require('backbone'); |
|||
var FrameView = require('./FrameView'); |
|||
|
|||
initialize: function(o) { |
|||
_.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 |
|||
}); |
|||
}, |
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
/** |
|||
* 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; |
|||
this.em.trigger('canvasScroll'); |
|||
}, |
|||
initialize(o) { |
|||
_.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 |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* Insert scripts into head, it will call renderBody after all scripts loaded or failed |
|||
* @private |
|||
*/ |
|||
renderScripts: function () { |
|||
var frame = this.frame; |
|||
var that = this; |
|||
/** |
|||
* Update tools position |
|||
* @private |
|||
*/ |
|||
onFrameScroll() { |
|||
var u = 'px'; |
|||
var body = this.frame.el.contentDocument.body; |
|||
this.toolsEl.style.top = '-' + body.scrollTop + u; |
|||
this.toolsEl.style.left = '-' + body.scrollLeft + u; |
|||
this.em.trigger('canvasScroll'); |
|||
}, |
|||
|
|||
frame.el.onload = function () { |
|||
var scripts = that.config.scripts.slice(0), // clone
|
|||
counter = 0; |
|||
/** |
|||
* Insert scripts into head, it will call renderBody after all scripts loaded or failed |
|||
* @private |
|||
*/ |
|||
renderScripts() { |
|||
var frame = this.frame; |
|||
var that = this; |
|||
|
|||
function appendScript(scripts) { |
|||
if (scripts.length > 0) { |
|||
var script = document.createElement('script'); |
|||
script.type = 'text/javascript'; |
|||
script.src = scripts.shift(); |
|||
script.onerror = script.onload = appendScript.bind(null, scripts); |
|||
frame.el.contentDocument.head.appendChild(script); |
|||
} else { |
|||
that.renderBody(); |
|||
} |
|||
frame.el.onload = () => { |
|||
var scripts = that.config.scripts.slice(0), // clone
|
|||
counter = 0; |
|||
|
|||
function appendScript(scripts) { |
|||
if (scripts.length > 0) { |
|||
var script = document.createElement('script'); |
|||
script.type = 'text/javascript'; |
|||
script.src = scripts.shift(); |
|||
script.onerror = script.onload = appendScript.bind(null, scripts); |
|||
frame.el.contentDocument.head.appendChild(script); |
|||
} else { |
|||
that.renderBody(); |
|||
} |
|||
appendScript(scripts); |
|||
}; |
|||
}, |
|||
} |
|||
appendScript(scripts); |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Render inside frame's body |
|||
* @private |
|||
*/ |
|||
renderBody: function() { |
|||
var wrap = this.model.get('frame').get('wrapper'); |
|||
var em = this.config.em; |
|||
if(wrap) { |
|||
var ppfx = this.ppfx; |
|||
var body = this.frame.$el.contents().find('body'); |
|||
var cssc = em.get('CssComposer'); |
|||
var conf = em.get('Config'); |
|||
body.append(wrap.render()).append(cssc.render()); |
|||
var protCss = conf.protectedCss; |
|||
/** |
|||
* Render inside frame's body |
|||
* @private |
|||
*/ |
|||
renderBody() { |
|||
var wrap = this.model.get('frame').get('wrapper'); |
|||
var em = this.config.em; |
|||
if(wrap) { |
|||
var ppfx = this.ppfx; |
|||
var body = this.frame.$el.contents().find('body'); |
|||
var cssc = em.get('CssComposer'); |
|||
var conf = em.get('Config'); |
|||
body.append(wrap.render()).append(cssc.render()); |
|||
var protCss = conf.protectedCss; |
|||
|
|||
// I need all this styles to make the editor work properly
|
|||
var frameCss = '* {box-sizing: border-box;} body{margin:0;height:auto;background-color:#fff} #wrapper{min-height:100%; overflow:auto}' + |
|||
'.' + ppfx + 'dashed :not([contenteditable]) > *[data-highlightable]{outline: 1px dashed rgba(170,170,170,0.7); outline-offset: -2px}' + |
|||
'.' + ppfx + 'comp-selected{outline: 3px solid #3b97e3 !important}' + |
|||
'.' + ppfx + 'no-select{user-select: none; -webkit-user-select:none; -moz-user-select: none}'+ |
|||
'.' + ppfx + 'freezed{opacity: 0.5; pointer-events: none}' + |
|||
'.' + ppfx + 'no-pointer{pointer-events: none}' + |
|||
'.' + ppfx + 'plh-image{background:#f5f5f5; border:none; height:50px; width:50px; display:block; outline:3px solid #ffca6f; cursor:pointer}' + |
|||
'.' + ppfx + 'grabbing{cursor: grabbing; cursor: -webkit-grabbing}' + |
|||
'* ::-webkit-scrollbar-track {background: rgba(0, 0, 0, 0.1)}' + |
|||
'* ::-webkit-scrollbar-thumb {background: rgba(255, 255, 255, 0.2)}' + |
|||
'* ::-webkit-scrollbar {width: 10px}' + |
|||
(conf.canvasCss || ''); |
|||
frameCss += protCss || ''; |
|||
body.append('<style>' + frameCss + '</style>'); |
|||
body.append(this.getJsContainer()); |
|||
em.trigger('loaded'); |
|||
this.frame.el.contentWindow.onscroll = this.onFrameScroll; |
|||
this.frame.udpateOffset(); |
|||
// I need all this styles to make the editor work properly
|
|||
var frameCss = '* {box-sizing: border-box;} body{margin:0;height:auto;background-color:#fff} #wrapper{min-height:100%; overflow:auto}' + |
|||
'.' + ppfx + 'dashed :not([contenteditable]) > *[data-highlightable]{outline: 1px dashed rgba(170,170,170,0.7); outline-offset: -2px}' + |
|||
'.' + ppfx + 'comp-selected{outline: 3px solid #3b97e3 !important}' + |
|||
'.' + ppfx + 'no-select{user-select: none; -webkit-user-select:none; -moz-user-select: none}'+ |
|||
'.' + ppfx + 'freezed{opacity: 0.5; pointer-events: none}' + |
|||
'.' + ppfx + 'no-pointer{pointer-events: none}' + |
|||
'.' + ppfx + 'plh-image{background:#f5f5f5; border:none; height:50px; width:50px; display:block; outline:3px solid #ffca6f; cursor:pointer}' + |
|||
'.' + ppfx + 'grabbing{cursor: grabbing; cursor: -webkit-grabbing}' + |
|||
'* ::-webkit-scrollbar-track {background: rgba(0, 0, 0, 0.1)}' + |
|||
'* ::-webkit-scrollbar-thumb {background: rgba(255, 255, 255, 0.2)}' + |
|||
'* ::-webkit-scrollbar {width: 10px}' + |
|||
(conf.canvasCss || ''); |
|||
frameCss += protCss || ''; |
|||
body.append('<style>' + frameCss + '</style>'); |
|||
body.append(this.getJsContainer()); |
|||
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)); |
|||
}); |
|||
} |
|||
}, |
|||
// 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', e => { |
|||
doc.dispatchEvent(new KeyboardEvent(e.type, e)); |
|||
}); |
|||
fdoc.addEventListener('keyup', 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 |
|||
}; |
|||
}, |
|||
/** |
|||
* Get the offset of the element |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
*/ |
|||
offset(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; |
|||
}, |
|||
/** |
|||
* Cleare cached offsets |
|||
* @private |
|||
*/ |
|||
clearOff() { |
|||
this.frmOff = null; |
|||
this.cvsOff = null; |
|||
}, |
|||
|
|||
/** |
|||
* Return frame offset |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getFrameOffset: function () { |
|||
if(!this.frmOff) |
|||
this.frmOff = this.offset(this.frame.el); |
|||
return this.frmOff; |
|||
}, |
|||
/** |
|||
* Return frame offset |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getFrameOffset() { |
|||
if(!this.frmOff) |
|||
this.frmOff = this.offset(this.frame.el); |
|||
return this.frmOff; |
|||
}, |
|||
|
|||
/** |
|||
* Return canvas offset |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getCanvasOffset: function () { |
|||
if(!this.cvsOff) |
|||
this.cvsOff = this.offset(this.el); |
|||
return this.cvsOff; |
|||
}, |
|||
/** |
|||
* Return canvas offset |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getCanvasOffset() { |
|||
if(!this.cvsOff) |
|||
this.cvsOff = this.offset(this.el); |
|||
return this.cvsOff; |
|||
}, |
|||
|
|||
/** |
|||
* Returns element's data info |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getElementPos: function(el) { |
|||
var frmOff = this.getFrameOffset(); |
|||
var cvsOff = this.getCanvasOffset(); |
|||
var eo = this.offset(el); |
|||
var top = eo.top + frmOff.top - cvsOff.top; |
|||
var left = eo.left + frmOff.left - cvsOff.left; |
|||
return { |
|||
top: top, |
|||
left: left, |
|||
height: el.offsetHeight, |
|||
width: el.offsetWidth |
|||
}; |
|||
}, |
|||
/** |
|||
* Returns element's data info |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getElementPos(el) { |
|||
var frmOff = this.getFrameOffset(); |
|||
var cvsOff = this.getCanvasOffset(); |
|||
var eo = this.offset(el); |
|||
var top = eo.top + frmOff.top - cvsOff.top; |
|||
var left = eo.left + frmOff.left - cvsOff.left; |
|||
return { |
|||
top, |
|||
left, |
|||
height: el.offsetHeight, |
|||
width: el.offsetWidth |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Returns position data of the canvas element |
|||
* @return {Object} obj Position object |
|||
* @private |
|||
*/ |
|||
getPosition: function() { |
|||
var bEl = this.frame.el.contentDocument.body; |
|||
var fo = this.getFrameOffset(); |
|||
var co = this.getCanvasOffset(); |
|||
return { |
|||
top: fo.top + bEl.scrollTop - co.top, |
|||
left: fo.left + bEl.scrollLeft - co.left |
|||
}; |
|||
}, |
|||
/** |
|||
* Returns position data of the canvas element |
|||
* @return {Object} obj Position object |
|||
* @private |
|||
*/ |
|||
getPosition() { |
|||
var bEl = this.frame.el.contentDocument.body; |
|||
var fo = this.getFrameOffset(); |
|||
var co = this.getCanvasOffset(); |
|||
return { |
|||
top: fo.top + bEl.scrollTop - co.top, |
|||
left: fo.left + bEl.scrollLeft - co.left |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Update javascript of a specific component passed by its View |
|||
* @param {View} view Component's View |
|||
* @private |
|||
*/ |
|||
updateScript: function(view) { |
|||
if(!view.scriptContainer) { |
|||
view.scriptContainer = $('<div>'); |
|||
this.getJsContainer().append(view.scriptContainer.get(0)); |
|||
} |
|||
/** |
|||
* Update javascript of a specific component passed by its View |
|||
* @param {View} view Component's View |
|||
* @private |
|||
*/ |
|||
updateScript(view) { |
|||
if(!view.scriptContainer) { |
|||
view.scriptContainer = $('<div>'); |
|||
this.getJsContainer().append(view.scriptContainer.get(0)); |
|||
} |
|||
|
|||
var id = view.model.cid; |
|||
var script = view.model.get('script'); |
|||
var scrStr = 'function(){' + script + '}'; |
|||
scrStr = typeof script == 'function' ? script.toString() : scrStr; |
|||
var id = view.model.cid; |
|||
var script = view.model.get('script'); |
|||
var scrStr = 'function(){' + script + '}'; |
|||
scrStr = typeof script == 'function' ? script.toString() : scrStr; |
|||
|
|||
view.el.id = id; |
|||
view.scriptContainer.html(''); |
|||
view.el.id = id; |
|||
view.scriptContainer.html(''); |
|||
|
|||
view.scriptContainer.append('<script>' + |
|||
'var item = document.getElementById("'+id+'");' + |
|||
'(' + scrStr + '.bind(item))()</script>'); |
|||
}, |
|||
view.scriptContainer.append('<script>' + |
|||
'var item = document.getElementById("'+id+'");' + |
|||
'(' + scrStr + '.bind(item))()</script>'); |
|||
}, |
|||
|
|||
/** |
|||
* Get javascript container |
|||
* @private |
|||
*/ |
|||
getJsContainer: function () { |
|||
if (!this.jsContainer) { |
|||
this.jsContainer = $('<div>', {class: this.ppfx + 'js-cont'}).get(0); |
|||
} |
|||
return this.jsContainer; |
|||
}, |
|||
/** |
|||
* Get javascript container |
|||
* @private |
|||
*/ |
|||
getJsContainer() { |
|||
if (!this.jsContainer) { |
|||
this.jsContainer = $('<div>', {class: this.ppfx + 'js-cont'}).get(0); |
|||
} |
|||
return this.jsContainer; |
|||
}, |
|||
|
|||
|
|||
render: function() { |
|||
this.wrapper = this.model.get('wrapper'); |
|||
render() { |
|||
this.wrapper = this.model.get('wrapper'); |
|||
|
|||
if(this.wrapper && typeof this.wrapper.render == 'function'){ |
|||
this.model.get('frame').set('wrapper', this.wrapper); |
|||
this.$el.append(this.frame.render().el); |
|||
var frame = this.frame; |
|||
if (this.config.scripts.length === 0) { |
|||
frame.el.onload = this.renderBody; |
|||
} else { |
|||
this.renderScripts(); // will call renderBody later
|
|||
} |
|||
if(this.wrapper && typeof this.wrapper.render == 'function'){ |
|||
this.model.get('frame').set('wrapper', this.wrapper); |
|||
this.$el.append(this.frame.render().el); |
|||
var frame = this.frame; |
|||
if (this.config.scripts.length === 0) { |
|||
frame.el.onload = this.renderBody; |
|||
} else { |
|||
this.renderScripts(); // will call renderBody later
|
|||
} |
|||
var ppfx = this.ppfx; |
|||
toolsEl = $('<div>', { id: ppfx + 'tools' }).get(0); |
|||
this.hlEl = $('<div>', { class: ppfx + 'highlighter' }).get(0); |
|||
this.badgeEl = $('<div>', {class: ppfx + 'badge'}).get(0); |
|||
this.placerEl = $('<div>', {class: ppfx + 'placeholder'}).get(0); |
|||
this.placerIntEl = $('<div>', {class: ppfx + 'placeholder-int'}).get(0); |
|||
this.ghostEl = $('<div>', {class: ppfx + 'ghost'}).get(0); |
|||
this.toolbarEl = $('<div>', {class: ppfx + 'toolbar'}).get(0); |
|||
this.resizerEl = $('<div>', {class: ppfx + 'resizer'}).get(0); |
|||
this.offsetEl = $('<div>', {class: ppfx + 'offset-v'}).get(0); |
|||
this.fixedOffsetEl = $('<div>', {class: ppfx + 'offset-fixed-v'}).get(0); |
|||
this.placerEl.appendChild(this.placerIntEl); |
|||
toolsEl.appendChild(this.hlEl); |
|||
toolsEl.appendChild(this.badgeEl); |
|||
toolsEl.appendChild(this.placerEl); |
|||
toolsEl.appendChild(this.ghostEl); |
|||
toolsEl.appendChild(this.toolbarEl); |
|||
toolsEl.appendChild(this.resizerEl); |
|||
toolsEl.appendChild(this.offsetEl); |
|||
toolsEl.appendChild(this.fixedOffsetEl); |
|||
this.$el.append(toolsEl); |
|||
var rte = this.em.get('rte'); |
|||
} |
|||
var ppfx = this.ppfx; |
|||
var toolsEl = $('<div>', { id: ppfx + 'tools' }).get(0); |
|||
this.hlEl = $('<div>', { class: ppfx + 'highlighter' }).get(0); |
|||
this.badgeEl = $('<div>', {class: ppfx + 'badge'}).get(0); |
|||
this.placerEl = $('<div>', {class: ppfx + 'placeholder'}).get(0); |
|||
this.placerIntEl = $('<div>', {class: ppfx + 'placeholder-int'}).get(0); |
|||
this.ghostEl = $('<div>', {class: ppfx + 'ghost'}).get(0); |
|||
this.toolbarEl = $('<div>', {class: ppfx + 'toolbar'}).get(0); |
|||
this.resizerEl = $('<div>', {class: ppfx + 'resizer'}).get(0); |
|||
this.offsetEl = $('<div>', {class: ppfx + 'offset-v'}).get(0); |
|||
this.fixedOffsetEl = $('<div>', {class: ppfx + 'offset-fixed-v'}).get(0); |
|||
this.placerEl.appendChild(this.placerIntEl); |
|||
toolsEl.appendChild(this.hlEl); |
|||
toolsEl.appendChild(this.badgeEl); |
|||
toolsEl.appendChild(this.placerEl); |
|||
toolsEl.appendChild(this.ghostEl); |
|||
toolsEl.appendChild(this.toolbarEl); |
|||
toolsEl.appendChild(this.resizerEl); |
|||
toolsEl.appendChild(this.offsetEl); |
|||
toolsEl.appendChild(this.fixedOffsetEl); |
|||
this.$el.append(toolsEl); |
|||
var rte = this.em.get('rte'); |
|||
|
|||
if(rte) |
|||
toolsEl.appendChild(rte.render()); |
|||
if(rte) |
|||
toolsEl.appendChild(rte.render()); |
|||
|
|||
this.toolsEl = toolsEl; |
|||
this.$el.attr({class: this.className}); |
|||
return this; |
|||
}, |
|||
this.toolsEl = toolsEl; |
|||
this.$el.attr({class: this.className}); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,55 +1,51 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
var Backbone = require('backbone'); |
|||
|
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
tagName: 'iframe', |
|||
|
|||
attributes: { |
|||
src: 'about:blank', |
|||
allowfullscreen: 'allowfullscreen' |
|||
}, |
|||
|
|||
initialize(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); |
|||
}, |
|||
|
|||
/** |
|||
* @class CanvasView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
tagName: 'iframe', |
|||
|
|||
attributes: { |
|||
src: 'about:blank', |
|||
allowfullscreen: 'allowfullscreen' |
|||
}, |
|||
|
|||
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; |
|||
}, |
|||
|
|||
}); |
|||
* Update width of the frame |
|||
* @private |
|||
*/ |
|||
updateWidth(model) { |
|||
var device = this.em.getDeviceModel(); |
|||
this.el.style.width = device ? device.get('width') : ''; |
|||
this.udpateOffset(); |
|||
this.$el.on(this.motionsEv, this.udpateOffset); |
|||
}, |
|||
|
|||
udpateOffset() { |
|||
var offset = this.em.get('Canvas').getOffset(); |
|||
this.em.set('canvasOffset', offset); |
|||
this.$el.off(this.motionsEv, this.udpateOffset); |
|||
}, |
|||
|
|||
getBody() { |
|||
this.$el.contents().find('body'); |
|||
}, |
|||
|
|||
getWrapper() { |
|||
return this.$el.contents().find('body > div'); |
|||
}, |
|||
|
|||
render() { |
|||
this.$el.attr({class: this.ppfx + 'frame'}); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
|
|||
@ -1,8 +1,6 @@ |
|||
define(function () { |
|||
return { |
|||
// Style prefix
|
|||
stylePrefix: 'cm-', |
|||
module.exports = { |
|||
// Style prefix
|
|||
stylePrefix: 'cm-', |
|||
|
|||
inlineCss: false, |
|||
}; |
|||
}); |
|||
inlineCss: false, |
|||
}; |
|||
|
|||
@ -0,0 +1,221 @@ |
|||
/** |
|||
* - [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 |
|||
*/ |
|||
module.exports = () => { |
|||
|
|||
var c = {}, |
|||
defaults = require('./config/config'), |
|||
gHtml = require('./model/HtmlGenerator'), |
|||
gCss = require('./model/CssGenerator'), |
|||
gJson = require('./model/JsonGenerator'), |
|||
gJs = require('./model/JsGenerator'), |
|||
eCM = require('./model/CodeMirrorEditor'), |
|||
editorView = require('./view/EditorView'); |
|||
|
|||
var generators = {}, |
|||
defGenerators = {}, |
|||
viewers = {}, |
|||
defViewers = {}; |
|||
|
|||
return { |
|||
|
|||
getConfig() { |
|||
return c; |
|||
}, |
|||
|
|||
config: c, |
|||
|
|||
EditorView: editorView, |
|||
|
|||
/** |
|||
* 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(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(); |
|||
defGenerators.js = new gJs(); |
|||
|
|||
defViewers.CodeMirror = new eCM(); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Callback on load |
|||
*/ |
|||
onLoad() { |
|||
this.loadDefaultGenerators().loadDefaultViewers(); |
|||
}, |
|||
|
|||
/** |
|||
* 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'; |
|||
* } |
|||
* }); |
|||
* */ |
|||
addGenerator(id, generator) { |
|||
generators[id] = generator; |
|||
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
|
|||
* }; |
|||
* */ |
|||
getGenerator(id) { |
|||
return generators[id] || null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns all code generators |
|||
* @return {Array<Object>} |
|||
* */ |
|||
getGenerators() { |
|||
return generators; |
|||
}, |
|||
|
|||
/** |
|||
* 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); |
|||
* } |
|||
* }); |
|||
* */ |
|||
addViewer(id, viewer) { |
|||
viewers[id] = viewer; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Get code viewer by id |
|||
* @param {string} id Code viewer ID |
|||
* @return {Object|null} |
|||
* @example |
|||
* var viewer = codeManager.getViewer('ace'); |
|||
* */ |
|||
getViewer(id) { |
|||
return viewers[id] || null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns all code viewers |
|||
* @return {Array<Object>} |
|||
* */ |
|||
getViewers() { |
|||
return viewers; |
|||
}, |
|||
|
|||
/** |
|||
* 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'); |
|||
* */ |
|||
updateViewer(viewer, code) { |
|||
viewer.setContent(code); |
|||
}, |
|||
|
|||
/** |
|||
* 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'); |
|||
* */ |
|||
getCode(model, genId, opt) { |
|||
var generator = this.getGenerator(genId); |
|||
return generator ? generator.build(model, opt) : ''; |
|||
}, |
|||
|
|||
/** |
|||
* Load default code generators |
|||
* @return {this} |
|||
* @private |
|||
* */ |
|||
loadDefaultGenerators() { |
|||
for (var id in defGenerators) |
|||
this.addGenerator(id, defGenerators[id]); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Load default code viewers |
|||
* @return {this} |
|||
* @private |
|||
* */ |
|||
loadDefaultViewers() { |
|||
for (var id in defViewers) |
|||
this.addViewer(id, defViewers[id]); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
@ -1,227 +0,0 @@ |
|||
/** |
|||
* - [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) { |
|||
|
|||
var CodeManager = function() { |
|||
|
|||
var c = {}, |
|||
defaults = require('./config/config'), |
|||
gHtml = require('./model/HtmlGenerator'), |
|||
gCss = require('./model/CssGenerator'), |
|||
gJson = require('./model/JsonGenerator'), |
|||
gJs = require('./model/JsGenerator'), |
|||
eCM = require('./model/CodeMirrorEditor'), |
|||
editorView = require('./view/EditorView'); |
|||
|
|||
var generators = {}, |
|||
defGenerators = {}, |
|||
viewers = {}, |
|||
defViewers = {}; |
|||
|
|||
return { |
|||
|
|||
getConfig: function() { |
|||
return c; |
|||
}, |
|||
|
|||
config: c, |
|||
|
|||
EditorView: editorView, |
|||
|
|||
/** |
|||
* 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(); |
|||
defGenerators.js = new gJs(); |
|||
|
|||
defViewers.CodeMirror = new eCM(); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Callback on load |
|||
*/ |
|||
onLoad: function(){ |
|||
this.loadDefaultGenerators().loadDefaultViewers(); |
|||
}, |
|||
|
|||
/** |
|||
* 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'; |
|||
* } |
|||
* }); |
|||
* */ |
|||
addGenerator: function(id, generator) { |
|||
generators[id] = generator; |
|||
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
|
|||
* }; |
|||
* */ |
|||
getGenerator: function(id) { |
|||
return generators[id] || null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns all code generators |
|||
* @return {Array<Object>} |
|||
* */ |
|||
getGenerators: function() { |
|||
return generators; |
|||
}, |
|||
|
|||
/** |
|||
* 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); |
|||
* } |
|||
* }); |
|||
* */ |
|||
addViewer: function(id, viewer) { |
|||
viewers[id] = viewer; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Get code viewer by id |
|||
* @param {string} id Code viewer ID |
|||
* @return {Object|null} |
|||
* @example |
|||
* var viewer = codeManager.getViewer('ace'); |
|||
* */ |
|||
getViewer: function(id) { |
|||
return viewers[id] || null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns all code viewers |
|||
* @return {Array<Object>} |
|||
* */ |
|||
getViewers: function() { |
|||
return viewers; |
|||
}, |
|||
|
|||
/** |
|||
* 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'); |
|||
* */ |
|||
updateViewer: function(viewer, code) { |
|||
viewer.setContent(code); |
|||
}, |
|||
|
|||
/** |
|||
* 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'); |
|||
* */ |
|||
getCode: function(model, genId, opt) { |
|||
var generator = this.getGenerator(genId); |
|||
return generator ? generator.build(model, opt) : ''; |
|||
}, |
|||
|
|||
/** |
|||
* Load default code generators |
|||
* @return {this} |
|||
* @private |
|||
* */ |
|||
loadDefaultGenerators: function() { |
|||
for (var id in defGenerators) |
|||
this.addGenerator(id, defGenerators[id]); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Load default code viewers |
|||
* @return {this} |
|||
* @private |
|||
* */ |
|||
loadDefaultViewers: function() { |
|||
for (var id in defViewers) |
|||
this.addViewer(id, defViewers[id]); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
|
|||
return CodeManager; |
|||
|
|||
}); |
|||
@ -1,51 +1,44 @@ |
|||
define(['backbone', |
|||
'codemirror/lib/codemirror', |
|||
'codemirror/mode/htmlmixed/htmlmixed', |
|||
'codemirror/mode/css/css', |
|||
'formatting' |
|||
], |
|||
function(Backbone, CodeMirror, htmlMode, cssMode, formatting) { |
|||
/** |
|||
* @class CodeViewer |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
var Backbone = require('backbone'); |
|||
var CodeMirror = require('codemirror/lib/codemirror'); |
|||
var htmlMode = require('codemirror/mode/htmlmixed/htmlmixed'); |
|||
var cssMode = require('codemirror/mode/css/css'); |
|||
var formatting = require('codemirror-formatting'); |
|||
|
|||
defaults: { |
|||
input : '', |
|||
label : '', |
|||
codeName : '', |
|||
theme : '', |
|||
readOnly : true, |
|||
lineNumbers : true, |
|||
}, |
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
/** @inheritdoc */ |
|||
init: function(el) |
|||
{ |
|||
this.editor = CodeMirror.fromTextArea(el, { |
|||
dragDrop: false, |
|||
lineWrapping: true, |
|||
lineNumbers: this.get('lineNumbers'), |
|||
readOnly: this.get('readOnly'), |
|||
mode: this.get('codeName'), |
|||
theme: this.get('theme'), |
|||
}); |
|||
defaults: { |
|||
input : '', |
|||
label : '', |
|||
codeName : '', |
|||
theme : '', |
|||
readOnly : true, |
|||
lineNumbers : true, |
|||
}, |
|||
|
|||
return this; |
|||
}, |
|||
/** @inheritdoc */ |
|||
init(el) { |
|||
this.editor = CodeMirror.fromTextArea(el, { |
|||
dragDrop: false, |
|||
lineWrapping: true, |
|||
lineNumbers: this.get('lineNumbers'), |
|||
readOnly: this.get('readOnly'), |
|||
mode: this.get('codeName'), |
|||
theme: this.get('theme'), |
|||
}); |
|||
|
|||
/** @inheritdoc */ |
|||
setContent : function(v) |
|||
{ |
|||
if(!this.editor) |
|||
return; |
|||
this.editor.setValue(v); |
|||
if(this.editor.autoFormatRange){ |
|||
CodeMirror.commands.selectAll(this.editor); |
|||
this.editor.autoFormatRange(this.editor.getCursor(true), this.editor.getCursor(false) ); |
|||
CodeMirror.commands.goDocStart(this.editor); |
|||
} |
|||
}, |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
/** @inheritdoc */ |
|||
setContent(v) { |
|||
if(!this.editor) |
|||
return; |
|||
this.editor.setValue(v); |
|||
if(this.editor.autoFormatRange){ |
|||
CodeMirror.commands.selectAll(this.editor); |
|||
this.editor.autoFormatRange(this.editor.getCursor(true), this.editor.getCursor(false) ); |
|||
CodeMirror.commands.goDocStart(this.editor); |
|||
} |
|||
}, |
|||
|
|||
}); |
|||
|
|||
@ -1,151 +1,147 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class CssGenerator |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
initialize: function() { |
|||
this.compCls = []; |
|||
}, |
|||
|
|||
/** |
|||
* Get CSS from component |
|||
* @param {Model} model |
|||
* @return {String} |
|||
*/ |
|||
buildFromModel: function (model) { |
|||
var code = ''; |
|||
var style = model.get('style'); |
|||
var classes = model.get('classes'); |
|||
|
|||
// Let's know what classes I've found
|
|||
if(classes) { |
|||
classes.each(function(model){ |
|||
this.compCls.push(model.get('name')); |
|||
}, this); |
|||
var Backbone = require('backbone'); |
|||
|
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
initialize() { |
|||
this.compCls = []; |
|||
}, |
|||
|
|||
/** |
|||
* Get CSS from component |
|||
* @param {Model} model |
|||
* @return {String} |
|||
*/ |
|||
buildFromModel(model) { |
|||
var code = ''; |
|||
var style = model.get('style'); |
|||
var classes = model.get('classes'); |
|||
|
|||
// Let's know what classes I've found
|
|||
if(classes) { |
|||
classes.each(function(model){ |
|||
this.compCls.push(model.get('name')); |
|||
}, this); |
|||
} |
|||
|
|||
if(style && Object.keys(style).length !== 0) { |
|||
code += '#' + model.cid + '{'; |
|||
for(var prop in style){ |
|||
if(style.hasOwnProperty(prop)) |
|||
code += prop + ':' + style[prop] + ';'; |
|||
} |
|||
code += '}'; |
|||
} |
|||
|
|||
return code; |
|||
}, |
|||
|
|||
/** |
|||
* Get CSS from components |
|||
* @param {Model} model |
|||
* @return {String} |
|||
*/ |
|||
buildFromComp(model) { |
|||
var coll = model.get('components') || model, |
|||
code = ''; |
|||
|
|||
coll.each(function(m) { |
|||
var cln = m.get('components'); |
|||
code += this.buildFromModel(m); |
|||
|
|||
if(cln.length){ |
|||
code += this.buildFromComp(cln); |
|||
} |
|||
|
|||
}, this); |
|||
|
|||
return code; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
build(model, cssc) { |
|||
this.compCls = []; |
|||
var code = this.buildFromModel(model); |
|||
code += this.buildFromComp(model); |
|||
var compCls = this.compCls; |
|||
|
|||
if(cssc){ |
|||
var rules = cssc.getAll(); |
|||
var mediaRules = {}; |
|||
rules.each(function(rule) { |
|||
var width = rule.get('mediaText'); |
|||
|
|||
// If width setted will render it later
|
|||
if(width){ |
|||
var mRule = mediaRules[width]; |
|||
if(mRule) |
|||
mRule.push(rule); |
|||
else |
|||
mediaRules[width] = [rule]; |
|||
return; |
|||
} |
|||
|
|||
if(style && Object.keys(style).length !== 0) { |
|||
code += '#' + model.cid + '{'; |
|||
for(var prop in style){ |
|||
if(style.hasOwnProperty(prop)) |
|||
code += prop + ':' + style[prop] + ';'; |
|||
} |
|||
code += '}'; |
|||
} |
|||
code += this.buildFromRule(rule); |
|||
}, this); |
|||
|
|||
return code; |
|||
}, |
|||
|
|||
/** |
|||
* Get CSS from components |
|||
* @param {Model} model |
|||
* @return {String} |
|||
*/ |
|||
buildFromComp: function(model) { |
|||
var coll = model.get('components') || model, |
|||
code = ''; |
|||
|
|||
coll.each(function(m) { |
|||
var cln = m.get('components'); |
|||
code += this.buildFromModel(m); |
|||
|
|||
if(cln.length){ |
|||
code += this.buildFromComp(cln); |
|||
} |
|||
|
|||
}, this); |
|||
|
|||
return code; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
build: function(model, cssc) { |
|||
this.compCls = []; |
|||
var code = this.buildFromModel(model); |
|||
code += this.buildFromComp(model); |
|||
var compCls = this.compCls; |
|||
|
|||
if(cssc){ |
|||
var rules = cssc.getAll(); |
|||
var mediaRules = {}; |
|||
rules.each(function(rule) { |
|||
var width = rule.get('mediaText'); |
|||
|
|||
// If width setted will render it later
|
|||
if(width){ |
|||
var mRule = mediaRules[width]; |
|||
if(mRule) |
|||
mRule.push(rule); |
|||
else |
|||
mediaRules[width] = [rule]; |
|||
return; |
|||
} |
|||
|
|||
code += this.buildFromRule(rule); |
|||
}, this); |
|||
|
|||
// Get media rules
|
|||
for (var ruleW in mediaRules) { |
|||
var meRules = mediaRules[ruleW]; |
|||
var ruleC = ''; |
|||
for(var i = 0, len = meRules.length; i < len; i++){ |
|||
ruleC += this.buildFromRule(meRules[i]); |
|||
} |
|||
|
|||
if (ruleC) { |
|||
code += '@media ' + ruleW + '{' + ruleC + '}'; |
|||
} |
|||
} |
|||
// Get media rules
|
|||
for (var ruleW in mediaRules) { |
|||
var meRules = mediaRules[ruleW]; |
|||
var ruleC = ''; |
|||
for(var i = 0, len = meRules.length; i < len; i++){ |
|||
ruleC += this.buildFromRule(meRules[i]); |
|||
} |
|||
|
|||
if (ruleC) { |
|||
code += '@media ' + ruleW + '{' + ruleC + '}'; |
|||
} |
|||
return code; |
|||
}, |
|||
|
|||
/** |
|||
* Get CSS from the rule model |
|||
* @param {Model} rule |
|||
* @return {string} CSS string |
|||
*/ |
|||
buildFromRule: function(rule) { |
|||
var result = ''; |
|||
var selectorsAdd = rule.get('selectorsAdd'); |
|||
var selectors = rule.get('selectors'); |
|||
var ruleStyle = rule.get('style'); |
|||
var state = rule.get('state'); |
|||
var strSel = ''; |
|||
var found = 0; |
|||
var compCls = this.compCls; |
|||
|
|||
// Get string of selectors
|
|||
selectors.each(function(selector){ |
|||
strSel += '.' + selector.get('name'); |
|||
if(compCls.indexOf(selector.get('name')) > -1) |
|||
found = 1; |
|||
}); |
|||
|
|||
// With 'found' will skip rules which selectors are not found in
|
|||
// canvas components.
|
|||
if ((strSel && found) || selectorsAdd) { |
|||
strSel += state ? ':' + state : ''; |
|||
strSel += selectorsAdd ? (strSel ? ', ' : '') + selectorsAdd : ''; |
|||
var strStyle = ''; |
|||
|
|||
// Get string of style properties
|
|||
if(ruleStyle && Object.keys(ruleStyle).length !== 0){ |
|||
for(var prop2 in ruleStyle){ |
|||
if(ruleStyle.hasOwnProperty(prop2)) |
|||
strStyle += prop2 + ':' + ruleStyle[prop2] + ';'; |
|||
} |
|||
} |
|||
|
|||
if(strStyle) |
|||
result += strSel + '{' + strStyle + '}'; |
|||
} |
|||
|
|||
} |
|||
return code; |
|||
}, |
|||
|
|||
/** |
|||
* Get CSS from the rule model |
|||
* @param {Model} rule |
|||
* @return {string} CSS string |
|||
*/ |
|||
buildFromRule(rule) { |
|||
var result = ''; |
|||
var selectorsAdd = rule.get('selectorsAdd'); |
|||
var selectors = rule.get('selectors'); |
|||
var ruleStyle = rule.get('style'); |
|||
var state = rule.get('state'); |
|||
var strSel = ''; |
|||
var found = 0; |
|||
var compCls = this.compCls; |
|||
|
|||
// Get string of selectors
|
|||
selectors.each(selector => { |
|||
strSel += '.' + selector.get('name'); |
|||
if(compCls.indexOf(selector.get('name')) > -1) |
|||
found = 1; |
|||
}); |
|||
|
|||
// With 'found' will skip rules which selectors are not found in
|
|||
// canvas components.
|
|||
if ((strSel && found) || selectorsAdd) { |
|||
strSel += state ? ':' + state : ''; |
|||
strSel += selectorsAdd ? (strSel ? ', ' : '') + selectorsAdd : ''; |
|||
var strStyle = ''; |
|||
|
|||
// Get string of style properties
|
|||
if(ruleStyle && Object.keys(ruleStyle).length !== 0){ |
|||
for(var prop2 in ruleStyle){ |
|||
if(ruleStyle.hasOwnProperty(prop2)) |
|||
strStyle += prop2 + ':' + ruleStyle[prop2] + ';'; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
}, |
|||
if(strStyle) |
|||
result += strSel + '{' + strStyle + '}'; |
|||
} |
|||
|
|||
return result; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,23 +1,19 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class HtmlGenerator |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
var Backbone = require('backbone'); |
|||
|
|||
/** @inheritdoc */ |
|||
build: function(model, cssc){ |
|||
var coll = model.get('components') || model, |
|||
code = ''; |
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
coll.each(function(m){ |
|||
code += m.toHTML({ |
|||
cssc: cssc |
|||
}); |
|||
}, this); |
|||
/** @inheritdoc */ |
|||
build(model, cssc) { |
|||
var coll = model.get('components') || model, |
|||
code = ''; |
|||
|
|||
return code; |
|||
}, |
|||
coll.each(m => { |
|||
code += m.toHTML({ |
|||
cssc |
|||
}); |
|||
}, this); |
|||
|
|||
return code; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,62 +1,61 @@ |
|||
define(['backbone'], function (Backbone) { |
|||
|
|||
return Backbone.Model.extend({ |
|||
|
|||
mapModel: function (model) { |
|||
var code = ''; |
|||
var script = model.get('script'); |
|||
var type = model.get('type'); |
|||
var comps = model.get('components'); |
|||
var id = model.cid; |
|||
|
|||
if (script) { |
|||
// If the component has scripts we need to expose his ID
|
|||
var attr = model.get('attributes'); |
|||
attr = _.extend({}, attr, {id: id}); |
|||
model.set('attributes', attr); |
|||
|
|||
var scrStr = 'function(){' + script + '}'; |
|||
scrStr = typeof script == 'function' ? script.toString() : scrStr; |
|||
|
|||
// If the script was updated, I'll put its code in a separate container
|
|||
if (model.get('scriptUpdated')) { |
|||
this.mapJs[type+'-'+id] = {ids: [id], code: scrStr}; |
|||
} else { |
|||
var mapType = this.mapJs[type]; |
|||
|
|||
if(mapType) { |
|||
mapType.ids.push(id); |
|||
} else { |
|||
this.mapJs[type] = {ids: [id], code: scrStr}; |
|||
} |
|||
} |
|||
var Backbone = require('backbone'); |
|||
|
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
mapModel(model) { |
|||
var code = ''; |
|||
var script = model.get('script'); |
|||
var type = model.get('type'); |
|||
var comps = model.get('components'); |
|||
var id = model.cid; |
|||
|
|||
if (script) { |
|||
// If the component has scripts we need to expose his ID
|
|||
var attr = model.get('attributes'); |
|||
attr = _.extend({}, attr, {id}); |
|||
model.set('attributes', attr); |
|||
|
|||
var scrStr = 'function(){' + script + '}'; |
|||
scrStr = typeof script == 'function' ? script.toString() : scrStr; |
|||
|
|||
// If the script was updated, I'll put its code in a separate container
|
|||
if (model.get('scriptUpdated')) { |
|||
this.mapJs[type+'-'+id] = {ids: [id], code: scrStr}; |
|||
} else { |
|||
var mapType = this.mapJs[type]; |
|||
|
|||
if(mapType) { |
|||
mapType.ids.push(id); |
|||
} else { |
|||
this.mapJs[type] = {ids: [id], code: scrStr}; |
|||
} |
|||
} |
|||
} |
|||
|
|||
comps.each(function(model) { |
|||
code += this.mapModel(model); |
|||
}, this); |
|||
comps.each(function(model) { |
|||
code += this.mapModel(model); |
|||
}, this); |
|||
|
|||
return code; |
|||
}, |
|||
return code; |
|||
}, |
|||
|
|||
build: function(model) { |
|||
this.mapJs = {}; |
|||
this.mapModel(model); |
|||
build(model) { |
|||
this.mapJs = {}; |
|||
this.mapModel(model); |
|||
|
|||
var code = ''; |
|||
var code = ''; |
|||
|
|||
for(var type in this.mapJs) { |
|||
var mapType = this.mapJs[type]; |
|||
var ids = '#' + mapType.ids.join(', #'); |
|||
code += 'var items = document.querySelectorAll("'+ids+'");' + |
|||
'for (var i = 0, len = items.length; i < len; i++) {'+ |
|||
'(' + mapType.code + '.bind(items[i]))();' + |
|||
'}'; |
|||
} |
|||
for(var type in this.mapJs) { |
|||
var mapType = this.mapJs[type]; |
|||
var ids = '#' + mapType.ids.join(', #'); |
|||
code += 'var items = document.querySelectorAll("'+ids+'");' + |
|||
'for (var i = 0, len = items.length; i < len; i++) {'+ |
|||
'(' + mapType.code + '.bind(items[i]))();' + |
|||
'}'; |
|||
} |
|||
|
|||
|
|||
return code; |
|||
}, |
|||
return code; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,40 +1,36 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class JsonGenerator |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
var Backbone = require('backbone'); |
|||
|
|||
/** @inheritdoc */ |
|||
build: function(model) { |
|||
var json = model.toJSON(); |
|||
this.beforeEach(json); |
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
_.each(json,function(v, attr){ |
|||
var obj = json[attr]; |
|||
if(obj instanceof Backbone.Model){ |
|||
json[attr] = this.build(obj); |
|||
}else if(obj instanceof Backbone.Collection){ |
|||
var coll = obj; |
|||
json[attr] = []; |
|||
if(coll.length){ |
|||
coll.each(function (el, index) { |
|||
json[attr][index] = this.build(el); |
|||
}, this); |
|||
} |
|||
} |
|||
}, this); |
|||
/** @inheritdoc */ |
|||
build(model) { |
|||
var json = model.toJSON(); |
|||
this.beforeEach(json); |
|||
|
|||
return json; |
|||
}, |
|||
_.each(json,function(v, attr){ |
|||
var obj = json[attr]; |
|||
if(obj instanceof Backbone.Model){ |
|||
json[attr] = this.build(obj); |
|||
}else if(obj instanceof Backbone.Collection){ |
|||
var coll = obj; |
|||
json[attr] = []; |
|||
if(coll.length){ |
|||
coll.each(function (el, index) { |
|||
json[attr][index] = this.build(el); |
|||
}, this); |
|||
} |
|||
} |
|||
}, this); |
|||
|
|||
/** |
|||
* Execute on each object |
|||
* @param {Object} obj |
|||
*/ |
|||
beforeEach: function(obj) { |
|||
delete obj.status; |
|||
} |
|||
return json; |
|||
}, |
|||
|
|||
/** |
|||
* Execute on each object |
|||
* @param {Object} obj |
|||
*/ |
|||
beforeEach(obj) { |
|||
delete obj.status; |
|||
} |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,4 +0,0 @@ |
|||
<div class="<%= pfx %>editor" id="<%= pfx %><%= codeName %>"> |
|||
<div id="<%= pfx %>title"><%= label %></div> |
|||
<div id="<%= pfx %>code"></div> |
|||
</div> |
|||
@ -1,25 +1,25 @@ |
|||
define(['backbone', 'text!./../template/editor.html'], |
|||
function (Backbone, vTemplate) { |
|||
/** |
|||
* @class EditorView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
template: _.template(vTemplate), |
|||
|
|||
initialize: function(o){ |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix; |
|||
}, |
|||
|
|||
render : function(){ |
|||
var obj = this.model.toJSON(); |
|||
obj.pfx = this.pfx; |
|||
this.$el.html( this.template(obj) ); |
|||
this.$el.attr('class', this.pfx + 'editor-c'); |
|||
this.$el.find('#'+this.pfx+'code').html(this.model.get('input')); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
var Backbone = require('backbone'); |
|||
|
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
template: _.template(` |
|||
<div class="<%= pfx %>editor" id="<%= pfx %><%= codeName %>"> |
|||
<div id="<%= pfx %>title"><%= label %></div> |
|||
<div id="<%= pfx %>code"></div> |
|||
</div>`), |
|||
|
|||
initialize(o) { |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix; |
|||
}, |
|||
|
|||
render() { |
|||
var obj = this.model.toJSON(); |
|||
obj.pfx = this.pfx; |
|||
this.$el.html( this.template(obj) ); |
|||
this.$el.attr('class', this.pfx + 'editor-c'); |
|||
this.$el.find('#'+this.pfx+'code').html(this.model.get('input')); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
|
|||
@ -1,25 +1,23 @@ |
|||
define(function () { |
|||
return { |
|||
module.exports = { |
|||
|
|||
ESCAPE_KEY : 27, |
|||
ESCAPE_KEY: 27, |
|||
|
|||
stylePrefix : 'com-', |
|||
stylePrefix: 'com-', |
|||
|
|||
defaults : [], |
|||
defaults: [], |
|||
|
|||
// Editor model
|
|||
em : null, |
|||
// Editor model
|
|||
em: null, |
|||
|
|||
// If true center new first-level components
|
|||
firstCentered : true, |
|||
// If true center new first-level components
|
|||
firstCentered: true, |
|||
|
|||
// If true the new component will created with 'height', else 'min-height'
|
|||
newFixedH : false, |
|||
// If true the new component will created with 'height', else 'min-height'
|
|||
newFixedH: false, |
|||
|
|||
// Minimum height (in px) of new component
|
|||
minComponentH : 50, |
|||
// Minimum height (in px) of new component
|
|||
minComponentH: 50, |
|||
|
|||
// Minimum width (in px) of component on creation
|
|||
minComponentW : 50, |
|||
}; |
|||
}); |
|||
// Minimum width (in px) of component on creation
|
|||
minComponentW: 50, |
|||
}; |
|||
|
|||
@ -0,0 +1,236 @@ |
|||
/** |
|||
* |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [has](#has) |
|||
* |
|||
* You can init the editor with all necessary commands via configuration |
|||
* |
|||
* ```js
|
|||
* var editor = grapesjs.init({ |
|||
* ... |
|||
* commands: {...} // Check below for the properties
|
|||
* ... |
|||
* }); |
|||
* ``` |
|||
* |
|||
* Before using methods you should get first the module from the editor instance, in this way: |
|||
* |
|||
* ```js
|
|||
* var commands = editor.Commands; |
|||
* ``` |
|||
* |
|||
* @module Commands |
|||
* @param {Object} config Configurations |
|||
* @param {Array<Object>} [config.defaults=[]] Array of possible commands |
|||
* @example |
|||
* ... |
|||
* commands: { |
|||
* defaults: [{ |
|||
* id: 'helloWorld', |
|||
* run: function(editor, sender){ |
|||
* alert('Hello world!'); |
|||
* }, |
|||
* stop: function(editor, sender){ |
|||
* alert('Stop!'); |
|||
* }, |
|||
* }], |
|||
* }, |
|||
* ... |
|||
*/ |
|||
|
|||
module.exports = () => { |
|||
var c = {}, |
|||
commands = {}, |
|||
defaultCommands = {}, |
|||
defaults = require('./config/config'), |
|||
AbsCommands = require('./view/CommandAbstract'); |
|||
|
|||
// Need it here as it would be used below
|
|||
var add = function(id, obj){ |
|||
delete obj.initialize; |
|||
commands[id] = AbsCommands.extend(obj); |
|||
return this; |
|||
}; |
|||
|
|||
return { |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'Commands', |
|||
|
|||
/** |
|||
* Initialize module. Automatically called with a new instance of the editor |
|||
* @param {Object} config Configurations |
|||
* @private |
|||
*/ |
|||
init(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; |
|||
|
|||
// Load commands passed via configuration
|
|||
for( var k in c.defaults) { |
|||
var obj = c.defaults[k]; |
|||
if(obj.id) |
|||
this.add(obj.id, obj); |
|||
} |
|||
|
|||
defaultCommands['select-comp'] = require('./view/SelectComponent'); |
|||
defaultCommands['create-comp'] = require('./view/CreateComponent'); |
|||
defaultCommands['delete-comp'] = require('./view/DeleteComponent'); |
|||
defaultCommands['image-comp'] = require('./view/ImageComponent'); |
|||
defaultCommands['move-comp'] = require('./view/MoveComponent'); |
|||
defaultCommands['text-comp'] = require('./view/TextComponent'); |
|||
defaultCommands['insert-custom'] = require('./view/InsertCustom'); |
|||
defaultCommands['export-template'] = require('./view/ExportTemplate'); |
|||
defaultCommands['sw-visibility'] = require('./view/SwitchVisibility'); |
|||
defaultCommands['open-layers'] = require('./view/OpenLayers'); |
|||
defaultCommands['open-sm'] = require('./view/OpenStyleManager'); |
|||
defaultCommands['open-tm'] = require('./view/OpenTraitManager'); |
|||
defaultCommands['open-blocks'] = require('./view/OpenBlocks'); |
|||
defaultCommands['open-assets'] = require('./view/OpenAssets'); |
|||
defaultCommands['show-offset'] = require('./view/ShowOffset'); |
|||
defaultCommands.fullscreen = require('./view/Fullscreen'); |
|||
defaultCommands.preview = require('./view/Preview'); |
|||
defaultCommands.resize = require('./view/Resize'); |
|||
|
|||
defaultCommands['tlb-delete'] = { |
|||
run(ed) { |
|||
var sel = ed.getSelected(); |
|||
|
|||
if(!sel || !sel.get('removable')) { |
|||
console.warn('The element is not removable'); |
|||
return; |
|||
} |
|||
|
|||
sel.set('status', ''); |
|||
sel.destroy(); |
|||
ed.trigger('component:update', sel); |
|||
ed.editor.set('selectedComponent', null); |
|||
}, |
|||
}; |
|||
|
|||
defaultCommands['tlb-clone'] = { |
|||
run(ed) { |
|||
var sel = ed.getSelected(); |
|||
|
|||
if(!sel || !sel.get('copyable')) { |
|||
console.warn('The element is not clonable'); |
|||
return; |
|||
} |
|||
|
|||
var collection = sel.collection; |
|||
var index = collection.indexOf(sel); |
|||
collection.add(sel.clone(), {at: index + 1}); |
|||
ed.trigger('component:update', sel); |
|||
}, |
|||
}; |
|||
|
|||
defaultCommands['tlb-move'] = { |
|||
run(ed) { |
|||
var sel = ed.getSelected(); |
|||
|
|||
if(!sel || !sel.get('draggable')) { |
|||
console.warn('The element is not draggable'); |
|||
return; |
|||
} |
|||
|
|||
var toolbarEl = ed.Canvas.getToolbarEl(); |
|||
var cmdMove = ed.Commands.get('move-comp'); |
|||
|
|||
cmdMove.onEndMoveFromModel = () => { |
|||
ed.editor.runDefault(); |
|||
ed.editor.set('selectedComponent', sel); |
|||
ed.trigger('component:update', sel); |
|||
}; |
|||
|
|||
ed.editor.stopDefault(); |
|||
cmdMove.initSorterFromModel(sel); |
|||
sel.set('status', 'selected'); |
|||
toolbarEl.style.display = 'none'; |
|||
}, |
|||
}; |
|||
|
|||
if(c.em) |
|||
c.model = c.em.get('Canvas'); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* On load callback |
|||
* @private |
|||
*/ |
|||
onLoad() { |
|||
this.loadDefaultCommands(); |
|||
}, |
|||
|
|||
/** |
|||
* Add new command to the collection |
|||
* @param {string} id Command's ID |
|||
* @param {Object} command Object representing you command. Methods `run` and `stop` are required |
|||
* @return {this} |
|||
* @example |
|||
* commands.add('myCommand', { |
|||
* run: function(editor, sender){ |
|||
* alert('Hello world!'); |
|||
* }, |
|||
* stop: function(editor, sender){ |
|||
* }, |
|||
* }); |
|||
* */ |
|||
add, |
|||
|
|||
/** |
|||
* Get command by ID |
|||
* @param {string} id Command's ID |
|||
* @return {Object} Object representing the command |
|||
* @example |
|||
* var myCommand = commands.get('myCommand'); |
|||
* myCommand.run(); |
|||
* */ |
|||
get(id) { |
|||
var el = commands[id]; |
|||
|
|||
if(typeof el == 'function'){ |
|||
el = new el(c); |
|||
commands[id] = el; |
|||
} |
|||
|
|||
return el; |
|||
}, |
|||
|
|||
/** |
|||
* Check if command exists |
|||
* @param {string} id Command's ID |
|||
* @return {Boolean} |
|||
* */ |
|||
has(id) { |
|||
return !!commands[id]; |
|||
}, |
|||
|
|||
/** |
|||
* Load default commands |
|||
* @return {this} |
|||
* @private |
|||
* */ |
|||
loadDefaultCommands() { |
|||
for (var id in defaultCommands) { |
|||
this.add(id, defaultCommands[id]); |
|||
} |
|||
|
|||
return this; |
|||
}, |
|||
}; |
|||
|
|||
}; |
|||
@ -1,238 +0,0 @@ |
|||
/** |
|||
* |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [has](#has) |
|||
* |
|||
* You can init the editor with all necessary commands via configuration |
|||
* |
|||
* ```js
|
|||
* var editor = grapesjs.init({ |
|||
* ... |
|||
* commands: {...} // Check below for the properties
|
|||
* ... |
|||
* }); |
|||
* ``` |
|||
* |
|||
* Before using methods you should get first the module from the editor instance, in this way: |
|||
* |
|||
* ```js
|
|||
* var commands = editor.Commands; |
|||
* ``` |
|||
* |
|||
* @module Commands |
|||
* @param {Object} config Configurations |
|||
* @param {Array<Object>} [config.defaults=[]] Array of possible commands |
|||
* @example |
|||
* ... |
|||
* commands: { |
|||
* defaults: [{ |
|||
* id: 'helloWorld', |
|||
* run: function(editor, sender){ |
|||
* alert('Hello world!'); |
|||
* }, |
|||
* stop: function(editor, sender){ |
|||
* alert('Stop!'); |
|||
* }, |
|||
* }], |
|||
* }, |
|||
* ... |
|||
*/ |
|||
define(function(require) { |
|||
|
|||
return function() { |
|||
var c = {}, |
|||
commands = {}, |
|||
defaultCommands = {}, |
|||
defaults = require('./config/config'), |
|||
AbsCommands = require('./view/CommandAbstract'); |
|||
|
|||
// Need it here as it would be used below
|
|||
var add = function(id, obj){ |
|||
delete obj.initialize; |
|||
commands[id] = AbsCommands.extend(obj); |
|||
return this; |
|||
}; |
|||
|
|||
return { |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'Commands', |
|||
|
|||
/** |
|||
* Initialize 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; |
|||
|
|||
// Load commands passed via configuration
|
|||
for( var k in c.defaults) { |
|||
var obj = c.defaults[k]; |
|||
if(obj.id) |
|||
this.add(obj.id, obj); |
|||
} |
|||
|
|||
defaultCommands['select-comp'] = require('./view/SelectComponent'); |
|||
defaultCommands['create-comp'] = require('./view/CreateComponent'); |
|||
defaultCommands['delete-comp'] = require('./view/DeleteComponent'); |
|||
defaultCommands['image-comp'] = require('./view/ImageComponent'); |
|||
defaultCommands['move-comp'] = require('./view/MoveComponent'); |
|||
defaultCommands['text-comp'] = require('./view/TextComponent'); |
|||
defaultCommands['insert-custom'] = require('./view/InsertCustom'); |
|||
defaultCommands['export-template'] = require('./view/ExportTemplate'); |
|||
defaultCommands['sw-visibility'] = require('./view/SwitchVisibility'); |
|||
defaultCommands['open-layers'] = require('./view/OpenLayers'); |
|||
defaultCommands['open-sm'] = require('./view/OpenStyleManager'); |
|||
defaultCommands['open-tm'] = require('./view/OpenTraitManager'); |
|||
defaultCommands['open-blocks'] = require('./view/OpenBlocks'); |
|||
defaultCommands['open-assets'] = require('./view/OpenAssets'); |
|||
defaultCommands['show-offset'] = require('./view/ShowOffset'); |
|||
defaultCommands.fullscreen = require('./view/Fullscreen'); |
|||
defaultCommands.preview = require('./view/Preview'); |
|||
defaultCommands.resize = require('./view/Resize'); |
|||
|
|||
defaultCommands['tlb-delete'] = { |
|||
run: function(ed) { |
|||
var sel = ed.getSelected(); |
|||
|
|||
if(!sel || !sel.get('removable')) { |
|||
console.warn('The element is not removable'); |
|||
return; |
|||
} |
|||
|
|||
sel.set('status', ''); |
|||
sel.destroy(); |
|||
ed.trigger('component:update', sel); |
|||
ed.editor.set('selectedComponent', null); |
|||
}, |
|||
}; |
|||
|
|||
defaultCommands['tlb-clone'] = { |
|||
run: function(ed) { |
|||
var sel = ed.getSelected(); |
|||
|
|||
if(!sel || !sel.get('copyable')) { |
|||
console.warn('The element is not clonable'); |
|||
return; |
|||
} |
|||
|
|||
var collection = sel.collection; |
|||
var index = collection.indexOf(sel); |
|||
collection.add(sel.clone(), {at: index + 1}); |
|||
ed.trigger('component:update', sel); |
|||
}, |
|||
}; |
|||
|
|||
defaultCommands['tlb-move'] = { |
|||
run: function(ed){ |
|||
var sel = ed.getSelected(); |
|||
|
|||
if(!sel || !sel.get('draggable')) { |
|||
console.warn('The element is not draggable'); |
|||
return; |
|||
} |
|||
|
|||
var toolbarEl = ed.Canvas.getToolbarEl(); |
|||
var cmdMove = ed.Commands.get('move-comp'); |
|||
|
|||
cmdMove.onEndMoveFromModel = function() { |
|||
ed.editor.runDefault(); |
|||
ed.editor.set('selectedComponent', sel); |
|||
ed.trigger('component:update', sel); |
|||
}; |
|||
|
|||
ed.editor.stopDefault(); |
|||
cmdMove.initSorterFromModel(sel); |
|||
sel.set('status', 'selected'); |
|||
toolbarEl.style.display = 'none'; |
|||
}, |
|||
}; |
|||
|
|||
if(c.em) |
|||
c.model = c.em.get('Canvas'); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* On load callback |
|||
* @private |
|||
*/ |
|||
onLoad: function() { |
|||
this.loadDefaultCommands(); |
|||
}, |
|||
|
|||
/** |
|||
* Add new command to the collection |
|||
* @param {string} id Command's ID |
|||
* @param {Object} command Object representing you command. Methods `run` and `stop` are required |
|||
* @return {this} |
|||
* @example |
|||
* commands.add('myCommand', { |
|||
* run: function(editor, sender){ |
|||
* alert('Hello world!'); |
|||
* }, |
|||
* stop: function(editor, sender){ |
|||
* }, |
|||
* }); |
|||
* */ |
|||
add: add, |
|||
|
|||
/** |
|||
* Get command by ID |
|||
* @param {string} id Command's ID |
|||
* @return {Object} Object representing the command |
|||
* @example |
|||
* var myCommand = commands.get('myCommand'); |
|||
* myCommand.run(); |
|||
* */ |
|||
get: function(id) { |
|||
var el = commands[id]; |
|||
|
|||
if(typeof el == 'function'){ |
|||
el = new el(c); |
|||
commands[id] = el; |
|||
} |
|||
|
|||
return el; |
|||
}, |
|||
|
|||
/** |
|||
* Check if command exists |
|||
* @param {string} id Command's ID |
|||
* @return {Boolean} |
|||
* */ |
|||
has: function(id) { |
|||
return !!commands[id]; |
|||
}, |
|||
|
|||
/** |
|||
* Load default commands |
|||
* @return {this} |
|||
* @private |
|||
* */ |
|||
loadDefaultCommands: function(){ |
|||
for (var id in defaultCommands) { |
|||
this.add(id, defaultCommands[id]); |
|||
} |
|||
|
|||
return this; |
|||
}, |
|||
}; |
|||
|
|||
}; |
|||
}); |
|||
@ -1,13 +1,9 @@ |
|||
define([ 'backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class Command |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
id : '', |
|||
} |
|||
|
|||
}); |
|||
var Backbone = require('backbone'); |
|||
|
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
id: '', |
|||
} |
|||
|
|||
}); |
|||
|
|||
@ -1,11 +1,8 @@ |
|||
define([ 'backbone','./Command'], |
|||
function (Backbone, Command) { |
|||
/** |
|||
* @class Commands |
|||
* */ |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Command, |
|||
|
|||
}); |
|||
var Backbone = require('backbone'); |
|||
var Command = require('./Command'); |
|||
|
|||
module.exports = Backbone.Collection.extend({ |
|||
|
|||
model: Command, |
|||
|
|||
}); |
|||
|
|||
@ -1,116 +1,111 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
/** |
|||
* @class CommandAbstract |
|||
* @private |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
/** |
|||
* Initialize method that can't be removed |
|||
* @param {Object} o Options |
|||
* @private |
|||
* */ |
|||
initialize: function(o) { |
|||
this.config = o || {}; |
|||
this.editorModel = this.em = this.config.em || {}; |
|||
this.pfx = this.config.stylePrefix; |
|||
this.ppfx = this.config.pStylePrefix; |
|||
this.hoverClass = this.pfx + 'hover'; |
|||
this.badgeClass = this.pfx + 'badge'; |
|||
this.plhClass = this.pfx + 'placeholder'; |
|||
this.freezClass = this.ppfx + 'freezed'; |
|||
|
|||
this.canvas = this.em.get && this.em.get('Canvas'); |
|||
|
|||
if(this.em.get) |
|||
this.setElement(this.getCanvas()); |
|||
|
|||
if(this.canvas){ |
|||
this.$canvas = this.$el; |
|||
this.$wrapper = $(this.getCanvasWrapper()); |
|||
this.frameEl = this.canvas.getFrameEl(); |
|||
this.canvasTool = this.getCanvasTools(); |
|||
this.bodyEl = this.getCanvasBody(); |
|||
} |
|||
|
|||
this.init(this.config); |
|||
}, |
|||
|
|||
/** |
|||
* On frame scroll callback |
|||
* @param {[type]} e [description] |
|||
* @return {[type]} [description] |
|||
*/ |
|||
onFrameScroll: function(e){}, |
|||
|
|||
/** |
|||
* Returns canval element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getCanvas: function(){ |
|||
return this.canvas.getElement(); |
|||
}, |
|||
|
|||
/** |
|||
* Get canvas body element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getCanvasBody: function(){ |
|||
return this.canvas.getBody(); |
|||
}, |
|||
|
|||
/** |
|||
* Get canvas wrapper element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getCanvasWrapper: function(){ |
|||
return this.canvas.getWrapperEl(); |
|||
}, |
|||
|
|||
/** |
|||
* Get canvas wrapper element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getCanvasTools: function(){ |
|||
return this.canvas.getToolsEl(); |
|||
}, |
|||
|
|||
/** |
|||
* Get the offset of the element |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
*/ |
|||
offset: function(el){ |
|||
var rect = el.getBoundingClientRect(); |
|||
return { |
|||
top: rect.top + el.ownerDocument.body.scrollTop, |
|||
left: rect.left + el.ownerDocument.body.scrollLeft |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Callback triggered after initialize |
|||
* @param {Object} o Options |
|||
* @private |
|||
* */ |
|||
init: function(o){}, |
|||
|
|||
/** |
|||
* Method that run command |
|||
* @param {Object} em Editor model |
|||
* @param {Object} sender Button sender |
|||
* @private |
|||
* */ |
|||
run: function(em, sender) {}, |
|||
|
|||
/** |
|||
* Method that stop command |
|||
* @param {Object} em Editor model |
|||
* @param {Object} sender Button sender |
|||
* @private |
|||
* */ |
|||
stop: function(em, sender) {}, |
|||
|
|||
}); |
|||
}); |
|||
var Backbone = require('backbone'); |
|||
|
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
/** |
|||
* Initialize method that can't be removed |
|||
* @param {Object} o Options |
|||
* @private |
|||
* */ |
|||
initialize(o) { |
|||
this.config = o || {}; |
|||
this.editorModel = this.em = this.config.em || {}; |
|||
this.pfx = this.config.stylePrefix; |
|||
this.ppfx = this.config.pStylePrefix; |
|||
this.hoverClass = this.pfx + 'hover'; |
|||
this.badgeClass = this.pfx + 'badge'; |
|||
this.plhClass = this.pfx + 'placeholder'; |
|||
this.freezClass = this.ppfx + 'freezed'; |
|||
|
|||
this.canvas = this.em.get && this.em.get('Canvas'); |
|||
|
|||
if(this.em.get) |
|||
this.setElement(this.getCanvas()); |
|||
|
|||
if(this.canvas){ |
|||
this.$canvas = this.$el; |
|||
this.$wrapper = $(this.getCanvasWrapper()); |
|||
this.frameEl = this.canvas.getFrameEl(); |
|||
this.canvasTool = this.getCanvasTools(); |
|||
this.bodyEl = this.getCanvasBody(); |
|||
} |
|||
|
|||
this.init(this.config); |
|||
}, |
|||
|
|||
/** |
|||
* On frame scroll callback |
|||
* @param {[type]} e [description] |
|||
* @return {[type]} [description] |
|||
*/ |
|||
onFrameScroll(e) {}, |
|||
|
|||
/** |
|||
* Returns canval element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getCanvas() { |
|||
return this.canvas.getElement(); |
|||
}, |
|||
|
|||
/** |
|||
* Get canvas body element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getCanvasBody() { |
|||
return this.canvas.getBody(); |
|||
}, |
|||
|
|||
/** |
|||
* Get canvas wrapper element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getCanvasWrapper() { |
|||
return this.canvas.getWrapperEl(); |
|||
}, |
|||
|
|||
/** |
|||
* Get canvas wrapper element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getCanvasTools() { |
|||
return this.canvas.getToolsEl(); |
|||
}, |
|||
|
|||
/** |
|||
* Get the offset of the element |
|||
* @param {HTMLElement} el |
|||
* @return {Object} |
|||
*/ |
|||
offset(el) { |
|||
var rect = el.getBoundingClientRect(); |
|||
return { |
|||
top: rect.top + el.ownerDocument.body.scrollTop, |
|||
left: rect.left + el.ownerDocument.body.scrollLeft |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* Callback triggered after initialize |
|||
* @param {Object} o Options |
|||
* @private |
|||
* */ |
|||
init(o) {}, |
|||
|
|||
/** |
|||
* Method that run command |
|||
* @param {Object} em Editor model |
|||
* @param {Object} sender Button sender |
|||
* @private |
|||
* */ |
|||
run(em, sender) {}, |
|||
|
|||
/** |
|||
* Method that stop command |
|||
* @param {Object} em Editor model |
|||
* @param {Object} sender Button sender |
|||
* @private |
|||
* */ |
|||
stop(em, sender) {}, |
|||
|
|||
}); |
|||
|
|||
@ -1,231 +1,230 @@ |
|||
define(['backbone','./SelectPosition'], |
|||
function(Backbone, SelectPosition) { |
|||
|
|||
return _.extend({}, SelectPosition, { |
|||
|
|||
init: function(opt) { |
|||
_.bindAll(this,'startDraw','draw','endDraw','rollback'); |
|||
this.config = opt || {}; |
|||
this.hType = this.config.newFixedH ? 'height' : 'min-height'; |
|||
this.allowDraw = 1; |
|||
}, |
|||
|
|||
/** |
|||
* Start with enabling to select position and listening to start drawning |
|||
* @private |
|||
* */ |
|||
enable: function() { |
|||
SelectPosition.enable.apply(this, arguments); |
|||
this.$wr.css('cursor','crosshair'); |
|||
if(this.allowDraw) |
|||
this.$wr.on('mousedown', this.startDraw); |
|||
this.ghost = this.canvas.getGhostEl(); |
|||
}, |
|||
|
|||
/** |
|||
* Start drawing component |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
startDraw : function(e) { |
|||
e.preventDefault(); |
|||
this.stopSelectPosition(); |
|||
this.ghost.style.display = 'block'; |
|||
this.frameOff = this.getOffsetDim(); |
|||
this.startPos = { |
|||
top : e.pageY + this.frameOff.top, |
|||
left: e.pageX + this.frameOff.left |
|||
}; |
|||
this.isDragged = false; |
|||
this.tempComponent = {style: {}}; |
|||
this.beforeDraw(this.tempComponent); |
|||
this.updateSize(this.startPos.top, this.startPos.left, 0, 0); |
|||
this.toggleEvents(1); |
|||
}, |
|||
|
|||
/** |
|||
* Enable/Disable events |
|||
* @param {Boolean} enable |
|||
*/ |
|||
toggleEvents: function(enable) { |
|||
var method = enable ? 'on' : 'off'; |
|||
this.$wr[method]('mousemove', this.draw); |
|||
this.$wr[method]('mouseup', this.endDraw); |
|||
this.$canvas[method]('mousemove', this.draw); |
|||
$(document)[method]('mouseup', this.endDraw); |
|||
$(document)[method]('keypress', this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* While drawing the component |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
draw: function(e) { |
|||
this.isDragged = true; |
|||
this.updateComponentSize(e); |
|||
}, |
|||
|
|||
/** |
|||
* End drawing component |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
endDraw : function(e) { |
|||
this.toggleEvents(); |
|||
var model = {}; |
|||
// Only if the mouse was moved
|
|||
if(this.isDragged){ |
|||
this.updateComponentSize(e); |
|||
this.setRequirements(this.tempComponent); |
|||
var lp = this.sorter.lastPos; |
|||
model = this.create(this.sorter.target, this.tempComponent, lp.index, lp.method); |
|||
this.sorter.prevTarget = null; |
|||
} |
|||
this.ghost.style.display = 'none'; |
|||
this.startSelectPosition(); |
|||
this.afterDraw(model); |
|||
}, |
|||
|
|||
/** |
|||
* Create new component inside the target |
|||
* @param {Object} target Tha target collection |
|||
* @param {Object} component New component to create |
|||
* @param {number} index Index inside the collection, 0 if no children inside |
|||
* @param {string} method Before or after of the children |
|||
* @param {Object} opts Options |
|||
*/ |
|||
create: function(target, component, index, method, opts) { |
|||
index = method === 'after' ? index + 1 : index; |
|||
var opt = opts || {}; |
|||
var $trg = $(target); |
|||
var trgModel = $trg.data('model'); |
|||
var trgCollection = $trg.data('collection'); |
|||
var droppable = trgModel ? trgModel.get('droppable') : 1; |
|||
opt.at = index; |
|||
if(trgCollection && droppable) |
|||
return trgCollection.add(component, opt); |
|||
else |
|||
console.warn("Invalid target position"); |
|||
}, |
|||
|
|||
/** |
|||
* Check and set basic requirements for the component |
|||
* @param {Object} component New component to be created |
|||
* @return {Object} Component updated |
|||
* @private |
|||
* */ |
|||
setRequirements: function(component) { |
|||
var c = this.config; |
|||
var compStl = component.style; |
|||
// Check min width
|
|||
if(compStl.width.replace(/\D/g,'') < c.minComponentW) |
|||
compStl.width = c.minComponentW +'px'; |
|||
// Check min height
|
|||
if(compStl[this.hType].replace(/\D/g,'') < c.minComponentH) |
|||
compStl[this.hType] = c.minComponentH +'px'; |
|||
// Set overflow in case of fixed height
|
|||
if(c.newFixedH) |
|||
compStl.overflow = 'auto'; |
|||
if(!this.absoluteMode){ |
|||
delete compStl.left; |
|||
delete compStl.top; |
|||
}else |
|||
compStl.position = 'absolute'; |
|||
var lp = this.sorter.lastPos; |
|||
|
|||
if(this.nearFloat(lp.index, lp.method, this.sorter.lastDims)) |
|||
compStl.float = 'left'; |
|||
|
|||
if(this.config.firstCentered && |
|||
this.getCanvasWrapper() == this.sorter.target){ |
|||
compStl.margin = '0 auto'; |
|||
} |
|||
|
|||
return component; |
|||
}, |
|||
|
|||
/** |
|||
* Update new component size while drawing |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
updateComponentSize : function (e) { |
|||
var y = e.pageY + this.frameOff.top; |
|||
var x = e.pageX + this.frameOff.left; |
|||
var start = this.startPos; |
|||
var top = start.top; |
|||
var left = start.left; |
|||
var height = y - top; |
|||
var width = x - left; |
|||
if (x < left) { |
|||
left = x; |
|||
width = start.left - x; |
|||
} |
|||
if (y < top) { |
|||
top = y; |
|||
height = start.top - y; |
|||
} |
|||
this.updateSize(top, left, width, height); |
|||
}, |
|||
|
|||
/** |
|||
* Update size |
|||
* @private |
|||
*/ |
|||
updateSize: function(top, left, width, height){ |
|||
var u = 'px'; |
|||
var ghStl = this.ghost.style; |
|||
var compStl = this.tempComponent.style; |
|||
ghStl.top = compStl.top = top + u; |
|||
ghStl.left = compStl.left = left + u; |
|||
ghStl.width = compStl.width = width + u; |
|||
ghStl[this.hType] = compStl[this.hType] = height + u; |
|||
}, |
|||
|
|||
/** |
|||
* Used to bring the previous situation before event started |
|||
* @param {Object} e Event |
|||
* @param {Boolean} forse Indicates if rollback in anycase |
|||
* @private |
|||
* */ |
|||
rollback: function(e, force) { |
|||
var key = e.which || e.keyCode; |
|||
if(key == this.config.ESCAPE_KEY || force){ |
|||
this.isDragged = false; |
|||
this.endDraw(); |
|||
} |
|||
return; |
|||
}, |
|||
|
|||
/** |
|||
* This event is triggered at the beginning of a draw operation |
|||
* @param {Object} component Object component before creation |
|||
* @private |
|||
* */ |
|||
beforeDraw: function(component){ |
|||
component.editable = false;//set this component editable
|
|||
}, |
|||
|
|||
/** |
|||
* This event is triggered at the end of a draw operation |
|||
* @param {Object} model Component model created |
|||
* @private |
|||
* */ |
|||
afterDraw: function(model){}, |
|||
|
|||
|
|||
run: function(editor, sender, opts){ |
|||
this.editor = editor; |
|||
this.sender = sender; |
|||
this.$wr = this.$wrapper; |
|||
this.enable(); |
|||
}, |
|||
|
|||
stop: function(){ |
|||
this.stopSelectPosition(); |
|||
this.$wrapper.css('cursor',''); |
|||
this.$wrapper.unbind(); |
|||
} |
|||
}); |
|||
}); |
|||
var Backbone = require('backbone'); |
|||
var SelectPosition = require('./SelectPosition'); |
|||
|
|||
module.exports = _.extend({}, SelectPosition, { |
|||
|
|||
init(opt) { |
|||
_.bindAll(this,'startDraw','draw','endDraw','rollback'); |
|||
this.config = opt || {}; |
|||
this.hType = this.config.newFixedH ? 'height' : 'min-height'; |
|||
this.allowDraw = 1; |
|||
}, |
|||
|
|||
/** |
|||
* Start with enabling to select position and listening to start drawning |
|||
* @private |
|||
* */ |
|||
enable(...args) { |
|||
SelectPosition.enable.apply(this, args); |
|||
this.$wr.css('cursor','crosshair'); |
|||
if(this.allowDraw) |
|||
this.$wr.on('mousedown', this.startDraw); |
|||
this.ghost = this.canvas.getGhostEl(); |
|||
}, |
|||
|
|||
/** |
|||
* Start drawing component |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
startDraw(e) { |
|||
e.preventDefault(); |
|||
this.stopSelectPosition(); |
|||
this.ghost.style.display = 'block'; |
|||
this.frameOff = this.getOffsetDim(); |
|||
this.startPos = { |
|||
top : e.pageY + this.frameOff.top, |
|||
left: e.pageX + this.frameOff.left |
|||
}; |
|||
this.isDragged = false; |
|||
this.tempComponent = {style: {}}; |
|||
this.beforeDraw(this.tempComponent); |
|||
this.updateSize(this.startPos.top, this.startPos.left, 0, 0); |
|||
this.toggleEvents(1); |
|||
}, |
|||
|
|||
/** |
|||
* Enable/Disable events |
|||
* @param {Boolean} enable |
|||
*/ |
|||
toggleEvents(enable) { |
|||
var method = enable ? 'on' : 'off'; |
|||
this.$wr[method]('mousemove', this.draw); |
|||
this.$wr[method]('mouseup', this.endDraw); |
|||
this.$canvas[method]('mousemove', this.draw); |
|||
$(document)[method]('mouseup', this.endDraw); |
|||
$(document)[method]('keypress', this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* While drawing the component |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
draw(e) { |
|||
this.isDragged = true; |
|||
this.updateComponentSize(e); |
|||
}, |
|||
|
|||
/** |
|||
* End drawing component |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
endDraw(e) { |
|||
this.toggleEvents(); |
|||
var model = {}; |
|||
// Only if the mouse was moved
|
|||
if(this.isDragged){ |
|||
this.updateComponentSize(e); |
|||
this.setRequirements(this.tempComponent); |
|||
var lp = this.sorter.lastPos; |
|||
model = this.create(this.sorter.target, this.tempComponent, lp.index, lp.method); |
|||
this.sorter.prevTarget = null; |
|||
} |
|||
this.ghost.style.display = 'none'; |
|||
this.startSelectPosition(); |
|||
this.afterDraw(model); |
|||
}, |
|||
|
|||
/** |
|||
* Create new component inside the target |
|||
* @param {Object} target Tha target collection |
|||
* @param {Object} component New component to create |
|||
* @param {number} index Index inside the collection, 0 if no children inside |
|||
* @param {string} method Before or after of the children |
|||
* @param {Object} opts Options |
|||
*/ |
|||
create(target, component, index, method, opts) { |
|||
index = method === 'after' ? index + 1 : index; |
|||
var opt = opts || {}; |
|||
var $trg = $(target); |
|||
var trgModel = $trg.data('model'); |
|||
var trgCollection = $trg.data('collection'); |
|||
var droppable = trgModel ? trgModel.get('droppable') : 1; |
|||
opt.at = index; |
|||
if(trgCollection && droppable) |
|||
return trgCollection.add(component, opt); |
|||
else |
|||
console.warn("Invalid target position"); |
|||
}, |
|||
|
|||
/** |
|||
* Check and set basic requirements for the component |
|||
* @param {Object} component New component to be created |
|||
* @return {Object} Component updated |
|||
* @private |
|||
* */ |
|||
setRequirements(component) { |
|||
var c = this.config; |
|||
var compStl = component.style; |
|||
// Check min width
|
|||
if(compStl.width.replace(/\D/g,'') < c.minComponentW) |
|||
compStl.width = c.minComponentW +'px'; |
|||
// Check min height
|
|||
if(compStl[this.hType].replace(/\D/g,'') < c.minComponentH) |
|||
compStl[this.hType] = c.minComponentH +'px'; |
|||
// Set overflow in case of fixed height
|
|||
if(c.newFixedH) |
|||
compStl.overflow = 'auto'; |
|||
if(!this.absoluteMode){ |
|||
delete compStl.left; |
|||
delete compStl.top; |
|||
}else |
|||
compStl.position = 'absolute'; |
|||
var lp = this.sorter.lastPos; |
|||
|
|||
if(this.nearFloat(lp.index, lp.method, this.sorter.lastDims)) |
|||
compStl.float = 'left'; |
|||
|
|||
if(this.config.firstCentered && |
|||
this.getCanvasWrapper() == this.sorter.target){ |
|||
compStl.margin = '0 auto'; |
|||
} |
|||
|
|||
return component; |
|||
}, |
|||
|
|||
/** |
|||
* Update new component size while drawing |
|||
* @param {Object} e Event |
|||
* @private |
|||
* */ |
|||
updateComponentSize(e) { |
|||
var y = e.pageY + this.frameOff.top; |
|||
var x = e.pageX + this.frameOff.left; |
|||
var start = this.startPos; |
|||
var top = start.top; |
|||
var left = start.left; |
|||
var height = y - top; |
|||
var width = x - left; |
|||
if (x < left) { |
|||
left = x; |
|||
width = start.left - x; |
|||
} |
|||
if (y < top) { |
|||
top = y; |
|||
height = start.top - y; |
|||
} |
|||
this.updateSize(top, left, width, height); |
|||
}, |
|||
|
|||
/** |
|||
* Update size |
|||
* @private |
|||
*/ |
|||
updateSize(top, left, width, height) { |
|||
var u = 'px'; |
|||
var ghStl = this.ghost.style; |
|||
var compStl = this.tempComponent.style; |
|||
ghStl.top = compStl.top = top + u; |
|||
ghStl.left = compStl.left = left + u; |
|||
ghStl.width = compStl.width = width + u; |
|||
ghStl[this.hType] = compStl[this.hType] = height + u; |
|||
}, |
|||
|
|||
/** |
|||
* Used to bring the previous situation before event started |
|||
* @param {Object} e Event |
|||
* @param {Boolean} forse Indicates if rollback in anycase |
|||
* @private |
|||
* */ |
|||
rollback(e, force) { |
|||
var key = e.which || e.keyCode; |
|||
if(key == this.config.ESCAPE_KEY || force){ |
|||
this.isDragged = false; |
|||
this.endDraw(); |
|||
} |
|||
return; |
|||
}, |
|||
|
|||
/** |
|||
* This event is triggered at the beginning of a draw operation |
|||
* @param {Object} component Object component before creation |
|||
* @private |
|||
* */ |
|||
beforeDraw(component) { |
|||
component.editable = false;//set this component editable
|
|||
}, |
|||
|
|||
/** |
|||
* This event is triggered at the end of a draw operation |
|||
* @param {Object} model Component model created |
|||
* @private |
|||
* */ |
|||
afterDraw(model) {}, |
|||
|
|||
|
|||
run(editor, sender, opts) { |
|||
this.editor = editor; |
|||
this.sender = sender; |
|||
this.$wr = this.$wrapper; |
|||
this.enable(); |
|||
}, |
|||
|
|||
stop() { |
|||
this.stopSelectPosition(); |
|||
this.$wrapper.css('cursor',''); |
|||
this.$wrapper.unbind(); |
|||
} |
|||
}); |
|||
|
|||
@ -1,88 +1,79 @@ |
|||
define(['backbone', './SelectComponent'], |
|||
function(Backbone, SelectComponent) { |
|||
/** |
|||
* @class DeleteComponent |
|||
* @private |
|||
* */ |
|||
return _.extend({},SelectComponent,{ |
|||
var Backbone = require('backbone'); |
|||
var SelectComponent = require('./SelectComponent'); |
|||
|
|||
init: function(o){ |
|||
_.bindAll(this, 'startDelete', 'stopDelete', 'onDelete'); |
|||
this.hoverClass = this.pfx + 'hover-delete'; |
|||
this.badgeClass = this.pfx + 'badge-red'; |
|||
}, |
|||
module.exports = _.extend({},SelectComponent,{ |
|||
|
|||
enable: function() |
|||
{ |
|||
var that = this; |
|||
this.$el.find('*') |
|||
.mouseover(this.startDelete) |
|||
.mouseout(this.stopDelete) |
|||
.click(this.onDelete); |
|||
}, |
|||
init(o) { |
|||
_.bindAll(this, 'startDelete', 'stopDelete', 'onDelete'); |
|||
this.hoverClass = this.pfx + 'hover-delete'; |
|||
this.badgeClass = this.pfx + 'badge-red'; |
|||
}, |
|||
|
|||
/** |
|||
* Start command |
|||
* @param {Object} e |
|||
* @private |
|||
*/ |
|||
startDelete: function(e) |
|||
{ |
|||
e.stopPropagation(); |
|||
var $this = $(e.target); |
|||
enable() { |
|||
var that = this; |
|||
this.$el.find('*') |
|||
.mouseover(this.startDelete) |
|||
.mouseout(this.stopDelete) |
|||
.click(this.onDelete); |
|||
}, |
|||
|
|||
// Show badge if possible
|
|||
if($this.data('model').get('removable')){ |
|||
$this.addClass(this.hoverClass); |
|||
this.attachBadge($this.get(0)); |
|||
} |
|||
/** |
|||
* Start command |
|||
* @param {Object} e |
|||
* @private |
|||
*/ |
|||
startDelete(e) { |
|||
e.stopPropagation(); |
|||
var $this = $(e.target); |
|||
|
|||
}, |
|||
// Show badge if possible
|
|||
if($this.data('model').get('removable')){ |
|||
$this.addClass(this.hoverClass); |
|||
this.attachBadge($this.get(0)); |
|||
} |
|||
|
|||
/** |
|||
* Stop command |
|||
* @param {Object} e |
|||
* @private |
|||
*/ |
|||
stopDelete: function(e) |
|||
{ |
|||
e.stopPropagation(); |
|||
var $this = $(e.target); |
|||
$this.removeClass(this.hoverClass); |
|||
}, |
|||
|
|||
// Hide badge if possible
|
|||
if(this.badge) |
|||
this.badge.css({ left: -1000, top:-1000 }); |
|||
}, |
|||
/** |
|||
* Stop command |
|||
* @param {Object} e |
|||
* @private |
|||
*/ |
|||
stopDelete(e) { |
|||
e.stopPropagation(); |
|||
var $this = $(e.target); |
|||
$this.removeClass(this.hoverClass); |
|||
|
|||
/** |
|||
* Delete command |
|||
* @param {Object} e |
|||
* @private |
|||
*/ |
|||
onDelete: function(e) |
|||
{ |
|||
e.stopPropagation(); |
|||
var $this = $(e.target); |
|||
// Hide badge if possible
|
|||
if(this.badge) |
|||
this.badge.css({ left: -1000, top:-1000 }); |
|||
}, |
|||
|
|||
// Do nothing in case can't remove
|
|||
if(!$this.data('model').get('removable')) |
|||
return; |
|||
/** |
|||
* Delete command |
|||
* @param {Object} e |
|||
* @private |
|||
*/ |
|||
onDelete(e) { |
|||
e.stopPropagation(); |
|||
var $this = $(e.target); |
|||
|
|||
$this.data('model').destroy(); |
|||
this.removeBadge(); |
|||
this.clean(); |
|||
}, |
|||
// Do nothing in case can't remove
|
|||
if(!$this.data('model').get('removable')) |
|||
return; |
|||
|
|||
/** |
|||
* Updates badge label |
|||
* @param {Object} model |
|||
* @private |
|||
* */ |
|||
updateBadgeLabel: function (model) |
|||
{ |
|||
this.badge.html( 'Remove ' + model.getName() ); |
|||
}, |
|||
$this.data('model').destroy(); |
|||
this.removeBadge(); |
|||
this.clean(); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
/** |
|||
* Updates badge label |
|||
* @param {Object} model |
|||
* @private |
|||
* */ |
|||
updateBadgeLabel(model) { |
|||
this.badge.html( 'Remove ' + model.getName() ); |
|||
}, |
|||
|
|||
}); |
|||
|
|||
@ -1,78 +1,72 @@ |
|||
define(function() { |
|||
/** |
|||
* @class ExportTemplate |
|||
* @private |
|||
* */ |
|||
return { |
|||
module.exports = { |
|||
|
|||
run: function(editor, sender) { |
|||
this.sender = sender; |
|||
this.wrapper = editor.DomComponents.getWrapper(); |
|||
this.components = editor.DomComponents.getComponents(); |
|||
this.modal = editor.Modal || null; |
|||
this.cm = editor.CodeManager || null; |
|||
this.cssc = editor.CssComposer || null; |
|||
this.protCss = editor.Config.protectedCss; |
|||
this.pfx = editor.Config.stylePrefix || ''; |
|||
this.enable(); |
|||
}, |
|||
run(editor, sender) { |
|||
this.sender = sender; |
|||
this.wrapper = editor.DomComponents.getWrapper(); |
|||
this.components = editor.DomComponents.getComponents(); |
|||
this.modal = editor.Modal || null; |
|||
this.cm = editor.CodeManager || null; |
|||
this.cssc = editor.CssComposer || null; |
|||
this.protCss = editor.Config.protectedCss; |
|||
this.pfx = editor.Config.stylePrefix || ''; |
|||
this.enable(); |
|||
}, |
|||
|
|||
/** |
|||
* Build editor |
|||
* @param {String} codeName |
|||
* @param {String} theme |
|||
* @param {String} label |
|||
* |
|||
* @return {Object} Editor |
|||
* @private |
|||
* */ |
|||
buildEditor: function(codeName, theme, label) { |
|||
if(!this.codeMirror) |
|||
this.codeMirror = this.cm.getViewer('CodeMirror'); |
|||
/** |
|||
* Build editor |
|||
* @param {String} codeName |
|||
* @param {String} theme |
|||
* @param {String} label |
|||
* |
|||
* @return {Object} Editor |
|||
* @private |
|||
* */ |
|||
buildEditor(codeName, theme, label) { |
|||
if(!this.codeMirror) |
|||
this.codeMirror = this.cm.getViewer('CodeMirror'); |
|||
|
|||
var $input = $('<textarea>'), |
|||
var $input = $('<textarea>'), |
|||
|
|||
editor = this.codeMirror.clone().set({ |
|||
label : label, |
|||
codeName : codeName, |
|||
theme : theme, |
|||
input : $input[0], |
|||
}), |
|||
editor = this.codeMirror.clone().set({ |
|||
label, |
|||
codeName, |
|||
theme, |
|||
input : $input[0], |
|||
}), |
|||
|
|||
$editor = new this.cm.EditorView({ |
|||
model : editor, |
|||
config : this.cm.getConfig() |
|||
}).render().$el; |
|||
$editor = new this.cm.EditorView({ |
|||
model : editor, |
|||
config : this.cm.getConfig() |
|||
}).render().$el; |
|||
|
|||
editor.init( $input[0] ); |
|||
editor.init( $input[0] ); |
|||
|
|||
return { el: editor, $el: $editor }; |
|||
}, |
|||
return { el: editor, $el: $editor }; |
|||
}, |
|||
|
|||
enable: function() { |
|||
if(!this.$editors){ |
|||
var oHtmlEd = this.buildEditor('htmlmixed', 'hopscotch', 'HTML'), |
|||
oCsslEd = this.buildEditor('css', 'hopscotch', 'CSS'); |
|||
this.htmlEditor = oHtmlEd.el; |
|||
this.cssEditor = oCsslEd.el; |
|||
this.$editors = $('<div>', {class: this.pfx + 'export-dl'}); |
|||
this.$editors.append(oHtmlEd.$el).append(oCsslEd.$el); |
|||
} |
|||
enable() { |
|||
if(!this.$editors){ |
|||
var oHtmlEd = this.buildEditor('htmlmixed', 'hopscotch', 'HTML'), |
|||
oCsslEd = this.buildEditor('css', 'hopscotch', 'CSS'); |
|||
this.htmlEditor = oHtmlEd.el; |
|||
this.cssEditor = oCsslEd.el; |
|||
this.$editors = $('<div>', {class: this.pfx + 'export-dl'}); |
|||
this.$editors.append(oHtmlEd.$el).append(oCsslEd.$el); |
|||
} |
|||
|
|||
if(this.modal){ |
|||
this.modal.setTitle('Export template'); |
|||
this.modal.setContent(this.$editors); |
|||
this.modal.open(); |
|||
} |
|||
var addCss = this.protCss || ''; |
|||
//this.htmlEditor.setContent(this.cm.getCode(this.components, 'html', this.cssc));
|
|||
this.htmlEditor.setContent(this.em.getHtml()); |
|||
this.cssEditor.setContent(addCss + this.cm.getCode(this.wrapper, 'css', this.cssc)); |
|||
if(this.modal){ |
|||
this.modal.setTitle('Export template'); |
|||
this.modal.setContent(this.$editors); |
|||
this.modal.open(); |
|||
} |
|||
var addCss = this.protCss || ''; |
|||
//this.htmlEditor.setContent(this.cm.getCode(this.components, 'html', this.cssc));
|
|||
this.htmlEditor.setContent(this.em.getHtml()); |
|||
this.cssEditor.setContent(addCss + this.cm.getCode(this.wrapper, 'css', this.cssc)); |
|||
|
|||
if(this.sender) |
|||
this.sender.set('active',false); |
|||
}, |
|||
if(this.sender) |
|||
this.sender.set('active',false); |
|||
}, |
|||
|
|||
stop: function(){} |
|||
}; |
|||
}); |
|||
stop() {} |
|||
}; |
|||
|
|||
@ -1,86 +1,83 @@ |
|||
define(function() { |
|||
module.exports = { |
|||
/** |
|||
* Check if fullscreen mode is enabled |
|||
* @return {Boolean} |
|||
*/ |
|||
isEnabled() { |
|||
var d = document; |
|||
if(d.fullscreenElement || d.webkitFullscreenElement || d.mozFullScreenElement) |
|||
return 1; |
|||
else |
|||
return 0; |
|||
}, |
|||
|
|||
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(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; |
|||
}, |
|||
|
|||
/** |
|||
* 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() { |
|||
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(); |
|||
}, |
|||
|
|||
/** |
|||
* 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(pfx, e) { |
|||
var d = document; |
|||
var ev = (pfx || '') + 'fullscreenchange'; |
|||
if(!this.isEnabled()){ |
|||
this.stop(null, this.sender); |
|||
document.removeEventListener(ev, this.fsChanged); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 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(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'); |
|||
}, |
|||
|
|||
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(editor, sender) { |
|||
if(sender && sender.set) |
|||
sender.set('active', false); |
|||
this.disable(); |
|||
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,39 +1,35 @@ |
|||
define(['backbone', './InsertCustom'], |
|||
function(Backbone, InsertCustom) { |
|||
/** |
|||
* @class ImageComponent |
|||
* @private |
|||
* */ |
|||
return _.extend({}, InsertCustom, { |
|||
var Backbone = require('backbone'); |
|||
var InsertCustom = require('./InsertCustom'); |
|||
|
|||
/** |
|||
* Trigger before insert |
|||
* @param {Object} object |
|||
* @private |
|||
* |
|||
* */ |
|||
beforeInsert: function(object){ |
|||
object.type = 'image'; |
|||
object.style = {}; |
|||
object.attributes = {}; |
|||
object.attributes.onmousedown = 'return false'; |
|||
if (this.config.firstCentered && |
|||
this.getCanvasWrapper() == this.sorter.target ) { |
|||
object.style.margin = '0 auto'; |
|||
} |
|||
}, |
|||
module.exports = _.extend({}, InsertCustom, { |
|||
|
|||
/** |
|||
* Trigger after insert |
|||
* @param {Object} model Model created after insert |
|||
* @private |
|||
* */ |
|||
afterInsert: function(model){ |
|||
model.trigger('dblclick'); |
|||
if(this.sender) |
|||
this.sender.set('active', false); |
|||
}, |
|||
/** |
|||
* Trigger before insert |
|||
* @param {Object} object |
|||
* @private |
|||
* |
|||
* */ |
|||
beforeInsert(object) { |
|||
object.type = 'image'; |
|||
object.style = {}; |
|||
object.attributes = {}; |
|||
object.attributes.onmousedown = 'return false'; |
|||
if (this.config.firstCentered && |
|||
this.getCanvasWrapper() == this.sorter.target ) { |
|||
object.style.margin = '0 auto'; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Trigger after insert |
|||
* @param {Object} model Model created after insert |
|||
* @private |
|||
* */ |
|||
afterInsert(model) { |
|||
model.trigger('dblclick'); |
|||
if(this.sender) |
|||
this.sender.set('active', false); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
@ -1,83 +1,79 @@ |
|||
define(['backbone', './CreateComponent'], |
|||
function(Backbone, CreateComponent) { |
|||
/** |
|||
* @class InsertCustom |
|||
* @private |
|||
* */ |
|||
return _.extend({}, CreateComponent, { |
|||
var Backbone = require('backbone'); |
|||
var CreateComponent = require('./CreateComponent'); |
|||
|
|||
init: function(){ |
|||
CreateComponent.init.apply(this, arguments); |
|||
_.bindAll(this, 'insertComponent'); |
|||
this.allowDraw = 0; |
|||
}, |
|||
module.exports = _.extend({}, CreateComponent, { |
|||
|
|||
/** |
|||
* Run method |
|||
* @private |
|||
* */ |
|||
run: function(em, sender, options) { |
|||
this.em = em; |
|||
this.sender = sender; |
|||
this.opt = options || {}; |
|||
this.$wr = this.$wrapper; |
|||
this.enable(); |
|||
}, |
|||
init(...args) { |
|||
CreateComponent.init.apply(this, args); |
|||
_.bindAll(this, 'insertComponent'); |
|||
this.allowDraw = 0; |
|||
}, |
|||
|
|||
enable: function(){ |
|||
CreateComponent.enable.apply(this, arguments); |
|||
this.$wr.on('click', this.insertComponent); |
|||
}, |
|||
/** |
|||
* Run method |
|||
* @private |
|||
* */ |
|||
run(em, sender, options) { |
|||
this.em = em; |
|||
this.sender = sender; |
|||
this.opt = options || {}; |
|||
this.$wr = this.$wrapper; |
|||
this.enable(); |
|||
}, |
|||
|
|||
/** |
|||
* Start insert event |
|||
* @private |
|||
* */ |
|||
insertComponent: function(){ |
|||
this.$wr.off('click', this.insertComponent); |
|||
this.stopSelectPosition(); |
|||
var object = this.buildContent(); |
|||
this.beforeInsert(object); |
|||
var index = this.sorter.lastPos.index; |
|||
// By default, collections do not trigger add event, so silent is used
|
|||
var model = this.create(this.sorter.target, object, index, null, {silent: false}); |
|||
enable(...args) { |
|||
CreateComponent.enable.apply(this, args); |
|||
this.$wr.on('click', this.insertComponent); |
|||
}, |
|||
|
|||
if(this.opt.terminateAfterInsert && this.sender) |
|||
this.sender.set('active', false); |
|||
else |
|||
this.enable(); |
|||
/** |
|||
* Start insert event |
|||
* @private |
|||
* */ |
|||
insertComponent() { |
|||
this.$wr.off('click', this.insertComponent); |
|||
this.stopSelectPosition(); |
|||
var object = this.buildContent(); |
|||
this.beforeInsert(object); |
|||
var index = this.sorter.lastPos.index; |
|||
// By default, collections do not trigger add event, so silent is used
|
|||
var model = this.create(this.sorter.target, object, index, null, {silent: false}); |
|||
|
|||
if(!model) |
|||
return; |
|||
if(this.opt.terminateAfterInsert && this.sender) |
|||
this.sender.set('active', false); |
|||
else |
|||
this.enable(); |
|||
|
|||
if(this.em) |
|||
this.em.editor.initChildrenComp(model); |
|||
if(!model) |
|||
return; |
|||
|
|||
this.afterInsert(model, this); |
|||
}, |
|||
if(this.em) |
|||
this.em.editor.initChildrenComp(model); |
|||
|
|||
/** |
|||
* Trigger before insert |
|||
* @param {Object} obj |
|||
* @private |
|||
* */ |
|||
beforeInsert: function(obj){}, |
|||
this.afterInsert(model, this); |
|||
}, |
|||
|
|||
/** |
|||
* Trigger after insert |
|||
* @param {Object} model Model created after insert |
|||
* @private |
|||
* */ |
|||
afterInsert: function(model){}, |
|||
/** |
|||
* Trigger before insert |
|||
* @param {Object} obj |
|||
* @private |
|||
* */ |
|||
beforeInsert(obj) {}, |
|||
|
|||
/** |
|||
* Create different object, based on content, to insert inside canvas |
|||
* |
|||
* @return {Object} |
|||
* @private |
|||
* */ |
|||
buildContent: function(){ |
|||
return this.opt.content || {}; |
|||
}, |
|||
}); |
|||
}); |
|||
/** |
|||
* Trigger after insert |
|||
* @param {Object} model Model created after insert |
|||
* @private |
|||
* */ |
|||
afterInsert(model) {}, |
|||
|
|||
/** |
|||
* Create different object, based on content, to insert inside canvas |
|||
* |
|||
* @return {Object} |
|||
* @private |
|||
* */ |
|||
buildContent() { |
|||
return this.opt.content || {}; |
|||
}, |
|||
}); |
|||
|
|||
@ -1,148 +1,148 @@ |
|||
define(['backbone', './SelectComponent','./SelectPosition'], |
|||
function(Backbone, SelectComponent, SelectPosition) { |
|||
|
|||
return _.extend({}, SelectPosition, SelectComponent, { |
|||
|
|||
init: function(o){ |
|||
SelectComponent.init.apply(this, arguments); |
|||
_.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() { |
|||
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); |
|||
}, |
|||
|
|||
/** |
|||
* Overwrite for doing nothing |
|||
* @private |
|||
*/ |
|||
toggleClipboard: function(){}, |
|||
|
|||
/** |
|||
* Delegate sorting |
|||
* @param {Event} e |
|||
* @private |
|||
* */ |
|||
initSorter: function(e){ |
|||
var el = $(e.target).data('model'); |
|||
var drag = el.get('draggable'); |
|||
if(!drag) |
|||
return; |
|||
|
|||
// Avoid badge showing on move
|
|||
this.cacheEl = null; |
|||
this.startSelectPosition(e.target, this.frameEl.contentDocument); |
|||
this.sorter.draggable = drag; |
|||
this.sorter.onEndMove = this.onEndMove.bind(this); |
|||
this.stopSelectComponent(); |
|||
this.$wrapper.off('mousedown', this.initSorter); |
|||
this.getContentWindow().on('keydown', this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* Init sorter from model |
|||
* @param {Object} model |
|||
* @private |
|||
*/ |
|||
initSorterFromModel: function(model) { |
|||
var drag = model.get('draggable'); |
|||
if(!drag) |
|||
return; |
|||
// Avoid badge showing on move
|
|||
this.cacheEl = null; |
|||
var el = model.view.el; |
|||
this.startSelectPosition(el, this.frameEl.contentDocument); |
|||
this.sorter.draggable = drag; |
|||
this.sorter.onEndMove = this.onEndMoveFromModel.bind(this); |
|||
|
|||
/* |
|||
this.sorter.setDragHelper(el); |
|||
var dragHelper = this.sorter.dragHelper; |
|||
dragHelper.className = this.ppfx + 'drag-helper'; |
|||
dragHelper.innerHTML = ''; |
|||
dragHelper.backgroundColor = 'white'; |
|||
*/ |
|||
|
|||
this.stopSelectComponent(); |
|||
this.getContentWindow().on('keydown', this.rollback); |
|||
}, |
|||
|
|||
onEndMoveFromModel: function() { |
|||
this.getContentWindow().off('keydown', this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* Callback after sorting |
|||
* @private |
|||
*/ |
|||
onEndMove: function(){ |
|||
this.enable(); |
|||
this.getContentWindow().off('keydown', this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* Say what to do after the component was selected (selectComponent) |
|||
* @param {Event} e |
|||
* @param {Object} Selected element |
|||
* @private |
|||
* */ |
|||
onSelect: function(e,el){}, |
|||
|
|||
/** |
|||
* 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.sorter.moved = false; |
|||
this.sorter.endMove(); |
|||
} |
|||
return; |
|||
}, |
|||
|
|||
/** |
|||
* Returns badge element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getBadgeEl: function(){ |
|||
if(!this.$badge) |
|||
this.$badge = $(this.getBadge()); |
|||
return this.$badge; |
|||
}, |
|||
|
|||
/** |
|||
* Returns highlighter element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getHighlighterEl: function(){ |
|||
if(!this.$hl) |
|||
this.$hl = $(this.canvas.getHighlighter()); |
|||
return this.$hl; |
|||
}, |
|||
|
|||
stop: function(){ |
|||
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); |
|||
} |
|||
}); |
|||
}); |
|||
var Backbone = require('backbone'); |
|||
var SelectComponent = require('./SelectComponent'); |
|||
var SelectPosition = require('./SelectPosition'); |
|||
|
|||
module.exports = _.extend({}, SelectPosition, SelectComponent, { |
|||
|
|||
init(o) { |
|||
SelectComponent.init.apply(this, arguments); |
|||
_.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(...args) { |
|||
SelectComponent.enable.apply(this, args); |
|||
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); |
|||
}, |
|||
|
|||
/** |
|||
* Overwrite for doing nothing |
|||
* @private |
|||
*/ |
|||
toggleClipboard() {}, |
|||
|
|||
/** |
|||
* Delegate sorting |
|||
* @param {Event} e |
|||
* @private |
|||
* */ |
|||
initSorter(e) { |
|||
var el = $(e.target).data('model'); |
|||
var drag = el.get('draggable'); |
|||
if(!drag) |
|||
return; |
|||
|
|||
// Avoid badge showing on move
|
|||
this.cacheEl = null; |
|||
this.startSelectPosition(e.target, this.frameEl.contentDocument); |
|||
this.sorter.draggable = drag; |
|||
this.sorter.onEndMove = this.onEndMove.bind(this); |
|||
this.stopSelectComponent(); |
|||
this.$wrapper.off('mousedown', this.initSorter); |
|||
this.getContentWindow().on('keydown', this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* Init sorter from model |
|||
* @param {Object} model |
|||
* @private |
|||
*/ |
|||
initSorterFromModel(model) { |
|||
var drag = model.get('draggable'); |
|||
if(!drag) |
|||
return; |
|||
// Avoid badge showing on move
|
|||
this.cacheEl = null; |
|||
var el = model.view.el; |
|||
this.startSelectPosition(el, this.frameEl.contentDocument); |
|||
this.sorter.draggable = drag; |
|||
this.sorter.onEndMove = this.onEndMoveFromModel.bind(this); |
|||
|
|||
/* |
|||
this.sorter.setDragHelper(el); |
|||
var dragHelper = this.sorter.dragHelper; |
|||
dragHelper.className = this.ppfx + 'drag-helper'; |
|||
dragHelper.innerHTML = ''; |
|||
dragHelper.backgroundColor = 'white'; |
|||
*/ |
|||
|
|||
this.stopSelectComponent(); |
|||
this.getContentWindow().on('keydown', this.rollback); |
|||
}, |
|||
|
|||
onEndMoveFromModel() { |
|||
this.getContentWindow().off('keydown', this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* Callback after sorting |
|||
* @private |
|||
*/ |
|||
onEndMove() { |
|||
this.enable(); |
|||
this.getContentWindow().off('keydown', this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* Say what to do after the component was selected (selectComponent) |
|||
* @param {Event} e |
|||
* @param {Object} Selected element |
|||
* @private |
|||
* */ |
|||
onSelect(e, el) {}, |
|||
|
|||
/** |
|||
* Used to bring the previous situation before start moving the component |
|||
* @param {Event} e |
|||
* @param {Boolean} Indicates if rollback in anycase |
|||
* @private |
|||
* */ |
|||
rollback(e, force) { |
|||
var key = e.which || e.keyCode; |
|||
if(key == this.opt.ESCAPE_KEY || force){ |
|||
this.sorter.moved = false; |
|||
this.sorter.endMove(); |
|||
} |
|||
return; |
|||
}, |
|||
|
|||
/** |
|||
* Returns badge element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getBadgeEl() { |
|||
if(!this.$badge) |
|||
this.$badge = $(this.getBadge()); |
|||
return this.$badge; |
|||
}, |
|||
|
|||
/** |
|||
* Returns highlighter element |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
getHighlighterEl() { |
|||
if(!this.$hl) |
|||
this.$hl = $(this.canvas.getHighlighter()); |
|||
return this.$hl; |
|||
}, |
|||
|
|||
stop(...args) { |
|||
SelectComponent.stop.apply(this, args); |
|||
this.getBadgeEl().removeClass(this.badgeClass); |
|||
this.getHighlighterEl().removeClass(this.hoverClass); |
|||
var wp = this.$wrapper; |
|||
wp.css('cursor', '').unbind().removeClass(this.noSelClass); |
|||
} |
|||
}); |
|||
|
|||
@ -1,24 +1,21 @@ |
|||
define(function() { |
|||
module.exports = { |
|||
|
|||
return { |
|||
run(editor, sender, opts) { |
|||
var opt = opts || {}; |
|||
var config = editor.getConfig(); |
|||
var modal = editor.Modal; |
|||
var assetManager = editor.AssetManager; |
|||
|
|||
run: function(editor, sender, opts) { |
|||
var opt = opts || {}; |
|||
var config = editor.getConfig(); |
|||
var modal = editor.Modal; |
|||
var assetManager = editor.AssetManager; |
|||
assetManager.onClick(opt.onClick); |
|||
assetManager.onDblClick(opt.onDblClick); |
|||
|
|||
assetManager.onClick(opt.onClick); |
|||
assetManager.onDblClick(opt.onDblClick); |
|||
// old API
|
|||
assetManager.setTarget(opt.target); |
|||
assetManager.onSelect(opt.onSelect); |
|||
|
|||
// old API
|
|||
assetManager.setTarget(opt.target); |
|||
assetManager.onSelect(opt.onSelect); |
|||
modal.setTitle(opt.modalTitle || 'Select image'); |
|||
modal.setContent(assetManager.render()); |
|||
modal.open(); |
|||
}, |
|||
|
|||
modal.setTitle(opt.modalTitle || 'Select image'); |
|||
modal.setContent(assetManager.render()); |
|||
modal.open(); |
|||
}, |
|||
|
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
@ -1,28 +1,26 @@ |
|||
define(function() { |
|||
module.exports = { |
|||
|
|||
return { |
|||
run(editor, sender) { |
|||
var config = editor.Config; |
|||
var pfx = config.stylePrefix; |
|||
var bm = editor.BlockManager; |
|||
var panelC; |
|||
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'); |
|||
} |
|||
|
|||
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'; |
|||
}, |
|||
|
|||
this.blocks.style.display = 'block'; |
|||
}, |
|||
|
|||
stop: function() { |
|||
if(this.blocks) |
|||
this.blocks.style.display = 'none'; |
|||
} |
|||
}; |
|||
}); |
|||
stop() { |
|||
if(this.blocks) |
|||
this.blocks.style.display = 'none'; |
|||
} |
|||
}; |
|||
|
|||
@ -1,38 +1,34 @@ |
|||
define(['Navigator'], function(Layers) { |
|||
/** |
|||
* @class OpenStyleManager |
|||
* @private |
|||
* */ |
|||
return { |
|||
var Layers = require('navigator'); |
|||
|
|||
run: function(em, sender) { |
|||
if(!this.$layers) { |
|||
var collection = em.DomComponents.getComponent().get('components'), |
|||
config = em.getConfig(), |
|||
panels = em.Panels, |
|||
lyStylePfx = config.layers.stylePrefix || 'nv-'; |
|||
module.exports = { |
|||
|
|||
config.layers.stylePrefix = config.stylePrefix + lyStylePfx; |
|||
config.layers.pStylePrefix = config.stylePrefix; |
|||
config.layers.em = em.editor; |
|||
config.layers.opened = em.editor.get('opened'); |
|||
var layers = new Layers(collection, config.layers); |
|||
this.$layers = layers.render(); |
|||
run(em, sender) { |
|||
if(!this.$layers) { |
|||
var collection = em.DomComponents.getComponent().get('components'), |
|||
config = em.getConfig(), |
|||
panels = em.Panels, |
|||
lyStylePfx = config.layers.stylePrefix || 'nv-'; |
|||
|
|||
// Check if panel exists otherwise crate it
|
|||
if(!panels.getPanel('views-container')) |
|||
this.panel = panels.addPanel({id: 'views-container'}); |
|||
else |
|||
this.panel = panels.getPanel('views-container'); |
|||
config.layers.stylePrefix = config.stylePrefix + lyStylePfx; |
|||
config.layers.pStylePrefix = config.stylePrefix; |
|||
config.layers.em = em.editor; |
|||
config.layers.opened = em.editor.get('opened'); |
|||
var layers = new Layers(collection, config.layers); |
|||
this.$layers = layers.render(); |
|||
|
|||
this.panel.set('appendContent', this.$layers).trigger('change:appendContent'); |
|||
} |
|||
this.$layers.show(); |
|||
}, |
|||
// Check if panel exists otherwise crate it
|
|||
if(!panels.getPanel('views-container')) |
|||
this.panel = panels.addPanel({id: 'views-container'}); |
|||
else |
|||
this.panel = panels.getPanel('views-container'); |
|||
|
|||
stop: function() { |
|||
if(this.$layers) |
|||
this.$layers.hide(); |
|||
this.panel.set('appendContent', this.$layers).trigger('change:appendContent'); |
|||
} |
|||
}; |
|||
}); |
|||
this.$layers.show(); |
|||
}, |
|||
|
|||
stop() { |
|||
if(this.$layers) |
|||
this.$layers.hide(); |
|||
} |
|||
}; |
|||
|
|||
@ -1,82 +1,78 @@ |
|||
define(['StyleManager'], function(StyleManager) { |
|||
/** |
|||
* @class OpenStyleManager |
|||
* @private |
|||
* */ |
|||
return { |
|||
var StyleManager = require('style_manager'); |
|||
|
|||
run: function(em, sender) { |
|||
this.sender = sender; |
|||
if(!this.$cn){ |
|||
var config = em.getConfig(), |
|||
panels = em.Panels; |
|||
// Main container
|
|||
this.$cn = $('<div/>'); |
|||
// Secondary container
|
|||
this.$cn2 = $('<div/>'); |
|||
this.$cn.append(this.$cn2); |
|||
module.exports = { |
|||
|
|||
// Device Manager
|
|||
var dvm = em.DeviceManager; |
|||
if(dvm && config.showDevices){ |
|||
var devicePanel = panels.addPanel({ id: 'devices-c'}); |
|||
devicePanel.set('appendContent', dvm.render()).trigger('change:appendContent'); |
|||
} |
|||
run(em, sender) { |
|||
this.sender = sender; |
|||
if(!this.$cn){ |
|||
var config = em.getConfig(), |
|||
panels = em.Panels; |
|||
// Main container
|
|||
this.$cn = $('<div/>'); |
|||
// Secondary container
|
|||
this.$cn2 = $('<div/>'); |
|||
this.$cn.append(this.$cn2); |
|||
|
|||
// Class Manager container
|
|||
var clm = em.SelectorManager; |
|||
if(clm) |
|||
this.$cn2.append(clm.render([])); |
|||
// Device Manager
|
|||
var dvm = em.DeviceManager; |
|||
if(dvm && config.showDevices){ |
|||
var devicePanel = panels.addPanel({ id: 'devices-c'}); |
|||
devicePanel.set('appendContent', dvm.render()).trigger('change:appendContent'); |
|||
} |
|||
|
|||
this.$cn2.append(em.StyleManager.render()); |
|||
var smConfig = em.StyleManager.getConfig(); |
|||
// Create header
|
|||
this.$header = $('<div>', { |
|||
class: smConfig.stylePrefix + 'header', |
|||
text: smConfig.textNoElement, |
|||
}); |
|||
//this.$cn = this.$cn.add(this.$header);
|
|||
this.$cn.append(this.$header); |
|||
// Class Manager container
|
|||
var clm = em.SelectorManager; |
|||
if(clm) |
|||
this.$cn2.append(clm.render([])); |
|||
|
|||
// Create panel if not exists
|
|||
if(!panels.getPanel('views-container')) |
|||
this.panel = panels.addPanel({ id: 'views-container'}); |
|||
else |
|||
this.panel = panels.getPanel('views-container'); |
|||
this.$cn2.append(em.StyleManager.render()); |
|||
var smConfig = em.StyleManager.getConfig(); |
|||
// Create header
|
|||
this.$header = $('<div>', { |
|||
class: smConfig.stylePrefix + 'header', |
|||
text: smConfig.textNoElement, |
|||
}); |
|||
//this.$cn = this.$cn.add(this.$header);
|
|||
this.$cn.append(this.$header); |
|||
|
|||
// Add all containers to the panel
|
|||
this.panel.set('appendContent', this.$cn).trigger('change:appendContent'); |
|||
// Create panel if not exists
|
|||
if(!panels.getPanel('views-container')) |
|||
this.panel = panels.addPanel({ id: 'views-container'}); |
|||
else |
|||
this.panel = panels.getPanel('views-container'); |
|||
|
|||
this.target = em.editor; |
|||
this.listenTo( this.target ,'change:selectedComponent', this.toggleSm); |
|||
} |
|||
this.toggleSm(); |
|||
}, |
|||
// Add all containers to the panel
|
|||
this.panel.set('appendContent', this.$cn).trigger('change:appendContent'); |
|||
|
|||
/** |
|||
* Toggle Style Manager visibility |
|||
* @private |
|||
*/ |
|||
toggleSm: function() { |
|||
if(!this.sender.get('active')) |
|||
return; |
|||
if(this.target.get('selectedComponent')){ |
|||
this.$cn2.show(); |
|||
this.$header.hide(); |
|||
}else{ |
|||
this.$cn2.hide(); |
|||
this.$header.show(); |
|||
} |
|||
}, |
|||
this.target = em.editor; |
|||
this.listenTo( this.target ,'change:selectedComponent', this.toggleSm); |
|||
} |
|||
this.toggleSm(); |
|||
}, |
|||
|
|||
stop: function() { |
|||
// Hide secondary container if exists
|
|||
if(this.$cn2) |
|||
this.$cn2.hide(); |
|||
/** |
|||
* Toggle Style Manager visibility |
|||
* @private |
|||
*/ |
|||
toggleSm() { |
|||
if(!this.sender.get('active')) |
|||
return; |
|||
if(this.target.get('selectedComponent')){ |
|||
this.$cn2.show(); |
|||
this.$header.hide(); |
|||
}else{ |
|||
this.$cn2.hide(); |
|||
this.$header.show(); |
|||
} |
|||
}, |
|||
|
|||
// Hide header container if exists
|
|||
if(this.$header) |
|||
this.$header.hide(); |
|||
} |
|||
}; |
|||
}); |
|||
stop() { |
|||
// Hide secondary container if exists
|
|||
if(this.$cn2) |
|||
this.$cn2.hide(); |
|||
|
|||
// Hide header container if exists
|
|||
if(this.$header) |
|||
this.$header.hide(); |
|||
} |
|||
}; |
|||
|
|||
@ -1,32 +1,30 @@ |
|||
define(function() { |
|||
module.exports = { |
|||
|
|||
return { |
|||
run(editor, sender) { |
|||
var config = editor.Config; |
|||
var pfx = config.stylePrefix; |
|||
var tm = editor.TraitManager; |
|||
var panelC; |
|||
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'); |
|||
} |
|||
|
|||
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'; |
|||
}, |
|||
|
|||
this.obj.style.display = 'block'; |
|||
}, |
|||
|
|||
stop: function() { |
|||
if(this.obj) |
|||
this.obj.style.display = 'none'; |
|||
} |
|||
}; |
|||
}); |
|||
stop() { |
|||
if(this.obj) |
|||
this.obj.style.display = 'none'; |
|||
} |
|||
}; |
|||
|
|||
@ -1,68 +1,65 @@ |
|||
define(function() { |
|||
module.exports = { |
|||
|
|||
return { |
|||
getPanels(editor) { |
|||
if(!this.panels) |
|||
this.panels = editor.Panels.getPanelsEl(); |
|||
return this.panels; |
|||
}, |
|||
|
|||
getPanels: function(editor){ |
|||
if(!this.panels) |
|||
this.panels = editor.Panels.getPanelsEl(); |
|||
return this.panels; |
|||
}, |
|||
tglPointers(editor, v) { |
|||
var elP = editor.Canvas.getBody().querySelectorAll('.' + this.ppfx + 'no-pointer'); |
|||
_.each(elP, item => { |
|||
item.style.pointerEvents = v ? '' : 'all'; |
|||
}); |
|||
}, |
|||
|
|||
tglPointers: function(editor, v) { |
|||
var elP = editor.Canvas.getBody().querySelectorAll('.' + this.ppfx + 'no-pointer'); |
|||
_.each(elP, function(item){ |
|||
item.style.pointerEvents = v ? '' : 'all'; |
|||
}); |
|||
}, |
|||
run(editor, sender) { |
|||
if(sender && sender.set) |
|||
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 = () => { |
|||
that.stop(editor); |
|||
}; |
|||
} |
|||
this.helper.style.display = 'inline-block'; |
|||
this.tglPointers(editor); |
|||
|
|||
run: function(editor, sender) { |
|||
if(sender && sender.set) |
|||
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'; |
|||
this.tglPointers(editor); |
|||
/* |
|||
editor.Canvas.getBody().querySelectorAll('.' + pfx + 'no-pointer').forEach(function(){ |
|||
this.style.pointerEvents = 'all'; |
|||
});*/ |
|||
|
|||
/* |
|||
editor.Canvas.getBody().querySelectorAll('.' + pfx + 'no-pointer').forEach(function(){ |
|||
this.style.pointerEvents = 'all'; |
|||
});*/ |
|||
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'); |
|||
}, |
|||
|
|||
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'); |
|||
this.tglPointers(editor, 1); |
|||
} |
|||
}; |
|||
}); |
|||
stop(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'); |
|||
this.tglPointers(editor, 1); |
|||
} |
|||
}; |
|||
|
|||
@ -1,32 +1,30 @@ |
|||
define(function() { |
|||
return { |
|||
module.exports = { |
|||
|
|||
run: function(editor, sender, opts) { |
|||
var el = (opts && opts.el) || ''; |
|||
var canvas = editor.Canvas; |
|||
var canvasResizer = this.canvasResizer; |
|||
var options = opts.options || {}; |
|||
run(editor, sender, opts) { |
|||
var el = (opts && opts.el) || ''; |
|||
var canvas = editor.Canvas; |
|||
var canvasResizer = this.canvasResizer; |
|||
var options = opts.options || {}; |
|||
|
|||
// Create the resizer for the canvas if not yet created
|
|||
if(!canvasResizer) { |
|||
var canvasView = canvas.getCanvasView(); |
|||
options.ratioDefault = 1; |
|||
options.appendTo = canvas.getResizerEl(); |
|||
options.prefix = editor.getConfig().stylePrefix; |
|||
options.posFetcher = canvasView.getElementPos.bind(canvasView); |
|||
options.mousePosFetcher = canvas.getMouseRelativePos; |
|||
this.canvasResizer = editor.Utils.Resizer.init(options); |
|||
canvasResizer = this.canvasResizer; |
|||
} |
|||
// Create the resizer for the canvas if not yet created
|
|||
if(!canvasResizer) { |
|||
var canvasView = canvas.getCanvasView(); |
|||
options.ratioDefault = 1; |
|||
options.appendTo = canvas.getResizerEl(); |
|||
options.prefix = editor.getConfig().stylePrefix; |
|||
options.posFetcher = canvasView.getElementPos.bind(canvasView); |
|||
options.mousePosFetcher = canvas.getMouseRelativePos; |
|||
this.canvasResizer = editor.Utils.Resizer.init(options); |
|||
canvasResizer = this.canvasResizer; |
|||
} |
|||
|
|||
canvasResizer.setOptions(options); |
|||
canvasResizer.focus(el); |
|||
}, |
|||
canvasResizer.setOptions(options); |
|||
canvasResizer.focus(el); |
|||
}, |
|||
|
|||
stop: function() { |
|||
if(this.canvasResizer) |
|||
this.canvasResizer.blur(); |
|||
}, |
|||
stop() { |
|||
if(this.canvasResizer) |
|||
this.canvasResizer.blur(); |
|||
}, |
|||
|
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
File diff suppressed because it is too large
@ -1,103 +1,100 @@ |
|||
define(function() { |
|||
module.exports = { |
|||
|
|||
return { |
|||
/** |
|||
* Start select position event |
|||
* @param {HTMLElement} trg |
|||
* @private |
|||
* */ |
|||
startSelectPosition(trg, doc) { |
|||
this.isPointed = false; |
|||
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, |
|||
canvasRelative: 1, |
|||
}); |
|||
this.sorter.startSort(trg); |
|||
}, |
|||
|
|||
/** |
|||
* Start select position event |
|||
* @param {HTMLElement} trg |
|||
* @private |
|||
* */ |
|||
startSelectPosition: function(trg, doc) { |
|||
this.isPointed = false; |
|||
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, |
|||
canvasRelative: 1, |
|||
}); |
|||
this.sorter.startSort(trg); |
|||
}, |
|||
/** |
|||
* Get frame position |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getOffsetDim() { |
|||
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, left }; |
|||
}, |
|||
|
|||
/** |
|||
* 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 |
|||
* @private |
|||
* */ |
|||
stopSelectPosition() { |
|||
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.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"); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Stop select position event |
|||
* @private |
|||
* */ |
|||
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.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"); |
|||
} |
|||
}, |
|||
/** |
|||
* Enabel select position |
|||
* @private |
|||
*/ |
|||
enable() { |
|||
this.startSelectPosition(); |
|||
}, |
|||
|
|||
/** |
|||
* Enabel select position |
|||
* @private |
|||
*/ |
|||
enable: function() { |
|||
this.startSelectPosition(); |
|||
}, |
|||
/** |
|||
* Check if the pointer is near to the float component |
|||
* @param {number} index |
|||
* @param {string} method |
|||
* @param {Array<Array>} dims |
|||
* @return {Boolean} |
|||
* @private |
|||
* */ |
|||
nearFloat(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; |
|||
}, |
|||
|
|||
/** |
|||
* 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() { |
|||
this.enable(); |
|||
}, |
|||
|
|||
run: function() { |
|||
this.enable(); |
|||
}, |
|||
|
|||
stop: function() { |
|||
this.stopSelectPosition(); |
|||
this.$wrapper.css('cursor',''); |
|||
this.$wrapper.unbind(); |
|||
} |
|||
}; |
|||
}); |
|||
stop() { |
|||
this.stopSelectPosition(); |
|||
this.$wrapper.css('cursor',''); |
|||
this.$wrapper.unbind(); |
|||
} |
|||
}; |
|||
|
|||
@ -1,149 +1,147 @@ |
|||
define(function() { |
|||
return { |
|||
|
|||
getOffsetMethod: function(state) { |
|||
var method = state || ''; |
|||
return 'get' + method + 'OffsetViewerEl'; |
|||
}, |
|||
|
|||
run: function(editor, sender, opts) { |
|||
var opt = opts || {}; |
|||
var state = opt.state || ''; |
|||
var config = editor.getConfig(); |
|||
|
|||
if (!config.showOffsets || |
|||
(!config.showOffsetsSelected && state == 'Fixed') ) { |
|||
return; |
|||
} |
|||
|
|||
var canvas = editor.Canvas; |
|||
var el = opt.el || ''; |
|||
var pos = opt.elPos || canvas.getElementPos(el); |
|||
var style = window.getComputedStyle(el); |
|||
var ppfx = this.ppfx; |
|||
var stateVar = state + 'State'; |
|||
var method = this.getOffsetMethod(state); |
|||
var offsetViewer = canvas[method](); |
|||
offsetViewer.style.display = 'block'; |
|||
|
|||
var marginT = this['marginT' + state]; |
|||
var marginB = this['marginB' + state]; |
|||
var marginL = this['marginL' + state]; |
|||
var marginR = this['marginR' + state]; |
|||
var padT = this['padT' + state]; |
|||
var padB = this['padB' + state]; |
|||
var padL = this['padL' + state]; |
|||
var padR = this['padR' + state]; |
|||
|
|||
if(!this[stateVar]) { |
|||
var stateLow = state.toLowerCase(); |
|||
var marginName = stateLow + 'margin-v'; |
|||
var paddingName = stateLow + 'padding-v'; |
|||
var marginV = $('<div>', {class: ppfx + marginName}).get(0); |
|||
var paddingV = $('<div>', {class: ppfx + paddingName}).get(0); |
|||
var marginEls = ppfx + marginName + '-el'; |
|||
var paddingEls = ppfx + paddingName + '-el'; |
|||
marginT = $('<div>', {class: ppfx + marginName + '-top ' + marginEls}).get(0); |
|||
marginB = $('<div>', {class: ppfx + marginName + '-bottom ' + marginEls}).get(0); |
|||
marginL = $('<div>', {class: ppfx + marginName + '-left ' + marginEls}).get(0); |
|||
marginR = $('<div>', {class: ppfx + marginName + '-right ' + marginEls}).get(0); |
|||
padT = $('<div>', {class: ppfx + paddingName + '-top ' + paddingEls}).get(0); |
|||
padB = $('<div>', {class: ppfx + paddingName + '-bottom ' + paddingEls}).get(0); |
|||
padL = $('<div>', {class: ppfx + paddingName + '-left ' + paddingEls}).get(0); |
|||
padR = $('<div>', {class: ppfx + paddingName + '-right ' + paddingEls}).get(0); |
|||
this['marginT' + state] = marginT; |
|||
this['marginB' + state] = marginB; |
|||
this['marginL' + state] = marginL; |
|||
this['marginR' + state] = marginR; |
|||
this['padT' + state] = padT; |
|||
this['padB' + state] = padB; |
|||
this['padL' + state] = padL; |
|||
this['padR' + state] = padR; |
|||
marginV.appendChild(marginT); |
|||
marginV.appendChild(marginB); |
|||
marginV.appendChild(marginL); |
|||
marginV.appendChild(marginR); |
|||
paddingV.appendChild(padT); |
|||
paddingV.appendChild(padB); |
|||
paddingV.appendChild(padL); |
|||
paddingV.appendChild(padR); |
|||
offsetViewer.appendChild(marginV); |
|||
offsetViewer.appendChild(paddingV); |
|||
this[stateVar] = '1'; |
|||
} |
|||
|
|||
var unit = 'px'; |
|||
var marginLeftSt = style.marginLeft.replace(unit, ''); |
|||
var marginTopSt = parseInt(style.marginTop.replace(unit, '')); |
|||
var marginBottomSt = parseInt(style.marginBottom.replace(unit, '')); |
|||
var mtStyle = marginT.style; |
|||
var mbStyle = marginB.style; |
|||
var mlStyle = marginL.style; |
|||
var mrStyle = marginR.style; |
|||
var ptStyle = padT.style; |
|||
var pbStyle = padB.style; |
|||
var plStyle = padL.style; |
|||
var prStyle = padR.style; |
|||
var posLeft = parseInt(pos.left); |
|||
|
|||
// Margin style
|
|||
mtStyle.height = style.marginTop; |
|||
mtStyle.width = style.width; |
|||
mtStyle.top = pos.top - style.marginTop.replace(unit, '') + unit; |
|||
mtStyle.left = posLeft + unit; |
|||
|
|||
mbStyle.height = style.marginBottom; |
|||
mbStyle.width = style.width; |
|||
mbStyle.top = pos.top + pos.height + unit; |
|||
mbStyle.left = posLeft + unit; |
|||
|
|||
var marginSideH = pos.height + marginTopSt + marginBottomSt + unit; |
|||
var marginSideT = pos.top - marginTopSt + unit; |
|||
mlStyle.height = marginSideH; |
|||
mlStyle.width = style.marginLeft; |
|||
mlStyle.top = marginSideT; |
|||
mlStyle.left = posLeft - marginLeftSt + unit; |
|||
|
|||
mrStyle.height = marginSideH; |
|||
mrStyle.width = style.marginRight; |
|||
mrStyle.top = marginSideT; |
|||
mrStyle.left = posLeft + pos.width + unit; |
|||
|
|||
// Padding style
|
|||
var padTop = parseInt(style.paddingTop.replace(unit, '')); |
|||
ptStyle.height = style.paddingTop; |
|||
ptStyle.width = style.width; |
|||
ptStyle.top = pos.top + unit; |
|||
ptStyle.left = posLeft + unit; |
|||
|
|||
var padBot = parseInt(style.paddingBottom.replace(unit, '')); |
|||
pbStyle.height = style.paddingBottom; |
|||
pbStyle.width = style.width; |
|||
pbStyle.top = pos.top + pos.height - padBot + unit; |
|||
pbStyle.left = posLeft + unit; |
|||
|
|||
var padSideH = (pos.height - padBot - padTop) + unit; |
|||
var padSideT = pos.top + padTop + unit; |
|||
plStyle.height = padSideH; |
|||
plStyle.width = style.paddingLeft; |
|||
plStyle.top = padSideT; |
|||
plStyle.left = pos.left + unit; |
|||
|
|||
var padRight = parseInt(style.paddingRight.replace(unit, '')); |
|||
prStyle.height = padSideH; |
|||
prStyle.width = style.paddingRight; |
|||
prStyle.top = padSideT; |
|||
prStyle.left = pos.left + pos.width - padRight + unit; |
|||
}, |
|||
|
|||
stop: function(editor, sender, opts) { |
|||
var opt = opts || {}; |
|||
var state = opt.state || ''; |
|||
var method = this.getOffsetMethod(state); |
|||
var canvas = editor.Canvas; |
|||
var offsetViewer = canvas[method](); |
|||
offsetViewer.style.display = 'none'; |
|||
}, |
|||
|
|||
}; |
|||
}); |
|||
module.exports = { |
|||
|
|||
getOffsetMethod(state) { |
|||
var method = state || ''; |
|||
return 'get' + method + 'OffsetViewerEl'; |
|||
}, |
|||
|
|||
run(editor, sender, opts) { |
|||
var opt = opts || {}; |
|||
var state = opt.state || ''; |
|||
var config = editor.getConfig(); |
|||
|
|||
if (!config.showOffsets || |
|||
(!config.showOffsetsSelected && state == 'Fixed') ) { |
|||
return; |
|||
} |
|||
|
|||
var canvas = editor.Canvas; |
|||
var el = opt.el || ''; |
|||
var pos = opt.elPos || canvas.getElementPos(el); |
|||
var style = window.getComputedStyle(el); |
|||
var ppfx = this.ppfx; |
|||
var stateVar = state + 'State'; |
|||
var method = this.getOffsetMethod(state); |
|||
var offsetViewer = canvas[method](); |
|||
offsetViewer.style.display = 'block'; |
|||
|
|||
var marginT = this['marginT' + state]; |
|||
var marginB = this['marginB' + state]; |
|||
var marginL = this['marginL' + state]; |
|||
var marginR = this['marginR' + state]; |
|||
var padT = this['padT' + state]; |
|||
var padB = this['padB' + state]; |
|||
var padL = this['padL' + state]; |
|||
var padR = this['padR' + state]; |
|||
|
|||
if(!this[stateVar]) { |
|||
var stateLow = state.toLowerCase(); |
|||
var marginName = stateLow + 'margin-v'; |
|||
var paddingName = stateLow + 'padding-v'; |
|||
var marginV = $('<div>', {class: ppfx + marginName}).get(0); |
|||
var paddingV = $('<div>', {class: ppfx + paddingName}).get(0); |
|||
var marginEls = ppfx + marginName + '-el'; |
|||
var paddingEls = ppfx + paddingName + '-el'; |
|||
marginT = $('<div>', {class: ppfx + marginName + '-top ' + marginEls}).get(0); |
|||
marginB = $('<div>', {class: ppfx + marginName + '-bottom ' + marginEls}).get(0); |
|||
marginL = $('<div>', {class: ppfx + marginName + '-left ' + marginEls}).get(0); |
|||
marginR = $('<div>', {class: ppfx + marginName + '-right ' + marginEls}).get(0); |
|||
padT = $('<div>', {class: ppfx + paddingName + '-top ' + paddingEls}).get(0); |
|||
padB = $('<div>', {class: ppfx + paddingName + '-bottom ' + paddingEls}).get(0); |
|||
padL = $('<div>', {class: ppfx + paddingName + '-left ' + paddingEls}).get(0); |
|||
padR = $('<div>', {class: ppfx + paddingName + '-right ' + paddingEls}).get(0); |
|||
this['marginT' + state] = marginT; |
|||
this['marginB' + state] = marginB; |
|||
this['marginL' + state] = marginL; |
|||
this['marginR' + state] = marginR; |
|||
this['padT' + state] = padT; |
|||
this['padB' + state] = padB; |
|||
this['padL' + state] = padL; |
|||
this['padR' + state] = padR; |
|||
marginV.appendChild(marginT); |
|||
marginV.appendChild(marginB); |
|||
marginV.appendChild(marginL); |
|||
marginV.appendChild(marginR); |
|||
paddingV.appendChild(padT); |
|||
paddingV.appendChild(padB); |
|||
paddingV.appendChild(padL); |
|||
paddingV.appendChild(padR); |
|||
offsetViewer.appendChild(marginV); |
|||
offsetViewer.appendChild(paddingV); |
|||
this[stateVar] = '1'; |
|||
} |
|||
|
|||
var unit = 'px'; |
|||
var marginLeftSt = style.marginLeft.replace(unit, ''); |
|||
var marginTopSt = parseInt(style.marginTop.replace(unit, '')); |
|||
var marginBottomSt = parseInt(style.marginBottom.replace(unit, '')); |
|||
var mtStyle = marginT.style; |
|||
var mbStyle = marginB.style; |
|||
var mlStyle = marginL.style; |
|||
var mrStyle = marginR.style; |
|||
var ptStyle = padT.style; |
|||
var pbStyle = padB.style; |
|||
var plStyle = padL.style; |
|||
var prStyle = padR.style; |
|||
var posLeft = parseInt(pos.left); |
|||
|
|||
// Margin style
|
|||
mtStyle.height = style.marginTop; |
|||
mtStyle.width = style.width; |
|||
mtStyle.top = pos.top - style.marginTop.replace(unit, '') + unit; |
|||
mtStyle.left = posLeft + unit; |
|||
|
|||
mbStyle.height = style.marginBottom; |
|||
mbStyle.width = style.width; |
|||
mbStyle.top = pos.top + pos.height + unit; |
|||
mbStyle.left = posLeft + unit; |
|||
|
|||
var marginSideH = pos.height + marginTopSt + marginBottomSt + unit; |
|||
var marginSideT = pos.top - marginTopSt + unit; |
|||
mlStyle.height = marginSideH; |
|||
mlStyle.width = style.marginLeft; |
|||
mlStyle.top = marginSideT; |
|||
mlStyle.left = posLeft - marginLeftSt + unit; |
|||
|
|||
mrStyle.height = marginSideH; |
|||
mrStyle.width = style.marginRight; |
|||
mrStyle.top = marginSideT; |
|||
mrStyle.left = posLeft + pos.width + unit; |
|||
|
|||
// Padding style
|
|||
var padTop = parseInt(style.paddingTop.replace(unit, '')); |
|||
ptStyle.height = style.paddingTop; |
|||
ptStyle.width = style.width; |
|||
ptStyle.top = pos.top + unit; |
|||
ptStyle.left = posLeft + unit; |
|||
|
|||
var padBot = parseInt(style.paddingBottom.replace(unit, '')); |
|||
pbStyle.height = style.paddingBottom; |
|||
pbStyle.width = style.width; |
|||
pbStyle.top = pos.top + pos.height - padBot + unit; |
|||
pbStyle.left = posLeft + unit; |
|||
|
|||
var padSideH = (pos.height - padBot - padTop) + unit; |
|||
var padSideT = pos.top + padTop + unit; |
|||
plStyle.height = padSideH; |
|||
plStyle.width = style.paddingLeft; |
|||
plStyle.top = padSideT; |
|||
plStyle.left = pos.left + unit; |
|||
|
|||
var padRight = parseInt(style.paddingRight.replace(unit, '')); |
|||
prStyle.height = padSideH; |
|||
prStyle.width = style.paddingRight; |
|||
prStyle.top = padSideT; |
|||
prStyle.left = pos.left + pos.width - padRight + unit; |
|||
}, |
|||
|
|||
stop(editor, sender, opts) { |
|||
var opt = opts || {}; |
|||
var state = opt.state || ''; |
|||
var method = this.getOffsetMethod(state); |
|||
var canvas = editor.Canvas; |
|||
var offsetViewer = canvas[method](); |
|||
offsetViewer.style.display = 'none'; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
@ -1,13 +1,11 @@ |
|||
define(function() { |
|||
return { |
|||
module.exports = { |
|||
|
|||
run: function(ed) { |
|||
ed.Canvas.getBody().className = this.ppfx + 'dashed'; |
|||
}, |
|||
run(ed) { |
|||
ed.Canvas.getBody().className = this.ppfx + 'dashed'; |
|||
}, |
|||
|
|||
stop: function(ed) { |
|||
ed.Canvas.getBody().className = ""; |
|||
} |
|||
stop(ed) { |
|||
ed.Canvas.getBody().className = ""; |
|||
} |
|||
|
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
@ -1,35 +1,31 @@ |
|||
define(['backbone', './CreateComponent'], |
|||
function(Backbone, CreateComponent) { |
|||
/** |
|||
* @class TextComponent |
|||
* @private |
|||
* */ |
|||
return _.extend({}, CreateComponent, { |
|||
var Backbone = require('backbone'); |
|||
var CreateComponent = require('./CreateComponent'); |
|||
|
|||
/** |
|||
* This event is triggered at the beginning of a draw operation |
|||
* @param {Object} component Object component before creation |
|||
* @private |
|||
* */ |
|||
beforeDraw: function(component){ |
|||
component.type = 'text'; |
|||
if(!component.style) |
|||
component.style = {}; |
|||
component.style.padding = '10px'; |
|||
}, |
|||
module.exports = _.extend({}, CreateComponent, { |
|||
|
|||
/** |
|||
* This event is triggered at the end of a draw operation |
|||
* @param {Object} model Component model created |
|||
* @private |
|||
* */ |
|||
afterDraw: function(model){ |
|||
if(!model || !model.set) |
|||
return; |
|||
model.trigger('focus'); |
|||
if(this.sender) |
|||
this.sender.set('active', false); |
|||
}, |
|||
/** |
|||
* This event is triggered at the beginning of a draw operation |
|||
* @param {Object} component Object component before creation |
|||
* @private |
|||
* */ |
|||
beforeDraw(component) { |
|||
component.type = 'text'; |
|||
if(!component.style) |
|||
component.style = {}; |
|||
component.style.padding = '10px'; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
/** |
|||
* This event is triggered at the end of a draw operation |
|||
* @param {Object} model Component model created |
|||
* @private |
|||
* */ |
|||
afterDraw(model) { |
|||
if(!model || !model.set) |
|||
return; |
|||
model.trigger('focus'); |
|||
if(this.sender) |
|||
this.sender.set('active', false); |
|||
}, |
|||
|
|||
}); |
|||
|
|||
@ -1,59 +0,0 @@ |
|||
require.config({ |
|||
shim: { |
|||
underscore: { |
|||
exports: '_' |
|||
}, |
|||
backbone: { |
|||
deps: [ 'underscore', 'jquery' ], |
|||
exports: 'Backbone' |
|||
}, |
|||
rte: { |
|||
deps: [ 'jquery' ], |
|||
exports: 'rte' |
|||
}, |
|||
backboneUndo: { |
|||
deps: ['backbone'], |
|||
exports: 'backboneUndo' |
|||
}, |
|||
keymaster: { |
|||
exports: 'keymaster' |
|||
}, |
|||
}, |
|||
|
|||
paths: { |
|||
jquery: '../node_modules/jquery/dist/jquery', |
|||
underscore: '../node_modules/underscore/underscore', |
|||
backbone: '../node_modules/backbone/backbone', |
|||
backboneUndo: '../node_modules/backbone-undo/Backbone.Undo', |
|||
keymaster: '../node_modules/keymaster/keymaster', |
|||
text: '../node_modules/requirejs-text/text', |
|||
Spectrum: '../node_modules/spectrum-colorpicker/spectrum', |
|||
codemirror: '../node_modules/codemirror', |
|||
formatting: '../node_modules/codemirror-formatting/formatting', |
|||
}, |
|||
|
|||
packages : [ |
|||
{ name: 'GrapesJS', location: 'grapesjs' }, |
|||
{ name: 'Abstract', location: 'domain_abstract' }, |
|||
{ name: 'Editor', location: 'editor', }, |
|||
{ name: 'AssetManager', location: 'asset_manager', }, |
|||
{ name: 'BlockManager', location: 'block_manager', }, |
|||
{ name: 'TraitManager', location: 'trait_manager', }, |
|||
{ name: 'StyleManager', location: 'style_manager', }, |
|||
{ name: 'DeviceManager', location: 'device_manager', }, |
|||
{ name: 'StorageManager', location: 'storage_manager', }, |
|||
{ name: 'PluginManager', location: 'plugin_manager', }, |
|||
{ name: 'Navigator', location: 'navigator', }, |
|||
{ name: 'DomComponents', location: 'dom_components', }, |
|||
{ name: 'RichTextEditor', location: 'rich_text_editor', }, |
|||
{ name: 'SelectorManager', location: 'selector_manager', }, |
|||
{ name: 'ModalDialog', location: 'modal_dialog', }, |
|||
{ name: 'CodeManager', location: 'code_manager', }, |
|||
{ name: 'CssComposer', location: 'css_composer', }, |
|||
{ name: 'Commands', location: 'commands', }, |
|||
{ name: 'Canvas', location: 'canvas', }, |
|||
{ name: 'Panels', location: 'panels', }, |
|||
{ name: 'Parser', location: 'parser', }, |
|||
{ name: 'Utils', location: 'utils', } |
|||
] |
|||
}); |
|||
@ -1,14 +1,12 @@ |
|||
define(function () { |
|||
return { |
|||
module.exports = { |
|||
|
|||
// Style prefix
|
|||
stylePrefix: 'css-', |
|||
// Style prefix
|
|||
stylePrefix: 'css-', |
|||
|
|||
// Custom CSS string to render on top
|
|||
'staticRules': '', |
|||
// Custom CSS string to render on top
|
|||
'staticRules': '', |
|||
|
|||
// Default CSS style
|
|||
rules: [], |
|||
// Default CSS style
|
|||
rules: [], |
|||
|
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
@ -0,0 +1,272 @@ |
|||
/** |
|||
* * [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}', |
|||
* } |
|||
*/ |
|||
|
|||
module.exports = () => { |
|||
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, |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'CssComposer', |
|||
|
|||
/** |
|||
* Mandatory for the storage manager |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
storageKey() { |
|||
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(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() { |
|||
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(data) { |
|||
var d = data || ''; |
|||
if(!d && c.stm) |
|||
d = c.em.getCacheLoad(); |
|||
var obj = ''; |
|||
if(d.styles) { |
|||
try{ |
|||
obj = JSON.parse(d.styles); |
|||
}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(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 |
|||
* @param {Object} opts Other options for the rule |
|||
* @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', |
|||
* }); |
|||
* */ |
|||
add(selectors, state, width, opts) { |
|||
var s = state || ''; |
|||
var w = width || ''; |
|||
var opt = opts || {}; |
|||
var rule = this.get(selectors, s, w, opt); |
|||
if(rule) |
|||
return rule; |
|||
else { |
|||
opt.state = s; |
|||
opt.mediaText = w; |
|||
opt.selectors = ''; |
|||
rule = new CssRule(opt); |
|||
rule.get('selectors').add(selectors); |
|||
rules.add(rule); |
|||
return rule; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 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 |
|||
* @param {Object} ruleProps Other rule props |
|||
* @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', |
|||
* }); |
|||
* */ |
|||
get(selectors, state, width, ruleProps) { |
|||
var rule = null; |
|||
rules.each(m => { |
|||
if(rule) |
|||
return; |
|||
if(m.compare(selectors, state, width, ruleProps)) |
|||
rule = m; |
|||
}); |
|||
return rule; |
|||
}, |
|||
|
|||
/** |
|||
* Get the collection of rules |
|||
* @return {Collection} |
|||
* */ |
|||
getAll() { |
|||
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, eg . [{selectors: ['class1'], style: {....}}, ..] |
|||
* @param {Object} opts Options |
|||
* @return {Array<Model>} |
|||
* @private |
|||
*/ |
|||
addCollection(data, opts) { |
|||
var opt = opts || {}; |
|||
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.mediaText, rule); |
|||
if (opt.extend) { |
|||
var newStyle = _.extend({}, model.get('style'), rule.style || {}); |
|||
model.set('style', newStyle); |
|||
} else { |
|||
model.set('style', rule.style || {}); |
|||
} |
|||
|
|||
result.push(model); |
|||
} |
|||
|
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Render the block of CSS rules |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
render() { |
|||
return rulesView.render().el; |
|||
} |
|||
|
|||
}; |
|||
}; |
|||
@ -1,274 +0,0 @@ |
|||
/** |
|||
* * [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) { |
|||
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, |
|||
|
|||
/** |
|||
* 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.styles) { |
|||
try{ |
|||
obj = JSON.parse(d.styles); |
|||
}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 |
|||
* @param {Object} opts Other options for the rule |
|||
* @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', |
|||
* }); |
|||
* */ |
|||
add: function(selectors, state, width, opts) { |
|||
var s = state || ''; |
|||
var w = width || ''; |
|||
var opt = opts || {}; |
|||
var rule = this.get(selectors, s, w, opt); |
|||
if(rule) |
|||
return rule; |
|||
else { |
|||
opt.state = s; |
|||
opt.mediaText = w; |
|||
opt.selectors = ''; |
|||
rule = new CssRule(opt); |
|||
rule.get('selectors').add(selectors); |
|||
rules.add(rule); |
|||
return rule; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 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 |
|||
* @param {Object} ruleProps Other rule props |
|||
* @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', |
|||
* }); |
|||
* */ |
|||
get: function(selectors, state, width, ruleProps) { |
|||
var rule = null; |
|||
rules.each(function(m) { |
|||
if(rule) |
|||
return; |
|||
if(m.compare(selectors, state, width, ruleProps)) |
|||
rule = m; |
|||
}); |
|||
return rule; |
|||
}, |
|||
|
|||
/** |
|||
* Get the collection of rules |
|||
* @return {Collection} |
|||
* */ |
|||
getAll: 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, eg . [{selectors: ['class1'], style: {....}}, ..] |
|||
* @param {Object} opts Options |
|||
* @return {Array<Model>} |
|||
* @private |
|||
*/ |
|||
addCollection: function(data, opts) { |
|||
var opt = opts || {}; |
|||
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.mediaText, rule); |
|||
if (opt.extend) { |
|||
var newStyle = _.extend({}, model.get('style'), rule.style || {}); |
|||
model.set('style', newStyle); |
|||
} else { |
|||
model.set('style', rule.style || {}); |
|||
} |
|||
|
|||
result.push(model); |
|||
} |
|||
|
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Render the block of CSS rules |
|||
* @return {HTMLElement} |
|||
* @private |
|||
*/ |
|||
render: function() { |
|||
return rulesView.render().el; |
|||
} |
|||
|
|||
}; |
|||
}; |
|||
|
|||
}); |
|||
@ -1,93 +1,89 @@ |
|||
define(['backbone', './Selectors'], |
|||
function (Backbone, Selectors) { |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
// Css selectors
|
|||
selectors: {}, |
|||
|
|||
// Additional string css selectors
|
|||
selectorsAdd: '', |
|||
|
|||
// Css properties style
|
|||
style: {}, |
|||
|
|||
// On which device width this rule should be rendered, eg. @media (max-width: 1000px)
|
|||
mediaText: '', |
|||
|
|||
// State of the rule, eg: hover | pressed | focused
|
|||
state: '', |
|||
|
|||
// Indicates if the rule is stylable
|
|||
stylable: true, |
|||
}, |
|||
|
|||
initialize: function(c, opt) { |
|||
this.config = c || {}; |
|||
this.sm = opt ? opt.sm || {} : {}; |
|||
this.slct = this.config.selectors || []; |
|||
|
|||
if(this.sm.get){ |
|||
var slct = []; |
|||
for(var i = 0; i < this.slct.length; i++) |
|||
slct.push(this.sm.get('SelectorManager').add(this.slct[i].name || this.slct[i])); |
|||
this.slct = slct; |
|||
} |
|||
|
|||
this.set('selectors', new Selectors(this.slct)); |
|||
}, |
|||
|
|||
/** |
|||
* Compare the actual model with parameters |
|||
* @param {Object} selectors Collection of selectors |
|||
* @param {String} state Css rule state |
|||
* @param {String} width For which device this style is oriented |
|||
* @param {Object} ruleProps Other rule props |
|||
* @return {Boolean} |
|||
* @private |
|||
*/ |
|||
compare: function(selectors, state, width, ruleProps){ |
|||
var otherRule = ruleProps || {}; |
|||
var st = state || ''; |
|||
var wd = width || ''; |
|||
var selectorsAdd = otherRule.selectorsAdd || ''; |
|||
var cId = 'cid'; |
|||
//var a1 = _.pluck(selectors.models || selectors, cId);
|
|||
//var a2 = _.pluck(this.get('selectors').models, cId);
|
|||
if(!(selectors instanceof Array) && !selectors.models) |
|||
selectors = [selectors]; |
|||
var a1 = _.map((selectors.models || selectors), function(model) { |
|||
return model.get('name'); |
|||
}); |
|||
var a2 = _.map(this.get('selectors').models, function(model) { |
|||
return model.get('name'); |
|||
}); |
|||
var f = false; |
|||
|
|||
if(a1.length !== a2.length) |
|||
return f; |
|||
|
|||
for (var i = 0; i < a1.length; i++) { |
|||
var re = 0; |
|||
for (var j = 0; j < a2.length; j++) { |
|||
if (a1[i] === a2[j]) |
|||
re = 1; |
|||
} |
|||
if(re === 0) |
|||
return f; |
|||
} |
|||
|
|||
if(this.get('state') !== st) |
|||
return f; |
|||
|
|||
if(this.get('mediaText') !== wd) |
|||
return f; |
|||
|
|||
if(this.get('selectorsAdd') !== selectorsAdd) |
|||
return f; |
|||
|
|||
return true; |
|||
}, |
|||
|
|||
}); |
|||
var Backbone = require('backbone'); |
|||
var Selectors = require('./Selectors'); |
|||
|
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
// Css selectors
|
|||
selectors: {}, |
|||
|
|||
// Additional string css selectors
|
|||
selectorsAdd: '', |
|||
|
|||
// Css properties style
|
|||
style: {}, |
|||
|
|||
// On which device width this rule should be rendered, eg. @media (max-width: 1000px)
|
|||
mediaText: '', |
|||
|
|||
// State of the rule, eg: hover | pressed | focused
|
|||
state: '', |
|||
|
|||
// Indicates if the rule is stylable
|
|||
stylable: true, |
|||
}, |
|||
|
|||
initialize(c, opt) { |
|||
this.config = c || {}; |
|||
this.sm = opt ? opt.sm || {} : {}; |
|||
this.slct = this.config.selectors || []; |
|||
|
|||
if(this.sm.get){ |
|||
var slct = []; |
|||
for(var i = 0; i < this.slct.length; i++) |
|||
slct.push(this.sm.get('SelectorManager').add(this.slct[i].name || this.slct[i])); |
|||
this.slct = slct; |
|||
} |
|||
|
|||
this.set('selectors', new Selectors(this.slct)); |
|||
}, |
|||
|
|||
/** |
|||
* Compare the actual model with parameters |
|||
* @param {Object} selectors Collection of selectors |
|||
* @param {String} state Css rule state |
|||
* @param {String} width For which device this style is oriented |
|||
* @param {Object} ruleProps Other rule props |
|||
* @return {Boolean} |
|||
* @private |
|||
*/ |
|||
compare(selectors, state, width, ruleProps) { |
|||
var otherRule = ruleProps || {}; |
|||
var st = state || ''; |
|||
var wd = width || ''; |
|||
var selectorsAdd = otherRule.selectorsAdd || ''; |
|||
var cId = 'cid'; |
|||
//var a1 = _.pluck(selectors.models || selectors, cId);
|
|||
//var a2 = _.pluck(this.get('selectors').models, cId);
|
|||
if(!(selectors instanceof Array) && !selectors.models) |
|||
selectors = [selectors]; |
|||
var a1 = _.map((selectors.models || selectors), model => model.get('name')); |
|||
var a2 = _.map(this.get('selectors').models, model => model.get('name')); |
|||
var f = false; |
|||
|
|||
if(a1.length !== a2.length) |
|||
return f; |
|||
|
|||
for (var i = 0; i < a1.length; i++) { |
|||
var re = 0; |
|||
for (var j = 0; j < a2.length; j++) { |
|||
if (a1[i] === a2[j]) |
|||
re = 1; |
|||
} |
|||
if(re === 0) |
|||
return f; |
|||
} |
|||
|
|||
if(this.get('state') !== st) |
|||
return f; |
|||
|
|||
if(this.get('mediaText') !== wd) |
|||
return f; |
|||
|
|||
if(this.get('selectorsAdd') !== selectorsAdd) |
|||
return f; |
|||
|
|||
return true; |
|||
}, |
|||
|
|||
}); |
|||
|
|||
@ -1,34 +1,34 @@ |
|||
define(['backbone','./CssRule'], |
|||
function (Backbone, CssRule) { |
|||
return Backbone.Collection.extend({ |
|||
var Backbone = require('backbone'); |
|||
var CssRule = require('./CssRule'); |
|||
|
|||
initialize: function(models, opt){ |
|||
module.exports = Backbone.Collection.extend({ |
|||
|
|||
// Inject editor
|
|||
if(opt && opt.sm) |
|||
this.editor = opt.sm; |
|||
initialize(models, opt) { |
|||
|
|||
this.model = function(attrs, options) { |
|||
var model; |
|||
// Inject editor
|
|||
if(opt && opt.sm) |
|||
this.editor = opt.sm; |
|||
|
|||
if(!options.sm && opt && opt.sm) |
|||
options.sm = opt.sm; |
|||
this.model = (attrs, options) => { |
|||
var model; |
|||
|
|||
switch(1){ |
|||
default: |
|||
model = new CssRule(attrs, options); |
|||
} |
|||
if(!options.sm && opt && opt.sm) |
|||
options.sm = opt.sm; |
|||
|
|||
return model; |
|||
}; |
|||
switch(1){ |
|||
default: |
|||
model = new CssRule(attrs, options); |
|||
} |
|||
|
|||
}, |
|||
return model; |
|||
}; |
|||
|
|||
add: function(models, opt){ |
|||
if(typeof models === 'string') |
|||
models = this.editor.get('Parser').parseCss(models); |
|||
return Backbone.Collection.prototype.add.apply(this, [models, opt]); |
|||
}, |
|||
}, |
|||
|
|||
add(models, opt) { |
|||
if(typeof models === 'string') |
|||
models = this.editor.get('Parser').parseCss(models); |
|||
return Backbone.Collection.prototype.add.apply(this, [models, opt]); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,25 +1,24 @@ |
|||
define([ 'backbone', 'require'], |
|||
function (Backbone, require) { |
|||
return Backbone.Collection.extend({ |
|||
var Backbone = require('backbone'); |
|||
|
|||
initialize: function(models, opt){ |
|||
module.exports = Backbone.Collection.extend({ |
|||
|
|||
this.model = function(attrs, opts) { |
|||
var model; |
|||
initialize(models, opt) { |
|||
|
|||
switch(1){ |
|||
this.model = function(attrs, opts) { |
|||
var model; |
|||
|
|||
default: |
|||
if(!this.ClassTag) |
|||
this.ClassTag = require("SelectorManager/model/Selector"); |
|||
model = new this.ClassTag(attrs, opts); |
|||
switch(1){ |
|||
|
|||
} |
|||
default: |
|||
if(!this.ClassTag) |
|||
this.ClassTag = require("selector_manager/model/Selector"); |
|||
model = new this.ClassTag(attrs, opts); |
|||
|
|||
return model; |
|||
}; |
|||
} |
|||
|
|||
}, |
|||
return model; |
|||
}; |
|||
|
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,78 +1,77 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
return Backbone.View.extend({ |
|||
var Backbone = require('backbone'); |
|||
|
|||
tagName: 'style', |
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
this.config = o.config || {}; |
|||
this.listenTo(this.model, 'change:style', this.render); |
|||
this.listenTo(this.model, 'change:state', this.render); |
|||
this.listenTo(this.model, 'destroy remove', this.remove); |
|||
this.listenTo(this.model, 'change:mediaText', this.render); |
|||
this.listenTo(this.model.get('selectors'), 'change', this.selChanged); |
|||
}, |
|||
tagName: 'style', |
|||
|
|||
/** |
|||
* Triggered when some selector is changed |
|||
* @private |
|||
*/ |
|||
selChanged: function(){ |
|||
this.selStr = this.renderSelectors(); |
|||
this.render(); |
|||
}, |
|||
initialize(o) { |
|||
this.config = o.config || {}; |
|||
this.listenTo(this.model, 'change:style', this.render); |
|||
this.listenTo(this.model, 'change:state', this.render); |
|||
this.listenTo(this.model, 'destroy remove', this.remove); |
|||
this.listenTo(this.model, 'change:mediaText', this.render); |
|||
this.listenTo(this.model.get('selectors'), 'change', this.selChanged); |
|||
}, |
|||
|
|||
/** |
|||
* Triggered when some selector is changed |
|||
* @private |
|||
*/ |
|||
selChanged() { |
|||
this.selStr = this.renderSelectors(); |
|||
this.render(); |
|||
}, |
|||
|
|||
/** |
|||
* Returns string of selectors |
|||
* @return {String} |
|||
* @private |
|||
*/ |
|||
renderSelectors: function() { |
|||
var sel = []; |
|||
var model = this.model; |
|||
var add = model.get('selectorsAdd'); |
|||
model.get('selectors').each(function(m){ |
|||
sel.push('.' + m.get('name')); |
|||
}); |
|||
var sels = sel.join(''); |
|||
return sels + (sels && add ? ', ' : '') + add; |
|||
}, |
|||
/** |
|||
* Returns string of selectors |
|||
* @return {String} |
|||
* @private |
|||
*/ |
|||
renderSelectors() { |
|||
var sel = []; |
|||
var model = this.model; |
|||
var add = model.get('selectorsAdd'); |
|||
model.get('selectors').each(m => { |
|||
sel.push('.' + m.get('name')); |
|||
}); |
|||
var sels = sel.join(''); |
|||
return sels + (sels && add ? ', ' : '') + add; |
|||
}, |
|||
|
|||
/** |
|||
* Returns string of properties |
|||
* @return {String} |
|||
* @private |
|||
*/ |
|||
renderProperties: function(){ |
|||
var sel = [], |
|||
props = this.model.get('style'); |
|||
for (var prop in props){ |
|||
sel.push(prop + ':' + props[prop] + ';'); |
|||
} |
|||
return sel.join(''); |
|||
}, |
|||
/** |
|||
* Returns string of properties |
|||
* @return {String} |
|||
* @private |
|||
*/ |
|||
renderProperties() { |
|||
var sel = [], |
|||
props = this.model.get('style'); |
|||
for (var prop in props){ |
|||
sel.push(prop + ':' + props[prop] + ';'); |
|||
} |
|||
return sel.join(''); |
|||
}, |
|||
|
|||
render : function(){ |
|||
var block = '', |
|||
selStr = ''; |
|||
o = ''; |
|||
if(!this.selStr) |
|||
this.selStr = this.renderSelectors(); |
|||
var prpStr = this.renderProperties(); |
|||
var stateStr = this.model.get('state'); |
|||
var mediaText = this.model.get('mediaText'); |
|||
if(this.selStr){ |
|||
stateStr = stateStr ? ':' + stateStr : ''; |
|||
block = prpStr !== '' ? '{' + prpStr + '}' : ''; |
|||
} |
|||
o = this.selStr && block ? this.selStr + stateStr + block : ''; |
|||
render() { |
|||
var block = '', |
|||
selStr = '', |
|||
o = ''; |
|||
if(!this.selStr) |
|||
this.selStr = this.renderSelectors(); |
|||
var prpStr = this.renderProperties(); |
|||
var stateStr = this.model.get('state'); |
|||
var mediaText = this.model.get('mediaText'); |
|||
if(this.selStr){ |
|||
stateStr = stateStr ? ':' + stateStr : ''; |
|||
block = prpStr !== '' ? '{' + prpStr + '}' : ''; |
|||
} |
|||
o = this.selStr && block ? this.selStr + stateStr + block : ''; |
|||
|
|||
if(mediaText && o) |
|||
o = '@media ' + mediaText + '{' + o + '}'; |
|||
if(mediaText && o) |
|||
o = '@media ' + mediaText + '{' + o + '}'; |
|||
|
|||
this.$el.html(o); |
|||
return this; |
|||
}, |
|||
this.$el.html(o); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,61 +1,61 @@ |
|||
define(['backbone','./CssRuleView'], |
|||
function (Backbone, CssRuleView) { |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix || ''; |
|||
this.className = this.pfx + 'rules'; |
|||
this.listenTo( this.collection, 'add', this.addTo ); |
|||
this.listenTo( this.collection, 'reset', this.render ); |
|||
}, |
|||
|
|||
/** |
|||
* Add to collection |
|||
* @param {Object} model |
|||
* @private |
|||
* */ |
|||
addTo: function(model){ |
|||
//console.log('Added');
|
|||
this.addToCollection(model); |
|||
}, |
|||
|
|||
/** |
|||
* Add new object to collection |
|||
* @param {Object} model |
|||
* @param {Object} fragmentEl |
|||
* @return {Object} |
|||
* @private |
|||
* */ |
|||
addToCollection: function(model, fragmentEl){ |
|||
var fragment = fragmentEl || null; |
|||
var viewObject = CssRuleView; |
|||
|
|||
var view = new viewObject({ |
|||
model: model, |
|||
config: this.config, |
|||
}); |
|||
var rendered = view.render().el; |
|||
|
|||
if(fragment) |
|||
fragment.appendChild( rendered ); |
|||
else |
|||
this.$el.append(rendered); |
|||
|
|||
return rendered; |
|||
}, |
|||
|
|||
render: function() { |
|||
var fragment = document.createDocumentFragment(); |
|||
this.$el.empty(); |
|||
|
|||
this.collection.each(function(model){ |
|||
this.addToCollection(model, fragment); |
|||
}, this); |
|||
|
|||
this.$el.append(fragment); |
|||
this.$el.attr('class', this.className); |
|||
return this; |
|||
} |
|||
}); |
|||
var Backbone = require('backbone'); |
|||
var CssRuleView = require('./CssRuleView'); |
|||
|
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
initialize(o) { |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix || ''; |
|||
this.className = this.pfx + 'rules'; |
|||
this.listenTo( this.collection, 'add', this.addTo ); |
|||
this.listenTo( this.collection, 'reset', this.render ); |
|||
}, |
|||
|
|||
/** |
|||
* Add to collection |
|||
* @param {Object} model |
|||
* @private |
|||
* */ |
|||
addTo(model) { |
|||
//console.log('Added');
|
|||
this.addToCollection(model); |
|||
}, |
|||
|
|||
/** |
|||
* Add new object to collection |
|||
* @param {Object} model |
|||
* @param {Object} fragmentEl |
|||
* @return {Object} |
|||
* @private |
|||
* */ |
|||
addToCollection(model, fragmentEl) { |
|||
var fragment = fragmentEl || null; |
|||
var viewObject = CssRuleView; |
|||
|
|||
var view = new viewObject({ |
|||
model, |
|||
config: this.config, |
|||
}); |
|||
var rendered = view.render().el; |
|||
|
|||
if(fragment) |
|||
fragment.appendChild( rendered ); |
|||
else |
|||
this.$el.append(rendered); |
|||
|
|||
return rendered; |
|||
}, |
|||
|
|||
render() { |
|||
var fragment = document.createDocumentFragment(); |
|||
this.$el.empty(); |
|||
|
|||
this.collection.each(function(model){ |
|||
this.addToCollection(model, fragment); |
|||
}, this); |
|||
|
|||
this.$el.append(fragment); |
|||
this.$el.attr('class', this.className); |
|||
return this; |
|||
} |
|||
}); |
|||
|
|||
@ -1,369 +0,0 @@ |
|||
require(['config/require-config'], function() { |
|||
|
|||
require(['grapesjs/main'],function (grapesjs){ |
|||
|
|||
var editor = grapesjs.init( |
|||
|
|||
|
|||
{ |
|||
allowScripts: 1, |
|||
showOffsets: 1, |
|||
autorender: 0, |
|||
noticeOnUnload: 0, |
|||
container : '#gjs', |
|||
height: '100%', |
|||
fromElement: true, |
|||
clearOnRender: 0, |
|||
|
|||
storageManager:{ |
|||
autoload: 0, |
|||
storeComponents: 1, |
|||
storeStyles: 1, |
|||
}, |
|||
|
|||
/* |
|||
components: [{ |
|||
//script: 'var el = this; setInterval(function(){el.style.marginLeft = Math.random() * 50 +"px";}, 1000)',
|
|||
script: 'loadScript = function(){console.log("loaded INSIDE", $);}', |
|||
style: { |
|||
background: 'red', |
|||
width:'500px', |
|||
height:'100px', |
|||
margin: '50px auto', |
|||
} |
|||
},{ |
|||
script: 'this.innerHTML= "test1";', |
|||
style: { |
|||
background: 'blue', |
|||
width:'500px', |
|||
height:'100px', |
|||
margin: '50px auto', |
|||
} |
|||
},{ |
|||
script: 'this.innerHTML= "test2";', |
|||
style: { |
|||
background: 'green', |
|||
width:'500px', |
|||
height:'100px', |
|||
margin: '50px auto', |
|||
} |
|||
},{ |
|||
style: { |
|||
background: 'yellow', |
|||
width:'500px', |
|||
height:'100px', |
|||
margin: '50px auto', |
|||
} |
|||
},{ |
|||
type: 'text', |
|||
style:{ |
|||
width:'100px', |
|||
height:'100px', |
|||
margin: '50px auto', |
|||
}, |
|||
traits: ['title'], |
|||
components: [{ |
|||
type: 'textnode', |
|||
content: 'text node row', |
|||
},{ |
|||
type: 'textnode', |
|||
content: ', another text node', |
|||
},{ |
|||
type: 'link', |
|||
content: 'someLink', |
|||
},{ |
|||
type: 'textnode', |
|||
content: " More text node --- ", |
|||
}], |
|||
}], |
|||
*/ |
|||
|
|||
commands: { |
|||
defaults : [{ |
|||
id: 'open-github', |
|||
run: function(editor, sender){ |
|||
sender.set('active',false); |
|||
window.open('https://github.com/artf/grapesjs','_blank'); |
|||
} |
|||
},{ |
|||
id: 'undo', |
|||
run: function(editor, sender){ |
|||
sender.set('active',false); |
|||
editor.UndoManager.undo(true); |
|||
} |
|||
},{ |
|||
id: 'redo', |
|||
run: function(editor, sender){ |
|||
sender.set('active',false); |
|||
editor.UndoManager.redo(true); |
|||
} |
|||
},{ |
|||
id: 'clean-all', |
|||
run: function(editor, sender){ |
|||
sender.set('active',false); |
|||
if(confirm('Are you sure to clean the canvas?')){ |
|||
var comps = editor.DomComponents.clear(); |
|||
} |
|||
} |
|||
}], |
|||
}, |
|||
|
|||
assetManager: { |
|||
storageType : '', |
|||
storeOnChange : true, |
|||
storeAfterUpload : true, |
|||
assets : [ |
|||
{ type: 'image', src : 'http://placehold.it/350x250/78c5d6/fff/image1.jpg', height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/459ba8/fff/image2.jpg', height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/79c267/fff/image3.jpg', height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/c5d647/fff/image4.jpg', height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/f28c33/fff/image5.jpg', height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/e868a2/fff/image6.jpg', height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/cc4360/fff/image7.jpg', height:350, width:250}, |
|||
{ type: 'image', src : './img/work-desk.jpg', date: '2015-02-01',height:1080, width:1728}, |
|||
{ type: 'image', src : './img/phone-app.png', date: '2015-02-01',height:650, width:320}, |
|||
{ type: 'image', src : './img/bg-gr-v.png', date: '2015-02-01',height:1, width:1728}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
styleManager : { |
|||
sectors: [{ |
|||
name: 'General', |
|||
open: false, |
|||
buildProps: ['float', 'display', 'position', 'top', 'right', 'left', 'bottom'], |
|||
},{ |
|||
name: 'Dimension', |
|||
open: false, |
|||
buildProps: ['width', 'height', 'max-width', 'min-height', 'margin', 'padding'], |
|||
},{ |
|||
name: 'Typography', |
|||
open: false, |
|||
buildProps: ['font-family', 'font-size', 'font-weight', 'letter-spacing', 'color', 'line-height', 'text-align', 'text-shadow'], |
|||
properties: [{ |
|||
property: 'text-align', |
|||
list : [ |
|||
{value: 'left', className: 'fa fa-align-left'}, |
|||
{value: 'center', className: 'fa fa-align-center' }, |
|||
{value: 'right', className: 'fa fa-align-right'}, |
|||
{value: 'justify', className: 'fa fa-align-justify'} |
|||
], |
|||
}] |
|||
},{ |
|||
name: 'Decorations', |
|||
open: false, |
|||
buildProps: ['border-radius-c', 'background-color', 'border-radius', 'border', 'box-shadow', 'background'], |
|||
},{ |
|||
name: 'Extra', |
|||
open: false, |
|||
buildProps: ['transition', 'perspective', 'transform'], |
|||
},{ |
|||
name: 'Flex', |
|||
open: false, |
|||
properties: [{ |
|||
name : 'Flex Container', |
|||
property : 'display', |
|||
type : 'select', |
|||
defaults : 'block', |
|||
list : [{ |
|||
value : 'block', |
|||
name : 'Disable', |
|||
},{ |
|||
value : 'flex', |
|||
name : 'Enable', |
|||
}], |
|||
},{ |
|||
name: 'Flex Parent', |
|||
property: 'label-parent-flex', |
|||
},{ |
|||
name : 'Direction', |
|||
property : 'flex-direction', |
|||
type : 'radio', |
|||
defaults : 'row', |
|||
list : [{ |
|||
value : 'row', |
|||
name : 'Row', |
|||
className : 'icons-flex icon-dir-row', |
|||
title : 'Row', |
|||
},{ |
|||
value : 'row-reverse', |
|||
name : 'Row reverse', |
|||
className : 'icons-flex icon-dir-row-rev', |
|||
title : 'Row reverse', |
|||
},{ |
|||
value : 'column', |
|||
name : 'Column', |
|||
title : 'Column', |
|||
className : 'icons-flex icon-dir-col', |
|||
},{ |
|||
value : 'column-reverse', |
|||
name : 'Column reverse', |
|||
title : 'Column reverse', |
|||
className : 'icons-flex icon-dir-col-rev', |
|||
}], |
|||
},{ |
|||
name : 'Wrap', |
|||
property : 'flex-wrap', |
|||
type : 'radio', |
|||
defaults : 'nowrap', |
|||
list : [{ |
|||
value : 'nowrap', |
|||
title : 'Single line', |
|||
},{ |
|||
value : 'wrap', |
|||
title : 'Multiple lines', |
|||
},{ |
|||
value : 'wrap-reverse', |
|||
title : 'Multiple lines reverse', |
|||
}], |
|||
},{ |
|||
name : 'Justify', |
|||
property : 'justify-content', |
|||
type : 'radio', |
|||
defaults : 'flex-start', |
|||
list : [{ |
|||
value : 'flex-start', |
|||
className : 'icons-flex icon-just-start', |
|||
title : 'Start', |
|||
},{ |
|||
value : 'flex-end', |
|||
title : 'End', |
|||
className : 'icons-flex icon-just-end', |
|||
},{ |
|||
value : 'space-between', |
|||
title : 'Space between', |
|||
className : 'icons-flex icon-just-sp-bet', |
|||
},{ |
|||
value : 'space-around', |
|||
title : 'Space around', |
|||
className : 'icons-flex icon-just-sp-ar', |
|||
},{ |
|||
value : 'center', |
|||
title : 'Center', |
|||
className : 'icons-flex icon-just-sp-cent', |
|||
}], |
|||
},{ |
|||
name : 'Align', |
|||
property : 'align-items', |
|||
type : 'radio', |
|||
defaults : 'center', |
|||
list : [{ |
|||
value : 'flex-start', |
|||
title : 'Start', |
|||
className : 'icons-flex icon-al-start', |
|||
},{ |
|||
value : 'flex-end', |
|||
title : 'End', |
|||
className : 'icons-flex icon-al-end', |
|||
},{ |
|||
value : 'stretch', |
|||
title : 'Stretch', |
|||
className : 'icons-flex icon-al-str', |
|||
},{ |
|||
value : 'center', |
|||
title : 'Center', |
|||
className : 'icons-flex icon-al-center', |
|||
}], |
|||
},{ |
|||
name: 'Flex Children', |
|||
property: 'label-parent-flex', |
|||
},{ |
|||
name: 'Order', |
|||
property: 'order', |
|||
type: 'integer', |
|||
defaults : 0, |
|||
min: 0 |
|||
},{ |
|||
name : 'Flex', |
|||
property : 'flex', |
|||
type : 'composite', |
|||
properties : [{ |
|||
name: 'Grow', |
|||
property: 'flex-grow', |
|||
type: 'integer', |
|||
defaults : 0, |
|||
min: 0 |
|||
},{ |
|||
name: 'Shrink', |
|||
property: 'flex-shrink', |
|||
type: 'integer', |
|||
defaults : 0, |
|||
min: 0 |
|||
},{ |
|||
name: 'Basis', |
|||
property: 'flex-basis', |
|||
type: 'integer', |
|||
units: ['px','%',''], |
|||
unit: '', |
|||
defaults : 'auto', |
|||
}], |
|||
},{ |
|||
name : 'Align', |
|||
property : 'align-self', |
|||
type : 'radio', |
|||
defaults : 'auto', |
|||
list : [{ |
|||
value : 'auto', |
|||
name : 'Auto', |
|||
},{ |
|||
value : 'flex-start', |
|||
title : 'Start', |
|||
className : 'icons-flex icon-al-start', |
|||
},{ |
|||
value : 'flex-end', |
|||
title : 'End', |
|||
className : 'icons-flex icon-al-end', |
|||
},{ |
|||
value : 'stretch', |
|||
title : 'Stretch', |
|||
className : 'icons-flex icon-al-str', |
|||
},{ |
|||
value : 'center', |
|||
title : 'Center', |
|||
className : 'icons-flex icon-al-center', |
|||
}], |
|||
}] |
|||
} |
|||
|
|||
], |
|||
|
|||
}, |
|||
|
|||
|
|||
}); |
|||
|
|||
window.editor = editor; |
|||
|
|||
var pnm = editor.Panels; |
|||
pnm.addButton('options', [{ |
|||
id: 'undo', |
|||
className: 'fa fa-undo icon-undo', |
|||
command: function(editor, sender) { |
|||
sender.set('active', 0); |
|||
editor.UndoManager.undo(1); |
|||
}, |
|||
attributes: { title: 'Undo (CTRL/CMD + Z)'} |
|||
},{ |
|||
id: 'redo', |
|||
className: 'fa fa-repeat icon-redo', |
|||
command: function(editor, sender) { |
|||
sender.set('active', 0); |
|||
editor.UndoManager.redo(1); |
|||
}, |
|||
attributes: { title: 'Redo (CTRL/CMD + SHIFT + Z)' } |
|||
},{ |
|||
id: 'clean-all', |
|||
className: 'fa fa-trash icon-blank', |
|||
command: function(editor, sender) { |
|||
if(sender) sender.set('active', false); |
|||
if(confirm('Are you sure to clean the canvas?')) { |
|||
var comps = editor.DomComponents.clear(); |
|||
localStorage.clear(); |
|||
} |
|||
}, |
|||
attributes: { title: 'Empty canvas' } |
|||
}]); |
|||
|
|||
editor.render(); |
|||
}); |
|||
}); |
|||
@ -1,9 +1,7 @@ |
|||
define(function () { |
|||
return { |
|||
module.exports = { |
|||
|
|||
devices: [], |
|||
devices: [], |
|||
|
|||
deviceLabel: 'Device', |
|||
deviceLabel: 'Device', |
|||
|
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
@ -0,0 +1,111 @@ |
|||
/** |
|||
* * [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 |
|||
*/ |
|||
module.exports = () => { |
|||
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(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(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(name) { |
|||
return devices.get(name); |
|||
}, |
|||
|
|||
/** |
|||
* Return all devices |
|||
* @return {Collection} |
|||
* @example |
|||
* var devices = deviceManager.getAll(); |
|||
* console.log(JSON.stringify(devices)); |
|||
* // [{name: 'Desktop', width: ''}, ...]
|
|||
*/ |
|||
getAll() { |
|||
return devices; |
|||
}, |
|||
|
|||
/** |
|||
* Render devices |
|||
* @return {string} HTML string |
|||
* @private |
|||
*/ |
|||
render() { |
|||
return view.render().el; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
@ -1,115 +0,0 @@ |
|||
/** |
|||
* * [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; |
|||
}, |
|||
|
|||
}; |
|||
|
|||
}; |
|||
|
|||
}); |
|||
@ -1,14 +1,12 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
var Backbone = require('backbone'); |
|||
|
|||
return Backbone.Model.extend({ |
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
idAttribute: 'name', |
|||
idAttribute: 'name', |
|||
|
|||
defaults :{ |
|||
name: '', |
|||
width: '', |
|||
}, |
|||
defaults :{ |
|||
name: '', |
|||
width: '', |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
@ -1,9 +1,6 @@ |
|||
define(['backbone','./Device'], |
|||
function (Backbone, Device) { |
|||
var Backbone = require('backbone'); |
|||
var Device = require('./Device'); |
|||
|
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Device, |
|||
|
|||
}); |
|||
module.exports = Backbone.Collection.extend({ |
|||
model: Device, |
|||
}); |
|||
|
|||
@ -1,10 +0,0 @@ |
|||
<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> |
|||
@ -1,82 +1,90 @@ |
|||
define(['backbone', 'text!./../template/devices.html'], |
|||
function(Backbone, devicesTemplate) { |
|||
var Backbone = require('backbone'); |
|||
|
|||
return Backbone.View.extend({ |
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
template: _.template(devicesTemplate), |
|||
template: _.template(` |
|||
<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>`), |
|||
|
|||
events: { |
|||
'change': 'updateDevice' |
|||
}, |
|||
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(); |
|||
}, |
|||
initialize(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(){}, |
|||
/** |
|||
* Start adding new device |
|||
* @return {[type]} [description] |
|||
* @private |
|||
*/ |
|||
startAdd() {}, |
|||
|
|||
/** |
|||
* 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; |
|||
/** |
|||
* Update device of the editor |
|||
* @private |
|||
*/ |
|||
updateDevice() { |
|||
var em = this.em; |
|||
if(em){ |
|||
var devEl = this.devicesEl; |
|||
if(em && em.getDeviceModel && devEl){ |
|||
var device = em.getDeviceModel(); |
|||
var name = device ? device.get('name') : ''; |
|||
devEl.val(name); |
|||
} |
|||
}, |
|||
var val = devEl ? devEl.val() : ''; |
|||
em.set('device', val); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Update select value on device update |
|||
* @private |
|||
*/ |
|||
updateSelect() { |
|||
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; |
|||
}, |
|||
/** |
|||
* Return devices options |
|||
* @return {string} String of options |
|||
* @private |
|||
*/ |
|||
getOptions() { |
|||
var result = ''; |
|||
this.collection.each(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; |
|||
}, |
|||
render() { |
|||
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,32 +1,30 @@ |
|||
define(function () { |
|||
return { |
|||
stylePrefix: 'comp-', |
|||
module.exports = { |
|||
stylePrefix: 'comp-', |
|||
|
|||
wrapperId: 'wrapper', |
|||
wrapperId: 'wrapper', |
|||
|
|||
// Default wrapper configuration
|
|||
wrapper: { |
|||
//classes: ['body'],
|
|||
removable: false, |
|||
copyable: false, |
|||
stylable: ['background','background-color','background-image', 'background-repeat','background-attachment','background-position'], |
|||
draggable: false, |
|||
badgable: false, |
|||
components: [], |
|||
}, |
|||
// Default wrapper configuration
|
|||
wrapper: { |
|||
//classes: ['body'],
|
|||
removable: false, |
|||
copyable: false, |
|||
stylable: ['background','background-color','background-image', 'background-repeat','background-attachment','background-position'], |
|||
draggable: false, |
|||
badgable: false, |
|||
components: [], |
|||
}, |
|||
|
|||
// Could be used for default components
|
|||
components: [], |
|||
// Could be used for default components
|
|||
components: [], |
|||
|
|||
rte: {}, |
|||
rte: {}, |
|||
|
|||
// Class for new image component
|
|||
imageCompClass : 'fa fa-picture-o', |
|||
// Class for new image component
|
|||
imageCompClass : 'fa fa-picture-o', |
|||
|
|||
// Open assets manager on create of image component
|
|||
oAssetsOnCreate : true, |
|||
// Open assets manager on create of image component
|
|||
oAssetsOnCreate : true, |
|||
|
|||
// List of void elements
|
|||
voidElements: ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'], |
|||
}; |
|||
}); |
|||
// List of void elements
|
|||
voidElements: ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'], |
|||
}; |
|||
|
|||
@ -0,0 +1,395 @@ |
|||
/** |
|||
* |
|||
* * [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!'}} |
|||
* ], |
|||
* } |
|||
* ... |
|||
*/ |
|||
module.exports = () => { |
|||
var c = {}, |
|||
componentTypes = {}, |
|||
defaults = require('./config/config'), |
|||
Component = require('./model/Component'), |
|||
ComponentView = require('./view/ComponentView'); |
|||
|
|||
var component, componentView; |
|||
var defaultTypes = [ |
|||
{ |
|||
id: 'cell', |
|||
model: require('./model/ComponentTableCell'), |
|||
view: require('./view/ComponentTableCellView'), |
|||
}, |
|||
{ |
|||
id: 'row', |
|||
model: require('./model/ComponentTableRow'), |
|||
view: require('./view/ComponentTableRowView'), |
|||
}, |
|||
{ |
|||
id: 'table', |
|||
model: require('./model/ComponentTable'), |
|||
view: require('./view/ComponentTableView'), |
|||
}, |
|||
{ |
|||
id: 'map', |
|||
model: require('./model/ComponentMap'), |
|||
view: require('./view/ComponentMapView'), |
|||
}, |
|||
{ |
|||
id: 'link', |
|||
model: require('./model/ComponentLink'), |
|||
view: require('./view/ComponentLinkView'), |
|||
}, |
|||
{ |
|||
id: 'video', |
|||
model: require('./model/ComponentVideo'), |
|||
view: require('./view/ComponentVideoView'), |
|||
}, |
|||
{ |
|||
id: 'image', |
|||
model: require('./model/ComponentImage'), |
|||
view: require('./view/ComponentImageView'), |
|||
}, |
|||
{ |
|||
id: 'script', |
|||
model: require('./model/ComponentScript'), |
|||
view: require('./view/ComponentScriptView'), |
|||
}, |
|||
{ |
|||
id: 'textnode', |
|||
model: require('./model/ComponentTextNode'), |
|||
view: require('./view/ComponentTextNodeView'), |
|||
}, |
|||
{ |
|||
id: 'text', |
|||
model: require('./model/ComponentText'), |
|||
view: require('./view/ComponentTextView'), |
|||
}, |
|||
{ |
|||
id: 'default', |
|||
model: Component, |
|||
view: ComponentView, |
|||
}, |
|||
]; |
|||
|
|||
return { |
|||
|
|||
componentTypes: defaultTypes, |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'DomComponents', |
|||
|
|||
/** |
|||
* Returns config |
|||
* @return {Object} Config object |
|||
* @private |
|||
*/ |
|||
getConfig() { |
|||
return c; |
|||
}, |
|||
|
|||
/** |
|||
* Mandatory for the storage manager |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
storageKey() { |
|||
var keys = []; |
|||
var smc = (c.stm && c.stm.getConfig()) || {}; |
|||
if(smc.storeHtml) |
|||
keys.push('html'); |
|||
if(smc.storeComponents) |
|||
keys.push('components'); |
|||
return keys; |
|||
}, |
|||
|
|||
/** |
|||
* Initialize module. Called on a new instance of the editor with configurations passed |
|||
* inside 'domComponents' field |
|||
* @param {Object} config Configurations |
|||
* @private |
|||
*/ |
|||
init(config) { |
|||
c = config || {}; |
|||
if(c.em) |
|||
c.components = c.em.config.components || c.components; |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
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') || ''; |
|||
c.em.get('Parser').compTypes = defaultTypes; |
|||
} |
|||
|
|||
component = new Component(c.wrapper, { |
|||
sm: c.em, |
|||
config: c, |
|||
defaultTypes, |
|||
componentTypes, |
|||
}); |
|||
component.set({ attributes: {id: 'wrapper'}}); |
|||
|
|||
if(c.em && !c.em.config.loadCompsOnRender) { |
|||
component.get('components').add(c.components); |
|||
} |
|||
|
|||
componentView = new ComponentView({ |
|||
model: component, |
|||
config: c, |
|||
defaultTypes, |
|||
componentTypes, |
|||
}); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* On load callback |
|||
* @private |
|||
*/ |
|||
onLoad() { |
|||
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(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; |
|||
|
|||
if(obj) |
|||
this.getComponents().reset(obj); |
|||
return obj; |
|||
}, |
|||
|
|||
/** |
|||
* Store components on the selected storage |
|||
* @param {Boolean} noStore If true, won't store |
|||
* @return {Object} Data to store |
|||
*/ |
|||
store(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 privately the main wrapper |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getComponent() { |
|||
return component; |
|||
}, |
|||
|
|||
/** |
|||
* 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() { |
|||
return this.getComponent(); |
|||
}, |
|||
|
|||
/** |
|||
* 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() { |
|||
return this.getWrapper().get('components'); |
|||
}, |
|||
|
|||
/** |
|||
* 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' } |
|||
* }); |
|||
*/ |
|||
addComponent(component) { |
|||
return this.getComponents().add(component); |
|||
}, |
|||
|
|||
/** |
|||
* 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() { |
|||
return componentView.render().el; |
|||
}, |
|||
|
|||
/** |
|||
* Remove all components |
|||
* @return {this} |
|||
*/ |
|||
clear() { |
|||
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(components) { |
|||
this.clear().addComponent(components); |
|||
}, |
|||
|
|||
/** |
|||
* Add new component type |
|||
* @param {string} type |
|||
* @param {Object} methods |
|||
* @private |
|||
*/ |
|||
addType(type, methods) { |
|||
var compType = this.getType(type); |
|||
if(compType) { |
|||
compType.model = methods.model; |
|||
compType.view = methods.view; |
|||
} else { |
|||
methods.id = type; |
|||
defaultTypes.unshift(methods); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Get component type |
|||
* @param {string} type |
|||
* @private |
|||
*/ |
|||
getType(type) { |
|||
var df = defaultTypes; |
|||
|
|||
for (var it = 0; it < df.length; it++) { |
|||
var dfId = df[it].id; |
|||
if(dfId == type) { |
|||
return df[it]; |
|||
} |
|||
} |
|||
return; |
|||
}, |
|||
|
|||
}; |
|||
}; |
|||
@ -1,398 +0,0 @@ |
|||
/** |
|||
* |
|||
* * [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) { |
|||
|
|||
return function (){ |
|||
var c = {}, |
|||
componentTypes = {}, |
|||
defaults = require('./config/config'), |
|||
Component = require('./model/Component'), |
|||
ComponentView = require('./view/ComponentView'); |
|||
|
|||
var component, componentView; |
|||
var defaultTypes = [ |
|||
{ |
|||
id: 'cell', |
|||
model: require('./model/ComponentTableCell'), |
|||
view: require('./view/ComponentTableCellView'), |
|||
}, |
|||
{ |
|||
id: 'row', |
|||
model: require('./model/ComponentTableRow'), |
|||
view: require('./view/ComponentTableRowView'), |
|||
}, |
|||
{ |
|||
id: 'table', |
|||
model: require('./model/ComponentTable'), |
|||
view: require('./view/ComponentTableView'), |
|||
}, |
|||
{ |
|||
id: 'map', |
|||
model: require('./model/ComponentMap'), |
|||
view: require('./view/ComponentMapView'), |
|||
}, |
|||
{ |
|||
id: 'link', |
|||
model: require('./model/ComponentLink'), |
|||
view: require('./view/ComponentLinkView'), |
|||
}, |
|||
{ |
|||
id: 'video', |
|||
model: require('./model/ComponentVideo'), |
|||
view: require('./view/ComponentVideoView'), |
|||
}, |
|||
{ |
|||
id: 'image', |
|||
model: require('./model/ComponentImage'), |
|||
view: require('./view/ComponentImageView'), |
|||
}, |
|||
{ |
|||
id: 'script', |
|||
model: require('./model/ComponentScript'), |
|||
view: require('./view/ComponentScriptView'), |
|||
}, |
|||
{ |
|||
id: 'textnode', |
|||
model: require('./model/ComponentTextNode'), |
|||
view: require('./view/ComponentTextNodeView'), |
|||
}, |
|||
{ |
|||
id: 'text', |
|||
model: require('./model/ComponentText'), |
|||
view: require('./view/ComponentTextView'), |
|||
}, |
|||
{ |
|||
id: 'default', |
|||
model: Component, |
|||
view: ComponentView, |
|||
}, |
|||
]; |
|||
|
|||
return { |
|||
|
|||
componentTypes: defaultTypes, |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'DomComponents', |
|||
|
|||
/** |
|||
* Returns config |
|||
* @return {Object} Config object |
|||
* @private |
|||
*/ |
|||
getConfig: function () { |
|||
return c; |
|||
}, |
|||
|
|||
/** |
|||
* 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; |
|||
}, |
|||
|
|||
/** |
|||
* 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; |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
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') || ''; |
|||
c.em.get('Parser').compTypes = defaultTypes; |
|||
} |
|||
|
|||
component = new Component(c.wrapper, { |
|||
sm: c.em, |
|||
config: c, |
|||
defaultTypes: defaultTypes, |
|||
componentTypes: componentTypes, |
|||
}); |
|||
component.set({ attributes: {id: 'wrapper'}}); |
|||
|
|||
if(c.em && !c.em.config.loadCompsOnRender) { |
|||
component.get('components').add(c.components); |
|||
} |
|||
|
|||
componentView = new ComponentView({ |
|||
model: component, |
|||
config: c, |
|||
defaultTypes: defaultTypes, |
|||
componentTypes: componentTypes, |
|||
}); |
|||
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; |
|||
|
|||
if(obj) |
|||
this.getComponents().reset(obj); |
|||
return obj; |
|||
}, |
|||
|
|||
/** |
|||
* 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 privately the main wrapper |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getComponent : function(){ |
|||
return component; |
|||
}, |
|||
|
|||
/** |
|||
* 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 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'); |
|||
}, |
|||
|
|||
/** |
|||
* 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' } |
|||
* }); |
|||
*/ |
|||
addComponent: function(component){ |
|||
return this.getComponents().add(component); |
|||
}, |
|||
|
|||
/** |
|||
* 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); |
|||
}, |
|||
|
|||
/** |
|||
* Add new component type |
|||
* @param {string} type |
|||
* @param {Object} methods |
|||
* @private |
|||
*/ |
|||
addType: function(type, methods) { |
|||
var compType = this.getType(type); |
|||
if(compType) { |
|||
compType.model = methods.model; |
|||
compType.view = methods.view; |
|||
} else { |
|||
methods.id = type; |
|||
defaultTypes.unshift(methods); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Get component type |
|||
* @param {string} type |
|||
* @private |
|||
*/ |
|||
getType: function(type) { |
|||
var df = defaultTypes; |
|||
|
|||
for (var it = 0; it < df.length; it++) { |
|||
var dfId = df[it].id; |
|||
if(dfId == type) { |
|||
return df[it]; |
|||
} |
|||
} |
|||
return; |
|||
}, |
|||
|
|||
}; |
|||
}; |
|||
}); |
|||
@ -1,371 +1,370 @@ |
|||
define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitManager/model/Traits'], |
|||
function (Backbone, Components, Selectors, Traits) { |
|||
var Backbone = require('backbone'); |
|||
var Components = require('./Components'); |
|||
var Selectors = require('selector_manager/model/Selectors'); |
|||
var Traits = require('trait_manager/model/Traits'); |
|||
|
|||
return Backbone.Model.extend({ |
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
// HTML tag of the component
|
|||
tagName: 'div', |
|||
|
|||
// Component type, eg. 'text', 'image', 'video', etc.
|
|||
type: '', |
|||
|
|||
// True if the component is removable from the canvas
|
|||
removable: true, |
|||
|
|||
// Indicates if it's possible to drag the component inside other
|
|||
// Tip: Indicate an array of selectors where it could be dropped inside
|
|||
draggable: true, |
|||
|
|||
// Indicates if it's possible to drop other components inside
|
|||
// Tip: Indicate an array of selectors which could be dropped inside
|
|||
droppable: true, |
|||
|
|||
// Set false if don't want to see the badge (with the name) over the component
|
|||
badgable: true, |
|||
|
|||
// True if it's possible to style it
|
|||
// Tip: Indicate an array of CSS properties which is possible to style
|
|||
stylable: true, |
|||
|
|||
// Highlightable with 'dotted' style if true
|
|||
highlightable: true, |
|||
|
|||
// True if it's possible to clone the component
|
|||
copyable: true, |
|||
|
|||
// Indicates if it's possible to resize the component (at the moment implemented only on Image Components)
|
|||
resizable: false, |
|||
|
|||
// Allow to edit the content of the component (used on Text components)
|
|||
editable: false, |
|||
|
|||
// Hide the component inside Layers
|
|||
hiddenLayer: false, |
|||
|
|||
// This property is used by the HTML exporter as void elements do not
|
|||
// have closing tag, eg. <br/>, <hr/>, etc.
|
|||
void: false, |
|||
|
|||
// Indicates if the component is in some CSS state like ':hover', ':active', etc.
|
|||
state: '', |
|||
|
|||
// State, eg. 'selected'
|
|||
status: '', |
|||
|
|||
// Content of the component (not escaped) which will be appended before children rendering
|
|||
content: '', |
|||
|
|||
// Component related style
|
|||
style: {}, |
|||
|
|||
// Key-value object of the component's attributes
|
|||
attributes: '', |
|||
|
|||
// Array of classes
|
|||
classes: '', |
|||
|
|||
// Component's javascript
|
|||
script: '', |
|||
|
|||
// Traits
|
|||
traits: ['id', 'title'], |
|||
|
|||
/** |
|||
* Set an array of items to show up inside the toolbar (eg. move, clone, delete) |
|||
* when the component is selected |
|||
* toolbar: [{ |
|||
* attributes: {class: 'fa fa-arrows'}, |
|||
* command: 'tlb-move', |
|||
* },{ |
|||
* attributes: {class: 'fa fa-clone'}, |
|||
* command: 'tlb-clone', |
|||
* }] |
|||
*/ |
|||
toolbar: null, |
|||
|
|||
// TODO
|
|||
previousModel: '', |
|||
mirror: '', |
|||
}, |
|||
|
|||
initialize: function(o, opt) { |
|||
// Check void elements
|
|||
if(opt && opt.config && opt.config.voidElements.indexOf(this.get('tagName')) >= 0) |
|||
this.set('void', true); |
|||
|
|||
this.opt = opt; |
|||
this.sm = opt ? opt.sm || {} : {}; |
|||
this.config = o || {}; |
|||
this.defaultC = this.config.components || []; |
|||
this.defaultCl = this.normalizeClasses(this.get('classes') || this.config.classes || []); |
|||
this.components = new Components(this.defaultC, opt); |
|||
this.components.parent = this; |
|||
this.listenTo(this, 'change:script', this.scriptUpdated); |
|||
this.set('attributes', this.get('attributes') || {}); |
|||
this.set('components', this.components); |
|||
this.set('classes', new Selectors(this.defaultCl)); |
|||
var traits = new Traits(); |
|||
traits.setTarget(this); |
|||
traits.add(this.get('traits')); |
|||
this.set('traits', traits); |
|||
this.initToolbar(); |
|||
|
|||
// Normalize few properties from strings to arrays
|
|||
var toNormalize = ['stylable']; |
|||
toNormalize.forEach(function(name) { |
|||
var value = this.get(name); |
|||
|
|||
if (typeof value == 'string') { |
|||
var newValue = value.split(',').map(function(prop) { |
|||
return prop.trim(); |
|||
}); |
|||
this.set(name, newValue); |
|||
} |
|||
}, this); |
|||
|
|||
this.init(); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize callback |
|||
*/ |
|||
init: function () {}, |
|||
|
|||
/** |
|||
* Script updated |
|||
*/ |
|||
scriptUpdated: function() { |
|||
this.set('scriptUpdated', 1); |
|||
}, |
|||
|
|||
/** |
|||
* Init toolbar |
|||
*/ |
|||
initToolbar: function () { |
|||
var model = this; |
|||
if(!model.get('toolbar')) { |
|||
var tb = []; |
|||
if(model.get('draggable')) { |
|||
tb.push({ |
|||
attributes: {class: 'fa fa-arrows'}, |
|||
command: 'tlb-move', |
|||
}); |
|||
} |
|||
if(model.get('copyable')) { |
|||
tb.push({ |
|||
attributes: {class: 'fa fa-clone'}, |
|||
command: 'tlb-clone', |
|||
}); |
|||
} |
|||
if(model.get('removable')) { |
|||
tb.push({ |
|||
attributes: {class: 'fa fa-trash-o'}, |
|||
command: 'tlb-delete', |
|||
}); |
|||
} |
|||
model.set('toolbar', tb); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Load traits |
|||
* @param {Array} traits |
|||
* @private |
|||
*/ |
|||
loadTraits: function(traits) { |
|||
var trt = new Traits(); |
|||
trt.setTarget(this); |
|||
trt.add(traits); |
|||
this.set('traits', trt); |
|||
}, |
|||
|
|||
/** |
|||
* Normalize input classes from array to array of objects |
|||
* @param {Array} arr |
|||
* @return {Array} |
|||
* @private |
|||
*/ |
|||
normalizeClasses: function(arr) { |
|||
var res = []; |
|||
|
|||
if(!this.sm.get) |
|||
return; |
|||
|
|||
var clm = this.sm.get('SelectorManager'); |
|||
if(!clm) |
|||
return; |
|||
|
|||
arr.forEach(function(val){ |
|||
var name = ''; |
|||
|
|||
if(typeof val === 'string') |
|||
name = val; |
|||
else |
|||
name = val.name; |
|||
|
|||
var model = clm.add(name); |
|||
res.push(model); |
|||
}); |
|||
return res; |
|||
}, |
|||
|
|||
/** |
|||
* Override original clone method |
|||
* @private |
|||
*/ |
|||
clone: function(reset) { |
|||
var attr = _.clone(this.attributes), |
|||
comp = this.get('components'), |
|||
traits = this.get('traits'), |
|||
cls = this.get('classes'); |
|||
attr.components = []; |
|||
attr.classes = []; |
|||
attr.traits = []; |
|||
|
|||
comp.each(function(md,i) { |
|||
attr.components[i] = md.clone(1); |
|||
}); |
|||
traits.each(function(md, i) { |
|||
attr.traits[i] = md.clone(); |
|||
defaults: { |
|||
// HTML tag of the component
|
|||
tagName: 'div', |
|||
|
|||
// Component type, eg. 'text', 'image', 'video', etc.
|
|||
type: '', |
|||
|
|||
// True if the component is removable from the canvas
|
|||
removable: true, |
|||
|
|||
// Indicates if it's possible to drag the component inside other
|
|||
// Tip: Indicate an array of selectors where it could be dropped inside
|
|||
draggable: true, |
|||
|
|||
// Indicates if it's possible to drop other components inside
|
|||
// Tip: Indicate an array of selectors which could be dropped inside
|
|||
droppable: true, |
|||
|
|||
// Set false if don't want to see the badge (with the name) over the component
|
|||
badgable: true, |
|||
|
|||
// True if it's possible to style it
|
|||
// Tip: Indicate an array of CSS properties which is possible to style
|
|||
stylable: true, |
|||
|
|||
// Highlightable with 'dotted' style if true
|
|||
highlightable: true, |
|||
|
|||
// True if it's possible to clone the component
|
|||
copyable: true, |
|||
|
|||
// Indicates if it's possible to resize the component (at the moment implemented only on Image Components)
|
|||
resizable: false, |
|||
|
|||
// Allow to edit the content of the component (used on Text components)
|
|||
editable: false, |
|||
|
|||
// Hide the component inside Layers
|
|||
hiddenLayer: false, |
|||
|
|||
// This property is used by the HTML exporter as void elements do not
|
|||
// have closing tag, eg. <br/>, <hr/>, etc.
|
|||
void: false, |
|||
|
|||
// Indicates if the component is in some CSS state like ':hover', ':active', etc.
|
|||
state: '', |
|||
|
|||
// State, eg. 'selected'
|
|||
status: '', |
|||
|
|||
// Content of the component (not escaped) which will be appended before children rendering
|
|||
content: '', |
|||
|
|||
// Component related style
|
|||
style: {}, |
|||
|
|||
// Key-value object of the component's attributes
|
|||
attributes: '', |
|||
|
|||
// Array of classes
|
|||
classes: '', |
|||
|
|||
// Component's javascript
|
|||
script: '', |
|||
|
|||
// Traits
|
|||
traits: ['id', 'title'], |
|||
|
|||
/** |
|||
* Set an array of items to show up inside the toolbar (eg. move, clone, delete) |
|||
* when the component is selected |
|||
* toolbar: [{ |
|||
* attributes: {class: 'fa fa-arrows'}, |
|||
* command: 'tlb-move', |
|||
* },{ |
|||
* attributes: {class: 'fa fa-clone'}, |
|||
* command: 'tlb-clone', |
|||
* }] |
|||
*/ |
|||
toolbar: null, |
|||
|
|||
// TODO
|
|||
previousModel: '', |
|||
mirror: '', |
|||
}, |
|||
|
|||
initialize(o, opt) { |
|||
// Check void elements
|
|||
if(opt && opt.config && opt.config.voidElements.indexOf(this.get('tagName')) >= 0) |
|||
this.set('void', true); |
|||
|
|||
this.opt = opt; |
|||
this.sm = opt ? opt.sm || {} : {}; |
|||
this.config = o || {}; |
|||
this.defaultC = this.config.components || []; |
|||
this.defaultCl = this.normalizeClasses(this.get('classes') || this.config.classes || []); |
|||
this.components = new Components(this.defaultC, opt); |
|||
this.components.parent = this; |
|||
this.listenTo(this, 'change:script', this.scriptUpdated); |
|||
this.set('attributes', this.get('attributes') || {}); |
|||
this.set('components', this.components); |
|||
this.set('classes', new Selectors(this.defaultCl)); |
|||
var traits = new Traits(); |
|||
traits.setTarget(this); |
|||
traits.add(this.get('traits')); |
|||
this.set('traits', traits); |
|||
this.initToolbar(); |
|||
|
|||
// Normalize few properties from strings to arrays
|
|||
var toNormalize = ['stylable']; |
|||
toNormalize.forEach(function(name) { |
|||
var value = this.get(name); |
|||
|
|||
if (typeof value == 'string') { |
|||
var newValue = value.split(',').map(prop => prop.trim()); |
|||
this.set(name, newValue); |
|||
} |
|||
}, this); |
|||
|
|||
this.init(); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize callback |
|||
*/ |
|||
init() {}, |
|||
|
|||
/** |
|||
* Script updated |
|||
*/ |
|||
scriptUpdated() { |
|||
this.set('scriptUpdated', 1); |
|||
}, |
|||
|
|||
/** |
|||
* Init toolbar |
|||
*/ |
|||
initToolbar() { |
|||
var model = this; |
|||
if(!model.get('toolbar')) { |
|||
var tb = []; |
|||
if(model.get('draggable')) { |
|||
tb.push({ |
|||
attributes: {class: 'fa fa-arrows'}, |
|||
command: 'tlb-move', |
|||
}); |
|||
cls.each(function(md,i) { |
|||
attr.classes[i] = md.get('name'); |
|||
} |
|||
if(model.get('copyable')) { |
|||
tb.push({ |
|||
attributes: {class: 'fa fa-clone'}, |
|||
command: 'tlb-clone', |
|||
}); |
|||
|
|||
attr.status = ''; |
|||
attr.view = ''; |
|||
|
|||
if(reset){ |
|||
this.opt.collection = null; |
|||
} |
|||
|
|||
return new this.constructor(attr, this.opt); |
|||
}, |
|||
|
|||
/** |
|||
* Get name of the component |
|||
* @return {string} |
|||
* @private |
|||
* */ |
|||
getName: function() { |
|||
if(!this.name){ |
|||
var id = this.cid.replace(/\D/g,''), |
|||
type = this.get('type'); |
|||
var tag = this.get('tagName'); |
|||
tag = tag == 'div' ? 'box' : tag; |
|||
tag = type ? type : tag; |
|||
this.name = tag.charAt(0).toUpperCase() + tag.slice(1); |
|||
} |
|||
return this.name; |
|||
}, |
|||
|
|||
/** |
|||
* Return HTML string of the component |
|||
* @param {Object} opts Options |
|||
* @return {string} HTML string |
|||
* @private |
|||
*/ |
|||
toHTML: function(opts) { |
|||
var code = ''; |
|||
var m = this; |
|||
var tag = m.get('tagName'), |
|||
sTag = m.get('void'), |
|||
attrId = ''; |
|||
// Build the string of attributes
|
|||
var strAttr = ''; |
|||
var attr = this.getAttrToHTML(); |
|||
for(var prop in attr){ |
|||
var val = attr[prop]; |
|||
strAttr += typeof val !== undefined && val !== '' ? |
|||
' ' + prop + '="' + val + '"' : ''; |
|||
} |
|||
// Build the string of classes
|
|||
var strCls = ''; |
|||
m.get('classes').each(function(m){ |
|||
strCls += ' ' + m.get('name'); |
|||
} |
|||
if(model.get('removable')) { |
|||
tb.push({ |
|||
attributes: {class: 'fa fa-trash-o'}, |
|||
command: 'tlb-delete', |
|||
}); |
|||
strCls = strCls !== '' ? ' class="' + strCls.trim() + '"' : ''; |
|||
|
|||
// If style is not empty I need an ID attached to the component
|
|||
// TODO: need to refactor in case of 'ID Trait'
|
|||
if(!_.isEmpty(m.get('style'))) |
|||
attrId = ' id="' + m.cid + '" '; |
|||
} |
|||
model.set('toolbar', tb); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Load traits |
|||
* @param {Array} traits |
|||
* @private |
|||
*/ |
|||
loadTraits(traits) { |
|||
var trt = new Traits(); |
|||
trt.setTarget(this); |
|||
trt.add(traits); |
|||
this.set('traits', trt); |
|||
}, |
|||
|
|||
/** |
|||
* Normalize input classes from array to array of objects |
|||
* @param {Array} arr |
|||
* @return {Array} |
|||
* @private |
|||
*/ |
|||
normalizeClasses(arr) { |
|||
var res = []; |
|||
|
|||
if(!this.sm.get) |
|||
return; |
|||
|
|||
var clm = this.sm.get('SelectorManager'); |
|||
if(!clm) |
|||
return; |
|||
|
|||
arr.forEach(val => { |
|||
var name = ''; |
|||
|
|||
if(typeof val === 'string') |
|||
name = val; |
|||
else |
|||
name = val.name; |
|||
|
|||
var model = clm.add(name); |
|||
res.push(model); |
|||
}); |
|||
return res; |
|||
}, |
|||
|
|||
/** |
|||
* Override original clone method |
|||
* @private |
|||
*/ |
|||
clone(reset) { |
|||
var attr = _.clone(this.attributes), |
|||
comp = this.get('components'), |
|||
traits = this.get('traits'), |
|||
cls = this.get('classes'); |
|||
attr.components = []; |
|||
attr.classes = []; |
|||
attr.traits = []; |
|||
|
|||
comp.each((md, i) => { |
|||
attr.components[i] = md.clone(1); |
|||
}); |
|||
traits.each((md, i) => { |
|||
attr.traits[i] = md.clone(); |
|||
}); |
|||
cls.each((md, i) => { |
|||
attr.classes[i] = md.get('name'); |
|||
}); |
|||
|
|||
code += '<' + tag + strCls + attrId + strAttr + (sTag ? '/' : '') + '>' + m.get('content'); |
|||
attr.status = ''; |
|||
attr.view = ''; |
|||
|
|||
if(reset){ |
|||
this.opt.collection = null; |
|||
} |
|||
|
|||
return new this.constructor(attr, this.opt); |
|||
}, |
|||
|
|||
/** |
|||
* Get name of the component |
|||
* @return {string} |
|||
* @private |
|||
* */ |
|||
getName() { |
|||
if(!this.name){ |
|||
var id = this.cid.replace(/\D/g,''), |
|||
type = this.get('type'); |
|||
var tag = this.get('tagName'); |
|||
tag = tag == 'div' ? 'box' : tag; |
|||
tag = type ? type : tag; |
|||
this.name = tag.charAt(0).toUpperCase() + tag.slice(1); |
|||
} |
|||
return this.name; |
|||
}, |
|||
|
|||
/** |
|||
* Return HTML string of the component |
|||
* @param {Object} opts Options |
|||
* @return {string} HTML string |
|||
* @private |
|||
*/ |
|||
toHTML(opts) { |
|||
var code = ''; |
|||
var m = this; |
|||
var tag = m.get('tagName'), |
|||
sTag = m.get('void'), |
|||
attrId = ''; |
|||
// Build the string of attributes
|
|||
var strAttr = ''; |
|||
var attr = this.getAttrToHTML(); |
|||
for(var prop in attr){ |
|||
var val = attr[prop]; |
|||
strAttr += typeof val !== undefined && val !== '' ? |
|||
' ' + prop + '="' + val + '"' : ''; |
|||
} |
|||
// Build the string of classes
|
|||
var strCls = ''; |
|||
m.get('classes').each(m => { |
|||
strCls += ' ' + m.get('name'); |
|||
}); |
|||
strCls = strCls !== '' ? ' class="' + strCls.trim() + '"' : ''; |
|||
|
|||
m.get('components').each(function(m) { |
|||
code += m.toHTML(); |
|||
}); |
|||
// If style is not empty I need an ID attached to the component
|
|||
// TODO: need to refactor in case of 'ID Trait'
|
|||
if(!_.isEmpty(m.get('style'))) |
|||
attrId = ' id="' + m.cid + '" '; |
|||
|
|||
if(!sTag) |
|||
code += '</'+tag+'>'; |
|||
|
|||
return code; |
|||
}, |
|||
|
|||
/** |
|||
* Returns object of attributes for HTML |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getAttrToHTML: function() { |
|||
var attr = this.get('attributes') || {}; |
|||
delete attr.style; |
|||
return attr; |
|||
}, |
|||
|
|||
/** |
|||
* Return a shallow copy of the model's attributes for JSON |
|||
* stringification. |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
toJSON: function() { |
|||
var obj = Backbone.Model.prototype.toJSON.apply(this, arguments); |
|||
var scriptStr = this.getScriptString(); |
|||
|
|||
if (scriptStr) { |
|||
obj.script = scriptStr; |
|||
} |
|||
|
|||
return obj; |
|||
}, |
|||
|
|||
/** |
|||
* Return script in string format, cleans 'function() {..' from scripts |
|||
* if it's a function |
|||
* @param {string|Function} script |
|||
* @return {string} |
|||
* @private |
|||
*/ |
|||
getScriptString: function (script) { |
|||
var scr = script || this.get('script'); |
|||
|
|||
// Need to cast script functions to string
|
|||
if (typeof scr == 'function') { |
|||
var scrStr = scr.toString().trim(); |
|||
scrStr = scrStr.replace(/^function\s?\(\)\s?\{/, ''); |
|||
scrStr = scrStr.replace(/\}$/, ''); |
|||
scr = scrStr; |
|||
} |
|||
|
|||
return scr; |
|||
} |
|||
code += '<' + tag + strCls + attrId + strAttr + (sTag ? '/' : '') + '>' + m.get('content'); |
|||
|
|||
},{ |
|||
m.get('components').each(m => { |
|||
code += m.toHTML(); |
|||
}); |
|||
|
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent: function(el) { |
|||
return {tagName: el.tagName ? el.tagName.toLowerCase() : ''}; |
|||
}, |
|||
if(!sTag) |
|||
code += '</'+tag+'>'; |
|||
|
|||
return code; |
|||
}, |
|||
|
|||
/** |
|||
* Returns object of attributes for HTML |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getAttrToHTML() { |
|||
var attr = this.get('attributes') || {}; |
|||
delete attr.style; |
|||
return attr; |
|||
}, |
|||
|
|||
/** |
|||
* Return a shallow copy of the model's attributes for JSON |
|||
* stringification. |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
toJSON(...args) { |
|||
var obj = Backbone.Model.prototype.toJSON.apply(this, args); |
|||
var scriptStr = this.getScriptString(); |
|||
|
|||
if (scriptStr) { |
|||
obj.script = scriptStr; |
|||
} |
|||
|
|||
return obj; |
|||
}, |
|||
|
|||
/** |
|||
* Return script in string format, cleans 'function() {..' from scripts |
|||
* if it's a function |
|||
* @param {string|Function} script |
|||
* @return {string} |
|||
* @private |
|||
*/ |
|||
getScriptString(script) { |
|||
var scr = script || this.get('script'); |
|||
|
|||
// Need to cast script functions to string
|
|||
if (typeof scr == 'function') { |
|||
var scrStr = scr.toString().trim(); |
|||
scrStr = scrStr.replace(/^function\s?\(\)\s?\{/, ''); |
|||
scrStr = scrStr.replace(/\}$/, ''); |
|||
scr = scrStr; |
|||
} |
|||
|
|||
return scr; |
|||
} |
|||
|
|||
},{ |
|||
|
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent(el) { |
|||
return {tagName: el.tagName ? el.tagName.toLowerCase() : ''}; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,103 +1,101 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
var Component = require('./Component'); |
|||
|
|||
return Component.extend({ |
|||
module.exports = Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'image', |
|||
tagName: 'img', |
|||
src: '', |
|||
void: 1, |
|||
droppable: false, |
|||
resizable: true, |
|||
traits: ['alt'] |
|||
}), |
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'image', |
|||
tagName: 'img', |
|||
src: '', |
|||
void: 1, |
|||
droppable: false, |
|||
resizable: true, |
|||
traits: ['alt'] |
|||
}), |
|||
|
|||
initialize: function(o, opt) { |
|||
Component.prototype.initialize.apply(this, arguments); |
|||
var attr = this.get('attributes'); |
|||
if(attr.src) |
|||
this.set('src', attr.src); |
|||
}, |
|||
initialize(o, opt) { |
|||
Component.prototype.initialize.apply(this, arguments); |
|||
var attr = this.get('attributes'); |
|||
if(attr.src) |
|||
this.set('src', attr.src); |
|||
}, |
|||
|
|||
initToolbar: function() { |
|||
Component.prototype.initToolbar.apply(this, arguments); |
|||
initToolbar(...args) { |
|||
Component.prototype.initToolbar.apply(this, args); |
|||
|
|||
if (this.sm && this.sm.get) { |
|||
var cmd = this.sm.get('Commands'); |
|||
var cmdName = 'image-editor'; |
|||
if (this.sm && this.sm.get) { |
|||
var cmd = this.sm.get('Commands'); |
|||
var cmdName = 'image-editor'; |
|||
|
|||
// Add Image Editor button only if the default command exists
|
|||
if (cmd.has(cmdName)) { |
|||
var tb = this.get('toolbar'); |
|||
tb.push({ |
|||
attributes: {class: 'fa fa-pencil'}, |
|||
command: cmdName, |
|||
}); |
|||
this.set('toolbar', tb); |
|||
} |
|||
} |
|||
}, |
|||
// Add Image Editor button only if the default command exists
|
|||
if (cmd.has(cmdName)) { |
|||
var tb = this.get('toolbar'); |
|||
tb.push({ |
|||
attributes: {class: 'fa fa-pencil'}, |
|||
command: cmdName, |
|||
}); |
|||
this.set('toolbar', tb); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Returns object of attributes for HTML |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getAttrToHTML: function() { |
|||
var attr = Component.prototype.getAttrToHTML.apply(this, arguments); |
|||
delete attr.onmousedown; |
|||
var src = this.get('src'); |
|||
if(src) |
|||
attr.src = src; |
|||
return attr; |
|||
}, |
|||
/** |
|||
* Returns object of attributes for HTML |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getAttrToHTML(...args) { |
|||
var attr = Component.prototype.getAttrToHTML.apply(this, args); |
|||
delete attr.onmousedown; |
|||
var src = this.get('src'); |
|||
if(src) |
|||
attr.src = src; |
|||
return attr; |
|||
}, |
|||
|
|||
/** |
|||
* Parse uri |
|||
* @param {string} uri |
|||
* @return {object} |
|||
* @private |
|||
*/ |
|||
parseUri: function(uri) { |
|||
var el = document.createElement('a'); |
|||
el.href = uri; |
|||
var query = {}; |
|||
var qrs = el.search.substring(1).split('&'); |
|||
for (var i = 0; i < qrs.length; i++) { |
|||
var pair = qrs[i].split('='); |
|||
var name = decodeURIComponent(pair[0]); |
|||
if(name) |
|||
query[name] = decodeURIComponent(pair[1]); |
|||
} |
|||
return { |
|||
hostname: el.hostname, |
|||
pathname: el.pathname, |
|||
protocol: el.protocol, |
|||
search: el.search, |
|||
hash: el.hash, |
|||
port: el.port, |
|||
query: query, |
|||
}; |
|||
}, |
|||
/** |
|||
* Parse uri |
|||
* @param {string} uri |
|||
* @return {object} |
|||
* @private |
|||
*/ |
|||
parseUri(uri) { |
|||
var el = document.createElement('a'); |
|||
el.href = uri; |
|||
var query = {}; |
|||
var qrs = el.search.substring(1).split('&'); |
|||
for (var i = 0; i < qrs.length; i++) { |
|||
var pair = qrs[i].split('='); |
|||
var name = decodeURIComponent(pair[0]); |
|||
if(name) |
|||
query[name] = decodeURIComponent(pair[1]); |
|||
} |
|||
return { |
|||
hostname: el.hostname, |
|||
pathname: el.pathname, |
|||
protocol: el.protocol, |
|||
search: el.search, |
|||
hash: el.hash, |
|||
port: el.port, |
|||
query, |
|||
}; |
|||
}, |
|||
|
|||
},{ |
|||
},{ |
|||
|
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent: function(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'IMG'){ |
|||
result = {type: 'image'}; |
|||
} |
|||
return result; |
|||
}, |
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'IMG'){ |
|||
result = {type: 'image'}; |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,42 +1,40 @@ |
|||
define(['./ComponentText'], |
|||
function (Component) { |
|||
var Component = require('./ComponentText'); |
|||
|
|||
return Component.extend({ |
|||
module.exports = Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'link', |
|||
tagName: 'a', |
|||
traits: ['title', 'href', 'target'], |
|||
}), |
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'link', |
|||
tagName: 'a', |
|||
traits: ['title', 'href', 'target'], |
|||
}), |
|||
|
|||
/** |
|||
* Returns object of attributes for HTML |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getAttrToHTML: function() { |
|||
var attr = Component.prototype.getAttrToHTML.apply(this, arguments); |
|||
delete attr.onmousedown; |
|||
return attr; |
|||
}, |
|||
/** |
|||
* Returns object of attributes for HTML |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
getAttrToHTML(...args) { |
|||
var attr = Component.prototype.getAttrToHTML.apply(this, args); |
|||
delete attr.onmousedown; |
|||
return attr; |
|||
}, |
|||
|
|||
},{ |
|||
},{ |
|||
|
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent: function(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'A'){ |
|||
result = {type: 'link'}; |
|||
} |
|||
return result; |
|||
}, |
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'A'){ |
|||
result = {type: 'link'}; |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,108 +1,107 @@ |
|||
define(['./ComponentImage', './Component'], |
|||
function (Component, OComponent) { |
|||
var Component = require('./ComponentImage'); |
|||
var OComponent = require('./Component'); |
|||
|
|||
return Component.extend({ |
|||
module.exports = Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'map', |
|||
void: 0, |
|||
mapUrl: 'https://maps.google.com/maps', |
|||
tagName: 'iframe', |
|||
mapType: 'q', |
|||
address: '', |
|||
zoom: '1', |
|||
attributes: {frameborder: 0}, |
|||
toolbar: OComponent.prototype.defaults.toolbar, |
|||
traits: [{ |
|||
label: 'Address', |
|||
name: 'address', |
|||
placeholder: 'eg. London, UK', |
|||
changeProp: 1, |
|||
},{ |
|||
type: 'select', |
|||
label: 'Map type', |
|||
name: 'mapType', |
|||
changeProp: 1, |
|||
options: [ |
|||
{value: 'q', name: 'Roadmap'}, |
|||
{value: 'w', name: 'Satellite'} |
|||
] |
|||
},{ |
|||
label: 'Zoom', |
|||
name: 'zoom', |
|||
type: 'range', |
|||
min: '1', |
|||
max: '20', |
|||
changeProp: 1, |
|||
}], |
|||
}), |
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'map', |
|||
void: 0, |
|||
mapUrl: 'https://maps.google.com/maps', |
|||
tagName: 'iframe', |
|||
mapType: 'q', |
|||
address: '', |
|||
zoom: '1', |
|||
attributes: {frameborder: 0}, |
|||
toolbar: OComponent.prototype.defaults.toolbar, |
|||
traits: [{ |
|||
label: 'Address', |
|||
name: 'address', |
|||
placeholder: 'eg. London, UK', |
|||
changeProp: 1, |
|||
},{ |
|||
type: 'select', |
|||
label: 'Map type', |
|||
name: 'mapType', |
|||
changeProp: 1, |
|||
options: [ |
|||
{value: 'q', name: 'Roadmap'}, |
|||
{value: 'w', name: 'Satellite'} |
|||
] |
|||
},{ |
|||
label: 'Zoom', |
|||
name: 'zoom', |
|||
type: 'range', |
|||
min: '1', |
|||
max: '20', |
|||
changeProp: 1, |
|||
}], |
|||
}), |
|||
|
|||
|
|||
initialize: function(o, opt) { |
|||
if(this.get('src')) |
|||
this.parseFromSrc(); |
|||
else |
|||
this.updateSrc(); |
|||
Component.prototype.initialize.apply(this, arguments); |
|||
this.listenTo(this, 'change:address change:zoom change:mapType', this.updateSrc); |
|||
}, |
|||
initialize(o, opt) { |
|||
if(this.get('src')) |
|||
this.parseFromSrc(); |
|||
else |
|||
this.updateSrc(); |
|||
Component.prototype.initialize.apply(this, arguments); |
|||
this.listenTo(this, 'change:address change:zoom change:mapType', this.updateSrc); |
|||
}, |
|||
|
|||
updateSrc: function() { |
|||
this.set('src', this.getMapUrl()); |
|||
}, |
|||
updateSrc() { |
|||
this.set('src', this.getMapUrl()); |
|||
}, |
|||
|
|||
/** |
|||
* Returns url of the map |
|||
* @return {string} |
|||
* @private |
|||
*/ |
|||
getMapUrl: function() { |
|||
var md = this; |
|||
var addr = md.get('address'); |
|||
var zoom = md.get('zoom'); |
|||
var type = md.get('mapType'); |
|||
var size = ''; |
|||
addr = addr ? '&q=' + addr : ''; |
|||
zoom = zoom ? '&z=' + zoom : ''; |
|||
type = type ? '&t=' + type : ''; |
|||
var result = md.get('mapUrl')+'?' + addr + zoom + type; |
|||
result += '&output=embed'; |
|||
return result; |
|||
}, |
|||
/** |
|||
* Returns url of the map |
|||
* @return {string} |
|||
* @private |
|||
*/ |
|||
getMapUrl() { |
|||
var md = this; |
|||
var addr = md.get('address'); |
|||
var zoom = md.get('zoom'); |
|||
var type = md.get('mapType'); |
|||
var size = ''; |
|||
addr = addr ? '&q=' + addr : ''; |
|||
zoom = zoom ? '&z=' + zoom : ''; |
|||
type = type ? '&t=' + type : ''; |
|||
var result = md.get('mapUrl')+'?' + addr + zoom + type; |
|||
result += '&output=embed'; |
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Set attributes by src string |
|||
* @private |
|||
*/ |
|||
parseFromSrc: function() { |
|||
var uri = this.parseUri(this.get('src')); |
|||
var qr = uri.query; |
|||
if(qr.q) |
|||
this.set('address', qr.q); |
|||
if(qr.z) |
|||
this.set('zoom', qr.z); |
|||
if(qr.t) |
|||
this.set('mapType', qr.t); |
|||
}, |
|||
/** |
|||
* Set attributes by src string |
|||
* @private |
|||
*/ |
|||
parseFromSrc() { |
|||
var uri = this.parseUri(this.get('src')); |
|||
var qr = uri.query; |
|||
if(qr.q) |
|||
this.set('address', qr.q); |
|||
if(qr.z) |
|||
this.set('zoom', qr.z); |
|||
if(qr.t) |
|||
this.set('mapType', qr.t); |
|||
}, |
|||
|
|||
},{ |
|||
},{ |
|||
|
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent: function(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'IFRAME' && |
|||
/maps\.google\.com/.test(el.src) ){ |
|||
result = {type: 'map', src: el.src}; |
|||
} |
|||
return result; |
|||
}, |
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'IFRAME' && |
|||
/maps\.google\.com/.test(el.src) ){ |
|||
result = {type: 'map', src: el.src}; |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,29 +1,27 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
var Component = require('./Component'); |
|||
|
|||
return Component.extend({ |
|||
module.exports = Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'script', |
|||
droppable: false, |
|||
draggable: false, |
|||
hiddenLayer: true, |
|||
}), |
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'script', |
|||
droppable: false, |
|||
draggable: false, |
|||
hiddenLayer: true, |
|||
}), |
|||
|
|||
}, { |
|||
}, { |
|||
|
|||
isComponent: function(el) { |
|||
if (el.tagName == 'SCRIPT') { |
|||
var result = {type: 'script'}; |
|||
isComponent(el) { |
|||
if (el.tagName == 'SCRIPT') { |
|||
var result = {type: 'script'}; |
|||
|
|||
if (el.src) { |
|||
result.src = el.src; |
|||
result.onload = el.onload; |
|||
} |
|||
if (el.src) { |
|||
result.src = el.src; |
|||
result.onload = el.onload; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
}, |
|||
return result; |
|||
} |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,91 +1,89 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
var Component = require('./Component'); |
|||
|
|||
return Component.extend({ |
|||
module.exports = Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'table', |
|||
tagName: 'table', |
|||
droppable: ['tr', 'tbody', 'thead', 'tfoot'], |
|||
columns: 3, |
|||
rows: 2, |
|||
/* |
|||
traits: [{ |
|||
label: 'Columns', |
|||
name: 'columns', |
|||
changeProp: 1, |
|||
},{ |
|||
label: 'Rows', |
|||
name: 'rows', |
|||
changeProp: 1, |
|||
}] |
|||
*/ |
|||
}), |
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'table', |
|||
tagName: 'table', |
|||
droppable: ['tr', 'tbody', 'thead', 'tfoot'], |
|||
columns: 3, |
|||
rows: 2, |
|||
/* |
|||
traits: [{ |
|||
label: 'Columns', |
|||
name: 'columns', |
|||
changeProp: 1, |
|||
},{ |
|||
label: 'Rows', |
|||
name: 'rows', |
|||
changeProp: 1, |
|||
}] |
|||
*/ |
|||
}), |
|||
|
|||
initialize: function(o, opt) { |
|||
Component.prototype.initialize.apply(this, arguments); |
|||
var components = this.get('components'); |
|||
var rows = this.get('rows'); |
|||
var columns = this.get('columns'); |
|||
initialize(o, opt) { |
|||
Component.prototype.initialize.apply(this, arguments); |
|||
var components = this.get('components'); |
|||
var rows = this.get('rows'); |
|||
var columns = this.get('columns'); |
|||
|
|||
// Init components if empty
|
|||
if(!components.length){ |
|||
var rowsToAdd = []; |
|||
// Init components if empty
|
|||
if(!components.length){ |
|||
var rowsToAdd = []; |
|||
|
|||
while(rows--){ |
|||
var columnsToAdd = []; |
|||
var clm = columns; |
|||
while(rows--){ |
|||
var columnsToAdd = []; |
|||
var clm = columns; |
|||
|
|||
while (clm--) { |
|||
columnsToAdd.push({ |
|||
type: 'cell', |
|||
classes: ['cell'] |
|||
}); |
|||
} |
|||
while (clm--) { |
|||
columnsToAdd.push({ |
|||
type: 'cell', |
|||
classes: ['cell'] |
|||
}); |
|||
} |
|||
|
|||
rowsToAdd.push({ |
|||
type: 'row', |
|||
classes: ['row'], |
|||
components: columnsToAdd |
|||
}); |
|||
} |
|||
components.add(rowsToAdd); |
|||
} |
|||
rowsToAdd.push({ |
|||
type: 'row', |
|||
classes: ['row'], |
|||
components: columnsToAdd |
|||
}); |
|||
} |
|||
components.add(rowsToAdd); |
|||
} |
|||
|
|||
// Clean table from non rows
|
|||
var rowsColl = []; |
|||
components.each(function(model){ |
|||
if(model.get('type') != 'row'){ |
|||
model.get('components').each(function(row) { |
|||
if(row.get('type') == 'row'){ |
|||
row.collection = components; |
|||
rowsColl.push(row); |
|||
} |
|||
}); |
|||
}else{ |
|||
rowsColl.push(model); |
|||
} |
|||
}); |
|||
components.reset(rowsColl); |
|||
}, |
|||
// Clean table from non rows
|
|||
var rowsColl = []; |
|||
components.each(model => { |
|||
if(model.get('type') != 'row'){ |
|||
model.get('components').each(row => { |
|||
if(row.get('type') == 'row'){ |
|||
row.collection = components; |
|||
rowsColl.push(row); |
|||
} |
|||
}); |
|||
}else{ |
|||
rowsColl.push(model); |
|||
} |
|||
}); |
|||
components.reset(rowsColl); |
|||
}, |
|||
|
|||
},{ |
|||
},{ |
|||
|
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent: function(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'TABLE'){ |
|||
result = {type: 'table'}; |
|||
} |
|||
return result; |
|||
}, |
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'TABLE'){ |
|||
result = {type: 'table'}; |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,35 +1,33 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
var Component = require('./Component'); |
|||
|
|||
return Component.extend({ |
|||
module.exports = Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'cell', |
|||
tagName: 'td', |
|||
draggable: ['tr'], |
|||
}), |
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'cell', |
|||
tagName: 'td', |
|||
draggable: ['tr'], |
|||
}), |
|||
|
|||
},{ |
|||
},{ |
|||
|
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent: function(el) { |
|||
var result = ''; |
|||
var tag = el.tagName; |
|||
if(tag == 'TD' || tag == 'TH'){ |
|||
result = { |
|||
type: 'cell', |
|||
tagName: tag.toLowerCase() |
|||
}; |
|||
} |
|||
return result; |
|||
}, |
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent(el) { |
|||
var result = ''; |
|||
var tag = el.tagName; |
|||
if(tag == 'TD' || tag == 'TH'){ |
|||
result = { |
|||
type: 'cell', |
|||
tagName: tag.toLowerCase() |
|||
}; |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,46 +1,44 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
var Component = require('./Component'); |
|||
|
|||
return Component.extend({ |
|||
module.exports = Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'row', |
|||
tagName: 'tr', |
|||
draggable: ['table', 'tbody', 'thead'], |
|||
droppable: ['th', 'td'] |
|||
}), |
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'row', |
|||
tagName: 'tr', |
|||
draggable: ['table', 'tbody', 'thead'], |
|||
droppable: ['th', 'td'] |
|||
}), |
|||
|
|||
initialize: function(o, opt) { |
|||
Component.prototype.initialize.apply(this, arguments); |
|||
initialize(o, opt) { |
|||
Component.prototype.initialize.apply(this, arguments); |
|||
|
|||
// Clean the row from non cell components
|
|||
var cells = []; |
|||
var components = this.get('components'); |
|||
components.each(function(model){ |
|||
if(model.get('type') == 'cell'){ |
|||
cells.push(model); |
|||
} |
|||
}); |
|||
components.reset(cells); |
|||
} |
|||
// Clean the row from non cell components
|
|||
var cells = []; |
|||
var components = this.get('components'); |
|||
components.each(model => { |
|||
if(model.get('type') == 'cell'){ |
|||
cells.push(model); |
|||
} |
|||
}); |
|||
components.reset(cells); |
|||
} |
|||
|
|||
},{ |
|||
},{ |
|||
|
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent: function(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'TR'){ |
|||
result = {type: 'row'}; |
|||
} |
|||
return result; |
|||
}, |
|||
/** |
|||
* Detect if the passed element is a valid component. |
|||
* In case the element is valid an object abstracted |
|||
* from the element will be returned |
|||
* @param {HTMLElement} |
|||
* @return {Object} |
|||
* @private |
|||
*/ |
|||
isComponent(el) { |
|||
var result = ''; |
|||
if(el.tagName == 'TR'){ |
|||
result = {type: 'row'}; |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,13 +1,11 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
var Component = require('./Component'); |
|||
|
|||
return Component.extend({ |
|||
module.exports = Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'text', |
|||
droppable: false, |
|||
editable: true, |
|||
}), |
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
type: 'text', |
|||
droppable: false, |
|||
editable: true, |
|||
}), |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -1,29 +1,27 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
var Component = require('./Component'); |
|||
|
|||
return Component.extend({ |
|||
module.exports = Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
droppable: false, |
|||
editable: true, |
|||
}), |
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
droppable: false, |
|||
editable: true, |
|||
}), |
|||
|
|||
toHTML: function() { |
|||
return this.get('content'); |
|||
}, |
|||
toHTML() { |
|||
return this.get('content'); |
|||
}, |
|||
|
|||
}, { |
|||
}, { |
|||
|
|||
isComponent: function(el) { |
|||
var result = ''; |
|||
if(el.nodeType === 3){ |
|||
result = { |
|||
type: 'textnode', |
|||
content: el.textContent |
|||
}; |
|||
} |
|||
return result; |
|||
}, |
|||
isComponent(el) { |
|||
var result = ''; |
|||
if(el.nodeType === 3){ |
|||
result = { |
|||
type: 'textnode', |
|||
content: el.textContent |
|||
}; |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
|
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue