Merge branch 'master' of github.com:discourse/discourse

This commit is contained in:
Neil Lalonde 2013-09-23 09:51:35 -07:00
commit 500a24ebf9
15 changed files with 75 additions and 31 deletions

View File

@ -89,6 +89,13 @@ GIT
rake rake
rake-compiler rake-compiler
GIT
remote: https://github.com/MiniProfiler/rack-mini-profiler.git
revision: e08b751091a41f0066a1b28bd4e2b9b3480a1c1b
specs:
rack-mini-profiler (0.1.31)
rack (>= 1.1.3)
GIT GIT
remote: https://github.com/SamSaffron/annotate_models.git remote: https://github.com/SamSaffron/annotate_models.git
revision: ebe4ba7e3f6ceeb43e4e40078da2b261a1bb71b2 revision: ebe4ba7e3f6ceeb43e4e40078da2b261a1bb71b2
@ -146,12 +153,6 @@ GIT
activerecord (>= 3.0.0) activerecord (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
PATH
remote: /Users/sam/Source/rack-mini-profiler
specs:
rack-mini-profiler (0.1.31)
rack (>= 1.1.3)
PATH PATH
remote: vendor/gems/discourse_emoji remote: vendor/gems/discourse_emoji
specs: specs:

View File

@ -6,7 +6,7 @@
@namespace Discourse @namespace Discourse
@module Discourse @module Discourse
**/ **/
Discourse.AdminEmailIndexController = Discourse.Controller.extend(Discourse.Presence, { Discourse.AdminEmailIndexController = Discourse.Controller.extend({
/** /**
Is the "send test email" button disabled? Is the "send test email" button disabled?

View File

@ -6,7 +6,7 @@
@namespace Discourse @namespace Discourse
@module Discourse @module Discourse
**/ **/
Discourse.AdminEmailPreviewDigestController = Discourse.ObjectController.extend(Discourse.Presence, { Discourse.AdminEmailPreviewDigestController = Discourse.ObjectController.extend({
refresh: function() { refresh: function() {
var model = this.get('model'); var model = this.get('model');

View File

@ -208,6 +208,17 @@ Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
} }
}, },
/**
Add an initializer hook for after the Discourse Application starts up.
@method addInitializer
@param {Function} init the initializer to add.
**/
addInitializer: function(init) {
Discourse.initializers = Discourse.initializers || [];
Discourse.initializers.push(init);
},
/** /**
Start up the Discourse application. Start up the Discourse application.
@ -223,6 +234,12 @@ Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
// Developer specific functions // Developer specific functions
Discourse.Development.observeLiveChanges(); Discourse.Development.observeLiveChanges();
Discourse.subscribeUserToNotifications(); Discourse.subscribeUserToNotifications();
if (Discourse.initializers) {
Discourse.initializers.forEach(function (init) {
init.call(this);
});
}
} }
}); });

View File

@ -8,7 +8,7 @@
@namespace Discourse @namespace Discourse
@module Discourse @module Discourse
**/ **/
Discourse.ComposerView = Discourse.View.extend({ Discourse.ComposerView = Discourse.View.extend(Ember.Evented, {
templateName: 'composer', templateName: 'composer',
elementId: 'reply-control', elementId: 'reply-control',
classNameBindings: ['model.creatingPrivateMessage:private-message', classNameBindings: ['model.creatingPrivateMessage:private-message',
@ -49,18 +49,17 @@ Discourse.ComposerView = Discourse.View.extend({
}.property('model.createdPost'), }.property('model.createdPost'),
observeReplyChanges: function() { observeReplyChanges: function() {
var composerView = this; var self = this;
if (this.get('model.hidePreview')) return; if (this.get('model.hidePreview')) return;
Ember.run.next(null, function() { Ember.run.next(function() {
var $wmdPreview, caretPosition; if (self.editor) {
if (composerView.editor) { self.editor.refreshPreview();
composerView.editor.refreshPreview();
// if the caret is on the last line ensure preview scrolled to bottom // if the caret is on the last line ensure preview scrolled to bottom
caretPosition = Discourse.Utilities.caretPosition(composerView.wmdInput[0]); var caretPosition = Discourse.Utilities.caretPosition(self.wmdInput[0]);
if (!composerView.wmdInput.val().substring(caretPosition).match(/\n/)) { if (!self.wmdInput.val().substring(caretPosition).match(/\n/)) {
$wmdPreview = $('#wmd-preview'); var $wmdPreview = $('#wmd-preview');
if ($wmdPreview.is(':visible')) { if ($wmdPreview.is(':visible')) {
return $wmdPreview.scrollTop($wmdPreview[0].scrollHeight); $wmdPreview.scrollTop($wmdPreview[0].scrollHeight);
} }
} }
} }
@ -129,8 +128,8 @@ Discourse.ComposerView = Discourse.View.extend({
Discourse.SyntaxHighlighting.apply($wmdPreview); Discourse.SyntaxHighlighting.apply($wmdPreview);
var post = this.get('model.post'); var post = this.get('model.post'),
var refresh = false; refresh = false;
// If we are editing a post, we'll refresh its contents once. This is a feature that // If we are editing a post, we'll refresh its contents once. This is a feature that
// allows a user to refresh its contents once. // allows a user to refresh its contents once.
@ -146,6 +145,8 @@ Discourse.ComposerView = Discourse.View.extend({
$('span.mention', $wmdPreview).each(function(i, e) { $('span.mention', $wmdPreview).each(function(i, e) {
Discourse.Mention.load(e, refresh); Discourse.Mention.load(e, refresh);
}); });
this.trigger('previewRefreshed', $wmdPreview);
}, 100), }, 100),
initEditor: function() { initEditor: function() {

View File

@ -6,7 +6,7 @@
@namespace Discourse @namespace Discourse
@module Discourse @module Discourse
**/ **/
Discourse.PostView = Discourse.GroupedView.extend({ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, {
classNames: ['topic-post', 'clearfix'], classNames: ['topic-post', 'clearfix'],
templateName: 'post', templateName: 'post',
classNameBindings: ['postTypeClass', classNameBindings: ['postTypeClass',
@ -193,8 +193,9 @@ Discourse.PostView = Discourse.GroupedView.extend({
}, },
didInsertElement: function() { didInsertElement: function() {
var $post = this.$(); var $post = this.$(),
var post = this.get('post'); post = this.get('post');
this.showLinkCounts(); this.showLinkCounts();
// Track this post // Track this post
@ -204,6 +205,8 @@ Discourse.PostView = Discourse.GroupedView.extend({
Discourse.SyntaxHighlighting.apply($post); Discourse.SyntaxHighlighting.apply($post);
Discourse.Lightbox.apply($post); Discourse.Lightbox.apply($post);
this.trigger('postViewInserted', $post);
// Find all the quotes // Find all the quotes
this.insertQuoteControls(); this.insertQuoteControls();

View File

@ -31,6 +31,8 @@ span.badge-posts {
} }
} }
button.create { button.create {
float: right !important; float: right !important;
border: 1px solid #888; border: 1px solid #888;
@ -449,6 +451,8 @@ blockquote {
margin-left: 8px; margin-left: 8px;
color: #323232; color: #323232;
font-family: "FontAwesome"; font-family: "FontAwesome";
position: relative;
z-index: 20;
} }
.back:before { .back:before {
content: "\f062"; content: "\f062";

View File

@ -284,7 +284,8 @@ class Post < ActiveRecord::Base
AND p2.user_id <> post_timings.user_id AND p2.user_id <> post_timings.user_id
GROUP BY post_timings.topic_id, post_timings.post_number) AS x GROUP BY post_timings.topic_id, post_timings.post_number) AS x
WHERE x.topic_id = posts.topic_id WHERE x.topic_id = posts.topic_id
AND x.post_number = posts.post_number") AND x.post_number = posts.post_number
AND (posts.avg_time <> (x.gmean / 1000)::int OR posts.avg_time IS NULL)")
end end
end end

View File

@ -778,7 +778,7 @@ ru:
Если вам интересно, пройдите по ссылке ниже, чтобы попасть в обсуждение: Если вам интересно, пройдите по ссылке ниже, чтобы попасть в обсуждение:
[Visit %{site_name}[1] [Visit %{site_name}][1]
Вы приглашены доверенным пользователем, поэтому сразу сможете разместить свой ответ без входа на сайт. Вы приглашены доверенным пользователем, поэтому сразу сможете разместить свой ответ без входа на сайт.

View File

@ -87,6 +87,7 @@ module Oneboxer
Entry.new(/^https?:\/\/(?:www\.)?screenr\.com\/.+/), Entry.new(/^https?:\/\/(?:www\.)?screenr\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?tumblr\.com\/.+/, false), Entry.new(/^https?:\/\/(?:www\.)?tumblr\.com\/.+/, false),
Entry.new(/^https?:\/\/(?:www\.)?howtogeek\.com\/.+/, false), Entry.new(/^https?:\/\/(?:www\.)?howtogeek\.com\/.+/, false),
Entry.new(/^https?:\/\/(?:www\.)?screencast\.com\/.+/),
Entry.new(/\/\d{4}\/\d{2}\/\d{2}\//, false), # wordpress Entry.new(/\/\d{4}\/\d{2}\/\d{2}\//, false), # wordpress
Entry.new(/^https?:\/\/[^\/]+\/t\/[^\/]+\/\d+(\/\d+)?(\?.*)?$/), Entry.new(/^https?:\/\/[^\/]+\/t\/[^\/]+\/\d+(\/\d+)?(\?.*)?$/),

View File

@ -47,6 +47,8 @@ class Plugin::Instance
end end
def delete_extra_automatic_assets(good_paths) def delete_extra_automatic_assets(good_paths)
return unless Dir.exists? auto_generated_path
filenames = good_paths.map{|f| File.basename(f)} filenames = good_paths.map{|f| File.basename(f)}
# nuke old files # nuke old files
Dir.foreach(auto_generated_path) do |p| Dir.foreach(auto_generated_path) do |p|
@ -102,7 +104,7 @@ class Plugin::Instance
def automatic_assets def automatic_assets
css = "" css = ""
js = "(function(){" js = ""
css = @styles.join("\n") if @styles css = @styles.join("\n") if @styles
js = @javascripts.join("\n") if @javascripts js = @javascripts.join("\n") if @javascripts
@ -127,10 +129,14 @@ class Plugin::Instance
end end
end end
js << "})();" # Generate an IIFE for the JS
js = "(function(){#{js}})();" if js.present?
# TODO don't serve blank assets result = []
[[css,"css"],[js,"js"]].map do |asset, extension| result << [css, 'css'] if css.present?
result << [js, 'js'] if js.present?
result.map do |asset, extension|
hash = Digest::SHA1.hexdigest asset hash = Digest::SHA1.hexdigest asset
["#{auto_generated_path}/plugin_#{hash}.#{extension}", asset] ["#{auto_generated_path}/plugin_#{hash}.#{extension}", asset]
end end

View File

@ -176,7 +176,7 @@ class TopicQuery
end end
def list_new_in_category(category) def list_new_in_category(category)
create_list(:new_in_category) {|l| l.where(category_id: category.id).by_newest.first(25)} create_list(:new_in_category, unordered: true) {|l| l.where(category_id: category.id).by_newest.first(25)}
end end
def self.new_filter(list, treat_as_new_topic_start_date) def self.new_filter(list, treat_as_new_topic_start_date)

View File

@ -34,7 +34,7 @@ describe Plugin::Instance do
auth_provider.authenticator.name.should == 'ubuntu' auth_provider.authenticator.name.should == 'ubuntu'
# calls ensure_assets! make sure they are there # calls ensure_assets! make sure they are there
plugin.assets.count.should == 2 plugin.assets.count.should == 1
plugin.assets.each do |a| plugin.assets.each do |a|
File.exists?(a).should be_true File.exists?(a).should be_true
end end

View File

@ -0,0 +1,5 @@
module("Discourse.AdminEmailIndexController");
test("mixes in Discourse.Presence", function() {
ok(Discourse.Presence.detect(Discourse.AdminEmailIndexController.create()));
});

View File

@ -0,0 +1,5 @@
module("Discourse.AdminEmailPreviewDigestController");
test("mixes in Discourse.Presence", function() {
ok(Discourse.Presence.detect(Discourse.AdminEmailPreviewDigestController.create()));
});