Version bump
This commit is contained in:
commit
7d9c21143f
@ -20,5 +20,5 @@ vendor/
|
||||
test/javascripts/helpers/
|
||||
test/javascripts/test_helper.js
|
||||
test/javascripts/test_helper.js
|
||||
test/javascripts/fixtures
|
||||
app/assets/javascripts/ember-addons/
|
||||
|
||||
105
.eslintrc
Normal file
105
.eslintrc
Normal file
@ -0,0 +1,105 @@
|
||||
{
|
||||
"env": {
|
||||
"jasmine": true,
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"browser": true,
|
||||
"builtin": true
|
||||
},
|
||||
ecmaVersion: 7,
|
||||
"globals":
|
||||
{"Ember":true,
|
||||
"jQuery":true,
|
||||
"$":true,
|
||||
"RSVP":true,
|
||||
"Discourse":true,
|
||||
"Em":true,
|
||||
"PreloadStore":true,
|
||||
"Handlebars":true,
|
||||
"I18n":true,
|
||||
"bootbox":true,
|
||||
"module":true,
|
||||
"moduleFor":true,
|
||||
"moduleForComponent":true,
|
||||
"Pretender":true,
|
||||
"sandbox":true,
|
||||
"controllerFor":true,
|
||||
"test":true,
|
||||
"ok":true,
|
||||
"not":true,
|
||||
"expect":true,
|
||||
"equal":true,
|
||||
"visit":true,
|
||||
"andThen":true,
|
||||
"click":true,
|
||||
"currentPath":true,
|
||||
"currentRouteName":true,
|
||||
"currentURL":true,
|
||||
"fillIn":true,
|
||||
"keyEvent":true,
|
||||
"triggerEvent":true,
|
||||
"count":true,
|
||||
"exists":true,
|
||||
"visible":true,
|
||||
"invisible":true,
|
||||
"asyncRender":true,
|
||||
"selectDropdown":true,
|
||||
"asyncTestDiscourse":true,
|
||||
"fixture":true,
|
||||
"find":true,
|
||||
"sinon":true,
|
||||
"moment":true,
|
||||
"start":true,
|
||||
"_":true,
|
||||
"alert":true,
|
||||
"containsInstance":true,
|
||||
"deepEqual":true,
|
||||
"notEqual":true,
|
||||
"define":true,
|
||||
"require":true,
|
||||
"requirejs":true,
|
||||
"hasModule":true,
|
||||
"Blob":true,
|
||||
"File":true},
|
||||
"rules": {
|
||||
"block-scoped-var": 2,
|
||||
"dot-notation": 0,
|
||||
"eqeqeq": [
|
||||
2,
|
||||
"allow-null"
|
||||
],
|
||||
"guard-for-in": 2,
|
||||
"no-bitwise": 2,
|
||||
"no-caller": 2,
|
||||
"no-cond-assign": 0,
|
||||
"no-debugger": 2,
|
||||
"no-empty": 0,
|
||||
"no-eval": 2,
|
||||
"no-extend-native": 2,
|
||||
"no-extra-parens": 0,
|
||||
"no-irregular-whitespace": 2,
|
||||
"no-iterator": 2,
|
||||
"no-loop-func": 2,
|
||||
"no-multi-str": 2,
|
||||
"no-new": 2,
|
||||
"no-plusplus": 0,
|
||||
"no-proto": 2,
|
||||
"no-script-url": 2,
|
||||
"no-sequences": 2,
|
||||
"no-shadow": 2,
|
||||
"no-undef": 2,
|
||||
"no-unused-vars": 2,
|
||||
"no-with": 2,
|
||||
"semi": [
|
||||
0,
|
||||
"never"
|
||||
],
|
||||
"strict": 0,
|
||||
"valid-typeof": 2,
|
||||
"wrap-iife": [
|
||||
2,
|
||||
"inside"
|
||||
]
|
||||
},
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
86
.jshintrc
86
.jshintrc
@ -1,86 +0,0 @@
|
||||
{
|
||||
"predef":["Ember",
|
||||
"jQuery",
|
||||
"$",
|
||||
"RSVP",
|
||||
"Discourse",
|
||||
"Em",
|
||||
"PreloadStore",
|
||||
"Handlebars",
|
||||
"I18n",
|
||||
"bootbox",
|
||||
"module",
|
||||
"moduleFor",
|
||||
"moduleForComponent",
|
||||
"Pretender",
|
||||
"sandbox",
|
||||
"controllerFor",
|
||||
"test",
|
||||
"ok",
|
||||
"not",
|
||||
"expect",
|
||||
"equal",
|
||||
"blank",
|
||||
"present",
|
||||
"visit",
|
||||
"andThen",
|
||||
"click",
|
||||
"currentPath",
|
||||
"currentRouteName",
|
||||
"currentURL",
|
||||
"fillIn",
|
||||
"keyEvent",
|
||||
"triggerEvent",
|
||||
"count",
|
||||
"exists",
|
||||
"visible",
|
||||
"invisible",
|
||||
"asyncRender",
|
||||
"selectDropdown",
|
||||
"asyncTestDiscourse",
|
||||
"fixture",
|
||||
"find",
|
||||
"sinon",
|
||||
"moment",
|
||||
"start",
|
||||
"_",
|
||||
"alert",
|
||||
"containsInstance",
|
||||
"parseHTML",
|
||||
"deepEqual",
|
||||
"notEqual",
|
||||
"define",
|
||||
"require",
|
||||
"requirejs",
|
||||
"hasModule",
|
||||
"Blob",
|
||||
"File"],
|
||||
"node" : false,
|
||||
"browser" : true,
|
||||
"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,
|
||||
"unused": true,
|
||||
"sub": true,
|
||||
"strict": false,
|
||||
"white": false,
|
||||
"eqnull": true,
|
||||
"quotmark": false,
|
||||
"lastsemic": true,
|
||||
"esnext": true
|
||||
}
|
||||
19
.travis.yml
19
.travis.yml
@ -11,6 +11,12 @@ env:
|
||||
|
||||
addons:
|
||||
postgresql: 9.3
|
||||
apt:
|
||||
packages:
|
||||
- gifsicle
|
||||
- jpegoptim
|
||||
- optipng
|
||||
- jhead
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
@ -23,18 +29,23 @@ rvm:
|
||||
- 2.0.0
|
||||
- 2.1
|
||||
- 2.2
|
||||
- rbx-2
|
||||
|
||||
services:
|
||||
- redis-server
|
||||
|
||||
sudo: false
|
||||
|
||||
cache: bundler
|
||||
cache:
|
||||
directories:
|
||||
- vendor/bundle
|
||||
|
||||
before_install:
|
||||
- npm i -g jshint
|
||||
- jshint .
|
||||
- gem install bundler
|
||||
- npm i -g eslint babel-eslint
|
||||
- eslint app/assets/javascripts
|
||||
- eslint --ext .es6 app/assets/javascripts
|
||||
- eslint --ext .es6 test/javascripts
|
||||
- eslint test/javascripts
|
||||
|
||||
before_script:
|
||||
- bundle exec rake db:create db:migrate
|
||||
|
||||
15
Brewfile
15
Brewfile
@ -1,22 +1,19 @@
|
||||
# Install development dependencies on Mac OS X using Homebrew (http://mxcl.github.com/homebrew)
|
||||
|
||||
# ensure that Homebrew's sources are up to date
|
||||
update
|
||||
|
||||
# add this repo to Homebrew's sources
|
||||
tap homebrew/dupes
|
||||
tap 'homebrew/dupes'
|
||||
|
||||
# install the gcc compiler required for ruby
|
||||
install apple-gcc42
|
||||
brew 'apple-gcc42'
|
||||
|
||||
# you probably already have git installed; ensure that it is the latest version
|
||||
install git
|
||||
brew 'git'
|
||||
|
||||
# install the PostgreSQL database
|
||||
install postgresql
|
||||
brew 'postgresql'
|
||||
|
||||
# install the Redis datastore
|
||||
install redis
|
||||
brew 'redis'
|
||||
|
||||
# install headless Javascript testing library
|
||||
install phantomjs
|
||||
brew 'phantomjs'
|
||||
|
||||
3
Gemfile
3
Gemfile
@ -40,7 +40,7 @@ gem 'active_model_serializers', '~> 0.8.3'
|
||||
gem 'onebox'
|
||||
|
||||
gem 'ember-rails'
|
||||
gem 'ember-source', '1.11.3.1'
|
||||
gem 'ember-source', '1.12.1'
|
||||
gem 'handlebars-source', '2.0.0'
|
||||
gem 'barber'
|
||||
gem 'babel-transpiler'
|
||||
@ -131,6 +131,7 @@ group :test, :development do
|
||||
gem 'rspec-given'
|
||||
gem 'pry-nav'
|
||||
gem 'spork-rails'
|
||||
gem 'byebug'
|
||||
end
|
||||
|
||||
group :development do
|
||||
|
||||
31
Gemfile.lock
31
Gemfile.lock
@ -46,9 +46,9 @@ GEM
|
||||
multi_json (~> 1.0)
|
||||
aws-sdk-resources (2.0.45)
|
||||
aws-sdk-core (= 2.0.45)
|
||||
babel-source (4.6.6)
|
||||
babel-transpiler (0.6.0)
|
||||
babel-source (>= 4.0, < 5)
|
||||
babel-source (5.8.19)
|
||||
babel-transpiler (0.7.0)
|
||||
babel-source (>= 4.0, < 6)
|
||||
execjs (~> 2.0)
|
||||
barber (0.9.0)
|
||||
ember-source (>= 1.0, < 2)
|
||||
@ -60,10 +60,13 @@ GEM
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
builder (3.2.2)
|
||||
byebug (5.0.0)
|
||||
columnize (= 0.9.0)
|
||||
celluloid (0.16.0)
|
||||
timers (~> 4.0.0)
|
||||
certified (1.0.0)
|
||||
coderay (1.1.0)
|
||||
columnize (0.9.0)
|
||||
connection_pool (2.2.0)
|
||||
crass (1.0.1)
|
||||
daemons (1.2.2)
|
||||
@ -86,7 +89,7 @@ GEM
|
||||
ember-source (>= 1.1.0)
|
||||
jquery-rails (>= 1.0.17)
|
||||
railties (>= 3.1)
|
||||
ember-source (1.11.3.1)
|
||||
ember-source (1.12.1)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.7)
|
||||
excon (0.45.3)
|
||||
@ -145,7 +148,7 @@ GEM
|
||||
thor (~> 0.15)
|
||||
libv8 (3.16.14.7)
|
||||
listen (0.7.3)
|
||||
logster (0.8.4.5.pre)
|
||||
logster (1.0.0.3.pre)
|
||||
lru_redux (1.1.0)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
@ -324,12 +327,12 @@ GEM
|
||||
shoulda-context (1.2.1)
|
||||
shoulda-matchers (2.7.0)
|
||||
activesupport (>= 3.0.0)
|
||||
sidekiq (3.3.4)
|
||||
celluloid (>= 0.16.0)
|
||||
connection_pool (>= 2.1.1)
|
||||
json
|
||||
redis (>= 3.0.6)
|
||||
redis-namespace (>= 1.3.1)
|
||||
sidekiq (3.4.2)
|
||||
celluloid (~> 0.16.0)
|
||||
connection_pool (~> 2.2, >= 2.2.0)
|
||||
json (~> 1.0)
|
||||
redis (~> 3.2, >= 3.2.1)
|
||||
redis-namespace (~> 1.5, >= 1.5.2)
|
||||
simple-rss (1.3.1)
|
||||
simplecov (0.9.1)
|
||||
docile (~> 1.1.0)
|
||||
@ -397,11 +400,12 @@ DEPENDENCIES
|
||||
barber
|
||||
better_errors
|
||||
binding_of_caller
|
||||
byebug
|
||||
certified
|
||||
discourse-qunit-rails
|
||||
email_reply_parser
|
||||
ember-rails
|
||||
ember-source (= 1.11.3.1)
|
||||
ember-source (= 1.12.1)
|
||||
excon
|
||||
fabrication (= 2.9.8)
|
||||
fakeweb (~> 1.3.0)
|
||||
@ -481,6 +485,3 @@ DEPENDENCIES
|
||||
uglifier
|
||||
unf
|
||||
unicorn
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.3
|
||||
|
||||
@ -2,4 +2,12 @@
|
||||
require_asset("main_include_admin.js")
|
||||
|
||||
DiscoursePluginRegistry.admin_javascripts.each { |js| require_asset(js) }
|
||||
|
||||
DiscoursePluginRegistry.each_globbed_asset(admin: true) do |f, ext|
|
||||
if File.directory?(f)
|
||||
depend_on(f)
|
||||
elsif f.to_s.end_with?(".#{ext}")
|
||||
require_asset(f)
|
||||
end
|
||||
end
|
||||
%>
|
||||
|
||||
7
app/assets/javascripts/admin/adapters/embedding.js.es6
Normal file
7
app/assets/javascripts/admin/adapters/embedding.js.es6
Normal file
@ -0,0 +1,7 @@
|
||||
import RestAdapter from 'discourse/adapters/rest';
|
||||
|
||||
export default RestAdapter.extend({
|
||||
pathFor() {
|
||||
return "/admin/customize/embedding";
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,63 @@
|
||||
import { bufferedProperty } from 'discourse/mixins/buffered-content';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import { on, observes } from 'ember-addons/ember-computed-decorators';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
|
||||
export default Ember.Component.extend(bufferedProperty('host'), {
|
||||
editToggled: false,
|
||||
tagName: 'tr',
|
||||
categoryId: null,
|
||||
|
||||
editing: Ember.computed.or('host.isNew', 'editToggled'),
|
||||
|
||||
@on('didInsertElement')
|
||||
@observes('editing')
|
||||
_focusOnInput() {
|
||||
Ember.run.schedule('afterRender', () => { this.$('.host-name').focus(); });
|
||||
},
|
||||
|
||||
@computed('buffered.host', 'host.isSaving')
|
||||
cantSave(host, isSaving) {
|
||||
return isSaving || Ember.isEmpty(host);
|
||||
},
|
||||
|
||||
actions: {
|
||||
edit() {
|
||||
this.set('categoryId', this.get('host.category.id'));
|
||||
this.set('editToggled', true);
|
||||
},
|
||||
|
||||
save() {
|
||||
if (this.get('cantSave')) { return; }
|
||||
|
||||
const props = this.get('buffered').getProperties('host');
|
||||
props.category_id = this.get('categoryId');
|
||||
|
||||
const host = this.get('host');
|
||||
host.save(props).then(() => {
|
||||
host.set('category', Discourse.Category.findById(this.get('categoryId')));
|
||||
this.set('editToggled', false);
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
delete() {
|
||||
bootbox.confirm(I18n.t('admin.embedding.confirm_delete'), (result) => {
|
||||
if (result) {
|
||||
this.get('host').destroyRecord().then(() => {
|
||||
this.sendAction('deleteHost', this.get('host'));
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
cancel() {
|
||||
const host = this.get('host');
|
||||
if (host.get('isNew')) {
|
||||
this.sendAction('deleteHost', host);
|
||||
} else {
|
||||
this.rollbackBuffer();
|
||||
this.set('editToggled', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['embed-setting'],
|
||||
|
||||
@computed('field')
|
||||
inputId(field) { return field.dasherize(); },
|
||||
|
||||
@computed('field')
|
||||
translationKey(field) { return `admin.embedding.${field}`; },
|
||||
|
||||
@computed('type')
|
||||
isCheckbox(type) { return type === "checkbox"; },
|
||||
|
||||
@computed('value')
|
||||
checked: {
|
||||
get(value) { return !!value; },
|
||||
set(value) {
|
||||
this.set('value', value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,12 @@
|
||||
import { on, observes } from 'ember-addons/ember-computed-decorators';
|
||||
import highlightSyntax from 'discourse/lib/highlight-syntax';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
|
||||
@on('didInsertElement')
|
||||
@observes('code')
|
||||
_refresh: function() {
|
||||
highlightSyntax(this.$());
|
||||
}
|
||||
|
||||
});
|
||||
@ -2,8 +2,9 @@ import BufferedContent from 'discourse/mixins/buffered-content';
|
||||
import ScrollTop from 'discourse/mixins/scroll-top';
|
||||
import SiteSetting from 'admin/models/site-setting';
|
||||
import { propertyNotEqual } from 'discourse/lib/computed';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
const CustomTypes = ['bool', 'enum', 'list', 'url_list', 'host_list'];
|
||||
const CustomTypes = ['bool', 'enum', 'list', 'url_list', 'host_list', 'category_list'];
|
||||
|
||||
export default Ember.Component.extend(BufferedContent, ScrollTop, {
|
||||
classNameBindings: [':row', ':setting', 'setting.overridden', 'typeClass'],
|
||||
@ -11,41 +12,32 @@ export default Ember.Component.extend(BufferedContent, ScrollTop, {
|
||||
dirty: propertyNotEqual('buffered.value', 'setting.value'),
|
||||
validationMessage: null,
|
||||
|
||||
preview: function() {
|
||||
const preview = this.get('setting.preview');
|
||||
@computed("setting.preview", "buffered.value")
|
||||
preview(preview, value) {
|
||||
if (preview) {
|
||||
return new Handlebars.SafeString("<div class='preview'>" +
|
||||
preview.replace(/\{\{value\}\}/g, this.get('buffered.value')) +
|
||||
"</div>");
|
||||
return new Handlebars.SafeString("<div class='preview'>" + preview.replace(/\{\{value\}\}/g, value) + "</div>");
|
||||
}
|
||||
}.property('buffered.value'),
|
||||
},
|
||||
|
||||
typeClass: function() {
|
||||
return this.get('partialType').replace("_", "-");
|
||||
}.property('partialType'),
|
||||
@computed('componentType')
|
||||
typeClass(componentType) {
|
||||
return componentType.replace("_", "-");
|
||||
},
|
||||
|
||||
enabled: function(key, value) {
|
||||
if (arguments.length > 1) {
|
||||
this.set('buffered.value', value ? 'true' : 'false');
|
||||
}
|
||||
@computed("setting.setting")
|
||||
settingName(setting) {
|
||||
return setting.replace(/\_/g, ' ');
|
||||
},
|
||||
|
||||
const bufferedValue = this.get('buffered.value');
|
||||
if (Ember.isEmpty(bufferedValue)) { return false; }
|
||||
return bufferedValue === 'true';
|
||||
}.property('buffered.value'),
|
||||
@computed("setting.type")
|
||||
componentType(type) {
|
||||
return CustomTypes.indexOf(type) !== -1 ? type : 'string';
|
||||
},
|
||||
|
||||
settingName: function() {
|
||||
return this.get('setting.setting').replace(/\_/g, ' ');
|
||||
}.property('setting.setting'),
|
||||
|
||||
partialType: function() {
|
||||
let type = this.get('setting.type');
|
||||
return (CustomTypes.indexOf(type) !== -1) ? type : 'string';
|
||||
}.property('setting.type'),
|
||||
|
||||
partialName: function() {
|
||||
return 'admin/templates/site-settings/' + this.get('partialType');
|
||||
}.property('partialType'),
|
||||
@computed("typeClass")
|
||||
componentName(typeClass) {
|
||||
return "site-settings/" + typeClass;
|
||||
},
|
||||
|
||||
_watchEnterKey: function() {
|
||||
const self = this;
|
||||
@ -61,8 +53,8 @@ export default Ember.Component.extend(BufferedContent, ScrollTop, {
|
||||
}.on("willDestroyElement"),
|
||||
|
||||
_save() {
|
||||
const setting = this.get('buffered');
|
||||
const self = this;
|
||||
const self = this,
|
||||
setting = this.get('buffered');
|
||||
SiteSetting.update(setting.get('setting'), setting.get('value')).then(function() {
|
||||
self.set('validationMessage', null);
|
||||
self.commitBuffer();
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
|
||||
@computed("value")
|
||||
enabled: {
|
||||
get(value) {
|
||||
if (Ember.isEmpty(value)) { return false; }
|
||||
return value === "true";
|
||||
},
|
||||
set(value) {
|
||||
this.set("value", value ? "true" : "false");
|
||||
return value;
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
@ -0,0 +1,16 @@
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
|
||||
@computed("value")
|
||||
selectedCategories: {
|
||||
get(value) {
|
||||
return Discourse.Category.findByIds(value.split("|"));
|
||||
},
|
||||
set(value) {
|
||||
this.set("value", value.mapBy("id").join("|"));
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,8 +1,6 @@
|
||||
export default Ember.ArrayController.extend({
|
||||
needs: ["adminBackups"],
|
||||
status: Em.computed.alias("controllers.adminBackups"),
|
||||
isOperationRunning: Ember.computed.alias("status.model.isOperationRunning"),
|
||||
restoreDisabled: Ember.computed.alias("status.model.restoreDisabled"),
|
||||
status: Ember.computed.alias("controllers.adminBackups"),
|
||||
|
||||
uploadLabel: function() { return I18n.t("admin.backups.upload.label"); }.property(),
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
noOperationIsRunning: Ember.computed.not("model.isOperationRunning"),
|
||||
rollbackEnabled: Ember.computed.and("model.canRollback", "model.restoreEnabled", "noOperationIsRunning"),
|
||||
rollbackDisabled: Ember.computed.not("rollbackEnabled")
|
||||
|
||||
@ -2,7 +2,7 @@ import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
import BufferedContent from 'discourse/mixins/buffered-content';
|
||||
import { propertyNotEqual } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.ObjectController.extend(BufferedContent, {
|
||||
export default Ember.Controller.extend(BufferedContent, {
|
||||
needs: ['admin-badges'],
|
||||
saving: false,
|
||||
savingStatus: '',
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
|
||||
export default DiscourseController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
|
||||
/**
|
||||
Is the "send test email" button disabled?
|
||||
|
||||
@ -1,20 +1,17 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
|
||||
actions: {
|
||||
refresh: function() {
|
||||
var model = this.get('model'),
|
||||
self = this;
|
||||
refresh() {
|
||||
const model = this.get('model');
|
||||
|
||||
self.set('loading', true);
|
||||
Discourse.EmailPreview.findDigest(this.get('lastSeen')).then(function (email) {
|
||||
this.set('loading', true);
|
||||
Discourse.EmailPreview.findDigest(this.get('lastSeen')).then(email => {
|
||||
model.setProperties(email.getProperties('html_content', 'text_content'));
|
||||
self.set('loading', false);
|
||||
this.set('loading', false);
|
||||
});
|
||||
},
|
||||
|
||||
toggleShowHtml: function() {
|
||||
toggleShowHtml() {
|
||||
this.toggleProperty('showHtml');
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
import debounce from 'discourse/lib/debounce';
|
||||
|
||||
export default DiscourseController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
|
||||
filterEmailLogs: Discourse.debounce(function() {
|
||||
filterEmailLogs: debounce(function() {
|
||||
var self = this;
|
||||
Discourse.EmailLog.findAll(this.get("filter")).then(function(logs) {
|
||||
self.set("model", logs);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
import debounce from 'discourse/lib/debounce';
|
||||
|
||||
export default DiscourseController.extend({
|
||||
filterEmailLogs: Discourse.debounce(function() {
|
||||
export default Ember.Controller.extend({
|
||||
filterEmailLogs: debounce(function() {
|
||||
var self = this;
|
||||
Discourse.EmailLog.findAll(this.get("filter")).then(function(logs) {
|
||||
self.set("model", logs);
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
saved: false,
|
||||
embedding: null,
|
||||
|
||||
// show settings if we have at least one created host
|
||||
@computed('embedding.embeddable_hosts.@each.isCreated')
|
||||
showSecondary() {
|
||||
const hosts = this.get('embedding.embeddable_hosts');
|
||||
return hosts.length && hosts.findProperty('isCreated');
|
||||
},
|
||||
|
||||
@computed('embedding.base_url')
|
||||
embeddingCode(baseUrl) {
|
||||
|
||||
const html =
|
||||
`<div id='discourse-comments'></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
DiscourseEmbed = { discourseUrl: '${baseUrl}/',
|
||||
discourseEmbedUrl: 'REPLACE_ME' };
|
||||
|
||||
(function() {
|
||||
var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
|
||||
d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
|
||||
})();
|
||||
</script>`;
|
||||
|
||||
return html;
|
||||
},
|
||||
|
||||
actions: {
|
||||
saveChanges() {
|
||||
const embedding = this.get('embedding');
|
||||
const updates = embedding.getProperties(embedding.get('fields'));
|
||||
|
||||
this.set('saved', false);
|
||||
this.get('embedding').update(updates).then(() => {
|
||||
this.set('saved', true);
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
addHost() {
|
||||
const host = this.store.createRecord('embeddable-host');
|
||||
this.get('embedding.embeddable_hosts').pushObject(host);
|
||||
},
|
||||
|
||||
deleteHost(host) {
|
||||
this.get('embedding.embeddable_hosts').removeObject(host);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,7 +1,7 @@
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
|
||||
export default Em.ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
needs: ['adminGroupsType'],
|
||||
disableSave: false,
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
editing: false,
|
||||
savedIpAddress: null,
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import debounce from 'discourse/lib/debounce';
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
import { exportEntity } from 'discourse/lib/export-csv';
|
||||
|
||||
@ -6,7 +7,7 @@ export default Ember.ArrayController.extend({
|
||||
itemController: 'admin-log-screened-ip-address',
|
||||
filter: null,
|
||||
|
||||
show: Discourse.debounce(function() {
|
||||
show: debounce(function() {
|
||||
var self = this;
|
||||
self.set('loading', true);
|
||||
Discourse.ScreenedIpAddress.findAll(this.get("filter")).then(function(result) {
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import debounce from 'discourse/lib/debounce';
|
||||
|
||||
export default Ember.ArrayController.extend({
|
||||
loading: false,
|
||||
filter: null,
|
||||
|
||||
show: Discourse.debounce(function() {
|
||||
show: debounce(function() {
|
||||
var self = this;
|
||||
self.set('loading', true);
|
||||
Discourse.Permalink.findAll(self.get("filter")).then(function(result) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
viewMode: 'table',
|
||||
viewingTable: Em.computed.equal('viewMode', 'table'),
|
||||
viewingBarChart: Em.computed.equal('viewMode', 'barChart'),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
categoryNameKey: null,
|
||||
needs: ['adminSiteSettings'],
|
||||
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import debounce from 'discourse/lib/debounce';
|
||||
|
||||
export default Ember.ArrayController.extend(Presence, {
|
||||
export default Ember.ArrayController.extend({
|
||||
filter: null,
|
||||
onlyOverridden: false,
|
||||
filtered: Ember.computed.notEmpty('filter'),
|
||||
|
||||
filterContentNow: function(category) {
|
||||
// If we have no content, don't bother filtering anything
|
||||
if (!this.present('allSiteSettings')) return;
|
||||
if (!!Ember.isEmpty(this.get('allSiteSettings'))) return;
|
||||
|
||||
let filter;
|
||||
if (this.get('filter')) {
|
||||
@ -50,7 +50,7 @@ export default Ember.ArrayController.extend(Presence, {
|
||||
this.transitionToRoute("adminSiteSettingsCategory", category || "all_results");
|
||||
},
|
||||
|
||||
filterContent: Discourse.debounce(function() {
|
||||
filterContent: debounce(function() {
|
||||
if (this.get("_skipBounce")) {
|
||||
this.set("_skipBounce", false);
|
||||
} else {
|
||||
@ -64,6 +64,10 @@ export default Ember.ArrayController.extend(Presence, {
|
||||
filter: '',
|
||||
onlyOverridden: false
|
||||
});
|
||||
},
|
||||
|
||||
toggleMenu() {
|
||||
$('.admin-detail').toggleClass('mobile-closed mobile-open');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,25 +1,18 @@
|
||||
/**
|
||||
This controller supports the interface for granting and revoking badges from
|
||||
individual users.
|
||||
import UserBadge from 'discourse/models/user-badge';
|
||||
|
||||
@class AdminUserBadgesController
|
||||
@extends Ember.ArrayController
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
export default Ember.ArrayController.extend({
|
||||
needs: ["adminUser"],
|
||||
user: Em.computed.alias('controllers.adminUser'),
|
||||
user: Em.computed.alias('controllers.adminUser.model'),
|
||||
sortProperties: ['granted_at'],
|
||||
sortAscending: false,
|
||||
|
||||
groupedBadges: function(){
|
||||
const badges = this.get('model');
|
||||
const allBadges = this.get('model');
|
||||
|
||||
var grouped = _.groupBy(badges, badge => badge.badge_id);
|
||||
var grouped = _.groupBy(allBadges, badge => badge.badge_id);
|
||||
|
||||
var expanded = [];
|
||||
const expandedBadges = badges.get('expandedBadges');
|
||||
const expandedBadges = allBadges.get('expandedBadges');
|
||||
|
||||
_(grouped).each(function(badges){
|
||||
var lastGranted = badges[0].granted_at;
|
||||
@ -95,7 +88,7 @@ export default Ember.ArrayController.extend({
|
||||
**/
|
||||
grantBadge: function(badgeId) {
|
||||
var self = this;
|
||||
Discourse.UserBadge.grant(badgeId, this.get('user.username'), this.get('badgeReason')).then(function(userBadge) {
|
||||
UserBadge.grant(badgeId, this.get('user.username'), this.get('badgeReason')).then(function(userBadge) {
|
||||
self.set('badgeReason', '');
|
||||
self.pushObject(userBadge);
|
||||
Ember.run.next(function() {
|
||||
@ -111,12 +104,6 @@ export default Ember.ArrayController.extend({
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Revoke the selected userBadge.
|
||||
|
||||
@method revokeBadge
|
||||
@param {Discourse.UserBadge} userBadge the `Discourse.UserBadge` instance that needs to be revoked.
|
||||
**/
|
||||
revokeBadge: function(userBadge) {
|
||||
var self = this;
|
||||
return bootbox.confirm(I18n.t("admin.badges.revoke_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
||||
import { propertyNotEqual, setting } from 'discourse/lib/computed';
|
||||
|
||||
export default ObjectController.extend(CanCheckEmails, {
|
||||
export default Ember.Controller.extend(CanCheckEmails, {
|
||||
editingTitle: false,
|
||||
originalPrimaryGroupId: null,
|
||||
availableGroups: null,
|
||||
@ -37,8 +36,8 @@ export default ObjectController.extend(CanCheckEmails, {
|
||||
saveTitle() {
|
||||
const self = this;
|
||||
|
||||
return Discourse.ajax("/users/" + this.get('username').toLowerCase(), {
|
||||
data: {title: this.get('title')},
|
||||
return Discourse.ajax("/users/" + this.get('model.username').toLowerCase(), {
|
||||
data: {title: this.get('model.title')},
|
||||
type: 'PUT'
|
||||
}).catch(function(e) {
|
||||
bootbox.alert(I18n.t("generic_error_with_reason", {error: "http: " + e.status + " - " + e.body}));
|
||||
@ -66,7 +65,7 @@ export default ObjectController.extend(CanCheckEmails, {
|
||||
savePrimaryGroup() {
|
||||
const self = this;
|
||||
|
||||
return Discourse.ajax("/admin/users/" + this.get('id') + "/primary_group", {
|
||||
return Discourse.ajax("/admin/users/" + this.get('model.id') + "/primary_group", {
|
||||
type: 'PUT',
|
||||
data: {primary_group_id: this.get('model.primary_group_id')}
|
||||
}).then(function () {
|
||||
|
||||
@ -1,3 +1 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend();
|
||||
export default Ember.Controller.extend();
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import debounce from 'discourse/lib/debounce';
|
||||
import { i18n } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.ArrayController.extend({
|
||||
@ -33,7 +34,7 @@ export default Ember.ArrayController.extend({
|
||||
return I18n.t('admin.users.titles.' + this.get('query'));
|
||||
}.property('query'),
|
||||
|
||||
_filterUsers: Discourse.debounce(function() {
|
||||
_filterUsers: debounce(function() {
|
||||
this._refreshUsers();
|
||||
}, 250).observes('listFilter'),
|
||||
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
|
||||
export default DiscourseController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
showBadges: function() {
|
||||
return this.get('currentUser.admin') && this.siteSettings.enable_badges;
|
||||
}.property()
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend(ModalFunctionality, {
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
needs: ["admin-flags-list"],
|
||||
|
||||
_agreeFlag: function (actionOnPost) {
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend(ModalFunctionality, {
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
needs: ["admin-flags-list"],
|
||||
|
||||
actions: {
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend(ModalFunctionality);
|
||||
export default Ember.Controller.extend(ModalFunctionality);
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import Controller from 'discourse/controllers/controller';
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
needs: ["adminBackupsLogs"],
|
||||
|
||||
_startBackup: function (withUploads) {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend(ModalFunctionality, {
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
|
||||
submitDisabled: function() {
|
||||
return (!this.get('reason') || this.get('reason').length < 1);
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend(ModalFunctionality, {
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
previousSelected: Ember.computed.equal('selectedTab', 'previous'),
|
||||
newSelected: Ember.computed.equal('selectedTab', 'new'),
|
||||
|
||||
|
||||
12
app/assets/javascripts/admin/models/backup-status.js.es6
Normal file
12
app/assets/javascripts/admin/models/backup-status.js.es6
Normal file
@ -0,0 +1,12 @@
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Discourse.Model.extend({
|
||||
|
||||
restoreDisabled: Em.computed.not("restoreEnabled"),
|
||||
|
||||
@computed("allowRestore", "isOperationRunning")
|
||||
restoreEnabled(allowRestore, isOperationRunning) {
|
||||
return allowRestore && !isOperationRunning;
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,9 +0,0 @@
|
||||
Discourse.BackupStatus = Discourse.Model.extend({
|
||||
|
||||
restoreDisabled: Em.computed.not("restoreEnabled"),
|
||||
|
||||
restoreEnabled: function() {
|
||||
return this.get('allowRestore') && !this.get("isOperationRunning");
|
||||
}.property("isOperationRunning", "allowRestore")
|
||||
|
||||
});
|
||||
@ -47,7 +47,7 @@ Discourse.FlaggedPost = Discourse.Post.extend({
|
||||
},
|
||||
|
||||
wasEdited: function () {
|
||||
if (this.blank("last_revised_at")) { return false; }
|
||||
if (Ember.isEmpty(this.get("last_revised_at"))) { return false; }
|
||||
var lastRevisedAt = Date.parse(this.get("last_revised_at"));
|
||||
return _.some(this.get("post_actions"), function (postAction) {
|
||||
return Date.parse(postAction.created_at) < lastRevisedAt;
|
||||
|
||||
@ -50,7 +50,7 @@ export default Discourse.Route.extend({
|
||||
},
|
||||
|
||||
backupStarted() {
|
||||
this.modelFor("adminBackups").set("isOperationRunning", true);
|
||||
this.controllerFor("adminBackups").set("isOperationRunning", true);
|
||||
this.transitionTo("admin.backups.logs");
|
||||
this.send("closeModal");
|
||||
},
|
||||
@ -82,7 +82,7 @@ export default Discourse.Route.extend({
|
||||
Discourse.User.currentProp("hideReadOnlyAlert", true);
|
||||
backup.restore().then(function() {
|
||||
self.controllerFor("adminBackupsLogs").clear();
|
||||
self.modelFor("adminBackups").set("model.isOperationRunning", true);
|
||||
self.controllerFor("adminBackups").set("model.isOperationRunning", true);
|
||||
self.transitionTo("admin.backups.logs");
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import Badge from 'discourse/models/badge';
|
||||
import showModal from 'discourse/lib/show-modal';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
@ -7,7 +8,7 @@ export default Ember.Route.extend({
|
||||
|
||||
model(params) {
|
||||
if (params.badge_id === "new") {
|
||||
return Discourse.Badge.create({
|
||||
return Badge.create({
|
||||
name: I18n.t('admin.badges.new_badge')
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import Badge from 'discourse/models/badge';
|
||||
|
||||
export default Discourse.Route.extend({
|
||||
_json: null,
|
||||
|
||||
@ -5,7 +7,7 @@ export default Discourse.Route.extend({
|
||||
var self = this;
|
||||
return Discourse.ajax('/admin/badges.json').then(function(json) {
|
||||
self._json = json;
|
||||
return Discourse.Badge.createFromJson(json);
|
||||
return Badge.createFromJson(json);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
export default Discourse.Route.extend({
|
||||
|
||||
model() {
|
||||
return Discourse.EmailPreview.findDigest();
|
||||
},
|
||||
|
||||
afterModel(model) {
|
||||
const controller = this.controllerFor('adminEmailPreviewDigest');
|
||||
controller.setProperties({
|
||||
model: model,
|
||||
lastSeen: moment().subtract(7, 'days').format('YYYY-MM-DD'),
|
||||
showHtml: true
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
@ -0,0 +1,9 @@
|
||||
export default Ember.Route.extend({
|
||||
model() {
|
||||
return this.store.find('embedding');
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.set('embedding', model);
|
||||
}
|
||||
});
|
||||
@ -27,6 +27,7 @@ export default {
|
||||
this.resource('adminUserFields', { path: '/user_fields' });
|
||||
this.resource('adminEmojis', { path: '/emojis' });
|
||||
this.resource('adminPermalinks', { path: '/permalinks' });
|
||||
this.resource('adminEmbedding', { path: '/embedding' });
|
||||
});
|
||||
this.route('api');
|
||||
|
||||
|
||||
26
app/assets/javascripts/admin/routes/admin-user-badges.js.es6
Normal file
26
app/assets/javascripts/admin/routes/admin-user-badges.js.es6
Normal file
@ -0,0 +1,26 @@
|
||||
import UserBadge from 'discourse/models/user-badge';
|
||||
import Badge from 'discourse/models/badge';
|
||||
|
||||
export default Discourse.Route.extend({
|
||||
model() {
|
||||
const username = this.modelFor('adminUser').get('username');
|
||||
return UserBadge.findByUsername(username);
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
// Find all badges.
|
||||
controller.set('loading', true);
|
||||
Badge.findAll().then(function(badges) {
|
||||
controller.set('badges', badges);
|
||||
if (badges.length > 0) {
|
||||
var grantableBadges = controller.get('grantableBadges');
|
||||
if (grantableBadges.length > 0) {
|
||||
controller.set('selectedBadgeId', grantableBadges[0].get('id'));
|
||||
}
|
||||
}
|
||||
controller.set('loading', false);
|
||||
});
|
||||
// Set the model.
|
||||
controller.set('model', model);
|
||||
}
|
||||
});
|
||||
@ -1,25 +0,0 @@
|
||||
/**
|
||||
Previews the Email Digests
|
||||
|
||||
@class AdminEmailPreviewDigest
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
|
||||
Discourse.AdminEmailPreviewDigestRoute = Discourse.Route.extend({
|
||||
|
||||
model: function() {
|
||||
return Discourse.EmailPreview.findDigest();
|
||||
},
|
||||
|
||||
afterModel: function(model) {
|
||||
var controller = this.controllerFor('adminEmailPreviewDigest');
|
||||
controller.setProperties({
|
||||
model: model,
|
||||
lastSeen: moment().subtract(7, 'days').format('YYYY-MM-DD'),
|
||||
showHtml: true
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,32 +0,0 @@
|
||||
/**
|
||||
Shows all of the badges that have been granted to a user, and allow granting and
|
||||
revoking badges.
|
||||
|
||||
@class AdminUserBadgesRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUserBadgesRoute = Discourse.Route.extend({
|
||||
model: function() {
|
||||
var username = this.modelFor('adminUser').get('username');
|
||||
return Discourse.UserBadge.findByUsername(username);
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
// Find all badges.
|
||||
controller.set('loading', true);
|
||||
Discourse.Badge.findAll().then(function(badges) {
|
||||
controller.set('badges', badges);
|
||||
if (badges.length > 0) {
|
||||
var grantableBadges = controller.get('grantableBadges');
|
||||
if (grantableBadges.length > 0) {
|
||||
controller.set('selectedBadgeId', grantableBadges[0].get('id'));
|
||||
}
|
||||
}
|
||||
controller.set('loading', false);
|
||||
});
|
||||
// Set the model.
|
||||
controller.set('model', model);
|
||||
}
|
||||
});
|
||||
@ -6,9 +6,9 @@
|
||||
<div class="pull-right">
|
||||
{{resumable-upload target="/admin/backups/upload" success="uploadSuccess" error="uploadError" uploadText=uploadLabel title="admin.backups.upload.title"}}
|
||||
{{#if site.isReadOnly}}
|
||||
{{d-button icon="eye" action="toggleReadOnlyMode" disabled=model.isOperationRunning title="admin.backups.read_only.disable.title" label="admin.backups.read_only.disable.label"}}
|
||||
{{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.model.isOperationRunning title="admin.backups.read_only.disable.title" label="admin.backups.read_only.disable.label"}}
|
||||
{{else}}
|
||||
{{d-button icon="eye" action="toggleReadOnlyMode" disabled=model.isOperationRunning title="admin.backups.read_only.enable.title" label="admin.backups.read_only.enable.label"}}
|
||||
{{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.model.isOperationRunning title="admin.backups.read_only.enable.title" label="admin.backups.read_only.enable.label"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</th>
|
||||
@ -20,12 +20,12 @@
|
||||
<td>
|
||||
<div class="pull-right">
|
||||
<a {{bind-attr href="backup.link"}} class="btn download" title="{{i18n 'admin.backups.operations.download.title'}}">{{fa-icon "download"}}{{i18n 'admin.backups.operations.download.label'}}</a>
|
||||
{{#if model.isOperationRunning}}
|
||||
{{#if status.model.isOperationRunning}}
|
||||
{{d-button icon="trash-o" action="destroyBackup" actionParam=backup class="btn-danger" disabled="true" title="admin.backups.operations.is_running"}}
|
||||
{{d-button icon="play" action="startRestore" actionParam=backup disabled=model.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
|
||||
{{d-button icon="play" action="startRestore" actionParam=backup disabled=status.model.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
|
||||
{{else}}
|
||||
{{d-button icon="trash-o" action="destroyBackup" actionParam=backup class="btn-danger" title="admin.backups.operations.destroy.title"}}
|
||||
{{d-button icon="play" action="startRestore" actionParam=backup disabled=model.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
|
||||
{{d-button icon="play" action="startRestore" actionParam=backup disabled=status.model.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
{{#if editing}}
|
||||
<td>
|
||||
{{input value=buffered.host placeholder="example.com" enter="save" class="host-name"}}
|
||||
</td>
|
||||
<td>
|
||||
{{category-chooser value=categoryId}}
|
||||
</td>
|
||||
<td>
|
||||
{{d-button icon="check" action="save" class="btn-primary" disabled=cantSave}}
|
||||
{{d-button icon="times" action="cancel" class="btn-danger" disabled=host.isSaving}}
|
||||
</td>
|
||||
{{else}}
|
||||
<td>{{host.host}}</td>
|
||||
<td>{{category-badge host.category}}</td>
|
||||
<td>
|
||||
{{d-button icon="pencil" action="edit"}}
|
||||
{{d-button icon="trash-o" action="delete" class='btn-danger'}}
|
||||
</td>
|
||||
{{/if}}
|
||||
@ -0,0 +1,11 @@
|
||||
{{#if isCheckbox}}
|
||||
<label for={{inputId}}>
|
||||
{{input checked=checked id=inputId type="checkbox"}}
|
||||
{{i18n translationKey}}
|
||||
</label>
|
||||
{{else}}
|
||||
<label for={{inputId}}>{{i18n translationKey}}</label>
|
||||
{{input value=value id=inputId}}
|
||||
{{/if}}
|
||||
|
||||
<div class='clearfix'></div>
|
||||
@ -0,0 +1 @@
|
||||
<pre><code class={{lang}}>{{code}}</code></pre>
|
||||
@ -2,7 +2,7 @@
|
||||
<h3>{{unbound settingName}}</h3>
|
||||
</div>
|
||||
<div class="setting-value">
|
||||
{{partial partialName}}
|
||||
{{component componentName setting=setting value=buffered.value validationMessage=validationMessage}}
|
||||
</div>
|
||||
{{#if dirty}}
|
||||
<div class='setting-controls'>
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
{{category-group categories=selectedCategories blacklist=selectedCategories}}
|
||||
<div class='desc'>{{{unbound setting.description}}}</div>
|
||||
{{setting-validation-message message=validationMessage}}
|
||||
@ -1,4 +1,4 @@
|
||||
{{combo-box valueAttribute="value" content=setting.validValues value=buffered.value none=setting.allowsNone}}
|
||||
{{combo-box valueAttribute="value" content=setting.validValues value=value none=setting.allowsNone}}
|
||||
{{preview}}
|
||||
{{setting-validation-message message=validationMessage}}
|
||||
<div class='desc'>{{{unbound setting.description}}}</div>
|
||||
@ -1,3 +1,3 @@
|
||||
{{value-list values=buffered.value addKey="admin.site_settings.add_url"}}
|
||||
{{value-list values=value addKey="admin.site_settings.add_host"}}
|
||||
{{setting-validation-message message=validationMessage}}
|
||||
<div class='desc'>{{{unbound setting.description}}}</div>
|
||||
@ -1,3 +1,3 @@
|
||||
{{list-setting settingValue=buffered.value choices=setting.choices settingName=setting.setting}}
|
||||
{{list-setting settingValue=value choices=setting.choices settingName=setting.setting}}
|
||||
{{setting-validation-message message=validationMessage}}
|
||||
<div class='desc'>{{{unbound setting.description}}}</div>
|
||||
@ -1,3 +1,3 @@
|
||||
{{text-field value=buffered.value classNames="input-setting-string"}}
|
||||
{{text-field value=value classNames="input-setting-string"}}
|
||||
{{setting-validation-message message=validationMessage}}
|
||||
<div class='desc'>{{{unbound setting.description}}}</div>
|
||||
@ -1,3 +1,3 @@
|
||||
{{value-list values=buffered.value addKey="admin.site_settings.add_host"}}
|
||||
{{value-list values=value addKey="admin.site_settings.add_url"}}
|
||||
{{setting-validation-message message=validationMessage}}
|
||||
<div class='desc'>{{{unbound setting.description}}}</div>
|
||||
@ -5,6 +5,7 @@
|
||||
{{nav-item route='adminUserFields' label='admin.user_fields.title'}}
|
||||
{{nav-item route='adminEmojis' label='admin.emoji.title'}}
|
||||
{{nav-item route='adminPermalinks' label='admin.permalink.title'}}
|
||||
{{nav-item route='adminEmbedding' label='admin.embedding.title'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
|
||||
@ -40,6 +40,93 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="greyexplain">
|
||||
Various greys used throught the UI.
|
||||
<div><div class="cboxcontainer primary">
|
||||
<div class="cbox0"></div>
|
||||
<div class="cbox5"></div>
|
||||
<div class="cbox10"></div>
|
||||
<div class="cbox15"></div>
|
||||
<div class="cbox20"></div>
|
||||
<div class="cbox25"></div>
|
||||
<div class="cbox30"></div>
|
||||
<div class="cbox40"></div>
|
||||
<div class="cbox50"></div>
|
||||
<div class="cbox60"></div>
|
||||
<div class="cbox70"></div>
|
||||
<div class="cbox75"></div>
|
||||
<div class="cbox80"></div>
|
||||
<div class="cbox85"></div>
|
||||
<div class="cbox90"></div>
|
||||
<div class="cbox95"></div>
|
||||
<div class="cbox100"></div>
|
||||
blend-primary-secondary()
|
||||
</div></div>
|
||||
|
||||
<div><div class="cboxcontainer secondary">
|
||||
<div class="cbox0"></div>
|
||||
<div class="cbox5"></div>
|
||||
<div class="cbox10"></div>
|
||||
<div class="cbox15"></div>
|
||||
<div class="cbox20"></div>
|
||||
<div class="cbox25"></div>
|
||||
<div class="cbox30"></div>
|
||||
<div class="cbox40"></div>
|
||||
<div class="cbox50"></div>
|
||||
<div class="cbox60"></div>
|
||||
<div class="cbox70"></div>
|
||||
<div class="cbox75"></div>
|
||||
<div class="cbox80"></div>
|
||||
<div class="cbox85"></div>
|
||||
<div class="cbox90"></div>
|
||||
<div class="cbox95"></div>
|
||||
<div class="cbox100"></div>
|
||||
blend-primary-secondary()
|
||||
</div></div>
|
||||
|
||||
<div><div class="cboxcontainer primary">
|
||||
<div class="dbox100"></div>
|
||||
<div class="dbox95"></div>
|
||||
<div class="dbox90"></div>
|
||||
<div class="dbox85"></div>
|
||||
<div class="dbox80"></div>
|
||||
<div class="dbox75"></div>
|
||||
<div class="dbox70"></div>
|
||||
<div class="dbox60"></div>
|
||||
<div class="dbox50"></div>
|
||||
<div class="dbox40"></div>
|
||||
<div class="dbox30"></div>
|
||||
<div class="dbox25"></div>
|
||||
<div class="dbox20"></div>
|
||||
<div class="dbox15"></div>
|
||||
<div class="dbox10"></div>
|
||||
<div class="dbox5"></div>
|
||||
<div class="dbox0"></div>
|
||||
dark-light-diff()
|
||||
</div></div>
|
||||
|
||||
<div><div class="cboxcontainer secondary">
|
||||
<div class="dbox100"></div>
|
||||
<div class="dbox95"></div>
|
||||
<div class="dbox90"></div>
|
||||
<div class="dbox85"></div>
|
||||
<div class="dbox80"></div>
|
||||
<div class="dbox75"></div>
|
||||
<div class="dbox70"></div>
|
||||
<div class="dbox60"></div>
|
||||
<div class="dbox50"></div>
|
||||
<div class="dbox40"></div>
|
||||
<div class="dbox30"></div>
|
||||
<div class="dbox25"></div>
|
||||
<div class="dbox20"></div>
|
||||
<div class="dbox15"></div>
|
||||
<div class="dbox10"></div>
|
||||
<div class="dbox5"></div>
|
||||
<div class="dbox0"></div>
|
||||
dark-light-diff()
|
||||
</div></div>
|
||||
</div>
|
||||
|
||||
{{#if colors.length}}
|
||||
<table class="table colors">
|
||||
<thead>
|
||||
|
||||
@ -4,24 +4,22 @@
|
||||
<div class='span7 controls'>
|
||||
<label for='last-seen'>{{i18n 'admin.email.last_seen_user'}}</label>
|
||||
{{input type="date" value=lastSeen id="last-seen"}}
|
||||
</div>
|
||||
<div>
|
||||
<button class='btn' {{action "refresh"}}>{{i18n 'admin.email.refresh'}}</button>
|
||||
</div>
|
||||
<div class="span7 toggle">
|
||||
<label>{{i18n 'admin.email.format'}}</label>
|
||||
{{#if showHtml}}
|
||||
<span>{{i18n 'admin.email.html'}}</span> | <a href='#' {{action "toggleShowHtml"}}>{{i18n 'admin.email.text'}}</a>
|
||||
{{else}}
|
||||
<a href='#' {{action "toggleShowHtml"}}>{{i18n 'admin.email.html'}}</a> | <span>{{i18n 'admin.email.text'}}</span>
|
||||
{{/if}}
|
||||
<div class="toggle">
|
||||
<label>{{i18n 'admin.email.format'}}</label>
|
||||
{{#if showHtml}}
|
||||
<span>{{i18n 'admin.email.html'}}</span> | <a href='#' {{action "toggleShowHtml"}}>{{i18n 'admin.email.text'}}</a>
|
||||
{{else}}
|
||||
<a href='#' {{action "toggleShowHtml"}}>{{i18n 'admin.email.html'}}</a> | <span>{{i18n 'admin.email.text'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
{{#if showHtml}}
|
||||
{{{html_content}}}
|
||||
{{{model.html_content}}}
|
||||
{{else}}
|
||||
<pre>{{{text_content}}}</pre>
|
||||
<pre>{{{model.text_content}}}</pre>
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
||||
|
||||
61
app/assets/javascripts/admin/templates/embedding.hbs
Normal file
61
app/assets/javascripts/admin/templates/embedding.hbs
Normal file
@ -0,0 +1,61 @@
|
||||
<div class='embeddable-hosts'>
|
||||
{{#if embedding.embeddable_hosts}}
|
||||
<table class='embedding'>
|
||||
<tr>
|
||||
<th style='width: 50%'>{{i18n "admin.embedding.host"}}</th>
|
||||
<th style='width: 30%'>{{i18n "admin.embedding.category"}}</th>
|
||||
<th style='width: 20%'> </th>
|
||||
</tr>
|
||||
{{#each embedding.embeddable_hosts as |host|}}
|
||||
{{embeddable-host host=host deleteHost="deleteHost"}}
|
||||
{{/each}}
|
||||
</table>
|
||||
{{else}}
|
||||
<p>{{i18n "admin.embedding.get_started"}}</p>
|
||||
{{/if}}
|
||||
|
||||
{{d-button label="admin.embedding.add_host" action="addHost" icon="plus" class="btn-primary add-host"}}
|
||||
</div>
|
||||
|
||||
{{#if showSecondary}}
|
||||
<div class='embedding-secondary'>
|
||||
<p>{{{i18n "admin.embedding.sample"}}}</p>
|
||||
{{highlighted-code code=embeddingCode lang="html"}}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class='embedding-secondary'>
|
||||
<h3>{{i18n "admin.embedding.settings"}}</h3>
|
||||
|
||||
{{embedding-setting field="embed_by_username" value=embedding.embed_by_username}}
|
||||
{{embedding-setting field="embed_post_limit" value=embedding.embed_post_limit}}
|
||||
{{embedding-setting field="embed_truncate" value=embedding.embed_truncate type="checkbox"}}
|
||||
</div>
|
||||
|
||||
<div class='embedding-secondary'>
|
||||
<h3>{{i18n "admin.embedding.feed_settings"}}</h3>
|
||||
<p class="description">{{i18n "admin.embedding.feed_description"}}</p>
|
||||
|
||||
{{embedding-setting field="feed_polling_enabled" value=embedding.feed_polling_enabled type="checkbox"}}
|
||||
{{embedding-setting field="feed_polling_url" value=embedding.feed_polling_url}}
|
||||
{{embedding-setting field="embed_username_key_from_feed" value=embedding.embed_username_key_from_feed}}
|
||||
</div>
|
||||
|
||||
<div class='embedding-secondary'>
|
||||
<h3>{{i18n "admin.embedding.crawling_settings"}}</h3>
|
||||
<p class="description">{{i18n "admin.embedding.crawling_description"}}</p>
|
||||
|
||||
{{embedding-setting field="embed_whitelist_selector" value=embedding.embed_whitelist_selector}}
|
||||
{{embedding-setting field="embed_blacklist_selector" value=embedding.embed_blacklist_selector}}
|
||||
</div>
|
||||
|
||||
<div class='embedding-secondary'>
|
||||
{{d-button label="admin.embedding.save"
|
||||
action="saveChanges"
|
||||
class="btn-primary embed-save"
|
||||
disabled=embedding.isSaving}}
|
||||
|
||||
{{#if saved}}{{i18n "saved"}}{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
@ -6,6 +6,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class='controls'>
|
||||
<button {{action "toggleMenu"}} class="menu-toggle">{{fa-icon "bars"}}</button>
|
||||
{{text-field value=filter placeholderKey="type_to_filter" class="no-blur"}}
|
||||
<button {{action "clearFilter"}} class="btn">{{i18n 'admin.site_settings.clear_filter'}}</button>
|
||||
</div>
|
||||
@ -26,7 +27,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="admin-detail pull-left">
|
||||
<div class="admin-detail pull-left mobile-closed">
|
||||
{{outlet}}
|
||||
</div>
|
||||
|
||||
|
||||
@ -143,19 +143,19 @@
|
||||
<div class='display-row'>
|
||||
<div class='field'>{{i18n 'admin.users.approved'}}</div>
|
||||
<div class='value'>
|
||||
{{#if approved}}
|
||||
{{#if model.approved}}
|
||||
{{i18n 'admin.user.approved_by'}}
|
||||
{{#link-to 'adminUser' approvedBy}}{{avatar approvedBy imageSize="small"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' approvedBy}}{{approvedBy.username}}{{/link-to}}
|
||||
{{#link-to 'adminUser' approvedBy}}{{avatar model.approvedBy imageSize="small"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' approvedBy}}{{model.approvedBy.username}}{{/link-to}}
|
||||
{{else}}
|
||||
{{i18n 'no_value'}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class='controls'>
|
||||
{{#if approved}}
|
||||
{{#if model.approved}}
|
||||
{{i18n 'admin.user.approve_success'}}
|
||||
{{else}}
|
||||
{{#if can_approve}}
|
||||
{{#if model.can_approve}}
|
||||
<button class='btn' {{action "approve" target="content"}}>
|
||||
{{fa-icon "check"}}
|
||||
{{i18n 'admin.user.approve'}}
|
||||
@ -306,12 +306,12 @@
|
||||
<div class='display-row highlight-danger'>
|
||||
<div class='field'>{{i18n 'admin.user.suspended_by'}}</div>
|
||||
<div class='value'>
|
||||
{{#link-to 'adminUser' suspendedBy}}{{avatar suspendedBy imageSize="tiny"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' suspendedBy}}{{suspendedBy.username}}{{/link-to}}
|
||||
{{#link-to 'adminUser' suspendedBy}}{{avatar model.suspendedBy imageSize="tiny"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' suspendedBy}}{{model.suspendedBy.username}}{{/link-to}}
|
||||
</div>
|
||||
<div class='controls'>
|
||||
<b>{{i18n 'admin.user.suspend_reason'}}</b>:
|
||||
{{suspend_reason}}
|
||||
{{model.suspend_reason}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
137
app/assets/javascripts/admin/templates/user-tl3-requirements.hbs
Normal file
137
app/assets/javascripts/admin/templates/user-tl3-requirements.hbs
Normal file
@ -0,0 +1,137 @@
|
||||
<div class='admin-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#link-to 'adminUser' model}}<i class="fa fa-caret-left"></i> {{model.username}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminUsersList.show' 'regular'}}{{i18n 'admin.user.trust_level_2_users'}}{{/link-to}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-container tl3-requirements">
|
||||
<h2>{{model.username}} - {{i18n 'admin.user.tl3_requirements.title'}}</h2>
|
||||
<br/>
|
||||
<p>{{i18n 'admin.user.tl3_requirements.table_title'}}</p>
|
||||
|
||||
<table class="table" style="width: auto;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.value_heading'}}</th>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.requirement_heading'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.visits'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.days_visited:fa-check:fa-times"}}></i></td>
|
||||
<td>
|
||||
{{model.tl3Requirements.days_visited_percent}}% ({{model.tl3Requirements.days_visited}} / {{model.tl3Requirements.time_period}} {{i18n 'admin.user.tl3_requirements.days'}})
|
||||
</td>
|
||||
<td>{{model.tl3Requirements.min_days_visited_percent}}%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.topics_replied_to'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.topics_replied_to:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.num_topics_replied_to}}</td>
|
||||
<td>{{model.tl3Requirements.min_topics_replied_to}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.topics_viewed'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.topics_viewed:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.topics_viewed}}</td>
|
||||
<td>{{model.tl3Requirements.min_topics_viewed}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.topics_viewed_all_time'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.topics_viewed_all_time:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.topics_viewed_all_time}}</td>
|
||||
<td>{{model.tl3Requirements.min_topics_viewed_all_time}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.posts_read'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.posts_read:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.posts_read}}</td>
|
||||
<td>{{model.tl3Requirements.min_posts_read}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.posts_read_all_time'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.posts_read_all_time:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.posts_read_all_time}}</td>
|
||||
<td>{{model.tl3Requirements.min_posts_read_all_time}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.flagged_posts'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.flagged_posts:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.num_flagged_posts}}</td>
|
||||
<td>{{i18n 'max_of_count' count=model.tl3Requirements.max_flagged_posts}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.flagged_by_users'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.flagged_by_users:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.num_flagged_by_users}}</td>
|
||||
<td>{{i18n 'max_of_count' count=model.tl3Requirements.max_flagged_by_users}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.likes_given'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.likes_given:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.num_likes_given}}</td>
|
||||
<td>{{model.tl3Requirements.min_likes_given}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.likes_received'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.likes_received:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.num_likes_received}}</td>
|
||||
<td>{{model.tl3Requirements.min_likes_received}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.likes_received_days'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.likes_received_days:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.num_likes_received_days}}</td>
|
||||
<td>{{model.tl3Requirements.min_likes_received_days}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.likes_received_users'}}</th>
|
||||
<td><i {{bind-attr class=":fa model.tl3Requirements.met.likes_received_users:fa-check:fa-times"}}></i></td>
|
||||
<td>{{model.tl3Requirements.num_likes_received_users}}</td>
|
||||
<td>{{model.tl3Requirements.min_likes_received_users}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
{{#if model.istl3}}
|
||||
{{#if model.tl3Requirements.requirements_lost}}
|
||||
{{! tl implicitly not locked }}
|
||||
{{#if model.tl3Requirements.on_grace_period}}
|
||||
<i class="fa fa-times"></i> {{i18n 'admin.user.tl3_requirements.on_grace_period'}}
|
||||
{{else}} {{! not on grace period }}
|
||||
<i class="fa fa-times"></i> {{i18n 'admin.user.tl3_requirements.does_not_qualify'}}
|
||||
{{i18n 'admin.user.tl3_requirements.will_be_demoted'}}
|
||||
{{/if}}
|
||||
{{else}} {{! requirements not lost - remains tl3 }}
|
||||
{{#if model.tl3Requirements.trust_level_locked}}
|
||||
<i class="fa fa-lock"></i> {{i18n 'admin.user.tl3_requirements.locked_will_not_be_demoted'}}
|
||||
{{else}} {{! tl not locked }}
|
||||
<i class="fa fa-check"></i> {{i18n 'admin.user.tl3_requirements.qualifies'}}
|
||||
{{#if model.tl3Requirements.on_grace_period}}
|
||||
{{i18n 'admin.user.tl3_requirements.on_grace_period'}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}} {{! is not tl3 }}
|
||||
{{#if model.tl3Requirements.requirements_met}}
|
||||
{{! met & not tl3 - will be promoted}}
|
||||
<i class="fa fa-check"></i> {{i18n 'admin.user.tl3_requirements.qualifies'}}
|
||||
{{i18n 'admin.user.tl3_requirements.will_be_promoted'}}
|
||||
{{else}} {{! requirements not met - remains regular }}
|
||||
{{#if model.tl3Requirements.trust_level_locked}}
|
||||
<i class="fa fa-lock"></i> {{i18n 'admin.user.tl3_requirements.locked_will_not_be_promoted'}}
|
||||
{{else}}
|
||||
<i class="fa fa-times"></i> {{i18n 'admin.user.tl3_requirements.does_not_qualify'}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
@ -1,137 +0,0 @@
|
||||
<div class='admin-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#link-to 'adminUser' this}}<i class="fa fa-caret-left"></i> {{username}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminUsersList.show' 'regular'}}{{i18n 'admin.user.trust_level_2_users'}}{{/link-to}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-container tl3-requirements">
|
||||
<h2>{{username}} - {{i18n 'admin.user.tl3_requirements.title'}}</h2>
|
||||
<br/>
|
||||
<p>{{i18n 'admin.user.tl3_requirements.table_title'}}</p>
|
||||
|
||||
<table class="table" style="width: auto;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.value_heading'}}</th>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.requirement_heading'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.visits'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.days_visited:fa-check:fa-times"}}></i></td>
|
||||
<td>
|
||||
{{tl3Requirements.days_visited_percent}}% ({{tl3Requirements.days_visited}} / {{tl3Requirements.time_period}} {{i18n 'admin.user.tl3_requirements.days'}})
|
||||
</td>
|
||||
<td>{{tl3Requirements.min_days_visited_percent}}%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.topics_replied_to'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.topics_replied_to:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.num_topics_replied_to}}</td>
|
||||
<td>{{tl3Requirements.min_topics_replied_to}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.topics_viewed'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.topics_viewed:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.topics_viewed}}</td>
|
||||
<td>{{tl3Requirements.min_topics_viewed}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.topics_viewed_all_time'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.topics_viewed_all_time:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.topics_viewed_all_time}}</td>
|
||||
<td>{{tl3Requirements.min_topics_viewed_all_time}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.posts_read'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.posts_read:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.posts_read}}</td>
|
||||
<td>{{tl3Requirements.min_posts_read}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.posts_read_all_time'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.posts_read_all_time:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.posts_read_all_time}}</td>
|
||||
<td>{{tl3Requirements.min_posts_read_all_time}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.flagged_posts'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.flagged_posts:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.num_flagged_posts}}</td>
|
||||
<td>{{i18n 'max_of_count' count=tl3Requirements.max_flagged_posts}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.flagged_by_users'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.flagged_by_users:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.num_flagged_by_users}}</td>
|
||||
<td>{{i18n 'max_of_count' count=tl3Requirements.max_flagged_by_users}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.likes_given'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.likes_given:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.num_likes_given}}</td>
|
||||
<td>{{tl3Requirements.min_likes_given}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.likes_received'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.likes_received:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.num_likes_received}}</td>
|
||||
<td>{{tl3Requirements.min_likes_received}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.likes_received_days'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.likes_received_days:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.num_likes_received_days}}</td>
|
||||
<td>{{tl3Requirements.min_likes_received_days}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.user.tl3_requirements.likes_received_users'}}</th>
|
||||
<td><i {{bind-attr class=":fa tl3Requirements.met.likes_received_users:fa-check:fa-times"}}></i></td>
|
||||
<td>{{tl3Requirements.num_likes_received_users}}</td>
|
||||
<td>{{tl3Requirements.min_likes_received_users}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
{{#if istl3}}
|
||||
{{#if tl3Requirements.requirements_lost}}
|
||||
{{! tl implicitly not locked }}
|
||||
{{#if tl3Requirements.on_grace_period}}
|
||||
<i class="fa fa-times"></i> {{i18n 'admin.user.tl3_requirements.on_grace_period'}}
|
||||
{{else}} {{! not on grace period }}
|
||||
<i class="fa fa-times"></i> {{i18n 'admin.user.tl3_requirements.does_not_qualify'}}
|
||||
{{i18n 'admin.user.tl3_requirements.will_be_demoted'}}
|
||||
{{/if}}
|
||||
{{else}} {{! requirements not lost - remains tl3 }}
|
||||
{{#if tl3Requirements.trust_level_locked}}
|
||||
<i class="fa fa-lock"></i> {{i18n 'admin.user.tl3_requirements.locked_will_not_be_demoted'}}
|
||||
{{else}} {{! tl not locked }}
|
||||
<i class="fa fa-check"></i> {{i18n 'admin.user.tl3_requirements.qualifies'}}
|
||||
{{#if tl3Requirements.on_grace_period}}
|
||||
{{i18n 'admin.user.tl3_requirements.on_grace_period'}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}} {{! is not tl3 }}
|
||||
{{#if tl3Requirements.requirements_met}}
|
||||
{{! met & not tl3 - will be promoted}}
|
||||
<i class="fa fa-check"></i> {{i18n 'admin.user.tl3_requirements.qualifies'}}
|
||||
{{i18n 'admin.user.tl3_requirements.will_be_promoted'}}
|
||||
{{else}} {{! requirements not met - remains regular }}
|
||||
{{#if tl3Requirements.trust_level_locked}}
|
||||
<i class="fa fa-lock"></i> {{i18n 'admin.user.tl3_requirements.locked_will_not_be_promoted'}}
|
||||
{{else}}
|
||||
<i class="fa fa-times"></i> {{i18n 'admin.user.tl3_requirements.does_not_qualify'}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
@ -1,6 +1,7 @@
|
||||
import debounce from 'discourse/lib/debounce';
|
||||
import { renderSpinner } from 'discourse/helpers/loading-spinner';
|
||||
|
||||
export default Discourse.View.extend({
|
||||
export default Ember.View.extend({
|
||||
classNames: ["admin-backups-logs"],
|
||||
|
||||
_initialize: function() { this._reset(); }.on("init"),
|
||||
@ -9,7 +10,7 @@ export default Discourse.View.extend({
|
||||
this.setProperties({ formattedLogs: "", index: 0 });
|
||||
},
|
||||
|
||||
_updateFormattedLogs: Discourse.debounce(function() {
|
||||
_updateFormattedLogs: debounce(function() {
|
||||
const logs = this.get("controller.model");
|
||||
if (logs.length === 0) {
|
||||
this._reset(); // reset the cached logs whenever the model is reset
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
export default Discourse.View.extend({
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
|
||||
export default Ember.View.extend({
|
||||
classNames: ["admin-backups"],
|
||||
|
||||
_hijackDownloads: function() {
|
||||
@ -12,7 +14,7 @@ export default Discourse.View.extend({
|
||||
$link.data("auto-route", true);
|
||||
}
|
||||
|
||||
Discourse.URL.redirectTo($link.data("href"));
|
||||
DiscourseURL.redirectTo($link.data("href"));
|
||||
});
|
||||
}.on("didInsertElement"),
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import LoadMore from "discourse/mixins/load-more";
|
||||
|
||||
export default Discourse.View.extend(LoadMore, {
|
||||
export default Ember.View.extend(LoadMore, {
|
||||
loading: false,
|
||||
eyelineSelector: '.admin-flags tbody tr',
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export default Discourse.View.extend({
|
||||
export default Ember.View.extend({
|
||||
_disableCustomStylesheets: function() {
|
||||
if (this.session.get("disableCustomCSS")) {
|
||||
$("link.custom-css").attr("rel", "");
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
/**
|
||||
A view to handle color selections within a site customization
|
||||
|
||||
@class AdminCustomizeColorsView
|
||||
@extends Discourse.View
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminCustomizeColorsView = Discourse.View.extend({
|
||||
Discourse.AdminCustomizeColorsView = Ember.View.extend({
|
||||
templateName: 'admin/templates/customize_colors'
|
||||
});
|
||||
|
||||
@ -1,10 +1 @@
|
||||
/**
|
||||
The view class for an Admin User
|
||||
|
||||
@class AdminUserView
|
||||
@extends Discourse.View
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUserView = Discourse.View.extend(Discourse.ScrollTop);
|
||||
|
||||
Discourse.AdminUserView = Ember.View.extend(Discourse.ScrollTop);
|
||||
|
||||
@ -6,15 +6,11 @@ require_asset ("./main_include.js")
|
||||
DiscoursePluginRegistry.javascripts.each { |js| require_asset(js) }
|
||||
DiscoursePluginRegistry.handlebars.each { |hb| require_asset(hb) }
|
||||
|
||||
# Load any glob dependencies
|
||||
DiscoursePluginRegistry.asset_globs.each do |g|
|
||||
root, extension = *g
|
||||
Dir.glob("#{root}/**/*") do |f|
|
||||
if File.directory?(f)
|
||||
depend_on(f)
|
||||
elsif f.to_s.end_with?(".#{extension}")
|
||||
require_asset(f)
|
||||
end
|
||||
DiscoursePluginRegistry.each_globbed_asset do |f, ext|
|
||||
if File.directory?(f)
|
||||
depend_on(f)
|
||||
elsif f.to_s.end_with?(".#{ext}")
|
||||
require_asset(f)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ var DiscourseResolver = require('discourse/ember/resolver').default;
|
||||
|
||||
// Allow us to import Ember
|
||||
define('ember', ['exports'], function(__exports__) {
|
||||
__exports__["default"] = Ember;
|
||||
__exports__.default = Ember;
|
||||
});
|
||||
|
||||
window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
||||
@ -16,7 +16,7 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
||||
// if it's a non relative URL, return it.
|
||||
if (!/^\/[^\/]/.test(url)) return url;
|
||||
|
||||
var u = (Discourse.BaseUri === undefined ? "/" : Discourse.BaseUri);
|
||||
var u = Discourse.BaseUri === undefined ? "/" : Discourse.BaseUri;
|
||||
|
||||
if (u[u.length-1] === '/') u = u.substring(0, u.length-1);
|
||||
if (url.indexOf(u) !== -1) return url;
|
||||
@ -57,7 +57,11 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
||||
|
||||
faviconChanged: function() {
|
||||
if(Discourse.User.currentProp('dynamic_favicon')) {
|
||||
new Favcount(Discourse.SiteSettings.favicon_url).set(
|
||||
var url = Discourse.SiteSettings.favicon_url;
|
||||
if (/^http/.test(url)) {
|
||||
url = Discourse.getURL("/favicon/proxied?" + encodeURIComponent(url));
|
||||
}
|
||||
new Favcount(url).set(
|
||||
this.get('notifyCount')
|
||||
);
|
||||
}
|
||||
@ -66,7 +70,7 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
||||
// The classes of buttons to show on a post
|
||||
postButtons: function() {
|
||||
return Discourse.SiteSettings.post_menu.split("|").map(function(i) {
|
||||
return (i.replace(/\+/, '').capitalize());
|
||||
return i.replace(/\+/, '').capitalize();
|
||||
});
|
||||
}.property(),
|
||||
|
||||
@ -109,12 +113,26 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
||||
|
||||
$('noscript').remove();
|
||||
|
||||
// Load any ES6 initializers
|
||||
Ember.keys(requirejs._eak_seen).forEach(function(key) {
|
||||
if (/\/pre\-initializers\//.test(key)) {
|
||||
var module = require(key, null, null, true);
|
||||
if (!module) { throw new Error(key + ' must export an initializer.'); }
|
||||
Discourse.initializer(module.default);
|
||||
}
|
||||
});
|
||||
|
||||
Ember.keys(requirejs._eak_seen).forEach(function(key) {
|
||||
if (/\/initializers\//.test(key)) {
|
||||
var module = require(key, null, null, true);
|
||||
if (!module) { throw new Error(key + ' must export an initializer.'); }
|
||||
Discourse.initializer(module.default);
|
||||
|
||||
var init = module.default;
|
||||
var oldInitialize = init.initialize;
|
||||
init.initialize = function(app) {
|
||||
oldInitialize.call(this, app.container, Discourse);
|
||||
};
|
||||
|
||||
Discourse.instanceInitializer(init);
|
||||
}
|
||||
});
|
||||
|
||||
@ -125,22 +143,24 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
||||
return desired && Discourse.get("currentAssetVersion") !== desired;
|
||||
}.property("currentAssetVersion", "desiredAssetVersion"),
|
||||
|
||||
assetVersion: function(prop, val) {
|
||||
if(val) {
|
||||
if(this.get("currentAssetVersion")){
|
||||
this.set("desiredAssetVersion", val);
|
||||
} else {
|
||||
this.set("currentAssetVersion", val);
|
||||
|
||||
assetVersion: Ember.computed({
|
||||
get: function() {
|
||||
return this.get("currentAssetVersion");
|
||||
},
|
||||
set: function(key, val) {
|
||||
if(val) {
|
||||
if (this.get("currentAssetVersion")) {
|
||||
this.set("desiredAssetVersion", val);
|
||||
} else {
|
||||
this.set("currentAssetVersion", val);
|
||||
}
|
||||
}
|
||||
return this.get("currentAssetVersion");
|
||||
}
|
||||
return this.get("currentAssetVersion");
|
||||
}.property()
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
// TODO: Remove this, it is in for backwards compatibiltiy with plugins
|
||||
Discourse.HasCurrentUser = {};
|
||||
|
||||
function proxyDep(propName, moduleFunc, msg) {
|
||||
if (Discourse.hasOwnProperty(propName)) { return; }
|
||||
Object.defineProperty(Discourse, propName, {
|
||||
@ -155,3 +175,7 @@ function proxyDep(propName, moduleFunc, msg) {
|
||||
proxyDep('computed', function() { return require('discourse/lib/computed') });
|
||||
proxyDep('Formatter', function() { return require('discourse/lib/formatter') });
|
||||
proxyDep('PageTracker', function() { return require('discourse/lib/page-tracker').default });
|
||||
proxyDep('URL', function() { return require('discourse/lib/url').default });
|
||||
proxyDep('Quote', function() { return require('discourse/lib/quote').default });
|
||||
proxyDep('debounce', function() { return require('discourse/lib/debounce').default });
|
||||
proxyDep('View', function() { return Ember.View }, "Use `Ember.View` instead");
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
const ADMIN_MODELS = ['plugin', 'site-customization'];
|
||||
const ADMIN_MODELS = ['plugin', 'site-customization', 'embeddable-host'];
|
||||
|
||||
export function Result(payload, responseJson) {
|
||||
this.payload = payload;
|
||||
@ -19,7 +19,7 @@ function rethrow(error) {
|
||||
export default Ember.Object.extend({
|
||||
|
||||
basePath(store, type) {
|
||||
if (ADMIN_MODELS.indexOf(type) !== -1) { return "/admin/"; }
|
||||
if (ADMIN_MODELS.indexOf(type.replace('_', '-')) !== -1) { return "/admin/"; }
|
||||
return "/";
|
||||
},
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ export default Ember.Component.extend({
|
||||
const slug = link.match(regexp)[1];
|
||||
return Discourse.Category.findSingleBySlug(slug);
|
||||
});
|
||||
self.set("categories", categories);
|
||||
Em.run.next(() => self.set("categories", categories));
|
||||
},
|
||||
template,
|
||||
transformComplete(category) {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'button',
|
||||
@ -7,17 +8,15 @@ export default Ember.Component.extend({
|
||||
|
||||
noText: Ember.computed.empty('translatedLabel'),
|
||||
|
||||
translatedTitle: function() {
|
||||
const title = this.get('title');
|
||||
return title ? I18n.t(title) : this.get('translatedLabel');
|
||||
}.property('title', 'translatedLabel'),
|
||||
@computed("title", "translatedLabel")
|
||||
translatedTitle(title, translatedLabel) {
|
||||
return title ? I18n.t(title) : translatedLabel;
|
||||
},
|
||||
|
||||
translatedLabel: function() {
|
||||
const label = this.get('label');
|
||||
if (label) {
|
||||
return I18n.t(this.get('label'));
|
||||
}
|
||||
}.property('label'),
|
||||
@computed("label")
|
||||
translatedLabel(label) {
|
||||
if (label) return I18n.t(label);
|
||||
},
|
||||
|
||||
render(buffer) {
|
||||
const label = this.get('translatedLabel'),
|
||||
|
||||
@ -1,23 +1,29 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['controls'],
|
||||
|
||||
notificationsPermission: function() {
|
||||
@computed
|
||||
notificationsPermission() {
|
||||
if (this.get('isNotSupported')) return '';
|
||||
|
||||
return Notification.permission;
|
||||
}.property(),
|
||||
},
|
||||
|
||||
notificationsDisabled: function(_, value) {
|
||||
if (arguments.length > 1) {
|
||||
@computed
|
||||
notificationsDisabled: {
|
||||
set(value) {
|
||||
localStorage.setItem('notifications-disabled', value);
|
||||
return localStorage.getItem('notifications-disabled');
|
||||
},
|
||||
get() {
|
||||
return localStorage.getItem('notifications-disabled');
|
||||
}
|
||||
return localStorage.getItem('notifications-disabled');
|
||||
}.property(),
|
||||
},
|
||||
|
||||
|
||||
isNotSupported: function() {
|
||||
return !window['Notification'];
|
||||
}.property(),
|
||||
@computed
|
||||
isNotSupported() {
|
||||
return typeof window.Notification === "undefined";
|
||||
},
|
||||
|
||||
isDefaultPermission: function() {
|
||||
if (this.get('isNotSupported')) return false;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
|
||||
import { categoryBadgeHTML } from 'discourse/helpers/category-link';
|
||||
|
||||
@ -53,7 +54,7 @@ export default buildCategoryPanel('general', {
|
||||
|
||||
actions: {
|
||||
showCategoryTopic() {
|
||||
Discourse.URL.routeTo(this.get('category.topic_url'));
|
||||
DiscourseURL.routeTo(this.get('category.topic_url'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
|
||||
const TopicCategoryComponent = Ember.Component.extend({
|
||||
needsSecondRow: Ember.computed.gt('secondRowItems.length', 0),
|
||||
secondRowItems: function() { return []; }.property(),
|
||||
@ -10,7 +12,7 @@ const TopicCategoryComponent = Ember.Component.extend({
|
||||
jumpToTopPost() {
|
||||
const topic = this.get('topic');
|
||||
if (topic) {
|
||||
Discourse.URL.routeTo(topic.get('firstPostUrl'));
|
||||
DiscourseURL.routeTo(topic.get('firstPostUrl'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
@ -26,7 +27,7 @@ export default Ember.Component.extend({
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
Discourse.URL.routeTo('/');
|
||||
DiscourseURL.routeTo('/');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'ul',
|
||||
classNameBindings: [':nav', ':nav-pills'],
|
||||
@ -6,8 +8,8 @@ export default Ember.Component.extend({
|
||||
const filterMode = this.get('filterMode'),
|
||||
navItems = this.get('navItems');
|
||||
|
||||
var item = navItems.find(function(item){
|
||||
return item.get('filterMode').indexOf(filterMode) === 0;
|
||||
var item = navItems.find(function(i){
|
||||
return i.get('filterMode').indexOf(filterMode) === 0;
|
||||
});
|
||||
|
||||
return item || navItems[0];
|
||||
@ -24,7 +26,7 @@ export default Ember.Component.extend({
|
||||
this.set('expanded',false);
|
||||
}
|
||||
$(window).off('click.navigation-bar');
|
||||
Discourse.URL.appEvents.off('dom:clean', this, this.ensureDropClosed);
|
||||
DiscourseURL.appEvents.off('dom:clean', this, this.ensureDropClosed);
|
||||
},
|
||||
|
||||
actions: {
|
||||
@ -33,7 +35,7 @@ export default Ember.Component.extend({
|
||||
var self = this;
|
||||
if (this.get('expanded')) {
|
||||
|
||||
Discourse.URL.appEvents.on('dom:clean', this, this.ensureDropClosed);
|
||||
DiscourseURL.appEvents.on('dom:clean', this, this.ensureDropClosed);
|
||||
|
||||
Em.run.next(function() {
|
||||
|
||||
|
||||
@ -45,8 +45,8 @@ export default Ember.Component.extend({
|
||||
this.rerender();
|
||||
});
|
||||
|
||||
on('th.sortable', function(e){
|
||||
this.sendAction('changeSort', e.data('sort-order'));
|
||||
on('th.sortable', function(e2){
|
||||
this.sendAction('changeSort', e2.data('sort-order'));
|
||||
this.rerender();
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
|
||||
export default DiscourseController.extend(ModalFunctionality, {
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
uploadedAvatarTemplate: null,
|
||||
saveDisabled: Em.computed.alias("uploading"),
|
||||
hasUploadedAvatar: Em.computed.or('uploadedAvatarTemplate', 'custom_avatar_upload_id'),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
import UserBadge from 'discourse/models/user-badge';
|
||||
|
||||
export default ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
noMoreBadges: false,
|
||||
userBadges: null,
|
||||
needs: ["application"],
|
||||
@ -10,7 +10,7 @@ export default ObjectController.extend({
|
||||
const self = this;
|
||||
const userBadges = this.get('userBadges');
|
||||
|
||||
Discourse.UserBadge.findByBadgeId(this.get('model.id'), {
|
||||
UserBadge.findByBadgeId(this.get('model.id'), {
|
||||
offset: userBadges.length
|
||||
}).then(function(result) {
|
||||
userBadges.pushObjects(result);
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
|
||||
// Modal related to changing the ownership of posts
|
||||
export default Ember.Controller.extend(Presence, SelectedPostsCount, ModalFunctionality, {
|
||||
export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, {
|
||||
needs: ['topic'],
|
||||
|
||||
topicController: Em.computed.alias('controllers.topic'),
|
||||
@ -13,7 +13,7 @@ export default Ember.Controller.extend(Presence, SelectedPostsCount, ModalFuncti
|
||||
|
||||
buttonDisabled: function() {
|
||||
if (this.get('saving')) return true;
|
||||
return this.blank('new_user');
|
||||
return Ember.isEmpty(this.get('new_user'));
|
||||
}.property('saving', 'new_user'),
|
||||
|
||||
buttonTitle: function() {
|
||||
@ -43,7 +43,7 @@ export default Ember.Controller.extend(Presence, SelectedPostsCount, ModalFuncti
|
||||
// success
|
||||
self.send('closeModal');
|
||||
self.get('topicController').send('toggleMultiSelect');
|
||||
Em.run.next(function() { Discourse.URL.routeTo(result.url); });
|
||||
Em.run.next(function() { DiscourseURL.routeTo(result.url); });
|
||||
}, function() {
|
||||
// failure
|
||||
self.flash(I18n.t('topic.change_owner.error'), 'alert-error');
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
// Modal related to changing the timestamp of posts
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
needs: ['topic'],
|
||||
|
||||
topicController: Em.computed.alias('controllers.topic'),
|
||||
saving: false,
|
||||
date: '',
|
||||
time: '',
|
||||
|
||||
@computed('saving')
|
||||
buttonTitle(saving) {
|
||||
return saving ? I18n.t('saving') : I18n.t('topic.change_timestamp.action');
|
||||
},
|
||||
|
||||
@computed('date', 'time')
|
||||
createdAt(date, time) {
|
||||
return moment(date + ' ' + time, 'YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
|
||||
@computed('createdAt')
|
||||
validTimestamp(createdAt) {
|
||||
return moment().diff(createdAt, 'minutes') < 0;
|
||||
},
|
||||
|
||||
@computed('saving', 'date', 'validTimestamp')
|
||||
buttonDisabled() {
|
||||
if (this.get('saving') || this.get('validTimestamp')) return true;
|
||||
return Ember.isEmpty(this.get('date'));
|
||||
},
|
||||
|
||||
onShow: function() {
|
||||
this.setProperties({
|
||||
date: moment().format('YYYY-MM-DD')
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
changeTimestamp: function() {
|
||||
this.set('saving', true);
|
||||
const self = this;
|
||||
|
||||
Discourse.Topic.changeTimestamp(
|
||||
this.get('topicController.model.id'),
|
||||
this.get('createdAt').unix()
|
||||
).then(function() {
|
||||
self.send('closeModal');
|
||||
self.setProperties({ date: '', time: '', saving: false });
|
||||
}).catch(function() {
|
||||
self.flash(I18n.t('topic.change_timestamp.error'), 'alert-error');
|
||||
self.set('saving', false);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,7 +1,9 @@
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
import Quote from 'discourse/lib/quote';
|
||||
import Draft from 'discourse/models/draft';
|
||||
|
||||
export default Ember.ObjectController.extend(Presence, {
|
||||
export default Ember.Controller.extend({
|
||||
needs: ['modal', 'topic', 'composer-messages', 'application'],
|
||||
|
||||
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY),
|
||||
@ -72,7 +74,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
const composer = this;
|
||||
|
||||
return this.store.find('post', postId).then(function(post) {
|
||||
const quote = Discourse.Quote.build(post, post.get("raw"), {raw: true, full: true});
|
||||
const quote = Quote.build(post, post.get("raw"), {raw: true, full: true});
|
||||
composer.appendBlockAtCursor(quote);
|
||||
composer.set('model.loading', false);
|
||||
});
|
||||
@ -149,7 +151,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
this.closeAutocomplete();
|
||||
switch (this.get('model.composeState')) {
|
||||
case Discourse.Composer.OPEN:
|
||||
if (this.blank('model.reply') && this.blank('model.title')) {
|
||||
if (Ember.isEmpty(this.get('model.reply')) && Ember.isEmpty(this.get('model.title'))) {
|
||||
this.close();
|
||||
} else {
|
||||
this.shrink();
|
||||
@ -262,7 +264,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
if (!composer.get('replyingToTopic') || !disableJumpReply) {
|
||||
const post = result.target;
|
||||
if (post && !staged) {
|
||||
Discourse.URL.routeTo(post.get('url'));
|
||||
DiscourseURL.routeTo(post.get('url'));
|
||||
}
|
||||
}
|
||||
}).catch(function(error) {
|
||||
@ -278,7 +280,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
Em.run.schedule('afterRender', function() {
|
||||
if (staged && !disableJumpReply) {
|
||||
const postNumber = staged.get('post_number');
|
||||
Discourse.URL.jumpToPost(postNumber, { skipIfOnScreen: true });
|
||||
DiscourseURL.jumpToPost(postNumber, { skipIfOnScreen: true });
|
||||
self.appEvents.trigger('post:highlight', postNumber);
|
||||
}
|
||||
});
|
||||
@ -396,7 +398,8 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
|
||||
// If we're already open, we don't have to do anything
|
||||
if (composerModel.get('composeState') === Discourse.Composer.OPEN &&
|
||||
composerModel.get('draftKey') === opts.draftKey) {
|
||||
composerModel.get('draftKey') === opts.draftKey &&
|
||||
composerModel.get('action') === opts.action ) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
@ -404,7 +407,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
if (composerModel.get('composeState') === Discourse.Composer.DRAFT &&
|
||||
composerModel.get('draftKey') === opts.draftKey) {
|
||||
composerModel.set('composeState', Discourse.Composer.OPEN);
|
||||
return resolve();
|
||||
if (composerModel.get('action') === opts.action) return resolve();
|
||||
}
|
||||
|
||||
// If it's a different draft, cancel it and try opening again.
|
||||
@ -415,7 +418,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
|
||||
// we need a draft sequence for the composer to work
|
||||
if (opts.draftSequence === undefined) {
|
||||
return Discourse.Draft.get(opts.draftKey).then(function(data) {
|
||||
return Draft.get(opts.draftKey).then(function(data) {
|
||||
opts.draftSequence = data.draft_sequence;
|
||||
opts.draft = data.draft;
|
||||
self._setModel(composerModel, opts);
|
||||
@ -477,7 +480,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
|
||||
// View a new reply we've made
|
||||
viewNewReply() {
|
||||
Discourse.URL.routeTo(this.get('model.createdPost.url'));
|
||||
DiscourseURL.routeTo(this.get('model.createdPost.url'));
|
||||
this.close();
|
||||
return false;
|
||||
},
|
||||
@ -485,7 +488,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
destroyDraft() {
|
||||
const key = this.get('model.draftKey');
|
||||
if (key) {
|
||||
Discourse.Draft.clear(key, this.get('model.draftSequence'));
|
||||
Draft.clear(key, this.get('model.draftSequence'));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
|
||||
export default Ember.Controller.extend(Presence);
|
||||
@ -1,8 +1,8 @@
|
||||
import debounce from 'discourse/lib/debounce';
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
|
||||
export default DiscourseController.extend(ModalFunctionality, {
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
needs: ['login'],
|
||||
|
||||
uniqueUsernameValidation: null,
|
||||
@ -65,7 +65,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
usernameRequired: Ember.computed.not('authOptions.omit_username'),
|
||||
|
||||
passwordRequired: function() {
|
||||
return this.blank('authOptions.auth_provider');
|
||||
return Ember.isEmpty(this.get('authOptions.auth_provider'));
|
||||
}.property('authOptions.auth_provider'),
|
||||
|
||||
passwordInstructions: function() {
|
||||
@ -82,7 +82,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
this.fetchConfirmationValue();
|
||||
}
|
||||
|
||||
if (Discourse.SiteSettings.full_name_required && this.blank('accountName')) {
|
||||
if (Discourse.SiteSettings.full_name_required && Ember.isEmpty(this.get('accountName'))) {
|
||||
return Discourse.InputValidation.create({ failed: true });
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
emailValidation: function() {
|
||||
// If blank, fail without a reason
|
||||
let email;
|
||||
if (this.blank('accountEmail')) {
|
||||
if (Ember.isEmpty(this.get('accountEmail'))) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true
|
||||
});
|
||||
@ -143,7 +143,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
}
|
||||
this.set('prefilledUsername', null);
|
||||
}
|
||||
if (this.get('emailValidation.ok') && (this.blank('accountUsername') || this.get('authOptions.email'))) {
|
||||
if (this.get('emailValidation.ok') && (Ember.isEmpty(this.get('accountUsername')) || this.get('authOptions.email'))) {
|
||||
// If email is valid and username has not been entered yet,
|
||||
// or email and username were filled automatically by 3rd parth auth,
|
||||
// then look for a registered username that matches the email.
|
||||
@ -151,10 +151,10 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
}
|
||||
}.observes('emailValidation', 'accountEmail'),
|
||||
|
||||
fetchExistingUsername: Discourse.debounce(function() {
|
||||
fetchExistingUsername: debounce(function() {
|
||||
const self = this;
|
||||
Discourse.User.checkUsername(null, this.get('accountEmail')).then(function(result) {
|
||||
if (result.suggestion && (self.blank('accountUsername') || self.get('accountUsername') === self.get('authOptions.username'))) {
|
||||
if (result.suggestion && (Ember.isEmpty(self.get('accountUsername')) || self.get('accountUsername') === self.get('authOptions.username'))) {
|
||||
self.set('accountUsername', result.suggestion);
|
||||
self.set('prefilledUsername', result.suggestion);
|
||||
}
|
||||
@ -193,7 +193,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
}
|
||||
|
||||
// If blank, fail without a reason
|
||||
if (this.blank('accountUsername')) {
|
||||
if (Ember.isEmpty(this.get('accountUsername'))) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true
|
||||
});
|
||||
@ -224,10 +224,10 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
}.property('accountUsername'),
|
||||
|
||||
shouldCheckUsernameMatch: function() {
|
||||
return !this.blank('accountUsername') && this.get('accountUsername').length >= this.get('minUsernameLength');
|
||||
return !Ember.isEmpty(this.get('accountUsername')) && this.get('accountUsername').length >= this.get('minUsernameLength');
|
||||
},
|
||||
|
||||
checkUsernameAvailability: Discourse.debounce(function() {
|
||||
checkUsernameAvailability: debounce(function() {
|
||||
const _this = this;
|
||||
if (this.shouldCheckUsernameMatch()) {
|
||||
return Discourse.User.checkUsername(this.get('accountUsername'), this.get('accountEmail')).then(function(result) {
|
||||
@ -295,7 +295,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
|
||||
// If blank, fail without a reason
|
||||
const password = this.get("accountPassword");
|
||||
if (this.blank('accountPassword')) {
|
||||
if (Ember.isEmpty(this.get('accountPassword'))) {
|
||||
return Discourse.InputValidation.create({ failed: true });
|
||||
}
|
||||
|
||||
@ -314,14 +314,14 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.blank('accountUsername') && this.get('accountPassword') === this.get('accountUsername')) {
|
||||
if (!Ember.isEmpty(this.get('accountUsername')) && this.get('accountPassword') === this.get('accountUsername')) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: I18n.t('user.password.same_as_username')
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.blank('accountEmail') && this.get('accountPassword') === this.get('accountEmail')) {
|
||||
if (!Ember.isEmpty(this.get('accountEmail')) && this.get('accountPassword') === this.get('accountEmail')) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: I18n.t('user.password.same_as_email')
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
|
||||
// Just add query params here to have them automatically passed to topic list filters.
|
||||
export var queryParams = {
|
||||
order: { replace: true, refreshModel: true },
|
||||
@ -22,4 +20,4 @@ controllerOpts.queryParams.forEach(function(p) {
|
||||
controllerOpts[p] = Em.computed.alias('controllers.discovery/topics.' + p);
|
||||
});
|
||||
|
||||
export default DiscourseController.extend(controllerOpts);
|
||||
export default Ember.Controller.extend(controllerOpts);
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
needs: ['navigation/category', 'discovery/topics', 'application'],
|
||||
loading: false,
|
||||
|
||||
@ -22,7 +24,7 @@ export default Ember.ObjectController.extend({
|
||||
|
||||
actions: {
|
||||
changePeriod(p) {
|
||||
Discourse.URL.routeTo(this.showMoreUrl(p));
|
||||
DiscourseURL.routeTo(this.showMoreUrl(p));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -95,6 +95,10 @@ const controllerOpts = {
|
||||
return this.get('model.filter') === 'new' && this.get('model.topics.length') > 0;
|
||||
}.property('model.filter', 'model.topics.length'),
|
||||
|
||||
tooManyTracked: function(){
|
||||
return Discourse.TopicTrackingState.current().tooManyTracked();
|
||||
}.property(),
|
||||
|
||||
showDismissAtTop: function() {
|
||||
return (this.isFilterPage(this.get('model.filter'), 'new') ||
|
||||
this.isFilterPage(this.get('model.filter'), 'unread')) &&
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user