mirror of https://github.com/artf/grapesjs.git
commit
69cfec68bd
180 changed files with 16426 additions and 0 deletions
@ -0,0 +1,7 @@ |
|||
.DS_Store |
|||
.settings/ |
|||
.project |
|||
|
|||
private/ |
|||
libs/ |
|||
node_modules/ |
|||
@ -0,0 +1,137 @@ |
|||
module.exports = function(grunt) { |
|||
|
|||
var appPath = 'bundle', |
|||
buildPath = 'dist', |
|||
configPath = 'config/require-config.js'; |
|||
|
|||
grunt.loadNpmTasks('grunt-contrib-watch'); |
|||
grunt.loadNpmTasks('grunt-contrib-sass'); |
|||
grunt.loadNpmTasks('grunt-contrib-uglify'); |
|||
grunt.loadNpmTasks('grunt-contrib-jshint'); |
|||
grunt.loadNpmTasks('grunt-contrib-requirejs'); |
|||
grunt.loadNpmTasks('grunt-contrib-connect'); |
|||
grunt.loadNpmTasks('grunt-mocha'); |
|||
|
|||
grunt.initConfig({ |
|||
appDir: appPath, |
|||
builtDir: buildPath, |
|||
pkg: grunt.file.readJSON("package.json"), |
|||
requirejs:{ |
|||
compile:{ |
|||
options: { |
|||
mainConfigFile: '<%= appDir %>/' + configPath, |
|||
appDir: '<%= appDir %>', |
|||
dir: '<%= builtDir %>', |
|||
baseUrl: './', |
|||
name: 'main', |
|||
removeCombined: true, |
|||
findNestedDependencies: true, |
|||
keepBuildDir: true, |
|||
inlineText: true, |
|||
optimize: 'none' |
|||
//paths: { "jquery": "empty:" }, //try to exclude
|
|||
} |
|||
} |
|||
}, |
|||
|
|||
jshint: { |
|||
all: [ |
|||
'Gruntfile.js', |
|||
'<%= appDir %>/**/*.js', |
|||
] |
|||
}, |
|||
|
|||
uglify: { |
|||
options: { |
|||
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> */' |
|||
}, |
|||
build:{ |
|||
files: { |
|||
'<%= builtDir %>/grapes.min.js': ['<%= builtDir %>/main.js'] |
|||
} |
|||
} |
|||
}, |
|||
|
|||
sass: { |
|||
dist: { |
|||
files: [{ |
|||
expand: true, |
|||
cwd: 'styles/scss', |
|||
src: ['**/*.scss'], |
|||
dest: 'styles/css', |
|||
ext: '.css' |
|||
}] |
|||
} |
|||
}, |
|||
|
|||
mocha: { |
|||
test: { |
|||
src: ['test/index.html'], |
|||
options: { log: true, }, |
|||
}, |
|||
}, |
|||
|
|||
connect: { |
|||
/* |
|||
app: { |
|||
options: { |
|||
port: 8001, |
|||
open: { |
|||
target: 'http://localhost:8001', |
|||
//appName: 'Firefox' // 'Google Chrome'
|
|||
} |
|||
} |
|||
}, |
|||
*/ |
|||
test: { |
|||
options: { |
|||
open: { |
|||
target: 'http://localhost:8000/test', |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
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
|
|||
} |
|||
} |
|||
|
|||
}); |
|||
|
|||
/** |
|||
* Need 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 and only for the pleasure of using separate config |
|||
* requirejs file. |
|||
* */ |
|||
grunt.registerTask('before-requirejs', function() { |
|||
//if(grunt.file.exists(buildPath))
|
|||
//grunt.file.delete(buildPath);
|
|||
grunt.file.mkdir(buildPath); |
|||
grunt.file.copy(appPath + '/' + configPath, buildPath + '/' + appPath + '/' + configPath); |
|||
}); |
|||
|
|||
grunt.registerTask('after-requirejs', function() { |
|||
//grunt.file.copy(buildPath + '/main.js', buildPath + '/main.min.js');
|
|||
}); |
|||
|
|||
grunt.registerTask('dev', ['connect', 'watch']); |
|||
|
|||
grunt.registerTask('test', ['mocha']); |
|||
|
|||
grunt.registerTask('deploy', ['jshint', 'before-requirejs', 'requirejs', 'after-requirejs', 'uglify']); |
|||
|
|||
grunt.registerTask('default', ['dev']); |
|||
|
|||
}; |
|||
@ -0,0 +1,27 @@ |
|||
# Grapes.js |
|||
|
|||
Copyright (c) Artur Arseniev |
|||
All rights reserved. |
|||
|
|||
Redistribution and use in source and binary forms, with or without modification, |
|||
are permitted provided that the following conditions are met: |
|||
|
|||
- Redistributions of source code must retain the above copyright notice, this |
|||
list of conditions and the following disclaimer. |
|||
- Redistributions in binary form must reproduce the above copyright notice, this |
|||
list of conditions and the following disclaimer in the documentation and/or |
|||
other materials provided with the distribution. |
|||
- Neither the name "Grapes" nor the names of its contributors may be |
|||
used to endorse or promote products derived from this software without |
|||
specific prior written permission. |
|||
|
|||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
|||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
|||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
|||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
@ -0,0 +1,29 @@ |
|||
# README # |
|||
|
|||
This README would normally document whatever steps are necessary to get your application up and running. |
|||
|
|||
### What is this repository for? ### |
|||
|
|||
* Quick summary |
|||
* Version |
|||
* [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo) |
|||
|
|||
### How do I get set up? ### |
|||
|
|||
* Summary of set up |
|||
* Configuration |
|||
* Dependencies |
|||
* Database configuration |
|||
* How to run tests |
|||
* Deployment instructions |
|||
|
|||
### Contribution guidelines ### |
|||
|
|||
* Writing tests |
|||
* Code review |
|||
* Other guidelines |
|||
|
|||
### Who do I talk to? ### |
|||
|
|||
* Repo owner or admin |
|||
* Other community or team contact |
|||
@ -0,0 +1,52 @@ |
|||
define(function () { |
|||
return { |
|||
|
|||
// Style prefix
|
|||
stylePrefix : 'am-', |
|||
|
|||
// Default assets
|
|||
assets : [], |
|||
|
|||
// Indicates which storage to use. Available: local | remote
|
|||
storageType : 'local', |
|||
|
|||
// The name that will be used to identify assets inside storage.
|
|||
// If empty will be used: prefix + 'assets'
|
|||
storageName : 'assets', |
|||
|
|||
// Where store remote assets
|
|||
urlStore : 'http://localhost/assets/store', |
|||
|
|||
// Where fetch remote assets
|
|||
urlLoad : 'http://localhost/assets/load', |
|||
|
|||
// Custom parameters to pass with set request
|
|||
paramsStore : {}, |
|||
|
|||
// Custom parameters to pass with get request
|
|||
paramsLoad : {}, |
|||
|
|||
// Callback before request
|
|||
beforeSend : function(jqXHR,settings){}, |
|||
|
|||
// Callback after request
|
|||
onComplete : function(jqXHR,status){}, |
|||
|
|||
// Url where uploads will be send
|
|||
urlUpload : 'http://localhost/assets/upload', |
|||
|
|||
// Text on upload input
|
|||
uploadText : 'Drop files here or click to upload', |
|||
|
|||
// Disable upload input
|
|||
disableUpload : false, |
|||
|
|||
// Store assets data where the new one is added or deleted
|
|||
storeOnChange : true, |
|||
|
|||
// It could be useful avoid to send other requests, for saving assets,
|
|||
// after each upload because the uploader script has already done it
|
|||
storeAfterUpload : false, |
|||
|
|||
}; |
|||
}); |
|||
@ -0,0 +1,70 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class AssetManager |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
var AssetManager = function(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Assets = require('./model/Assets'), |
|||
AssetsView = require('./view/AssetsView'), |
|||
FileUpload = require('./view/FileUploader'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.assets = new Assets(c.assets); |
|||
var obj = { |
|||
collection : this.assets, |
|||
config : c, |
|||
}; |
|||
|
|||
this.am = new AssetsView(obj); |
|||
this.fu = new FileUpload(obj); |
|||
}; |
|||
|
|||
AssetManager.prototype = { |
|||
|
|||
/** |
|||
* Get collection of assets |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
getAssets : function(){ |
|||
return this.assets; |
|||
}, |
|||
|
|||
/** |
|||
* Set new target |
|||
* @param {Object} m Model |
|||
* |
|||
* @return void |
|||
* */ |
|||
setTarget : function(m){ |
|||
this.am.collection.target = m; |
|||
}, |
|||
|
|||
/** |
|||
* Set callback after asset was selected |
|||
* @param {Object} f Callback function |
|||
* |
|||
* @return void |
|||
* */ |
|||
onSelect : function(f){ |
|||
this.am.collection.onSelect = f; |
|||
}, |
|||
|
|||
render : function(){ |
|||
if(!this.rendered) |
|||
this.rendered = this.am.render().$el.add(this.fu.render().$el); |
|||
return this.rendered; |
|||
}, |
|||
}; |
|||
|
|||
return AssetManager; |
|||
}); |
|||
@ -0,0 +1,36 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class Asset |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
type: 'none', //Type of the asset
|
|||
src: '', //Location
|
|||
}, |
|||
|
|||
initialize: function(options) { |
|||
this.options = options || {}; |
|||
}, |
|||
|
|||
/** |
|||
* Get filename of the asset |
|||
* |
|||
* @return {String} |
|||
* */ |
|||
getFilename: function(){ |
|||
return this.get('src').split('/').pop(); |
|||
}, |
|||
|
|||
/** |
|||
* Get extension of the asset |
|||
* |
|||
* @return {String} |
|||
* */ |
|||
getExtension: function(){ |
|||
return this.getFilename().split('.').pop(); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,18 @@ |
|||
define(['backbone', './Asset'], |
|||
function (Backbone, Asset) { |
|||
/** |
|||
* @class AssetImage |
|||
* */ |
|||
return Asset.extend({ |
|||
|
|||
defaults: _.extend({},Asset.prototype.defaults, |
|||
{ |
|||
type: 'image', |
|||
unitDim: 'px', |
|||
height: 0, |
|||
width: 0, |
|||
} |
|||
), |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,11 @@ |
|||
define(['backbone','./Asset'], |
|||
function (Backbone, Asset) { |
|||
/** |
|||
* @class Assets |
|||
* */ |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Asset, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,7 @@ |
|||
<div id="<%= pfx %>preview" style="background-image: url(<%= src %>);"></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> |
|||
@ -0,0 +1,5 @@ |
|||
<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> |
|||
@ -0,0 +1,89 @@ |
|||
define(['./AssetView','text!./../template/assetImage.html'], |
|||
function (AssetView, assetTemplate) { |
|||
/** |
|||
* @class AssetImageView |
|||
* */ |
|||
return AssetView.extend({ |
|||
|
|||
events:{ |
|||
'click' : 'selected', |
|||
'dblclick' : 'chosen', |
|||
}, |
|||
|
|||
template: _.template(assetTemplate), |
|||
|
|||
initialize: function(o) { |
|||
AssetView.prototype.initialize.apply(this, arguments); |
|||
this.className += ' ' + this.pfx + 'asset-image'; |
|||
this.events['click #' + this.pfx + 'close'] = 'removeItem'; |
|||
}, |
|||
|
|||
/** |
|||
* Trigger when asset is been selected |
|||
* |
|||
* @return void |
|||
* */ |
|||
selected: function(){ |
|||
this.model.collection.trigger('deselectAll'); |
|||
this.$el.addClass(this.pfx + 'highlight'); |
|||
|
|||
this.updateTarget(this.model.get('src')); |
|||
}, |
|||
|
|||
/** |
|||
* Trigger when asset is been chosen (double clicked) |
|||
* |
|||
* @return void |
|||
* */ |
|||
chosen: function(){ |
|||
this.updateTarget(this.model.get('src')); |
|||
var f = this.model.collection.onSelect; |
|||
if(f && typeof f == 'function'){ |
|||
f(this.model); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Update target if exists |
|||
* @param {String} v Value |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateTarget: function(v){ |
|||
var target = this.model.collection.target; |
|||
if(target && target.set){ |
|||
var attr = _.clone( target.get('attributes') ); |
|||
attr['class'] = []; |
|||
target.set('attributes', attr ); |
|||
target.set('src', v ); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Remove asset from collection |
|||
* |
|||
* @return void |
|||
* */ |
|||
removeItem: function(e){ |
|||
e.stopPropagation(); |
|||
this.model.collection.remove(this.model); |
|||
}, |
|||
|
|||
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 |
|||
})); |
|||
this.$el.attr('class', this.className); |
|||
return this; |
|||
}, |
|||
}); |
|||
}); |
|||
@ -0,0 +1,17 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class AssetView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
this.options = o; |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix; |
|||
this.className = this.pfx + 'asset'; |
|||
this.listenTo( this.model, 'destroy remove', this.remove ); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,122 @@ |
|||
define(['backbone', './AssetView', './AssetImageView', './FileUploader'], |
|||
function (Backbone, AssetView, AssetImageView, FileUploader) { |
|||
/** |
|||
* @class AssetsView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
this.options = o; |
|||
this.config = o.config; |
|||
this.pfx = this.config.stylePrefix; |
|||
this.listenTo( this.collection, 'add', this.addToAsset ); |
|||
this.listenTo( this.collection, 'deselectAll', this.deselectAll ); |
|||
this.className = this.pfx + 'assets'; |
|||
|
|||
// Check if storage is required and if Storage Manager is available
|
|||
if(this.config.stm && this.config.storageType !== ''){ |
|||
var type = this.config.storageType; |
|||
this.provider = this.config.stm.getProvider(type); |
|||
this.storeName = this.config.storageName ? this.config.storageName : this.className; |
|||
if(this.provider){ |
|||
// Create new instance of provider
|
|||
this.storagePrv = this.provider.clone().set(this.config); |
|||
this.collection.reset(); |
|||
this.collection.add(this.load()); |
|||
if(this.config.storeOnChange){ |
|||
var ev = 'remove' + (this.config.storeAfterUpload ? ' add' : ''); |
|||
this.listenTo(this.collection, ev, this.store); |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Store collection |
|||
* |
|||
* @return void |
|||
* */ |
|||
store: function(){ |
|||
if(this.storagePrv) |
|||
this.storagePrv.store(this.storeName, JSON.stringify(this.collection.toJSON()) ); |
|||
}, |
|||
|
|||
/** |
|||
* Load collection |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
load: function(){ |
|||
var result = null; |
|||
if(this.storagePrv) |
|||
result = this.storagePrv.load(this.storeName); |
|||
if(typeof result !== 'object'){ |
|||
try{ |
|||
result = JSON.parse(result); |
|||
}catch(err){ |
|||
console.warn(err); |
|||
} |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Add asset to collection |
|||
* */ |
|||
addToAsset: function(model){ |
|||
this.addAsset(model); |
|||
}, |
|||
|
|||
/** |
|||
* Add new asset to collection |
|||
* @param Object Model |
|||
* @param Object Fragment collection |
|||
* |
|||
* @return Object Object created |
|||
* */ |
|||
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{ |
|||
this.$el.prepend(rendered); |
|||
} |
|||
|
|||
return rendered; |
|||
}, |
|||
|
|||
/** |
|||
* Deselect all assets |
|||
* |
|||
* @return void |
|||
* */ |
|||
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.append(fragment); |
|||
this.$el.attr('class', this.className); |
|||
|
|||
return this; |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,102 @@ |
|||
define(['backbone', 'text!./../template/fileUploader.html'], |
|||
function (Backbone, fileUploaderTemplate) { |
|||
/** |
|||
* @class FileUploader |
|||
* */ |
|||
|
|||
return Backbone.View.extend({ |
|||
|
|||
template: _.template(fileUploaderTemplate), |
|||
|
|||
events: {}, |
|||
|
|||
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.disableUpload; |
|||
this.events['change #' + this.uploadId] = 'uploadFile'; |
|||
}, |
|||
|
|||
/** |
|||
* Upload files |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
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.urlUpload, //this.config.urlUpload
|
|||
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
|
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* Make input file droppable |
|||
* |
|||
* @return void |
|||
* */ |
|||
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; |
|||
}; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
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; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,10 @@ |
|||
define(function () { |
|||
return { |
|||
|
|||
stylePrefix : 'cv-', |
|||
|
|||
// Coming soon
|
|||
rulers : false, |
|||
|
|||
}; |
|||
}); |
|||
@ -0,0 +1,60 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class Canvas |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
var Canvas = function(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Canvas = require('./model/Canvas'), |
|||
CanvasView = require('./view/CanvasView'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.canvas = new Canvas(config); |
|||
var obj = { |
|||
model : this.canvas, |
|||
config : c, |
|||
}; |
|||
|
|||
this.CanvasView = new CanvasView(obj); |
|||
}; |
|||
|
|||
Canvas.prototype = { |
|||
/** |
|||
* Add wrapper |
|||
* @param {Object} wrp Wrapper |
|||
* |
|||
* */ |
|||
setWrapper : function(wrp) |
|||
{ |
|||
this.canvas.set('wrapper', wrp); |
|||
}, |
|||
|
|||
/** |
|||
* Get wrapper |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
getWrapper : function() |
|||
{ |
|||
return this.canvas.get('wrapper').getComponent(); |
|||
}, |
|||
|
|||
/** |
|||
* Render canvas |
|||
* */ |
|||
render : function() |
|||
{ |
|||
return this.CanvasView.render().$el; |
|||
}, |
|||
}; |
|||
|
|||
return Canvas; |
|||
}); |
|||
@ -0,0 +1,14 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
/** |
|||
* @class Canvas |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
wrapper : '', |
|||
rulers : false, |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,25 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
/** |
|||
* @class CanvasView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
id: 'canvas', |
|||
|
|||
initialize: function(o) { |
|||
this.config = o.config; |
|||
this.className = this.config.stylePrefix + 'canvas'; |
|||
}, |
|||
|
|||
render: function() { |
|||
this.wrapper = this.model.get('wrapper'); |
|||
if(this.wrapper && typeof this.wrapper.render == 'function'){ |
|||
this.$el.append( this.wrapper.render() ); |
|||
} |
|||
this.$el.attr('class', this.className); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,6 @@ |
|||
define(function () { |
|||
return { |
|||
// Style prefix
|
|||
stylePrefix : 'cm-', |
|||
}; |
|||
}); |
|||
@ -0,0 +1,254 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class CodeManager |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function CodeManager(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
gInterface = require('./model/GeneratorInterface'), |
|||
gHtml = require('./model/HtmlGenerator'), |
|||
gCss = require('./model/CssGenerator'), |
|||
gJson = require('./model/JsonGenerator'), |
|||
eInterface = require('./model/EditorInterface'), |
|||
eCM = require('./model/CodeMirrorEditor'), |
|||
editorView = require('./view/EditorView'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.gi = new gInterface(); |
|||
this.generators = {}; |
|||
this.defaultGenerators = {}; |
|||
this.currentGenerator = null; |
|||
|
|||
this.ei = new eInterface(); |
|||
this.editors = {}; |
|||
this.defaultEditors = {}; |
|||
this.currentEditor = null; |
|||
|
|||
var geHtml = new gHtml(), |
|||
geCss = new gCss(), |
|||
geJson = new gJson(), |
|||
edCM = new eCM(); |
|||
|
|||
this.defaultGenerators[geHtml.getId()] = geHtml; |
|||
this.defaultGenerators[geCss.getId()] = geCss; |
|||
this.defaultGenerators[geJson.getId()] = geJson; |
|||
|
|||
this.defaultEditors[edCM.getId()] = edCM; |
|||
|
|||
this.EditorView = editorView; |
|||
this.config = c; |
|||
} |
|||
|
|||
CodeManager.prototype = { |
|||
|
|||
/** |
|||
* Add new code generator |
|||
* @param {GeneratorInterface} generator |
|||
* |
|||
* @return this |
|||
* */ |
|||
addGenerator : function(generator) |
|||
{ |
|||
// Check interface implementation
|
|||
for (var method in this.gi) |
|||
if(!generator[method]){ |
|||
console.warn("addGenerator: method '"+ method +"' was not found"); |
|||
return; |
|||
} |
|||
|
|||
var id = generator.getId(); |
|||
this.generators[id] = generator; |
|||
|
|||
if(!this.currentGenerator) |
|||
this.currentGenerator = id; |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns generator |
|||
* @param {String}|{Integer} id Generator ID |
|||
* |
|||
* @return {GeneratorInterface}|null |
|||
* */ |
|||
getGenerator : function(id) |
|||
{ |
|||
if(id && this.generators[id]) |
|||
generator = this.generators[id]; |
|||
|
|||
return generator ? generator : null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns generators |
|||
* |
|||
* @return {Array} |
|||
* */ |
|||
getGenerators : function() |
|||
{ |
|||
return this.generators; |
|||
}, |
|||
|
|||
/** |
|||
* Get current generator |
|||
* |
|||
* @return {GeneratorInterface} |
|||
* */ |
|||
getCurrentGenerator : function() |
|||
{ |
|||
if(!this.currentGenerator) |
|||
this.loadDefaultGenerators(); |
|||
return this.getGenerator(this.currentGenerator); |
|||
}, |
|||
|
|||
/** |
|||
* Set current generator |
|||
* @param {Integer} id Generator ID |
|||
* |
|||
* @return this |
|||
* */ |
|||
setCurrentGenerator : function(id) |
|||
{ |
|||
this.currentGenerator = id; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Load default generators |
|||
* |
|||
* @return this |
|||
* */ |
|||
loadDefaultGenerators : function() |
|||
{ |
|||
for (var id in this.defaultGenerators) { |
|||
this.addGenerator(this.defaultGenerators[id]); |
|||
} |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Add new editor |
|||
* @param {EditorInterface} editor |
|||
* |
|||
* @return this |
|||
* */ |
|||
addEditor : function(editor) |
|||
{ |
|||
// Check interface implementation
|
|||
for (var method in this.ei) |
|||
if(!editor[method]){ |
|||
console.warn("addEditor: method '"+ method +"' was not found"); |
|||
return; |
|||
} |
|||
|
|||
var id = editor.getId(); |
|||
this.editors[id] = editor; |
|||
|
|||
if(!this.currentEditor) |
|||
this.currentEditor = id; |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns editor |
|||
* @param {String}|{Integer} id Editor ID |
|||
* |
|||
* @return {EditorInterface}|null |
|||
* */ |
|||
getEditor : function(id) |
|||
{ |
|||
if(id && this.editors[id]) |
|||
editor = this.editors[id]; |
|||
|
|||
return editor ? editor : null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns editors |
|||
* |
|||
* @return {Array} |
|||
* */ |
|||
getEditors : function() |
|||
{ |
|||
return this.editors; |
|||
}, |
|||
|
|||
/** |
|||
* Get current editor |
|||
* |
|||
* @return {EditorInterface} |
|||
* */ |
|||
getCurrentEditor : function() |
|||
{ |
|||
if(!this.currentEditor) |
|||
this.loadDefaultEditors(); |
|||
return this.getEditor(this.currentEditor); |
|||
}, |
|||
|
|||
/** |
|||
* Set current editor |
|||
* @param {Integer} id Editor ID |
|||
* |
|||
* @return this |
|||
* */ |
|||
setCurrentEditor : function(id) |
|||
{ |
|||
this.currentEditor = id; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Load default editors |
|||
* |
|||
* @return this |
|||
* */ |
|||
loadDefaultEditors : function() |
|||
{ |
|||
for (var id in this.defaultEditors) { |
|||
this.addEditor(this.defaultEditors[id]); |
|||
} |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Get code by name |
|||
* @param {Backbone.Model} model Model |
|||
* @param {String}|{Integer} v Id of code generator |
|||
* |
|||
* @return {String}|null |
|||
* */ |
|||
getCode : function(model, v) |
|||
{ |
|||
var id = v || this.currentGenerator, |
|||
generator = this.generators[id]; |
|||
return generator ? generator.build(model) : null; |
|||
}, |
|||
|
|||
/** |
|||
* Update editor content |
|||
* @param {EditorInteface} editor Editor |
|||
* @param {String} code Code value |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateEditor : function(editor, code) |
|||
{ |
|||
editor.setContent(code); |
|||
}, |
|||
|
|||
|
|||
}; |
|||
|
|||
return CodeManager; |
|||
}); |
|||
@ -0,0 +1,57 @@ |
|||
define(['backbone', |
|||
'text!../../../libs/codemirror/lib/codemirror.css', |
|||
'../../../libs/codemirror/lib/codemirror', |
|||
'../../../libs/codemirror/mode/htmlmixed/htmlmixed', |
|||
'../../../libs/codemirror/mode/css/css', |
|||
'../../../libs/codemirror/lib/util/formatting' |
|||
], |
|||
function(Backbone, CodeMirrorStyle, CodeMirror, htmlMode, cssMode, formatting ) { |
|||
/** |
|||
* @class CodeViewer |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
input : '', |
|||
label : '', |
|||
codeName : '', |
|||
theme : '', |
|||
readOnly : true, |
|||
lineNumbers : true, |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
getId : function() |
|||
{ |
|||
return 'CodeMirror'; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
init: function(el) |
|||
{ |
|||
this.editor = CodeMirror.fromTextArea(el, { |
|||
dragDrop : false, |
|||
lineNumbers : this.get('lineNumbers'), |
|||
readOnly : this.get('readOnly'), |
|||
mode : this.get('codeName'), |
|||
theme : this.get('theme'), |
|||
}); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
/** @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); |
|||
} |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,44 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class CssGenerator |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
/** @inheritdoc */ |
|||
getId : function() |
|||
{ |
|||
return 'css'; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
build: function(model) |
|||
{ |
|||
|
|||
var coll = model.get('components') || model, |
|||
code = ''; |
|||
|
|||
coll.each(function(m){ |
|||
var css = m.get('style'), |
|||
cln = m.get('components'); // Children
|
|||
|
|||
if(css && Object.keys(css).length !== 0){ |
|||
code += '#' + m.cid + '{'; |
|||
|
|||
for(var prop in css) |
|||
if(css.hasOwnProperty(prop)) |
|||
code += prop + ': ' + css[prop] + ';'; |
|||
|
|||
code += '}'; |
|||
} |
|||
|
|||
if(cln.length) |
|||
code += this.build(cln); |
|||
|
|||
}, this); |
|||
|
|||
return code; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,31 @@ |
|||
define(function() { |
|||
/** |
|||
* @class EditorInterface |
|||
* */ |
|||
function EditorInterface() {} |
|||
|
|||
EditorInterface.prototype = { |
|||
|
|||
/** |
|||
* Get id |
|||
* |
|||
* @return {String}|{Integer} |
|||
* */ |
|||
getId : function(){}, |
|||
|
|||
/** |
|||
* Set content |
|||
* @param {String} str |
|||
* |
|||
* */ |
|||
setContent : function(str){}, |
|||
|
|||
/** |
|||
* Init editor |
|||
* @param {Object} el DOM element |
|||
* */ |
|||
init : function(el){}, |
|||
}; |
|||
|
|||
return EditorInterface; |
|||
}); |
|||
@ -0,0 +1,26 @@ |
|||
define(function() { |
|||
/** |
|||
* @class GeneratorInterface |
|||
* */ |
|||
function GeneratorInterface() {} |
|||
|
|||
GeneratorInterface.prototype = { |
|||
|
|||
/** |
|||
* Get id |
|||
* |
|||
* @return {String}|{Integer} |
|||
* */ |
|||
getId : function(){}, |
|||
|
|||
/** |
|||
* Generate code from model |
|||
* @param {Backbone.Model} model |
|||
* |
|||
* @return {String} |
|||
* */ |
|||
build : function(model){}, |
|||
}; |
|||
|
|||
return GeneratorInterface; |
|||
}); |
|||
@ -0,0 +1,39 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class HtmlGenerator |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
/** @inheritdoc */ |
|||
getId : function(){ |
|||
return 'html'; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
build: function(model){ |
|||
var coll = model.get('components') || model, |
|||
code = ''; |
|||
|
|||
coll.each(function(m){ |
|||
var tag = m.get('tagName'), // Tag name
|
|||
attr = '', // Attributes string
|
|||
cln = m.get('components'); // Children
|
|||
|
|||
_.each(m.get('attributes'),function(value, prop){ |
|||
attr += value && prop!='style' ? ' ' + prop + '="' + value + '" ' : ''; |
|||
}); |
|||
|
|||
code += '<'+tag+' id="'+m.cid+'"' + attr + '>' + m.get('content'); |
|||
|
|||
if(cln.length) |
|||
code += this.build(cln); |
|||
|
|||
code += '</'+tag+'>'; |
|||
}, this); |
|||
|
|||
return code; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,40 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class JsonGenerator |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
/** @inheritdoc */ |
|||
getId : function() |
|||
{ |
|||
return 'json'; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
build: function(model) |
|||
{ |
|||
var json = model.toJSON(); |
|||
|
|||
// Avoid jshint 'loopfunc' error
|
|||
_.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); |
|||
|
|||
return json; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,4 @@ |
|||
<div class="<%= pfx %>editor" id="<%= pfx %><%= codeName %>"> |
|||
<div id="<%= pfx %>title"><%= label %></div> |
|||
<div id="<%= pfx %>code"></div> |
|||
</div> |
|||
@ -0,0 +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; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,25 @@ |
|||
define(function () { |
|||
return { |
|||
|
|||
ESCAPE_KEY : 27, |
|||
|
|||
stylePrefix : 'com-', |
|||
|
|||
defaults : [], |
|||
|
|||
// Editor model
|
|||
em : null, |
|||
|
|||
// If true center new first-level components
|
|||
firstCentered : true, |
|||
|
|||
// If true the new component will created with 'height', else 'min-height'
|
|||
newFixedH : false, |
|||
|
|||
// Minimum height (in px) of new component
|
|||
minComponentH : 50, |
|||
|
|||
// Minimum width (in px) of component on creation
|
|||
minComponentW : 50, |
|||
}; |
|||
}); |
|||
@ -0,0 +1,90 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class Commands |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function Commands(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
AbsCommands = require('./view/CommandAbstract'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.commands = {}; |
|||
this.config = c; |
|||
this.Abstract = AbsCommands; |
|||
|
|||
this.defaultCommands = {}; |
|||
this.defaultCommands['select-comp'] = require('./view/SelectComponent'); |
|||
this.defaultCommands['create-comp'] = require('./view/CreateComponent'); |
|||
this.defaultCommands['delete-comp'] = require('./view/DeleteComponent'); |
|||
this.defaultCommands['resize-comp'] = require('./view/ResizeComponent'); |
|||
this.defaultCommands['image-comp'] = require('./view/ImageComponent'); |
|||
this.defaultCommands['move-comp'] = require('./view/MoveComponent'); |
|||
this.defaultCommands['text-comp'] = require('./view/TextComponent'); |
|||
this.defaultCommands['insert-var'] = require('./view/InsertCustom'); |
|||
this.defaultCommands['export-template'] = require('./view/ExportTemplate'); |
|||
this.defaultCommands['sw-visibility'] = require('./view/SwitchVisibility'); |
|||
this.defaultCommands['open-layers'] = require('./view/OpenLayers'); |
|||
this.defaultCommands['open-sm'] = require('./view/OpenStyleManager'); |
|||
|
|||
this.config.model = this.config.em.get('Canvas'); |
|||
} |
|||
|
|||
Commands.prototype = { |
|||
|
|||
/** |
|||
* Add new command |
|||
* @param {String} id |
|||
* @param {Object} obj |
|||
* |
|||
* @return this |
|||
* */ |
|||
add : function(id, obj) |
|||
{ |
|||
delete obj.initialize; |
|||
this.commands[id] = this.Abstract.extend(obj); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Get command |
|||
* @param {String} id |
|||
* |
|||
* @return Command |
|||
* */ |
|||
get : function(id) |
|||
{ |
|||
var el = this.commands[id]; |
|||
|
|||
if(typeof el == 'function'){ |
|||
el = new el(this.config); |
|||
this.commands[id] = el; |
|||
} |
|||
|
|||
return el; |
|||
}, |
|||
|
|||
/** |
|||
* Load default commands |
|||
* |
|||
* @return this |
|||
* */ |
|||
loadDefaultCommands : function() |
|||
{ |
|||
for (var id in this.defaultCommands) { |
|||
this.add(id, this.defaultCommands[id]); |
|||
} |
|||
|
|||
return this; |
|||
}, |
|||
}; |
|||
|
|||
return Commands; |
|||
}); |
|||
@ -0,0 +1,13 @@ |
|||
define([ 'backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class Command |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
id : '', |
|||
} |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,11 @@ |
|||
define([ 'backbone','./Command'], |
|||
function (Backbone, Command) { |
|||
/** |
|||
* @class Commands |
|||
* */ |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Command, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,51 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
/** |
|||
* @class CommandAbstract |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
/** |
|||
* Initialize method that can't be removed |
|||
* @param {Object} o Options |
|||
* */ |
|||
initialize: function(o) { |
|||
this.editorModel = this.em = o.em || {}; |
|||
this.canvasId = o.canvasId || ''; |
|||
this.wrapperId = o.wrapperId || ''; |
|||
this.pfx = o.stylePrefix; |
|||
this.hoverClass = this.pfx + 'hover'; |
|||
this.badgeClass = this.pfx + 'badge'; |
|||
this.plhClass = this.pfx + 'placeholder'; |
|||
this.setElement('#' + this.canvasId); |
|||
this.$canvas = this.$el; |
|||
this.$wrapper = $('#' + this.wrapperId); |
|||
this.init(o); |
|||
}, |
|||
|
|||
/** |
|||
* Callback triggered after initialize |
|||
* @param {Object} o Options |
|||
* */ |
|||
init: function(o){}, |
|||
|
|||
/** |
|||
* Method that run command |
|||
* @param {Object} em Editor model |
|||
* @param {Object} sender Button sender |
|||
* */ |
|||
run: function(em, sender) { |
|||
console.warn("No run method found"); |
|||
}, |
|||
|
|||
/** |
|||
* Method that stop command |
|||
* @param {Object} em Editor model |
|||
* @param {Object} sender Button sender |
|||
* */ |
|||
stop: function(em, sender) { |
|||
console.warn("No stop method found"); |
|||
} |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,269 @@ |
|||
define(['backbone','./SelectPosition'], |
|||
function(Backbone, SelectPosition) { |
|||
/** |
|||
* @class CreateComponent |
|||
* */ |
|||
return _.extend({},SelectPosition,{ |
|||
|
|||
newElement : null, |
|||
|
|||
tempComponent: { style:{} }, |
|||
|
|||
init: function(opt) { |
|||
SelectPosition.init.apply(this, arguments); |
|||
_.bindAll(this,'startDraw','draw','endDraw','rollback'); |
|||
this.config = opt; |
|||
this.heightType = this.config.newFixedH ? 'height' : 'min-height'; |
|||
}, |
|||
|
|||
/** |
|||
* Returns creation placeholder |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
getCreationPlaceholder: function() |
|||
{ |
|||
return this.newElem; |
|||
}, |
|||
|
|||
/** |
|||
* Removes creation placeholder |
|||
* |
|||
* @return void |
|||
* */ |
|||
removeCreationPlaceholder: function() |
|||
{ |
|||
this.newElem.remove(); |
|||
}, |
|||
|
|||
/** |
|||
* Start with enabling to select position and listening to start drawning |
|||
* @return void |
|||
* */ |
|||
enable: function() |
|||
{ |
|||
SelectPosition.enable.apply(this, arguments); |
|||
this.$el.css('cursor','crosshair'); |
|||
this.enableToDraw(); |
|||
}, |
|||
|
|||
/** |
|||
* Enable user to draw components |
|||
* |
|||
* @return void |
|||
* */ |
|||
enableToDraw: function() |
|||
{ |
|||
this.$el.on('mousedown', this.startDraw); |
|||
this.$el.disableSelection(); //Disable text selection
|
|||
}, |
|||
|
|||
/** |
|||
* Start drawing component |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
startDraw : function(e) |
|||
{ |
|||
e.preventDefault(); |
|||
this.stopSelectPosition(); //Interrupt selecting position
|
|||
this.tempComponent = { style: {} }; //Reset the helper
|
|||
this.isDragged = false; |
|||
this.beforeDraw(this.tempComponent); |
|||
this.getPositionPlaceholder().addClass('change-placeholder'); //Change color of the position placeholder
|
|||
this.newElemOrig = { top : e.pageY, left: e.pageX }; |
|||
this.newElem = $('<div>', {class: "tempComp"}).css(this.newElemOrig); //Create helper element with initial position
|
|||
this.newElem.data('helper',1); |
|||
$('body').append(this.newElem); //Show helper component
|
|||
this.parentElem=this.newElem.parent(); //For percent count
|
|||
this.targetC = this.outsideElem; |
|||
$(document).mousemove(this.draw); |
|||
$(document).mouseup(this.endDraw); |
|||
$(document).keypress(this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* While drawing the component |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
draw: function(e) |
|||
{ |
|||
this.isDragged = true; |
|||
this.updateComponentSize(e); |
|||
}, |
|||
|
|||
/** |
|||
* End drawing component |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
endDraw : function(e) |
|||
{ |
|||
$(document).off('mouseup', this.endDraw); |
|||
$(document).off('mousemove', this.draw); |
|||
$(document).off('keypress',this.rollback); |
|||
var model = {}; |
|||
if(this.isDragged){ //Only if the mouse was moved
|
|||
this.updateComponentSize(e); |
|||
this.setRequirements(this.tempComponent); |
|||
model = this.create(null,this.tempComponent,this.posIndex,this.posMethod); |
|||
} |
|||
if(this.getPositionPlaceholder()) |
|||
this.getPositionPlaceholder().removeClass('change-placeholder'); //Turn back the original color of the placeholder
|
|||
this.startSelectPosition(); //Return with selecting new position
|
|||
this.removeCreationPlaceholder(); //Remove the element used for size indication
|
|||
this.afterDraw(model); |
|||
}, |
|||
|
|||
/** |
|||
* Create component |
|||
* @param {Object} target DOM of the target element which to push new component |
|||
* @param {Object} component New component to push |
|||
* @param {Integer} posIndex Index inside the collection, 0 if no children inside |
|||
* @param {String} method Before or after of the children |
|||
* |
|||
* @return {Object} Created model |
|||
* */ |
|||
create: function(target, component, posIndex, method) |
|||
{ |
|||
var index = posIndex || 0; |
|||
if(this.posTargetCollection && this.posTargetModel.get('droppable')){ |
|||
//Check config parameters for center in wrapper
|
|||
if(this.config.firstCentered && (this.el == this.posTargetEl.get(0)) ){ |
|||
component.style.margin = '0 auto'; |
|||
} |
|||
if(this.nearToFloat()) //Set not in flow if the nearest is too
|
|||
component.style.float = 'left'; |
|||
this.beforeCreation(component); |
|||
var model = this.posTargetCollection.add(component, { at: index, silent:false }); |
|||
this.afterCreation(model); |
|||
return model; |
|||
}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 |
|||
* */ |
|||
setRequirements: function(component) |
|||
{ |
|||
var c = this.config; |
|||
if(component.style.width.replace(/\D/g,'') < c.minComponentW) //Check min width
|
|||
component.style.width = c.minComponentW +'px'; |
|||
if(component.style[this.heightType].replace(/\D/g,'') < c.minComponentH) //Check min height
|
|||
component.style[this.heightType] = c.minComponentH +'px'; |
|||
if(c.newFixedH) //Set overflow in case of fixed height
|
|||
component.style.overflow = 'auto'; |
|||
if(!this.absoluteMode){ |
|||
delete component.style.left; |
|||
delete component.style.top; |
|||
}else |
|||
component.style.position = 'absolute'; |
|||
return component; |
|||
}, |
|||
|
|||
/** |
|||
* Update new component size while drawing |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateComponentSize : function (e) |
|||
{ |
|||
var newLeft = e.pageX; |
|||
var newTop = e.pageY; |
|||
var startLeft = this.newElemOrig.left; |
|||
var startTop = this.newElemOrig.top; |
|||
var newWidth = newLeft - startLeft;//$(this.newElem).offset().left
|
|||
var newHeight = newTop - startTop;//$(this.newElem).offset().top
|
|||
if (newLeft < this.newElemOrig.left) { |
|||
startLeft = newLeft; |
|||
newWidth = this.newElemOrig.left - newLeft; |
|||
} |
|||
if (newTop < this.newElemOrig.top) { |
|||
startTop = newTop; |
|||
newHeight = this.newElemOrig.top - newTop; |
|||
} |
|||
newWidth = this.absoluteMode ? (newWidth/this.parentElem.width()*100+"%") : newWidth+'px'; |
|||
this.newElem[0].style.left = startLeft+'px'; |
|||
this.newElem[0].style.top = startTop+'px'; |
|||
this.newElem[0].style.width = newWidth; |
|||
this.newElem[0].style['min-height'] = newHeight+'px'; |
|||
this.tempComponent.style.width = newWidth; |
|||
this.tempComponent.style[this.heightType] = newHeight+"px"; |
|||
this.tempComponent.style.left = startLeft + "px"; |
|||
this.tempComponent.style.top = startTop + "px"; |
|||
}, |
|||
|
|||
/** |
|||
* Used to bring the previous situation before event started |
|||
* @param {Object} e Event |
|||
* @param {Boolean} forse Indicates if rollback in anycase |
|||
* |
|||
* @return void |
|||
* */ |
|||
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 |
|||
* |
|||
* @return void |
|||
* */ |
|||
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 |
|||
* |
|||
* @return void |
|||
* */ |
|||
afterDraw: function(model){}, |
|||
|
|||
/** |
|||
* This event is triggered just before a create operation |
|||
* @param {Object} component Object component before creation |
|||
* |
|||
* @return void |
|||
* */ |
|||
beforeCreation: function(component){}, |
|||
|
|||
/** |
|||
* This event is triggered at the end of a create operation |
|||
* @param {Object} model Component model created |
|||
* |
|||
* @return void |
|||
* */ |
|||
afterCreation: function(model){}, |
|||
|
|||
/** Run method |
|||
* */ |
|||
run: function(){ |
|||
this.enable(); |
|||
}, |
|||
|
|||
/** Stop method |
|||
* */ |
|||
stop: function(){ |
|||
this.removePositionPlaceholder(); //Removes placeholder from eventSelectPosition
|
|||
this.$el.css('cursor',''); //Changes back aspect of the cursor
|
|||
this.$el.unbind(); //Removes all attached events
|
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,59 @@ |
|||
define(['backbone', './SelectComponent'], |
|||
function(Backbone, SelectComponent) { |
|||
/** |
|||
* @class DeleteComponent |
|||
* */ |
|||
return _.extend({},SelectComponent,{ |
|||
|
|||
init: function(o){ |
|||
this.hoverClass = this.pfx + 'hover-delete'; |
|||
this.badgeClass = this.pfx + 'badge-red'; |
|||
}, |
|||
|
|||
enable: function(){ |
|||
|
|||
if(!this.$el.length) |
|||
this.$el = $('#' + this.canvasId); |
|||
|
|||
var that = this; |
|||
this.$el.find('*').mouseover(function (e){ |
|||
e.stopPropagation(); |
|||
if($(this).data('model').get('removable')){ //Show badge if possible
|
|||
$(this).addClass(that.hoverClass); |
|||
that.attachBadge(this); |
|||
} |
|||
}).mouseout(function (e){ //hover out
|
|||
e.stopPropagation(); |
|||
$(this).removeClass(that.hoverClass); |
|||
if(that.badge) //Hide badge if possible
|
|||
that.badge.css({ left: -1000, top:-1000 }); |
|||
}).click(function(e){ |
|||
that.onSelect(e,this); //Callback on select
|
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* Say what to do after the component was selected |
|||
* @param Event |
|||
* @param Object Selected element |
|||
* */ |
|||
onSelect: function(e, el){ |
|||
e.stopPropagation(); |
|||
var $selected = $(el); |
|||
if(!$selected.data('model').get('removable')) //Do nothing in case can't remove
|
|||
return; |
|||
$selected.data('model').destroy(); |
|||
this.removeBadge(); |
|||
this.clean(); |
|||
}, |
|||
|
|||
/** |
|||
* Updates badge label |
|||
* @param Object Model |
|||
* @return void |
|||
* */ |
|||
updateBadgeLabel: function (model){ |
|||
this.badge.html( 'Remove '+model.getName() ); |
|||
}, |
|||
}); |
|||
}); |
|||
@ -0,0 +1,73 @@ |
|||
define(function() { |
|||
/** |
|||
* @class ExportTemplate |
|||
* */ |
|||
return { |
|||
|
|||
run: function(em, sender){ |
|||
this.sender = sender; |
|||
this.components = em.get('Canvas').getWrapper().get('components'); |
|||
this.modal = em.get('Modal') || null; |
|||
this.cm = em.get('CodeManager') || null; |
|||
this.enable(); |
|||
}, |
|||
|
|||
/** |
|||
* Build editor |
|||
* @param {String} codeName |
|||
* @param {String} theme |
|||
* @param {String} label |
|||
* |
|||
* @return {Object} Editor |
|||
* */ |
|||
buildEditor: function(codeName, theme, label) |
|||
{ |
|||
if(!this.codeMirror) |
|||
this.codeMirror = this.cm.getEditor('CodeMirror'); |
|||
|
|||
var $input = $('<textarea>'), |
|||
|
|||
editor = this.codeMirror.clone().set({ |
|||
label : label, |
|||
codeName : codeName, |
|||
theme : theme, |
|||
input : $input[0], |
|||
}), |
|||
|
|||
$editor = new this.cm.EditorView({ |
|||
model : editor, |
|||
config : this.cm.config |
|||
}).render().$el; |
|||
|
|||
editor.init( $input[0] ); |
|||
|
|||
return { el: editor, $el: $editor }; |
|||
}, |
|||
|
|||
enable: function() |
|||
{ |
|||
if(!this.$editors){ |
|||
var oHtmlEd = this.buildEditor('htmlmixed', 'codepen codepen-html', 'HTML2'), |
|||
oCsslEd = this.buildEditor('css', 'codepen codepen-css', 'CSS2'); |
|||
this.htmlEditor = oHtmlEd.el; |
|||
this.cssEditor = oCsslEd.el; |
|||
this.$editors = $('<div>'); |
|||
this.$editors.append(oHtmlEd.$el).append(oCsslEd.$el); |
|||
} |
|||
|
|||
if(this.modal){ |
|||
this.modal.setTitle('Export template'); |
|||
this.modal.setContent(this.$editors); |
|||
this.modal.show(); |
|||
} |
|||
|
|||
this.htmlEditor.setContent( this.cm.getCode(this.components, 'html') ); |
|||
this.cssEditor.setContent( this.cm.getCode(this.components, 'css') ); |
|||
|
|||
if(this.sender) |
|||
this.sender.set('active',false); |
|||
}, |
|||
|
|||
stop: function(){} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,39 @@ |
|||
define(['backbone','./InsertCustom'], |
|||
function(Backbone, InsertCustom) { |
|||
/** |
|||
* @class ImageComponent |
|||
* */ |
|||
return _.extend({}, InsertCustom, { |
|||
|
|||
/** |
|||
* Trigger before insert |
|||
* @param {Object} object |
|||
* |
|||
* @return void |
|||
* */ |
|||
beforeInsert: function(object){ |
|||
object.type = 'image'; |
|||
object.style = {}; |
|||
if (!this.nearToFloat()) { |
|||
object.style.display = 'block'; |
|||
} |
|||
if (this.config.firstCentered && (this.el == this.posTargetEl.get(0)) ) { |
|||
object.style.margin = '0 auto'; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Trigger after insert |
|||
* @param {Object} model Model created after insert |
|||
* |
|||
* @return void |
|||
* */ |
|||
afterInsert: function(model){ |
|||
model.trigger('dblclick'); |
|||
if(this.sender) |
|||
this.sender.set('active',false); |
|||
}, |
|||
|
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,79 @@ |
|||
define(['backbone', './SelectPosition'], |
|||
function(Backbone, SelectPosition) { |
|||
/** |
|||
* @class InsertCustom |
|||
* */ |
|||
return _.extend({}, SelectPosition, { |
|||
|
|||
/** |
|||
* Run method |
|||
* */ |
|||
run: function(em, sender){ |
|||
this.enable(); |
|||
this.sender = sender; |
|||
this.opt = sender.get('options') || {}; |
|||
this.content = this.opt.content; |
|||
}, |
|||
|
|||
enable: function(){ |
|||
SelectPosition.enable.apply(this, arguments); |
|||
_.bindAll(this,'insertComponent'); |
|||
this.$el.on('click', this.insertComponent); |
|||
}, |
|||
|
|||
/** |
|||
* Start insert event |
|||
* |
|||
* @return void |
|||
* */ |
|||
insertComponent: function(){ |
|||
this.$el.off('click', this.insertComponent); |
|||
this.stopSelectPosition(); |
|||
this.removePositionPlaceholder(); |
|||
var object = this.buildContent(); |
|||
this.beforeInsert(object); |
|||
var model = this.posTargetCollection.add(object, { at: this.posIndex, silent:false }); |
|||
if(this.opt.terminateAfterInsert && this.sender){ |
|||
this.sender.set('active',false); |
|||
//if(this.senderBtn.model.get('parentModel'))
|
|||
//this.senderBtn.model.get('parentModel').set('active', false);
|
|||
}else |
|||
this.enable(); |
|||
this.afterInsert(model, this); |
|||
}, |
|||
|
|||
/** |
|||
* Trigger before insert |
|||
* @param {Object} obj |
|||
* |
|||
* @return void |
|||
* */ |
|||
beforeInsert: function(obj){}, |
|||
|
|||
/** |
|||
* Trigger after insert |
|||
* @param {Object} model Model created after insert |
|||
* |
|||
* @return void |
|||
* */ |
|||
afterInsert: function(model){}, |
|||
|
|||
/** |
|||
* Create different object, based on content, to insert inside canvas |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
buildContent: function(){ |
|||
var result = {}; |
|||
if(typeof this.content === 'string'){ |
|||
result = { |
|||
content : this.content, |
|||
tagName : 'span', |
|||
}; |
|||
}else if(typeof this.content === 'object'){ |
|||
result = this.content; |
|||
} |
|||
return result; |
|||
}, |
|||
}); |
|||
}); |
|||
@ -0,0 +1,186 @@ |
|||
define(['backbone', './SelectComponent','./SelectPosition'], |
|||
function(Backbone, SelectComponent, SelectPosition) { |
|||
/** |
|||
* @class MoveComponent |
|||
* */ |
|||
return _.extend({},SelectComponent, SelectPosition,{ |
|||
|
|||
init: function(o){ |
|||
_.bindAll(this,'startMove','onMove','endMove','rollback','selectingPosition','itemLeft');//to mantein 'this' context
|
|||
this.opt = o; |
|||
this.hoverClass = this.pfx + 'hover-move'; |
|||
this.badgeClass = this.pfx + 'badge-yellow'; |
|||
}, |
|||
|
|||
enable: function(){ |
|||
|
|||
if(!this.$el.length){ |
|||
this.$el = $('#' + this.canvasId); |
|||
this.$canvas = this.$el; |
|||
this.canvasTop = this.$canvas.offset().top; |
|||
this.canvasLeft = this.$canvas.offset().left; |
|||
} |
|||
|
|||
this.$el.css('cursor','move'); |
|||
this.$el.on('mousedown', this.startMove); |
|||
this.startSelectComponent(); |
|||
this.$el.disableSelection(); //Avoid strange moving behavior
|
|||
}, |
|||
|
|||
/** Highlight component when pointer is over it |
|||
* @param Event |
|||
* @param Object Component |
|||
* @return void |
|||
* */ |
|||
highlightComponent: function(e, el){ |
|||
e.stopPropagation(); |
|||
if($(el).data('model').get('movable')){ //Show badge if possible
|
|||
$(el).addClass(this.hoverClass); |
|||
this.attachBadge(el); |
|||
} |
|||
}, |
|||
|
|||
/** Say what to do after the component was selected |
|||
* - Method from selectComponent |
|||
* @param Event |
|||
* @param Object Selected element |
|||
* */ |
|||
onSelect: function(e,el){}, |
|||
|
|||
/** Picking component to move |
|||
* @param event |
|||
* */ |
|||
startMove: function(e, el){ |
|||
this.moved = false; |
|||
if( !$(e.target).data('model').get('movable') ){ return; } //In case the component selected is not movable
|
|||
this.$el.off('mousedown', this.startMove); |
|||
this.stopSelectComponent(e); |
|||
this.$selectedEl = $(e.target); |
|||
this.freezeComponent(this.$selectedEl); |
|||
this.helperObj = $('<div>', {class: "tempComp"}).css({ //HELPER gray box
|
|||
top : (e.pageY - this.canvasTop) + this.$canvas.scrollTop(), |
|||
left: (e.pageX - this.canvasLeft) + this.$canvas.scrollLeft(), |
|||
width: $(e.target).width(), |
|||
height: $(e.target).height(), |
|||
position : 'absolute', |
|||
'pointer-events': 'none', //disable events for the element
|
|||
}).data('helper',1).appendTo(this.$el); |
|||
|
|||
this.startSelectPosition(); |
|||
|
|||
this.$el.on('mousemove',this.onMove); |
|||
$(document).on('mouseup',this.endMove); |
|||
$(document).on('keypress',this.rollback); |
|||
}, |
|||
|
|||
/** During move |
|||
* @param event */ |
|||
onMove: function(e){ |
|||
this.moved = true; |
|||
var relativeY = (e.pageY - this.canvasTop) + this.$canvas.scrollTop(); |
|||
var relativeX = (e.pageX - this.canvasLeft) + this.$canvas.scrollLeft(); |
|||
this.helperObj[0].style.top = (relativeY)+'px'; |
|||
this.helperObj[0].style.left = (relativeX)+'px'; |
|||
}, |
|||
|
|||
/** Leave component |
|||
* @param event */ |
|||
endMove: function(e){ |
|||
this.$el.off('mousemove',this.onMove); |
|||
$(document).off('mouseup', this.endMove); |
|||
$(document).off('keypress', this.rollback); |
|||
this.helperObj.remove(); |
|||
|
|||
this.removePositionPlaceholder(); |
|||
this.stopSelectPosition(); |
|||
|
|||
//this.highlightComponent(e,el) after end of move
|
|||
if(this.moved) |
|||
this.move(null, this.$selectedEl, this.posIndex, this.posMethod); |
|||
this.unfreezeComponent(this.$selectedEl); |
|||
this.enable(); |
|||
}, |
|||
|
|||
/** Move component to new position |
|||
* @param object Component to move |
|||
* @param object Target component |
|||
* @param int Indicates the position inside the collection |
|||
* @param string Before of after component |
|||
* |
|||
* @return void |
|||
* */ |
|||
move: function(target, el, posIndex, posMethod){ |
|||
var index = posIndex || 0; |
|||
var model = el.data("model"); |
|||
var collection = model.collection; |
|||
|
|||
var targetCollection = this.posTargetCollection; |
|||
var targetModel = this.posTargetModel; |
|||
|
|||
if(targetCollection && targetModel.get('droppable')){ |
|||
var modelTemp = targetCollection.add({css:{}}, { at: index }); |
|||
var modelRemoved = collection.remove(model); |
|||
targetCollection.add(modelRemoved, { at: index }); |
|||
targetCollection.remove(modelTemp); |
|||
}else |
|||
console.warn("Invalid target position"); |
|||
}, |
|||
|
|||
/** Make component untouchable |
|||
* @param object Component |
|||
* @return void |
|||
* */ |
|||
freezeComponent: function($component){ |
|||
$component.css({'pointer-events':'none'}); |
|||
$component.addClass('freezed'); |
|||
}, |
|||
|
|||
/** Make component touchable |
|||
* @param object Component |
|||
* @return void |
|||
* */ |
|||
unfreezeComponent: function($component){ |
|||
$component.css({'pointer-events':'auto'}); |
|||
$component.removeClass('freezed'); |
|||
}, |
|||
|
|||
/** Used to bring the previous situation before start moving the component |
|||
* @param Event |
|||
* @param Bool Indicates if rollback in anycase |
|||
* @return void |
|||
* */ |
|||
rollback: function(e, force){ |
|||
var key = e.which || e.keyCode; |
|||
if(key == this.opt.ESCAPE_KEY || force){ |
|||
this.moved = false; |
|||
this.endMove(); |
|||
} |
|||
return; |
|||
}, |
|||
|
|||
/** Closing method |
|||
* */ |
|||
last: function(){ |
|||
this.placeholder.remove(); |
|||
this.placeholderStart.remove(); |
|||
this.helperObj.remove(); |
|||
this.$el.off('mousemove',this.move); |
|||
$(document).off('mouseup', this.endMove); |
|||
$(document).off('keypress', this.rollback); |
|||
}, |
|||
|
|||
/* Run method */ |
|||
run: function(){ |
|||
this.enable(); |
|||
this.active = true; |
|||
}, |
|||
|
|||
/* Stop method */ |
|||
stop: function(){ |
|||
this.stopSelectComponent(); |
|||
this.$el.css('cursor','');//changes back aspect of the cursor
|
|||
this.$el.unbind();//removes all attached events
|
|||
this.active = false; |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,35 @@ |
|||
define(['Navigator'], function(Layers) { |
|||
/** |
|||
* @class OpenStyleManager |
|||
* */ |
|||
return { |
|||
|
|||
run: function(em, sender) |
|||
{ |
|||
if(!this.$layers){ |
|||
var collection = em.get('Components').getComponent().get('components'), |
|||
config = em.get('Config'), |
|||
panels = em.get('Panels'), |
|||
lyStylePfx = config.layers.stylePrefix || 'nv-'; |
|||
|
|||
config.layers.stylePrefix = config.stylePrefix + lyStylePfx; |
|||
var layers = new Layers(collection, config.layers); |
|||
this.$layers = layers.render(); |
|||
|
|||
if(!panels.getPanel('views-container')) |
|||
this.panel = panels.addPanel({ id: 'views-container'}); |
|||
else |
|||
this.panel = panels.getPanel('views-container'); |
|||
|
|||
this.panel.set('appendContent', this.$layers).trigger('change:appendContent'); |
|||
} |
|||
this.$layers.show(); |
|||
}, |
|||
|
|||
stop: function() |
|||
{ |
|||
if(this.$layers) |
|||
this.$layers.hide(); |
|||
} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,36 @@ |
|||
define(['StyleManager'], function(StyleManager) { |
|||
/** |
|||
* @class OpenStyleManager |
|||
* */ |
|||
return { |
|||
|
|||
run: function(em, sender) |
|||
{ |
|||
if(!this.$sm){ |
|||
var config = em.get('Config'), |
|||
panels = em.get('Panels'), |
|||
smStylePfx = config.styleManager.stylePrefix || 'sm-'; |
|||
|
|||
config.styleManager.stylePrefix = config.stylePrefix + smStylePfx; |
|||
config.styleManager.target = em; |
|||
|
|||
var sm = new StyleManager(config.styleManager); |
|||
this.$sm = sm.render(); |
|||
|
|||
if(!panels.getPanel('views-container')) |
|||
this.panel = panels.addPanel({ id: 'views-container'}); |
|||
else |
|||
this.panel = panels.getPanel('views-container'); |
|||
|
|||
this.panel.set('appendContent', this.$sm).trigger('change:appendContent'); |
|||
} |
|||
this.$sm.show(); |
|||
}, |
|||
|
|||
stop: function() |
|||
{ |
|||
if(this.$sm) |
|||
this.$sm.hide(); |
|||
} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,57 @@ |
|||
define(['backbone', 'jqueryUi', './MoveComponent'], |
|||
function(Backbone, jqueryUi, MoveComponent) { |
|||
/** |
|||
* @class ResizeComponent |
|||
* */ |
|||
return _.extend({}, MoveComponent,{ |
|||
|
|||
enable: function(){ |
|||
var $this = this; |
|||
this.startSelectComponent(); |
|||
this.$el.find('*').resizable({ |
|||
containment: 'parent', |
|||
start: function(event,ui){ |
|||
ui.element[0].style.height = ui.element.height()+'px'; |
|||
ui.element.css({'min-height':'', 'min-width':'' }); |
|||
}, |
|||
stop: function(event,ui){ |
|||
ui.element.css('overflow','auto'); |
|||
$this.updateModel(ui); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* Update model of resized element |
|||
* @param object Component model |
|||
* */ |
|||
updateModel: function(el){ |
|||
var um = 'px'; |
|||
var model = el.element.data("model"); |
|||
delete model.get('style')['min-height']; //resize event removes fixed measures
|
|||
delete model.get('style')['min-width']; |
|||
model.get('style').height = el.size.height+um; //update with new height and width
|
|||
model.get('style').width = el.size.width+um; |
|||
model.get('style').overflow = 'auto'; |
|||
}, |
|||
|
|||
/** |
|||
* Run method |
|||
* */ |
|||
run: function(){ |
|||
this.enable(); |
|||
this.active = true; |
|||
}, |
|||
|
|||
/** |
|||
* Stop method |
|||
* */ |
|||
stop: function(){ |
|||
this.stopSelectComponent(); |
|||
this.$el.find('.ui-resizable').resizable("destroy"); |
|||
this.$el.unbind();//removes all attached events
|
|||
this.active = false; |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,165 @@ |
|||
define(function() { |
|||
/** |
|||
* @class SelectComponent |
|||
* */ |
|||
return { |
|||
|
|||
enable: function(){ |
|||
this.startSelectComponent(); |
|||
}, |
|||
|
|||
/** Start select component event |
|||
* @return void |
|||
* */ |
|||
startSelectComponent: function(){ |
|||
var that = this; |
|||
|
|||
if(!this.$el.length) |
|||
this.$el = $('#' + this.canvasId); |
|||
|
|||
this.$el.find('*').on('mouseover',function(e){ that.highlightComponent(e,this); }) |
|||
.on('mouseout' ,function(e){ that.removeHighlightComponent(e,this); }) |
|||
.on('click' ,function(e){ that.selectComponent(e,this); }); |
|||
this.selEl = this.$el.find('*'); |
|||
}, |
|||
|
|||
/** Stop select component event |
|||
* @param Event |
|||
* @return void |
|||
* */ |
|||
stopSelectComponent: function(e){ |
|||
if(this.selEl) |
|||
this.selEl.trigger('mouseout').off('mouseover mouseout click'); |
|||
this.selEl = null; |
|||
}, |
|||
|
|||
/** Highlight component when pointer is over it |
|||
* @param Event |
|||
* @param Object Component |
|||
* @return void |
|||
* */ |
|||
highlightComponent: function(e, el){ |
|||
e.stopPropagation(); |
|||
$(el).addClass(this.hoverClass); |
|||
this.attachBadge(el); |
|||
}, |
|||
/** Remove highlight from component |
|||
* @param Event |
|||
* @param Object Component |
|||
* @return void |
|||
* */ |
|||
removeHighlightComponent: function(e, el){ |
|||
e.stopPropagation(); |
|||
$(el).removeClass(this.hoverClass); |
|||
if(this.badge) //Hide badge if possible
|
|||
this.badge.css({ left: -10000, top:-10000 }); //TODO HIDE
|
|||
}, |
|||
/** Select highlighted component |
|||
* @param Event |
|||
* @param Object Component |
|||
* @return void |
|||
* */ |
|||
selectComponent: function(e, el){ |
|||
this.onSelect(e,el); //Callback on select
|
|||
}, |
|||
|
|||
/** Say what to do after the component was selected |
|||
* @param Event |
|||
* @param Object Selected element |
|||
* */ |
|||
onSelect: function(e,el){ |
|||
e.stopPropagation(); |
|||
if(this.$selected) //Check if already selected before
|
|||
this.$selected.removeClass('selected-component'); |
|||
this.$selected = $(el).addClass('selected-component'); |
|||
if(this.$selected.data('model')){ |
|||
// Generates too much recursions with JsonGenerator
|
|||
//this.$selected.data('model').set('previousModel',this.editorModel.get('selectedComponent'));
|
|||
this.editorModel.set('selectedComponent',this.$selected.data('model')); //Update selected component
|
|||
this.$selected.data('model').set('status','selected'); |
|||
} |
|||
}, |
|||
|
|||
/** Removes all highlighting effects on components |
|||
* @return void |
|||
* */ |
|||
clean: function(){ |
|||
this.$el.find('*').removeClass(this.hoverClass); |
|||
}, |
|||
|
|||
/** Attach badge to component |
|||
* @param Object Component |
|||
* @return void |
|||
* */ |
|||
attachBadge: function(el){ |
|||
var model = $(el).data("model"); |
|||
if(!model || !model.get('badgable')) |
|||
return; |
|||
if(!this.badge) |
|||
this.createBadge(); |
|||
var badgeH = this.badge.outerHeight(); |
|||
this.updateBadgeLabel(model); |
|||
var $el = $(el); |
|||
if(!this.wrapper) |
|||
this.wrapper = $('#wrapper'); |
|||
if(!this.wrapperTop) |
|||
this.wrapperTop = this.wrapper.offset() ? this.wrapper.offset().top : 0; |
|||
if(!this.wrapperLeft) |
|||
this.wrapperLeft= this.wrapper.offset() ? this.wrapper.offset().left : 0; |
|||
var relativeT = ($el.offset().top - this.wrapperTop) + this.wrapper.scrollTop(); |
|||
var relativeL = ($el.offset().left- this.wrapperLeft) + this.wrapper.scrollLeft(); |
|||
if( (relativeT-badgeH) > this.wrapperTop) //If it's possible set badge to top
|
|||
relativeT -= badgeH; |
|||
this.badge.css({ left: relativeL, top:relativeT }); |
|||
}, |
|||
|
|||
/** Create badge for the component |
|||
* @return void |
|||
* */ |
|||
createBadge: function (){ |
|||
this.badge = $('<div>', {class: this.badgeClass + " no-dots"}).appendTo('#' + this.wrapperId); |
|||
}, |
|||
|
|||
/** Remove badge |
|||
* @return void |
|||
* */ |
|||
removeBadge: function (){ |
|||
if(this.badge){ |
|||
this.badge.remove(); |
|||
delete this.badge; |
|||
} |
|||
}, |
|||
|
|||
/** Updates badge label |
|||
* @param Object Model |
|||
* @return void |
|||
* */ |
|||
updateBadgeLabel: function (model){ |
|||
if(model) |
|||
this.badge.html( model.getName() ); |
|||
}, |
|||
|
|||
/** Run method |
|||
* */ |
|||
run: function(){ |
|||
this.enable(); |
|||
this.render(); |
|||
this.active = true; |
|||
}, |
|||
|
|||
/** Stop method |
|||
* */ |
|||
stop: function(){ |
|||
if(this.editorModel.get('selectedComponent')) |
|||
this.editorModel.get('selectedComponent').set('status',''); |
|||
this.$el.unbind(); //removes all attached events
|
|||
if(this.$selected) //check if already selected before
|
|||
this.$selected.removeClass('selected-component'); |
|||
this.removeBadge(); |
|||
this.clean(); |
|||
this.$el.find('*').unbind('mouseover').unbind('mouseout').unbind('click'); |
|||
this.editorModel.set('selectedComponent',null); |
|||
this.active = false; |
|||
} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,375 @@ |
|||
define(function() { |
|||
/** |
|||
* @class SelectPosition |
|||
* */ |
|||
return { |
|||
|
|||
init: function(opt) { |
|||
_.bindAll(this,'selectingPosition','itemLeft'); |
|||
this.setElement('#'+this.wrapperId); |
|||
this.config = opt; |
|||
}, |
|||
|
|||
/** |
|||
* Returns position placeholder |
|||
* |
|||
* @return {Object} Placeholder |
|||
* */ |
|||
getPositionPlaceholder: function() |
|||
{ |
|||
return this.$plh; |
|||
}, |
|||
|
|||
/** |
|||
* Creates position placeholder |
|||
* |
|||
* @return {Object} Placeholder |
|||
* */ |
|||
createPositionPlaceholder: function() |
|||
{ |
|||
this.$plh = $('<div>', { class: this.plhClass + " no-dots" }) |
|||
.css({'pointer-events':'none'}).data('helper',1); |
|||
this.$plh.append( $('<div>', { class: this.plhClass + "-int no-dots" } ) ); |
|||
this.$plh.appendTo( this.$wp ); //Append helper to the canvas
|
|||
return this.$plh; |
|||
}, |
|||
|
|||
enable: function() |
|||
{ |
|||
if(!this.$el.length){ |
|||
this.setElement('#'+this.wrapperId); |
|||
this.$el = $('#'+this.wrapperId); |
|||
} |
|||
this.$el.css('cursor','pointer'); //changes aspect of the cursor
|
|||
this.startSelectPosition(); |
|||
}, |
|||
|
|||
/** |
|||
* Start select position event |
|||
* |
|||
* @return void |
|||
* */ |
|||
startSelectPosition: function() |
|||
{ |
|||
this.isPointed = false; |
|||
this.$el.on('mousemove', this.selectingPosition); |
|||
}, |
|||
|
|||
/** |
|||
* Stop select position event |
|||
* @return void |
|||
* */ |
|||
stopSelectPosition: function() |
|||
{ |
|||
this.$el.off('mousemove',this.selectingPosition); |
|||
this.posTargetCollection = null; |
|||
this.posIndex = this.posMethod=='after' && this.cDim.length!==0 ? this.posIndex + 1 : this.posIndex; //Normalize
|
|||
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][5]).parent() : $(this.outsideElem) )); |
|||
this.posTargetModel = this.posTargetEl.data("model"); |
|||
this.posTargetCollection = this.posTargetEl.data("model-comp"); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* During event |
|||
* @param {Object} e Event |
|||
* */ |
|||
selectingPosition: function(e) |
|||
{ |
|||
this.isPointed = true; |
|||
|
|||
if(!this.$wp){ |
|||
this.$wp = $('#' + this.wrapperId); |
|||
this.wp = this.$wp[0]; |
|||
} |
|||
var wpO = this.$wp.offset(); |
|||
this.wpT = wpO.top; |
|||
this.wpL = wpO.left; |
|||
this.wpScT = this.$wp.scrollTop(); |
|||
this.wpScL = this.$wp.scrollLeft(); |
|||
|
|||
if(!this.$plh) |
|||
this.createPositionPlaceholder(); |
|||
|
|||
this.rY = (e.pageY - this.wpT) + this.wpScT; |
|||
this.rX = (e.pageX - this.wpL) + this.wpScL; |
|||
|
|||
this.entered(e); |
|||
this.updatePosition(this.rX, this.rY); |
|||
var actualPos = this.posIndex + ':' + this.posMethod; //save globally the new index
|
|||
|
|||
if(!this.lastPos || (this.lastPos != actualPos)){ //If there is a significant changes with mouse
|
|||
this.updatePositionPlaceholder(this.posIndex, this.posMethod); |
|||
this.lastPos = actualPos; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Search where to put placeholder |
|||
* @param {Integer} posX X position of the mouse |
|||
* @param {Integer} posY Y position of the mouse |
|||
* |
|||
* @retun void |
|||
* */ |
|||
updatePosition: function( posX, posY ){ |
|||
this.posMethod = "before"; |
|||
this.posIndex = 0; |
|||
var leftLimit = 0, xLimit = 0, dimRight = 0, yLimit = 0, xCenter = 0, yCenter = 0, dimDown = 0, dim = 0; |
|||
for(var i = 0; i < this.cDim.length; i++){ |
|||
dim = this.cDim[i]; |
|||
dimDown = dim[0] + dim[2]; |
|||
yCenter = dim[0] + (dim[2] / 2); //Horizontal center
|
|||
xCenter = dim[1] + (dim[3] / 2); //Vertical center
|
|||
dimRight = dim[1] + dim[3]; |
|||
if( (xLimit && dim[1] > xLimit) || (yLimit && yCenter > yLimit) || |
|||
(leftLimit && dimRight < leftLimit)) //No need with this one if over the limit
|
|||
continue; |
|||
if(!dim[4]){ //If it's not inFlow (like float element)
|
|||
if( posY < dimDown) |
|||
yLimit = dimDown; |
|||
if( posX < xCenter){ //If mouse lefter than center
|
|||
xLimit = xCenter; |
|||
this.posMethod = "before"; |
|||
}else{ |
|||
leftLimit = xCenter; |
|||
this.posMethod = "after"; |
|||
} |
|||
this.posIndex = i; |
|||
}else{ |
|||
this.posIndex = i; |
|||
if( posY < yCenter ){ //If mouse upper than center
|
|||
this.posMethod = "before"; //Should place helper before
|
|||
break; //No need to continue under inFlow element
|
|||
}else |
|||
this.posMethod = "after"; |
|||
} |
|||
} |
|||
if(this.posIndex == (this.cDim.length) && this.posMethod == 'after' ){ |
|||
this.posIndex--; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Updates the position of the placeholder |
|||
* @param {Integer} index Index of the nearest child |
|||
* @param {String} method Before or after position |
|||
* |
|||
* @return void |
|||
* */ |
|||
updatePositionPlaceholder: function(index, method){ |
|||
var t = 0, l = 0, w = 0, h = 0, |
|||
marg = 2, |
|||
un = 'px', |
|||
margI = 5, |
|||
plh = this.$plh[0]; |
|||
if( this.cDim[index] ){ |
|||
var elDim = this.cDim[index]; |
|||
if(!elDim[4]){ |
|||
w = 'auto'; |
|||
t = elDim[0] + marg; |
|||
h = elDim[2] - (marg * 2) + un; |
|||
l = (method == 'before') ? (elDim[1] - marg) : (elDim[1] + elDim[3] - marg); |
|||
}else{ |
|||
w = elDim[3] + un; |
|||
t = (method == 'before') ? (elDim[0] - marg) : (elDim[0] + elDim[2] - marg); |
|||
l = elDim[1]; |
|||
h = 'auto'; |
|||
} |
|||
//t -= this.wpScT;
|
|||
//l -= this.wpScL;
|
|||
}else{ |
|||
if(this.$targetEl){ |
|||
var trg = this.$targetEl[0], |
|||
$eO = this.$targetEl.offset(); |
|||
t = $eO.top - this.wpT + this.wpScT + margI; |
|||
l = $eO.left - this.wpL + this.wpScL + margI; |
|||
w = (parseInt(trg.offsetWidth) - margI * 2) + un; |
|||
h = 'auto'; |
|||
} |
|||
} |
|||
|
|||
plh.style.top = t + un; |
|||
plh.style.left = l + un; |
|||
if(w) |
|||
plh.style.width = w; |
|||
if(h) |
|||
plh.style.height = h; |
|||
}, |
|||
|
|||
/** |
|||
* Track inside which element pointer entered |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
entered: function(e){ |
|||
if( (!this.outsideElem || this.outsideElem != e.target) ){ //If I'm in the new element
|
|||
this.outsideElem = e.target; //Set the element in which it's actually inside
|
|||
this.$targetEl = $(e.target); |
|||
$(this.outsideElem).on('mouseleave',this.itemLeft); |
|||
this.cDim = this.getChildrenDim(); |
|||
this.dimT = this.getTargetDim(e); |
|||
if( this.nearToBorders(e) && (e.target.parentNode!=this.wp.parentNode) ) //Avoid flickering
|
|||
this.cDim = this.getChildrenDim(e.target.parentNode); |
|||
}else if( this.nearToBorders(e) && (e.target.parentNode!=this.wp.parentNode) ){ //Near to borders and parent is not the canvas
|
|||
this.cDim = this.getChildrenDim(e.target.parentNode); |
|||
}else if( !(this.nearToBorders(e)) ){ |
|||
this.cDim = this.getChildrenDim(); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Check if pointer is near to the borders of the target |
|||
* @param {Object} e Event |
|||
* |
|||
* @return {Integer} |
|||
* */ |
|||
nearToBorders: function(e){ |
|||
var m = 7; //Limit in pixels for be near
|
|||
if(!this.dimT) |
|||
return; |
|||
var dimT = this.dimT; |
|||
if(dimT[2] < 40) |
|||
m = 5; |
|||
if( ((dimT[0] + m) > this.rY) || (this.rY > (dimT[0] + dimT[2] - m)) || |
|||
((dimT[1] + m) > this.rX) || (this.rX > (dimT[1] + dimT[3] - m)) ) //Check if the pointer is near
|
|||
return 1; |
|||
else |
|||
return 0; |
|||
}, |
|||
|
|||
/** |
|||
* Check if pointer is near to the float component |
|||
* |
|||
* @return {Integer} |
|||
* */ |
|||
nearToFloat: function() |
|||
{ |
|||
var index = this.posIndex; |
|||
var isLastEl = this.posIsLastEl; |
|||
if(this.cDim.length !== 0 && ( |
|||
(!isLastEl && !this.cDim[index][4]) || |
|||
(this.cDim[index-1] && !this.cDim[index-1][4]) || |
|||
(isLastEl && !this.cDim[index-1][4]) ) ) |
|||
return 1; |
|||
else |
|||
return 0; |
|||
}, |
|||
|
|||
/** |
|||
* Returns dimension of the taget |
|||
* @param {Object} e Event |
|||
* |
|||
* @return {Array} |
|||
* */ |
|||
getTargetDim: function(e) |
|||
{ |
|||
var elT = e.target, |
|||
$el = $(elT); |
|||
return [ elT.offsetTop, elT.offsetLeft, $el.outerHeight(), $el.outerWidth() ]; |
|||
}, |
|||
|
|||
/** |
|||
* Returns children and their dimensions of the target element, |
|||
* excluding text nodes and the move placeholder |
|||
* @param {Object} el Element |
|||
* |
|||
* @return {Array} |
|||
* */ |
|||
getChildrenDim: function(el) |
|||
{ |
|||
var dim = []; |
|||
var elToPars = el || this.outsideElem; |
|||
var isInFlow = this.isInFlow; //Assign method for make it work inside $.each
|
|||
var $this = this; //Store context
|
|||
$(elToPars.childNodes).each(function(){ |
|||
var $el = $(this); |
|||
if(this.nodeName != '#text' && !$el.data('helper') ){ //Ignore text nodes and helpers
|
|||
dim.push( [ this.offsetTop, this.offsetLeft, $el.outerHeight(), $el.outerWidth(), isInFlow($this, this), this ] ); |
|||
} |
|||
}); |
|||
return dim; |
|||
}, |
|||
|
|||
/** |
|||
* Track when I go ouside of the element (basically when the target changes) |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
itemLeft: function(e) |
|||
{ |
|||
$(this.outsideElem).off('mouseleave',this.itemLeft); |
|||
this.outsideElem = null; |
|||
this.$targetEl = null; |
|||
this.lastPos = null; |
|||
}, |
|||
|
|||
/** |
|||
* Returns true if the elements is in flow, or better is not in flow where |
|||
* for example the component is with float:left |
|||
* @param {Object} $this Context |
|||
* @param {Object} elm Element |
|||
* |
|||
* @return {Boolean} |
|||
* */ |
|||
isInFlow: function($this, elm) |
|||
{ |
|||
var $elm = $(elm), ch = -1; |
|||
if(!$elm.length) |
|||
return false; |
|||
if( ($elm.height() < ch) || !$this.okProps($elm) ) |
|||
return false; |
|||
return true; |
|||
}, |
|||
|
|||
/** |
|||
* Returns true only if the element follow the standard flow |
|||
* @param {Object} $elm Element |
|||
* |
|||
* @return {Boolean} |
|||
* */ |
|||
okProps: function($elm) |
|||
{ |
|||
if ($elm.css('float')!=='none') |
|||
return false; |
|||
switch($elm.css('position')) { |
|||
case 'static': case 'relative': break; |
|||
default: return false; |
|||
} |
|||
switch ($elm.css('display')) { |
|||
case 'block': case 'list-item': case 'table': return true; |
|||
} |
|||
return false; |
|||
}, |
|||
|
|||
/** |
|||
* Removes position placeholder |
|||
* |
|||
* @param void |
|||
* */ |
|||
removePositionPlaceholder: function() |
|||
{ |
|||
if(this.$plh) |
|||
this.$plh.remove(); |
|||
this.$plh = null; |
|||
}, |
|||
|
|||
/* Run method */ |
|||
run: function(){ |
|||
this.enable(); |
|||
this.active = true; |
|||
}, |
|||
|
|||
/* Stop method */ |
|||
stop: function(){ |
|||
this.removePositionPlaceholder(); |
|||
this.$el.css('cursor','');//changes back aspect of the cursor
|
|||
this.$el.unbind();//removes all attached events
|
|||
this.active = false; |
|||
} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,17 @@ |
|||
define(function() { |
|||
/** |
|||
* @class SwitchVisibility |
|||
* */ |
|||
return { |
|||
|
|||
run: function() |
|||
{ |
|||
this.$canvas.addClass(this.pfx + 'dashed'); |
|||
}, |
|||
|
|||
stop: function() |
|||
{ |
|||
this.$canvas.removeClass(this.pfx + 'dashed'); |
|||
} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,44 @@ |
|||
define(['backbone', './CreateComponent'], |
|||
function(Backbone, CreateComponent) { |
|||
/** |
|||
* @class TextComponent |
|||
* */ |
|||
return _.extend({}, CreateComponent, { |
|||
|
|||
/** |
|||
* This event is triggered at the beginning of a draw operation |
|||
* @param {Object} component Object component before creation |
|||
* |
|||
* @return void |
|||
* */ |
|||
beforeDraw: function(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 |
|||
* |
|||
* @return void |
|||
* */ |
|||
afterDraw: function(model){ |
|||
if(!model.set) |
|||
return; |
|||
model.trigger('focus'); |
|||
if(this.senderBtn) |
|||
this.senderBtn.set('active',false); |
|||
}, |
|||
|
|||
/** |
|||
* Run method |
|||
* */ |
|||
run: function(em, sender){ |
|||
this.enable(); |
|||
this.senderBtn = sender; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,49 @@ |
|||
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: '../libs/jquery', |
|||
jqueryUi: '../libs/jquery-ui.min', |
|||
underscore: '../libs/underscore', |
|||
backbone: '../libs/backbone', |
|||
backboneUndo: '../libs/backbone-undo-min', |
|||
keymaster: '../node_modules/keymaster/keymaster', |
|||
text: '../libs/require-text', |
|||
Spectrum: '../libs/spectrum', |
|||
rte: '../libs/wysiwyg', |
|||
config: 'config/config', |
|||
}, |
|||
|
|||
packages : [ |
|||
{ name: 'AssetManager', location: 'asset_manager', }, |
|||
{ name: 'StyleManager', location: 'style_manager', }, |
|||
{ name: 'StorageManager', location: 'storage_manager', }, |
|||
{ name: 'Navigator', location: 'navigator', }, |
|||
{ name: 'DomComponents', location: 'dom_components', }, |
|||
{ name: 'RichTextEditor', location: 'rich_text_editor', }, |
|||
{ name: 'ModalDialog', location: 'modal_dialog', }, |
|||
{ name: 'CodeManager', location: 'code_manager', }, |
|||
{ name: 'Commands', location: 'commands', }, |
|||
{ name: 'Canvas', location: 'canvas', }, |
|||
{ name: 'Panel', location: 'panel', } |
|||
] |
|||
}); |
|||
@ -0,0 +1,60 @@ |
|||
require(['bundle/config/require-config.js'], function() { |
|||
|
|||
require(['editor/main'],function (Grapes){ |
|||
var grapes = new Grapes({ |
|||
storageType: 'local', |
|||
remoteStorage: { |
|||
urlStore : 'http://test.localhost/wte/index.php', |
|||
urlLoad : 'http://test.localhost/wte/read.php', |
|||
paramsStore : { type:'homeTemplate',}, |
|||
paramsLoad : { type:'homeTemplate',}, |
|||
}, |
|||
assetManager: { |
|||
storageType : '', |
|||
storeOnChange : true, |
|||
storeAfterUpload : true, |
|||
assets : [ |
|||
{ type: 'image', src : 'http://placehold.it/350x250/78c5d6/fff/image1.jpg', date: '2015-01-01',height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/459ba8/fff/image2.jpg', date: '2015-02-01',height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/79c267/fff/image3.jpg', date: '2015-02-01',height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/c5d647/fff/image4.jpg', date: '2015-02-01',height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/f28c33/fff/image5.jpg', date: '2015-02-01',height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/e868a2/fff/image6.jpg', date: '2015-02-01',height:350, width:250}, |
|||
{ type: 'image', src : 'http://placehold.it/350x250/cc4360/fff/image7.jpg', date: '2015-02-01',height:350, width:250}, |
|||
] |
|||
}, |
|||
styleManager : {}, |
|||
defaultComponents: [ { style: {'width':'500px', 'height': '35px', 'margin':'0 auto',}, }, |
|||
{ style: {'width':'500px', 'height': '35px', 'margin':'0 auto',}, }, |
|||
{ style: {'width':'500px', 'height': '35px', 'margin':'0 auto',}, }, |
|||
{ style: {'width':'400px', 'height': '300px', 'margin':'0 auto', 'padding':'5px'}, |
|||
components: [{ style: {'width':'130px','height': '30px','float':'left'}}, |
|||
{ style: {'width':'50px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '80px','float':'left'},}, |
|||
{ style: {'width':'50px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '70px','float':'left'},}, |
|||
{ style: {'width':'50px','height': '80px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'50px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'50px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'75px','height': '50px','clear':'both'}}] |
|||
}, |
|||
{ style: {'width':'700px', 'height': '250px', 'margin':'0 auto'}, |
|||
components: [{ style: {'width':'100px','height': '30px','float':'left'}}, |
|||
{ style: {'width':'200px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'150px','height': '150px','float':'left'},}] |
|||
|
|||
}, |
|||
{ style: {'width':'500px', 'height': '150px', 'margin':'0 auto'}, } |
|||
], |
|||
}); |
|||
|
|||
grapes.render(); |
|||
|
|||
}); |
|||
}); |
|||
|
|||
@ -0,0 +1,20 @@ |
|||
define(function () { |
|||
return { |
|||
stylePrefix : 'comp-', |
|||
|
|||
wrapperId : 'wrapper', |
|||
|
|||
component : {}, |
|||
|
|||
// Could be used for default components
|
|||
components : {}, |
|||
|
|||
rte : {}, |
|||
|
|||
// Class for new image component
|
|||
imageCompClass : 'fa fa-picture-o', |
|||
|
|||
// Open assets manager on create of image component
|
|||
oAssetsOnCreate : true, |
|||
}; |
|||
}); |
|||
@ -0,0 +1,46 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class Components |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function Components(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Component = require('./model/Component'), |
|||
ComponentText = require('./model/ComponentText'), |
|||
ComponentImage = require('./model/ComponentImage'), |
|||
ComponentView = require('./view/ComponentView'), |
|||
ComponentImageView = require('./view/ComponentImageView'), |
|||
ComponentTextView = require('./view/ComponentTextView'); |
|||
|
|||
// Set default options
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.component = new Component(c.component); |
|||
var obj = { |
|||
model : this.component, |
|||
config : c, |
|||
}; |
|||
|
|||
this.ComponentView = new ComponentView(obj); |
|||
} |
|||
|
|||
Components.prototype = { |
|||
|
|||
render : function(){ |
|||
return this.ComponentView.render().$el; |
|||
}, |
|||
|
|||
getComponent : function(){ |
|||
return this.component; |
|||
}, |
|||
}; |
|||
|
|||
return Components; |
|||
}); |
|||
@ -0,0 +1,44 @@ |
|||
define(['backbone','./Components'], |
|||
function (Backbone, Components) { |
|||
/** |
|||
* @class Component |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
tagName : 'div', |
|||
type : '', |
|||
editable : false, |
|||
removable : true, |
|||
movable : true, |
|||
droppable : true, |
|||
badgable : true, |
|||
status : '', |
|||
previousModel : '', |
|||
content : '', |
|||
style : {}, |
|||
attributes : {}, |
|||
}, |
|||
|
|||
initialize: function(options) { |
|||
this.defaultC = options.components || []; |
|||
this.components = new Components(this.defaultC); |
|||
this.set('components', this.components); |
|||
}, |
|||
|
|||
/** |
|||
* Get name of the component |
|||
* |
|||
* @return string |
|||
* */ |
|||
getName: function(){ |
|||
if(!this.name){ |
|||
var id = this.cid.replace(/\D/g,''), |
|||
type = this.get('type'); |
|||
this.name = type.charAt(0).toUpperCase() + type.slice(1) + 'Box' + id; |
|||
} |
|||
return this.name; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,14 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
/** |
|||
* @class ComponentImage |
|||
* */ |
|||
return Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
src : '', |
|||
droppable : false, |
|||
}), |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,14 @@ |
|||
define(['./Component'], |
|||
function (Component) { |
|||
/** |
|||
* @class ComponentText |
|||
* */ |
|||
return Component.extend({ |
|||
|
|||
defaults: _.extend({}, Component.prototype.defaults, { |
|||
content : '', |
|||
droppable : false, |
|||
}), |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,41 @@ |
|||
define([ 'backbone', 'require'], |
|||
function (Backbone, require) { |
|||
/** |
|||
* @class Components |
|||
* */ |
|||
|
|||
return Backbone.Collection.extend({ |
|||
|
|||
initialize: function(models, opt){ |
|||
|
|||
this.model = function(attrs, options) { |
|||
var model; |
|||
|
|||
switch(attrs.type){ |
|||
|
|||
case 'text': |
|||
if(!this.mComponentText) |
|||
this.mComponentText = require("./ComponentText"); |
|||
model = new this.mComponentText(attrs, options); |
|||
break; |
|||
|
|||
case 'image': |
|||
if(!this.mComponentImage) |
|||
this.mComponentImage = require("./ComponentImage"); |
|||
model = new this.mComponentImage(attrs, options); |
|||
break; |
|||
|
|||
default: |
|||
if(!this.mComponent) |
|||
this.mComponent = require("./Component"); |
|||
model = new this.mComponent(attrs, options); |
|||
|
|||
} |
|||
|
|||
return model; |
|||
}; |
|||
|
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,65 @@ |
|||
define(['backbone', './ComponentView'], |
|||
function (Backbone, ComponentView) { |
|||
/** |
|||
* @class ComponentImageView |
|||
* */ |
|||
|
|||
return ComponentView.extend({ |
|||
|
|||
tagName : 'img', |
|||
|
|||
events : { |
|||
'dblclick' : 'openModal', |
|||
}, |
|||
|
|||
initialize: function(o){ |
|||
ComponentView.prototype.initialize.apply(this, arguments); |
|||
this.listenTo( this.model, 'change:src', this.updateSrc); |
|||
this.listenTo( this.model, 'dblclick', this.openModal); |
|||
this.classEmpty = this.config.stylePrefix + 'image-placeholder ' + this.config.imageCompClass; |
|||
|
|||
if(!this.model.get('src')) |
|||
this.$el.attr('class', this.classEmpty); |
|||
|
|||
if(this.config.modal) |
|||
this.modal = this.config.modal; |
|||
|
|||
if(this.config.am) |
|||
this.am = this.config.am; |
|||
}, |
|||
|
|||
/** |
|||
* Update src attribute |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateSrc: function(){ |
|||
this.$el.attr('src',this.model.get("src")); |
|||
}, |
|||
|
|||
/** |
|||
* Open dialog for image changing |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
openModal: function(e){ |
|||
var that = this; |
|||
if(this.modal && this.am){ |
|||
this.modal.setTitle('Select image'); |
|||
this.modal.setContent(this.am.render()); |
|||
this.am.setTarget(this.model); |
|||
this.modal.show(); |
|||
this.am.onSelect(function(){ |
|||
that.modal.hide(); |
|||
that.am.setTarget(null); |
|||
}); |
|||
} |
|||
}, |
|||
|
|||
render: function() { |
|||
this.updateAttributes(); |
|||
return this; |
|||
}, |
|||
}); |
|||
}); |
|||
@ -0,0 +1,72 @@ |
|||
define(['backbone', './ComponentView'], |
|||
function (Backbone, ComponentView) { |
|||
/** |
|||
* @class ComponentTextView |
|||
* */ |
|||
|
|||
return ComponentView.extend({ |
|||
|
|||
events: { |
|||
'dblclick' : 'enableEditing', |
|||
}, |
|||
|
|||
initialize: function(o){ |
|||
ComponentView.prototype.initialize.apply(this, arguments); |
|||
_.bindAll(this,'disableEditing'); |
|||
this.listenTo( this.model, 'focus', this.enableEditing); |
|||
if(this.config.rte){ |
|||
this.rte = this.config.rte; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Enable this component to be editable, |
|||
* load also the mini toolbar for quick editing |
|||
* @param Event |
|||
* */ |
|||
enableEditing: function(e){ |
|||
if(this.rte){ |
|||
if(!this.$wrapper) |
|||
this.$wrapper = $('#'+this.config.wrapperId); |
|||
this.rte.bind(this, this.$wrapper); |
|||
} |
|||
$(document).on('mousedown', this.disableEditing); //Close edit mode
|
|||
this.$el.on('mousedown', this.disablePropagation); //Avoid closing edit mode on component click
|
|||
}, |
|||
|
|||
/** |
|||
* Disable this component to be editable |
|||
* @param Event |
|||
* */ |
|||
disableEditing: function(e){ |
|||
if(this.rte){ |
|||
this.rte.unbind(this); |
|||
} |
|||
$(document).off('mousedown', this.disableEditing); |
|||
this.$el.off('mousedown',this.disablePropagation); |
|||
this.updateContents(); |
|||
}, |
|||
|
|||
/** Isolate disable propagation method |
|||
* @param Event |
|||
* */ |
|||
disablePropagation: function(e){ |
|||
e.stopPropagation(); |
|||
}, |
|||
|
|||
/** |
|||
* Update contents of the element |
|||
* |
|||
* @return void |
|||
**/ |
|||
updateContents : function(){ |
|||
this.model.set('content', this.$el.html()); |
|||
}, |
|||
|
|||
render: function() { |
|||
this.updateAttributes(); |
|||
this.$el.html(this.model.get('content')); |
|||
return this; |
|||
}, |
|||
}); |
|||
}); |
|||
@ -0,0 +1,152 @@ |
|||
define(['backbone', './ComponentsView'], |
|||
function (Backbone, ComponentsView) { |
|||
/** |
|||
* @class ComponentView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
className : function(){ //load classes from model
|
|||
return this.getClasses(); |
|||
}, |
|||
|
|||
tagName: function(){ //load tagName from model
|
|||
return this.model.get('tagName'); |
|||
}, |
|||
|
|||
initialize: function(opt){ |
|||
this.config = opt.config; |
|||
this.components = this.model.get('components'); |
|||
this.attr = this.model.get("attributes"); |
|||
this.classe = this.attr.class || []; |
|||
this.listenTo( this.model, 'destroy remove', this.remove); |
|||
this.listenTo( this.model, 'change:style', this.updateStyle); |
|||
this.listenTo( this.model, 'change:attributes', this.updateAttributes); |
|||
this.$el.data("model", this.model); |
|||
this.$el.data("model-comp", this.components); |
|||
}, |
|||
|
|||
/** |
|||
* Get classes from attributes. |
|||
* This method is called before initialize |
|||
* |
|||
* @return {Array}|null |
|||
* */ |
|||
getClasses: function(){ |
|||
var attr = this.model.get("attributes"), |
|||
classes = attr['class'] || []; |
|||
if(classes.length){ |
|||
return classes.join(" "); |
|||
}else |
|||
return null; |
|||
}, |
|||
|
|||
/** |
|||
* Update attributes |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateAttributes: function(){ |
|||
var attributes = {}, |
|||
attr = this.model.get("attributes"); |
|||
for(var key in attr) { |
|||
if(attr.hasOwnProperty(key)) |
|||
attributes[key] = attr[key]; |
|||
} |
|||
// Update src
|
|||
if(this.model.get("src")) |
|||
attributes.src = this.model.get("src"); |
|||
|
|||
attributes.style = this.getStyleString(); |
|||
|
|||
this.$el.attr(attributes); |
|||
}, |
|||
|
|||
/** |
|||
* Update style attribute |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateStyle: function(){ |
|||
this.$el.attr('style', this.getStyleString()); |
|||
}, |
|||
|
|||
/** |
|||
* Return style string |
|||
* |
|||
* @return {String} |
|||
* */ |
|||
getStyleString: function(){ |
|||
var style = ''; |
|||
this.style = this.model.get('style'); |
|||
for(var key in this.style) { |
|||
if(this.style.hasOwnProperty(key)) |
|||
style += key + ':' + this.style[key] + ';'; |
|||
} |
|||
|
|||
return style; |
|||
}, |
|||
|
|||
/** |
|||
* Update classe attribute |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateClasses: function(){ |
|||
if(this.classe.length) |
|||
this.$el.attr('class', this.classe.join(" ")); |
|||
}, |
|||
|
|||
/** |
|||
* Reply to event call |
|||
* @param object Event that generated the request |
|||
* */ |
|||
eventCall: function(event){ |
|||
event.viewResponse = this; |
|||
}, |
|||
|
|||
render: function() { |
|||
this.updateAttributes(); |
|||
this.$el.html(this.model.get('content')); |
|||
var view = new ComponentsView({ |
|||
collection : this.components, |
|||
config : this.config, |
|||
}); |
|||
this.$components = view; |
|||
// With childNodes lets avoid wrapping 'div'
|
|||
this.$el.append(view.render(this.$el).el.childNodes); |
|||
return this; |
|||
}, |
|||
|
|||
/** TODO DELETE |
|||
* Add new component to canvas |
|||
* @param Object Component added |
|||
* @param Object Collection |
|||
* @param Object Parameters |
|||
* |
|||
addComponent: function (component, collection, params) { |
|||
var viewObject = require('componentView'); //Set default view
|
|||
if(component.get('editable')) //If editable component, change view
|
|||
viewObject = require('componentTextView'); //Change view in case is editable
|
|||
if(component.get('src')){ //If editable component, change view
|
|||
viewObject = require('componentImageView'); //Change view in case is editable
|
|||
} |
|||
var view = new viewObject({ |
|||
model: component, |
|||
editorModel: this.editorModel, |
|||
}); |
|||
if(params && (typeof params.at!='undefined') ){ //If i have index position change the way to append
|
|||
if (params.at === 0){ |
|||
this.$el.prepend(view.render().el); |
|||
}else{ |
|||
this.$el.children().filter(function(){ |
|||
return !$(this).data('helper'); |
|||
}).eq(params.at-1).after(view.render().el); |
|||
//console.log("insert at "+params.at+" children: "+this.$el.children().filter(function() { return !$(this).data('helper');}).length);
|
|||
} |
|||
}else |
|||
this.$el.append(view.render().el); |
|||
}, |
|||
*/ |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,96 @@ |
|||
define(['backbone','require'], |
|||
function(Backbone, require) { |
|||
/** |
|||
* @class ComponentsView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
this.config = o.config; |
|||
this.listenTo( this.collection, 'add', this.addTo ); |
|||
this.listenTo( this.collection, 'reset', this.render ); |
|||
}, |
|||
|
|||
/** |
|||
* Add to collection |
|||
* @param {Object} Model |
|||
* |
|||
* @return void |
|||
* */ |
|||
addTo: function(model){ |
|||
var i = this.collection.indexOf(model); |
|||
this.addToCollection(model, null, i); |
|||
}, |
|||
|
|||
/** |
|||
* Add new object to collection |
|||
* @param {Object} Model |
|||
* @param {Object} Fragment collection |
|||
* @param {Integer} Index of append |
|||
* |
|||
* @return {Object} Object rendered |
|||
* */ |
|||
addToCollection: function(model, fragmentEl, index){ |
|||
if(!this.compView) |
|||
this.compView = require('./ComponentView'); |
|||
var fragment = fragmentEl || null, |
|||
viewObject = this.compView; |
|||
|
|||
switch(model.get('type')){ |
|||
case 'text': |
|||
if(!this.compViewText) |
|||
this.compViewText = require('./ComponentTextView'); |
|||
viewObject = this.compViewText; |
|||
break; |
|||
case 'image': |
|||
if(!this.compViewImage) |
|||
this.compViewImage = require('./ComponentImageView'); |
|||
viewObject = this.compViewImage; |
|||
break; |
|||
} |
|||
|
|||
var view = new viewObject({ |
|||
model : model, |
|||
config : this.config, |
|||
}); |
|||
var rendered = view.render().el; |
|||
|
|||
if(fragment){ |
|||
fragment.appendChild(rendered); |
|||
}else{ |
|||
var p = this.$parent; |
|||
if(typeof index != 'undefined'){ |
|||
var method = 'before'; |
|||
// If the added model is the last of collection
|
|||
// need to change the logic of append
|
|||
if(p.children().length == index){ |
|||
index--; |
|||
method = 'after'; |
|||
} |
|||
// In case the added is new in the collection index will be -1
|
|||
if(index < 0){ |
|||
p.append(rendered); |
|||
}else |
|||
p.children().eq(index)[method](rendered); |
|||
}else{ |
|||
p.append(rendered); |
|||
} |
|||
} |
|||
|
|||
return rendered; |
|||
}, |
|||
|
|||
render: function($p) { |
|||
var fragment = document.createDocumentFragment(); |
|||
this.$parent = $p || this.$el; |
|||
this.$el.empty(); |
|||
this.collection.each(function(model){ |
|||
this.addToCollection(model, fragment); |
|||
},this); |
|||
this.$el.append(fragment); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,72 @@ |
|||
define(function () { |
|||
var config = { |
|||
|
|||
// Style prefix
|
|||
stylePrefix: 'wte-', |
|||
|
|||
// Prefix to use inside local storage name
|
|||
storagePrefix: 'wte-', |
|||
|
|||
// Editor ID. Useful in case of multiple editors on the same page
|
|||
id: '', |
|||
|
|||
appContainer : '#wte-app', |
|||
|
|||
idCanvas : 'canvas', |
|||
|
|||
idCanvasOverlay : 'canvas-overlay', |
|||
|
|||
idWrapper : 'wrapper', |
|||
|
|||
// Enable/Disable undo manager
|
|||
undoManager : true, |
|||
|
|||
// Enable/Disable autosaving
|
|||
autosave : true, |
|||
|
|||
//Indicates which storage to use. Available: local | remote | none
|
|||
storageType : 'local', |
|||
|
|||
// If autosave enabled, indicates how many changes (general changes to structure)
|
|||
// need to be done before save. Useful with remoteStorage to reduce remote calls
|
|||
changesBeforeSave: 1, |
|||
|
|||
//Enabled only if localStorage is false
|
|||
remoteStorage : {}, |
|||
|
|||
//Configurations for Asset Manager
|
|||
assetManager : {}, |
|||
|
|||
//Configurations for Canvas
|
|||
canvas : {}, |
|||
|
|||
//Configurations for Style Manager
|
|||
styleManager : {}, |
|||
|
|||
//Configurations for Layers
|
|||
layers : {}, |
|||
|
|||
//Configurations for Storage Manager
|
|||
storageManager : {}, |
|||
|
|||
//Configurations for Rich Text Editor
|
|||
rte : {}, |
|||
|
|||
//Configurations for Components
|
|||
components : {}, |
|||
|
|||
//Configurations for Modal Dialog
|
|||
modal : {}, |
|||
|
|||
//Configurations for Code Manager
|
|||
codeManager : {}, |
|||
|
|||
//Configurations for Panels
|
|||
panels : {}, |
|||
|
|||
//Configurations for Commands
|
|||
commands : {}, |
|||
|
|||
}; |
|||
return config; |
|||
}); |
|||
@ -0,0 +1,39 @@ |
|||
define(function (require){ |
|||
/** |
|||
* @class Grapes |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
var Grapes = function(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Editor = require('./model/Editor'), |
|||
EditorView = require('./view/EditorView'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.editor = new Editor(c); |
|||
var obj = { |
|||
model : this.editor, |
|||
config : c, |
|||
}; |
|||
|
|||
this.editorView = new EditorView(obj); |
|||
}; |
|||
|
|||
Grapes.prototype = { |
|||
|
|||
render : function() |
|||
{ |
|||
return this.editorView.render().$el; |
|||
} |
|||
|
|||
}; |
|||
|
|||
return Grapes; |
|||
}); |
|||
@ -0,0 +1,336 @@ |
|||
define([ |
|||
'backbone', |
|||
'backboneUndo', |
|||
'keymaster', |
|||
'AssetManager', |
|||
'StorageManager', |
|||
'ModalDialog', |
|||
'CodeManager', |
|||
'Commands', |
|||
'Canvas', |
|||
'RichTextEditor', |
|||
'DomComponents', |
|||
'Panel'], |
|||
function( |
|||
Backbone, |
|||
UndoManager, |
|||
Keymaster, |
|||
AssetManager, |
|||
StorageManager, |
|||
ModalDialog, |
|||
CodeManager, |
|||
Commands, |
|||
Canvas, |
|||
RichTextEditor, |
|||
DomComponents, |
|||
Panels |
|||
){ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults:{ |
|||
selectedComponent: null, |
|||
changesCount: 0, |
|||
}, |
|||
|
|||
initialize: function(c) |
|||
{ |
|||
this.config = c; |
|||
this.compName = this.config.storagePrefix + 'componentsTree' + this.config.id; |
|||
this.set('Config', c); |
|||
|
|||
this.initStorage(); |
|||
this.initModal(); |
|||
this.initAssetManager(); |
|||
this.initCodeManager(); |
|||
this.initCommands(); |
|||
this.initPanels(); |
|||
this.initRichTextEditor(); |
|||
this.initComponents(); |
|||
this.initCanvas(); |
|||
this.initUndoManager(); |
|||
|
|||
this.on('change:selectedComponent', this.componentSelected, this); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize components |
|||
* */ |
|||
initComponents: function() |
|||
{ |
|||
var cfg = this.config.components, |
|||
comps = this.loadComponentsTree(), |
|||
cmpStylePfx = cfg.stylePrefix || 'comp-'; |
|||
|
|||
if(!comps){ |
|||
comps = { |
|||
removable : false, |
|||
movable : false, |
|||
badgable : false, |
|||
attributes : { id: this.config.idWrapper }, |
|||
style : { position: 'relative',}, |
|||
components : cfg.components, |
|||
}; |
|||
} |
|||
|
|||
cfg.stylePrefix = this.config.stylePrefix + cmpStylePfx; |
|||
cfg.component = comps; |
|||
|
|||
if(this.rte) |
|||
cfg.rte = this.rte; |
|||
|
|||
if(this.modal) |
|||
cfg.modal = this.modal; |
|||
|
|||
if(this.am) |
|||
cfg.am = this.am; |
|||
|
|||
this.cmp = new DomComponents(cfg); |
|||
|
|||
if(this.stm.isAutosave()){ // TODO Currently doesn't listen already created models
|
|||
this.updateComponents( this.cmp.getComponent(), null, { avoidStore : 1 }); |
|||
} |
|||
|
|||
this.set('Components', this.cmp); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize canvas |
|||
* */ |
|||
initCanvas: function() |
|||
{ |
|||
var cfg = this.config.canvas, |
|||
pfx = cfg.stylePrefix || 'cv-'; |
|||
cfg.stylePrefix = this.config.stylePrefix + pfx; |
|||
this.cv = new Canvas(this.config.canvas); |
|||
|
|||
if(this.cmp) |
|||
this.cv.setWrapper(this.cmp); |
|||
|
|||
this.set('Canvas', this.cv); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize rich text editor |
|||
* */ |
|||
initRichTextEditor: function() |
|||
{ |
|||
var cfg = this.config.rte, |
|||
rteStylePfx = cfg.stylePrefix || 'rte-'; |
|||
cfg.stylePrefix = this.config.stylePrefix + rteStylePfx; |
|||
this.rte = new RichTextEditor(cfg); |
|||
this.set('RichTextEditor', this.rte); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize storage |
|||
* */ |
|||
initStorage: function() |
|||
{ |
|||
this.stm = new StorageManager(this.config.storageManager); |
|||
this.stm.loadDefaultProviders().setCurrentProvider(this.config.storageType); |
|||
this.set('StorageManager', this.stm); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize asset manager |
|||
* */ |
|||
initAssetManager: function() |
|||
{ |
|||
var cfg = this.config.assetManager, |
|||
pfx = cfg.stylePrefix || 'am-'; |
|||
cfg.stylePrefix = this.config.stylePrefix + pfx; |
|||
|
|||
if(this.stm) |
|||
cfg.stm = this.stm; |
|||
|
|||
this.am = new AssetManager(cfg); |
|||
this.set('AssetManager', this.am); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize modal |
|||
* */ |
|||
initModal: function() |
|||
{ |
|||
var cfg = this.config.modal, |
|||
pfx = cfg.stylePrefix || 'mdl-'; |
|||
cfg.stylePrefix = this.config.stylePrefix + pfx; |
|||
this.modal = new ModalDialog(cfg); |
|||
this.modal.render().appendTo('body'); |
|||
this.set('Modal', this.modal); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize Code Manager |
|||
* */ |
|||
initCodeManager: function() |
|||
{ |
|||
var cfg = this.config.codeManager, |
|||
pfx = cfg.stylePrefix || 'cm-'; |
|||
cfg.stylePrefix = this.config.stylePrefix + pfx; |
|||
this.cm = new CodeManager(cfg); |
|||
this.cm.loadDefaultGenerators().loadDefaultEditors(); |
|||
this.set('CodeManager', this.cm); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize Commands |
|||
* */ |
|||
initCommands: function() |
|||
{ |
|||
var cfg = this.config.commands, |
|||
pfx = cfg.stylePrefix || 'com-'; |
|||
cfg.stylePrefix = this.config.stylePrefix + pfx; |
|||
cfg.em = this; |
|||
cfg.canvasId = this.config.idCanvas; |
|||
cfg.wrapperId = this.config.idWrapper; |
|||
this.com = new Commands(cfg); |
|||
this.com.loadDefaultCommands(); |
|||
this.set('Commands', this.com); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize Panels |
|||
* */ |
|||
initPanels: function() |
|||
{ |
|||
var cfg = this.config.panels, |
|||
pfx = cfg.stylePrefix || 'pn-'; |
|||
cfg.stylePrefix = this.config.stylePrefix + pfx; |
|||
cfg.em = this; |
|||
this.pn = new Panels(cfg); |
|||
this.pn.addPanel({ id: 'views-container'}); |
|||
this.set('Panels', this.pn); |
|||
}, |
|||
|
|||
/** |
|||
* Initialize Undo manager |
|||
* */ |
|||
initUndoManager: function(){ |
|||
if(this.cmp && this.config.undoManager){ |
|||
var backboneUndo = new Backbone.UndoManager({ |
|||
register: [this.cmp.getComponent().get('components')], |
|||
track: true |
|||
}); |
|||
key('⌘+z, ctrl+z', function(){ |
|||
backboneUndo.undo(); |
|||
}); |
|||
key('⌘+shift+z, ctrl+shift+z', function(){ |
|||
backboneUndo.redo(); |
|||
}); |
|||
|
|||
Backbone.UndoManager.removeUndoType("change"); |
|||
var beforeCache; |
|||
Backbone.UndoManager.addUndoType("change:style", { |
|||
"on": function (model, value, opt) { |
|||
if(!beforeCache) |
|||
beforeCache = model.toJSON(); |
|||
if (opt && opt.avoidStore) { |
|||
return; |
|||
} else { |
|||
var obj = { |
|||
"object": model, |
|||
"before": beforeCache, |
|||
"after": model.toJSON() |
|||
}; |
|||
beforeCache = null; |
|||
return obj; |
|||
} |
|||
}, |
|||
"undo": function (model, bf, af, opt) { |
|||
model.set(bf); |
|||
}, |
|||
"redo": function (model, bf, af, opt) { |
|||
model.set(af); |
|||
} |
|||
}); |
|||
|
|||
//TODO when, for example, undo delete cant redelete it, so need to
|
|||
//recall 'remove command'
|
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Triggered when components are updated |
|||
* */ |
|||
componentsUpdated: function() |
|||
{ |
|||
var updatedCount = this.get('changesCount') + 1; |
|||
this.set('changesCount', updatedCount); |
|||
if(this.stm.isAutosave() && updatedCount < this.stm.getChangesBeforeSave()){ |
|||
return; |
|||
} |
|||
this.storeComponentsTree(); |
|||
this.set('changesCount', 0 ); |
|||
}, |
|||
|
|||
/** |
|||
* Callback on component selection |
|||
* @param {Object} Model |
|||
* @param {Mixed} New value |
|||
* @param {Object} Options |
|||
* |
|||
* */ |
|||
componentSelected: function(model, val, options) |
|||
{ |
|||
if(!this.get('selectedComponent')) |
|||
this.trigger('deselect-comp'); |
|||
else |
|||
this.trigger('select-comp',[model,val,options]); |
|||
}, |
|||
|
|||
/** |
|||
* Load components from storage |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
loadComponentsTree: function(){ |
|||
var result = null; |
|||
try{ |
|||
result = JSON.parse(this.stm.load(this.compName)); |
|||
}catch(err){ |
|||
console.warn("Error encountered while parsing JSON response"); |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Save components to storage |
|||
* |
|||
* @return void |
|||
* */ |
|||
storeComponentsTree: function(){ |
|||
var wrp = this.cmp.getComponent(); |
|||
if(wrp && this.cm){ |
|||
var res = this.cm.getCode(wrp, 'json'); |
|||
console.log(res); |
|||
this.stm.store(this.compName, JSON.stringify(res)); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Triggered when components are updated |
|||
* @param {Object} model |
|||
* @param {Mixed} val Value |
|||
* @param {Object} opt Options |
|||
* |
|||
* */ |
|||
updateComponents: function(model, val, opt){ |
|||
var comps = model.get('components'), |
|||
avSt = opt ? opt.avoidStore : 0; |
|||
|
|||
// Call stopListening for not creating nested listenings
|
|||
this.stopListening(comps, 'add', this.updateComponents); |
|||
this.stopListening(comps, 'remove', this.componentsUpdated); |
|||
this.listenTo(comps, 'add', this.updateComponents); |
|||
this.listenTo(comps, 'remove', this.componentsUpdated); |
|||
|
|||
this.stopListening(model, 'change:style change:content', this.updateComponents); |
|||
this.listenTo(model, 'change:style change:content', this.updateComponents); |
|||
|
|||
if(!avSt) |
|||
this.componentsUpdated(); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,33 @@ |
|||
define(['backbone'], |
|||
function(Backbone){ |
|||
/** |
|||
* @class EditorView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function() { |
|||
this.cv = this.model.get('Canvas'); |
|||
this.pn = this.model.get('Panels'); |
|||
this.className = this.model.config.stylePrefix + 'editor'; |
|||
}, |
|||
|
|||
render: function(){ |
|||
this.$el.empty(); |
|||
|
|||
if(this.cv) |
|||
this.$el.append(this.cv.render()); |
|||
|
|||
if(this.pn) |
|||
this.$el.append(this.pn.render()); |
|||
|
|||
this.$el.attr('class', this.className); |
|||
|
|||
$('body '+this.model.config.appContainer).html(this.$el); |
|||
|
|||
if(this.pn) |
|||
this.pn.active(); |
|||
|
|||
return this; |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,157 @@ |
|||
|
|||
require(['bundle/config/require-config.js'], function() { |
|||
|
|||
require(['editor/main'],function (Grapes){ |
|||
return Grapes; |
|||
}); |
|||
|
|||
/* |
|||
require(['startup/main'], function (Grapes){ |
|||
/* |
|||
Grapes.run({ |
|||
storageType: 'local', |
|||
remoteStorage: { |
|||
urlStore : 'http://test.localhost/wte/index.php', |
|||
urlLoad : 'http://test.localhost/wte/read.php', |
|||
paramsStore : { type:'homeTemplate',}, |
|||
paramsLoad : { type:'homeTemplate',}, |
|||
}, |
|||
assetManager: { |
|||
storageType : 'local', |
|||
storeOnChange : true, |
|||
storeAfterUpload : true, |
|||
}, |
|||
styleManager : {}, //sectors: [{ name: 'MainConfig', properties:[] }]
|
|||
defaultComponents: [ { style: {'width':'500px', 'height': '35px', 'margin':'0 auto',}, }, |
|||
{ style: {'width':'500px', 'height': '35px', 'margin':'0 auto',}, }, |
|||
{ style: {'width':'500px', 'height': '35px', 'margin':'0 auto',}, }, |
|||
{ style: {'width':'400px', 'height': '300px', 'margin':'0 auto', 'padding':'5px'}, |
|||
components: [{ style: {'width':'130px','height': '30px','float':'left'}}, |
|||
{ style: {'width':'50px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '80px','float':'left'},}, |
|||
{ style: {'width':'50px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '70px','float':'left'},}, |
|||
{ style: {'width':'50px','height': '80px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'50px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'50px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'80px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'75px','height': '50px','clear':'both'}}] |
|||
}, |
|||
{ style: {'width':'700px', 'height': '250px', 'margin':'0 auto'}, |
|||
components: [{ style: {'width':'100px','height': '30px','float':'left'}}, |
|||
{ style: {'width':'200px','height': '50px','float':'left'},}, |
|||
{ style: {'width':'150px','height': '150px','float':'left'},}] |
|||
|
|||
}, |
|||
{ style: {'width':'500px', 'height': '150px', 'margin':'0 auto'}, } |
|||
/* |
|||
{ |
|||
css:{'width':'100%', 'background-color':'#372828'}, |
|||
components:[{ |
|||
css:{'width':'90%','max-width':'980px', 'min-height':'70px', 'margin':'0 auto'}, |
|||
components: [ |
|||
{ |
|||
css:{'width':'50%','float':'left'}, |
|||
components: [ |
|||
{ editable: true, contents: 'myLogo', css:{ 'color':'#fff','font-size':'30px','padding-top':'20px','font-family':'Helvetica','font-weight':'100'} } |
|||
], |
|||
}, |
|||
{ |
|||
css:{'width':'50%','min-height':'70px','float':'left','font-family':'Helvetica','color':'#fff',}, |
|||
components: [{ contents: '{{ TOPMENU }}', css:{ 'padding-top':'35px','font-weight':'100','text-align':'right'} },], |
|||
}, |
|||
{css:{'clear':'both'}}, |
|||
], |
|||
},], |
|||
}, |
|||
{ |
|||
css:{'width':'100%', 'background-color':'#e54b4b', 'font-family':'Helvetica'}, |
|||
components:[ |
|||
{ |
|||
css:{'width':'90%','max-width':'980px','height':'500px', 'margin':'0 auto','text-align':'center',},//,'padding-top':'75px'
|
|||
components: [ |
|||
{ contents:'YOUR HOSTING SOLUTION',editable:true, |
|||
css:{ 'color':'#ffffff','font-size':'40px','font-weight':'700','text-align':'center','padding-top':'75px'} |
|||
}, |
|||
{ contents:'Powerful hardware for you business right now',editable:true, |
|||
css:{ 'color':'#ffffff','font-size':'20px','font-weight':'100','text-align':'center','margin-top':'10px'} |
|||
}, |
|||
{ attributes: {src:'./images/media/red-server-icon.png'}, tagName: 'img', css:{ 'display':'inline', 'margin':'70px auto','margin-left':'auto','margin-right':'auto'},} |
|||
//{css:{'width':'50%','min-height':'50px','float':'left'}},
|
|||
//{css:{'width':'50%','min-height':'50px','float':'left'}},
|
|||
], |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
css:{'width':'100%','background-color':'#ffffff'}, |
|||
components:[ |
|||
{ |
|||
css:{'width':'90%','max-width':'980px','height':'350px', 'margin':'0 auto','color':'#352828'},//,'padding-top':'75px'
|
|||
components: [ |
|||
{ |
|||
css:{ 'margin-left':'1%','margin-right':'1%','width':'31.333%', 'float':'left','height':'100%','padding-left':'20px','padding-right':'20px'}, |
|||
components: [ |
|||
{ |
|||
css:{ 'width':'100px','height':'100px','margin':'0 auto', 'background-color':'#352828','border-radius':'50px','margin-top':'75px','text-align':'center'}, |
|||
components: [ |
|||
{ attributes: {src:'./images/media/cloud-logo.png'}, tagName: 'img', css:{'padding-top':'15px'},} |
|||
], |
|||
}, |
|||
{ editable:true, contents:'Cloud servers', css:{ 'font-size':'20px','text-align':'center','margin-top':'25px'}}, |
|||
{ editable:true, |
|||
contents:'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna.', |
|||
css:{ 'text-align':'center','margin-top':'20px'}}, |
|||
], |
|||
}, |
|||
{ |
|||
css:{ 'margin-left':'1%','margin-right':'1%','width':'31.333%', 'float':'left','height':'100%','padding-left':'20px','padding-right':'20px'}, |
|||
components: [ |
|||
{ |
|||
css:{ 'width':'100px','height':'100px','margin':'0 auto', 'background-color':'#352828','border-radius':'50px','margin-top':'75px','text-align':'center'}, |
|||
components: [ |
|||
{ attributes: {src:'./images/media/network-icon.png'}, tagName: 'img', css:{'width':'59px','padding-top':'21px'},} |
|||
], |
|||
}, |
|||
{ editable:true, contents:'Big networks', css:{ 'font-size':'20px','text-align':'center','margin-top':'25px'}}, |
|||
{ editable:true, |
|||
contents:'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna.', |
|||
css:{ 'text-align':'center','margin-top':'20px'}}, |
|||
], |
|||
}, |
|||
{ |
|||
css:{ 'margin-left':'1%','margin-right':'1%','width':'31.333%', 'float':'left','height':'100%','padding-left':'20px','padding-right':'20px'}, |
|||
components: [ |
|||
{ |
|||
css:{ 'width':'100px','height':'100px','margin':'0 auto', 'background-color':'#352828','border-radius':'50px','margin-top':'75px','text-align':'center'}, |
|||
components: [ |
|||
{ attributes: {src:'./images/media/settings-icon.png'}, tagName: 'img', css:{'width':'59px','padding-top':'21px'},} |
|||
], |
|||
}, |
|||
{ editable:true, contents:'High scalability', css:{ 'font-size':'20px','text-align':'center','margin-top':'25px'}}, |
|||
{ editable:true, |
|||
contents:'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna.', |
|||
css:{ 'text-align':'center','margin-top':'20px'}}, |
|||
], |
|||
}, |
|||
], |
|||
}, |
|||
], |
|||
},** |
|||
], |
|||
});//Initialize the application
|
|||
* |
|||
$(window).unload(function() { |
|||
console.log('unload test (save data before exit)'); |
|||
}); |
|||
window.onbeforeunload = function(e) { |
|||
console.log('onbeforeunload test'); |
|||
//return 'Please press the Logout button to logout.';
|
|||
}; |
|||
}); |
|||
*/ |
|||
}); |
|||
@ -0,0 +1,13 @@ |
|||
define(function () { |
|||
return { |
|||
|
|||
stylePrefix : 'mdl-', |
|||
|
|||
title : '', |
|||
|
|||
content : '', |
|||
|
|||
backdrop : true, |
|||
|
|||
}; |
|||
}); |
|||
@ -0,0 +1,57 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class Modal |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function Modal(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
ModalM = require('./model/Modal'), |
|||
ModalView = require('./view/ModalView'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.model = new ModalM(c); |
|||
var obj = { |
|||
model : this.model, |
|||
config : c, |
|||
}; |
|||
|
|||
this.modal = new ModalView(obj); |
|||
} |
|||
|
|||
Modal.prototype = { |
|||
|
|||
getModel : function(){ |
|||
return this.model; |
|||
}, |
|||
|
|||
render : function(){ |
|||
return this.modal.render().$el; |
|||
}, |
|||
|
|||
show : function(){ |
|||
return this.modal.show(); |
|||
}, |
|||
|
|||
hide : function(){ |
|||
return this.modal.hide(); |
|||
}, |
|||
|
|||
setTitle : function(v){ |
|||
return this.modal.setTitle(v); |
|||
}, |
|||
|
|||
setContent : function(v){ |
|||
return this.modal.setContent(v); |
|||
}, |
|||
}; |
|||
|
|||
return Modal; |
|||
}); |
|||
@ -0,0 +1,15 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
/** |
|||
* @class Modal |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
title : '', |
|||
content : '', |
|||
open : false, |
|||
} |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,11 @@ |
|||
<div class="<%= pfx %>dialog"> |
|||
<div class="<%= pfx %>header"> |
|||
<div class="<%= pfx %>title"><%= title %></div> |
|||
<div class="<%= pfx %>btn-close">⨯</div> |
|||
</div> |
|||
<div class="<%= pfx %>content"> |
|||
<div id="<%= pfx %>c"> <%= content %> </div> |
|||
<div style="clear:both"></div> |
|||
</div> |
|||
</div> |
|||
<div class="<%= pfx %>backlayer"></div> |
|||
@ -0,0 +1,110 @@ |
|||
define(['backbone', 'text!./../template/modal.html'], |
|||
function (Backbone, modalTemplate) { |
|||
/** |
|||
* @class ModalView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
template: _.template(modalTemplate), |
|||
|
|||
events : {}, |
|||
|
|||
initialize: function(o){ |
|||
this.config = o.config || {}; |
|||
this.pfx = this.config.stylePrefix; |
|||
this.listenTo( this.model, 'change:open', this.updateOpen); |
|||
this.listenTo( this.model, 'change:title', this.updateTitle); |
|||
this.listenTo( this.model, 'change:content',this.updateContent); |
|||
this.events['click .'+this.pfx+'btn-close'] = 'hide'; |
|||
|
|||
if(this.config.backdrop) |
|||
this.events['click .'+this.pfx+'backlayer'] = 'hide'; |
|||
}, |
|||
|
|||
/** |
|||
* Update content |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateContent: function(){ |
|||
if(!this.$content) |
|||
this.$content = this.$el.find('.'+this.pfx+'content #'+this.pfx+'c'); |
|||
this.$content.html(this.model.get('content')); |
|||
}, |
|||
|
|||
/** |
|||
* Update title |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateTitle: function(){ |
|||
if(!this.$title) |
|||
this.$title = this.$el.find('.'+this.pfx+'title'); |
|||
this.$title.html(this.model.get('title')); |
|||
}, |
|||
|
|||
/** |
|||
* Update open |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateOpen: function(){ |
|||
if(this.model.get('open')) |
|||
this.$el.show(); |
|||
else |
|||
this.$el.hide(); |
|||
}, |
|||
|
|||
/** |
|||
* Hide modal |
|||
* |
|||
* @return void |
|||
* */ |
|||
hide: function(){ |
|||
this.model.set('open', 0); |
|||
}, |
|||
|
|||
/** |
|||
* Show modal |
|||
* |
|||
* @return void |
|||
* */ |
|||
show: function(){ |
|||
this.model.set('open', 1); |
|||
}, |
|||
|
|||
/** |
|||
* Set title |
|||
* @param {String} v Title |
|||
* |
|||
* @return this |
|||
* */ |
|||
setTitle: function(v){ |
|||
this.model.set('title',v); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Set content |
|||
* @param {String} v Title |
|||
* |
|||
* @return this |
|||
* */ |
|||
setContent: function(v){ |
|||
this.model.set('content',v); |
|||
return this; |
|||
}, |
|||
|
|||
render : function(){ |
|||
var obj = this.model.toJSON(); |
|||
obj.pfx = this.pfx; |
|||
this.$el.html( this.template(obj) ); |
|||
this.$el.attr('class', this.pfx + 'container'); |
|||
this.updateOpen(); |
|||
|
|||
console.log('Modal rendered'); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,10 @@ |
|||
define(function () { |
|||
return { |
|||
stylePrefix : 'nv-', |
|||
sortable : true, |
|||
hidable : true, |
|||
containerId : 'navigator', |
|||
itemClass : 'item', |
|||
itemsClass : 'items', |
|||
}; |
|||
}); |
|||
@ -0,0 +1,40 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class Navigator |
|||
* @param {Object} Collection |
|||
* @param {Object} Configurations |
|||
* */ |
|||
function Navigator(collection, c) |
|||
{ |
|||
var config = c, |
|||
defaults = require('./config/config'), |
|||
ItemsView = require('./view/ItemsView'); |
|||
|
|||
// Set default options
|
|||
for (var name in defaults) { |
|||
if (!(name in config)) |
|||
config[name] = defaults[name]; |
|||
} |
|||
|
|||
var obj = { |
|||
collection : collection, |
|||
config : config, |
|||
}; |
|||
|
|||
// Check if sort is required
|
|||
if(config.sortable){ |
|||
var ItemSort = require('./view/ItemSort'); |
|||
obj.sorter = new ItemSort({config : config}); |
|||
} |
|||
|
|||
this.ItemsView = new ItemsView(obj); |
|||
} |
|||
|
|||
Navigator.prototype = { |
|||
render : function(){ |
|||
return this.ItemsView.render().$el; |
|||
}, |
|||
}; |
|||
|
|||
return Navigator; |
|||
}); |
|||
@ -0,0 +1,15 @@ |
|||
<% if (hidable) { %> |
|||
<i id="<%= prefix %>btn-eye" class="btn fa fa-eye <%= (visible ? '' : 'fa-eye-slash') %>"></i> |
|||
<% } %> |
|||
<div class="<%= prefix %>title <%= addClass %>"> |
|||
<i id="<%= prefix %>caret" class="fa fa-chevron-right"></i> |
|||
<%= title %> |
|||
</div> |
|||
|
|||
<div id="<%= prefix %>counter"><%= (count ? count : '') %></div> |
|||
|
|||
<div id="<%= prefix %>move"> |
|||
<i class="fa fa-arrows"></i> |
|||
</div> |
|||
|
|||
<div class="<%= prefix %>children"></div> |
|||
@ -0,0 +1,330 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
/** |
|||
* @class ItemSort |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
_.bindAll(this,'startMove','onMove','endMove','rollback', 'itemLeft'); |
|||
this.config = o.config || {}; |
|||
this.pfx = o.config.stylePrefix; |
|||
this.itemClass = '.' + this.pfx + this.config.itemClass; |
|||
this.itemsClass = '.' + this.pfx + this.config.itemsClass; |
|||
this.setElement('.'+this.pfx+this.config.containerId); |
|||
}, |
|||
|
|||
/** |
|||
* Picking component to move |
|||
* @param {Object} Element view |
|||
* @param {Object} Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
startMove: function(eV, e){ |
|||
this.moved = false; |
|||
this.eV = eV; |
|||
this.$sel = this.eV.$el; |
|||
this.$selParent = this.$sel.closest(this.itemsClass); |
|||
|
|||
// In case the component selected is not movable
|
|||
if( !eV.model.get('movable') ) |
|||
return; |
|||
|
|||
// Create placeholder if not exists
|
|||
if(!this.$plh){ |
|||
var pfx = this.pfx; |
|||
this.$plh = $('<div>', {id: pfx + 'placeholder'}).css({'pointer-events':'none'}).hide(); |
|||
this.$plh.append( $('<div>', {id: pfx + "plh-int", class: pfx + 'insert'} ) ); |
|||
|
|||
if(!this.$el.length) |
|||
this.$el = $('.'+this.pfx+this.config.containerId); |
|||
|
|||
this.$plh.appendTo(this.$el); |
|||
} |
|||
this.$plh.data('hide',1); |
|||
eV.freeze(); |
|||
this.$el.on('mousemove',this.onMove); |
|||
$(document).on('mouseup',this.endMove); |
|||
$(document).on('keypress',this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* Get children dimensions |
|||
* @param {Object} Parent element |
|||
* |
|||
* @retun {Array} |
|||
* */ |
|||
getChildrenDim: function(el){ |
|||
var dim = [], |
|||
p = el || this.$targetEl.parent(), |
|||
oT = this.elT, |
|||
oL = this.elL, |
|||
ch = p.children('.' + this.pfx + this.config.itemClass); |
|||
ch.each(function(){ |
|||
var $el = $(this), |
|||
$elO = $el.offset(); |
|||
dim.push( [ $elO.top - oT, $elO.left - oL, $el.outerHeight(), $el.outerWidth(), true, this]); |
|||
}); |
|||
return dim; |
|||
}, |
|||
|
|||
/** |
|||
* During move |
|||
* @param {Object} Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
onMove: function(e){ |
|||
this.moved = true; |
|||
|
|||
if(this.$plh.data('hide')){ |
|||
this.$plh.show(); |
|||
this.$plh.data('hide',0); |
|||
} |
|||
var eO = this.$el.offset(); |
|||
this.elT = eO.top; |
|||
this.elL = eO.left; |
|||
this.rY = (e.pageY - this.elT) + this.$el.scrollTop(); |
|||
this.rX = (e.pageX - this.elL) + this.$el.scrollLeft(); |
|||
this.inspect(e); |
|||
this.updatePosition(this.rX, this.rY); |
|||
var actualPos = this.posIndex+':'+this.posMethod; |
|||
|
|||
//If there is a significant changes with the pointer
|
|||
if(!this.lastPos || (this.lastPos != actualPos)){ |
|||
this.updatePlaceholderPos(this.posIndex, this.posMethod); |
|||
this.lastPos = this.posIndex+':'+this.posMethod; |
|||
} |
|||
//Working alternative for find taget element
|
|||
//var $targetEl = this.$selParent.children('.'+this.pfx+this.config.itemClass).eq(this.aIndex);
|
|||
}, |
|||
|
|||
/** |
|||
* Search where to put placeholder |
|||
* @param int X position of the mouse |
|||
* @param int Y position of the mouse |
|||
* @retun void |
|||
* */ |
|||
updatePosition: function( posX, posY ){ |
|||
this.posMethod = "before"; |
|||
this.posIndex = 0; |
|||
var leftLimit = 0, xLimit = 0, dimRight = 0, yLimit = 0, xCenter = 0, yCenter = 0, dimDown = 0, dim = 0; |
|||
for(var i = 0; i < this.cDim.length; i++){ //Dim => t,l,h,w
|
|||
dim = this.cDim[i]; |
|||
dimDown = dim[0] + dim[2]; |
|||
yCenter = dim[0] + (dim[2] / 2); //Horizontal center
|
|||
xCenter = dim[1] + (dim[3] / 2); //Vertical center
|
|||
dimRight = dim[1] + dim[3]; |
|||
if( (xLimit && dim[1] > xLimit) || (yLimit && yCenter > yLimit) || |
|||
(leftLimit && dimRight < leftLimit)) //No need with this one if over the limit
|
|||
continue; |
|||
if(!dim[4]){ //If it's not inFlow (like float element)
|
|||
if( posY < dimDown) |
|||
yLimit = dimDown; |
|||
if( posX < xCenter){ //If mouse lefter than center
|
|||
xLimit = xCenter; |
|||
this.posMethod = "before"; |
|||
}else{ |
|||
leftLimit = xCenter; |
|||
this.posMethod = "after"; |
|||
} |
|||
this.posIndex = i; |
|||
}else{ |
|||
this.posIndex = this.aIndex = i; |
|||
if( posY < yCenter ){ //If mouse upper than center
|
|||
this.posMethod = "before"; //Should place helper before
|
|||
if(posY < dim[0]) |
|||
this.aIndex = i - 1; |
|||
break; //No need to continue under inFlow element
|
|||
}else |
|||
this.posMethod = "after"; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Updates the position of the placeholder |
|||
* @param int Index of the nearest child |
|||
* @param str Before or after position |
|||
* @return void |
|||
* */ |
|||
updatePlaceholderPos: function(index, method){ |
|||
var marg = 0, t = 0, l = 0, w = 0, h = 0, |
|||
un = 'px', |
|||
margI = 5, |
|||
plh = this.$plh[0]; |
|||
if( this.cDim[index] ){ |
|||
var elDim = this.cDim[index]; |
|||
//If it's like with 'float' style
|
|||
if(!elDim[4]){ |
|||
w = 'auto'; |
|||
h = elDim[2] - (marg * 2) + un; |
|||
t = elDim[0] + marg; |
|||
l = (method == 'before') ? (elDim[1] - marg) : (elDim[1] + elDim[3] - marg); |
|||
}else{ |
|||
//w = '100%';
|
|||
w = elDim[3] + un; |
|||
//h = elDim[3] + un;
|
|||
t = (method == 'before') ? (elDim[0] - marg) : (elDim[0] + elDim[2] - marg); |
|||
l = elDim[1]; |
|||
} |
|||
}else{ |
|||
if(this.$targetEl){ |
|||
var trg = this.$targetEl[0], |
|||
$elO = this.$targetEl.offset(); |
|||
t = $elO.top - this.elT + margI + 17; |
|||
l = $elO.left - this.elL + margI * 7; |
|||
w = (parseInt(trg.offsetWidth) - margI * 14) + un; |
|||
} |
|||
} |
|||
plh.style.top = t + un; |
|||
plh.style.left = l + un; |
|||
if(w) |
|||
plh.style.width = w; |
|||
if(h) |
|||
plh.style.height = h; |
|||
}, |
|||
|
|||
/** |
|||
* Leave item |
|||
* @param event |
|||
* |
|||
* @return void |
|||
* */ |
|||
endMove: function(e){ |
|||
this.$el.off('mousemove',this.onMove); |
|||
$(document).off('mouseup', this.endMove); |
|||
$(document).off('keypress', this.rollback); |
|||
this.eV.unfreeze(); |
|||
this.$plh.hide(); |
|||
if(this.moved) |
|||
this.move(this.$targetEl, this.$sel, this.posIndex, this.posMethod); |
|||
this.itemLeft(); |
|||
}, |
|||
|
|||
/** |
|||
* Move component to new position |
|||
* @param {Object} Component to move |
|||
* @param {Object} Target component |
|||
* @param {Integer} Indicates the position inside the collection |
|||
* @param {String} Before of after component |
|||
* |
|||
* @return void |
|||
* */ |
|||
move: function(target, el, posIndex, method){ |
|||
var trg = target|| this.$targetEl; |
|||
trg = trg || this.$backupEl; |
|||
if(!trg) |
|||
return; |
|||
var index = posIndex || 0; |
|||
var model = el.data("model"); |
|||
var collection = model.collection; |
|||
var targetModel = trg.data('model'); |
|||
var targetCollection = targetModel.collection; |
|||
|
|||
if(!this.cDim.length) |
|||
targetCollection = targetModel.get('components'); |
|||
|
|||
if(targetCollection && targetModel.get('droppable')){ |
|||
index = method == 'after' ? index + 1 : index; |
|||
var modelTemp = targetCollection.add({style:{}}, { at: index}); |
|||
var modelRemoved = collection.remove(model, { silent:false }); |
|||
targetCollection.add(modelRemoved, { at: index, silent:false }); |
|||
targetCollection.remove(modelTemp); |
|||
}else |
|||
console.warn("Invalid target position"); |
|||
}, |
|||
|
|||
/** |
|||
* Track inside which element pointer entered |
|||
* @param event |
|||
* |
|||
* @return void |
|||
* */ |
|||
inspect: function(e){ |
|||
var item = $(e.target).closest(this.itemClass); |
|||
if(!this.$targetEl || (item.length && item[0] != this.$targetEl[0]) ){ |
|||
this.status = 1; |
|||
if(item.length){ |
|||
this.$targetEl = this.$backupEl = item; |
|||
this.$targetElP = this.$targetEl.parent(); |
|||
this.$targetsEl = this.$targetEl.find(this.itemsClass + ':first'); |
|||
this.$targetEl.on('mouseleave', this.itemLeft); |
|||
this.targetM = this.$targetEl.data('model'); |
|||
this.dimT = this.getTargetDim(this.$targetEl[0]); |
|||
this.cDim = this.getChildrenDim(); |
|||
} |
|||
}else if( this.nearToBorders(this.$targetEl[0]) || this.$targetEl[0] == this.$sel[0] ){ |
|||
if(this.status == 1){ |
|||
this.status = 2; |
|||
this.lastPos = null; |
|||
this.cDim = this.getChildrenDim(this.$targetElP); |
|||
} |
|||
}else if( !this.nearToBorders(this.$targetEl[0]) ){ |
|||
if(this.status == 2){ |
|||
this.status = 1; |
|||
this.lastPos = null; |
|||
} |
|||
this.cDim = []; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Triggered when pointer leaves item |
|||
* @param event |
|||
* |
|||
* @return void |
|||
* */ |
|||
itemLeft: function(e){ |
|||
if(this.$targetEl){ |
|||
this.$targetEl.off('mouseleave',this.itemLeft); |
|||
this.$targetEl = null; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Returns dimension of the target |
|||
* @param Event |
|||
* |
|||
* @return Array |
|||
* */ |
|||
getTargetDim: function(e){ |
|||
var $el = $(e), |
|||
$elO = $el.offset(); |
|||
return [ $elO.top - this.elT, $elO.left - this.elL, $el.outerHeight(), $el.outerWidth() ]; |
|||
}, |
|||
|
|||
/** |
|||
* Check if pointer is near to the borders of the target |
|||
* @param event |
|||
* @return Bool |
|||
* */ |
|||
nearToBorders: function(e){ |
|||
var m = 10; //Limit in pixels for be near
|
|||
if(!this.dimT) |
|||
return; |
|||
var dimT = this.dimT; |
|||
if( ((dimT[0] + m) > this.rY) || (this.rY > (dimT[0] + dimT[2] - m)) || |
|||
((dimT[1] + m) > this.rX) || (this.rX > (dimT[1] + dimT[3] - m)) ) |
|||
return 1; |
|||
else |
|||
return 0; |
|||
}, |
|||
|
|||
/** |
|||
* Rollback to previous situation |
|||
* @param Event |
|||
* @param Bool Indicates if rollback in anycase |
|||
* @return void |
|||
* */ |
|||
rollback: function(e, force){ |
|||
var key = e.which || e.keyCode; |
|||
if(key == 27 || force){ |
|||
this.moved = false; |
|||
this.endMove(); |
|||
} |
|||
return; |
|||
}, |
|||
}); |
|||
}); |
|||
@ -0,0 +1,198 @@ |
|||
define(['backbone', 'text!./../template/item.html','require'], |
|||
function (Backbone, ItemTemplate, require) { |
|||
/** |
|||
* @class ItemView |
|||
* */ |
|||
|
|||
return Backbone.View.extend({ |
|||
|
|||
template: _.template(ItemTemplate), |
|||
|
|||
initialize: function(o){ |
|||
this.opt = o; |
|||
this.config = o.config; |
|||
this.sorter = o.sorter || {}; |
|||
this.pfx = this.config.stylePrefix; |
|||
if(typeof this.model.get('open') == 'undefined') |
|||
this.model.set('open',false); |
|||
this.listenTo(this.model.components, 'remove add change reset', this.checkChildren); |
|||
this.listenTo(this.model, 'destroy remove', this.remove); |
|||
//this.listenTo(this.model, 'change:status', this.updateStatus);
|
|||
this.listenTo(this.model, 'change:open', this.updateOpening); |
|||
this.className = this.pfx + 'item no-select'; |
|||
this.events = {}; |
|||
this.events['click > #'+this.pfx+'btn-eye'] = 'toggleVisibility'; |
|||
this.events['click .'+this.pfx+'title'] = 'toggleOpening'; |
|||
this.$el.data("model", this.model); |
|||
if(o.config.sortable) |
|||
this.events['mousedown > #'+this.pfx+'move'] = 'startSort'; |
|||
}, |
|||
|
|||
/** |
|||
* Update item opening |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateOpening: function (){ |
|||
if(this.model.get('open')){ |
|||
this.$el.addClass("open"); |
|||
this.$caret.addClass('fa-chevron-down'); |
|||
}else{ |
|||
this.$el.removeClass("open"); |
|||
this.$caret.removeClass('fa-chevron-down'); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Toggle item opening |
|||
* @param {Object} e |
|||
* |
|||
* @return void |
|||
* */ |
|||
toggleOpening: function(e){ |
|||
e.stopPropagation(); |
|||
if(!this.model.components.length) |
|||
return; |
|||
this.model.set('open', !this.model.get('open') ); |
|||
}, |
|||
|
|||
/** |
|||
* Delegate to sorter |
|||
* @param Event |
|||
* */ |
|||
startSort: function(e){ |
|||
if(this.sorter) |
|||
this.sorter.startMove(this, e); |
|||
}, |
|||
|
|||
/** |
|||
* Freeze item |
|||
* @return void |
|||
* */ |
|||
freeze: function(){ |
|||
this.$el.addClass(this.pfx + 'opac50'); |
|||
this.model.set('open',0); |
|||
}, |
|||
|
|||
/** |
|||
* Unfreeze item |
|||
* @return void |
|||
* */ |
|||
unfreeze: function(){ |
|||
this.$el.removeClass(this.pfx + 'opac50'); |
|||
}, |
|||
|
|||
/** |
|||
* Update item on status change |
|||
* @param Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateStatus: function(e){ |
|||
var s = this.model.get('status'), |
|||
pr = this.model.get('previousModel'), |
|||
pfx = this.pfx; |
|||
switch(s) { |
|||
case 'selected': |
|||
this.$el.addClass(pfx + 'selected'); |
|||
break; |
|||
case 'moving': |
|||
break; |
|||
default: |
|||
this.$el.removeClass(pfx + 'selected'); |
|||
} |
|||
if(pr){ |
|||
pr.set('previousModel',''); |
|||
pr.set('status',''); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Toggle visibility |
|||
* @param Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
toggleVisibility: function(e){ |
|||
if(!this.$eye) |
|||
this.$eye = this.$el.find('> #'+this.pfx+'btn-eye'); |
|||
|
|||
var cCss = _.clone(this.model.get('style')), |
|||
hClass = this.pfx + 'hide'; |
|||
if(this.isVisible()){ |
|||
this.$el.addClass(hClass); |
|||
this.$eye.addClass('fa-eye-slash'); |
|||
cCss.display = 'none'; |
|||
}else{ |
|||
this.$el.removeClass(hClass); |
|||
this.$eye.removeClass('fa-eye-slash'); |
|||
delete cCss.display; |
|||
} |
|||
this.model.set('style', cCss); |
|||
}, |
|||
|
|||
/** |
|||
* Check if component is visible |
|||
* |
|||
* @return bool |
|||
* */ |
|||
isVisible: function(){ |
|||
var css = this.model.get('style'), |
|||
pr = css.display; |
|||
if(pr && pr == 'none' ) |
|||
return; |
|||
return 1; |
|||
}, |
|||
|
|||
/** |
|||
* Update item aspect after children changes |
|||
* |
|||
* @return void |
|||
* */ |
|||
checkChildren: function(){ |
|||
var c = this.model.components.length, |
|||
pfx = this.pfx; |
|||
if(!this.$counter) |
|||
this.$counter = this.$el.find('> #' + pfx + 'counter'); |
|||
if(c){ |
|||
this.$el.find('> .' + pfx + 'title').removeClass(pfx + 'no-chld'); |
|||
this.$counter.html(c); |
|||
}else{ |
|||
this.$el.find('> .' + pfx + 'title').addClass(pfx + 'no-chld'); |
|||
this.$counter.empty(); |
|||
this.model.set('open',0); |
|||
} |
|||
}, |
|||
|
|||
render : function(){ |
|||
var pfx = this.pfx, |
|||
vis = this.isVisible(); |
|||
this.$el.html( this.template({ |
|||
title : this.model.getName(), |
|||
addClass : (this.model.components.length ? '' : pfx+'no-chld'), |
|||
count : this.model.components.length, |
|||
visible : vis, |
|||
hidable : this.config.hidable, |
|||
prefix : pfx |
|||
})); |
|||
if(typeof ItemsView == 'undefined') |
|||
ItemsView = require('./ItemsView'); |
|||
this.$components = new ItemsView({ |
|||
collection : this.model.components, |
|||
config : this.config, |
|||
sorter : this.sorter, |
|||
parent : this.model |
|||
}).render().$el; |
|||
this.$el.find('.'+ pfx +'children').html(this.$components); |
|||
this.$caret = this.$el.find('> .' + pfx + 'title > #' + pfx + 'caret'); |
|||
if(!this.model.get('movable') || !this.config.sortable){ |
|||
this.$el.find('> #' + pfx + 'move').detach(); |
|||
} |
|||
if(!vis) |
|||
this.className += ' ' + pfx + 'hide'; |
|||
this.$el.attr('class', _.result(this, 'className')); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,89 @@ |
|||
define(['backbone','./ItemView'], |
|||
function (Backbone, ItemView) { |
|||
/** |
|||
* @class ItemsView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
this.opt = o; |
|||
this.config = o.config; |
|||
this.preview = o.preview; |
|||
this.sorter = o.sorter || {}; |
|||
this.pfx = o.config.stylePrefix; |
|||
this.parent = o.parent; |
|||
this.listenTo( this.collection, 'add', this.addTo ); |
|||
this.listenTo( this.collection, 'reset', this.render ); |
|||
this.className = this.pfx + 'items'; |
|||
|
|||
if(!this.parent) |
|||
this.className += ' ' + this.pfx + this.config.containerId; |
|||
}, |
|||
|
|||
/** |
|||
* Add to collection |
|||
* @param Object Model |
|||
* |
|||
* @return Object |
|||
* */ |
|||
addTo: function(model){ |
|||
var i = this.collection.indexOf(model); |
|||
this.addToCollection(model, null, i); |
|||
}, |
|||
|
|||
/** |
|||
* Add new object to collection |
|||
* @param Object Model |
|||
* @param Object Fragment collection |
|||
* @param integer Index of append |
|||
* |
|||
* @return Object Object created |
|||
* */ |
|||
addToCollection: function(model, fragmentEl, index){ |
|||
var fragment = fragmentEl || null; |
|||
var viewObject = ItemView; |
|||
|
|||
var view = new viewObject({ |
|||
model : model, |
|||
config : this.config, |
|||
sorter : this.sorter, |
|||
}); |
|||
var rendered = view.render().el; |
|||
|
|||
if(fragment){ |
|||
fragment.appendChild(rendered); |
|||
}else{ |
|||
if(typeof index != 'undefined'){ |
|||
var method = 'before'; |
|||
// If the added model is the last of collection
|
|||
// need to change the logic of append
|
|||
if(this.$el.children().length == index){ |
|||
index--; |
|||
method = 'after'; |
|||
} |
|||
// In case the added is new in the collection index will be -1
|
|||
if(index < 0){ |
|||
this.$el.append(rendered); |
|||
}else |
|||
this.$el.children().eq(index)[method](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', _.result(this, 'className')); |
|||
return this; |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,48 @@ |
|||
define(function () { |
|||
return { |
|||
stylePrefix : 'pn-', |
|||
|
|||
defaults : [{ |
|||
id : 'commands', |
|||
buttons : [{ id: 'select', className: 'fa fa-mouse-pointer', command: 'select-comp', attributes: {title:'Create'}}, |
|||
{ id: 'create', className: 'fa fa-plus-square-o', command: 'create-comp', |
|||
buttons: [ |
|||
{ id: 'image2', className: 'fa fa-picture-o', command: 'image-comp' }, |
|||
{ id: 'move2', className: 'fa fa-arrows', command: 'move-comp' }, |
|||
{ id: 'text2', className: 'fa fa-font' , command: 'text-comp' }, |
|||
{ id: 'var', className: 'fa fa-hashtag', command: 'insert-var', |
|||
options: { content: '{{ VAR22 }}', terminateAfterInsert: false, }, }, |
|||
] }, |
|||
{ id: 'remove', className: 'fa fa-minus-square-o', command: 'delete-comp' }, |
|||
{ id: 'move', className: 'fa fa-arrows', command: 'move-comp' }, |
|||
{ id: 'resize', className: 'fa fa-arrows-alt', command: 'resize-comp' }, |
|||
{ id: 'text', className: 'fa fa-font' , command: 'text-comp' }, |
|||
{ id: 'image', className: 'fa fa-picture-o', command: 'image-comp' }, |
|||
{ id: 'var', className: 'fa fa-hashtag', command: 'insert-var', |
|||
options: { content: '{{ VAR11 }}', terminateAfterInsert: true, }, |
|||
buttons: [ |
|||
{ id: 'image2', className: 'fa fa-picture-o', command: 'image-comp' }, |
|||
{ id: 'move2', className: 'fa fa-arrows', command: 'move-comp' }, |
|||
{ id: 'text2', className: 'fa fa-font' , command: 'text-comp' }, |
|||
{ id: 'var', className: 'fa fa-hashtag', command: 'insert-var', |
|||
options: { content: '{{ VAR22 }}', terminateAfterInsert: false, }, }, |
|||
]}, |
|||
], |
|||
},{ |
|||
id : 'options', |
|||
buttons : [{ id: 'visibility', className: 'fa fa-eye', command: 'sw-visibility', active: true, context: 'sw-visibility' }, |
|||
//{ id: 'select2', className: 'fa fa-mouse-pointer', command: 'select-comp' },
|
|||
{ id: 'export', className: 'fa fa-code', command: 'export-template' },], |
|||
},{ |
|||
id : 'views', |
|||
buttons : [{ id: 'open-sm', className: 'fa fa-paint-brush', command: 'open-sm'}, |
|||
{ id: 'open-layers', className: 'fa fa-bars', command: 'open-layers' },], |
|||
}], |
|||
|
|||
// Editor model
|
|||
em : null, |
|||
|
|||
// Delay before show children buttons (in milliseconds)
|
|||
delayBtnsShow : 300, |
|||
}; |
|||
}); |
|||
@ -0,0 +1,74 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class Panel |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function Panel(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Panels = require('./model/Panels'), |
|||
PanelsView = require('./view/PanelsView'); |
|||
|
|||
// Set default options
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.panels = new Panels(c.defaults); |
|||
var obj = { |
|||
collection : this.panels, |
|||
config : c, |
|||
}; |
|||
|
|||
this.PanelsView = new PanelsView(obj); |
|||
} |
|||
|
|||
Panel.prototype = { |
|||
|
|||
getPanels : function(){ |
|||
return this.panels; |
|||
}, |
|||
|
|||
addPanel : function(obj){ |
|||
return this.panels.add(obj); |
|||
}, |
|||
|
|||
getPanel : function(id){ |
|||
var res = this.panels.where({id: id}); |
|||
return res.length ? res[0] : null; |
|||
}, |
|||
|
|||
addButton : function(panelId, obj){ |
|||
var pn = this.getPanel(panelId); |
|||
return pn ? pn.get('buttons').add(obj) : null; |
|||
}, |
|||
|
|||
getButton : function(panelId, id){ |
|||
var pn = this.getPanel(panelId); |
|||
if(pn){ |
|||
var res = pn.get('buttons').where({id: id}); |
|||
return res.length ? res[0] : null; |
|||
} |
|||
return null; |
|||
}, |
|||
|
|||
active : function(){ |
|||
this.getPanels().each(function(p){ |
|||
p.get('buttons').each(function(btn){ |
|||
if(btn.get('active')) |
|||
btn.trigger('updateActive'); |
|||
}); |
|||
}); |
|||
}, |
|||
|
|||
render : function(){ |
|||
return this.PanelsView.render().el; |
|||
}, |
|||
}; |
|||
|
|||
return Panel; |
|||
}); |
|||
@ -0,0 +1,26 @@ |
|||
define([ 'backbone','require'], |
|||
function (Backbone, require) { |
|||
/** |
|||
* @class Button |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
id : '', |
|||
className : '', |
|||
command : '', |
|||
context : '', |
|||
buttons : [], |
|||
attributes : {}, |
|||
active : false, |
|||
}, |
|||
|
|||
initialize: function(options) { |
|||
if(this.get('buttons').length){ |
|||
var Buttons = require('./Buttons'); |
|||
this.set('buttons', new Buttons(this.get('buttons')) ); |
|||
} |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,44 @@ |
|||
define([ 'backbone','./Button'], |
|||
function (Backbone, Button) { |
|||
/** |
|||
* @class Buttons |
|||
* */ |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Button, |
|||
|
|||
/** |
|||
* Deactivate all buttons, except one passed |
|||
* @param {Object} except Model to ignore |
|||
* @param {Boolean} r Recursive flag |
|||
* |
|||
* @return void |
|||
* */ |
|||
deactivateAllExceptOne: function(except, r){ |
|||
this.forEach(function(model, index) { |
|||
if(model !== except){ |
|||
model.set('active', false); |
|||
if(r && model.get('buttons').length) |
|||
model.get('buttons').deactivateAllExceptOne(except,r); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* Deactivate all buttons |
|||
* @param {String} context Context string |
|||
* |
|||
* @return void |
|||
* */ |
|||
deactivateAll: function(context){ |
|||
this.forEach(function(model, index) { |
|||
if( model.get('context') == context ){ |
|||
model.set('active', false); |
|||
if(model.get('buttons').length) |
|||
model.get('buttons').deactivateAll(context); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,22 @@ |
|||
define([ 'backbone','./Buttons'], |
|||
function (Backbone, Buttons) { |
|||
/** |
|||
* @class Panel |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults :{ |
|||
id : '', |
|||
content : '', |
|||
visible : true, |
|||
buttons : [], |
|||
}, |
|||
|
|||
initialize: function(options) { |
|||
this.btn = this.get('buttons') || []; |
|||
this.buttons = new Buttons(this.btn); |
|||
this.set('buttons', this.buttons); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,11 @@ |
|||
define([ 'backbone','./Panel'], |
|||
function (Backbone, Panel) { |
|||
/** |
|||
* @class Panels |
|||
* */ |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Panel, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,236 @@ |
|||
define(['backbone','require'], |
|||
function(Backbone, require) { |
|||
/** |
|||
* @class ButtonView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
tagName : 'span', |
|||
|
|||
events : { 'click' : 'clicked' }, |
|||
|
|||
initialize: function(o){ |
|||
_.bindAll(this, 'startTimer', 'stopTimer', 'showButtons', 'hideButtons','closeOnKeyPress'); |
|||
this.config = o.config; |
|||
this.em = this.config.em || {}; |
|||
this.pfx = this.config.stylePrefix; |
|||
this.id = this.pfx + this.model.get('id'); |
|||
this.className = this.pfx + 'btn ' + this.model.get('className'); |
|||
this.activeCls = this.pfx + 'active'; |
|||
this.btnsVisCls = this.pfx + 'visible'; |
|||
this.parentM = o.parentM || null; |
|||
this.listenTo(this.model, 'change:active updateActive', this.updateActive); |
|||
this.listenTo(this.model, 'checkActive', this.checkActive); |
|||
this.listenTo(this.model, 'change:bntsVis', this.updateBtnsVis); |
|||
this.listenTo(this.model, 'change:attributes', this.updateAttributes); |
|||
this.listenTo(this.model, 'change:className', this.updateClassName); |
|||
|
|||
if(this.model.get('buttons').length){ |
|||
this.$el.disableSelection(); |
|||
this.$el.on('mousedown', this.startTimer); |
|||
this.$el.append($('<div>',{class: this.pfx + 'arrow-rd'})); |
|||
} |
|||
|
|||
if(this.em) |
|||
this.commands = this.em.get('Commands'); |
|||
}, |
|||
|
|||
/** |
|||
* Updates class name of the button |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateClassName: function() |
|||
{ |
|||
this.$el.attr('class', this.pfx + 'btn ' + this.model.get('className')); |
|||
}, |
|||
|
|||
/** |
|||
* Updates attributes of the button |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateAttributes: function() |
|||
{ |
|||
this.$el.attr(this.model.get("attributes")); |
|||
}, |
|||
|
|||
/** |
|||
* Updates visibility of children buttons |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateBtnsVis: function() |
|||
{ |
|||
if(!this.$buttons) |
|||
return; |
|||
|
|||
if(this.model.get('bntsVis')) |
|||
this.$buttons.addClass(this.btnsVisCls); |
|||
else |
|||
this.$buttons.removeClass(this.btnsVisCls); |
|||
}, |
|||
|
|||
/** |
|||
* Start timer for showing children buttons |
|||
* |
|||
* @return void |
|||
* */ |
|||
startTimer: function() |
|||
{ |
|||
this.timeout = setTimeout(this.showButtons, this.config.delayBtnsShow); |
|||
$(document).on('mouseup', this.stopTimer); |
|||
}, |
|||
|
|||
/** |
|||
* Stop timer for showing children buttons |
|||
* |
|||
* @return void |
|||
* */ |
|||
stopTimer: function() |
|||
{ |
|||
$(document).off('mouseup', this.stopTimer); |
|||
if(this.timeout) |
|||
clearTimeout(this.timeout); |
|||
}, |
|||
|
|||
/** |
|||
* Show children buttons |
|||
* |
|||
* @return void |
|||
* */ |
|||
showButtons: function() |
|||
{ |
|||
clearTimeout(this.timeout); |
|||
this.model.set('bntsVis', true); |
|||
$(document).on('mousedown', this.hideButtons); |
|||
$(document).on('keypress', this.closeOnKeyPress); |
|||
}, |
|||
/** |
|||
* Hide children buttons |
|||
* |
|||
* @return void |
|||
* */ |
|||
hideButtons: function(e) |
|||
{ |
|||
if(e){ $(e.target).trigger('click'); } |
|||
this.model.set('bntsVis', false); |
|||
$(document).off('mousedown', this.hideButtons); |
|||
$(document).off('keypress', this.closeOnKeyPress); |
|||
}, |
|||
|
|||
/** |
|||
* Close buttons on ESC key press |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
closeOnKeyPress: function(e) |
|||
{ |
|||
var key = e.which || e.keyCode; |
|||
if(key == 27) |
|||
this.hideButtons(); |
|||
}, |
|||
|
|||
/** |
|||
* Update active status of the button |
|||
* |
|||
* @return void |
|||
* */ |
|||
updateActive: function(){ |
|||
var command = null; |
|||
|
|||
if(this.commands) |
|||
command = this.commands.get(this.model.get('command')); |
|||
|
|||
if(this.model.get('active')){ |
|||
//this.$el.addClass(this.activeCls);
|
|||
//this.model.collection.deactivateAllExceptOne(this.model);
|
|||
|
|||
this.model.collection.deactivateAll(this.model.get('context')); |
|||
this.model.set('active', true, { silent: true }).trigger('checkActive'); |
|||
|
|||
if(this.parentM) |
|||
this.parentM.set('active', true, { silent: true }).trigger('checkActive'); |
|||
|
|||
if(command) |
|||
command.run(this.em, this.model); |
|||
}else{ |
|||
this.$el.removeClass(this.activeCls); |
|||
|
|||
this.model.collection.deactivateAll(this.model.get('context')); |
|||
|
|||
if(this.parentM) |
|||
this.parentM.set('active', false, { silent: true }).trigger('checkActive'); |
|||
|
|||
if(command) |
|||
command.stop(this.em, this.model); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Update active style status |
|||
* |
|||
* @return void |
|||
* */ |
|||
checkActive: function(){ |
|||
if(this.model.get('active')) |
|||
this.$el.addClass(this.activeCls); |
|||
else |
|||
this.$el.removeClass(this.activeCls); |
|||
}, |
|||
|
|||
/** |
|||
* Triggered when button is clicked |
|||
* @param {Object} e Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
clicked: function(e) |
|||
{ |
|||
if(this.model.get('bntsVis') ) |
|||
return; |
|||
|
|||
if(this.parentM) |
|||
this.swapParent(); |
|||
|
|||
this.model.set('active', !this.model.get('active')); |
|||
}, |
|||
|
|||
/** |
|||
* Updates parent model swapping properties |
|||
* |
|||
* @return void |
|||
* */ |
|||
swapParent: function() |
|||
{ |
|||
this.parentM.collection.deactivateAll(this.model.get('context')); |
|||
this.parentM.set('attributes', this.model.get('attributes')); |
|||
this.parentM.set('options', this.model.get('options')); |
|||
this.parentM.set('command', this.model.get('command')); |
|||
this.parentM.set('className', this.model.get('className')); |
|||
this.parentM.set('active', true, { silent: true }).trigger('checkActive'); |
|||
}, |
|||
|
|||
render: function() |
|||
{ |
|||
this.updateAttributes(); |
|||
this.$el.attr('class', this.className); |
|||
|
|||
if(this.model.get('buttons').length){ |
|||
var btnsView = require('./ButtonsView'); //Avoid Circular Dependencies
|
|||
var view = new btnsView({ |
|||
collection : this.model.get('buttons'), |
|||
config : this.config, |
|||
parentM : this.model |
|||
}); |
|||
this.$buttons = view.render().$el; |
|||
this.$buttons.append($('<div>',{class: this.pfx + 'arrow-l'})); |
|||
this.$el.append(this.$buttons); //childNodes avoids wrapping 'div'
|
|||
} |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,68 @@ |
|||
define(['backbone','./ButtonView'], |
|||
function (Backbone, ButtonView) { |
|||
/** |
|||
* @class ButtonsView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
this.opt = o; |
|||
this.config = o.config; |
|||
this.pfx = o.config.stylePrefix; |
|||
this.parentM = o.parentM || null; |
|||
this.listenTo( this.collection, 'add', this.addTo ); |
|||
this.listenTo( this.collection, 'reset', this.render ); |
|||
this.className = this.pfx + 'buttons'; |
|||
}, |
|||
|
|||
/** |
|||
* Add to collection |
|||
* @param Object Model |
|||
* |
|||
* @return Object |
|||
* */ |
|||
addTo: function(model){ |
|||
this.addToCollection(model); |
|||
}, |
|||
|
|||
/** |
|||
* Add new object to collection |
|||
* @param Object Model |
|||
* @param Object Fragment collection |
|||
* |
|||
* @return Object Object created |
|||
* */ |
|||
addToCollection: function(model, fragmentEl){ |
|||
var fragment = fragmentEl || null; |
|||
var viewObject = ButtonView; |
|||
|
|||
var view = new viewObject({ |
|||
model : model, |
|||
config : this.config, |
|||
parentM : this.parentM |
|||
}); |
|||
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', _.result(this, 'className')); |
|||
return this; |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,50 @@ |
|||
define(['backbone','./ButtonsView'], |
|||
function(Backbone, ButtonsView) { |
|||
/** |
|||
* @class PanelView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o){ |
|||
this.config = o.config; |
|||
this.pfx = this.config.stylePrefix; |
|||
this.buttons = this.model.get('buttons'); |
|||
this.className = this.pfx + 'panel'; |
|||
this.id = this.pfx + this.model.get('id'); |
|||
this.listenTo(this.model, 'change:appendContent', this.appendContent); |
|||
this.listenTo(this.model, 'change:content', this.updateContent); |
|||
}, |
|||
|
|||
/** |
|||
* Append content of the panel |
|||
* */ |
|||
appendContent: function() |
|||
{ |
|||
this.$el.append(this.model.get('appendContent')); |
|||
}, |
|||
|
|||
/** |
|||
* Update content |
|||
* */ |
|||
updateContent: function() |
|||
{ |
|||
this.$el.html(this.model.get('content')); |
|||
}, |
|||
|
|||
|
|||
render: function() { |
|||
this.$el.attr('class', _.result(this, 'className')); |
|||
this.$el.attr('id', this.id); |
|||
if(this.buttons.length){ |
|||
var buttons = new ButtonsView({ |
|||
collection : this.buttons, |
|||
config : this.config, |
|||
}); |
|||
this.$el.append(buttons.render().el); |
|||
} |
|||
this.$el.append(this.model.get('content')); |
|||
return this; |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,67 @@ |
|||
define(['backbone','./PanelView'], |
|||
function (Backbone, PanelView) { |
|||
/** |
|||
* @class ItemsView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
this.opt = o; |
|||
this.config = o.config; |
|||
this.pfx = o.config.stylePrefix; |
|||
this.listenTo( this.collection, 'add', this.addTo ); |
|||
this.listenTo( this.collection, 'reset', this.render ); |
|||
this.className = this.pfx + 'panels'; |
|||
}, |
|||
|
|||
/** |
|||
* Add to collection |
|||
* @param Object Model |
|||
* |
|||
* @return Object |
|||
* */ |
|||
addTo: function(model){ |
|||
this.addToCollection(model); |
|||
}, |
|||
|
|||
/** |
|||
* Add new object to collection |
|||
* @param Object Model |
|||
* @param Object Fragment collection |
|||
* @param integer Index of append |
|||
* |
|||
* @return Object Object created |
|||
* */ |
|||
addToCollection: function(model, fragmentEl){ |
|||
var fragment = fragmentEl || null; |
|||
var viewObject = PanelView; |
|||
|
|||
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', _.result(this, 'className')); |
|||
return this; |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,23 @@ |
|||
define(function () { |
|||
return { |
|||
stylePrefix : 'rte-', |
|||
toolbarId : 'toolbar', |
|||
containerId : 'wrapper', |
|||
commands : [{ |
|||
command: 'bold', |
|||
title: 'Bold', |
|||
class: 'fa fa-bold', |
|||
group: 'format' |
|||
},{ |
|||
command: 'italic', |
|||
title: 'Italic', |
|||
class: 'fa fa-italic', |
|||
group: 'format' |
|||
},{ |
|||
command: 'underline', |
|||
title: 'Underline', |
|||
class: 'fa fa-underline', |
|||
group: 'format' |
|||
},], |
|||
}; |
|||
}); |
|||
@ -0,0 +1,131 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class RichTextEditor |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function RichTextEditor(config) |
|||
{ |
|||
var c = config || {}, |
|||
rte = require('rte'), |
|||
defaults = require('./config/config'), |
|||
CommandButtons = require('./model/CommandButtons'), |
|||
CommandButtonsView = require('./view/CommandButtonsView'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.tlbPfx = c.stylePrefix; |
|||
this.commands = new CommandButtons(c.commands); |
|||
var obj = { |
|||
collection : this.commands, |
|||
config : c, |
|||
}; |
|||
|
|||
this.toolbar = new CommandButtonsView(obj); |
|||
this.$toolbar = this.toolbar.render().$el; |
|||
} |
|||
|
|||
RichTextEditor.prototype = { |
|||
|
|||
/** |
|||
* Bind rich text editor to element |
|||
* @param {Object} view |
|||
* @param {Object} container |
|||
* |
|||
* @return void |
|||
* */ |
|||
bind : function(view, container){ |
|||
if(!this.$contaniner){ |
|||
this.$container = container; |
|||
this.$toolbar.appendTo(this.$container); |
|||
} |
|||
view.$el.wysiwyg({hotKeys: {}}).focus(); |
|||
this.updatePosition(view.$el); |
|||
this.bindToolbar(view).show(); |
|||
//Avoid closing edit mode clicking on toolbar
|
|||
this.$toolbar.on('mousedown', this.disableProp); |
|||
}, |
|||
|
|||
/** |
|||
* Unbind rich text editor from element |
|||
* @param {Object} view |
|||
* |
|||
* @return void |
|||
* */ |
|||
unbind : function(view){ |
|||
view.$el.wysiwyg('destroy'); |
|||
this.hide(); |
|||
this.$toolbar.off('mousedown', this.disableProp); |
|||
}, |
|||
|
|||
/** |
|||
* Bind toolbar to element |
|||
* @param {Object} view |
|||
* |
|||
* @return this |
|||
* */ |
|||
bindToolbar : function(view){ |
|||
var id = this.tlbPfx + view.model.cid, |
|||
dId = this.tlbPfx + 'inited'; |
|||
if(!view.$el.data(dId)){ |
|||
view.$el.data(dId, 1); |
|||
view.$el.attr('id',id); |
|||
} |
|||
this.toolbar.updateTarget('#' + id); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Update toolbar position |
|||
* @param {Object} $el Element |
|||
* |
|||
* @return void |
|||
*/ |
|||
updatePosition: function($el){ |
|||
var cOffset = this.$container.offset(), |
|||
cTop = cOffset ? cOffset.top : 0, |
|||
cLeft = cOffset ? cOffset.left : 0, |
|||
eOffset = $el.offset(), |
|||
rTop = eOffset.top - cTop + this.$container.scrollTop(), |
|||
rLeft = eOffset.left - cLeft + this.$container.scrollLeft(); |
|||
if(!this.tlbH) |
|||
this.tlbH = this.$toolbar.outerHeight(); |
|||
this.$toolbar.css({ |
|||
top : (rTop - this.tlbH - 5), |
|||
left : rLeft |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* Show toolbar |
|||
* |
|||
* @return void |
|||
* */ |
|||
show : function(){ |
|||
this.$toolbar.show(); |
|||
}, |
|||
|
|||
/** |
|||
* Hide toolbar |
|||
* |
|||
* @return void |
|||
* */ |
|||
hide : function(){ |
|||
this.$toolbar.hide(); |
|||
}, |
|||
|
|||
/** |
|||
* Isolate disable propagation method |
|||
* @param Event |
|||
* */ |
|||
disableProp: function(e){ |
|||
e.stopPropagation(); |
|||
}, |
|||
}; |
|||
|
|||
return RichTextEditor; |
|||
}); |
|||
@ -0,0 +1,16 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class CommandButton |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
command : '', |
|||
title : '', |
|||
class : '', |
|||
group : '', |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,11 @@ |
|||
define([ 'backbone','./CommandButton'], |
|||
function (Backbone, CommandButton) { |
|||
/** |
|||
* @class CommandButtons |
|||
* */ |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: CommandButton, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,20 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class CommandButtonView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
tagName: 'a', |
|||
|
|||
initialize: function(o){ |
|||
this.config = o.config || {}; |
|||
this.className = this.config.stylePrefix + 'btn ' + this.model.get('class'); |
|||
}, |
|||
|
|||
render: function() { |
|||
this.$el.attr('class', _.result( this, 'className' ) ); |
|||
return this; |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,51 @@ |
|||
define(['backbone','./CommandButtonView'], |
|||
function (Backbone, CommandButtonView) { |
|||
/** |
|||
* @class CommandButtonsView |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
className: 'no-dots', |
|||
|
|||
attributes : { |
|||
'data-role' : 'editor-toolbar', |
|||
}, |
|||
|
|||
initialize: function(o){ |
|||
this.config = o.config || {}; |
|||
this.id = this.config.stylePrefix + this.config.toolbarId; |
|||
this.$el.data('helper',1); |
|||
}, |
|||
|
|||
/** |
|||
* Update RTE target pointer |
|||
* @param {String} target |
|||
* |
|||
* @return this |
|||
* */ |
|||
updateTarget: function(target){ |
|||
this.$el.attr('data-target',target); |
|||
return this; |
|||
}, |
|||
|
|||
render: function() { |
|||
var fragment = document.createDocumentFragment(); |
|||
this.$el.empty(); |
|||
|
|||
this.collection.each(function(item){ |
|||
var view = new CommandButtonView({ |
|||
model : item, |
|||
config : this.config, |
|||
attributes : { |
|||
'title' : item.get('title'), |
|||
'data-edit' : item.get('command'), |
|||
}, |
|||
}); |
|||
fragment.appendChild(view.render().el); |
|||
},this); |
|||
this.$el.append(fragment); |
|||
this.$el.attr('id', _.result( this, 'id' ) ); |
|||
return this; |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,51 @@ |
|||
define(function () { |
|||
return { |
|||
// Enable/Disable autosaving
|
|||
autosave : 1, |
|||
|
|||
// Indicates which storage to use. Available: local | remote
|
|||
storageType : 'local', |
|||
|
|||
// If autosave enabled, indicates how many changes (general changes to structure)
|
|||
changesBeforeSave : 1, |
|||
|
|||
// Defaults for remote storage
|
|||
remoteStorage : { |
|||
//Enable/Disable components model (JSON format)
|
|||
storeComponents: true, |
|||
//Enable/Disable styles model (JSON format)
|
|||
storeStyles: false, |
|||
//Enable/Disable saving HTML template
|
|||
storeHTML: false, |
|||
/** |
|||
* Url where to save all stuff. |
|||
* The request will send a POST via AJAX, like this: |
|||
* { |
|||
* components: '', |
|||
* style: '', |
|||
* html: '', //if storeHTML is enabled
|
|||
* } |
|||
* */ |
|||
urlStore: '', |
|||
/** |
|||
* Use this url to fetch model data, does expect in response something like this: |
|||
* { data: { |
|||
* components: '', |
|||
* style: '', |
|||
* } } |
|||
*/ |
|||
urlLoad: '', |
|||
/** |
|||
* Url where assets will be send |
|||
* */ |
|||
urlUpload: '', |
|||
paramsStore :{}, //Custom parameters to pass with set request
|
|||
paramsLoad :{}, //Custom parameters to pass with get request
|
|||
beforeSend : function(jqXHR,settings){}, //Callback before request
|
|||
onComplete : function(jqXHR,status){}, //Callback after request
|
|||
}, |
|||
|
|||
// Defaults for local storage
|
|||
localStorage : {}, |
|||
}; |
|||
}); |
|||
@ -0,0 +1,184 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class StorageManager |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function StorageManager(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
LocalStorage = require('./model/LocalStorage'), |
|||
RemoteStorage = require('./model/RemoteStorage'), |
|||
StorageInterface = require('./model/StorageInterface'); |
|||
|
|||
for (var name in defaults){ |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.providers = {}; |
|||
this.defaultProviders = {}; |
|||
this.autosave = c.autosave; |
|||
this.currentProvider = c.storageType || null; |
|||
this.changesBeforeSave = c.changesBeforeSave; |
|||
this.si = new StorageInterface(); |
|||
|
|||
var Local = new LocalStorage(c.localStorage), |
|||
Remote = new RemoteStorage(c.remoteStorage); |
|||
|
|||
this.defaultProviders[Local.getId()] = Local; |
|||
this.defaultProviders[Remote.getId()] = Remote; |
|||
} |
|||
|
|||
StorageManager.prototype = { |
|||
|
|||
/** |
|||
* Check if autosave enabled |
|||
* |
|||
* @return boolean |
|||
* */ |
|||
isAutosave : function(){ |
|||
return this.autosave; |
|||
}, |
|||
|
|||
/** |
|||
* Set autosave |
|||
* @param {Mixed} v Value |
|||
* |
|||
* @return this |
|||
* */ |
|||
setAutosave : function(v){ |
|||
this.autosave = v; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns value of changes required before save |
|||
* |
|||
* @return {Integer} |
|||
* */ |
|||
getChangesBeforeSave : function(){ |
|||
return this.changesBeforeSave; |
|||
}, |
|||
|
|||
/** |
|||
* Set changesBeforeSave value |
|||
* @param {Mixed} v Value |
|||
* |
|||
* @return this |
|||
* */ |
|||
setChangesBeforeSave : function(v){ |
|||
this.changesBeforeSave = v; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Add new storage provider |
|||
* @param {StorageInterface} provider |
|||
* |
|||
* @return self |
|||
* */ |
|||
addProvider : function(provider) { |
|||
// Check interface implementation
|
|||
for (var method in this.si) |
|||
if(!provider[method]) |
|||
console.warn("addProvider: method '"+ method +"' was not found inside '"+ provider.getId() +"' object"); |
|||
|
|||
this.providers[provider.getId()] = provider; |
|||
if(!this.currentProvider) |
|||
this.currentProvider = provider.getId(); |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Returns storage provider |
|||
* @param {Integer} id Storage provider ID |
|||
* |
|||
* @return {StorageInterface}|null |
|||
* */ |
|||
getProvider : function(id){ |
|||
var provider = null; |
|||
if(id && this.providers[id]) |
|||
provider = this.providers[id]; |
|||
return provider; |
|||
}, |
|||
|
|||
/** |
|||
* Returns storage providers |
|||
* |
|||
* @return {Array} |
|||
* */ |
|||
getProviders : function(){ |
|||
return this.providers; |
|||
}, |
|||
|
|||
/** |
|||
* Get current provider |
|||
* |
|||
* @return {StorageInterface} |
|||
* */ |
|||
getCurrentProvider : function() { |
|||
if(!this.currentProvider) |
|||
this.loadDefaultProviders(); |
|||
return this.getProvider(this.currentProvider); |
|||
}, |
|||
|
|||
/** |
|||
* Set current provider |
|||
* @param {Integer} id Storage provider ID |
|||
* |
|||
* @return this |
|||
* */ |
|||
setCurrentProvider : function(id) { |
|||
this.currentProvider = id; |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Load default providers |
|||
* |
|||
* @return this |
|||
* */ |
|||
loadDefaultProviders : function() { |
|||
for (var id in this.defaultProviders) { |
|||
this.addProvider(this.defaultProviders[id]); |
|||
} |
|||
return this; |
|||
}, |
|||
|
|||
/** |
|||
* Store resource |
|||
* @param {String} name Name of the resource |
|||
* @param {String} value Value of the resource |
|||
* |
|||
* @return {Object}|void |
|||
* */ |
|||
store : function(name, value){ |
|||
return this.getCurrentProvider().store(name, value); |
|||
}, |
|||
|
|||
/** |
|||
* Load resource |
|||
* @param {String} name Name of the resource |
|||
* |
|||
* @return {Object}|void |
|||
* */ |
|||
load : function(name){ |
|||
return this.getCurrentProvider().load(name); |
|||
}, |
|||
|
|||
/** |
|||
* Remove resource |
|||
* @param {String} name Name of the resource |
|||
* |
|||
* @return {Object}|void |
|||
* */ |
|||
remove : function(name){ |
|||
return this.getCurrentProvider().remove(name); |
|||
}, |
|||
}; |
|||
|
|||
return StorageManager; |
|||
}); |
|||
@ -0,0 +1,59 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class LocalStorage |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
id: 'local', |
|||
|
|||
defaults: { |
|||
checkSupport : true, |
|||
errorNoSupport : 'Error encountered while parsing JSON response', |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
getId : function() { |
|||
return this.id; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
store : function(name, value) { |
|||
this.checkStorageEnvironment(); |
|||
localStorage.setItem(name, value ); |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
load: function(name){ |
|||
var result = null; |
|||
this.checkStorageEnvironment(); |
|||
if(localStorage.getItem(name)) |
|||
result = localStorage.getItem(name); |
|||
try{ |
|||
var prx = "Loading '" + name + "': "; |
|||
if(!result) |
|||
throw prx + ' Resource was not found'; |
|||
}catch(err){ |
|||
console.warn(err); |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
remove : function(name) { |
|||
this.checkStorageEnvironment(); |
|||
localStorage.removeItem(name); |
|||
}, |
|||
|
|||
/** |
|||
* Check storage environment |
|||
* @return void |
|||
* */ |
|||
checkStorageEnvironment: function(){ |
|||
if(this.get('checkSupport')) |
|||
if( !localStorage ) |
|||
console.warn(this.get('errorNoSupport')); |
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,80 @@ |
|||
define(['backbone'], |
|||
function (Backbone) { |
|||
/** |
|||
* @class RemoteStorage |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
id: 'remote', |
|||
|
|||
defaults: { |
|||
urlLoad : 'http://localhost/load', |
|||
urlStore : 'http://localhost/store', |
|||
beforeSend : function(){}, |
|||
onComplete : function(){}, |
|||
paramsStore : {}, |
|||
paramsLoad : {}, |
|||
errorLoad : 'Response is not a valid JSON', |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
getId : function() { |
|||
return this.id; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
store : function(name, value) { |
|||
var fd = new FormData(), |
|||
params = this.get('paramsStore'); |
|||
fd.append( name, value ); |
|||
for(var key in params){ |
|||
fd.append(key, params[key] ); |
|||
} |
|||
$.ajax({ |
|||
url: this.get('urlStore'), |
|||
beforeSend: this.get('beforeSend'), |
|||
complete: this.get('onComplete'), |
|||
type: 'POST', |
|||
processData: false, |
|||
contentType: false, |
|||
data: fd, |
|||
}); |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
load: function(name){ |
|||
var result = null, |
|||
t = this; |
|||
$.ajax({ |
|||
url : this.get('urlLoad'), |
|||
beforeSend : this.get('beforeSend'), |
|||
complete : this.get('onComplete'), |
|||
data : this.get('paramsLoad'), |
|||
async : false, |
|||
type : 'GET', |
|||
}).done(function(d){ |
|||
try{ |
|||
var prx = "Loading '" + name + "': "; |
|||
|
|||
if(typeof d !== 'object') |
|||
throw prx + t.get('errorLoad'); |
|||
|
|||
result = d.data ? d.data[name] : d[name]; |
|||
|
|||
if(!result) |
|||
throw prx + ' Resource was not found'; |
|||
|
|||
}catch(err){ |
|||
console.warn(err); |
|||
} |
|||
}); |
|||
return result; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
remove : function(name) { |
|||
|
|||
}, |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,19 @@ |
|||
define(function() { |
|||
/** |
|||
* @class StorageInterface |
|||
* */ |
|||
function StorageInterface() {} |
|||
|
|||
StorageInterface.prototype = { |
|||
|
|||
getId : function() {}, |
|||
|
|||
store : function(name, value) {}, |
|||
|
|||
load : function(name) {}, |
|||
|
|||
remove : function(name) {}, |
|||
}; |
|||
|
|||
return StorageInterface; |
|||
}); |
|||
@ -0,0 +1,431 @@ |
|||
define(function () { |
|||
return { |
|||
|
|||
stylePrefix : 'sm-', |
|||
|
|||
target : null, |
|||
//sectors: [],
|
|||
sectors: [{ |
|||
name: 'Positions', |
|||
properties:[{ |
|||
name: 'Alignment', |
|||
property: 'float', |
|||
type: 'radio', |
|||
defaults : 'none', |
|||
list: [{ |
|||
value : 'none', |
|||
//icon: 'none',
|
|||
info: 'None', |
|||
},{ |
|||
value : 'left', |
|||
info: 'Float element to the left', |
|||
//icon: 'float-left',
|
|||
},{ |
|||
value : '0 auto', |
|||
//icon: 'float-center',
|
|||
info: 'Center the element', |
|||
property: 'margin' |
|||
},{ |
|||
value : 'right', |
|||
info: 'Float element to the right', |
|||
//icon: 'float-right',
|
|||
}], |
|||
}], |
|||
},{ |
|||
name: 'Dimension', |
|||
properties:[{ |
|||
name: 'Width', |
|||
property: 'width', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
defaults : 'auto', |
|||
min: 0, |
|||
},{ |
|||
name: 'Height', |
|||
property: 'height', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
defaults : 'auto', |
|||
min: 0, |
|||
},], |
|||
},{ |
|||
name: 'Typography', |
|||
properties:[{ |
|||
name: 'Font', |
|||
property: 'font-family', |
|||
type: 'select', |
|||
defaults : 'Arial, Helvetica, sans-serif', |
|||
list: [{ |
|||
value : 'Arial, Helvetica, sans-serif', |
|||
name : 'Arial', |
|||
style: 'font-family: Arial, Helvetica, sans-serif', |
|||
},{ |
|||
value : '"Arial Black", Gadget, sans-serif', |
|||
style: 'font-family: "Arial Black", Gadget, sans-serif', |
|||
name : 'Arial Black', |
|||
},{ |
|||
value : '"Brush Script MT", sans-serif', |
|||
style: 'font-family: "Brush Script MT", sans-serif', |
|||
name : 'Brush Script MT', |
|||
},{ |
|||
value : '"Comic Sans MS", cursive, sans-serif', |
|||
style: 'font-family: "Comic Sans MS", cursive, sans-serif', |
|||
name : 'Comica Sans', |
|||
},{ |
|||
value : '"Courier New", Courier, monospace', |
|||
style: 'font-family: "Courier New", Courier, monospace', |
|||
name : 'Courier New', |
|||
},{ |
|||
value : 'Georgia, serif', |
|||
style: 'font-family: Georgia, serif', |
|||
name : 'Georgia', |
|||
},{ |
|||
value : 'Helvetica, serif', |
|||
style: 'font-family: Helvetica, serif', |
|||
name : 'Helvetica', |
|||
},{ |
|||
value : 'Impact, Charcoal, sans-serif', |
|||
style: 'font-family: Impact, Charcoal, sans-serif', |
|||
name : 'Impact', |
|||
},{ |
|||
value : '"Lucida Sans Unicode", "Lucida Grande", sans-serif', |
|||
style: 'font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif', |
|||
name : 'Lucida Sans', |
|||
},{ |
|||
value : 'Tahoma, Geneva, sans-serif', |
|||
style: 'font-family: Tahoma, Geneva, sans-serif', |
|||
name : 'Tahoma', |
|||
},{ |
|||
value : '"Times New Roman", Times, serif', |
|||
style: 'font-family: "Times New Roman", Times, serif', |
|||
name : 'Times New Roman', |
|||
},{ |
|||
value : '"Trebuchet MS", Helvetica, sans-serif', |
|||
style: 'font-family: "Trebuchet MS", Helvetica, sans-serif', |
|||
name : 'Trebuchet', |
|||
},{ |
|||
value : 'Verdana, Geneva, sans-serif', |
|||
style: 'font-family: Verdana, Geneva, sans-serif', |
|||
name : 'Verdana', |
|||
}], |
|||
},{ |
|||
name: 'Weight', |
|||
property: 'font-weight', |
|||
type: 'select', |
|||
defaults : '400', |
|||
list: [{ value : '100', name : 'Thin', }, |
|||
{ value : '200', name : 'Extra-Light', }, |
|||
{ value : '300', name : 'Light', }, |
|||
{ value : '400', name : 'Normal', }, |
|||
{ value : '500', name : 'Medium',}, |
|||
{ value : '600', name : 'Semi-Bold',}, |
|||
{ value : '700', name : 'Bold', }, |
|||
{ value : '800', name : 'Extra-Bold',}, |
|||
{ value : '900', name : 'Ultra-Bold', }], |
|||
},{ |
|||
name: 'Text align', |
|||
property: 'text-align', |
|||
type: 'radio', |
|||
defaults : 'left', |
|||
list: [{ value : 'left', name : 'Left', style:"font-weight:bold", }, |
|||
{ value : 'center', name : 'Center', }, |
|||
{ value : 'right', name : 'Right', }, |
|||
{ value : 'justify', name : 'Justify', },], |
|||
},{ |
|||
name: 'Weight', |
|||
property: 'font-weight', |
|||
type: 'select', |
|||
defaults : '400', |
|||
list: [{ value : '100', name : 'Thin', }, |
|||
{ value : '200', name : 'Extra-Light', }, |
|||
{ value : '300', name : 'Light', }, |
|||
{ value : '400', name : 'Normal', }, |
|||
{ value : '500', name : 'Medium',}, |
|||
{ value : '600', name : 'Semi-Bold',}, |
|||
{ value : '700', name : 'Bold', }, |
|||
{ value : '800', name : 'Extra-Bold',}, |
|||
{ value : '900', name : 'Ultra-Bold', }], |
|||
}], |
|||
},{ |
|||
name: 'Decorations', |
|||
properties: [{ |
|||
name: 'Borders radius', |
|||
property: 'border-radius', |
|||
type: 'integer', |
|||
units: ['px'], |
|||
unit: 'px', |
|||
defaults : '0', |
|||
min: 0, |
|||
},{ |
|||
name: 'Borders radius', |
|||
property: 'border-radius', |
|||
type: 'composite', |
|||
properties:[{ |
|||
name: 'Top', |
|||
property: 'pad-top', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
defaults : 0, |
|||
min: 0, |
|||
},{ |
|||
name: 'Right', |
|||
property: 'pad-right', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
min: 0, |
|||
defaults : 0, |
|||
},{ |
|||
name: 'Bottom', |
|||
property: 'pad-bot', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
min: 0, |
|||
defaults : 0, |
|||
},{ |
|||
name: 'Left', |
|||
property: 'pad-left', |
|||
type: 'integer', |
|||
units: ['px'], |
|||
min: 0, |
|||
defaults : 0, |
|||
},], |
|||
}, |
|||
{ |
|||
name: 'Box shadow', |
|||
property: 'box-shadow', |
|||
type: 'stack', |
|||
preview: true, |
|||
properties:[{ |
|||
name: 'Shadow type', |
|||
property: 'shadow-type', |
|||
type: 'select', |
|||
defaults: '', |
|||
list: [ { value : '', name : 'Outside', }, |
|||
{ value : 'inset', name : 'Inside', }], |
|||
},{ |
|||
name: 'X position', |
|||
property: 'shadow-x', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
defaults : 0, |
|||
},{ |
|||
name: 'Y position', |
|||
property: 'shadow-y', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
defaults : 0, |
|||
},{ |
|||
name: 'Blur', |
|||
property: 'shadow-blur', |
|||
type: 'integer', |
|||
units: ['px'], |
|||
defaults : 5, |
|||
min: 0, |
|||
},{ |
|||
name: 'Spread', |
|||
property: 'shadow-spread', |
|||
type: 'integer', |
|||
units: ['px'], |
|||
defaults : 0, |
|||
},{ |
|||
name: 'Color', |
|||
property: 'shadow-color', |
|||
type: 'color', |
|||
defaults: 'black', |
|||
}, |
|||
], |
|||
},{ |
|||
name: 'Background', |
|||
property: 'background', |
|||
type: 'stack', |
|||
preview: true, |
|||
properties:[{ |
|||
name: 'Image', |
|||
property: 'background-image', |
|||
type: 'file', |
|||
defaults: 'none', |
|||
}, |
|||
/*{ |
|||
name: 'Background position', |
|||
property: 'background-position', |
|||
type: 'composite', |
|||
properties: [ { |
|||
name: 'BpX', |
|||
property: 'bpx', |
|||
type: 'select', |
|||
defaults: 'left', |
|||
list: [ { value : 'left', name : 'Left', }, |
|||
{ value : 'center', name : 'Center', }, |
|||
{ value : 'right', name : 'Right', }], |
|||
},{ |
|||
name: 'BpY', |
|||
property: 'bpy', |
|||
type: 'select', |
|||
defaults: 'top', |
|||
list: [ { value : 'top', name : 'Top', }, |
|||
{ value : 'center', name : 'Center', }, |
|||
{ value : 'bottom', name : 'Bottom', }], |
|||
}, |
|||
], |
|||
}*/ |
|||
{ |
|||
name: 'Repeat', |
|||
property: 'background-repeat', |
|||
type: 'select', |
|||
defaults: 'repeat', |
|||
list: [{ value : 'repeat', name : 'Repeat', }, |
|||
{ value : 'repeat-x', name : 'Repeat X', }, |
|||
{ value : 'repeat-y', name : 'Repeat Y', }, |
|||
{ value : 'no-repeat', name : 'No repeat', }], |
|||
}, |
|||
{ |
|||
name: 'Position X', |
|||
property: 'bpx', |
|||
type: 'select', |
|||
defaults: 'left', |
|||
list: [ { value : 'left', name : 'Left', }, |
|||
{ value : 'center', name : 'Center', }, |
|||
{ value : 'right', name : 'Right', }], |
|||
},{ |
|||
name: 'Position Y', |
|||
property: 'bpy', |
|||
type: 'select', |
|||
defaults: 'top', |
|||
list: [ { value : 'top', name : 'Top', }, |
|||
{ value : 'center', name : 'Center', }, |
|||
{ value : 'bottom', name : 'Bottom', }], |
|||
},{ |
|||
name: 'Attach', |
|||
property: 'background-attachment', |
|||
type: 'select', |
|||
defaults: 'scroll', |
|||
list: [{ value : 'scroll', name : 'Scroll', }, |
|||
{ value : 'fixed', name : 'Fixed', }, |
|||
{ value : 'local', name : 'Local', }], |
|||
}, |
|||
/*{ |
|||
name: 'Background origin', |
|||
property: 'background-origin', |
|||
type: 'select', |
|||
defaults: 'padding-box', |
|||
list: [{ value : 'padding-box', name : 'Padding', }, |
|||
{ value : 'border-box', name : 'Border', }, |
|||
{ value : 'content-box', name : 'Content', }], |
|||
},{ |
|||
name: 'Background clip', |
|||
property: 'background-clip', |
|||
type: 'select', |
|||
defaults: 'border-box', |
|||
list: [{ value : 'border-box', name : 'Border', }, |
|||
{ value : 'padding-box', name : 'Padding', }, |
|||
{ value : 'content-box', name : 'Content', }], |
|||
},{ |
|||
name: 'Color', |
|||
property: 'background-color', |
|||
type: 'color', |
|||
defaults: 'black', |
|||
},*/ |
|||
], |
|||
},{ |
|||
name: 'Transition', |
|||
property: 'transition', |
|||
type: 'stack', |
|||
preview: false, |
|||
properties:[{ |
|||
name: 'Property', |
|||
property: 'transition-property', |
|||
type: 'select', |
|||
defaults: '', |
|||
list: [{ value : 'width', name : 'Width', }, |
|||
{ value : 'height', name : 'Height', }, |
|||
{ value : 'background-color', name : 'Background', }], |
|||
},{ |
|||
name: 'Duration', |
|||
property: 'transition-duration', |
|||
type: 'integer', |
|||
units: ['s'], |
|||
defaults : '2', |
|||
min: 0, |
|||
},{ |
|||
name: 'Easing', |
|||
property: 'transition-timing-function', |
|||
type: 'select', |
|||
defaults: 'ease', |
|||
list: [{ value : 'linear', name : 'Linear', }, |
|||
{ value : 'ease', name : 'Ease', }, |
|||
{ value : 'ease-in', name : 'Ease-in', }, |
|||
{ value : 'ease-out', name : 'Ease-out', }, |
|||
{ value : 'ease-in-out', name : 'Ease-in-out', }], |
|||
}], |
|||
},{ |
|||
name: 'Perspective', |
|||
property: 'perspective', |
|||
type: 'integer', |
|||
units: ['px'], |
|||
defaults : '0', |
|||
min: 0, |
|||
},{ |
|||
name: 'Transform', |
|||
property: 'transform', |
|||
type: 'composite', |
|||
properties:[{ |
|||
name: 'Rotate X', |
|||
property: 'transform-rotate-x', |
|||
type: 'integer', |
|||
units: ['deg'], |
|||
defaults : '0', |
|||
functionName: 'rotateX', |
|||
},{ |
|||
name: 'Rotate Y', |
|||
property: 'transform-rotate-y', |
|||
type: 'integer', |
|||
units: ['deg'], |
|||
defaults : '0', |
|||
functionName: 'rotateY', |
|||
},{ |
|||
name: 'Rotate Z', |
|||
property: 'transform-rotate-z', |
|||
type: 'integer', |
|||
units: ['deg'], |
|||
defaults : '0', |
|||
functionName: 'rotateZ', |
|||
}], |
|||
}/*{ |
|||
name: 'Padding', |
|||
property: 'padding', |
|||
type: 'composite', |
|||
properties:[{ |
|||
name: 'Top', |
|||
property: 'pad-top', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
defaults : 0, |
|||
min: 0, |
|||
},{ |
|||
name: 'Right', |
|||
property: 'pad-right', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
min: 0, |
|||
defaults : 0, |
|||
},{ |
|||
name: 'Bottom', |
|||
property: 'pad-bot', |
|||
type: 'integer', |
|||
units: ['px','%'], |
|||
min: 0, |
|||
defaults : 0, |
|||
},{ |
|||
name: 'Left', |
|||
property: 'pad-left', |
|||
type: 'integer', |
|||
units: ['px'], |
|||
min: 0, |
|||
defaults : 0, |
|||
},], |
|||
},*/ |
|||
], |
|||
} |
|||
], |
|||
}; |
|||
}); |
|||
@ -0,0 +1,80 @@ |
|||
define(function(require) { |
|||
/** |
|||
* @class StyleManager |
|||
* @param {Object} Configurations |
|||
* |
|||
* @return {Object} |
|||
* */ |
|||
function StyleManager(config) |
|||
{ |
|||
var c = config || {}, |
|||
defaults = require('./config/config'), |
|||
Sectors = require('./model/Sectors'), |
|||
SectorsView = require('./view/SectorsView'); |
|||
|
|||
for (var name in defaults) { |
|||
if (!(name in c)) |
|||
c[name] = defaults[name]; |
|||
} |
|||
|
|||
this.sectors = new Sectors(c.sectors); |
|||
var obj = { |
|||
collection : this.sectors, |
|||
target : c.target, |
|||
config : c, |
|||
}; |
|||
|
|||
this.SectorsView = new SectorsView(obj); |
|||
} |
|||
|
|||
StyleManager.prototype = { |
|||
|
|||
/** |
|||
* Get all sectors |
|||
* |
|||
* @return {Sectors} |
|||
* */ |
|||
getSectors : function() |
|||
{ |
|||
return this.sectors; |
|||
}, |
|||
|
|||
/** |
|||
* Get sector by id |
|||
* @param {String} id Object id |
|||
* |
|||
* @return {Sector}|{null} |
|||
* */ |
|||
getSector : function(id) |
|||
{ |
|||
var res = this.sectors.where({id: id}); |
|||
return res.length ? res[0] : null; |
|||
}, |
|||
|
|||
/** |
|||
* Add new Sector |
|||
* @param {String} id Object id |
|||
* @param {Object} obj Object data |
|||
* |
|||
* @return {Sector} |
|||
* */ |
|||
addSector : function(id, obj) |
|||
{ |
|||
if(!this.getSector(id)){ |
|||
obj.id = id; |
|||
return this.sectors.add(obj); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Render sectors |
|||
* |
|||
* @return {String} |
|||
* */ |
|||
render : function(){ |
|||
return this.SectorsView.render().$el; |
|||
}, |
|||
}; |
|||
|
|||
return StyleManager; |
|||
}); |
|||
@ -0,0 +1,16 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
/** |
|||
* @class Layer |
|||
* */ |
|||
return Backbone.Model.extend({ |
|||
|
|||
defaults: { |
|||
name : '', |
|||
active : true, |
|||
value : '', |
|||
preview : false, |
|||
} |
|||
|
|||
}); |
|||
}); |
|||
@ -0,0 +1,11 @@ |
|||
define([ 'backbone','./Layer'], |
|||
function (Backbone,Layer) { |
|||
/** |
|||
* @class Layers |
|||
* */ |
|||
return Backbone.Collection.extend({ |
|||
|
|||
model: Layer, |
|||
|
|||
}); |
|||
}); |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue