mirror of
https://github.com/discourse/discourse.git
synced 2025-05-25 00:32:52 +08:00
Clean up JS, add YUIDoc support, automatically create IIFE via asset pipeline
This commit is contained in:
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
This controller supports interface for creating custom CSS skins in Discourse.
|
This controller supports interface for creating custom CSS skins in Discourse.
|
||||||
|
|
||||||
@class AdminCustomizeController
|
@class AdminCustomizeController
|
||||||
@extends Ember.Controller
|
@extends Ember.Controller
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.AdminCustomizeController = Ember.Controller.extend({
|
Discourse.AdminCustomizeController = Ember.Controller.extend({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a new customization style
|
Create a new customization style
|
||||||
@ -58,6 +56,4 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
This controller supports the default interface when you enter the admin section.
|
This controller supports the default interface when you enter the admin section.
|
||||||
|
|
||||||
@class AdminDashboardController
|
@class AdminDashboardController
|
||||||
@extends Ember.Controller
|
@extends Ember.Controller
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.AdminDashboardController = Ember.Controller.extend({
|
Discourse.AdminDashboardController = Ember.Controller.extend({
|
||||||
loading: true,
|
loading: true,
|
||||||
versionCheck: null
|
versionCheck: null
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
This controller supports the interface for reviewing email logs.
|
This controller supports the interface for reviewing email logs.
|
||||||
|
|
||||||
@class AdminEmailLogsController
|
@class AdminEmailLogsController
|
||||||
@extends Ember.ArrayController
|
@extends Ember.ArrayController
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.AdminEmailLogsController = Ember.ArrayController.extend(Discourse.Presence, {
|
Discourse.AdminEmailLogsController = Ember.ArrayController.extend(Discourse.Presence, {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Is the "send test email" button disabled?
|
Is the "send test email" button disabled?
|
||||||
@ -38,6 +36,4 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
This controller supports the interface for dealing with flags in the admin section.
|
This controller supports the interface for dealing with flags in the admin section.
|
||||||
|
|
||||||
@class AdminFlagsController
|
@class AdminFlagsController
|
||||||
@extends Ember.Controller
|
@extends Ember.Controller
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.AdminFlagsController = Ember.Controller.extend({
|
Discourse.AdminFlagsController = Ember.Controller.extend({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Clear all flags on a post
|
Clear all flags on a post
|
||||||
@ -58,6 +56,4 @@
|
|||||||
return this.query === 'active';
|
return this.query === 'active';
|
||||||
}).property('query')
|
}).property('query')
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
This controller supports the interface for SiteSettings.
|
This controller supports the interface for SiteSettings.
|
||||||
|
|
||||||
@class AdminSiteSettingsController
|
@class AdminSiteSettingsController
|
||||||
@extends Ember.ArrayController
|
@extends Ember.ArrayController
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.AdminSiteSettingsController = Ember.ArrayController.extend(Discourse.Presence, {
|
Discourse.AdminSiteSettingsController = Ember.ArrayController.extend(Discourse.Presence, {
|
||||||
filter: null,
|
filter: null,
|
||||||
onlyOverridden: false,
|
onlyOverridden: false,
|
||||||
|
|
||||||
@ -69,6 +67,4 @@
|
|||||||
setting.resetValue();
|
setting.resetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
This controller supports the interface for listing users in the admin section.
|
This controller supports the interface for listing users in the admin section.
|
||||||
|
|
||||||
@class AdminUsersListController
|
@class AdminUsersListController
|
||||||
@extends Ember.ArrayController
|
@extends Ember.ArrayController
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.AdminUsersListController = Ember.ArrayController.extend(Discourse.Presence, {
|
Discourse.AdminUsersListController = Ember.ArrayController.extend(Discourse.Presence, {
|
||||||
username: null,
|
username: null,
|
||||||
query: null,
|
query: null,
|
||||||
selectAll: false,
|
selectAll: false,
|
||||||
@ -106,6 +104,4 @@
|
|||||||
Discourse.AdminUser.bulkApprove(this.get('content').filterProperty('selected'));
|
Discourse.AdminUser.bulkApprove(this.get('content').filterProperty('selected'));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Our data model for dealing with users from the admin section.
|
Our data model for dealing with users from the admin section.
|
||||||
|
|
||||||
@class AdminUser
|
@class AdminUser
|
||||||
@extends Discourse.Model
|
@extends Discourse.Model
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.AdminUser = Discourse.Model.extend({
|
Discourse.AdminUser = Discourse.Model.extend({
|
||||||
|
|
||||||
deleteAllPosts: function() {
|
deleteAllPosts: function() {
|
||||||
this.set('can_delete_all_posts', false);
|
this.set('can_delete_all_posts', false);
|
||||||
@ -137,9 +135,9 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
window.Discourse.AdminUser.reopenClass({
|
window.Discourse.AdminUser.reopenClass({
|
||||||
|
|
||||||
bulkApprove: function(users) {
|
bulkApprove: function(users) {
|
||||||
users.each(function(user) {
|
users.each(function(user) {
|
||||||
@ -185,6 +183,4 @@
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Our data model for representing an email log.
|
Our data model for representing an email log.
|
||||||
|
|
||||||
@class EmailLog
|
@class EmailLog
|
||||||
@extends Discourse.Model
|
@extends Discourse.Model
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.EmailLog = Discourse.Model.extend({});
|
Discourse.EmailLog = Discourse.Model.extend({});
|
||||||
|
|
||||||
window.Discourse.EmailLog.reopenClass({
|
Discourse.EmailLog.reopenClass({
|
||||||
|
|
||||||
create: function(attrs) {
|
create: function(attrs) {
|
||||||
if (attrs.user) {
|
if (attrs.user) {
|
||||||
@ -33,6 +31,6 @@
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Our data model for interacting with flagged posts.
|
Our data model for interacting with flagged posts.
|
||||||
|
|
||||||
@class FlaggedPost
|
@class FlaggedPost
|
||||||
@extends Discourse.Post
|
@extends Discourse.Post
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.FlaggedPost = Discourse.Post.extend({
|
Discourse.FlaggedPost = Discourse.Post.extend({
|
||||||
|
|
||||||
flaggers: (function() {
|
flaggers: (function() {
|
||||||
var r,
|
var r,
|
||||||
@ -95,9 +93,9 @@
|
|||||||
if (this.get('hidden') === "t") return "hidden-post";
|
if (this.get('hidden') === "t") return "hidden-post";
|
||||||
}).property()
|
}).property()
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
window.Discourse.FlaggedPost.reopenClass({
|
Discourse.FlaggedPost.reopenClass({
|
||||||
findAll: function(filter) {
|
findAll: function(filter) {
|
||||||
var result;
|
var result;
|
||||||
result = Em.A();
|
result = Em.A();
|
||||||
@ -119,6 +117,6 @@
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
var SiteCustomizations;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Our data model for interacting with site customizations.
|
Our data model for interacting with site customizations.
|
||||||
|
|
||||||
@class SiteCustomization
|
@class SiteCustomization
|
||||||
@extends Discourse.Model
|
@extends Discourse.Model
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.SiteCustomization = Discourse.Model.extend({
|
Discourse.SiteCustomization = Discourse.Model.extend({
|
||||||
trackedProperties: ['enabled', 'name', 'stylesheet', 'header', 'override_default_style'],
|
trackedProperties: ['enabled', 'name', 'stylesheet', 'header', 'override_default_style'],
|
||||||
|
|
||||||
init: function() {
|
init: function() {
|
||||||
@ -76,9 +73,9 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
SiteCustomizations = Ember.ArrayProxy.extend({
|
var SiteCustomizations = Ember.ArrayProxy.extend({
|
||||||
selectedItemChanged: (function() {
|
selectedItemChanged: (function() {
|
||||||
var selected;
|
var selected;
|
||||||
selected = this.get('selectedItem');
|
selected = this.get('selectedItem');
|
||||||
@ -86,9 +83,9 @@
|
|||||||
return i.set('selected', selected === i);
|
return i.set('selected', selected === i);
|
||||||
});
|
});
|
||||||
}).observes('selectedItem')
|
}).observes('selectedItem')
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.SiteCustomization.reopenClass({
|
Discourse.SiteCustomization.reopenClass({
|
||||||
findAll: function() {
|
findAll: function() {
|
||||||
var content,
|
var content,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -112,6 +109,4 @@
|
|||||||
});
|
});
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Our data model for interacting with site settings.
|
Our data model for interacting with site settings.
|
||||||
|
|
||||||
@class SiteSetting
|
@class SiteSetting
|
||||||
@extends Discourse.Model
|
@extends Discourse.Model
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.SiteSetting = Discourse.Model.extend({
|
Discourse.SiteSetting = Discourse.Model.extend({
|
||||||
|
|
||||||
// Whether a property is short.
|
// Whether a property is short.
|
||||||
short: (function() {
|
short: (function() {
|
||||||
@ -46,9 +44,9 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.Discourse.SiteSetting.reopenClass({
|
Discourse.SiteSetting.reopenClass({
|
||||||
findAll: function() {
|
findAll: function() {
|
||||||
var result;
|
var result;
|
||||||
result = Em.A();
|
result = Em.A();
|
||||||
@ -60,6 +58,6 @@
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Our data model for determining whether there's a new version of Discourse
|
Our data model for determining whether there's a new version of Discourse
|
||||||
|
|
||||||
@class VersionCheck
|
@class VersionCheck
|
||||||
@extends Discourse.Model
|
@extends Discourse.Model
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.VersionCheck = Discourse.Model.extend({
|
Discourse.VersionCheck = Discourse.Model.extend({
|
||||||
upToDate: function() {
|
upToDate: function() {
|
||||||
return this.get('latest_version') === this.get('installed_version');
|
return this.get('latest_version') === this.get('installed_version');
|
||||||
}.property('latest_version', 'installed_version'),
|
}.property('latest_version', 'installed_version'),
|
||||||
@ -20,9 +18,9 @@
|
|||||||
shortSha: function() {
|
shortSha: function() {
|
||||||
return this.get('installed_sha').substr(0,10);
|
return this.get('installed_sha').substr(0,10);
|
||||||
}.property('installed_sha')
|
}.property('installed_sha')
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.VersionCheck.reopenClass({
|
Discourse.VersionCheck.reopenClass({
|
||||||
find: function() {
|
find: function() {
|
||||||
var promise = new RSVP.Promise();
|
var promise = new RSVP.Promise();
|
||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
@ -34,6 +32,4 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles routes related to customization
|
Handles routes related to customization
|
||||||
|
|
||||||
@class AdminCustomizeRoute
|
@class AdminCustomizeRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminCustomizeRoute = Discourse.Route.extend({
|
Discourse.AdminCustomizeRoute = Discourse.Route.extend({
|
||||||
model: function() {
|
model: function() {
|
||||||
return Discourse.SiteCustomization.findAll();
|
return Discourse.SiteCustomization.findAll();
|
||||||
},
|
},
|
||||||
@ -16,6 +14,6 @@
|
|||||||
renderTemplate: function() {
|
renderTemplate: function() {
|
||||||
this.render({into: 'admin/templates/admin'});
|
this.render({into: 'admin/templates/admin'});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles the default admin route
|
Handles the default admin route
|
||||||
|
|
||||||
@class AdminDashboardRoute
|
@class AdminDashboardRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminDashboardRoute = Discourse.Route.extend({
|
Discourse.AdminDashboardRoute = Discourse.Route.extend({
|
||||||
setupController: function(c) {
|
setupController: function(c) {
|
||||||
if( !c.get('versionCheckedAt') || Date.create('12 hours ago') > c.get('versionCheckedAt') ) {
|
if( !c.get('versionCheckedAt') || Date.create('12 hours ago') > c.get('versionCheckedAt') ) {
|
||||||
this.checkVersion(c);
|
this.checkVersion(c);
|
||||||
@ -28,6 +26,5 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles routes related to viewing email logs.
|
Handles routes related to viewing email logs.
|
||||||
|
|
||||||
@class AdminEmailLogsRoute
|
@class AdminEmailLogsRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminEmailLogsRoute = Discourse.Route.extend({
|
Discourse.AdminEmailLogsRoute = Discourse.Route.extend({
|
||||||
model: function() {
|
model: function() {
|
||||||
return Discourse.EmailLog.findAll();
|
return Discourse.EmailLog.findAll();
|
||||||
},
|
},
|
||||||
@ -16,6 +14,6 @@
|
|||||||
renderTemplate: function() {
|
renderTemplate: function() {
|
||||||
this.render('admin/templates/email_logs');
|
this.render('admin/templates/email_logs');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles routes related to viewing active flags.
|
Handles routes related to viewing active flags.
|
||||||
|
|
||||||
@class AdminFlagsActiveRoute
|
@class AdminFlagsActiveRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminFlagsActiveRoute = Discourse.Route.extend({
|
Discourse.AdminFlagsActiveRoute = Discourse.Route.extend({
|
||||||
|
|
||||||
model: function() {
|
model: function() {
|
||||||
return Discourse.FlaggedPost.findAll('active');
|
return Discourse.FlaggedPost.findAll('active');
|
||||||
@ -20,6 +18,6 @@
|
|||||||
adminFlagsController.set('query', 'active');
|
adminFlagsController.set('query', 'active');
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles routes related to viewing old flags.
|
Handles routes related to viewing old flags.
|
||||||
|
|
||||||
@class AdminFlagsOldRoute
|
@class AdminFlagsOldRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminFlagsOldRoute = Discourse.Route.extend({
|
Discourse.AdminFlagsOldRoute = Discourse.Route.extend({
|
||||||
|
|
||||||
model: function() {
|
model: function() {
|
||||||
return Discourse.FlaggedPost.findAll('old');
|
return Discourse.FlaggedPost.findAll('old');
|
||||||
@ -20,6 +18,6 @@
|
|||||||
adminFlagsController.set('query', 'old');
|
adminFlagsController.set('query', 'old');
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Basic route for admin flags
|
Basic route for admin flags
|
||||||
|
|
||||||
@class AdminFlagsRoute
|
@class AdminFlagsRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminFlagsRoute = Discourse.Route.extend({
|
Discourse.AdminFlagsRoute = Discourse.Route.extend({
|
||||||
renderTemplate: function() {
|
renderTemplate: function() {
|
||||||
this.render('admin/templates/flags');
|
this.render('admin/templates/flags');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
The base admin route
|
The base admin route
|
||||||
|
|
||||||
@class AdminRoute
|
@class AdminRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminRoute = Discourse.Route.extend({
|
Discourse.AdminRoute = Discourse.Route.extend({
|
||||||
renderTemplate: function() {
|
renderTemplate: function() {
|
||||||
this.render('admin/templates/admin');
|
this.render('admin/templates/admin');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
(function() {
|
/**
|
||||||
|
Builds the routes for the admin section
|
||||||
|
|
||||||
/**
|
@method buildRoutes
|
||||||
Declare all the routes used in the admin section.
|
@for Discourse.AdminRoute
|
||||||
**/
|
**/
|
||||||
Discourse.buildRoutes(function() {
|
Discourse.buildRoutes(function() {
|
||||||
return this.resource('admin', { path: '/admin' }, function() {
|
this.resource('admin', { path: '/admin' }, function() {
|
||||||
|
|
||||||
this.route('dashboard', { path: '/' });
|
this.route('dashboard', { path: '/' });
|
||||||
this.route('site_settings', { path: '/site_settings' });
|
this.route('site_settings', { path: '/site_settings' });
|
||||||
@ -26,6 +27,6 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles routes related to viewing and editing site settings.
|
Handles routes related to viewing and editing site settings.
|
||||||
|
|
||||||
@class AdminSiteSettingsRoute
|
@class AdminSiteSettingsRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminSiteSettingsRoute = Discourse.Route.extend({
|
Discourse.AdminSiteSettingsRoute = Discourse.Route.extend({
|
||||||
model: function() {
|
model: function() {
|
||||||
return Discourse.SiteSetting.findAll();
|
return Discourse.SiteSetting.findAll();
|
||||||
},
|
},
|
||||||
@ -16,6 +14,6 @@
|
|||||||
renderTemplate: function() {
|
renderTemplate: function() {
|
||||||
this.render('admin/templates/site_settings', {into: 'admin/templates/admin'});
|
this.render('admin/templates/site_settings', {into: 'admin/templates/admin'});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles routes related to users in the admin section.
|
Handles routes related to users in the admin section.
|
||||||
|
|
||||||
@class AdminUserRoute
|
@class AdminUserRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminUserRoute = Discourse.Route.extend({
|
Discourse.AdminUserRoute = Discourse.Route.extend({
|
||||||
model: function(params) {
|
model: function(params) {
|
||||||
return Discourse.AdminUser.find(params.username);
|
return Discourse.AdminUser.find(params.username);
|
||||||
},
|
},
|
||||||
@ -17,6 +15,6 @@
|
|||||||
this.render('admin/templates/user', {into: 'admin/templates/admin'});
|
this.render('admin/templates/user', {into: 'admin/templates/admin'});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles the route that lists active users.
|
Handles the route that lists active users.
|
||||||
|
|
||||||
@class AdminUsersListActiveRoute
|
@class AdminUsersListActiveRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminUsersListActiveRoute = Discourse.Route.extend({
|
Discourse.AdminUsersListActiveRoute = Discourse.Route.extend({
|
||||||
setupController: function() {
|
setupController: function() {
|
||||||
return this.controllerFor('adminUsersList').show('active');
|
return this.controllerFor('adminUsersList').show('active');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles the route that lists new users.
|
Handles the route that lists new users.
|
||||||
|
|
||||||
@class AdminUsersListNewRoute
|
@class AdminUsersListNewRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminUsersListNewRoute = Discourse.Route.extend({
|
Discourse.AdminUsersListNewRoute = Discourse.Route.extend({
|
||||||
setupController: function() {
|
setupController: function() {
|
||||||
return this.controllerFor('adminUsersList').show('new');
|
return this.controllerFor('adminUsersList').show('new');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles the route that lists pending users.
|
Handles the route that lists pending users.
|
||||||
|
|
||||||
@class AdminUsersListNewRoute
|
@class AdminUsersListNewRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminUsersListPendingRoute = Discourse.Route.extend({
|
Discourse.AdminUsersListPendingRoute = Discourse.Route.extend({
|
||||||
setupController: function() {
|
setupController: function() {
|
||||||
return this.controllerFor('adminUsersList').show('pending');
|
return this.controllerFor('adminUsersList').show('pending');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
Handles the route that deals with listing users
|
Handles the route that deals with listing users
|
||||||
|
|
||||||
@class AdminUsersListRoute
|
@class AdminUsersListRoute
|
||||||
@extends Discourse.Route
|
@extends Discourse.Route
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminUsersListRoute = Discourse.Route.extend({
|
Discourse.AdminUsersListRoute = Discourse.Route.extend({
|
||||||
renderTemplate: function() {
|
renderTemplate: function() {
|
||||||
this.render('admin/templates/users_list', {into: 'admin/templates/admin'});
|
this.render('admin/templates/users_list', {into: 'admin/templates/admin'});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
/*global ace:true */
|
/*global ace:true */
|
||||||
(function() {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A view that wraps the ACE editor (http://ace.ajax.org/)
|
A view that wraps the ACE editor (http://ace.ajax.org/)
|
||||||
|
|
||||||
@class AceEditorView
|
@class AceEditorView
|
||||||
@extends Em.View
|
@extends Em.View
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AceEditorView = Discourse.View.extend({
|
Discourse.AceEditorView = Discourse.View.extend({
|
||||||
mode: 'css',
|
mode: 'css',
|
||||||
classNames: ['ace-wrapper'],
|
classNames: ['ace-wrapper'],
|
||||||
|
|
||||||
@ -61,6 +60,6 @@
|
|||||||
return $LAB.script('http://d1n0x3qji82z53.cloudfront.net/src-min-noconflict/ace.js').wait(initAce);
|
return $LAB.script('http://d1n0x3qji82z53.cloudfront.net/src-min-noconflict/ace.js').wait(initAce);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
/*global Mousetrap:true */
|
/*global Mousetrap:true */
|
||||||
(function() {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A view to handle site customizations
|
A view to handle site customizations
|
||||||
|
|
||||||
@class AdminCustomizeView
|
@class AdminCustomizeView
|
||||||
@extends Em.View
|
@extends Em.View
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminCustomizeView = Discourse.View.extend({
|
Discourse.AdminCustomizeView = Discourse.View.extend({
|
||||||
templateName: 'admin/templates/customize',
|
templateName: 'admin/templates/customize',
|
||||||
classNames: ['customize'],
|
classNames: ['customize'],
|
||||||
|
|
||||||
@ -46,6 +45,6 @@
|
|||||||
return Mousetrap.unbindGlobal('meta+s', 'ctrl+s');
|
return Mousetrap.unbindGlobal('meta+s', 'ctrl+s');
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
The default view in the admin section
|
The default view in the admin section
|
||||||
|
|
||||||
@class AdminDashboardView
|
@class AdminDashboardView
|
||||||
@extends Em.View
|
@extends Em.View
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.AdminDashboardView = Discourse.View.extend({
|
Discourse.AdminDashboardView = Discourse.View.extend({
|
||||||
templateName: 'admin/templates/dashboard',
|
templateName: 'admin/templates/dashboard',
|
||||||
|
|
||||||
updateIconClasses: function() {
|
updateIconClasses: function() {
|
||||||
@ -28,6 +26,6 @@
|
|||||||
}
|
}
|
||||||
return 'version-check normal';
|
return 'version-check normal';
|
||||||
}.property('controller.versionCheck.critical_updates')
|
}.property('controller.versionCheck.critical_updates')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
//= require ./discourse/views/view
|
//= require ./discourse/views/view
|
||||||
//= require ./discourse/components/debounce
|
//= require ./discourse/components/debounce
|
||||||
//= require ./discourse/controllers/controller
|
//= require ./discourse/controllers/controller
|
||||||
|
//= require ./discourse/controllers/object_controller
|
||||||
//= require ./discourse/views/modal/modal_body_view
|
//= require ./discourse/views/modal/modal_body_view
|
||||||
//= require ./discourse/models/model
|
//= require ./discourse/models/model
|
||||||
//= require ./discourse/routes/discourse_route
|
//= require ./discourse/routes/discourse_route
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
/*global assetPath:true*/
|
/*global assetPath:true*/
|
||||||
/*global FastClick:true*/
|
/*global FastClick:true*/
|
||||||
|
|
||||||
(function() {
|
var csrf_token;
|
||||||
var csrf_token;
|
|
||||||
|
|
||||||
window.Discourse = Ember.Application.createWithMixins({
|
Discourse = Ember.Application.createWithMixins({
|
||||||
rootElement: '#main',
|
rootElement: '#main',
|
||||||
|
|
||||||
// Data we want to remember for a short period
|
// Data we want to remember for a short period
|
||||||
@ -34,7 +33,7 @@
|
|||||||
title += "" + (this.get('title')) + " - ";
|
title += "" + (this.get('title')) + " - ";
|
||||||
}
|
}
|
||||||
title += Discourse.SiteSettings.title;
|
title += Discourse.SiteSettings.title;
|
||||||
jQuery('title').text(title);
|
$('title').text(title);
|
||||||
if (!this.get('hasFocus') && this.get('notify')) {
|
if (!this.get('hasFocus') && this.get('notify')) {
|
||||||
title = "(*) " + title;
|
title = "(*) " + title;
|
||||||
}
|
}
|
||||||
@ -134,7 +133,7 @@
|
|||||||
bindDOMEvents: function() {
|
bindDOMEvents: function() {
|
||||||
var $html, hasTouch,
|
var $html, hasTouch,
|
||||||
_this = this;
|
_this = this;
|
||||||
$html = jQuery('html');
|
$html = $('html');
|
||||||
|
|
||||||
/* Add the discourse touch event */
|
/* Add the discourse touch event */
|
||||||
hasTouch = false;
|
hasTouch = false;
|
||||||
@ -160,17 +159,17 @@
|
|||||||
$html.addClass('discourse-no-touch');
|
$html.addClass('discourse-no-touch');
|
||||||
this.touch = false;
|
this.touch = false;
|
||||||
}
|
}
|
||||||
jQuery('#main').on('click.discourse', '[data-not-implemented=true]', function(e) {
|
$('#main').on('click.discourse', '[data-not-implemented=true]', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
alert(Em.String.i18n('not_implemented'));
|
alert(Em.String.i18n('not_implemented'));
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
jQuery('#main').on('click.discourse', 'a', function(e) {
|
$('#main').on('click.discourse', 'a', function(e) {
|
||||||
var $currentTarget, href;
|
var $currentTarget, href;
|
||||||
if (e.isDefaultPrevented() || e.metaKey || e.ctrlKey) {
|
if (e.isDefaultPrevented() || e.metaKey || e.ctrlKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$currentTarget = jQuery(e.currentTarget);
|
$currentTarget = $(e.currentTarget);
|
||||||
href = $currentTarget.attr('href');
|
href = $currentTarget.attr('href');
|
||||||
if (href === void 0) {
|
if (href === void 0) {
|
||||||
return;
|
return;
|
||||||
@ -197,7 +196,7 @@
|
|||||||
_this.routeTo(href);
|
_this.routeTo(href);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
return jQuery(window).focus(function() {
|
return $(window).focus(function() {
|
||||||
_this.set('hasFocus', true);
|
_this.set('hasFocus', true);
|
||||||
return _this.set('notify', false);
|
return _this.set('notify', false);
|
||||||
}).blur(function() {
|
}).blur(function() {
|
||||||
@ -310,7 +309,7 @@
|
|||||||
Discourse.insertProbes();
|
Discourse.insertProbes();
|
||||||
|
|
||||||
// subscribe to any site customizations that are loaded
|
// subscribe to any site customizations that are loaded
|
||||||
jQuery('link.custom-css').each(function() {
|
$('link.custom-css').each(function() {
|
||||||
var id, split, stylesheet,
|
var id, split, stylesheet,
|
||||||
_this = this;
|
_this = this;
|
||||||
split = this.href.split("/");
|
split = this.href.split("/");
|
||||||
@ -318,18 +317,18 @@
|
|||||||
stylesheet = this;
|
stylesheet = this;
|
||||||
return Discourse.MessageBus.subscribe("/file-change/" + id, function(data) {
|
return Discourse.MessageBus.subscribe("/file-change/" + id, function(data) {
|
||||||
var orig, sp;
|
var orig, sp;
|
||||||
if (!jQuery(stylesheet).data('orig')) {
|
if (!$(stylesheet).data('orig')) {
|
||||||
jQuery(stylesheet).data('orig', stylesheet.href);
|
$(stylesheet).data('orig', stylesheet.href);
|
||||||
}
|
}
|
||||||
orig = jQuery(stylesheet).data('orig');
|
orig = $(stylesheet).data('orig');
|
||||||
sp = orig.split(".css?");
|
sp = orig.split(".css?");
|
||||||
stylesheet.href = sp[0] + ".css?" + data;
|
stylesheet.href = sp[0] + ".css?" + data;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
jQuery('header.custom').each(function() {
|
$('header.custom').each(function() {
|
||||||
var header;
|
var header;
|
||||||
header = jQuery(this);
|
header = $(this);
|
||||||
return Discourse.MessageBus.subscribe("/header-change/" + (jQuery(this).data('key')), function(data) {
|
return Discourse.MessageBus.subscribe("/header-change/" + ($(this).data('key')), function(data) {
|
||||||
return header.html(data);
|
return header.html(data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -359,31 +358,31 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return jQuery('link').each(function() {
|
return $('link').each(function() {
|
||||||
if (this.href.match(me.name) && me.hash) {
|
if (this.href.match(me.name) && me.hash) {
|
||||||
if (!jQuery(this).data('orig')) {
|
if (!$(this).data('orig')) {
|
||||||
jQuery(this).data('orig', this.href);
|
$(this).data('orig', this.href);
|
||||||
}
|
}
|
||||||
this.href = jQuery(this).data('orig') + "&hash=" + me.hash;
|
this.href = $(this).data('orig') + "&hash=" + me.hash;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.Discourse.Router = Discourse.Router.reopen({
|
Discourse.Router = Discourse.Router.reopen({
|
||||||
location: 'discourse_location'
|
location: 'discourse_location'
|
||||||
});
|
});
|
||||||
|
|
||||||
// since we have no jquery-rails these days, hook up csrf token
|
// since we have no jquery-rails these days, hook up csrf token
|
||||||
csrf_token = jQuery('meta[name=csrf-token]').attr('content');
|
csrf_token = $('meta[name=csrf-token]').attr('content');
|
||||||
|
|
||||||
jQuery.ajaxPrefilter(function(options, originalOptions, xhr) {
|
jQuery.ajaxPrefilter(function(options, originalOptions, xhr) {
|
||||||
if (!options.crossDomain) {
|
if (!options.crossDomain) {
|
||||||
xhr.setRequestHeader('X-CSRF-Token', csrf_token);
|
xhr.setRequestHeader('X-CSRF-Token', csrf_token);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This is a jQuery plugin to support autocompleting values in our text fields.
|
||||||
|
|
||||||
|
@module $.fn.autocomplete
|
||||||
|
**/
|
||||||
|
$.fn.autocomplete = function(options) {
|
||||||
|
|
||||||
(function($) {
|
|
||||||
var template;
|
|
||||||
template = null;
|
|
||||||
$.fn.autocomplete = function(options) {
|
|
||||||
var addInputSelectedItem, autocompleteOptions, closeAutocomplete, completeEnd, completeStart, completeTerm, div, height;
|
var addInputSelectedItem, autocompleteOptions, closeAutocomplete, completeEnd, completeStart, completeTerm, div, height;
|
||||||
var inputSelectedItems, isInput, markSelected, me, oldClose, renderAutocomplete, selectedOption, updateAutoComplete, vals;
|
var inputSelectedItems, isInput, markSelected, me, oldClose, renderAutocomplete, selectedOption, updateAutoComplete, vals;
|
||||||
var width, wrap, _this = this;
|
var width, wrap, _this = this;
|
||||||
if (this.length === 0) {
|
|
||||||
return;
|
if (this.length === 0) return;
|
||||||
}
|
|
||||||
if (options && options.cancel && this.data("closeAutocomplete")) {
|
if (options && options.cancel && this.data("closeAutocomplete")) {
|
||||||
this.data("closeAutocomplete")();
|
this.data("closeAutocomplete")();
|
||||||
return this;
|
return this;
|
||||||
@ -23,17 +24,17 @@
|
|||||||
completeEnd = null;
|
completeEnd = null;
|
||||||
me = this;
|
me = this;
|
||||||
div = null;
|
div = null;
|
||||||
/* input is handled differently
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// input is handled differently
|
||||||
isInput = this[0].tagName === "INPUT";
|
isInput = this[0].tagName === "INPUT";
|
||||||
inputSelectedItems = [];
|
inputSelectedItems = [];
|
||||||
|
|
||||||
addInputSelectedItem = function(item) {
|
addInputSelectedItem = function(item) {
|
||||||
var d, prev, transformed;
|
var d, prev, transformed;
|
||||||
if (options.transformComplete) {
|
if (options.transformComplete) {
|
||||||
transformed = options.transformComplete(item);
|
transformed = options.transformComplete(item);
|
||||||
}
|
}
|
||||||
d = jQuery("<div class='item'><span>" + (transformed || item) + "<a href='#'><i class='icon-remove'></i></a></span></div>");
|
d = $("<div class='item'><span>" + (transformed || item) + "<a href='#'><i class='icon-remove'></i></a></span></div>");
|
||||||
prev = me.parent().find('.item:last');
|
prev = me.parent().find('.item:last');
|
||||||
if (prev.length === 0) {
|
if (prev.length === 0) {
|
||||||
me.parent().prepend(d);
|
me.parent().prepend(d);
|
||||||
@ -47,12 +48,13 @@
|
|||||||
return d.find('a').click(function() {
|
return d.find('a').click(function() {
|
||||||
closeAutocomplete();
|
closeAutocomplete();
|
||||||
inputSelectedItems.splice(jQuery.inArray(item), 1);
|
inputSelectedItems.splice(jQuery.inArray(item), 1);
|
||||||
jQuery(this).parent().parent().remove();
|
$(this).parent().parent().remove();
|
||||||
if (options.onChangeItems) {
|
if (options.onChangeItems) {
|
||||||
return options.onChangeItems(inputSelectedItems);
|
return options.onChangeItems(inputSelectedItems);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isInput) {
|
if (isInput) {
|
||||||
width = this.width();
|
width = this.width();
|
||||||
height = this.height();
|
height = this.height();
|
||||||
@ -76,12 +78,14 @@
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
markSelected = function() {
|
markSelected = function() {
|
||||||
var links;
|
var links;
|
||||||
links = div.find('li a');
|
links = div.find('li a');
|
||||||
links.removeClass('selected');
|
links.removeClass('selected');
|
||||||
return jQuery(links[selectedOption]).addClass('selected');
|
return $(links[selectedOption]).addClass('selected');
|
||||||
};
|
};
|
||||||
|
|
||||||
renderAutocomplete = function() {
|
renderAutocomplete = function() {
|
||||||
var borderTop, mePos, pos, ul;
|
var borderTop, mePos, pos, ul;
|
||||||
if (div) {
|
if (div) {
|
||||||
@ -90,7 +94,7 @@
|
|||||||
if (autocompleteOptions.length === 0) {
|
if (autocompleteOptions.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
div = jQuery(options.template({
|
div = $(options.template({
|
||||||
options: autocompleteOptions
|
options: autocompleteOptions
|
||||||
}));
|
}));
|
||||||
ul = div.find('ul');
|
ul = div.find('ul');
|
||||||
@ -125,6 +129,7 @@
|
|||||||
left: (mePos.left + pos.left + 27) + 'px'
|
left: (mePos.left + pos.left + 27) + 'px'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateAutoComplete = function(r) {
|
updateAutoComplete = function(r) {
|
||||||
if (completeStart === null) return;
|
if (completeStart === null) return;
|
||||||
|
|
||||||
@ -135,6 +140,7 @@
|
|||||||
return renderAutocomplete();
|
return renderAutocomplete();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
closeAutocomplete = function() {
|
closeAutocomplete = function() {
|
||||||
if (div) {
|
if (div) {
|
||||||
div.hide().remove();
|
div.hide().remove();
|
||||||
@ -143,9 +149,8 @@
|
|||||||
completeStart = null;
|
completeStart = null;
|
||||||
autocompleteOptions = null;
|
autocompleteOptions = null;
|
||||||
};
|
};
|
||||||
/* chain to allow multiples
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// chain to allow multiples
|
||||||
oldClose = me.data("closeAutocomplete");
|
oldClose = me.data("closeAutocomplete");
|
||||||
me.data("closeAutocomplete", function() {
|
me.data("closeAutocomplete", function() {
|
||||||
if (oldClose) {
|
if (oldClose) {
|
||||||
@ -153,6 +158,7 @@
|
|||||||
}
|
}
|
||||||
return closeAutocomplete();
|
return closeAutocomplete();
|
||||||
});
|
});
|
||||||
|
|
||||||
completeTerm = function(term) {
|
completeTerm = function(term) {
|
||||||
var text;
|
var text;
|
||||||
if (term) {
|
if (term) {
|
||||||
@ -171,7 +177,8 @@
|
|||||||
}
|
}
|
||||||
return closeAutocomplete();
|
return closeAutocomplete();
|
||||||
};
|
};
|
||||||
jQuery(this).keypress(function(e) {
|
|
||||||
|
$(this).keypress(function(e) {
|
||||||
var caretPosition, prevChar, term;
|
var caretPosition, prevChar, term;
|
||||||
if (!options.key) {
|
if (!options.key) {
|
||||||
return;
|
return;
|
||||||
@ -189,7 +196,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return jQuery(this).keydown(function(e) {
|
|
||||||
|
return $(this).keydown(function(e) {
|
||||||
var c, caretPosition, i, initial, next, nextIsGood, prev, prevIsGood, stopFound, term, total, userToComplete;
|
var c, caretPosition, i, initial, next, nextIsGood, prev, prevIsGood, stopFound, term, total, userToComplete;
|
||||||
if (!options.key) {
|
if (!options.key) {
|
||||||
completeStart = 0;
|
completeStart = 0;
|
||||||
@ -306,8 +314,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return $.fn.autocomplete;
|
|
||||||
})(jQuery);
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,44 +1,31 @@
|
|||||||
/*global HANDLEBARS_TEMPLATES:true*/
|
/*global HANDLEBARS_TEMPLATES:true*/
|
||||||
|
|
||||||
(function() {
|
/**
|
||||||
|
Support for BBCode rendering
|
||||||
|
|
||||||
|
@class BBCode
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.BBCode = {
|
||||||
|
|
||||||
Discourse.BBCode = {
|
|
||||||
QUOTE_REGEXP: /\[quote=([^\]]*)\]([\s\S]*?)\[\/quote\]/im,
|
QUOTE_REGEXP: /\[quote=([^\]]*)\]([\s\S]*?)\[\/quote\]/im,
|
||||||
/* Define our replacers
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Define our replacers
|
||||||
replacers: {
|
replacers: {
|
||||||
base: {
|
base: {
|
||||||
withoutArgs: {
|
withoutArgs: {
|
||||||
"ol": function(_, content) {
|
"ol": function(_, content) { return "<ol>" + content + "</ol>"; },
|
||||||
return "<ol>" + content + "</ol>";
|
"li": function(_, content) { return "<li>" + content + "</li>"; },
|
||||||
},
|
"ul": function(_, content) { return "<ul>" + content + "</ul>"; },
|
||||||
"li": function(_, content) {
|
"code": function(_, content) { return "<pre>" + content + "</pre>"; },
|
||||||
return "<li>" + content + "</li>";
|
"url": function(_, url) { return "<a href=\"" + url + "\">" + url + "</a>"; },
|
||||||
},
|
"email": function(_, address) { return "<a href=\"mailto:" + address + "\">" + address + "</a>"; },
|
||||||
"ul": function(_, content) {
|
"img": function(_, src) { return "<img src=\"" + src + "\">"; }
|
||||||
return "<ul>" + content + "</ul>";
|
|
||||||
},
|
|
||||||
"code": function(_, content) {
|
|
||||||
return "<pre>" + content + "</pre>";
|
|
||||||
},
|
|
||||||
"url": function(_, url) {
|
|
||||||
return "<a href=\"" + url + "\">" + url + "</a>";
|
|
||||||
},
|
|
||||||
"email": function(_, address) {
|
|
||||||
return "<a href=\"mailto:" + address + "\">" + address + "</a>";
|
|
||||||
},
|
|
||||||
"img": function(_, src) {
|
|
||||||
return "<img src=\"" + src + "\">";
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
withArgs: {
|
withArgs: {
|
||||||
"url": function(_, href, title) {
|
"url": function(_, href, title) { return "<a href=\"" + href + "\">" + title + "</a>"; },
|
||||||
return "<a href=\"" + href + "\">" + title + "</a>";
|
"email": function(_, address, title) { return "<a href=\"mailto:" + address + "\">" + title + "</a>"; },
|
||||||
},
|
|
||||||
"email": function(_, address, title) {
|
|
||||||
return "<a href=\"mailto:" + address + "\">" + title + "</a>";
|
|
||||||
},
|
|
||||||
"color": function(_, color, content) {
|
"color": function(_, color, content) {
|
||||||
if (!/^(\#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?)|(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)$/.test(color)) {
|
if (!/^(\#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?)|(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)$/.test(color)) {
|
||||||
return content;
|
return content;
|
||||||
@ -47,26 +34,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* For HTML emails
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// For HTML emails
|
||||||
email: {
|
email: {
|
||||||
withoutArgs: {
|
withoutArgs: {
|
||||||
"b": function(_, content) {
|
"b": function(_, content) { return "<b>" + content + "</b>"; },
|
||||||
return "<b>" + content + "</b>";
|
"i": function(_, content) { return "<i>" + content + "</i>"; },
|
||||||
},
|
"u": function(_, content) { return "<u>" + content + "</u>"; },
|
||||||
"i": function(_, content) {
|
"s": function(_, content) { return "<s>" + content + "</s>"; },
|
||||||
return "<i>" + content + "</i>";
|
"spoiler": function(_, content) { return "<span style='background-color: #000'>" + content + "</span>"; }
|
||||||
},
|
|
||||||
"u": function(_, content) {
|
|
||||||
return "<u>" + content + "</u>";
|
|
||||||
},
|
|
||||||
"s": function(_, content) {
|
|
||||||
return "<s>" + content + "</s>";
|
|
||||||
},
|
|
||||||
"spoiler": function(_, content) {
|
|
||||||
return "<span style='background-color: #000'>" + content + "</span>";
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
withArgs: {
|
withArgs: {
|
||||||
"size": function(_, size, content) {
|
"size": function(_, size, content) {
|
||||||
@ -74,25 +50,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* For sane environments that support CSS
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// For sane environments that support CSS
|
||||||
"default": {
|
"default": {
|
||||||
withoutArgs: {
|
withoutArgs: {
|
||||||
"b": function(_, content) {
|
"b": function(_, content) { return "<span class='bbcode-b'>" + content + "</span>"; },
|
||||||
return "<span class='bbcode-b'>" + content + "</span>";
|
"i": function(_, content) { return "<span class='bbcode-i'>" + content + "</span>"; },
|
||||||
},
|
"u": function(_, content) { return "<span class='bbcode-u'>" + content + "</span>"; },
|
||||||
"i": function(_, content) {
|
"s": function(_, content) { return "<span class='bbcode-s'>" + content + "</span>"; },
|
||||||
return "<span class='bbcode-i'>" + content + "</span>";
|
"spoiler": function(_, content) { return "<span class=\"spoiler\">" + content + "</span>";
|
||||||
},
|
|
||||||
"u": function(_, content) {
|
|
||||||
return "<span class='bbcode-u'>" + content + "</span>";
|
|
||||||
},
|
|
||||||
"s": function(_, content) {
|
|
||||||
return "<span class='bbcode-s'>" + content + "</span>";
|
|
||||||
},
|
|
||||||
"spoiler": function(_, content) {
|
|
||||||
return "<span class=\"spoiler\">" + content + "</span>";
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
withArgs: {
|
withArgs: {
|
||||||
@ -103,7 +69,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Apply a particular set of replacers */
|
// Apply a particular set of replacers
|
||||||
apply: function(text, environment) {
|
apply: function(text, environment) {
|
||||||
var replacer;
|
var replacer;
|
||||||
replacer = Discourse.BBCode.parsedReplacers()[environment];
|
replacer = Discourse.BBCode.parsedReplacers()[environment];
|
||||||
@ -116,9 +82,8 @@
|
|||||||
|
|
||||||
parsedReplacers: function() {
|
parsedReplacers: function() {
|
||||||
var result;
|
var result;
|
||||||
if (this.parsed) {
|
if (this.parsed) return this.parsed;
|
||||||
return this.parsed;
|
|
||||||
}
|
|
||||||
result = {};
|
result = {};
|
||||||
Object.keys(Discourse.BBCode.replacers, function(name, rules) {
|
Object.keys(Discourse.BBCode.replacers, function(name, rules) {
|
||||||
var parsed;
|
var parsed;
|
||||||
@ -207,6 +172,14 @@
|
|||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
Format a text string using BBCode
|
||||||
|
|
||||||
|
@method format
|
||||||
|
@param {String} text The text we want to format
|
||||||
|
@param {Object} opts Rendering options
|
||||||
|
**/
|
||||||
format: function(text, opts) {
|
format: function(text, opts) {
|
||||||
var environment;
|
var environment;
|
||||||
if (opts && opts.environment) environment = opts.environment;
|
if (opts && opts.environment) environment = opts.environment;
|
||||||
@ -217,6 +190,4 @@
|
|||||||
text = Discourse.BBCode.formatQuote(text, opts);
|
text = Discourse.BBCode.formatQuote(text, opts);
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}).call(this);
|
|
@ -1,16 +1,6 @@
|
|||||||
|
// http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea
|
||||||
/* caret position in textarea ... very hacky ... sorry
|
var clone, getCaret;
|
||||||
*/
|
getCaret = function(el) {
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
(function($) {
|
|
||||||
/* http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea
|
|
||||||
*/
|
|
||||||
|
|
||||||
var clone, getCaret;
|
|
||||||
getCaret = function(el) {
|
|
||||||
var r, rc, re;
|
var r, rc, re;
|
||||||
if (el.selectionStart) {
|
if (el.selectionStart) {
|
||||||
return el.selectionStart;
|
return el.selectionStart;
|
||||||
@ -25,15 +15,23 @@
|
|||||||
return rc.text.length;
|
return rc.text.length;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
clone = null;
|
|
||||||
$.fn.caretPosition = function(options) {
|
clone = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
This is a jQuery plugin to retrieve the caret position in a textarea
|
||||||
|
|
||||||
|
@module $.fn.caretPosition
|
||||||
|
**/
|
||||||
|
$.fn.caretPosition = function(options) {
|
||||||
var after, before, getStyles, guard, html, important, insertSpaceAfterBefore, letter, makeCursor, p, pPos, pos, span, styles, textarea, val;
|
var after, before, getStyles, guard, html, important, insertSpaceAfterBefore, letter, makeCursor, p, pPos, pos, span, styles, textarea, val;
|
||||||
if (clone) {
|
if (clone) {
|
||||||
clone.remove();
|
clone.remove();
|
||||||
}
|
}
|
||||||
span = jQuery("#pos span");
|
span = $("#pos span");
|
||||||
textarea = jQuery(this);
|
textarea = $(this);
|
||||||
|
|
||||||
getStyles = function(el, prop) {
|
getStyles = function(el, prop) {
|
||||||
if (el.currentStyle) {
|
if (el.currentStyle) {
|
||||||
return el.currentStyle;
|
return el.currentStyle;
|
||||||
@ -41,14 +39,17 @@
|
|||||||
return document.defaultView.getComputedStyle(el, "");
|
return document.defaultView.getComputedStyle(el, "");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
styles = getStyles(textarea[0]);
|
styles = getStyles(textarea[0]);
|
||||||
clone = jQuery("<div><p></p></div>").appendTo("body");
|
clone = $("<div><p></p></div>").appendTo("body");
|
||||||
p = clone.find("p");
|
p = clone.find("p");
|
||||||
clone.width(textarea.width());
|
clone.width(textarea.width());
|
||||||
clone.height(textarea.height());
|
clone.height(textarea.height());
|
||||||
|
|
||||||
important = function(prop) {
|
important = function(prop) {
|
||||||
return styles.getPropertyValue(prop);
|
return styles.getPropertyValue(prop);
|
||||||
};
|
};
|
||||||
|
|
||||||
clone.css({
|
clone.css({
|
||||||
border: "1px solid black",
|
border: "1px solid black",
|
||||||
padding: important("padding"),
|
padding: important("padding"),
|
||||||
@ -59,6 +60,7 @@
|
|||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: "-7000px"
|
left: "-7000px"
|
||||||
});
|
});
|
||||||
|
|
||||||
p.css({
|
p.css({
|
||||||
margin: 0,
|
margin: 0,
|
||||||
padding: 0,
|
padding: 0,
|
||||||
@ -68,6 +70,7 @@
|
|||||||
"font-size": important("font-size"),
|
"font-size": important("font-size"),
|
||||||
"line-height": important("line-height")
|
"line-height": important("line-height")
|
||||||
});
|
});
|
||||||
|
|
||||||
before = void 0;
|
before = void 0;
|
||||||
after = void 0;
|
after = void 0;
|
||||||
pos = options && (options.pos || options.pos === 0) ? options.pos : getCaret(textarea[0]);
|
pos = options && (options.pos || options.pos === 0) ? options.pos : getCaret(textarea[0]);
|
||||||
@ -78,12 +81,12 @@
|
|||||||
before = pos - 1;
|
before = pos - 1;
|
||||||
after = pos;
|
after = pos;
|
||||||
insertSpaceAfterBefore = false;
|
insertSpaceAfterBefore = false;
|
||||||
/* if before and after are \n insert a space
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// if before and after are \n insert a space
|
||||||
if (val[before] === "\n" && val[after] === "\n") {
|
if (val[before] === "\n" && val[after] === "\n") {
|
||||||
insertSpaceAfterBefore = true;
|
insertSpaceAfterBefore = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
guard = function(v) {
|
guard = function(v) {
|
||||||
var buf;
|
var buf;
|
||||||
buf = v.replace(/</g, "<");
|
buf = v.replace(/</g, "<");
|
||||||
@ -91,14 +94,14 @@
|
|||||||
buf = buf.replace(/[ ]/g, "​ ​");
|
buf = buf.replace(/[ ]/g, "​ ​");
|
||||||
return buf.replace(/\n/g, "<br />");
|
return buf.replace(/\n/g, "<br />");
|
||||||
};
|
};
|
||||||
|
|
||||||
makeCursor = function(pos, klass, color) {
|
makeCursor = function(pos, klass, color) {
|
||||||
var l;
|
var l;
|
||||||
l = val.substring(pos, pos + 1);
|
l = val.substring(pos, pos + 1);
|
||||||
if (l === "\n") {
|
if (l === "\n") return "<br>";
|
||||||
return "<br>";
|
|
||||||
}
|
|
||||||
return "<span class='" + klass + "' style='background-color:" + color + "; margin:0; padding: 0'>" + guard(l) + "</span>";
|
return "<span class='" + klass + "' style='background-color:" + color + "; margin:0; padding: 0'>" + guard(l) + "</span>";
|
||||||
};
|
};
|
||||||
|
|
||||||
html = "";
|
html = "";
|
||||||
if (before >= 0) {
|
if (before >= 0) {
|
||||||
html += guard(val.substring(0, pos - 1)) + makeCursor(before, "before", "#d0ffff");
|
html += guard(val.substring(0, pos - 1)) + makeCursor(before, "before", "#d0ffff");
|
||||||
@ -106,12 +109,14 @@
|
|||||||
html += makeCursor(0, "post-before", "#d0ffff");
|
html += makeCursor(0, "post-before", "#d0ffff");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (after >= 0) {
|
if (after >= 0) {
|
||||||
html += makeCursor(after, "after", "#ffd0ff");
|
html += makeCursor(after, "after", "#ffd0ff");
|
||||||
if (after - 1 < val.length) {
|
if (after - 1 < val.length) {
|
||||||
html += guard(val.substring(after + 1));
|
html += guard(val.substring(after + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.html(html);
|
p.html(html);
|
||||||
clone.scrollTop(textarea.scrollTop());
|
clone.scrollTop(textarea.scrollTop());
|
||||||
letter = p.find("span:first");
|
letter = p.find("span:first");
|
||||||
@ -119,17 +124,11 @@
|
|||||||
if (letter.hasClass("before")) {
|
if (letter.hasClass("before")) {
|
||||||
pos.left = pos.left + letter.width();
|
pos.left = pos.left + letter.width();
|
||||||
}
|
}
|
||||||
|
|
||||||
pPos = p.offset();
|
pPos = p.offset();
|
||||||
return {
|
return {
|
||||||
/*clone.hide().remove()
|
|
||||||
*/
|
|
||||||
|
|
||||||
left: pos.left - pPos.left,
|
left: pos.left - pPos.left,
|
||||||
top: (pos.top - pPos.top) - clone.scrollTop()
|
top: (pos.top - pPos.top) - clone.scrollTop()
|
||||||
};
|
};
|
||||||
};
|
|
||||||
return $.fn.caretPosition;
|
|
||||||
|
|
||||||
})(jQuery);
|
};
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,51 +1,49 @@
|
|||||||
|
/**
|
||||||
|
Used for tracking when the user clicks on a link
|
||||||
|
|
||||||
/* We use this object to keep track of click counts.
|
@class ClickTrack
|
||||||
*/
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ClickTrack = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Track a click on a link
|
||||||
|
|
||||||
(function() {
|
@method trackClick
|
||||||
|
@param {jQuery.Event} e The click event that occurred
|
||||||
window.Discourse.ClickTrack = {
|
**/
|
||||||
/* Pass the event of the click here and we'll do the magic!
|
|
||||||
*/
|
|
||||||
|
|
||||||
trackClick: function(e) {
|
trackClick: function(e) {
|
||||||
var $a, $article, $badge, count, destination, href, ownLink, postId, topicId, trackingUrl, userId;
|
var $a, $article, $badge, count, destination, href, ownLink, postId, topicId, trackingUrl, userId;
|
||||||
$a = jQuery(e.currentTarget);
|
$a = $(e.currentTarget);
|
||||||
if ($a.hasClass('lightbox')) {
|
if ($a.hasClass('lightbox')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
/* We don't track clicks on quote back buttons
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ($a.hasClass('back') || $a.hasClass('quote-other-topic')) {
|
// We don't track clicks on quote back buttons
|
||||||
return true;
|
if ($a.hasClass('back') || $a.hasClass('quote-other-topic')) return true;
|
||||||
}
|
|
||||||
/* Remove the href, put it as a data attribute
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Remove the href, put it as a data attribute
|
||||||
if (!$a.data('href')) {
|
if (!$a.data('href')) {
|
||||||
$a.addClass('no-href');
|
$a.addClass('no-href');
|
||||||
$a.data('href', $a.attr('href'));
|
$a.data('href', $a.attr('href'));
|
||||||
$a.attr('href', null);
|
$a.attr('href', null);
|
||||||
/* Don't route to this URL
|
// Don't route to this URL
|
||||||
*/
|
|
||||||
|
|
||||||
$a.data('auto-route', true);
|
$a.data('auto-route', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
href = $a.data('href');
|
href = $a.data('href');
|
||||||
$article = $a.closest('article');
|
$article = $a.closest('article');
|
||||||
postId = $article.data('post-id');
|
postId = $article.data('post-id');
|
||||||
topicId = jQuery('#topic').data('topic-id');
|
topicId = $('#topic').data('topic-id');
|
||||||
userId = $a.data('user-id');
|
userId = $a.data('user-id');
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
userId = $article.data('user-id');
|
userId = $article.data('user-id');
|
||||||
}
|
}
|
||||||
ownLink = userId && (userId === Discourse.get('currentUser.id'));
|
ownLink = userId && (userId === Discourse.get('currentUser.id'));
|
||||||
/* Build a Redirect URL
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Build a Redirect URL
|
||||||
trackingUrl = "/clicks/track?url=" + encodeURIComponent(href);
|
trackingUrl = "/clicks/track?url=" + encodeURIComponent(href);
|
||||||
if (postId && (!$a.data('ignore-post-id'))) {
|
if (postId && (!$a.data('ignore-post-id'))) {
|
||||||
trackingUrl += "&post_id=" + encodeURI(postId);
|
trackingUrl += "&post_id=" + encodeURI(postId);
|
||||||
@ -53,27 +51,24 @@
|
|||||||
if (topicId) {
|
if (topicId) {
|
||||||
trackingUrl += "&topic_id=" + encodeURI(topicId);
|
trackingUrl += "&topic_id=" + encodeURI(topicId);
|
||||||
}
|
}
|
||||||
/* Update badge clicks unless it's our own
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Update badge clicks unless it's our own
|
||||||
if (!ownLink) {
|
if (!ownLink) {
|
||||||
$badge = jQuery('span.badge', $a);
|
$badge = $('span.badge', $a);
|
||||||
if ($badge.length === 1) {
|
if ($badge.length === 1) {
|
||||||
count = parseInt($badge.html(), 10);
|
count = parseInt($badge.html(), 10);
|
||||||
$badge.html(count + 1);
|
$badge.html(count + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* If they right clicked, change the destination href
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If they right clicked, change the destination href
|
||||||
if (e.which === 3) {
|
if (e.which === 3) {
|
||||||
destination = Discourse.SiteSettings.track_external_right_clicks ? trackingUrl : href;
|
destination = Discourse.SiteSettings.track_external_right_clicks ? trackingUrl : href;
|
||||||
$a.attr('href', destination);
|
$a.attr('href', destination);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/* if they want to open in a new tab, do an AJAX request
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// if they want to open in a new tab, do an AJAX request
|
||||||
if (e.metaKey || e.ctrlKey || e.which === 2) {
|
if (e.metaKey || e.ctrlKey || e.which === 2) {
|
||||||
jQuery.get("/clicks/track", {
|
jQuery.get("/clicks/track", {
|
||||||
url: href,
|
url: href,
|
||||||
@ -84,9 +79,8 @@
|
|||||||
window.open(href, '_blank');
|
window.open(href, '_blank');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* If we're on the same site, use the router and track via AJAX
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If we're on the same site, use the router and track via AJAX
|
||||||
if (href.indexOf(window.location.origin) === 0) {
|
if (href.indexOf(window.location.origin) === 0) {
|
||||||
jQuery.get("/clicks/track", {
|
jQuery.get("/clicks/track", {
|
||||||
url: href,
|
url: href,
|
||||||
@ -97,12 +91,11 @@
|
|||||||
Discourse.routeTo(href);
|
Discourse.routeTo(href);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* Otherwise, use a custom URL with a redirect
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Otherwise, use a custom URL with a redirect
|
||||||
window.location = trackingUrl;
|
window.location = trackingUrl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,4 +1,14 @@
|
|||||||
window.Discourse.debounce = function(func, wait, trickle) {
|
/**
|
||||||
|
Debounce a Javascript function. This means if it's called many times in a time limit it
|
||||||
|
should only be executed once.
|
||||||
|
|
||||||
|
@method debounce
|
||||||
|
@module Discourse
|
||||||
|
@param {function} func The function to debounce
|
||||||
|
@param {Numbers} wait how long to wait
|
||||||
|
@param {Boolean} trickle
|
||||||
|
**/
|
||||||
|
Discourse.debounce = function(func, wait, trickle) {
|
||||||
var timeout;
|
var timeout;
|
||||||
|
|
||||||
timeout = null;
|
timeout = null;
|
||||||
@ -12,7 +22,7 @@ window.Discourse.debounce = function(func, wait, trickle) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (timeout && trickle) {
|
if (timeout && trickle) {
|
||||||
/* already queued, let it through */
|
// already queued, let it through
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
(function() {
|
|
||||||
|
|
||||||
Discourse.TextField = Ember.TextField.extend({
|
|
||||||
attributeBindings: ['autocorrect', 'autocapitalize'],
|
|
||||||
placeholder: (function() {
|
|
||||||
return Em.String.i18n(this.get('placeholderKey'));
|
|
||||||
}).property('placeholderKey')
|
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
|
@ -1,22 +1,23 @@
|
|||||||
|
/**
|
||||||
|
This is a jQuery plugin to support resizing text areas.
|
||||||
|
|
||||||
/*based off text area resizer by Ryan O'Dell : http://plugins.jquery.com/misc/textarea.js
|
Originally based off text area resizer by Ryan O'Dell : http://plugins.jquery.com/misc/textarea.js
|
||||||
*/
|
|
||||||
|
|
||||||
|
@module $.fn.DivResizer
|
||||||
|
**/
|
||||||
|
|
||||||
(function() {
|
var div, endDrag, grip, lastMousePos, min, mousePosition, originalDivHeight, originalPos, performDrag, startDrag, wrappedEndDrag, wrappedPerformDrag;
|
||||||
|
div = void 0;
|
||||||
|
originalPos = void 0;
|
||||||
|
originalDivHeight = void 0;
|
||||||
|
lastMousePos = 0;
|
||||||
|
min = 230;
|
||||||
|
grip = void 0;
|
||||||
|
wrappedEndDrag = void 0;
|
||||||
|
wrappedPerformDrag = void 0;
|
||||||
|
|
||||||
(function($) {
|
startDrag = function(e, opts) {
|
||||||
var div, endDrag, grip, lastMousePos, min, mousePosition, originalDivHeight, originalPos, performDrag, startDrag, wrappedEndDrag, wrappedPerformDrag;
|
div = $(e.data.el);
|
||||||
div = void 0;
|
|
||||||
originalPos = void 0;
|
|
||||||
originalDivHeight = void 0;
|
|
||||||
lastMousePos = 0;
|
|
||||||
min = 230;
|
|
||||||
grip = void 0;
|
|
||||||
wrappedEndDrag = void 0;
|
|
||||||
wrappedPerformDrag = void 0;
|
|
||||||
startDrag = function(e, opts) {
|
|
||||||
div = jQuery(e.data.el);
|
|
||||||
div.addClass('clear-transitions');
|
div.addClass('clear-transitions');
|
||||||
div.blur();
|
div.blur();
|
||||||
lastMousePos = mousePosition(e).y;
|
lastMousePos = mousePosition(e).y;
|
||||||
@ -32,15 +33,16 @@
|
|||||||
return endDrag(e, opts);
|
return endDrag(e, opts);
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
jQuery(document).mousemove(wrappedPerformDrag).mouseup(wrappedEndDrag);
|
$(document).mousemove(wrappedPerformDrag).mouseup(wrappedEndDrag);
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
performDrag = function(e, opts) {
|
|
||||||
|
performDrag = function(e, opts) {
|
||||||
var size, sizePx, thisMousePos;
|
var size, sizePx, thisMousePos;
|
||||||
thisMousePos = mousePosition(e).y;
|
thisMousePos = mousePosition(e).y;
|
||||||
size = originalDivHeight + (originalPos - thisMousePos);
|
size = originalDivHeight + (originalPos - thisMousePos);
|
||||||
lastMousePos = thisMousePos;
|
lastMousePos = thisMousePos;
|
||||||
size = Math.min(size, jQuery(window).height());
|
size = Math.min(size, $(window).height());
|
||||||
size = Math.max(min, size);
|
size = Math.max(min, size);
|
||||||
sizePx = size + "px";
|
sizePx = size + "px";
|
||||||
if (typeof opts.onDrag === "function") {
|
if (typeof opts.onDrag === "function") {
|
||||||
@ -51,29 +53,30 @@
|
|||||||
endDrag(e, opts);
|
endDrag(e, opts);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
endDrag = function(e, opts) {
|
|
||||||
jQuery(document).unbind("mousemove", wrappedPerformDrag).unbind("mouseup", wrappedEndDrag);
|
endDrag = function(e, opts) {
|
||||||
|
$(document).unbind("mousemove", wrappedPerformDrag).unbind("mouseup", wrappedEndDrag);
|
||||||
div.removeClass('clear-transitions');
|
div.removeClass('clear-transitions');
|
||||||
div.focus();
|
div.focus();
|
||||||
if (typeof opts.resize === "function") {
|
if (typeof opts.resize === "function") {
|
||||||
opts.resize();
|
opts.resize();
|
||||||
}
|
}
|
||||||
div = null;
|
div = null;
|
||||||
};
|
};
|
||||||
mousePosition = function(e) {
|
|
||||||
|
mousePosition = function(e) {
|
||||||
return {
|
return {
|
||||||
x: e.clientX + document.documentElement.scrollLeft,
|
x: e.clientX + document.documentElement.scrollLeft,
|
||||||
y: e.clientY + document.documentElement.scrollTop
|
y: e.clientY + document.documentElement.scrollTop
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
$.fn.DivResizer = function(opts) {
|
|
||||||
|
$.fn.DivResizer = function(opts) {
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
var grippie, start, staticOffset;
|
var grippie, start, staticOffset;
|
||||||
div = jQuery(this);
|
div = $(this);
|
||||||
if (div.hasClass("processed")) {
|
if (div.hasClass("processed")) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
div.addClass("processed");
|
div.addClass("processed");
|
||||||
staticOffset = null;
|
staticOffset = null;
|
||||||
start = function() {
|
start = function() {
|
||||||
@ -85,8 +88,4 @@
|
|||||||
el: this
|
el: this
|
||||||
}, start());
|
}, start());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return $.fn.DivResizer;
|
|
||||||
})(jQuery);
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,129 +1,97 @@
|
|||||||
|
/**
|
||||||
|
Track visible elemnts on the screen.
|
||||||
|
|
||||||
/* Track visible elements on the screen
|
You can register for triggers on:
|
||||||
*/
|
|
||||||
|
|
||||||
|
`focusChanged` the top element we're focusing on
|
||||||
|
|
||||||
/* You can register for triggers on:
|
`seenElement` if we've seen the element
|
||||||
*/
|
|
||||||
|
|
||||||
|
@class Eyeline
|
||||||
/* focusChanged: -> the top element we're focusing on
|
@namespace Discourse
|
||||||
*/
|
@module Discourse
|
||||||
|
@uses RSVP.EventTarget
|
||||||
|
**/
|
||||||
/* seenElement: -> if we've seen the element
|
Discourse.Eyeline = function Eyeline(selector) {
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
Discourse.Eyeline = (function() {
|
|
||||||
|
|
||||||
function Eyeline(selector) {
|
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call this whenever we want to consider what is currently being seen by the browser
|
/**
|
||||||
*/
|
Call this whenever you want to consider what is being seen by the browser
|
||||||
|
|
||||||
|
@method update
|
||||||
Eyeline.prototype.update = function() {
|
**/
|
||||||
|
Discourse.Eyeline.prototype.update = function() {
|
||||||
var $elements, $results, atBottom, bottomOffset, docViewBottom, docViewTop, documentHeight, foundElement, windowHeight,
|
var $elements, $results, atBottom, bottomOffset, docViewBottom, docViewTop, documentHeight, foundElement, windowHeight,
|
||||||
_this = this;
|
_this = this;
|
||||||
docViewTop = jQuery(window).scrollTop();
|
|
||||||
windowHeight = jQuery(window).height();
|
docViewTop = $(window).scrollTop();
|
||||||
|
windowHeight = $(window).height();
|
||||||
docViewBottom = docViewTop + windowHeight;
|
docViewBottom = docViewTop + windowHeight;
|
||||||
documentHeight = jQuery(document).height();
|
documentHeight = $(document).height();
|
||||||
$elements = jQuery(this.selector);
|
$elements = $(this.selector);
|
||||||
atBottom = false;
|
atBottom = false;
|
||||||
|
|
||||||
if (bottomOffset = $elements.last().offset()) {
|
if (bottomOffset = $elements.last().offset()) {
|
||||||
atBottom = (bottomOffset.top <= docViewBottom) && (bottomOffset.top >= docViewTop);
|
atBottom = (bottomOffset.top <= docViewBottom) && (bottomOffset.top >= docViewTop);
|
||||||
}
|
}
|
||||||
/* Whether we've seen any elements in this search
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Whether we've seen any elements in this search
|
||||||
foundElement = false;
|
foundElement = false;
|
||||||
$results = jQuery(this.selector);
|
$results = $(this.selector);
|
||||||
return $results.each(function(i, elem) {
|
return $results.each(function(i, elem) {
|
||||||
var $elem, elemBottom, elemTop, markSeen;
|
var $elem, elemBottom, elemTop, markSeen;
|
||||||
$elem = jQuery(elem);
|
$elem = $(elem);
|
||||||
elemTop = $elem.offset().top;
|
elemTop = $elem.offset().top;
|
||||||
elemBottom = elemTop + $elem.height();
|
elemBottom = elemTop + $elem.height();
|
||||||
markSeen = false;
|
markSeen = false;
|
||||||
/* It's seen if...
|
// It's seen if...
|
||||||
*/
|
|
||||||
|
|
||||||
/* ...the element is vertically within the top and botom
|
// ...the element is vertically within the top and botom
|
||||||
*/
|
if ((elemTop <= docViewBottom) && (elemTop >= docViewTop)) markSeen = true;
|
||||||
|
|
||||||
if ((elemTop <= docViewBottom) && (elemTop >= docViewTop)) {
|
// ...the element top is above the top and the bottom is below the bottom (large elements)
|
||||||
markSeen = true;
|
if ((elemTop <= docViewTop) && (elemBottom >= docViewBottom)) markSeen = true;
|
||||||
}
|
|
||||||
/* ...the element top is above the top and the bottom is below the bottom (large elements)
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ((elemTop <= docViewTop) && (elemBottom >= docViewBottom)) {
|
// ...we're at the bottom and the bottom of the element is visible (large bottom elements)
|
||||||
markSeen = true;
|
if (atBottom && (elemBottom >= docViewTop)) markSeen = true;
|
||||||
}
|
|
||||||
/* ...we're at the bottom and the bottom of the element is visible (large bottom elements)
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (atBottom && (elemBottom >= docViewTop)) {
|
if (!markSeen) return true;
|
||||||
markSeen = true;
|
|
||||||
}
|
|
||||||
if (!markSeen) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/* If you hit the bottom we mark all the elements as seen. Otherwise, just the first one
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If you hit the bottom we mark all the elements as seen. Otherwise, just the first one
|
||||||
if (!atBottom) {
|
if (!atBottom) {
|
||||||
_this.trigger('saw', {
|
_this.trigger('saw', {
|
||||||
detail: $elem
|
detail: $elem
|
||||||
});
|
});
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
_this.trigger('sawTop', {
|
_this.trigger('sawTop', { detail: $elem });
|
||||||
detail: $elem
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
_this.trigger('sawTop', {
|
_this.trigger('sawTop', { detail: $elem });
|
||||||
detail: $elem
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (i === ($results.length - 1)) {
|
if (i === ($results.length - 1)) {
|
||||||
return _this.trigger('sawBottom', {
|
return _this.trigger('sawBottom', { detail: $elem });
|
||||||
detail: $elem
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 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
|
||||||
|
|
||||||
|
@method flushRest
|
||||||
Eyeline.prototype.flushRest = function() {
|
**/
|
||||||
|
Discourse.Eyeline.prototype.flushRest = function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery(this.selector).each(function(i, elem) {
|
return $(this.selector).each(function(i, elem) {
|
||||||
var $elem;
|
var $elem;
|
||||||
$elem = jQuery(elem);
|
$elem = $(elem);
|
||||||
return _this.trigger('saw', {
|
return _this.trigger('saw', { detail: $elem });
|
||||||
detail: $elem
|
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return Eyeline;
|
RSVP.EventTarget.mixin(Discourse.Eyeline.prototype);
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
RSVP.EventTarget.mixin(Discourse.Eyeline.prototype);
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
|
/**
|
||||||
|
A simple key value store that uses LocalStorage
|
||||||
|
|
||||||
/* key value store
|
@class KeyValueStore
|
||||||
*/
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.KeyValueStore = {
|
||||||
|
initialized: false,
|
||||||
|
context: "",
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
window.Discourse.KeyValueStore = (function() {
|
|
||||||
var context, initialized;
|
|
||||||
initialized = false;
|
|
||||||
context = "";
|
|
||||||
return {
|
|
||||||
init: function(ctx, messageBus) {
|
init: function(ctx, messageBus) {
|
||||||
initialized = true;
|
initialized = true;
|
||||||
context = ctx;
|
context = ctx;
|
||||||
},
|
},
|
||||||
|
|
||||||
abandonLocal: function() {
|
abandonLocal: function() {
|
||||||
var i, k;
|
var i, k;
|
||||||
if (!(localStorage && initialized)) {
|
if (!(localStorage && initialized)) {
|
||||||
@ -29,22 +29,23 @@
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
remove: function(key) {
|
remove: function(key) {
|
||||||
return localStorage.removeItem(context + key);
|
return localStorage.removeItem(context + key);
|
||||||
},
|
},
|
||||||
|
|
||||||
set: function(opts) {
|
set: function(opts) {
|
||||||
if (!(localStorage && initialized)) {
|
if (!(localStorage && initialized)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
localStorage[context + opts.key] = opts.value;
|
localStorage[context + opts.key] = opts.value;
|
||||||
},
|
},
|
||||||
|
|
||||||
get: function(key) {
|
get: function(key) {
|
||||||
if (!localStorage) {
|
if (!localStorage) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return localStorage[context + key];
|
return localStorage[context + key];
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
})();
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
|
/**
|
||||||
|
Helper object for lightboxes.
|
||||||
|
|
||||||
/* Helper object for light boxes. Uses highlight.js which is loaded
|
@class Lightbox
|
||||||
*/
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
/* on demand.
|
Discourse.Lightbox = {
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
window.Discourse.Lightbox = {
|
|
||||||
apply: function($elem) {
|
apply: function($elem) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery('a.lightbox', $elem).each(function(i, e) {
|
return $('a.lightbox', $elem).each(function(i, e) {
|
||||||
return $LAB.script("/javascripts/jquery.colorbox-min.js").wait(function() {
|
return $LAB.script("/javascripts/jquery.colorbox-min.js").wait(function() {
|
||||||
return jQuery(e).colorbox();
|
return $(e).colorbox();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
59
app/assets/javascripts/discourse/components/mention.js
Normal file
59
app/assets/javascripts/discourse/components/mention.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
Helps us determine whether someone has been mentioned by looking up their username.
|
||||||
|
|
||||||
|
@class Mention
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Mention = (function() {
|
||||||
|
var cache, load, localCache, lookup, lookupCache;
|
||||||
|
localCache = {};
|
||||||
|
cache = function(name, valid) {
|
||||||
|
localCache[name] = valid;
|
||||||
|
};
|
||||||
|
lookupCache = function(name) {
|
||||||
|
return localCache[name];
|
||||||
|
};
|
||||||
|
lookup = function(name, callback) {
|
||||||
|
var cached;
|
||||||
|
cached = lookupCache(name);
|
||||||
|
if (cached === true || cached === false) {
|
||||||
|
callback(cached);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
jQuery.get("/users/is_local_username", {
|
||||||
|
username: name
|
||||||
|
}, function(r) {
|
||||||
|
cache(name, r.valid);
|
||||||
|
return callback(r.valid);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
load = function(e) {
|
||||||
|
var $elem, loading, username;
|
||||||
|
$elem = $(e);
|
||||||
|
if ($elem.data('mention-tested')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
username = $elem.text();
|
||||||
|
username = username.substr(1);
|
||||||
|
loading = lookup(username, function(valid) {
|
||||||
|
if (valid) {
|
||||||
|
return $elem.replaceWith("<a href='/users/" + (username.toLowerCase()) + "' class='mention'>@" + username + "</a>");
|
||||||
|
} else {
|
||||||
|
return $elem.removeClass('mention-loading').addClass('mention-tested');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (loading) {
|
||||||
|
return $elem.addClass('mention-loading');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
load: load,
|
||||||
|
lookup: lookup,
|
||||||
|
lookupCache: lookupCache
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
@ -1,11 +1,16 @@
|
|||||||
/*jshint bitwise: false*/
|
/*jshint bitwise: false*/
|
||||||
(function() {
|
|
||||||
|
|
||||||
window.Discourse.MessageBus = (function() {
|
/**
|
||||||
/* http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
Message Bus functionality.
|
||||||
*/
|
|
||||||
|
|
||||||
|
@class MessageBus
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.MessageBus = (function() {
|
||||||
|
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
||||||
var callbacks, clientId, failCount, interval, isHidden, queue, responseCallbacks, uniqueId;
|
var callbacks, clientId, failCount, interval, isHidden, queue, responseCallbacks, uniqueId;
|
||||||
|
|
||||||
uniqueId = function() {
|
uniqueId = function() {
|
||||||
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||||
var r, v;
|
var r, v;
|
||||||
@ -14,12 +19,14 @@
|
|||||||
return v.toString(16);
|
return v.toString(16);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
clientId = uniqueId();
|
clientId = uniqueId();
|
||||||
responseCallbacks = {};
|
responseCallbacks = {};
|
||||||
callbacks = [];
|
callbacks = [];
|
||||||
queue = [];
|
queue = [];
|
||||||
interval = null;
|
interval = null;
|
||||||
failCount = 0;
|
failCount = 0;
|
||||||
|
|
||||||
isHidden = function() {
|
isHidden = function() {
|
||||||
if (document.hidden !== void 0) {
|
if (document.hidden !== void 0) {
|
||||||
return document.hidden;
|
return document.hidden;
|
||||||
@ -30,29 +37,26 @@
|
|||||||
} else if (document.mozHidden !== void 0) {
|
} else if (document.mozHidden !== void 0) {
|
||||||
return document.mozHidden;
|
return document.mozHidden;
|
||||||
} else {
|
} else {
|
||||||
/* fallback to problamatic window.focus
|
// fallback to problamatic window.focus
|
||||||
*/
|
|
||||||
|
|
||||||
return !Discourse.get('hasFocus');
|
return !Discourse.get('hasFocus');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enableLongPolling: true,
|
enableLongPolling: true,
|
||||||
callbackInterval: 60000,
|
callbackInterval: 60000,
|
||||||
maxPollInterval: 3 * 60 * 1000,
|
maxPollInterval: 3 * 60 * 1000,
|
||||||
callbacks: callbacks,
|
callbacks: callbacks,
|
||||||
clientId: clientId,
|
clientId: clientId,
|
||||||
/*TODO
|
|
||||||
*/
|
|
||||||
|
|
||||||
stop: false,
|
stop: false,
|
||||||
/* Start polling
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Start polling
|
||||||
start: function(opts) {
|
start: function(opts) {
|
||||||
var poll,
|
var poll,
|
||||||
_this = this;
|
_this = this;
|
||||||
if (!opts) opts = {};
|
if (!opts) opts = {};
|
||||||
|
|
||||||
poll = function() {
|
poll = function() {
|
||||||
var data, gotData;
|
var data, gotData;
|
||||||
if (callbacks.length === 0) {
|
if (callbacks.length === 0) {
|
||||||
@ -117,9 +121,8 @@
|
|||||||
};
|
};
|
||||||
poll();
|
poll();
|
||||||
},
|
},
|
||||||
/* Subscribe to a channel
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Subscribe to a channel
|
||||||
subscribe: function(channel, func, lastId) {
|
subscribe: function(channel, func, lastId) {
|
||||||
callbacks.push({
|
callbacks.push({
|
||||||
channel: channel,
|
channel: channel,
|
||||||
@ -130,13 +133,10 @@
|
|||||||
return this.longPoll.abort();
|
return this.longPoll.abort();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* Unsubscribe from a channel
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Unsubscribe from a channel
|
||||||
unsubscribe: function(channel) {
|
unsubscribe: function(channel) {
|
||||||
/* TODO proper globbing
|
// TODO proper globbing
|
||||||
*/
|
|
||||||
|
|
||||||
var glob;
|
var glob;
|
||||||
if (channel.endsWith("*")) {
|
if (channel.endsWith("*")) {
|
||||||
channel = channel.substr(0, channel.length - 1);
|
channel = channel.substr(0, channel.length - 1);
|
||||||
@ -154,6 +154,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
}).call(this);
|
|
89
app/assets/javascripts/discourse/components/onebox.js
Normal file
89
app/assets/javascripts/discourse/components/onebox.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
A helper for looking up oneboxes and displaying them
|
||||||
|
|
||||||
|
For now it only stores in a var, in future we can change it so it uses localStorage.
|
||||||
|
|
||||||
|
@class Notification
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Onebox = (function() {
|
||||||
|
|
||||||
|
var cache, load, localCache, lookup, lookupCache;
|
||||||
|
localCache = {};
|
||||||
|
|
||||||
|
cache = function(url, contents) {
|
||||||
|
localCache[url] = contents;
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
lookupCache = function(url) {
|
||||||
|
var cached;
|
||||||
|
cached = localCache[url];
|
||||||
|
if (cached && cached.then) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
lookup = function(url, refresh, callback) {
|
||||||
|
var cached;
|
||||||
|
cached = localCache[url];
|
||||||
|
if (refresh && cached && !cached.then) {
|
||||||
|
cached = null;
|
||||||
|
}
|
||||||
|
if (cached) {
|
||||||
|
if (cached.then) {
|
||||||
|
cached.then(callback(lookupCache(url)));
|
||||||
|
} else {
|
||||||
|
callback(cached);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
cache(url, jQuery.get("/onebox", {
|
||||||
|
url: url,
|
||||||
|
refresh: refresh
|
||||||
|
}, function(html) {
|
||||||
|
cache(url, html);
|
||||||
|
return callback(html);
|
||||||
|
}));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
load = function(e, refresh) {
|
||||||
|
var $elem, loading, url;
|
||||||
|
if (!refresh) refresh = false;
|
||||||
|
|
||||||
|
url = e.href;
|
||||||
|
$elem = $(e);
|
||||||
|
if ($elem.data('onebox-loaded')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loading = lookup(url, refresh, function(html) {
|
||||||
|
$elem.removeClass('loading-onebox');
|
||||||
|
$elem.data('onebox-loaded');
|
||||||
|
if (!html) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (html.trim().length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return $elem.replaceWith(html);
|
||||||
|
});
|
||||||
|
if (loading) {
|
||||||
|
return $elem.addClass('loading-onebox');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
load: load,
|
||||||
|
lookup: lookup,
|
||||||
|
lookupCache: lookupCache
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
|||||||
/*global Markdown:true*/
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
window.Discourse.PagedownEditor = Ember.ContainerView.extend({
|
|
||||||
elementId: 'pagedown-editor',
|
|
||||||
init: function() {
|
|
||||||
this._super();
|
|
||||||
/* Add a button bar
|
|
||||||
*/
|
|
||||||
|
|
||||||
this.pushObject(Em.View.create({
|
|
||||||
elementId: 'wmd-button-bar'
|
|
||||||
}));
|
|
||||||
this.pushObject(Em.TextArea.create({
|
|
||||||
valueBinding: 'parentView.value',
|
|
||||||
elementId: 'wmd-input'
|
|
||||||
}));
|
|
||||||
return this.pushObject(Em.View.createWithMixins(Discourse.Presence, {
|
|
||||||
elementId: 'wmd-preview',
|
|
||||||
classNameBindings: [':preview', 'hidden'],
|
|
||||||
hidden: (function() {
|
|
||||||
return this.blank('parentView.value');
|
|
||||||
}).property('parentView.value')
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
didInsertElement: function() {
|
|
||||||
var $wmdInput;
|
|
||||||
$wmdInput = jQuery('#wmd-input');
|
|
||||||
$wmdInput.data('init', true);
|
|
||||||
this.editor = new Markdown.Editor(Discourse.Utilities.markdownConverter({
|
|
||||||
sanitize: true
|
|
||||||
}));
|
|
||||||
return this.editor.run();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
|
@ -5,27 +5,26 @@
|
|||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
|
*
|
||||||
someFunction = window.probes.measure(someFunction, {
|
* someFunction = window.probes.measure(someFunction, {
|
||||||
name: "somename" // or function(args) { return "name"; },
|
* name: "somename" // or function(args) { return "name"; },
|
||||||
before: function(data, owner, args) {
|
* before: function(data, owner, args) {
|
||||||
// if owner is true, we are not in a recursive function call.
|
* // if owner is true, we are not in a recursive function call.
|
||||||
//
|
* //
|
||||||
// data contains the bucker of data already measuer
|
* // data contains the bucker of data already measuer
|
||||||
// data.count >= 0
|
* // data.count >= 0
|
||||||
// data.time is the total time measured till now
|
* // data.time is the total time measured till now
|
||||||
//
|
* //
|
||||||
// arguments contains the original arguments sent to the function
|
* // arguments contains the original arguments sent to the function
|
||||||
},
|
* },
|
||||||
after: function(data, owner, args) {
|
* after: function(data, owner, args) {
|
||||||
// same format as before
|
* // same format as before
|
||||||
}
|
* }
|
||||||
});
|
* });
|
||||||
|
*
|
||||||
|
*
|
||||||
// minimal
|
* // minimal
|
||||||
someFunction = window.probes.measure(someFunction, "someFunction");
|
* someFunction = window.probes.measure(someFunction, "someFunction");
|
||||||
|
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* */
|
* */
|
||||||
|
@ -1,92 +0,0 @@
|
|||||||
// Sam: I wrote this but it is totally unsafe so I ported Google Cajole
|
|
||||||
// Thing is Cajole is old and complex (albeit super duper fast)
|
|
||||||
//
|
|
||||||
// I would like this ported to: https://github.com/tautologistics/node-htmlparser , perf tested
|
|
||||||
// and move off cajole
|
|
||||||
//
|
|
||||||
// See also: http://stackoverflow.com/questions/14971083/is-jquerys-safe-from-xss
|
|
||||||
//
|
|
||||||
|
|
||||||
// (function( $ ) {
|
|
||||||
//
|
|
||||||
// var elements = ["a", "abbr", "aside", "b", "bdo", "blockquote", "br",
|
|
||||||
// "caption", "cite", "code", "col", "colgroup", "dd", "div",
|
|
||||||
// "del", "dfn", "dl", "dt", "em", "hr", "figcaption", "figure",
|
|
||||||
// "h1", "h2", "h3", "h4", "h5", "h6", "hgroup", "i", "img", "ins",
|
|
||||||
// "kbd", "li", "mark", "ol", "p", "pre", "q", "rp", "rt", "ruby",
|
|
||||||
// "s", "samp", "small", "span", "strike", "strong", "sub", "sup",
|
|
||||||
// "table", "tbody", "td", "tfoot", "th", "thead", "time", "tr", "u",
|
|
||||||
// "ul", "var", "wbr"];
|
|
||||||
//
|
|
||||||
// var attributes = {
|
|
||||||
// 'all' : ['dir', 'lang', 'title', 'class'],
|
|
||||||
// 'aside' : ['data-post', 'data-full', 'data-topic'],
|
|
||||||
// 'a' : ['href'],
|
|
||||||
// 'blockquote' : ['cite'],
|
|
||||||
// 'col' : ['span', 'width'],
|
|
||||||
// 'colgroup' : ['span', 'width'],
|
|
||||||
// 'del' : ['cite', 'datetime'],
|
|
||||||
// 'img' : ['align', 'alt', 'height', 'src', 'width'],
|
|
||||||
// 'ins' : ['cite', 'datetime'],
|
|
||||||
// 'ol' : ['start', 'reversed', 'type'],
|
|
||||||
// 'q' : ['cite'],
|
|
||||||
// 'span' : ['style'],
|
|
||||||
// 'table' : ['summary', 'width', 'style', 'cellpadding', 'cellspacing'],
|
|
||||||
// 'td' : ['abbr', 'axis', 'colspan', 'rowspan', 'width', 'style'],
|
|
||||||
// 'th' : ['abbr', 'axis', 'colspan', 'rowspan', 'scope', 'width', 'style'],
|
|
||||||
// 'time' : ['datetime', 'pubdate'],
|
|
||||||
// 'ul' : ['type']
|
|
||||||
//
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// var elementMap = {};
|
|
||||||
// jQuery.each(elements, function(idx,e){
|
|
||||||
// elementMap[e] = true;
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// var scrubAttributes = function(e){
|
|
||||||
// jQuery.each(e.attributes, function(idx, attr){
|
|
||||||
//
|
|
||||||
// if(jQuery.inArray(attr.name, attributes.all) === -1 &&
|
|
||||||
// jQuery.inArray(attr.name, attributes[e.tagName.toLowerCase()]) === -1) {
|
|
||||||
// e.removeAttribute(attr.name);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// return(e);
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// var scrubNode = function(e){
|
|
||||||
// if (!e.tagName) { return(e); }
|
|
||||||
// if(elementMap[e.tagName.toLowerCase()]){
|
|
||||||
// return scrubAttributes(e);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// var scrubTree = function(e) {
|
|
||||||
// if (!e) { return; }
|
|
||||||
//
|
|
||||||
// var clean = scrubNode(e);
|
|
||||||
// if(!clean){
|
|
||||||
// e.parentNode.removeChild(e);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// jQuery.each(clean.children, function(idx, inner){
|
|
||||||
// scrubTree(inner);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// $.fn.sanitize = function() {
|
|
||||||
// clean = this.filter(function(){
|
|
||||||
// return scrubNode(this);
|
|
||||||
// }).each(function(){
|
|
||||||
// scrubTree(this);
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// return clean;
|
|
||||||
// };
|
|
||||||
// })( jQuery );
|
|
@ -1,52 +1,47 @@
|
|||||||
|
/**
|
||||||
|
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
|
||||||
*/
|
@extends Ember.Object
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
/* This could be a potentially awesome metric to keep track of.
|
**/
|
||||||
*/
|
Discourse.ScreenTrack = Ember.Object.extend({
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
window.Discourse.ScreenTrack = Ember.Object.extend({
|
|
||||||
/* Don't send events if we haven't scrolled in a long time
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Don't send events if we haven't scrolled in a long time
|
||||||
PAUSE_UNLESS_SCROLLED: 1000 * 60 * 3,
|
PAUSE_UNLESS_SCROLLED: 1000 * 60 * 3,
|
||||||
/* After 6 minutes stop tracking read position on post
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// After 6 minutes stop tracking read position on post
|
||||||
MAX_TRACKING_TIME: 1000 * 60 * 6,
|
MAX_TRACKING_TIME: 1000 * 60 * 6,
|
||||||
totalTimings: {},
|
|
||||||
/* Elements to track
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
totalTimings: {},
|
||||||
|
|
||||||
|
// Elements to track
|
||||||
timings: {},
|
timings: {},
|
||||||
topicTime: 0,
|
topicTime: 0,
|
||||||
cancelled: false,
|
cancelled: false,
|
||||||
|
|
||||||
track: function(elementId, postNumber) {
|
track: function(elementId, postNumber) {
|
||||||
this.timings["#" + elementId] = {
|
this.timings["#" + elementId] = {
|
||||||
time: 0,
|
time: 0,
|
||||||
postNumber: postNumber
|
postNumber: postNumber
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
guessedSeen: function(postNumber) {
|
guessedSeen: function(postNumber) {
|
||||||
if (postNumber > (this.highestSeen || 0)) {
|
if (postNumber > (this.highestSeen || 0)) {
|
||||||
this.highestSeen = postNumber;
|
this.highestSeen = postNumber;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* Reset our timers
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Reset our timers
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.lastTick = new Date().getTime();
|
this.lastTick = new Date().getTime();
|
||||||
this.lastFlush = 0;
|
this.lastFlush = 0;
|
||||||
this.cancelled = false;
|
this.cancelled = false;
|
||||||
},
|
},
|
||||||
/* Start tracking
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Start tracking
|
||||||
start: function() {
|
start: function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this.reset();
|
this.reset();
|
||||||
@ -55,9 +50,8 @@
|
|||||||
return _this.tick();
|
return _this.tick();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
},
|
},
|
||||||
/* Cancel and eject any tracking we have buffered
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Cancel and eject any tracking we have buffered
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
this.cancelled = true;
|
this.cancelled = true;
|
||||||
this.timings = {};
|
this.timings = {};
|
||||||
@ -65,26 +59,25 @@
|
|||||||
clearInterval(this.interval);
|
clearInterval(this.interval);
|
||||||
this.interval = null;
|
this.interval = null;
|
||||||
},
|
},
|
||||||
/* Stop tracking and flush buffered read records
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Stop tracking and flush buffered read records
|
||||||
stop: function() {
|
stop: function() {
|
||||||
clearInterval(this.interval);
|
clearInterval(this.interval);
|
||||||
this.interval = null;
|
this.interval = null;
|
||||||
return this.flush();
|
return this.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
scrolled: function() {
|
scrolled: function() {
|
||||||
this.lastScrolled = new Date().getTime();
|
this.lastScrolled = new Date().getTime();
|
||||||
},
|
},
|
||||||
|
|
||||||
flush: function() {
|
flush: function() {
|
||||||
var highestSeenByTopic, newTimings, topicId,
|
var highestSeenByTopic, newTimings, topicId,
|
||||||
_this = this;
|
_this = this;
|
||||||
if (this.cancelled) {
|
if (this.cancelled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* We don't log anything unless we're logged in
|
// We don't log anything unless we're logged in
|
||||||
*/
|
|
||||||
|
|
||||||
if (!Discourse.get('currentUser')) {
|
if (!Discourse.get('currentUser')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -122,10 +115,9 @@
|
|||||||
}
|
}
|
||||||
this.lastFlush = 0;
|
this.lastFlush = 0;
|
||||||
},
|
},
|
||||||
tick: function() {
|
|
||||||
/* If the user hasn't scrolled the browser in a long time, stop tracking time read
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
tick: function() {
|
||||||
|
// If the user hasn't scrolled the browser in a long time, stop tracking time read
|
||||||
var diff, docViewBottom, docViewTop, sinceScrolled,
|
var diff, docViewBottom, docViewTop, sinceScrolled,
|
||||||
_this = this;
|
_this = this;
|
||||||
sinceScrolled = new Date().getTime() - this.lastScrolled;
|
sinceScrolled = new Date().getTime() - this.lastScrolled;
|
||||||
@ -139,24 +131,21 @@
|
|||||||
if (this.lastFlush > (Discourse.SiteSettings.flush_timings_secs * 1000)) {
|
if (this.lastFlush > (Discourse.SiteSettings.flush_timings_secs * 1000)) {
|
||||||
this.flush();
|
this.flush();
|
||||||
}
|
}
|
||||||
/* Don't track timings if we're not in focus
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!Discourse.get("hasFocus")) {
|
// Don't track timings if we're not in focus
|
||||||
return;
|
if (!Discourse.get("hasFocus")) return;
|
||||||
}
|
|
||||||
this.topicTime += diff;
|
this.topicTime += diff;
|
||||||
docViewTop = jQuery(window).scrollTop() + jQuery('header').height();
|
docViewTop = $(window).scrollTop() + $('header').height();
|
||||||
docViewBottom = docViewTop + jQuery(window).height();
|
docViewBottom = docViewTop + $(window).height();
|
||||||
return Object.keys(this.timings, function(id) {
|
return Object.keys(this.timings, function(id) {
|
||||||
var $element, elemBottom, elemTop, timing;
|
var $element, elemBottom, elemTop, timing;
|
||||||
$element = jQuery(id);
|
$element = $(id);
|
||||||
if ($element.length === 1) {
|
if ($element.length === 1) {
|
||||||
elemTop = $element.offset().top;
|
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
|
||||||
if (((docViewTop <= elemTop && elemTop <= docViewBottom)) || ((docViewTop <= elemBottom && elemBottom <= docViewBottom))) {
|
if (((docViewTop <= elemTop && elemTop <= docViewBottom)) || ((docViewTop <= elemBottom && elemBottom <= docViewBottom))) {
|
||||||
timing = _this.timings[id];
|
timing = _this.timings[id];
|
||||||
timing.time = timing.time + diff;
|
timing.time = timing.time + diff;
|
||||||
@ -164,6 +153,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,18 +1,28 @@
|
|||||||
/*global hljs:true */
|
/*global hljs:true */
|
||||||
|
|
||||||
/* Helper object for syntax highlighting. Uses highlight.js which is loaded
|
/**
|
||||||
on demand. */
|
Helper object for syntax highlighting. Uses highlight.js which is loaded on demand.
|
||||||
(function() {
|
|
||||||
|
|
||||||
window.Discourse.SyntaxHighlighting = {
|
@class SyntaxHighlighting
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.SyntaxHighlighting = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Apply syntax highlighting to a jQuery element
|
||||||
|
|
||||||
|
@method apply
|
||||||
|
@param {jQuery.selector} $elem The element we want to apply our highlighting to
|
||||||
|
**/
|
||||||
apply: function($elem) {
|
apply: function($elem) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery('pre code[class]', $elem).each(function(i, e) {
|
return $('pre code[class]', $elem).each(function(i, e) {
|
||||||
return $LAB.script("/javascripts/highlight-handlebars.pack.js").wait(function() {
|
return $LAB.script("/javascripts/highlight-handlebars.pack.js").wait(function() {
|
||||||
return hljs.highlightBlock(e);
|
return hljs.highlightBlock(e);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,29 +1,27 @@
|
|||||||
|
/**
|
||||||
|
CSS transitions are a PITA, often we need to queue some js after a transition, this helper ensures
|
||||||
|
it happens after the transition.
|
||||||
|
|
||||||
/* CSS transitions are a PITA, often we need to queue some js after a transition, this helper ensures
|
SO: http://stackoverflow.com/questions/9943435/css3-animation-end-techniques
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* it happens after the transition
|
@class TransitionHelper
|
||||||
*/
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
|
||||||
|
var dummy, eventNameHash, transitionEnd, _getTransitionEndEventName;
|
||||||
|
|
||||||
/* SO: http://stackoverflow.com/questions/9943435/css3-animation-end-techniques
|
dummy = document.createElement("div");
|
||||||
*/
|
|
||||||
|
|
||||||
|
eventNameHash = {
|
||||||
(function() {
|
|
||||||
var dummy, eventNameHash, transitionEnd, _getTransitionEndEventName;
|
|
||||||
|
|
||||||
dummy = document.createElement("div");
|
|
||||||
|
|
||||||
eventNameHash = {
|
|
||||||
webkit: "webkitTransitionEnd",
|
webkit: "webkitTransitionEnd",
|
||||||
Moz: "transitionend",
|
Moz: "transitionend",
|
||||||
O: "oTransitionEnd",
|
O: "oTransitionEnd",
|
||||||
ms: "MSTransitionEnd"
|
ms: "MSTransitionEnd"
|
||||||
};
|
};
|
||||||
|
|
||||||
_getTransitionEndEventName = function() {
|
_getTransitionEndEventName = function() {
|
||||||
var retValue;
|
var retValue;
|
||||||
retValue = "transitionend";
|
retValue = "transitionend";
|
||||||
Object.keys(eventNameHash).some(function(vendor) {
|
Object.keys(eventNameHash).some(function(vendor) {
|
||||||
@ -33,13 +31,13 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return retValue;
|
return retValue;
|
||||||
};
|
};
|
||||||
transitionEnd = _getTransitionEndEventName();
|
transitionEnd = _getTransitionEndEventName();
|
||||||
|
|
||||||
window.Discourse.TransitionHelper = {
|
window.Discourse.TransitionHelper = {
|
||||||
after: function(element, callback) {
|
after: function(element, callback) {
|
||||||
return jQuery(element).on(transitionEnd, callback);
|
return $(element).on(transitionEnd, callback);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
(function() {
|
/**
|
||||||
var cache, cacheTime, cacheTopicId, debouncedSearch, doSearch;
|
Helper for searching for Users
|
||||||
|
|
||||||
cache = {};
|
@class UserSearch
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
var cache, cacheTime, cacheTopicId, debouncedSearch, doSearch;
|
||||||
|
|
||||||
cacheTopicId = null;
|
cache = {};
|
||||||
|
|
||||||
cacheTime = null;
|
cacheTopicId = null;
|
||||||
|
|
||||||
doSearch = function(term, topicId, success) {
|
cacheTime = null;
|
||||||
|
|
||||||
|
doSearch = function(term, topicId, success) {
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
url: '/users/search/users',
|
url: '/users/search/users',
|
||||||
dataType: 'JSON',
|
dataType: 'JSON',
|
||||||
@ -21,11 +27,11 @@
|
|||||||
return success(r);
|
return success(r);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
debouncedSearch = Discourse.debounce(doSearch, 200);
|
debouncedSearch = Discourse.debounce(doSearch, 200);
|
||||||
|
|
||||||
window.Discourse.UserSearch = {
|
Discourse.UserSearch = {
|
||||||
search: function(options) {
|
search: function(options) {
|
||||||
var callback, exclude, limit, success, term, topicId;
|
var callback, exclude, limit, success, term, topicId;
|
||||||
term = options.term || "";
|
term = options.term || "";
|
||||||
@ -36,9 +42,8 @@
|
|||||||
if (!callback) {
|
if (!callback) {
|
||||||
throw "missing callback";
|
throw "missing callback";
|
||||||
}
|
}
|
||||||
/*TODO site setting for allowed regex in username ?
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// TODO site setting for allowed regex in username
|
||||||
if (term.match(/[^a-zA-Z0-9\_\.]/)) {
|
if (term.match(/[^a-zA-Z0-9\_\.]/)) {
|
||||||
callback([]);
|
callback([]);
|
||||||
return true;
|
return true;
|
||||||
@ -71,6 +76,6 @@
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
/*global sanitizeHtml:true Markdown:true */
|
/*global sanitizeHtml:true Markdown:true */
|
||||||
|
|
||||||
(function() {
|
/**
|
||||||
var baseUrl, site;
|
General utility functions
|
||||||
|
|
||||||
baseUrl = null;
|
@class Utilities
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Utilities = {
|
||||||
|
|
||||||
site = null;
|
|
||||||
|
|
||||||
Discourse.Utilities = {
|
|
||||||
translateSize: function(size) {
|
translateSize: function(size) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 'tiny':
|
case 'tiny':
|
||||||
@ -24,6 +25,7 @@
|
|||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
},
|
},
|
||||||
|
|
||||||
categoryUrlId: function(category) {
|
categoryUrlId: function(category) {
|
||||||
var id, slug;
|
var id, slug;
|
||||||
if (!category) {
|
if (!category) {
|
||||||
@ -36,9 +38,8 @@
|
|||||||
}
|
}
|
||||||
return slug;
|
return slug;
|
||||||
},
|
},
|
||||||
/* Create a badge like category link
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Create a badge like category link
|
||||||
categoryLink: function(category) {
|
categoryLink: function(category) {
|
||||||
var color, name, description, result;
|
var color, name, description, result;
|
||||||
if (!category) return "";
|
if (!category) return "";
|
||||||
@ -48,15 +49,14 @@
|
|||||||
description = Em.get(category, 'description');
|
description = Em.get(category, 'description');
|
||||||
|
|
||||||
// Build the HTML link
|
// Build the HTML link
|
||||||
result = "<a href=\"/category/" +
|
result = "<a href=\"/category/" + this.categoryUrlId(category) + "\" class=\"badge-category\" ";
|
||||||
this.categoryUrlId(category) +
|
|
||||||
"\" class=\"badge-category excerptable\" data-excerpt-size=\"medium\" ";
|
|
||||||
|
|
||||||
// Add description if we have it
|
// Add description if we have it
|
||||||
if (description) result += "title=\"" + description + "\" ";
|
if (description) result += "title=\"" + description + "\" ";
|
||||||
|
|
||||||
return result + "style=\"background-color: #" + color + "\">" + name + "</a>";
|
return result + "style=\"background-color: #" + color + "\">" + name + "</a>";
|
||||||
},
|
},
|
||||||
|
|
||||||
avatarUrl: function(username, size, template) {
|
avatarUrl: function(username, size, template) {
|
||||||
var rawSize;
|
var rawSize;
|
||||||
if (!username) {
|
if (!username) {
|
||||||
@ -69,6 +69,7 @@
|
|||||||
}
|
}
|
||||||
return "/users/" + (username.toLowerCase()) + "/avatar/" + rawSize + "?__ws=" + (encodeURIComponent(Discourse.BaseUrl || ""));
|
return "/users/" + (username.toLowerCase()) + "/avatar/" + rawSize + "?__ws=" + (encodeURIComponent(Discourse.BaseUrl || ""));
|
||||||
},
|
},
|
||||||
|
|
||||||
avatarImg: function(options) {
|
avatarImg: function(options) {
|
||||||
var extraClasses, size, title, url;
|
var extraClasses, size, title, url;
|
||||||
size = Discourse.Utilities.translateSize(options.size);
|
size = Discourse.Utilities.translateSize(options.size);
|
||||||
@ -78,6 +79,7 @@
|
|||||||
return "<img width='" + size + "' height='" + size + "' src='" + url + "' class='avatar " +
|
return "<img width='" + size + "' height='" + size + "' src='" + url + "' class='avatar " +
|
||||||
(extraClasses || "") + "' title='" + (Handlebars.Utils.escapeExpression(title || "")) + "'>";
|
(extraClasses || "") + "' title='" + (Handlebars.Utils.escapeExpression(title || "")) + "'>";
|
||||||
},
|
},
|
||||||
|
|
||||||
postUrl: function(slug, topicId, postNumber) {
|
postUrl: function(slug, topicId, postNumber) {
|
||||||
var url;
|
var url;
|
||||||
url = "/t/";
|
url = "/t/";
|
||||||
@ -90,14 +92,14 @@
|
|||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
emailValid: function(email) {
|
|
||||||
/* see: http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
emailValid: function(email) {
|
||||||
|
// see: http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
|
||||||
var re;
|
var re;
|
||||||
re = /^[a-zA-Z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-zA-Z0-9!#$%&'\*+\/=?\^_`{|}~\-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/;
|
re = /^[a-zA-Z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-zA-Z0-9!#$%&'\*+\/=?\^_`{|}~\-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/;
|
||||||
return re.test(email);
|
return re.test(email);
|
||||||
},
|
},
|
||||||
|
|
||||||
selectedText: function() {
|
selectedText: function() {
|
||||||
var t;
|
var t;
|
||||||
t = '';
|
t = '';
|
||||||
@ -110,9 +112,8 @@
|
|||||||
}
|
}
|
||||||
return String(t).trim();
|
return String(t).trim();
|
||||||
},
|
},
|
||||||
/* Determine the position of the caret in an element
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Determine the position of the caret in an element
|
||||||
caretPosition: function(el) {
|
caretPosition: function(el) {
|
||||||
var r, rc, re;
|
var r, rc, re;
|
||||||
if (el.selectionStart) {
|
if (el.selectionStart) {
|
||||||
@ -131,9 +132,8 @@
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
/* Set the caret's position
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Set the caret's position
|
||||||
setCaretPosition: function(ctrl, pos) {
|
setCaretPosition: function(ctrl, pos) {
|
||||||
var range;
|
var range;
|
||||||
if (ctrl.setSelectionRange) {
|
if (ctrl.setSelectionRange) {
|
||||||
@ -149,6 +149,7 @@
|
|||||||
return range.select();
|
return range.select();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
markdownConverter: function(opts) {
|
markdownConverter: function(opts) {
|
||||||
var converter, mentionLookup,
|
var converter, mentionLookup,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -157,9 +158,8 @@
|
|||||||
mentionLookup = opts.mentionLookup;
|
mentionLookup = opts.mentionLookup;
|
||||||
}
|
}
|
||||||
mentionLookup = mentionLookup || Discourse.Mention.lookupCache;
|
mentionLookup = mentionLookup || Discourse.Mention.lookupCache;
|
||||||
/* Before cooking callbacks
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Before cooking callbacks
|
||||||
converter.hooks.chain("preConversion", function(text) {
|
converter.hooks.chain("preConversion", function(text) {
|
||||||
_this.trigger('beforeCook', {
|
_this.trigger('beforeCook', {
|
||||||
detail: text,
|
detail: text,
|
||||||
@ -167,17 +167,15 @@
|
|||||||
});
|
});
|
||||||
return _this.textResult || text;
|
return _this.textResult || text;
|
||||||
});
|
});
|
||||||
/* Support autolinking of www.something.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Support autolinking of www.something.com
|
||||||
converter.hooks.chain("preConversion", function(text) {
|
converter.hooks.chain("preConversion", function(text) {
|
||||||
return text.replace(/(^|[\s\n])(www\.[a-z\.\-\_\(\)\/\?\=\%0-9]+)/gim, function(full, _, rest) {
|
return text.replace(/(^|[\s\n])(www\.[a-z\.\-\_\(\)\/\?\=\%0-9]+)/gim, function(full, _, rest) {
|
||||||
return " <a href=\"http://" + rest + "\">" + rest + "</a>";
|
return " <a href=\"http://" + rest + "\">" + rest + "</a>";
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
/* newline prediction in trivial cases
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// newline prediction in trivial cases
|
||||||
if (!Discourse.SiteSettings.traditional_markdown_linebreaks) {
|
if (!Discourse.SiteSettings.traditional_markdown_linebreaks) {
|
||||||
converter.hooks.chain("preConversion", function(text) {
|
converter.hooks.chain("preConversion", function(text) {
|
||||||
return text.replace(/(^[\w<][^\n]*\n+)/gim, function(t) {
|
return text.replace(/(^[\w<][^\n]*\n+)/gim, function(t) {
|
||||||
@ -188,9 +186,8 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/* github style fenced code
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// github style fenced code
|
||||||
converter.hooks.chain("preConversion", function(text) {
|
converter.hooks.chain("preConversion", function(text) {
|
||||||
return text.replace(/^`{3}(?:(.*$)\n)?([\s\S]*?)^`{3}/gm, function(wholeMatch, m1, m2) {
|
return text.replace(/^`{3}(?:(.*$)\n)?([\s\S]*?)^`{3}/gm, function(wholeMatch, m1, m2) {
|
||||||
var escaped;
|
var escaped;
|
||||||
@ -198,19 +195,16 @@
|
|||||||
return "<pre><code class='" + (m1 || 'lang-auto') + "'>" + escaped + "</code></pre>";
|
return "<pre><code class='" + (m1 || 'lang-auto') + "'>" + escaped + "</code></pre>";
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
converter.hooks.chain("postConversion", function(text) {
|
|
||||||
if (!text) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
/* don't to mention voodoo in pres
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
converter.hooks.chain("postConversion", function(text) {
|
||||||
|
if (!text) return "";
|
||||||
|
|
||||||
|
// don't to mention voodoo in pres
|
||||||
text = text.replace(/<pre>([\s\S]*@[\s\S]*)<\/pre>/gi, function(wholeMatch, inner) {
|
text = text.replace(/<pre>([\s\S]*@[\s\S]*)<\/pre>/gi, function(wholeMatch, inner) {
|
||||||
return "<pre>" + (inner.replace(/@/g, '@')) + "</pre>";
|
return "<pre>" + (inner.replace(/@/g, '@')) + "</pre>";
|
||||||
});
|
});
|
||||||
/* Add @mentions of names
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Add @mentions of names
|
||||||
text = text.replace(/([\s\t>,:'|";\]])(@[A-Za-z0-9_-|\.]*[A-Za-z0-9_-|]+)(?=[\s\t<\!:|;',"\?\.])/g, function(x, pre, name) {
|
text = text.replace(/([\s\t>,:'|";\]])(@[A-Za-z0-9_-|\.]*[A-Za-z0-9_-|]+)(?=[\s\t<\!:|;',"\?\.])/g, function(x, pre, name) {
|
||||||
if (mentionLookup(name.substr(1))) {
|
if (mentionLookup(name.substr(1))) {
|
||||||
return "" + pre + "<a href='/users/" + (name.substr(1).toLowerCase()) + "' class='mention'>" + name + "</a>";
|
return "" + pre + "<a href='/users/" + (name.substr(1).toLowerCase()) + "' class='mention'>" + name + "</a>";
|
||||||
@ -218,13 +212,10 @@
|
|||||||
return "" + pre + "<span class='mention'>" + name + "</span>";
|
return "" + pre + "<span class='mention'>" + name + "</span>";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
/* a primitive attempt at oneboxing, this regex gives me much eye sores
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// a primitive attempt at oneboxing, this regex gives me much eye sores
|
||||||
text = text.replace(/(<li>)?((<p>|<br>)[\s\n\r]*)(<a href=["]([^"]+)[^>]*)>([^<]+<\/a>[\s\n\r]*(?=<\/p>|<br>))/gi, function() {
|
text = text.replace(/(<li>)?((<p>|<br>)[\s\n\r]*)(<a href=["]([^"]+)[^>]*)>([^<]+<\/a>[\s\n\r]*(?=<\/p>|<br>))/gi, function() {
|
||||||
/* We don't onebox items in a list
|
// We don't onebox items in a list
|
||||||
*/
|
|
||||||
|
|
||||||
var onebox, url;
|
var onebox, url;
|
||||||
if (arguments[1]) {
|
if (arguments[1]) {
|
||||||
return arguments[0];
|
return arguments[0];
|
||||||
@ -246,6 +237,7 @@
|
|||||||
converter.hooks.chain("postConversion", function(text) {
|
converter.hooks.chain("postConversion", function(text) {
|
||||||
return Discourse.BBCode.format(text, opts);
|
return Discourse.BBCode.format(text, opts);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (opts.sanitize) {
|
if (opts.sanitize) {
|
||||||
converter.hooks.chain("postConversion", function(text) {
|
converter.hooks.chain("postConversion", function(text) {
|
||||||
if (!window.sanitizeHtml) {
|
if (!window.sanitizeHtml) {
|
||||||
@ -256,9 +248,8 @@
|
|||||||
}
|
}
|
||||||
return converter;
|
return converter;
|
||||||
},
|
},
|
||||||
/* Takes raw input and cooks it to display nicely (mostly markdown)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Takes raw input and cooks it to display nicely (mostly markdown)
|
||||||
cook: function(raw, opts) {
|
cook: function(raw, opts) {
|
||||||
if (!opts) opts = {};
|
if (!opts) opts = {};
|
||||||
|
|
||||||
@ -270,8 +261,6 @@
|
|||||||
this.converter = this.markdownConverter(opts);
|
this.converter = this.markdownConverter(opts);
|
||||||
return this.converter.makeHtml(raw);
|
return this.converter.makeHtml(raw);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
RSVP.EventTarget.mixin(Discourse.Utilities);
|
RSVP.EventTarget.mixin(Discourse.Utilities);
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,7 +1,16 @@
|
|||||||
/*global _gaq:true */
|
/*global _gaq:true */
|
||||||
|
|
||||||
window.Discourse.ApplicationController = Ember.Controller.extend({
|
/**
|
||||||
|
The base controller for all things Discourse
|
||||||
|
|
||||||
|
@class ApplicationController
|
||||||
|
@extends Discourse.Controller
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ApplicationController = Discourse.Controller.extend({
|
||||||
needs: ['modal'],
|
needs: ['modal'],
|
||||||
|
|
||||||
showLogin: function() {
|
showLogin: function() {
|
||||||
var _ref;
|
var _ref;
|
||||||
return (_ref = this.get('controllers.modal')) ? _ref.show(Discourse.LoginView.create()) : void 0;
|
return (_ref = this.get('controllers.modal')) ? _ref.show(Discourse.LoginView.create()) : void 0;
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports composing new posts and topics.
|
||||||
|
|
||||||
window.Discourse.ComposerController = Ember.Controller.extend(Discourse.Presence, {
|
@class ComposerController
|
||||||
|
@extends Discourse.Controller
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ComposerController = Discourse.Controller.extend({
|
||||||
needs: ['modal', 'topic'],
|
needs: ['modal', 'topic'],
|
||||||
hasReply: false,
|
hasReply: false,
|
||||||
|
|
||||||
togglePreview: function() {
|
togglePreview: function() {
|
||||||
return this.get('content').togglePreview();
|
return this.get('content').togglePreview();
|
||||||
},
|
},
|
||||||
/* Import a quote from the post
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Import a quote from the post
|
||||||
importQuote: function() {
|
importQuote: function() {
|
||||||
return this.get('content').importQuote();
|
return this.get('content').importQuote();
|
||||||
},
|
},
|
||||||
|
|
||||||
appendText: function(text) {
|
appendText: function(text) {
|
||||||
var c;
|
var c;
|
||||||
c = this.get('content');
|
c = this.get('content');
|
||||||
@ -19,6 +26,7 @@
|
|||||||
return c.appendText(text);
|
return c.appendText(text);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
save: function() {
|
save: function() {
|
||||||
var composer,
|
var composer,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -34,36 +42,37 @@
|
|||||||
} else {
|
} else {
|
||||||
Discourse.set('currentUser.reply_count', Discourse.get('currentUser.reply_count') + 1);
|
Discourse.set('currentUser.reply_count', Discourse.get('currentUser.reply_count') + 1);
|
||||||
}
|
}
|
||||||
return Discourse.routeTo(opts.post.get('url'));
|
Discourse.routeTo(opts.post.get('url'));
|
||||||
}, function(error) {
|
}, function(error) {
|
||||||
composer.set('disableDrafts', false);
|
composer.set('disableDrafts', false);
|
||||||
return bootbox.alert(error);
|
bootbox.alert(error);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
checkReplyLength: function() {
|
checkReplyLength: function() {
|
||||||
if (this.present('content.reply')) {
|
if (this.present('content.reply')) {
|
||||||
return this.set('hasReply', true);
|
this.set('hasReply', true);
|
||||||
} else {
|
} else {
|
||||||
return this.set('hasReply', false);
|
this.set('hasReply', false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveDraft: function() {
|
saveDraft: function() {
|
||||||
var model;
|
var model;
|
||||||
model = this.get('content');
|
model = this.get('content');
|
||||||
if (model) {
|
if (model) model.saveDraft();
|
||||||
return model.saveDraft();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
Open the reply view
|
|
||||||
|
|
||||||
opts:
|
/**
|
||||||
action - The action we're performing: edit, reply or createTopic
|
Open the composer view
|
||||||
post - The post we're replying to, if present
|
|
||||||
topic - The topic we're replying to, if present
|
|
||||||
quote - If we're opening a reply from a quote, the quote we're making
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
@method open
|
||||||
|
@param {Object} opts Options for creating a post
|
||||||
|
@param {String} opts.action The action we're performing: edit, reply or createTopic
|
||||||
|
@param {Discourse.Post} [opts.post] The post we're replying to
|
||||||
|
@param {Discourse.Topic} [opts.topic] The topic we're replying to
|
||||||
|
@param {String} [opts.quote] If we're opening a reply from a quote, the quote we're making
|
||||||
|
**/
|
||||||
open: function(opts) {
|
open: function(opts) {
|
||||||
var composer, promise, view,
|
var composer, promise, view,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -75,22 +84,17 @@
|
|||||||
alert("composer was opened without a draft key");
|
alert("composer was opened without a draft key");
|
||||||
throw "composer opened without a proper draft key";
|
throw "composer opened without a proper draft key";
|
||||||
}
|
}
|
||||||
/* ensure we have a view now, without it transitions are going to be messed
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// ensure we have a view now, without it transitions are going to be messed
|
||||||
view = this.get('view');
|
view = this.get('view');
|
||||||
if (!view) {
|
if (!view) {
|
||||||
view = Discourse.ComposerView.create({
|
view = Discourse.ComposerView.create({
|
||||||
controller: this
|
controller: this
|
||||||
});
|
});
|
||||||
view.appendTo(jQuery('#main'));
|
view.appendTo($('#main'));
|
||||||
this.set('view', view);
|
this.set('view', view);
|
||||||
/* the next runloop is too soon, need to get the control rendered and then
|
// the next runloop is too soon, need to get the control rendered and then
|
||||||
*/
|
// we need to change stuff, otherwise css animations don't kick in
|
||||||
|
|
||||||
/* we need to change stuff, otherwise css animations don't kick in
|
|
||||||
*/
|
|
||||||
|
|
||||||
Em.run.next(function() {
|
Em.run.next(function() {
|
||||||
return Em.run.next(function() {
|
return Em.run.next(function() {
|
||||||
return _this.open(opts);
|
return _this.open(opts);
|
||||||
@ -98,11 +102,13 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
composer = this.get('content');
|
composer = this.get('content');
|
||||||
if (composer && opts.draftKey !== composer.draftKey && composer.composeState === Discourse.Composer.DRAFT) {
|
if (composer && opts.draftKey !== composer.draftKey && composer.composeState === Discourse.Composer.DRAFT) {
|
||||||
this.close();
|
this.close();
|
||||||
composer = null;
|
composer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (composer && !opts.tested && composer.wouldLoseChanges()) {
|
if (composer && !opts.tested && composer.wouldLoseChanges()) {
|
||||||
if (composer.composeState === Discourse.Composer.DRAFT && composer.draftKey === opts.draftKey && composer.action === opts.action) {
|
if (composer.composeState === Discourse.Composer.DRAFT && composer.draftKey === opts.draftKey && composer.action === opts.action) {
|
||||||
composer.set('composeState', Discourse.Composer.OPEN);
|
composer.set('composeState', Discourse.Composer.OPEN);
|
||||||
@ -120,9 +126,8 @@
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* we need a draft sequence, without it drafts are bust
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// we need a draft sequence, without it drafts are bust
|
||||||
if (opts.draftSequence === void 0) {
|
if (opts.draftSequence === void 0) {
|
||||||
Discourse.Draft.get(opts.draftKey).then(function(data) {
|
Discourse.Draft.get(opts.draftKey).then(function(data) {
|
||||||
opts.draftSequence = data.draft_sequence;
|
opts.draftSequence = data.draft_sequence;
|
||||||
@ -131,31 +136,34 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.draft) {
|
if (opts.draft) {
|
||||||
composer = Discourse.Composer.loadDraft(opts.draftKey, opts.draftSequence, opts.draft);
|
composer = Discourse.Composer.loadDraft(opts.draftKey, opts.draftSequence, opts.draft);
|
||||||
if (composer) {
|
if (composer) {
|
||||||
composer.set('topic', opts.topic);
|
composer.set('topic', opts.topic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
composer = composer || Discourse.Composer.open(opts);
|
composer = composer || Discourse.Composer.open(opts);
|
||||||
this.set('content', composer);
|
this.set('content', composer);
|
||||||
this.set('view.content', composer);
|
this.set('view.content', composer);
|
||||||
promise.resolve();
|
promise.resolve();
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
wouldLoseChanges: function() {
|
wouldLoseChanges: function() {
|
||||||
var composer;
|
var composer;
|
||||||
composer = this.get('content');
|
composer = this.get('content');
|
||||||
return composer && composer.wouldLoseChanges();
|
return composer && composer.wouldLoseChanges();
|
||||||
},
|
},
|
||||||
/* View a new reply we've made
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// View a new reply we've made
|
||||||
viewNewReply: function() {
|
viewNewReply: function() {
|
||||||
Discourse.routeTo(this.get('createdPost.url'));
|
Discourse.routeTo(this.get('createdPost.url'));
|
||||||
this.close();
|
this.close();
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyDraft: function() {
|
destroyDraft: function() {
|
||||||
var key;
|
var key;
|
||||||
key = this.get('content.draftKey');
|
key = this.get('content.draftKey');
|
||||||
@ -163,6 +171,7 @@
|
|||||||
return Discourse.Draft.clear(key, this.get('content.draftSequence'));
|
return Discourse.Draft.clear(key, this.get('content.draftSequence'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel: function(success, fail) {
|
cancel: function(success, fail) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
if (this.get('content.hasMetaData') || ((this.get('content.reply') || "") !== (this.get('content.originalText') || ""))) {
|
if (this.get('content.hasMetaData') || ((this.get('content.reply') || "") !== (this.get('content.originalText') || ""))) {
|
||||||
@ -180,9 +189,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
/* it is possible there is some sort of crazy draft with no body ... just give up on it
|
// it is possible there is some sort of crazy draft with no body ... just give up on it
|
||||||
*/
|
|
||||||
|
|
||||||
this.destroyDraft();
|
this.destroyDraft();
|
||||||
this.close();
|
this.close();
|
||||||
if (typeof success === "function") {
|
if (typeof success === "function") {
|
||||||
@ -190,11 +197,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
click: function() {
|
click: function() {
|
||||||
if (this.get('content.composeState') === Discourse.Composer.DRAFT) {
|
if (this.get('content.composeState') === Discourse.Composer.DRAFT) {
|
||||||
return this.set('content.composeState', Discourse.Composer.OPEN);
|
return this.set('content.composeState', Discourse.Composer.OPEN);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
shrink: function() {
|
shrink: function() {
|
||||||
if (this.get('content.reply') === this.get('content.originalText')) {
|
if (this.get('content.reply') === this.get('content.originalText')) {
|
||||||
return this.close();
|
return this.close();
|
||||||
@ -202,27 +211,28 @@
|
|||||||
return this.collapse();
|
return this.collapse();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
collapse: function() {
|
collapse: function() {
|
||||||
this.saveDraft();
|
this.saveDraft();
|
||||||
return this.set('content.composeState', Discourse.Composer.DRAFT);
|
this.set('content.composeState', Discourse.Composer.DRAFT);
|
||||||
},
|
},
|
||||||
|
|
||||||
close: function() {
|
close: function() {
|
||||||
this.set('content', null);
|
this.set('content', null);
|
||||||
return this.set('view.content', null);
|
this.set('view.content', null);
|
||||||
},
|
},
|
||||||
|
|
||||||
closeIfCollapsed: function() {
|
closeIfCollapsed: function() {
|
||||||
if (this.get('content.composeState') === Discourse.Composer.DRAFT) {
|
if (this.get('content.composeState') === Discourse.Composer.DRAFT) {
|
||||||
return this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
closeAutocomplete: function() {
|
|
||||||
return jQuery('#wmd-input').autocomplete({
|
|
||||||
cancel: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/* Toggle the reply view
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
closeAutocomplete: function() {
|
||||||
|
$('#wmd-input').autocomplete({ cancel: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
// Toggle the reply view
|
||||||
toggle: function() {
|
toggle: function() {
|
||||||
this.closeAutocomplete();
|
this.closeAutocomplete();
|
||||||
switch (this.get('content.composeState')) {
|
switch (this.get('content.composeState')) {
|
||||||
@ -241,14 +251,14 @@
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
/* ESC key hit
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// ESC key hit
|
||||||
hitEsc: function() {
|
hitEsc: function() {
|
||||||
if (this.get('content.composeState') === Discourse.Composer.OPEN) {
|
if (this.get('content.composeState') === Discourse.Composer.OPEN) {
|
||||||
return this.shrink();
|
this.shrink();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
showOptions: function() {
|
showOptions: function() {
|
||||||
var _ref;
|
var _ref;
|
||||||
return (_ref = this.get('controllers.modal')) ? _ref.show(Discourse.ArchetypeOptionsModalView.create({
|
return (_ref = this.get('controllers.modal')) ? _ref.show(Discourse.ArchetypeOptionsModalView.create({
|
||||||
@ -256,6 +266,6 @@
|
|||||||
metaData: this.get('content.metaData')
|
metaData: this.get('content.metaData')
|
||||||
})) : void 0;
|
})) : void 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A base controller for Discourse that includes Presence support.
|
||||||
|
|
||||||
|
@class Controller
|
||||||
|
@extends Ember.Controller
|
||||||
|
@namespace Discourse
|
||||||
|
@uses Discourse.Presence
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Controller = Ember.Controller.extend(Discourse.Presence);
|
||||||
|
|
||||||
Discourse.Controller = Ember.Controller.extend(Discourse.Presence);
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports actions on the site header
|
||||||
|
|
||||||
Discourse.HeaderController = Ember.Controller.extend(Discourse.Presence, {
|
@class HeaderController
|
||||||
|
@extends Discourse.Controller
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.HeaderController = Discourse.Controller.extend({
|
||||||
topic: null,
|
topic: null,
|
||||||
showExtraInfo: false,
|
showExtraInfo: false,
|
||||||
|
|
||||||
toggleStar: function() {
|
toggleStar: function() {
|
||||||
var _ref;
|
var topic = this.get('topic');
|
||||||
if (_ref = this.get('topic')) {
|
if (topic) topic.toggleStar();
|
||||||
_ref.toggleStar();
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports actions when listing categories
|
||||||
|
|
||||||
Discourse.ListCategoriesController = Ember.ObjectController.extend(Discourse.Presence, {
|
@class ListCategoriesController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ListCategoriesController = Discourse.ObjectController.extend({
|
||||||
needs: ['modal'],
|
needs: ['modal'],
|
||||||
|
|
||||||
categoriesEven: (function() {
|
categoriesEven: (function() {
|
||||||
if (this.blank('categories')) {
|
if (this.blank('categories')) {
|
||||||
return Em.A();
|
return Em.A();
|
||||||
@ -10,6 +17,7 @@
|
|||||||
return (index % 2) === 0;
|
return (index % 2) === 0;
|
||||||
});
|
});
|
||||||
}).property('categories.@each'),
|
}).property('categories.@each'),
|
||||||
|
|
||||||
categoriesOdd: (function() {
|
categoriesOdd: (function() {
|
||||||
if (this.blank('categories')) {
|
if (this.blank('categories')) {
|
||||||
return Em.A();
|
return Em.A();
|
||||||
@ -18,17 +26,18 @@
|
|||||||
return (index % 2) === 1;
|
return (index % 2) === 1;
|
||||||
});
|
});
|
||||||
}).property('categories.@each'),
|
}).property('categories.@each'),
|
||||||
|
|
||||||
editCategory: function(category) {
|
editCategory: function(category) {
|
||||||
this.get('controllers.modal').show(Discourse.EditCategoryView.create({
|
this.get('controllers.modal').show(Discourse.EditCategoryView.create({ category: category }));
|
||||||
category: category
|
|
||||||
}));
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
canEdit: (function() {
|
canEdit: (function() {
|
||||||
var u;
|
var u;
|
||||||
u = Discourse.get('currentUser');
|
u = Discourse.get('currentUser');
|
||||||
return u && u.admin;
|
return u && u.admin;
|
||||||
}).property()
|
}).property()
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports actions when listing topics or categories
|
||||||
|
|
||||||
Discourse.ListController = Ember.Controller.extend(Discourse.Presence, {
|
@class ListController
|
||||||
|
@extends Discourse.Controller
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ListController = Discourse.Controller.extend({
|
||||||
currentUserBinding: 'Discourse.currentUser',
|
currentUserBinding: 'Discourse.currentUser',
|
||||||
categoriesBinding: 'Discourse.site.categories',
|
categoriesBinding: 'Discourse.site.categories',
|
||||||
categoryBinding: 'topicList.category',
|
categoryBinding: 'topicList.category',
|
||||||
canCreateCategory: false,
|
canCreateCategory: false,
|
||||||
canCreateTopic: false,
|
canCreateTopic: false,
|
||||||
needs: ['composer', 'modal', 'listTopics'],
|
needs: ['composer', 'modal', 'listTopics'],
|
||||||
|
|
||||||
availableNavItems: (function() {
|
availableNavItems: (function() {
|
||||||
var hasCategories, loggedOn, summary;
|
var hasCategories, loggedOn, summary;
|
||||||
summary = this.get('filterSummary');
|
summary = this.get('filterSummary');
|
||||||
@ -22,6 +29,7 @@
|
|||||||
return i !== null;
|
return i !== null;
|
||||||
});
|
});
|
||||||
}).property('filterSummary'),
|
}).property('filterSummary'),
|
||||||
|
|
||||||
load: function(filterMode) {
|
load: function(filterMode) {
|
||||||
var current,
|
var current,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -54,9 +62,8 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* Put in the appropriate page title based on our view
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Put in the appropriate page title based on our view
|
||||||
updateTitle: (function() {
|
updateTitle: (function() {
|
||||||
if (this.get('filterMode') === 'categories') {
|
if (this.get('filterMode') === 'categories') {
|
||||||
return Discourse.set('title', Em.String.i18n('categories_list'));
|
return Discourse.set('title', Em.String.i18n('categories_list'));
|
||||||
@ -68,9 +75,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).observes('filterMode', 'category'),
|
}).observes('filterMode', 'category'),
|
||||||
/* Create topic button
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Create topic button
|
||||||
createTopic: function() {
|
createTopic: function() {
|
||||||
var topicList;
|
var topicList;
|
||||||
topicList = this.get('controllers.listTopics.content');
|
topicList = this.get('controllers.listTopics.content');
|
||||||
@ -84,14 +90,16 @@
|
|||||||
draftSequence: topicList.get('draft_sequence')
|
draftSequence: topicList.get('draft_sequence')
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
createCategory: function() {
|
createCategory: function() {
|
||||||
var _ref;
|
var _ref;
|
||||||
return (_ref = this.get('controllers.modal')) ? _ref.show(Discourse.EditCategoryView.create()) : void 0;
|
return (_ref = this.get('controllers.modal')) ? _ref.show(Discourse.EditCategoryView.create()) : void 0;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
Discourse.ListController.reopenClass({
|
});
|
||||||
|
|
||||||
|
Discourse.ListController.reopenClass({
|
||||||
filters: ['popular', 'favorited', 'read', 'unread', 'new', 'posted']
|
filters: ['popular', 'favorited', 'read', 'unread', 'new', 'posted']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports actions when listing topics or categories
|
||||||
|
|
||||||
Discourse.ListTopicsController = Ember.ObjectController.extend({
|
@class ListTopicsController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ListTopicsController = Discourse.ObjectController.extend({
|
||||||
needs: ['list', 'composer'],
|
needs: ['list', 'composer'],
|
||||||
/* If we're changing our channel
|
// If we're changing our channel
|
||||||
*/
|
|
||||||
|
|
||||||
previousChannel: null,
|
previousChannel: null,
|
||||||
|
|
||||||
popular: (function() {
|
popular: (function() {
|
||||||
return this.get('content.filter') === 'popular';
|
return this.get('content.filter') === 'popular';
|
||||||
}).property('content.filter'),
|
}).property('content.filter'),
|
||||||
filterModeChanged: (function() {
|
|
||||||
/* Unsubscribe from a previous channel if necessary
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
filterModeChanged: (function() {
|
||||||
|
// Unsubscribe from a previous channel if necessary
|
||||||
var channel, filterMode, previousChannel,
|
var channel, filterMode, previousChannel,
|
||||||
_this = this;
|
_this = this;
|
||||||
if (previousChannel = this.get('previousChannel')) {
|
if (previousChannel = this.get('previousChannel')) {
|
||||||
@ -41,33 +45,29 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).observes('content.draft'),
|
}).observes('content.draft'),
|
||||||
/* Star a topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Star a topic
|
||||||
toggleStar: function(topic) {
|
toggleStar: function(topic) {
|
||||||
topic.toggleStar();
|
topic.toggleStar();
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
createTopic: function() {
|
createTopic: function() {
|
||||||
this.get('controllers.list').createTopic();
|
this.get('controllers.list').createTopic();
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
observer: (function() {
|
observer: (function() {
|
||||||
return this.set('filterMode', this.get('controllser.list.filterMode'));
|
return this.set('filterMode', this.get('controllser.list.filterMode'));
|
||||||
}).observes('controller.list.filterMode'),
|
}).observes('controller.list.filterMode'),
|
||||||
/* Show newly inserted topics
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Show newly inserted topics
|
||||||
showInserted: function(e) {
|
showInserted: function(e) {
|
||||||
/* Move inserted into topics
|
// Move inserted into topics
|
||||||
*/
|
|
||||||
this.get('content.topics').unshiftObjects(this.get('content.inserted'));
|
this.get('content.topics').unshiftObjects(this.get('content.inserted'));
|
||||||
/* Clear inserted
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Clear inserted
|
||||||
this.set('content.inserted', Em.A());
|
this.set('content.inserted', Em.A());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports actions related to showing modals
|
||||||
|
|
||||||
Discourse.ModalController = Ember.Controller.extend(Discourse.Presence, {
|
@class ModalController
|
||||||
|
@extends Discourse.Controller
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ModalController = Discourse.Controller.extend({
|
||||||
show: function(view) {
|
show: function(view) {
|
||||||
return this.set('currentView', view);
|
this.set('currentView', view);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
A custom object controller for Discourse
|
||||||
|
|
||||||
|
@class ObjectController
|
||||||
|
@extends Ember.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@uses Discourse.Presence
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ObjectController = Ember.ObjectController.extend(Discourse.Presence);
|
||||||
|
|
||||||
|
|
@ -1,132 +1,63 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports actions related to updating one's preferences
|
||||||
Discourse.PreferencesController = Ember.ObjectController.extend(Discourse.Presence, {
|
|
||||||
/* By default we haven't saved anything
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
@class PreferencesController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.PreferencesController = Discourse.ObjectController.extend({
|
||||||
|
// By default we haven't saved anything
|
||||||
saved: false,
|
saved: false,
|
||||||
|
|
||||||
saveDisabled: (function() {
|
saveDisabled: (function() {
|
||||||
if (this.get('saving')) {
|
if (this.get('saving')) return true;
|
||||||
return true;
|
if (this.blank('content.name')) return true;
|
||||||
}
|
if (this.blank('content.email')) return true;
|
||||||
if (this.blank('content.name')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.blank('content.email')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}).property('saving', 'content.name', 'content.email'),
|
}).property('saving', 'content.name', 'content.email'),
|
||||||
|
|
||||||
digestFrequencies: (function() {
|
digestFrequencies: (function() {
|
||||||
var freqs;
|
var freqs;
|
||||||
freqs = Em.A();
|
freqs = Em.A();
|
||||||
freqs.addObject({
|
freqs.addObject({ name: Em.String.i18n('user.email_digests.daily'), value: 1 });
|
||||||
name: Em.String.i18n('user.email_digests.daily'),
|
freqs.addObject({ name: Em.String.i18n('user.email_digests.weekly'), value: 7 });
|
||||||
value: 1
|
freqs.addObject({ name: Em.String.i18n('user.email_digests.bi_weekly'), value: 14 });
|
||||||
});
|
|
||||||
freqs.addObject({
|
|
||||||
name: Em.String.i18n('user.email_digests.weekly'),
|
|
||||||
value: 7
|
|
||||||
});
|
|
||||||
freqs.addObject({
|
|
||||||
name: Em.String.i18n('user.email_digests.bi_weekly'),
|
|
||||||
value: 14
|
|
||||||
});
|
|
||||||
return freqs;
|
return freqs;
|
||||||
}).property(),
|
}).property(),
|
||||||
|
|
||||||
autoTrackDurations: (function() {
|
autoTrackDurations: (function() {
|
||||||
var freqs;
|
var freqs;
|
||||||
freqs = Em.A();
|
freqs = Em.A();
|
||||||
freqs.addObject({
|
freqs.addObject({ name: Em.String.i18n('user.auto_track_options.never'), value: -1 });
|
||||||
name: Em.String.i18n('user.auto_track_options.never'),
|
freqs.addObject({ name: Em.String.i18n('user.auto_track_options.always'), value: 0 });
|
||||||
value: -1
|
freqs.addObject({ name: Em.String.i18n('user.auto_track_options.after_n_seconds', { count: 30 }), value: 30000 });
|
||||||
});
|
freqs.addObject({ name: Em.String.i18n('user.auto_track_options.after_n_minutes', { count: 1 }), value: 60000 });
|
||||||
freqs.addObject({
|
freqs.addObject({ name: Em.String.i18n('user.auto_track_options.after_n_minutes', { count: 2 }), value: 120000 });
|
||||||
name: Em.String.i18n('user.auto_track_options.always'),
|
freqs.addObject({ name: Em.String.i18n('user.auto_track_options.after_n_minutes', { count: 3 }), value: 180000 });
|
||||||
value: 0
|
freqs.addObject({ name: Em.String.i18n('user.auto_track_options.after_n_minutes', { count: 4 }), value: 240000 });
|
||||||
});
|
freqs.addObject({ name: Em.String.i18n('user.auto_track_options.after_n_minutes', { count: 5 }), value: 300000 });
|
||||||
freqs.addObject({
|
freqs.addObject({ name: Em.String.i18n('user.auto_track_options.after_n_minutes', { count: 10 }), value: 600000 });
|
||||||
name: Em.String.i18n('user.auto_track_options.after_n_seconds', {
|
|
||||||
count: 30
|
|
||||||
}),
|
|
||||||
value: 30000
|
|
||||||
});
|
|
||||||
freqs.addObject({
|
|
||||||
name: Em.String.i18n('user.auto_track_options.after_n_minutes', {
|
|
||||||
count: 1
|
|
||||||
}),
|
|
||||||
value: 60000
|
|
||||||
});
|
|
||||||
freqs.addObject({
|
|
||||||
name: Em.String.i18n('user.auto_track_options.after_n_minutes', {
|
|
||||||
count: 2
|
|
||||||
}),
|
|
||||||
value: 120000
|
|
||||||
});
|
|
||||||
freqs.addObject({
|
|
||||||
name: Em.String.i18n('user.auto_track_options.after_n_minutes', {
|
|
||||||
count: 3
|
|
||||||
}),
|
|
||||||
value: 180000
|
|
||||||
});
|
|
||||||
freqs.addObject({
|
|
||||||
name: Em.String.i18n('user.auto_track_options.after_n_minutes', {
|
|
||||||
count: 4
|
|
||||||
}),
|
|
||||||
value: 240000
|
|
||||||
});
|
|
||||||
freqs.addObject({
|
|
||||||
name: Em.String.i18n('user.auto_track_options.after_n_minutes', {
|
|
||||||
count: 5
|
|
||||||
}),
|
|
||||||
value: 300000
|
|
||||||
});
|
|
||||||
freqs.addObject({
|
|
||||||
name: Em.String.i18n('user.auto_track_options.after_n_minutes', {
|
|
||||||
count: 10
|
|
||||||
}),
|
|
||||||
value: 600000
|
|
||||||
});
|
|
||||||
return freqs;
|
return freqs;
|
||||||
}).property(),
|
}).property(),
|
||||||
|
|
||||||
considerNewTopicOptions: (function() {
|
considerNewTopicOptions: (function() {
|
||||||
var opts;
|
var opts;
|
||||||
opts = Em.A();
|
opts = Em.A();
|
||||||
opts.addObject({
|
opts.addObject({ name: Em.String.i18n('user.new_topic_duration.not_viewed'), value: -1 });
|
||||||
name: Em.String.i18n('user.new_topic_duration.not_viewed'),
|
opts.addObject({ name: Em.String.i18n('user.new_topic_duration.after_n_days', { count: 1 }), value: 60 * 24 });
|
||||||
value: -1
|
opts.addObject({ name: Em.String.i18n('user.new_topic_duration.after_n_days', { count: 2 }), value: 60 * 48 });
|
||||||
});
|
opts.addObject({ name: Em.String.i18n('user.new_topic_duration.after_n_weeks', { count: 1 }), value: 7 * 60 * 24 });
|
||||||
opts.addObject({
|
opts.addObject({ name: Em.String.i18n('user.new_topic_duration.last_here'), value: -2 });
|
||||||
name: Em.String.i18n('user.new_topic_duration.after_n_days', {
|
|
||||||
count: 1
|
|
||||||
}),
|
|
||||||
value: 60 * 24
|
|
||||||
});
|
|
||||||
opts.addObject({
|
|
||||||
name: Em.String.i18n('user.new_topic_duration.after_n_days', {
|
|
||||||
count: 2
|
|
||||||
}),
|
|
||||||
value: 60 * 48
|
|
||||||
});
|
|
||||||
opts.addObject({
|
|
||||||
name: Em.String.i18n('user.new_topic_duration.after_n_weeks', {
|
|
||||||
count: 1
|
|
||||||
}),
|
|
||||||
value: 7 * 60 * 24
|
|
||||||
});
|
|
||||||
opts.addObject({
|
|
||||||
name: Em.String.i18n('user.new_topic_duration.last_here'),
|
|
||||||
value: -2
|
|
||||||
});
|
|
||||||
return opts;
|
return opts;
|
||||||
}).property(),
|
}).property(),
|
||||||
|
|
||||||
save: function() {
|
save: function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this.set('saving', true);
|
this.set('saving', true);
|
||||||
this.set('saved', false);
|
this.set('saved', false);
|
||||||
/* Cook the bio for preview
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Cook the bio for preview
|
||||||
return this.get('content').save(function(result) {
|
return this.get('content').save(function(result) {
|
||||||
_this.set('saving', false);
|
_this.set('saving', false);
|
||||||
if (result) {
|
if (result) {
|
||||||
@ -137,12 +68,12 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
saveButtonText: (function() {
|
saveButtonText: (function() {
|
||||||
if (this.get('saving')) {
|
if (this.get('saving')) return Em.String.i18n('saving');
|
||||||
return Em.String.i18n('saving');
|
|
||||||
}
|
|
||||||
return Em.String.i18n('save');
|
return Em.String.i18n('save');
|
||||||
}).property('saving'),
|
}).property('saving'),
|
||||||
|
|
||||||
changePassword: function() {
|
changePassword: function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
if (!this.get('passwordProgress')) {
|
if (!this.get('passwordProgress')) {
|
||||||
@ -153,6 +84,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,36 +1,37 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports actions related to updating one's email address
|
||||||
|
|
||||||
Discourse.PreferencesEmailController = Ember.ObjectController.extend(Discourse.Presence, {
|
@class PreferencesEmailController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.PreferencesEmailController = Discourse.ObjectController.extend({
|
||||||
taken: false,
|
taken: false,
|
||||||
saving: false,
|
saving: false,
|
||||||
error: false,
|
error: false,
|
||||||
success: false,
|
success: false,
|
||||||
|
|
||||||
saveDisabled: (function() {
|
saveDisabled: (function() {
|
||||||
if (this.get('saving')) {
|
if (this.get('saving')) return true;
|
||||||
return true;
|
if (this.blank('newEmail')) return true;
|
||||||
}
|
if (this.get('taken')) return true;
|
||||||
if (this.blank('newEmail')) {
|
if (this.get('unchanged')) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.get('taken')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.get('unchanged')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}).property('newEmail', 'taken', 'unchanged', 'saving'),
|
}).property('newEmail', 'taken', 'unchanged', 'saving'),
|
||||||
|
|
||||||
unchanged: (function() {
|
unchanged: (function() {
|
||||||
return this.get('newEmail') === this.get('content.email');
|
return this.get('newEmail') === this.get('content.email');
|
||||||
}).property('newEmail', 'content.email'),
|
}).property('newEmail', 'content.email'),
|
||||||
|
|
||||||
initializeEmail: (function() {
|
initializeEmail: (function() {
|
||||||
return this.set('newEmail', this.get('content.email'));
|
this.set('newEmail', this.get('content.email'));
|
||||||
}).observes('content.email'),
|
}).observes('content.email'),
|
||||||
|
|
||||||
saveButtonText: (function() {
|
saveButtonText: (function() {
|
||||||
if (this.get('saving')) {
|
if (this.get('saving')) return Em.String.i18n("saving");
|
||||||
return Em.String.i18n("saving");
|
|
||||||
}
|
|
||||||
return Em.String.i18n("user.change_email.action");
|
return Em.String.i18n("user.change_email.action");
|
||||||
}).property('saving'),
|
}).property('saving'),
|
||||||
|
|
||||||
changeEmail: function() {
|
changeEmail: function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this.set('saving', true);
|
this.set('saving', true);
|
||||||
@ -43,6 +44,7 @@
|
|||||||
return _this.set('saving', false);
|
return _this.set('saving', false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,42 +1,37 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports actions related to updating one's username
|
||||||
|
|
||||||
Discourse.PreferencesUsernameController = Ember.ObjectController.extend(Discourse.Presence, {
|
@class PreferencesUsernameController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.PreferencesUsernameController = Discourse.ObjectController.extend({
|
||||||
taken: false,
|
taken: false,
|
||||||
saving: false,
|
saving: false,
|
||||||
error: false,
|
error: false,
|
||||||
errorMessage: null,
|
errorMessage: null,
|
||||||
|
|
||||||
saveDisabled: (function() {
|
saveDisabled: (function() {
|
||||||
if (this.get('saving')) {
|
if (this.get('saving')) return true;
|
||||||
return true;
|
if (this.blank('newUsername')) return true;
|
||||||
}
|
if (this.get('taken')) return true;
|
||||||
if (this.blank('newUsername')) {
|
if (this.get('unchanged')) return true;
|
||||||
return true;
|
if (this.get('errorMessage')) return true;
|
||||||
}
|
|
||||||
if (this.get('taken')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.get('unchanged')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.get('errorMessage')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}).property('newUsername', 'taken', 'errorMessage', 'unchanged', 'saving'),
|
}).property('newUsername', 'taken', 'errorMessage', 'unchanged', 'saving'),
|
||||||
|
|
||||||
unchanged: (function() {
|
unchanged: (function() {
|
||||||
return this.get('newUsername') === this.get('content.username');
|
return this.get('newUsername') === this.get('content.username');
|
||||||
}).property('newUsername', 'content.username'),
|
}).property('newUsername', 'content.username'),
|
||||||
|
|
||||||
checkTaken: (function() {
|
checkTaken: (function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this.set('taken', false);
|
this.set('taken', false);
|
||||||
this.set('errorMessage', null);
|
this.set('errorMessage', null);
|
||||||
if (this.blank('newUsername')) {
|
if (this.blank('newUsername')) return;
|
||||||
return;
|
if (this.get('unchanged')) return;
|
||||||
}
|
Discourse.User.checkUsername(this.get('newUsername')).then(function(result) {
|
||||||
if (this.get('unchanged')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return Discourse.User.checkUsername(this.get('newUsername')).then(function(result) {
|
|
||||||
if (result.errors) {
|
if (result.errors) {
|
||||||
return _this.set('errorMessage', result.errors.join(' '));
|
return _this.set('errorMessage', result.errors.join(' '));
|
||||||
} else if (result.available === false) {
|
} else if (result.available === false) {
|
||||||
@ -44,12 +39,12 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).observes('newUsername'),
|
}).observes('newUsername'),
|
||||||
|
|
||||||
saveButtonText: (function() {
|
saveButtonText: (function() {
|
||||||
if (this.get('saving')) {
|
if (this.get('saving')) return Em.String.i18n("saving");
|
||||||
return Em.String.i18n("saving");
|
|
||||||
}
|
|
||||||
return Em.String.i18n("user.change_username.action");
|
return Em.String.i18n("user.change_username.action");
|
||||||
}).property('saving'),
|
}).property('saving'),
|
||||||
|
|
||||||
changeUsername: function() {
|
changeUsername: function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return bootbox.confirm(Em.String.i18n("user.change_username.confirm"), Em.String.i18n("no_value"), Em.String.i18n("yes_value"), function(result) {
|
return bootbox.confirm(Em.String.i18n("user.change_username.confirm"), Em.String.i18n("no_value"), Em.String.i18n("yes_value"), function(result) {
|
||||||
@ -66,6 +61,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,44 +1,45 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports the pop up quote button
|
||||||
|
|
||||||
Discourse.QuoteButtonController = Discourse.Controller.extend({
|
@class QuoteButtonController
|
||||||
|
@extends Discourse.Controller
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.QuoteButtonController = Discourse.Controller.extend({
|
||||||
needs: ['topic', 'composer'],
|
needs: ['topic', 'composer'],
|
||||||
started: null,
|
started: null,
|
||||||
/* If the buffer is cleared, clear out other state (post)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If the buffer is cleared, clear out other state (post)
|
||||||
bufferChanged: (function() {
|
bufferChanged: (function() {
|
||||||
if (this.blank('buffer')) {
|
if (this.blank('buffer')) {
|
||||||
return this.set('post', null);
|
return this.set('post', null);
|
||||||
}
|
}
|
||||||
}).observes('buffer'),
|
}).observes('buffer'),
|
||||||
|
|
||||||
mouseDown: function(e) {
|
mouseDown: function(e) {
|
||||||
this.started = [e.pageX, e.pageY];
|
this.started = [e.pageX, e.pageY];
|
||||||
},
|
},
|
||||||
|
|
||||||
mouseUp: function(e) {
|
mouseUp: function(e) {
|
||||||
if (this.started[1] > e.pageY) {
|
if (this.started[1] > e.pageY) {
|
||||||
this.started = [e.pageX, e.pageY];
|
this.started = [e.pageX, e.pageY];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
selectText: function(e) {
|
selectText: function(e) {
|
||||||
var $quoteButton, left, selectedText, top;
|
var $quoteButton, left, selectedText, top;
|
||||||
if (!Discourse.get('currentUser')) {
|
if (!Discourse.get('currentUser')) return;
|
||||||
return;
|
if (!this.get('controllers.topic.content.can_create_post')) return;
|
||||||
}
|
|
||||||
if (!this.get('controllers.topic.content.can_create_post')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedText = Discourse.Utilities.selectedText();
|
selectedText = Discourse.Utilities.selectedText();
|
||||||
if (this.get('buffer') === selectedText) {
|
if (this.get('buffer') === selectedText) return;
|
||||||
return;
|
if (this.get('lastSelected') === selectedText) return;
|
||||||
}
|
|
||||||
if (this.get('lastSelected') === selectedText) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.set('post', e.context);
|
this.set('post', e.context);
|
||||||
this.set('buffer', selectedText);
|
this.set('buffer', selectedText);
|
||||||
top = e.pageY + 5;
|
top = e.pageY + 5;
|
||||||
left = e.pageX + 5;
|
left = e.pageX + 5;
|
||||||
$quoteButton = jQuery('.quote-button');
|
$quoteButton = $('.quote-button');
|
||||||
if (this.started) {
|
if (this.started) {
|
||||||
top = this.started[1] - 50;
|
top = this.started[1] - 50;
|
||||||
left = ((left - this.started[0]) / 2) + this.started[0] - ($quoteButton.width() / 2);
|
left = ((left - this.started[0]) / 2) + this.started[0] - ($quoteButton.width() / 2);
|
||||||
@ -50,6 +51,7 @@
|
|||||||
this.started = null;
|
this.started = null;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
quoteText: function(e) {
|
quoteText: function(e) {
|
||||||
var buffer, composerController, composerOpts, composerPost, post, quotedText,
|
var buffer, composerController, composerOpts, composerPost, post, quotedText,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -61,9 +63,8 @@
|
|||||||
action: Discourse.Composer.REPLY,
|
action: Discourse.Composer.REPLY,
|
||||||
draftKey: this.get('post.topic.draft_key')
|
draftKey: this.get('post.topic.draft_key')
|
||||||
};
|
};
|
||||||
/* If the composer is associated with a different post, we don't change it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If the composer is associated with a different post, we don't change it.
|
||||||
if (composerPost = composerController.get('content.post')) {
|
if (composerPost = composerController.get('content.post')) {
|
||||||
if (composerPost.get('id') !== this.get('post.id')) {
|
if (composerPost.get('id') !== this.get('post.id')) {
|
||||||
composerOpts.post = composerPost;
|
composerOpts.post = composerPost;
|
||||||
@ -71,6 +72,7 @@
|
|||||||
}
|
}
|
||||||
buffer = this.get('buffer');
|
buffer = this.get('buffer');
|
||||||
quotedText = Discourse.BBCode.buildQuoteBBCode(post, buffer);
|
quotedText = Discourse.BBCode.buildQuoteBBCode(post, buffer);
|
||||||
|
|
||||||
if (composerController.wouldLoseChanges()) {
|
if (composerController.wouldLoseChanges()) {
|
||||||
composerController.appendText(quotedText);
|
composerController.appendText(quotedText);
|
||||||
} else {
|
} else {
|
||||||
@ -81,6 +83,4 @@
|
|||||||
this.set('buffer', '');
|
this.set('buffer', '');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,29 +1,33 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports the "share" link controls
|
||||||
|
|
||||||
Discourse.ShareController = Ember.Controller.extend({
|
@class ShareController
|
||||||
/* When the user clicks the post number, we pop up a share box
|
@extends Discourse.Controller
|
||||||
*/
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ShareController = Discourse.Controller.extend({
|
||||||
|
|
||||||
|
// When the user clicks the post number, we pop up a share box
|
||||||
shareLink: function(e, url) {
|
shareLink: function(e, url) {
|
||||||
var x;
|
var x;
|
||||||
x = e.pageX - 150;
|
x = e.pageX - 150;
|
||||||
if (x < 25) {
|
if (x < 25) {
|
||||||
x = 25;
|
x = 25;
|
||||||
}
|
}
|
||||||
jQuery('#share-link').css({
|
$('#share-link').css({
|
||||||
left: "" + x + "px",
|
left: "" + x + "px",
|
||||||
top: "" + (e.pageY - 100) + "px"
|
top: "" + (e.pageY - 100) + "px"
|
||||||
});
|
});
|
||||||
this.set('link', url);
|
this.set('link', url);
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
/* Close the share controller
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Close the share controller
|
||||||
close: function() {
|
close: function() {
|
||||||
this.set('link', '');
|
this.set('link', '');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports displaying static content.
|
||||||
|
|
||||||
Discourse.StaticController = Ember.Controller.extend({
|
@class StaticController
|
||||||
|
@extends Discourse.Controller
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.StaticController = Discourse.Controller.extend({
|
||||||
content: null,
|
content: null,
|
||||||
|
|
||||||
loadPath: function(path) {
|
loadPath: function(path) {
|
||||||
var $preloaded, text,
|
var $preloaded, text,
|
||||||
_this = this;
|
_this = this;
|
||||||
this.set('content', null);
|
this.set('content', null);
|
||||||
/* Load from <noscript> if we have it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
$preloaded = jQuery("noscript[data-path=\"" + path + "\"]");
|
// Load from <noscript> if we have it.
|
||||||
|
$preloaded = $("noscript[data-path=\"" + path + "\"]");
|
||||||
if ($preloaded.length) {
|
if ($preloaded.length) {
|
||||||
text = $preloaded.text();
|
text = $preloaded.text();
|
||||||
text = text.replace(/<header[\s\S]*<\/header\>/, '');
|
text = text.replace(/<header[\s\S]*<\/header\>/, '');
|
||||||
@ -23,10 +29,10 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.StaticController.reopenClass({
|
Discourse.StaticController.reopenClass({
|
||||||
pages: ['faq', 'tos', 'privacy']
|
pages: ['faq', 'tos', 'privacy']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports the admin menu on topics
|
||||||
|
|
||||||
Discourse.TopicAdminMenuController = Ember.ObjectController.extend({
|
@class TopicAdminMenuController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.TopicAdminMenuController = Discourse.ObjectController.extend({
|
||||||
visible: false,
|
visible: false,
|
||||||
show: function() {
|
|
||||||
return this.set('visible', true);
|
|
||||||
},
|
|
||||||
hide: function() {
|
|
||||||
return this.set('visible', false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
show: function() {
|
||||||
|
this.set('visible', true);
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function() {
|
||||||
|
this.set('visible', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
@ -1,64 +1,56 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports all actions related to a topic
|
||||||
Discourse.TopicController = Ember.ObjectController.extend(Discourse.Presence, {
|
|
||||||
/* A list of usernames we want to filter by
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
@class TopicController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.TopicController = Discourse.ObjectController.extend({
|
||||||
userFilters: new Em.Set(),
|
userFilters: new Em.Set(),
|
||||||
multiSelect: false,
|
multiSelect: false,
|
||||||
bestOf: false,
|
bestOf: false,
|
||||||
showExtraHeaderInfo: false,
|
showExtraHeaderInfo: false,
|
||||||
needs: ['header', 'modal', 'composer', 'quoteButton'],
|
needs: ['header', 'modal', 'composer', 'quoteButton'],
|
||||||
|
|
||||||
filter: (function() {
|
filter: (function() {
|
||||||
if (this.get('bestOf') === true) {
|
if (this.get('bestOf') === true) return 'best_of';
|
||||||
return 'best_of';
|
if (this.get('userFilters').length > 0) return 'user';
|
||||||
}
|
|
||||||
if (this.get('userFilters').length > 0) {
|
|
||||||
return 'user';
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}).property('userFilters.[]', 'bestOf'),
|
}).property('userFilters.[]', 'bestOf'),
|
||||||
|
|
||||||
filterDesc: (function() {
|
filterDesc: (function() {
|
||||||
var filter;
|
var filter;
|
||||||
if (!(filter = this.get('filter'))) {
|
if (!(filter = this.get('filter'))) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return Em.String.i18n("topic.filters." + filter);
|
return Em.String.i18n("topic.filters." + filter);
|
||||||
}).property('filter'),
|
}).property('filter'),
|
||||||
|
|
||||||
selectedPosts: (function() {
|
selectedPosts: (function() {
|
||||||
var posts;
|
var posts;
|
||||||
if (!(posts = this.get('content.posts'))) {
|
if (!(posts = this.get('content.posts'))) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return posts.filterProperty('selected');
|
return posts.filterProperty('selected');
|
||||||
}).property('content.posts.@each.selected'),
|
}).property('content.posts.@each.selected'),
|
||||||
|
|
||||||
selectedCount: (function() {
|
selectedCount: (function() {
|
||||||
if (!this.get('selectedPosts')) {
|
if (!this.get('selectedPosts')) return 0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return this.get('selectedPosts').length;
|
return this.get('selectedPosts').length;
|
||||||
}).property('selectedPosts'),
|
}).property('selectedPosts'),
|
||||||
|
|
||||||
canMoveSelected: (function() {
|
canMoveSelected: (function() {
|
||||||
if (!this.get('content.can_move_posts')) {
|
if (!this.get('content.can_move_posts')) return false;
|
||||||
return false;
|
// For now, we can move it if we can delete it since the posts need to be deleted.
|
||||||
}
|
|
||||||
/* For now, we can move it if we can delete it since the posts
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* need to be deleted.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return this.get('canDeleteSelected');
|
return this.get('canDeleteSelected');
|
||||||
}).property('canDeleteSelected'),
|
}).property('canDeleteSelected'),
|
||||||
|
|
||||||
showExtraHeaderInfoChanged: (function() {
|
showExtraHeaderInfoChanged: (function() {
|
||||||
return this.set('controllers.header.showExtraInfo', this.get('showExtraHeaderInfo'));
|
this.set('controllers.header.showExtraInfo', this.get('showExtraHeaderInfo'));
|
||||||
}).observes('showExtraHeaderInfo'),
|
}).observes('showExtraHeaderInfo'),
|
||||||
|
|
||||||
canDeleteSelected: (function() {
|
canDeleteSelected: (function() {
|
||||||
var canDelete, selectedPosts;
|
var canDelete, selectedPosts;
|
||||||
selectedPosts = this.get('selectedPosts');
|
selectedPosts = this.get('selectedPosts');
|
||||||
if (!(selectedPosts && selectedPosts.length > 0)) {
|
if (!(selectedPosts && selectedPosts.length > 0)) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
canDelete = true;
|
canDelete = true;
|
||||||
selectedPosts.each(function(p) {
|
selectedPosts.each(function(p) {
|
||||||
if (!p.get('can_delete')) {
|
if (!p.get('can_delete')) {
|
||||||
@ -68,10 +60,9 @@
|
|||||||
});
|
});
|
||||||
return canDelete;
|
return canDelete;
|
||||||
}).property('selectedPosts'),
|
}).property('selectedPosts'),
|
||||||
multiSelectChanged: (function() {
|
|
||||||
/* Deselect all posts when multi select is turned off
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
multiSelectChanged: (function() {
|
||||||
|
// Deselect all posts when multi select is turned off
|
||||||
var posts;
|
var posts;
|
||||||
if (!this.get('multiSelect')) {
|
if (!this.get('multiSelect')) {
|
||||||
if (posts = this.get('content.posts')) {
|
if (posts = this.get('content.posts')) {
|
||||||
@ -81,24 +72,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).observes('multiSelect'),
|
}).observes('multiSelect'),
|
||||||
|
|
||||||
hideProgress: (function() {
|
hideProgress: (function() {
|
||||||
if (!this.get('content.loaded')) {
|
if (!this.get('content.loaded')) return true;
|
||||||
return true;
|
if (!this.get('currentPost')) return true;
|
||||||
}
|
if (this.get('content.highest_post_number') < 2) return true;
|
||||||
if (!this.get('currentPost')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.get('content.highest_post_number') < 2) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return this.present('filter');
|
return this.present('filter');
|
||||||
}).property('filter', 'content.loaded', 'currentPost'),
|
}).property('filter', 'content.loaded', 'currentPost'),
|
||||||
|
|
||||||
selectPost: function(post) {
|
selectPost: function(post) {
|
||||||
return post.toggleProperty('selected');
|
post.toggleProperty('selected');
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleMultiSelect: function() {
|
toggleMultiSelect: function() {
|
||||||
return this.toggleProperty('multiSelect');
|
this.toggleProperty('multiSelect');
|
||||||
},
|
},
|
||||||
|
|
||||||
moveSelected: function() {
|
moveSelected: function() {
|
||||||
var _ref;
|
var _ref;
|
||||||
return (_ref = this.get('controllers.modal')) ? _ref.show(Discourse.MoveSelectedView.create({
|
return (_ref = this.get('controllers.modal')) ? _ref.show(Discourse.MoveSelectedView.create({
|
||||||
@ -106,6 +95,7 @@
|
|||||||
selectedPosts: this.get('selectedPosts')
|
selectedPosts: this.get('selectedPosts')
|
||||||
})) : void 0;
|
})) : void 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteSelected: function() {
|
deleteSelected: function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return bootbox.confirm(Em.String.i18n("post.delete.confirm", {
|
return bootbox.confirm(Em.String.i18n("post.delete.confirm", {
|
||||||
@ -117,22 +107,25 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
jumpTop: function() {
|
jumpTop: function() {
|
||||||
return Discourse.routeTo(this.get('content.url'));
|
Discourse.routeTo(this.get('content.url'));
|
||||||
},
|
},
|
||||||
|
|
||||||
jumpBottom: function() {
|
jumpBottom: function() {
|
||||||
return Discourse.routeTo(this.get('content.lastPostUrl'));
|
Discourse.routeTo(this.get('content.lastPostUrl'));
|
||||||
},
|
},
|
||||||
|
|
||||||
cancelFilter: function() {
|
cancelFilter: function() {
|
||||||
this.set('bestOf', false);
|
this.set('bestOf', false);
|
||||||
return this.get('userFilters').clear();
|
this.get('userFilters').clear();
|
||||||
},
|
},
|
||||||
|
|
||||||
replyAsNewTopic: function(post) {
|
replyAsNewTopic: function(post) {
|
||||||
var composerController, postLink, postUrl, promise;
|
var composerController, postLink, postUrl, promise;
|
||||||
composerController = this.get('controllers.composer');
|
composerController = this.get('controllers.composer');
|
||||||
/*TODO shut down topic draft cleanly if it exists ...
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// TODO shut down topic draft cleanly if it exists ...
|
||||||
promise = composerController.open({
|
promise = composerController.open({
|
||||||
action: Discourse.Composer.CREATE_TOPIC,
|
action: Discourse.Composer.CREATE_TOPIC,
|
||||||
draftKey: Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY
|
draftKey: Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY
|
||||||
@ -147,9 +140,8 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Topic related
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Topic related
|
||||||
reply: function() {
|
reply: function() {
|
||||||
var composerController;
|
var composerController;
|
||||||
composerController = this.get('controllers.composer');
|
composerController = this.get('controllers.composer');
|
||||||
@ -160,6 +152,7 @@
|
|||||||
draftSequence: this.get('content.draft_sequence')
|
draftSequence: this.get('content.draft_sequence')
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleParticipant: function(user) {
|
toggleParticipant: function(user) {
|
||||||
var userFilters, username;
|
var userFilters, username;
|
||||||
this.set('bestOf', false);
|
this.set('bestOf', false);
|
||||||
@ -172,17 +165,20 @@
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
enableBestOf: function(e) {
|
enableBestOf: function(e) {
|
||||||
this.set('bestOf', true);
|
this.set('bestOf', true);
|
||||||
this.get('userFilters').clear();
|
this.get('userFilters').clear();
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
showBestOf: (function() {
|
showBestOf: (function() {
|
||||||
if (this.get('bestOf') === true) {
|
if (this.get('bestOf') === true) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.get('content.has_best_of') === true;
|
return this.get('content.has_best_of') === true;
|
||||||
}).property('bestOf', 'content.has_best_of'),
|
}).property('bestOf', 'content.has_best_of'),
|
||||||
|
|
||||||
postFilters: (function() {
|
postFilters: (function() {
|
||||||
if (this.get('bestOf') === true) {
|
if (this.get('bestOf') === true) {
|
||||||
return {
|
return {
|
||||||
@ -193,17 +189,14 @@
|
|||||||
userFilters: this.get('userFilters')
|
userFilters: this.get('userFilters')
|
||||||
};
|
};
|
||||||
}).property('userFilters.[]', 'bestOf'),
|
}).property('userFilters.[]', 'bestOf'),
|
||||||
|
|
||||||
reloadTopics: (function() {
|
reloadTopics: (function() {
|
||||||
var posts, topic,
|
var posts, topic,
|
||||||
_this = this;
|
_this = this;
|
||||||
topic = this.get('content');
|
topic = this.get('content');
|
||||||
if (!topic) {
|
if (!topic) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
posts = topic.get('posts');
|
posts = topic.get('posts');
|
||||||
if (!posts) {
|
if (!posts) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
posts.clear();
|
posts.clear();
|
||||||
this.set('content.loaded', false);
|
this.set('content.loaded', false);
|
||||||
return Discourse.Topic.find(this.get('content.id'), this.get('postFilters')).then(function(result) {
|
return Discourse.Topic.find(this.get('content.id'), this.get('postFilters')).then(function(result) {
|
||||||
@ -212,67 +205,68 @@
|
|||||||
if (first) {
|
if (first) {
|
||||||
_this.set('currentPost', first.post_number);
|
_this.set('currentPost', first.post_number);
|
||||||
}
|
}
|
||||||
jQuery('#topic-progress .solid').data('progress', false);
|
$('#topic-progress .solid').data('progress', false);
|
||||||
result.posts.each(function(p) {
|
result.posts.each(function(p) {
|
||||||
return posts.pushObject(Discourse.Post.create(p, topic));
|
return posts.pushObject(Discourse.Post.create(p, topic));
|
||||||
});
|
});
|
||||||
return _this.set('content.loaded', true);
|
return _this.set('content.loaded', true);
|
||||||
});
|
});
|
||||||
}).observes('postFilters'),
|
}).observes('postFilters'),
|
||||||
|
|
||||||
deleteTopic: function(e) {
|
deleteTopic: function(e) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this.unsubscribe();
|
this.unsubscribe();
|
||||||
return this.get('content')["delete"](function() {
|
this.get('content')["delete"](function() {
|
||||||
_this.set('message', "The topic has been deleted");
|
_this.set('message', "The topic has been deleted");
|
||||||
return _this.set('loaded', false);
|
_this.set('loaded', false);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleVisibility: function() {
|
toggleVisibility: function() {
|
||||||
return this.get('content').toggleStatus('visible');
|
this.get('content').toggleStatus('visible');
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleClosed: function() {
|
toggleClosed: function() {
|
||||||
return this.get('content').toggleStatus('closed');
|
this.get('content').toggleStatus('closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
togglePinned: function() {
|
togglePinned: function() {
|
||||||
return this.get('content').toggleStatus('pinned');
|
this.get('content').toggleStatus('pinned');
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleArchived: function() {
|
toggleArchived: function() {
|
||||||
return this.get('content').toggleStatus('archived');
|
this.get('content').toggleStatus('archived');
|
||||||
},
|
},
|
||||||
|
|
||||||
convertToRegular: function() {
|
convertToRegular: function() {
|
||||||
return this.get('content').convertArchetype('regular');
|
this.get('content').convertArchetype('regular');
|
||||||
},
|
},
|
||||||
|
|
||||||
startTracking: function() {
|
startTracking: function() {
|
||||||
var screenTrack;
|
var screenTrack;
|
||||||
screenTrack = Discourse.ScreenTrack.create({
|
screenTrack = Discourse.ScreenTrack.create({ topic_id: this.get('content.id') });
|
||||||
topic_id: this.get('content.id')
|
|
||||||
});
|
|
||||||
screenTrack.start();
|
screenTrack.start();
|
||||||
return this.set('content.screenTrack', screenTrack);
|
return this.set('content.screenTrack', screenTrack);
|
||||||
},
|
},
|
||||||
|
|
||||||
stopTracking: function() {
|
stopTracking: function() {
|
||||||
var _ref;
|
var screenTrack = this.get('content.screenTrack');
|
||||||
if (_ref = this.get('content.screenTrack')) {
|
if (screenTrack) screenTrack.stop();
|
||||||
_ref.stop();
|
this.set('content.screenTrack', null);
|
||||||
}
|
|
||||||
return this.set('content.screenTrack', null);
|
|
||||||
},
|
},
|
||||||
/* Toggle the star on the topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Toggle the star on the topic
|
||||||
toggleStar: function(e) {
|
toggleStar: function(e) {
|
||||||
return this.get('content').toggleStar();
|
this.get('content').toggleStar();
|
||||||
},
|
},
|
||||||
/* Receive notifications for this topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Receive notifications for this topic
|
||||||
subscribe: function() {
|
subscribe: function() {
|
||||||
var bus,
|
var bus,
|
||||||
_this = this;
|
_this = this;
|
||||||
bus = Discourse.MessageBus;
|
bus = Discourse.MessageBus;
|
||||||
/* there is a condition where the view never calls unsubscribe, navigate to a topic from a topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// there is a condition where the view never calls unsubscribe, navigate to a topic from a topic
|
||||||
bus.unsubscribe('/topic/*');
|
bus.unsubscribe('/topic/*');
|
||||||
return bus.subscribe("/topic/" + (this.get('content.id')), function(data) {
|
return bus.subscribe("/topic/" + (this.get('content.id')), function(data) {
|
||||||
var posts, topic;
|
var posts, topic;
|
||||||
@ -295,6 +289,7 @@
|
|||||||
return Discourse.notifyTitle();
|
return Discourse.notifyTitle();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
unsubscribe: function() {
|
unsubscribe: function() {
|
||||||
var bus, topicId;
|
var bus, topicId;
|
||||||
topicId = this.get('content.id');
|
topicId = this.get('content.id');
|
||||||
@ -304,9 +299,8 @@
|
|||||||
bus = Discourse.MessageBus;
|
bus = Discourse.MessageBus;
|
||||||
return bus.unsubscribe("/topic/" + topicId);
|
return bus.unsubscribe("/topic/" + topicId);
|
||||||
},
|
},
|
||||||
/* Post related methods
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Post related methods
|
||||||
replyToPost: function(post) {
|
replyToPost: function(post) {
|
||||||
var composerController, promise, quoteController, quotedText,
|
var composerController, promise, quoteController, quotedText,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -325,15 +319,12 @@
|
|||||||
draftKey: post.get('topic.draft_key'),
|
draftKey: post.get('topic.draft_key'),
|
||||||
draftSequence: post.get('topic.draft_sequence')
|
draftSequence: post.get('topic.draft_sequence')
|
||||||
});
|
});
|
||||||
promise.then(function() {
|
promise.then(function() { return composerController.appendText(quotedText); });
|
||||||
return composerController.appendText(quotedText);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
/* Edits a post
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Edits a post
|
||||||
editPost: function(post) {
|
editPost: function(post) {
|
||||||
return this.get('controllers.composer').open({
|
return this.get('controllers.composer').open({
|
||||||
post: post,
|
post: post,
|
||||||
@ -342,6 +333,7 @@
|
|||||||
draftSequence: post.get('topic.draft_sequence')
|
draftSequence: post.get('topic.draft_sequence')
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleBookmark: function(post) {
|
toggleBookmark: function(post) {
|
||||||
if (!Discourse.get('currentUser')) {
|
if (!Discourse.get('currentUser')) {
|
||||||
alert(Em.String.i18n("bookmarks.not_bookmarked"));
|
alert(Em.String.i18n("bookmarks.not_bookmarked"));
|
||||||
@ -350,16 +342,17 @@
|
|||||||
post.toggleProperty('bookmarked');
|
post.toggleProperty('bookmarked');
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
clearFlags: function(actionType) {
|
|
||||||
return actionType.clearFlags();
|
|
||||||
},
|
|
||||||
/* Who acted on a particular post / action type
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
clearFlags: function(actionType) {
|
||||||
|
actionType.clearFlags();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Who acted on a particular post / action type
|
||||||
whoActed: function(actionType) {
|
whoActed: function(actionType) {
|
||||||
actionType.loadUsers();
|
actionType.loadUsers();
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
showPrivateInviteModal: function() {
|
showPrivateInviteModal: function() {
|
||||||
var modal, _ref;
|
var modal, _ref;
|
||||||
modal = Discourse.InvitePrivateModalView.create({
|
modal = Discourse.InvitePrivateModalView.create({
|
||||||
@ -370,6 +363,7 @@
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
showInviteModal: function() {
|
showInviteModal: function() {
|
||||||
var _ref;
|
var _ref;
|
||||||
if (_ref = this.get('controllers.modal')) {
|
if (_ref = this.get('controllers.modal')) {
|
||||||
@ -379,6 +373,7 @@
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Clicked the flag button
|
// Clicked the flag button
|
||||||
showFlags: function(post) {
|
showFlags: function(post) {
|
||||||
var flagView, _ref;
|
var flagView, _ref;
|
||||||
@ -388,23 +383,23 @@
|
|||||||
});
|
});
|
||||||
return (_ref = this.get('controllers.modal')) ? _ref.show(flagView) : void 0;
|
return (_ref = this.get('controllers.modal')) ? _ref.show(flagView) : void 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
showHistory: function(post) {
|
showHistory: function(post) {
|
||||||
var view, _ref;
|
var view, _ref;
|
||||||
view = Discourse.HistoryView.create({
|
view = Discourse.HistoryView.create({ originalPost: post });
|
||||||
originalPost: post
|
|
||||||
});
|
|
||||||
if (_ref = this.get('controllers.modal')) {
|
if (_ref = this.get('controllers.modal')) {
|
||||||
_ref.show(view);
|
_ref.show(view);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
recoverPost: function(post) {
|
recoverPost: function(post) {
|
||||||
post.set('deleted_at', null);
|
post.set('deleted_at', null);
|
||||||
return post.recover();
|
return post.recover();
|
||||||
},
|
},
|
||||||
|
|
||||||
deletePost: function(post) {
|
deletePost: function(post) {
|
||||||
/* Moderators can delete posts. Regular users can only create a deleted at message.
|
// Moderators can delete posts. Regular users can only create a deleted at message.
|
||||||
*/
|
|
||||||
if (Discourse.get('currentUser.moderator')) {
|
if (Discourse.get('currentUser.moderator')) {
|
||||||
post.set('deleted_at', new Date());
|
post.set('deleted_at', new Date());
|
||||||
} else {
|
} else {
|
||||||
@ -414,6 +409,6 @@
|
|||||||
}
|
}
|
||||||
return post["delete"]();
|
return post["delete"]();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,12 +1,20 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller supports all actions on a user's activity stream
|
||||||
|
|
||||||
Discourse.UserActivityController = Ember.ObjectController.extend({
|
@class UserActivityController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserActivityController = Discourse.ObjectController.extend({
|
||||||
needs: ['composer'],
|
needs: ['composer'],
|
||||||
|
|
||||||
kickOffPrivateMessage: (function() {
|
kickOffPrivateMessage: (function() {
|
||||||
if (this.get('content.openPrivateMessage')) {
|
if (this.get('content.openPrivateMessage')) {
|
||||||
return this.composePrivateMessage();
|
this.composePrivateMessage();
|
||||||
}
|
}
|
||||||
}).observes('content.openPrivateMessage'),
|
}).observes('content.openPrivateMessage'),
|
||||||
|
|
||||||
composePrivateMessage: function() {
|
composePrivateMessage: function() {
|
||||||
return this.get('controllers.composer').open({
|
return this.get('controllers.composer').open({
|
||||||
action: Discourse.Composer.PRIVATE_MESSAGE,
|
action: Discourse.Composer.PRIVATE_MESSAGE,
|
||||||
@ -15,6 +23,6 @@
|
|||||||
draftKey: 'new_private_message'
|
draftKey: 'new_private_message'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller handles general user actions
|
||||||
|
|
||||||
|
@class UserController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserController = Discourse.ObjectController.extend({
|
||||||
|
|
||||||
Discourse.UserController = Ember.ObjectController.extend({
|
|
||||||
viewingSelf: (function() {
|
viewingSelf: (function() {
|
||||||
return this.get('content.username') === Discourse.get('currentUser.username');
|
return this.get('content.username') === Discourse.get('currentUser.username');
|
||||||
}).property('content.username', 'Discourse.currentUser.username'),
|
}).property('content.username', 'Discourse.currentUser.username'),
|
||||||
|
|
||||||
canSeePrivateMessages: (function() {
|
canSeePrivateMessages: (function() {
|
||||||
return this.get('viewingSelf') || Discourse.get('currentUser.admin');
|
return this.get('viewingSelf') || Discourse.get('currentUser.admin');
|
||||||
}).property('viewingSelf', 'Discourse.currentUser')
|
}).property('viewingSelf', 'Discourse.currentUser')
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller handles actions related to a user's invitations
|
||||||
|
|
||||||
Discourse.UserInvitedController = Ember.ObjectController.extend({
|
@class UserInvitedController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserInvitedController = Discourse.ObjectController.extend({
|
||||||
rescind: function(invite) {
|
rescind: function(invite) {
|
||||||
invite.rescind();
|
invite.rescind();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
(function() {
|
/**
|
||||||
|
This controller handles actions related to a user's private messages.
|
||||||
|
|
||||||
|
@class UserPrivateMessagesController
|
||||||
|
@extends Discourse.ObjectController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserPrivateMessagesController = Discourse.ObjectController.extend({
|
||||||
|
|
||||||
Discourse.UserPrivateMessagesController = Ember.ObjectController.extend({
|
|
||||||
editPreferences: function() {
|
editPreferences: function() {
|
||||||
return Discourse.routeTo("/users/" + (this.get('content.username_lower')) + "/preferences");
|
return Discourse.routeTo("/users/" + (this.get('content.username_lower')) + "/preferences");
|
||||||
},
|
},
|
||||||
|
|
||||||
composePrivateMessage: function() {
|
composePrivateMessage: function() {
|
||||||
var composerController;
|
var composerController;
|
||||||
composerController = Discourse.get('router.composerController');
|
composerController = Discourse.get('router.composerController');
|
||||||
@ -13,6 +21,5 @@
|
|||||||
draftKey: 'new_private_message'
|
draftKey: 'new_private_message'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
/*global humaneDate:true */
|
/*global humaneDate:true */
|
||||||
|
|
||||||
(function() {
|
/**
|
||||||
|
Breaks up a long string
|
||||||
|
|
||||||
Handlebars.registerHelper('breakUp', function(property, options) {
|
@method breakUp
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('breakUp', function(property, options) {
|
||||||
var prop, result, tokens;
|
var prop, result, tokens;
|
||||||
prop = Ember.Handlebars.get(this, property, options);
|
prop = Ember.Handlebars.get(this, property, options);
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
@ -20,28 +24,50 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('shorten', function(property, options) {
|
/**
|
||||||
var str;
|
Truncates long strings
|
||||||
str = Ember.Handlebars.get(this, property, options);
|
|
||||||
return str.truncate(35);
|
|
||||||
});
|
|
||||||
|
|
||||||
Handlebars.registerHelper('topicLink', function(property, options) {
|
@method shorten
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('shorten', function(property, options) {
|
||||||
|
return Ember.Handlebars.get(this, property, options).truncate(35);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
Produces a link to a topic
|
||||||
|
|
||||||
|
@method topicLink
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('topicLink', function(property, options) {
|
||||||
var title, topic;
|
var title, topic;
|
||||||
topic = Ember.Handlebars.get(this, property, options);
|
topic = Ember.Handlebars.get(this, property, options);
|
||||||
title = topic.get('fancy_title') || topic.get('title');
|
title = topic.get('fancy_title') || topic.get('title');
|
||||||
return "<a href='" + (topic.get('lastReadUrl')) + "' class='title excerptable'>" + title + "</a>";
|
return "<a href='" + (topic.get('lastReadUrl')) + "' class='title'>" + title + "</a>";
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('categoryLink', function(property, options) {
|
/**
|
||||||
|
Produces a link to a category
|
||||||
|
|
||||||
|
@method categoryLink
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('categoryLink', function(property, options) {
|
||||||
var category;
|
var category;
|
||||||
category = Ember.Handlebars.get(this, property, options);
|
category = Ember.Handlebars.get(this, property, options);
|
||||||
return new Handlebars.SafeString(Discourse.Utilities.categoryLink(category));
|
return new Handlebars.SafeString(Discourse.Utilities.categoryLink(category));
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('titledLinkTo', function(name, object) {
|
/**
|
||||||
|
Produces a link to a route with support for i18n on the title
|
||||||
|
|
||||||
|
@method titledLinkTo
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('titledLinkTo', function(name, object) {
|
||||||
var options;
|
var options;
|
||||||
options = [].slice.call(arguments, -1)[0];
|
options = [].slice.call(arguments, -1)[0];
|
||||||
if (options.hash.titleKey) {
|
if (options.hash.titleKey) {
|
||||||
@ -52,23 +78,33 @@
|
|||||||
} else {
|
} else {
|
||||||
return Ember.Handlebars.helpers.linkTo.call(this, name, options);
|
return Ember.Handlebars.helpers.linkTo.call(this, name, options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('shortenUrl', function(property, options) {
|
/**
|
||||||
|
Shorten a URL for display by removing common components
|
||||||
|
|
||||||
|
@method shortenUrl
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('shortenUrl', function(property, options) {
|
||||||
var url;
|
var url;
|
||||||
url = Ember.Handlebars.get(this, property, options);
|
url = Ember.Handlebars.get(this, property, options);
|
||||||
/* Remove trailing slash if it's a top level URL
|
// Remove trailing slash if it's a top level URL
|
||||||
*/
|
|
||||||
|
|
||||||
if (url.match(/\//g).length === 3) {
|
if (url.match(/\//g).length === 3) {
|
||||||
url = url.replace(/\/$/, '');
|
url = url.replace(/\/$/, '');
|
||||||
}
|
}
|
||||||
url = url.replace(/^https?:\/\//, '');
|
url = url.replace(/^https?:\/\//, '');
|
||||||
url = url.replace(/^www\./, '');
|
url = url.replace(/^www\./, '');
|
||||||
return url.truncate(80);
|
return url.truncate(80);
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('lower', function(property, options) {
|
/**
|
||||||
|
Display a property in lower case
|
||||||
|
|
||||||
|
@method lower
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('lower', function(property, options) {
|
||||||
var o;
|
var o;
|
||||||
o = Ember.Handlebars.get(this, property, options);
|
o = Ember.Handlebars.get(this, property, options);
|
||||||
if (o && typeof o === 'string') {
|
if (o && typeof o === 'string') {
|
||||||
@ -76,9 +112,15 @@
|
|||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('avatar', function(user, options) {
|
/**
|
||||||
|
Show an avatar for a user, intelligently making use of available properties
|
||||||
|
|
||||||
|
@method avatar
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('avatar', function(user, options) {
|
||||||
var title, username;
|
var title, username;
|
||||||
if (typeof user === 'string') {
|
if (typeof user === 'string') {
|
||||||
user = Ember.Handlebars.get(this, user, options);
|
user = Ember.Handlebars.get(this, user, options);
|
||||||
@ -97,15 +139,27 @@
|
|||||||
title: title || username,
|
title: title || username,
|
||||||
avatarTemplate: Ember.get(user, 'avatar_template') || options.hash.avatarTemplate
|
avatarTemplate: Ember.get(user, 'avatar_template') || options.hash.avatarTemplate
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('unboundDate', function(property, options) {
|
/**
|
||||||
|
Nicely format a date without a binding since the date doesn't need to change.
|
||||||
|
|
||||||
|
@method unboundDate
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('unboundDate', function(property, options) {
|
||||||
var dt;
|
var dt;
|
||||||
dt = new Date(Ember.Handlebars.get(this, property, options));
|
dt = new Date(Ember.Handlebars.get(this, property, options));
|
||||||
return dt.format("{d} {Mon}, {yyyy} {hh}:{mm}");
|
return dt.format("{d} {Mon}, {yyyy} {hh}:{mm}");
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('editDate', function(property, options) {
|
/**
|
||||||
|
Display a date related to an edit of a post
|
||||||
|
|
||||||
|
@method editDate
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('editDate', function(property, options) {
|
||||||
var dt, yesterday;
|
var dt, yesterday;
|
||||||
dt = Date.create(Ember.Handlebars.get(this, property, options));
|
dt = Date.create(Ember.Handlebars.get(this, property, options));
|
||||||
yesterday = new Date() - (60 * 60 * 24 * 1000);
|
yesterday = new Date() - (60 * 60 * 24 * 1000);
|
||||||
@ -114,9 +168,15 @@
|
|||||||
} else {
|
} else {
|
||||||
return humaneDate(dt);
|
return humaneDate(dt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('number', function(property, options) {
|
/**
|
||||||
|
Display logic for numbers.
|
||||||
|
|
||||||
|
@method number
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('number', function(property, options) {
|
||||||
var n, orig, title;
|
var n, orig, title;
|
||||||
orig = parseInt(Ember.Handlebars.get(this, property, options), 10);
|
orig = parseInt(Ember.Handlebars.get(this, property, options), 10);
|
||||||
if (isNaN(orig)) {
|
if (isNaN(orig)) {
|
||||||
@ -128,17 +188,21 @@
|
|||||||
number: orig
|
number: orig
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/* Round off the thousands to one decimal place
|
// Round off the thousands to one decimal place
|
||||||
*/
|
|
||||||
|
|
||||||
n = orig;
|
n = orig;
|
||||||
if (orig > 999) {
|
if (orig > 999) {
|
||||||
n = (orig / 1000).toFixed(1) + "K";
|
n = (orig / 1000).toFixed(1) + "K";
|
||||||
}
|
}
|
||||||
return new Handlebars.SafeString("<span class='number' title='" + title + "'>" + n + "</span>");
|
return new Handlebars.SafeString("<span class='number' title='" + title + "'>" + n + "</span>");
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('date', function(property, options) {
|
/**
|
||||||
|
Display logic for dates.
|
||||||
|
|
||||||
|
@method date
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('date', function(property, options) {
|
||||||
var displayDate, dt, fiveDaysAgo, fullReadable, humanized, leaveAgo, val;
|
var displayDate, dt, fiveDaysAgo, fullReadable, humanized, leaveAgo, val;
|
||||||
if (property.hash) {
|
if (property.hash) {
|
||||||
if (property.hash.leaveAgo) {
|
if (property.hash.leaveAgo) {
|
||||||
@ -173,9 +237,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Handlebars.SafeString("<span class='date' title='" + fullReadable + "'>" + displayDate + "</span>");
|
return new Handlebars.SafeString("<span class='date' title='" + fullReadable + "'>" + displayDate + "</span>");
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('personalizedName', function(property, options) {
|
/**
|
||||||
|
A personalized name for display
|
||||||
|
|
||||||
|
@method personalizedName
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Handlebars.registerHelper('personalizedName', function(property, options) {
|
||||||
var name, username;
|
var name, username;
|
||||||
name = Ember.Handlebars.get(this, property, options);
|
name = Ember.Handlebars.get(this, property, options);
|
||||||
if (options.hash.usernamePath) {
|
if (options.hash.usernamePath) {
|
||||||
@ -185,6 +255,6 @@
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
return Em.String.i18n('you');
|
return Em.String.i18n('you');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
(function() {
|
/**
|
||||||
|
Look up a translation for an i18n key in our dictionary.
|
||||||
Ember.Handlebars.registerHelper('i18n', function(property, options) {
|
|
||||||
/* Resolve any properties
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
@method i18n
|
||||||
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Ember.Handlebars.registerHelper('i18n', function(property, options) {
|
||||||
|
// Resolve any properties
|
||||||
var params,
|
var params,
|
||||||
_this = this;
|
_this = this;
|
||||||
params = options.hash;
|
params = options.hash;
|
||||||
@ -11,21 +13,28 @@
|
|||||||
params[key] = Em.Handlebars.get(_this, value, options);
|
params[key] = Em.Handlebars.get(_this, value, options);
|
||||||
});
|
});
|
||||||
return Ember.String.i18n(property, params);
|
return Ember.String.i18n(property, params);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* We always prefix with .js to select exactly what we want passed through to the front end.
|
/* We always prefix with .js to select exactly what we want passed through to the front end.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
Look up a translation for an i18n key in our dictionary.
|
||||||
|
|
||||||
Ember.String.i18n = function(scope, options) {
|
@method i18n
|
||||||
|
@for Ember.String
|
||||||
|
**/
|
||||||
|
Ember.String.i18n = function(scope, options) {
|
||||||
return I18n.translate("js." + scope, options);
|
return I18n.translate("js." + scope, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Bind an i18n count
|
/**
|
||||||
*/
|
Set up an i18n binding that will update as a count changes, complete with pluralization.
|
||||||
|
|
||||||
|
@method countI18n
|
||||||
Ember.Handlebars.registerHelper('countI18n', function(key, options) {
|
@for Handlebars
|
||||||
|
**/
|
||||||
|
Ember.Handlebars.registerHelper('countI18n', function(key, options) {
|
||||||
var view;
|
var view;
|
||||||
view = Discourse.View.extend({
|
view = Discourse.View.extend({
|
||||||
tagName: 'span',
|
tagName: 'span',
|
||||||
@ -39,12 +48,12 @@
|
|||||||
}).observes('count')
|
}).observes('count')
|
||||||
});
|
});
|
||||||
return Ember.Handlebars.helpers.view.call(this, view, options);
|
return Ember.Handlebars.helpers.view.call(this, view, options);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Ember.EXTEND_PROTOTYPES) {
|
if (Ember.EXTEND_PROTOTYPES) {
|
||||||
String.prototype.i18n = function(options) {
|
String.prototype.i18n = function(options) {
|
||||||
return Ember.String.i18n(String(this), options);
|
return Ember.String.i18n(String(this), options);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
This mixin provides `blank` and `present` to determine whether properties are
|
This mixin provides `blank` and `present` to determine whether properties are
|
||||||
there, accounting for more cases than just null and undefined.
|
there, accounting for more cases than just null and undefined.
|
||||||
|
|
||||||
@ -8,8 +6,8 @@
|
|||||||
@extends Ember.Mixin
|
@extends Ember.Mixin
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.Presence = Em.Mixin.create({
|
Discourse.Presence = Em.Mixin.create({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns whether a property is blank. It considers empty arrays, string, objects, undefined and null
|
Returns whether a property is blank. It considers empty arrays, string, objects, undefined and null
|
||||||
@ -43,6 +41,6 @@
|
|||||||
present: function(name) {
|
present: function(name) {
|
||||||
return !this.blank(name);
|
return !this.blank(name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,24 +1,37 @@
|
|||||||
|
/**
|
||||||
|
This mixin adds support for being notified every time the browser window
|
||||||
|
is scrolled.
|
||||||
|
|
||||||
/* Use this mixin if you want to be notified every time the user scrolls the window
|
@class Discourse.Scrolling
|
||||||
*/
|
@extends Ember.Mixin
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Scrolling = Em.Mixin.create({
|
||||||
|
|
||||||
|
/**
|
||||||
|
Begin watching for scroll events. They will be called at max every 100ms.
|
||||||
|
|
||||||
(function() {
|
@method bindScrolling
|
||||||
|
*/
|
||||||
window.Discourse.Scrolling = Em.Mixin.create({
|
|
||||||
bindScrolling: function() {
|
bindScrolling: function() {
|
||||||
var onScroll,
|
var onScroll,
|
||||||
_this = this;
|
_this = this;
|
||||||
onScroll = Discourse.debounce(function() {
|
onScroll = Discourse.debounce(function() { return _this.scrolled(); }, 100);
|
||||||
return _this.scrolled();
|
$(document).bind('touchmove.discourse', onScroll);
|
||||||
}, 100);
|
$(window).bind('scroll.discourse', onScroll);
|
||||||
jQuery(document).bind('touchmove.discourse', onScroll);
|
|
||||||
return jQuery(window).bind('scroll.discourse', onScroll);
|
|
||||||
},
|
},
|
||||||
unbindScrolling: function() {
|
|
||||||
jQuery(window).unbind('scroll.discourse');
|
|
||||||
return jQuery(document).unbind('touchmove.discourse');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
/**
|
||||||
|
Begin watching for scroll events. They will be called at max every 100ms.
|
||||||
|
|
||||||
|
@method unbindScrolling
|
||||||
|
*/
|
||||||
|
unbindScrolling: function() {
|
||||||
|
$(window).unbind('scroll.discourse');
|
||||||
|
$(document).unbind('touchmove.discourse');
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model for summarizing actions a user has taken, for example liking a post.
|
||||||
|
|
||||||
window.Discourse.ActionSummary = Discourse.Model.extend({
|
@class ActionSummary
|
||||||
/* Description for the action
|
@extends Discourse.Model
|
||||||
*/
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ActionSummary = Discourse.Model.extend({
|
||||||
|
|
||||||
|
// Description for the action
|
||||||
description: (function() {
|
description: (function() {
|
||||||
if (this.get('acted')) {
|
if (this.get('acted')) {
|
||||||
return Em.String.i18n('post.actions.by_you_and_others', {
|
return Em.String.i18n('post.actions.by_you_and_others', {
|
||||||
@ -17,43 +22,37 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).property('count', 'acted', 'actionType'),
|
}).property('count', 'acted', 'actionType'),
|
||||||
|
|
||||||
canAlsoAction: (function() {
|
canAlsoAction: (function() {
|
||||||
if (this.get('hidden')) {
|
if (this.get('hidden')) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this.get('can_act');
|
return this.get('can_act');
|
||||||
}).property('can_act', 'hidden'),
|
}).property('can_act', 'hidden'),
|
||||||
/* Remove it
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Remove it
|
||||||
removeAction: function() {
|
removeAction: function() {
|
||||||
this.set('acted', false);
|
this.set('acted', false);
|
||||||
this.set('count', this.get('count') - 1);
|
this.set('count', this.get('count') - 1);
|
||||||
this.set('can_act', true);
|
this.set('can_act', true);
|
||||||
return this.set('can_undo', false);
|
return this.set('can_undo', false);
|
||||||
},
|
},
|
||||||
/* Perform this action
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Perform this action
|
||||||
act: function(opts) {
|
act: function(opts) {
|
||||||
/* Mark it as acted
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Mark it as acted
|
||||||
var promise,
|
var promise,
|
||||||
_this = this;
|
_this = this;
|
||||||
this.set('acted', true);
|
this.set('acted', true);
|
||||||
this.set('count', this.get('count') + 1);
|
this.set('count', this.get('count') + 1);
|
||||||
this.set('can_act', false);
|
this.set('can_act', false);
|
||||||
this.set('can_undo', true);
|
this.set('can_undo', true);
|
||||||
/* Add ourselves to the users who liked it if present
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Add ourselves to the users who liked it if present
|
||||||
if (this.present('users')) {
|
if (this.present('users')) {
|
||||||
this.users.pushObject(Discourse.get('currentUser'));
|
this.users.pushObject(Discourse.get('currentUser'));
|
||||||
}
|
}
|
||||||
/* Create our post action
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Create our post action
|
||||||
promise = new RSVP.Promise();
|
promise = new RSVP.Promise();
|
||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
url: "/post_actions",
|
url: "/post_actions",
|
||||||
@ -75,14 +74,12 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
/* Undo this action
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Undo this action
|
||||||
undo: function() {
|
undo: function() {
|
||||||
this.removeAction();
|
this.removeAction();
|
||||||
/* Remove our post action
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Remove our post action
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
url: "/post_actions/" + (this.get('post.id')),
|
url: "/post_actions/" + (this.get('post.id')),
|
||||||
type: 'DELETE',
|
type: 'DELETE',
|
||||||
@ -91,6 +88,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
clearFlags: function() {
|
clearFlags: function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
@ -106,6 +104,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
loadUsers: function() {
|
loadUsers: function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery.getJSON("/post_actions/users", {
|
return jQuery.getJSON("/post_actions/users", {
|
||||||
@ -118,6 +117,7 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model for archetypes such as polls, tasks, etc.
|
||||||
|
|
||||||
|
@class Archetype
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Archetype = Discourse.Model.extend({
|
||||||
|
|
||||||
window.Discourse.Archetype = Discourse.Model.extend({
|
|
||||||
hasOptions: (function() {
|
hasOptions: (function() {
|
||||||
if (!this.get('options')) {
|
if (!this.get('options')) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this.get('options').length > 0;
|
return this.get('options').length > 0;
|
||||||
}).property('options.@each'),
|
}).property('options.@each'),
|
||||||
|
|
||||||
isDefault: (function() {
|
isDefault: (function() {
|
||||||
return this.get('id') === Discourse.get('site.default_archetype');
|
return this.get('id') === Discourse.get('site.default_archetype');
|
||||||
}).property('id')
|
}).property('id')
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,36 +1,45 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model that represents a category
|
||||||
|
|
||||||
|
@class Category
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Category = Discourse.Model.extend({
|
||||||
|
|
||||||
window.Discourse.Category = Discourse.Model.extend({
|
|
||||||
url: (function() {
|
url: (function() {
|
||||||
return "/category/" + (this.get('slug'));
|
return "/category/" + (this.get('slug'));
|
||||||
}).property('name'),
|
}).property('name'),
|
||||||
|
|
||||||
style: (function() {
|
style: (function() {
|
||||||
return "background-color: #" + (this.get('color'));
|
return "background-color: #" + (this.get('color'));
|
||||||
}).property('color'),
|
}).property('color'),
|
||||||
|
|
||||||
moreTopics: (function() {
|
moreTopics: (function() {
|
||||||
return this.get('topic_count') > Discourse.SiteSettings.category_featured_topics;
|
return this.get('topic_count') > Discourse.SiteSettings.category_featured_topics;
|
||||||
}).property('topic_count'),
|
}).property('topic_count'),
|
||||||
|
|
||||||
save: function(args) {
|
save: function(args) {
|
||||||
var url,
|
var url,
|
||||||
_this = this;
|
_this = this;
|
||||||
|
|
||||||
url = "/categories";
|
url = "/categories";
|
||||||
if (this.get('id')) {
|
if (this.get('id')) {
|
||||||
url = "/categories/" + (this.get('id'));
|
url = "/categories/" + (this.get('id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.ajax(url, {
|
return this.ajax(url, {
|
||||||
data: {
|
data: {
|
||||||
name: this.get('name'),
|
name: this.get('name'),
|
||||||
color: this.get('color')
|
color: this.get('color')
|
||||||
},
|
},
|
||||||
type: this.get('id') ? 'PUT' : 'POST',
|
type: this.get('id') ? 'PUT' : 'POST',
|
||||||
success: function(result) {
|
success: function(result) { return args.success(result); },
|
||||||
return args.success(result);
|
error: function(errors) { return args.error(errors); }
|
||||||
},
|
|
||||||
error: function(errors) {
|
|
||||||
return args.error(errors);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
"delete": function(callback) {
|
"delete": function(callback) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery.ajax("/categories/" + (this.get('slug')), {
|
return jQuery.ajax("/categories/" + (this.get('slug')), {
|
||||||
@ -40,6 +49,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model for containing a list of categories
|
||||||
|
|
||||||
window.Discourse.CategoryList = Discourse.Model.extend({});
|
@class CategoryList
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
window.Discourse.CategoryList = Discourse.Model.extend({});
|
||||||
|
|
||||||
|
window.Discourse.CategoryList.reopenClass({
|
||||||
|
|
||||||
window.Discourse.CategoryList.reopenClass({
|
|
||||||
categoriesFrom: function(result) {
|
categoriesFrom: function(result) {
|
||||||
var categories, users;
|
var categories, users;
|
||||||
categories = Em.A();
|
categories = Em.A();
|
||||||
@ -22,6 +29,7 @@
|
|||||||
});
|
});
|
||||||
return categories;
|
return categories;
|
||||||
},
|
},
|
||||||
|
|
||||||
list: function(filter) {
|
list: function(filter) {
|
||||||
var promise,
|
var promise,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -36,6 +44,7 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,34 +1,29 @@
|
|||||||
|
/**
|
||||||
|
A data model for representing the composer's current state
|
||||||
|
|
||||||
/* The status the compose view can have
|
@class Composer
|
||||||
*/
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
|
||||||
|
var CLOSED, CREATE_TOPIC, DRAFT, EDIT, OPEN, PRIVATE_MESSAGE, REPLY, REPLY_AS_NEW_TOPIC_KEY, SAVING;
|
||||||
|
|
||||||
(function() {
|
CLOSED = 'closed';
|
||||||
var CLOSED, CREATE_TOPIC, DRAFT, EDIT, OPEN, PRIVATE_MESSAGE, REPLY, REPLY_AS_NEW_TOPIC_KEY, SAVING;
|
SAVING = 'saving';
|
||||||
|
OPEN = 'open';
|
||||||
|
DRAFT = 'draft';
|
||||||
|
|
||||||
CLOSED = 'closed';
|
// The actions the composer can take
|
||||||
|
CREATE_TOPIC = 'createTopic';
|
||||||
|
PRIVATE_MESSAGE = 'privateMessage';
|
||||||
|
REPLY = 'reply';
|
||||||
|
EDIT = 'edit';
|
||||||
|
REPLY_AS_NEW_TOPIC_KEY = "reply_as_new_topic";
|
||||||
|
|
||||||
SAVING = 'saving';
|
Discourse.Composer = Discourse.Model.extend({
|
||||||
|
archetypesBinding: 'Discourse.site.archetypes',
|
||||||
|
|
||||||
OPEN = 'open';
|
|
||||||
|
|
||||||
DRAFT = 'draft';
|
|
||||||
|
|
||||||
/* The actions the composer can take
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
CREATE_TOPIC = 'createTopic';
|
|
||||||
|
|
||||||
PRIVATE_MESSAGE = 'privateMessage';
|
|
||||||
|
|
||||||
REPLY = 'reply';
|
|
||||||
|
|
||||||
EDIT = 'edit';
|
|
||||||
|
|
||||||
REPLY_AS_NEW_TOPIC_KEY = "reply_as_new_topic";
|
|
||||||
|
|
||||||
window.Discourse.Composer = Discourse.Model.extend({
|
|
||||||
init: function() {
|
init: function() {
|
||||||
var val;
|
var val;
|
||||||
this._super();
|
this._super();
|
||||||
@ -36,34 +31,37 @@
|
|||||||
this.set('showPreview', val === 'true');
|
this.set('showPreview', val === 'true');
|
||||||
return this.set('archetypeId', Discourse.get('site.default_archetype'));
|
return this.set('archetypeId', Discourse.get('site.default_archetype'));
|
||||||
},
|
},
|
||||||
archetypesBinding: 'Discourse.site.archetypes',
|
|
||||||
creatingTopic: (function() {
|
creatingTopic: (function() {
|
||||||
return this.get('action') === CREATE_TOPIC;
|
return this.get('action') === CREATE_TOPIC;
|
||||||
}).property('action'),
|
}).property('action'),
|
||||||
|
|
||||||
creatingPrivateMessage: (function() {
|
creatingPrivateMessage: (function() {
|
||||||
return this.get('action') === PRIVATE_MESSAGE;
|
return this.get('action') === PRIVATE_MESSAGE;
|
||||||
}).property('action'),
|
}).property('action'),
|
||||||
|
|
||||||
editingPost: (function() {
|
editingPost: (function() {
|
||||||
return this.get('action') === EDIT;
|
return this.get('action') === EDIT;
|
||||||
}).property('action'),
|
}).property('action'),
|
||||||
|
|
||||||
viewOpen: (function() {
|
viewOpen: (function() {
|
||||||
return this.get('composeState') === OPEN;
|
return this.get('composeState') === OPEN;
|
||||||
}).property('composeState'),
|
}).property('composeState'),
|
||||||
|
|
||||||
archetype: (function() {
|
archetype: (function() {
|
||||||
return this.get('archetypes').findProperty('id', this.get('archetypeId'));
|
return this.get('archetypes').findProperty('id', this.get('archetypeId'));
|
||||||
}).property('archetypeId'),
|
}).property('archetypeId'),
|
||||||
|
|
||||||
archetypeChanged: (function() {
|
archetypeChanged: (function() {
|
||||||
return this.set('metaData', Em.Object.create());
|
return this.set('metaData', Em.Object.create());
|
||||||
}).observes('archetype'),
|
}).observes('archetype'),
|
||||||
|
|
||||||
editTitle: (function() {
|
editTitle: (function() {
|
||||||
if (this.get('creatingTopic') || this.get('creatingPrivateMessage')) {
|
if (this.get('creatingTopic') || this.get('creatingPrivateMessage')) return true;
|
||||||
return true;
|
if (this.get('editingPost') && this.get('post.post_number') === 1) return true;
|
||||||
}
|
|
||||||
if (this.get('editingPost') && this.get('post.post_number') === 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}).property('editingPost', 'creatingTopic', 'post.post_number'),
|
}).property('editingPost', 'creatingTopic', 'post.post_number'),
|
||||||
|
|
||||||
togglePreview: function() {
|
togglePreview: function() {
|
||||||
this.toggleProperty('showPreview');
|
this.toggleProperty('showPreview');
|
||||||
return Discourse.KeyValueStore.set({
|
return Discourse.KeyValueStore.set({
|
||||||
@ -71,9 +69,8 @@
|
|||||||
value: this.get('showPreview')
|
value: this.get('showPreview')
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Import a quote from the post
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Import a quote from the post
|
||||||
importQuote: function() {
|
importQuote: function() {
|
||||||
var post, posts,
|
var post, posts,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -94,12 +91,12 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
appendText: function(text) {
|
appendText: function(text) {
|
||||||
return this.set('reply', (this.get('reply') || '') + text);
|
return this.set('reply', (this.get('reply') || '') + text);
|
||||||
},
|
},
|
||||||
/* Determine the appropriate title for this action
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Determine the appropriate title for this action
|
||||||
actionTitle: (function() {
|
actionTitle: (function() {
|
||||||
var postLink, postNumber, replyAvatar, topic, topicLink;
|
var postLink, postNumber, replyAvatar, topic, topicLink;
|
||||||
topic = this.get('topic');
|
topic = this.get('topic');
|
||||||
@ -136,49 +133,37 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).property('action', 'post', 'topic', 'topic.title'),
|
}).property('action', 'post', 'topic', 'topic.title'),
|
||||||
|
|
||||||
toggleText: (function() {
|
toggleText: (function() {
|
||||||
if (this.get('showPreview')) {
|
if (this.get('showPreview')) {
|
||||||
return Em.String.i18n('composer.hide_preview');
|
return Em.String.i18n('composer.hide_preview');
|
||||||
}
|
}
|
||||||
return Em.String.i18n('composer.show_preview');
|
return Em.String.i18n('composer.show_preview');
|
||||||
}).property('showPreview'),
|
}).property('showPreview'),
|
||||||
|
|
||||||
hidePreview: (function() {
|
hidePreview: (function() {
|
||||||
return !this.get('showPreview');
|
return !this.get('showPreview');
|
||||||
}).property('showPreview'),
|
}).property('showPreview'),
|
||||||
/* Whether to disable the post button
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Whether to disable the post button
|
||||||
cantSubmitPost: (function() {
|
cantSubmitPost: (function() {
|
||||||
/* Can't submit while loading
|
|
||||||
*/
|
|
||||||
if (this.get('loading')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/* Title is required on new posts
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Can't submit while loading
|
||||||
|
if (this.get('loading')) return true;
|
||||||
|
|
||||||
|
// Title is required on new posts
|
||||||
if (this.get('creatingTopic')) {
|
if (this.get('creatingTopic')) {
|
||||||
if (this.blank('title')) {
|
if (this.blank('title')) return true;
|
||||||
return true;
|
if (this.get('title').trim().length < Discourse.SiteSettings.min_topic_title_length) return true;
|
||||||
}
|
}
|
||||||
if (this.get('title').trim().length < Discourse.SiteSettings.min_topic_title_length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Otherwise just reply is required
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (this.blank('reply')) {
|
// Otherwise just reply is required
|
||||||
return true;
|
if (this.blank('reply')) return true;
|
||||||
}
|
if (this.get('reply').trim().length < Discourse.SiteSettings.min_post_length) return true;
|
||||||
if (this.get('reply').trim().length < Discourse.SiteSettings.min_post_length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}).property('reply', 'title', 'creatingTopic', 'loading'),
|
}).property('reply', 'title', 'creatingTopic', 'loading'),
|
||||||
/* The text for the save button
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// The text for the save button
|
||||||
saveText: (function() {
|
saveText: (function() {
|
||||||
switch (this.get('action')) {
|
switch (this.get('action')) {
|
||||||
case EDIT:
|
case EDIT:
|
||||||
@ -191,6 +176,7 @@
|
|||||||
return Em.String.i18n('composer.create_pm');
|
return Em.String.i18n('composer.create_pm');
|
||||||
}
|
}
|
||||||
}).property('action'),
|
}).property('action'),
|
||||||
|
|
||||||
hasMetaData: (function() {
|
hasMetaData: (function() {
|
||||||
var metaData;
|
var metaData;
|
||||||
metaData = this.get('metaData');
|
metaData = this.get('metaData');
|
||||||
@ -199,6 +185,7 @@
|
|||||||
}
|
}
|
||||||
return Em.empty(Em.keys(this.get('metaData')));
|
return Em.empty(Em.keys(this.get('metaData')));
|
||||||
}).property('metaData'),
|
}).property('metaData'),
|
||||||
|
|
||||||
wouldLoseChanges: function() {
|
wouldLoseChanges: function() {
|
||||||
return this.get('reply') !== this.get('originalText');
|
return this.get('reply') !== this.get('originalText');
|
||||||
},
|
},
|
||||||
@ -212,7 +199,6 @@
|
|||||||
topic - The topic we're replying to, if present
|
topic - The topic we're replying to, if present
|
||||||
quote - If we're opening a reply from a quote, the quote we're making
|
quote - If we're opening a reply from a quote, the quote we're making
|
||||||
*/
|
*/
|
||||||
|
|
||||||
open: function(opts) {
|
open: function(opts) {
|
||||||
var replyBlank, topicId,
|
var replyBlank, topicId,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -223,6 +209,7 @@
|
|||||||
topicId = opts.topic.get('id');
|
topicId = opts.topic.get('id');
|
||||||
}
|
}
|
||||||
replyBlank = (this.get("reply") || "") === "";
|
replyBlank = (this.get("reply") || "") === "";
|
||||||
|
|
||||||
if (!replyBlank &&
|
if (!replyBlank &&
|
||||||
(opts.action !== this.get('action') || ((opts.reply || opts.action === this.EDIT) && this.get('reply') !== this.get('originalText'))) &&
|
(opts.action !== this.get('action') || ((opts.reply || opts.action === this.EDIT) && this.get('reply') !== this.get('originalText'))) &&
|
||||||
!opts.tested) {
|
!opts.tested) {
|
||||||
@ -232,11 +219,10 @@
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set('draftKey', opts.draftKey);
|
this.set('draftKey', opts.draftKey);
|
||||||
this.set('draftSequence', opts.draftSequence);
|
this.set('draftSequence', opts.draftSequence);
|
||||||
if (!opts.draftKey) {
|
if (!opts.draftKey) throw 'draft key is required';
|
||||||
throw 'draft key is required';
|
|
||||||
}
|
|
||||||
if (opts.draftSequence === null) throw 'draft sequence is required';
|
if (opts.draftSequence === null) throw 'draft sequence is required';
|
||||||
|
|
||||||
this.set('composeState', opts.composerState || OPEN);
|
this.set('composeState', opts.composerState || OPEN);
|
||||||
@ -249,6 +235,7 @@
|
|||||||
this.set('topic', opts.post.get('topic'));
|
this.set('topic', opts.post.get('topic'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set('categoryName', opts.categoryName || this.get('topic.category.name'));
|
this.set('categoryName', opts.categoryName || this.get('topic.category.name'));
|
||||||
this.set('archetypeId', opts.archetypeId || Discourse.get('site.default_archetype'));
|
this.set('archetypeId', opts.archetypeId || Discourse.get('site.default_archetype'));
|
||||||
this.set('metaData', opts.metaData ? Em.Object.create(opts.metaData) : null);
|
this.set('metaData', opts.metaData ? Em.Object.create(opts.metaData) : null);
|
||||||
@ -260,9 +247,8 @@
|
|||||||
return _this.set('loading', false);
|
return _this.set('loading', false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/* If we are editing a post, load it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If we are editing a post, load it.
|
||||||
if (opts.action === EDIT && opts.post) {
|
if (opts.action === EDIT && opts.post) {
|
||||||
this.set('title', this.get('topic.title'));
|
this.set('title', this.get('topic.title'));
|
||||||
this.set('loading', true);
|
this.set('loading', true);
|
||||||
@ -272,9 +258,11 @@
|
|||||||
return _this.set('loading', false);
|
return _this.set('loading', false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.title) {
|
if (opts.title) {
|
||||||
this.set('title', opts.title);
|
this.set('title', opts.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.draft) {
|
if (opts.draft) {
|
||||||
this.set('originalText', '');
|
this.set('originalText', '');
|
||||||
} else if (opts.reply) {
|
} else if (opts.reply) {
|
||||||
@ -282,25 +270,21 @@
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
save: function(opts) {
|
|
||||||
if (this.get('editingPost')) {
|
|
||||||
return this.editPost(opts);
|
|
||||||
} else {
|
|
||||||
return this.createPost(opts);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* When you edit a post
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
save: function(opts) {
|
||||||
|
if (this.get('editingPost')) return this.editPost(opts);
|
||||||
|
return this.createPost(opts);
|
||||||
|
},
|
||||||
|
|
||||||
|
// When you edit a post
|
||||||
editPost: function(opts) {
|
editPost: function(opts) {
|
||||||
var oldCooked, post, promise, topic,
|
var oldCooked, post, promise, topic,
|
||||||
_this = this;
|
_this = this;
|
||||||
promise = new RSVP.Promise();
|
promise = new RSVP.Promise();
|
||||||
post = this.get('post');
|
post = this.get('post');
|
||||||
oldCooked = post.get('cooked');
|
oldCooked = post.get('cooked');
|
||||||
/* Update the title if we've changed it
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Update the title if we've changed it
|
||||||
if (this.get('title') && post.get('post_number') === 1) {
|
if (this.get('title') && post.get('post_number') === 1) {
|
||||||
topic = this.get('topic');
|
topic = this.get('topic');
|
||||||
topic.set('title', this.get('title'));
|
topic.set('title', this.get('title'));
|
||||||
@ -309,15 +293,14 @@
|
|||||||
}
|
}
|
||||||
post.set('raw', this.get('reply'));
|
post.set('raw', this.get('reply'));
|
||||||
post.set('imageSizes', opts.imageSizes);
|
post.set('imageSizes', opts.imageSizes);
|
||||||
post.set('cooked', jQuery('#wmd-preview').html());
|
post.set('cooked', $('#wmd-preview').html());
|
||||||
this.set('composeState', CLOSED);
|
this.set('composeState', CLOSED);
|
||||||
post.save(function(savedPost) {
|
post.save(function(savedPost) {
|
||||||
|
|
||||||
var idx, postNumber, posts;
|
var idx, postNumber, posts;
|
||||||
posts = _this.get('topic.posts');
|
posts = _this.get('topic.posts');
|
||||||
/* perhaps our post came from elsewhere eg. draft
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// perhaps our post came from elsewhere eg. draft
|
||||||
idx = -1;
|
idx = -1;
|
||||||
postNumber = post.get('post_number');
|
postNumber = post.get('post_number');
|
||||||
posts.each(function(p, i) {
|
posts.each(function(p, i) {
|
||||||
@ -342,9 +325,8 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
/* Create a new Post
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Create a new Post
|
||||||
createPost: function(opts) {
|
createPost: function(opts) {
|
||||||
var addedToStream, createdPost, diff, lastPost, post, promise, topic,
|
var addedToStream, createdPost, diff, lastPost, post, promise, topic,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -359,7 +341,7 @@
|
|||||||
reply_to_post_number: post ? post.get('post_number') : null,
|
reply_to_post_number: post ? post.get('post_number') : null,
|
||||||
imageSizes: opts.imageSizes,
|
imageSizes: opts.imageSizes,
|
||||||
post_number: this.get('topic.highest_post_number') + 1,
|
post_number: this.get('topic.highest_post_number') + 1,
|
||||||
cooked: jQuery('#wmd-preview').html(),
|
cooked: $('#wmd-preview').html(),
|
||||||
reply_count: 0,
|
reply_count: 0,
|
||||||
display_username: Discourse.get('currentUser.name'),
|
display_username: Discourse.get('currentUser.name'),
|
||||||
username: Discourse.get('currentUser.username'),
|
username: Discourse.get('currentUser.username'),
|
||||||
@ -372,39 +354,32 @@
|
|||||||
newPost: true
|
newPost: true
|
||||||
});
|
});
|
||||||
addedToStream = false;
|
addedToStream = false;
|
||||||
/* If we're in a topic, we can append the post instantly.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If we're in a topic, we can append the post instantly.
|
||||||
if (topic) {
|
if (topic) {
|
||||||
/* Increase the reply count
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Increase the reply count
|
||||||
if (post) {
|
if (post) {
|
||||||
post.set('reply_count', (post.get('reply_count') || 0) + 1);
|
post.set('reply_count', (post.get('reply_count') || 0) + 1);
|
||||||
}
|
}
|
||||||
topic.set('posts_count', topic.get('posts_count') + 1);
|
topic.set('posts_count', topic.get('posts_count') + 1);
|
||||||
/* Update last post
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Update last post
|
||||||
topic.set('last_posted_at', new Date());
|
topic.set('last_posted_at', new Date());
|
||||||
topic.set('highest_post_number', createdPost.get('post_number'));
|
topic.set('highest_post_number', createdPost.get('post_number'));
|
||||||
topic.set('last_poster', Discourse.get('currentUser'));
|
topic.set('last_poster', Discourse.get('currentUser'));
|
||||||
/* Set the topic view for the new post
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Set the topic view for the new post
|
||||||
createdPost.set('topic', topic);
|
createdPost.set('topic', topic);
|
||||||
createdPost.set('created_at', new Date());
|
createdPost.set('created_at', new Date());
|
||||||
/* If we're near the end of the topic, load new posts
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If we're near the end of the topic, load new posts
|
||||||
lastPost = topic.posts.last();
|
lastPost = topic.posts.last();
|
||||||
if (lastPost) {
|
if (lastPost) {
|
||||||
diff = topic.get('highest_post_number') - lastPost.get('post_number');
|
diff = topic.get('highest_post_number') - lastPost.get('post_number');
|
||||||
/* If the new post is within a threshold of the end of the topic,
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* add it and scroll there instead of adding the link.
|
// If the new post is within a threshold of the end of the topic,
|
||||||
*/
|
// add it and scroll there instead of adding the link.
|
||||||
|
|
||||||
if (diff < 5) {
|
if (diff < 5) {
|
||||||
createdPost.set('scrollToAfterInsert', createdPost.get('post_number'));
|
createdPost.set('scrollToAfterInsert', createdPost.get('post_number'));
|
||||||
@ -413,24 +388,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Save callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Save callback
|
||||||
createdPost.save(function(result) {
|
createdPost.save(function(result) {
|
||||||
var addedPost, saving;
|
var addedPost, saving;
|
||||||
addedPost = false;
|
addedPost = false;
|
||||||
saving = true;
|
saving = true;
|
||||||
createdPost.updateFromSave(result);
|
createdPost.updateFromSave(result);
|
||||||
if (topic) {
|
if (topic) {
|
||||||
/* It's no longer a new post
|
// It's no longer a new post
|
||||||
*/
|
|
||||||
|
|
||||||
createdPost.set('newPost', false);
|
createdPost.set('newPost', false);
|
||||||
topic.set('draft_sequence', result.draft_sequence);
|
topic.set('draft_sequence', result.draft_sequence);
|
||||||
} else {
|
} else {
|
||||||
/* We created a new topic, let's show it.
|
// We created a new topic, let's show it.
|
||||||
*/
|
|
||||||
|
|
||||||
_this.set('composeState', CLOSED);
|
_this.set('composeState', CLOSED);
|
||||||
saving = false;
|
saving = false;
|
||||||
}
|
}
|
||||||
@ -455,18 +425,14 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
saveDraft: function() {
|
saveDraft: function() {
|
||||||
var data,
|
var data,
|
||||||
_this = this;
|
_this = this;
|
||||||
if (this.get('disableDrafts')) {
|
if (this.get('disableDrafts')) return;
|
||||||
return;
|
if (!this.get('reply')) return;
|
||||||
}
|
if (this.get('reply').length < Discourse.SiteSettings.min_post_length) return;
|
||||||
if (!this.get('reply')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.get('reply').length < Discourse.SiteSettings.min_post_length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data = {
|
data = {
|
||||||
reply: this.get('reply'),
|
reply: this.get('reply'),
|
||||||
action: this.get('action'),
|
action: this.get('action'),
|
||||||
@ -477,13 +443,15 @@
|
|||||||
metaData: this.get('metaData'),
|
metaData: this.get('metaData'),
|
||||||
usernames: this.get('targetUsernames')
|
usernames: this.get('targetUsernames')
|
||||||
};
|
};
|
||||||
|
|
||||||
this.set('draftStatus', Em.String.i18n('composer.saving_draft_tip'));
|
this.set('draftStatus', Em.String.i18n('composer.saving_draft_tip'));
|
||||||
return Discourse.Draft.save(this.get('draftKey'), this.get('draftSequence'), data).then((function() {
|
return Discourse.Draft.save(this.get('draftKey'), this.get('draftSequence'), data).then((function() {
|
||||||
return _this.set('draftStatus', Em.String.i18n('composer.saved_draft_tip'));
|
_this.set('draftStatus', Em.String.i18n('composer.saved_draft_tip'));
|
||||||
}), (function() {
|
}), (function() {
|
||||||
return _this.set('draftStatus', 'drafts offline');
|
_this.set('draftStatus', 'drafts offline');
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
resetDraftStatus: (function() {
|
resetDraftStatus: (function() {
|
||||||
var len, reply;
|
var len, reply;
|
||||||
reply = this.get('reply');
|
reply = this.get('reply');
|
||||||
@ -500,20 +468,23 @@
|
|||||||
return this.set('draftStatus', null);
|
return this.set('draftStatus', null);
|
||||||
}
|
}
|
||||||
}).observes('reply', 'title'),
|
}).observes('reply', 'title'),
|
||||||
|
|
||||||
blank: function(prop) {
|
blank: function(prop) {
|
||||||
var p;
|
var p;
|
||||||
p = this.get(prop);
|
p = this.get(prop);
|
||||||
return !(p && p.length > 0);
|
return !(p && p.length > 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Discourse.Composer.reopenClass({
|
||||||
|
|
||||||
Discourse.Composer.reopenClass({
|
|
||||||
open: function(opts) {
|
open: function(opts) {
|
||||||
var composer;
|
var composer;
|
||||||
composer = Discourse.Composer.create();
|
composer = Discourse.Composer.create();
|
||||||
composer.open(opts);
|
composer.open(opts);
|
||||||
return composer;
|
return composer;
|
||||||
},
|
},
|
||||||
|
|
||||||
loadDraft: function(draftKey, draftSequence, draft, topic) {
|
loadDraft: function(draftKey, draftSequence, draft, topic) {
|
||||||
var composer;
|
var composer;
|
||||||
try {
|
try {
|
||||||
@ -543,24 +514,21 @@
|
|||||||
}
|
}
|
||||||
return composer;
|
return composer;
|
||||||
},
|
},
|
||||||
/* The status the compose view can have
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// The status the compose view can have
|
||||||
CLOSED: CLOSED,
|
CLOSED: CLOSED,
|
||||||
SAVING: SAVING,
|
SAVING: SAVING,
|
||||||
OPEN: OPEN,
|
OPEN: OPEN,
|
||||||
DRAFT: DRAFT,
|
DRAFT: DRAFT,
|
||||||
/* The actions the composer can take
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// The actions the composer can take
|
||||||
CREATE_TOPIC: CREATE_TOPIC,
|
CREATE_TOPIC: CREATE_TOPIC,
|
||||||
PRIVATE_MESSAGE: PRIVATE_MESSAGE,
|
PRIVATE_MESSAGE: PRIVATE_MESSAGE,
|
||||||
REPLY: REPLY,
|
REPLY: REPLY,
|
||||||
EDIT: EDIT,
|
EDIT: EDIT,
|
||||||
/* Draft key
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Draft key
|
||||||
REPLY_AS_NEW_TOPIC_KEY: REPLY_AS_NEW_TOPIC_KEY
|
REPLY_AS_NEW_TOPIC_KEY: REPLY_AS_NEW_TOPIC_KEY
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing a draft post
|
||||||
|
|
||||||
window.Discourse.Draft = Discourse.Model.extend({});
|
@class Draft
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Draft = Discourse.Model.extend({});
|
||||||
|
|
||||||
|
Discourse.Draft.reopenClass({
|
||||||
|
|
||||||
Discourse.Draft.reopenClass({
|
|
||||||
clear: function(key, sequence) {
|
clear: function(key, sequence) {
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
type: 'DELETE',
|
type: 'DELETE',
|
||||||
@ -12,10 +19,8 @@
|
|||||||
sequence: sequence
|
sequence: sequence
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
/* Discourse.KeyValueStore.remove("draft_#{key}")
|
|
||||||
*/
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
get: function(key) {
|
get: function(key) {
|
||||||
var promise,
|
var promise,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -32,18 +37,12 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
getLocal: function(key, current) {
|
getLocal: function(key, current) {
|
||||||
var local;
|
var local;
|
||||||
return current;
|
return current;
|
||||||
/* disabling for now to see if it helps with siracusa issue.
|
|
||||||
local = Discourse.KeyValueStore.get("draft_" + key);
|
|
||||||
if (!current || (local && local.length > current.length)) {
|
|
||||||
return local;
|
|
||||||
} else {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
},
|
},
|
||||||
|
|
||||||
save: function(key, sequence, data) {
|
save: function(key, sequence, data) {
|
||||||
var promise;
|
var promise;
|
||||||
promise = new RSVP.Promise();
|
promise = new RSVP.Promise();
|
||||||
@ -75,6 +74,5 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A trivial model we use to handle input validation
|
||||||
|
|
||||||
|
@class InputValidation
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
window.Discourse.InputValidation = Discourse.Model.extend({});
|
||||||
|
|
||||||
window.Discourse.InputValidation = Discourse.Model.extend({});
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,18 +1,26 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing an Invite
|
||||||
|
|
||||||
|
@class Invite
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
|
||||||
|
Discourse.Invite = Discourse.Model.extend({
|
||||||
|
|
||||||
window.Discourse.Invite = Discourse.Model.extend({
|
|
||||||
rescind: function() {
|
rescind: function() {
|
||||||
jQuery.ajax('/invites', {
|
jQuery.ajax('/invites', {
|
||||||
type: 'DELETE',
|
type: 'DELETE',
|
||||||
data: {
|
data: { email: this.get('email') }
|
||||||
email: this.get('email')
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return this.set('rescinded', true);
|
this.set('rescinded', true);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
window.Discourse.Invite.reopenClass({
|
});
|
||||||
|
|
||||||
|
Discourse.Invite.reopenClass({
|
||||||
|
|
||||||
create: function(invite) {
|
create: function(invite) {
|
||||||
var result;
|
var result;
|
||||||
result = this._super(invite);
|
result = this._super(invite);
|
||||||
@ -21,6 +29,7 @@
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing a list of Invites
|
||||||
|
|
||||||
window.Discourse.InviteList = Discourse.Model.extend({
|
@class InviteList
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.InviteList = Discourse.Model.extend({
|
||||||
empty: (function() {
|
empty: (function() {
|
||||||
return this.blank('pending') && this.blank('redeemed');
|
return this.blank('pending') && this.blank('redeemed');
|
||||||
}).property('pending.@each', 'redeemed.@each')
|
}).property('pending.@each', 'redeemed.@each')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Discourse.InviteList.reopenClass({
|
||||||
|
|
||||||
window.Discourse.InviteList.reopenClass({
|
|
||||||
findInvitedBy: function(user) {
|
findInvitedBy: function(user) {
|
||||||
var promise;
|
var promise;
|
||||||
promise = new RSVP.Promise();
|
promise = new RSVP.Promise();
|
||||||
@ -31,6 +38,7 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
(function() {
|
|
||||||
|
|
||||||
Discourse.Mention = (function() {
|
|
||||||
var cache, load, localCache, lookup, lookupCache;
|
|
||||||
localCache = {};
|
|
||||||
cache = function(name, valid) {
|
|
||||||
localCache[name] = valid;
|
|
||||||
};
|
|
||||||
lookupCache = function(name) {
|
|
||||||
return localCache[name];
|
|
||||||
};
|
|
||||||
lookup = function(name, callback) {
|
|
||||||
var cached;
|
|
||||||
cached = lookupCache(name);
|
|
||||||
if (cached === true || cached === false) {
|
|
||||||
callback(cached);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
jQuery.get("/users/is_local_username", {
|
|
||||||
username: name
|
|
||||||
}, function(r) {
|
|
||||||
cache(name, r.valid);
|
|
||||||
return callback(r.valid);
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
load = function(e) {
|
|
||||||
var $elem, loading, username;
|
|
||||||
$elem = jQuery(e);
|
|
||||||
if ($elem.data('mention-tested')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
username = $elem.text();
|
|
||||||
username = username.substr(1);
|
|
||||||
loading = lookup(username, function(valid) {
|
|
||||||
if (valid) {
|
|
||||||
return $elem.replaceWith("<a href='/users/" + (username.toLowerCase()) + "' class='mention'>@" + username + "</a>");
|
|
||||||
} else {
|
|
||||||
return $elem.removeClass('mention-loading').addClass('mention-tested');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (loading) {
|
|
||||||
return $elem.addClass('mention-loading');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
load: load,
|
|
||||||
lookup: lookup,
|
|
||||||
lookupCache: lookupCache
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
}).call(this);
|
|
@ -1,6 +1,4 @@
|
|||||||
(function() {
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
A base object we can use to handle models in the Discourse client application.
|
A base object we can use to handle models in the Discourse client application.
|
||||||
|
|
||||||
@class Model
|
@class Model
|
||||||
@ -8,8 +6,8 @@
|
|||||||
@uses Discourse.Presence
|
@uses Discourse.Presence
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
window.Discourse.Model = Ember.Object.extend(Discourse.Presence, {
|
Discourse.Model = Ember.Object.extend(Discourse.Presence, {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Our own AJAX handler that handles erronous responses
|
Our own AJAX handler that handles erronous responses
|
||||||
@ -51,9 +49,9 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.Discourse.Model.reopenClass({
|
Discourse.Model.reopenClass({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Given an array of values, return them in a hash
|
Given an array of values, return them in a hash
|
||||||
@ -75,6 +73,6 @@
|
|||||||
});
|
});
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
|
/**
|
||||||
|
A data model representing a navigation item on the list views
|
||||||
|
|
||||||
/* closure wrapping means this does not leak into global context
|
@class InviteList
|
||||||
*/
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
var validAnon, validNavNames;
|
||||||
|
validNavNames = ['read', 'popular', 'categories', 'favorited', 'category', 'unread', 'new', 'posted'];
|
||||||
|
validAnon = ['popular', 'category', 'categories'];
|
||||||
|
|
||||||
|
Discourse.NavItem = Discourse.Model.extend({
|
||||||
(function() {
|
|
||||||
var validAnon, validNavNames;
|
|
||||||
|
|
||||||
validNavNames = ['read', 'popular', 'categories', 'favorited', 'category', 'unread', 'new', 'posted'];
|
|
||||||
|
|
||||||
validAnon = ['popular', 'category', 'categories'];
|
|
||||||
|
|
||||||
window.Discourse.NavItem = Discourse.Model.extend({
|
|
||||||
categoryName: (function() {
|
categoryName: (function() {
|
||||||
var split;
|
var split;
|
||||||
split = this.get('name').split('/');
|
split = this.get('name').split('/');
|
||||||
@ -32,12 +32,11 @@
|
|||||||
return "/" + name;
|
return "/" + name;
|
||||||
}
|
}
|
||||||
}).property()
|
}).property()
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.NavItem.reopenClass({
|
Discourse.NavItem.reopenClass({
|
||||||
/* create a nav item from the text, will return null if there is not valid nav item for this particular text
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// create a nav item from the text, will return null if there is not valid nav item for this particular text
|
||||||
fromText: function(text, opts) {
|
fromText: function(text, opts) {
|
||||||
var countSummary, hasCategories, loggedOn, name, split, testName;
|
var countSummary, hasCategories, loggedOn, name, split, testName;
|
||||||
countSummary = opts.countSummary;
|
countSummary = opts.countSummary;
|
||||||
@ -46,15 +45,11 @@
|
|||||||
split = text.split(",");
|
split = text.split(",");
|
||||||
name = split[0];
|
name = split[0];
|
||||||
testName = name.split("/")[0];
|
testName = name.split("/")[0];
|
||||||
if (!loggedOn && !validAnon.contains(testName)) {
|
|
||||||
return null;
|
if (!loggedOn && !validAnon.contains(testName)) return null;
|
||||||
}
|
if (!hasCategories && testName === "categories") return null;
|
||||||
if (!hasCategories && testName === "categories") {
|
if (!validNavNames.contains(testName)) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!validNavNames.contains(testName)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
opts = {
|
opts = {
|
||||||
name: name,
|
name: name,
|
||||||
hasIcon: name === "unread" || name === "favorited",
|
hasIcon: name === "unread" || name === "favorited",
|
||||||
@ -67,6 +62,7 @@
|
|||||||
}
|
}
|
||||||
return Discourse.NavItem.create(opts);
|
return Discourse.NavItem.create(opts);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing a notification a user receives
|
||||||
|
|
||||||
|
@class Notification
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Notification = Discourse.Model.extend({
|
||||||
|
|
||||||
window.Discourse.Notification = Discourse.Model.extend({
|
|
||||||
readClass: (function() {
|
readClass: (function() {
|
||||||
if (this.read) {
|
if (this.read) return 'read';
|
||||||
return 'read';
|
|
||||||
} else {
|
|
||||||
return '';
|
return '';
|
||||||
}
|
|
||||||
}).property('read'),
|
}).property('read'),
|
||||||
|
|
||||||
url: (function() {
|
url: (function() {
|
||||||
var slug;
|
var slug;
|
||||||
if (this.blank('data.topic_title')) {
|
if (this.blank('data.topic_title')) return "";
|
||||||
return "";
|
|
||||||
}
|
|
||||||
slug = this.get('slug');
|
slug = this.get('slug');
|
||||||
return "/t/" + slug + "/" + (this.get('topic_id')) + "/" + (this.get('post_number'));
|
return "/t/" + slug + "/" + (this.get('topic_id')) + "/" + (this.get('post_number'));
|
||||||
}).property(),
|
}).property(),
|
||||||
|
|
||||||
rendered: (function() {
|
rendered: (function() {
|
||||||
var notificationName;
|
var notificationName;
|
||||||
notificationName = Discourse.get('site.notificationLookup')[this.notification_type];
|
notificationName = Discourse.get('site.notificationLookup')[this.notification_type];
|
||||||
@ -24,9 +28,10 @@
|
|||||||
link: "<a href='" + (this.get('url')) + "'>" + this.data.topic_title + "</a>"
|
link: "<a href='" + (this.get('url')) + "'>" + this.data.topic_title + "</a>"
|
||||||
});
|
});
|
||||||
}).property()
|
}).property()
|
||||||
});
|
|
||||||
|
|
||||||
window.Discourse.Notification.reopenClass({
|
});
|
||||||
|
|
||||||
|
Discourse.Notification.reopenClass({
|
||||||
create: function(obj) {
|
create: function(obj) {
|
||||||
var result;
|
var result;
|
||||||
result = this._super(obj);
|
result = this._super(obj);
|
||||||
@ -35,6 +40,6 @@
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
(function() {
|
|
||||||
|
|
||||||
Discourse.Onebox = (function() {
|
|
||||||
/* for now it only stores in a var, in future we can change it so it uses localStorage,
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* trouble with localStorage is that expire semantics need some thinking
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*cacheKey = "__onebox__"
|
|
||||||
*/
|
|
||||||
|
|
||||||
var cache, load, localCache, lookup, lookupCache;
|
|
||||||
localCache = {};
|
|
||||||
cache = function(url, contents) {
|
|
||||||
localCache[url] = contents;
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
lookupCache = function(url) {
|
|
||||||
var cached;
|
|
||||||
cached = localCache[url];
|
|
||||||
if (cached && cached.then) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
lookup = function(url, refresh, callback) {
|
|
||||||
var cached;
|
|
||||||
cached = localCache[url];
|
|
||||||
if (refresh && cached && !cached.then) {
|
|
||||||
cached = null;
|
|
||||||
}
|
|
||||||
if (cached) {
|
|
||||||
if (cached.then) {
|
|
||||||
cached.then(callback(lookupCache(url)));
|
|
||||||
} else {
|
|
||||||
callback(cached);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
cache(url, jQuery.get("/onebox", {
|
|
||||||
url: url,
|
|
||||||
refresh: refresh
|
|
||||||
}, function(html) {
|
|
||||||
cache(url, html);
|
|
||||||
return callback(html);
|
|
||||||
}));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
load = function(e, refresh) {
|
|
||||||
var $elem, loading, url;
|
|
||||||
if (!refresh) refresh = false;
|
|
||||||
|
|
||||||
url = e.href;
|
|
||||||
$elem = jQuery(e);
|
|
||||||
if ($elem.data('onebox-loaded')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading = lookup(url, refresh, function(html) {
|
|
||||||
$elem.removeClass('loading-onebox');
|
|
||||||
$elem.data('onebox-loaded');
|
|
||||||
if (!html) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (html.trim().length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return $elem.replaceWith(html);
|
|
||||||
});
|
|
||||||
if (loading) {
|
|
||||||
return $elem.addClass('loading-onebox');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
load: load,
|
|
||||||
lookup: lookup,
|
|
||||||
lookupCache: lookupCache
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
}).call(this);
|
|
@ -1,41 +1,44 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing a post in a topic
|
||||||
|
|
||||||
window.Discourse.Post = Discourse.Model.extend({
|
@class Post
|
||||||
/* Url to this post
|
@extends Discourse.Model
|
||||||
*/
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Post = Discourse.Model.extend({
|
||||||
|
|
||||||
url: (function() {
|
url: (function() {
|
||||||
return Discourse.Utilities.postUrl(this.get('topic.slug') || this.get('topic_slug'), this.get('topic_id'), this.get('post_number'));
|
return Discourse.Utilities.postUrl(this.get('topic.slug') || this.get('topic_slug'), this.get('topic_id'), this.get('post_number'));
|
||||||
}).property('post_number', 'topic_id', 'topic.slug'),
|
}).property('post_number', 'topic_id', 'topic.slug'),
|
||||||
|
|
||||||
originalPostUrl: (function() {
|
originalPostUrl: (function() {
|
||||||
return "/t/" + (this.get('topic_id')) + "/" + (this.get('reply_to_post_number'));
|
return "/t/" + (this.get('topic_id')) + "/" + (this.get('reply_to_post_number'));
|
||||||
}).property('reply_to_post_number'),
|
}).property('reply_to_post_number'),
|
||||||
|
|
||||||
showUserReplyTab: (function() {
|
showUserReplyTab: (function() {
|
||||||
return this.get('reply_to_user') && (this.get('reply_to_post_number') < (this.get('post_number') - 1));
|
return this.get('reply_to_user') && (this.get('reply_to_post_number') < (this.get('post_number') - 1));
|
||||||
}).property('reply_to_user', 'reply_to_post_number', 'post_number'),
|
}).property('reply_to_user', 'reply_to_post_number', 'post_number'),
|
||||||
|
|
||||||
firstPost: (function() {
|
firstPost: (function() {
|
||||||
if (this.get('bestOfFirst') === true) {
|
if (this.get('bestOfFirst') === true) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return this.get('post_number') === 1;
|
return this.get('post_number') === 1;
|
||||||
}).property('post_number'),
|
}).property('post_number'),
|
||||||
|
|
||||||
hasHistory: (function() {
|
hasHistory: (function() {
|
||||||
return this.get('version') > 1;
|
return this.get('version') > 1;
|
||||||
}).property('version'),
|
}).property('version'),
|
||||||
|
|
||||||
postElementId: (function() {
|
postElementId: (function() {
|
||||||
return "post_" + (this.get('post_number'));
|
return "post_" + (this.get('post_number'));
|
||||||
}).property(),
|
}).property(),
|
||||||
/*
|
|
||||||
The class for the read icon of the post. It starts with read-icon then adds 'seen' or
|
|
||||||
'last-read' if the post has been seen or is the highest post number seen so far respectively.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// The class for the read icon of the post. It starts with read-icon then adds 'seen' or
|
||||||
|
// 'last-read' if the post has been seen or is the highest post number seen so far respectively.
|
||||||
bookmarkClass: (function() {
|
bookmarkClass: (function() {
|
||||||
var result, topic;
|
var result, topic;
|
||||||
result = 'read-icon';
|
result = 'read-icon';
|
||||||
if (this.get('bookmarked')) {
|
if (this.get('bookmarked')) return result + ' bookmarked';
|
||||||
return result + ' bookmarked';
|
|
||||||
}
|
|
||||||
topic = this.get('topic');
|
topic = this.get('topic');
|
||||||
if (topic && topic.get('last_read_post_number') === this.get('post_number')) {
|
if (topic && topic.get('last_read_post_number') === this.get('post_number')) {
|
||||||
result += ' last-read';
|
result += ' last-read';
|
||||||
@ -46,23 +49,19 @@
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}).property('read', 'topic.last_read_post_number', 'bookmarked'),
|
}).property('read', 'topic.last_read_post_number', 'bookmarked'),
|
||||||
/* Custom tooltips for the bookmark icons
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Custom tooltips for the bookmark icons
|
||||||
bookmarkTooltip: (function() {
|
bookmarkTooltip: (function() {
|
||||||
var topic;
|
var topic;
|
||||||
if (this.get('bookmarked')) {
|
if (this.get('bookmarked')) return Em.String.i18n('bookmarks.created');
|
||||||
return Em.String.i18n('bookmarks.created');
|
if (!this.get('read')) return "";
|
||||||
}
|
|
||||||
if (!this.get('read')) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
topic = this.get('topic');
|
topic = this.get('topic');
|
||||||
if (topic && topic.get('last_read_post_number') === this.get('post_number')) {
|
if (topic && topic.get('last_read_post_number') === this.get('post_number')) {
|
||||||
return Em.String.i18n('bookmarks.last_read');
|
return Em.String.i18n('bookmarks.last_read');
|
||||||
}
|
}
|
||||||
return Em.String.i18n('bookmarks.not_bookmarked');
|
return Em.String.i18n('bookmarks.not_bookmarked');
|
||||||
}).property('read', 'topic.last_read_post_number', 'bookmarked'),
|
}).property('read', 'topic.last_read_post_number', 'bookmarked'),
|
||||||
|
|
||||||
bookmarkedChanged: (function() {
|
bookmarkedChanged: (function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
@ -79,48 +78,38 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).observes('bookmarked'),
|
}).observes('bookmarked'),
|
||||||
|
|
||||||
internalLinks: (function() {
|
internalLinks: (function() {
|
||||||
if (this.blank('link_counts')) {
|
if (this.blank('link_counts')) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.get('link_counts').filterProperty('internal').filterProperty('title');
|
return this.get('link_counts').filterProperty('internal').filterProperty('title');
|
||||||
}).property('link_counts.@each.internal'),
|
}).property('link_counts.@each.internal'),
|
||||||
/* Edits are the version - 1, so version 2 = 1 edit
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Edits are the version - 1, so version 2 = 1 edit
|
||||||
editCount: (function() {
|
editCount: (function() {
|
||||||
return this.get('version') - 1;
|
return this.get('version') - 1;
|
||||||
}).property('version'),
|
}).property('version'),
|
||||||
|
|
||||||
historyHeat: (function() {
|
historyHeat: (function() {
|
||||||
var rightNow, updatedAt, updatedAtDate;
|
var rightNow, updatedAt, updatedAtDate;
|
||||||
if (!(updatedAt = this.get('updated_at'))) {
|
if (!(updatedAt = this.get('updated_at'))) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
rightNow = new Date().getTime();
|
rightNow = new Date().getTime();
|
||||||
/* Show heat on age
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Show heat on age
|
||||||
updatedAtDate = Date.create(updatedAt).getTime();
|
updatedAtDate = Date.create(updatedAt).getTime();
|
||||||
if (updatedAtDate > (rightNow - 60 * 60 * 1000 * 12)) {
|
if (updatedAtDate > (rightNow - 60 * 60 * 1000 * 12)) return 'heatmap-high';
|
||||||
return 'heatmap-high';
|
if (updatedAtDate > (rightNow - 60 * 60 * 1000 * 24)) return 'heatmap-med';
|
||||||
}
|
if (updatedAtDate > (rightNow - 60 * 60 * 1000 * 48)) return 'heatmap-low';
|
||||||
if (updatedAtDate > (rightNow - 60 * 60 * 1000 * 24)) {
|
|
||||||
return 'heatmap-med';
|
|
||||||
}
|
|
||||||
if (updatedAtDate > (rightNow - 60 * 60 * 1000 * 48)) {
|
|
||||||
return 'heatmap-low';
|
|
||||||
}
|
|
||||||
}).property('updated_at'),
|
}).property('updated_at'),
|
||||||
|
|
||||||
flagsAvailable: (function() {
|
flagsAvailable: (function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return Discourse.get('site.flagTypes').filter(function(item) {
|
return Discourse.get('site.flagTypes').filter(function(item) {
|
||||||
return _this.get("actionByName." + (item.get('name_key')) + ".can_act");
|
return _this.get("actionByName." + (item.get('name_key')) + ".can_act");
|
||||||
});
|
});
|
||||||
}).property('Discourse.site.flagTypes', 'actions_summary.@each.can_act'),
|
}).property('Discourse.site.flagTypes', 'actions_summary.@each.can_act'),
|
||||||
|
|
||||||
actionsHistory: (function() {
|
actionsHistory: (function() {
|
||||||
if (!this.present('actions_summary')) {
|
if (!this.present('actions_summary')) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.get('actions_summary').filter(function(i) {
|
return this.get('actions_summary').filter(function(i) {
|
||||||
if (i.get('count') === 0) {
|
if (i.get('count') === 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -131,15 +120,12 @@
|
|||||||
return !i.get('hidden');
|
return !i.get('hidden');
|
||||||
});
|
});
|
||||||
}).property('actions_summary.@each.users', 'actions_summary.@each.count'),
|
}).property('actions_summary.@each.users', 'actions_summary.@each.count'),
|
||||||
/* Save a post and call the callback when done.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Save a post and call the callback when done.
|
||||||
save: function(complete, error) {
|
save: function(complete, error) {
|
||||||
var data, metaData;
|
var data, metaData;
|
||||||
if (!this.get('newPost')) {
|
if (!this.get('newPost')) {
|
||||||
/* We're updating a post
|
// We're updating a post
|
||||||
*/
|
|
||||||
|
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
url: "/posts/" + (this.get('id')),
|
url: "/posts/" + (this.get('id')),
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
@ -148,17 +134,11 @@
|
|||||||
image_sizes: this.get('imageSizes')
|
image_sizes: this.get('imageSizes')
|
||||||
},
|
},
|
||||||
success: function(result) {
|
success: function(result) {
|
||||||
|
|
||||||
console.log(result)
|
|
||||||
|
|
||||||
// If we received a category update, update it
|
// If we received a category update, update it
|
||||||
if (result.category) Discourse.get('site').updateCategory(result.category);
|
if (result.category) Discourse.get('site').updateCategory(result.category);
|
||||||
|
|
||||||
return typeof complete === "function" ? complete(Discourse.Post.create(result.post)) : void 0;
|
return typeof complete === "function" ? complete(Discourse.Post.create(result.post)) : void 0;
|
||||||
},
|
},
|
||||||
error: function(result) {
|
error: function(result) { return typeof error === "function" ? error(result) : void 0; }
|
||||||
return typeof error === "function" ? error(result) : void 0;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -170,14 +150,11 @@
|
|||||||
image_sizes: this.get('imageSizes'),
|
image_sizes: this.get('imageSizes'),
|
||||||
target_usernames: this.get('target_usernames')
|
target_usernames: this.get('target_usernames')
|
||||||
};
|
};
|
||||||
/* Put the metaData into the request
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Put the metaData into the request
|
||||||
if (metaData = this.get('metaData')) {
|
if (metaData = this.get('metaData')) {
|
||||||
data.meta_data = {};
|
data.meta_data = {};
|
||||||
Ember.keys(metaData).forEach(function(key) {
|
Ember.keys(metaData).forEach(function(key) { data.meta_data[key] = metaData.get(key); });
|
||||||
data.meta_data[key] = metaData.get(key);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
@ -192,12 +169,11 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
recover: function() {
|
recover: function() {
|
||||||
return jQuery.ajax("/posts/" + (this.get('id')) + "/recover", {
|
return jQuery.ajax("/posts/" + (this.get('id')) + "/recover", { type: 'PUT', cache: false });
|
||||||
type: 'PUT',
|
|
||||||
cache: false
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"delete": function(complete) {
|
"delete": function(complete) {
|
||||||
return jQuery.ajax("/posts/" + (this.get('id')), {
|
return jQuery.ajax("/posts/" + (this.get('id')), {
|
||||||
type: 'DELETE',
|
type: 'DELETE',
|
||||||
@ -206,11 +182,9 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
Update the properties of this post from an obj, ignoring cooked as we should already
|
|
||||||
have that rendered.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Update the properties of this post from an obj, ignoring cooked as we should already
|
||||||
|
// have that rendered.
|
||||||
updateFromSave: function(obj) {
|
updateFromSave: function(obj) {
|
||||||
var lookup,
|
var lookup,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -225,9 +199,8 @@
|
|||||||
return _this.set(key, val);
|
return _this.set(key, val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
/* Rebuild actions summary
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Rebuild actions summary
|
||||||
this.set('actions_summary', Em.A());
|
this.set('actions_summary', Em.A());
|
||||||
if (obj.actions_summary) {
|
if (obj.actions_summary) {
|
||||||
lookup = Em.Object.create();
|
lookup = Em.Object.create();
|
||||||
@ -262,6 +235,7 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
loadVersions: function(callback) {
|
loadVersions: function(callback) {
|
||||||
return jQuery.get("/posts/" + (this.get('id')) + "/versions.json", function(result) {
|
return jQuery.get("/posts/" + (this.get('id')) + "/versions.json", function(result) {
|
||||||
return callback(result);
|
return callback(result);
|
||||||
@ -272,35 +246,25 @@
|
|||||||
showRepliesBelow: (function() {
|
showRepliesBelow: (function() {
|
||||||
var reply_count, _ref;
|
var reply_count, _ref;
|
||||||
reply_count = this.get('reply_count');
|
reply_count = this.get('reply_count');
|
||||||
/* We don't show replies if there aren't any
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (reply_count === 0) {
|
// We don't show replies if there aren't any
|
||||||
return false;
|
if (reply_count === 0) return false;
|
||||||
}
|
|
||||||
/* Always show replies if the setting `supress_reply_directly_below` is false.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!Discourse.SiteSettings.supress_reply_directly_below) {
|
// Always show replies if the setting `supress_reply_directly_below` is false.
|
||||||
return true;
|
if (!Discourse.SiteSettings.supress_reply_directly_below) return true;
|
||||||
}
|
|
||||||
/*Always show replies if there's more than one
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (reply_count > 1) {
|
// Always show replies if there's more than one
|
||||||
return true;
|
if (reply_count > 1) return true;
|
||||||
}
|
|
||||||
/* If we have *exactly* one reply, we have to consider if it's directly below us
|
// If we have *exactly* one reply, we have to consider if it's directly below us
|
||||||
*/
|
if ((_ref = this.get('topic')) ? _ref.isReplyDirectlyBelow(this) : void 0) return false;
|
||||||
|
|
||||||
if ((_ref = this.get('topic')) ? _ref.isReplyDirectlyBelow(this) : void 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}).property('reply_count')
|
}).property('reply_count')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.Discourse.Post.reopenClass({
|
||||||
|
|
||||||
window.Discourse.Post.reopenClass({
|
|
||||||
createActionSummary: function(result) {
|
createActionSummary: function(result) {
|
||||||
var lookup;
|
var lookup;
|
||||||
if (result.actions_summary) {
|
if (result.actions_summary) {
|
||||||
@ -316,6 +280,7 @@
|
|||||||
return result.set('actionByName', lookup);
|
return result.set('actionByName', lookup);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
create: function(obj, topic) {
|
create: function(obj, topic) {
|
||||||
var result;
|
var result;
|
||||||
result = this._super(obj);
|
result = this._super(obj);
|
||||||
@ -326,6 +291,7 @@
|
|||||||
result.set('topic', topic);
|
result.set('topic', topic);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteMany: function(posts) {
|
deleteMany: function(posts) {
|
||||||
return jQuery.ajax("/posts/destroy_many", {
|
return jQuery.ajax("/posts/destroy_many", {
|
||||||
type: 'DELETE',
|
type: 'DELETE',
|
||||||
@ -336,18 +302,21 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
loadVersion: function(postId, version, callback) {
|
loadVersion: function(postId, version, callback) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery.getJSON("/posts/" + postId + ".json?version=" + version, function(result) {
|
return jQuery.getJSON("/posts/" + postId + ".json?version=" + version, function(result) {
|
||||||
return callback(Discourse.Post.create(result));
|
return callback(Discourse.Post.create(result));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
loadByPostNumber: function(topicId, postId, callback) {
|
loadByPostNumber: function(topicId, postId, callback) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery.getJSON("/posts/by_number/" + topicId + "/" + postId + ".json", function(result) {
|
return jQuery.getJSON("/posts/by_number/" + topicId + "/" + postId + ".json", function(result) {
|
||||||
return callback(Discourse.Post.create(result));
|
return callback(Discourse.Post.create(result));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
loadQuote: function(postId) {
|
loadQuote: function(postId) {
|
||||||
var promise,
|
var promise,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -359,12 +328,14 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
load: function(postId, callback) {
|
load: function(postId, callback) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery.getJSON("/posts/" + postId + ".json", function(result) {
|
return jQuery.getJSON("/posts/" + postId + ".json", function(result) {
|
||||||
return callback(Discourse.Post.create(result));
|
return callback(Discourse.Post.create(result));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing action types (flags, likes) against a Post
|
||||||
|
|
||||||
|
@class PostActionType
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.PostActionType = Discourse.Model.extend({
|
||||||
|
|
||||||
window.Discourse.PostActionType = Discourse.Model.extend({
|
|
||||||
alsoName: (function() {
|
alsoName: (function() {
|
||||||
if (this.get('is_flag')) {
|
if (this.get('is_flag')) return Em.String.i18n('post.actions.flag');
|
||||||
return Em.String.i18n('post.actions.flag');
|
|
||||||
}
|
|
||||||
return this.get('name');
|
return this.get('name');
|
||||||
}).property('is_flag', 'name'),
|
}).property('is_flag', 'name'),
|
||||||
|
|
||||||
alsoNameLower: (function() {
|
alsoNameLower: (function() {
|
||||||
var _ref;
|
var _ref;
|
||||||
return (_ref = this.get('alsoName')) ? _ref.toLowerCase() : void 0;
|
return (_ref = this.get('alsoName')) ? _ref.toLowerCase() : void 0;
|
||||||
}).property('alsoName')
|
}).property('alsoName')
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing the site (instance of Discourse)
|
||||||
|
|
||||||
window.Discourse.Site = Discourse.Model.extend({
|
@class Site
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Site = Discourse.Model.extend({
|
||||||
|
|
||||||
notificationLookup: (function() {
|
notificationLookup: (function() {
|
||||||
var result;
|
var result;
|
||||||
@ -28,9 +34,9 @@
|
|||||||
var existingCategory = this.get('categories').findProperty('id', Em.get(newCategory, 'id'));
|
var existingCategory = this.get('categories').findProperty('id', Em.get(newCategory, 'id'));
|
||||||
if (existingCategory) existingCategory.mergeAttributes(newCategory);
|
if (existingCategory) existingCategory.mergeAttributes(newCategory);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.Discourse.Site.reopenClass({
|
Discourse.Site.reopenClass({
|
||||||
create: function(obj) {
|
create: function(obj) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return Object.tap(this._super(obj), function(result) {
|
return Object.tap(this._super(obj), function(result) {
|
||||||
@ -55,6 +61,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing a Topic
|
||||||
|
|
||||||
Discourse.Topic = Discourse.Model.extend({
|
@class Topic
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.Topic = Discourse.Model.extend({
|
||||||
categoriesBinding: 'Discourse.site.categories',
|
categoriesBinding: 'Discourse.site.categories',
|
||||||
|
|
||||||
fewParticipants: (function() {
|
fewParticipants: (function() {
|
||||||
if (!this.present('participants')) {
|
if (!this.present('participants')) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.get('participants').slice(0, 3);
|
return this.get('participants').slice(0, 3);
|
||||||
}).property('participants'),
|
}).property('participants'),
|
||||||
|
|
||||||
canConvertToRegular: (function() {
|
canConvertToRegular: (function() {
|
||||||
var a;
|
var a = this.get('archetype');
|
||||||
a = this.get('archetype');
|
|
||||||
return a !== 'regular' && a !== 'private_message';
|
return a !== 'regular' && a !== 'private_message';
|
||||||
}).property('archetype'),
|
}).property('archetype'),
|
||||||
|
|
||||||
convertArchetype: function(archetype) {
|
convertArchetype: function(archetype) {
|
||||||
var a;
|
var a;
|
||||||
a = this.get('archetype');
|
a = this.get('archetype');
|
||||||
@ -24,22 +30,22 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
category: (function() {
|
category: (function() {
|
||||||
if (this.get('categories')) {
|
if (this.get('categories')) {
|
||||||
return this.get('categories').findProperty('name', this.get('categoryName'));
|
return this.get('categories').findProperty('name', this.get('categoryName'));
|
||||||
}
|
}
|
||||||
}).property('categoryName', 'categories'),
|
}).property('categoryName', 'categories'),
|
||||||
|
|
||||||
url: (function() {
|
url: (function() {
|
||||||
var slug;
|
var slug = this.get('slug');
|
||||||
slug = this.get('slug');
|
|
||||||
if (slug.isBlank()) {
|
if (slug.isBlank()) {
|
||||||
slug = "topic";
|
slug = "topic";
|
||||||
}
|
}
|
||||||
return "/t/" + slug + "/" + (this.get('id'));
|
return "/t/" + slug + "/" + (this.get('id'));
|
||||||
}).property('id', 'slug'),
|
}).property('id', 'slug'),
|
||||||
/* Helper to build a Url with a post number
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Helper to build a Url with a post number
|
||||||
urlForPostNumber: function(postNumber) {
|
urlForPostNumber: function(postNumber) {
|
||||||
var url;
|
var url;
|
||||||
url = this.get('url');
|
url = this.get('url');
|
||||||
@ -48,42 +54,35 @@
|
|||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
|
|
||||||
lastReadUrl: (function() {
|
lastReadUrl: (function() {
|
||||||
return this.urlForPostNumber(this.get('last_read_post_number'));
|
return this.urlForPostNumber(this.get('last_read_post_number'));
|
||||||
}).property('url', 'last_read_post_number'),
|
}).property('url', 'last_read_post_number'),
|
||||||
|
|
||||||
lastPostUrl: (function() {
|
lastPostUrl: (function() {
|
||||||
return this.urlForPostNumber(this.get('highest_post_number'));
|
return this.urlForPostNumber(this.get('highest_post_number'));
|
||||||
}).property('url', 'highest_post_number'),
|
}).property('url', 'highest_post_number'),
|
||||||
/* The last post in the topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// The last post in the topic
|
||||||
lastPost: function() {
|
lastPost: function() {
|
||||||
return this.get('posts').last();
|
return this.get('posts').last();
|
||||||
},
|
},
|
||||||
|
|
||||||
postsChanged: (function() {
|
postsChanged: (function() {
|
||||||
var last, posts;
|
var last, posts;
|
||||||
posts = this.get('posts');
|
posts = this.get('posts');
|
||||||
last = posts.last();
|
last = posts.last();
|
||||||
if (!(last && last.set && !last.lastPost)) {
|
if (!(last && last.set && !last.lastPost)) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
posts.each(function(p) {
|
posts.each(function(p) {
|
||||||
if (p.lastPost) {
|
if (p.lastPost) return p.set('lastPost', false);
|
||||||
return p.set('lastPost', false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
last.set('lastPost', true);
|
last.set('lastPost', true);
|
||||||
return true;
|
return true;
|
||||||
}).observes('posts.@each', 'posts'),
|
}).observes('posts.@each', 'posts'),
|
||||||
/* The amount of new posts to display. It might be different than what the server
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* tells us if we are still asynchronously flushing our "recently read" data.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* So take what the browser has seen into consideration.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// The amount of new posts to display. It might be different than what the server
|
||||||
|
// tells us if we are still asynchronously flushing our "recently read" data.
|
||||||
|
// So take what the browser has seen into consideration.
|
||||||
displayNewPosts: (function() {
|
displayNewPosts: (function() {
|
||||||
var delta, highestSeen, result;
|
var delta, highestSeen, result;
|
||||||
if (highestSeen = Discourse.get('highestSeenByTopic')[this.get('id')]) {
|
if (highestSeen = Discourse.get('highestSeenByTopic')[this.get('id')]) {
|
||||||
@ -98,52 +97,41 @@
|
|||||||
}
|
}
|
||||||
return this.get('new_posts');
|
return this.get('new_posts');
|
||||||
}).property('new_posts', 'id'),
|
}).property('new_posts', 'id'),
|
||||||
/* The coldmap class for the age of the topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// The coldmap class for the age of the topic
|
||||||
ageCold: (function() {
|
ageCold: (function() {
|
||||||
var createdAt, createdAtDays, daysSinceEpoch, lastPost, nowDays;
|
var createdAt, createdAtDays, daysSinceEpoch, lastPost, nowDays;
|
||||||
if (!(lastPost = this.get('last_posted_at'))) {
|
if (!(lastPost = this.get('last_posted_at'))) return;
|
||||||
return;
|
if (!(createdAt = this.get('created_at'))) return;
|
||||||
}
|
|
||||||
if (!(createdAt = this.get('created_at'))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
daysSinceEpoch = function(dt) {
|
daysSinceEpoch = function(dt) {
|
||||||
/* 1000 * 60 * 60 * 24 = days since epoch
|
// 1000 * 60 * 60 * 24 = days since epoch
|
||||||
*/
|
|
||||||
return dt.getTime() / 86400000;
|
return dt.getTime() / 86400000;
|
||||||
};
|
};
|
||||||
/* Show heat on age
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Show heat on age
|
||||||
nowDays = daysSinceEpoch(new Date());
|
nowDays = daysSinceEpoch(new Date());
|
||||||
createdAtDays = daysSinceEpoch(new Date(createdAt));
|
createdAtDays = daysSinceEpoch(new Date(createdAt));
|
||||||
if (daysSinceEpoch(new Date(lastPost)) > nowDays - 90) {
|
if (daysSinceEpoch(new Date(lastPost)) > nowDays - 90) {
|
||||||
if (createdAtDays < nowDays - 60) {
|
if (createdAtDays < nowDays - 60) return 'coldmap-high';
|
||||||
return 'coldmap-high';
|
if (createdAtDays < nowDays - 30) return 'coldmap-med';
|
||||||
}
|
if (createdAtDays < nowDays - 14) return 'coldmap-low';
|
||||||
if (createdAtDays < nowDays - 30) {
|
|
||||||
return 'coldmap-med';
|
|
||||||
}
|
|
||||||
if (createdAtDays < nowDays - 14) {
|
|
||||||
return 'coldmap-low';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}).property('age', 'created_at'),
|
}).property('age', 'created_at'),
|
||||||
|
|
||||||
archetypeObject: (function() {
|
archetypeObject: (function() {
|
||||||
return Discourse.get('site.archetypes').findProperty('id', this.get('archetype'));
|
return Discourse.get('site.archetypes').findProperty('id', this.get('archetype'));
|
||||||
}).property('archetype'),
|
}).property('archetype'),
|
||||||
|
|
||||||
isPrivateMessage: (function() {
|
isPrivateMessage: (function() {
|
||||||
return this.get('archetype') === 'private_message';
|
return this.get('archetype') === 'private_message';
|
||||||
}).property('archetype'),
|
}).property('archetype'),
|
||||||
/* Does this topic only have a single post?
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Does this topic only have a single post?
|
||||||
singlePost: (function() {
|
singlePost: (function() {
|
||||||
return this.get('posts_count') === 1;
|
return this.get('posts_count') === 1;
|
||||||
}).property('posts_count'),
|
}).property('posts_count'),
|
||||||
|
|
||||||
toggleStatus: function(property) {
|
toggleStatus: function(property) {
|
||||||
this.toggleProperty(property);
|
this.toggleProperty(property);
|
||||||
return jQuery.post("" + (this.get('url')) + "/status", {
|
return jQuery.post("" + (this.get('url')) + "/status", {
|
||||||
@ -152,6 +140,7 @@
|
|||||||
enabled: this.get(property) ? 'true' : 'false'
|
enabled: this.get(property) ? 'true' : 'false'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleStar: function() {
|
toggleStar: function() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this.toggleProperty('starred');
|
this.toggleProperty('starred');
|
||||||
@ -169,24 +158,19 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Save any changes we've made to the model
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Save any changes we've made to the model
|
||||||
save: function() {
|
save: function() {
|
||||||
/* Don't save unless we can
|
// Don't save unless we can
|
||||||
*/
|
if (!this.get('can_edit')) return;
|
||||||
if (!this.get('can_edit')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return jQuery.post(this.get('url'), {
|
return jQuery.post(this.get('url'), {
|
||||||
_method: 'put',
|
_method: 'put',
|
||||||
title: this.get('title'),
|
title: this.get('title'),
|
||||||
category: this.get('category.name')
|
category: this.get('category.name')
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Reset our read data for this topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Reset our read data for this topic
|
||||||
resetRead: function(callback) {
|
resetRead: function(callback) {
|
||||||
return jQuery.ajax("/t/" + (this.get('id')) + "/timings", {
|
return jQuery.ajax("/t/" + (this.get('id')) + "/timings", {
|
||||||
type: 'DELETE',
|
type: 'DELETE',
|
||||||
@ -195,9 +179,8 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Invite a user to this topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Invite a user to this topic
|
||||||
inviteUser: function(user) {
|
inviteUser: function(user) {
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
@ -207,9 +190,8 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Delete this topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Delete this topic
|
||||||
"delete": function(callback) {
|
"delete": function(callback) {
|
||||||
return jQuery.ajax("/t/" + (this.get('id')), {
|
return jQuery.ajax("/t/" + (this.get('id')), {
|
||||||
type: 'DELETE',
|
type: 'DELETE',
|
||||||
@ -218,47 +200,37 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Load the posts for this topic
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Load the posts for this topic
|
||||||
loadPosts: function(opts) {
|
loadPosts: function(opts) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
if (!opts) {
|
if (!opts) {
|
||||||
opts = {};
|
opts = {};
|
||||||
}
|
}
|
||||||
/* Load the first post by default
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Load the first post by default
|
||||||
if (!opts.bestOf) {
|
if (!opts.bestOf) {
|
||||||
if (!opts.nearPost) opts.nearPost = 1
|
if (!opts.nearPost) opts.nearPost = 1
|
||||||
}
|
}
|
||||||
/* If we already have that post in the DOM, jump to it
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (Discourse.TopicView.scrollTo(this.get('id'), opts.nearPost)) {
|
// If we already have that post in the DOM, jump to it
|
||||||
return;
|
if (Discourse.TopicView.scrollTo(this.get('id'), opts.nearPost)) return;
|
||||||
}
|
|
||||||
return Discourse.Topic.find(this.get('id'), {
|
return Discourse.Topic.find(this.get('id'), {
|
||||||
nearPost: opts.nearPost,
|
nearPost: opts.nearPost,
|
||||||
bestOf: opts.bestOf,
|
bestOf: opts.bestOf,
|
||||||
trackVisit: opts.trackVisit
|
trackVisit: opts.trackVisit
|
||||||
}).then(function(result) {
|
}).then(function(result) {
|
||||||
/* If loading the topic succeeded...
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Update the slug if different
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If loading the topic succeeded...
|
||||||
|
// Update the slug if different
|
||||||
var closestPostNumber, lastPost, postDiff;
|
var closestPostNumber, lastPost, postDiff;
|
||||||
if (result.slug) {
|
if (result.slug) {
|
||||||
_this.set('slug', result.slug);
|
_this.set('slug', result.slug);
|
||||||
}
|
}
|
||||||
/* If we want to scroll to a post that doesn't exist, just pop them to the closest
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* one instead. This is likely happening due to a deleted post.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// If we want to scroll to a post that doesn't exist, just pop them to the closest
|
||||||
|
// one instead. This is likely happening due to a deleted post.
|
||||||
opts.nearPost = parseInt(opts.nearPost, 10);
|
opts.nearPost = parseInt(opts.nearPost, 10);
|
||||||
closestPostNumber = 0;
|
closestPostNumber = 0;
|
||||||
postDiff = Number.MAX_VALUE;
|
postDiff = Number.MAX_VALUE;
|
||||||
@ -273,6 +245,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
opts.nearPost = closestPostNumber;
|
opts.nearPost = closestPostNumber;
|
||||||
if (_this.get('participants')) {
|
if (_this.get('participants')) {
|
||||||
_this.get('participants').clear();
|
_this.get('participants').clear();
|
||||||
@ -293,12 +266,8 @@
|
|||||||
ignoreIfChanged: true
|
ignoreIfChanged: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/* Okay this is weird, but let's store the length of the next post
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* when there
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Okay this is weird, but let's store the length of the next post when there
|
||||||
lastPost = null;
|
lastPost = null;
|
||||||
result.posts.each(function(p) {
|
result.posts.each(function(p) {
|
||||||
var post;
|
var post;
|
||||||
@ -314,16 +283,16 @@
|
|||||||
return _this.set('message', Em.String.i18n('topic.not_found.description'));
|
return _this.set('message', Em.String.i18n('topic.not_found.description'));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
notificationReasonText: (function() {
|
notificationReasonText: (function() {
|
||||||
var locale_string;
|
var locale_string;
|
||||||
locale_string = "topic.notifications.reasons." + this.notification_level;
|
locale_string = "topic.notifications.reasons." + this.notification_level;
|
||||||
if (typeof this.notifications_reason_id === 'number') {
|
if (typeof this.notifications_reason_id === 'number') {
|
||||||
locale_string += "_" + this.notifications_reason_id;
|
locale_string += "_" + this.notifications_reason_id;
|
||||||
}
|
}
|
||||||
return Em.String.i18n(locale_string, {
|
return Em.String.i18n(locale_string, { username: Discourse.currentUser.username.toLowerCase() });
|
||||||
username: Discourse.currentUser.username.toLowerCase()
|
|
||||||
});
|
|
||||||
}).property('notifications_reason_id'),
|
}).property('notifications_reason_id'),
|
||||||
|
|
||||||
updateNotifications: function(v) {
|
updateNotifications: function(v) {
|
||||||
this.set('notification_level', v);
|
this.set('notification_level', v);
|
||||||
this.set('notifications_reason_id', null);
|
this.set('notifications_reason_id', null);
|
||||||
@ -335,9 +304,8 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* use to add post to topics protecting from dupes
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// use to add post to topics protecting from dupes
|
||||||
pushPosts: function(newPosts) {
|
pushPosts: function(newPosts) {
|
||||||
var map, posts;
|
var map, posts;
|
||||||
map = {};
|
map = {};
|
||||||
@ -351,9 +319,8 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Is the reply to a post directly below it?
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Is the reply to a post directly below it?
|
||||||
isReplyDirectlyBelow: function(post) {
|
isReplyDirectlyBelow: function(post) {
|
||||||
var postBelow, posts;
|
var postBelow, posts;
|
||||||
posts = this.get('posts');
|
posts = this.get('posts');
|
||||||
@ -361,28 +328,23 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
postBelow = posts[posts.indexOf(post) + 1];
|
postBelow = posts[posts.indexOf(post) + 1];
|
||||||
/* If the post directly below's reply_to_post_number is our post number, it's
|
// If the post directly below's reply_to_post_number is our post number, it's
|
||||||
considered directly below. */
|
// considered directly below.
|
||||||
return (postBelow ? postBelow.get('reply_to_post_number') : void 0) === post.get('post_number');
|
return (postBelow ? postBelow.get('reply_to_post_number') : void 0) === post.get('post_number');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.Discourse.Topic.reopenClass({
|
window.Discourse.Topic.reopenClass({
|
||||||
NotificationLevel: {
|
NotificationLevel: {
|
||||||
WATCHING: 3,
|
WATCHING: 3,
|
||||||
TRACKING: 2,
|
TRACKING: 2,
|
||||||
REGULAR: 1,
|
REGULAR: 1,
|
||||||
MUTE: 0
|
MUTE: 0
|
||||||
},
|
},
|
||||||
/* Load a topic, but accepts a set of filters
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* options:
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* onLoad - the callback after the topic is loaded
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Load a topic, but accepts a set of filters
|
||||||
|
// options:
|
||||||
|
// onLoad - the callback after the topic is loaded
|
||||||
find: function(topicId, opts) {
|
find: function(topicId, opts) {
|
||||||
var data, promise, url,
|
var data, promise, url,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -400,24 +362,21 @@
|
|||||||
if (opts.trackVisit) {
|
if (opts.trackVisit) {
|
||||||
data.track_visit = true;
|
data.track_visit = true;
|
||||||
}
|
}
|
||||||
/* Add username filters if we have them
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Add username filters if we have them
|
||||||
if (opts.userFilters && opts.userFilters.length > 0) {
|
if (opts.userFilters && opts.userFilters.length > 0) {
|
||||||
data.username_filters = [];
|
data.username_filters = [];
|
||||||
opts.userFilters.forEach(function(username) {
|
opts.userFilters.forEach(function(username) {
|
||||||
return data.username_filters.push(username);
|
return data.username_filters.push(username);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/* Add the best of filter if we have it
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Add the best of filter if we have it
|
||||||
if (opts.bestOf === true) {
|
if (opts.bestOf === true) {
|
||||||
data.best_of = true;
|
data.best_of = true;
|
||||||
}
|
}
|
||||||
/* Check the preload store. If not, load it via JSON
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Check the preload store. If not, load it via JSON
|
||||||
promise = new RSVP.Promise();
|
promise = new RSVP.Promise();
|
||||||
PreloadStore.get("topic_" + topicId, function() {
|
PreloadStore.get("topic_" + topicId, function() {
|
||||||
return jQuery.getJSON(url + ".json", data);
|
return jQuery.getJSON(url + ".json", data);
|
||||||
@ -433,9 +392,8 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
/* Create a topic from posts
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Create a topic from posts
|
||||||
movePosts: function(topicId, title, postIds) {
|
movePosts: function(topicId, title, postIds) {
|
||||||
return jQuery.ajax("/t/" + topicId + "/move-posts", {
|
return jQuery.ajax("/t/" + topicId + "/move-posts", {
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
@ -445,6 +403,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
create: function(obj, topicView) {
|
create: function(obj, topicView) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return Object.tap(this._super(obj), function(result) {
|
return Object.tap(this._super(obj), function(result) {
|
||||||
@ -463,6 +422,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}).call(this);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing a list of topics
|
||||||
|
|
||||||
|
@class TopicList
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
|
||||||
|
Discourse.TopicList = Discourse.Model.extend({
|
||||||
|
|
||||||
window.Discourse.TopicList = Discourse.Model.extend({
|
|
||||||
loadMoreTopics: function() {
|
loadMoreTopics: function() {
|
||||||
var moreUrl, promise,
|
var moreUrl, promise,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -33,6 +41,7 @@
|
|||||||
}
|
}
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
insert: function(json) {
|
insert: function(json) {
|
||||||
var newTopic;
|
var newTopic;
|
||||||
newTopic = Discourse.TopicList.decodeTopic(json);
|
newTopic = Discourse.TopicList.decodeTopic(json);
|
||||||
@ -43,9 +52,11 @@
|
|||||||
newTopic.set('highlightAfterInsert', true);
|
newTopic.set('highlightAfterInsert', true);
|
||||||
return this.get('inserted').unshiftObject(newTopic);
|
return this.get('inserted').unshiftObject(newTopic);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
window.Discourse.TopicList.reopenClass({
|
});
|
||||||
|
|
||||||
|
Discourse.TopicList.reopenClass({
|
||||||
|
|
||||||
decodeTopic: function(result) {
|
decodeTopic: function(result) {
|
||||||
var categories, topic, users;
|
var categories, topic, users;
|
||||||
categories = this.extractByKey(result.categories, Discourse.Category);
|
categories = this.extractByKey(result.categories, Discourse.Category);
|
||||||
@ -57,10 +68,9 @@
|
|||||||
});
|
});
|
||||||
return Discourse.Topic.create(topic);
|
return Discourse.Topic.create(topic);
|
||||||
},
|
},
|
||||||
topicsFrom: function(result) {
|
|
||||||
/* Stitch together our side loaded data
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
topicsFrom: function(result) {
|
||||||
|
// Stitch together our side loaded data
|
||||||
var categories, topics, users;
|
var categories, topics, users;
|
||||||
categories = this.extractByKey(result.categories, Discourse.Category);
|
categories = this.extractByKey(result.categories, Discourse.Category);
|
||||||
users = this.extractByKey(result.users, Discourse.User);
|
users = this.extractByKey(result.users, Discourse.User);
|
||||||
@ -74,6 +84,7 @@
|
|||||||
});
|
});
|
||||||
return topics;
|
return topics;
|
||||||
},
|
},
|
||||||
|
|
||||||
list: function(menuItem) {
|
list: function(menuItem) {
|
||||||
var filter, found, list, promise, topic_list, url;
|
var filter, found, list, promise, topic_list, url;
|
||||||
filter = menuItem.name;
|
filter = menuItem.name;
|
||||||
@ -114,6 +125,6 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,24 +1,37 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing a user on Discourse
|
||||||
|
|
||||||
|
@class User
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.User = Discourse.Model.extend({
|
||||||
|
|
||||||
window.Discourse.User = Discourse.Model.extend({
|
|
||||||
avatarLarge: (function() {
|
avatarLarge: (function() {
|
||||||
return Discourse.Utilities.avatarUrl(this.get('username'), 'large', this.get('avatar_template'));
|
return Discourse.Utilities.avatarUrl(this.get('username'), 'large', this.get('avatar_template'));
|
||||||
}).property('username'),
|
}).property('username'),
|
||||||
|
|
||||||
avatarSmall: (function() {
|
avatarSmall: (function() {
|
||||||
return Discourse.Utilities.avatarUrl(this.get('username'), 'small', this.get('avatar_template'));
|
return Discourse.Utilities.avatarUrl(this.get('username'), 'small', this.get('avatar_template'));
|
||||||
}).property('username'),
|
}).property('username'),
|
||||||
|
|
||||||
websiteName: (function() {
|
websiteName: (function() {
|
||||||
return this.get('website').split("/")[2];
|
return this.get('website').split("/")[2];
|
||||||
}).property('website'),
|
}).property('website'),
|
||||||
|
|
||||||
path: (function() {
|
path: (function() {
|
||||||
return "/users/" + (this.get('username_lower'));
|
return "/users/" + (this.get('username_lower'));
|
||||||
}).property('username'),
|
}).property('username'),
|
||||||
|
|
||||||
username_lower: (function() {
|
username_lower: (function() {
|
||||||
return this.get('username').toLowerCase();
|
return this.get('username').toLowerCase();
|
||||||
}).property('username'),
|
}).property('username'),
|
||||||
|
|
||||||
trustLevel: (function() {
|
trustLevel: (function() {
|
||||||
return Discourse.get('site.trust_levels').findProperty('id', this.get('trust_level'));
|
return Discourse.get('site.trust_levels').findProperty('id', this.get('trust_level'));
|
||||||
}).property('trust_level'),
|
}).property('trust_level'),
|
||||||
|
|
||||||
changeUsername: function(newUsername) {
|
changeUsername: function(newUsername) {
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
url: "/users/" + (this.get('username_lower')) + "/preferences/username",
|
url: "/users/" + (this.get('username_lower')) + "/preferences/username",
|
||||||
@ -28,6 +41,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
changeEmail: function(email) {
|
changeEmail: function(email) {
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
url: "/users/" + (this.get('username_lower')) + "/preferences/email",
|
url: "/users/" + (this.get('username_lower')) + "/preferences/email",
|
||||||
@ -37,9 +51,11 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
copy: function(deep) {
|
copy: function(deep) {
|
||||||
return Discourse.User.create(this.getProperties(Ember.keys(this)));
|
return Discourse.User.create(this.getProperties(Ember.keys(this)));
|
||||||
},
|
},
|
||||||
|
|
||||||
save: function(finished) {
|
save: function(finished) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
return jQuery.ajax("/users/" + this.get('username').toLowerCase(), {
|
return jQuery.ajax("/users/" + this.get('username').toLowerCase(), {
|
||||||
@ -53,14 +69,11 @@
|
|||||||
'digest_after_days',
|
'digest_after_days',
|
||||||
'new_topic_duration_minutes'),
|
'new_topic_duration_minutes'),
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
success: function() {
|
success: function() { return finished(true); },
|
||||||
return finished(true);
|
error: function() { return finished(false); }
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
return finished(false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
changePassword: function(callback) {
|
changePassword: function(callback) {
|
||||||
var good;
|
var good;
|
||||||
good = false;
|
good = false;
|
||||||
@ -71,9 +84,7 @@
|
|||||||
username: this.get('username')
|
username: this.get('username')
|
||||||
},
|
},
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
success: function() {
|
success: function() { good = true; },
|
||||||
good = true;
|
|
||||||
},
|
|
||||||
complete: function() {
|
complete: function() {
|
||||||
var message;
|
var message;
|
||||||
message = "error";
|
message = "error";
|
||||||
@ -84,6 +95,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
filterStream: function(filter) {
|
filterStream: function(filter) {
|
||||||
if (Discourse.UserAction.statGroups[filter]) {
|
if (Discourse.UserAction.statGroups[filter]) {
|
||||||
filter = Discourse.UserAction.statGroups[filter].join(",");
|
filter = Discourse.UserAction.statGroups[filter].join(",");
|
||||||
@ -92,6 +104,7 @@
|
|||||||
this.set('stream', Em.A());
|
this.set('stream', Em.A());
|
||||||
return this.loadMoreUserActions();
|
return this.loadMoreUserActions();
|
||||||
},
|
},
|
||||||
|
|
||||||
loadUserAction: function(id) {
|
loadUserAction: function(id) {
|
||||||
var stream,
|
var stream,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -117,17 +130,18 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
loadMoreUserActions: function(callback) {
|
loadMoreUserActions: function(callback) {
|
||||||
var stream, url,
|
var stream, url,
|
||||||
_this = this;
|
_this = this;
|
||||||
stream = this.get('stream');
|
stream = this.get('stream');
|
||||||
if (!stream) {
|
if (!stream) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
url = "/user_actions?offset=" + stream.length + "&user_id=" + (this.get("id"));
|
url = "/user_actions?offset=" + stream.length + "&user_id=" + (this.get("id"));
|
||||||
if (this.get('streamFilter')) {
|
if (this.get('streamFilter')) {
|
||||||
url += "&filter=" + (this.get('streamFilter'));
|
url += "&filter=" + (this.get('streamFilter'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
@ -149,12 +163,11 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
statsCountNonPM: (function() {
|
statsCountNonPM: (function() {
|
||||||
var stats, total;
|
var stats, total;
|
||||||
total = 0;
|
total = 0;
|
||||||
if (!(stats = this.get('stats'))) {
|
if (!(stats = this.get('stats'))) return 0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
this.get('stats').each(function(s) {
|
this.get('stats').each(function(s) {
|
||||||
if (!s.get("isPM")) {
|
if (!s.get("isPM")) {
|
||||||
total += parseInt(s.count, 10);
|
total += parseInt(s.count, 10);
|
||||||
@ -162,12 +175,11 @@
|
|||||||
});
|
});
|
||||||
return total;
|
return total;
|
||||||
}).property('stats.@each'),
|
}).property('stats.@each'),
|
||||||
|
|
||||||
statsExcludingPms: (function() {
|
statsExcludingPms: (function() {
|
||||||
var r;
|
var r;
|
||||||
r = [];
|
r = [];
|
||||||
if (this.blank('stats')) {
|
if (this.blank('stats')) return r;
|
||||||
return r;
|
|
||||||
}
|
|
||||||
this.get('stats').each(function(s) {
|
this.get('stats').each(function(s) {
|
||||||
if (!s.get('isPM')) {
|
if (!s.get('isPM')) {
|
||||||
return r.push(s);
|
return r.push(s);
|
||||||
@ -175,19 +187,17 @@
|
|||||||
});
|
});
|
||||||
return r;
|
return r;
|
||||||
}).property('stats.@each'),
|
}).property('stats.@each'),
|
||||||
|
|
||||||
statsPmsOnly: (function() {
|
statsPmsOnly: (function() {
|
||||||
var r;
|
var r;
|
||||||
r = [];
|
r = [];
|
||||||
if (this.blank('stats')) {
|
if (this.blank('stats')) return r;
|
||||||
return r;
|
|
||||||
}
|
|
||||||
this.get('stats').each(function(s) {
|
this.get('stats').each(function(s) {
|
||||||
if (s.get('isPM')) {
|
if (s.get('isPM')) return r.push(s);
|
||||||
return r.push(s);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return r;
|
return r;
|
||||||
}).property('stats.@each'),
|
}).property('stats.@each'),
|
||||||
|
|
||||||
inboxCount: (function() {
|
inboxCount: (function() {
|
||||||
var r;
|
var r;
|
||||||
r = 0;
|
r = 0;
|
||||||
@ -199,6 +209,7 @@
|
|||||||
});
|
});
|
||||||
return r;
|
return r;
|
||||||
}).property('stats.@each'),
|
}).property('stats.@each'),
|
||||||
|
|
||||||
sentItemsCount: (function() {
|
sentItemsCount: (function() {
|
||||||
var r;
|
var r;
|
||||||
r = 0;
|
r = 0;
|
||||||
@ -210,9 +221,10 @@
|
|||||||
});
|
});
|
||||||
return r;
|
return r;
|
||||||
}).property('stats.@each')
|
}).property('stats.@each')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Discourse.User.reopenClass({
|
||||||
|
|
||||||
window.Discourse.User.reopenClass({
|
|
||||||
checkUsername: function(username, email) {
|
checkUsername: function(username, email) {
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
url: '/users/check_username',
|
url: '/users/check_username',
|
||||||
@ -223,6 +235,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
groupStats: function(stats) {
|
groupStats: function(stats) {
|
||||||
var g,
|
var g,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -260,6 +273,7 @@
|
|||||||
return !s;
|
return !s;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
find: function(username) {
|
find: function(username) {
|
||||||
var promise,
|
var promise,
|
||||||
_this = this;
|
_this = this;
|
||||||
@ -267,9 +281,7 @@
|
|||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
url: "/users/" + username + '.json',
|
url: "/users/" + username + '.json',
|
||||||
success: function(json) {
|
success: function(json) {
|
||||||
/* todo: decompose to object
|
// todo: decompose to object
|
||||||
*/
|
|
||||||
|
|
||||||
var user;
|
var user;
|
||||||
json.user.stats = _this.groupStats(json.user.stats.map(function(s) {
|
json.user.stats = _this.groupStats(json.user.stats.map(function(s) {
|
||||||
var obj;
|
var obj;
|
||||||
@ -291,6 +303,7 @@
|
|||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
createAccount: function(name, email, password, username, passwordConfirm, challenge) {
|
createAccount: function(name, email, password, username, passwordConfirm, challenge) {
|
||||||
return jQuery.ajax({
|
return jQuery.ajax({
|
||||||
url: '/users',
|
url: '/users',
|
||||||
@ -306,6 +319,4 @@
|
|||||||
type: 'POST'
|
type: 'POST'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,22 +1,32 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing actions users have taken
|
||||||
|
|
||||||
|
@class UserAction
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserAction = Discourse.Model.extend({
|
||||||
|
|
||||||
window.Discourse.UserAction = Discourse.Model.extend({
|
|
||||||
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'));
|
||||||
}).property(),
|
}).property(),
|
||||||
|
|
||||||
replyUrl: (function() {
|
replyUrl: (function() {
|
||||||
return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('reply_to_post_number'));
|
return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('reply_to_post_number'));
|
||||||
}).property(),
|
}).property(),
|
||||||
|
|
||||||
isPM: (function() {
|
isPM: (function() {
|
||||||
var a;
|
var a = this.get('action_type');
|
||||||
a = this.get('action_type');
|
|
||||||
return a === Discourse.UserAction.NEW_PRIVATE_MESSAGE || a === Discourse.UserAction.GOT_PRIVATE_MESSAGE;
|
return a === Discourse.UserAction.NEW_PRIVATE_MESSAGE || a === Discourse.UserAction.GOT_PRIVATE_MESSAGE;
|
||||||
}).property(),
|
}).property(),
|
||||||
|
|
||||||
isPostAction: (function() {
|
isPostAction: (function() {
|
||||||
var a;
|
var a;
|
||||||
a = this.get('action_type');
|
a = this.get('action_type');
|
||||||
return a === Discourse.UserAction.RESPONSE || a === Discourse.UserAction.POST || a === Discourse.UserAction.NEW_TOPIC;
|
return a === Discourse.UserAction.RESPONSE || a === Discourse.UserAction.POST || a === Discourse.UserAction.NEW_TOPIC;
|
||||||
}).property(),
|
}).property(),
|
||||||
|
|
||||||
addChild: function(action) {
|
addChild: function(action) {
|
||||||
var bucket, current, groups, ua;
|
var bucket, current, groups, ua;
|
||||||
groups = this.get("childGroups");
|
groups = this.get("childGroups");
|
||||||
@ -56,6 +66,7 @@
|
|||||||
current.push(action);
|
current.push(action);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
children: (function() {
|
children: (function() {
|
||||||
var g, rval;
|
var g, rval;
|
||||||
g = this.get("childGroups");
|
g = this.get("childGroups");
|
||||||
@ -67,14 +78,15 @@
|
|||||||
}
|
}
|
||||||
return rval;
|
return rval;
|
||||||
}).property("childGroups"),
|
}).property("childGroups"),
|
||||||
|
|
||||||
switchToActing: function() {
|
switchToActing: function() {
|
||||||
this.set('username', this.get('acting_username'));
|
this.set('username', this.get('acting_username'));
|
||||||
this.set('avatar_template', this.get('acting_avatar_template'));
|
this.set('avatar_template', this.get('acting_avatar_template'));
|
||||||
return this.set('name', this.get('acting_name'));
|
this.set('name', this.get('acting_name'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.Discourse.UserAction.reopenClass({
|
Discourse.UserAction.reopenClass({
|
||||||
collapseStream: function(stream) {
|
collapseStream: function(stream) {
|
||||||
var collapse, collapsed, pos, uniq;
|
var collapse, collapsed, pos, uniq;
|
||||||
collapse = [this.LIKE, this.WAS_LIKED, this.STAR, this.EDIT, this.BOOKMARK];
|
collapse = [this.LIKE, this.WAS_LIKED, this.STAR, this.EDIT, this.BOOKMARK];
|
||||||
@ -110,9 +122,8 @@
|
|||||||
});
|
});
|
||||||
return collapsed;
|
return collapsed;
|
||||||
},
|
},
|
||||||
/* in future we should be sending this through from the server
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// in future we should be sending this through from the server
|
||||||
LIKE: 1,
|
LIKE: 1,
|
||||||
WAS_LIKED: 2,
|
WAS_LIKED: 2,
|
||||||
BOOKMARK: 3,
|
BOOKMARK: 3,
|
||||||
@ -125,15 +136,15 @@
|
|||||||
EDIT: 11,
|
EDIT: 11,
|
||||||
NEW_PRIVATE_MESSAGE: 12,
|
NEW_PRIVATE_MESSAGE: 12,
|
||||||
GOT_PRIVATE_MESSAGE: 13
|
GOT_PRIVATE_MESSAGE: 13
|
||||||
});
|
});
|
||||||
|
|
||||||
window.Discourse.UserAction.reopenClass({
|
window.Discourse.UserAction.reopenClass({
|
||||||
statGroups: (function() {
|
statGroups: (function() {
|
||||||
var g;
|
var g;
|
||||||
g = {};
|
g = {};
|
||||||
g[Discourse.UserAction.RESPONSE] = [Discourse.UserAction.RESPONSE, Discourse.UserAction.MENTION, Discourse.UserAction.QUOTE];
|
g[Discourse.UserAction.RESPONSE] = [Discourse.UserAction.RESPONSE, Discourse.UserAction.MENTION, Discourse.UserAction.QUOTE];
|
||||||
return g;
|
return g;
|
||||||
})()
|
})()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing a group of UserActions
|
||||||
|
|
||||||
window.Discourse.UserActionGroup = Discourse.Model.extend({
|
@class UserActionGroup
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserActionGroup = Discourse.Model.extend({
|
||||||
push: function(item) {
|
push: function(item) {
|
||||||
if (!this.items) {
|
if (!this.items) {
|
||||||
this.items = [];
|
this.items = [];
|
||||||
}
|
}
|
||||||
return this.items.push(item);
|
return this.items.push(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
(function() {
|
/**
|
||||||
|
A data model representing a statistic on a UserAction
|
||||||
|
|
||||||
|
@class UserActionStat
|
||||||
|
@extends Discourse.Model
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserActionStat = Discourse.Model.extend({});
|
||||||
|
|
||||||
window.Discourse.UserActionStat = Discourse.Model.extend({});
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user