mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
ES6ify some of the remaining files
This commit is contained in:
parent
378087727f
commit
b7e6eaa961
96 changed files with 684 additions and 720 deletions
|
@ -1,13 +1,14 @@
|
||||||
import { bufferedProperty } from 'discourse/mixins/buffered-content';
|
|
||||||
import UserField from 'admin/models/user-field';
|
import UserField from 'admin/models/user-field';
|
||||||
|
import { bufferedProperty } from 'discourse/mixins/buffered-content';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.Component.extend(bufferedProperty('userField'), {
|
export default Ember.Component.extend(bufferedProperty('userField'), {
|
||||||
editing: Ember.computed.empty('userField.id'),
|
editing: Ember.computed.empty('userField.id'),
|
||||||
classNameBindings: [':user-field'],
|
classNameBindings: [':user-field'],
|
||||||
|
|
||||||
cantMoveUp: Discourse.computed.propertyEqual('userField', 'firstField'),
|
cantMoveUp: propertyEqual('userField', 'firstField'),
|
||||||
cantMoveDown: Discourse.computed.propertyEqual('userField', 'lastField'),
|
cantMoveDown: propertyEqual('userField', 'lastField'),
|
||||||
|
|
||||||
userFieldsDescription: function() {
|
userFieldsDescription: function() {
|
||||||
return I18n.t('admin.user_fields.description');
|
return I18n.t('admin.user_fields.description');
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import BufferedContent from 'discourse/mixins/buffered-content';
|
import BufferedContent from 'discourse/mixins/buffered-content';
|
||||||
import ScrollTop from 'discourse/mixins/scroll-top';
|
import ScrollTop from 'discourse/mixins/scroll-top';
|
||||||
import SiteSetting from 'admin/models/site-setting';
|
import SiteSetting from 'admin/models/site-setting';
|
||||||
|
import { propertyNotEqual } from 'discourse/lib/computed';
|
||||||
|
|
||||||
const CustomTypes = ['bool', 'enum', 'list', 'url_list', 'host_list'];
|
const CustomTypes = ['bool', 'enum', 'list', 'url_list', 'host_list'];
|
||||||
|
|
||||||
export default Ember.Component.extend(BufferedContent, ScrollTop, {
|
export default Ember.Component.extend(BufferedContent, ScrollTop, {
|
||||||
classNameBindings: [':row', ':setting', 'setting.overridden', 'typeClass'],
|
classNameBindings: [':row', ':setting', 'setting.overridden', 'typeClass'],
|
||||||
content: Ember.computed.alias('setting'),
|
content: Ember.computed.alias('setting'),
|
||||||
dirty: Discourse.computed.propertyNotEqual('buffered.value', 'setting.value'),
|
dirty: propertyNotEqual('buffered.value', 'setting.value'),
|
||||||
validationMessage: null,
|
validationMessage: null,
|
||||||
|
|
||||||
preview: function() {
|
preview: function() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import BufferedContent from 'discourse/mixins/buffered-content';
|
import BufferedContent from 'discourse/mixins/buffered-content';
|
||||||
|
import { propertyNotEqual } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.ObjectController.extend(BufferedContent, {
|
export default Ember.ObjectController.extend(BufferedContent, {
|
||||||
needs: ['admin-badges'],
|
needs: ['admin-badges'],
|
||||||
|
@ -12,7 +13,7 @@ export default Ember.ObjectController.extend(BufferedContent, {
|
||||||
protectedSystemFields: Em.computed.alias('controllers.admin-badges.protectedSystemFields'),
|
protectedSystemFields: Em.computed.alias('controllers.admin-badges.protectedSystemFields'),
|
||||||
|
|
||||||
readOnly: Ember.computed.alias('buffered.system'),
|
readOnly: Ember.computed.alias('buffered.system'),
|
||||||
showDisplayName: Discourse.computed.propertyNotEqual('name', 'displayName'),
|
showDisplayName: propertyNotEqual('name', 'displayName'),
|
||||||
canEditDescription: Em.computed.none('buffered.translatedDescription'),
|
canEditDescription: Em.computed.none('buffered.translatedDescription'),
|
||||||
|
|
||||||
_resetSaving: function() {
|
_resetSaving: function() {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { url } from 'discourse/lib/computed';
|
||||||
|
|
||||||
const sections = ['css', 'header', 'top', 'footer', 'head-tag', 'body-tag',
|
const sections = ['css', 'header', 'top', 'footer', 'head-tag', 'body-tag',
|
||||||
'mobile-css', 'mobile-header', 'mobile-top', 'mobile-footer',
|
'mobile-css', 'mobile-header', 'mobile-top', 'mobile-footer',
|
||||||
'embedded-css'];
|
'embedded-css'];
|
||||||
|
@ -12,8 +14,8 @@ export default Ember.Controller.extend(activeSections, {
|
||||||
maximized: false,
|
maximized: false,
|
||||||
section: null,
|
section: null,
|
||||||
|
|
||||||
previewUrl: Discourse.computed.url("model.key", "/?preview-style=%@"),
|
previewUrl: url("model.key", "/?preview-style=%@"),
|
||||||
downloadUrl: Discourse.computed.url('model.id', '/admin/size_customizations/%@'),
|
downloadUrl: url('model.id', '/admin/size_customizations/%@'),
|
||||||
|
|
||||||
mobile: function() {
|
mobile: function() {
|
||||||
return this.get('section').startsWith('mobile-');
|
return this.get('section').startsWith('mobile-');
|
||||||
|
@ -33,8 +35,8 @@ export default Ember.Controller.extend(activeSections, {
|
||||||
|
|
||||||
needs: ['adminCustomizeCssHtml'],
|
needs: ['adminCustomizeCssHtml'],
|
||||||
|
|
||||||
undoPreviewUrl: Discourse.computed.url('/?preview-style='),
|
undoPreviewUrl: url('/?preview-style='),
|
||||||
defaultStyleUrl: Discourse.computed.url('/?preview-style=default'),
|
defaultStyleUrl: url('/?preview-style=default'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
save() {
|
save() {
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
/**
|
import { setting } from 'discourse/lib/computed';
|
||||||
This controller supports the default interface when you enter the admin section.
|
|
||||||
|
|
||||||
@class AdminDashboardController
|
// This controller supports the default interface when you enter the admin section.
|
||||||
@extends Ember.Controller
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
export default Ember.Controller.extend({
|
export default Ember.Controller.extend({
|
||||||
loading: true,
|
loading: true,
|
||||||
versionCheck: null,
|
versionCheck: null,
|
||||||
problemsCheckMinutes: 1,
|
problemsCheckMinutes: 1,
|
||||||
|
|
||||||
showVersionChecks: Discourse.computed.setting('version_checks'),
|
showVersionChecks: setting('version_checks'),
|
||||||
|
|
||||||
foundProblems: function() {
|
foundProblems: function() {
|
||||||
return(Discourse.User.currentProp('admin') && this.get('problems') && this.get('problems').length > 0);
|
return(Discourse.User.currentProp('admin') && this.get('problems') && this.get('problems').length > 0);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Em.ObjectController.extend({
|
export default Em.ObjectController.extend({
|
||||||
needs: ['adminGroupsType'],
|
needs: ['adminGroupsType'],
|
||||||
|
@ -15,7 +16,7 @@ export default Em.ObjectController.extend({
|
||||||
}.property("limit", "user_count"),
|
}.property("limit", "user_count"),
|
||||||
|
|
||||||
showingFirst: Em.computed.lte("currentPage", 1),
|
showingFirst: Em.computed.lte("currentPage", 1),
|
||||||
showingLast: Discourse.computed.propertyEqual("currentPage", "totalPages"),
|
showingLast: propertyEqual("currentPage", "totalPages"),
|
||||||
|
|
||||||
aliasLevelOptions: function() {
|
aliasLevelOptions: function() {
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import ObjectController from 'discourse/controllers/object';
|
import ObjectController from 'discourse/controllers/object';
|
||||||
import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
||||||
|
import { propertyNotEqual, setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default ObjectController.extend(CanCheckEmails, {
|
export default ObjectController.extend(CanCheckEmails, {
|
||||||
editingTitle: false,
|
editingTitle: false,
|
||||||
originalPrimaryGroupId: null,
|
originalPrimaryGroupId: null,
|
||||||
availableGroups: null,
|
availableGroups: null,
|
||||||
|
|
||||||
showApproval: Discourse.computed.setting('must_approve_users'),
|
showApproval: setting('must_approve_users'),
|
||||||
showBadges: Discourse.computed.setting('enable_badges'),
|
showBadges: setting('enable_badges'),
|
||||||
|
|
||||||
primaryGroupDirty: Discourse.computed.propertyNotEqual('originalPrimaryGroupId', 'model.primary_group_id'),
|
primaryGroupDirty: propertyNotEqual('originalPrimaryGroupId', 'model.primary_group_id'),
|
||||||
|
|
||||||
automaticGroups: function() {
|
automaticGroups: function() {
|
||||||
return this.get("model.automaticGroups").map((g) => g.name).join(", ");
|
return this.get("model.automaticGroups").map((g) => g.name).join(", ");
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { i18n } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.ArrayController.extend({
|
export default Ember.ArrayController.extend({
|
||||||
query: null,
|
query: null,
|
||||||
showEmails: false,
|
showEmails: false,
|
||||||
|
@ -9,7 +11,7 @@ export default Ember.ArrayController.extend({
|
||||||
queryPending: Em.computed.equal('query', 'pending'),
|
queryPending: Em.computed.equal('query', 'pending'),
|
||||||
queryHasApproval: Em.computed.or('queryNew', 'queryPending'),
|
queryHasApproval: Em.computed.or('queryNew', 'queryPending'),
|
||||||
showApproval: Em.computed.and('siteSettings.must_approve_users', 'queryHasApproval'),
|
showApproval: Em.computed.and('siteSettings.must_approve_users', 'queryHasApproval'),
|
||||||
searchHint: Discourse.computed.i18n('search_hint'),
|
searchHint: i18n('search_hint'),
|
||||||
hasSelection: Em.computed.gt('selectedCount', 0),
|
hasSelection: Em.computed.gt('selectedCount', 0),
|
||||||
|
|
||||||
selectedCount: function() {
|
selectedCount: function() {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { propertyNotEqual } from 'discourse/lib/computed';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
|
||||||
const AdminUser = Discourse.User.extend({
|
const AdminUser = Discourse.User.extend({
|
||||||
|
@ -144,7 +145,7 @@ const AdminUser = Discourse.User.extend({
|
||||||
this.set('originalTrustLevel', this.get('trust_level'));
|
this.set('originalTrustLevel', this.get('trust_level'));
|
||||||
},
|
},
|
||||||
|
|
||||||
dirty: Discourse.computed.propertyNotEqual('originalTrustLevel', 'trustLevel.id'),
|
dirty: propertyNotEqual('originalTrustLevel', 'trustLevel.id'),
|
||||||
|
|
||||||
saveTrustLevel() {
|
saveTrustLevel() {
|
||||||
return Discourse.ajax("/admin/users/" + this.id + "/trust_level", {
|
return Discourse.ajax("/admin/users/" + this.id + "/trust_level", {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import round from "discourse/lib/round";
|
import round from "discourse/lib/round";
|
||||||
|
import { fmt } from 'discourse/lib/computed';
|
||||||
|
|
||||||
const Report = Discourse.Model.extend({
|
const Report = Discourse.Model.extend({
|
||||||
reportUrl: Discourse.computed.fmt("type", "/admin/reports/%@"),
|
reportUrl: fmt("type", "/admin/reports/%@"),
|
||||||
|
|
||||||
valueAt(numDaysAgo) {
|
valueAt(numDaysAgo) {
|
||||||
if (this.data) {
|
if (this.data) {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import RestModel from 'discourse/models/rest';
|
import RestModel from 'discourse/models/rest';
|
||||||
|
import { i18n } from 'discourse/lib/computed';
|
||||||
|
|
||||||
const UserField = RestModel.extend();
|
const UserField = RestModel.extend();
|
||||||
|
|
||||||
const UserFieldType = Ember.Object.extend({
|
const UserFieldType = Ember.Object.extend({
|
||||||
name: Discourse.computed.i18n('id', 'admin.user_fields.field_types.%@')
|
name: i18n('id', 'admin.user_fields.field_types.%@')
|
||||||
});
|
});
|
||||||
|
|
||||||
UserField.reopenClass({
|
UserField.reopenClass({
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||||
|
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
export default Ember.Component.extend(StringBuffer, {
|
export default Ember.Component.extend(StringBuffer, {
|
||||||
tagName: 'section',
|
tagName: 'section',
|
||||||
|
@ -57,7 +58,7 @@ export default Ember.Component.extend(StringBuffer, {
|
||||||
buffer.push("<div class='post-action'>" +
|
buffer.push("<div class='post-action'>" +
|
||||||
iconHTML('fa-trash-o') + ' ' +
|
iconHTML('fa-trash-o') + ' ' +
|
||||||
Discourse.Utilities.tinyAvatar(post.get('postDeletedBy.avatar_template'), {title: post.get('postDeletedBy.username')}) +
|
Discourse.Utilities.tinyAvatar(post.get('postDeletedBy.avatar_template'), {title: post.get('postDeletedBy.username')}) +
|
||||||
Discourse.Formatter.autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) +
|
autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) +
|
||||||
"</div>");
|
"</div>");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
var get = Ember.get;
|
var get = Ember.get;
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
classNameBindings: ['category::no-category', 'categories:has-drop','categoryStyle'],
|
classNameBindings: ['category::no-category', 'categories:has-drop','categoryStyle'],
|
||||||
categoryStyle: Discourse.computed.setting('category_style'),
|
categoryStyle: setting('category_style'),
|
||||||
|
|
||||||
tagName: 'li',
|
tagName: 'li',
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
|
import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
|
||||||
|
|
||||||
export default buildCategoryPanel('settings', {
|
export default buildCategoryPanel('settings', {
|
||||||
emailInEnabled: Discourse.computed.setting('email_in'),
|
emailInEnabled: setting('email_in'),
|
||||||
showPositionInput: Discourse.computed.setting('fixed_category_positions'),
|
showPositionInput: setting('fixed_category_positions'),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Em.Component.extend({
|
export default Em.Component.extend({
|
||||||
tagName: 'li',
|
tagName: 'li',
|
||||||
classNameBindings: ['active', 'tabClassName'],
|
classNameBindings: ['active', 'tabClassName'],
|
||||||
|
@ -6,7 +8,7 @@ export default Em.Component.extend({
|
||||||
return 'edit-category-' + this.get('tab');
|
return 'edit-category-' + this.get('tab');
|
||||||
}.property('tab'),
|
}.property('tab'),
|
||||||
|
|
||||||
active: Discourse.computed.propertyEqual('selectedTab', 'tab'),
|
active: propertyEqual('selectedTab', 'tab'),
|
||||||
|
|
||||||
title: function() {
|
title: function() {
|
||||||
return I18n.t('category.' + this.get('tab').replace('-', '_'));
|
return I18n.t('category.' + this.get('tab').replace('-', '_'));
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
classNames: ["title"],
|
classNames: ["title"],
|
||||||
|
|
||||||
|
@ -13,10 +15,10 @@ export default Ember.Component.extend({
|
||||||
return Discourse.Mobile.mobileView && !Ember.isBlank(this.get('mobileBigLogoUrl'));
|
return Discourse.Mobile.mobileView && !Ember.isBlank(this.get('mobileBigLogoUrl'));
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
smallLogoUrl: Discourse.computed.setting('logo_small_url'),
|
smallLogoUrl: setting('logo_small_url'),
|
||||||
bigLogoUrl: Discourse.computed.setting('logo_url'),
|
bigLogoUrl: setting('logo_url'),
|
||||||
mobileBigLogoUrl: Discourse.computed.setting('mobile_logo_url'),
|
mobileBigLogoUrl: setting('mobile_logo_url'),
|
||||||
title: Discourse.computed.setting('title'),
|
title: setting('title'),
|
||||||
|
|
||||||
click: function(e) {
|
click: function(e) {
|
||||||
// if they want to open in a new tab, let it so
|
// if they want to open in a new tab, let it so
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
const PosterNameComponent = Em.Component.extend({
|
const PosterNameComponent = Em.Component.extend({
|
||||||
classNames: ['names', 'trigger-user-card'],
|
classNames: ['names', 'trigger-user-card'],
|
||||||
displayNameOnPosts: Discourse.computed.setting('display_name_on_posts'),
|
displayNameOnPosts: setting('display_name_on_posts'),
|
||||||
|
|
||||||
// sanitize name for comparison
|
// sanitize name for comparison
|
||||||
sanitizeName(name){
|
sanitizeName(name){
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { relativeAge } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
'closed.enabled': 'lock',
|
'closed.enabled': 'lock',
|
||||||
'closed.disabled': 'unlock-alt',
|
'closed.disabled': 'unlock-alt',
|
||||||
|
@ -19,7 +21,7 @@ export function actionDescription(actionCode, createdAt) {
|
||||||
const ac = this.get(actionCode);
|
const ac = this.get(actionCode);
|
||||||
if (ac) {
|
if (ac) {
|
||||||
const dt = new Date(this.get(createdAt));
|
const dt = new Date(this.get(createdAt));
|
||||||
const when = Discourse.Formatter.relativeAge(dt, {format: 'medium-with-ago'});
|
const when = relativeAge(dt, {format: 'medium-with-ago'});
|
||||||
return I18n.t(`action_codes.${ac}`, {when}).htmlSafe();
|
return I18n.t(`action_codes.${ac}`, {when}).htmlSafe();
|
||||||
}
|
}
|
||||||
}.property(actionCode, createdAt);
|
}.property(actionCode, createdAt);
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
import { actionDescription } from "discourse/components/small-action";
|
import { actionDescription } from "discourse/components/small-action";
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
classNameBindings: [":item", "item.hidden", "item.deleted", "moderatorAction"],
|
classNameBindings: [":item", "item.hidden", "item.deleted", "moderatorAction"],
|
||||||
moderatorAction: Discourse.computed.propertyEqual("item.post_type", "site.post_types.moderator_action"),
|
moderatorAction: propertyEqual("item.post_type", "site.post_types.moderator_action"),
|
||||||
actionDescription: actionDescription("item.action_code", "item.created_at"),
|
actionDescription: actionDescription("item.action_code", "item.created_at"),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import { fmt } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
classNameBindings: [':user-field', 'field.field_type'],
|
classNameBindings: [':user-field', 'field.field_type'],
|
||||||
layoutName: Discourse.computed.fmt('field.field_type', 'components/user-fields/%@'),
|
layoutName: fmt('field.field_type', 'components/user-fields/%@'),
|
||||||
|
|
||||||
noneLabel: function() {
|
noneLabel: function() {
|
||||||
if (!this.get('field.required')) {
|
if (!this.get('field.required')) {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
import { url } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
classNames: ['user-small'],
|
classNames: ['user-small'],
|
||||||
|
|
||||||
userPath: Discourse.computed.url('user.username', '/users/%@'),
|
userPath: url('user.username', '/users/%@'),
|
||||||
|
|
||||||
name: function() {
|
name: function() {
|
||||||
const name = this.get('user.name');
|
const name = this.get('user.name');
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
import Presence from 'discourse/mixins/presence';
|
import Presence from 'discourse/mixins/presence';
|
||||||
|
|
||||||
export default Ember.ObjectController.extend(Presence, {
|
export default Ember.ObjectController.extend(Presence, {
|
||||||
|
@ -8,7 +9,7 @@ export default Ember.ObjectController.extend(Presence, {
|
||||||
|
|
||||||
showEditReason: false,
|
showEditReason: false,
|
||||||
editReason: null,
|
editReason: null,
|
||||||
maxTitleLength: Discourse.computed.setting('max_topic_title_length'),
|
maxTitleLength: setting('max_topic_title_length'),
|
||||||
scopedCategoryId: null,
|
scopedCategoryId: null,
|
||||||
similarTopics: null,
|
similarTopics: null,
|
||||||
similarTopicsMessage: null,
|
similarTopicsMessage: null,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||||
import DiscourseController from 'discourse/controllers/controller';
|
import DiscourseController from 'discourse/controllers/controller';
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default DiscourseController.extend(ModalFunctionality, {
|
export default DiscourseController.extend(ModalFunctionality, {
|
||||||
needs: ['login'],
|
needs: ['login'],
|
||||||
|
@ -16,10 +17,10 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||||
userFields: null,
|
userFields: null,
|
||||||
|
|
||||||
hasAuthOptions: Em.computed.notEmpty('authOptions'),
|
hasAuthOptions: Em.computed.notEmpty('authOptions'),
|
||||||
canCreateLocal: Discourse.computed.setting('enable_local_logins'),
|
canCreateLocal: setting('enable_local_logins'),
|
||||||
showCreateForm: Em.computed.or('hasAuthOptions', 'canCreateLocal'),
|
showCreateForm: Em.computed.or('hasAuthOptions', 'canCreateLocal'),
|
||||||
maxUsernameLength: Discourse.computed.setting('max_username_length'),
|
maxUsernameLength: setting('max_username_length'),
|
||||||
minUsernameLength: Discourse.computed.setting('min_username_length'),
|
minUsernameLength: setting('min_username_length'),
|
||||||
|
|
||||||
resetForm() {
|
resetForm() {
|
||||||
// We wrap the fields in a structure so we can assign a value
|
// We wrap the fields in a structure so we can assign a value
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Ember.Controller.extend({
|
||||||
me: Discourse.computed.propertyEqual('model.user.id', 'currentUser.id')
|
me: propertyEqual('model.user.id', 'currentUser.id')
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import DiscoveryController from 'discourse/controllers/discovery';
|
import DiscoveryController from 'discourse/controllers/discovery';
|
||||||
import { queryParams } from 'discourse/controllers/discovery-sortable';
|
import { queryParams } from 'discourse/controllers/discovery-sortable';
|
||||||
import BulkTopicSelection from 'discourse/mixins/bulk-topic-selection';
|
import BulkTopicSelection from 'discourse/mixins/bulk-topic-selection';
|
||||||
|
import { endWith } from 'discourse/lib/computed';
|
||||||
|
|
||||||
const controllerOpts = {
|
const controllerOpts = {
|
||||||
needs: ['discovery'],
|
needs: ['discovery'],
|
||||||
|
@ -102,8 +103,8 @@ const controllerOpts = {
|
||||||
|
|
||||||
hasTopics: Em.computed.gt('model.topics.length', 0),
|
hasTopics: Em.computed.gt('model.topics.length', 0),
|
||||||
allLoaded: Em.computed.empty('model.more_topics_url'),
|
allLoaded: Em.computed.empty('model.more_topics_url'),
|
||||||
latest: Discourse.computed.endWith('model.filter', 'latest'),
|
latest: endWith('model.filter', 'latest'),
|
||||||
new: Discourse.computed.endWith('model.filter', 'new'),
|
new: endWith('model.filter', 'new'),
|
||||||
top: Em.computed.notEmpty('period'),
|
top: Em.computed.notEmpty('period'),
|
||||||
yearly: Em.computed.equal('period', 'yearly'),
|
yearly: Em.computed.equal('period', 'yearly'),
|
||||||
quarterly: Em.computed.equal('period', 'quarterly'),
|
quarterly: Em.computed.equal('period', 'quarterly'),
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import ObjectController from 'discourse/controllers/object';
|
export default Ember.Controller.extend({
|
||||||
|
|
||||||
// The basic controller for a group
|
|
||||||
export default ObjectController.extend({
|
|
||||||
counts: null,
|
counts: null,
|
||||||
showing: null,
|
showing: null,
|
||||||
|
|
||||||
|
@ -10,4 +7,3 @@ export default ObjectController.extend({
|
||||||
showingIndex: Em.computed.equal('showing', 'index'),
|
showingIndex: Em.computed.equal('showing', 'index'),
|
||||||
showingMembers: Em.computed.equal('showing', 'members')
|
showingMembers: Em.computed.equal('showing', 'members')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
export default Ember.ObjectController.extend({
|
export default Ember.Controller.extend({
|
||||||
loading: false,
|
loading: false,
|
||||||
|
limit: null,
|
||||||
|
offset: null,
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
loadMore() {
|
loadMore() {
|
||||||
if (this.get("loading")) { return; }
|
if (this.get("loading")) { return; }
|
||||||
// we've reached the end
|
// we've reached the end
|
||||||
if (this.get("model.members.length") >= this.get("user_count")) { return; }
|
if (this.get("model.members.length") >= this.get("model.user_count")) { return; }
|
||||||
|
|
||||||
this.set("loading", true);
|
this.set("loading", true);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||||
import DiscourseController from 'discourse/controllers/controller';
|
import DiscourseController from 'discourse/controllers/controller';
|
||||||
import showModal from 'discourse/lib/show-modal';
|
import showModal from 'discourse/lib/show-modal';
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
// This is happening outside of the app via popup
|
// This is happening outside of the app via popup
|
||||||
const AuthErrors =
|
const AuthErrors =
|
||||||
|
@ -13,7 +14,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||||
loggingIn: false,
|
loggingIn: false,
|
||||||
loggedIn: false,
|
loggedIn: false,
|
||||||
|
|
||||||
canLoginLocal: Discourse.computed.setting('enable_local_logins'),
|
canLoginLocal: setting('enable_local_logins'),
|
||||||
loginRequired: Em.computed.alias('controllers.application.loginRequired'),
|
loginRequired: Em.computed.alias('controllers.application.loginRequired'),
|
||||||
|
|
||||||
resetForm: function() {
|
resetForm: function() {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import NavigationDefaultController from 'discourse/controllers/navigation/default';
|
import NavigationDefaultController from 'discourse/controllers/navigation/default';
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default NavigationDefaultController.extend({
|
export default NavigationDefaultController.extend({
|
||||||
subcategoryListSetting: Discourse.computed.setting('show_subcategory_list'),
|
subcategoryListSetting: setting('show_subcategory_list'),
|
||||||
showingParentCategory: Em.computed.none('category.parentCategory'),
|
showingParentCategory: Em.computed.none('category.parentCategory'),
|
||||||
showingSubcategoryList: Em.computed.and('subcategoryListSetting', 'showingParentCategory'),
|
showingSubcategoryList: Em.computed.and('subcategoryListSetting', 'showingParentCategory'),
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import { url } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.ArrayController.extend({
|
export default Ember.ArrayController.extend({
|
||||||
needs: ['header'],
|
needs: ['header'],
|
||||||
loadingNotifications: Em.computed.alias('controllers.header.loadingNotifications'),
|
loadingNotifications: Em.computed.alias('controllers.header.loadingNotifications'),
|
||||||
myNotificationsUrl: Discourse.computed.url('/my/notifications')
|
myNotificationsUrl: url('/my/notifications')
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
import ObjectController from 'discourse/controllers/object';
|
import ObjectController from 'discourse/controllers/object';
|
||||||
import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
|
||||||
export default ObjectController.extend(CanCheckEmails, {
|
export default ObjectController.extend(CanCheckEmails, {
|
||||||
|
|
||||||
allowAvatarUpload: Discourse.computed.setting('allow_uploaded_avatars'),
|
allowAvatarUpload: setting('allow_uploaded_avatars'),
|
||||||
allowUserLocale: Discourse.computed.setting('allow_user_locale'),
|
allowUserLocale: setting('allow_user_locale'),
|
||||||
ssoOverridesAvatar: Discourse.computed.setting('sso_overrides_avatar'),
|
ssoOverridesAvatar: setting('sso_overrides_avatar'),
|
||||||
allowBackgrounds: Discourse.computed.setting('allow_profile_backgrounds'),
|
allowBackgrounds: setting('allow_profile_backgrounds'),
|
||||||
editHistoryVisible: Discourse.computed.setting('edit_history_visible_to_public'),
|
editHistoryVisible: setting('edit_history_visible_to_public'),
|
||||||
|
|
||||||
selectedCategories: function(){
|
selectedCategories: function(){
|
||||||
return [].concat(this.get("model.watchedCategories"),
|
return [].concat(this.get("model.watchedCategories"),
|
||||||
|
@ -40,7 +41,7 @@ export default ObjectController.extend(CanCheckEmails, {
|
||||||
cannotDeleteAccount: Em.computed.not('can_delete_account'),
|
cannotDeleteAccount: Em.computed.not('can_delete_account'),
|
||||||
deleteDisabled: Em.computed.or('saving', 'deleting', 'cannotDeleteAccount'),
|
deleteDisabled: Em.computed.or('saving', 'deleting', 'cannotDeleteAccount'),
|
||||||
|
|
||||||
canEditName: Discourse.computed.setting('enable_names'),
|
canEditName: setting('enable_names'),
|
||||||
|
|
||||||
nameInstructions: function() {
|
nameInstructions: function() {
|
||||||
return I18n.t(Discourse.SiteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions');
|
return I18n.t(Discourse.SiteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions');
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
import ObjectController from 'discourse/controllers/object';
|
import ObjectController from 'discourse/controllers/object';
|
||||||
|
|
||||||
/**
|
|
||||||
This controller supports actions related to updating one's email address
|
|
||||||
|
|
||||||
@class PreferencesEmailController
|
|
||||||
@extends ObjectController
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
export default ObjectController.extend({
|
export default ObjectController.extend({
|
||||||
taken: false,
|
taken: false,
|
||||||
saving: false,
|
saving: false,
|
||||||
|
@ -17,7 +10,7 @@ export default ObjectController.extend({
|
||||||
|
|
||||||
newEmailEmpty: Em.computed.empty('newEmail'),
|
newEmailEmpty: Em.computed.empty('newEmail'),
|
||||||
saveDisabled: Em.computed.or('saving', 'newEmailEmpty', 'taken', 'unchanged'),
|
saveDisabled: Em.computed.or('saving', 'newEmailEmpty', 'taken', 'unchanged'),
|
||||||
unchanged: Discourse.computed.propertyEqual('newEmailLower', 'email'),
|
unchanged: propertyEqual('newEmailLower', 'email'),
|
||||||
|
|
||||||
newEmailLower: function() {
|
newEmailLower: function() {
|
||||||
return this.get('newEmail').toLowerCase();
|
return this.get('newEmail').toLowerCase();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { setting, propertyEqual } from 'discourse/lib/computed';
|
||||||
import Presence from 'discourse/mixins/presence';
|
import Presence from 'discourse/mixins/presence';
|
||||||
import ObjectController from 'discourse/controllers/object';
|
import ObjectController from 'discourse/controllers/object';
|
||||||
|
|
||||||
|
@ -8,11 +9,11 @@ export default ObjectController.extend(Presence, {
|
||||||
errorMessage: null,
|
errorMessage: null,
|
||||||
newUsername: null,
|
newUsername: null,
|
||||||
|
|
||||||
maxLength: Discourse.computed.setting('max_username_length'),
|
maxLength: setting('max_username_length'),
|
||||||
minLength: Discourse.computed.setting('min_username_length'),
|
minLength: setting('min_username_length'),
|
||||||
newUsernameEmpty: Em.computed.empty('newUsername'),
|
newUsernameEmpty: Em.computed.empty('newUsername'),
|
||||||
saveDisabled: Em.computed.or('saving', 'newUsernameEmpty', 'taken', 'unchanged', 'errorMessage'),
|
saveDisabled: Em.computed.or('saving', 'newUsernameEmpty', 'taken', 'unchanged', 'errorMessage'),
|
||||||
unchanged: Discourse.computed.propertyEqual('newUsername', 'username'),
|
unchanged: propertyEqual('newUsername', 'username'),
|
||||||
|
|
||||||
checkTaken: function() {
|
checkTaken: function() {
|
||||||
if( this.get('newUsername') && this.get('newUsername').length < this.get('minLength') ) {
|
if( this.get('newUsername') && this.get('newUsername').length < this.get('minLength') ) {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
import BufferedContent from 'discourse/mixins/buffered-content';
|
import BufferedContent from 'discourse/mixins/buffered-content';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ export default Ember.Controller.extend(BufferedContent, {
|
||||||
post: Ember.computed.alias('model'),
|
post: Ember.computed.alias('model'),
|
||||||
currentlyEditing: Ember.computed.alias('controllers.queued-posts.editing'),
|
currentlyEditing: Ember.computed.alias('controllers.queued-posts.editing'),
|
||||||
|
|
||||||
editing: Discourse.computed.propertyEqual('model', 'currentlyEditing'),
|
editing: propertyEqual('model', 'currentlyEditing'),
|
||||||
|
|
||||||
_confirmDelete: updateState('rejected', {deleteUser: true}),
|
_confirmDelete: updateState('rejected', {deleteUser: true}),
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import Sharing from 'discourse/lib/sharing';
|
import Sharing from 'discourse/lib/sharing';
|
||||||
|
import { longDateNoYear } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Ember.Controller.extend({
|
||||||
needs: ['topic'],
|
needs: ['topic'],
|
||||||
title: Ember.computed.alias('controllers.topic.model.title'),
|
title: Ember.computed.alias('controllers.topic.model.title'),
|
||||||
|
|
||||||
displayDate: function() {
|
displayDate: function() {
|
||||||
return Discourse.Formatter.longDateNoYear(new Date(this.get('date')));
|
return longDateNoYear(new Date(this.get('date')));
|
||||||
}.property('date'),
|
}.property('date'),
|
||||||
|
|
||||||
// Close the share controller
|
// Close the share controller
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { url } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.ArrayController.extend({
|
export default Ember.ArrayController.extend({
|
||||||
needs: ['application', 'header'],
|
needs: ['application', 'header'],
|
||||||
|
|
||||||
|
@ -8,7 +10,7 @@ export default Ember.ArrayController.extend({
|
||||||
return Discourse.SiteSettings.faq_url ? Discourse.SiteSettings.faq_url : Discourse.getURL('/faq');
|
return Discourse.SiteSettings.faq_url ? Discourse.SiteSettings.faq_url : Discourse.getURL('/faq');
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
badgesUrl: Discourse.computed.url('/badges'),
|
badgesUrl: url('/badges'),
|
||||||
|
|
||||||
showKeyboardShortcuts: function(){
|
showKeyboardShortcuts: function(){
|
||||||
return !Discourse.Mobile.mobileView && !this.capabilities.touch;
|
return !Discourse.Mobile.mobileView && !this.capabilities.touch;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import BufferedContent from 'discourse/mixins/buffered-content';
|
||||||
import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
|
import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
|
||||||
import { spinnerHTML } from 'discourse/helpers/loading-spinner';
|
import { spinnerHTML } from 'discourse/helpers/loading-spinner';
|
||||||
import Topic from 'discourse/models/topic';
|
import Topic from 'discourse/models/topic';
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default ObjectController.extend(SelectedPostsCount, BufferedContent, {
|
export default ObjectController.extend(SelectedPostsCount, BufferedContent, {
|
||||||
multiSelect: false,
|
multiSelect: false,
|
||||||
|
@ -18,7 +19,7 @@ export default ObjectController.extend(SelectedPostsCount, BufferedContent, {
|
||||||
firstPostExpanded: false,
|
firstPostExpanded: false,
|
||||||
retrying: false,
|
retrying: false,
|
||||||
|
|
||||||
maxTitleLength: Discourse.computed.setting('max_topic_title_length'),
|
maxTitleLength: setting('max_topic_title_length'),
|
||||||
|
|
||||||
contextChanged: function() {
|
contextChanged: function() {
|
||||||
this.set('controllers.search.searchContext', this.get('model.searchContext'));
|
this.set('controllers.search.searchContext', this.get('model.searchContext'));
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||||
import DiscourseController from 'discourse/controllers/controller';
|
import DiscourseController from 'discourse/controllers/controller';
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default DiscourseController.extend(ModalFunctionality, {
|
export default DiscourseController.extend(ModalFunctionality, {
|
||||||
remote: Em.computed.not("local"),
|
remote: Em.computed.not("local"),
|
||||||
|
@ -13,7 +14,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||||
});
|
});
|
||||||
}.on('init'),
|
}.on('init'),
|
||||||
|
|
||||||
maxSize: Discourse.computed.setting('max_attachment_size_kb'),
|
maxSize: setting('max_attachment_size_kb'),
|
||||||
allowLocal: Em.computed.gt('maxSize', 0),
|
allowLocal: Em.computed.gt('maxSize', 0),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { propertyNotEqual, setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Ember.Controller.extend({
|
||||||
needs: ['topic', 'application'],
|
needs: ['topic', 'application'],
|
||||||
visible: false,
|
visible: false,
|
||||||
|
@ -16,10 +18,10 @@ export default Ember.Controller.extend({
|
||||||
viewingTopic: Em.computed.match('controllers.application.currentPath', /^topic\./),
|
viewingTopic: Em.computed.match('controllers.application.currentPath', /^topic\./),
|
||||||
viewingAdmin: Em.computed.match('controllers.application.currentPath', /^admin\./),
|
viewingAdmin: Em.computed.match('controllers.application.currentPath', /^admin\./),
|
||||||
showFilter: Em.computed.and('viewingTopic', 'postStream.hasNoFilters', 'enoughPostsForFiltering'),
|
showFilter: Em.computed.and('viewingTopic', 'postStream.hasNoFilters', 'enoughPostsForFiltering'),
|
||||||
showName: Discourse.computed.propertyNotEqual('user.name', 'user.username'),
|
showName: propertyNotEqual('user.name', 'user.username'),
|
||||||
hasUserFilters: Em.computed.gt('postStream.userFilters.length', 0),
|
hasUserFilters: Em.computed.gt('postStream.userFilters.length', 0),
|
||||||
isSuspended: Em.computed.notEmpty('user.suspend_reason'),
|
isSuspended: Em.computed.notEmpty('user.suspend_reason'),
|
||||||
showBadges: Discourse.computed.setting('enable_badges'),
|
showBadges: setting('enable_badges'),
|
||||||
showMoreBadges: Em.computed.gt('moreBadgesCount', 0),
|
showMoreBadges: Em.computed.gt('moreBadgesCount', 0),
|
||||||
showDelete: Em.computed.and("viewingAdmin", "showName", "user.canBeDeleted"),
|
showDelete: Em.computed.and("viewingAdmin", "showName", "user.canBeDeleted"),
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export default Ember.ObjectController.extend({
|
export default Ember.Controller.extend({
|
||||||
needs: ["application"],
|
needs: ["application"],
|
||||||
|
|
||||||
_showFooter: function() {
|
_showFooter: function() {
|
||||||
this.set("controllers.application.showFooter", !this.get("canLoadMore"));
|
this.set("controllers.application.showFooter", !this.get("model.canLoadMore"));
|
||||||
}.observes("canLoadMore")
|
}.observes("model.canLoadMore")
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
var safe = Handlebars.SafeString;
|
import registerUnbound from 'discourse/helpers/register-unbound';
|
||||||
|
import avatarTemplate from 'discourse/lib/avatar-template';
|
||||||
|
import { longDate, autoUpdatingRelativeAge, number } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
// TODO: Remove me when ES6ified
|
const safe = Handlebars.SafeString;
|
||||||
var registerUnbound = require('discourse/helpers/register-unbound', null, null, true).default;
|
|
||||||
var avatarTemplate = require('discourse/lib/avatar-template', null, null, true).default;
|
|
||||||
|
|
||||||
Em.Handlebars.helper('bound-avatar', function(user, size, uploadId) {
|
Em.Handlebars.helper('bound-avatar', function(user, size, uploadId) {
|
||||||
if (Em.isEmpty(user)) {
|
if (Em.isEmpty(user)) {
|
||||||
return new safe("<div class='avatar-placeholder'></div>");
|
return new safe("<div class='avatar-placeholder'></div>");
|
||||||
}
|
}
|
||||||
|
|
||||||
var username = Em.get(user, 'username');
|
const username = Em.get(user, 'username');
|
||||||
if (arguments.length < 4) { uploadId = Em.get(user, 'uploaded_avatar_id'); }
|
if (arguments.length < 4) { uploadId = Em.get(user, 'uploaded_avatar_id'); }
|
||||||
var avatar = Em.get(user, 'avatar_template') || avatarTemplate(username, uploadId);
|
const avatar = Em.get(user, 'avatar_template') || avatarTemplate(username, uploadId);
|
||||||
|
|
||||||
return new safe(Discourse.Utilities.avatarImg({ size: size, avatarTemplate: avatar }));
|
return new safe(Discourse.Utilities.avatarImg({ size: size, avatarTemplate: avatar }));
|
||||||
}, 'username', 'uploaded_avatar_id', 'avatar_template');
|
}, 'username', 'uploaded_avatar_id', 'avatar_template');
|
||||||
|
@ -24,30 +24,30 @@ Em.Handlebars.helper('bound-avatar-template', function(avatarTemplate, size) {
|
||||||
});
|
});
|
||||||
|
|
||||||
registerUnbound('raw-date', function(dt) {
|
registerUnbound('raw-date', function(dt) {
|
||||||
return Discourse.Formatter.longDate(new Date(dt));
|
return longDate(new Date(dt));
|
||||||
});
|
});
|
||||||
|
|
||||||
registerUnbound('age-with-tooltip', function(dt) {
|
registerUnbound('age-with-tooltip', function(dt) {
|
||||||
return new safe(Discourse.Formatter.autoUpdatingRelativeAge(new Date(dt), {title: true}));
|
return new safe(autoUpdatingRelativeAge(new Date(dt), {title: true}));
|
||||||
});
|
});
|
||||||
|
|
||||||
registerUnbound('number', function(orig, params) {
|
registerUnbound('number', function(orig, params) {
|
||||||
orig = parseInt(orig, 10);
|
orig = parseInt(orig, 10);
|
||||||
if (isNaN(orig)) { orig = 0; }
|
if (isNaN(orig)) { orig = 0; }
|
||||||
|
|
||||||
var title = orig;
|
let title = orig;
|
||||||
if (params.numberKey) {
|
if (params.numberKey) {
|
||||||
title = I18n.t(params.numberKey, { number: orig });
|
title = I18n.t(params.numberKey, { number: orig });
|
||||||
}
|
}
|
||||||
|
|
||||||
var classNames = 'number';
|
let classNames = 'number';
|
||||||
if (params['class']) {
|
if (params['class']) {
|
||||||
classNames += ' ' + params['class'];
|
classNames += ' ' + params['class'];
|
||||||
}
|
}
|
||||||
var result = "<span class='" + classNames + "'";
|
let result = "<span class='" + classNames + "'";
|
||||||
|
|
||||||
// Round off the thousands to one decimal place
|
// Round off the thousands to one decimal place
|
||||||
var n = Discourse.Formatter.number(orig);
|
const n = number(orig);
|
||||||
if (n !== title) {
|
if (n !== title) {
|
||||||
result += " title='" + Handlebars.Utils.escapeExpression(title) + "'";
|
result += " title='" + Handlebars.Utils.escapeExpression(title) + "'";
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
export default Ember.Handlebars.makeBoundHelper(function(dt) {
|
export default Ember.Handlebars.makeBoundHelper(function(dt) {
|
||||||
return new Handlebars.SafeString(Discourse.Formatter.autoUpdatingRelativeAge(new Date(dt), {format: 'medium', title: true }));
|
return new Handlebars.SafeString(autoUpdatingRelativeAge(new Date(dt), {format: 'medium', title: true }));
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
||||||
import registerUnbound from 'discourse/helpers/register-unbound';
|
import registerUnbound from 'discourse/helpers/register-unbound';
|
||||||
|
|
||||||
registerUnbound('format-age', function(dt) {
|
registerUnbound('format-age', function(dt) {
|
||||||
dt = new Date(dt);
|
dt = new Date(dt);
|
||||||
return new Handlebars.SafeString(Discourse.Formatter.autoUpdatingRelativeAge(dt));
|
return new Handlebars.SafeString(autoUpdatingRelativeAge(dt));
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import registerUnbound from 'discourse/helpers/register-unbound';
|
import registerUnbound from 'discourse/helpers/register-unbound';
|
||||||
|
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Display logic for dates. It is unbound in Ember but will use jQuery to
|
Display logic for dates. It is unbound in Ember but will use jQuery to
|
||||||
|
@ -21,6 +22,6 @@ registerUnbound('format-date', function(val, params) {
|
||||||
|
|
||||||
if (val) {
|
if (val) {
|
||||||
var date = new Date(val);
|
var date = new Date(val);
|
||||||
return new Handlebars.SafeString(Discourse.Formatter.autoUpdatingRelativeAge(date, {format: format, title: title, leaveAgo: leaveAgo}));
|
return new Handlebars.SafeString(autoUpdatingRelativeAge(date, {format: format, title: title, leaveAgo: leaveAgo}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,5 +7,28 @@ export default {
|
||||||
require(entry, null, null, true);
|
require(entry, null, null, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: Once things have migrated remove these
|
||||||
|
if (!Discourse.hasOwnProperty('computed')) {
|
||||||
|
const computed = require('discourse/lib/computed');
|
||||||
|
Object.defineProperty(Discourse, 'computed', {
|
||||||
|
get: function() {
|
||||||
|
Ember.warn('DEPRECATION: `Discourse.computed` is deprecated, import the functions as needed.');
|
||||||
|
return computed;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Discourse.hasOwnProperty('Formatter')) {
|
||||||
|
const Formatter = require('discourse/lib/formatter');
|
||||||
|
Object.defineProperty(Discourse, 'Formatter', {
|
||||||
|
get: function() {
|
||||||
|
Ember.warn('DEPRECATION: `Discourse.Formatter` is deprecated, import the formatters as needed.');
|
||||||
|
return Formatter;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { cleanDOM } from 'discourse/routes/discourse';
|
import { cleanDOM } from 'discourse/routes/discourse';
|
||||||
|
import PageTracker from 'discourse/lib/page-tracker';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "page-tracking",
|
name: "page-tracking",
|
||||||
after: 'register-discourse-location',
|
after: 'register-discourse-location',
|
||||||
|
|
||||||
initialize: function(container) {
|
initialize(container) {
|
||||||
|
|
||||||
// Tell our AJAX system to track a page transition
|
// Tell our AJAX system to track a page transition
|
||||||
var router = container.lookup('router:main');
|
const router = container.lookup('router:main');
|
||||||
router.on('willTransition', function() {
|
router.on('willTransition', function() {
|
||||||
Discourse.viewTrackingRequired();
|
Discourse.viewTrackingRequired();
|
||||||
});
|
});
|
||||||
|
@ -16,7 +17,7 @@ export default {
|
||||||
Em.run.scheduleOnce('afterRender', Ember.Route, cleanDOM);
|
Em.run.scheduleOnce('afterRender', Ember.Route, cleanDOM);
|
||||||
});
|
});
|
||||||
|
|
||||||
var pageTracker = Discourse.PageTracker.current();
|
const pageTracker = PageTracker.current();
|
||||||
pageTracker.start();
|
pageTracker.start();
|
||||||
|
|
||||||
// Out of the box, Discourse tries to track google analytics
|
// Out of the box, Discourse tries to track google analytics
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/**
|
import { updateRelativeAge } from 'discourse/lib/formatter';
|
||||||
Updates the relative ages of dates on the screen.
|
|
||||||
**/
|
// Updates the relative ages of dates on the screen.
|
||||||
export default {
|
export default {
|
||||||
name: "relative-ages",
|
name: "relative-ages",
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
setInterval(function(){
|
setInterval(function(){
|
||||||
Discourse.Formatter.updateRelativeAge($('.relative-date'));
|
updateRelativeAge($('.relative-date'));
|
||||||
}, 60 * 1000);
|
}, 60 * 1000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
Discourse.computed = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns whether two properties are equal to each other.
|
|
||||||
|
|
||||||
@method propertyEqual
|
|
||||||
@params {String} p1 the first property
|
|
||||||
@params {String} p2 the second property
|
|
||||||
@return {Function} computedProperty function
|
|
||||||
**/
|
|
||||||
propertyEqual: function(p1, p2) {
|
|
||||||
return Em.computed(function() {
|
|
||||||
return this.get(p1) === this.get(p2);
|
|
||||||
}).property(p1, p2);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns whether two properties are not equal to each other.
|
|
||||||
|
|
||||||
@method propertyNotEqual
|
|
||||||
@params {String} p1 the first property
|
|
||||||
@params {String} p2 the second property
|
|
||||||
@return {Function} computedProperty function
|
|
||||||
**/
|
|
||||||
propertyNotEqual: function(p1, p2) {
|
|
||||||
return Em.computed(function() {
|
|
||||||
return this.get(p1) !== this.get(p2);
|
|
||||||
}).property(p1, p2);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns i18n version of a string based on a property.
|
|
||||||
|
|
||||||
@method i18n
|
|
||||||
@params {String} properties* to format
|
|
||||||
@params {String} format the i18n format string
|
|
||||||
@return {Function} computedProperty function
|
|
||||||
**/
|
|
||||||
i18n: function() {
|
|
||||||
var args = Array.prototype.slice.call(arguments, 0);
|
|
||||||
var format = args.pop();
|
|
||||||
var computed = Em.computed(function() {
|
|
||||||
var self = this;
|
|
||||||
return I18n.t(format.fmt.apply(format, args.map(function (a) {
|
|
||||||
return self.get(a);
|
|
||||||
})));
|
|
||||||
});
|
|
||||||
return computed.property.apply(computed, args);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Uses an Ember String `fmt` call to format a string. See:
|
|
||||||
http://emberjs.com/api/classes/Em.String.html#method_fmt
|
|
||||||
|
|
||||||
@method fmt
|
|
||||||
@params {String} properties* to format
|
|
||||||
@params {String} format the format string
|
|
||||||
@return {Function} computedProperty function
|
|
||||||
**/
|
|
||||||
fmt: function() {
|
|
||||||
var args = Array.prototype.slice.call(arguments, 0);
|
|
||||||
var format = args.pop();
|
|
||||||
var computed = Em.computed(function() {
|
|
||||||
var self = this;
|
|
||||||
return format.fmt.apply(format, args.map(function (a) {
|
|
||||||
return self.get(a);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
return computed.property.apply(computed, args);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Creates a URL using Discourse.getURL. It takes a fmt string just like
|
|
||||||
fmt does.
|
|
||||||
|
|
||||||
@method url
|
|
||||||
@params {String} properties* to format
|
|
||||||
@params {String} format the format string for the URL
|
|
||||||
@return {Function} computedProperty function returning a URL
|
|
||||||
**/
|
|
||||||
url: function() {
|
|
||||||
var args = Array.prototype.slice.call(arguments, 0);
|
|
||||||
var format = args.pop();
|
|
||||||
var computed = Em.computed(function() {
|
|
||||||
var self = this;
|
|
||||||
return Discourse.getURL(format.fmt.apply(format, args.map(function (a) {
|
|
||||||
return self.get(a);
|
|
||||||
})));
|
|
||||||
});
|
|
||||||
return computed.property.apply(computed, args);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns whether properties end with a string
|
|
||||||
|
|
||||||
@method endWith
|
|
||||||
@params {String} properties* to check
|
|
||||||
@params {String} substring the substring
|
|
||||||
@return {Function} computedProperty function
|
|
||||||
**/
|
|
||||||
endWith: function() {
|
|
||||||
var args = Array.prototype.slice.call(arguments, 0);
|
|
||||||
var substring = args.pop();
|
|
||||||
var computed = Em.computed(function() {
|
|
||||||
var self = this;
|
|
||||||
return _.all(args.map(function(a) { return self.get(a); }), function(s) {
|
|
||||||
var position = s.length - substring.length,
|
|
||||||
lastIndex = s.lastIndexOf(substring);
|
|
||||||
return lastIndex !== -1 && lastIndex === position;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return computed.property.apply(computed, args);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Creates a property from a SiteSetting. In the future the plan is for them to
|
|
||||||
be able to update when changed.
|
|
||||||
|
|
||||||
@method setting
|
|
||||||
@param {String} name of site setting
|
|
||||||
**/
|
|
||||||
setting: function(name) {
|
|
||||||
return Em.computed(function() {
|
|
||||||
return Discourse.SiteSettings[name];
|
|
||||||
}).property();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
124
app/assets/javascripts/discourse/lib/computed.js.es6
Normal file
124
app/assets/javascripts/discourse/lib/computed.js.es6
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/**
|
||||||
|
Returns whether two properties are equal to each other.
|
||||||
|
|
||||||
|
@method propertyEqual
|
||||||
|
@params {String} p1 the first property
|
||||||
|
@params {String} p2 the second property
|
||||||
|
@return {Function} computedProperty function
|
||||||
|
**/
|
||||||
|
export function propertyEqual(p1, p2) {
|
||||||
|
return Em.computed(function() {
|
||||||
|
return this.get(p1) === this.get(p2);
|
||||||
|
}).property(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns whether two properties are not equal to each other.
|
||||||
|
|
||||||
|
@method propertyNotEqual
|
||||||
|
@params {String} p1 the first property
|
||||||
|
@params {String} p2 the second property
|
||||||
|
@return {Function} computedProperty function
|
||||||
|
**/
|
||||||
|
export function propertyNotEqual(p1, p2) {
|
||||||
|
return Em.computed(function() {
|
||||||
|
return this.get(p1) !== this.get(p2);
|
||||||
|
}).property(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns i18n version of a string based on a property.
|
||||||
|
|
||||||
|
@method i18n
|
||||||
|
@params {String} properties* to format
|
||||||
|
@params {String} format the i18n format string
|
||||||
|
@return {Function} computedProperty function
|
||||||
|
**/
|
||||||
|
export function i18n() {
|
||||||
|
const args = Array.prototype.slice.call(arguments, 0);
|
||||||
|
const format = args.pop();
|
||||||
|
const computed = Em.computed(function() {
|
||||||
|
const self = this;
|
||||||
|
return I18n.t(format.fmt.apply(format, args.map(function (a) {
|
||||||
|
return self.get(a);
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
return computed.property.apply(computed, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Uses an Ember String `fmt` call to format a string. See:
|
||||||
|
http://emberjs.com/api/classes/Em.String.html#method_fmt
|
||||||
|
|
||||||
|
@method fmt
|
||||||
|
@params {String} properties* to format
|
||||||
|
@params {String} format the format string
|
||||||
|
@return {Function} computedProperty function
|
||||||
|
**/
|
||||||
|
export function fmt() {
|
||||||
|
const args = Array.prototype.slice.call(arguments, 0);
|
||||||
|
const format = args.pop();
|
||||||
|
const computed = Em.computed(function() {
|
||||||
|
const self = this;
|
||||||
|
return format.fmt.apply(format, args.map(function (a) {
|
||||||
|
return self.get(a);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
return computed.property.apply(computed, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a URL using Discourse.getURL. It takes a fmt string just like
|
||||||
|
fmt does.
|
||||||
|
|
||||||
|
@method url
|
||||||
|
@params {String} properties* to format
|
||||||
|
@params {String} format the format string for the URL
|
||||||
|
@return {Function} computedProperty function returning a URL
|
||||||
|
**/
|
||||||
|
export function url() {
|
||||||
|
const args = Array.prototype.slice.call(arguments, 0);
|
||||||
|
const format = args.pop();
|
||||||
|
const computed = Em.computed(function() {
|
||||||
|
const self = this;
|
||||||
|
return Discourse.getURL(format.fmt.apply(format, args.map(function (a) {
|
||||||
|
return self.get(a);
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
return computed.property.apply(computed, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns whether properties end with a string
|
||||||
|
|
||||||
|
@method endWith
|
||||||
|
@params {String} properties* to check
|
||||||
|
@params {String} substring the substring
|
||||||
|
@return {Function} computedProperty function
|
||||||
|
**/
|
||||||
|
export function endWith() {
|
||||||
|
const args = Array.prototype.slice.call(arguments, 0);
|
||||||
|
const substring = args.pop();
|
||||||
|
const computed = Em.computed(function() {
|
||||||
|
const self = this;
|
||||||
|
return _.all(args.map(function(a) { return self.get(a); }), function(s) {
|
||||||
|
const position = s.length - substring.length,
|
||||||
|
lastIndex = s.lastIndexOf(substring);
|
||||||
|
return lastIndex !== -1 && lastIndex === position;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return computed.property.apply(computed, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a property from a SiteSetting. In the future the plan is for them to
|
||||||
|
be able to update when changed.
|
||||||
|
|
||||||
|
@method setting
|
||||||
|
@param {String} name of site setting
|
||||||
|
**/
|
||||||
|
export function setting(name) {
|
||||||
|
return Em.computed(function() {
|
||||||
|
return Discourse.SiteSettings[name];
|
||||||
|
}).property();
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import PageTracker from 'discourse/lib/page-tracker';
|
||||||
|
|
||||||
let primaryTab = false;
|
let primaryTab = false;
|
||||||
let liveEnabled = false;
|
let liveEnabled = false;
|
||||||
|
@ -79,7 +80,7 @@ function setupNotifications() {
|
||||||
document.addEventListener("scroll", resetIdle);
|
document.addEventListener("scroll", resetIdle);
|
||||||
}
|
}
|
||||||
window.addEventListener("mouseover", resetIdle);
|
window.addEventListener("mouseover", resetIdle);
|
||||||
Discourse.PageTracker.on("change", resetIdle);
|
PageTracker.on("change", resetIdle);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetIdle() {
|
function resetIdle() {
|
||||||
|
|
|
@ -1,38 +1,29 @@
|
||||||
/**
|
// Track visible elemnts on the screen.
|
||||||
Track visible elemnts on the screen.
|
const Eyeline = function Eyeline(selector) {
|
||||||
|
|
||||||
@class Eyeline
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
@uses RSVP.EventTarget
|
|
||||||
**/
|
|
||||||
Discourse.Eyeline = function Eyeline(selector) {
|
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
Eyeline.prototype.update = function() {
|
||||||
Call this whenever you want to consider what is being seen by the browser
|
if (Ember.Test) { return; }
|
||||||
|
|
||||||
@method update
|
const docViewTop = $(window).scrollTop(),
|
||||||
**/
|
windowHeight = $(window).height(),
|
||||||
Discourse.Eyeline.prototype.update = function() {
|
docViewBottom = docViewTop + windowHeight,
|
||||||
var docViewTop = $(window).scrollTop(),
|
$elements = $(this.selector),
|
||||||
windowHeight = $(window).height(),
|
bottomOffset = $elements.last().offset(),
|
||||||
docViewBottom = docViewTop + windowHeight,
|
self = this;
|
||||||
$elements = $(this.selector),
|
|
||||||
atBottom = false,
|
|
||||||
bottomOffset = $elements.last().offset(),
|
|
||||||
self = this;
|
|
||||||
|
|
||||||
|
let atBottom = false;
|
||||||
if (bottomOffset) {
|
if (bottomOffset) {
|
||||||
atBottom = (bottomOffset.top <= docViewBottom) && (bottomOffset.top >= docViewTop);
|
atBottom = (bottomOffset.top <= docViewBottom) && (bottomOffset.top >= docViewTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements.each(function(i, elem) {
|
return $elements.each(function(i, elem) {
|
||||||
var $elem = $(elem),
|
const $elem = $(elem),
|
||||||
elemTop = $elem.offset().top,
|
elemTop = $elem.offset().top,
|
||||||
elemBottom = elemTop + $elem.height(),
|
elemBottom = elemTop + $elem.height();
|
||||||
markSeen = false;
|
|
||||||
|
let markSeen = false;
|
||||||
|
|
||||||
// Make sure the element is visible
|
// Make sure the element is visible
|
||||||
if (!$elem.is(':visible')) return true;
|
if (!$elem.is(':visible')) return true;
|
||||||
|
@ -67,18 +58,15 @@ Discourse.Eyeline.prototype.update = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
// Call this when we know aren't loading any more elements. Mark the rest as seen
|
||||||
Call this when we know aren't loading any more elements. Mark the rest as seen
|
Eyeline.prototype.flushRest = function() {
|
||||||
|
if (Ember.Test) { return; }
|
||||||
@method flushRest
|
const self = this;
|
||||||
**/
|
|
||||||
Discourse.Eyeline.prototype.flushRest = function() {
|
|
||||||
var self = this;
|
|
||||||
$(this.selector).each(function(i, elem) {
|
$(this.selector).each(function(i, elem) {
|
||||||
return self.trigger('saw', { detail: $(elem) });
|
return self.trigger('saw', { detail: $(elem) });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
RSVP.EventTarget.mixin(Discourse.Eyeline.prototype);
|
RSVP.EventTarget.mixin(Eyeline.prototype);
|
||||||
|
|
||||||
|
|
||||||
|
export default Eyeline;
|
|
@ -1,9 +1,5 @@
|
||||||
/* global BreakString:true */
|
/* global BreakString:true */
|
||||||
|
|
||||||
var updateRelativeAge, autoUpdatingRelativeAge, relativeAge, relativeAgeTiny,
|
|
||||||
relativeAgeMedium, relativeAgeMediumSpan, longDate, longDateNoYear, toTitleCase,
|
|
||||||
shortDate, shortDateNoYear, tinyDateYear, relativeAgeTinyShowsYear;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* memoize.js
|
* memoize.js
|
||||||
* by @philogb and @addyosmani
|
* by @philogb and @addyosmani
|
||||||
|
@ -14,15 +10,15 @@ var updateRelativeAge, autoUpdatingRelativeAge, relativeAge, relativeAgeTiny,
|
||||||
*
|
*
|
||||||
* modified with cap by Sam
|
* modified with cap by Sam
|
||||||
*/
|
*/
|
||||||
var cappedMemoize = function ( fn, max ) {
|
function cappedMemoize(fn, max) {
|
||||||
fn.maxMemoize = max;
|
fn.maxMemoize = max;
|
||||||
fn.memoizeLength = 0;
|
fn.memoizeLength = 0;
|
||||||
|
|
||||||
return function () {
|
return function () {
|
||||||
var args = Array.prototype.slice.call(arguments),
|
const args = Array.prototype.slice.call(arguments);
|
||||||
hash = "",
|
let hash = "";
|
||||||
i = args.length;
|
let i = args.length;
|
||||||
var currentArg = null;
|
let currentArg = null;
|
||||||
while (i--) {
|
while (i--) {
|
||||||
currentArg = args[i];
|
currentArg = args[i];
|
||||||
hash += (currentArg === new Object(currentArg)) ?
|
hash += (currentArg === new Object(currentArg)) ?
|
||||||
|
@ -39,44 +35,45 @@ var cappedMemoize = function ( fn, max ) {
|
||||||
fn.memoizeLength = 0;
|
fn.memoizeLength = 0;
|
||||||
fn.memoize = {};
|
fn.memoize = {};
|
||||||
}
|
}
|
||||||
var result = fn.apply(this, args);
|
const result = fn.apply(this, args);
|
||||||
fn.memoize[hash] = result;
|
fn.memoize[hash] = result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
var breakUp = cappedMemoize(function(str, hint){
|
const breakUp = cappedMemoize(function(str, hint){
|
||||||
return new BreakString(str).break(hint);
|
return new BreakString(str).break(hint);
|
||||||
}, 100);
|
}, 100);
|
||||||
|
export { breakUp };
|
||||||
|
|
||||||
shortDate = function(date){
|
export function shortDate(date){
|
||||||
return moment(date).format(I18n.t("dates.medium.date_year"));
|
return moment(date).format(I18n.t("dates.medium.date_year"));
|
||||||
};
|
}
|
||||||
|
|
||||||
shortDateNoYear = function(date) {
|
function shortDateNoYear(date) {
|
||||||
return moment(date).format(I18n.t("dates.tiny.date_month"));
|
return moment(date).format(I18n.t("dates.tiny.date_month"));
|
||||||
};
|
}
|
||||||
|
|
||||||
tinyDateYear = function(date) {
|
function tinyDateYear(date) {
|
||||||
return moment(date).format(I18n.t("dates.tiny.date_year"));
|
return moment(date).format(I18n.t("dates.tiny.date_year"));
|
||||||
};
|
}
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
|
// http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
|
||||||
// TODO: locale support ?
|
// TODO: locale support ?
|
||||||
toTitleCase = function toTitleCase(str) {
|
export function toTitleCase(str) {
|
||||||
return str.replace(/\w\S*/g, function(txt){
|
return str.replace(/\w\S*/g, function(txt){
|
||||||
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
longDate = function(dt) {
|
export function longDate(dt) {
|
||||||
if (!dt) return;
|
if (!dt) return;
|
||||||
return moment(dt).longDate();
|
return moment(dt).longDate();
|
||||||
};
|
}
|
||||||
|
|
||||||
// suppress year, if current year
|
// suppress year, if current year
|
||||||
longDateNoYear = function(dt) {
|
export function longDateNoYear(dt) {
|
||||||
if (!dt) return;
|
if (!dt) return;
|
||||||
|
|
||||||
if ((new Date()).getFullYear() !== dt.getFullYear()) {
|
if ((new Date()).getFullYear() !== dt.getFullYear()) {
|
||||||
|
@ -84,26 +81,25 @@ longDateNoYear = function(dt) {
|
||||||
} else {
|
} else {
|
||||||
return moment(dt).format(I18n.t("dates.long_date_without_year"));
|
return moment(dt).format(I18n.t("dates.long_date_without_year"));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
updateRelativeAge = function(elems) {
|
export function updateRelativeAge(elems) {
|
||||||
// jQuery .each
|
// jQuery .each
|
||||||
elems.each(function(){
|
elems.each(function(){
|
||||||
var $this = $(this);
|
const $this = $(this);
|
||||||
$this.html(relativeAge(new Date($this.data('time')), {format: $this.data('format'), wrapInSpan: false}));
|
$this.html(relativeAge(new Date($this.data('time')), {format: $this.data('format'), wrapInSpan: false}));
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
autoUpdatingRelativeAge = function(date,options) {
|
export function autoUpdatingRelativeAge(date,options) {
|
||||||
if (!date) return "";
|
if (!date) return "";
|
||||||
if (+date === +new Date(0)) return "";
|
if (+date === +new Date(0)) return "";
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var format = options.format || "tiny";
|
let format = options.format || "tiny";
|
||||||
|
|
||||||
var append = "";
|
let append = "";
|
||||||
|
if (format === 'medium') {
|
||||||
if(format === 'medium') {
|
|
||||||
append = " date";
|
append = " date";
|
||||||
if(options.leaveAgo) {
|
if(options.leaveAgo) {
|
||||||
format = 'medium-with-ago';
|
format = 'medium-with-ago';
|
||||||
|
@ -111,7 +107,7 @@ autoUpdatingRelativeAge = function(date,options) {
|
||||||
options.wrapInSpan = false;
|
options.wrapInSpan = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var relAge = relativeAge(date, options);
|
const relAge = relativeAge(date, options);
|
||||||
|
|
||||||
if (format === 'tiny' && relativeAgeTinyShowsYear(relAge)) {
|
if (format === 'tiny' && relativeAgeTinyShowsYear(relAge)) {
|
||||||
append += " with-year";
|
append += " with-year";
|
||||||
|
@ -122,16 +118,16 @@ autoUpdatingRelativeAge = function(date,options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return "<span class='relative-date" + append + "' data-time='" + date.getTime() + "' data-format='" + format + "'>" + relAge + "</span>";
|
return "<span class='relative-date" + append + "' data-time='" + date.getTime() + "' data-format='" + format + "'>" + relAge + "</span>";
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
relativeAgeTiny = function(date){
|
function relativeAgeTiny(date){
|
||||||
var format = "tiny";
|
const format = "tiny";
|
||||||
var distance = Math.round((new Date() - date) / 1000);
|
const distance = Math.round((new Date() - date) / 1000);
|
||||||
var distanceInMinutes = Math.round(distance / 60.0);
|
const distanceInMinutes = Math.round(distance / 60.0);
|
||||||
|
|
||||||
var formatted;
|
let formatted;
|
||||||
var t = function(key,opts){
|
const t = function(key,opts){
|
||||||
return I18n.t("dates." + format + "." + key, opts);
|
return I18n.t("dates." + format + "." + key, opts);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -168,22 +164,21 @@ relativeAgeTiny = function(date){
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatted;
|
return formatted;
|
||||||
};
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns true if the given tiny date string includes the year.
|
* Returns true if the given tiny date string includes the year.
|
||||||
* Useful for checking if the string isn't so tiny.
|
* Useful for checking if the string isn't so tiny.
|
||||||
*/
|
*/
|
||||||
relativeAgeTinyShowsYear = function(relativeAgeString) {
|
function relativeAgeTinyShowsYear(relativeAgeString) {
|
||||||
return relativeAgeString.match(/'[\d]{2}$/);
|
return relativeAgeString.match(/'[\d]{2}$/);
|
||||||
};
|
}
|
||||||
|
|
||||||
relativeAgeMediumSpan = function(distance, leaveAgo) {
|
function relativeAgeMediumSpan(distance, leaveAgo) {
|
||||||
var formatted, distanceInMinutes;
|
let formatted;
|
||||||
|
const distanceInMinutes = Math.round(distance / 60.0);
|
||||||
|
|
||||||
distanceInMinutes = Math.round(distance / 60.0);
|
const t = function(key, opts){
|
||||||
|
|
||||||
var t = function(key, opts){
|
|
||||||
return I18n.t("dates.medium" + (leaveAgo?"_with_ago":"") + "." + key, opts);
|
return I18n.t("dates.medium" + (leaveAgo?"_with_ago":"") + "." + key, opts);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -205,24 +200,22 @@ relativeAgeMediumSpan = function(distance, leaveAgo) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return formatted || '&mdash';
|
return formatted || '&mdash';
|
||||||
};
|
}
|
||||||
|
|
||||||
relativeAgeMedium = function(date, options){
|
function relativeAgeMedium(date, options) {
|
||||||
var displayDate, fiveDaysAgo, oneMinuteAgo, fullReadable, leaveAgo;
|
const wrapInSpan = options.wrapInSpan !== false;
|
||||||
var wrapInSpan = options.wrapInSpan !== false;
|
const leaveAgo = options.leaveAgo;
|
||||||
|
const distance = Math.round((new Date() - date) / 1000);
|
||||||
leaveAgo = options.leaveAgo;
|
|
||||||
var distance = Math.round((new Date() - date) / 1000);
|
|
||||||
|
|
||||||
if (!date) {
|
if (!date) {
|
||||||
return "—";
|
return "—";
|
||||||
}
|
}
|
||||||
|
|
||||||
fullReadable = longDate(date);
|
const fullReadable = longDate(date);
|
||||||
displayDate = "";
|
const fiveDaysAgo = 432000;
|
||||||
fiveDaysAgo = 432000;
|
const oneMinuteAgo = 60;
|
||||||
oneMinuteAgo = 60;
|
|
||||||
|
|
||||||
|
let displayDate = "";
|
||||||
if (distance < oneMinuteAgo) {
|
if (distance < oneMinuteAgo) {
|
||||||
displayDate = I18n.t("now");
|
displayDate = I18n.t("now");
|
||||||
} else if (distance > fiveDaysAgo) {
|
} else if (distance > fiveDaysAgo) {
|
||||||
|
@ -239,12 +232,12 @@ relativeAgeMedium = function(date, options){
|
||||||
} else {
|
} else {
|
||||||
return displayDate;
|
return displayDate;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// mostly lifted from rails with a few amendments
|
// mostly lifted from rails with a few amendments
|
||||||
relativeAge = function(date, options) {
|
export function relativeAge(date, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var format = options.format || "tiny";
|
const format = options.format || "tiny";
|
||||||
|
|
||||||
if(format === "tiny") {
|
if(format === "tiny") {
|
||||||
return relativeAgeTiny(date, options);
|
return relativeAgeTiny(date, options);
|
||||||
|
@ -255,10 +248,10 @@ relativeAge = function(date, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return "UNKNOWN FORMAT";
|
return "UNKNOWN FORMAT";
|
||||||
};
|
}
|
||||||
|
|
||||||
var number = function(val) {
|
export function number(val) {
|
||||||
var formattedNumber;
|
let formattedNumber;
|
||||||
|
|
||||||
val = parseInt(val, 10);
|
val = parseInt(val, 10);
|
||||||
if (isNaN(val)) val = 0;
|
if (isNaN(val)) val = 0;
|
||||||
|
@ -272,17 +265,5 @@ var number = function(val) {
|
||||||
return I18n.t("number.short.thousands", {number: formattedNumber});
|
return I18n.t("number.short.thousands", {number: formattedNumber});
|
||||||
}
|
}
|
||||||
return val.toString();
|
return val.toString();
|
||||||
};
|
}
|
||||||
|
|
||||||
Discourse.Formatter = {
|
|
||||||
longDate: longDate,
|
|
||||||
longDateNoYear: longDateNoYear,
|
|
||||||
relativeAge: relativeAge,
|
|
||||||
autoUpdatingRelativeAge: autoUpdatingRelativeAge,
|
|
||||||
updateRelativeAge: updateRelativeAge,
|
|
||||||
toTitleCase: toTitleCase,
|
|
||||||
shortDate: shortDate,
|
|
||||||
breakUp: breakUp,
|
|
||||||
cappedMemoize: cappedMemoize,
|
|
||||||
number: number
|
|
||||||
};
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import Singleton from 'discourse/mixins/singleton';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Called whenever the "page" changes. This allows us to set up analytics
|
Called whenever the "page" changes. This allows us to set up analytics
|
||||||
and other tracking.
|
and other tracking.
|
||||||
|
@ -5,12 +7,12 @@
|
||||||
To get notified when the page changes, you can install a hook like so:
|
To get notified when the page changes, you can install a hook like so:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
Discourse.PageTracker.current().on('change', function(url, title) {
|
PageTracker.current().on('change', function(url, title) {
|
||||||
console.log('the page changed to: ' + url + ' and title ' + title);
|
console.log('the page changed to: ' + url + ' and title ' + title);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**/
|
**/
|
||||||
Discourse.PageTracker = Ember.Object.extend(Ember.Evented, {
|
const PageTracker = Ember.Object.extend(Ember.Evented, {
|
||||||
start: function() {
|
start: function() {
|
||||||
if (this.get('started')) { return; }
|
if (this.get('started')) { return; }
|
||||||
|
|
||||||
|
@ -30,4 +32,6 @@ Discourse.PageTracker = Ember.Object.extend(Ember.Evented, {
|
||||||
this.set('started', true);
|
this.set('started', true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Discourse.PageTracker.reopenClass(Discourse.Singleton);
|
PageTracker.reopenClass(Singleton);
|
||||||
|
|
||||||
|
export default PageTracker;
|
|
@ -1,23 +1,18 @@
|
||||||
/**
|
// We use this class to track how long posts in a topic are on the screen.
|
||||||
We use this class to track how long posts in a topic are on the screen.
|
|
||||||
|
|
||||||
@class ScreenTrack
|
import Singleton from 'discourse/mixins/singleton';
|
||||||
@extends Ember.Object
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
|
|
||||||
var PAUSE_UNLESS_SCROLLED = 1000 * 60 * 3,
|
const PAUSE_UNLESS_SCROLLED = 1000 * 60 * 3,
|
||||||
MAX_TRACKING_TIME = 1000 * 60 * 6;
|
MAX_TRACKING_TIME = 1000 * 60 * 6;
|
||||||
|
|
||||||
Discourse.ScreenTrack = Ember.Object.extend({
|
const ScreenTrack = Ember.Object.extend({
|
||||||
|
|
||||||
init: function() {
|
init() {
|
||||||
this.reset();
|
this.reset();
|
||||||
},
|
},
|
||||||
|
|
||||||
start: function(topicId, topicController) {
|
start(topicId, topicController) {
|
||||||
var currentTopicId = this.get('topicId');
|
const currentTopicId = this.get('topicId');
|
||||||
if (currentTopicId && (currentTopicId !== topicId)) {
|
if (currentTopicId && (currentTopicId !== topicId)) {
|
||||||
this.tick();
|
this.tick();
|
||||||
this.flush();
|
this.flush();
|
||||||
|
@ -27,7 +22,7 @@ Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
|
|
||||||
// Create an interval timer if we don't have one.
|
// Create an interval timer if we don't have one.
|
||||||
if (!this.get('interval')) {
|
if (!this.get('interval')) {
|
||||||
var self = this;
|
const self = this;
|
||||||
this.set('interval', setInterval(function () {
|
this.set('interval', setInterval(function () {
|
||||||
self.tick();
|
self.tick();
|
||||||
}, 1000));
|
}, 1000));
|
||||||
|
@ -39,7 +34,7 @@ Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
this.set('topicController', topicController);
|
this.set('topicController', topicController);
|
||||||
},
|
},
|
||||||
|
|
||||||
stop: function() {
|
stop() {
|
||||||
if(!this.get('topicId')) {
|
if(!this.get('topicId')) {
|
||||||
// already stopped no need to "extra stop"
|
// already stopped no need to "extra stop"
|
||||||
return;
|
return;
|
||||||
|
@ -56,19 +51,19 @@ Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
track: function(elementId, postNumber) {
|
track(elementId, postNumber) {
|
||||||
this.get('timings')["#" + elementId] = {
|
this.get('timings')["#" + elementId] = {
|
||||||
time: 0,
|
time: 0,
|
||||||
postNumber: postNumber
|
postNumber: postNumber
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
stopTracking: function(elementId) {
|
stopTracking(elementId) {
|
||||||
delete this.get('timings')['#' + elementId];
|
delete this.get('timings')['#' + elementId];
|
||||||
},
|
},
|
||||||
|
|
||||||
// Reset our timers
|
// Reset our timers
|
||||||
reset: function() {
|
reset() {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
lastTick: new Date().getTime(),
|
lastTick: new Date().getTime(),
|
||||||
lastScrolled: new Date().getTime(),
|
lastScrolled: new Date().getTime(),
|
||||||
|
@ -80,17 +75,17 @@ Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
scrolled: function() {
|
scrolled() {
|
||||||
this.set('lastScrolled', new Date().getTime());
|
this.set('lastScrolled', new Date().getTime());
|
||||||
},
|
},
|
||||||
|
|
||||||
flush: function() {
|
flush() {
|
||||||
if (this.get('cancelled')) { return; }
|
if (this.get('cancelled')) { return; }
|
||||||
|
|
||||||
// We don't log anything unless we're logged in
|
// We don't log anything unless we're logged in
|
||||||
if (!Discourse.User.current()) return;
|
if (!Discourse.User.current()) return;
|
||||||
|
|
||||||
var newTimings = {},
|
const newTimings = {},
|
||||||
totalTimings = this.get('totalTimings'),
|
totalTimings = this.get('totalTimings'),
|
||||||
self = this;
|
self = this;
|
||||||
|
|
||||||
|
@ -105,14 +100,14 @@ Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
timing.time = 0;
|
timing.time = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
var topicId = parseInt(this.get('topicId'), 10),
|
const topicId = parseInt(this.get('topicId'), 10);
|
||||||
highestSeen = 0;
|
let highestSeen = 0;
|
||||||
|
|
||||||
_.each(newTimings, function(time,postNumber) {
|
_.each(newTimings, function(time,postNumber) {
|
||||||
highestSeen = Math.max(highestSeen, parseInt(postNumber, 10));
|
highestSeen = Math.max(highestSeen, parseInt(postNumber, 10));
|
||||||
});
|
});
|
||||||
|
|
||||||
var highestSeenByTopic = Discourse.Session.currentProp('highestSeenByTopic');
|
const highestSeenByTopic = Discourse.Session.currentProp('highestSeenByTopic');
|
||||||
if ((highestSeenByTopic[topicId] || 0) < highestSeen) {
|
if ((highestSeenByTopic[topicId] || 0) < highestSeen) {
|
||||||
highestSeenByTopic[topicId] = highestSeen;
|
highestSeenByTopic[topicId] = highestSeen;
|
||||||
}
|
}
|
||||||
|
@ -132,9 +127,9 @@ Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
'X-SILENCE-LOGGER': 'true'
|
'X-SILENCE-LOGGER': 'true'
|
||||||
}
|
}
|
||||||
}).then(function(){
|
}).then(function(){
|
||||||
var controller = self.get('topicController');
|
const controller = self.get('topicController');
|
||||||
if(controller){
|
if(controller){
|
||||||
var postNumbers = Object.keys(newTimings).map(function(v){
|
const postNumbers = Object.keys(newTimings).map(function(v){
|
||||||
return parseInt(v,10);
|
return parseInt(v,10);
|
||||||
});
|
});
|
||||||
controller.readPosts(topicId, postNumbers);
|
controller.readPosts(topicId, postNumbers);
|
||||||
|
@ -146,23 +141,23 @@ Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
this.set('lastFlush', 0);
|
this.set('lastFlush', 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
tick: function() {
|
tick() {
|
||||||
|
|
||||||
// If the user hasn't scrolled the browser in a long time, stop tracking time read
|
// If the user hasn't scrolled the browser in a long time, stop tracking time read
|
||||||
var sinceScrolled = new Date().getTime() - this.get('lastScrolled');
|
const sinceScrolled = new Date().getTime() - this.get('lastScrolled');
|
||||||
if (sinceScrolled > PAUSE_UNLESS_SCROLLED) {
|
if (sinceScrolled > PAUSE_UNLESS_SCROLLED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var diff = new Date().getTime() - this.get('lastTick');
|
const diff = new Date().getTime() - this.get('lastTick');
|
||||||
this.set('lastFlush', this.get('lastFlush') + diff);
|
this.set('lastFlush', this.get('lastFlush') + diff);
|
||||||
this.set('lastTick', new Date().getTime());
|
this.set('lastTick', new Date().getTime());
|
||||||
|
|
||||||
var totalTimings = this.get('totalTimings'), timings = this.get('timings');
|
const totalTimings = this.get('totalTimings'), timings = this.get('timings');
|
||||||
var nextFlush = Discourse.SiteSettings.flush_timings_secs * 1000;
|
const nextFlush = Discourse.SiteSettings.flush_timings_secs * 1000;
|
||||||
|
|
||||||
// rush new post numbers
|
// rush new post numbers
|
||||||
var rush = _.any(_.filter(timings, function(t){return t.time>0;}), function(t){
|
const rush = _.any(_.filter(timings, function(t){return t.time>0;}), function(t){
|
||||||
return !totalTimings[t.postNumber];
|
return !totalTimings[t.postNumber];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -174,15 +169,15 @@ Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
if (!Discourse.get("hasFocus")) return;
|
if (!Discourse.get("hasFocus")) return;
|
||||||
|
|
||||||
this.set('topicTime', this.get('topicTime') + diff);
|
this.set('topicTime', this.get('topicTime') + diff);
|
||||||
var docViewTop = $(window).scrollTop() + $('header').height(),
|
const docViewTop = $(window).scrollTop() + $('header').height(),
|
||||||
docViewBottom = docViewTop + $(window).height();
|
docViewBottom = docViewTop + $(window).height();
|
||||||
|
|
||||||
// TODO: Eyeline has a smarter more accurate function here. It's bad to do jQuery
|
// TODO: Eyeline has a smarter more accurate function here. It's bad to do jQuery
|
||||||
// in a model like component, so we should refactor this out later.
|
// in a model like component, so we should refactor this out later.
|
||||||
_.each(this.get('timings'),function(timing,id) {
|
_.each(this.get('timings'),function(timing,id) {
|
||||||
var $element = $(id);
|
const $element = $(id);
|
||||||
if ($element.length === 1) {
|
if ($element.length === 1) {
|
||||||
var elemTop = $element.offset().top,
|
const elemTop = $element.offset().top,
|
||||||
elemBottom = elemTop + $element.height();
|
elemBottom = elemTop + $element.height();
|
||||||
|
|
||||||
// If part of the element is on the screen, increase the counter
|
// If part of the element is on the screen, increase the counter
|
||||||
|
@ -195,5 +190,5 @@ Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Discourse.ScreenTrack.reopenClass(Discourse.Singleton);
|
ScreenTrack.reopenClass(Singleton);
|
||||||
|
export default ScreenTrack;
|
|
@ -1,6 +1,8 @@
|
||||||
|
import { propertyEqual, setting } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.Mixin.create({
|
export default Ember.Mixin.create({
|
||||||
isOwnEmail: Discourse.computed.propertyEqual("model.id", "currentUser.id"),
|
isOwnEmail: propertyEqual("model.id", "currentUser.id"),
|
||||||
showEmailOnProfile: Discourse.computed.setting("show_email_on_profile"),
|
showEmailOnProfile: setting("show_email_on_profile"),
|
||||||
canStaffCheckEmails: Em.computed.and("showEmailOnProfile", "currentUser.staff"),
|
canStaffCheckEmails: Em.computed.and("showEmailOnProfile", "currentUser.staff"),
|
||||||
canAdminCheckEmails: Em.computed.alias("currentUser.admin"),
|
canAdminCheckEmails: Em.computed.alias("currentUser.admin"),
|
||||||
canCheckEmails: Em.computed.or("isOwnEmail", "canStaffCheckEmails", "canAdminCheckEmails"),
|
canCheckEmails: Em.computed.or("isOwnEmail", "canStaffCheckEmails", "canAdminCheckEmails"),
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
import Eyeline from 'discourse/lib/eyeline';
|
||||||
|
import Scrolling from 'discourse/mixins/scrolling';
|
||||||
|
|
||||||
// Provides the ability to load more items for a view which is scrolled to the bottom.
|
// Provides the ability to load more items for a view which is scrolled to the bottom.
|
||||||
export default Em.Mixin.create(Ember.ViewTargetActionSupport, Discourse.Scrolling, {
|
export default Ember.Mixin.create(Ember.ViewTargetActionSupport, Scrolling, {
|
||||||
|
|
||||||
scrolled: function() {
|
scrolled: function() {
|
||||||
const eyeline = this.get('eyeline');
|
const eyeline = this.get('eyeline');
|
||||||
|
@ -7,7 +10,7 @@ export default Em.Mixin.create(Ember.ViewTargetActionSupport, Discourse.Scrollin
|
||||||
},
|
},
|
||||||
|
|
||||||
_bindEyeline: function() {
|
_bindEyeline: function() {
|
||||||
const eyeline = new Discourse.Eyeline(this.get('eyelineSelector') + ":last");
|
const eyeline = new Eyeline(this.get('eyelineSelector') + ":last");
|
||||||
this.set('eyeline', eyeline);
|
this.set('eyeline', eyeline);
|
||||||
eyeline.on('sawBottom', () => this.send('loadMore'));
|
eyeline.on('sawBottom', () => this.send('loadMore'));
|
||||||
this.bindScrolling();
|
this.bindScrolling();
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
/**
|
|
||||||
This mixin adds support for being notified every time the browser window
|
|
||||||
is scrolled.
|
|
||||||
|
|
||||||
@class Scrolling
|
|
||||||
@extends Ember.Mixin
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
|
|
||||||
Discourse.Scrolling = Em.Mixin.create({
|
|
||||||
|
|
||||||
/**
|
|
||||||
Begin watching for scroll events. By default they will be called at max every 100ms.
|
|
||||||
call with {debounce: N} for a diff time
|
|
||||||
|
|
||||||
@method bindScrolling
|
|
||||||
*/
|
|
||||||
bindScrolling: function(opts) {
|
|
||||||
opts = opts || {debounce: 100};
|
|
||||||
|
|
||||||
// So we can not call the scrolled event while transitioning
|
|
||||||
var router = Discourse.__container__.lookup('router:main').router;
|
|
||||||
|
|
||||||
var self = this,
|
|
||||||
onScrollMethod = function() {
|
|
||||||
if (router.activeTransition) { return; }
|
|
||||||
return Em.run.scheduleOnce('afterRender', self, 'scrolled');
|
|
||||||
};
|
|
||||||
|
|
||||||
if (opts.debounce) {
|
|
||||||
onScrollMethod = Discourse.debounce(onScrollMethod, opts.debounce);
|
|
||||||
}
|
|
||||||
|
|
||||||
Discourse.ScrollingDOMMethods.bindOnScroll(onScrollMethod, opts.name);
|
|
||||||
Em.run.scheduleOnce('afterRender', onScrollMethod);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Stop watching for scroll events.
|
|
||||||
|
|
||||||
@method unbindScrolling
|
|
||||||
*/
|
|
||||||
unbindScrolling: function(name) {
|
|
||||||
Discourse.ScrollingDOMMethods.unbindOnScroll(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This object provides the DOM methods we need for our Mixin to bind to scrolling
|
|
||||||
methods in the browser. By removing them from the Mixin we can test them
|
|
||||||
easier.
|
|
||||||
|
|
||||||
@class ScrollingDOMMethods
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.ScrollingDOMMethods = {
|
|
||||||
|
|
||||||
bindOnScroll: function(onScrollMethod, name) {
|
|
||||||
name = name || 'default';
|
|
||||||
$(document).bind('touchmove.discourse-' + name, onScrollMethod);
|
|
||||||
$(window).bind('scroll.discourse-' + name, onScrollMethod);
|
|
||||||
},
|
|
||||||
|
|
||||||
unbindOnScroll: function(name) {
|
|
||||||
name = name || 'default';
|
|
||||||
$(window).unbind('scroll.discourse-' + name);
|
|
||||||
$(document).unbind('touchmove.discourse-' + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
50
app/assets/javascripts/discourse/mixins/scrolling.js.es6
Normal file
50
app/assets/javascripts/discourse/mixins/scrolling.js.es6
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
This object provides the DOM methods we need for our Mixin to bind to scrolling
|
||||||
|
methods in the browser. By removing them from the Mixin we can test them
|
||||||
|
easier.
|
||||||
|
**/
|
||||||
|
const ScrollingDOMMethods = {
|
||||||
|
bindOnScroll: function(onScrollMethod, name) {
|
||||||
|
name = name || 'default';
|
||||||
|
$(document).bind('touchmove.discourse-' + name, onScrollMethod);
|
||||||
|
$(window).bind('scroll.discourse-' + name, onScrollMethod);
|
||||||
|
},
|
||||||
|
|
||||||
|
unbindOnScroll: function(name) {
|
||||||
|
name = name || 'default';
|
||||||
|
$(window).unbind('scroll.discourse-' + name);
|
||||||
|
$(document).unbind('touchmove.discourse-' + name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Scrolling = Ember.Mixin.create({
|
||||||
|
|
||||||
|
// Begin watching for scroll events. By default they will be called at max every 100ms.
|
||||||
|
// call with {debounce: N} for a diff time
|
||||||
|
bindScrolling: function(opts) {
|
||||||
|
opts = opts || {debounce: 100};
|
||||||
|
|
||||||
|
// So we can not call the scrolled event while transitioning
|
||||||
|
const router = Discourse.__container__.lookup('router:main').router;
|
||||||
|
|
||||||
|
const self = this;
|
||||||
|
var onScrollMethod = function() {
|
||||||
|
if (router.activeTransition) { return; }
|
||||||
|
return Em.run.scheduleOnce('afterRender', self, 'scrolled');
|
||||||
|
};
|
||||||
|
|
||||||
|
if (opts.debounce) {
|
||||||
|
onScrollMethod = Discourse.debounce(onScrollMethod, opts.debounce);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollingDOMMethods.bindOnScroll(onScrollMethod, opts.name);
|
||||||
|
Em.run.scheduleOnce('afterRender', onScrollMethod);
|
||||||
|
},
|
||||||
|
|
||||||
|
unbindScrolling: function(name) {
|
||||||
|
ScrollingDOMMethods.unbindOnScroll(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export { ScrollingDOMMethods };
|
||||||
|
export default Scrolling;
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
// Define your class and apply the Mixin
|
// Define your class and apply the Mixin
|
||||||
User = Ember.Object.extend({});
|
User = Ember.Object.extend({});
|
||||||
User.reopenClass(Discourse.Singleton);
|
User.reopenClass(Singleton);
|
||||||
|
|
||||||
// Retrieve the current instance:
|
// Retrieve the current instance:
|
||||||
var instance = User.current();
|
var instance = User.current();
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
// Define your class and apply the Mixin
|
// Define your class and apply the Mixin
|
||||||
Foot = Ember.Object.extend({});
|
Foot = Ember.Object.extend({});
|
||||||
Foot.reopenClass(Discourse.Singleton, {
|
Foot.reopenClass(Singleton, {
|
||||||
createCurrent: function() {
|
createCurrent: function() {
|
||||||
return Foot.create({toes: 5});
|
return Foot.create({toes: 5});
|
||||||
}
|
}
|
||||||
|
@ -44,51 +44,28 @@
|
||||||
console.log(Foot.currentProp('toes')); // 5
|
console.log(Foot.currentProp('toes')); // 5
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@class Discourse.Singleton
|
|
||||||
@extends Ember.Mixin
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
**/
|
||||||
Discourse.Singleton = Em.Mixin.create({
|
const Singleton = Ember.Mixin.create({
|
||||||
|
|
||||||
/**
|
current() {
|
||||||
Returns the current singleton instance of the class.
|
|
||||||
|
|
||||||
@method current
|
|
||||||
@returns {Ember.Object} the instance of the singleton
|
|
||||||
**/
|
|
||||||
current: function() {
|
|
||||||
if (!this._current) {
|
if (!this._current) {
|
||||||
this._current = this.createCurrent();
|
this._current = this.createCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._current;
|
return this._current;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
How the singleton instance is created. This can be overridden
|
How the singleton instance is created. This can be overridden
|
||||||
with logic for creating (or even returning null) your instance.
|
with logic for creating (or even returning null) your instance.
|
||||||
|
|
||||||
By default it just calls `create` with an empty object.
|
By default it just calls `create` with an empty object.
|
||||||
|
|
||||||
@method createCurrent
|
|
||||||
@returns {Ember.Object} the instance that will be your singleton
|
|
||||||
**/
|
**/
|
||||||
createCurrent: function() {
|
createCurrent() {
|
||||||
return this.create({});
|
return this.create({});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// Returns OR sets a property on the singleton instance.
|
||||||
Returns or sets a property on the singleton instance.
|
currentProp(property, value) {
|
||||||
|
|
||||||
@method currentProp
|
|
||||||
@param {String} property the property we want to get or set
|
|
||||||
@param {String} value the optional value to set the property to
|
|
||||||
@returns the value of the property
|
|
||||||
**/
|
|
||||||
currentProp: function(property, value) {
|
|
||||||
var instance = this.current();
|
var instance = this.current();
|
||||||
if (!instance) { return; }
|
if (!instance) { return; }
|
||||||
|
|
||||||
|
@ -100,14 +77,9 @@ Discourse.Singleton = Em.Mixin.create({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
resetCurrent(val) {
|
||||||
Resets the current singleton. Useful in testing.
|
|
||||||
|
|
||||||
@method resetCurrent
|
|
||||||
**/
|
|
||||||
resetCurrent: function(val) {
|
|
||||||
this._current = val;
|
this._current = val;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default Singleton;
|
|
@ -1,15 +1,9 @@
|
||||||
/**
|
import Post from 'discourse/models/post';
|
||||||
A data model for flagged/deleted posts.
|
|
||||||
|
|
||||||
@class AdminPost
|
export default Post.extend({
|
||||||
@extends Discourse.Post
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.AdminPost = Discourse.Post.extend({
|
|
||||||
|
|
||||||
_attachCategory: function () {
|
_attachCategory: function () {
|
||||||
var categoryId = this.get("category_id");
|
const categoryId = this.get("category_id");
|
||||||
if (categoryId) {
|
if (categoryId) {
|
||||||
this.set("category", Discourse.Category.findById(categoryId));
|
this.set("category", Discourse.Category.findById(categoryId));
|
||||||
}
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
/**
|
|
||||||
A data model for archetypes such as polls, tasks, etc.
|
|
||||||
|
|
||||||
@class Archetype
|
|
||||||
@extends Discourse.Model
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.Archetype = Discourse.Model.extend({
|
|
||||||
|
|
||||||
hasOptions: Em.computed.gt('options.length', 0),
|
|
||||||
|
|
||||||
site: function() {
|
|
||||||
return Discourse.Site.current();
|
|
||||||
}.property(),
|
|
||||||
|
|
||||||
isDefault: Discourse.computed.propertyEqual('id', 'site.default_archetype'),
|
|
||||||
notDefault: Em.computed.not('isDefault')
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
8
app/assets/javascripts/discourse/models/archetype.js.es6
Normal file
8
app/assets/javascripts/discourse/models/archetype.js.es6
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
|
import RestModel from 'discourse/models/rest';
|
||||||
|
|
||||||
|
export default RestModel.extend({
|
||||||
|
hasOptions: Em.computed.gt('options.length', 0),
|
||||||
|
isDefault: propertyEqual('id', 'site.default_archetype'),
|
||||||
|
notDefault: Em.computed.not('isDefault')
|
||||||
|
});
|
|
@ -1,11 +1,4 @@
|
||||||
/**
|
import { toTitleCase } from 'discourse/lib/formatter';
|
||||||
A data model representing a navigation item on the list views
|
|
||||||
|
|
||||||
@class NavItem
|
|
||||||
@extends Discourse.Model
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
|
|
||||||
const NavItem = Discourse.Model.extend({
|
const NavItem = Discourse.Model.extend({
|
||||||
|
|
||||||
|
@ -22,7 +15,7 @@ const NavItem = Discourse.Model.extend({
|
||||||
|
|
||||||
if (categoryName) {
|
if (categoryName) {
|
||||||
name = 'category';
|
name = 'category';
|
||||||
extra.categoryName = Discourse.Formatter.toTitleCase(categoryName);
|
extra.categoryName = toTitleCase(categoryName);
|
||||||
}
|
}
|
||||||
return I18n.t("filters." + name.replace("/", ".") + ".title", extra);
|
return I18n.t("filters." + name.replace("/", ".") + ".title", extra);
|
||||||
}.property('categoryName', 'name', 'count'),
|
}.property('categoryName', 'name', 'count'),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import RestModel from 'discourse/models/rest';
|
import RestModel from 'discourse/models/rest';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import ActionSummary from 'discourse/models/action-summary';
|
import ActionSummary from 'discourse/models/action-summary';
|
||||||
|
import { url, fmt, propertyEqual } from 'discourse/lib/computed';
|
||||||
|
|
||||||
const Post = RestModel.extend({
|
const Post = RestModel.extend({
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ const Post = RestModel.extend({
|
||||||
return (this.get('post_number') === 1) ? url + "/1" : url;
|
return (this.get('post_number') === 1) ? url + "/1" : url;
|
||||||
}.property('post_number', 'url'),
|
}.property('post_number', 'url'),
|
||||||
|
|
||||||
usernameUrl: Discourse.computed.url('username', '/users/%@'),
|
usernameUrl: url('username', '/users/%@'),
|
||||||
|
|
||||||
showUserReplyTab: function() {
|
showUserReplyTab: function() {
|
||||||
return this.get('reply_to_user') && (
|
return this.get('reply_to_user') && (
|
||||||
|
@ -66,9 +67,9 @@ const Post = RestModel.extend({
|
||||||
);
|
);
|
||||||
}.property('reply_to_user', 'reply_to_post_number', 'post_number'),
|
}.property('reply_to_user', 'reply_to_post_number', 'post_number'),
|
||||||
|
|
||||||
topicOwner: Discourse.computed.propertyEqual('topic.details.created_by.id', 'user_id'),
|
topicOwner: propertyEqual('topic.details.created_by.id', 'user_id'),
|
||||||
hasHistory: Em.computed.gt('version', 1),
|
hasHistory: Em.computed.gt('version', 1),
|
||||||
postElementId: Discourse.computed.fmt('post_number', 'post_%@'),
|
postElementId: fmt('post_number', 'post_%@'),
|
||||||
|
|
||||||
canViewRawEmail: function() {
|
canViewRawEmail: function() {
|
||||||
return this.get("user_id") === Discourse.User.currentProp("id") || Discourse.User.currentProp('staff');
|
return this.get("user_id") === Discourse.User.currentProp("id") || Discourse.User.currentProp('staff');
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
import RestModel from 'discourse/models/rest';
|
||||||
|
import Singleton from 'discourse/mixins/singleton';
|
||||||
|
|
||||||
// A data model representing current session data. You can put transient
|
// A data model representing current session data. You can put transient
|
||||||
// data here you might want later. It is not stored or serialized anywhere.
|
// data here you might want later. It is not stored or serialized anywhere.
|
||||||
var Session = Discourse.Model.extend({
|
const Session = RestModel.extend({
|
||||||
init: function() {
|
init: function() {
|
||||||
this.set('highestSeenByTopic', {});
|
this.set('highestSeenByTopic', {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Session.reopenClass(Discourse.Singleton);
|
Session.reopenClass(Singleton);
|
||||||
|
|
||||||
export default Session;
|
export default Session;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
import Archetype from 'discourse/models/archetype';
|
||||||
import PostActionType from 'discourse/models/post-action-type';
|
import PostActionType from 'discourse/models/post-action-type';
|
||||||
|
import Singleton from 'discourse/mixins/singleton';
|
||||||
|
|
||||||
const Site = Discourse.Model.extend({
|
const Site = Discourse.Model.extend({
|
||||||
|
|
||||||
|
@ -85,11 +87,11 @@ const Site = Discourse.Model.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Site.reopenClass(Discourse.Singleton, {
|
Site.reopenClass(Singleton, {
|
||||||
|
|
||||||
// The current singleton will retrieve its attributes from the `PreloadStore`.
|
// The current singleton will retrieve its attributes from the `PreloadStore`.
|
||||||
createCurrent() {
|
createCurrent() {
|
||||||
return Discourse.Site.create(PreloadStore.get('site'));
|
return Site.create(PreloadStore.get('site'));
|
||||||
},
|
},
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
|
@ -137,7 +139,8 @@ Site.reopenClass(Discourse.Singleton, {
|
||||||
|
|
||||||
if (result.archetypes) {
|
if (result.archetypes) {
|
||||||
result.archetypes = _.map(result.archetypes,function(a) {
|
result.archetypes = _.map(result.archetypes,function(a) {
|
||||||
return Discourse.Archetype.create(a);
|
a.site = result;
|
||||||
|
return Archetype.create(a);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { flushMap } from 'discourse/models/store';
|
import { flushMap } from 'discourse/models/store';
|
||||||
import RestModel from 'discourse/models/rest';
|
import RestModel from 'discourse/models/rest';
|
||||||
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
|
import { longDate } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
const Topic = RestModel.extend({
|
const Topic = RestModel.extend({
|
||||||
message: null,
|
message: null,
|
||||||
|
@ -20,8 +22,8 @@ const Topic = RestModel.extend({
|
||||||
}.property('bumped_at', 'createdAt'),
|
}.property('bumped_at', 'createdAt'),
|
||||||
|
|
||||||
bumpedAtTitle: function() {
|
bumpedAtTitle: function() {
|
||||||
return I18n.t('first_post') + ": " + Discourse.Formatter.longDate(this.get('createdAt')) + "\n" +
|
return I18n.t('first_post') + ": " + longDate(this.get('createdAt')) + "\n" +
|
||||||
I18n.t('last_post') + ": " + Discourse.Formatter.longDate(this.get('bumpedAt'));
|
I18n.t('last_post') + ": " + longDate(this.get('bumpedAt'));
|
||||||
}.property('bumpedAt'),
|
}.property('bumpedAt'),
|
||||||
|
|
||||||
createdAt: function() {
|
createdAt: function() {
|
||||||
|
@ -364,7 +366,7 @@ const Topic = RestModel.extend({
|
||||||
return( e && e.substr(e.length - 8,8) === '…' );
|
return( e && e.substr(e.length - 8,8) === '…' );
|
||||||
}.property('excerpt'),
|
}.property('excerpt'),
|
||||||
|
|
||||||
readLastPost: Discourse.computed.propertyEqual('last_read_post_number', 'highest_post_number'),
|
readLastPost: propertyEqual('last_read_post_number', 'highest_post_number'),
|
||||||
canClearPin: Em.computed.and('pinned', 'readLastPost')
|
canClearPin: Em.computed.and('pinned', 'readLastPost')
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import RestModel from 'discourse/models/rest';
|
||||||
|
import { fmt } from 'discourse/lib/computed';
|
||||||
|
|
||||||
|
export default RestModel.extend({
|
||||||
|
detailedName: fmt('id', 'name', '%@ - %@')
|
||||||
|
});
|
|
@ -1,11 +0,0 @@
|
||||||
/**
|
|
||||||
Represents a user's trust level in the system
|
|
||||||
|
|
||||||
@class TrustLevel
|
|
||||||
@extends Discourse.Model
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.TrustLevel = Discourse.Model.extend({
|
|
||||||
detailedName: Discourse.computed.fmt('id', 'name', '%@ - %@')
|
|
||||||
});
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import RestModel from 'discourse/models/rest';
|
||||||
|
import UserAction from 'discourse/models/user-action';
|
||||||
|
import { i18n } from 'discourse/lib/computed';
|
||||||
|
|
||||||
|
export default RestModel.extend({
|
||||||
|
|
||||||
|
isPM: function() {
|
||||||
|
const actionType = this.get('action_type');
|
||||||
|
return actionType === UserAction.TYPES.messages_sent ||
|
||||||
|
actionType === UserAction.TYPES.messages_received;
|
||||||
|
}.property('action_type'),
|
||||||
|
|
||||||
|
description: i18n('action_type', 'user_action_groups.%@'),
|
||||||
|
|
||||||
|
isResponse: function() {
|
||||||
|
const actionType = this.get('action_type');
|
||||||
|
return actionType === UserAction.TYPES.replies ||
|
||||||
|
actionType === UserAction.TYPES.quotes;
|
||||||
|
}.property('action_type')
|
||||||
|
|
||||||
|
});
|
|
@ -1,39 +1,37 @@
|
||||||
var UserActionTypes = {
|
import RestModel from 'discourse/models/rest';
|
||||||
likes_given: 1,
|
import { url } from 'discourse/lib/computed';
|
||||||
likes_received: 2,
|
|
||||||
bookmarks: 3,
|
const UserActionTypes = {
|
||||||
topics: 4,
|
likes_given: 1,
|
||||||
posts: 5,
|
likes_received: 2,
|
||||||
replies: 6,
|
bookmarks: 3,
|
||||||
mentions: 7,
|
topics: 4,
|
||||||
quotes: 9,
|
posts: 5,
|
||||||
edits: 11,
|
replies: 6,
|
||||||
messages_sent: 12,
|
mentions: 7,
|
||||||
messages_received: 13,
|
quotes: 9,
|
||||||
pending: 14
|
edits: 11,
|
||||||
},
|
messages_sent: 12,
|
||||||
InvertedActionTypes = {};
|
messages_received: 13,
|
||||||
|
pending: 14
|
||||||
|
};
|
||||||
|
const InvertedActionTypes = {};
|
||||||
|
|
||||||
_.each(UserActionTypes, function (k, v) {
|
_.each(UserActionTypes, function (k, v) {
|
||||||
InvertedActionTypes[k] = v;
|
InvertedActionTypes[k] = v;
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.UserAction = Discourse.Model.extend({
|
const UserAction = RestModel.extend({
|
||||||
|
|
||||||
_attachCategory: function() {
|
_attachCategory: function() {
|
||||||
var categoryId = this.get('category_id');
|
const categoryId = this.get('category_id');
|
||||||
if (categoryId) {
|
if (categoryId) {
|
||||||
this.set('category', Discourse.Category.findById(categoryId));
|
this.set('category', Discourse.Category.findById(categoryId));
|
||||||
}
|
}
|
||||||
}.on('init'),
|
}.on('init'),
|
||||||
|
|
||||||
/**
|
|
||||||
Return an i18n key we will use for the description text of a user action.
|
|
||||||
|
|
||||||
@property descriptionKey
|
|
||||||
**/
|
|
||||||
descriptionKey: function() {
|
descriptionKey: function() {
|
||||||
var action = this.get('action_type');
|
const action = this.get('action_type');
|
||||||
if (action === null || Discourse.UserAction.TO_SHOW.indexOf(action) >= 0) {
|
if (action === null || Discourse.UserAction.TO_SHOW.indexOf(action) >= 0) {
|
||||||
if (this.get('isPM')) {
|
if (this.get('isPM')) {
|
||||||
return this.get('sameUser') ? 'sent_by_you' : 'sent_by_user';
|
return this.get('sameUser') ? 'sent_by_you' : 'sent_by_user';
|
||||||
|
@ -74,13 +72,13 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||||
presentName: Em.computed.any('name', 'username'),
|
presentName: Em.computed.any('name', 'username'),
|
||||||
targetDisplayName: Em.computed.any('target_name', 'target_username'),
|
targetDisplayName: Em.computed.any('target_name', 'target_username'),
|
||||||
actingDisplayName: Em.computed.any('acting_name', 'acting_username'),
|
actingDisplayName: Em.computed.any('acting_name', 'acting_username'),
|
||||||
targetUserUrl: Discourse.computed.url('target_username', '/users/%@'),
|
targetUserUrl: url('target_username', '/users/%@'),
|
||||||
|
|
||||||
usernameLower: function() {
|
usernameLower: function() {
|
||||||
return this.get('username').toLowerCase();
|
return this.get('username').toLowerCase();
|
||||||
}.property('username'),
|
}.property('username'),
|
||||||
|
|
||||||
userUrl: Discourse.computed.url('usernameLower', '/users/%@'),
|
userUrl: url('usernameLower', '/users/%@'),
|
||||||
|
|
||||||
postUrl: function() {
|
postUrl: function() {
|
||||||
return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('post_number'));
|
return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('post_number'));
|
||||||
|
@ -102,7 +100,7 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||||
removableBookmark: Em.computed.and('bookmarkType', 'sameUser'),
|
removableBookmark: Em.computed.and('bookmarkType', 'sameUser'),
|
||||||
|
|
||||||
addChild: function(action) {
|
addChild: function(action) {
|
||||||
var groups = this.get("childGroups");
|
let groups = this.get("childGroups");
|
||||||
if (!groups) {
|
if (!groups) {
|
||||||
groups = {
|
groups = {
|
||||||
likes: Discourse.UserActionGroup.create({ icon: "fa fa-heart" }),
|
likes: Discourse.UserActionGroup.create({ icon: "fa fa-heart" }),
|
||||||
|
@ -113,7 +111,7 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||||
}
|
}
|
||||||
this.set("childGroups", groups);
|
this.set("childGroups", groups);
|
||||||
|
|
||||||
var bucket = (function() {
|
const bucket = (function() {
|
||||||
switch (action.action_type) {
|
switch (action.action_type) {
|
||||||
case UserActionTypes.likes_given:
|
case UserActionTypes.likes_given:
|
||||||
case UserActionTypes.likes_received:
|
case UserActionTypes.likes_received:
|
||||||
|
@ -124,15 +122,15 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||||
return "bookmarks";
|
return "bookmarks";
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
var current = groups[bucket];
|
const current = groups[bucket];
|
||||||
if (current) {
|
if (current) {
|
||||||
current.push(action);
|
current.push(action);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
children: function() {
|
children: function() {
|
||||||
var g = this.get("childGroups");
|
const g = this.get("childGroups");
|
||||||
var rval = [];
|
let rval = [];
|
||||||
if (g) {
|
if (g) {
|
||||||
rval = [g.likes, g.stars, g.edits, g.bookmarks].filter(function(i) {
|
rval = [g.likes, g.stars, g.edits, g.bookmarks].filter(function(i) {
|
||||||
return i.get("items") && i.get("items").length > 0;
|
return i.get("items") && i.get("items").length > 0;
|
||||||
|
@ -154,20 +152,20 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.UserAction.reopenClass({
|
UserAction.reopenClass({
|
||||||
collapseStream: function(stream) {
|
collapseStream: function(stream) {
|
||||||
var uniq = {},
|
const uniq = {};
|
||||||
collapsed = [],
|
const collapsed = [];
|
||||||
pos = 0;
|
let pos = 0;
|
||||||
|
|
||||||
stream.forEach(function(item) {
|
stream.forEach(function(item) {
|
||||||
var key = "" + item.topic_id + "-" + item.post_number;
|
const key = "" + item.topic_id + "-" + item.post_number;
|
||||||
var found = uniq[key];
|
const found = uniq[key];
|
||||||
if (found === void 0) {
|
if (found === void 0) {
|
||||||
|
|
||||||
var current;
|
let current;
|
||||||
if (Discourse.UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) {
|
if (Discourse.UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) {
|
||||||
current = Discourse.UserAction.create(item);
|
current = UserAction.create(item);
|
||||||
item.switchToActing();
|
item.switchToActing();
|
||||||
current.addChild(item);
|
current.addChild(item);
|
||||||
} else {
|
} else {
|
||||||
|
@ -177,7 +175,7 @@ Discourse.UserAction.reopenClass({
|
||||||
collapsed[pos] = current;
|
collapsed[pos] = current;
|
||||||
pos += 1;
|
pos += 1;
|
||||||
} else {
|
} else {
|
||||||
if (Discourse.UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) {
|
if (UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) {
|
||||||
item.switchToActing();
|
item.switchToActing();
|
||||||
collapsed[found].addChild(item);
|
collapsed[found].addChild(item);
|
||||||
} else {
|
} else {
|
||||||
|
@ -208,3 +206,5 @@ Discourse.UserAction.reopenClass({
|
||||||
]
|
]
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default UserAction;
|
|
@ -1,12 +1,7 @@
|
||||||
/**
|
import { url } from 'discourse/lib/computed';
|
||||||
Represents a user's stream
|
import AdminPost from 'discourse/models/admin-post';
|
||||||
|
|
||||||
@class UserPostsStream
|
export default Discourse.Model.extend({
|
||||||
@extends Discourse.Model
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.UserPostsStream = Discourse.Model.extend({
|
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
|
||||||
_initialize: function () {
|
_initialize: function () {
|
||||||
|
@ -17,9 +12,9 @@ Discourse.UserPostsStream = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
}.on("init"),
|
}.on("init"),
|
||||||
|
|
||||||
url: Discourse.computed.url("user.username_lower", "filter", "itemsLoaded", "/posts/%@/%@?offset=%@"),
|
url: url("user.username_lower", "filter", "itemsLoaded", "/posts/%@/%@?offset=%@"),
|
||||||
|
|
||||||
filterBy: function (filter) {
|
filterBy(filter) {
|
||||||
if (this.get("loaded") && this.get("filter") === filter) { return Ember.RSVP.resolve(); }
|
if (this.get("loaded") && this.get("filter") === filter) { return Ember.RSVP.resolve(); }
|
||||||
|
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
|
@ -32,15 +27,15 @@ Discourse.UserPostsStream = Discourse.Model.extend({
|
||||||
return this.findItems();
|
return this.findItems();
|
||||||
},
|
},
|
||||||
|
|
||||||
findItems: function () {
|
findItems() {
|
||||||
var self = this;
|
const self = this;
|
||||||
if (this.get("loading") || !this.get("canLoadMore")) { return Ember.RSVP.reject(); }
|
if (this.get("loading") || !this.get("canLoadMore")) { return Ember.RSVP.reject(); }
|
||||||
|
|
||||||
this.set("loading", true);
|
this.set("loading", true);
|
||||||
|
|
||||||
return Discourse.ajax(this.get("url"), { cache: false }).then(function (result) {
|
return Discourse.ajax(this.get("url"), { cache: false }).then(function (result) {
|
||||||
if (result) {
|
if (result) {
|
||||||
var posts = result.map(function (post) { return Discourse.AdminPost.create(post); });
|
const posts = result.map(function (post) { return AdminPost.create(post); });
|
||||||
self.get("content").pushObjects(posts);
|
self.get("content").pushObjects(posts);
|
||||||
self.setProperties({
|
self.setProperties({
|
||||||
loaded: true,
|
loaded: true,
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { url } from 'discourse/lib/computed';
|
||||||
import RestModel from 'discourse/models/rest';
|
import RestModel from 'discourse/models/rest';
|
||||||
|
|
||||||
export default RestModel.extend({
|
export default RestModel.extend({
|
||||||
|
@ -22,7 +23,7 @@ export default RestModel.extend({
|
||||||
return filter;
|
return filter;
|
||||||
}.property('filter'),
|
}.property('filter'),
|
||||||
|
|
||||||
baseUrl: Discourse.computed.url('itemsLoaded', 'user.username_lower', '/user_actions.json?offset=%@&username=%@'),
|
baseUrl: url('itemsLoaded', 'user.username_lower', '/user_actions.json?offset=%@&username=%@'),
|
||||||
|
|
||||||
filterBy(filter) {
|
filterBy(filter) {
|
||||||
this.setProperties({ filter, itemsLoaded: 0, content: [], lastLoadedUrl: null });
|
this.setProperties({ filter, itemsLoaded: 0, content: [], lastLoadedUrl: null });
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
|
import { url } from 'discourse/lib/computed';
|
||||||
import RestModel from 'discourse/models/rest';
|
import RestModel from 'discourse/models/rest';
|
||||||
import avatarTemplate from 'discourse/lib/avatar-template';
|
import avatarTemplate from 'discourse/lib/avatar-template';
|
||||||
|
import UserStream from 'discourse/models/user-stream';
|
||||||
|
import UserPostsStream from 'discourse/models/user-posts-stream';
|
||||||
|
import Singleton from 'discourse/mixins/singleton';
|
||||||
|
import { longDate } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
const User = RestModel.extend({
|
const User = RestModel.extend({
|
||||||
|
|
||||||
|
@ -10,24 +15,12 @@ const User = RestModel.extend({
|
||||||
hasNotPosted: Em.computed.not("hasPosted"),
|
hasNotPosted: Em.computed.not("hasPosted"),
|
||||||
canBeDeleted: Em.computed.and("can_be_deleted", "hasNotPosted"),
|
canBeDeleted: Em.computed.and("can_be_deleted", "hasNotPosted"),
|
||||||
|
|
||||||
/**
|
|
||||||
The user's stream
|
|
||||||
|
|
||||||
@property stream
|
|
||||||
@type {Discourse.UserStream}
|
|
||||||
**/
|
|
||||||
stream: function() {
|
stream: function() {
|
||||||
return Discourse.UserStream.create({ user: this });
|
return UserStream.create({ user: this });
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
/**
|
|
||||||
The user's posts stream
|
|
||||||
|
|
||||||
@property postsStream
|
|
||||||
@type {Discourse.UserPostsStream}
|
|
||||||
**/
|
|
||||||
postsStream: function() {
|
postsStream: function() {
|
||||||
return Discourse.UserPostsStream.create({ user: this });
|
return UserPostsStream.create({ user: this });
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +82,7 @@ const User = RestModel.extend({
|
||||||
@property adminPath
|
@property adminPath
|
||||||
@type {String}
|
@type {String}
|
||||||
**/
|
**/
|
||||||
adminPath: Discourse.computed.url('username_lower', "/admin/users/%@"),
|
adminPath: url('username_lower', "/admin/users/%@"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This user's username in lowercase.
|
This user's username in lowercase.
|
||||||
|
@ -123,7 +116,7 @@ const User = RestModel.extend({
|
||||||
}.property('suspended_till'),
|
}.property('suspended_till'),
|
||||||
|
|
||||||
suspendedTillDate: function() {
|
suspendedTillDate: function() {
|
||||||
return Discourse.Formatter.longDate(this.get('suspended_till'));
|
return longDate(this.get('suspended_till'));
|
||||||
}.property('suspended_till'),
|
}.property('suspended_till'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -434,15 +427,15 @@ const User = RestModel.extend({
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
User.reopenClass(Discourse.Singleton, {
|
User.reopenClass(Singleton, {
|
||||||
|
|
||||||
// Find a `Discourse.User` for a given username.
|
// Find a `Discourse.User` for a given username.
|
||||||
findByUsername: function(username, options) {
|
findByUsername: function(username, options) {
|
||||||
const user = Discourse.User.create({username: username});
|
const user = User.create({username: username});
|
||||||
return user.findDetails(options);
|
return user.findDetails(options);
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Use app.register and junk Discourse.Singleton
|
// TODO: Use app.register and junk Singleton
|
||||||
createCurrent: function() {
|
createCurrent: function() {
|
||||||
var userJson = PreloadStore.get('currentUser');
|
var userJson = PreloadStore.get('currentUser');
|
||||||
if (userJson) {
|
if (userJson) {
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
/**
|
|
||||||
A data model representing a statistic on a UserAction
|
|
||||||
|
|
||||||
@class UserActionStat
|
|
||||||
@extends Discourse.Model
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.UserActionStat = Discourse.Model.extend({
|
|
||||||
|
|
||||||
isPM: function() {
|
|
||||||
var actionType = this.get('action_type');
|
|
||||||
return actionType === Discourse.UserAction.TYPES.messages_sent ||
|
|
||||||
actionType === Discourse.UserAction.TYPES.messages_received;
|
|
||||||
}.property('action_type'),
|
|
||||||
|
|
||||||
description: Discourse.computed.i18n('action_type', 'user_action_groups.%@'),
|
|
||||||
|
|
||||||
isResponse: function() {
|
|
||||||
var actionType = this.get('action_type');
|
|
||||||
return actionType === Discourse.UserAction.TYPES.replies ||
|
|
||||||
actionType === Discourse.UserAction.TYPES.quotes;
|
|
||||||
}.property('action_type')
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
import showModal from 'discourse/lib/show-modal';
|
import showModal from 'discourse/lib/show-modal';
|
||||||
import OpenComposer from "discourse/mixins/open-composer";
|
import OpenComposer from "discourse/mixins/open-composer";
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ function unlessReadOnly(method) {
|
||||||
|
|
||||||
const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
|
const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
|
||||||
|
|
||||||
siteTitle: Discourse.computed.setting('title'),
|
siteTitle: setting('title'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
_collectTitleTokens(tokens) {
|
_collectTitleTokens(tokens) {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import ScreenTrack from 'discourse/lib/screen-track';
|
||||||
import { queryParams } from 'discourse/controllers/discovery-sortable';
|
import { queryParams } from 'discourse/controllers/discovery-sortable';
|
||||||
|
|
||||||
// A helper to build a topic route for a filter
|
// A helper to build a topic route for a filter
|
||||||
|
@ -82,7 +83,7 @@ export default function(filter, extras) {
|
||||||
|
|
||||||
model(data, transition) {
|
model(data, transition) {
|
||||||
// attempt to stop early cause we need this to be called before .sync
|
// attempt to stop early cause we need this to be called before .sync
|
||||||
Discourse.ScreenTrack.current().stop();
|
ScreenTrack.current().stop();
|
||||||
|
|
||||||
const findOpts = filterQueryParams(transition.queryParams),
|
const findOpts = filterQueryParams(transition.queryParams),
|
||||||
extras = { cached: this.isPoppedState(transition) };
|
extras = { cached: this.isPoppedState(transition) };
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import ScreenTrack from 'discourse/lib/screen-track';
|
||||||
|
|
||||||
let isTransitioning = false,
|
let isTransitioning = false,
|
||||||
scheduledReplace = null,
|
scheduledReplace = null,
|
||||||
lastScrollPos = null;
|
lastScrollPos = null;
|
||||||
|
@ -185,7 +187,7 @@ const TopicRoute = Discourse.Route.extend({
|
||||||
topicController.set('multiSelect', false);
|
topicController.set('multiSelect', false);
|
||||||
topicController.unsubscribe();
|
topicController.unsubscribe();
|
||||||
this.controllerFor('composer').set('topic', null);
|
this.controllerFor('composer').set('topic', null);
|
||||||
Discourse.ScreenTrack.current().stop();
|
ScreenTrack.current().stop();
|
||||||
|
|
||||||
const headerController = this.controllerFor('header');
|
const headerController = this.controllerFor('header');
|
||||||
if (headerController) {
|
if (headerController) {
|
||||||
|
@ -226,7 +228,7 @@ const TopicRoute = Discourse.Route.extend({
|
||||||
|
|
||||||
this.controllerFor('topic-progress').set('model', model);
|
this.controllerFor('topic-progress').set('model', model);
|
||||||
// We reset screen tracking every time a topic is entered
|
// We reset screen tracking every time a topic is entered
|
||||||
Discourse.ScreenTrack.current().start(model.get('id'), controller);
|
ScreenTrack.current().start(model.get('id'), controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{{#each p in model.content}}
|
{{#each p in model.content}}
|
||||||
<div {{bind-attr class=":item p.hidden p.deleted moderator_action"}}>
|
<div {{bind-attr class=":item p.hidden p.deleted p.moderator_action"}}>
|
||||||
<div class="clearfix info">
|
<div class="clearfix info">
|
||||||
<a href="{{unbound p.usernameUrl}}" class="avatar-link">
|
<a href="{{unbound p.usernameUrl}}" class="avatar-link">
|
||||||
<div class="avatar-wrapper">
|
<div class="avatar-wrapper">
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
|
import ScreenTrack from 'discourse/lib/screen-track';
|
||||||
|
|
||||||
export default Discourse.GroupedView.extend({
|
export default Discourse.GroupedView.extend({
|
||||||
templateName: 'embedded-post',
|
templateName: 'embedded-post',
|
||||||
classNames: ['reply'],
|
classNames: ['reply'],
|
||||||
|
|
||||||
_startTracking: function() {
|
_startTracking: function() {
|
||||||
const post = this.get('content');
|
const post = this.get('content');
|
||||||
Discourse.ScreenTrack.current().track(this.get('elementId'), post.get('post_number'));
|
ScreenTrack.current().track(this.get('elementId'), post.get('post_number'));
|
||||||
}.on('didInsertElement'),
|
}.on('didInsertElement'),
|
||||||
|
|
||||||
_stopTracking: function() {
|
_stopTracking: function() {
|
||||||
Discourse.ScreenTrack.current().stopTracking(this.get('elementId'));
|
ScreenTrack.current().stopTracking(this.get('elementId'));
|
||||||
}.on('willDestroyElement')
|
}.on('willDestroyElement')
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { fmt } from 'discourse/lib/computed';
|
||||||
|
|
||||||
export default Ember.Object.extend({
|
export default Ember.Object.extend({
|
||||||
tagName: "td",
|
tagName: "td",
|
||||||
ratio: function() {
|
ratio: function() {
|
||||||
|
@ -26,6 +28,6 @@ export default Ember.Object.extend({
|
||||||
return '';
|
return '';
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
likesHeat: Discourse.computed.fmt('ratioText', 'heatmap-%@'),
|
likesHeat: fmt('ratioText', 'heatmap-%@'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import ScreenTrack from 'discourse/lib/screen-track';
|
||||||
|
import { number } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
const DAY = 60 * 50 * 1000;
|
const DAY = 60 * 50 * 1000;
|
||||||
|
|
||||||
const PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
const PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
||||||
|
@ -178,7 +181,7 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
||||||
// don't display badge counts on category badge & oneboxes (unless when explicitely stated)
|
// don't display badge counts on category badge & oneboxes (unless when explicitely stated)
|
||||||
if ($link.hasClass("track-link") ||
|
if ($link.hasClass("track-link") ||
|
||||||
$link.closest('.badge-category,.onebox-result,.onebox-body').length === 0) {
|
$link.closest('.badge-category,.onebox-result,.onebox-body').length === 0) {
|
||||||
$link.append("<span class='badge badge-notification clicks' title='" + I18n.t("topic_map.clicks", {count: lc.clicks}) + "'>" + Discourse.Formatter.number(lc.clicks) + "</span>");
|
$link.append("<span class='badge badge-notification clicks' title='" + I18n.t("topic_map.clicks", {count: lc.clicks}) + "'>" + number(lc.clicks) + "</span>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -263,7 +266,7 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
||||||
},
|
},
|
||||||
|
|
||||||
_destroyedPostView: function() {
|
_destroyedPostView: function() {
|
||||||
Discourse.ScreenTrack.current().stopTracking(this.get('elementId'));
|
ScreenTrack.current().stopTracking(this.get('elementId'));
|
||||||
}.on('willDestroyElement'),
|
}.on('willDestroyElement'),
|
||||||
|
|
||||||
_postViewInserted: function() {
|
_postViewInserted: function() {
|
||||||
|
@ -272,7 +275,7 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
||||||
|
|
||||||
this._showLinkCounts();
|
this._showLinkCounts();
|
||||||
|
|
||||||
Discourse.ScreenTrack.current().track($post.prop('id'), postNumber);
|
ScreenTrack.current().track($post.prop('id'), postNumber);
|
||||||
|
|
||||||
this.trigger('postViewInserted', $post);
|
this.trigger('postViewInserted', $post);
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,9 @@ import AddArchetypeClass from 'discourse/mixins/add-archetype-class';
|
||||||
import ClickTrack from 'discourse/lib/click-track';
|
import ClickTrack from 'discourse/lib/click-track';
|
||||||
import { listenForViewEvent } from 'discourse/lib/app-events';
|
import { listenForViewEvent } from 'discourse/lib/app-events';
|
||||||
import { categoryBadgeHTML } from 'discourse/helpers/category-link';
|
import { categoryBadgeHTML } from 'discourse/helpers/category-link';
|
||||||
|
import Scrolling from 'discourse/mixins/scrolling';
|
||||||
|
|
||||||
const TopicView = Discourse.View.extend(AddCategoryClass, AddArchetypeClass, Discourse.Scrolling, {
|
const TopicView = Discourse.View.extend(AddCategoryClass, AddArchetypeClass, Scrolling, {
|
||||||
templateName: 'topic',
|
templateName: 'topic',
|
||||||
topicBinding: 'controller.model',
|
topicBinding: 'controller.model',
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { setting } from 'discourse/lib/computed';
|
||||||
import CleansUp from 'discourse/mixins/cleans-up';
|
import CleansUp from 'discourse/mixins/cleans-up';
|
||||||
|
|
||||||
import afterTransition from 'discourse/lib/after-transition';
|
import afterTransition from 'discourse/lib/after-transition';
|
||||||
|
|
||||||
const clickOutsideEventName = "mousedown.outside-user-card",
|
const clickOutsideEventName = "mousedown.outside-user-card",
|
||||||
|
@ -9,7 +9,7 @@ const clickOutsideEventName = "mousedown.outside-user-card",
|
||||||
export default Discourse.View.extend(CleansUp, {
|
export default Discourse.View.extend(CleansUp, {
|
||||||
elementId: 'user-card',
|
elementId: 'user-card',
|
||||||
classNameBindings: ['controller.visible:show', 'controller.showBadges', 'controller.hasCardBadgeImage'],
|
classNameBindings: ['controller.visible:show', 'controller.showBadges', 'controller.hasCardBadgeImage'],
|
||||||
allowBackgrounds: Discourse.computed.setting('allow_profile_backgrounds'),
|
allowBackgrounds: setting('allow_profile_backgrounds'),
|
||||||
|
|
||||||
addBackground: function() {
|
addBackground: function() {
|
||||||
const url = this.get('controller.user.card_background');
|
const url = this.get('controller.user.card_background');
|
||||||
|
|
|
@ -8,10 +8,14 @@
|
||||||
//= require ./discourse/lib/load-script
|
//= require ./discourse/lib/load-script
|
||||||
//= require ./discourse/lib/notification-levels
|
//= require ./discourse/lib/notification-levels
|
||||||
//= require ./discourse/lib/app-events
|
//= require ./discourse/lib/app-events
|
||||||
|
//= require ./discourse/lib/avatar-template
|
||||||
//= require ./discourse/helpers/i18n
|
//= require ./discourse/helpers/i18n
|
||||||
//= require ./discourse/helpers/fa-icon
|
//= require ./discourse/helpers/fa-icon
|
||||||
|
//= require ./discourse/helpers/register-unbound
|
||||||
//= require ./discourse/lib/ember_compat_handlebars
|
//= require ./discourse/lib/ember_compat_handlebars
|
||||||
//= require ./discourse/lib/computed
|
//= require ./discourse/lib/computed
|
||||||
|
//= require ./discourse/lib/formatter
|
||||||
|
//= require ./discourse/lib/eyeline
|
||||||
//= require ./discourse/helpers/register-unbound
|
//= require ./discourse/helpers/register-unbound
|
||||||
//= require ./discourse/mixins/scrolling
|
//= require ./discourse/mixins/scrolling
|
||||||
//= require_tree ./discourse/mixins
|
//= require_tree ./discourse/mixins
|
||||||
|
@ -36,7 +40,7 @@
|
||||||
//= require ./discourse/models/post-stream
|
//= require ./discourse/models/post-stream
|
||||||
//= require ./discourse/models/topic-details
|
//= require ./discourse/models/topic-details
|
||||||
//= require ./discourse/models/topic
|
//= require ./discourse/models/topic
|
||||||
//= require ./discourse/models/user_action
|
//= require ./discourse/models/user-action
|
||||||
//= require ./discourse/models/composer
|
//= require ./discourse/models/composer
|
||||||
//= require ./discourse/controllers/controller
|
//= require ./discourse/controllers/controller
|
||||||
//= require ./discourse/controllers/discovery-sortable
|
//= require ./discourse/controllers/discovery-sortable
|
||||||
|
@ -58,6 +62,7 @@
|
||||||
//= require ./discourse/lib/link-mentions
|
//= require ./discourse/lib/link-mentions
|
||||||
//= require ./discourse/views/composer
|
//= require ./discourse/views/composer
|
||||||
//= require ./discourse/lib/show-modal
|
//= require ./discourse/lib/show-modal
|
||||||
|
//= require ./discourse/lib/screen-track
|
||||||
//= require ./discourse/routes/discourse
|
//= require ./discourse/routes/discourse
|
||||||
//= require ./discourse/routes/build-topic-route
|
//= require ./discourse/routes/build-topic-route
|
||||||
//= require ./discourse/routes/restricted-user
|
//= require ./discourse/routes/restricted-user
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
moduleFor('controller:admin-user-badges', 'Admin User Badges Controller', {
|
moduleFor('controller:admin-user-badges', {
|
||||||
needs: ['controller:adminUser']
|
needs: ['controller:adminUser']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ function setTemplates(lookupTemplateStrings) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module("Resolver", {
|
module("lib:resolver", {
|
||||||
setup: function() {
|
setup: function() {
|
||||||
originalTemplates = Ember.TEMPLATES;
|
originalTemplates = Ember.TEMPLATES;
|
||||||
Ember.TEMPLATES = {};
|
Ember.TEMPLATES = {};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import avatarTemplate from 'discourse/lib/avatar-template';
|
import avatarTemplate from 'discourse/lib/avatar-template';
|
||||||
|
|
||||||
module('avatarTemplate');
|
module('lib:avatar-template');
|
||||||
|
|
||||||
test("avatarTemplate", function(){
|
test("avatarTemplate", function(){
|
||||||
var oldCDN = Discourse.CDN;
|
var oldCDN = Discourse.CDN;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module("categoryBadgeHTML");
|
module("lib:category-link");
|
||||||
|
|
||||||
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ var windowOpen,
|
||||||
win,
|
win,
|
||||||
redirectTo;
|
redirectTo;
|
||||||
|
|
||||||
module("ClickTrack", {
|
module("lib:click-track", {
|
||||||
setup: function() {
|
setup: function() {
|
||||||
|
|
||||||
// Prevent any of these tests from navigating away
|
// Prevent any of these tests from navigating away
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
module("Discourse.Computed", {
|
import { setting, propertyEqual, propertyNotEqual, fmt, i18n, url } from 'discourse/lib/computed';
|
||||||
|
|
||||||
|
module("lib:computed", {
|
||||||
setup: function() {
|
setup: function() {
|
||||||
sandbox.stub(I18n, "t", function(scope) {
|
sandbox.stub(I18n, "t", function(scope) {
|
||||||
return "%@ translated: " + scope;
|
return "%@ translated: " + scope;
|
||||||
|
@ -12,8 +14,8 @@ module("Discourse.Computed", {
|
||||||
|
|
||||||
test("setting", function() {
|
test("setting", function() {
|
||||||
var t = Em.Object.extend({
|
var t = Em.Object.extend({
|
||||||
vehicle: Discourse.computed.setting('vehicle'),
|
vehicle: setting('vehicle'),
|
||||||
missingProp: Discourse.computed.setting('madeUpThing')
|
missingProp: setting('madeUpThing')
|
||||||
}).create();
|
}).create();
|
||||||
|
|
||||||
Discourse.SiteSettings.vehicle = "airplane";
|
Discourse.SiteSettings.vehicle = "airplane";
|
||||||
|
@ -23,7 +25,7 @@ test("setting", function() {
|
||||||
|
|
||||||
test("propertyEqual", function() {
|
test("propertyEqual", function() {
|
||||||
var t = Em.Object.extend({
|
var t = Em.Object.extend({
|
||||||
same: Discourse.computed.propertyEqual('cookies', 'biscuits')
|
same: propertyEqual('cookies', 'biscuits')
|
||||||
}).create({
|
}).create({
|
||||||
cookies: 10,
|
cookies: 10,
|
||||||
biscuits: 10
|
biscuits: 10
|
||||||
|
@ -36,7 +38,7 @@ test("propertyEqual", function() {
|
||||||
|
|
||||||
test("propertyNotEqual", function() {
|
test("propertyNotEqual", function() {
|
||||||
var t = Em.Object.extend({
|
var t = Em.Object.extend({
|
||||||
diff: Discourse.computed.propertyNotEqual('cookies', 'biscuits')
|
diff: propertyNotEqual('cookies', 'biscuits')
|
||||||
}).create({
|
}).create({
|
||||||
cookies: 10,
|
cookies: 10,
|
||||||
biscuits: 10
|
biscuits: 10
|
||||||
|
@ -50,8 +52,8 @@ test("propertyNotEqual", function() {
|
||||||
|
|
||||||
test("fmt", function() {
|
test("fmt", function() {
|
||||||
var t = Em.Object.extend({
|
var t = Em.Object.extend({
|
||||||
exclaimyUsername: Discourse.computed.fmt('username', "!!! %@ !!!"),
|
exclaimyUsername: fmt('username', "!!! %@ !!!"),
|
||||||
multiple: Discourse.computed.fmt('username', 'mood', "%@ is %@")
|
multiple: fmt('username', 'mood', "%@ is %@")
|
||||||
}).create({
|
}).create({
|
||||||
username: 'eviltrout',
|
username: 'eviltrout',
|
||||||
mood: "happy"
|
mood: "happy"
|
||||||
|
@ -69,8 +71,8 @@ test("fmt", function() {
|
||||||
|
|
||||||
test("i18n", function() {
|
test("i18n", function() {
|
||||||
var t = Em.Object.extend({
|
var t = Em.Object.extend({
|
||||||
exclaimyUsername: Discourse.computed.i18n('username', "!!! %@ !!!"),
|
exclaimyUsername: i18n('username', "!!! %@ !!!"),
|
||||||
multiple: Discourse.computed.i18n('username', 'mood', "%@ is %@")
|
multiple: i18n('username', 'mood', "%@ is %@")
|
||||||
}).create({
|
}).create({
|
||||||
username: 'eviltrout',
|
username: 'eviltrout',
|
||||||
mood: "happy"
|
mood: "happy"
|
||||||
|
@ -90,7 +92,7 @@ test("url", function() {
|
||||||
var t, testClass;
|
var t, testClass;
|
||||||
|
|
||||||
testClass = Em.Object.extend({
|
testClass = Em.Object.extend({
|
||||||
userUrl: Discourse.computed.url('username', "/users/%@")
|
userUrl: url('username', "/users/%@")
|
||||||
});
|
});
|
||||||
|
|
||||||
t = testClass.create({ username: 'eviltrout' });
|
t = testClass.create({ username: 'eviltrout' });
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
var clock;
|
var clock;
|
||||||
|
|
||||||
module("Discourse.Formatter", {
|
import { relativeAge, autoUpdatingRelativeAge, updateRelativeAge, breakUp, number } from 'discourse/lib/formatter';
|
||||||
|
|
||||||
|
module("lib:formatter", {
|
||||||
setup: function() {
|
setup: function() {
|
||||||
clock = sinon.useFakeTimers(new Date(2012,11,31,12,0).getTime());
|
clock = sinon.useFakeTimers(new Date(2012,11,31,12,0).getTime());
|
||||||
},
|
},
|
||||||
|
@ -17,7 +19,7 @@ var mins_ago = function(mins){
|
||||||
};
|
};
|
||||||
|
|
||||||
var formatMins = function(mins) {
|
var formatMins = function(mins) {
|
||||||
return Discourse.Formatter.relativeAge(mins_ago(mins), {format: format, leaveAgo: leaveAgo});
|
return relativeAge(mins_ago(mins), {format: format, leaveAgo: leaveAgo});
|
||||||
};
|
};
|
||||||
|
|
||||||
var formatHours = function(hours) {
|
var formatHours = function(hours) {
|
||||||
|
@ -141,26 +143,24 @@ test("formating tiny dates", function() {
|
||||||
Discourse.SiteSettings.relative_date_duration = originalValue;
|
Discourse.SiteSettings.relative_date_duration = originalValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
module("Discourse.Formatter");
|
|
||||||
|
|
||||||
test("autoUpdatingRelativeAge", function() {
|
test("autoUpdatingRelativeAge", function() {
|
||||||
var d = moment().subtract(1, 'day').toDate();
|
var d = moment().subtract(1, 'day').toDate();
|
||||||
|
|
||||||
var $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d));
|
var $elem = $(autoUpdatingRelativeAge(d));
|
||||||
equal($elem.data('format'), "tiny");
|
equal($elem.data('format'), "tiny");
|
||||||
equal($elem.data('time'), d.getTime());
|
equal($elem.data('time'), d.getTime());
|
||||||
equal($elem.attr('title'), undefined);
|
equal($elem.attr('title'), undefined);
|
||||||
|
|
||||||
$elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d, {title: true}));
|
$elem = $(autoUpdatingRelativeAge(d, {title: true}));
|
||||||
equal($elem.attr('title'), moment(d).longDate());
|
equal($elem.attr('title'), moment(d).longDate());
|
||||||
|
|
||||||
$elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d,{format: 'medium', title: true, leaveAgo: true}));
|
$elem = $(autoUpdatingRelativeAge(d,{format: 'medium', title: true, leaveAgo: true}));
|
||||||
equal($elem.data('format'), "medium-with-ago");
|
equal($elem.data('format'), "medium-with-ago");
|
||||||
equal($elem.data('time'), d.getTime());
|
equal($elem.data('time'), d.getTime());
|
||||||
equal($elem.attr('title'), moment(d).longDate());
|
equal($elem.attr('title'), moment(d).longDate());
|
||||||
equal($elem.html(), '1 day ago');
|
equal($elem.html(), '1 day ago');
|
||||||
|
|
||||||
$elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d,{format: 'medium'}));
|
$elem = $(autoUpdatingRelativeAge(d,{format: 'medium'}));
|
||||||
equal($elem.data('format'), "medium");
|
equal($elem.data('format'), "medium");
|
||||||
equal($elem.data('time'), d.getTime());
|
equal($elem.data('time'), d.getTime());
|
||||||
equal($elem.attr('title'), undefined);
|
equal($elem.attr('title'), undefined);
|
||||||
|
@ -170,25 +170,25 @@ test("autoUpdatingRelativeAge", function() {
|
||||||
test("updateRelativeAge", function(){
|
test("updateRelativeAge", function(){
|
||||||
|
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
var $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d));
|
var $elem = $(autoUpdatingRelativeAge(d));
|
||||||
$elem.data('time', d.getTime() - 2 * 60 * 1000);
|
$elem.data('time', d.getTime() - 2 * 60 * 1000);
|
||||||
|
|
||||||
Discourse.Formatter.updateRelativeAge($elem);
|
updateRelativeAge($elem);
|
||||||
|
|
||||||
equal($elem.html(), "2m");
|
equal($elem.html(), "2m");
|
||||||
|
|
||||||
d = new Date();
|
d = new Date();
|
||||||
$elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d, {format: 'medium', leaveAgo: true}));
|
$elem = $(autoUpdatingRelativeAge(d, {format: 'medium', leaveAgo: true}));
|
||||||
$elem.data('time', d.getTime() - 2 * 60 * 1000);
|
$elem.data('time', d.getTime() - 2 * 60 * 1000);
|
||||||
|
|
||||||
Discourse.Formatter.updateRelativeAge($elem);
|
updateRelativeAge($elem);
|
||||||
|
|
||||||
equal($elem.html(), "2 mins ago");
|
equal($elem.html(), "2 mins ago");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("breakUp", function(){
|
test("breakUp", function(){
|
||||||
|
|
||||||
var b = function(s,hint){ return Discourse.Formatter.breakUp(s,hint); };
|
var b = function(s,hint){ return breakUp(s,hint); };
|
||||||
|
|
||||||
equal(b("hello"), "hello");
|
equal(b("hello"), "hello");
|
||||||
equal(b("helloworld"), "helloworld");
|
equal(b("helloworld"), "helloworld");
|
||||||
|
@ -201,9 +201,9 @@ test("breakUp", function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
test("number", function() {
|
test("number", function() {
|
||||||
equal(Discourse.Formatter.number(123), "123", "it returns a string version of the number");
|
equal(number(123), "123", "it returns a string version of the number");
|
||||||
equal(Discourse.Formatter.number("123"), "123", "it works with a string command");
|
equal(number("123"), "123", "it works with a string command");
|
||||||
equal(Discourse.Formatter.number(NaN), "0", "it returns 0 for NaN");
|
equal(number(NaN), "0", "it returns 0 for NaN");
|
||||||
equal(Discourse.Formatter.number(3333), "3.3k", "it abbreviates thousands");
|
equal(number(3333), "3.3k", "it abbreviates thousands");
|
||||||
equal(Discourse.Formatter.number(2499999), "2.5M", "it abbreviates millions");
|
equal(number(2499999), "2.5M", "it abbreviates millions");
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module("SelectedPostsCount");
|
module("mixin:selected-posts-count");
|
||||||
|
|
||||||
import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
|
import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
|
||||||
import Topic from 'discourse/models/topic';
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
module("Discourse.Singleton");
|
import Singleton from 'discourse/mixins/singleton';
|
||||||
|
|
||||||
|
module("mixin:singleton");
|
||||||
|
|
||||||
test("current", function() {
|
test("current", function() {
|
||||||
var DummyModel = Ember.Object.extend({});
|
var DummyModel = Ember.Object.extend({});
|
||||||
DummyModel.reopenClass(Discourse.Singleton);
|
DummyModel.reopenClass(Singleton);
|
||||||
|
|
||||||
var current = DummyModel.current();
|
var current = DummyModel.current();
|
||||||
present(current, 'current returns the current instance');
|
present(current, 'current returns the current instance');
|
||||||
|
@ -12,7 +14,7 @@ test("current", function() {
|
||||||
|
|
||||||
test("currentProp reading", function() {
|
test("currentProp reading", function() {
|
||||||
var DummyModel = Ember.Object.extend({});
|
var DummyModel = Ember.Object.extend({});
|
||||||
DummyModel.reopenClass(Discourse.Singleton);
|
DummyModel.reopenClass(Singleton);
|
||||||
var current = DummyModel.current();
|
var current = DummyModel.current();
|
||||||
|
|
||||||
blank(DummyModel.currentProp('evil'), 'by default attributes are blank');
|
blank(DummyModel.currentProp('evil'), 'by default attributes are blank');
|
||||||
|
@ -22,7 +24,7 @@ test("currentProp reading", function() {
|
||||||
|
|
||||||
test("currentProp writing", function() {
|
test("currentProp writing", function() {
|
||||||
var DummyModel = Ember.Object.extend({});
|
var DummyModel = Ember.Object.extend({});
|
||||||
DummyModel.reopenClass(Discourse.Singleton);
|
DummyModel.reopenClass(Singleton);
|
||||||
|
|
||||||
blank(DummyModel.currentProp('adventure'), 'by default attributes are blank');
|
blank(DummyModel.currentProp('adventure'), 'by default attributes are blank');
|
||||||
var result = DummyModel.currentProp('adventure', 'time');
|
var result = DummyModel.currentProp('adventure', 'time');
|
||||||
|
@ -38,7 +40,7 @@ test("currentProp writing", function() {
|
||||||
|
|
||||||
test("createCurrent", function() {
|
test("createCurrent", function() {
|
||||||
var Shoe = Ember.Object.extend({});
|
var Shoe = Ember.Object.extend({});
|
||||||
Shoe.reopenClass(Discourse.Singleton, {
|
Shoe.reopenClass(Singleton, {
|
||||||
createCurrent: function() {
|
createCurrent: function() {
|
||||||
return Shoe.create({toes: 5});
|
return Shoe.create({toes: 5});
|
||||||
}
|
}
|
||||||
|
@ -50,7 +52,7 @@ test("createCurrent", function() {
|
||||||
|
|
||||||
test("createCurrent that returns null", function() {
|
test("createCurrent that returns null", function() {
|
||||||
var Missing = Ember.Object.extend({});
|
var Missing = Ember.Object.extend({});
|
||||||
Missing.reopenClass(Discourse.Singleton, {
|
Missing.reopenClass(Singleton, {
|
||||||
createCurrent: function() {
|
createCurrent: function() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import Session from "discourse/models/session";
|
import Session from "discourse/models/session";
|
||||||
|
|
||||||
module("Discourse.Session");
|
module("model:session");
|
||||||
|
|
||||||
test('highestSeenByTopic', function() {
|
test('highestSeenByTopic', function() {
|
||||||
var session = Session.current();
|
const session = Session.current();
|
||||||
deepEqual(session.get('highestSeenByTopic'), {}, "by default it returns an empty object");
|
deepEqual(session.get('highestSeenByTopic'), {}, "by default it returns an empty object");
|
||||||
});
|
});
|
||||||
|
|
|
@ -79,6 +79,7 @@ var origDebounce = Ember.run.debounce,
|
||||||
createPretendServer = require('helpers/create-pretender', null, null, false).default,
|
createPretendServer = require('helpers/create-pretender', null, null, false).default,
|
||||||
fixtures = require('fixtures/site_fixtures', null, null, false).default,
|
fixtures = require('fixtures/site_fixtures', null, null, false).default,
|
||||||
flushMap = require('discourse/models/store', null, null, false).flushMap,
|
flushMap = require('discourse/models/store', null, null, false).flushMap,
|
||||||
|
ScrollingDOMMethods = require('discourse/mixins/scrolling', null, null, false).ScrollingDOMMethods,
|
||||||
server;
|
server;
|
||||||
|
|
||||||
function dup(obj) {
|
function dup(obj) {
|
||||||
|
@ -92,6 +93,7 @@ QUnit.testStart(function(ctx) {
|
||||||
Discourse.SiteSettings = dup(Discourse.SiteSettingsOriginal);
|
Discourse.SiteSettings = dup(Discourse.SiteSettingsOriginal);
|
||||||
Discourse.BaseUri = "/";
|
Discourse.BaseUri = "/";
|
||||||
Discourse.BaseUrl = "localhost";
|
Discourse.BaseUrl = "localhost";
|
||||||
|
Discourse.Session.resetCurrent();
|
||||||
Discourse.User.resetCurrent();
|
Discourse.User.resetCurrent();
|
||||||
Discourse.Site.resetCurrent(Discourse.Site.create(dup(fixtures['site.json'].site)));
|
Discourse.Site.resetCurrent(Discourse.Site.create(dup(fixtures['site.json'].site)));
|
||||||
|
|
||||||
|
@ -103,8 +105,8 @@ QUnit.testStart(function(ctx) {
|
||||||
PreloadStore.reset();
|
PreloadStore.reset();
|
||||||
|
|
||||||
window.sandbox = sinon.sandbox.create();
|
window.sandbox = sinon.sandbox.create();
|
||||||
window.sandbox.stub(Discourse.ScrollingDOMMethods, "bindOnScroll");
|
window.sandbox.stub(ScrollingDOMMethods, "bindOnScroll");
|
||||||
window.sandbox.stub(Discourse.ScrollingDOMMethods, "unbindOnScroll");
|
window.sandbox.stub(ScrollingDOMMethods, "unbindOnScroll");
|
||||||
|
|
||||||
// Don't debounce in test unless we're testing debouncing
|
// Don't debounce in test unless we're testing debouncing
|
||||||
if (ctx.module.indexOf('debounce') === -1) {
|
if (ctx.module.indexOf('debounce') === -1) {
|
||||||
|
|
Loading…
Reference in a new issue