mirror of
https://github.com/flarum/framework.git
synced 2025-04-29 08:04:03 +08:00
Replace Ember app with Mithril app
This commit is contained in:
parent
cceb2b1249
commit
b5c95a222f
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"directory": "bower_components",
|
|
||||||
"analytics": false
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
# EditorConfig helps developers define and maintain consistent
|
|
||||||
# coding styles between different editors and IDEs
|
|
||||||
# editorconfig.org
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
|
|
||||||
[*]
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.js]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.hbs]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.css]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.html]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.{diff,md}]
|
|
||||||
trim_trailing_whitespace = false
|
|
17
framework/core/ember/admin/.gitignore
vendored
17
framework/core/ember/admin/.gitignore
vendored
@ -1,17 +0,0 @@
|
|||||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# compiled output
|
|
||||||
/dist
|
|
||||||
/tmp
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/bower_components
|
|
||||||
|
|
||||||
# misc
|
|
||||||
/.sass-cache
|
|
||||||
/connect.lock
|
|
||||||
/coverage/*
|
|
||||||
/libpeerconnection.log
|
|
||||||
npm-debug.log
|
|
||||||
testem.log
|
|
@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"predef": [
|
|
||||||
"document",
|
|
||||||
"window",
|
|
||||||
"-Promise",
|
|
||||||
"moment"
|
|
||||||
],
|
|
||||||
"browser": true,
|
|
||||||
"boss": true,
|
|
||||||
"curly": true,
|
|
||||||
"debug": false,
|
|
||||||
"devel": true,
|
|
||||||
"eqeqeq": true,
|
|
||||||
"evil": true,
|
|
||||||
"forin": false,
|
|
||||||
"immed": false,
|
|
||||||
"laxbreak": false,
|
|
||||||
"newcap": true,
|
|
||||||
"noarg": true,
|
|
||||||
"noempty": false,
|
|
||||||
"nonew": false,
|
|
||||||
"nomen": false,
|
|
||||||
"onevar": false,
|
|
||||||
"plusplus": false,
|
|
||||||
"regexp": false,
|
|
||||||
"undef": true,
|
|
||||||
"sub": true,
|
|
||||||
"strict": false,
|
|
||||||
"white": false,
|
|
||||||
"eqnull": true,
|
|
||||||
"esnext": true,
|
|
||||||
"unused": true
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
language: node_js
|
|
||||||
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- node_modules
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- "npm config set spin false"
|
|
||||||
- "npm install -g npm@^2"
|
|
||||||
|
|
||||||
install:
|
|
||||||
- npm install -g bower
|
|
||||||
- npm install
|
|
||||||
- bower install
|
|
||||||
|
|
||||||
script:
|
|
||||||
- npm test
|
|
@ -1,20 +0,0 @@
|
|||||||
/* global require, module */
|
|
||||||
|
|
||||||
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
|
|
||||||
|
|
||||||
var app = new EmberApp();
|
|
||||||
|
|
||||||
app.import('bower_components/bootstrap/dist/js/bootstrap.js');
|
|
||||||
app.import('bower_components/spin.js/spin.js');
|
|
||||||
app.import('bower_components/spin.js/jquery.spin.js');
|
|
||||||
app.import('bower_components/moment/moment.js');
|
|
||||||
app.import('bower_components/jquery.hotkeys/jquery.hotkeys.js');
|
|
||||||
app.import('bower_components/blurjs/dist/jquery.blur.js');
|
|
||||||
|
|
||||||
app.import('bower_components/font-awesome/fonts/fontawesome-webfont.eot');
|
|
||||||
app.import('bower_components/font-awesome/fonts/fontawesome-webfont.svg');
|
|
||||||
app.import('bower_components/font-awesome/fonts/fontawesome-webfont.ttf');
|
|
||||||
app.import('bower_components/font-awesome/fonts/fontawesome-webfont.woff');
|
|
||||||
app.import('bower_components/font-awesome/fonts/FontAwesome.otf');
|
|
||||||
|
|
||||||
module.exports = app.toTree();
|
|
@ -1,18 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
import Resolver from 'ember/resolver';
|
|
||||||
import loadInitializers from 'ember/load-initializers';
|
|
||||||
import config from './config/environment';
|
|
||||||
|
|
||||||
Ember.MODEL_FACTORY_INJECTIONS = true;
|
|
||||||
|
|
||||||
var App = Ember.Application.extend({
|
|
||||||
modulePrefix: config.modulePrefix,
|
|
||||||
podModulePrefix: config.podModulePrefix,
|
|
||||||
Resolver: Resolver
|
|
||||||
});
|
|
||||||
|
|
||||||
loadInitializers(App, config.modulePrefix);
|
|
||||||
|
|
||||||
Ember.$('#assets-loading').remove();
|
|
||||||
|
|
||||||
export default App;
|
|
@ -1,8 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
import NavItem from './nav-item';
|
|
||||||
|
|
||||||
var precompileTemplate = Ember.Handlebars.compile;
|
|
||||||
|
|
||||||
export default NavItem.extend({
|
|
||||||
layout: precompileTemplate('{{#link-to routeName}}{{fa-icon icon class="icon"}} <span class="label">{{label}}</span> <div class="description">{{description}}</div>{{/link-to}}')
|
|
||||||
});
|
|
@ -1,23 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
import HasItemLists from '../mixins/has-item-lists';
|
|
||||||
import DropdownButton from './ui/dropdown-button';
|
|
||||||
|
|
||||||
var precompileTemplate = Ember.Handlebars.compile;
|
|
||||||
|
|
||||||
export default DropdownButton.extend(HasItemLists, {
|
|
||||||
layoutName: 'components/application/user-dropdown',
|
|
||||||
itemLists: ['items'],
|
|
||||||
|
|
||||||
buttonClass: 'btn btn-default btn-naked btn-rounded btn-user',
|
|
||||||
menuClass: 'pull-right',
|
|
||||||
label: Ember.computed.alias('user.username'),
|
|
||||||
|
|
||||||
populateItems: function(items) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.addActionItem(items, 'logout', 'Log Out', 'sign-out', null, function() {
|
|
||||||
self.get('parentController').send('invalidateSession');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,9 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
|
||||||
actions: {
|
|
||||||
toggleDrawer: function() {
|
|
||||||
this.toggleProperty('drawerShowing');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,25 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<title>Flarum</title>
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
|
|
||||||
{{content-for 'head'}}
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="assets/vendor.css">
|
|
||||||
<link rel="stylesheet" href="assets/flarum.css">
|
|
||||||
|
|
||||||
{{content-for 'head-footer'}}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{{content-for 'body'}}
|
|
||||||
|
|
||||||
<script src="assets/vendor.js"></script>
|
|
||||||
<script src="assets/flarum.js"></script>
|
|
||||||
|
|
||||||
{{content-for 'body-footer'}}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,16 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
import config from './config/environment';
|
|
||||||
|
|
||||||
var Router = Ember.Router.extend({
|
|
||||||
location: config.locationType
|
|
||||||
});
|
|
||||||
|
|
||||||
Router.map(function() {
|
|
||||||
this.resource('dashboard', {path: '/'});
|
|
||||||
this.resource('basics');
|
|
||||||
this.resource('permissions');
|
|
||||||
this.resource('appearance');
|
|
||||||
this.resource('extensions');
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Router;
|
|
@ -1,2 +0,0 @@
|
|||||||
// Flarum styles are stored in the top-level `less` directory. This remains
|
|
||||||
// here as a placeholder file to prevent ember-cli from crashing.
|
|
@ -1 +0,0 @@
|
|||||||
Appearance
|
|
@ -1,43 +0,0 @@
|
|||||||
<div id="page" class="global-page with-pane">
|
|
||||||
|
|
||||||
{{application/back-button className="back-control" toggleDrawer="toggleDrawer" goBack="goBack" canGoBack=false}}
|
|
||||||
|
|
||||||
<div id="drawer" class="global-drawer">
|
|
||||||
<header id="header" class="global-header">
|
|
||||||
{{application/back-button goBack="goBack" canGoBack=true}}
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
<div class="header-primary">
|
|
||||||
<h1 class="header-title">
|
|
||||||
Administration
|
|
||||||
</h1>
|
|
||||||
{{ui/item-list items=view.headerPrimary class="header-controls"}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="header-secondary">
|
|
||||||
{{ui/item-list items=view.headerSecondary class="header-controls"}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<main id="content" class="global-content">
|
|
||||||
<div class="container">
|
|
||||||
<div class="side-nav admin-nav title-control">
|
|
||||||
{{ui/dropdown-select items=view.adminNav}}
|
|
||||||
</div>
|
|
||||||
<div class="admin-content">
|
|
||||||
{{outlet}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="modal" class="modal fade">
|
|
||||||
{{outlet "modal"}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{render "alerts"}}
|
|
@ -1 +0,0 @@
|
|||||||
Basics
|
|
@ -1 +0,0 @@
|
|||||||
Dashboard
|
|
@ -1 +0,0 @@
|
|||||||
Extensions
|
|
@ -1 +0,0 @@
|
|||||||
{{ui/loading-indicator class="loading-indicator-block"}}
|
|
@ -1 +0,0 @@
|
|||||||
Permissions
|
|
@ -1,79 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
import HasItemLists from '../mixins/has-item-lists';
|
|
||||||
import AdminNavItem from '../components/ui/admin-nav-item';
|
|
||||||
import SearchInput from '../components/ui/search-input';
|
|
||||||
import UserDropdown from '../components/user-dropdown';
|
|
||||||
|
|
||||||
export default Ember.View.extend(HasItemLists, {
|
|
||||||
itemLists: ['headerPrimary', 'headerSecondary', 'adminNav'],
|
|
||||||
|
|
||||||
drawerShowingChanged: Ember.observer('controller.drawerShowing', function() {
|
|
||||||
Ember.run.scheduleOnce('afterRender', this, function() {
|
|
||||||
$('body').toggleClass('drawer-open', this.get('controller.drawerShowing'));
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
this.$('.global-content').click(function(e) {
|
|
||||||
if (view.get('controller.drawerShowing')) {
|
|
||||||
e.preventDefault();
|
|
||||||
view.set('controller.drawerShowing', false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
populateHeaderSecondary: function(items) {
|
|
||||||
var controller = this.get('controller');
|
|
||||||
|
|
||||||
items.pushObjectWithTag(SearchInput.extend({
|
|
||||||
placeholder: 'Search Forum',
|
|
||||||
controller: controller,
|
|
||||||
valueBinding: Ember.Binding.oneWay('controller.searchQuery'),
|
|
||||||
activeBinding: Ember.Binding.oneWay('controller.searchActive'),
|
|
||||||
action: function(value) { controller.send('search', value); }
|
|
||||||
}), 'search');
|
|
||||||
|
|
||||||
items.pushObjectWithTag(UserDropdown.extend({
|
|
||||||
user: this.get('controller.session.user'),
|
|
||||||
parentController: controller
|
|
||||||
}), 'user');
|
|
||||||
},
|
|
||||||
|
|
||||||
populateAdminNav: function(items) {
|
|
||||||
items.pushObjectWithTag(AdminNavItem.extend({
|
|
||||||
routeName: 'dashboard',
|
|
||||||
icon: 'bar-chart',
|
|
||||||
label: 'Dashboard',
|
|
||||||
description: 'Your forum at a glance.'
|
|
||||||
}), 'dashboard');
|
|
||||||
|
|
||||||
items.pushObjectWithTag(AdminNavItem.extend({
|
|
||||||
routeName: 'basics',
|
|
||||||
icon: 'pencil',
|
|
||||||
label: 'Basics',
|
|
||||||
description: 'Set your forum title, language, and other basic settings.'
|
|
||||||
}), 'basics');
|
|
||||||
|
|
||||||
items.pushObjectWithTag(AdminNavItem.extend({
|
|
||||||
routeName: 'permissions',
|
|
||||||
icon: 'key',
|
|
||||||
label: 'Permissions',
|
|
||||||
description: 'Configure who can see and do what.'
|
|
||||||
}), 'permissions');
|
|
||||||
|
|
||||||
items.pushObjectWithTag(AdminNavItem.extend({
|
|
||||||
routeName: 'appearance',
|
|
||||||
icon: 'paint-brush',
|
|
||||||
label: 'Appearance',
|
|
||||||
description: 'Customize your forum\'s colors, logos, and other variables.'
|
|
||||||
}), 'appearance');
|
|
||||||
|
|
||||||
items.pushObjectWithTag(AdminNavItem.extend({
|
|
||||||
routeName: 'extensions',
|
|
||||||
icon: 'puzzle-piece',
|
|
||||||
label: 'Extensions',
|
|
||||||
description: 'Add extra functionality to your forum and make it your own.'
|
|
||||||
}), 'extensions');
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "flarum-admin",
|
|
||||||
"dependencies": {
|
|
||||||
"jquery": "2.1.3",
|
|
||||||
"ember": "1.11.0-beta.3",
|
|
||||||
"ember-data": "1.0.0-beta.16.1",
|
|
||||||
"ember-resolver": "~0.1.11",
|
|
||||||
"loader.js": "ember-cli/loader.js#1.0.1",
|
|
||||||
"ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3",
|
|
||||||
"ember-cli-test-loader": "0.1.3",
|
|
||||||
"ember-load-initializers": "ember-cli/ember-load-initializers#0.0.2",
|
|
||||||
"ember-qunit": "0.2.8",
|
|
||||||
"ember-qunit-notifications": "0.0.7",
|
|
||||||
"qunit": "~1.17.1",
|
|
||||||
"bootstrap": "~3.3.2",
|
|
||||||
"font-awesome": "~4",
|
|
||||||
"spin.js": "~2.0.1",
|
|
||||||
"moment": "~2.8.4",
|
|
||||||
"ember-simple-auth": "0.7.2",
|
|
||||||
"jquery.hotkeys": "jeresig/jquery.hotkeys#0.2.0",
|
|
||||||
"blurjs": ""
|
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"ember-cli-test-loader": "0.1.3",
|
|
||||||
"ember-qunit": "0.2.8",
|
|
||||||
"ember-qunit-notifications": "0.0.7"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
/* jshint node: true */
|
|
||||||
|
|
||||||
module.exports = function(environment) {
|
|
||||||
var ENV = {
|
|
||||||
modulePrefix: 'flarum-admin',
|
|
||||||
environment: environment,
|
|
||||||
baseURL: '/',
|
|
||||||
apiURL: '/api',
|
|
||||||
locationType: 'hash',
|
|
||||||
EmberENV: {
|
|
||||||
FEATURES: {
|
|
||||||
// Here you can enable experimental features on an ember canary build
|
|
||||||
// e.g. 'with-controller': true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
APP: {
|
|
||||||
// Here you can pass flags/options to your application instance
|
|
||||||
// when it is created
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ENV['simple-auth'] = {
|
|
||||||
authorizer: 'authorizer:flarum'
|
|
||||||
};
|
|
||||||
|
|
||||||
if (environment === 'development') {
|
|
||||||
// ENV.APP.LOG_RESOLVER = true;
|
|
||||||
// ENV.APP.LOG_ACTIVE_GENERATION = true;
|
|
||||||
// ENV.APP.LOG_TRANSITIONS = true;
|
|
||||||
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
|
|
||||||
// ENV.APP.LOG_VIEW_LOOKUPS = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (environment === 'test') {
|
|
||||||
// Testem prefers this...
|
|
||||||
ENV.baseURL = '/';
|
|
||||||
ENV.locationType = 'none';
|
|
||||||
ENV.apiURL = 'http://flarum.dev/api',
|
|
||||||
|
|
||||||
// keep test console output quieter
|
|
||||||
ENV.APP.LOG_ACTIVE_GENERATION = false;
|
|
||||||
ENV.APP.LOG_VIEW_LOOKUPS = false;
|
|
||||||
|
|
||||||
ENV.APP.rootElement = '#ember-testing';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (environment === 'production') {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return ENV;
|
|
||||||
};
|
|
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "flarum-admin",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"directories": {
|
|
||||||
"doc": "doc",
|
|
||||||
"test": "tests"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "ember server",
|
|
||||||
"build": "ember build",
|
|
||||||
"test": "ember test",
|
|
||||||
"preinstall": "sudo npm link ../common"
|
|
||||||
},
|
|
||||||
"repository": "",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10.0"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "MIT",
|
|
||||||
"devDependencies": {
|
|
||||||
"ember-cli": "^0.2.0-beta.1",
|
|
||||||
"ember-cli-app-version": "0.3.1",
|
|
||||||
"ember-cli-babel": "^4.1.0",
|
|
||||||
"ember-cli-content-security-policy": "0.3.0",
|
|
||||||
"ember-cli-dependency-checker": "0.0.7",
|
|
||||||
"ember-cli-htmlbars": "^0.7.4",
|
|
||||||
"ember-cli-ic-ajax": "0.1.1",
|
|
||||||
"ember-cli-inject-live-reload": "^1.3.0",
|
|
||||||
"ember-cli-qunit": "^0.3.8",
|
|
||||||
"ember-cli-simple-auth": "^0.7.2",
|
|
||||||
"ember-cli-uglify": "1.0.1",
|
|
||||||
"ember-data": "1.0.0-beta.16.1",
|
|
||||||
"ember-export-application-global": "^1.0.2",
|
|
||||||
"ember-json-api": "eneuhauser/ember-json-api",
|
|
||||||
"broccoli-ember-inline-template-compiler": "tobscure/broccoli-ember-inline-template-compiler#f884d11",
|
|
||||||
"express": "^4.8.5",
|
|
||||||
"glob": "^4.0.5",
|
|
||||||
"flarum-common": "*"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"framework": "qunit",
|
|
||||||
"test_page": "tests/index.html?hidepassed",
|
|
||||||
"launch_in_ci": [
|
|
||||||
"PhantomJS"
|
|
||||||
],
|
|
||||||
"launch_in_dev": [
|
|
||||||
"PhantomJS",
|
|
||||||
"Chrome"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
{
|
|
||||||
"predef": [
|
|
||||||
"document",
|
|
||||||
"window",
|
|
||||||
"location",
|
|
||||||
"setTimeout",
|
|
||||||
"$",
|
|
||||||
"-Promise",
|
|
||||||
"QUnit",
|
|
||||||
"define",
|
|
||||||
"console",
|
|
||||||
"equal",
|
|
||||||
"notEqual",
|
|
||||||
"notStrictEqual",
|
|
||||||
"test",
|
|
||||||
"asyncTest",
|
|
||||||
"testBoth",
|
|
||||||
"testWithDefault",
|
|
||||||
"raises",
|
|
||||||
"throws",
|
|
||||||
"deepEqual",
|
|
||||||
"start",
|
|
||||||
"stop",
|
|
||||||
"ok",
|
|
||||||
"strictEqual",
|
|
||||||
"module",
|
|
||||||
"moduleFor",
|
|
||||||
"moduleForComponent",
|
|
||||||
"moduleForModel",
|
|
||||||
"process",
|
|
||||||
"expect",
|
|
||||||
"visit",
|
|
||||||
"exists",
|
|
||||||
"fillIn",
|
|
||||||
"click",
|
|
||||||
"keyEvent",
|
|
||||||
"triggerEvent",
|
|
||||||
"find",
|
|
||||||
"findWithAssert",
|
|
||||||
"wait",
|
|
||||||
"DS",
|
|
||||||
"isolatedContainer",
|
|
||||||
"startApp",
|
|
||||||
"andThen",
|
|
||||||
"currentURL",
|
|
||||||
"currentPath",
|
|
||||||
"currentRouteName"
|
|
||||||
],
|
|
||||||
"node": false,
|
|
||||||
"browser": false,
|
|
||||||
"boss": true,
|
|
||||||
"curly": false,
|
|
||||||
"debug": false,
|
|
||||||
"devel": false,
|
|
||||||
"eqeqeq": true,
|
|
||||||
"evil": true,
|
|
||||||
"forin": false,
|
|
||||||
"immed": false,
|
|
||||||
"laxbreak": false,
|
|
||||||
"newcap": true,
|
|
||||||
"noarg": true,
|
|
||||||
"noempty": false,
|
|
||||||
"nonew": false,
|
|
||||||
"nomen": false,
|
|
||||||
"onevar": false,
|
|
||||||
"plusplus": false,
|
|
||||||
"regexp": false,
|
|
||||||
"undef": true,
|
|
||||||
"sub": true,
|
|
||||||
"strict": false,
|
|
||||||
"white": false,
|
|
||||||
"eqnull": true,
|
|
||||||
"esnext": true
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import Resolver from 'ember/resolver';
|
|
||||||
import config from '../../config/environment';
|
|
||||||
|
|
||||||
var resolver = Resolver.create();
|
|
||||||
|
|
||||||
resolver.namespace = {
|
|
||||||
modulePrefix: config.modulePrefix,
|
|
||||||
podModulePrefix: config.podModulePrefix
|
|
||||||
};
|
|
||||||
|
|
||||||
export default resolver;
|
|
@ -1,19 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
import Application from '../../app';
|
|
||||||
import Router from '../../router';
|
|
||||||
import config from '../../config/environment';
|
|
||||||
|
|
||||||
export default function startApp(attrs) {
|
|
||||||
var application;
|
|
||||||
|
|
||||||
var attributes = Ember.merge({}, config.APP);
|
|
||||||
attributes = Ember.merge(attributes, attrs); // use defaults, but you can override;
|
|
||||||
|
|
||||||
Ember.run(function() {
|
|
||||||
application = Application.create(attributes);
|
|
||||||
application.setupForTesting();
|
|
||||||
application.injectTestHelpers();
|
|
||||||
});
|
|
||||||
|
|
||||||
return application;
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<title>Flarum Tests</title>
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
|
|
||||||
{{content-for 'head'}}
|
|
||||||
{{content-for 'test-head'}}
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="assets/vendor.css">
|
|
||||||
<link rel="stylesheet" href="assets/flarum-admin.css">
|
|
||||||
<link rel="stylesheet" href="assets/test-support.css">
|
|
||||||
|
|
||||||
{{content-for 'head-footer'}}
|
|
||||||
{{content-for 'test-head-footer'}}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
{{content-for 'body'}}
|
|
||||||
{{content-for 'test-body'}}
|
|
||||||
<script src="assets/vendor.js"></script>
|
|
||||||
<script src="assets/test-support.js"></script>
|
|
||||||
<script src="assets/flarum-admin.js"></script>
|
|
||||||
<script src="testem.js"></script>
|
|
||||||
<script src="assets/test-loader.js"></script>
|
|
||||||
|
|
||||||
{{content-for 'body-footer'}}
|
|
||||||
{{content-for 'test-body-footer'}}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,48 +0,0 @@
|
|||||||
import Ember from "ember";
|
|
||||||
import { test } from 'ember-qunit';
|
|
||||||
import startApp from '../helpers/start-app';
|
|
||||||
var App;
|
|
||||||
|
|
||||||
module('Index', {
|
|
||||||
setup: function() {
|
|
||||||
App = startApp();
|
|
||||||
},
|
|
||||||
teardown: function() {
|
|
||||||
Ember.run(App, App.destroy);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Discussion list loading', function() {
|
|
||||||
expect(3);
|
|
||||||
visit('/').then(function() {
|
|
||||||
equal(find('.discussions-list').length, 1, 'Page contains list of discussions');
|
|
||||||
equal(find('.discussions-list li').length, 20, 'There are 20 discussions in the list');
|
|
||||||
|
|
||||||
click('.control-loadMore').then(function() {
|
|
||||||
equal(find('.discussions-list li').length, 40, 'There are 40 discussions in the list');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Discussion list sorting', function() {
|
|
||||||
expect(1);
|
|
||||||
visit('/').then(function() {
|
|
||||||
fillIn('.control-sort select', 'replies').then(function() {
|
|
||||||
var discussions = find('.discussions-list li');
|
|
||||||
var good = true;
|
|
||||||
var getCount = function(item) {
|
|
||||||
return parseInt(item.find('.count strong').text());
|
|
||||||
};
|
|
||||||
var previousCount = getCount(discussions.eq(0));
|
|
||||||
for (var i = 1; i < discussions.length; i++) {
|
|
||||||
var count = getCount(discussions.eq(i));
|
|
||||||
if (count > previousCount) {
|
|
||||||
good = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
previousCount = count;
|
|
||||||
}
|
|
||||||
ok(good, 'Discussions are listed in order of reply count');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
import resolver from './helpers/resolver';
|
|
||||||
import {
|
|
||||||
setResolver
|
|
||||||
} from 'ember-qunit';
|
|
||||||
|
|
||||||
setResolver(resolver);
|
|
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"directory": "bower_components",
|
|
||||||
"analytics": false
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
# EditorConfig helps developers define and maintain consistent
|
|
||||||
# coding styles between different editors and IDEs
|
|
||||||
# editorconfig.org
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
|
|
||||||
[*]
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.js]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.hbs]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.css]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.html]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.{diff,md}]
|
|
||||||
trim_trailing_whitespace = false
|
|
17
framework/core/ember/common/.gitignore
vendored
17
framework/core/ember/common/.gitignore
vendored
@ -1,17 +0,0 @@
|
|||||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# compiled output
|
|
||||||
/dist
|
|
||||||
/tmp
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/bower_components
|
|
||||||
|
|
||||||
# misc
|
|
||||||
/.sass-cache
|
|
||||||
/connect.lock
|
|
||||||
/coverage/*
|
|
||||||
/libpeerconnection.log
|
|
||||||
npm-debug.log
|
|
||||||
testem.log
|
|
@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"predef": [
|
|
||||||
"document",
|
|
||||||
"window",
|
|
||||||
"-Promise"
|
|
||||||
],
|
|
||||||
"browser": true,
|
|
||||||
"boss": true,
|
|
||||||
"curly": true,
|
|
||||||
"debug": false,
|
|
||||||
"devel": true,
|
|
||||||
"eqeqeq": true,
|
|
||||||
"evil": true,
|
|
||||||
"forin": false,
|
|
||||||
"immed": false,
|
|
||||||
"laxbreak": false,
|
|
||||||
"newcap": true,
|
|
||||||
"noarg": true,
|
|
||||||
"noempty": false,
|
|
||||||
"nonew": false,
|
|
||||||
"nomen": false,
|
|
||||||
"onevar": false,
|
|
||||||
"plusplus": false,
|
|
||||||
"regexp": false,
|
|
||||||
"undef": true,
|
|
||||||
"sub": true,
|
|
||||||
"strict": false,
|
|
||||||
"white": false,
|
|
||||||
"eqnull": true,
|
|
||||||
"esnext": true,
|
|
||||||
"unused": true
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
bower_components/
|
|
||||||
tests/
|
|
||||||
|
|
||||||
.bowerrc
|
|
||||||
.editorconfig
|
|
||||||
.ember-cli
|
|
||||||
.travis.yml
|
|
||||||
.npmignore
|
|
||||||
**/.gitkeep
|
|
||||||
bower.json
|
|
||||||
Brocfile.js
|
|
||||||
testem.json
|
|
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
language: node_js
|
|
||||||
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- node_modules
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- "npm config set spin false"
|
|
||||||
- "npm install -g npm@^2"
|
|
||||||
|
|
||||||
install:
|
|
||||||
- npm install -g bower
|
|
||||||
- npm install
|
|
||||||
- bower install
|
|
||||||
|
|
||||||
script:
|
|
||||||
- npm test
|
|
@ -1,21 +0,0 @@
|
|||||||
/* jshint node: true */
|
|
||||||
/* global require, module */
|
|
||||||
|
|
||||||
var EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
|
|
||||||
|
|
||||||
var app = new EmberAddon();
|
|
||||||
|
|
||||||
// Use `app.import` to add additional libraries to the generated
|
|
||||||
// output files.
|
|
||||||
//
|
|
||||||
// If you need to use different assets in different
|
|
||||||
// environments, specify an object as the first parameter. That
|
|
||||||
// object's keys should be the environment name and the values
|
|
||||||
// should be the asset to use in that environment.
|
|
||||||
//
|
|
||||||
// If the library that you are including contains AMD or ES6
|
|
||||||
// modules that you would like to import into your application
|
|
||||||
// please specify an object with the list of modules as keys
|
|
||||||
// along with the exports of each module as its value.
|
|
||||||
|
|
||||||
module.exports = app.toTree();
|
|
@ -1,50 +0,0 @@
|
|||||||
import DS from 'ember-data';
|
|
||||||
import JsonApiAdapter from 'ember-json-api/json-api-adapter';
|
|
||||||
|
|
||||||
import config from '../config/environment';
|
|
||||||
import AlertMessage from '../components/ui/alert-message';
|
|
||||||
|
|
||||||
export default JsonApiAdapter.extend({
|
|
||||||
host: config.apiURL,
|
|
||||||
|
|
||||||
pathForType: function(type) {
|
|
||||||
if (type == 'activity') {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
return this._super(type);
|
|
||||||
},
|
|
||||||
|
|
||||||
ajaxError: function(jqXHR) {
|
|
||||||
var errors = this._super(jqXHR);
|
|
||||||
|
|
||||||
// Reparse the errors in accordance with the JSON-API spec to fit with
|
|
||||||
// Ember Data style. Hopefully something like this will eventually be a
|
|
||||||
// part of the JsonApiAdapter.
|
|
||||||
if (errors instanceof DS.InvalidError) {
|
|
||||||
var newErrors = {};
|
|
||||||
for (var i in errors.errors) {
|
|
||||||
var error = errors.errors[i];
|
|
||||||
newErrors[error.path] = error.detail;
|
|
||||||
}
|
|
||||||
return new DS.InvalidError(newErrors);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's a server error, show an alert message. The alerts controller
|
|
||||||
// has been injected into this adapter.
|
|
||||||
if (errors instanceof JsonApiAdapter.ServerError) {
|
|
||||||
var message;
|
|
||||||
if (errors.status === 401) {
|
|
||||||
message = 'You don\'t have permission to do this.';
|
|
||||||
} else {
|
|
||||||
message = errors.message;
|
|
||||||
}
|
|
||||||
var alert = AlertMessage.extend({
|
|
||||||
type: 'warning',
|
|
||||||
message: message
|
|
||||||
});
|
|
||||||
this.get('alerts').send('alert', alert);
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,28 +0,0 @@
|
|||||||
import Base from 'simple-auth/authenticators/base';
|
|
||||||
import config from '../config/environment';
|
|
||||||
|
|
||||||
export default Base.extend({
|
|
||||||
|
|
||||||
authenticate: function(credentials) {
|
|
||||||
var container = this.container;
|
|
||||||
return new Ember.RSVP.Promise(function(resolve, reject) {
|
|
||||||
Ember.$.ajax({
|
|
||||||
url: config.baseURL+'login',
|
|
||||||
type: 'POST',
|
|
||||||
data: { identification: credentials.identification, password: credentials.password }
|
|
||||||
}).then(function(response) {
|
|
||||||
container.lookup('store:main').find('user', response.userId).then(function(user) {
|
|
||||||
resolve({ token: response.token, userId: response.userId, user: user });
|
|
||||||
});
|
|
||||||
}, function(xhr, status, error) {
|
|
||||||
reject(xhr.responseJSON.errors);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
invalidate: function(data) {
|
|
||||||
return new Ember.RSVP.Promise(function() {
|
|
||||||
window.location = config.baseURL+'logout';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,10 +0,0 @@
|
|||||||
import Base from 'simple-auth/authorizers/base';
|
|
||||||
|
|
||||||
export default Base.extend({
|
|
||||||
authorize: function(jqXHR, requestOptions) {
|
|
||||||
var token = this.get('session.token');
|
|
||||||
if (this.get('session.isAuthenticated') && !Ember.isEmpty(token)) {
|
|
||||||
jqXHR.setRequestHeader('Authorization', 'Token ' + token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,43 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
The back/pin button group in the top-left corner of Flarum's interface.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
classNames: ['back-button'],
|
|
||||||
classNameBindings: ['active', 'className'],
|
|
||||||
|
|
||||||
active: Ember.computed.or('target.paneIsShowing', 'target.paneIsPinned'),
|
|
||||||
|
|
||||||
mouseEnter: function() {
|
|
||||||
var target = this.get('target');
|
|
||||||
if (target) {
|
|
||||||
target.send('showPane');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mouseLeave: function() {
|
|
||||||
var target = this.get('target');
|
|
||||||
if (target) {
|
|
||||||
target.send('hidePane');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
// WE HAVE TO GO BACK. WAAAAAALLLLLLTTTTT
|
|
||||||
back: function() {
|
|
||||||
this.sendAction('goBack');
|
|
||||||
},
|
|
||||||
|
|
||||||
togglePinned: function() {
|
|
||||||
var target = this.get('target');
|
|
||||||
if (target) {
|
|
||||||
target.send('togglePinned');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleDrawer: function() {
|
|
||||||
this.sendAction('toggleDrawer');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,29 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
var precompileTemplate = Ember.Handlebars.compile;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Button which sends an action when clicked.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
tagName: 'a',
|
|
||||||
attributeBindings: ['href', 'title'],
|
|
||||||
classNameBindings: ['className'],
|
|
||||||
href: '#',
|
|
||||||
layout: precompileTemplate('{{#if icon}}{{fa-icon icon class="fa-fw icon-glyph"}} {{/if}}<span class="label">{{label}}</span>'),
|
|
||||||
|
|
||||||
label: '',
|
|
||||||
icon: '',
|
|
||||||
className: '',
|
|
||||||
action: null,
|
|
||||||
|
|
||||||
click: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var action = this.get('action');
|
|
||||||
if (typeof action === 'string') {
|
|
||||||
this.sendAction('action');
|
|
||||||
} else if (typeof action === 'function') {
|
|
||||||
action.call(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,53 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
import HasItemLists from '../../mixins/has-item-lists';
|
|
||||||
import ActionButton from './action-button';
|
|
||||||
|
|
||||||
/**
|
|
||||||
An alert message. Has a message, a `controls` item list, and a dismiss
|
|
||||||
button.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend(HasItemLists, {
|
|
||||||
layoutName: 'components/ui/alert-message',
|
|
||||||
classNames: ['alert'],
|
|
||||||
classNameBindings: ['classForType'],
|
|
||||||
itemLists: ['controls'],
|
|
||||||
|
|
||||||
message: '',
|
|
||||||
type: '',
|
|
||||||
dismissable: true,
|
|
||||||
buttons: [],
|
|
||||||
|
|
||||||
classForType: Ember.computed('type', function() {
|
|
||||||
return 'alert-'+this.get('type');
|
|
||||||
}),
|
|
||||||
|
|
||||||
populateControls: function(controls) {
|
|
||||||
var component = this;
|
|
||||||
|
|
||||||
this.get('buttons').forEach(function(button) {
|
|
||||||
controls.pushObject(ActionButton.extend({
|
|
||||||
label: button.label,
|
|
||||||
action: function() {
|
|
||||||
component.send('dismiss');
|
|
||||||
button.action();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.get('dismissable')) {
|
|
||||||
var dismiss = ActionButton.extend({
|
|
||||||
icon: 'times',
|
|
||||||
className: 'btn btn-icon btn-link',
|
|
||||||
action: function() { component.send('dismiss'); }
|
|
||||||
});
|
|
||||||
controls.pushObjectWithTag(dismiss, 'dismiss');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
dismiss: function() {
|
|
||||||
this.sendAction('dismiss', this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,11 +0,0 @@
|
|||||||
import ActionButton from './action-button';
|
|
||||||
|
|
||||||
export default ActionButton.extend({
|
|
||||||
tagName: 'span',
|
|
||||||
classNames: ['badge'],
|
|
||||||
title: Ember.computed.alias('label'),
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
this.$().tooltip();
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,31 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
Button which has an attached dropdown menu containing an item list.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layoutName: 'components/ui/dropdown-button',
|
|
||||||
classNames: ['dropdown', 'btn-group'],
|
|
||||||
classNameBindings: ['itemCountClass', 'class'],
|
|
||||||
|
|
||||||
label: 'Controls',
|
|
||||||
icon: 'ellipsis-v',
|
|
||||||
buttonClass: 'btn btn-default',
|
|
||||||
menuClass: '',
|
|
||||||
items: null,
|
|
||||||
|
|
||||||
dropdownMenuClass: Ember.computed('menuClass', function() {
|
|
||||||
return 'dropdown-menu '+this.get('menuClass');
|
|
||||||
}),
|
|
||||||
|
|
||||||
itemCountClass: Ember.computed('items.length', function() {
|
|
||||||
var count = this.get('items.length');
|
|
||||||
return count ? 'item-count-'+this.get('items.length') : '';
|
|
||||||
}),
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
buttonClick: function() {
|
|
||||||
this.sendAction('buttonClick');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,32 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
Button which has an attached dropdown menu containing an item list. The
|
|
||||||
currently-active item's label is displayed as the label of the button.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layoutName: 'components/ui/dropdown-select',
|
|
||||||
classNames: ['dropdown', 'dropdown-select', 'btn-group'],
|
|
||||||
classNameBindings: ['itemCountClass', 'className'],
|
|
||||||
|
|
||||||
buttonClass: 'btn btn-default',
|
|
||||||
menuClass: '',
|
|
||||||
icon: 'ellipsis-v',
|
|
||||||
items: [],
|
|
||||||
|
|
||||||
mainButtonClass: Ember.computed('buttonClass', function() {
|
|
||||||
return 'btn '+this.get('buttonClass');
|
|
||||||
}),
|
|
||||||
|
|
||||||
dropdownMenuClass: Ember.computed('menuClass', function() {
|
|
||||||
return 'dropdown-menu '+this.get('menuClass');
|
|
||||||
}),
|
|
||||||
|
|
||||||
itemCountClass: Ember.computed('items.length', function() {
|
|
||||||
return 'item-count-'+this.get('items.length');
|
|
||||||
}),
|
|
||||||
|
|
||||||
activeItem: Ember.computed('menu.childViews.@each.active', function() {
|
|
||||||
return this.get('menu.childViews').findBy('active');
|
|
||||||
})
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
import DropdownButton from './dropdown-button';
|
|
||||||
|
|
||||||
/**
|
|
||||||
Given a list of items, this component displays a split button: the left side
|
|
||||||
is the first item in the list, while the right side is a dropdown-toggle
|
|
||||||
which shows a dropdown menu containing all of the items.
|
|
||||||
*/
|
|
||||||
export default DropdownButton.extend({
|
|
||||||
layoutName: 'components/ui/dropdown-split',
|
|
||||||
classNames: ['dropdown', 'dropdown-split', 'btn-group'],
|
|
||||||
menuClass: 'pull-right',
|
|
||||||
|
|
||||||
mainButtonClass: Ember.computed('buttonClass', function() {
|
|
||||||
return 'btn '+this.get('buttonClass');
|
|
||||||
}),
|
|
||||||
|
|
||||||
firstItem: Ember.computed('items.[]', function() {
|
|
||||||
return this.get('items').objectAt(0);
|
|
||||||
})
|
|
||||||
});
|
|
@ -1,13 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
A set of fields with a heading.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layoutName: 'components/ui/field-set',
|
|
||||||
tagName: 'fieldset',
|
|
||||||
classNameBindings: ['className'],
|
|
||||||
|
|
||||||
label: '',
|
|
||||||
fields: []
|
|
||||||
});
|
|
@ -1,24 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
Output a list of components within a <ul>, making sure each one is contained
|
|
||||||
in an <li> element.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layoutName: 'components/ui/item-list',
|
|
||||||
tagName: 'ul',
|
|
||||||
|
|
||||||
listItems: Ember.computed('items.[]', function() {
|
|
||||||
var items = this.get('items');
|
|
||||||
if (!Ember.isArray(items)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
var instances = [];
|
|
||||||
items.forEach(function(item) {
|
|
||||||
item = item.create();
|
|
||||||
item.set('isListItem', item.constructor.proto().tagName === 'li');
|
|
||||||
instances.pushObject(item);
|
|
||||||
});
|
|
||||||
return instances;
|
|
||||||
})
|
|
||||||
});
|
|
@ -1,19 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
var precompileTemplate = Ember.Handlebars.compile;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Loading spinner.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
classNames: ['loading-indicator'],
|
|
||||||
|
|
||||||
layout: precompileTemplate(' '),
|
|
||||||
size: 'small',
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
var size = this.get('size');
|
|
||||||
Ember.$.fn.spin.presets[size].zIndex = 'auto';
|
|
||||||
this.$().spin(size);
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
var precompileTemplate = Ember.Handlebars.compile;
|
|
||||||
|
|
||||||
/**
|
|
||||||
A list item which contains a navigation link. The list item's `active`
|
|
||||||
property reflects whether or not the link is active.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layout: precompileTemplate('{{#link-to routeName}}{{fa-icon icon}} {{label}} <span class="count">{{badge}}</span>{{/link-to}}'),
|
|
||||||
tagName: 'li',
|
|
||||||
classNameBindings: ['active'],
|
|
||||||
|
|
||||||
icon: '',
|
|
||||||
label: '',
|
|
||||||
badge: '',
|
|
||||||
routeName: '',
|
|
||||||
|
|
||||||
active: Ember.computed('childViews.@each.active', function() {
|
|
||||||
return !!this.get('childViews').anyBy('active');
|
|
||||||
})
|
|
||||||
});
|
|
@ -1,36 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
A basic search input. Comes with the ability to be cleared by pressing
|
|
||||||
escape or with a button. Sends an action when enter is pressed.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layoutName: 'components/ui/search-input',
|
|
||||||
classNames: ['search-input'],
|
|
||||||
classNameBindings: ['active', 'value:clearable'],
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
this.$('input').on('keydown', 'esc', function(e) {
|
|
||||||
self.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
this.$('.clear').on('mousedown click', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
}).on('click', function(e) {
|
|
||||||
self.clear();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
clear: function() {
|
|
||||||
this.set('value', '');
|
|
||||||
this.send('search');
|
|
||||||
this.$().find('input').focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
search: function() {
|
|
||||||
this.get('action')(this.get('value'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,16 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
var precompileTemplate = Ember.Handlebars.compile;
|
|
||||||
|
|
||||||
/**
|
|
||||||
A basic select input. Wraps Ember's select component with a span/icon so
|
|
||||||
that we can style it more fancily.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layout: precompileTemplate('{{view "select" content=view.content optionValuePath=view.optionValuePath optionLabelPath=view.optionLabelPath value=view.value class="form-control"}} {{fa-icon "sort"}}'),
|
|
||||||
tagName: 'span',
|
|
||||||
classNames: ['select-input'],
|
|
||||||
|
|
||||||
optionValuePath: 'content',
|
|
||||||
optionLabelPath: 'content'
|
|
||||||
});
|
|
@ -1,9 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
A simple separator list item for use in menus.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
tagName: 'li',
|
|
||||||
classNames: ['divider']
|
|
||||||
});
|
|
@ -1,19 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
A toggle switch.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layoutName: 'components/ui/switch-input',
|
|
||||||
classNames: ['checkbox', 'checkbox-switch'],
|
|
||||||
|
|
||||||
label: '',
|
|
||||||
toggleState: true,
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
var component = this;
|
|
||||||
this.$('input').on('change', function() {
|
|
||||||
component.get('changed')($(this).prop('checked'), component);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,33 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
import HasItemLists from '../../mixins/has-item-lists';
|
|
||||||
import ActionButton from './action-button';
|
|
||||||
|
|
||||||
/**
|
|
||||||
A text editor. Contains a textarea and an item list of `controls`, including
|
|
||||||
a submit button.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend(HasItemLists, {
|
|
||||||
classNames: ['text-editor'],
|
|
||||||
itemLists: ['controls'],
|
|
||||||
|
|
||||||
value: '',
|
|
||||||
disabled: false,
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
var component = this;
|
|
||||||
this.$('textarea').bind('keydown', 'meta+return', function() {
|
|
||||||
component.send('submit');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
populateControls: function(items) {
|
|
||||||
this.addActionItem(items, 'submit', this.get('submitLabel'), 'check').reopen({className: 'btn btn-primary', listItemClass: 'primary-control'});
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
submit: function() {
|
|
||||||
this.sendAction('submit', this.get('value'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,26 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
An extension of Ember's text field with an option to set up an auto-growing
|
|
||||||
text input.
|
|
||||||
*/
|
|
||||||
export default Ember.TextField.extend({
|
|
||||||
autoGrow: false,
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
if (this.get('autoGrow')) {
|
|
||||||
var component = this;
|
|
||||||
this.$().on('input', function() {
|
|
||||||
var empty = !$(this).val();
|
|
||||||
if (empty) {
|
|
||||||
$(this).val(component.get('placeholder'));
|
|
||||||
}
|
|
||||||
$(this).css('width', 0);
|
|
||||||
$(this).width($(this)[0].scrollWidth);
|
|
||||||
if (empty) {
|
|
||||||
$(this).val('');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,20 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
A toggle switch.
|
|
||||||
*/
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layoutName: 'components/ui/yesno-input',
|
|
||||||
tagName: 'label',
|
|
||||||
classNames: ['yesno-control'],
|
|
||||||
|
|
||||||
toggleState: true,
|
|
||||||
disabled: false,
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
var component = this;
|
|
||||||
this.$('input').on('change', function() {
|
|
||||||
component.get('changed')($(this).prop('checked'), component);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
|
||||||
alerts: [],
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
alert: function(message) {
|
|
||||||
this.get('alerts').pushObject(message);
|
|
||||||
},
|
|
||||||
dismissAlert: function(message) {
|
|
||||||
this.get('alerts').removeObject(message.constructor);
|
|
||||||
},
|
|
||||||
clearAlerts: function() {
|
|
||||||
this.get('alerts').clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Handlebars.makeBoundHelper(function(number) {
|
|
||||||
return new Ember.Handlebars.SafeString(''+number);
|
|
||||||
});
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Handlebars.makeBoundHelper(function(icon, options) {
|
|
||||||
return new Ember.Handlebars.SafeString('<i class="fa fa-fw fa-'+icon+' '+(options.hash.class || '')+'"></i>');
|
|
||||||
});
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Handlebars.makeBoundHelper(function(time) {
|
|
||||||
var m = moment(time);
|
|
||||||
var datetime = m.format();
|
|
||||||
var full = m.format('LLLL');
|
|
||||||
|
|
||||||
return new Ember.Handlebars.SafeString('<time pubdate datetime="'+datetime+'">'+full+'</time>');
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Handlebars.makeBoundHelper(function(text, phrase) {
|
|
||||||
if (phrase) {
|
|
||||||
var words = phrase.split(' ');
|
|
||||||
var replacement = function(matched) {
|
|
||||||
return '<span class="highlight-keyword">'+matched+'</span>';
|
|
||||||
};
|
|
||||||
words.forEach(function(word) {
|
|
||||||
text = text.replace(
|
|
||||||
new RegExp("\\b"+word+"\\b", 'gi'),
|
|
||||||
replacement
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return new Ember.Handlebars.SafeString(text);
|
|
||||||
});
|
|
@ -1,13 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
import humanTime from '../utils/human-time';
|
|
||||||
|
|
||||||
export default Ember.Handlebars.makeBoundHelper(function(time) {
|
|
||||||
var m = moment(time);
|
|
||||||
var datetime = m.format();
|
|
||||||
var full = m.format('LLLL');
|
|
||||||
|
|
||||||
var ago = humanTime(m);
|
|
||||||
|
|
||||||
return new Ember.Handlebars.SafeString('<time pubdate datetime="'+datetime+'" title="'+full+'" data-humantime>'+ago+'</time>');
|
|
||||||
});
|
|
@ -1,26 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Handlebars.makeBoundHelper(function(user, options) {
|
|
||||||
var attributes = 'class="avatar '+(options.hash.class || '')+'"';
|
|
||||||
var content = '';
|
|
||||||
|
|
||||||
if (user) {
|
|
||||||
var username = user.get('username') || '?';
|
|
||||||
|
|
||||||
if (typeof options.hash.title === 'undefined') {
|
|
||||||
options.hash.title = Ember.Handlebars.Utils.escapeExpression(username);
|
|
||||||
}
|
|
||||||
attributes += ' title="'+options.hash.title+'"';
|
|
||||||
|
|
||||||
var avatarUrl = user.get('avatarUrl');
|
|
||||||
if (avatarUrl) {
|
|
||||||
return new Ember.Handlebars.SafeString('<img src="'+avatarUrl+'" '+attributes+'>');
|
|
||||||
}
|
|
||||||
|
|
||||||
content = username.charAt(0).toUpperCase();
|
|
||||||
attributes += ' style="background:'+user.get('color')+'"';
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Ember.Handlebars.SafeString('<span '+attributes+'>'+content+'</span>');
|
|
||||||
}, 'avatarUrl', 'username', 'color');
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Handlebars.makeBoundHelper(function(user, options) {
|
|
||||||
var username;
|
|
||||||
if (user) {
|
|
||||||
username = user.get('username');
|
|
||||||
}
|
|
||||||
username = username || '[deleted]';
|
|
||||||
|
|
||||||
return new Ember.Handlebars.SafeString('<span class="username">'+Ember.Handlebars.Utils.escapeExpression(username)+'</span>');
|
|
||||||
});
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
import FlarumAuthorizer from '../authorizers/flarum';
|
|
||||||
import Config from '../config/environment';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'authentication',
|
|
||||||
before: 'simple-auth',
|
|
||||||
initialize: function(container) {
|
|
||||||
container.register('authorizer:flarum', FlarumAuthorizer);
|
|
||||||
Config['simple-auth'] = {authorizer: 'authorizer:flarum'};
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,25 +0,0 @@
|
|||||||
import DS from 'ember-data';
|
|
||||||
|
|
||||||
// This can be removed when
|
|
||||||
// https://github.com/emberjs/data/pull/2584 is implemented.
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'find-query-one',
|
|
||||||
initialize: function(container) {
|
|
||||||
DS.Store.reopen({
|
|
||||||
findQueryOne: function(type, id, query) {
|
|
||||||
var store = this;
|
|
||||||
var typeClass = store.modelFor(type);
|
|
||||||
var adapter = store.adapterFor(typeClass);
|
|
||||||
var serializer = store.serializerFor(typeClass);
|
|
||||||
var url = adapter.buildURL(type, id);
|
|
||||||
var ajaxPromise = adapter.ajax(url, 'GET', { data: query });
|
|
||||||
|
|
||||||
return ajaxPromise.then(function(rawPayload) {
|
|
||||||
var extractedPayload = serializer.extract(store, typeClass, rawPayload, id, 'find');
|
|
||||||
return store.push(typeClass, extractedPayload);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,147 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
import humanTime from '../utils/human-time';
|
|
||||||
|
|
||||||
var $ = Ember.$;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'human-time-updater',
|
|
||||||
initialize: function(container) {
|
|
||||||
|
|
||||||
// Livestamp.js / v1.1.2 / (c) 2012 Matt Bradley / MIT License
|
|
||||||
// @todo rewrite this to be simpler and cleaner
|
|
||||||
(function($, moment) {
|
|
||||||
var updateInterval = 1e3,
|
|
||||||
paused = false,
|
|
||||||
$livestamps = $([]),
|
|
||||||
|
|
||||||
init = function() {
|
|
||||||
livestampGlobal.resume();
|
|
||||||
},
|
|
||||||
|
|
||||||
prep = function($el, timestamp) {
|
|
||||||
var oldData = $el.data('livestampdata');
|
|
||||||
if (typeof timestamp == 'number')
|
|
||||||
timestamp *= 1e3;
|
|
||||||
|
|
||||||
$el.removeAttr('data-livestamp')
|
|
||||||
.removeData('livestamp');
|
|
||||||
|
|
||||||
timestamp = moment(timestamp);
|
|
||||||
if (timestamp.diff(moment(new Date())) < 60 * 60) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (moment.isMoment(timestamp) && !isNaN(+timestamp)) {
|
|
||||||
var newData = $.extend({ }, { 'original': $el.contents() }, oldData);
|
|
||||||
newData.moment = moment(timestamp);
|
|
||||||
|
|
||||||
$el.data('livestampdata', newData).empty();
|
|
||||||
$livestamps.push($el[0]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
run = function() {
|
|
||||||
if (paused) return;
|
|
||||||
livestampGlobal.update();
|
|
||||||
setTimeout(run, updateInterval);
|
|
||||||
},
|
|
||||||
|
|
||||||
livestampGlobal = {
|
|
||||||
update: function() {
|
|
||||||
$('[data-humantime]').each(function() {
|
|
||||||
var $this = $(this);
|
|
||||||
prep($this, $this.attr('datetime'));
|
|
||||||
});
|
|
||||||
|
|
||||||
var toRemove = [];
|
|
||||||
$livestamps.each(function() {
|
|
||||||
var $this = $(this),
|
|
||||||
data = $this.data('livestampdata');
|
|
||||||
|
|
||||||
if (data === undefined)
|
|
||||||
toRemove.push(this);
|
|
||||||
else if (moment.isMoment(data.moment)) {
|
|
||||||
var from = $this.html(),
|
|
||||||
to = humanTime(data.moment);
|
|
||||||
// to = data.moment.fromNow();
|
|
||||||
|
|
||||||
if (from != to) {
|
|
||||||
var e = $.Event('change.livestamp');
|
|
||||||
$this.trigger(e, [from, to]);
|
|
||||||
if (!e.isDefaultPrevented())
|
|
||||||
$this.html(to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$livestamps = $livestamps.not(toRemove);
|
|
||||||
},
|
|
||||||
|
|
||||||
pause: function() {
|
|
||||||
paused = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
resume: function() {
|
|
||||||
paused = false;
|
|
||||||
run();
|
|
||||||
},
|
|
||||||
|
|
||||||
interval: function(interval) {
|
|
||||||
if (interval === undefined)
|
|
||||||
return updateInterval;
|
|
||||||
updateInterval = interval;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
livestampLocal = {
|
|
||||||
add: function($el, timestamp) {
|
|
||||||
if (typeof timestamp == 'number')
|
|
||||||
timestamp *= 1e3;
|
|
||||||
timestamp = moment(timestamp);
|
|
||||||
|
|
||||||
if (moment.isMoment(timestamp) && !isNaN(+timestamp)) {
|
|
||||||
$el.each(function() {
|
|
||||||
prep($(this), timestamp);
|
|
||||||
});
|
|
||||||
livestampGlobal.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $el;
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function($el) {
|
|
||||||
$livestamps = $livestamps.not($el);
|
|
||||||
$el.each(function() {
|
|
||||||
var $this = $(this),
|
|
||||||
data = $this.data('livestampdata');
|
|
||||||
|
|
||||||
if (data === undefined)
|
|
||||||
return $el;
|
|
||||||
|
|
||||||
$this
|
|
||||||
.html(data.original ? data.original : '')
|
|
||||||
.removeData('livestampdata');
|
|
||||||
});
|
|
||||||
|
|
||||||
return $el;
|
|
||||||
},
|
|
||||||
|
|
||||||
isLivestamp: function($el) {
|
|
||||||
return $el.data('livestampdata') !== undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$.livestamp = livestampGlobal;
|
|
||||||
$(init);
|
|
||||||
$.fn.livestamp = function(method, options) {
|
|
||||||
if (!livestampLocal[method]) {
|
|
||||||
options = method;
|
|
||||||
method = 'add';
|
|
||||||
}
|
|
||||||
|
|
||||||
return livestampLocal[method](this, options);
|
|
||||||
};
|
|
||||||
})(jQuery, moment);
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,10 +0,0 @@
|
|||||||
export default {
|
|
||||||
name: 'inject-components',
|
|
||||||
initialize: function(container, application) {
|
|
||||||
application.inject('adapter', 'alerts', 'controller:alerts')
|
|
||||||
application.inject('component', 'alerts', 'controller:alerts')
|
|
||||||
application.inject('model', 'session', 'simple-auth-session:main')
|
|
||||||
application.inject('component', 'session', 'simple-auth-session:main')
|
|
||||||
application.inject('component', 'store', 'store:main')
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'preload-data',
|
|
||||||
after: 'ember-data',
|
|
||||||
initialize: function(container) {
|
|
||||||
var store = container.lookup('store:main');
|
|
||||||
if (!Ember.isEmpty(FLARUM_DATA)) {
|
|
||||||
store.pushPayload({included: FLARUM_DATA});
|
|
||||||
}
|
|
||||||
if (!Ember.isEmpty(FLARUM_SESSION)) {
|
|
||||||
FLARUM_SESSION.user = store.getById('user', FLARUM_SESSION.userId);
|
|
||||||
container.lookup('simple-auth-session:main').setProperties({
|
|
||||||
isAuthenticated: true,
|
|
||||||
authenticator: 'authenticator:flarum',
|
|
||||||
content: FLARUM_SESSION
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,16 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Mixin.create({
|
|
||||||
activate: function() {
|
|
||||||
var cssClass = this.toCssClass();
|
|
||||||
Ember.$('body').addClass(cssClass);
|
|
||||||
},
|
|
||||||
|
|
||||||
deactivate: function() {
|
|
||||||
Ember.$('body').removeClass(this.toCssClass());
|
|
||||||
},
|
|
||||||
|
|
||||||
toCssClass: function() {
|
|
||||||
return this.routeName.replace(/\./g, '-').dasherize();
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,14 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Mixin.create({
|
|
||||||
fadeIn: Ember.on('didInsertElement', function() {
|
|
||||||
var $this = this.$();
|
|
||||||
var targetOpacity = $this.css('opacity');
|
|
||||||
$this.css('opacity', 0);
|
|
||||||
setTimeout(function() {
|
|
||||||
$this.animate({opacity: targetOpacity}, 'fast', function() {
|
|
||||||
$this.css('opacity', '');
|
|
||||||
});
|
|
||||||
}, 100);
|
|
||||||
})
|
|
||||||
});
|
|
@ -1,62 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
import TaggedArray from '../utils/tagged-array';
|
|
||||||
import ActionButton from '../components/ui/action-button';
|
|
||||||
import SeparatorItem from '../components/ui/separator-item';
|
|
||||||
|
|
||||||
export default Ember.Mixin.create({
|
|
||||||
itemLists: [],
|
|
||||||
|
|
||||||
initItemLists: Ember.on('init', function() {
|
|
||||||
var self = this;
|
|
||||||
this.get('itemLists').forEach(function(name) {
|
|
||||||
self.initItemList(name);
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
|
|
||||||
initItemList: function(name) {
|
|
||||||
this.set(name, this.populateItemList(name));
|
|
||||||
},
|
|
||||||
|
|
||||||
populateItemList: function(name) {
|
|
||||||
var items = TaggedArray.create();
|
|
||||||
this.trigger('populate'+name.charAt(0).toUpperCase()+name.slice(1), items);
|
|
||||||
this.removeUnneededSeparatorItems(items);
|
|
||||||
return items;
|
|
||||||
},
|
|
||||||
|
|
||||||
addActionItem: function(items, tag, label, icon, conditionProperty, action) {
|
|
||||||
if (conditionProperty && !this.get(conditionProperty)) { return; }
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
var item = ActionButton.extend({
|
|
||||||
label: label,
|
|
||||||
icon: icon,
|
|
||||||
action: action || function() {
|
|
||||||
self.get('controller').send(tag);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
items.pushObjectWithTag(item, tag);
|
|
||||||
|
|
||||||
return item;
|
|
||||||
},
|
|
||||||
|
|
||||||
addSeparatorItem: function(items) {
|
|
||||||
items.pushObject(SeparatorItem);
|
|
||||||
},
|
|
||||||
|
|
||||||
removeUnneededSeparatorItems: function(items) {
|
|
||||||
var prevItem = null;
|
|
||||||
items.forEach(function(item) {
|
|
||||||
if (prevItem === SeparatorItem && item === SeparatorItem) {
|
|
||||||
items.removeObject(item);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
prevItem = item;
|
|
||||||
});
|
|
||||||
if (prevItem === SeparatorItem) {
|
|
||||||
items.removeObject(prevItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,9 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Mixin.create(Ember.Evented, {
|
|
||||||
actions: {
|
|
||||||
focus: function() {
|
|
||||||
this.trigger('focus');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,15 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Mixin.create({
|
|
||||||
focusEventOn: Ember.on('didInsertElement', function() {
|
|
||||||
this.get('controller').on('focus', this, this.focus);
|
|
||||||
}),
|
|
||||||
|
|
||||||
focusEventOff: Ember.on('willDestroyElement', function() {
|
|
||||||
this.get('controller').off('focus', this, this.focus);
|
|
||||||
}),
|
|
||||||
|
|
||||||
focus: Ember.on('didInsertElement', function() {
|
|
||||||
this.$('input:first:visible:enabled').focus();
|
|
||||||
})
|
|
||||||
});
|
|
@ -1,11 +0,0 @@
|
|||||||
import DS from 'ember-data';
|
|
||||||
|
|
||||||
export default DS.Model.extend({
|
|
||||||
contentType: DS.attr('string'),
|
|
||||||
content: DS.attr(),
|
|
||||||
time: DS.attr('date'),
|
|
||||||
|
|
||||||
user: DS.belongsTo('user'),
|
|
||||||
sender: DS.belongsTo('user'),
|
|
||||||
post: DS.belongsTo('post')
|
|
||||||
});
|
|
@ -1,7 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.ObjectProxy.extend({
|
|
||||||
relevantPosts: null,
|
|
||||||
startPost: null,
|
|
||||||
lastPost: null
|
|
||||||
});
|
|
@ -1,73 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
import DS from 'ember-data';
|
|
||||||
|
|
||||||
import HasItemLists from '../mixins/has-item-lists';
|
|
||||||
import Subject from './subject';
|
|
||||||
|
|
||||||
export default Subject.extend(HasItemLists, {
|
|
||||||
/**
|
|
||||||
Define a "badges" item list. Example usage:
|
|
||||||
```
|
|
||||||
populateBadges: function(items) {
|
|
||||||
items.pushObjectWithTag(BadgeButton.extend({
|
|
||||||
label: 'Sticky',
|
|
||||||
icon: 'thumb-tack',
|
|
||||||
className: 'badge-sticky',
|
|
||||||
discussion: this,
|
|
||||||
isHiddenInList: Ember.computed.not('discussion.sticky')
|
|
||||||
}), 'sticky');
|
|
||||||
}
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
itemLists: ['badges'],
|
|
||||||
|
|
||||||
title: DS.attr('string'),
|
|
||||||
slug: Ember.computed('title', function() {
|
|
||||||
return this.get('title').toLowerCase().replace(/[^a-z0-9]/gi, '-').replace(/-+/g, '-').replace(/-$|^-/g, '');
|
|
||||||
}),
|
|
||||||
|
|
||||||
startTime: DS.attr('date'),
|
|
||||||
startUser: DS.belongsTo('user'),
|
|
||||||
startPost: DS.belongsTo('post'),
|
|
||||||
|
|
||||||
lastTime: DS.attr('date'),
|
|
||||||
lastUser: DS.belongsTo('user'),
|
|
||||||
lastPost: DS.belongsTo('post'),
|
|
||||||
lastPostNumber: DS.attr('number'),
|
|
||||||
|
|
||||||
canReply: DS.attr('boolean'),
|
|
||||||
canEdit: DS.attr('boolean'),
|
|
||||||
canDelete: DS.attr('boolean'),
|
|
||||||
|
|
||||||
commentsCount: DS.attr('number'),
|
|
||||||
repliesCount: Ember.computed('commentsCount', function() {
|
|
||||||
return Math.max(0, this.get('commentsCount') - 1);
|
|
||||||
}),
|
|
||||||
|
|
||||||
// The API returns the `posts` relationship as a list of IDs. To hydrate a
|
|
||||||
// post-stream object, we're only interested in obtaining a list of IDs, so
|
|
||||||
// we make it a string and then split it by comma. Instead, we'll put a
|
|
||||||
// relationship on `loadedPosts`.
|
|
||||||
// posts: DS.attr('string'),
|
|
||||||
posts: DS.hasMany('post', {async: true}),
|
|
||||||
postIds: Ember.computed(function() {
|
|
||||||
var ids = [];
|
|
||||||
this.get('data.posts').forEach(function(post) {
|
|
||||||
ids.push(post.id);
|
|
||||||
});
|
|
||||||
return ids;
|
|
||||||
}),
|
|
||||||
loadedPosts: DS.hasMany('post'),
|
|
||||||
relevantPosts: DS.hasMany('post'),
|
|
||||||
addedPosts: DS.hasMany('post'),
|
|
||||||
|
|
||||||
readTime: DS.attr('date'),
|
|
||||||
readNumber: DS.attr('number'),
|
|
||||||
unreadCount: Ember.computed('lastPostNumber', 'readNumber', 'session.user.readTime', function() {
|
|
||||||
return this.get('session.user.readTime') < this.get('lastTime') ? Math.max(0, this.get('lastPostNumber') - (this.get('readNumber') || 0)) : 0;
|
|
||||||
}),
|
|
||||||
isUnread: Ember.computed.bool('unreadCount'),
|
|
||||||
|
|
||||||
// Only used to save a new discussion
|
|
||||||
content: DS.attr('string')
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
import DS from 'ember-data';
|
|
||||||
|
|
||||||
export default DS.Model.extend({
|
|
||||||
name: DS.attr('string'),
|
|
||||||
users: DS.hasMany('group'),
|
|
||||||
});
|
|
@ -1,21 +0,0 @@
|
|||||||
import DS from 'ember-data';
|
|
||||||
|
|
||||||
export default DS.Model.extend({
|
|
||||||
contentType: DS.attr('string'),
|
|
||||||
subjectId: DS.attr('number'),
|
|
||||||
content: DS.attr(),
|
|
||||||
time: DS.attr('date'),
|
|
||||||
isRead: DS.attr('boolean'),
|
|
||||||
unreadCount: DS.attr('number'),
|
|
||||||
additionalUnreadCount: Ember.computed('unreadCount', function() {
|
|
||||||
return Math.max(0, this.get('unreadCount') - 1);
|
|
||||||
}),
|
|
||||||
|
|
||||||
decodedContent: Ember.computed('content', function() {
|
|
||||||
return JSON.parse(this.get('content'));
|
|
||||||
}),
|
|
||||||
|
|
||||||
user: DS.belongsTo('user'),
|
|
||||||
sender: DS.belongsTo('user'),
|
|
||||||
subject: DS.belongsTo('subject', {polymorphic: true})
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
var PostResult = Ember.ObjectProxy.extend({
|
|
||||||
|
|
||||||
relevantContent: ''
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
PostResult.reopenClass({
|
|
||||||
create: function(post) {
|
|
||||||
if (!post) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = this._super();
|
|
||||||
result.set('content', post);
|
|
||||||
result.set('relevantContent', post.get('content'));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default PostResult;
|
|
@ -1,209 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
/**
|
|
||||||
The post stream is an object which represents the posts in a discussion as
|
|
||||||
they are displayed on the discussion page, from top to bottom. ...
|
|
||||||
*/
|
|
||||||
export default Ember.ArrayProxy.extend(Ember.Evented, {
|
|
||||||
|
|
||||||
// An array of all of the post IDs, in chronological order, in the discussion.
|
|
||||||
ids: null,
|
|
||||||
|
|
||||||
content: null,
|
|
||||||
|
|
||||||
store: null,
|
|
||||||
discussion: null,
|
|
||||||
|
|
||||||
postLoadCount: 20,
|
|
||||||
|
|
||||||
count: Ember.computed.alias('ids.length'),
|
|
||||||
|
|
||||||
loadedCount: Ember.computed('content.@each', function() {
|
|
||||||
return this.get('content').filterBy('content').length;
|
|
||||||
}),
|
|
||||||
|
|
||||||
firstLoaded: Ember.computed('content.@each', function() {
|
|
||||||
var first = this.objectAt(0);
|
|
||||||
return first && first.content;
|
|
||||||
}),
|
|
||||||
|
|
||||||
lastLoaded: Ember.computed('content.@each', function() {
|
|
||||||
var last = this.objectAt(this.get('length') - 1);
|
|
||||||
return last && last.content;
|
|
||||||
}),
|
|
||||||
|
|
||||||
init: function() {
|
|
||||||
this._super();
|
|
||||||
this.set('ids', Ember.A());
|
|
||||||
this.clear();
|
|
||||||
},
|
|
||||||
|
|
||||||
setup: function(ids) {
|
|
||||||
// Set our ids to the array provided and reset the content of the
|
|
||||||
// stream to a big gap that covers the amount of posts we now have.
|
|
||||||
this.set('ids', ids);
|
|
||||||
this.clear();
|
|
||||||
},
|
|
||||||
|
|
||||||
// Clear the contents of the post stream, resetting it to one big gap.
|
|
||||||
clear: function() {
|
|
||||||
var content = Ember.A();
|
|
||||||
content.clear().pushObject(this.makeItem(0, this.get('count') - 1).set('loading', true));
|
|
||||||
this.set('content', content);
|
|
||||||
},
|
|
||||||
|
|
||||||
loadRange: function(start, end, backwards) {
|
|
||||||
var limit = this.get('postLoadCount');
|
|
||||||
|
|
||||||
// Find the appropriate gap objects in the post stream. When we find
|
|
||||||
// one, we will turn on its loading flag.
|
|
||||||
this.get('content').forEach(function(item) {
|
|
||||||
if (!item.content && ((item.indexStart >= start && item.indexStart <= end) || (item.indexEnd >= start && item.indexEnd <= end))) {
|
|
||||||
item.set('loading', true);
|
|
||||||
item.set('direction', backwards ? 'up' : 'down');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get a list of post numbers that we'll want to retrieve. If there are
|
|
||||||
// more post IDs than the number of posts we want to load, then take a
|
|
||||||
// slice of the array in the appropriate direction.
|
|
||||||
var ids = this.get('ids').slice(start, end + 1);
|
|
||||||
ids = backwards ? ids.slice(-limit) : ids.slice(0, limit);
|
|
||||||
|
|
||||||
return this.loadPosts(ids);
|
|
||||||
},
|
|
||||||
|
|
||||||
loadPosts: function(ids) {
|
|
||||||
if (!ids.length) {
|
|
||||||
return Ember.RSVP.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
var stream = this;
|
|
||||||
return this.store.find('post', {ids: ids}).then(function(posts) {
|
|
||||||
stream.addPosts(posts);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
loadNearNumber: function(number) {
|
|
||||||
// Find the item in the post stream which is nearest to this number. If
|
|
||||||
// it turns out the be the actual post we're trying to load, then we can
|
|
||||||
// return a resolved promise (i.e. we don't need to make an API
|
|
||||||
// request.) Or, if it's a gap, we'll switch on its loading flag.
|
|
||||||
var item = this.findNearestToNumber(number);
|
|
||||||
if (item) {
|
|
||||||
if (item.get('content.number') == number) {
|
|
||||||
return Ember.RSVP.resolve([item.get('content')]);
|
|
||||||
} else if (! item.content) {
|
|
||||||
item.set('direction', 'down').set('loading', true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var stream = this;
|
|
||||||
return this.store.find('post', {
|
|
||||||
discussions: this.get('discussion.id'),
|
|
||||||
near: number,
|
|
||||||
count: this.get('postLoadCount')
|
|
||||||
}).then(function(posts) {
|
|
||||||
stream.addPosts(posts);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
loadNearIndex: function(index, backwards) {
|
|
||||||
// Find the item in the post stream which is nearest to this index. If
|
|
||||||
// it turns out the be the actual post we're trying to load, then we can
|
|
||||||
// return a resolved promise (i.e. we don't need to make an API
|
|
||||||
// request.) Or, if it's a gap, we'll switch on its loading flag.
|
|
||||||
var item = this.findNearestToIndex(index);
|
|
||||||
if (item) {
|
|
||||||
if (item.content) {
|
|
||||||
return Ember.RSVP.resolve([item.get('content')]);
|
|
||||||
}
|
|
||||||
return this.loadRange(Math.max(item.indexStart, index - this.get('postLoadCount') / 2), item.indexEnd, backwards);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ember.RSVP.reject();
|
|
||||||
},
|
|
||||||
|
|
||||||
addPosts: function(posts) {
|
|
||||||
this.trigger('postsLoaded', posts);
|
|
||||||
|
|
||||||
var stream = this;
|
|
||||||
var content = this.get('content');
|
|
||||||
content.beginPropertyChanges();
|
|
||||||
posts.forEach(function(post) {
|
|
||||||
stream.addPost(post);
|
|
||||||
});
|
|
||||||
content.endPropertyChanges();
|
|
||||||
|
|
||||||
this.trigger('postsAdded');
|
|
||||||
},
|
|
||||||
|
|
||||||
addPost: function(post) {
|
|
||||||
var index = this.get('ids').indexOf(post.get('id'));
|
|
||||||
var content = this.get('content');
|
|
||||||
var makeItem = this.makeItem;
|
|
||||||
|
|
||||||
// Here we loop through each item in the post stream, and find the gap
|
|
||||||
// in which this post should be situated. When we find it, we can replace
|
|
||||||
// it with the post, and new gaps either side if appropriate.
|
|
||||||
content.some(function(item, i) {
|
|
||||||
if (item.indexStart <= index && item.indexEnd >= index) {
|
|
||||||
var newItems = [];
|
|
||||||
if (item.indexStart < index) {
|
|
||||||
newItems.push(makeItem(item.indexStart, index - 1));
|
|
||||||
}
|
|
||||||
newItems.push(makeItem(index, index, post));
|
|
||||||
if (item.indexEnd > index) {
|
|
||||||
newItems.push(makeItem(index + 1, item.indexEnd));
|
|
||||||
}
|
|
||||||
content.replace(i, 1, newItems);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
addPostToEnd: function(post) {
|
|
||||||
this.get('ids').pushObject(post.get('id'));
|
|
||||||
var index = this.get('count') - 1;
|
|
||||||
this.get('content').pushObject(this.makeItem(index, index, post));
|
|
||||||
},
|
|
||||||
|
|
||||||
removePost: function(post) {
|
|
||||||
this.get('ids').removeObject(post.get('id'));
|
|
||||||
var content = this.get('content');
|
|
||||||
content.removeObject(content.findBy('content', post));
|
|
||||||
},
|
|
||||||
|
|
||||||
makeItem: function(indexStart, indexEnd, post) {
|
|
||||||
var item = Ember.Object.create({
|
|
||||||
indexStart: indexStart,
|
|
||||||
indexEnd: indexEnd
|
|
||||||
});
|
|
||||||
if (post) {
|
|
||||||
item.setProperties({
|
|
||||||
content: post,
|
|
||||||
component: 'discussion/post-'+post.get('contentType')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
},
|
|
||||||
|
|
||||||
findNearestTo: function(index, property) {
|
|
||||||
var nearestItem;
|
|
||||||
this.get('content').some(function(item) {
|
|
||||||
if (item.get(property) > index) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
nearestItem = item;
|
|
||||||
});
|
|
||||||
return nearestItem;
|
|
||||||
},
|
|
||||||
|
|
||||||
findNearestToNumber: function(number) {
|
|
||||||
return this.findNearestTo(number, 'content.number');
|
|
||||||
},
|
|
||||||
|
|
||||||
findNearestToIndex: function(index) {
|
|
||||||
return this.findNearestTo(index, 'indexStart');
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,25 +0,0 @@
|
|||||||
import Ember from 'ember';
|
|
||||||
import DS from 'ember-data';
|
|
||||||
import Subject from './subject';
|
|
||||||
|
|
||||||
export default Subject.extend({
|
|
||||||
discussion: DS.belongsTo('discussion', {inverse: 'loadedPosts'}),
|
|
||||||
number: DS.attr('number'),
|
|
||||||
|
|
||||||
time: DS.attr('date'),
|
|
||||||
user: DS.belongsTo('user'),
|
|
||||||
contentType: DS.attr('string'),
|
|
||||||
content: DS.attr(),
|
|
||||||
contentHtml: DS.attr('string'),
|
|
||||||
|
|
||||||
editTime: DS.attr('date'),
|
|
||||||
editUser: DS.belongsTo('user'),
|
|
||||||
isEdited: Ember.computed.notEmpty('editTime'),
|
|
||||||
|
|
||||||
hideTime: DS.attr('date'),
|
|
||||||
hideUser: DS.belongsTo('user'),
|
|
||||||
isHidden: DS.attr('boolean'),
|
|
||||||
|
|
||||||
canEdit: DS.attr('boolean'),
|
|
||||||
canDelete: DS.attr('boolean')
|
|
||||||
});
|
|
@ -1,5 +0,0 @@
|
|||||||
import DS from 'ember-data';
|
|
||||||
|
|
||||||
export default DS.Model.extend({
|
|
||||||
notification: DS.belongsTo('notification')
|
|
||||||
});
|
|
@ -1,36 +0,0 @@
|
|||||||
import DS from 'ember-data';
|
|
||||||
|
|
||||||
import HasItemLists from '../mixins/has-item-lists';
|
|
||||||
import stringToColor from '../utils/string-to-color';
|
|
||||||
|
|
||||||
export default DS.Model.extend(HasItemLists, {
|
|
||||||
itemLists: ['badges'],
|
|
||||||
|
|
||||||
username: DS.attr('string'),
|
|
||||||
email: DS.attr('string'),
|
|
||||||
password: DS.attr('string'),
|
|
||||||
avatarUrl: DS.attr('string'),
|
|
||||||
bio: DS.attr('string'),
|
|
||||||
bioHtml: DS.attr('string'),
|
|
||||||
preferences: DS.attr(),
|
|
||||||
|
|
||||||
groups: DS.hasMany('group'),
|
|
||||||
|
|
||||||
joinTime: DS.attr('date'),
|
|
||||||
lastSeenTime: DS.attr('date'),
|
|
||||||
online: Ember.computed('lastSeenTime', function() {
|
|
||||||
return this.get('lastSeenTime') > moment().subtract(5, 'minutes').toDate();
|
|
||||||
}),
|
|
||||||
readTime: DS.attr('date'),
|
|
||||||
unreadNotificationsCount: DS.attr('number'),
|
|
||||||
|
|
||||||
discussionsCount: DS.attr('number'),
|
|
||||||
commentsCount: DS.attr('number'),
|
|
||||||
|
|
||||||
canEdit: DS.attr('boolean'),
|
|
||||||
canDelete: DS.attr('boolean'),
|
|
||||||
|
|
||||||
color: Ember.computed('username', function() {
|
|
||||||
return '#'+stringToColor(this.get('username'));
|
|
||||||
})
|
|
||||||
});
|
|
@ -1,5 +0,0 @@
|
|||||||
import JsonApiSerializer from 'ember-json-api/json-api-serializer';
|
|
||||||
|
|
||||||
export default JsonApiSerializer.extend({
|
|
||||||
store: Ember.inject.service()
|
|
||||||
});
|
|
@ -1,16 +0,0 @@
|
|||||||
import ApplicationSerializer from '../serializers/application';
|
|
||||||
|
|
||||||
export default ApplicationSerializer.extend({
|
|
||||||
attrs: {
|
|
||||||
number: {serialize: false},
|
|
||||||
time: {serialize: false},
|
|
||||||
type: {serialize: false},
|
|
||||||
contentHtml: {serialize: false},
|
|
||||||
editTime: {serialize: false},
|
|
||||||
editUser: {serialize: false},
|
|
||||||
hideTime: {serialize: false},
|
|
||||||
hideUser: {serialize: false},
|
|
||||||
canEdit: {serialize: false},
|
|
||||||
canDelete: {serialize: false}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,7 +0,0 @@
|
|||||||
<div class="alerts">
|
|
||||||
{{#each alert in alerts}}
|
|
||||||
<div class="alert-wrapper">
|
|
||||||
{{view alert dismiss="dismissAlert"}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user