Merge pull request #2141 from riking/correctness

Lots of JS correctness fixes
This commit is contained in:
Robin Ward 2014-03-19 11:20:15 -04:00
commit 51e3d72461
50 changed files with 99 additions and 102 deletions

View File

@ -25,7 +25,7 @@ Discourse.AdminApiController = Ember.ArrayController.extend({
Creates an API key instance with internal user object
@method regenerateKey
@param {Discourse.ApiKey} the key to regenerate
@param {Discourse.ApiKey} key the key to regenerate
**/
regenerateKey: function(key) {
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
@method revokeKey
@param {Discourse.ApiKey} the key to revoke
@param {Discourse.ApiKey} key the key to revoke
**/
revokeKey: function(key) {
var self = this;

View File

@ -1,5 +1,5 @@
Discourse.AdminBackupsController = Ember.ObjectController.extend({
noOperationIsRunning: Em.computed.not("isOperationRunning"),
rollbackEnabled: Em.computed.and("canRollback", "restoreEnabled", "noOperationIsRunning"),
rollbackDisabled: Em.computed.not("rollbackEnabled"),
rollbackDisabled: Em.computed.not("rollbackEnabled")
});

View File

@ -71,6 +71,5 @@ Discourse.AdminBackupsIndexController = Ember.ArrayController.extend({
}).then(function() {
Discourse.set("isReadOnly", enable);
});
},
}
});

View File

@ -1,4 +1,4 @@
Discourse.AdminBackupsLogsController = Ember.ArrayController.extend({
needs: ["adminBackups"],
status: Em.computed.alias("controllers.adminBackups"),
status: Em.computed.alias("controllers.adminBackups")
});

View File

@ -13,8 +13,7 @@ Discourse.AdminEmailSentController = Discourse.Controller.extend({
Discourse.EmailLog.findAll(this.get("filter")).then(function(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) {
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")
});

View File

@ -40,7 +40,7 @@ Discourse.ApiKey.reopenClass({
Creates an API key instance with internal user object
@method create
@param {Object} the properties to create
@param {...} var_args the properties to initialize this with
@returns {Discourse.ApiKey} the ApiKey instance
**/
create: function() {

View File

@ -85,6 +85,5 @@ Discourse.Backup.reopenClass({
window.location.pathname = Discourse.getURL("/");
}
});
},
}
});

View File

@ -12,6 +12,5 @@ Discourse.BackupStatus = Discourse.Model.extend({
restoreEnabled: function() {
return Discourse.SiteSettings.allow_restore && !this.get("isOperationRunning");
}.property("isOperationRunning"),
}.property("isOperationRunning")
});

View File

