Version bump
This commit is contained in:
commit
fbd5325031
@ -145,7 +145,7 @@ GEM
|
||||
thor (~> 0.15)
|
||||
libv8 (3.16.14.7)
|
||||
listen (0.7.3)
|
||||
logster (0.8.4.1.pre)
|
||||
logster (0.8.4.5.pre)
|
||||
lru_redux (1.1.0)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
import CustomizationBase from 'admin/adapters/customization-base';
|
||||
export default CustomizationBase;
|
||||
2
app/assets/javascripts/admin/adapters/site-text.js.es6
Normal file
2
app/assets/javascripts/admin/adapters/site-text.js.es6
Normal file
@ -0,0 +1,2 @@
|
||||
import CustomizationBase from 'admin/adapters/customization-base';
|
||||
export default CustomizationBase;
|
||||
2
app/assets/javascripts/admin/adapters/user-field.js.es6
Normal file
2
app/assets/javascripts/admin/adapters/user-field.js.es6
Normal file
@ -0,0 +1,2 @@
|
||||
import CustomizationBase from 'admin/adapters/customization-base';
|
||||
export default CustomizationBase;
|
||||
@ -1,13 +1,14 @@
|
||||
import { bufferedProperty } from 'discourse/mixins/buffered-content';
|
||||
import UserField from 'admin/models/user-field';
|
||||
import { bufferedProperty } from 'discourse/mixins/buffered-content';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.Component.extend(bufferedProperty('userField'), {
|
||||
editing: Ember.computed.empty('userField.id'),
|
||||
classNameBindings: [':user-field'],
|
||||
|
||||
cantMoveUp: Discourse.computed.propertyEqual('userField', 'firstField'),
|
||||
cantMoveDown: Discourse.computed.propertyEqual('userField', 'lastField'),
|
||||
cantMoveUp: propertyEqual('userField', 'firstField'),
|
||||
cantMoveDown: propertyEqual('userField', 'lastField'),
|
||||
|
||||
userFieldsDescription: function() {
|
||||
return I18n.t('admin.user_fields.description');
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
export default Ember.Component.extend({
|
||||
router: function() {
|
||||
return this.container.lookup('router:main');
|
||||
}.property(),
|
||||
|
||||
active: function() {
|
||||
const id = this.get('customization.id');
|
||||
return this.get('router.url').indexOf(`/customize/css_html/${id}/css`) !== -1;
|
||||
}.property('router.url', 'customization.id')
|
||||
});
|
||||
@ -0,0 +1,9 @@
|
||||
export default Ember.Component.extend({
|
||||
classNames: ["item"],
|
||||
|
||||
actions: {
|
||||
remove() {
|
||||
this.sendAction('removeAction', this.get('member'));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,20 +1,21 @@
|
||||
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';
|
||||
|
||||
const CustomTypes = ['bool', 'enum', 'list', 'url_list', 'host_list'];
|
||||
|
||||
export default Ember.Component.extend(BufferedContent, ScrollTop, {
|
||||
classNameBindings: [':row', ':setting', 'setting.overridden', 'typeClass'],
|
||||
content: Ember.computed.alias('setting'),
|
||||
dirty: Discourse.computed.propertyNotEqual('buffered.value', 'setting.value'),
|
||||
dirty: propertyNotEqual('buffered.value', 'setting.value'),
|
||||
validationMessage: null,
|
||||
|
||||
preview: function() {
|
||||
const preview = this.get('setting.preview');
|
||||
if (preview) {
|
||||
return new Handlebars.SafeString("<div class='preview'>" +
|
||||
preview.replace("{{value}}", this.get('buffered.value')) +
|
||||
preview.replace(/\{\{value\}\}/g, this.get('buffered.value')) +
|
||||
"</div>");
|
||||
}
|
||||
}.property('buffered.value'),
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
export default Ember.ArrayController.extend({
|
||||
needs: ["adminBackups"],
|
||||
status: Em.computed.alias("controllers.adminBackups"),
|
||||
isOperationRunning: Em.computed.alias("status.isOperationRunning"),
|
||||
restoreDisabled: Em.computed.alias("status.restoreDisabled"),
|
||||
isOperationRunning: Ember.computed.alias("status.model.isOperationRunning"),
|
||||
restoreDisabled: Ember.computed.alias("status.model.restoreDisabled"),
|
||||
|
||||
uploadLabel: function() { return I18n.t("admin.backups.upload.label"); }.property(),
|
||||
|
||||
restoreTitle: function() {
|
||||
if (!this.get('status.allowRestore')) {
|
||||
if (!this.get('status.model.allowRestore')) {
|
||||
return "admin.backups.operations.restore.is_disabled";
|
||||
} else if (this.get("status.isOperationRunning")) {
|
||||
} else if (this.get("status.model.isOperationRunning")) {
|
||||
return "admin.backups.operations.is_running";
|
||||
} else {
|
||||
return "admin.backups.operations.restore.title";
|
||||
}
|
||||
}.property("status.{allowRestore,isOperationRunning}"),
|
||||
}.property("status.model.{allowRestore,isOperationRunning}"),
|
||||
|
||||
actions: {
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
noOperationIsRunning: Em.computed.not("isOperationRunning"),
|
||||
rollbackEnabled: Em.computed.and("canRollback", "restoreEnabled", "noOperationIsRunning"),
|
||||
rollbackDisabled: Em.computed.not("rollbackEnabled")
|
||||
noOperationIsRunning: Ember.computed.not("model.isOperationRunning"),
|
||||
rollbackEnabled: Ember.computed.and("model.canRollback", "model.restoreEnabled", "noOperationIsRunning"),
|
||||
rollbackDisabled: Ember.computed.not("rollbackEnabled")
|
||||
});
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
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, {
|
||||
needs: ['admin-badges'],
|
||||
@ -12,7 +13,7 @@ export default Ember.ObjectController.extend(BufferedContent, {
|
||||
protectedSystemFields: Em.computed.alias('controllers.admin-badges.protectedSystemFields'),
|
||||
|
||||
readOnly: Ember.computed.alias('buffered.system'),
|
||||
showDisplayName: Discourse.computed.propertyNotEqual('name', 'displayName'),
|
||||
showDisplayName: propertyNotEqual('name', 'displayName'),
|
||||
canEditDescription: Em.computed.none('buffered.translatedDescription'),
|
||||
|
||||
_resetSaving: function() {
|
||||
|
||||
@ -1,13 +1,4 @@
|
||||
/**
|
||||
This controller supports interface for creating custom CSS skins in Discourse.
|
||||
|
||||
@class AdminCustomizeColorsController
|
||||
@extends Ember.Controller
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
export default Ember.ArrayController.extend({
|
||||
|
||||
onlyOverridden: false,
|
||||
|
||||
baseColorScheme: function() {
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
import { url } from 'discourse/lib/computed';
|
||||
|
||||
const sections = ['css', 'header', 'top', 'footer', 'head-tag', 'body-tag',
|
||||
'mobile-css', 'mobile-header', 'mobile-top', 'mobile-footer',
|
||||
'embedded-css'];
|
||||
|
||||
const activeSections = {};
|
||||
sections.forEach(function(s) {
|
||||
activeSections[Ember.String.camelize(s) + "Active"] = Ember.computed.equal('section', s);
|
||||
});
|
||||
|
||||
|
||||
export default Ember.Controller.extend(activeSections, {
|
||||
maximized: false,
|
||||
section: null,
|
||||
|
||||
previewUrl: url("model.key", "/?preview-style=%@"),
|
||||
downloadUrl: url('model.id', '/admin/site_customizations/%@'),
|
||||
|
||||
mobile: function() {
|
||||
return this.get('section').indexOf('mobile-') === 0;
|
||||
}.property('section'),
|
||||
|
||||
maximizeIcon: function() {
|
||||
return this.get('maximized') ? 'compress' : 'expand';
|
||||
}.property('maximized'),
|
||||
|
||||
saveButtonText: function() {
|
||||
return this.get('model.isSaving') ? I18n.t('saving') : I18n.t('admin.customize.save');
|
||||
}.property('model.isSaving'),
|
||||
|
||||
saveDisabled: function() {
|
||||
return !this.get('model.changed') || this.get('model.isSaving');
|
||||
}.property('model.changed', 'model.isSaving'),
|
||||
|
||||
needs: ['adminCustomizeCssHtml'],
|
||||
|
||||
undoPreviewUrl: url('/?preview-style='),
|
||||
defaultStyleUrl: url('/?preview-style=default'),
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
this.get('model').saveChanges();
|
||||
},
|
||||
|
||||
destroy() {
|
||||
const self = this;
|
||||
return bootbox.confirm(I18n.t("admin.customize.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
|
||||
if (result) {
|
||||
const model = self.get('model');
|
||||
model.destroyRecord().then(function() {
|
||||
self.get('controllers.adminCustomizeCssHtml').get('model').removeObject(model);
|
||||
self.transitionToRoute('adminCustomizeCssHtml');
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
toggleMaximize: function() {
|
||||
this.toggleProperty('maximized');
|
||||
},
|
||||
|
||||
toggleMobile: function() {
|
||||
const section = this.get('section');
|
||||
|
||||
// Try to send to the same tab as before
|
||||
let dest;
|
||||
if (this.get('mobile')) {
|
||||
dest = section.replace('mobile-', '');
|
||||
if (sections.indexOf(dest) === -1) { dest = 'css'; }
|
||||
} else {
|
||||
dest = 'mobile-' + section;
|
||||
if (sections.indexOf(dest) === -1) { dest = 'mobile-css'; }
|
||||
}
|
||||
this.replaceRoute('adminCustomizeCssHtml.show', this.get('model.id'), dest);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,77 +0,0 @@
|
||||
import showModal from 'discourse/lib/show-modal';
|
||||
|
||||
/**
|
||||
This controller supports interface for creating custom CSS skins in Discourse.
|
||||
|
||||
@class AdminCustomizeCssHtmlController
|
||||
@extends Ember.Controller
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
export default Ember.ArrayController.extend({
|
||||
|
||||
undoPreviewUrl: function() {
|
||||
return Discourse.getURL("/?preview-style=");
|
||||
}.property(),
|
||||
|
||||
defaultStyleUrl: function() {
|
||||
return Discourse.getURL("/?preview-style=default");
|
||||
}.property(),
|
||||
|
||||
actions: {
|
||||
|
||||
/**
|
||||
Create a new customization style
|
||||
|
||||
@method newCustomization
|
||||
**/
|
||||
newCustomization: function() {
|
||||
var item = Discourse.SiteCustomization.create({name: I18n.t("admin.customize.new_style")});
|
||||
this.pushObject(item);
|
||||
this.set('selectedItem', item);
|
||||
},
|
||||
|
||||
importModal: function() {
|
||||
showModal('upload-customization');
|
||||
},
|
||||
|
||||
/**
|
||||
Select a given style
|
||||
|
||||
@method selectStyle
|
||||
@param {Discourse.SiteCustomization} style The style we are selecting
|
||||
**/
|
||||
selectStyle: function(style) {
|
||||
this.set('selectedItem', style);
|
||||
},
|
||||
|
||||
/**
|
||||
Save the current customization
|
||||
|
||||
@method save
|
||||
**/
|
||||
save: function() {
|
||||
this.get('selectedItem').save();
|
||||
},
|
||||
|
||||
/**
|
||||
Destroy the current customization
|
||||
|
||||
@method destroy
|
||||
**/
|
||||
destroy: function() {
|
||||
var _this = this;
|
||||
return bootbox.confirm(I18n.t("admin.customize.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
|
||||
var selected;
|
||||
if (result) {
|
||||
selected = _this.get('selectedItem');
|
||||
selected.destroy();
|
||||
_this.set('selectedItem', null);
|
||||
return _this.removeObject(selected);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,17 +1,12 @@
|
||||
/**
|
||||
This controller supports the default interface when you enter the admin section.
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
|
||||
@class AdminDashboardController
|
||||
@extends Ember.Controller
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
// This controller supports the default interface when you enter the admin section.
|
||||
export default Ember.Controller.extend({
|
||||
loading: true,
|
||||
versionCheck: null,
|
||||
problemsCheckMinutes: 1,
|
||||
|
||||
showVersionChecks: Discourse.computed.setting('version_checks'),
|
||||
showVersionChecks: setting('version_checks'),
|
||||
|
||||
foundProblems: function() {
|
||||
return(Discourse.User.currentProp('admin') && this.get('problems') && this.get('problems').length > 0);
|
||||
|
||||
@ -1,21 +1,22 @@
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
|
||||
export default Em.ObjectController.extend({
|
||||
needs: ['adminGroupsType'],
|
||||
disableSave: false,
|
||||
|
||||
currentPage: function() {
|
||||
if (this.get("user_count") === 0) { return 0; }
|
||||
return Math.floor(this.get("offset") / this.get("limit")) + 1;
|
||||
}.property("limit", "offset", "user_count"),
|
||||
if (this.get("model.user_count") === 0) { return 0; }
|
||||
return Math.floor(this.get("model.offset") / this.get("model.limit")) + 1;
|
||||
}.property("model.limit", "model.offset", "model.user_count"),
|
||||
|
||||
totalPages: function() {
|
||||
if (this.get("user_count") === 0) { return 0; }
|
||||
return Math.floor(this.get("user_count") / this.get("limit")) + 1;
|
||||
}.property("limit", "user_count"),
|
||||
if (this.get("model.user_count") === 0) { return 0; }
|
||||
return Math.floor(this.get("model.user_count") / this.get("model.limit")) + 1;
|
||||
}.property("model.limit", "model.user_count"),
|
||||
|
||||
showingFirst: Em.computed.lte("currentPage", 1),
|
||||
showingLast: Discourse.computed.propertyEqual("currentPage", "totalPages"),
|
||||
showingLast: propertyEqual("currentPage", "totalPages"),
|
||||
|
||||
aliasLevelOptions: function() {
|
||||
return [
|
||||
@ -31,7 +32,7 @@ export default Em.ObjectController.extend({
|
||||
if (this.get("showingLast")) { return; }
|
||||
|
||||
const group = this.get("model"),
|
||||
offset = Math.min(group.get("offset") + group.get("limit"), group.get("user_count"));
|
||||
offset = Math.min(group.get("offset") + group.get("model.limit"), group.get("user_count"));
|
||||
|
||||
group.set("offset", offset);
|
||||
|
||||
@ -42,7 +43,7 @@ export default Em.ObjectController.extend({
|
||||
if (this.get("showingFirst")) { return; }
|
||||
|
||||
const group = this.get("model"),
|
||||
offset = Math.max(group.get("offset") - group.get("limit"), 0);
|
||||
offset = Math.max(group.get("offset") - group.get("model.limit"), 0);
|
||||
|
||||
group.set("offset", offset);
|
||||
|
||||
@ -51,7 +52,7 @@ export default Em.ObjectController.extend({
|
||||
|
||||
removeMember(member) {
|
||||
const self = this,
|
||||
message = I18n.t("admin.groups.delete_member_confirm", { username: member.get("username"), group: this.get("name") });
|
||||
message = I18n.t("admin.groups.delete_member_confirm", { username: member.get("username"), group: this.get("model.name") });
|
||||
return bootbox.confirm(message, I18n.t("no_value"), I18n.t("yes_value"), function(confirm) {
|
||||
if (confirm) {
|
||||
self.get("model").removeMember(member);
|
||||
@ -60,10 +61,9 @@ export default Em.ObjectController.extend({
|
||||
},
|
||||
|
||||
addMembers() {
|
||||
if (Em.isEmpty(this.get("usernames"))) { return; }
|
||||
this.get("model").addMembers(this.get("usernames"));
|
||||
// clear the user selector
|
||||
this.set("usernames", null);
|
||||
if (Em.isEmpty(this.get("model.usernames"))) { return; }
|
||||
this.get("model").addMembers(this.get("model.usernames")).catch(popupAjaxError);
|
||||
this.set("model.usernames", null);
|
||||
},
|
||||
|
||||
save() {
|
||||
|
||||
@ -1,20 +1,16 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
saving: false,
|
||||
export default Ember.Controller.extend({
|
||||
saved: false,
|
||||
|
||||
saveDisabled: function() {
|
||||
if (this.get('saving')) { return true; }
|
||||
if ((!this.get('allow_blank')) && Ember.isEmpty(this.get('value'))) { return true; }
|
||||
if (this.get('model.isSaving')) { return true; }
|
||||
if ((!this.get('allow_blank')) && Ember.isEmpty(this.get('model.value'))) { return true; }
|
||||
return false;
|
||||
}.property('saving', 'value'),
|
||||
}.property('model.iSaving', 'model.value'),
|
||||
|
||||
actions: {
|
||||
saveChanges: function() {
|
||||
var self = this;
|
||||
self.setProperties({saving: true, saved: false});
|
||||
self.get('model').save().then(function () {
|
||||
self.setProperties({saving: false, saved: true});
|
||||
});
|
||||
saveChanges() {
|
||||
const model = this.get('model');
|
||||
model.save(model.getProperties('value')).then(() => this.set('saved', true));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
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, {
|
||||
editingTitle: false,
|
||||
originalPrimaryGroupId: null,
|
||||
availableGroups: null,
|
||||
|
||||
showApproval: Discourse.computed.setting('must_approve_users'),
|
||||
showBadges: Discourse.computed.setting('enable_badges'),
|
||||
showApproval: setting('must_approve_users'),
|
||||
showBadges: setting('enable_badges'),
|
||||
|
||||
primaryGroupDirty: Discourse.computed.propertyNotEqual('originalPrimaryGroupId', 'model.primary_group_id'),
|
||||
primaryGroupDirty: propertyNotEqual('originalPrimaryGroupId', 'model.primary_group_id'),
|
||||
|
||||
automaticGroups: function() {
|
||||
return this.get("model.automaticGroups").map((g) => g.name).join(", ");
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { i18n } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.ArrayController.extend({
|
||||
query: null,
|
||||
showEmails: false,
|
||||
@ -9,7 +11,7 @@ export default Ember.ArrayController.extend({
|
||||
queryPending: Em.computed.equal('query', 'pending'),
|
||||
queryHasApproval: Em.computed.or('queryNew', 'queryPending'),
|
||||
showApproval: Em.computed.and('siteSettings.must_approve_users', 'queryHasApproval'),
|
||||
searchHint: Discourse.computed.i18n('search_hint'),
|
||||
searchHint: i18n('search_hint'),
|
||||
hasSelection: Em.computed.gt('selectedCount', 0),
|
||||
|
||||
selectedCount: function() {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { propertyNotEqual } from 'discourse/lib/computed';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
|
||||
const AdminUser = Discourse.User.extend({
|
||||
@ -144,7 +145,7 @@ const AdminUser = Discourse.User.extend({
|
||||
this.set('originalTrustLevel', this.get('trust_level'));
|
||||
},
|
||||
|
||||
dirty: Discourse.computed.propertyNotEqual('originalTrustLevel', 'trustLevel.id'),
|
||||
dirty: propertyNotEqual('originalTrustLevel', 'trustLevel.id'),
|
||||
|
||||
saveTrustLevel() {
|
||||
return Discourse.ajax("/admin/users/" + this.id + "/trust_level", {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import round from "discourse/lib/round";
|
||||
import { fmt } from 'discourse/lib/computed';
|
||||
|
||||
const Report = Discourse.Model.extend({
|
||||
reportUrl: Discourse.computed.fmt("type", "/admin/reports/%@"),
|
||||
reportUrl: fmt("type", "/admin/reports/%@"),
|
||||
|
||||
valueAt(numDaysAgo) {
|
||||
if (this.data) {
|
||||
@ -26,7 +27,7 @@ const Report = Discourse.Model.extend({
|
||||
count++;
|
||||
}
|
||||
});
|
||||
if (this.get("method") === "average") { sum /= count; }
|
||||
if (this.get("method") === "average" && count > 0) { sum /= count; }
|
||||
return round(sum, -2);
|
||||
}
|
||||
},
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
import RestModel from 'discourse/models/rest';
|
||||
|
||||
const trackedProperties = [
|
||||
'enabled', 'name', 'stylesheet', 'header', 'top', 'footer', 'mobile_stylesheet',
|
||||
'mobile_header', 'mobile_top', 'mobile_footer', 'head_tag', 'body_tag', 'embedded_css'
|
||||
];
|
||||
|
||||
function changed() {
|
||||
const originals = this.get('originals');
|
||||
if (!originals) { return false; }
|
||||
return _.some(trackedProperties, (p) => originals[p] !== this.get(p));
|
||||
}
|
||||
|
||||
const SiteCustomization = RestModel.extend({
|
||||
description: function() {
|
||||
return "" + this.name + (this.enabled ? ' (*)' : '');
|
||||
}.property('selected', 'name', 'enabled'),
|
||||
|
||||
changed: changed.property.apply(changed, trackedProperties.concat('originals')),
|
||||
|
||||
startTrackingChanges: function() {
|
||||
this.set('originals', this.getProperties(trackedProperties));
|
||||
}.on('init'),
|
||||
|
||||
saveChanges() {
|
||||
return this.save(this.getProperties(trackedProperties)).then(() => this.startTrackingChanges());
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default SiteCustomization;
|
||||
@ -0,0 +1,2 @@
|
||||
import RestModel from 'discourse/models/rest';
|
||||
export default RestModel.extend();
|
||||
8
app/assets/javascripts/admin/models/site-text.js.es6
Normal file
8
app/assets/javascripts/admin/models/site-text.js.es6
Normal file
@ -0,0 +1,8 @@
|
||||
import RestModel from 'discourse/models/rest';
|
||||
|
||||
export default RestModel.extend({
|
||||
markdown: Em.computed.equal('format', 'markdown'),
|
||||
plainText: Em.computed.equal('format', 'plain'),
|
||||
html: Em.computed.equal('format', 'html'),
|
||||
css: Em.computed.equal('format', 'css'),
|
||||
});
|
||||
@ -1,116 +0,0 @@
|
||||
/**
|
||||
Our data model for interacting with site customizations.
|
||||
|
||||
@class SiteCustomization
|
||||
@extends Discourse.Model
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.SiteCustomization = Discourse.Model.extend({
|
||||
trackedProperties: [
|
||||
'enabled', 'name',
|
||||
'stylesheet', 'header', 'top', 'footer',
|
||||
'mobile_stylesheet', 'mobile_header', 'mobile_top', 'mobile_footer',
|
||||
'head_tag', 'body_tag'
|
||||
],
|
||||
|
||||
description: function() {
|
||||
return "" + this.name + (this.enabled ? ' (*)' : '');
|
||||
}.property('selected', 'name', 'enabled'),
|
||||
|
||||
changed: function() {
|
||||
var self = this;
|
||||
|
||||
if (!this.originals) { return false; }
|
||||
|
||||
var changed = _.some(this.trackedProperties, function (p) {
|
||||
return self.originals[p] !== self.get(p);
|
||||
});
|
||||
|
||||
if (changed) { this.set('savingStatus', ''); }
|
||||
|
||||
return changed;
|
||||
}.property('enabled', 'name', 'originals',
|
||||
'stylesheet', 'header', 'top', 'footer',
|
||||
'mobile_stylesheet', 'mobile_header', 'mobile_top', 'mobile_footer',
|
||||
'head_tag', 'body_tag'),
|
||||
|
||||
startTrackingChanges: function() {
|
||||
var self = this;
|
||||
var originals = {};
|
||||
_.each(this.trackedProperties, function (prop) {
|
||||
originals[prop] = self.get(prop);
|
||||
});
|
||||
this.set('originals', originals);
|
||||
}.on('init'),
|
||||
|
||||
previewUrl: function() { return Discourse.getURL("/?preview-style=" + this.get('key')); }.property('key'),
|
||||
disableSave: function() { return !this.get('changed') || this.get('saving'); }.property('changed'),
|
||||
|
||||
save: function() {
|
||||
this.set('savingStatus', I18n.t('saving'));
|
||||
this.set('saving',true);
|
||||
|
||||
var data = {
|
||||
name: this.name,
|
||||
enabled: this.enabled,
|
||||
stylesheet: this.stylesheet,
|
||||
header: this.header,
|
||||
top: this.top,
|
||||
footer: this.footer,
|
||||
mobile_stylesheet: this.mobile_stylesheet,
|
||||
mobile_header: this.mobile_header,
|
||||
mobile_top: this.mobile_top,
|
||||
mobile_footer: this.mobile_footer,
|
||||
head_tag: this.head_tag,
|
||||
body_tag: this.body_tag
|
||||
};
|
||||
|
||||
var siteCustomization = this;
|
||||
return Discourse.ajax("/admin/site_customizations" + (this.id ? '/' + this.id : ''), {
|
||||
data: { site_customization: data },
|
||||
type: this.id ? 'PUT' : 'POST'
|
||||
}).then(function (result) {
|
||||
if (!siteCustomization.id) {
|
||||
siteCustomization.set('id', result.id);
|
||||
siteCustomization.set('key', result.key);
|
||||
}
|
||||
siteCustomization.set('savingStatus', I18n.t('saved'));
|
||||
siteCustomization.set('saving',false);
|
||||
siteCustomization.startTrackingChanges();
|
||||
return siteCustomization;
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (!this.id) return;
|
||||
return Discourse.ajax("/admin/site_customizations/" + this.id, { type: 'DELETE' });
|
||||
},
|
||||
|
||||
download_url: function() {
|
||||
return Discourse.getURL('/admin/site_customizations/' + this.id);
|
||||
}.property('id')
|
||||
});
|
||||
|
||||
var SiteCustomizations = Ember.ArrayProxy.extend({
|
||||
selectedItemChanged: function() {
|
||||
var selected = this.get('selectedItem');
|
||||
_.each(this.get('content'), function (i) {
|
||||
i.set('selected', selected === i);
|
||||
});
|
||||
}.observes('selectedItem')
|
||||
});
|
||||
|
||||
Discourse.SiteCustomization.reopenClass({
|
||||
findAll: function() {
|
||||
return Discourse.ajax("/admin/site_customizations").then(function (data) {
|
||||
var content = [];
|
||||
if (data) {
|
||||
content = data.site_customizations.map(function(c) {
|
||||
return Discourse.SiteCustomization.create(c);
|
||||
});
|
||||
}
|
||||
return SiteCustomizations.create({ content: content });
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,21 +0,0 @@
|
||||
Discourse.SiteText = Discourse.Model.extend({
|
||||
markdown: Em.computed.equal('format', 'markdown'),
|
||||
plainText: Em.computed.equal('format', 'plain'),
|
||||
html: Em.computed.equal('format', 'html'),
|
||||
css: Em.computed.equal('format', 'css'),
|
||||
|
||||
save: function() {
|
||||
return Discourse.ajax("/admin/customize/site_text/" + this.get('text_type'), {
|
||||
type: 'PUT',
|
||||
data: {value: this.get('value')}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Discourse.SiteText.reopenClass({
|
||||
find: function(type) {
|
||||
return Discourse.ajax("/admin/customize/site_text/" + type).then(function (data) {
|
||||
return Discourse.SiteText.create(data.site_text);
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,11 +0,0 @@
|
||||
Discourse.SiteTextType = Discourse.Model.extend();
|
||||
|
||||
Discourse.SiteTextType.reopenClass({
|
||||
findAll: function() {
|
||||
return Discourse.ajax("/admin/customize/site_text_types").then(function(data) {
|
||||
return data.map(function(ct) {
|
||||
return Discourse.SiteTextType.create(ct);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,9 +1,10 @@
|
||||
import RestModel from 'discourse/models/rest';
|
||||
import { i18n } from 'discourse/lib/computed';
|
||||
|
||||
const UserField = RestModel.extend();
|
||||
|
||||
const UserFieldType = Ember.Object.extend({
|
||||
name: Discourse.computed.i18n('id', 'admin.user_fields.field_types.%@')
|
||||
name: i18n('id', 'admin.user_fields.field_types.%@')
|
||||
});
|
||||
|
||||
UserField.reopenClass({
|
||||
|
||||
5
app/assets/javascripts/admin/routes/admin-api.js.es6
Normal file
5
app/assets/javascripts/admin/routes/admin-api.js.es6
Normal file
@ -0,0 +1,5 @@
|
||||
export default Ember.Route.extend({
|
||||
model() {
|
||||
return Discourse.ApiKey.find();
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,5 @@
|
||||
export default Ember.Route.extend({
|
||||
model() {
|
||||
return Discourse.Backup.find();
|
||||
}
|
||||
});
|
||||
@ -1,15 +1,15 @@
|
||||
Discourse.AdminBackupsLogsRoute = Discourse.Route.extend({
|
||||
export default Ember.Route.extend({
|
||||
|
||||
// since the logs are pushed via the message bus
|
||||
// we only want to preload them (hence the beforeModel hook)
|
||||
beforeModel: function() {
|
||||
var logsController = this.controllerFor("adminBackupsLogs");
|
||||
beforeModel() {
|
||||
const logsController = this.controllerFor("adminBackupsLogs");
|
||||
// preload the logs if any
|
||||
PreloadStore.getAndRemove("logs").then(function (preloadedLogs) {
|
||||
if (preloadedLogs && preloadedLogs.length) {
|
||||
// we need to filter out message like: "[SUCCESS]"
|
||||
// and convert POJOs to Ember Objects
|
||||
var logs = _.chain(preloadedLogs)
|
||||
const logs = _.chain(preloadedLogs)
|
||||
.reject(function (log) { return log.message.length === 0 || log.message[0] === "["; })
|
||||
.map(function (log) { return Em.Object.create(log); })
|
||||
.value();
|
||||
@ -18,6 +18,6 @@ Discourse.AdminBackupsLogsRoute = Discourse.Route.extend({
|
||||
});
|
||||
},
|
||||
|
||||
setupController: function() { /* prevent default behavior */ }
|
||||
setupController() { /* prevent default behavior */ }
|
||||
|
||||
});
|
||||
@ -10,14 +10,14 @@ export default Discourse.Route.extend({
|
||||
|
||||
_processLogMessage(log) {
|
||||
if (log.message === "[STARTED]") {
|
||||
this.controllerFor("adminBackups").set("isOperationRunning", true);
|
||||
this.controllerFor("adminBackups").set("model.isOperationRunning", true);
|
||||
this.controllerFor("adminBackupsLogs").clear();
|
||||
} else if (log.message === "[FAILED]") {
|
||||
this.controllerFor("adminBackups").set("isOperationRunning", false);
|
||||
this.controllerFor("adminBackups").set("model.isOperationRunning", false);
|
||||
bootbox.alert(I18n.t("admin.backups.operations.failed", { operation: log.operation }));
|
||||
} else if (log.message === "[SUCCESS]") {
|
||||
Discourse.User.currentProp("hideReadOnlyAlert", false);
|
||||
this.controllerFor("adminBackups").set("isOperationRunning", false);
|
||||
this.controllerFor("adminBackups").set("model.isOperationRunning", false);
|
||||
if (log.operation === "restore") {
|
||||
// redirect to homepage when the restore is done (session might be lost)
|
||||
window.location.pathname = Discourse.getURL("/");
|
||||
@ -30,7 +30,7 @@ export default Discourse.Route.extend({
|
||||
model() {
|
||||
return PreloadStore.getAndRemove("operations_status", function() {
|
||||
return Discourse.ajax("/admin/backups/status.json");
|
||||
}).then(function (status) {
|
||||
}).then(status => {
|
||||
return Discourse.BackupStatus.create({
|
||||
isOperationRunning: status.is_operation_running,
|
||||
canRollback: status.can_rollback,
|
||||
@ -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("isOperationRunning", true);
|
||||
self.modelFor("adminBackups").set("model.isOperationRunning", true);
|
||||
self.transitionTo("admin.backups.logs");
|
||||
});
|
||||
}
|
||||
@ -99,7 +99,7 @@ export default Discourse.Route.extend({
|
||||
function(confirmed) {
|
||||
if (confirmed) {
|
||||
Discourse.Backup.cancel().then(function() {
|
||||
self.controllerFor("adminBackups").set("isOperationRunning", false);
|
||||
self.controllerFor("adminBackups").set("model.isOperationRunning", false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
export default Ember.Route.extend({
|
||||
|
||||
model() {
|
||||
return Discourse.ColorScheme.findAll();
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
this._super();
|
||||
this.controllerFor('adminCustomizeColors').set('selectedItem', null);
|
||||
},
|
||||
|
||||
});
|
||||
@ -0,0 +1,11 @@
|
||||
export default Ember.Route.extend({
|
||||
model(params) {
|
||||
const all = this.modelFor('adminCustomizeCssHtml');
|
||||
const model = all.findProperty('id', parseInt(params.site_customization_id));
|
||||
return model ? { model, section: params.section } : this.replaceWith('adminCustomizeCssHtml.index');
|
||||
},
|
||||
|
||||
setupController(controller, hash) {
|
||||
controller.setProperties(hash);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,26 @@
|
||||
import showModal from 'discourse/lib/show-modal';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
model() {
|
||||
return this.store.findAll('site-customization');
|
||||
},
|
||||
|
||||
actions: {
|
||||
importModal() {
|
||||
showModal('upload-customization');
|
||||
},
|
||||
|
||||
newCustomization(obj) {
|
||||
obj = obj || {name: I18n.t("admin.customize.new_style")};
|
||||
const item = this.store.createRecord('site-customization');
|
||||
|
||||
const all = this.modelFor('adminCustomizeCssHtml');
|
||||
const self = this;
|
||||
item.save(obj).then(function() {
|
||||
all.pushObject(item);
|
||||
self.transitionTo('adminCustomizeCssHtml.show', item.get('id'), 'css');
|
||||
}).catch(popupAjaxError);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,5 @@
|
||||
export default Ember.Route.extend({
|
||||
beforeModel() {
|
||||
this.replaceWith('adminCustomize.colors');
|
||||
}
|
||||
});
|
||||
@ -11,9 +11,7 @@ export default Discourse.Route.extend({
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.set("model", model);
|
||||
// clear the user selector
|
||||
controller.set("usernames", null);
|
||||
// load the members of the group
|
||||
controller.set("model.usernames", null);
|
||||
model.findMembers();
|
||||
}
|
||||
|
||||
|
||||
@ -16,8 +16,12 @@ export default {
|
||||
|
||||
this.resource('adminCustomize', { path: '/customize' } ,function() {
|
||||
this.route('colors');
|
||||
this.route('css_html');
|
||||
this.resource('adminSiteText', { path: '/site_text' }, function() {
|
||||
|
||||
this.resource('adminCustomizeCssHtml', { path: 'css_html' }, function() {
|
||||
this.route('show', {path: '/:site_customization_id/:section'});
|
||||
});
|
||||
|
||||
this.resource('adminSiteText', { path: '/site_texts' }, function() {
|
||||
this.route('edit', {path: '/:text_type'});
|
||||
});
|
||||
this.resource('adminUserFields', { path: '/user_fields' });
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export default Discourse.Route.extend({
|
||||
model: function(params) {
|
||||
return Discourse.SiteText.find(params.text_type);
|
||||
model(params) {
|
||||
return this.store.find('site-text', params.text_type);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export default Discourse.Route.extend({
|
||||
model: function() {
|
||||
return Discourse.SiteTextType.findAll();
|
||||
model() {
|
||||
return this.store.findAll('site-text-type');
|
||||
}
|
||||
});
|
||||
|
||||
16
app/assets/javascripts/admin/routes/admin.js.es6
Normal file
16
app/assets/javascripts/admin/routes/admin.js.es6
Normal file
@ -0,0 +1,16 @@
|
||||
export default Discourse.Route.extend({
|
||||
titleToken() {
|
||||
return I18n.t('admin_title');
|
||||
},
|
||||
|
||||
activate() {
|
||||
this.controllerFor("application").setProperties({
|
||||
showTop: false,
|
||||
showFooter: false,
|
||||
});
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
this.controllerFor("application").set("showTop", true);
|
||||
}
|
||||
});
|
||||
@ -1,15 +0,0 @@
|
||||
/**
|
||||
Handles routes related to api
|
||||
|
||||
@class AdminApiRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminApiRoute = Discourse.Route.extend({
|
||||
|
||||
model: function() {
|
||||
return Discourse.ApiKey.find();
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,7 +0,0 @@
|
||||
Discourse.AdminBackupsIndexRoute = Discourse.Route.extend({
|
||||
|
||||
model: function() {
|
||||
return Discourse.Backup.find();
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,20 +0,0 @@
|
||||
/**
|
||||
Handles routes related to colors customization
|
||||
|
||||
@class AdminCustomizeColorsRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminCustomizeColorsRoute = Discourse.Route.extend({
|
||||
|
||||
model: function() {
|
||||
return Discourse.ColorScheme.findAll();
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
this._super();
|
||||
this.controllerFor('adminCustomizeColors').set('selectedItem', null);
|
||||
},
|
||||
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
Discourse.AdminCustomizeCssHtmlRoute = Discourse.Route.extend({
|
||||
model: function() {
|
||||
return Discourse.SiteCustomization.findAll();
|
||||
}
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
Discourse.AdminCustomizeIndexRoute = Discourse.Route.extend({
|
||||
beforeModel: function() {
|
||||
this.replaceWith('adminCustomize.colors');
|
||||
}
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
Discourse.AdminRoute = Discourse.Route.extend({
|
||||
titleToken: function() {
|
||||
return I18n.t('admin_title');
|
||||
}
|
||||
});
|
||||
@ -6,7 +6,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
{{#if canRollback}}
|
||||
{{#if model.canRollback}}
|
||||
{{d-button action="rollback"
|
||||
class="btn-rollback"
|
||||
label="admin.backups.operations.rollback.label"
|
||||
@ -14,7 +14,7 @@
|
||||
icon="ambulance"
|
||||
disabled=rollbackDisabled}}
|
||||
{{/if}}
|
||||
{{#if isOperationRunning}}
|
||||
{{#if model.isOperationRunning}}
|
||||
{{d-button action="cancelOperation"
|
||||
class="btn-danger"
|
||||
title="admin.backups.operations.cancel.title"
|
||||
|
||||
@ -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=isOperationRunning title="admin.backups.read_only.disable.title" label="admin.backups.read_only.disable.label"}}
|
||||
{{d-button icon="eye" action="toggleReadOnlyMode" disabled=model.isOperationRunning title="admin.backups.read_only.disable.title" label="admin.backups.read_only.disable.label"}}
|
||||
{{else}}
|
||||
{{d-button icon="eye" action="toggleReadOnlyMode" disabled=isOperationRunning title="admin.backups.read_only.enable.title" label="admin.backups.read_only.enable.label"}}
|
||||
{{d-button icon="eye" action="toggleReadOnlyMode" disabled=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 isOperationRunning}}
|
||||
{{#if 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=restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
|
||||
{{d-button icon="play" action="startRestore" actionParam=backup disabled=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=restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
|
||||
{{d-button icon="play" action="startRestore" actionParam=backup disabled=model.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
<li>
|
||||
<a href="/admin/customize/css_html/{{customization.id}}/css" class="{{if active 'active'}}">
|
||||
{{customization.description}}
|
||||
</a>
|
||||
</li>
|
||||
@ -0,0 +1 @@
|
||||
<a href={{member.adminPath}}>{{avatar member imageSize="small"}}</a> {{member.username}} {{#unless automatic}}<a class='remove' {{action "remove"}}>{{fa-icon "times"}}</a>{{/unless}}
|
||||
@ -0,0 +1 @@
|
||||
<p class="about">{{i18n 'admin.customize.about'}}</p>
|
||||
@ -0,0 +1,75 @@
|
||||
<div class="current-style {{if maximized 'maximized'}}">
|
||||
<div class='wrapper'>
|
||||
{{text-field class="style-name" value=model.name}}
|
||||
<a class="btn export" download target="_blank" href={{downloadUrl}}>{{fa-icon "download"}} {{i18n 'admin.export_json.button_text'}}</a>
|
||||
|
||||
<div class='admin-controls'>
|
||||
<ul class="nav nav-pills">
|
||||
{{#if mobile}}
|
||||
<li>{{#link-to 'adminCustomizeCssHtml.show' model.id 'mobile-css' replace=true}}{{i18n "admin.customize.css"}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminCustomizeCssHtml.show' model.id 'mobile-header' replace=true}}{{i18n "admin.customize.header"}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminCustomizeCssHtml.show' model.id 'mobile-top' replace=true}}{{i18n "admin.customize.top"}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminCustomizeCssHtml.show' model.id 'mobile-footer' replace=true}}{{i18n "admin.customize.footer"}}{{/link-to}}</li>
|
||||
{{else}}
|
||||
<li>{{#link-to 'adminCustomizeCssHtml.show' model.id 'css' replace=true}}{{i18n "admin.customize.css"}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminCustomizeCssHtml.show' model.id 'header' replace=true}}{{i18n "admin.customize.header"}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminCustomizeCssHtml.show' model.id 'top' replace=true}}{{i18n "admin.customize.top"}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminCustomizeCssHtml.show' model.id 'footer' replace=true}}{{i18n "admin.customize.footer"}}{{/link-to}}</li>
|
||||
<li>
|
||||
{{#link-to 'adminCustomizeCssHtml.show' model.id 'head-tag'}}
|
||||
{{fa-icon "file-text-o"}} {{i18n 'admin.customize.head_tag.text'}}
|
||||
{{/link-to}}
|
||||
</li>
|
||||
<li>
|
||||
{{#link-to 'adminCustomizeCssHtml.show' model.id 'body-tag'}}
|
||||
{{fa-icon "file-text-o"}} {{i18n 'admin.customize.body_tag.text'}}
|
||||
{{/link-to}}
|
||||
</li>
|
||||
<li>{{#link-to 'adminCustomizeCssHtml.show' model.id 'embedded-css' replace=true}}{{i18n "admin.customize.embedded_css"}}{{/link-to}}</li>
|
||||
{{/if}}
|
||||
<li class='toggle-mobile'>
|
||||
<a {{bind-attr class="mobile:active"}} {{action "toggleMobile"}}>{{fa-icon "mobile"}}</a>
|
||||
</li>
|
||||
<li class='toggle-maximize'>
|
||||
<a {{action "toggleMaximize"}}>
|
||||
{{fa-icon-bound maximizeIcon}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="admin-container">
|
||||
{{#if cssActive}}{{ace-editor content=model.stylesheet mode="scss"}}{{/if}}
|
||||
{{#if headerActive}}{{ace-editor content=model.header mode="html"}}{{/if}}
|
||||
{{#if topActive}}{{ace-editor content=model.top mode="html"}}{{/if}}
|
||||
{{#if footerActive}}{{ace-editor content=model.footer mode="html"}}{{/if}}
|
||||
{{#if headTagActive}}{{ace-editor content=model.head_tag mode="html"}}{{/if}}
|
||||
{{#if bodyTagActive}}{{ace-editor content=model.body_tag mode="html"}}{{/if}}
|
||||
{{#if embeddedCssActive}}{{ace-editor content=model.embedded_css mode="css"}}{{/if}}
|
||||
{{#if mobileCssActive}}{{ace-editor content=model.mobile_stylesheet mode="scss"}}{{/if}}
|
||||
{{#if mobileHeaderActive}}{{ace-editor content=model.mobile_header mode="html"}}{{/if}}
|
||||
{{#if mobileTopActive}}{{ace-editor content=model.mobile_top mode="html"}}{{/if}}
|
||||
{{#if mobileFooterActive}}{{ace-editor content=model.mobile_footer mode="html"}}{{/if}}
|
||||
</div>
|
||||
|
||||
<div class='admin-footer'>
|
||||
<div class='status-actions'>
|
||||
<span>{{i18n 'admin.customize.enabled'}} {{input type="checkbox" checked=model.enabled}}</span>
|
||||
{{#unless model.changed}}
|
||||
<a class='preview-link' href={{previewUrl}} target='_blank' title="{{i18n 'admin.customize.explain_preview'}}">{{i18n 'admin.customize.preview'}}</a>
|
||||
|
|
||||
<a href={{undoPreviewUrl}} target='_blank' title="{{i18n 'admin.customize.explain_undo_preview'}}">{{i18n 'admin.customize.undo_preview'}}</a>
|
||||
|
|
||||
<a href={{defaultStyleUrl}} target='_blank' title="{{i18n 'admin.customize.explain_rescue_preview'}}">{{i18n 'admin.customize.rescue_preview'}}</a><br>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
<div class='buttons'>
|
||||
{{#d-button action="save" disabled=saveDisabled class='btn-primary'}}
|
||||
{{saveButtonText}}
|
||||
{{/d-button}}
|
||||
{{d-button action="destroy" label="admin.customize.delete" icon="trash" class="btn-danger"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,13 @@
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n 'admin.customize.css_html.long_title'}}</h3>
|
||||
<ul>
|
||||
{{#each model as |c|}}
|
||||
{{customize-link customization=c}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
{{d-button label="admin.customize.new" icon="plus" action="newCustomization" class="btn-primary"}}
|
||||
{{d-button action="importModal" icon="upload" label="admin.customize.import"}}
|
||||
</div>
|
||||
|
||||
{{outlet}}
|
||||
@ -1,6 +1,6 @@
|
||||
{{#admin-nav}}
|
||||
{{nav-item route='adminCustomize.colors' label='admin.customize.colors.title'}}
|
||||
{{nav-item route='adminCustomize.css_html' label='admin.customize.css_html.title'}}
|
||||
{{nav-item route='adminCustomizeCssHtml.index' label='admin.customize.css_html.title'}}
|
||||
{{nav-item route='adminSiteText' label='admin.site_text.title'}}
|
||||
{{nav-item route='adminUserFields' label='admin.user_fields.title'}}
|
||||
{{nav-item route='adminEmojis' label='admin.emoji.title'}}
|
||||
|
||||
@ -1,84 +0,0 @@
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n 'admin.customize.css_html.long_title'}}</h3>
|
||||
<ul>
|
||||
{{#each style in model}}
|
||||
<li><a {{action "selectStyle" style}} {{bind-attr class="style.selected:active"}}>{{style.description}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<button {{action "newCustomization"}} class='btn'>
|
||||
{{fa-icon "plus"}}{{i18n 'admin.customize.new'}}
|
||||
</button>
|
||||
{{d-button action="importModal" icon="upload" label="admin.customize.import"}}
|
||||
</div>
|
||||
|
||||
{{#if selectedItem}}
|
||||
<div {{bind-attr class=":current-style view.maximized:maximized"}}>
|
||||
<div class='wrapper'>
|
||||
{{text-field class="style-name" value=selectedItem.name}}
|
||||
<a class="btn export" download target="_blank" href={{selectedItem.download_url}}>{{fa-icon "download"}} {{i18n 'admin.export_json.button_text'}}</a>
|
||||
|
||||
<div class='admin-controls'>
|
||||
<ul class="nav nav-pills">
|
||||
{{#if view.mobile}}
|
||||
<li><a {{bind-attr class="view.mobileStylesheetActive:active"}} {{action "select" "mobile_stylesheet" target="view"}}>{{fa-icon "mobile"}} {{i18n 'admin.customize.css'}}</a></li>
|
||||
<li><a {{bind-attr class="view.mobileHeaderActive:active"}} {{action "select" "mobile_header" target="view"}}>{{fa-icon "mobile"}} {{i18n 'admin.customize.header'}}</a></li>
|
||||
<li><a {{bind-attr class="view.mobileTopActive:active"}} {{action "select" "mobile_top" target="view"}}>{{fa-icon "mobile"}} {{i18n 'admin.customize.top'}}</a></li>
|
||||
<li><a {{bind-attr class="view.mobileFooterActive:active"}} {{action "select" "mobile_footer" target="view"}}>{{fa-icon "mobile"}} {{i18n 'admin.customize.footer'}}</a></li>
|
||||
{{else}}
|
||||
<li><a {{bind-attr class="view.stylesheetActive:active"}} {{action "select" "stylesheet" target="view"}}>{{i18n 'admin.customize.css'}}</a></li>
|
||||
<li><a {{bind-attr class="view.headerActive:active"}} {{action "select" "header" target="view"}}>{{i18n 'admin.customize.header'}}</a></li>
|
||||
<li><a {{bind-attr class="view.topActive:active"}} {{action "select" "top" target="view"}}>{{i18n 'admin.customize.top'}}</a></li>
|
||||
<li><a {{bind-attr class="view.footerActive:active"}} {{action "select" "footer" target="view"}}>{{i18n 'admin.customize.footer'}}</a></li>
|
||||
<li><a {{bind-attr class="view.headTagActive:active"}} {{action "select" "head_tag" target="view"}} title="{{i18n 'admin.customize.head_tag.title'}}">{{fa-icon "file-text-o"}} {{i18n 'admin.customize.head_tag.text'}}</a></li>
|
||||
<li><a {{bind-attr class="view.bodyTagActive:active"}} {{action "select" "body_tag" target="view"}} title="{{i18n 'admin.customize.body_tag.title'}}">{{fa-icon "file-text-o"}} {{i18n 'admin.customize.body_tag.text'}}</a></li>
|
||||
{{/if}}
|
||||
<li class='toggle-mobile'>
|
||||
<a {{bind-attr class="view.mobile:active"}} {{action "toggleMobile" target="view"}}>{{fa-icon "mobile"}}</a>
|
||||
</li>
|
||||
<li class='toggle-maximize'>
|
||||
<a {{action "toggleMaximize" target="view"}}>
|
||||
{{#if view.maximized}}
|
||||
{{fa-icon "compress"}}
|
||||
{{else}}
|
||||
{{fa-icon "expand"}}
|
||||
{{/if}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="admin-container">
|
||||
{{#if view.stylesheetActive}}{{ace-editor content=selectedItem.stylesheet mode="scss"}}{{/if}}
|
||||
{{#if view.headerActive}}{{ace-editor content=selectedItem.header mode="html"}}{{/if}}
|
||||
{{#if view.topActive}}{{ace-editor content=selectedItem.top mode="html"}}{{/if}}
|
||||
{{#if view.footerActive}}{{ace-editor content=selectedItem.footer mode="html"}}{{/if}}
|
||||
{{#if view.headTagActive}}{{ace-editor content=selectedItem.head_tag mode="html"}}{{/if}}
|
||||
{{#if view.bodyTagActive}}{{ace-editor content=selectedItem.body_tag mode="html"}}{{/if}}
|
||||
{{#if view.mobileStylesheetActive}}{{ace-editor content=selectedItem.mobile_stylesheet mode="scss"}}{{/if}}
|
||||
{{#if view.mobileHeaderActive}}{{ace-editor content=selectedItem.mobile_header mode="html"}}{{/if}}
|
||||
{{#if view.mobileTopActive}}{{ace-editor content=selectedItem.mobile_top mode="html"}}{{/if}}
|
||||
{{#if view.mobileFooterActive}}{{ace-editor content=selectedItem.mobile_footer mode="html"}}{{/if}}
|
||||
</div>
|
||||
<div class='admin-footer'>
|
||||
<div class='status-actions'>
|
||||
<span>{{i18n 'admin.customize.enabled'}} {{input type="checkbox" checked=selectedItem.enabled}}</span>
|
||||
{{#unless selectedItem.changed}}
|
||||
<a class='preview-link' {{bind-attr href="selectedItem.previewUrl"}} target='_blank' title="{{i18n 'admin.customize.explain_preview'}}">{{i18n 'admin.customize.preview'}}</a>
|
||||
|
|
||||
<a href="{{undoPreviewUrl}}" target='_blank' title="{{i18n 'admin.customize.explain_undo_preview'}}">{{i18n 'admin.customize.undo_preview'}}</a>
|
||||
|
|
||||
<a href="{{defaultStyleUrl}}" target='_blank' title="{{i18n 'admin.customize.explain_rescue_preview'}}">{{i18n 'admin.customize.rescue_preview'}}</a><br>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
<div class='buttons'>
|
||||
<button {{action "save"}} {{bind-attr disabled="selectedItem.disableSave"}} class='btn'>{{i18n 'admin.customize.save'}}</button>
|
||||
<span class='saving'>{{selectedItem.savingStatus}}</span>
|
||||
<a {{action "destroy"}} class='delete-link'>{{i18n 'admin.customize.delete'}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="about">{{i18n 'admin.customize.about'}}</p>
|
||||
{{/if}}
|
||||
@ -1,31 +1,33 @@
|
||||
<form class="form-horizontal">
|
||||
|
||||
<div>
|
||||
{{#if automatic}}
|
||||
<h3>{{name}}</h3>
|
||||
{{#if model.automatic}}
|
||||
<h3>{{model.name}}</h3>
|
||||
{{else}}
|
||||
<label for="name">{{i18n 'admin.groups.name'}}</label>
|
||||
{{text-field name="name" value=name placeholderKey="admin.groups.name_placeholder"}}
|
||||
{{text-field name="name" value=model.name placeholderKey="admin.groups.name_placeholder"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if id}}
|
||||
{{#if model.id}}
|
||||
<div>
|
||||
<label>{{i18n 'admin.groups.group_members'}} ({{user_count}})</label>
|
||||
<label>{{i18n 'admin.groups.group_members'}} ({{model.user_count}})</label>
|
||||
<div>
|
||||
<a {{bind-attr class=":previous showingFirst:disabled"}} {{action "previous"}}>{{fa-icon "fast-backward"}}</a>
|
||||
{{currentPage}}/{{totalPages}}
|
||||
<a {{bind-attr class=":next showingLast:disabled"}} {{action "next"}}>{{fa-icon "fast-forward"}}</a>
|
||||
</div>
|
||||
<div class="ac-wrap clearfix">
|
||||
{{each member in members itemView="group-member"}}
|
||||
{{#each model.members as |member|}}
|
||||
{{group-member member=member automatic=model.automatic removeAction="removeMember"}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#unless automatic}}
|
||||
{{#unless model.automatic}}
|
||||
<div>
|
||||
<label for="user-selector">{{i18n 'admin.groups.add_members'}}</label>
|
||||
{{user-selector usernames=usernames placeholderKey="admin.groups.selector_placeholder" id="user-selector"}}
|
||||
{{user-selector usernames=model.usernames placeholderKey="admin.groups.selector_placeholder" id="user-selector"}}
|
||||
<button {{action "addMembers"}} class='btn add'>{{fa-icon "plus"}} {{i18n 'admin.groups.add'}}</button>
|
||||
</div>
|
||||
{{/unless}}
|
||||
@ -33,15 +35,15 @@
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{input type="checkbox" checked=visible}}
|
||||
{{input type="checkbox" checked=model.visible}}
|
||||
{{i18n 'groups.visible'}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{{#unless automatic}}
|
||||
{{#unless model.automatic}}
|
||||
<div>
|
||||
<label for="primary_group">
|
||||
{{input type="checkbox" checked=primary_group}}
|
||||
{{input type="checkbox" checked=model.primary_group}}
|
||||
{{i18n 'admin.groups.primary_group'}}
|
||||
</label>
|
||||
</div>
|
||||
@ -49,15 +51,15 @@
|
||||
|
||||
<div>
|
||||
<label for="alias">{{i18n 'groups.alias_levels.title'}}</label>
|
||||
{{combo-box name="alias" valueAttribute="value" value=alias_level content=aliasLevelOptions}}
|
||||
{{combo-box name="alias" valueAttribute="value" value=model.alias_level content=aliasLevelOptions}}
|
||||
</div>
|
||||
|
||||
{{#unless automatic}}
|
||||
{{#unless model.automatic}}
|
||||
<div>
|
||||
<label for="automatic_membership">{{i18n 'admin.groups.automatic_membership_email_domains'}}</label>
|
||||
{{list-setting name="automatic_membership" settingValue=emailDomains}}
|
||||
{{list-setting name="automatic_membership" settingValue=model.emailDomains}}
|
||||
<label>
|
||||
{{input type="checkbox" checked=automatic_membership_retroactive}}
|
||||
{{input type="checkbox" checked=model.automatic_membership_retroactive}}
|
||||
{{i18n 'admin.groups.automatic_membership_retroactive'}}
|
||||
</label>
|
||||
</div>
|
||||
@ -66,13 +68,13 @@
|
||||
<label for="title">
|
||||
{{i18n 'admin.groups.default_title'}}
|
||||
</label>
|
||||
{{input value=title}}
|
||||
{{input value=model.title}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
<div class='buttons'>
|
||||
<button {{action "save"}} {{bind-attr disabled="disableSave"}} class='btn btn-primary'>{{i18n 'admin.customize.save'}}</button>
|
||||
{{#unless automatic}}
|
||||
{{#unless model.automatic}}
|
||||
<button {{action "destroy"}} class='btn btn-danger'>{{fa-icon "trash-o"}}{{i18n 'admin.customize.delete'}}</button>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
@ -1 +0,0 @@
|
||||
<a href='{{unbound member.adminPath}}'>{{avatar member imageSize="small"}}</a> {{member.username}} {{#unless automatic}}<a class='remove' {{action "removeMember" member}}>{{fa-icon "times"}}</a>{{/unless}}
|
||||
26
app/assets/javascripts/admin/templates/site-text-edit.hbs
Normal file
26
app/assets/javascripts/admin/templates/site-text-edit.hbs
Normal file
@ -0,0 +1,26 @@
|
||||
<h3>{{model.title}}</h3>
|
||||
<p class='description'>{{model.description}}</p>
|
||||
|
||||
{{#if model.markdown}}
|
||||
{{pagedown-editor value=model.value}}
|
||||
{{/if}}
|
||||
{{#if model.plainText}}
|
||||
{{textarea value=model.value class="plain"}}
|
||||
{{/if}}
|
||||
{{#if model.html}}
|
||||
{{ace-editor content=model.value mode="html"}}
|
||||
{{/if}}
|
||||
{{#if model.css}}
|
||||
{{ace-editor content=model.value mode="css"}}
|
||||
{{/if}}
|
||||
|
||||
<div class='controls'>
|
||||
<button class='btn' {{action "saveChanges"}} disabled={{saveDisabled}}>
|
||||
{{#if model.isSaving}}
|
||||
{{i18n 'saving'}}
|
||||
{{else}}
|
||||
{{i18n 'save'}}
|
||||
{{/if}}
|
||||
</button>
|
||||
{{#if saved}}{{i18n 'saved'}}{{/if}}
|
||||
</div>
|
||||
@ -1,26 +0,0 @@
|
||||
<h3>{{title}}</h3>
|
||||
<p class='description'>{{description}}</p>
|
||||
|
||||
{{#if markdown}}
|
||||
{{pagedown-editor value=value}}
|
||||
{{/if}}
|
||||
{{#if plainText}}
|
||||
{{textarea value=value class="plain"}}
|
||||
{{/if}}
|
||||
{{#if html}}
|
||||
{{ace-editor content=value mode="html"}}
|
||||
{{/if}}
|
||||
{{#if css}}
|
||||
{{ace-editor content=value mode="css"}}
|
||||
{{/if}}
|
||||
|
||||
<div class='controls'>
|
||||
<button class='btn' {{action "saveChanges"}} {{bind-attr disabled="saveDisabled"}}>
|
||||
{{#if saving}}
|
||||
{{i18n 'saving'}}
|
||||
{{else}}
|
||||
{{i18n 'save'}}
|
||||
{{/if}}
|
||||
</button>
|
||||
{{#if saved}}{{i18n 'saved'}}{{/if}}
|
||||
</div>
|
||||
@ -5,20 +5,20 @@ export default Discourse.View.extend({
|
||||
|
||||
_initialize: function() { this._reset(); }.on("init"),
|
||||
|
||||
_reset: function() {
|
||||
_reset() {
|
||||
this.setProperties({ formattedLogs: "", index: 0 });
|
||||
},
|
||||
|
||||
_updateFormattedLogs: Discourse.debounce(function() {
|
||||
var logs = this.get("controller.model");
|
||||
const logs = this.get("controller.model");
|
||||
if (logs.length === 0) {
|
||||
this._reset(); // reset the cached logs whenever the model is reset
|
||||
} else {
|
||||
// do the log formatting only once for HELLish performance
|
||||
var formattedLogs = this.get("formattedLogs");
|
||||
for (var i = this.get("index"), length = logs.length; i < length; i++) {
|
||||
var date = logs[i].get("timestamp"),
|
||||
message = Handlebars.Utils.escapeExpression(logs[i].get("message"));
|
||||
let formattedLogs = this.get("formattedLogs");
|
||||
for (let i = this.get("index"), length = logs.length; i < length; i++) {
|
||||
const date = logs[i].get("timestamp"),
|
||||
message = Handlebars.Utils.escapeExpression(logs[i].get("message"));
|
||||
formattedLogs += "[" + date + "] " + message + "\n";
|
||||
}
|
||||
// update the formatted logs & cache index
|
||||
@ -28,8 +28,8 @@ export default Discourse.View.extend({
|
||||
}
|
||||
}, 150).observes("controller.model.@each"),
|
||||
|
||||
render: function(buffer) {
|
||||
var formattedLogs = this.get("formattedLogs");
|
||||
render(buffer) {
|
||||
const formattedLogs = this.get("formattedLogs");
|
||||
if (formattedLogs && formattedLogs.length > 0) {
|
||||
buffer.push("<pre>");
|
||||
buffer.push(formattedLogs);
|
||||
@ -38,13 +38,13 @@ export default Discourse.View.extend({
|
||||
buffer.push("<p>" + I18n.t("admin.backups.logs.none") + "</p>");
|
||||
}
|
||||
// add a loading indicator
|
||||
if (this.get("controller.status.isOperationRunning")) {
|
||||
if (this.get("controller.status.model.isOperationRunning")) {
|
||||
buffer.push(renderSpinner('small'));
|
||||
}
|
||||
},
|
||||
|
||||
_forceScrollToBottom: function() {
|
||||
var $div = this.$()[0];
|
||||
const $div = this.$()[0];
|
||||
$div.scrollTop = $div.scrollHeight;
|
||||
}.on("didInsertElement")
|
||||
|
||||
|
||||
18
app/assets/javascripts/admin/views/admin-customize.js.es6
Normal file
18
app/assets/javascripts/admin/views/admin-customize.js.es6
Normal file
@ -0,0 +1,18 @@
|
||||
/*global Mousetrap:true */
|
||||
|
||||
export default Ember.View.extend({
|
||||
classNames: ['customize'],
|
||||
|
||||
_init: function() {
|
||||
var controller = this.get('controller');
|
||||
Mousetrap.bindGlobal('mod+s', function() {
|
||||
controller.send("save");
|
||||
return false;
|
||||
});
|
||||
}.on("didInsertElement"),
|
||||
|
||||
_cleanUp: function() {
|
||||
Mousetrap.unbindGlobal('mod+s');
|
||||
}.on("willDestroyElement")
|
||||
|
||||
});
|
||||
@ -1,68 +0,0 @@
|
||||
/*global Mousetrap:true */
|
||||
|
||||
/**
|
||||
A view to handle site customizations
|
||||
|
||||
@class AdminCustomizeView
|
||||
@extends Discourse.View
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminCustomizeView = Discourse.View.extend({
|
||||
templateName: 'admin/templates/customize',
|
||||
classNames: ['customize'],
|
||||
selected: 'stylesheet',
|
||||
mobile: false,
|
||||
|
||||
stylesheetActive: Em.computed.equal('selected', 'stylesheet'),
|
||||
headerActive: Em.computed.equal('selected', 'header'),
|
||||
topActive: Em.computed.equal('selected', 'top'),
|
||||
footerActive: Em.computed.equal('selected', 'footer'),
|
||||
headTagActive: Em.computed.equal('selected', 'head_tag'),
|
||||
bodyTagActive: Em.computed.equal('selected', 'body_tag'),
|
||||
|
||||
mobileStylesheetActive: Em.computed.equal('selected', 'mobile_stylesheet'),
|
||||
mobileHeaderActive: Em.computed.equal('selected', 'mobile_header'),
|
||||
mobileTopActive: Em.computed.equal('selected', 'mobile_top'),
|
||||
mobileFooterActive: Em.computed.equal('selected', 'mobile_footer'),
|
||||
|
||||
actions: {
|
||||
toggleMobile: function() {
|
||||
// auto-select best tab
|
||||
var tab = this.get("selected");
|
||||
if (/_tag$/.test(tab)) { tab = "stylesheet"; }
|
||||
if (this.get("mobile")) { tab = tab.replace("mobile_", ""); }
|
||||
else { tab = "mobile_" + tab; }
|
||||
this.set("selected", tab);
|
||||
// toggle mobile
|
||||
this.toggleProperty("mobile");
|
||||
},
|
||||
|
||||
select: function(tab) {
|
||||
this.set('selected', tab);
|
||||
},
|
||||
|
||||
toggleMaximize: function() {
|
||||
this.set("maximized", !this.get("maximized"));
|
||||
|
||||
Em.run.scheduleOnce('afterRender', this, function(){
|
||||
$('.ace-wrapper').each(function(){
|
||||
$(this).data("editor").resize();
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
_init: function() {
|
||||
var controller = this.get('controller');
|
||||
Mousetrap.bindGlobal('mod+s', function() {
|
||||
controller.send("save");
|
||||
return false;
|
||||
});
|
||||
}.on("didInsertElement"),
|
||||
|
||||
_cleanUp: function() {
|
||||
Mousetrap.unbindGlobal('mod+s');
|
||||
}.on("willDestroyElement")
|
||||
|
||||
});
|
||||
@ -1,4 +0,0 @@
|
||||
export default Discourse.View.extend({
|
||||
classNames: ["item"],
|
||||
templateName: "admin/templates/group_member"
|
||||
});
|
||||
@ -140,3 +140,18 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
||||
|
||||
// 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, {
|
||||
get: function() {
|
||||
msg = msg || "import the module";
|
||||
Ember.warn("DEPRECATION: `Discourse." + propName + "` is deprecated, " + msg + ".");
|
||||
return moduleFunc();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 });
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
const ADMIN_MODELS = ['plugin'];
|
||||
const ADMIN_MODELS = ['plugin', 'site-customization'];
|
||||
|
||||
export function Result(payload, responseJson) {
|
||||
this.payload = payload;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
||||
|
||||
export default Ember.Component.extend(StringBuffer, {
|
||||
tagName: 'section',
|
||||
@ -57,7 +58,7 @@ export default Ember.Component.extend(StringBuffer, {
|
||||
buffer.push("<div class='post-action'>" +
|
||||
iconHTML('fa-trash-o') + ' ' +
|
||||
Discourse.Utilities.tinyAvatar(post.get('postDeletedBy.avatar_template'), {title: post.get('postDeletedBy.username')}) +
|
||||
Discourse.Formatter.autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) +
|
||||
autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) +
|
||||
"</div>");
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
var get = Ember.get;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNameBindings: ['category::no-category', 'categories:has-drop','categoryStyle'],
|
||||
categoryStyle: Discourse.computed.setting('category_style'),
|
||||
categoryStyle: setting('category_style'),
|
||||
|
||||
tagName: 'li',
|
||||
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
/* global Pikaday:true */
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
|
||||
export default Em.Component.extend({
|
||||
tagName: "input",
|
||||
classNames: ["date-picker"],
|
||||
_picker: null,
|
||||
|
||||
_loadDatePicker: function() {
|
||||
const self = this,
|
||||
input = this.$()[0];
|
||||
|
||||
loadScript("/javascripts/pikaday.js").then(function() {
|
||||
self._picker = new Pikaday({
|
||||
field: input,
|
||||
format: "YYYY-MM-DD",
|
||||
defaultDate: moment().add(1, "day").toDate(),
|
||||
minDate: new Date(),
|
||||
onSelect: function(date) {
|
||||
self.set("value", moment(date).format("YYYY-MM-DD"));
|
||||
},
|
||||
});
|
||||
});
|
||||
}.on("didInsertElement"),
|
||||
|
||||
_destroy: function() {
|
||||
this._picker = null;
|
||||
}.on("willDestroyElement"),
|
||||
|
||||
});
|
||||
@ -24,8 +24,11 @@ export default Ember.Component.extend(StringBuffer, {
|
||||
}.on('willDestroyElement'),
|
||||
|
||||
renderString(buffer) {
|
||||
const title = this.get('title');
|
||||
if (title) {
|
||||
buffer.push("<h4 class='title'>" + title + "</h4>");
|
||||
}
|
||||
|
||||
buffer.push("<h4 class='title'>" + this.get('title') + "</h4>");
|
||||
buffer.push("<button class='btn standard dropdown-toggle' data-toggle='dropdown'>");
|
||||
buffer.push(this.get('text'));
|
||||
buffer.push("</button>");
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
|
||||
|
||||
export default buildCategoryPanel('settings', {
|
||||
emailInEnabled: Discourse.computed.setting('email_in'),
|
||||
showPositionInput: Discourse.computed.setting('fixed_category_positions'),
|
||||
emailInEnabled: setting('email_in'),
|
||||
showPositionInput: setting('fixed_category_positions'),
|
||||
});
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
|
||||
export default Em.Component.extend({
|
||||
tagName: 'li',
|
||||
classNameBindings: ['active', 'tabClassName'],
|
||||
@ -6,7 +8,7 @@ export default Em.Component.extend({
|
||||
return 'edit-category-' + this.get('tab');
|
||||
}.property('tab'),
|
||||
|
||||
active: Discourse.computed.propertyEqual('selectedTab', 'tab'),
|
||||
active: propertyEqual('selectedTab', 'tab'),
|
||||
|
||||
title: function() {
|
||||
return I18n.t('category.' + this.get('tab').replace('-', '_'));
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ["title"],
|
||||
|
||||
@ -13,10 +15,10 @@ export default Ember.Component.extend({
|
||||
return Discourse.Mobile.mobileView && !Ember.isBlank(this.get('mobileBigLogoUrl'));
|
||||
}.property(),
|
||||
|
||||
smallLogoUrl: Discourse.computed.setting('logo_small_url'),
|
||||
bigLogoUrl: Discourse.computed.setting('logo_url'),
|
||||
mobileBigLogoUrl: Discourse.computed.setting('mobile_logo_url'),
|
||||
title: Discourse.computed.setting('title'),
|
||||
smallLogoUrl: setting('logo_small_url'),
|
||||
bigLogoUrl: setting('logo_url'),
|
||||
mobileBigLogoUrl: setting('mobile_logo_url'),
|
||||
title: setting('title'),
|
||||
|
||||
click: function(e) {
|
||||
// if they want to open in a new tab, let it so
|
||||
|
||||
@ -30,9 +30,9 @@ export default Ember.Component.extend({
|
||||
}
|
||||
|
||||
if (it.get('notification_type') === INVITED_TYPE) {
|
||||
return Discourse.getURL('/my/invited');
|
||||
return Discourse.getURL('/users/' + it.get('data.display_username'));
|
||||
}
|
||||
}.property("notification.data.{badge_id,badge_name}", "model.slug", "model.topic_id", "model.post_number"),
|
||||
}.property("notification.data.{badge_id,badge_name,display_username}", "model.slug", "model.topic_id", "model.post_number"),
|
||||
|
||||
description: function() {
|
||||
const badgeName = this.get("notification.data.badge_name");
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
|
||||
const PosterNameComponent = Em.Component.extend({
|
||||
classNames: ['names', 'trigger-user-card'],
|
||||
displayNameOnPosts: Discourse.computed.setting('display_name_on_posts'),
|
||||
displayNameOnPosts: setting('display_name_on_posts'),
|
||||
|
||||
// sanitize name for comparison
|
||||
sanitizeName(name){
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { relativeAge } from 'discourse/lib/formatter';
|
||||
|
||||
const icons = {
|
||||
'closed.enabled': 'lock',
|
||||
'closed.disabled': 'unlock-alt',
|
||||
@ -19,7 +21,7 @@ export function actionDescription(actionCode, createdAt) {
|
||||
const ac = this.get(actionCode);
|
||||
if (ac) {
|
||||
const dt = new Date(this.get(createdAt));
|
||||
const when = Discourse.Formatter.relativeAge(dt, {format: 'medium-with-ago'});
|
||||
const when = relativeAge(dt, {format: 'medium-with-ago'});
|
||||
return I18n.t(`action_codes.${ac}`, {when}).htmlSafe();
|
||||
}
|
||||
}.property(actionCode, createdAt);
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
import { actionDescription } from "discourse/components/small-action";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNameBindings: [":item", "item.hidden", "item.deleted", "moderatorAction"],
|
||||
moderatorAction: Discourse.computed.propertyEqual("item.post_type", "site.post_types.moderator_action"),
|
||||
moderatorAction: propertyEqual("item.post_type", "site.post_types.moderator_action"),
|
||||
actionDescription: actionDescription("item.action_code", "item.created_at"),
|
||||
|
||||
actions: {
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { fmt } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNameBindings: [':user-field', 'field.field_type'],
|
||||
layoutName: Discourse.computed.fmt('field.field_type', 'components/user-fields/%@'),
|
||||
layoutName: fmt('field.field_type', 'components/user-fields/%@'),
|
||||
|
||||
noneLabel: function() {
|
||||
if (!this.get('field.required')) {
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import { url } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['user-small'],
|
||||
|
||||
userPath: Discourse.computed.url('user.username', '/users/%@'),
|
||||
userPath: url('user.username', '/users/%@'),
|
||||
|
||||
name: function() {
|
||||
const name = this.get('user.name');
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export default Ember.Controller.extend({
|
||||
showTop: true,
|
||||
showFooter: false,
|
||||
styleCategory: null,
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
|
||||
export default Ember.ObjectController.extend(Presence, {
|
||||
@ -8,7 +9,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||
|
||||
showEditReason: false,
|
||||
editReason: null,
|
||||
maxTitleLength: Discourse.computed.setting('max_topic_title_length'),
|
||||
maxTitleLength: setting('max_topic_title_length'),
|
||||
scopedCategoryId: null,
|
||||
similarTopics: null,
|
||||
similarTopicsMessage: null,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
|
||||
export default DiscourseController.extend(ModalFunctionality, {
|
||||
needs: ['login'],
|
||||
@ -16,10 +17,10 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
userFields: null,
|
||||
|
||||
hasAuthOptions: Em.computed.notEmpty('authOptions'),
|
||||
canCreateLocal: Discourse.computed.setting('enable_local_logins'),
|
||||
canCreateLocal: setting('enable_local_logins'),
|
||||
showCreateForm: Em.computed.or('hasAuthOptions', 'canCreateLocal'),
|
||||
maxUsernameLength: Discourse.computed.setting('max_username_length'),
|
||||
minUsernameLength: Discourse.computed.setting('min_username_length'),
|
||||
maxUsernameLength: setting('max_username_length'),
|
||||
minUsernameLength: setting('min_username_length'),
|
||||
|
||||
resetForm() {
|
||||
// We wrap the fields in a structure so we can assign a value
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
me: Discourse.computed.propertyEqual('model.user.id', 'currentUser.id')
|
||||
me: propertyEqual('model.user.id', 'currentUser.id')
|
||||
});
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import DiscoveryController from 'discourse/controllers/discovery';
|
||||
import { queryParams } from 'discourse/controllers/discovery-sortable';
|
||||
import BulkTopicSelection from 'discourse/mixins/bulk-topic-selection';
|
||||
import { endWith } from 'discourse/lib/computed';
|
||||
|
||||
const controllerOpts = {
|
||||
needs: ['discovery'],
|
||||
@ -102,8 +103,8 @@ const controllerOpts = {
|
||||
|
||||
hasTopics: Em.computed.gt('model.topics.length', 0),
|
||||
allLoaded: Em.computed.empty('model.more_topics_url'),
|
||||
latest: Discourse.computed.endWith('model.filter', 'latest'),
|
||||
new: Discourse.computed.endWith('model.filter', 'new'),
|
||||
latest: endWith('model.filter', 'latest'),
|
||||
new: endWith('model.filter', 'new'),
|
||||
top: Em.computed.notEmpty('period'),
|
||||
yearly: Em.computed.equal('period', 'yearly'),
|
||||
quarterly: Em.computed.equal('period', 'quarterly'),
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
// The basic controller for a group
|
||||
export default ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
counts: null,
|
||||
showing: null,
|
||||
|
||||
@ -10,4 +7,3 @@ export default ObjectController.extend({
|
||||
showingIndex: Em.computed.equal('showing', 'index'),
|
||||
showingMembers: Em.computed.equal('showing', 'members')
|
||||
});
|
||||
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
loading: false,
|
||||
limit: null,
|
||||
offset: null,
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
if (this.get("loading")) { return; }
|
||||
// we've reached the end
|
||||
if (this.get("model.members.length") >= this.get("user_count")) { return; }
|
||||
if (this.get("model.members.length") >= this.get("model.user_count")) { return; }
|
||||
|
||||
this.set("loading", true);
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ export default ObjectController.extend(Presence, ModalFunctionality, {
|
||||
}.property(),
|
||||
|
||||
disabled: function() {
|
||||
if (this.get('saving')) return true;
|
||||
if (this.get('model.saving')) return true;
|
||||
if (this.blank('emailOrUsername')) return true;
|
||||
const emailOrUsername = this.get('emailOrUsername').trim();
|
||||
// when inviting to forum, email must be valid
|
||||
@ -22,14 +22,14 @@ export default ObjectController.extend(Presence, ModalFunctionality, {
|
||||
// normal users (not admin) can't invite users to private topic via email
|
||||
if (!this.get('isAdmin') && this.get('isPrivateTopic') && Discourse.Utilities.emailValid(emailOrUsername)) return true;
|
||||
// when invting to private topic via email, group name must be specified
|
||||
if (this.get('isPrivateTopic') && this.blank('groupNames') && Discourse.Utilities.emailValid(emailOrUsername)) return true;
|
||||
if (this.get('isPrivateTopic') && this.blank('model.groupNames') && Discourse.Utilities.emailValid(emailOrUsername)) return true;
|
||||
if (this.get('model.details.can_invite_to')) return false;
|
||||
return false;
|
||||
}.property('isAdmin', 'emailOrUsername', 'invitingToTopic', 'isPrivateTopic', 'groupNames', 'saving'),
|
||||
}.property('isAdmin', 'emailOrUsername', 'invitingToTopic', 'isPrivateTopic', 'model.groupNames', 'model.saving'),
|
||||
|
||||
buttonTitle: function() {
|
||||
return this.get('saving') ? I18n.t('topic.inviting') : I18n.t('topic.invite_reply.action');
|
||||
}.property('saving'),
|
||||
return this.get('model.saving') ? I18n.t('topic.inviting') : I18n.t('topic.invite_reply.action');
|
||||
}.property('model.saving'),
|
||||
|
||||
// We are inviting to a topic if the model isn't the current user.
|
||||
// The current user would mean we are inviting to the forum in general.
|
||||
@ -117,8 +117,8 @@ export default ObjectController.extend(Presence, ModalFunctionality, {
|
||||
|
||||
// Reset the modal to allow a new user to be invited.
|
||||
reset() {
|
||||
this.setProperties({
|
||||
emailOrUsername: null,
|
||||
this.set('emailOrUsername', null);
|
||||
this.get('model').setProperties({
|
||||
groupNames: null,
|
||||
error: false,
|
||||
saving: false,
|
||||
@ -131,13 +131,14 @@ export default ObjectController.extend(Presence, ModalFunctionality, {
|
||||
createInvite() {
|
||||
if (this.get('disabled')) { return; }
|
||||
|
||||
const groupNames = this.get('groupNames'),
|
||||
userInvitedController = this.get('controllers.user-invited-show');
|
||||
const groupNames = this.get('model.groupNames'),
|
||||
userInvitedController = this.get('controllers.user-invited-show'),
|
||||
model = this.get('model');
|
||||
|
||||
this.setProperties({ saving: true, error: false });
|
||||
model.setProperties({ saving: true, error: false });
|
||||
|
||||
return this.get('model').createInvite(this.get('emailOrUsername').trim(), groupNames).then(result => {
|
||||
this.setProperties({ saving: false, finished: true });
|
||||
model.setProperties({ saving: false, finished: true });
|
||||
if (!this.get('invitingToTopic')) {
|
||||
Discourse.Invite.findInvitedBy(this.currentUser, userInvitedController.get('filter')).then(invite_model => {
|
||||
userInvitedController.set('model', invite_model);
|
||||
@ -146,7 +147,7 @@ export default ObjectController.extend(Presence, ModalFunctionality, {
|
||||
} else if (this.get('isMessage') && result && result.user) {
|
||||
this.get('model.details.allowed_users').pushObject(result.user);
|
||||
}
|
||||
}).catch(() => this.setProperties({ saving: false, error: true }));
|
||||
}).catch(() => model.setProperties({ saving: false, error: true }));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
import showModal from 'discourse/lib/show-modal';
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
|
||||
// This is happening outside of the app via popup
|
||||
const AuthErrors =
|
||||
@ -13,7 +14,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||
loggingIn: false,
|
||||
loggedIn: false,
|
||||
|
||||
canLoginLocal: Discourse.computed.setting('enable_local_logins'),
|
||||
canLoginLocal: setting('enable_local_logins'),
|
||||
loginRequired: Em.computed.alias('controllers.application.loginRequired'),
|
||||
|
||||
resetForm: function() {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import NavigationDefaultController from 'discourse/controllers/navigation/default';
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
|
||||
export default NavigationDefaultController.extend({
|
||||
subcategoryListSetting: Discourse.computed.setting('show_subcategory_list'),
|
||||
subcategoryListSetting: setting('show_subcategory_list'),
|
||||
showingParentCategory: Em.computed.none('category.parentCategory'),
|
||||
showingSubcategoryList: Em.computed.and('subcategoryListSetting', 'showingParentCategory'),
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { url } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.ArrayController.extend({
|
||||
needs: ['header'],
|
||||
loadingNotifications: Em.computed.alias('controllers.header.loadingNotifications'),
|
||||
myNotificationsUrl: Discourse.computed.url('/my/notifications')
|
||||
myNotificationsUrl: url('/my/notifications')
|
||||
});
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
import { setting } from 'discourse/lib/computed';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
|
||||
export default ObjectController.extend(CanCheckEmails, {
|
||||
|
||||
allowAvatarUpload: Discourse.computed.setting('allow_uploaded_avatars'),
|
||||
allowUserLocale: Discourse.computed.setting('allow_user_locale'),
|
||||
ssoOverridesAvatar: Discourse.computed.setting('sso_overrides_avatar'),
|
||||
allowBackgrounds: Discourse.computed.setting('allow_profile_backgrounds'),
|
||||
editHistoryVisible: Discourse.computed.setting('edit_history_visible_to_public'),
|
||||
allowAvatarUpload: setting('allow_uploaded_avatars'),
|
||||
allowUserLocale: setting('allow_user_locale'),
|
||||
ssoOverridesAvatar: setting('sso_overrides_avatar'),
|
||||
allowBackgrounds: setting('allow_profile_backgrounds'),
|
||||
editHistoryVisible: setting('edit_history_visible_to_public'),
|
||||
|
||||
selectedCategories: function(){
|
||||
return [].concat(this.get("model.watchedCategories"),
|
||||
@ -40,7 +41,7 @@ export default ObjectController.extend(CanCheckEmails, {
|
||||
cannotDeleteAccount: Em.computed.not('can_delete_account'),
|
||||
deleteDisabled: Em.computed.or('saving', 'deleting', 'cannotDeleteAccount'),
|
||||
|
||||
canEditName: Discourse.computed.setting('enable_names'),
|
||||
canEditName: setting('enable_names'),
|
||||
|
||||
nameInstructions: function() {
|
||||
return I18n.t(Discourse.SiteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions');
|
||||
|
||||
@ -1,13 +1,6 @@
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
/**
|
||||
This controller supports actions related to updating one's email address
|
||||
|
||||
@class PreferencesEmailController
|
||||
@extends ObjectController
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
export default ObjectController.extend({
|
||||
taken: false,
|
||||
saving: false,
|
||||
@ -17,7 +10,7 @@ export default ObjectController.extend({
|
||||
|
||||
newEmailEmpty: Em.computed.empty('newEmail'),
|
||||
saveDisabled: Em.computed.or('saving', 'newEmailEmpty', 'taken', 'unchanged'),
|
||||
unchanged: Discourse.computed.propertyEqual('newEmailLower', 'email'),
|
||||
unchanged: propertyEqual('newEmailLower', 'email'),
|
||||
|
||||
newEmailLower: function() {
|
||||
return this.get('newEmail').toLowerCase();
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { setting, propertyEqual } from 'discourse/lib/computed';
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
@ -8,11 +9,11 @@ export default ObjectController.extend(Presence, {
|
||||
errorMessage: null,
|
||||
newUsername: null,
|
||||
|
||||
maxLength: Discourse.computed.setting('max_username_length'),
|
||||
minLength: Discourse.computed.setting('min_username_length'),
|
||||
maxLength: setting('max_username_length'),
|
||||
minLength: setting('min_username_length'),
|
||||
newUsernameEmpty: Em.computed.empty('newUsername'),
|
||||
saveDisabled: Em.computed.or('saving', 'newUsernameEmpty', 'taken', 'unchanged', 'errorMessage'),
|
||||
unchanged: Discourse.computed.propertyEqual('newUsername', 'username'),
|
||||
unchanged: propertyEqual('newUsername', 'username'),
|
||||
|
||||
checkTaken: function() {
|
||||
if( this.get('newUsername') && this.get('newUsername').length < this.get('minLength') ) {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
import BufferedContent from 'discourse/mixins/buffered-content';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
|
||||
@ -21,7 +22,7 @@ export default Ember.Controller.extend(BufferedContent, {
|
||||
post: Ember.computed.alias('model'),
|
||||
currentlyEditing: Ember.computed.alias('controllers.queued-posts.editing'),
|
||||
|
||||
editing: Discourse.computed.propertyEqual('model', 'currentlyEditing'),
|
||||
editing: propertyEqual('model', 'currentlyEditing'),
|
||||
|
||||
_confirmDelete: updateState('rejected', {deleteUser: true}),
|
||||
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import searchForTerm from 'discourse/lib/search-for-term';
|
||||
|
||||
var _dontSearch = false;
|
||||
let _dontSearch = false;
|
||||
|
||||
export default Em.Controller.extend(Presence, {
|
||||
typeFilter: null,
|
||||
|
||||
contextType: function(key, value){
|
||||
if(arguments.length > 1) {
|
||||
// a bit hacky, consider cleaning this up, need to work through all observers though
|
||||
var context = $.extend({}, this.get('searchContext'));
|
||||
const context = $.extend({}, this.get('searchContext'));
|
||||
context.type = value;
|
||||
this.set('searchContext', context);
|
||||
}
|
||||
@ -29,8 +30,8 @@ export default Em.Controller.extend(Presence, {
|
||||
return null;
|
||||
}
|
||||
|
||||
var url = '/search?q=' + encodeURIComponent(this.get('term'));
|
||||
var searchContext = this.get('searchContext');
|
||||
let url = '/search?q=' + encodeURIComponent(this.get('term'));
|
||||
const searchContext = this.get('searchContext');
|
||||
|
||||
if (this.get('searchContextEnabled') && searchContext) {
|
||||
url += encodeURIComponent(" " + searchContext.type + ":" + searchContext.id);
|
||||
@ -41,14 +42,14 @@ export default Em.Controller.extend(Presence, {
|
||||
}.property('searchContext','term','searchContextEnabled'),
|
||||
|
||||
fullSearchUrl: function(){
|
||||
var url = this.get('fullSearchUrlRelative');
|
||||
const url = this.get('fullSearchUrlRelative');
|
||||
if (url) {
|
||||
return Discourse.getURL(url);
|
||||
}
|
||||
}.property('fullSearchUrlRelative'),
|
||||
|
||||
searchContextDescription: function(){
|
||||
var ctx = this.get('searchContext');
|
||||
const ctx = this.get('searchContext');
|
||||
if (ctx) {
|
||||
switch(Em.get(ctx, 'type')) {
|
||||
case 'topic':
|
||||
@ -71,7 +72,7 @@ export default Em.Controller.extend(Presence, {
|
||||
// If we need to perform another search
|
||||
newSearchNeeded: function() {
|
||||
this.set('noResults', false);
|
||||
var term = (this.get('term') || '').trim();
|
||||
const term = (this.get('term') || '').trim();
|
||||
if (term.length >= Discourse.SiteSettings.min_search_term_length) {
|
||||
this.set('loading', true);
|
||||
|
||||
@ -82,23 +83,32 @@ export default Em.Controller.extend(Presence, {
|
||||
this.set('selectedIndex', 0);
|
||||
}.observes('term', 'typeFilter'),
|
||||
|
||||
searchTerm: function(term, typeFilter) {
|
||||
var self = this;
|
||||
searchTerm(term, typeFilter) {
|
||||
const self = this;
|
||||
|
||||
var context;
|
||||
if(this.get('searchContextEnabled')){
|
||||
context = this.get('searchContext');
|
||||
// for cancelling debounced search
|
||||
if (this._cancelSearch){
|
||||
this._cancelSearch = null;
|
||||
return;
|
||||
}
|
||||
|
||||
searchForTerm(term, {
|
||||
typeFilter: typeFilter,
|
||||
searchContext: context,
|
||||
if (this._search) {
|
||||
this._search.abort();
|
||||
}
|
||||
|
||||
const searchContext = this.get('searchContextEnabled') ? this.get('searchContext') : null;
|
||||
|
||||
this._search = searchForTerm(term, {
|
||||
typeFilter,
|
||||
searchContext,
|
||||
fullSearchUrl: this.get('fullSearchUrl')
|
||||
}).then(function(results) {
|
||||
});
|
||||
|
||||
this._search.then(function(results) {
|
||||
self.setProperties({ noResults: !results, content: results });
|
||||
}).finally(function() {
|
||||
self.set('loading', false);
|
||||
}).catch(function() {
|
||||
self.set('loading', false);
|
||||
self._search = null;
|
||||
});
|
||||
},
|
||||
|
||||
@ -112,22 +122,36 @@ export default Em.Controller.extend(Presence, {
|
||||
}.observes('term'),
|
||||
|
||||
actions: {
|
||||
fullSearch: function() {
|
||||
var url = this.get('fullSearchUrlRelative');
|
||||
fullSearch() {
|
||||
const self = this;
|
||||
|
||||
if (this._search) {
|
||||
this._search.abort();
|
||||
}
|
||||
|
||||
// maybe we are debounced and delayed
|
||||
// stop that as well
|
||||
this._cancelSearch = true;
|
||||
Em.run.later(function(){
|
||||
self._cancelSearch = false;
|
||||
}, 400);
|
||||
|
||||
const url = this.get('fullSearchUrlRelative');
|
||||
if (url) {
|
||||
Discourse.URL.routeTo(url);
|
||||
}
|
||||
},
|
||||
moreOfType: function(type) {
|
||||
|
||||
moreOfType(type) {
|
||||
this.set('typeFilter', type);
|
||||
},
|
||||
|
||||
cancelType: function() {
|
||||
cancelType() {
|
||||
this.cancelTypeFilter();
|
||||
}
|
||||
},
|
||||
|
||||
cancelTypeFilter: function() {
|
||||
cancelTypeFilter() {
|
||||
this.set('typeFilter', null);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import Sharing from 'discourse/lib/sharing';
|
||||
import { longDateNoYear } from 'discourse/lib/formatter';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
needs: ['topic'],
|
||||
title: Ember.computed.alias('controllers.topic.model.title'),
|
||||
|
||||
displayDate: function() {
|
||||
return Discourse.Formatter.longDateNoYear(new Date(this.get('date')));
|
||||
return longDateNoYear(new Date(this.get('date')));
|
||||
}.property('date'),
|
||||
|
||||
// Close the share controller
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user