Skip to content
This repository has been archived by the owner on Sep 2, 2022. It is now read-only.

[DISCUSS] Remove packery - custom js #304

Open
wants to merge 4 commits into
base: production
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
end

require 'lib/helpers'
require 'lib/tiler'
helpers Helpers

data.people.each do |person|
Expand Down
2 changes: 1 addition & 1 deletion lib/helpers.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require './lib/article_info'
require 'lib/article_info'

module Helpers
def retina_srcset(path)
Expand Down
111 changes: 111 additions & 0 deletions lib/tiler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
class Tiler
class TilingError < StandardError; end

attr_reader :rows, :columns

def initialize(rows: 10, columns: 3)
@rows = rows
@columns = columns
@tiles = []
end

def lay_tiles
tile_layout = generate_empty_tile_layout
@tiles.each do |tile|
lay_tile(tile, tile_layout)
end
tile_layout
end

def add_tile(tile_contents, width: 1, height: 1)
@tiles << Tiler::Tile.new(tile_contents, width: width, height: height)
end

class NoTile
def self.width; 1; end
def self.height; 1; end
def self.contents; nil; end
end

class Tile
attr_reader :contents, :width, :height

def initialize(contents, width: 1, height: 1)
@contents = contents
@width = width
@height = height
end
end

class LargeTileReference
attr_reader :tile

def initialize(tile)
@tile = tile
end

def contents
tile.contents
end

def width
tile.width
end

def height
tile.height
end
end

private

def generate_empty_tile_layout
rows.times.map do |_row_idx|
columns.times.map do |_column_idx|
NoTile
end
end
end

def lay_tile(tile, tile_layout)
space = empty_slots(tile_layout).detect { |empty_slot| fits?(tile, empty_slot, tile_layout) }
raise TilingError, "No room left!" if space.nil?

slots_to_fill = slots_for_tile(tile, space)
top_left_slot, *other_slots = slots_to_fill
tile_layout[top_left_slot.last][top_left_slot.first] = tile
if other_slots.any?
tile_ref = Tiler::LargeTileReference.new(tile)
other_slots.each do |slot|
tile_layout[slot.last][slot.first] = tile_ref
end
end
end

def empty_slots(tile_layout)
Enumerator.new do |yielder|
tile_layout.each.with_index do |row, row_idx|
row.each.with_index do |cell, column_idx|
if (cell == NoTile)
yielder << [column_idx, row_idx]
end
end
end
end
end

def slots_for_tile(tile, location = [0 , 0])
tile.height.times.flat_map do |y|
tile.width.times.map do |x|
[location.first + x, location.last + y]
end
end
end

def fits?(tile, location, tile_layout)
return false if tile_layout[location.last][location.first] != NoTile
return true if tile.width == 1 && tile.height == 1
needed_slots = slots_for_tile(tile, location)
needed_slots.all? { |slot| tile_layout[slot.last][slot.first] == NoTile }
end
end
81 changes: 23 additions & 58 deletions source/_blog_grid.erb
Original file line number Diff line number Diff line change
@@ -1,59 +1,24 @@
<div class="container--grid" data-packery-target>
<div class="blog-tile__grid-sizer"></div>
<% articles.each do |article| %>
<% if article.data.weekly_roundup %>
<%= partial 'blog_small_tile', locals: { article: article } %>
<% elsif article.data.main_image.to_s.empty? %>
<%= partial 'blog_medium_tile', locals: { article: article } %>
<% else %>
<%= partial 'blog_large_tile', locals: { article: article } %>
<% end %>
<% end %>
<div class="container--grid" data-tile-layout data-tile-gap="6">
<%
tiler = Tiler.new(columns: 3, rows: articles.size * 2)
articles.each do |article|
if article.data.weekly_roundup
tiler.add_tile([article, 'blog_small_tile'])
elsif article.data.main_image.to_s.empty?
tiler.add_tile([article, 'blog_medium_tile'], width: 1, height: 2)
else
tiler.add_tile([article, 'blog_large_tile'], width: 2, height: 2)
end
end
tiles = tiler.lay_tiles
tiles.each.with_index do |row, row_idx|
row.each.with_index do |article_tile, column_idx|
next if article_tile == Tiler::NoTile
next if article_tile.is_a? Tiler::LargeTileReference
%>
<%= partial article_tile.contents.last, locals: { article: article_tile.contents.first, row: row_idx, column: column_idx } %>
<%
end
end
%>
</div>

