| Index: pkg/polymer/lib/elements/polymer-grid-layout/polymer-grid-layout.html
|
| diff --git a/pkg/polymer/lib/elements/polymer-grid-layout/polymer-grid-layout.html b/pkg/polymer/lib/elements/polymer-grid-layout/polymer-grid-layout.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8925e90d4d12d8c4a177f35c8ae0b1fabfbf2145
|
| --- /dev/null
|
| +++ b/pkg/polymer/lib/elements/polymer-grid-layout/polymer-grid-layout.html
|
| @@ -0,0 +1,324 @@
|
| +<link rel="import" href="../polymer/polymer.html">
|
| +
|
| +<polymer-element name="polymer-grid-layout" attributes="nodes layout auto">
|
| + <template>
|
| + </template>
|
| + <script>
|
| + (function() {
|
| + Polymer('polymer-grid-layout', {
|
| + nodes: null,
|
| + layout: null,
|
| + auto: false,
|
| + created: function() {
|
| + this.layout = [];
|
| + },
|
| + nodesChanged: function() {
|
| + this.invalidate();
|
| + },
|
| + layoutChanged: function() {
|
| + this.invalidate();
|
| + },
|
| + autoNodes: function() {
|
| + this.nodes = this.parentNode.children.array().filter(
|
| + function(node) {
|
| + switch(node.localName) {
|
| + case 'polymer-grid-layout':
|
| + case 'style':
|
| + return false;
|
| + }
|
| + return true;
|
| + }
|
| + );
|
| + },
|
| + invalidate: function() {
|
| + if (this.layout && this.layout.length) {
|
| + // job debounces layout, only letting it occur every N ms
|
| + this.layoutJob = this.job(this.layoutJob, this.relayout);
|
| + }
|
| + },
|
| + relayout: function() {
|
| + if (!this.nodes || this.auto) {
|
| + this.autoNodes();
|
| + }
|
| + layout(this.layout, this.nodes);
|
| + this.asyncFire('polymer-grid-layout');
|
| + }
|
| + });
|
| +
|
| + //
|
| +
|
| + var lineParent;
|
| +
|
| + function line(axis, p, d) {
|
| + var l = document.createElement('line');
|
| + var extent = (axis === 'left' ? 'width' :
|
| + (axis === 'top' ? 'height' : axis));
|
| + l.setAttribute('extent', extent);
|
| + if (d < 0) {
|
| + axis = (axis === 'left' ? 'right' :
|
| + (axis === 'top' ? 'bottom' : axis));
|
| + }
|
| + p = Math.abs(p);
|
| + l.style[axis] = p + 'px';
|
| + l.style[extent] = '0px';
|
| + lineParent.appendChild(l);
|
| + }
|
| +
|
| + var colCount, colOwners, rowCount, rowOwners;
|
| +
|
| + function matrixillate(matrix) {
|
| + // mesaure the matrix, must be rectangular
|
| + rowCount = matrix.length;
|
| + colCount = rowCount && matrix[0].length || 0;
|
| + // transpose matrix
|
| + var transpose = [];
|
| + for (var i=0; i<colCount; i++) {
|
| + var c = [];
|
| + for (var j=0; j<rowCount; j++) {
|
| + c.push(matrix[j][i]);
|
| + }
|
| + transpose.push(c);
|
| + }
|
| + // assign sizing control
|
| + colOwners = findOwners(matrix);
|
| + rowOwners = findOwners(transpose);
|
| + //console.log('colOwners', colOwners);
|
| + //console.log('rowOwners', rowOwners);
|
| + }
|
| +
|
| + function findOwners(matrix) {
|
| + var majCount = matrix.length;
|
| + var minCount = majCount && matrix[0].length || 0;
|
| + var owners = [];
|
| + // for each column (e.g.)
|
| + for (var i=0; i<minCount; i++) {
|
| + // array of contained areas
|
| + var contained = {};
|
| + // look at each row to find a containing area
|
| + for (var j=0; j<majCount; j++) {
|
| + // get the row vector
|
| + var vector = matrix[j]
|
| + // node index at [i,j]
|
| + var nodei = vector[i];
|
| + // if a node is there
|
| + if (nodei) {
|
| + // determine if it bounds this column
|
| + var owns = false;
|
| + if (i === 0) {
|
| + owns = (i === minCount-1) || (nodei !== vector[i+1]);
|
| + } else if (i === minCount - 1) {
|
| + owns = (i === 0) || (nodei !== vector[i-1]);
|
| + } else {
|
| + owns = nodei !== vector[i-1] && nodei !== vector[i+1];
|
| + }
|
| + if (owns) {
|
| + contained[nodei] = 1;
|
| + }
|
| + }
|
| + // store the owners for this column
|
| + owners[i] = contained;
|
| + }
|
| + }
|
| + return owners;
|
| + }
|
| +
|
| + var nodes;
|
| +
|
| + function colWidth(i) {
|
| + for (var col in colOwners[i]) {
|
| + col = Number(col);
|
| + if (col === 0) {
|
| + return 96;
|
| + }
|
| + var node = nodes[col - 1];
|
| + if (node.hasAttribute('h-flex') || node.hasAttribute('flex')) {
|
| + return -1;
|
| + }
|
| + var w = node.offsetWidth;
|
| + //console.log('colWidth(' + i + ') ==', w);
|
| + return w;
|
| + }
|
| + return -1;
|
| + }
|
| +
|
| + function rowHeight(i) {
|
| + for (var row in rowOwners[i]) {
|
| + row = Number(row);
|
| + if (row === 0) {
|
| + return 96;
|
| + }
|
| + var node = nodes[row - 1];
|
| + if (node.hasAttribute('v-flex') || node.hasAttribute('flex')) {
|
| + return -1;
|
| + }
|
| + var h = node.offsetHeight;
|
| + //console.log('rowHeight(' + i + ') ==', h);
|
| + return h;
|
| + }
|
| + return -1;
|
| + }
|
| +
|
| + var m = 0;
|
| +
|
| + function railize(count, sizeFn) {
|
| + //
|
| + // create rails for `count` tracks using
|
| + // sizing function `sizeFn(trackNo)`
|
| + //
|
| + // for n tracks there are (n+1) rails
|
| + //
|
| + // |track|track|track|
|
| + // 0|->sz0|->sz1|<-sz2|0
|
| + //
|
| + // |track|track|track|
|
| + // 0|->sz0| |<-sz2|0
|
| + //
|
| + // there can be one elastic track per set
|
| + //
|
| + // |track|track|track|track|
|
| + // 0|-->s0|-->s1|<--s1|<--s2|0
|
| + //
|
| + // sz1 spans multiple tracks which makes
|
| + // it elastic (it's underconstrained)
|
| + //
|
| + var rails = [];
|
| + var a = 0;
|
| + for (var i=0, x; i<count; i++) {
|
| + rails[i] = {p: a, s: 1};
|
| + x = sizeFn(i) + m + m;
|
| + if (x == -1) {
|
| + break;
|
| + }
|
| + a += x;
|
| + }
|
| + if (i === count) {
|
| + rails[i] = {p: 0, s: -1};
|
| + }
|
| + var b = 0;
|
| + for (var ii=count, x; ii>i; ii--) {
|
| + rails[ii] = {p: b, s: -1};
|
| + x = sizeFn(ii - 1) + m + m;
|
| + if (x !== -1) {
|
| + b += x;
|
| + }
|
| + }
|
| + return rails;
|
| + }
|
| +
|
| + // TODO(sjmiles): this code tries to preserve actual position,
|
| + // so 'unposition' is really 'naturalize' or something
|
| + function unposition(box) {
|
| + var style = box.style;
|
| + //style.right = style.bottom = style.width = style.height = '';
|
| + style.position = 'absolute';
|
| + style.display = 'inline-block';
|
| + style.boxSizing = style.mozBoxSizing = 'border-box';
|
| + }
|
| +
|
| + function _position(style, maj, min, ext, a, b) {
|
| + style[maj] = style[min] = '';
|
| + style[ext] = 'auto';
|
| + if (a.s < 0 && b.s < 0) {
|
| + var siz = a.p - b.p - m - m;
|
| + style[ext] = siz + 'px';
|
| + var c = 'calc(100% - ' + (b.p + siz + m) + 'px' + ')';
|
| + style[maj] = '-webkit-' + c;
|
| + style[maj] = c;
|
| + } else if (b.s < 0) {
|
| + style[maj] = a.p + m + 'px';
|
| + style[min] = b.p + m + 'px';
|
| + } else {
|
| + style[maj] = a.p + m + 'px';
|
| + style[ext] = b.p - a.p - m - m + 'px';
|
| + }
|
| + }
|
| +
|
| + function position(elt, left, right, top, bottom) {
|
| + _position(elt.style, 'top', 'bottom', 'height', rows[top],
|
| + rows[bottom]);
|
| + _position(elt.style, 'left', 'right', 'width', columns[left],
|
| + columns[right]);
|
| + }
|
| +
|
| + function layout(matrix, anodes, alineParent) {
|
| + //console.group('layout');
|
| +
|
| + lineParent = alineParent;
|
| + nodes = anodes;
|
| + matrixillate(matrix);
|
| +
|
| + nodes.forEach(unposition);
|
| +
|
| + columns = railize(colCount, colWidth);
|
| + rows = railize(rowCount, rowHeight);
|
| +
|
| + if (alineParent) {
|
| + //console.group('column rails');
|
| + columns.forEach(function(c) {
|
| + //console.log(c.p, c.s);
|
| + line('left', c.p, c.s);
|
| + });
|
| + //console.groupEnd();
|
| +
|
| + //console.group('row rails');
|
| + rows.forEach(function(r) {
|
| + //console.log(r.p, r.s);
|
| + line('top', r.p, r.s);
|
| + });
|
| + //console.groupEnd();
|
| + }
|
| +
|
| + //console.group('rail boundaries');
|
| + nodes.forEach(function(node, i) {
|
| + // node indices are 1-based
|
| + var n = i + 1;
|
| + // boundary rails
|
| + var l, r, t = 1e10, b = -1e10;
|
| + matrix.forEach(function(vector, i) {
|
| + var f = vector.indexOf(n);
|
| + if (f > -1) {
|
| + l = f;
|
| + r = vector.lastIndexOf(n) + 1;
|
| + t = Math.min(t, i);
|
| + b = Math.max(b, i) + 1;
|
| + }
|
| + });
|
| + if (l == undefined) {
|
| + //console.log('unused');
|
| + node.style.position = 'absolute';
|
| + var offscreen = node.getAttribute('offscreen');
|
| + switch (offscreen) {
|
| + case 'basement':
|
| + node.style.zIndex = 0;
|
| + break;
|
| + case 'left':
|
| + case 'top':
|
| + node.style[offscreen] = node.offsetWidth * -2 + 'px';
|
| + break;
|
| + case 'right':
|
| + node.style.left = node.offsetParent.offsetWidth
|
| + + node.offsetWidth + 'px';
|
| + break;
|
| + case 'bottom':
|
| + node.style.top = node.parentNode.offsetHeight
|
| + + node.offsetHeight + 'px';
|
| + break;
|
| + default:
|
| + node.style[Math.random() >= 0.5 ? 'left' : 'top'] = '-110%';
|
| + }
|
| + //node.style.opacity = 0;
|
| + node.style.pointerEvents = 'none';
|
| + } else {
|
| + node.style.pointerEvents = '';
|
| + //node.style.opacity = '';
|
| + //console.log(l, r, t, b);
|
| + position(node, l, r, t, b);
|
| + }
|
| + });
|
| + //console.groupEnd();
|
| + //console.groupEnd();
|
| + }
|
| +
|
| + })();
|
| + </script>
|
| +</polymer-element>
|
|
|