Skip to content

Instantly share code, notes, and snippets.

@JBreit
Last active June 18, 2018 00:41
Show Gist options
  • Save JBreit/3897544e01eccc5107d3f4fec004c95d to your computer and use it in GitHub Desktop.
Save JBreit/3897544e01eccc5107d3f4fec004c95d to your computer and use it in GitHub Desktop.
import { $on } from './util';
import View from './view';
import Model from './model';
import Controller from './controller';
class App {
constructor() {
const model = new Model();
const view = new View();
this.controller = new Controller(model, view);
}
}
const app = new App();
const setView = () => {
app.controller.setView(document.location.hash);
};
$on(window, 'load', setView);
$on(window, 'hashchange', setView);
export default class Controller {
constructor(model, view) {
this.model = model;
this.view = view;
}
render() {
this.view.render(this.model.toJSON());
}
setView(hash) {
let validURL = /^#\/[\d]{2}\/[\d]{4}$/.test(hash);
if (validURL) {
let matches = hash.match(/^#\/([\d]{2})\/([\d]{4})$/);
let month = parseInt(matches[1], 10) - 1;
let year = parseInt(matches[2], 10);
this.model.setDate(month,year);
}
this.render();
}
}
<!DOCTYPE html>
<html lang="en-us">
<head>
<base href="/">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Jason Breitigan">
<link rel="stylesheet" type="text/css" href="css/app.css">
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="assets/img/apple-touch-icon-57x57.png" />
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="assets/img/apple-touch-icon-114x114.png" />
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="assets/img/apple-touch-icon-72x72.png" />
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="assets/img/apple-touch-icon-144x144.png" />
<link rel="apple-touch-icon-precomposed" sizes="60x60" href="assets/img/apple-touch-icon-60x60.png" />
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="assets/img/apple-touch-icon-120x120.png" />
<link rel="apple-touch-icon-precomposed" sizes="76x76" href="assets/img/apple-touch-icon-76x76.png" />
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="assets/img/apple-touch-icon-152x152.png" />
<link rel="icon" type="image/png" href="assets/img/favicon-196x196.png" sizes="196x196" />
<link rel="icon" type="image/png" href="assets/img/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/png" href="assets/img/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="assets/img/favicon-16x16.png" sizes="16x16" />
<link rel="icon" type="image/png" href="assets/img/favicon-128.png" sizes="128x128" />
<meta name="application-name" content="&nbsp;"/>
<meta name="msapplication-TileColor" content="#FFFFFF" />
<meta name="msapplication-TileImage" content="assets/img/mstile-144x144.png" />
<meta name="msapplication-square70x70logo" content="assets/img/mstile-70x70.png" />
<meta name="msapplication-square150x150logo" content="assets/img/mstile-150x150.png" />
<meta name="msapplication-wide310x150logo" content="assets/img/mstile-310x150.png" />
<meta name="msapplication-square310x310logo" content="assets/img/mstile-310x310.png" />
<link rel="icon" href="img/favicon.ico">
<title>calendar</title>
</head>
<body>
<div id="wrap">
<div id="container">
<div class="aspect-container">
<div class="aspect-content" id="target">
</div>
</div>
</div>
</div>
<div id="modal-overlay">
<div id="modal-content"></div>
</div>
<script src="js/app.js"></script>
</body>
</html>
import moment from 'moment';
export default class Model {
constructor() {
this.now = moment().day(16);
}
setDate(month, year) {
this.now.month(month).year(year);
}
getDays() {
const days = [];
const calendarStart = moment(this.now).startOf('month');
const calendarEnd = moment(this.now).endOf('month');
const timeRange = calendarEnd.valueOf() - calendarStart.valueOf();
const daysInView = Math.floor(moment.duration( timeRange ).asDays());
for (let i = 0; i <= daysInView; i++) {
days.push({
iso: moment(calendarStart).add(i, 'days').toISOString()
});
};
return days;
}
toJSON() {
const iso = this.now.toISOString();
const days = this.getDays();
return { iso, days };
}
}
import moment from 'moment';
const html = (literals, ...values) => {
let result = '';
values.forEach((value, i) => {
let literal = literals[i];
if (Array.isArray(value)) {
value = value.join('');
}
result += literal;
result += value;
});
result += literals[literals.length - 1];
return result;
};
const controls = data => {
const curr = moment(data.iso);
const next = moment(data.iso).add(1, 'month');
const prev = moment(data.iso).subtract(1, 'month');
return html`
<div id="controls">
<a class="item" href="#/${prev.format('MM')}/${prev.format('YYYY')}">Back one month</a>
<p class="item">${curr.format('MMMM')}, ${curr.format('YYYY')}</p>
<a class="item" href="#/${next.format('MM')}/${next.format('YYYY')}">Forward one month</a>
</div>
`;
};
const day = data => html`
<li data-iso="${data.iso}">
<p class="date">${ moment(data.iso).format('D') }</p>
</li>
`;
const calendar = data => html`
${controls(data)}
<ul id="calendar" class="full-width weeks-${data.weekCount}">
${data.days.map(data => day(data))}
</ul>
`;
export { calendar };
const $on = (target, event, handler) => {
return target.addEventListener(event, handler);
};
export { $on };
import { calendar } from './template';
export default class View {
constructor() {
this.el = document.getElementById('target');
}
render(data) {
this.el.innerHTML = calendar(data);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment