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