Replace Ember app with Mithril app

This commit is contained in:
Toby Zerner
2015-04-25 22:28:39 +09:30
parent 6f67b8c247
commit b68a4711dc
377 changed files with 5641 additions and 7330 deletions

View File

@ -0,0 +1,3 @@
export default function(number) {
return ''+number; // todo
}

21
js/lib/utils/app.js Normal file
View File

@ -0,0 +1,21 @@
import ItemList from 'flarum/utils/item-list';
class App {
constructor() {
this.initializers = new ItemList();
this.cache = {};
}
boot() {
this.initializers.toArray().forEach((initializer) => initializer(this));
}
route(name, args, queryParams) {
var queryString = m.route.buildQueryString(queryParams);
return this.routes[name][0].replace(/:([^\/]+)/g, function(m, t) {
return typeof args[t] === 'function' ? args[t]() : args[t];
}) + (queryString ? '?'+queryString : '');
}
}
export default App;

View File

@ -0,0 +1,12 @@
export default function classList(classes) {
var classNames = [];
for (var i in classes) {
var value = classes[i];
if (value === true) {
classNames.push(i);
} else if (value) {
classNames.push(value);
}
}
return classNames.join(' ');
}

22
js/lib/utils/computed.js Normal file
View File

@ -0,0 +1,22 @@
export default function computed() {
var args = [].slice.apply(arguments);
var keys = args.slice(0, -1);
var compute = args.slice(-1)[0];
var values = {};
var computed;
return function() {
var recompute = false;
keys.forEach(function(key) {
var value = typeof this[key] === 'function' ? this[key]() : this[key];
if (values[key] !== value) {
recompute = true;
values[key] = value;
}
}.bind(this));
if (recompute) {
computed = compute.apply(this, keys.map((key) => values[key]));
}
return computed;
}
};

36
js/lib/utils/evented.js Normal file
View File

@ -0,0 +1,36 @@
export default {
handlers: null,
/**
*/
getHandlers(event) {
this.handlers = this.handlers || {};
return this.handlers[event] = this.handlers[event] || [];
},
/**
*/
trigger(event, ...args) {
this.getHandlers(event).forEach((handler) => handler.apply(this, args));
},
/**
*/
on(event, handler) {
this.getHandlers(event).push(handler);
},
/**
*/
off(event, handler) {
var handlers = this.getHandlers(event);
var index = handlers.indexOf(handler);
if (index !== -1) {
handlers.splice(index, 1);
}
}
}

View File

@ -0,0 +1,40 @@
moment.locale('en', {
relativeTime : {
future: "in %s",
past: "%s ago",
s: "seconds",
m: "1m",
mm: "%dm",
h: "1h",
hh: "%dh",
d: "1d",
dd: "%dd",
M: "a month",
MM: "%d months",
y: "a year",
yy: "%d years"
}
});
export default function humanTime(time) {
var m = moment(time);
var minute = 6e4;
var hour = 36e5;
var day = 864e5;
var ago = null;
var diff = m.diff(moment());
if (diff < -30 * day) {
if (m.year() === moment().year()) {
ago = m.format('D MMM');
} else {
ago = m.format('MMM \'YY');
}
} else {
ago = m.fromNow();
}
return ago;
};

55
js/lib/utils/item-list.js Normal file
View File

@ -0,0 +1,55 @@
export class Item {
constructor(content, position) {
this.content = content;
this.position = position;
}
}
export default class ItemList {
add(key, content, position) {
this[key] = new Item(content, position);
}
toArray() {
var items = [];
for (var i in this) {
if (this.hasOwnProperty(i) && this[i] instanceof Item) {
items.push(this[i]);
}
}
var array = [];
var addItems = function(method, position) {
items = items.filter(function(item) {
if ((position && item.position && item.position[position]) || (!position && !item.position)) {
array[method](item);
} else {
return true;
}
});
};
addItems('unshift', 'first');
addItems('push', false);
addItems('push', 'last');
items = items.filter(function(item) {
var key = item.position.before || item.position.after;
var type = item.position.before ? 'before' : 'after';
if (key) {
var index = array.indexOf(this[key]);
if (index === -1) {
console.log("Can't find item with key '"+key+"' to insert "+type+", inserting at end instead");
return true;
} else {
array.splice(array.indexOf(this[key]) + (type === 'after' ? 1 : 0), 0, item);
}
}
}.bind(this));
array = array.concat(items);
return array.map((item) => item.content);
}
}

View File

@ -0,0 +1,7 @@
export default function mapRoutes(routes) {
var map = {};
for (var r in routes) {
map[routes[r][0]] = routes[r][1];
}
return map;
}

11
js/lib/utils/mixin.js Normal file
View File

@ -0,0 +1,11 @@
export default function mixin(Parent, ...mixins) {
class Mixed extends Parent {}
for (var i in mixins) {
var keys = Object.keys(mixins[i]);
for (var j in keys) {
var prop = keys[j];
Mixed.prototype[prop] = mixins[i][prop];
}
}
return Mixed;
}

View File

@ -0,0 +1,43 @@
var scroll = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame ||
function(callback) { window.setTimeout(callback, 1000/60) };
export default class ScrollListener {
constructor(callback) {
this.callback = callback;
this.lastTop = -1;
}
loop() {
if (!this.active) {
return;
}
this.update();
scroll(this.loop.bind(this));
}
update(force) {
var top = window.pageYOffset;
if (this.lastTop !== top || force) {
this.callback(top);
this.lastTop = top;
}
}
stop() {
this.active = false;
}
start() {
if (!this.active) {
this.active = true;
this.loop();
}
}
}

View File

@ -0,0 +1,34 @@
function hsvToRgb(h, s, v) {
var r, g, b, i, f, p, q, t;
if (h && s === undefined && v === undefined) {
s = h.s; v = h.v; h = h.h;
}
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v; g = t; b = p; break;
case 1: r = q; g = v; b = p; break;
case 2: r = p; g = v; b = t; break;
case 3: r = p; g = q; b = v; break;
case 4: r = t; g = p; b = v; break;
case 5: r = v; g = p; b = q; break;
}
return {
r: Math.floor(r * 255),
g: Math.floor(g * 255),
b: Math.floor(b * 255)
};
}
export default function stringToColor(string) {
var num = 0;
for (var i = 0; i < string.length; i++) {
num += string.charCodeAt(i);
}
var hue = num % 360;
var rgb = hsvToRgb(hue / 360, 0.4, 0.9);
return ''+rgb.r.toString(16)+rgb.g.toString(16)+rgb.b.toString(16);
};

View File

@ -0,0 +1,33 @@
/**
// constructor
this.subtree = new SubtreeRetainer(
() => this.props.post.freshness,
() => this.showing
);
this.subtree.add(() => this.props.user.freshness);
// view
this.subtree.retain() || 'expensive expression'
*/
export default class SubtreeRetainer {
constructor() {
this.old = [];
this.callbacks = [].slice.call(arguments);
}
retain() {
var needsRebuild = false;
this.callbacks.forEach((callback, i) => {
var result = callback();
if (result !== this.old[i]) {
this.old[i] = result;
needsRebuild = true;
}
});
return needsRebuild ? false : {subtree: 'retain'};
}
add() {
this.callbacks = this.callbacks.concat([].slice.call(arguments));
}
}