UNPKG

akurath

Version:

IDE Frontend for codepsaces.io

296 lines (239 loc) 8.49 kB
define([ "hr/utils", "hr/dom", "hr/hr", "utils/dragdrop" ], function(_, $, hr, dnd) { var GridView = hr.View.extend({ className: "component-grid", defaults: { columns: 0 // 0 means auto }, events: { }, initialize: function() { GridView.__super__.initialize.apply(this, arguments); this.columns = this.options.columns; this.views = []; return this; }, /* * Add a view */ addView: function(view, options) { view._grid = this; view._gridOptions = _.defaults(options || {}, { width: null }); this.views.push(view); this.update(); return view; }, /* * Remove a view */ removeView: function(view) { if (!_.isString(view)) view = view.cid; this.views = _.filter(this.views, function(_v) { return _v.cid != view; }); this.update(); }, /* * Change layout by defining */ setLayout: function(n) { this.columns = n; this.update(); }, /* * Return current layout */ getLayout: function() { var layout = this.columns || Math.floor(Math.sqrt(this.views.length)); var nColumns = Math.min(layout, this.views.length); var nLines = Math.ceil(this.views.length/layout); return { 'columns': nColumns, 'lines': nLines }; }, /* * Signal an update on tha layout to all views */ signalLayout: function() { _.each(this.views, function(view) { view.trigger("grid:layout"); }); }, /* * Re-render the complete layout */ render: function() { var x, y, lineW; // Detach view _.each(this.views, function(view) { view.detach(); }); // Clear the view this.$el.empty(); // Calcul layout var layout = this.getLayout(); var sectionWidth = (100/layout.columns).toFixed(3); var sectionHeight = (100/layout.lines).toFixed(3); // Add grid content x = 0; y = 0; lineW = 100; _.each(this.views, function(view, i) { var $section, $content, w, dw; // Calcul width for this section using optional width dw = (lineW/(layout.columns - x)); w = view._gridOptions.width || dw w = w.toFixed(4); // Container object $section = $("<div>", { 'class': 'grid-section', 'css': { 'left': (100 - lineW)+"%", 'top': (y * sectionHeight)+"%", 'width': w+"%", 'height': sectionHeight+"%" } }); $section.appendTo(this.$el); lineW = lineW - w; // Content $content = $("<div>", { 'class': 'grid-section-content' }); $content.append(view.$el); $content.appendTo($section); view.trigger("grid:layout"); // Resize bar if (x < (layout.columns - 1)) { // Horrizontal var hBar = $("<div>", { 'class': "grid-resize-bar-h", 'mousedown': this.resizerHandler(x, y, "h") }); hBar.appendTo($section); $content.addClass("with-bar-h"); } if (y < (layout.lines - 1)) { // Vertical var vBar = $("<div>", { 'class': "grid-resize-bar-v", 'mousedown': this.resizerHandler(x, y, "v") }); vBar.appendTo($section); $content.addClass("with-bar-v"); } // Calcul next position x = x + 1; if (x >= layout.columns) { x = 0; y = y + 1; lineW = 100; } }, this); return this.ready(); }, // Create a resizer handler resizerHandler: function(x, y, type) { var that = this; var $document = $(document); var oX, oY, dX, dY; return function(e) { e.preventDefault(); oX = e.pageX; oY = e.pageY; dnd.cursor.set(type == "h" ? "col-resize" : "row-resize"); var f = function(e) { dx = oX - e.pageX; dy = oY - e.pageY; if (type == "h") { that.resizeColumn(x, -dx); } else { that.resizeLine(y, -dy); } oX = e.pageX; oY = e.pageY; }; $document.mousemove(f); $document.mouseup(function(e) { $document.unbind('mousemove', f); dnd.cursor.reset(); }); }; }, getSection: function(sx, sy) { var x, y, layout = this.getLayout(), that = this; x = 0; y = 0; return this.$("> .grid-section").filter(function() { var r = false; if ((sx !== null && sx == x) || (sy !== null && sy == y)) { r = true; } // Calcul next position x = x + 1; if (x >= layout.columns) { x = 0; y = y + 1; } return r; }); }, _resize: function(type, i, d) { var getSection = _.bind(_.partialRight(this.getSection, null), this); var pixelToPercent = _.bind(_.partialRight(this.pixelToPercent, null), this); var position = "left"; var size = "width"; if (type == "h") { getSection = _.bind(_.partial(this.getSection, null), this); pixelToPercent = _.bind(_.partial(this.pixelToPercent, null), this); position = "top"; size = "height"; } // Convert update to percent d = pixelToPercent(d); var $sections = getSection(i); var $sectionsAfter = getSection(i+1); // New size for next sections // We use el.get(0).style and not el.css because el.css returns pixel and not the real value var sAfterN = this.strToPercent($sectionsAfter.get(0).style[size])-d; // New size for current sections var sCurrentN = this.strToPercent($sections.get(0).style[size])+d; // Limited size if (sCurrentN < 10 || sAfterN < 10) return false; // Resize next line $sectionsAfter.css(_.object( [position, size], [ (this.strToPercent($sectionsAfter.get(0).style[position])+d).toFixed(2)+"%", sAfterN.toFixed(2)+"%" ] )); // Resize current line $sections.css(_.object( [size], [sCurrentN.toFixed(2)+"%"] )); this.signalLayout(); return true; }, resizeLine: function(i, d) { return this._resize("h", i, d); }, resizeColumn: function(i, d) { return this._resize("w", i, d); }, pixelToPercent: function(x, y) { if (x !== null) return ((x*100) / this.$el.width()); if (y !== null) return ((y*100) / this.$el.height()); }, strToPercent: function(size) { return parseFloat(size.replace("%", "")) } }); return GridView; });