<%= javascript_include_tag "packery.min" %>
<script>
var packeryContainer = document.querySelector('[data-packery-target]');
var packeryOptions = {
transitionDuration: 0,
percentPosition: true,
itemSelector: '.blog-tile',
columnWidth: '.blog-tile__grid-sizer'
};

if (typeof window.matchMedia != "undefined" || typeof window.msMatchMedia != "undefined") {
var mq = matchMedia('(min-width: 660px)');
var packery;

if (mq.matches) {
packery = new Packery(packeryContainer, packeryOptions);
}

mq.addListener(function(mql) {
if (mql.matches) {
packery = new Packery(packeryContainer, packeryOptions);
} else {
packery.destroy();
}
});
}
</script>

<!--[if IE 9]>
<script>

packery = new Packery(packeryContainer, packeryOptions);
var packeryEnabled = true;

window.onresize = function() {
if (window.innerWidth >= 660 && !packeryEnabled) {
packery = new Packery(packeryContainer, packeryOptions);
packeryEnabled = true;
} else if (window.innerWidth < 660 && packeryEnabled) {
packery.destroy();
packeryEnabled = false;
}
};

</script>
<![endif]-->
2 changes: 1 addition & 1 deletion source/_blog_large_tile.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<a class="blog-tile blog-large-tile" href="<%= article.url %>">
<a class="blog-tile blog-large-tile" href="<%= article.url %>" data-tile data-tile-width="2" data-tile-height="2" data-tile-row="<%= row %>" data-tile-column="<%= column %>">
<div class="blog-large-tile__container">
<div class="blog-large-tile__article-image-container">
<img class="blog-large-tile__article-image" src="<%= article.data.main_image %>" alt="Article image">
Expand Down
2 changes: 1 addition & 1 deletion source/_blog_medium_tile.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<a class="blog-tile blog-medium-tile" href="<%= article.url %>">
<a class="blog-tile blog-medium-tile" href="<%= article.url %>" data-tile data-tile-width="1" data-tile-height="2" data-tile-row="<%= row %>" data-tile-column="<%= column %>">
<div class="blog-medium-tile__container">
<div class="blog-medium-tile__top-content">
<div class="blog-medium-tile__title">
Expand Down
2 changes: 1 addition & 1 deletion source/_blog_small_tile.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<a class="blog-tile blog-small-tile" href="<%= article.url %>">
<a class="blog-tile blog-small-tile" href="<%= article.url %>" data-tile data-tile-width="1" data-tile-height="1" data-tile-row="<%= row %>" data-tile-column="<%= column %>">
<div class="blog-small-tile__content">
<div class="blog-small-tile__title">
<%= truncate(article.title, length: 70) %>
Expand Down
1 change: 1 addition & 0 deletions source/assets/javascripts/application.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//= require tiler
//= require waypoints.min

var waypointElement = document.querySelector('[data-header-waypoint]');
Expand Down
13 changes: 0 additions & 13 deletions source/assets/javascripts/packery.min.js

This file was deleted.

