diff --git a/src/asset_manager/index.js b/src/asset_manager/index.js
index 8063018bf..68ade299f 100644
--- a/src/asset_manager/index.js
+++ b/src/asset_manager/index.js
@@ -5,8 +5,13 @@
* * [remove](#remove)
* * [store](#store)
* * [load](#load)
+ * * [getContainer](#getcontainer)
+ * * [getAssetsEl](#getassetsel)
* * [onClick](#onClick)
* * [onDblClick](#onDblClick)
+ * * [addType](#addtype)
+ * * [getType](#gettype)
+ * * [getTypes](#gettypes)
*
* Before using this methods you should get first the module from the editor instance, in this way:
*
@@ -35,11 +40,12 @@
*/
module.exports = () => {
- var c = {},
- Assets = require('./model/Assets'),
- AssetsView = require('./view/AssetsView'),
- FileUpload = require('./view/FileUploader'),
- assets, am, fu;
+ let c = {};
+ const defaults = require('./config/config');
+ const Assets = require('./model/Assets');
+ const AssetsView = require('./view/AssetsView');
+ const FileUpload = require('./view/FileUploader');
+ let assets, am, fu;
return {
@@ -64,24 +70,42 @@ module.exports = () => {
*/
init(config) {
c = config || {};
- var defaults = require('./config/config');
- for (var name in defaults) {
+ for (let name in defaults) {
if (!(name in c))
c[name] = defaults[name];
}
- var ppfx = c.pStylePrefix;
- if(ppfx)
+ const ppfx = c.pStylePrefix;
+ const em = c.em;
+
+ if (ppfx) {
c.stylePrefix = ppfx + c.stylePrefix;
+ }
+ // Global assets collection
assets = new Assets(c.assets);
- var obj = {
- collection: assets,
+ const obj = {
+ // Collection visible in asset manager
+ collection: new Assets([]),
+ globalCollection: assets,
config: c,
};
- am = new AssetsView(obj);
fu = new FileUpload(obj);
+ obj.fu = fu;
+ am = new AssetsView(obj);
+
+ // Setup the sync between the global and public collections
+ assets.listenTo(assets, 'add', (model) => {
+ this.getAllVisible().add(model);
+ em && em.trigger('asset:add', model);
+ });
+
+ assets.listenTo(assets, 'remove', (model) => {
+ this.getAllVisible().remove(model);
+ em && em.trigger('asset:remove', model);
+ });
+
return this;
},
@@ -123,13 +147,21 @@ module.exports = () => {
},
/**
- * Return all assets
+ * Return global collection
* @return {Collection}
*/
getAll() {
return assets;
},
+ /**
+ * Return visible collection
+ * @return {Collection}
+ */
+ getAllVisible() {
+ return am.collection;
+ },
+
/**
* Remove the asset by its URL
* @param {string} src URL of the asset
@@ -194,22 +226,72 @@ module.exports = () => {
return assets;
},
+ /**
+ * Return the Asset Manager Container
+ * @return {HTMLElement}
+ */
+ getContainer() {
+ return am.el;
+ },
+
+ /**
+ * Get assets element container
+ * @return {HTMLElement}
+ */
+ getAssetsEl() {
+ return am.el.querySelector('[data-el=assets]');
+ },
+
/**
* Render assets
- * @param {Boolean} f Force to render, otherwise cached version will be returned
+ * @param {Boolean} f Force to render, otherwise cached version will be returned
* @return {HTMLElement}
* @private
*/
- render(f) {
- if(!this.rendered || f)
- this.rendered = am.render().$el.add(fu.render().$el);
- return this.rendered;
+ render(assets = []) {
+ const toRender = assets.length ? assets : this.getAll().models;
+ am.collection.reset(toRender);
+ return this.getContainer();
},
postRender(editorView) {
c.dropzone && fu.initDropzone(editorView);
},
+ /**
+ * Add new type
+ * @param {string} id Type ID
+ * @param {Object} definition Definition of the type. Each definition contains
+ * `model` (business logic), `view` (presentation logic)
+ * and `isType` function which recognize the type of the
+ * passed entity
+ * addType('my-type', {
+ * model: {},
+ * view: {},
+ * isType: (value) => {},
+ * })
+ */
+ addType(id, definition) {
+ this.getAll().addType(id, definition);
+ },
+
+ /**
+ * Get type
+ * @param {string} id Type ID
+ * @return {Object} Type definition
+ */
+ getType(id) {
+ return this.getAll().getType(id);
+ },
+
+ /**
+ * Get types
+ * @return {Array}
+ */
+ getTypes() {
+ return this.getAll().getTypes();
+ },
+
//-------
/**
diff --git a/src/asset_manager/model/Assets.js b/src/asset_manager/model/Assets.js
index 7c6395db5..191b48bc7 100644
--- a/src/asset_manager/model/Assets.js
+++ b/src/asset_manager/model/Assets.js
@@ -1,68 +1,20 @@
-var Backbone = require('backbone');
-var Asset = require('./Asset');
-var AssetImage = require('./AssetImage');
-
-module.exports = Backbone.Collection.extend({
-
- model: AssetImage,
-
- initialize(models, opt) {
-
- this.model = (attrs, options) => {
- var model;
- switch(attrs.type){
- default:
- model = new AssetImage(attrs, options);
- }
- return model;
- };
-
- },
-
- /**
- * Add new image asset to the collection
- * @param {string} url URL of the image
- * @param {Object} opts Options
- * @return {this}
- * @private
- */
- addImg(url, opts) {
- this.add({
- type: 'image',
- src: url,
- }, opts);
- return this;
- },
-
- /**
- * Prevent inserting assets with the same 'src'
- * Seems like idAttribute is not working with dynamic model assignament
- * @private
- */
- add(models, opt) {
- var mods = [];
- models = models instanceof Array ? models : [models];
-
- for (var i = 0, len = models.length; i < len; i++) {
- var model = models[i];
-
- if(typeof model === 'string')
- model = {src: model, type: 'image'};
-
- if(!model || !model.src)
- continue;
-
- var found = this.where({src: model.src});
-
- if(!found.length)
- mods.push(model);
- }
-
- if(mods.length == 1)
- mods = mods[0];
-
- return Backbone.Collection.prototype.add.apply(this, [mods, opt]);
- },
-
-
+import TypeableCollection from 'domain_abstract/model/TypeableCollection';
+
+module.exports = require('backbone').Collection.extend(TypeableCollection).extend({
+ getTypes() {
+ return [{
+ id: 'image',
+ model: require('./AssetImage'),
+ view: require('./../view/AssetImageView'),
+ isType(value) {
+ if (typeof value == 'string') {
+ return {
+ type: 'image',
+ src: value,
+ }
+ }
+ return value;
+ }
+ }];
+ }
});
diff --git a/src/asset_manager/view/AssetImageView.js b/src/asset_manager/view/AssetImageView.js
index fd369e525..8a1d35305 100644
--- a/src/asset_manager/view/AssetImageView.js
+++ b/src/asset_manager/view/AssetImageView.js
@@ -1,31 +1,37 @@
-var AssetView = require('./AssetView');
-var assetTemplate = `
-
-
-⨯
-
-`;
+module.exports = require('./AssetView').extend({
-module.exports = AssetView.extend({
-
- events:{
- 'click': 'handleClick',
- 'dblclick': 'handleDblClick',
+ events: {
+ click: 'handleClick',
+ dblclick: 'handleDblClick',
+ 'click [data-toggle=asset-remove]': 'removeItem',
},
- template: _.template(assetTemplate),
+ template(view, model) {
+ const pfx = view.pfx;
+ const ppfx = view.ppfx;
+ let name = model.get('name');
+ let width = model.get('width');
+ let height = model.get('height');
+ let unit = model.get('unitDim');
+ let dim = width && height ? `${width}x${height}${unit}` : '';
+ name = name || model.getFilename();
+ return `
+
+
+ ⨯
+
+ `;
+ },
- initialize(o) {
- AssetView.prototype.initialize.apply(this, arguments);
- this.className += ' ' + this.pfx + 'asset-image';
- this.events['click #' + this.pfx + 'close'] = 'removeItem';
- this.delegateEvents();
+ init(o) {
+ const pfx = this.pfx;
+ this.className += ` ${pfx}asset-image`;
},
/**
@@ -35,7 +41,7 @@ module.exports = AssetView.extend({
handleClick() {
var onClick = this.config.onClick;
var model = this.model;
- model.collection.trigger('deselectAll');
+ this.collection.trigger('deselectAll');
this.$el.addClass(this.pfx + 'highlight');
if (typeof onClick === 'function') {
@@ -59,8 +65,8 @@ module.exports = AssetView.extend({
this.updateTarget(model.get('src'));
}
- var onSelect = model.collection.onSelect;
- if(typeof onSelect == 'function'){
+ var onSelect = this.collection.onSelect;
+ if (typeof onSelect == 'function') {
onSelect(this.model);
}
},
@@ -71,9 +77,10 @@ module.exports = AssetView.extend({
* @private
* */
updateTarget(v) {
- var target = this.model.collection.target;
- if(target && target.set) {
- var attr = _.clone( target.get('attributes') );
+ const target = this.collection.target;
+
+ if (target && target.set) {
+ var attr = _.clone(target.get('attributes'));
target.set('attributes', attr );
target.set('src', v );
}
@@ -86,23 +93,5 @@ module.exports = AssetView.extend({
removeItem(e) {
e.stopPropagation();
this.model.collection.remove(this.model);
- },
-
- render() {
- var name = this.model.get('name'),
- dim = this.model.get('width') && this.model.get('height') ?
- this.model.get('width')+' x '+this.model.get('height') : '';
- name = name ? name : this.model.get('src').split("/").pop();
- name = name && name.length > 30 ? name.substring(0, 30)+'...' : name;
- dim = dim ? dim + (this.model.get('unitDim') ? this.model.get('unitDim') : ' px' ) : '';
- this.$el.html( this.template({
- name,
- src: this.model.get('src'),
- dim,
- pfx: this.pfx,
- ppfx: this.ppfx
- }));
- this.$el.attr('class', this.className);
- return this;
- },
+ }
});
diff --git a/src/asset_manager/view/AssetView.js b/src/asset_manager/view/AssetView.js
index 38ed331a1..43981747e 100644
--- a/src/asset_manager/view/AssetView.js
+++ b/src/asset_manager/view/AssetView.js
@@ -1,12 +1,23 @@
var Backbone = require('backbone');
module.exports = Backbone.View.extend({
- initialize(o) {
+
+ initialize(o = {}) {
this.options = o;
+ this.collection = o.collection;
this.config = o.config || {};
this.pfx = this.config.stylePrefix || '';
this.ppfx = this.config.pStylePrefix || '';
this.className = this.pfx + 'asset';
- this.listenTo( this.model, 'destroy remove', this.remove);
+ this.listenTo(this.model, 'destroy remove', this.remove);
+ const init = this.init && this.init.bind(this);
+ init && init(o);
+ },
+
+ render() {
+ const el = this.el;
+ el.innerHTML = this.template(this, this.model);
+ el.className = this.className;
+ return this;
},
});
diff --git a/src/asset_manager/view/AssetsView.js b/src/asset_manager/view/AssetsView.js
index 94208064d..97a66d64e 100644
--- a/src/asset_manager/view/AssetsView.js
+++ b/src/asset_manager/view/AssetsView.js
@@ -2,30 +2,32 @@ var Backbone = require('backbone');
var AssetView = require('./AssetView');
var AssetImageView = require('./AssetImageView');
var FileUploader = require('./FileUploader');
-var assetsTemplate = `
-
-
-`;
module.exports = Backbone.View.extend({
- template: _.template(assetsTemplate),
+ template(view) {
+ const pfx = view.pfx;
+ const ppfx = view.ppfx;
+ return `
+
+ `;
+ },
initialize(o) {
this.options = o;
@@ -35,7 +37,6 @@ module.exports = Backbone.View.extend({
this.listenTo(this.collection, 'add', this.addToAsset );
this.listenTo(this.collection, 'deselectAll', this.deselectAll);
this.listenTo(this.collection, 'reset', this.render);
- this.className = this.pfx + 'assets';
this.events = {};
this.events.submit = 'addFromStr';
@@ -50,16 +51,14 @@ module.exports = Backbone.View.extend({
*/
addFromStr(e) {
e.preventDefault();
+ const input = this.getInputUrl();
+ const url = input.value.trim();
- var input = this.getInputUrl();
-
- var url = input.value.trim();
-
- if(!url)
+ if (!url) {
return;
+ }
- this.collection.addImg(url, {at: 0});
-
+ this.options.globalCollection.add(url, {at: 0});
this.getAssetsEl().scrollTop = 0;
input.value = '';
return this;
@@ -72,8 +71,7 @@ module.exports = Backbone.View.extend({
*/
getAssetsEl() {
//if(!this.assets) // Not able to cache as after the rerender it losses the ref
- this.assets = this.el.querySelector('.' + this.pfx + 'assets');
- return this.assets;
+ return this.el.querySelector(`.${this.pfx}assets`);
},
/**
@@ -83,7 +81,7 @@ module.exports = Backbone.View.extend({
*/
getInputUrl() {
if(!this.inputUrl || !this.inputUrl.value)
- this.inputUrl = this.el.querySelector('.'+this.pfx+'add-asset input');
+ this.inputUrl = this.el.querySelector(`.${this.pfx}add-asset input`);
return this.inputUrl;
},
@@ -102,25 +100,23 @@ module.exports = Backbone.View.extend({
* @return Object Object created
* @private
* */
- addAsset(model, fragmentEl) {
- var fragment = fragmentEl || null;
- var viewObject = AssetView;
-
- if(model.get('type').indexOf("image") > -1)
- viewObject = AssetImageView;
-
- var view = new viewObject({
+ addAsset(model, fragmentEl = null) {
+ const fragment = fragmentEl;
+ const collection = this.collection;
+ const config = this.config;
+ const rendered = new model.typeView({
model,
- config : this.config,
- });
- var rendered = view.render().el;
+ collection,
+ config,
+ }).render().el;
- if(fragment){
+ if (fragment) {
fragment.appendChild( rendered );
- }else{
- var assetsEl = this.getAssetsEl();
- if(assetsEl)
+ } else {
+ const assetsEl = this.getAssetsEl();
+ if (assetsEl) {
assetsEl.insertBefore(rendered, assetsEl.firstChild);
+ }
}
return rendered;
@@ -131,24 +127,24 @@ module.exports = Backbone.View.extend({
* @private
* */
deselectAll() {
- this.$el.find('.' + this.pfx + 'highlight').removeClass(this.pfx + 'highlight');
+ const pfx = this.pfx;
+ this.$el.find(`.${pfx}highlight`).removeClass(`${pfx}highlight`);
},
render() {
- var fragment = document.createDocumentFragment();
+ const pfx = this.pfx;
+ const ppfx = this.ppfx;
+ const fuRendered = this.options.fu.render().el;
+ const fragment = document.createDocumentFragment();
this.$el.empty();
- this.collection.each(function(model){
+ this.collection.each((model) => {
this.addAsset(model, fragment);
- },this);
-
- this.$el.html(this.template({
- pfx: this.pfx,
- ppfx: this.ppfx,
- btnText: this.config.addBtnText,
- }));
+ });
- this.$el.find('.'+this.pfx + 'assets').append(fragment);
+ this.$el.append(fuRendered).append(this.template(this));
+ this.el.className = `${ppfx}asset-manager`;
+ this.$el.find(`.${pfx}assets`).append(fragment);
return this;
}
});
diff --git a/src/commands/view/OpenAssets.js b/src/commands/view/OpenAssets.js
index 17714a317..8cbb20e3e 100644
--- a/src/commands/view/OpenAssets.js
+++ b/src/commands/view/OpenAssets.js
@@ -12,9 +12,10 @@ module.exports = {
// old API
assetManager.setTarget(opt.target);
assetManager.onSelect(opt.onSelect);
+ assetManager.render();
modal.setTitle(opt.modalTitle || 'Select image');
- modal.setContent(assetManager.render());
+ modal.setContent(assetManager.getContainer());
modal.open();
},
diff --git a/src/domain_abstract/model/TypeableCollection.js b/src/domain_abstract/model/TypeableCollection.js
index a5278480f..4260b37e5 100644
--- a/src/domain_abstract/model/TypeableCollection.js
+++ b/src/domain_abstract/model/TypeableCollection.js
@@ -4,13 +4,24 @@ const View = Backbone.View;
export default {
initialize(models, opts) {
- this.model = (attrs, options) => {
- let modelType = this.getType(attrs.type);
- const baseType = this.getBaseType();
- const Model = modelType ? modelType.model : baseType.model;
- return new Model(attrs, options);
+ this.model = (attrs = {}, options = {}) => {
+ let Model, type;
+
+ if (attrs && attrs.type) {
+ type = this.getType(attrs.type);
+ Model = type ? type.model : this.getBaseType().model;
+ } else {
+ const typeFound = this.recognizeType(attrs);
+ type = typeFound.type;
+ Model = type.model;
+ attrs = typeFound.attributes;
+ }
+
+ const model = new Model(attrs, options);
+ model.typeView = type.view;
+ return model;
};
- const init = this.init;
+ const init = this.init && this.init.bind(this);
init && init();
},
@@ -29,9 +40,18 @@ export default {
{type: type.id} : typeFound;
if (typeFound) {
- return typeFound;
+ return {
+ type,
+ attributes: typeFound,
+ };
}
}
+
+ // If, for any reason, the type is not found it'll return the base one
+ return {
+ type: this.getBaseType(),
+ attributes: value,
+ }
},
/**
@@ -54,7 +74,7 @@ export default {
/**
* Get type
* @param {string} id Type ID
- *
+ * @return {Object} Type definition
*/
getType(id) {
const types = this.getTypes();
diff --git a/src/editor/index.js b/src/editor/index.js
index dc8ec0739..631272664 100644
--- a/src/editor/index.js
+++ b/src/editor/index.js
@@ -37,6 +37,8 @@
* * `component:update:{propertyName}` - Listen any property change
* * `component:styleUpdate` - Triggered when the style of the component is updated
* * `component:styleUpdate:{propertyName}` - Listen for a specific style property change
+ * * `asset:add` - New asset added
+ * * `asset:remove` - Asset removed
* * `asset:upload:start` - Before the upload is started
* * `asset:upload:end` - After the upload is ended
* * `asset:upload:error` - On any error in upload, passes the error as an argument