@ -31,7 +31,7 @@ Discourse.AdminBackupsRoute = Discourse.Route.extend({
}).then(function (status) {
return Discourse.BackupStatus.create({
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
@method destroyBackup
@param {Discourse.Backup} the backup to destroy
@param {Discourse.Backup} backup the backup to destroy
**/
destroyBackup: function(backup) {
var self = this;
@ -91,7 +91,7 @@ Discourse.AdminBackupsRoute = Discourse.Route.extend({
Start a restore and redirect the user to the logs tab
@method startRestore
@param {Discourse.Backup} the backup to restore
@param {Discourse.Backup} backup the backup to restore
**/
startRestore: function(backup) {
var self = this;
@ -160,7 +160,6 @@ Discourse.AdminBackupsRoute = Discourse.Route.extend({
uploadError: function(filename, message) {
bootbox.alert(I18n.t("admin.backups.upload.error", { filename: filename, message: message }));
},
}
}
});

View File

@ -22,7 +22,7 @@ Discourse.AdminCustomizeView = Discourse.View.extend({
selectStylesheet: function() { this.set('selected', 'stylesheet'); },
selectMobileHeader: function() { this.set('selected', 'mobileHeader'); },
selectMobileStylesheet: function() { this.set('selected', 'mobileStylesheet'); },
selectMobileStylesheet: function() { this.set('selected', 'mobileStylesheet'); }
},
didInsertElement: function() {

View File

@ -8,7 +8,7 @@ Discourse.AutoCloseFormComponent = Ember.Component.extend({
autoCloseChanged: function() {
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());
}.observes('autoCloseTime'),

View File

@ -20,5 +20,5 @@ Discourse.DiscoveryController = Discourse.ObjectController.extend({
showMoreDailyUrl: function() { return this.showMoreUrl('daily'); }.property('category', 'noSubcategories'),
showMoreWeeklyUrl: function() { return this.showMoreUrl('weekly'); }.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')
});

View File

@ -12,6 +12,6 @@ Discourse.GroupController = Discourse.ObjectController.extend({
// It would be nice if bootstrap marked action lists as selected when their links
// were 'active' not the `li` tags.
showingIndex: Em.computed.equal('showing', 'index'),
showingMembers: Em.computed.equal('showing', 'members'),
showingMembers: Em.computed.equal('showing', 'members')
});

View File

@ -44,8 +44,7 @@ Discourse.UserInvitedController = Ember.ArrayController.extend({
@property showSearch
**/
showSearch: function() {
if (Em.isNone(this.get('searchTerm')) && this.get('model.length') === 0) { return false; }
return true;
return !(Em.isNone(this.get('searchTerm')) && this.get('model.length') === 0);
}.property('searchTerm', 'model.length'),
/**

View File

@ -4,7 +4,14 @@
@method replaceBBCode
@param {tag} tag the tag we want to match
@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) {
opts = opts || {};

View File

@ -120,10 +120,10 @@ function parseTree(tree, path, insideCounts) {
**/
function invalidBoundary(args, prev) {
if (!args.wordBoundary && !args.spaceBoundary) { return; }
if (!args.wordBoundary && !args.spaceBoundary) { return false; }
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.spaceBoundary && (!last.match(/\s$/))) { return true; }
@ -143,15 +143,15 @@ Discourse.Dialect = {
@method cook
@param {String} text the raw text to cook
@param {Object} opts hash of options
@returns {String} the cooked text
**/
cook: function(text, opts) {
if (!initialized) { initializeDialects(); }
dialect.options = opts;
var tree = parser.toHTMLTree(text, 'Discourse'),
html = parser.renderJsonML(parseTree(tree));
var tree = parser.toHTMLTree(text, 'Discourse');
return html;
return parser.renderJsonML(parseTree(tree));
},
/**
@ -288,9 +288,8 @@ Discourse.Dialect = {
the other helpers such as `replaceBlock` so consider using them first!
@method registerBlock
@param {String} the name of the block handler
@param {Function} the handler
@param {String} name the name of the block handler
@param {Function} handler the handler
**/
registerBlock: function(name, handler) {
dialect.block[name] = handler;

View File

@ -271,7 +271,7 @@ $.fn.autocomplete = function(options) {
});
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){
// 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) {
c = Discourse.Utilities.caretPosition(me[0]);
next = me[0].value[c];
nextIsGood = next === void 0 || /\s/.test(next);
c -= 1;
initial = c;
prevIsGood = true;

View File

@ -71,8 +71,6 @@ $.fn.caretPosition = function(options) {
"line-height": important("line-height")
});
before = void 0;
after = void 0;
pos = options && (options.pos || options.pos === 0) ? options.pos : getCaret(textarea[0]);
val = textarea.val().replace("\r", "");
if (options && options.key) {

View File

@ -110,6 +110,6 @@ Discourse.computed = {
});
});
return computed.property.apply(computed, args);
},
}
};

View File

@ -21,7 +21,6 @@ Discourse.Eyeline.prototype.update = function() {
docViewBottom = docViewTop + windowHeight,
$elements = $(this.selector),
atBottom = false,
foundElement = false,
bottomOffset = $elements.last().offset(),
self = this;
@ -29,9 +28,6 @@ Discourse.Eyeline.prototype.update = function() {
atBottom = (bottomOffset.top <= docViewBottom) && (bottomOffset.top >= docViewTop);
}
// Whether we've seen any elements in this search
foundElement = false;
return $elements.each(function(i, elem) {
var $elem = $(elem),
elemTop = $elem.offset().top,

View File

@ -237,7 +237,7 @@ relativeAgeMediumSpan = function(distance, leaveAgo) {
relativeAgeMedium = function(date, options){
var displayDate, fiveDaysAgo, oneMinuteAgo, fullReadable, leaveAgo;
var wrapInSpan = options.wrapInSpan === false ? false : true;
var wrapInSpan = options.wrapInSpan !== false;
leaveAgo = options.leaveAgo;
var distance = Math.round((new Date() - date) / 1000);

View File

@ -13,10 +13,10 @@ Discourse.Markdown = {
validIframes: [],
/**
Whitelists classes for sanitization
Whitelists more classes for sanitization.
@param {...String} var_args Classes to whitelist
@method whiteListClass
@param {String} val The value to whitelist. Can supply more than one argument
**/
whiteListClass: function() {
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
@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
**/
urlAllowed: function (uri, effect, ltype, hints) {

View File

@ -14,7 +14,7 @@ Discourse.Mobile = {
this.mobileView = $html.hasClass('mobile-view');
if (localStorage && localStorage.mobileView) {
var savedValue = (localStorage.mobileView === 'true' ? true : false);
var savedValue = (localStorage.mobileView === 'true');
if (savedValue !== this.mobileView) {
this.reloadPage(savedValue);
}

View File

@ -22,7 +22,8 @@ Discourse.PageTracker = Ember.Object.extend(Ember.Evented, {
self = this;
router.on('didTransition', function() {
self.trigger('change', this.get('url'));
var router = this;
self.trigger('change', router.get('url'));
});
this.set('started', true);
}

View File

@ -35,7 +35,7 @@ Discourse.UserSearch = {
var promise = Ember.Deferred.create();
// TODO site setting for allowed regex in username
if (term.match(/[^a-zA-Z0-9\_\.]/)) {
if (term.match(/[^a-zA-Z0-9_\.]/)) {
promise.resolve([]);
return promise;
}
@ -54,8 +54,7 @@ Discourse.UserSearch = {
users.push(u);
results.push(u);
}
if (results.length > limit) return false;
return true;
return results.length <= limit;
});
_.each(r.groups,function(g) {

View File

@ -210,7 +210,7 @@ Discourse.Utilities = {
Check the extension of the file against the list of authorized extensions
@method isAuthorizedUpload
@param {File} files The file we want to upload
@param {File} file The file we want to upload
**/
isAuthorizedUpload: function(file) {
var extensions = Discourse.SiteSettings.authorized_extensions;

View File

@ -13,7 +13,8 @@ Discourse.ModalFunctionality = Em.Mixin.create({
Flash a message at the top of the modal
@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}
**/
flash: function(message, messageClass) {

View File

@ -12,7 +12,6 @@ Discourse.ScrollTop = Em.Mixin.create({
Em.run.schedule('afterRender', function() {
$(document).scrollTop(0);
});
}.on('didInsertElement'),
}.on('didInsertElement')
});

View File

@ -66,7 +66,7 @@ Discourse.CategoryList.reopenClass({
can_create_category: result.category_list.can_create_category,
can_create_topic: result.category_list.can_create_topic,
draft_key: result.category_list.draft_key,
draft_sequence: result.category_list.draft_sequence,
draft_sequence: result.category_list.draft_sequence
});
});
}

View File

@ -126,14 +126,10 @@ Discourse.Composer = Discourse.Model.extend({
// reply is always required
if (this.get('missingReplyCharacters') > 0) return true;
if (this.get('canCategorize') &&
return this.get('canCategorize') &&
!Discourse.SiteSettings.allow_uncategorized_topics &&
!this.get('categoryId') &&
!Discourse.User.currentProp('staff')) {
return true;
}
return false;
!Discourse.User.currentProp('staff');
}.property('loading', 'canEditTitle', 'titleLength', 'targetUsernames', 'replyLength', 'categoryId', 'missingReplyCharacters'),
/**

View File

@ -103,11 +103,10 @@ Discourse.Post = Discourse.Model.extend({
}.property('updated_at'),
flagsAvailable: function() {
var post = this,
flags = Discourse.Site.currentProp('flagTypes').filter(function(item) {
var post = this;
return Discourse.Site.currentProp('flagTypes').filter(function(item) {
return post.get("actionByName." + (item.get('name_key')) + ".can_act");
});
return flags;
}.property('actions_summary.@each.can_act'),
actionsHistory: function() {

View File

@ -179,7 +179,6 @@ Discourse.PostStream = Em.Object.extend({
Cancel any active filters on the stream.
@method cancelFilter
@returns {Ember.Deferred} a promise that resolves when the filter has been cancelled.
**/
cancelFilter: function() {
this.set('summary', false);
@ -373,8 +372,8 @@ Discourse.PostStream = Em.Object.extend({
`undoPost` when it fails.
@method stagePost
@param {Discourse.Post} the post to stage in the stream
@param {Discourse.User} the user creating the post
@param {Discourse.Post} post the post to stage in the stream
@param {Discourse.User} user the user creating the post
**/
stagePost: function(post, user) {

View File

@ -19,7 +19,7 @@ Discourse.TopList.reopenClass({
can_create_topic: result.can_create_topic,
draft: result.draft,
draft_key: result.draft_key,
draft_sequence: result.draft_sequence,
draft_sequence: result.draft_sequence
});
Discourse.Site.currentProp('periods').forEach(function(period) {

View File

@ -168,8 +168,7 @@ Discourse.Topic = Discourse.Model.extend({
if (!wordCount) return;
// Avg for 500 words per minute when you account for skimming
var minutes = Math.floor(wordCount / 500.0);
return minutes;
return Math.floor(wordCount / 500.0);
}.property('word_count'),
toggleStar: function() {

View File

@ -162,7 +162,7 @@ Discourse.TopicList.reopenClass({
Stitch together side loaded topic data
@method topicsFrom
@param {Object} JSON object with topic data
@param {Object} result JSON object with topic data
@returns {Array} the list of topics
**/
topicsFrom: function(result) {
@ -204,8 +204,8 @@ Discourse.TopicList.reopenClass({
Lists topics on a given menu item
@method list
@param {Object} The menu item to filter to
@param {Object} Any additional params
@param {Object} filter The menu item to filter to
@param {Object} params Any additional params to pass to TopicList.find()
@returns {Promise} a promise that resolves to the list of topics
**/
list: function(filter, params) {

View File

@ -461,6 +461,7 @@ Discourse.User.reopenClass(Discourse.Singleton, {
@method checkUsername
@param {String} username A username to check
@param {String} email An email address to check
@param {Number} forUserId user id - provide when changing username
**/
checkUsername: function(username, email, forUserId) {
return Discourse.ajax('/users/check_username', {
@ -472,7 +473,7 @@ Discourse.User.reopenClass(Discourse.Singleton, {
Groups the user's statistics
@method groupStats
@param {Array} Given stats
@param {Array} stats Given stats
@returns {Object}
**/
groupStats: function(stats) {
@ -507,6 +508,7 @@ Discourse.User.reopenClass(Discourse.Singleton, {
@param {String} name This user's name
@param {String} email This user's email
@param {String} password This user's password
@param {String} username This user's username
@param {String} passwordConfirm This user's confirmed password
@param {String} challenge
@returns Result of ajax call

View File

@ -45,5 +45,5 @@ Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend({
}));
this.controllerFor('editCategory').set('selectedTab', 'general');
}
},
}
});

View File

@ -57,7 +57,7 @@ Discourse.PreferencesRoute = Discourse.RestrictedUserRoute.extend({
Discourse.PreferencesIndexRoute = Discourse.RestrictedUserRoute.extend({
renderTemplate: function() {
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
},
}
});
/**

View File

@ -12,6 +12,7 @@
<div class='controls'>
<label class='radio'>
<input type='radio' id="choose-topic-{{unbound id}}" name='choose_topic_id' {{action chooseTopic this target="view"}}>{{title}}
</label>
</div>
{{/each}}
</ul>

View File

@ -7,9 +7,9 @@
</a>
{{else}}
{{#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}}
<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}}

View File

@ -1,5 +1,5 @@
<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'>
{{#each similarTopics}}

View File

@ -47,6 +47,7 @@ Discourse.ActionsHistoryComponent = Em.Component.extend({
var key = 'post.actions.people.' + c.get('actionType.name_key');
if (postUrl) { key = key + "_with_url"; }
// TODO postUrl might be uninitialized? pick a good default
buffer.push(" " + I18n.t(key, { icons: iconsHtml, postUrl: postUrl}) + ".");
}
renderActionIf('usersCollapsed', 'who-acted', c.get('description'));

View File

@ -504,7 +504,7 @@ Discourse.ComposerView = Discourse.View.extend(Ember.Evented, {
var $uploadTarget = $('#reply-control');
$uploadTarget.fileupload('destroy');
$uploadTarget.off();
},
}
});
// not sure if this is the right way, keeping here for now, we could use a mixin perhaps

View File

@ -14,7 +14,7 @@ Discourse.ContainerView = Ember.ContainerView.extend(Discourse.Presence, {
@method attachViewWithArgs
@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) {
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
@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) {
this.attachViewWithArgs(null, viewClass);

View File

@ -12,9 +12,10 @@ Discourse.ModalBodyView = Discourse.View.extend({
didInsertElement: function() {
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");
});

View File

@ -207,7 +207,8 @@ Discourse.PostMenuView = Discourse.View.extend({
}
buffer.push("<button title=\"" + tooltip +
"\" data-action=\"bookmark\" class='bookmark'><div class='" + iconClass +
"\" data-action=\"bookmark\" class='" + buttonClass +
"'><div class='" + iconClass +
"'></div></button>");
},

View File

@ -39,8 +39,9 @@ Discourse.ShareView = Discourse.View.extend({
}.observes('controller.link'),
didInsertElement: function() {
var shareView = this;
$('html').on('mousedown.outside-share-link', function(e) {
var shareView = this,
$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
// link is clicked (which is a click event) while the share dialog is showing.
if (shareView.$().has(e.target).length !== 0) { return; }
@ -49,9 +50,10 @@ Discourse.ShareView = Discourse.View.extend({
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();
var $currentTarget = $(e.currentTarget);
var $currentTarget = $(e.currentTarget),
$shareLink = $('#share-link');
var url = $currentTarget.data('share-url');
var postNumber = $currentTarget.data('post-number');
// Relative urls
@ -60,7 +62,7 @@ Discourse.ShareView = Discourse.View.extend({
url = window.location.protocol + "//" + window.location.host + url;
}
var shareLinkWidth = $('#share-link').width();
var shareLinkWidth = $shareLink.width();
var x = e.pageX - (shareLinkWidth / 2);
if (x < 25) {
x = 25;
@ -70,12 +72,12 @@ Discourse.ShareView = Discourse.View.extend({
}
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()) {
y = e.pageY + 10;
}
$('#share-link').css({
$shareLink.css({
left: "" + x + "px",
top: "" + y + "px"
});
@ -84,7 +86,7 @@ Discourse.ShareView = Discourse.View.extend({
return false;
});
$('html').on('keydown.share-view', function(e){
$html.on('keydown.share-view', function(e){
if (e.keyCode === 27) {
shareView.get('controller').send('close');
}
@ -92,9 +94,10 @@ Discourse.ShareView = Discourse.View.extend({
},
willDestroyElement: function() {
$('html').off('click.discoure-share-link');
$('html').off('mousedown.outside-share-link');
$('html').off('keydown.share-view');
var $html = $('html');
$html.off('click.discoure-share-link');
$html.off('mousedown.outside-share-link');
$html.off('keydown.share-view');
}
});

View File

@ -7,4 +7,4 @@ I18n.pluralizationRules['cs'] = function (n) {
if (n == 1) return "one";
if (n >= 2 && n <= 4) return "few";
return "other";
}
};

View File

@ -7,4 +7,4 @@ I18n.pluralizationRules['ru'] = function (n) {
if (n % 10 == 1 && n % 100 != 11) return "one";
if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)) return "few";
return "many";
}
};

View File

@ -22,7 +22,7 @@ module Jobs
begin
mail_string = mail.pop
Email::Receiver.new(mail_string).process
rescue Email::Receiver::UserNotSufficientTrustLevelError => e
rescue Email::Receiver::UserNotSufficientTrustLevelError
# inform the user about the rejection
@message = Mail::Message.new(mail_string)
clientMessage = RejectionMailer.send_trust_level(@message.from, @message.body)