Show estimated reading time near summarize button.

This commit is contained in:
Robin Ward 2013-12-10 13:47:07 -05:00
parent 561961eff6
commit 6853f37bee
10 changed files with 78 additions and 3 deletions

View file

@ -160,6 +160,15 @@ Discourse.Topic = Discourse.Model.extend({
return I18n.t(this.get('favoriteTooltipKey'));
}.property('favoriteTooltipKey'),
estimatedReadingTime: function() {
var wordCount = this.get('word_count');
if (!wordCount) return;
// Avg for 250 words per minute.
var minutes = Math.floor(wordCount / 250.0);
return minutes;
}.property('word_count'),
toggleStar: function() {
var topic = this;
topic.toggleProperty('starred');

View file

@ -2,6 +2,11 @@
<p>{{{i18n summary.enabled_description}}}</p>
<button class='btn' {{action toggleSummary}}>{{i18n summary.disable}}</button>
{{else}}
<p>{{{i18n summary.description count="topic.posts_count"}}}</p>
{{#if topic.estimatedReadingTime}}
<p>{{{i18n summary.description_time count="topic.posts_count" readingTime="topic.estimatedReadingTime"}}}</p>
{{else}}
<p>{{{i18n summary.description count="topic.posts_count"}}}</p>
{{/if}}
<button class='btn' {{action toggleSummary}}>{{i18n summary.enable}}</button>
{{/if}}

View file

@ -22,6 +22,7 @@ class TopicViewSerializer < ApplicationSerializer
:archetype,
:slug,
:category_id,
:word_count,
:deleted_at]
end

View file

@ -384,6 +384,7 @@ en:
summary:
enabled_description: "You're viewing a summary of this topic. To see all posts again, click below."
description: "There are <b>{{count}}</b> replies. Save reading time by displaying only the most relevant replies?"
description_time: "There are <b>{{count}}</b> replies with an estimated read time of <b>{{readingTime}} minutes</b>. Save reading time by displaying only the most relevant replies?"
enable: 'Summarize This Topic'
disable: 'Show All Posts'

View file

@ -0,0 +1,11 @@
class AddWordCountToPosts < ActiveRecord::Migration
def up
add_column :posts, :word_count, :integer
add_column :topics, :word_count, :integer
end
def down
remove_column :posts, :word_count, :integer
remove_column :topics, :word_count, :integer
end
end

View file

@ -0,0 +1,20 @@
class MigrateWordCounts < ActiveRecord::Migration
def up
disable_ddl_transaction
post_ids = execute("SELECT id FROM posts WHERE word_count IS NULL LIMIT 500").map {|r| r['id'].to_i }
while post_ids.length > 0
execute "UPDATE posts SET word_count = array_length(regexp_split_to_array(raw, ' '),1) WHERE id IN (#{post_ids.join(',')})"
post_ids = execute("SELECT id FROM posts WHERE word_count IS NULL LIMIT 500").map {|r| r['id'].to_i }
end
topic_ids = execute("SELECT id FROM topics WHERE word_count IS NULL LIMIT 500").map {|r| r['id'].to_i }
while topic_ids.length > 0
execute "UPDATE topics SET word_count = (SELECT SUM(COALESCE(posts.word_count, 0)) FROM posts WHERE posts.topic_id = topics.id) WHERE topics.id IN (#{topic_ids.join(',')})"
topic_ids = execute("SELECT id FROM topics WHERE word_count IS NULL LIMIT 500").map {|r| r['id'].to_i }
end
end
end

View file

@ -96,6 +96,7 @@ class PostCreator
post.reply_to_user_id ||= Post.select(:user_id).where(topic_id: post.topic_id, post_number: post.reply_to_post_number).first.try(:user_id)
end
post.word_count = post.raw.scan(/\w+/).size
post.post_number ||= Topic.next_post_number(post.topic_id, post.reply_to_post_number.present?)
cooking_options = post.cooking_options || {}
@ -198,6 +199,7 @@ class PostCreator
# Update attributes on the topic - featured users and last posted.
attrs = {last_posted_at: @post.created_at, last_post_user_id: @post.user_id}
attrs[:bumped_at] = @post.created_at unless @post.no_bump
attrs[:word_count] = (@topic.word_count || 0) + @post.word_count
@topic.update_attributes(attrs)
end

View file

@ -16,6 +16,7 @@ class PostRevisor
revise_post
update_category_description
post_process_post
update_topic_word_counts
@post.advance_draft_sequence
true
end
@ -66,8 +67,15 @@ class PostRevisor
end
end
def update_topic_word_counts
Topic.exec_sql("UPDATE topics SET word_count = (SELECT SUM(COALESCE(posts.word_count, 0))
FROM posts WHERE posts.topic_id = :topic_id)
WHERE topics.id = :topic_id", topic_id: @post.topic_id)
end
def update_post
@post.raw = @new_raw
@post.word_count = @new_raw.scan(/\w+/).size
@post.updated_by = @user
@post.last_editor_id = @user.id
@post.edit_reason = @opts[:edit_reason] if @opts[:edit_reason]

View file

@ -394,5 +394,17 @@ describe PostCreator do
creator.errors.should be_nil
end
end
describe "word_count" do
it "has a word count" do
creator = PostCreator.new(user, title: 'some inspired poetry for a rainy day', raw: 'mary had a little lamb, little lamb, little lamb. mary had a little lamb')
post = creator.create
post.word_count.should == 14
post.topic.reload
post.topic.word_count.should == 14
end
end
end

View file

@ -222,14 +222,14 @@ describe PostRevisor do
describe 'with a new body' do
let(:changed_by) { Fabricate(:coding_horror) }
let!(:result) { subject.revise!(changed_by, 'updated body') }
let!(:result) { subject.revise!(changed_by, "lets update the body") }
it 'returns true' do
result.should be_true
end
it 'updates the body' do
post.raw.should == 'updated body'
post.raw.should == "lets update the body"
end
it 'sets the invalidate oneboxes attribute' do
@ -252,6 +252,12 @@ describe PostRevisor do
post.versions.first.user.should be_present
end
it "updates the word count" do
post.word_count.should == 4
post.topic.reload
post.topic.word_count.should == 4
end
context 'second poster posts again quickly' do
before do
SiteSetting.expects(:ninja_edit_window).returns(1.minute.to_i)