mirror of
https://github.com/flarum/framework.git
synced 2025-05-22 14:49:57 +08:00
Replace Ember app with Mithril app
This commit is contained in:
3
js/lib/utils/abbreviate-number.js
Normal file
3
js/lib/utils/abbreviate-number.js
Normal file
@ -0,0 +1,3 @@
|
||||
export default function(number) {
|
||||
return ''+number; // todo
|
||||
}
|
21
js/lib/utils/app.js
Normal file
21
js/lib/utils/app.js
Normal 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;
|
12
js/lib/utils/class-list.js
Normal file
12
js/lib/utils/class-list.js
Normal 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
22
js/lib/utils/computed.js
Normal 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
36
js/lib/utils/evented.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
40
js/lib/utils/human-time.js
Normal file
40
js/lib/utils/human-time.js
Normal 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
55
js/lib/utils/item-list.js
Normal 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);
|
||||
}
|
||||
}
|
||||
|
7
js/lib/utils/map-routes.js
Normal file
7
js/lib/utils/map-routes.js
Normal 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
11
js/lib/utils/mixin.js
Normal 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;
|
||||
}
|
43
js/lib/utils/scroll-listener.js
Normal file
43
js/lib/utils/scroll-listener.js
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
34
js/lib/utils/string-to-color.js
Normal file
34
js/lib/utils/string-to-color.js
Normal 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);
|
||||
};
|
33
js/lib/utils/subtree-retainer.js
Normal file
33
js/lib/utils/subtree-retainer.js
Normal 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));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user