106 changes: 106 additions & 0 deletions source/assets/javascripts/tiler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
(function() {
"use strict";

var Tiler = function(container) {
// fail early without doing anything if the container is missing...
if (container === null) { return; }
this.container = container;
this.tiles = container.querySelectorAll('[data-tile]');
// ... of if it has no tiles in it
if (this.tiles.length === 0) { return; }
this.layoutTiles();
};

Tiler.prototype.layoutTiles = function() {
var cellDimensions = this.cellDimensions(),
topLeftPosition = this.topLeftPosition(),
tileGap = this.tileGap(),
containerHeight = 0,
containerWidth = 0;
for (var i = 0; i < this.tiles.length; i++) {
var tile = this.tiles[i];
this.layTile(tile, topLeftPosition, cellDimensions, tileGap);
var tileBottom = (tile.offsetTop + tile.offsetHeight),
tileRight = (tile.offsetLeft + tile.offsetWidth);

if (tileBottom > containerHeight) { containerHeight = tileBottom; }
if (tileRight > containerWidth) { containerWidth = tileRight; }
}
this.container.style.width = containerWidth + 'px';
this.container.style.height = containerHeight + 'px';
};

Tiler.prototype.layTile = function(tile, topLeft, dimensions, tileGap) {
var row = this.getNumberFromData(tile, 'tileRow'),
column = this.getNumberFromData(tile, 'tileColumn'),
width = this.getNumberFromData(tile, 'tileWidth', 1),
height = this.getNumberFromData(tile, 'tileHeight', 1);

if ((row === undefined) || (column === undefined)) {
// don't try to lay the tile if we don't know where it goes
return;
}

tile.style.position = 'absolute';
tile.style.top = (topLeft.top + ((dimensions.height + tileGap) * row)) + 'px';
tile.style.left = (topLeft.left + ((dimensions.width + tileGap) * column)) + 'px';
tile.style.width = ((dimensions.width * width) + (tileGap * Math.max(width - 1, 0))) + 'px';
tile.style.height = ((dimensions.width * width) + (tileGap * Math.max(width - 1, 0))) + 'px';
};

Tiler.prototype.topLeftPosition = function() {
if (this._topLeftPosition === undefined) {
for (var i = 0; i < this.tiles.length; i++) {
var tile = this.tiles[i];
if ((tile.dataset.tileRow === "0") && (tile.dataset.tileColumn === "0")) {
this._topLeftPosition = { top: tile.offsetTop, left: tile.offsetLeft };
return this._topLeftPosition;
}
}
}
return this._topLeftPosition;
};

Tiler.prototype.cellDimensions = function() {
if (this._cellDimensions === undefined) {
var aTile = this.container.querySelector('[data-tile]');
if (aTile === null) {
// if there are no tiles in the container, fail fast
return;
}
var cellWidth = Math.ceil(aTile.offsetWidth / this.getNumberFromData(aTile, 'tileWidth', 1)),
cellHeight = Math.ceil(aTile.offsetHeight / this.getNumberFromData(aTile, 'tileHeight', 1));
this._cellDimensions = { width: cellWidth, height: cellHeight };
}
return this._cellDimensions;
};

Tiler.prototype.tileGap = function() {
if (this._tileGap === undefined) {
this._tileGap = this.getNumberFromData(this.container, 'tileGap', 6);
}
return this._tileGap;
};

Tiler.prototype.getNumberFromData = function(element, dataName, defaultValue) {
var value = parseInt(element.dataset[dataName]);
if (isNaN(value)) {
return defaultValue;
} else {
return value;
}
}

var readyFunc = function() {
var mql = window.matchMedia("(min-width: 660px)");
if (mql.matches) {
new Tiler(document.querySelector('[data-tile-layout]'));
}
};

if (document.readyState != 'loading') {
readyFunc();
} else {
document.addEventListener("DOMContentLoaded", readyFunc);
}
}());
4 changes: 3 additions & 1 deletion source/assets/stylesheets/styles/_blog_large_tile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
text-decoration: none;

@include breakpoint($tablet-breakpoint) {
float: left;
display: inline-block;
width: 66%;
margin-bottom: 0px;
padding-right: 0px;
}
}

Expand Down
4 changes: 3 additions & 1 deletion source/assets/stylesheets/styles/_blog_medium_tile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
text-decoration: none;

@include breakpoint($tablet-breakpoint) {
float: left;
display: inline-block;
width: 33%;
margin-bottom: 0px;
padding-right: 0px;
}
}

Expand Down
4 changes: 3 additions & 1 deletion source/assets/stylesheets/styles/_blog_small_tile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
text-decoration: none;

@include breakpoint($tablet-breakpoint) {
float: left;
display: inline-block;
width: 33%;
margin-bottom: 0px;
padding-right: 0px;
}
}

Expand Down
Loading