gridstack-8.x-2.5/js/admin/gridstack.admin.backbone.js
js/admin/gridstack.admin.backbone.js
/**
* @file
* Provides GridStack admin UI utilities using backbone.
*/
(function ($, Drupal, drupalSettings, Backbone, _, _db, GridStack, window) {
'use strict';
Drupal.gridstack = Drupal.gridstack || {};
_.each(['base', 'models', 'views', 'crud'], function (key) {
Drupal.gridstack[key] = Drupal.gridstack[key] || {};
});
/**
* The GridStack views.
*/
Drupal.gridstack.views.GridStack = Backbone.View.extend(_.extend({
gridStack: null,
nodes: [],
nestedNodes: [],
wrapper: '.gridstack-wrapper',
initialize: function (o) {
var me = this;
var el = me.$el;
var base = Drupal.gridstack.base;
var defaults = drupalSettings.gridstack || {};
o = o || {};
// Merge all options.
o = _.extend({
options: {
breakpoint: null,
column: 12,
isNested: false,
storage: null
},
saveCallback: null
}, o);
o.options.column = parseInt(el.data('gsColumn')) || o.options.column;
me.isDisabled = el.hasClass('is-gs-disabled');
if (me.isDisabled) {
o.options.column = 1;
}
me.options = o.options;
me.saveCallback = o.saveCallback;
// Non Bootstrap/Foundation options.
base.config = el.data('config') || {};
// Bootstrap/Foundation options.
if (me.options.isNested) {
base.config = _.extend(el.data('configFramework') || {}, base.nestedOptions);
}
// Anywhere else.
base.options = _.extend(defaults, base.baseOptions, base.config, o.options);
// Provides common shortcuts.
me.gridStackOptions = base.options;
me.nestedOptions = _.extend(base.baseOptions, base.config, o.options);
me.isNested = me.options.isNested;
me.column = base.options.column;
me.breakpoint = base.options.breakpoint || 'xl';
me.isRendered = false;
if (me.collection) {
me.listenTo(me.collection, 'add', me.onAdd);
me.listenTo(me.collection, 'change', _db.throttle(me.onChange, 150, me));
me.listenTo(me.collection, 'remove', me.onRemove);
// Main buttons.
me.listenTo(me.collection, 'gridstack:main:save', _db.throttle(me.onSave, 200, me));
// Root box buttons.
me.listenTo(me.collection, 'gridstack:root:remove', me.onRootRemoveMultiple);
// Nested grids are css-driven: Bootstrap + Foundation.
if (me.isNested) {
me.listenTo(me.collection, 'gridstack:root:add', me.onNestedAddMultiple);
// Content has no .btn--add to avoid complication with deep nesting.
me.listenTo(me.collection, 'gridstack:nested:remove', me.onNestedRemoveMultiple);
}
// Provides context to collection.
me.collection._isNested = me.isNested;
}
},
init: function () {
var me = this;
var el = me.$el;
// Initialize GridStack root instances.
me.gridStack = GridStack.init(me.gridStackOptions, el);
me.nodes = GridStack.Utils.sort(Drupal.gridstack.base.newData(el));
me.nestedNodes = GridStack.Utils.sort(Drupal.gridstack.base.newData(el, true));
me.$wrapper = el.parent(me.wrapper);
// Update grid column.
el.addClass('grid-stack-' + me.column);
me.gridStack.column(me.column);
},
build: function () {
var me = this;
if (me.collection) {
Drupal.gridstack.base.lastBoxIndex = me.collection.length;
if (me.collection.length) {
me.collection.each(function (box, i) {
// Build the main boxes for each breakpoint: xs, sm, md, lg, xl.
me.addWidget(box);
// Build nested data boxes, if any.
if (me.isNested && me.nestedNodes.length) {
me.addNestedWidgetMultiple(box, i);
}
}, me);
}
}
if (!me.isNested) {
me.$el.on('change.gsimg', '.form-select--image-style', _.bind(me.onChangeImageStyle, me));
me.$el.on('click.gsimg', '.form-select--image-style', _.bind(me.onClickImageStyle, me));
$('.form-select--image-style', me.$el).each(_.bind(me.populateImageStyle, me));
}
},
render: function () {
var me = this;
// Initialize GridStack instance.
me.init();
me.build();
me.isRendered = true;
return me;
},
isValid: function (object) {
return !_.isNull(object) && !_.isUndefined(object);
},
isValidModel: function (box) {
return this.isValid(box) && box instanceof Drupal.gridstack.models.Box;
},
getModel: function ($box) {
return this.getModelById(this.getModelId($box));
},
getModelId: function ($box) {
return Drupal.gridstack.base.getModelId($box);
},
getModelById: function (id, collection) {
collection = collection || this.collection;
return collection.findWhere({id: id});
},
getBoxById: function (id, el) {
return $('> .box[data-gs-bid="' + id + '"]', el || this.$el);
},
isValidNode: function (node) {
return this.isValid(node) && (!_.isUndefined(node.x) || !_.isUndefined(node.width));
},
getParsedNode: function (node) {
return Drupal.gridstack.base.node(node);
},
getFakeModel: function (node, index, indexNested) {
if (!_.isUndefined(index)) {
node.index = index;
}
if (!_.isUndefined(indexNested)) {
node.indexNested = indexNested;
}
return _.extend(this.getParsedNode(node), Drupal.gridstack.base.attributes(node));
},
hasGridStack: function (el) {
el = el.length ? el : $(el);
return el.length && this.isValid(el[0].gridstack);
},
getGridStack: function (el) {
return this.hasGridStack(el) ? el[0].gridstack : this.gridStack;
},
getCurrentView: function (box) {
return this.isValidModel(box) ? new Drupal.gridstack.views.Box({
model: box
}) : null;
},
getStoredImageStyle: function (i) {
return this.isValid(this.nodes[i]) && !_.isUndefined(this.nodes[i].image_style) ? this.nodes[i].image_style : '';
},
populateImageStyle: function (i, el) {
var $el = $(el);
var $box = $el.closest('.box');
var v = $box.data('imageStyle');
var $selected = '<option value="' + v + '">' + v + '</option>';
if (v && v !== '' && !$el.children().length) {
$el.html($selected);
}
}
}, Drupal.gridstack.crud));
})(jQuery, Drupal, drupalSettings, Backbone, _, dBlazy, GridStack, this);
