mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
Merge pull request #2141 from riking/correctness
Lots of JS correctness fixes
This commit is contained in:
commit
51e3d72461
@ -25,7 +25,7 @@ Discourse.AdminApiController = Ember.ArrayController.extend({
|
|||||||
Creates an API key instance with internal user object
|
Creates an API key instance with internal user object
|
||||||
|
|
||||||
@method regenerateKey
|
@method regenerateKey
|
||||||
@param {Discourse.ApiKey} the key to regenerate
|
@param {Discourse.ApiKey} key the key to regenerate
|
||||||
**/
|
**/
|
||||||
regenerateKey: function(key) {
|
regenerateKey: function(key) {
|
||||||
bootbox.confirm(I18n.t("admin.api.confirm_regen"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
|
bootbox.confirm(I18n.t("admin.api.confirm_regen"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
|
||||||
@ -39,7 +39,7 @@ Discourse.AdminApiController = Ember.ArrayController.extend({
|
|||||||
Revokes an API key
|
Revokes an API key
|
||||||
|
|
||||||
@method revokeKey
|
@method revokeKey
|
||||||
@param {Discourse.ApiKey} the key to revoke
|
@param {Discourse.ApiKey} key the key to revoke
|
||||||
**/
|
**/
|
||||||
revokeKey: function(key) {
|
revokeKey: function(key) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Discourse.AdminBackupsController = Ember.ObjectController.extend({
|
Discourse.AdminBackupsController = Ember.ObjectController.extend({
|
||||||
noOperationIsRunning: Em.computed.not("isOperationRunning"),
|
noOperationIsRunning: Em.computed.not("isOperationRunning"),
|
||||||
rollbackEnabled: Em.computed.and("canRollback", "restoreEnabled", "noOperationIsRunning"),
|
rollbackEnabled: Em.computed.and("canRollback", "restoreEnabled", "noOperationIsRunning"),
|
||||||
rollbackDisabled: Em.computed.not("rollbackEnabled"),
|
rollbackDisabled: Em.computed.not("rollbackEnabled")
|
||||||
});
|
});
|
||||||
|
@ -71,6 +71,5 @@ Discourse.AdminBackupsIndexController = Ember.ArrayController.extend({
|
|||||||
}).then(function() {
|
}).then(function() {
|
||||||
Discourse.set("isReadOnly", enable);
|
Discourse.set("isReadOnly", enable);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Discourse.AdminBackupsLogsController = Ember.ArrayController.extend({
|
Discourse.AdminBackupsLogsController = Ember.ArrayController.extend({
|
||||||
needs: ["adminBackups"],
|
needs: ["adminBackups"],
|
||||||
status: Em.computed.alias("controllers.adminBackups"),
|
status: Em.computed.alias("controllers.adminBackups")
|
||||||
});
|
});
|
||||||
|
@ -13,8 +13,7 @@ Discourse.AdminEmailSentController = Discourse.Controller.extend({
|
|||||||
Discourse.EmailLog.findAll(this.get("filter")).then(function(logs) {
|
Discourse.EmailLog.findAll(this.get("filter")).then(function(logs) {
|
||||||
self.set("model", logs);
|
self.set("model", logs);
|
||||||
});
|
});
|
||||||
}, 250).observes("filter.user", "filter.address", "filter.type", "filter.reply_key"),
|
}, 250).observes("filter.user", "filter.address", "filter.type", "filter.reply_key")
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,8 +31,7 @@ Discourse.AdminEmailSkippedController = Discourse.Controller.extend({
|
|||||||
Discourse.EmailLog.findAll(this.get("filter")).then(function(logs) {
|
Discourse.EmailLog.findAll(this.get("filter")).then(function(logs) {
|
||||||
self.set("model", logs);
|
self.set("model", logs);
|
||||||
});
|
});
|
||||||
}, 250).observes("filter.user", "filter.address", "filter.type", "filter.skipped_reason"),
|
}, 250).observes("filter.user", "filter.address", "filter.type", "filter.skipped_reason")
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ Discourse.ApiKey.reopenClass({
|
|||||||
Creates an API key instance with internal user object
|
Creates an API key instance with internal user object
|
||||||
|
|
||||||
@method create
|
@method create
|
||||||
@param {Object} the properties to create
|
@param {...} var_args the properties to initialize this with
|
||||||
@returns {Discourse.ApiKey} the ApiKey instance
|
@returns {Discourse.ApiKey} the ApiKey instance
|
||||||
**/
|
**/
|
||||||
create: function() {
|
create: function() {
|
||||||
|
@ -85,6 +85,5 @@ Discourse.Backup.reopenClass({
|
|||||||
window.location.pathname = Discourse.getURL("/");
|
window.location.pathname = Discourse.getURL("/");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -12,6 +12,5 @@ Discourse.BackupStatus = Discourse.Model.extend({
|
|||||||
|
|
||||||
restoreEnabled: function() {
|
restoreEnabled: function() {
|
||||||
return Discourse.SiteSettings.allow_restore && !this.get("isOperationRunning");
|
return Discourse.SiteSettings.allow_restore && !this.get("isOperationRunning");
|
||||||
}.property("isOperationRunning"),
|
}.property("isOperationRunning")
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -31,7 +31,7 @@ Discourse.AdminBackupsRoute = Discourse.Route.extend({
|
|||||||
}).then(function (status) {
|
}).then(function (status) {
|
||||||
return Discourse.BackupStatus.create({
|
return Discourse.BackupStatus.create({
|
||||||
isOperationRunning: status.is_operation_running,
|
isOperationRunning: status.is_operation_running,
|
||||||
canRollback: status.can_rollback,
|
canRollback: status.can_rollback
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -69,7 +69,7 @@ Discourse.AdminBackupsRoute = Discourse.Route.extend({
|
|||||||
Destroys a backup
|
Destroys a backup
|
||||||
|
|
||||||
@method destroyBackup
|
@method destroyBackup
|
||||||
@param {Discourse.Backup} the backup to destroy
|
@param {Discourse.Backup} backup the backup to destroy
|
||||||
**/
|
**/
|
||||||
destroyBackup: function(backup) {
|
destroyBackup: function(backup) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -91,7 +91,7 @@ Discourse.AdminBackupsRoute = Discourse.Route.extend({
|
|||||||
Start a restore and redirect the user to the logs tab
|
Start a restore and redirect the user to the logs tab
|
||||||
|
|
||||||
@method startRestore
|
@method startRestore
|
||||||
@param {Discourse.Backup} the backup to restore
|
@param {Discourse.Backup} backup the backup to restore
|
||||||
**/
|
**/
|
||||||
startRestore: function(backup) {
|
startRestore: function(backup) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -160,7 +160,6 @@ Discourse.AdminBackupsRoute = Discourse.Route.extend({
|
|||||||
|
|
||||||
uploadError: function(filename, message) {
|
uploadError: function(filename, message) {
|
||||||
bootbox.alert(I18n.t("admin.backups.upload.error", { filename: filename, message: message }));
|
bootbox.alert(I18n.t("admin.backups.upload.error", { filename: filename, message: message }));
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -22,7 +22,7 @@ Discourse.AdminCustomizeView = Discourse.View.extend({
|
|||||||
selectStylesheet: function() { this.set('selected', 'stylesheet'); },
|
selectStylesheet: function() { this.set('selected', 'stylesheet'); },
|
||||||
|
|
||||||
selectMobileHeader: function() { this.set('selected', 'mobileHeader'); },
|
selectMobileHeader: function() { this.set('selected', 'mobileHeader'); },
|
||||||
selectMobileStylesheet: function() { this.set('selected', 'mobileStylesheet'); },
|
selectMobileStylesheet: function() { this.set('selected', 'mobileStylesheet'); }
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
|
@ -8,7 +8,7 @@ Discourse.AutoCloseFormComponent = Ember.Component.extend({
|
|||||||
|
|
||||||
autoCloseChanged: function() {
|
autoCloseChanged: function() {
|
||||||
if( this.get('autoCloseTime') && this.get('autoCloseTime').length > 0 ) {
|
if( this.get('autoCloseTime') && this.get('autoCloseTime').length > 0 ) {
|
||||||
this.set('autoCloseTime', this.get('autoCloseTime').replace(/[^\d-\s\:]/g, '') );
|
this.set('autoCloseTime', this.get('autoCloseTime').replace(/[^:\d-\s]/g, '') );
|
||||||
}
|
}
|
||||||
this.set('autoCloseValid', this.isAutoCloseValid());
|
this.set('autoCloseValid', this.isAutoCloseValid());
|
||||||
}.observes('autoCloseTime'),
|
}.observes('autoCloseTime'),
|
||||||
|
@ -20,5 +20,5 @@ Discourse.DiscoveryController = Discourse.ObjectController.extend({
|
|||||||
showMoreDailyUrl: function() { return this.showMoreUrl('daily'); }.property('category', 'noSubcategories'),
|
showMoreDailyUrl: function() { return this.showMoreUrl('daily'); }.property('category', 'noSubcategories'),
|
||||||
showMoreWeeklyUrl: function() { return this.showMoreUrl('weekly'); }.property('category', 'noSubcategories'),
|
showMoreWeeklyUrl: function() { return this.showMoreUrl('weekly'); }.property('category', 'noSubcategories'),
|
||||||
showMoreMonthlyUrl: function() { return this.showMoreUrl('monthly'); }.property('category', 'noSubcategories'),
|
showMoreMonthlyUrl: function() { return this.showMoreUrl('monthly'); }.property('category', 'noSubcategories'),
|
||||||
showMoreYearlyUrl: function() { return this.showMoreUrl('yearly'); }.property('category', 'noSubcategories'),
|
showMoreYearlyUrl: function() { return this.showMoreUrl('yearly'); }.property('category', 'noSubcategories')
|
||||||
});
|
});
|
||||||
|
@ -12,6 +12,6 @@ Discourse.GroupController = Discourse.ObjectController.extend({
|
|||||||
// It would be nice if bootstrap marked action lists as selected when their links
|
// It would be nice if bootstrap marked action lists as selected when their links
|
||||||
// were 'active' not the `li` tags.
|
// were 'active' not the `li` tags.
|
||||||
showingIndex: Em.computed.equal('showing', 'index'),
|
showingIndex: Em.computed.equal('showing', 'index'),
|
||||||
showingMembers: Em.computed.equal('showing', 'members'),
|
showingMembers: Em.computed.equal('showing', 'members')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -44,8 +44,7 @@ Discourse.UserInvitedController = Ember.ArrayController.extend({
|
|||||||
@property showSearch
|
@property showSearch
|
||||||
**/
|
**/
|
||||||
showSearch: function() {
|
showSearch: function() {
|
||||||
if (Em.isNone(this.get('searchTerm')) && this.get('model.length') === 0) { return false; }
|
return !(Em.isNone(this.get('searchTerm')) && this.get('model.length') === 0);
|
||||||
return true;
|
|
||||||
}.property('searchTerm', 'model.length'),
|
}.property('searchTerm', 'model.length'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,7 +4,14 @@
|
|||||||
@method replaceBBCode
|
@method replaceBBCode
|
||||||
@param {tag} tag the tag we want to match
|
@param {tag} tag the tag we want to match
|
||||||
@param {function} emitter the function that creates JsonML for the tag
|
@param {function} emitter the function that creates JsonML for the tag
|
||||||
@param {Object} hash of options to pass to `inlineBetween`
|
@param {Object} opts options to pass to Discourse.Dialect.inlineBetween
|
||||||
|
@param {Function} [opts.emitter] The function that will be called with the contents and returns JsonML.
|
||||||
|
@param {String} [opts.start] The starting token we want to find
|
||||||
|
@param {String} [opts.stop] The ending token we want to find
|
||||||
|
@param {String} [opts.between] A shortcut for when the `start` and `stop` are the same.
|
||||||
|
@param {Boolean} [opts.rawContents] If true, the contents between the tokens will not be parsed.
|
||||||
|
@param {Boolean} [opts.wordBoundary] If true, the match must be on a word boundary
|
||||||
|
@param {Boolean} [opts.spaceBoundary] If true, the match must be on a sppace boundary
|
||||||
**/
|
**/
|
||||||
function replaceBBCode(tag, emitter, opts) {
|
function replaceBBCode(tag, emitter, opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
@ -120,10 +120,10 @@ function parseTree(tree, path, insideCounts) {
|
|||||||
**/
|
**/
|
||||||
function invalidBoundary(args, prev) {
|
function invalidBoundary(args, prev) {
|
||||||
|
|
||||||
if (!args.wordBoundary && !args.spaceBoundary) { return; }
|
if (!args.wordBoundary && !args.spaceBoundary) { return false; }
|
||||||
|
|
||||||
var last = prev[prev.length - 1];
|
var last = prev[prev.length - 1];
|
||||||
if (typeof last !== "string") { return; }
|
if (typeof last !== "string") { return false; }
|
||||||
|
|
||||||
if (args.wordBoundary && (last.match(/(\w|\/)$/))) { return true; }
|
if (args.wordBoundary && (last.match(/(\w|\/)$/))) { return true; }
|
||||||
if (args.spaceBoundary && (!last.match(/\s$/))) { return true; }
|
if (args.spaceBoundary && (!last.match(/\s$/))) { return true; }
|
||||||
@ -143,15 +143,15 @@ Discourse.Dialect = {
|
|||||||
|
|
||||||
@method cook
|
@method cook
|
||||||
@param {String} text the raw text to cook
|
@param {String} text the raw text to cook
|
||||||
|
@param {Object} opts hash of options
|
||||||
@returns {String} the cooked text
|
@returns {String} the cooked text
|
||||||
**/
|
**/
|
||||||
cook: function(text, opts) {
|
cook: function(text, opts) {
|
||||||
if (!initialized) { initializeDialects(); }
|
if (!initialized) { initializeDialects(); }
|
||||||
dialect.options = opts;
|
dialect.options = opts;
|
||||||
var tree = parser.toHTMLTree(text, 'Discourse'),
|
var tree = parser.toHTMLTree(text, 'Discourse');
|
||||||
html = parser.renderJsonML(parseTree(tree));
|
|
||||||
|
|
||||||
return html;
|
return parser.renderJsonML(parseTree(tree));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -288,9 +288,8 @@ Discourse.Dialect = {
|
|||||||
the other helpers such as `replaceBlock` so consider using them first!
|
the other helpers such as `replaceBlock` so consider using them first!
|
||||||
|
|
||||||
@method registerBlock
|
@method registerBlock
|
||||||
@param {String} the name of the block handler
|
@param {String} name the name of the block handler
|
||||||
@param {Function} the handler
|
@param {Function} handler the handler
|
||||||
|
|
||||||
**/
|
**/
|
||||||
registerBlock: function(name, handler) {
|
registerBlock: function(name, handler) {
|
||||||
dialect.block[name] = handler;
|
dialect.block[name] = handler;
|
||||||
|
@ -271,7 +271,7 @@ $.fn.autocomplete = function(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return $(this).keydown(function(e) {
|
return $(this).keydown(function(e) {
|
||||||
var c, caretPosition, i, initial, next, nextIsGood, prev, prevIsGood, stopFound, term, total, userToComplete;
|
var c, caretPosition, i, initial, next, prev, prevIsGood, stopFound, term, total, userToComplete;
|
||||||
|
|
||||||
if(options.allowAny){
|
if(options.allowAny){
|
||||||
// saves us wiring up a change event as well, keypress is while its pressed
|
// saves us wiring up a change event as well, keypress is while its pressed
|
||||||
@ -298,7 +298,6 @@ $.fn.autocomplete = function(options) {
|
|||||||
if ((completeStart === null) && e.which === 8 && options.key) {
|
if ((completeStart === null) && e.which === 8 && options.key) {
|
||||||
c = Discourse.Utilities.caretPosition(me[0]);
|
c = Discourse.Utilities.caretPosition(me[0]);
|
||||||
next = me[0].value[c];
|
next = me[0].value[c];
|
||||||
nextIsGood = next === void 0 || /\s/.test(next);
|
|
||||||
c -= 1;
|
c -= 1;
|
||||||
initial = c;
|
initial = c;
|
||||||
prevIsGood = true;
|
prevIsGood = true;
|
||||||
|
@ -71,8 +71,6 @@ $.fn.caretPosition = function(options) {
|
|||||||
"line-height": important("line-height")
|
"line-height": important("line-height")
|
||||||
});
|
});
|
||||||
|
|
||||||
before = void 0;
|
|
||||||
after = void 0;
|
|
||||||
pos = options && (options.pos || options.pos === 0) ? options.pos : getCaret(textarea[0]);
|
pos = options && (options.pos || options.pos === 0) ? options.pos : getCaret(textarea[0]);
|
||||||
val = textarea.val().replace("\r", "");
|
val = textarea.val().replace("\r", "");
|
||||||
if (options && options.key) {
|
if (options && options.key) {
|
||||||
|
@ -110,6 +110,6 @@ Discourse.computed = {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
return computed.property.apply(computed, args);
|
return computed.property.apply(computed, args);
|
||||||
},
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,6 @@ Discourse.Eyeline.prototype.update = function() {
|
|||||||
docViewBottom = docViewTop + windowHeight,
|
docViewBottom = docViewTop + windowHeight,
|
||||||
$elements = $(this.selector),
|
$elements = $(this.selector),
|
||||||
atBottom = false,
|
atBottom = false,
|
||||||
foundElement = false,
|
|
||||||
bottomOffset = $elements.last().offset(),
|
bottomOffset = $elements.last().offset(),
|
||||||
self = this;
|
self = this;
|
||||||
|
|
||||||
@ -29,9 +28,6 @@ Discourse.Eyeline.prototype.update = function() {
|
|||||||
atBottom = (bottomOffset.top <= docViewBottom) && (bottomOffset.top >= docViewTop);
|
atBottom = (bottomOffset.top <= docViewBottom) && (bottomOffset.top >= docViewTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whether we've seen any elements in this search
|
|
||||||
foundElement = false;
|
|
||||||
|
|
||||||
return $elements.each(function(i, elem) {
|
return $elements.each(function(i, elem) {
|
||||||
var $elem = $(elem),
|
var $elem = $(elem),
|
||||||
elemTop = $elem.offset().top,
|
elemTop = $elem.offset().top,
|
||||||
|
@ -237,7 +237,7 @@ relativeAgeMediumSpan = function(distance, leaveAgo) {
|
|||||||
|
|
||||||
relativeAgeMedium = function(date, options){
|
relativeAgeMedium = function(date, options){
|
||||||
var displayDate, fiveDaysAgo, oneMinuteAgo, fullReadable, leaveAgo;
|
var displayDate, fiveDaysAgo, oneMinuteAgo, fullReadable, leaveAgo;
|
||||||
var wrapInSpan = options.wrapInSpan === false ? false : true;
|
var wrapInSpan = options.wrapInSpan !== false;
|
||||||
|
|
||||||
leaveAgo = options.leaveAgo;
|
leaveAgo = options.leaveAgo;
|
||||||
var distance = Math.round((new Date() - date) / 1000);
|
var distance = Math.round((new Date() - date) / 1000);
|
||||||
|
@ -13,10 +13,10 @@ Discourse.Markdown = {
|
|||||||
validIframes: [],
|
validIframes: [],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Whitelists classes for sanitization
|
Whitelists more classes for sanitization.
|
||||||
|
|
||||||
|
@param {...String} var_args Classes to whitelist
|
||||||
@method whiteListClass
|
@method whiteListClass
|
||||||
@param {String} val The value to whitelist. Can supply more than one argument
|
|
||||||
**/
|
**/
|
||||||
whiteListClass: function() {
|
whiteListClass: function() {
|
||||||
var args = Array.prototype.slice.call(arguments),
|
var args = Array.prototype.slice.call(arguments),
|
||||||
@ -113,7 +113,10 @@ Discourse.Markdown = {
|
|||||||
Checks to see if a URL is allowed in the cooked content
|
Checks to see if a URL is allowed in the cooked content
|
||||||
|
|
||||||
@method urlAllowed
|
@method urlAllowed
|
||||||
@param {String} url Url to check
|
@param {String} uri Url to check
|
||||||
|
@param {Number} effect ignored
|
||||||
|
@param {Number} ltype ignored
|
||||||
|
@param {Object} hints an object with hints, used to check if this url is from an iframe
|
||||||
@return {String} url to insert in the cooked content
|
@return {String} url to insert in the cooked content
|
||||||
**/
|
**/
|
||||||
urlAllowed: function (uri, effect, ltype, hints) {
|
urlAllowed: function (uri, effect, ltype, hints) {
|
||||||
|
@ -14,7 +14,7 @@ Discourse.Mobile = {
|
|||||||
this.mobileView = $html.hasClass('mobile-view');
|
this.mobileView = $html.hasClass('mobile-view');
|
||||||
|
|
||||||
if (localStorage && localStorage.mobileView) {
|
if (localStorage && localStorage.mobileView) {
|
||||||
var savedValue = (localStorage.mobileView === 'true' ? true : false);
|
var savedValue = (localStorage.mobileView === 'true');
|
||||||
if (savedValue !== this.mobileView) {
|
if (savedValue !== this.mobileView) {
|
||||||
this.reloadPage(savedValue);
|
this.reloadPage(savedValue);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,8 @@ Discourse.PageTracker = Ember.Object.extend(Ember.Evented, {
|
|||||||
self = this;
|
self = this;
|
||||||
|
|
||||||
router.on('didTransition', function() {
|
router.on('didTransition', function() {
|
||||||
self.trigger('change', this.get('url'));
|
var router = this;
|
||||||
|
self.trigger('change', router.get('url'));
|
||||||
});
|
});
|
||||||
this.set('started', true);
|
this.set('started', true);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ Discourse.UserSearch = {
|
|||||||
var promise = Ember.Deferred.create();
|
var promise = Ember.Deferred.create();
|
||||||
|
|
||||||
// TODO site setting for allowed regex in username
|
// TODO site setting for allowed regex in username
|
||||||
if (term.match(/[^a-zA-Z0-9\_\.]/)) {
|
if (term.match(/[^a-zA-Z0-9_\.]/)) {
|
||||||
promise.resolve([]);
|
promise.resolve([]);
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
@ -54,8 +54,7 @@ Discourse.UserSearch = {
|
|||||||
users.push(u);
|
users.push(u);
|
||||||
results.push(u);
|
results.push(u);
|
||||||
}
|
}
|
||||||
if (results.length > limit) return false;
|
return results.length <= limit;
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_.each(r.groups,function(g) {
|
_.each(r.groups,function(g) {
|
||||||
|
@ -210,7 +210,7 @@ Discourse.Utilities = {
|
|||||||
Check the extension of the file against the list of authorized extensions
|
Check the extension of the file against the list of authorized extensions
|
||||||
|
|
||||||
@method isAuthorizedUpload
|
@method isAuthorizedUpload
|
||||||
@param {File} files The file we want to upload
|
@param {File} file The file we want to upload
|
||||||
**/
|
**/
|
||||||
isAuthorizedUpload: function(file) {
|
isAuthorizedUpload: function(file) {
|
||||||
var extensions = Discourse.SiteSettings.authorized_extensions;
|
var extensions = Discourse.SiteSettings.authorized_extensions;
|
||||||
|
@ -13,7 +13,8 @@ Discourse.ModalFunctionality = Em.Mixin.create({
|
|||||||
Flash a message at the top of the modal
|
Flash a message at the top of the modal
|
||||||
|
|
||||||
@method blank
|
@method blank
|
||||||
@param {String} name the name of the property we want to check
|
@param {String} message I18n name of the message
|
||||||
|
@param {String} messageClass CSS class to apply
|
||||||
@return {Boolean}
|
@return {Boolean}
|
||||||
**/
|
**/
|
||||||
flash: function(message, messageClass) {
|
flash: function(message, messageClass) {
|
||||||
|
@ -12,7 +12,6 @@ Discourse.ScrollTop = Em.Mixin.create({
|
|||||||
Em.run.schedule('afterRender', function() {
|
Em.run.schedule('afterRender', function() {
|
||||||
$(document).scrollTop(0);
|
$(document).scrollTop(0);
|
||||||
});
|
});
|
||||||
}.on('didInsertElement'),
|
}.on('didInsertElement')
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ Discourse.CategoryList.reopenClass({
|
|||||||
can_create_category: result.category_list.can_create_category,
|
can_create_category: result.category_list.can_create_category,
|
||||||
can_create_topic: result.category_list.can_create_topic,
|
can_create_topic: result.category_list.can_create_topic,
|
||||||
draft_key: result.category_list.draft_key,
|
draft_key: result.category_list.draft_key,
|
||||||
draft_sequence: result.category_list.draft_sequence,
|
draft_sequence: result.category_list.draft_sequence
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -126,14 +126,10 @@ Discourse.Composer = Discourse.Model.extend({
|
|||||||
// reply is always required
|
// reply is always required
|
||||||
if (this.get('missingReplyCharacters') > 0) return true;
|
if (this.get('missingReplyCharacters') > 0) return true;
|
||||||
|
|
||||||
if (this.get('canCategorize') &&
|
return this.get('canCategorize') &&
|
||||||
!Discourse.SiteSettings.allow_uncategorized_topics &&
|
!Discourse.SiteSettings.allow_uncategorized_topics &&
|
||||||
!this.get('categoryId') &&
|
!this.get('categoryId') &&
|
||||||
!Discourse.User.currentProp('staff')) {
|
!Discourse.User.currentProp('staff');
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}.property('loading', 'canEditTitle', 'titleLength', 'targetUsernames', 'replyLength', 'categoryId', 'missingReplyCharacters'),
|
}.property('loading', 'canEditTitle', 'titleLength', 'targetUsernames', 'replyLength', 'categoryId', 'missingReplyCharacters'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,11 +103,10 @@ Discourse.Post = Discourse.Model.extend({
|
|||||||
}.property('updated_at'),
|
}.property('updated_at'),
|
||||||
|
|
||||||
flagsAvailable: function() {
|
flagsAvailable: function() {
|
||||||
var post = this,
|
var post = this;
|
||||||
flags = Discourse.Site.currentProp('flagTypes').filter(function(item) {
|
return Discourse.Site.currentProp('flagTypes').filter(function(item) {
|
||||||
return post.get("actionByName." + (item.get('name_key')) + ".can_act");
|
return post.get("actionByName." + (item.get('name_key')) + ".can_act");
|
||||||
});
|
});
|
||||||
return flags;
|
|
||||||
}.property('actions_summary.@each.can_act'),
|
}.property('actions_summary.@each.can_act'),
|
||||||
|
|
||||||
actionsHistory: function() {
|
actionsHistory: function() {
|
||||||
|
@ -179,7 +179,6 @@ Discourse.PostStream = Em.Object.extend({
|
|||||||
Cancel any active filters on the stream.
|
Cancel any active filters on the stream.
|
||||||
|
|
||||||
@method cancelFilter
|
@method cancelFilter
|
||||||
@returns {Ember.Deferred} a promise that resolves when the filter has been cancelled.
|
|
||||||
**/
|
**/
|
||||||
cancelFilter: function() {
|
cancelFilter: function() {
|
||||||
this.set('summary', false);
|
this.set('summary', false);
|
||||||
@ -373,8 +372,8 @@ Discourse.PostStream = Em.Object.extend({
|
|||||||
`undoPost` when it fails.
|
`undoPost` when it fails.
|
||||||
|
|
||||||
@method stagePost
|
@method stagePost
|
||||||
@param {Discourse.Post} the post to stage in the stream
|
@param {Discourse.Post} post the post to stage in the stream
|
||||||
@param {Discourse.User} the user creating the post
|
@param {Discourse.User} user the user creating the post
|
||||||
**/
|
**/
|
||||||
stagePost: function(post, user) {
|
stagePost: function(post, user) {
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ Discourse.TopList.reopenClass({
|
|||||||
can_create_topic: result.can_create_topic,
|
can_create_topic: result.can_create_topic,
|
||||||
draft: result.draft,
|
draft: result.draft,
|
||||||
draft_key: result.draft_key,
|
draft_key: result.draft_key,
|
||||||
draft_sequence: result.draft_sequence,
|
draft_sequence: result.draft_sequence
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.Site.currentProp('periods').forEach(function(period) {
|
Discourse.Site.currentProp('periods').forEach(function(period) {
|
||||||
|
@ -168,8 +168,7 @@ Discourse.Topic = Discourse.Model.extend({
|
|||||||
if (!wordCount) return;
|
if (!wordCount) return;
|
||||||
|
|
||||||
// Avg for 500 words per minute when you account for skimming
|
// Avg for 500 words per minute when you account for skimming
|
||||||
var minutes = Math.floor(wordCount / 500.0);
|
return Math.floor(wordCount / 500.0);
|
||||||
return minutes;
|
|
||||||
}.property('word_count'),
|
}.property('word_count'),
|
||||||
|
|
||||||
toggleStar: function() {
|
toggleStar: function() {
|
||||||
|
@ -162,7 +162,7 @@ Discourse.TopicList.reopenClass({
|
|||||||
Stitch together side loaded topic data
|
Stitch together side loaded topic data
|
||||||
|
|
||||||
@method topicsFrom
|
@method topicsFrom
|
||||||
@param {Object} JSON object with topic data
|
@param {Object} result JSON object with topic data
|
||||||
@returns {Array} the list of topics
|
@returns {Array} the list of topics
|
||||||
**/
|
**/
|
||||||
topicsFrom: function(result) {
|
topicsFrom: function(result) {
|
||||||
@ -204,8 +204,8 @@ Discourse.TopicList.reopenClass({
|
|||||||
Lists topics on a given menu item
|
Lists topics on a given menu item
|
||||||
|
|
||||||
@method list
|
@method list
|
||||||
@param {Object} The menu item to filter to
|
@param {Object} filter The menu item to filter to
|
||||||
@param {Object} Any additional params
|
@param {Object} params Any additional params to pass to TopicList.find()
|
||||||
@returns {Promise} a promise that resolves to the list of topics
|
@returns {Promise} a promise that resolves to the list of topics
|
||||||
**/
|
**/
|
||||||
list: function(filter, params) {
|
list: function(filter, params) {
|
||||||
|
@ -461,6 +461,7 @@ Discourse.User.reopenClass(Discourse.Singleton, {
|
|||||||
@method checkUsername
|
@method checkUsername
|
||||||
@param {String} username A username to check
|
@param {String} username A username to check
|
||||||
@param {String} email An email address to check
|
@param {String} email An email address to check
|
||||||
|
@param {Number} forUserId user id - provide when changing username
|
||||||
**/
|
**/
|
||||||
checkUsername: function(username, email, forUserId) {
|
checkUsername: function(username, email, forUserId) {
|
||||||
return Discourse.ajax('/users/check_username', {
|
return Discourse.ajax('/users/check_username', {
|
||||||
@ -472,7 +473,7 @@ Discourse.User.reopenClass(Discourse.Singleton, {
|
|||||||
Groups the user's statistics
|
Groups the user's statistics
|
||||||
|
|
||||||
@method groupStats
|
@method groupStats
|
||||||
@param {Array} Given stats
|
@param {Array} stats Given stats
|
||||||
@returns {Object}
|
@returns {Object}
|
||||||
**/
|
**/
|
||||||
groupStats: function(stats) {
|
groupStats: function(stats) {
|
||||||
@ -507,6 +508,7 @@ Discourse.User.reopenClass(Discourse.Singleton, {
|
|||||||
@param {String} name This user's name
|
@param {String} name This user's name
|
||||||
@param {String} email This user's email
|
@param {String} email This user's email
|
||||||
@param {String} password This user's password
|
@param {String} password This user's password
|
||||||
|
@param {String} username This user's username
|
||||||
@param {String} passwordConfirm This user's confirmed password
|
@param {String} passwordConfirm This user's confirmed password
|
||||||
@param {String} challenge
|
@param {String} challenge
|
||||||
@returns Result of ajax call
|
@returns Result of ajax call
|
||||||
|
@ -45,5 +45,5 @@ Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend({
|
|||||||
}));
|
}));
|
||||||
this.controllerFor('editCategory').set('selectedTab', 'general');
|
this.controllerFor('editCategory').set('selectedTab', 'general');
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
@ -57,7 +57,7 @@ Discourse.PreferencesRoute = Discourse.RestrictedUserRoute.extend({
|
|||||||
Discourse.PreferencesIndexRoute = Discourse.RestrictedUserRoute.extend({
|
Discourse.PreferencesIndexRoute = Discourse.RestrictedUserRoute.extend({
|
||||||
renderTemplate: function() {
|
renderTemplate: function() {
|
||||||
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
<div class='controls'>
|
<div class='controls'>
|
||||||
<label class='radio'>
|
<label class='radio'>
|
||||||
<input type='radio' id="choose-topic-{{unbound id}}" name='choose_topic_id' {{action chooseTopic this target="view"}}>{{title}}
|
<input type='radio' id="choose-topic-{{unbound id}}" name='choose_topic_id' {{action chooseTopic this target="view"}}>{{title}}
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
</a>
|
</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if noSubcategories}}
|
{{#if noSubcategories}}
|
||||||
<a href='#' {{action expand}} class='badge-category home' {{bind-attr style="badgeStyle"}}>{{i18n categories.no_subcategory}}</i></a>
|
<a href='#' {{action expand}} class='badge-category home' {{bind-attr style="badgeStyle"}}>{{i18n categories.no_subcategory}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a href='#' {{action expand}} class='badge-category home' {{bind-attr style="badgeStyle"}}>{{allCategoriesLabel}}</i></a>
|
<a href='#' {{action expand}} class='badge-category home' {{bind-attr style="badgeStyle"}}>{{allCategoriesLabel}}</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<a href='#' {{action closeMessage this}} class='close'><i class='fa fa-times-circle'></i></a>
|
<a href='#' {{action closeMessage this}} class='close'><i class='fa fa-times-circle'></i></a>
|
||||||
<h3>{{i18n composer.similar_topics}}<h3>
|
<h3>{{i18n composer.similar_topics}}</h3>
|
||||||
|
|
||||||
<ul class='topics'>
|
<ul class='topics'>
|
||||||
{{#each similarTopics}}
|
{{#each similarTopics}}
|
||||||
|
@ -47,6 +47,7 @@ Discourse.ActionsHistoryComponent = Em.Component.extend({
|
|||||||
var key = 'post.actions.people.' + c.get('actionType.name_key');
|
var key = 'post.actions.people.' + c.get('actionType.name_key');
|
||||||
if (postUrl) { key = key + "_with_url"; }
|
if (postUrl) { key = key + "_with_url"; }
|
||||||
|
|
||||||
|
// TODO postUrl might be uninitialized? pick a good default
|
||||||
buffer.push(" " + I18n.t(key, { icons: iconsHtml, postUrl: postUrl}) + ".");
|
buffer.push(" " + I18n.t(key, { icons: iconsHtml, postUrl: postUrl}) + ".");
|
||||||
}
|
}
|
||||||
renderActionIf('usersCollapsed', 'who-acted', c.get('description'));
|
renderActionIf('usersCollapsed', 'who-acted', c.get('description'));
|
||||||
|
@ -504,7 +504,7 @@ Discourse.ComposerView = Discourse.View.extend(Ember.Evented, {
|
|||||||
var $uploadTarget = $('#reply-control');
|
var $uploadTarget = $('#reply-control');
|
||||||
$uploadTarget.fileupload('destroy');
|
$uploadTarget.fileupload('destroy');
|
||||||
$uploadTarget.off();
|
$uploadTarget.off();
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// not sure if this is the right way, keeping here for now, we could use a mixin perhaps
|
// not sure if this is the right way, keeping here for now, we could use a mixin perhaps
|
||||||
|
@ -14,7 +14,7 @@ Discourse.ContainerView = Ember.ContainerView.extend(Discourse.Presence, {
|
|||||||
|
|
||||||
@method attachViewWithArgs
|
@method attachViewWithArgs
|
||||||
@param {Object} viewArgs The arguments to pass when creating the view
|
@param {Object} viewArgs The arguments to pass when creating the view
|
||||||
@param {Class} klass The view class we want to create
|
@param {Class} viewClass The view class we want to create
|
||||||
**/
|
**/
|
||||||
attachViewWithArgs: function(viewArgs, viewClass) {
|
attachViewWithArgs: function(viewArgs, viewClass) {
|
||||||
if (!viewClass) { viewClass = Ember.View.extend(); }
|
if (!viewClass) { viewClass = Ember.View.extend(); }
|
||||||
@ -26,7 +26,7 @@ Discourse.ContainerView = Ember.ContainerView.extend(Discourse.Presence, {
|
|||||||
Attaches a view with no arguments and wires up the container properly
|
Attaches a view with no arguments and wires up the container properly
|
||||||
|
|
||||||
@method attachViewClass
|
@method attachViewClass
|
||||||
@param {Class} klass The view class we want to create
|
@param {Class} viewClass The view class we want to add
|
||||||
**/
|
**/
|
||||||
attachViewClass: function(viewClass) {
|
attachViewClass: function(viewClass) {
|
||||||
this.attachViewWithArgs(null, viewClass);
|
this.attachViewWithArgs(null, viewClass);
|
||||||
|
@ -12,9 +12,10 @@ Discourse.ModalBodyView = Discourse.View.extend({
|
|||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
$('#discourse-modal').modal('show');
|
var $discourseModal = $('#discourse-modal');
|
||||||
|
|
||||||
$('#discourse-modal').one("hide", function () {
|
$discourseModal.modal('show');
|
||||||
|
$discourseModal.one("hide", function () {
|
||||||
self.get("controller").send("closeModal");
|
self.get("controller").send("closeModal");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -207,7 +207,8 @@ Discourse.PostMenuView = Discourse.View.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
buffer.push("<button title=\"" + tooltip +
|
buffer.push("<button title=\"" + tooltip +
|
||||||
"\" data-action=\"bookmark\" class='bookmark'><div class='" + iconClass +
|
"\" data-action=\"bookmark\" class='" + buttonClass +
|
||||||
|
"'><div class='" + iconClass +
|
||||||
"'></div></button>");
|
"'></div></button>");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -39,8 +39,9 @@ Discourse.ShareView = Discourse.View.extend({
|
|||||||
}.observes('controller.link'),
|
}.observes('controller.link'),
|
||||||
|
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
var shareView = this;
|
var shareView = this,
|
||||||
$('html').on('mousedown.outside-share-link', function(e) {
|
$html = $('html');
|
||||||
|
$html.on('mousedown.outside-share-link', function(e) {
|
||||||
// Use mousedown instead of click so this event is handled before routing occurs when a
|
// Use mousedown instead of click so this event is handled before routing occurs when a
|
||||||
// link is clicked (which is a click event) while the share dialog is showing.
|
// link is clicked (which is a click event) while the share dialog is showing.
|
||||||
if (shareView.$().has(e.target).length !== 0) { return; }
|
if (shareView.$().has(e.target).length !== 0) { return; }
|
||||||
@ -49,9 +50,10 @@ Discourse.ShareView = Discourse.View.extend({
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
$('html').on('click.discoure-share-link', '[data-share-url]', function(e) {
|
$html.on('click.discoure-share-link', '[data-share-url]', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $currentTarget = $(e.currentTarget);
|
var $currentTarget = $(e.currentTarget),
|
||||||
|
$shareLink = $('#share-link');
|
||||||
var url = $currentTarget.data('share-url');
|
var url = $currentTarget.data('share-url');
|
||||||
var postNumber = $currentTarget.data('post-number');
|
var postNumber = $currentTarget.data('post-number');
|
||||||
// Relative urls
|
// Relative urls
|
||||||
@ -60,7 +62,7 @@ Discourse.ShareView = Discourse.View.extend({
|
|||||||
url = window.location.protocol + "//" + window.location.host + url;
|
url = window.location.protocol + "//" + window.location.host + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
var shareLinkWidth = $('#share-link').width();
|
var shareLinkWidth = $shareLink.width();
|
||||||
var x = e.pageX - (shareLinkWidth / 2);
|
var x = e.pageX - (shareLinkWidth / 2);
|
||||||
if (x < 25) {
|
if (x < 25) {
|
||||||
x = 25;
|
x = 25;
|
||||||
@ -70,12 +72,12 @@ Discourse.ShareView = Discourse.View.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
var header = $('.d-header');
|
var header = $('.d-header');
|
||||||
var y = e.pageY - ($('#share-link').height() + 20);
|
var y = e.pageY - ($shareLink.height() + 20);
|
||||||
if (y < header.offset().top + header.height()) {
|
if (y < header.offset().top + header.height()) {
|
||||||
y = e.pageY + 10;
|
y = e.pageY + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#share-link').css({
|
$shareLink.css({
|
||||||
left: "" + x + "px",
|
left: "" + x + "px",
|
||||||
top: "" + y + "px"
|
top: "" + y + "px"
|
||||||
});
|
});
|
||||||
@ -84,7 +86,7 @@ Discourse.ShareView = Discourse.View.extend({
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
$('html').on('keydown.share-view', function(e){
|
$html.on('keydown.share-view', function(e){
|
||||||
if (e.keyCode === 27) {
|
if (e.keyCode === 27) {
|
||||||
shareView.get('controller').send('close');
|
shareView.get('controller').send('close');
|
||||||
}
|
}
|
||||||
@ -92,9 +94,10 @@ Discourse.ShareView = Discourse.View.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement: function() {
|
willDestroyElement: function() {
|
||||||
$('html').off('click.discoure-share-link');
|
var $html = $('html');
|
||||||
$('html').off('mousedown.outside-share-link');
|
$html.off('click.discoure-share-link');
|
||||||
$('html').off('keydown.share-view');
|
$html.off('mousedown.outside-share-link');
|
||||||
|
$html.off('keydown.share-view');
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -7,4 +7,4 @@ I18n.pluralizationRules['cs'] = function (n) {
|
|||||||
if (n == 1) return "one";
|
if (n == 1) return "one";
|
||||||
if (n >= 2 && n <= 4) return "few";
|
if (n >= 2 && n <= 4) return "few";
|
||||||
return "other";
|
return "other";
|
||||||
}
|
};
|
||||||
|
@ -7,4 +7,4 @@ I18n.pluralizationRules['ru'] = function (n) {
|
|||||||
if (n % 10 == 1 && n % 100 != 11) return "one";
|
if (n % 10 == 1 && n % 100 != 11) return "one";
|
||||||
if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)) return "few";
|
if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)) return "few";
|
||||||
return "many";
|
return "many";
|
||||||
}
|
};
|
||||||
|
@ -22,7 +22,7 @@ module Jobs
|
|||||||
begin
|
begin
|
||||||
mail_string = mail.pop
|
mail_string = mail.pop
|
||||||
Email::Receiver.new(mail_string).process
|
Email::Receiver.new(mail_string).process
|
||||||
rescue Email::Receiver::UserNotSufficientTrustLevelError => e
|
rescue Email::Receiver::UserNotSufficientTrustLevelError
|
||||||
# inform the user about the rejection
|
# inform the user about the rejection
|
||||||
@message = Mail::Message.new(mail_string)
|
@message = Mail::Message.new(mail_string)
|
||||||
clientMessage = RejectionMailer.send_trust_level(@message.from, @message.body)
|
clientMessage = RejectionMailer.send_trust_level(@message.from, @message.body)
|
||||||
|
Loading…
Reference in New Issue
Block a user