Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
254 lines
6.4 KiB
JavaScript
Executable file
254 lines
6.4 KiB
JavaScript
Executable file
/* global GaiaGrid */
|
|
/* global GridView */
|
|
|
|
/**
|
|
* The GaiaGrid component is a helper to display grid-like results.
|
|
* You can find this component used in places like the homescreen and search
|
|
* application.
|
|
*/
|
|
window.GaiaGrid = (function(win) {
|
|
'use strict';
|
|
|
|
// Extend from the HTMLElement prototype
|
|
var proto = Object.create(HTMLElement.prototype);
|
|
|
|
// Allow baseurl to be overridden (used for demo page)
|
|
var baseurl = window.GaiaGridBaseurl ||
|
|
'/shared/elements/gaia_grid/';
|
|
|
|
/* Configuration from the grid is picked up by attributes on the element.
|
|
* The following attributes are valid:
|
|
* - dragdrop
|
|
* Enables drag-and-drop of icons and groups within the grid.
|
|
* - zoom
|
|
* Enables changing the grid column-width with a pinch gesture.
|
|
* - disable-sections
|
|
* Only valid with dragdrop enabled, this disables creating new dividers
|
|
* or groups.
|
|
*/
|
|
proto.createdCallback = function() {
|
|
var shadow = this.createShadowRoot();
|
|
this._template = template.content.cloneNode(true);
|
|
this._styleHack();
|
|
|
|
// Todo: render in the shadowRoot
|
|
// By changing the element to this._template we should be able to render
|
|
// to the shadowRoot, although some things are not yet working.
|
|
this._grid = new GridView({
|
|
element: this,
|
|
features: {
|
|
dragdrop: this.getAttribute('dragdrop') !== null,
|
|
zoom: this.getAttribute('zoom') !== null,
|
|
disableSections: this.getAttribute('disable-sections') !== null
|
|
}
|
|
});
|
|
|
|
shadow.appendChild(this._template);
|
|
};
|
|
|
|
/**
|
|
* Helper for GridView.prototype.add
|
|
*/
|
|
proto.add = function() {
|
|
this._grid.add.apply(this._grid, arguments);
|
|
};
|
|
|
|
/**
|
|
* Helper for GridView.prototype.clear
|
|
*/
|
|
proto.clear = function() {
|
|
this._grid.clear.apply(this._grid, arguments);
|
|
};
|
|
|
|
/**
|
|
* Helper for GridView.prototype.render
|
|
*/
|
|
proto.render = function() {
|
|
this._grid.layout.calculateSize();
|
|
this._grid.render.apply(this._grid, arguments);
|
|
};
|
|
|
|
/**
|
|
* Helper for GridView.prototype.start
|
|
*/
|
|
proto.start = function() {
|
|
this._grid.start.apply(this._grid, arguments);
|
|
};
|
|
|
|
/**
|
|
* Helper for GridView.prototype.stop
|
|
*/
|
|
proto.stop = function() {
|
|
this._grid.stop.apply(this._grid, arguments);
|
|
};
|
|
|
|
/**
|
|
* Returns a reference of the grid icons.
|
|
*/
|
|
proto.getIcons = function() {
|
|
return this._grid.icons;
|
|
};
|
|
|
|
/**
|
|
* Returns a copy of the grid items.
|
|
*/
|
|
proto.getItems = function() {
|
|
return this._grid.items;
|
|
};
|
|
|
|
proto.getIcon = function(identifier) {
|
|
return this._grid.icons[identifier];
|
|
};
|
|
|
|
/**
|
|
* Removes an icon by identifier.
|
|
* @param {String} identifier
|
|
*/
|
|
proto.removeIconByIdentifier = function(identifier) {
|
|
delete this._grid.icons[identifier];
|
|
};
|
|
|
|
/**
|
|
* Removes an item by an index.
|
|
* @param {Integer} itemIndex
|
|
*/
|
|
proto.removeItemByIndex = function(itemIndex) {
|
|
this._grid.items.splice(itemIndex, 1);
|
|
};
|
|
|
|
/**
|
|
* Removes and returns the last divider, if there is one.
|
|
*/
|
|
proto.popDivider = function() {
|
|
var items = this._grid.items;
|
|
if (items.length && items[items.length - 1].detail.type === 'divider') {
|
|
return items.pop();
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Appends an item to the end of the group. If there is a divider at the end,
|
|
* the item is placed before said divider.
|
|
*/
|
|
proto.appendItem = function(item) {
|
|
var items = this._grid.items;
|
|
var lastIndex = items.length - 1;
|
|
|
|
if (items[lastIndex].detail.type === 'divider') {
|
|
this.add(item, lastIndex);
|
|
} else {
|
|
this.add(item);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* If the last item is a collapsed divider, expand that divider before
|
|
* appending the item.
|
|
*/
|
|
proto.appendItemToExpandedGroup = function(item) {
|
|
var items = this._grid.items;
|
|
var lastIndex = items.length - 1;
|
|
|
|
if (items[lastIndex].detail.type === 'divider' &&
|
|
items[lastIndex].detail.collapsed) {
|
|
items[lastIndex].expand();
|
|
}
|
|
|
|
this.appendItem(item);
|
|
};
|
|
|
|
/**
|
|
* Sets an element that should be considered as obscuring the top of the grid
|
|
* when in edit mode.
|
|
*/
|
|
proto.setEditHeaderElement = function(element) {
|
|
if (this._grid.dragdrop) {
|
|
this._grid.dragdrop.editHeaderElement = element;
|
|
}
|
|
};
|
|
|
|
Object.defineProperty(proto, 'maxIconSize', {
|
|
get: function() {
|
|
return this._grid.layout.gridMaxIconSize;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Returns the position of the last item which is not a divider
|
|
*/
|
|
proto.getIndexLastIcon = function() {
|
|
var items = this._grid.items;
|
|
for (var i = this._grid.items.length - 1; i >= 0; i--) {
|
|
if (items[i] instanceof GaiaGrid.Mozapp) {
|
|
return i;
|
|
}
|
|
}
|
|
};
|
|
|
|
proto.removeNonVisualElements = function() {
|
|
|
|
var nonVisualElements = [GaiaGrid.Placeholder];
|
|
|
|
function isNonVisual(elem) {
|
|
var retVal = false;
|
|
for (var i = 0, iLen = nonVisualElements.length; i < iLen && !retVal;
|
|
i++) {
|
|
retVal = elem instanceof nonVisualElements[i];
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
var i = 0 ;
|
|
var iLen = this._grid.items.length;
|
|
while (i < iLen) {
|
|
this._grid.items[i].detail.index = i;
|
|
if (isNonVisual(this._grid.items[i])) {
|
|
this._grid.items.splice(i,1);
|
|
iLen -= 1;
|
|
} else {
|
|
i += 1;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Move item on orig position to dst position
|
|
* This function only moves elements on the items array, without calling
|
|
* render.
|
|
* @param {number} orig Element's position to move
|
|
* @param {number} orig New position of the item
|
|
*/
|
|
proto.moveTo = function(orig, dst) {
|
|
this._grid.items.splice(dst, 0,
|
|
this._grid.items.splice(orig, 1)[0]);
|
|
};
|
|
|
|
/**
|
|
* We clone the scoped stylesheet and append
|
|
* it outside the shadow-root so that we can
|
|
* style projected <content> without the need
|
|
* of the :content selector.
|
|
*
|
|
* When the :content selector lands, we won't
|
|
* need this hack anymore and can style projected
|
|
* <content> from stylesheets within the shadow root.
|
|
* (bug 992249)
|
|
*
|
|
* @private
|
|
*/
|
|
proto._styleHack = function() {
|
|
var style = this._template.querySelector('style');
|
|
this.appendChild(style.cloneNode(true));
|
|
};
|
|
|
|
var stylesheet = baseurl + 'style.css';
|
|
var template = document.createElement('template');
|
|
template.innerHTML = `<style scoped>
|
|
@import url(${stylesheet});</style>
|
|
<content></content>`;
|
|
|
|
// Register and return the constructor
|
|
return document.registerElement('gaia-grid', { prototype: proto });
|
|
})(window);
|