mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-24 08:09:13 -05:00
Refactor: Back all modals by controllers
This commit is contained in:
parent
e0dae88885
commit
0af0a214b2
74 changed files with 1555 additions and 1382 deletions
|
@ -155,9 +155,9 @@ Discourse = Ember.Application.createWithMixins({
|
|||
},
|
||||
|
||||
authenticationComplete: function(options) {
|
||||
// TODO, how to dispatch this to the view without the container?
|
||||
var loginView = Discourse.__container__.lookup('controller:modal').get('currentView');
|
||||
return loginView.authenticationComplete(options);
|
||||
// TODO, how to dispatch this to the controller without the container?
|
||||
var loginController = Discourse.__container__.lookup('controller:login');
|
||||
return loginController.authenticationComplete(options);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,14 +9,6 @@
|
|||
@module Discourse
|
||||
**/
|
||||
Discourse.ApplicationController = Discourse.Controller.extend({
|
||||
needs: ['modal'],
|
||||
|
||||
showLogin: function() {
|
||||
var modalController = this.get('controllers.modal');
|
||||
if (modalController) {
|
||||
modalController.show(Discourse.LoginView.create())
|
||||
}
|
||||
},
|
||||
|
||||
routeChanged: function(){
|
||||
if (window._gaq === undefined) { return; }
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
/**
|
||||
The modal for creating accounts
|
||||
|
||||
@class CreateAccountController
|
||||
@extends Discourse.Controller
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.CreateAccountController = Discourse.Controller.extend(Discourse.ModalFunctionality, {
|
||||
uniqueUsernameValidation: null,
|
||||
globalNicknameExists: false,
|
||||
complete: false,
|
||||
accountPasswordConfirm: 0,
|
||||
accountChallenge: 0,
|
||||
formSubmitted: false,
|
||||
|
||||
submitDisabled: function() {
|
||||
if (this.get('formSubmitted')) return true;
|
||||
if (this.get('nameValidation.failed')) return true;
|
||||
if (this.get('emailValidation.failed')) return true;
|
||||
if (this.get('usernameValidation.failed')) return true;
|
||||
if (this.get('passwordValidation.failed')) return true;
|
||||
return false;
|
||||
}.property('nameValidation.failed', 'emailValidation.failed', 'usernameValidation.failed', 'passwordValidation.failed', 'formSubmitted'),
|
||||
|
||||
passwordRequired: function() {
|
||||
return this.blank('authOptions.auth_provider');
|
||||
}.property('authOptions.auth_provider'),
|
||||
|
||||
// Validate the name
|
||||
nameValidation: function() {
|
||||
|
||||
// If blank, fail without a reason
|
||||
if (this.blank('accountName')) return Discourse.InputValidation.create({ failed: true });
|
||||
|
||||
if (this.get('accountPasswordConfirm') === 0) {
|
||||
this.fetchConfirmationValue();
|
||||
}
|
||||
|
||||
// If too short
|
||||
if (this.get('accountName').length < 3) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.name.too_short')
|
||||
});
|
||||
}
|
||||
|
||||
// Looks good!
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.name.ok')
|
||||
});
|
||||
}.property('accountName'),
|
||||
|
||||
// Check the email address
|
||||
emailValidation: function() {
|
||||
// If blank, fail without a reason
|
||||
var email;
|
||||
if (this.blank('accountEmail')) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true
|
||||
});
|
||||
}
|
||||
|
||||
email = this.get("accountEmail");
|
||||
if ((this.get('authOptions.email') === email) && this.get('authOptions.email_valid')) {
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.email.authenticated', {
|
||||
provider: this.get('authOptions.auth_provider')
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (Discourse.Utilities.emailValid(email)) {
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.email.ok')
|
||||
});
|
||||
}
|
||||
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.email.invalid')
|
||||
});
|
||||
}.property('accountEmail'),
|
||||
|
||||
usernameMatch: function() {
|
||||
if (this.usernameNeedsToBeValidatedWithEmail()) {
|
||||
if (this.get('emailValidation.failed')) {
|
||||
if (this.shouldCheckUsernameMatch()) {
|
||||
return this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.enter_email')
|
||||
}));
|
||||
} else {
|
||||
return this.set('uniqueUsernameValidation', Discourse.InputValidation.create({ failed: true }));
|
||||
}
|
||||
} else if (this.shouldCheckUsernameMatch()) {
|
||||
this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.checking')
|
||||
}));
|
||||
return this.checkUsernameAvailability();
|
||||
}
|
||||
}
|
||||
}.observes('accountEmail'),
|
||||
|
||||
basicUsernameValidation: function() {
|
||||
this.set('uniqueUsernameValidation', null);
|
||||
|
||||
// If blank, fail without a reason
|
||||
if (this.blank('accountUsername')) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true
|
||||
});
|
||||
}
|
||||
|
||||
// If too short
|
||||
if (this.get('accountUsername').length < 3) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.too_short')
|
||||
});
|
||||
}
|
||||
|
||||
// If too long
|
||||
if (this.get('accountUsername').length > 15) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.too_long')
|
||||
});
|
||||
}
|
||||
|
||||
this.checkUsernameAvailability();
|
||||
// Let's check it out asynchronously
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.checking')
|
||||
});
|
||||
}.property('accountUsername'),
|
||||
|
||||
shouldCheckUsernameMatch: function() {
|
||||
return !this.blank('accountUsername') && this.get('accountUsername').length > 2;
|
||||
},
|
||||
|
||||
checkUsernameAvailability: Discourse.debounce(function() {
|
||||
var _this = this;
|
||||
if (this.shouldCheckUsernameMatch()) {
|
||||
return Discourse.User.checkUsername(this.get('accountUsername'), this.get('accountEmail')).then(function(result) {
|
||||
_this.set('globalNicknameExists', false);
|
||||
if (result.available) {
|
||||
if (result.global_match) {
|
||||
_this.set('globalNicknameExists', true);
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.username.global_match')
|
||||
}));
|
||||
} else {
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.username.available')
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
if (result.suggestion) {
|
||||
if (result.global_match !== void 0 && result.global_match === false) {
|
||||
_this.set('globalNicknameExists', true);
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.global_mismatch', result)
|
||||
}));
|
||||
} else {
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.not_available', result)
|
||||
}));
|
||||
}
|
||||
} else if (result.errors) {
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: result.errors.join(' ')
|
||||
}));
|
||||
} else {
|
||||
_this.set('globalNicknameExists', true);
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.enter_email')
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 500),
|
||||
|
||||
// Actually wait for the async name check before we're 100% sure we're good to go
|
||||
usernameValidation: function() {
|
||||
var basicValidation, uniqueUsername;
|
||||
basicValidation = this.get('basicUsernameValidation');
|
||||
uniqueUsername = this.get('uniqueUsernameValidation');
|
||||
if (uniqueUsername) {
|
||||
return uniqueUsername;
|
||||
}
|
||||
return basicValidation;
|
||||
}.property('uniqueUsernameValidation', 'basicUsernameValidation'),
|
||||
|
||||
usernameNeedsToBeValidatedWithEmail: function() {
|
||||
return( this.get('globalNicknameExists') || false );
|
||||
},
|
||||
|
||||
// Validate the password
|
||||
passwordValidation: function() {
|
||||
var password;
|
||||
if (!this.get('passwordRequired')) {
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true
|
||||
});
|
||||
}
|
||||
|
||||
// If blank, fail without a reason
|
||||
password = this.get("accountPassword");
|
||||
if (this.blank('accountPassword')) {
|
||||
return Discourse.InputValidation.create({ failed: true });
|
||||
}
|
||||
|
||||
// If too short
|
||||
if (password.length < 6) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.password.too_short')
|
||||
});
|
||||
}
|
||||
|
||||
// Looks good!
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.password.ok')
|
||||
});
|
||||
}.property('accountPassword'),
|
||||
|
||||
fetchConfirmationValue: function() {
|
||||
var createAccountController = this;
|
||||
return Discourse.ajax('/users/hp.json').then(function (json) {
|
||||
createAccountController.set('accountPasswordConfirm', json.value);
|
||||
createAccountController.set('accountChallenge', json.challenge.split("").reverse().join(""));
|
||||
});
|
||||
},
|
||||
|
||||
createAccount: function() {
|
||||
var createAccountController = this;
|
||||
this.set('formSubmitted', true);
|
||||
var name = this.get('accountName');
|
||||
var email = this.get('accountEmail');
|
||||
var password = this.get('accountPassword');
|
||||
var username = this.get('accountUsername');
|
||||
var passwordConfirm = this.get('accountPasswordConfirm');
|
||||
var challenge = this.get('accountChallenge');
|
||||
return Discourse.User.createAccount(name, email, password, username, passwordConfirm, challenge).then(function(result) {
|
||||
if (result.success) {
|
||||
createAccountController.flash(result.message);
|
||||
createAccountController.set('complete', true);
|
||||
} else {
|
||||
createAccountController.flash(result.message || Em.String.i18n('create_account.failed'), 'error');
|
||||
createAccountController.set('formSubmitted', false);
|
||||
}
|
||||
if (result.active) {
|
||||
return window.location.reload();
|
||||
}
|
||||
}, function() {
|
||||
createAccountController.set('formSubmitted', false);
|
||||
return createAccountController.flash(Em.String.i18n('create_account.failed'), 'error');
|
||||
});
|
||||
}
|
||||
|
||||
});
|
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
Modal for editing / creating a category
|
||||
|
||||
@class EditCategoryController
|
||||
@extends Discourse.ObjectController
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.EditCategoryController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
generalSelected: Ember.computed.equal('selectedTab', 'general'),
|
||||
securitySelected: Ember.computed.equal('selectedTab', 'security'),
|
||||
settingsSelected: Ember.computed.equal('selectedTab', 'settings'),
|
||||
foregroundColors: ['FFFFFF', '000000'],
|
||||
|
||||
descriptionChanged: function() {
|
||||
if (this.present('description')) {
|
||||
this.set('controllers.modal.modalClass', 'edit-category-modal full');
|
||||
} else {
|
||||
this.set('controllers.modal.modalClass', 'edit-category-modal small');
|
||||
}
|
||||
}.observes('description'),
|
||||
|
||||
title: function() {
|
||||
if (this.get('id')) return Em.String.i18n("category.edit_long");
|
||||
if (this.get('isUncategorized')) return Em.String.i18n("category.edit_uncategorized");
|
||||
return Em.String.i18n("category.create");
|
||||
}.property('id'),
|
||||
|
||||
titleChanged: function() {
|
||||
this.set('controllers.modal.title', this.get('title'));
|
||||
}.observes('title'),
|
||||
|
||||
selectGeneral: function() {
|
||||
this.set('selectedTab', 'general');
|
||||
},
|
||||
|
||||
selectSecurity: function() {
|
||||
this.set('selectedTab', 'security');
|
||||
},
|
||||
|
||||
selectSettings: function() {
|
||||
this.set('selectedTab', 'settings');
|
||||
},
|
||||
|
||||
disabled: function() {
|
||||
if (this.get('saving') || this.get('deleting')) return true;
|
||||
if (!this.get('name')) return true;
|
||||
if (!this.get('color')) return true;
|
||||
return false;
|
||||
}.property('name', 'color', 'deleting'),
|
||||
|
||||
deleteVisible: function() {
|
||||
return (this.get('id') && this.get('topic_count') === 0);
|
||||
}.property('id', 'topic_count'),
|
||||
|
||||
deleteDisabled: function() {
|
||||
return (this.get('deleting') || this.get('saving') || false);
|
||||
}.property('disabled', 'saving', 'deleting'),
|
||||
|
||||
colorStyle: function() {
|
||||
return "background-color: #" + (this.get('color')) + "; color: #" + (this.get('text_color')) + ";";
|
||||
}.property('color', 'text_color'),
|
||||
|
||||
// background colors are available as a pipe-separated string
|
||||
backgroundColors: function() {
|
||||
var categories = Discourse.Category.list();
|
||||
return Discourse.SiteSettings.category_colors.split("|").map(function(i) { return i.toUpperCase(); }).concat(
|
||||
categories.map(function(c) { return c.color.toUpperCase(); }) ).uniq();
|
||||
}.property('Discourse.SiteSettings.category_colors'),
|
||||
|
||||
usedBackgroundColors: function() {
|
||||
var categories = Discourse.Category.list();
|
||||
|
||||
var currentCat = this.get('model');
|
||||
|
||||
return categories.map(function(c) {
|
||||
// If editing a category, don't include its color:
|
||||
return (currentCat.get('id') && currentCat.get('color').toUpperCase() === c.color.toUpperCase()) ? null : c.color.toUpperCase();
|
||||
}, this).compact();
|
||||
}.property('id', 'color'),
|
||||
|
||||
categoryName: function() {
|
||||
var name = this.get('name') || "";
|
||||
return name.trim().length > 0 ? name : Em.String.i18n("preview");
|
||||
}.property('name'),
|
||||
|
||||
buttonTitle: function() {
|
||||
if (this.get('saving')) return Em.String.i18n("saving");
|
||||
if (this.get('isUncategorized')) return Em.String.i18n("save");
|
||||
return (this.get('id') ? Em.String.i18n("category.save") : Em.String.i18n("category.create"));
|
||||
}.property('saving', 'id'),
|
||||
|
||||
deleteButtonTitle: function() {
|
||||
return Em.String.i18n('category.delete');
|
||||
}.property(),
|
||||
|
||||
didInsertElement: function() {
|
||||
this._super();
|
||||
|
||||
if (this.get('id')) {
|
||||
this.set('loading', true);
|
||||
var categoryController = this;
|
||||
|
||||
// We need the topic_count to be correct, so get the most up-to-date info about this category from the server.
|
||||
Discourse.Category.findBySlugOrId( this.get('slug') || this.get('id') ).then( function(cat) {
|
||||
categoryController.set('category', cat);
|
||||
Discourse.Site.instance().updateCategory(cat);
|
||||
categoryController.set('id', categoryController.get('slug'));
|
||||
categoryController.set('loading', false);
|
||||
});
|
||||
} else if( this.get('isUncategorized') ) {
|
||||
this.set('category', Discourse.Category.uncategorizedInstance());
|
||||
} else {
|
||||
this.set('category', Discourse.Category.create({ color: 'AB9364', text_color: 'FFFFFF', hotness: 5 }));
|
||||
}
|
||||
},
|
||||
|
||||
showCategoryTopic: function() {
|
||||
$('#discourse-modal').modal('hide');
|
||||
Discourse.URL.routeTo(this.get('topic_url'));
|
||||
return false;
|
||||
},
|
||||
|
||||
addGroup: function(){
|
||||
this.get('model').addGroup(this.get("selectedGroup"));
|
||||
},
|
||||
|
||||
removeGroup: function(group){
|
||||
// OBVIOUS, Ember treats this as Ember.String, we need a real string here
|
||||
group = group + "";
|
||||
this.get('model').removeGroup(group);
|
||||
},
|
||||
|
||||
saveCategory: function() {
|
||||
var categoryController = this;
|
||||
this.set('saving', true);
|
||||
|
||||
|
||||
if( this.get('isUncategorized') ) {
|
||||
$.when(
|
||||
Discourse.SiteSetting.update('uncategorized_color', this.get('color')),
|
||||
Discourse.SiteSetting.update('uncategorized_text_color', this.get('text_color')),
|
||||
Discourse.SiteSetting.update('uncategorized_name', this.get('name'))
|
||||
).then(function(result) {
|
||||
// success
|
||||
$('#discourse-modal').modal('hide');
|
||||
// We can't redirect to the uncategorized category on save because the slug
|
||||
// might have changed.
|
||||
Discourse.URL.redirectTo("/categories");
|
||||
}, function(errors) {
|
||||
// errors
|
||||
if(errors.length === 0) errors.push(Em.String.i18n("category.save_error"));
|
||||
categoryController.displayErrors(errors);
|
||||
categoryController.set('saving', false);
|
||||
});
|
||||
} else {
|
||||
this.get('model').save().then(function(result) {
|
||||
// success
|
||||
$('#discourse-modal').modal('hide');
|
||||
Discourse.URL.redirectTo("/category/" + Discourse.Category.slugFor(result.category));
|
||||
}, function(errors) {
|
||||
// errors
|
||||
if(errors.length === 0) errors.push(Em.String.i18n("category.creation_error"));
|
||||
categoryController.displayErrors(errors);
|
||||
categoryController.set('saving', false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
deleteCategory: function() {
|
||||
var categoryController = this;
|
||||
this.set('deleting', true);
|
||||
$('#discourse-modal').modal('hide');
|
||||
bootbox.confirm(Em.String.i18n("category.delete_confirm"), Em.String.i18n("no_value"), Em.String.i18n("yes_value"), function(result) {
|
||||
if (result) {
|
||||
categoryController.get('category').destroy().then(function(){
|
||||
// success
|
||||
Discourse.URL.redirectTo("/categories");
|
||||
}, function(jqXHR){
|
||||
// error
|
||||
$('#discourse-modal').modal('show');
|
||||
categoryController.displayErrors([Em.String.i18n("category.delete_error")]);
|
||||
categoryController.set('deleting', false);
|
||||
});
|
||||
} else {
|
||||
$('#discourse-modal').modal('show');
|
||||
categoryController.set('deleting', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
Modal related to auto closing of topics
|
||||
|
||||
@class EditTopicAutoCloseController
|
||||
@extends Discourse.ObjectController
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.EditTopicAutoCloseController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
|
||||
setDays: function() {
|
||||
if( this.get('auto_close_at') ) {
|
||||
var closeTime = Date.create( this.get('auto_close_at') );
|
||||
if (closeTime.isFuture()) {
|
||||
this.set('auto_close_days', closeTime.daysSince());
|
||||
}
|
||||
} else {
|
||||
this.set('auto_close_days', "");
|
||||
}
|
||||
}.observes('auto_close_at'),
|
||||
|
||||
saveAutoClose: function() {
|
||||
this.setAutoClose( parseFloat(this.get('auto_close_days')) );
|
||||
},
|
||||
|
||||
removeAutoClose: function() {
|
||||
this.setAutoClose(null);
|
||||
},
|
||||
|
||||
setAutoClose: function(days) {
|
||||
var editTopicAutoCloseController = this;
|
||||
Discourse.ajax({
|
||||
url: "/t/" + this.get('id') + "/autoclose",
|
||||
type: 'PUT',
|
||||
dataType: 'json',
|
||||
data: { auto_close_days: days > 0 ? days : null }
|
||||
}).then(function(){
|
||||
editTopicAutoCloseController.set('auto_close_at', Date.create(days + ' days from now').toJSON());
|
||||
}, function (error) {
|
||||
bootbox.alert(Em.String.i18n('generic_error'));
|
||||
});
|
||||
}
|
||||
|
||||
});
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
This controller supports actions related to flagging
|
||||
|
||||
@class FlagController
|
||||
@extends Discourse.ObjectController
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.FlagController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
|
||||
// trick to bind user / post to flag
|
||||
boundFlags: function() {
|
||||
var _this = this;
|
||||
var original = this.get('flagsAvailable');
|
||||
if(original){
|
||||
return $.map(original, function(v){
|
||||
var b = Discourse.BoundPostActionType.create(v);
|
||||
b.set('post', _this.get('model'));
|
||||
return b;
|
||||
});
|
||||
}
|
||||
}.property('flagsAvailable.@each'),
|
||||
|
||||
changePostActionType: function(action) {
|
||||
if (this.get('postActionTypeId') === action.id) return false;
|
||||
|
||||
this.get('boundFlags').setEach('selected', false);
|
||||
action.set('selected', true);
|
||||
|
||||
this.set('postActionTypeId', action.id);
|
||||
this.set('isCustomFlag', action.is_custom_flag);
|
||||
this.set('selected', action);
|
||||
return false;
|
||||
},
|
||||
|
||||
showSubmit: function() {
|
||||
if (this.get('postActionTypeId')) {
|
||||
if (this.get('isCustomFlag')) {
|
||||
var m = this.get('selected.message');
|
||||
return m && m.length >= 10 && m.length <= 500;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}.property('isCustomFlag', 'selected.customMessageLength', 'postActionTypeId'),
|
||||
|
||||
submitText: function(){
|
||||
var action = this.get('selected');
|
||||
if (this.get('selected.is_custom_flag')) {
|
||||
return Em.String.i18n("flagging.notify_action");
|
||||
} else {
|
||||
return Em.String.i18n("flagging.action");
|
||||
}
|
||||
}.property('selected'),
|
||||
|
||||
createFlag: function() {
|
||||
var _this = this;
|
||||
|
||||
var action = this.get('selected');
|
||||
var postAction = this.get('actionByName.' + (action.get('name_key')));
|
||||
|
||||
var actionType = Discourse.Site.instance().postActionTypeById(this.get('postActionTypeId'));
|
||||
if (postAction) {
|
||||
postAction.act({
|
||||
message: action.get('message')
|
||||
}).then(function() {
|
||||
return $('#discourse-modal').modal('hide');
|
||||
}, function(errors) {
|
||||
return _this.displayErrors(errors);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
The modal for when the user has forgotten their password
|
||||
|
||||
@class ForgotPasswordController
|
||||
@extends Discourse.Controller
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ForgotPasswordController = Discourse.Controller.extend(Discourse.ModalFunctionality, {
|
||||
|
||||
// You need a value in the field to submit it.
|
||||
submitDisabled: function() {
|
||||
return this.blank('accountEmailOrUsername');
|
||||
}.property('accountEmailOrUsername'),
|
||||
|
||||
submit: function() {
|
||||
|
||||
Discourse.ajax("/session/forgot_password", {
|
||||
data: { login: this.get('accountEmailOrUsername') },
|
||||
type: 'POST'
|
||||
});
|
||||
|
||||
// don't tell people what happened, this keeps it more secure (ensure same on server)
|
||||
this.flash(Em.String.i18n('forgot_password.complete'));
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
|
@ -0,0 +1,85 @@
|
|||
/*jshint newcap:false*/
|
||||
/*global diff_match_patch:true assetPath:true*/
|
||||
|
||||
/**
|
||||
This controller handles displaying of history
|
||||
|
||||
@class HistoryController
|
||||
@extends Discourse.ObjectController
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.HistoryController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
diffLibraryLoaded: false,
|
||||
diff: null,
|
||||
|
||||
init: function(){
|
||||
this._super();
|
||||
var historyController = this;
|
||||
$LAB.script(assetPath('defer/google_diff_match_patch')).wait(function(){
|
||||
historyController.set('diffLibraryLoaded', true);
|
||||
});
|
||||
},
|
||||
|
||||
loadSide: function(side) {
|
||||
if (this.get("version" + side)) {
|
||||
var orig = this.get('model');
|
||||
var version = this.get("version" + side + ".number");
|
||||
if (version === orig.get('version')) {
|
||||
this.set("post" + side, orig);
|
||||
} else {
|
||||
var historyController = this;
|
||||
Discourse.Post.loadVersion(orig.get('id'), version).then(function(post) {
|
||||
historyController.set("post" + side, post);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
changedLeftVersion: function() {
|
||||
this.loadSide("Left");
|
||||
}.observes('versionLeft'),
|
||||
|
||||
changedRightVersion: function() {
|
||||
this.loadSide("Right");
|
||||
}.observes('versionRight'),
|
||||
|
||||
loadedPosts: function() {
|
||||
if (this.get('diffLibraryLoaded') && this.get('postLeft') && this.get('postRight')) {
|
||||
var dmp = new diff_match_patch(),
|
||||
before = this.get("postLeft.cooked"),
|
||||
after = this.get("postRight.cooked"),
|
||||
diff = dmp.diff_main(before, after);
|
||||
dmp.diff_cleanupSemantic(diff);
|
||||
this.set('diff', dmp.diff_prettyHtml(diff));
|
||||
}
|
||||
}.observes('diffLibraryLoaded', 'postLeft', 'postRight'),
|
||||
|
||||
refresh: function() {
|
||||
this.setProperties({
|
||||
loading: true,
|
||||
postLeft: null,
|
||||
postRight: null
|
||||
});
|
||||
|
||||
var historyController = this;
|
||||
this.get('model').loadVersions().then(function(result) {
|
||||
result.each(function(item) {
|
||||
item.description = "v" + item.number + " - " + Date.create(item.created_at).relative() + " - " +
|
||||
Em.String.i18n("changed_by", { author: item.display_username });
|
||||
});
|
||||
|
||||
console.log('wat');
|
||||
historyController.setProperties({
|
||||
loading: false,
|
||||
versionLeft: result.first(),
|
||||
versionRight: result.last(),
|
||||
versions: result
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
The modal for inviting a user to a topic
|
||||
|
||||
@class ImageSelectorController
|
||||
@extends Discourse.Controller
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ImageSelectorController = Discourse.Controller.extend(Discourse.ModalFunctionality, {
|
||||
|
||||
selectLocal: function() {
|
||||
this.set('localSelected', true);
|
||||
},
|
||||
|
||||
selectRemote: function() {
|
||||
this.set('localSelected', false);
|
||||
},
|
||||
|
||||
remoteSelected: Em.computed.not('localSelected')
|
||||
|
||||
});
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
The modal for inviting a user to a topic
|
||||
|
||||
@class InviteController
|
||||
@extends Discourse.Controller
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.InviteController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
|
||||
disabled: function() {
|
||||
if (this.get('saving')) return true;
|
||||
if (this.blank('email')) return true;
|
||||
if (!Discourse.Utilities.emailValid(this.get('email'))) return true;
|
||||
return false;
|
||||
}.property('email', 'saving'),
|
||||
|
||||
buttonTitle: function() {
|
||||
if (this.get('saving')) return Em.String.i18n('topic.inviting');
|
||||
return Em.String.i18n('topic.invite_reply.action');
|
||||
}.property('saving'),
|
||||
|
||||
successMessage: function() {
|
||||
return Em.String.i18n('topic.invite_reply.success', { email: this.get('email') });
|
||||
}.property('email'),
|
||||
|
||||
createInvite: function() {
|
||||
var inviteController = this;
|
||||
this.set('saving', true);
|
||||
this.set('error', false);
|
||||
this.get('model').inviteUser(this.get('email')).then(function() {
|
||||
// Success
|
||||
inviteController.set('saving', false);
|
||||
return inviteController.set('finished', true);
|
||||
}, function() {
|
||||
// Failure
|
||||
inviteController.set('error', true);
|
||||
return inviteController.set('saving', false);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
The modal for inviting a user to a private topic
|
||||
|
||||
@class InvitePrivateController
|
||||
@extends Discourse.Controller
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.InvitePrivateController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
|
||||
disabled: function() {
|
||||
if (this.get('saving')) return true;
|
||||
return this.blank('emailOrUsername');
|
||||
}.property('emailOrUsername', 'saving'),
|
||||
|
||||
buttonTitle: function() {
|
||||
if (this.get('saving')) return Em.String.i18n('topic.inviting');
|
||||
return Em.String.i18n('topic.invite_private.action');
|
||||
}.property('saving'),
|
||||
|
||||
invite: function() {
|
||||
var invitePrivateController = this;
|
||||
this.set('saving', true);
|
||||
this.set('error', false);
|
||||
// Invite the user to the private message
|
||||
this.get('content').inviteUser(this.get('emailOrUsername')).then(function() {
|
||||
// Success
|
||||
invitePrivateController.set('saving', false);
|
||||
invitePrivateController.set('finished', true);
|
||||
}, function() {
|
||||
// Failure
|
||||
invitePrivateController.set('error', true);
|
||||
invitePrivateController.set('saving', false);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
|
@ -24,11 +24,6 @@ Discourse.ListCategoriesController = Discourse.ObjectController.extend({
|
|||
});
|
||||
}.property('categories.@each'),
|
||||
|
||||
editCategory: function(category) {
|
||||
this.get('controllers.modal').show(Discourse.EditCategoryView.create({ category: category }));
|
||||
return false;
|
||||
},
|
||||
|
||||
canEdit: function() {
|
||||
var u = Discourse.User.current();
|
||||
return u && u.admin;
|
||||
|
|
|
@ -101,11 +101,6 @@ Discourse.ListController = Discourse.Controller.extend({
|
|||
});
|
||||
},
|
||||
|
||||
createCategory: function() {
|
||||
var _ref;
|
||||
return (_ref = this.get('controllers.modal')) ? _ref.show(Discourse.EditCategoryView.create()) : void 0;
|
||||
},
|
||||
|
||||
canEditCategory: function() {
|
||||
if( this.present('category') ) {
|
||||
var u = Discourse.User.current();
|
||||
|
@ -113,12 +108,7 @@ Discourse.ListController = Discourse.Controller.extend({
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
}.property('category'),
|
||||
|
||||
editCategory: function() {
|
||||
this.get('controllers.modal').show(Discourse.EditCategoryView.create({ category: this.get('category') }));
|
||||
return false;
|
||||
}
|
||||
}.property('category')
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -41,14 +41,6 @@ Discourse.ListTopicsController = Discourse.ObjectController.extend({
|
|||
this.toggleProperty('rankDetailsVisible');
|
||||
},
|
||||
|
||||
// Show rank details
|
||||
showRankDetails: function(topic) {
|
||||
var modalController = this.get('controllers.modal');
|
||||
if (modalController) {
|
||||
modalController.show(Discourse.TopicRankDetailsView.create({ topic: topic }));
|
||||
}
|
||||
},
|
||||
|
||||
createTopic: function() {
|
||||
this.get('controllers.list').createTopic();
|
||||
},
|
||||
|
|
156
app/assets/javascripts/discourse/controllers/login_controller.js
Normal file
156
app/assets/javascripts/discourse/controllers/login_controller.js
Normal file
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
This controller supports actions related to flagging
|
||||
|
||||
@class LoginController
|
||||
@extends Discourse.Controller
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.LoginController = Discourse.Controller.extend(Discourse.ModalFunctionality, {
|
||||
needs: ['modal', 'createAccount'],
|
||||
authenticate: null,
|
||||
loggingIn: false,
|
||||
|
||||
site: function() {
|
||||
return Discourse.Site.instance();
|
||||
}.property(),
|
||||
|
||||
|
||||
/**
|
||||
Determines whether at least one login button is enabled
|
||||
**/
|
||||
hasAtLeastOneLoginButton: function() {
|
||||
return Discourse.SiteSettings.enable_google_logins ||
|
||||
Discourse.SiteSettings.enable_facebook_logins ||
|
||||
Discourse.SiteSettings.enable_cas_logins ||
|
||||
Discourse.SiteSettings.enable_twitter_logins ||
|
||||
Discourse.SiteSettings.enable_yahoo_logins ||
|
||||
Discourse.SiteSettings.enable_github_logins ||
|
||||
Discourse.SiteSettings.enable_persona_logins;
|
||||
}.property(),
|
||||
|
||||
loginButtonText: function() {
|
||||
return this.get('loggingIn') ? Em.String.i18n('login.logging_in') : Em.String.i18n('login.title');
|
||||
}.property('loggingIn'),
|
||||
|
||||
loginDisabled: function() {
|
||||
return this.get('loggingIn') || this.blank('loginName') || this.blank('loginPassword');
|
||||
}.property('loginName', 'loginPassword', 'loggingIn'),
|
||||
|
||||
login: function() {
|
||||
this.set('loggingIn', true);
|
||||
|
||||
var loginController = this;
|
||||
Discourse.ajax("/session", {
|
||||
data: { login: this.get('loginName'), password: this.get('loginPassword') },
|
||||
type: 'POST'
|
||||
}).then(function (result) {
|
||||
// Successful login
|
||||
if (result.error) {
|
||||
loginController.set('loggingIn', false);
|
||||
if( result.reason === 'not_activated' ) {
|
||||
loginController.send('showNotActivated', {
|
||||
username: loginController.get('loginName'),
|
||||
sentTo: result.sent_to_email,
|
||||
currentEmail: result.current_email
|
||||
});
|
||||
}
|
||||
loginController.flash(result.error, 'error');
|
||||
} else {
|
||||
// Trigger the browser's password manager using the hidden static login form:
|
||||
var $hidden_login_form = $('#hidden-login-form');
|
||||
$hidden_login_form.find('input[name=username]').val(loginController.get('loginName'));
|
||||
$hidden_login_form.find('input[name=password]').val(loginController.get('loginPassword'));
|
||||
$hidden_login_form.find('input[name=redirect]').val(window.location.href);
|
||||
$hidden_login_form.find('input[name=authenticity_token]').val($('meta[name=csrf-token]').attr('content'));
|
||||
$hidden_login_form.submit();
|
||||
}
|
||||
|
||||
}, function(result) {
|
||||
// Failed to login
|
||||
loginController.flash(Em.String.i18n('login.error'), 'error');
|
||||
loginController.set('loggingIn', false);
|
||||
})
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
authMessage: (function() {
|
||||
if (this.blank('authenticate')) return "";
|
||||
return Em.String.i18n("login." + (this.get('authenticate')) + ".message");
|
||||
}).property('authenticate'),
|
||||
|
||||
twitterLogin: function() {
|
||||
this.set('authenticate', 'twitter');
|
||||
var left = this.get('lastX') - 400;
|
||||
var top = this.get('lastY') - 200;
|
||||
return window.open(Discourse.getURL("/auth/twitter"), "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
},
|
||||
|
||||
facebookLogin: function() {
|
||||
this.set('authenticate', 'facebook');
|
||||
var left = this.get('lastX') - 400;
|
||||
var top = this.get('lastY') - 200;
|
||||
return window.open(Discourse.getURL("/auth/facebook"), "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
},
|
||||
|
||||
casLogin: function() {
|
||||
var left, top;
|
||||
this.set('authenticate', 'cas');
|
||||
left = this.get('lastX') - 400;
|
||||
top = this.get('lastY') - 200;
|
||||
return window.open("/auth/cas", "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
},
|
||||
|
||||
openidLogin: function(provider) {
|
||||
var left = this.get('lastX') - 400;
|
||||
var top = this.get('lastY') - 200;
|
||||
if (provider === "yahoo") {
|
||||
this.set("authenticate", 'yahoo');
|
||||
return window.open(Discourse.getURL("/auth/yahoo"), "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
} else {
|
||||
window.open(Discourse.getURL("/auth/google"), "_blank", "menubar=no,status=no,height=500,width=850,left=" + left + ",top=" + top);
|
||||
return this.set("authenticate", 'google');
|
||||
}
|
||||
},
|
||||
|
||||
githubLogin: function() {
|
||||
this.set('authenticate', 'github');
|
||||
var left = this.get('lastX') - 400;
|
||||
var top = this.get('lastY') - 200;
|
||||
return window.open(Discourse.getURL("/auth/github"), "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
},
|
||||
|
||||
personaLogin: function() {
|
||||
navigator.id.request();
|
||||
},
|
||||
|
||||
authenticationComplete: function(options) {
|
||||
if (options.awaiting_approval) {
|
||||
this.flash(Em.String.i18n('login.awaiting_approval'), 'success');
|
||||
this.set('authenticate', null);
|
||||
return;
|
||||
}
|
||||
if (options.awaiting_activation) {
|
||||
this.flash(Em.String.i18n('login.awaiting_confirmation'), 'success');
|
||||
this.set('authenticate', null);
|
||||
return;
|
||||
}
|
||||
// Reload the page if we're authenticated
|
||||
if (options.authenticated) {
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
var createAccountController = this.get('controllers.createAccount');
|
||||
createAccountController.setProperties({
|
||||
accountEmail: options.email,
|
||||
accountUsername: options.username,
|
||||
accountName: options.name,
|
||||
authOptions: Em.Object.create(options)
|
||||
})
|
||||
this.send('showCreateAccount');
|
||||
}
|
||||
|
||||
});
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
Modal related to auto closing of topics
|
||||
|
||||
@class MergeTopicController
|
||||
@extends Discourse.ObjectController
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.MergeTopicController = Discourse.ObjectController.extend(Discourse.SelectedPostsCount, Discourse.ModalFunctionality, {
|
||||
needs: ['topic'],
|
||||
|
||||
topicController: Em.computed.alias('controllers.topic'),
|
||||
selectedPosts: Em.computed.alias('topicController.selectedPosts'),
|
||||
allPostsSelected: Em.computed.alias('topicController.allPostsSelected'),
|
||||
|
||||
buttonDisabled: function() {
|
||||
if (this.get('saving')) return true;
|
||||
return this.blank('selectedTopicId');
|
||||
}.property('selectedTopicId', 'saving'),
|
||||
|
||||
buttonTitle: function() {
|
||||
if (this.get('saving')) return Em.String.i18n('saving');
|
||||
return Em.String.i18n('topic.merge_topic.title');
|
||||
}.property('saving'),
|
||||
|
||||
movePostsToExistingTopic: function() {
|
||||
this.set('saving', true);
|
||||
|
||||
var moveSelectedView = this;
|
||||
|
||||
var promise = null;
|
||||
if (this.get('allPostsSelected')) {
|
||||
promise = Discourse.Topic.mergeTopic(this.get('id'), this.get('selectedTopicId'));
|
||||
} else {
|
||||
var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); });
|
||||
promise = Discourse.Topic.movePosts(this.get('id'), {
|
||||
destination_topic_id: this.get('selectedTopicId'),
|
||||
post_ids: postIds
|
||||
});
|
||||
}
|
||||
|
||||
promise.then(function(result) {
|
||||
// Posts moved
|
||||
$('#discourse-modal').modal('hide');
|
||||
moveSelectedView.get('topicController').toggleMultiSelect();
|
||||
Em.run.next(function() { Discourse.URL.routeTo(result.url); });
|
||||
}, function() {
|
||||
// Error moving posts
|
||||
moveSelectedView.flash(Em.String.i18n('topic.merge_topic.error'));
|
||||
moveSelectedView.set('saving', false);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
|
@ -7,9 +7,7 @@
|
|||
@module Discourse
|
||||
**/
|
||||
Discourse.ModalController = Discourse.Controller.extend({
|
||||
show: function(view) {
|
||||
this.set('currentView', view);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
Modal displayed to a user when they are not active yet.
|
||||
|
||||
@class NotActivatedController
|
||||
@extends Discourse.Controller
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.NotActivatedController = Discourse.Controller.extend(Discourse.ModalFunctionality, {
|
||||
emailSent: false,
|
||||
|
||||
sendActivationEmail: function() {
|
||||
Discourse.ajax('/users/' + this.get('username') + '/send_activation_email');
|
||||
this.set('emailSent', true);
|
||||
}
|
||||
|
||||
});
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
Modal related to auto closing of topics
|
||||
|
||||
@class SplitTopicController
|
||||
@extends Discourse.ObjectController
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.SplitTopicController = Discourse.ObjectController.extend(Discourse.SelectedPostsCount, Discourse.ModalFunctionality, {
|
||||
needs: ['topic'],
|
||||
|
||||
topicController: Em.computed.alias('controllers.topic'),
|
||||
selectedPosts: Em.computed.alias('topicController.selectedPosts'),
|
||||
saving: false,
|
||||
|
||||
buttonDisabled: function() {
|
||||
if (this.get('saving')) return true;
|
||||
return this.blank('topicName');
|
||||
}.property('saving', 'topicName'),
|
||||
|
||||
buttonTitle: function() {
|
||||
if (this.get('saving')) return Em.String.i18n('saving');
|
||||
return Em.String.i18n('topic.split_topic.action');
|
||||
}.property('saving'),
|
||||
|
||||
movePostsToNewTopic: function() {
|
||||
this.set('saving', true);
|
||||
|
||||
var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); });
|
||||
var moveSelectedView = this;
|
||||
|
||||
Discourse.Topic.movePosts(this.get('id'), {
|
||||
title: this.get('topicName'),
|
||||
post_ids: postIds
|
||||
}).then(function(result) {
|
||||
// Posts moved
|
||||
$('#discourse-modal').modal('hide');
|
||||
moveSelectedView.get('topicController').toggleMultiSelect();
|
||||
Em.run.next(function() { Discourse.URL.routeTo(result.url); });
|
||||
}, function() {
|
||||
// Error moving posts
|
||||
moveSelectedView.flash(Em.String.i18n('topic.split_topic.error'));
|
||||
moveSelectedView.set('saving', false);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
|
@ -16,15 +16,6 @@ Discourse.TopicAdminMenuController = Discourse.ObjectController.extend({
|
|||
|
||||
hide: function() {
|
||||
this.set('visible', false);
|
||||
},
|
||||
|
||||
autoClose: function() {
|
||||
var modalController = this.get('controllers.modal');
|
||||
if (modalController) {
|
||||
var v = Discourse.EditTopicAutoCloseView.create();
|
||||
v.set('topic', this.get('content'));
|
||||
modalController.show(v);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -107,29 +107,6 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
|
|||
this.toggleProperty('summaryCollapsed');
|
||||
},
|
||||
|
||||
splitTopic: function() {
|
||||
var modalController = this.get('controllers.modal');
|
||||
if (!modalController) return;
|
||||
|
||||
modalController.show(Discourse.SplitTopicView.create({
|
||||
topicController: this,
|
||||
topic: this.get('content'),
|
||||
selectedPosts: this.get('selectedPosts')
|
||||
}));
|
||||
},
|
||||
|
||||
mergeTopic: function() {
|
||||
var modalController = this.get('controllers.modal');
|
||||
if (!modalController) return;
|
||||
|
||||
modalController.show(Discourse.MergeTopicView.create({
|
||||
topicController: this,
|
||||
topic: this.get('content'),
|
||||
allPostsSelected: this.get('allPostsSelected'),
|
||||
selectedPosts: this.get('selectedPosts')
|
||||
}));
|
||||
},
|
||||
|
||||
deleteSelected: function() {
|
||||
var topicController = this;
|
||||
bootbox.confirm(Em.String.i18n("post.delete.confirm", { count: this.get('selectedPostsCount')}), function(result) {
|
||||
|
@ -432,47 +409,6 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
|
|||
actionType.loadUsers();
|
||||
},
|
||||
|
||||
showPrivateInviteModal: function() {
|
||||
var modal = Discourse.InvitePrivateModalView.create({
|
||||
topic: this.get('content')
|
||||
});
|
||||
|
||||
var modalController = this.get('controllers.modal');
|
||||
if (modalController) {
|
||||
modalController.show(modal);
|
||||
}
|
||||
},
|
||||
|
||||
showInviteModal: function() {
|
||||
var modalController = this.get('controllers.modal');
|
||||
if (modalController) {
|
||||
modalController.show(Discourse.InviteModalView.create({
|
||||
topic: this.get('content')
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// Clicked the flag button
|
||||
showFlags: function(post) {
|
||||
var modalController = this.get('controllers.modal');
|
||||
if (modalController) {
|
||||
modalController.show(Discourse.FlagView.create({
|
||||
post: post,
|
||||
controller: this
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
showHistory: function(post) {
|
||||
var modalController = this.get('controllers.modal');
|
||||
|
||||
if (modalController) {
|
||||
modalController.show(Discourse.HistoryView.create({
|
||||
originalPost: post
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
recoverPost: function(post) {
|
||||
post.set('deleted_at', null);
|
||||
post.recover();
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
This mixin provides functionality to modal controllers
|
||||
|
||||
@class Discourse.ModalFunctionality
|
||||
@extends Ember.Mixin
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ModalFunctionality = Em.Mixin.create({
|
||||
needs: ['modal'],
|
||||
|
||||
/**
|
||||
Flash a message at the top of the modal
|
||||
|
||||
@method blank
|
||||
@param {String} name the name of the property we want to check
|
||||
@return {Boolean}
|
||||
**/
|
||||
flash: function(message, messageClass) {
|
||||
this.set('flashMessage', Em.Object.create({
|
||||
message: message,
|
||||
messageClass: messageClass
|
||||
}));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -8,10 +8,10 @@
|
|||
**/
|
||||
Discourse.Archetype = Discourse.Model.extend({
|
||||
|
||||
hasOptions: (function() {
|
||||
hasOptions: function() {
|
||||
if (!this.get('options')) return false;
|
||||
return this.get('options').length > 0;
|
||||
}).property('options.@each'),
|
||||
}.property('options.@each'),
|
||||
|
||||
isDefault: function() {
|
||||
return this.get('id') === Discourse.Site.instance().get('default_archetype');
|
||||
|
|
47
app/assets/javascripts/discourse/routes/application_route.js
Normal file
47
app/assets/javascripts/discourse/routes/application_route.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
Application route for Discourse
|
||||
|
||||
@class ApplicationRoute
|
||||
@extends Ember.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ApplicationRoute = Em.Route.extend({
|
||||
|
||||
events: {
|
||||
showLogin: function() {
|
||||
Discourse.Route.showModal(this, 'login');
|
||||
},
|
||||
|
||||
showCreateAccount: function() {
|
||||
Discourse.Route.showModal(this, 'createAccount');
|
||||
},
|
||||
|
||||
showForgotPassword: function() {
|
||||
Discourse.Route.showModal(this, 'forgotPassword');
|
||||
},
|
||||
|
||||
showNotActivated: function(props) {
|
||||
Discourse.Route.showModal(this, 'notActivated');
|
||||
this.controllerFor('notActivated').setProperties(props);
|
||||
},
|
||||
|
||||
showImageSelector: function(composerView) {
|
||||
Discourse.Route.showModal(this, 'imageSelector');
|
||||
this.controllerFor('imageSelector').setProperties({
|
||||
localSelected: true,
|
||||
composerView: composerView
|
||||
});
|
||||
},
|
||||
|
||||
editCategory: function(category) {
|
||||
var router = this;
|
||||
Discourse.Category.findBySlugOrId(category.get('slug')).then(function (c) {
|
||||
Discourse.Route.showModal(router, 'editCategory', c);
|
||||
router.controllerFor('editCategory').set('selectedTab', 'general');
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
|
@ -27,6 +27,7 @@ Discourse.Route = Em.Route.extend({
|
|||
var hideDropDownFunction = $('html').data('hide-dropdown');
|
||||
if (hideDropDownFunction) return hideDropDownFunction();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -38,6 +39,23 @@ Discourse.Route.reopenClass({
|
|||
if (oldBuilder) oldBuilder.call(this);
|
||||
return builder.call(this);
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
Shows a modal
|
||||
|
||||
@method showModal
|
||||
**/
|
||||
showModal: function(router, name, model) {
|
||||
router.controllerFor('modal').set('modalClass', null);
|
||||
router.render(name, {into: 'modal', outlet: 'modalBody'});
|
||||
var controller = router.controllerFor(name);
|
||||
if (controller) {
|
||||
if (model) {
|
||||
controller.set('model', model);
|
||||
}
|
||||
controller.set('flashMessage', null);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -8,6 +8,15 @@
|
|||
**/
|
||||
Discourse.ListCategoriesRoute = Discourse.Route.extend({
|
||||
|
||||
events: {
|
||||
|
||||
createCategory: function() {
|
||||
Discourse.Route.showModal(this, 'editCategory', Discourse.Category.create());
|
||||
this.controllerFor('editCategory').set('selectedTab', 'general');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
model: function() {
|
||||
var listTopicsController = this.controllerFor('listTopics');
|
||||
if (listTopicsController) listTopicsController.set('content', null);
|
||||
|
|
|
@ -8,6 +8,57 @@
|
|||
**/
|
||||
Discourse.TopicRoute = Discourse.Route.extend({
|
||||
|
||||
events: {
|
||||
// Modals that can pop up within a topic
|
||||
|
||||
showFlags: function(post) {
|
||||
Discourse.Route.showModal(this, 'flag', post);
|
||||
this.controllerFor('flag').setProperties({
|
||||
postActionTypeId: null
|
||||
});
|
||||
},
|
||||
|
||||
showAutoClose: function() {
|
||||
Discourse.Route.showModal(this, 'editTopicAutoClose', this.modelFor('topic'));
|
||||
this.controllerFor('modal').set('modalClass', 'edit-auto-close-modal');
|
||||
},
|
||||
|
||||
showInvite: function() {
|
||||
Discourse.Route.showModal(this, 'invite', this.modelFor('topic'));
|
||||
this.controllerFor('invite').setProperties({
|
||||
email: null,
|
||||
error: false,
|
||||
saving: false,
|
||||
finished: false
|
||||
});
|
||||
},
|
||||
|
||||
showPrivateInvite: function() {
|
||||
Discourse.Route.showModal(this, 'invitePrivate', this.modelFor('topic'))
|
||||
this.controllerFor('invitePrivate').setProperties({
|
||||
email: null,
|
||||
error: false,
|
||||
saving: false,
|
||||
finished: false
|
||||
});
|
||||
},
|
||||
|
||||
showHistory: function(post) {
|
||||
Discourse.Route.showModal(this, 'history', post);
|
||||
this.controllerFor('history').refresh();
|
||||
this.controllerFor('modal').set('modalClass', 'history-modal')
|
||||
},
|
||||
|
||||
mergeTopic: function() {
|
||||
Discourse.Route.showModal(this, 'mergeTopic', this.modelFor('topic'));
|
||||
},
|
||||
|
||||
splitTopic: function() {
|
||||
Discourse.Route.showModal(this, 'splitTopic', this.modelFor('topic'));
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
model: function(params) {
|
||||
var currentModel, _ref;
|
||||
if (currentModel = (_ref = this.controllerFor('topic')) ? _ref.get('content') : void 0) {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<a href='#' {{action deleteCategory target="view"}} class='btn btn-small'>{{i18n category.delete}}</a>
|
||||
{{/if}}
|
||||
{{#if view.can_edit}}
|
||||
<a href='#' {{action editCategory target="view"}} class='btn btn-small'>{{i18n category.edit}}</a>
|
||||
<a href='#' {{action editCategory view}} class='btn btn-small'>{{i18n category.edit}}</a>
|
||||
{{/if}}
|
||||
<a href="/category/{{unbound view.slug}}" class='btn btn-small'>{{i18n category.view}}</a>
|
||||
</footer>
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
<div class="modal-body flag-modal">
|
||||
{{#if view.post.flagsAvailable}}
|
||||
<form>
|
||||
{{#each view.boundFlags}}
|
||||
<div class='controls'>
|
||||
<label class='radio'>
|
||||
<input type='radio' id="radio_{{unbound name_key}}" {{action changePostActionType this target="view"}} name='post_action_type_index'> <strong>{{formattedName}}</strong>
|
||||
{{#if is_custom_flag}}
|
||||
{{#unless selected}}
|
||||
<div class='description'>{{{description}}}</div>
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
{{#if description}}
|
||||
<div class='description'>{{{description}}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</label>
|
||||
{{#if is_custom_flag}}
|
||||
{{#if selected}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div {{bindAttr class="customMessageLengthClasses"}}>{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</form>
|
||||
{{else}}
|
||||
{{i18n flagging.cant}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if view.showSubmit}}
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{action createFlag target="view"}}>{{view.submitText}}</button>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -1,13 +1,13 @@
|
|||
<ul class="nav nav-pills image-options">
|
||||
<li title="{{i18n image_selector.local_title}}" {{bindAttr class="view.localSelected:active"}}>
|
||||
<a href="#" {{action selectLocal target="view"}}>{{i18n image_selector.from_my_computer}}</a>
|
||||
<li title="{{i18n image_selector.local_title}}" {{bindAttr class="localSelected:active"}}>
|
||||
<a href="#" {{action selectLocal}}>{{i18n image_selector.from_my_computer}}</a>
|
||||
</li>
|
||||
<li title="{{i18n image_selector.remote_title}}" {{bindAttr class="view.remoteSelected:active"}}>
|
||||
<a href="#" {{action selectRemote target="view"}}>{{i18n image_selector.from_the_web}}</a>
|
||||
<li title="{{i18n image_selector.remote_title}}" {{bindAttr class="remoteSelected:active"}}>
|
||||
<a href="#" {{action selectRemote}}>{{i18n image_selector.from_the_web}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{#if view.localSelected}}
|
||||
{{#if localSelected}}
|
||||
<div class='modal-body'>
|
||||
<form>
|
||||
<input type="file" name="file" id="filename-input" value="browse" accept="image/*"><br>
|
||||
|
@ -15,7 +15,7 @@
|
|||
</form>
|
||||
</div>
|
||||
<div class='modal-footer'>
|
||||
<button class='btn btn-large btn-primary' {{action "upload" target="view"}}>
|
||||
<button class='btn btn-large btn-primary' {{action upload target="view"}}>
|
||||
<span class='add-picture'><i class='icon-picture'></i><i class='icon-plus'></i></span>
|
||||
{{i18n image_selector.upload}}
|
||||
</button>
|
||||
|
@ -28,7 +28,7 @@
|
|||
</form>
|
||||
</div>
|
||||
<div class='modal-footer'>
|
||||
<button class='btn btn-large btn-primary' {{action "add" target="view"}}>
|
||||
<button class='btn btn-large btn-primary' {{action add target="view"}}>
|
||||
<span class='add-picture'><i class='icon-picture'></i><i class='icon-plus'></i></span>
|
||||
{{i18n image_selector.add_image}}
|
||||
</button>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
{{/if}}
|
||||
|
||||
{{#if canEditCategory}}
|
||||
<button class='btn btn-default' {{action editCategory}}>{{i18n category.edit_long}}</button>
|
||||
<button class='btn btn-default' {{action editCategory category}}>{{i18n category.edit_long}}</button>
|
||||
{{/if}}
|
||||
|
||||
{{#if canCreateCategory}}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<div class="modal-body">
|
||||
<form>
|
||||
{{autoCloseForm autoCloseDays=view.auto_close_days}}
|
||||
{{autoCloseForm autoCloseDays=auto_close_days}}
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{action saveAutoClose target="view"}} data-dismiss="modal">{{i18n topic.auto_close_save}}</button>
|
||||
<button class='btn btn-primary' {{action saveAutoClose}} data-dismiss="modal">{{i18n topic.auto_close_save}}</button>
|
||||
<button class='btn' data-dismiss="modal">{{i18n topic.auto_close_cancel}}</button>
|
||||
<button class='btn pull-right' {{action removeAutoClose target="view"}} data-dismiss="modal">{{i18n topic.auto_close_remove}}</button>
|
||||
<button class='btn pull-right' {{action removeAutoClose}} data-dismiss="modal">{{i18n topic.auto_close_remove}}</button>
|
||||
</div>
|
|
@ -1,4 +1,4 @@
|
|||
{{#unless view.complete}}
|
||||
{{#unless complete}}
|
||||
<div class="modal-body">
|
||||
<div>
|
||||
<form>
|
||||
|
@ -6,7 +6,7 @@
|
|||
<tr>
|
||||
<td style="width:80px"><label for='new-account-name'>{{i18n user.name.title}}</label></td>
|
||||
<td style="width:496px">
|
||||
{{textField value=view.accountName id="new-account-name" autofocus="autofocus"}}
|
||||
{{textField value=accountName id="new-account-name" autofocus="autofocus"}}
|
||||
{{inputTip validation=nameValidation}}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -18,8 +18,8 @@
|
|||
<tr>
|
||||
<td><label for='new-account-email'>{{i18n user.email.title}}</label></td>
|
||||
<td>
|
||||
{{input value=view.accountEmail id="new-account-email"}}
|
||||
{{inputTip validation=view.emailValidation}}
|
||||
{{input value=accountEmail id="new-account-email"}}
|
||||
{{inputTip validation=emailValidation}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -30,8 +30,8 @@
|
|||
<tr>
|
||||
<td><label for='new-account-username'>{{i18n user.username.title}}</label></td>
|
||||
<td>
|
||||
{{input value=view.accountUsername id="new-account-username" maxlength="15"}}
|
||||
{{inputTip validation=view.usernameValidation}}
|
||||
{{input value=accountUsername id="new-account-username" maxlength="15"}}
|
||||
{{inputTip validation=usernameValidation}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -39,12 +39,12 @@
|
|||
<td><label>{{i18n user.username.instructions}}</label></td>
|
||||
</tr>
|
||||
|
||||
{{#if view.passwordRequired}}
|
||||
{{#if passwordRequired}}
|
||||
<tr>
|
||||
<td><label for='new-account-password'>{{i18n user.password.title}}</label></td>
|
||||
<td>
|
||||
{{input type="password" value=view.accountPassword id="new-account-password"}}
|
||||
{{inputTip validation=view.passwordValidation}}
|
||||
{{input type="password" value=accountPassword id="new-account-password"}}
|
||||
{{inputTip validation=passwordValidation}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
|
@ -52,8 +52,8 @@
|
|||
<tr class="password-confirmation">
|
||||
<td><label for='new-account-password-confirmation'>{{i18n user.password_confirmation.title}}</label></td>
|
||||
<td>
|
||||
{{input type="password" value=view.accountPasswordConfirm id="new-account-confirmation"}}
|
||||
{{input value=view.accountChallenge id="new-account-challenge"}}
|
||||
{{input type="password" value=accountPasswordConfirm id="new-account-confirmation"}}
|
||||
{{input value=accountChallenge id="new-account-challenge"}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -63,6 +63,6 @@
|
|||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-large btn-primary' {{bindAttr disabled="view.submitDisabled"}} {{action createAccount target="view"}}>{{i18n create_account.title}}</button>
|
||||
<button class='btn btn-large btn-primary' {{bindAttr disabled="submitDisabled"}} {{action createAccount}}>{{i18n create_account.title}}</button>
|
||||
</div>
|
||||
{{/unless}}
|
|
@ -1,22 +1,20 @@
|
|||
{{#with view.category}}
|
||||
|
||||
<div {{bindAttr class="view.loading:invisible"}}>
|
||||
<div {{bindAttr class="loading:invisible"}}>
|
||||
<ul class="nav nav-pills">
|
||||
<li {{bindAttr class="view.generalSelected:active"}}>
|
||||
<a href="#" {{action selectGeneral target="view"}}>{{i18n category.general}}</a>
|
||||
<li {{bindAttr class="generalSelected:active"}}>
|
||||
<a href="#" {{action selectGeneral}}>{{i18n category.general}}</a>
|
||||
</li>
|
||||
{{#unless isUncategorized}}
|
||||
<li {{bindAttr class="view.securitySelected:active"}}>
|
||||
<a href="#" {{action selectSecurity target="view"}}>{{i18n category.security}}</a>
|
||||
<li {{bindAttr class="securitySelected:active"}}>
|
||||
<a href="#" {{action selectSecurity}}>{{i18n category.security}}</a>
|
||||
</li>
|
||||
<li {{bindAttr class="view.settingsSelected:active"}}>
|
||||
<a href="#" {{action selectSettings target="view"}}>{{i18n category.settings}}</a>
|
||||
<li {{bindAttr class="settingsSelected:active"}}>
|
||||
<a href="#" {{action selectSettings}}>{{i18n category.settings}}</a>
|
||||
</li>
|
||||
{{/unless}}
|
||||
</ul>
|
||||
|
||||
<div class="modal-body">
|
||||
<div {{bindAttr class=":modal-tab :general-tab view.generalSelected::invisible"}}>
|
||||
<div {{bindAttr class=":modal-tab :general-tab generalSelected::invisible"}}>
|
||||
<form>
|
||||
<section class='field'>
|
||||
<label>{{i18n category.name}}</label>
|
||||
|
@ -34,7 +32,7 @@
|
|||
{{/if}}
|
||||
{{#if topic_url}}
|
||||
<br/>
|
||||
<button class="btn btn-small" {{action showCategoryTopic target="view"}}>{{i18n category.change_in_category_topic}}</button>
|
||||
<button class="btn btn-small" {{action showCategoryTopic}}>{{i18n category.change_in_category_topic}}</button>
|
||||
{{/if}}
|
||||
</section>
|
||||
{{/unless}}
|
||||
|
@ -42,25 +40,25 @@
|
|||
<section class='field'>
|
||||
<label>{{i18n category.badge_colors}}</label>
|
||||
<div class="category-color-editor">
|
||||
<span class='badge-category' {{bindAttr style="view.colorStyle"}}>{{view.categoryName}}</span>
|
||||
<span class='badge-category' {{bindAttr style="colorStyle"}}>{{categoryName}}</span>
|
||||
|
||||
<div class='input-prepend input-append' style="margin-top: 10px;">
|
||||
<span class='color-title'>{{i18n category.background_color}}:</span>
|
||||
<span class='add-on'>#</span>{{textField value=color placeholderKey="category.color_placeholder" maxlength="6"}}
|
||||
{{colorPicker colors=view.backgroundColors usedColors=view.usedBackgroundColors value=color}}
|
||||
{{colorPicker colors=backgroundColors usedColors=usedBackgroundColors value=color}}
|
||||
</div>
|
||||
|
||||
<div class='input-prepend input-append'>
|
||||
<span class='color-title'>{{i18n category.foreground_color}}:</span>
|
||||
<span class='add-on'>#</span>{{textField value=text_color placeholderKey="category.color_placeholder" maxlength="6"}}
|
||||
{{colorPicker colors=view.foregroundColors value=text_color}}
|
||||
{{colorPicker colors=foregroundColors value=text_color}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</div>
|
||||
{{#unless isUncategorized}}
|
||||
<div {{bindAttr class=":modal-tab :options-tab view.securitySelected::invisible"}}>
|
||||
<div {{bindAttr class=":modal-tab :options-tab securitySelected::invisible"}}>
|
||||
<section class='field'>
|
||||
<label>
|
||||
{{input type="checkbox" checked=secure}}
|
||||
|
@ -73,17 +71,17 @@
|
|||
{{#each groups}}
|
||||
<li class="badge-group">
|
||||
{{this}}
|
||||
<a {{action removeGroup this target="view"}}><i class="icon icon-remove-sign"></i></a>
|
||||
<a {{action removeGroup this}}><i class="icon icon-remove-sign"></i></a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{view Ember.Select contentBinding="availableGroups" valueBinding="view.selectedGroup"}}
|
||||
<button {{action addGroup target="view"}} class="btn btn-small">{{i18n category.add_group}}</button>
|
||||
{{view Ember.Select contentBinding="availableGroups" valueBinding="selectedGroup"}}
|
||||
<button {{action addGroup}} class="btn btn-small">{{i18n category.add_group}}</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
<div {{bindAttr class=":modal-tab :options-tab view.settingsSelected::invisible"}}>
|
||||
<div {{bindAttr class=":modal-tab :options-tab settingsSelected::invisible"}}>
|
||||
<section class='field'>
|
||||
{{autoCloseForm autoCloseDays=auto_close_days labelKey="category.auto_close_label"}}
|
||||
</section>
|
||||
|
@ -96,11 +94,9 @@
|
|||
{{/unless}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{bindAttr disabled="view.disabled"}} {{action saveCategory target="view"}}>{{view.buttonTitle}}</button>
|
||||
{{#if view.deleteVisible}}
|
||||
<button class='btn btn-danger pull-right' {{bindAttr disabled="view.deleteDisabled"}} {{action deleteCategory target="view"}}><i class="icon icon-trash"></i>{{view.deleteButtonTitle}}</button>
|
||||
<button class='btn btn-primary' {{bindAttr disabled="disabled"}} {{action saveCategory}}>{{buttonTitle}}</button>
|
||||
{{#if deleteVisible}}
|
||||
<button class='btn btn-danger pull-right' {{bindAttr disabled="deleteDisabled"}} {{action deleteCategory}}><i class="icon icon-trash"></i>{{deleteButtonTitle}}</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/with}}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<div class="modal-body flag-modal">
|
||||
{{#if flagsAvailable}}
|
||||
<form>
|
||||
{{#each boundFlags}}
|
||||
<div class='controls'>
|
||||
<label class='radio'>
|
||||
<input type='radio' id="radio_{{unbound name_key}}" {{action changePostActionType this}} name='post_action_type_index'> <strong>{{formattedName}}</strong>
|
||||
{{#if is_custom_flag}}
|
||||
{{#unless selected}}
|
||||
<div class='description'>{{{description}}}</div>
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
{{#if description}}
|
||||
<div class='description'>{{{description}}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</label>
|
||||
{{#if is_custom_flag}}
|
||||
{{#if selected}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div {{bindAttr class="customMessageLengthClasses"}}>{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</form>
|
||||
{{else}}
|
||||
{{i18n flagging.cant}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if showSubmit}}
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{action createFlag}}>{{submitText}}</button>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -1,9 +1,9 @@
|
|||
<div class="modal-body">
|
||||
<form>
|
||||
<label for='username-or-email'>{{i18n forgot_password.invite}}</label>
|
||||
{{textField value=view.accountEmailOrUsername placeholderKey="login.email_placeholder" id="username-or-email" autocorrect="off" autocapitalize="off"}}
|
||||
{{textField value=accountEmailOrUsername placeholderKey="login.email_placeholder" id="username-or-email" autocorrect="off" autocapitalize="off"}}
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-large btn-primary' {{bindAttr disabled="view.submitDisabled"}} {{action submit target="view"}}>{{i18n forgot_password.reset}}</button>
|
||||
<button class='btn btn-large btn-primary' {{bindAttr disabled="submitDisabled"}} {{action submit}}>{{i18n forgot_password.reset}}</button>
|
||||
</div>
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
<div class="modal-body">
|
||||
|
||||
{{#if view.loading}}
|
||||
{{#if loading}}
|
||||
{{i18n loading}}
|
||||
{{else}}
|
||||
{{#if view.versions}}
|
||||
{{#if versions}}
|
||||
<div class='span8'>
|
||||
|
||||
{{view Ember.Select
|
||||
contentBinding="view.versions"
|
||||
contentBinding="versions"
|
||||
optionLabelPath="content.description"
|
||||
optionValuePath="content.number"
|
||||
selectionBinding="view.versionLeft"}}
|
||||
selectionBinding="versionLeft"}}
|
||||
|
||||
<div class='contents'>
|
||||
{{#if view.postLeft}}
|
||||
{{{view.postLeft.cooked}}}
|
||||
{{#if postLeft}}
|
||||
{{{postLeft.cooked}}}
|
||||
{{else}}
|
||||
<div class='history-loading'>{{i18n loading}}</div>
|
||||
{{/if}}
|
||||
|
@ -24,14 +24,14 @@
|
|||
|
||||
<div class='span8 offset1'>
|
||||
{{view Ember.Select
|
||||
contentBinding="view.versions"
|
||||
contentBinding="versions"
|
||||
optionLabelPath="content.description"
|
||||
optionValuePath="content.number"
|
||||
selectionBinding="view.versionRight"}}
|
||||
selectionBinding="versionRight"}}
|
||||
|
||||
<div class='contents'>
|
||||
{{#if view.diff}}
|
||||
{{{view.diff}}}
|
||||
{{#if diff}}
|
||||
{{{diff}}}
|
||||
{{else}}
|
||||
<div class='history-loading'>{{i18n loading}}</div>
|
||||
{{/if}}
|
|
@ -0,0 +1,36 @@
|
|||
<ul class="nav nav-pills image-options">
|
||||
<li title="{{i18n image_selector.local_title}}" {{bindAttr class="localSelected:active"}}>
|
||||
<a href="#" {{action selectLocal}}>{{i18n image_selector.from_my_computer}}</a>
|
||||
</li>
|
||||
<li title="{{i18n image_selector.remote_title}}" {{bindAttr class="remoteSelected:active"}}>
|
||||
<a href="#" {{action selectRemote}}>{{i18n image_selector.from_the_web}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{#if localSelected}}
|
||||
<div class='modal-body'>
|
||||
<form>
|
||||
<input type="file" name="file" id="filename-input" value="browse" accept="image/*"><br>
|
||||
<span class='description'>{{i18n image_selector.local_tip}}</span> <br>
|
||||
</form>
|
||||
</div>
|
||||
<div class='modal-footer'>
|
||||
<button class='btn btn-large btn-primary' {{action upload target="view"}}>
|
||||
<span class='add-picture'><i class='icon-picture'></i><i class='icon-plus'></i></span>
|
||||
{{i18n image_selector.upload}}
|
||||
</button>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class='modal-body'>
|
||||
<form>
|
||||
<input type="text" name="text" id="fileurl-input" autofocus><br>
|
||||
<span class='description'>{{i18n image_selector.remote_tip}}</span> <br>
|
||||
</form>
|
||||
</div>
|
||||
<div class='modal-footer'>
|
||||
<button class='btn btn-large btn-primary' {{action add target="view"}}>
|
||||
<span class='add-picture'><i class='icon-picture'></i><i class='icon-plus'></i></span>
|
||||
{{i18n image_selector.add_image}}
|
||||
</button>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -1,25 +1,25 @@
|
|||
<div class="modal-body">
|
||||
{{#if view.error}}
|
||||
{{#if error}}
|
||||
<div class="alert alert-error">
|
||||
<button class="close" data-dismiss="alert">×</button>
|
||||
{{i18n topic.invite_reply.error}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if view.finished}}
|
||||
{{{view.successMessage}}}
|
||||
{{#if finished}}
|
||||
{{{successMessage}}}
|
||||
{{else}}
|
||||
<form>
|
||||
<label>{{i18n topic.invite_reply.email}}</label>
|
||||
{{textField value=view.email placeholderKey="topic.invite_reply.email_placeholder"}}
|
||||
{{textField value=email placeholderKey="topic.invite_reply.email_placeholder"}}
|
||||
</form>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{{#if view.finished}}
|
||||
{{#if finished}}
|
||||
<button class='btn btn-primary' data-dismiss="modal">{{i18n close}}</button>
|
||||
{{else}}
|
||||
<button class='btn btn-primary' {{bindAttr disabled="view.disabled"}} {{action createInvite target="view"}}>{{view.buttonTitle}}</button>
|
||||
<button class='btn btn-primary' {{bindAttr disabled="disabled"}} {{action createInvite}}>{{buttonTitle}}</button>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
|
@ -1,25 +1,25 @@
|
|||
<div class="modal-body">
|
||||
{{#if view.error}}
|
||||
{{#if error}}
|
||||
<div class="alert alert-error">
|
||||
<button class="close" data-dismiss="alert">×</button>
|
||||
{{i18n topic.invite_private.error}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if view.finished}}
|
||||
{{#if finished}}
|
||||
{{i18n topic.invite_private.success}}
|
||||
{{else}}
|
||||
<form>
|
||||
<label>{{i18n topic.invite_private.email_or_username}}</label>
|
||||
{{textField value=view.emailOrUsername placeholderKey="topic.invite_private.email_or_username_placeholder"}}
|
||||
{{textField value=emailOrUsername placeholderKey="topic.invite_private.email_or_username_placeholder"}}
|
||||
</form>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{{#if view.finished}}
|
||||
{{#if finished}}
|
||||
<button class='btn btn-primary' data-dismiss="modal">{{i18n close}}</button>
|
||||
{{else}}
|
||||
<button class='btn btn-primary' {{bindAttr disabled="view.disabled"}} {{action invite target="view"}}>{{view.buttonTitle}}</button>
|
||||
<button class='btn btn-primary' {{bindAttr disabled="disabled"}} {{action invite}}>{{buttonTitle}}</button>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
|
@ -1,31 +1,31 @@
|
|||
<div class="modal-body">
|
||||
{{#if view.hasAtLeastOneLoginButton}}
|
||||
{{#if hasAtLeastOneLoginButton}}
|
||||
<div id="login-buttons">
|
||||
{{#if Discourse.SiteSettings.enable_google_logins}}
|
||||
<button class="btn btn-social google" title="{{i18n login.google.title}}" {{action openidLogin "google" target="view"}}>{{i18n login.google.title}}</button>
|
||||
<button class="btn btn-social google" title="{{i18n login.google.title}}" {{action openidLogin "google"}}>{{i18n login.google.title}}</button>
|
||||
{{/if}}
|
||||
{{#if Discourse.SiteSettings.enable_facebook_logins}}
|
||||
<button class="btn btn-social facebook" title="{{i18n login.facebook.title}}" {{action "facebookLogin" target="view"}}>{{i18n login.facebook.title}}</button>
|
||||
<button class="btn btn-social facebook" title="{{i18n login.facebook.title}}" {{action "facebookLogin"}}>{{i18n login.facebook.title}}</button>
|
||||
{{/if}}
|
||||
{{#if Discourse.SiteSettings.enable_cas_logins}}
|
||||
<button class="btn btn-social cas" title="{{i18n login.cas.title}}" {{action "casLogin" target="view"}}>{{i18n login.cas.title}}</button>
|
||||
<button class="btn btn-social cas" title="{{i18n login.cas.title}}" {{action "casLogin"}}>{{i18n login.cas.title}}</button>
|
||||
{{/if}}
|
||||
{{#if Discourse.SiteSettings.enable_twitter_logins}}
|
||||
<button class="btn btn-social twitter" title="{{i18n login.twitter.title}}" {{action "twitterLogin" target="view"}}>{{i18n login.twitter.title}}</button>
|
||||
<button class="btn btn-social twitter" title="{{i18n login.twitter.title}}" {{action "twitterLogin"}}>{{i18n login.twitter.title}}</button>
|
||||
{{/if}}
|
||||
{{#if Discourse.SiteSettings.enable_yahoo_logins}}
|
||||
<button class="btn btn-social yahoo" title="{{i18n login.yahoo.title}}" {{action openidLogin "yahoo" target="view"}}>{{i18n login.yahoo.title}}</button>
|
||||
<button class="btn btn-social yahoo" title="{{i18n login.yahoo.title}}" {{action openidLogin "yahoo"}}>{{i18n login.yahoo.title}}</button>
|
||||
{{/if}}
|
||||
{{#if Discourse.SiteSettings.enable_github_logins}}
|
||||
<button class="btn btn-social github" title="{{i18n login.github.title}}" {{action "githubLogin" target="view"}}>{{i18n login.github.title}}</button>
|
||||
<button class="btn btn-social github" title="{{i18n login.github.title}}" {{action "githubLogin"}}>{{i18n login.github.title}}</button>
|
||||
{{/if}}
|
||||
{{#if Discourse.SiteSettings.enable_persona_logins}}
|
||||
<button class="btn btn-social persona" title="{{i18n login.persona.title}}" {{action "personaLogin" target="view"}}>{{i18n login.persona.title}}</button>
|
||||
<button class="btn btn-social persona" title="{{i18n login.persona.title}}" {{action "personaLogin"}}>{{i18n login.persona.title}}</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if Discourse.SiteSettings.enable_local_logins}}
|
||||
{{#if view.hasAtLeastOneLoginButton}}
|
||||
{{#if hasAtLeastOneLoginButton}}
|
||||
<h3 style="text-align:center; margin-bottom:10px;">{{i18n login.or}}</h3>
|
||||
{{/if}}
|
||||
<form id='login-form'>
|
||||
|
@ -36,31 +36,31 @@
|
|||
<label for='login-account-name'>{{i18n login.username}} </label>
|
||||
</td>
|
||||
<td>
|
||||
{{textField value=view.loginName placeholderKey="login.email_placeholder" id="login-account-name" autocorrect="off" autocapitalize="off" autofocus="autofocus"}}
|
||||
{{textField value=loginName placeholderKey="login.email_placeholder" id="login-account-name" autocorrect="off" autocapitalize="off" autofocus="autofocus"}}
|
||||
</td>
|
||||
<tr>
|
||||
<td>
|
||||
<label for='login-account-password'>{{i18n login.password}} </label>
|
||||
</td>
|
||||
<td>
|
||||
{{textField value=view.loginPassword type="password" id="login-account-password"}}
|
||||
<a id="forgot-password-link" {{action forgotPassword target="view"}}>{{i18n forgot_password.action}}</a>
|
||||
{{textField value=loginPassword type="password" id="login-account-password"}}
|
||||
<a id="forgot-password-link" {{action showForgotPassword}}>{{i18n forgot_password.action}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
{{/if}}
|
||||
{{view.authMessage}}
|
||||
<div id='login-alert' {{bindAttr class="view.alertClass"}}>{{view.alert}}</div>
|
||||
{{authMessage}}
|
||||
<div id='login-alert' {{bindAttr class="alertClass"}}>{{alert}}</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{{#if view.authenticate}}
|
||||
{{#if authenticate}}
|
||||
{{i18n login.authenticating}}
|
||||
{{/if}}
|
||||
{{#if Discourse.SiteSettings.enable_local_logins}}
|
||||
<button class='btn btn-large btn-primary' {{bindAttr disabled="view.loginDisabled"}} {{action login target="view"}}><i class="icon-unlock"></i> {{view.loginButtonText}}</button>
|
||||
<button class='btn btn-large btn-primary' {{bindAttr disabled="loginDisabled"}} {{action login}}><i class="icon-unlock"></i> {{loginButtonText}}</button>
|
||||
|
||||
{{i18n create_account.invite}} <a id="new-account-link" {{action newAccount target="view"}}>{{i18n create_account.action}}</a>
|
||||
{{i18n create_account.invite}} <a id="new-account-link" {{action showCreateAccount}}>{{i18n create_account.action}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<div id='move-selected' class="modal-body">
|
||||
{{#if view.error}}
|
||||
{{#if error}}
|
||||
<div class="alert alert-error">
|
||||
<button class="close" data-dismiss="alert">×</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<p>{{{i18n topic.merge_topic.instructions count="view.selectedPostsCount"}}}</p>
|
||||
<p>{{{i18n topic.merge_topic.instructions count="selectedPostsCount"}}}</p>
|
||||
|
||||
{{view Discourse.ChooseTopicView selectedTopicIdBinding="view.selectedTopicId"}}
|
||||
{{chooseTopic selectedTopicId=selectedTopicId}}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{bindAttr disabled="view.buttonDisabled"}} {{action movePostsToExistingTopic target="view"}}>{{view.buttonTitle}}</button>
|
||||
<button class='btn btn-primary' {{bindAttr disabled="buttonDisabled"}} {{action movePostsToExistingTopic}}>{{buttonTitle}}</button>
|
||||
</div>
|
|
@ -0,0 +1,16 @@
|
|||
<div class="modal-header">
|
||||
<a class="close" data-dismiss="modal"><i class='icon-remove icon'></i></a>
|
||||
<h3>{{title}}</h3>
|
||||
</div>
|
||||
<div id='modal-alert'></div>
|
||||
|
||||
{{outlet modalBody}}
|
||||
|
||||
{{#each errors}}
|
||||
<div class="alert alert-error">
|
||||
<button class="close" data-dismiss="alert">×</button>
|
||||
{{this}}
|
||||
</div>
|
||||
{{/each}}
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
{{#if view.errors}}
|
||||
{{#each view.errors}}
|
||||
<div class="alert alert-error">
|
||||
<button class="close" data-dismiss="alert">×</button>
|
||||
{{this}}
|
||||
</div>
|
||||
{{/each}}
|
||||
{{/if}}
|
|
@ -1,5 +0,0 @@
|
|||
<div class="modal-header">
|
||||
<a class="close" data-dismiss="modal"><i class='icon-remove icon'></i></a>
|
||||
<h3>{{view.title}}</h3>
|
||||
</div>
|
||||
<div id='modal-alert'></div>
|
|
@ -1,9 +1,9 @@
|
|||
<div class="modal-body">
|
||||
{{#if view.emailSent}}
|
||||
{{{i18n login.sent_activation_email_again currentEmail="view.currentEmail"}}}
|
||||
{{#if emailSent}}
|
||||
{{{i18n login.sent_activation_email_again currentEmail="currentEmail"}}}
|
||||
{{else}}
|
||||
{{{i18n login.not_activated sentTo="view.sentTo"}}}
|
||||
<a href="#" {{action "sendActivationEmail" target="view"}}>{{i18n login.resend_activation_email}}</a>
|
||||
{{{i18n login.not_activated sentTo="sentTo"}}}
|
||||
<a href="#" {{action "sendActivationEmail"}}>{{i18n login.resend_activation_email}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<div id='move-selected' class="modal-body">
|
||||
{{#if view.error}}
|
||||
{{#if error}}
|
||||
<div class="alert alert-error">
|
||||
<button class="close" data-dismiss="alert">×</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{{i18n topic.split_topic.instructions count="view.selectedPostsCount"}}}
|
||||
{{{i18n topic.split_topic.instructions count="selectedPostsCount"}}}
|
||||
|
||||
<form>
|
||||
<label>{{i18n topic.split_topic.topic_name}}</label>
|
||||
{{textField value=view.topicName placeholderKey="composer.title_placeholder"}}
|
||||
{{textField value=topicName placeholderKey="composer.title_placeholder"}}
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{bindAttr disabled="view.buttonDisabled"}} {{action movePostsToNewTopic target="view"}}>{{view.buttonTitle}}</button>
|
||||
<button class='btn btn-primary' {{bindAttr disabled="buttonDisabled"}} {{action movePostsToNewTopic}}>{{buttonTitle}}</button>
|
||||
</div>
|
|
@ -1,46 +0,0 @@
|
|||
{{#with view.topic.rank_details}}
|
||||
<div class="modal-body">
|
||||
|
||||
<!-- Note this isn't translated because it's a debugging tool for a feature
|
||||
that is not complete yet. We will probably rip this out altogether -->
|
||||
|
||||
<table class='table'>
|
||||
<tr>
|
||||
<td>hot topic type</td>
|
||||
<td>
|
||||
{{hot_topic_type}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>random bias</td>
|
||||
<td>{{float random_bias}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>random multiplier</td>
|
||||
<td>{{float random_multiplier}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>days ago bias</td>
|
||||
<td>{{float days_ago_bias}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>days ago multiplier</td>
|
||||
<td>{{float days_ago_multiplier}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ranking formula</td>
|
||||
<td>
|
||||
<p>= (random_bias * random_multiplier) +<br/>
|
||||
(days_ago_bias * days_ago_multiplier)</p>
|
||||
<p>= ({{float random_bias}} * {{float random_multiplier}}) + ({{float days_ago_bias}} * {{float days_ago_multiplier}})</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ranking score</td>
|
||||
<td><b>{{float ranking_score}}</b></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
{{/with}}
|
|
@ -18,7 +18,7 @@
|
|||
<button {{action toggleClosed}} class='btn btn-admin'><i class='icon-unlock'></i> {{i18n topic.actions.open}}</button>
|
||||
{{else}}
|
||||
<button {{action toggleClosed}} class='btn btn-admin'><i class='icon-lock'></i> {{i18n topic.actions.close}}</button>
|
||||
<button {{action autoClose}} class='btn btn-admin'><i class='icon-time'></i> {{i18n topic.actions.auto_close}}</button>
|
||||
<button {{action showAutoClose}} class='btn btn-admin'><i class='icon-time'></i> {{i18n topic.actions.auto_close}}</button>
|
||||
{{/if}}
|
||||
</li>
|
||||
|
||||
|
|
|
@ -18,6 +18,6 @@
|
|||
</div>
|
||||
{{#if can_invite_to}}
|
||||
<div class='controls'>
|
||||
<button class='btn' {{action showPrivateInviteModal}}>{{i18n private_message_info.invite}}</button>
|
||||
<button class='btn' {{action showPrivateInvite}}>{{i18n private_message_info.invite}}</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
|
@ -40,7 +40,7 @@ Discourse.ChooseTopicView = Discourse.View.extend({
|
|||
var topicId = Em.get(topic, 'id');
|
||||
this.set('selectedTopicId', topicId);
|
||||
|
||||
Em.run.schedule('afterRender', function () {
|
||||
Em.run.next(function () {
|
||||
$('#choose-topic-' + topicId).prop('checked', 'true');
|
||||
});
|
||||
|
||||
|
@ -50,3 +50,4 @@ Discourse.ChooseTopicView = Discourse.View.extend({
|
|||
});
|
||||
|
||||
|
||||
Discourse.View.registerHelper('chooseTopic', Discourse.ChooseTopicView);
|
|
@ -197,10 +197,7 @@ Discourse.ComposerView = Discourse.View.extend({
|
|||
$uploadTarget = $('#reply-control');
|
||||
this.editor.hooks.insertImageDialog = function(callback) {
|
||||
callback(null);
|
||||
_this.get('controller.controllers.modal').show(Discourse.ImageSelectorView.create({
|
||||
composer: _this,
|
||||
uploadTarget: $uploadTarget
|
||||
}));
|
||||
_this.get('controller').send('showImageSelector', _this);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@ -342,7 +339,6 @@ Discourse.ComposerView = Discourse.View.extend({
|
|||
Em.run.schedule('afterRender', function() {
|
||||
Discourse.Utilities.setCaretPosition(ctrl, caretPosition + text.length);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
// Uses javascript to get the image sizes from the preview, if present
|
||||
|
|
|
@ -19,6 +19,8 @@ Discourse.ColorPickerView = Ember.ContainerView.extend({
|
|||
var _this = this;
|
||||
var isUsed, usedColors = this.get('usedColors') || [];
|
||||
|
||||
if (!colors) return;
|
||||
|
||||
colors.each(function(color) {
|
||||
isUsed = usedColors.indexOf(color.toUpperCase()) >= 0;
|
||||
_this.addObject(Discourse.View.create({
|
||||
|
|
|
@ -9,280 +9,18 @@
|
|||
Discourse.CreateAccountView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/create_account',
|
||||
title: Em.String.i18n('create_account.title'),
|
||||
uniqueUsernameValidation: null,
|
||||
globalNicknameExists: false,
|
||||
complete: false,
|
||||
accountPasswordConfirm: 0,
|
||||
accountChallenge: 0,
|
||||
formSubmitted: false,
|
||||
|
||||
submitDisabled: (function() {
|
||||
if (this.get('formSubmitted')) return true;
|
||||
if (this.get('nameValidation.failed')) return true;
|
||||
if (this.get('emailValidation.failed')) return true;
|
||||
if (this.get('usernameValidation.failed')) return true;
|
||||
if (this.get('passwordValidation.failed')) return true;
|
||||
return false;
|
||||
}).property('nameValidation.failed', 'emailValidation.failed', 'usernameValidation.failed', 'passwordValidation.failed', 'formSubmitted'),
|
||||
|
||||
passwordRequired: (function() {
|
||||
return this.blank('authOptions.auth_provider');
|
||||
}).property('authOptions.auth_provider'),
|
||||
|
||||
// Validate the name
|
||||
nameValidation: (function() {
|
||||
|
||||
// If blank, fail without a reason
|
||||
if (this.blank('accountName')) return Discourse.InputValidation.create({ failed: true });
|
||||
|
||||
if (this.get('accountPasswordConfirm') === 0) {
|
||||
this.fetchConfirmationValue();
|
||||
}
|
||||
|
||||
// If too short
|
||||
if (this.get('accountName').length < 3) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.name.too_short')
|
||||
});
|
||||
}
|
||||
|
||||
// Looks good!
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.name.ok')
|
||||
});
|
||||
}).property('accountName'),
|
||||
|
||||
// Check the email address
|
||||
emailValidation: (function() {
|
||||
// If blank, fail without a reason
|
||||
var email;
|
||||
if (this.blank('accountEmail')) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true
|
||||
});
|
||||
}
|
||||
|
||||
email = this.get("accountEmail");
|
||||
if ((this.get('authOptions.email') === email) && this.get('authOptions.email_valid')) {
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.email.authenticated', {
|
||||
provider: this.get('authOptions.auth_provider')
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (Discourse.Utilities.emailValid(email)) {
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.email.ok')
|
||||
});
|
||||
}
|
||||
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.email.invalid')
|
||||
});
|
||||
}).property('accountEmail'),
|
||||
|
||||
usernameMatch: (function() {
|
||||
if (this.usernameNeedsToBeValidatedWithEmail()) {
|
||||
if (this.get('emailValidation.failed')) {
|
||||
if (this.shouldCheckUsernameMatch()) {
|
||||
return this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.enter_email')
|
||||
}));
|
||||
} else {
|
||||
return this.set('uniqueUsernameValidation', Discourse.InputValidation.create({ failed: true }));
|
||||
}
|
||||
} else if (this.shouldCheckUsernameMatch()) {
|
||||
this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.checking')
|
||||
}));
|
||||
return this.checkUsernameAvailability();
|
||||
}
|
||||
}
|
||||
}).observes('accountEmail'),
|
||||
|
||||
basicUsernameValidation: (function() {
|
||||
this.set('uniqueUsernameValidation', null);
|
||||
|
||||
// If blank, fail without a reason
|
||||
if (this.blank('accountUsername')) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true
|
||||
});
|
||||
}
|
||||
|
||||
// If too short
|
||||
if (this.get('accountUsername').length < 3) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.too_short')
|
||||
});
|
||||
}
|
||||
|
||||
// If too long
|
||||
if (this.get('accountUsername').length > 15) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.too_long')
|
||||
});
|
||||
}
|
||||
|
||||
this.checkUsernameAvailability();
|
||||
// Let's check it out asynchronously
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.checking')
|
||||
});
|
||||
}).property('accountUsername'),
|
||||
|
||||
shouldCheckUsernameMatch: function() {
|
||||
return !this.blank('accountUsername') && this.get('accountUsername').length > 2;
|
||||
},
|
||||
|
||||
checkUsernameAvailability: Discourse.debounce(function() {
|
||||
var _this = this;
|
||||
if (this.shouldCheckUsernameMatch()) {
|
||||
return Discourse.User.checkUsername(this.get('accountUsername'), this.get('accountEmail')).then(function(result) {
|
||||
_this.set('globalNicknameExists', false);
|
||||
if (result.available) {
|
||||
if (result.global_match) {
|
||||
_this.set('globalNicknameExists', true);
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.username.global_match')
|
||||
}));
|
||||
} else {
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.username.available')
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
if (result.suggestion) {
|
||||
if (result.global_match !== void 0 && result.global_match === false) {
|
||||
_this.set('globalNicknameExists', true);
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.global_mismatch', result)
|
||||
}));
|
||||
} else {
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.not_available', result)
|
||||
}));
|
||||
}
|
||||
} else if (result.errors) {
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: result.errors.join(' ')
|
||||
}));
|
||||
} else {
|
||||
_this.set('globalNicknameExists', true);
|
||||
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.username.enter_email')
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 500),
|
||||
|
||||
// Actually wait for the async name check before we're 100% sure we're good to go
|
||||
usernameValidation: (function() {
|
||||
var basicValidation, uniqueUsername;
|
||||
basicValidation = this.get('basicUsernameValidation');
|
||||
uniqueUsername = this.get('uniqueUsernameValidation');
|
||||
if (uniqueUsername) {
|
||||
return uniqueUsername;
|
||||
}
|
||||
return basicValidation;
|
||||
}).property('uniqueUsernameValidation', 'basicUsernameValidation'),
|
||||
|
||||
usernameNeedsToBeValidatedWithEmail: function() {
|
||||
return( this.get('globalNicknameExists') || false );
|
||||
},
|
||||
|
||||
// Validate the password
|
||||
passwordValidation: (function() {
|
||||
var password;
|
||||
if (!this.get('passwordRequired')) {
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true
|
||||
});
|
||||
}
|
||||
|
||||
// If blank, fail without a reason
|
||||
password = this.get("accountPassword");
|
||||
if (this.blank('accountPassword')) {
|
||||
return Discourse.InputValidation.create({ failed: true });
|
||||
}
|
||||
|
||||
// If too short
|
||||
if (password.length < 6) {
|
||||
return Discourse.InputValidation.create({
|
||||
failed: true,
|
||||
reason: Em.String.i18n('user.password.too_short')
|
||||
});
|
||||
}
|
||||
|
||||
// Looks good!
|
||||
return Discourse.InputValidation.create({
|
||||
ok: true,
|
||||
reason: Em.String.i18n('user.password.ok')
|
||||
});
|
||||
}).property('accountPassword'),
|
||||
|
||||
fetchConfirmationValue: function() {
|
||||
var createAccountView = this;
|
||||
return Discourse.ajax('/users/hp.json').then(function (json) {
|
||||
createAccountView.set('accountPasswordConfirm', json.value);
|
||||
createAccountView.set('accountChallenge', json.challenge.split("").reverse().join(""));
|
||||
});
|
||||
},
|
||||
|
||||
createAccount: function() {
|
||||
var challenge, email, name, password, passwordConfirm, username,
|
||||
_this = this;
|
||||
this.set('formSubmitted', true);
|
||||
name = this.get('accountName');
|
||||
email = this.get('accountEmail');
|
||||
password = this.get('accountPassword');
|
||||
username = this.get('accountUsername');
|
||||
passwordConfirm = this.get('accountPasswordConfirm');
|
||||
challenge = this.get('accountChallenge');
|
||||
return Discourse.User.createAccount(name, email, password, username, passwordConfirm, challenge).then(function(result) {
|
||||
if (result.success) {
|
||||
_this.flash(result.message);
|
||||
_this.set('complete', true);
|
||||
} else {
|
||||
_this.flash(result.message || Em.String.i18n('create_account.failed'), 'error');
|
||||
_this.set('formSubmitted', false);
|
||||
}
|
||||
if (result.active) {
|
||||
return window.location.reload();
|
||||
}
|
||||
}, function() {
|
||||
_this.set('formSubmitted', false);
|
||||
return _this.flash(Em.String.i18n('create_account.failed'), 'error');
|
||||
});
|
||||
},
|
||||
|
||||
didInsertElement: function(e) {
|
||||
|
||||
this._super();
|
||||
|
||||
// allows the submission the form when pressing 'ENTER' on *any* text input field
|
||||
// but only when the submit button is enabled
|
||||
var createAccountView = this;
|
||||
var createAccountController = this.get('controller');
|
||||
Em.run.schedule('afterRender', function() {
|
||||
$("input[type='text'], input[type='password']").keydown(function(e) {
|
||||
if (createAccountView.get('submitDisabled') === false && e.keyCode === 13) {
|
||||
createAccountView.createAccount();
|
||||
if (createAccountController.get('submitDisabled') === false && e.keyCode === 13) {
|
||||
createAccountController.createAccount();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,181 +7,5 @@
|
|||
@module Discourse
|
||||
**/
|
||||
Discourse.EditCategoryView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/edit_category',
|
||||
generalSelected: Ember.computed.equal('selectedTab', 'general'),
|
||||
securitySelected: Ember.computed.equal('selectedTab', 'security'),
|
||||
settingsSelected: Ember.computed.equal('selectedTab', 'settings'),
|
||||
foregroundColors: ['FFFFFF', '000000'],
|
||||
|
||||
init: function() {
|
||||
this._super();
|
||||
this.set('selectedTab', 'general');
|
||||
},
|
||||
|
||||
modalClass: function() {
|
||||
return "edit-category-modal " + (this.present('category.description') ? 'full' : 'small');
|
||||
}.property('category.description'),
|
||||
|
||||
selectGeneral: function() {
|
||||
this.set('selectedTab', 'general');
|
||||
},
|
||||
|
||||
selectSecurity: function() {
|
||||
this.set('selectedTab', 'security');
|
||||
},
|
||||
|
||||
selectSettings: function() {
|
||||
this.set('selectedTab', 'settings');
|
||||
},
|
||||
|
||||
disabled: function() {
|
||||
if (this.get('saving') || this.get('deleting')) return true;
|
||||
if (!this.get('category.name')) return true;
|
||||
if (!this.get('category.color')) return true;
|
||||
return false;
|
||||
}.property('category.name', 'category.color', 'deleting'),
|
||||
|
||||
deleteVisible: function() {
|
||||
return (this.get('category.id') && this.get('category.topic_count') === 0);
|
||||
}.property('category.id', 'category.topic_count'),
|
||||
|
||||
deleteDisabled: function() {
|
||||
return (this.get('deleting') || this.get('saving') || false);
|
||||
}.property('disabled', 'saving', 'deleting'),
|
||||
|
||||
colorStyle: function() {
|
||||
return "background-color: #" + (this.get('category.color')) + "; color: #" + (this.get('category.text_color')) + ";";
|
||||
}.property('category.color', 'category.text_color'),
|
||||
|
||||
// background colors are available as a pipe-separated string
|
||||
backgroundColors: function() {
|
||||
var categories = Discourse.Category.list();
|
||||
return Discourse.SiteSettings.category_colors.split("|").map(function(i) { return i.toUpperCase(); }).concat(
|
||||
categories.map(function(c) { return c.color.toUpperCase(); }) ).uniq();
|
||||
}.property('Discourse.SiteSettings.category_colors'),
|
||||
|
||||
usedBackgroundColors: function() {
|
||||
var categories = Discourse.Category.list();
|
||||
return categories.map(function(c) {
|
||||
// If editing a category, don't include its color:
|
||||
return (this.get('category.id') && this.get('category.color').toUpperCase() === c.color.toUpperCase()) ? null : c.color.toUpperCase();
|
||||
}, this).compact();
|
||||
}.property('category.id', 'category.color'),
|
||||
|
||||
title: function() {
|
||||
if (this.get('category.id')) return Em.String.i18n("category.edit_long");
|
||||
if (this.get('category.isUncategorized')) return Em.String.i18n("category.edit_uncategorized");
|
||||
return Em.String.i18n("category.create");
|
||||
}.property('category.id'),
|
||||
|
||||
categoryName: function() {
|
||||
var name = this.get('category.name') || "";
|
||||
return name.trim().length > 0 ? name : Em.String.i18n("preview");
|
||||
}.property('category.name'),
|
||||
|
||||
buttonTitle: function() {
|
||||
if (this.get('saving')) return Em.String.i18n("saving");
|
||||
if (this.get('category.isUncategorized')) return Em.String.i18n("save");
|
||||
return (this.get('category.id') ? Em.String.i18n("category.save") : Em.String.i18n("category.create"));
|
||||
}.property('saving', 'category.id'),
|
||||
|
||||
deleteButtonTitle: function() {
|
||||
return Em.String.i18n('category.delete');
|
||||
}.property(),
|
||||
|
||||
didInsertElement: function() {
|
||||
this._super();
|
||||
|
||||
if (this.get('category.id')) {
|
||||
this.set('loading', true);
|
||||
var categoryView = this;
|
||||
|
||||
// We need the topic_count to be correct, so get the most up-to-date info about this category from the server.
|
||||
Discourse.Category.findBySlugOrId( this.get('category.slug') || this.get('category.id') ).then( function(cat) {
|
||||
categoryView.set('category', cat);
|
||||
Discourse.Site.instance().updateCategory(cat);
|
||||
categoryView.set('id', categoryView.get('category.slug'));
|
||||
categoryView.set('loading', false);
|
||||
});
|
||||
} else if( this.get('category.isUncategorized') ) {
|
||||
this.set('category', Discourse.Category.uncategorizedInstance());
|
||||
} else {
|
||||
this.set('category', Discourse.Category.create({ color: 'AB9364', text_color: 'FFFFFF', hotness: 5 }));
|
||||
}
|
||||
},
|
||||
|
||||
showCategoryTopic: function() {
|
||||
$('#discourse-modal').modal('hide');
|
||||
Discourse.URL.routeTo(this.get('category.topic_url'));
|
||||
return false;
|
||||
},
|
||||
|
||||
addGroup: function(){
|
||||
this.get("category").addGroup(this.get("selectedGroup"));
|
||||
},
|
||||
|
||||
removeGroup: function(group){
|
||||
// OBVIOUS, Ember treats this as Ember.String, we need a real string here
|
||||
group = group + "";
|
||||
this.get("category").removeGroup(group);
|
||||
},
|
||||
|
||||
saveCategory: function() {
|
||||
var categoryView = this;
|
||||
this.set('saving', true);
|
||||
|
||||
|
||||
if( this.get('category.isUncategorized') ) {
|
||||
$.when(
|
||||
Discourse.SiteSetting.update('uncategorized_color', this.get('category.color')),
|
||||
Discourse.SiteSetting.update('uncategorized_text_color', this.get('category.text_color')),
|
||||
Discourse.SiteSetting.update('uncategorized_name', this.get('category.name'))
|
||||
).then(function(result) {
|
||||
// success
|
||||
$('#discourse-modal').modal('hide');
|
||||
// We can't redirect to the uncategorized category on save because the slug
|
||||
// might have changed.
|
||||
Discourse.URL.redirectTo("/categories");
|
||||
}, function(errors) {
|
||||
// errors
|
||||
if(errors.length === 0) errors.push(Em.String.i18n("category.save_error"));
|
||||
categoryView.displayErrors(errors);
|
||||
categoryView.set('saving', false);
|
||||
});
|
||||
} else {
|
||||
this.get('category').save().then(function(result) {
|
||||
// success
|
||||
$('#discourse-modal').modal('hide');
|
||||
Discourse.URL.redirectTo("/category/" + Discourse.Category.slugFor(result.category));
|
||||
}, function(errors) {
|
||||
// errors
|
||||
if(errors.length === 0) errors.push(Em.String.i18n("category.creation_error"));
|
||||
categoryView.displayErrors(errors);
|
||||
categoryView.set('saving', false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
deleteCategory: function() {
|
||||
var categoryView = this;
|
||||
this.set('deleting', true);
|
||||
$('#discourse-modal').modal('hide');
|
||||
bootbox.confirm(Em.String.i18n("category.delete_confirm"), Em.String.i18n("no_value"), Em.String.i18n("yes_value"), function(result) {
|
||||
if (result) {
|
||||
categoryView.get('category').destroy().then(function(){
|
||||
// success
|
||||
Discourse.URL.redirectTo("/categories");
|
||||
}, function(jqXHR){
|
||||
// error
|
||||
$('#discourse-modal').modal('show');
|
||||
categoryView.displayErrors([Em.String.i18n("category.delete_error")]);
|
||||
categoryView.set('deleting', false);
|
||||
});
|
||||
} else {
|
||||
$('#discourse-modal').modal('show');
|
||||
categoryView.set('deleting', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
templateName: 'modal/edit_category'
|
||||
});
|
||||
|
|
|
@ -8,38 +8,5 @@
|
|||
**/
|
||||
Discourse.EditTopicAutoCloseView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/auto_close',
|
||||
title: Em.String.i18n('topic.auto_close_title'),
|
||||
modalClass: 'edit-auto-close-modal',
|
||||
|
||||
setDays: function() {
|
||||
if( this.get('topic.auto_close_at') ) {
|
||||
var closeTime = Date.create( this.get('topic.auto_close_at') );
|
||||
if (closeTime.isFuture()) {
|
||||
this.set('auto_close_days', closeTime.daysSince());
|
||||
}
|
||||
}
|
||||
}.observes('topic'),
|
||||
|
||||
saveAutoClose: function() {
|
||||
this.setAutoClose( parseFloat(this.get('auto_close_days')) );
|
||||
},
|
||||
|
||||
removeAutoClose: function() {
|
||||
this.setAutoClose(null);
|
||||
},
|
||||
|
||||
setAutoClose: function(days) {
|
||||
var view = this;
|
||||
Discourse.ajax({
|
||||
url: "/t/" + this.get('topic.id') + "/autoclose",
|
||||
type: 'PUT',
|
||||
dataType: 'json',
|
||||
data: { auto_close_days: days > 0 ? days : null }
|
||||
}).then(function(){
|
||||
view.get('topic').set('auto_close_at', Date.create(days + ' days from now').toJSON());
|
||||
}, function (error) {
|
||||
bootbox.alert(Em.String.i18n('generic_error'));
|
||||
});
|
||||
}
|
||||
|
||||
title: Em.String.i18n('topic.auto_close_title')
|
||||
});
|
|
@ -7,83 +7,19 @@
|
|||
@module Discourse
|
||||
**/
|
||||
Discourse.FlagView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'flag',
|
||||
templateName: 'modal/flag',
|
||||
title: Em.String.i18n('flagging.title'),
|
||||
|
||||
// trick to bind user / post to flag
|
||||
boundFlags: function(){
|
||||
var _this = this;
|
||||
var original = this.get('post.flagsAvailable');
|
||||
if(original){
|
||||
return $.map(original, function(v){
|
||||
var b = Discourse.BoundPostActionType.create(v);
|
||||
b.set('post', _this.get('post'));
|
||||
return b;
|
||||
});
|
||||
}
|
||||
}.property('post.flagsAvailable'),
|
||||
|
||||
changePostActionType: function(action) {
|
||||
|
||||
if (this.get('postActionTypeId') === action.id) return false;
|
||||
|
||||
this.get('boundFlags').each(function(f){
|
||||
f.set('selected', false);
|
||||
});
|
||||
action.set('selected', true);
|
||||
|
||||
this.set('postActionTypeId', action.id);
|
||||
this.set('isCustomFlag', action.is_custom_flag);
|
||||
this.set('selected', action);
|
||||
selectedChanged: function() {
|
||||
var nameKey = this.get('controller.selected.name_key');
|
||||
if (!nameKey) return;
|
||||
Em.run.next(function() {
|
||||
$('#radio_' + action.name_key).prop('checked', 'true');
|
||||
$('#radio_' + nameKey).prop('checked', 'true');
|
||||
});
|
||||
return false;
|
||||
},
|
||||
|
||||
createFlag: function() {
|
||||
var _this = this;
|
||||
|
||||
var action = this.get('selected');
|
||||
var postAction = this.get('post.actionByName.' + (action.get('name_key')));
|
||||
|
||||
var actionType = Discourse.Site.instance().postActionTypeById(this.get('postActionTypeId'));
|
||||
if (postAction) {
|
||||
postAction.act({
|
||||
message: action.get('message')
|
||||
}).then(function() {
|
||||
return $('#discourse-modal').modal('hide');
|
||||
}, function(errors) {
|
||||
return _this.displayErrors(errors);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
showSubmit: (function() {
|
||||
var m;
|
||||
if (this.get('postActionTypeId')) {
|
||||
if (this.get('isCustomFlag')) {
|
||||
m = this.get('selected.message');
|
||||
return m && m.length >= 10 && m.length <= 500;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}).property('isCustomFlag', 'selected.customMessageLength', 'postActionTypeId'),
|
||||
|
||||
submitText: function(){
|
||||
var action = this.get('selected');
|
||||
if (this.get('selected.is_custom_flag')) {
|
||||
return Em.String.i18n("flagging.notify_action");
|
||||
} else {
|
||||
return Em.String.i18n("flagging.action");
|
||||
}
|
||||
}.property('selected'),
|
||||
}.observes('controller.selected.name_key'),
|
||||
|
||||
didInsertElement: function() {
|
||||
this.set('postActionTypeId', null);
|
||||
this._super();
|
||||
|
||||
// Would be nice if there were an EmberJs radio button to do this for us. Oh well, one should be coming
|
||||
// in an upcoming release.
|
||||
|
|
|
@ -8,25 +8,7 @@
|
|||
**/
|
||||
Discourse.ForgotPasswordView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/forgot_password',
|
||||
title: Em.String.i18n('forgot_password.title'),
|
||||
|
||||
// You need a value in the field to submit it.
|
||||
submitDisabled: (function() {
|
||||
return this.blank('accountEmailOrUsername');
|
||||
}).property('accountEmailOrUsername'),
|
||||
|
||||
submit: function() {
|
||||
|
||||
Discourse.ajax("/session/forgot_password", {
|
||||
data: { login: this.get('accountEmailOrUsername') },
|
||||
type: 'POST'
|
||||
});
|
||||
|
||||
// don't tell people what happened, this keeps it more secure (ensure same on server)
|
||||
this.flash(Em.String.i18n('forgot_password.complete'));
|
||||
return false;
|
||||
}
|
||||
|
||||
title: Em.String.i18n('forgot_password.title')
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
/*jshint newcap:false*/
|
||||
/*global diff_match_patch:true assetPath:true*/
|
||||
|
||||
/**
|
||||
This view handles rendering of the history of a post
|
||||
|
||||
|
@ -9,75 +6,7 @@
|
|||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.HistoryView = Discourse.View.extend({
|
||||
templateName: 'history',
|
||||
title: Em.String.i18n('history'),
|
||||
modalClass: 'history-modal',
|
||||
diffLibraryLoaded: false,
|
||||
diff: null,
|
||||
|
||||
init: function(){
|
||||
this._super();
|
||||
var historyView = this;
|
||||
$LAB.script(assetPath('defer/google_diff_match_patch')).wait(function(){
|
||||
historyView.set('diffLibraryLoaded', true);
|
||||
});
|
||||
},
|
||||
|
||||
loadSide: function(side) {
|
||||
if (this.get("version" + side)) {
|
||||
var orig = this.get('originalPost');
|
||||
var version = this.get("version" + side + ".number");
|
||||
if (version === orig.get('version')) {
|
||||
this.set("post" + side, orig);
|
||||
} else {
|
||||
var historyView = this;
|
||||
Discourse.Post.loadVersion(orig.get('id'), version).then(function(post) {
|
||||
historyView.set("post" + side, post);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
changedLeftVersion: function() {
|
||||
this.loadSide("Left");
|
||||
}.observes('versionLeft'),
|
||||
|
||||
changedRightVersion: function() {
|
||||
this.loadSide("Right");
|
||||
}.observes('versionRight'),
|
||||
|
||||
loadedPosts: function() {
|
||||
if (this.get('diffLibraryLoaded') && this.get('postLeft') && this.get('postRight')) {
|
||||
var dmp = new diff_match_patch(),
|
||||
before = this.get("postLeft.cooked"),
|
||||
after = this.get("postRight.cooked"),
|
||||
diff = dmp.diff_main(before, after);
|
||||
dmp.diff_cleanupSemantic(diff);
|
||||
this.set('diff', dmp.diff_prettyHtml(diff));
|
||||
}
|
||||
}.observes('diffLibraryLoaded', 'postLeft', 'postRight'),
|
||||
|
||||
didInsertElement: function() {
|
||||
this.setProperties({
|
||||
loading: true,
|
||||
postLeft: null,
|
||||
postRight: null
|
||||
});
|
||||
|
||||
var historyView = this;
|
||||
this.get('originalPost').loadVersions().then(function(result) {
|
||||
result.each(function(item) {
|
||||
item.description = "v" + item.number + " - " + Date.create(item.created_at).relative() + " - " +
|
||||
Em.String.i18n("changed_by", { author: item.display_username });
|
||||
});
|
||||
|
||||
historyView.setProperties({
|
||||
loading: false,
|
||||
versionLeft: result.first(),
|
||||
versionRight: result.last(),
|
||||
versions: result
|
||||
});
|
||||
});
|
||||
}
|
||||
Discourse.HistoryView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/history',
|
||||
title: Em.String.i18n('history')
|
||||
});
|
||||
|
|
|
@ -2,38 +2,22 @@
|
|||
This view handles the image upload interface
|
||||
|
||||
@class ImageSelectorView
|
||||
@extends Discourse.View
|
||||
@extends Discourse.ModalBodyView
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ImageSelectorView = Discourse.View.extend({
|
||||
templateName: 'image_selector',
|
||||
Discourse.ImageSelectorView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/image_selector',
|
||||
classNames: ['image-selector'],
|
||||
title: Em.String.i18n('image_selector.title'),
|
||||
|
||||
init: function() {
|
||||
this._super();
|
||||
this.set('localSelected', true);
|
||||
},
|
||||
|
||||
selectLocal: function() {
|
||||
this.set('localSelected', true);
|
||||
},
|
||||
|
||||
selectRemote: function() {
|
||||
this.set('localSelected', false);
|
||||
},
|
||||
|
||||
remoteSelected: function() {
|
||||
return !this.get('localSelected');
|
||||
}.property('localSelected'),
|
||||
|
||||
upload: function() {
|
||||
this.get('uploadTarget').fileupload('add', { fileInput: $('#filename-input') });
|
||||
$('#reply-control').fileupload('add', { fileInput: $('#filename-input') });
|
||||
},
|
||||
|
||||
add: function() {
|
||||
this.get('composer').addMarkdown("![image](" + $('#fileurl-input').val() + ")");
|
||||
this.get('controller.composerView').addMarkdown("![image](" + $('#fileurl-input').val() + ")");
|
||||
$('#discourse-modal').modal('hide');
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
/**
|
||||
A modal view for inviting a user to Discourse
|
||||
|
||||
@class InviteModalView
|
||||
@extends Discourse.ModalBodyView
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.InviteModalView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/invite',
|
||||
title: Em.String.i18n('topic.invite_reply.title'),
|
||||
email: null,
|
||||
error: false,
|
||||
saving: false,
|
||||
finished: false,
|
||||
|
||||
disabled: (function() {
|
||||
if (this.get('saving')) return true;
|
||||
if (this.blank('email')) return true;
|
||||
if (!Discourse.Utilities.emailValid(this.get('email'))) return true;
|
||||
return false;
|
||||
}).property('email', 'saving'),
|
||||
|
||||
buttonTitle: (function() {
|
||||
if (this.get('saving')) return Em.String.i18n('topic.inviting');
|
||||
return Em.String.i18n('topic.invite_reply.action');
|
||||
}).property('saving'),
|
||||
|
||||
successMessage: (function() {
|
||||
return Em.String.i18n('topic.invite_reply.success', {
|
||||
email: this.get('email')
|
||||
});
|
||||
}).property('email'),
|
||||
|
||||
didInsertElement: function() {
|
||||
var inviteModalView = this;
|
||||
Em.run.schedule('afterRender', function() {
|
||||
inviteModalView.$('input').focus();
|
||||
});
|
||||
},
|
||||
|
||||
createInvite: function() {
|
||||
var _this = this;
|
||||
this.set('saving', true);
|
||||
this.set('error', false);
|
||||
this.get('topic').inviteUser(this.get('email')).then(function() {
|
||||
// Success
|
||||
_this.set('saving', false);
|
||||
return _this.set('finished', true);
|
||||
}, function() {
|
||||
// Failure
|
||||
_this.set('error', true);
|
||||
return _this.set('saving', false);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/**
|
||||
A modal view for inviting a user to private message
|
||||
|
||||
@class InvitePrivateModalView
|
||||
@extends Discourse.ModalBodyView
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.InvitePrivateModalView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/invite_private',
|
||||
title: Em.String.i18n('topic.invite_private.title'),
|
||||
email: null,
|
||||
error: false,
|
||||
saving: false,
|
||||
finished: false,
|
||||
|
||||
disabled: (function() {
|
||||
if (this.get('saving')) return true;
|
||||
return this.blank('emailOrUsername');
|
||||
}).property('emailOrUsername', 'saving'),
|
||||
|
||||
buttonTitle: (function() {
|
||||
if (this.get('saving')) return Em.String.i18n('topic.inviting');
|
||||
return Em.String.i18n('topic.invite_private.action');
|
||||
}).property('saving'),
|
||||
|
||||
didInsertElement: function() {
|
||||
var invitePrivateModalView = this;
|
||||
Em.run.schedule('afterRender', function() {
|
||||
invitePrivateModalView.$('input').focus();
|
||||
});
|
||||
},
|
||||
|
||||
invite: function() {
|
||||
var _this = this;
|
||||
this.set('saving', true);
|
||||
this.set('error', false);
|
||||
// Invite the user to the private message
|
||||
this.get('topic').inviteUser(this.get('emailOrUsername')).then(function() {
|
||||
// Success
|
||||
_this.set('saving', false);
|
||||
_this.set('finished', true);
|
||||
}, function() {
|
||||
// Failure
|
||||
_this.set('error', true);
|
||||
_this.set('saving', false);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
A modal view for inviting a user to private message
|
||||
|
||||
@class InvitePrivateView
|
||||
@extends Discourse.ModalBodyView
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.InvitePrivateView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/invite_private',
|
||||
title: Em.String.i18n('topic.invite_private.title'),
|
||||
|
||||
didInsertElement: function() {
|
||||
this._super();
|
||||
var invitePrivateModalView = this;
|
||||
Em.run.schedule('afterRender', function() {
|
||||
invitePrivateModalView.$('input').focus();
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
24
app/assets/javascripts/discourse/views/modal/invite_view.js
Normal file
24
app/assets/javascripts/discourse/views/modal/invite_view.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
A modal view for inviting a user to Discourse
|
||||
|
||||
@class InviteView
|
||||
@extends Discourse.ModalBodyView
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.InviteView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/invite',
|
||||
title: Em.String.i18n('topic.invite_reply.title'),
|
||||
|
||||
didInsertElement: function() {
|
||||
this._super();
|
||||
|
||||
var inviteModalView = this;
|
||||
Em.run.schedule('afterRender', function() {
|
||||
inviteModalView.$('input').focus();
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -9,175 +9,29 @@
|
|||
Discourse.LoginView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/login',
|
||||
title: Em.String.i18n('login.title'),
|
||||
authenticate: null,
|
||||
loggingIn: false,
|
||||
|
||||
|
||||
site: function() {
|
||||
return Discourse.Site.instance();
|
||||
}.property(),
|
||||
|
||||
showView: function(view) {
|
||||
return this.get('controller').show(view);
|
||||
},
|
||||
|
||||
newAccount: function() {
|
||||
return this.showView(Discourse.CreateAccountView.create());
|
||||
},
|
||||
|
||||
forgotPassword: function() {
|
||||
return this.showView(Discourse.ForgotPasswordView.create());
|
||||
},
|
||||
|
||||
/**
|
||||
Determines whether at least one login button is enabled
|
||||
**/
|
||||
hasAtLeastOneLoginButton: function() {
|
||||
return Discourse.SiteSettings.enable_google_logins ||
|
||||
Discourse.SiteSettings.enable_facebook_logins ||
|
||||
Discourse.SiteSettings.enable_cas_logins ||
|
||||
Discourse.SiteSettings.enable_twitter_logins ||
|
||||
Discourse.SiteSettings.enable_yahoo_logins ||
|
||||
Discourse.SiteSettings.enable_github_logins ||
|
||||
Discourse.SiteSettings.enable_persona_logins;
|
||||
}.property(),
|
||||
|
||||
loginButtonText: function() {
|
||||
return this.get('loggingIn') ? Em.String.i18n('login.logging_in') : Em.String.i18n('login.title');
|
||||
}.property('loggingIn'),
|
||||
|
||||
loginDisabled: function() {
|
||||
return this.get('loggingIn') || this.blank('loginName') || this.blank('loginPassword');
|
||||
}.property('loginName', 'loginPassword', 'loggingIn'),
|
||||
|
||||
login: function() {
|
||||
this.set('loggingIn', true);
|
||||
|
||||
var loginView = this;
|
||||
Discourse.ajax("/session", {
|
||||
data: { login: this.get('loginName'), password: this.get('loginPassword') },
|
||||
type: 'POST'
|
||||
}).then(function (result) {
|
||||
// Successful login
|
||||
if (result.error) {
|
||||
loginView.set('loggingIn', false);
|
||||
if( result.reason === 'not_activated' ) {
|
||||
return loginView.showView(Discourse.NotActivatedView.create({
|
||||
username: loginView.get('loginName'),
|
||||
sentTo: result.sent_to_email,
|
||||
currentEmail: result.current_email
|
||||
}));
|
||||
}
|
||||
loginView.flash(result.error, 'error');
|
||||
} else {
|
||||
// Trigger the browser's password manager using the hidden static login form:
|
||||
var $hidden_login_form = $('#hidden-login-form');
|
||||
$hidden_login_form.find('input[name=username]').val(loginView.get('loginName'));
|
||||
$hidden_login_form.find('input[name=password]').val(loginView.get('loginPassword'));
|
||||
$hidden_login_form.find('input[name=redirect]').val(window.location.href);
|
||||
$hidden_login_form.find('input[name=authenticity_token]').val($('meta[name=csrf-token]').attr('content'));
|
||||
$hidden_login_form.submit();
|
||||
}
|
||||
|
||||
}, function(result) {
|
||||
// Failed to login
|
||||
loginView.flash(Em.String.i18n('login.error'), 'error');
|
||||
loginView.set('loggingIn', false);
|
||||
})
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
authMessage: (function() {
|
||||
if (this.blank('authenticate')) return "";
|
||||
return Em.String.i18n("login." + (this.get('authenticate')) + ".message");
|
||||
}).property('authenticate'),
|
||||
|
||||
twitterLogin: function() {
|
||||
this.set('authenticate', 'twitter');
|
||||
var left = this.get('lastX') - 400;
|
||||
var top = this.get('lastY') - 200;
|
||||
return window.open(Discourse.getURL("/auth/twitter"), "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
},
|
||||
|
||||
facebookLogin: function() {
|
||||
this.set('authenticate', 'facebook');
|
||||
var left = this.get('lastX') - 400;
|
||||
var top = this.get('lastY') - 200;
|
||||
return window.open(Discourse.getURL("/auth/facebook"), "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
},
|
||||
|
||||
casLogin: function() {
|
||||
var left, top;
|
||||
this.set('authenticate', 'cas');
|
||||
left = this.get('lastX') - 400;
|
||||
top = this.get('lastY') - 200;
|
||||
return window.open("/auth/cas", "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
},
|
||||
|
||||
openidLogin: function(provider) {
|
||||
var left = this.get('lastX') - 400;
|
||||
var top = this.get('lastY') - 200;
|
||||
if (provider === "yahoo") {
|
||||
this.set("authenticate", 'yahoo');
|
||||
return window.open(Discourse.getURL("/auth/yahoo"), "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
} else {
|
||||
window.open(Discourse.getURL("/auth/google"), "_blank", "menubar=no,status=no,height=500,width=850,left=" + left + ",top=" + top);
|
||||
return this.set("authenticate", 'google');
|
||||
}
|
||||
},
|
||||
|
||||
githubLogin: function() {
|
||||
this.set('authenticate', 'github');
|
||||
var left = this.get('lastX') - 400;
|
||||
var top = this.get('lastY') - 200;
|
||||
return window.open(Discourse.getURL("/auth/github"), "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top);
|
||||
},
|
||||
|
||||
personaLogin: function() {
|
||||
navigator.id.request();
|
||||
},
|
||||
|
||||
authenticationComplete: function(options) {
|
||||
if (options.awaiting_approval) {
|
||||
this.flash(Em.String.i18n('login.awaiting_approval'), 'success');
|
||||
this.set('authenticate', null);
|
||||
return;
|
||||
}
|
||||
if (options.awaiting_activation) {
|
||||
this.flash(Em.String.i18n('login.awaiting_confirmation'), 'success');
|
||||
this.set('authenticate', null);
|
||||
return;
|
||||
}
|
||||
// Reload the page if we're authenticated
|
||||
if (options.authenticated) {
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
return this.showView(Discourse.CreateAccountView.create({
|
||||
accountEmail: options.email,
|
||||
accountUsername: options.username,
|
||||
accountName: options.name,
|
||||
authOptions: Em.Object.create(options)
|
||||
}));
|
||||
},
|
||||
|
||||
mouseMove: function(e) {
|
||||
this.set('lastX', e.screenX);
|
||||
return this.set('lastY', e.screenY);
|
||||
this.set('controller.lastX', e.screenX);
|
||||
this.set('controller.lastY', e.screenY);
|
||||
},
|
||||
|
||||
didInsertElement: function(e) {
|
||||
|
||||
this._super();
|
||||
|
||||
var loginController = this.get('controller');
|
||||
|
||||
// Get username and password from the browser's password manager,
|
||||
// if it filled the hidden static login form:
|
||||
this.set('loginName', $('#hidden-login-form input[name=username]').val());
|
||||
this.set('loginPassword', $('#hidden-login-form input[name=password]').val());
|
||||
loginController.set('loginName', $('#hidden-login-form input[name=username]').val());
|
||||
loginController.set('loginPassword', $('#hidden-login-form input[name=password]').val());
|
||||
|
||||
|
||||
var loginView = this;
|
||||
Em.run.schedule('afterRender', function() {
|
||||
$('#login-account-password').keydown(function(e) {
|
||||
if (e.keyCode === 13) {
|
||||
loginView.login();
|
||||
loginController.login();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,49 +6,9 @@
|
|||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.MergeTopicView = Discourse.ModalBodyView.extend(Discourse.SelectedPostsCount, {
|
||||
Discourse.MergeTopicView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/merge_topic',
|
||||
title: Em.String.i18n('topic.merge_topic.title'),
|
||||
|
||||
buttonDisabled: function() {
|
||||
if (this.get('saving')) return true;
|
||||
return this.blank('selectedTopicId');
|
||||
}.property('selectedTopicId', 'saving'),
|
||||
|
||||
buttonTitle: function() {
|
||||
if (this.get('saving')) return Em.String.i18n('saving');
|
||||
return Em.String.i18n('topic.merge_topic.title');
|
||||
}.property('saving'),
|
||||
|
||||
movePostsToExistingTopic: function() {
|
||||
this.set('saving', true);
|
||||
|
||||
var moveSelectedView = this;
|
||||
|
||||
var promise = null;
|
||||
if (this.get('allPostsSelected')) {
|
||||
promise = Discourse.Topic.mergeTopic(this.get('topic.id'), this.get('selectedTopicId'));
|
||||
} else {
|
||||
var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); });
|
||||
promise = Discourse.Topic.movePosts(this.get('topic.id'), {
|
||||
destination_topic_id: this.get('selectedTopicId'),
|
||||
post_ids: postIds
|
||||
});
|
||||
}
|
||||
|
||||
promise.then(function(result) {
|
||||
// Posts moved
|
||||
$('#discourse-modal').modal('hide');
|
||||
moveSelectedView.get('topicController').toggleMultiSelect();
|
||||
Em.run.next(function() { Discourse.URL.routeTo(result.url); });
|
||||
}, function() {
|
||||
// Error moving posts
|
||||
moveSelectedView.flash(Em.String.i18n('topic.merge_topic.error'));
|
||||
moveSelectedView.set('saving', false);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
title: Em.String.i18n('topic.merge_topic.title')
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -10,10 +10,18 @@ Discourse.ModalBodyView = Discourse.View.extend({
|
|||
|
||||
// Focus on first element
|
||||
didInsertElement: function() {
|
||||
$('#discourse-modal').modal('show');
|
||||
$('#modal-alert').hide();
|
||||
|
||||
var modalBodyView = this;
|
||||
Em.run.schedule('afterRender', function() {
|
||||
modalBodyView.$('form input:first').focus();
|
||||
});
|
||||
|
||||
var title = this.get('title');
|
||||
if (title) {
|
||||
this.set('controller.controllers.modal.title', title);
|
||||
}
|
||||
},
|
||||
|
||||
// Pass the errors to our errors view
|
||||
|
@ -22,14 +30,16 @@ Discourse.ModalBodyView = Discourse.View.extend({
|
|||
if (typeof callback === "function") callback();
|
||||
},
|
||||
|
||||
// Just use jQuery to show an alert. We don't need anythign fancier for now
|
||||
// like an actual ember view
|
||||
flash: function(msg, flashClass) {
|
||||
if (!flashClass) flashClass = "success";
|
||||
flashMessageChanged: function() {
|
||||
var flashMessage = this.get('controller.flashMessage');
|
||||
if (flashMessage) {
|
||||
var messageClass = flashMessage.get('messageClass') || 'success';
|
||||
var $alert = $('#modal-alert').hide().removeClass('alert-error', 'alert-success');
|
||||
$alert.addClass("alert alert-" + flashClass).html(msg);
|
||||
$alert.addClass("alert alert-" + messageClass).html(flashMessage.get('message'));
|
||||
$alert.fadeIn();
|
||||
}
|
||||
}.observes('controller.flashMessage')
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -6,30 +6,10 @@
|
|||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ModalView = Ember.ContainerView.extend({
|
||||
childViews: ['modalHeaderView', 'modalBodyView', 'modalErrorsView'],
|
||||
classNames: ['modal', 'hidden'],
|
||||
classNameBindings: ['controller.currentView.modalClass'],
|
||||
Discourse.ModalView = Discourse.View.extend({
|
||||
elementId: 'discourse-modal',
|
||||
|
||||
modalHeaderView: Ember.View.create({
|
||||
templateName: 'modal/modal_header',
|
||||
titleBinding: 'controller.currentView.title'
|
||||
}),
|
||||
modalBodyView: Ember.ContainerView.create({ currentViewBinding: 'controller.currentView' }),
|
||||
modalErrorsView: Ember.View.create({ templateName: 'modal/modal_errors' }),
|
||||
|
||||
viewChanged: function() {
|
||||
this.set('modalErrorsView.errors', null);
|
||||
|
||||
var view = this.get('controller.currentView');
|
||||
var modalView = this;
|
||||
if (view) {
|
||||
$('#modal-alert').hide();
|
||||
Em.run.schedule('afterRender', function() { modalView.$().modal('show'); });
|
||||
}
|
||||
}.observes('controller.currentView')
|
||||
|
||||
templateName: 'modal/modal',
|
||||
classNameBindings: [':modal', ':hidden', 'controller.modalClass']
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -8,11 +8,5 @@
|
|||
**/
|
||||
Discourse.NotActivatedView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/not_activated',
|
||||
title: Em.String.i18n('log_in'),
|
||||
emailSent: false,
|
||||
|
||||
sendActivationEmail: function() {
|
||||
Discourse.ajax('/users/' + this.get('username') + '/send_activation_email');
|
||||
this.set('emailSent', true);
|
||||
}
|
||||
title: Em.String.i18n('log_in')
|
||||
});
|
||||
|
|
|
@ -8,40 +8,7 @@
|
|||
**/
|
||||
Discourse.SplitTopicView = Discourse.ModalBodyView.extend(Discourse.SelectedPostsCount, {
|
||||
templateName: 'modal/split_topic',
|
||||
title: Em.String.i18n('topic.split_topic.title'),
|
||||
saving: false,
|
||||
|
||||
buttonDisabled: function() {
|
||||
if (this.get('saving')) return true;
|
||||
return this.blank('topicName');
|
||||
}.property('saving', 'topicName'),
|
||||
|
||||
buttonTitle: function() {
|
||||
if (this.get('saving')) return Em.String.i18n('saving');
|
||||
return Em.String.i18n('topic.split_topic.action');
|
||||
}.property('saving'),
|
||||
|
||||
movePostsToNewTopic: function() {
|
||||
this.set('saving', true);
|
||||
|
||||
var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); });
|
||||
var moveSelectedView = this;
|
||||
|
||||
Discourse.Topic.movePosts(this.get('topic.id'), {
|
||||
title: this.get('topicName'),
|
||||
post_ids: postIds
|
||||
}).then(function(result) {
|
||||
// Posts moved
|
||||
$('#discourse-modal').modal('hide');
|
||||
moveSelectedView.get('topicController').toggleMultiSelect();
|
||||
Em.run.next(function() { Discourse.URL.routeTo(result.url); });
|
||||
}, function() {
|
||||
// Error moving posts
|
||||
moveSelectedView.flash(Em.String.i18n('topic.split_topic.error'));
|
||||
moveSelectedView.set('saving', false);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
title: Em.String.i18n('topic.split_topic.title')
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
/**
|
||||
A modal view for displaying the ranking details of a topic
|
||||
|
||||
@class TopicRankDetailsView
|
||||
@extends Discourse.ModalBodyView
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.TopicRankDetailsView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/topic_rank_details',
|
||||
title: Em.String.i18n('rank_details.title')
|
||||
|
||||
});
|
|
@ -113,7 +113,7 @@ Discourse.PostMenuView = Discourse.View.extend({
|
|||
},
|
||||
|
||||
clickFlag: function() {
|
||||
this.get('controller').showFlags(this.get('post'));
|
||||
this.get('controller').send('showFlags', this.get('post'));
|
||||
},
|
||||
|
||||
// Edit button
|
||||
|
|
|
@ -38,7 +38,7 @@ Discourse.TopicFooterButtonsView = Ember.ContainerView.extend({
|
|||
},
|
||||
|
||||
click: function() {
|
||||
return this.get('controller').showInviteModal();
|
||||
return this.get('controller').send('showInvite');
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -170,8 +170,7 @@ Discourse.TopicFooterButtonsView = Ember.ContainerView.extend({
|
|||
textKey: 'topic.login_reply',
|
||||
classNames: ['btn', 'btn-primary', 'create'],
|
||||
click: function() {
|
||||
var _ref;
|
||||
return (_ref = this.get('controller.controllers.modal')) ? _ref.show(Discourse.LoginView.create()) : void 0;
|
||||
this.get('controller').send('showLogin');
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ class TopicList
|
|||
def has_rank_details?
|
||||
|
||||
# Only moderators can see rank details
|
||||
return false unless @current_user.try(:moderator?)
|
||||
return false unless @current_user.try(:staff?)
|
||||
|
||||
# Only show them on 'Hot'
|
||||
return @filter == :hot
|
||||
|
|
Loading…
Reference in a new issue