Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Kris Aubuchon 2014-02-04 21:49:34 -05:00
commit 3ae7c14b85
35 changed files with 228 additions and 77 deletions

View File

@ -1,6 +1,6 @@
GIT
remote: https://github.com/dysania/onebox.git
revision: a02540f9b1460277e7132fbbd71a7d1dbeb486c2
revision: 3753be3252dbb811f2ce94b56b55b5de54475a6c
specs:
onebox (1.1.0)
hexpress (~> 1.2)

View File

@ -9,8 +9,13 @@
**/
Discourse.AdminSuspendUserController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
submitDisabled: function() {
return (!this.get('reason') || this.get('reason').length < 1);
}.property('reason'),
actions: {
suspend: function() {
if (this.get('submitDisabled')) return;
var duration = parseInt(this.get('duration'), 10);
if (duration > 0) {
var self = this;

View File

@ -10,6 +10,6 @@
</form>
</div>
<div class="modal-footer">
<button class='btn btn-danger' {{action suspend}}><i class='fa fa-ban'></i>{{i18n admin.user.suspend}}</button>
<button class='btn btn-danger' {{action suspend}} {{bind-attr disabled="submitDisabled"}}><i class='fa fa-ban'></i>{{i18n admin.user.suspend}}</button>
<a {{action closeModal}}>{{i18n cancel}}</a>
</div>

View File

@ -831,14 +831,6 @@ html4.ATTRIBS = {
'bdo::dir': 0,
'blockquote::cite': 1,
'br::clear': 0,
'button::accesskey': 0,
'button::disabled': 0,
'button::name': 8,
'button::onblur': 2,
'button::onfocus': 2,
'button::tabindex': 0,
'button::type': 0,
'button::value': 0,
'canvas::height': 0,
'canvas::width': 0,
'caption::align': 0,
@ -987,19 +979,6 @@ html4.ATTRIBS = {
'select::size': 0,
'select::tabindex': 0,
'source::type': 0,
'textarea::accesskey': 0,
'textarea::autocomplete': 0,
'textarea::disabled': 0,
'textarea::inputmode': 0,
'textarea::name': 8,
'textarea::onblur': 2,
'textarea::onchange': 2,
'textarea::onfocus': 2,
'textarea::onselect': 2,
'textarea::placeholder': 0,
'textarea::readonly': 0,
'textarea::tabindex': 0,
'textarea::wrap': 0,
'track::default': 0,
'track::kind': 0,
'track::label': 0,
@ -1048,7 +1027,6 @@ html4.ELEMENTS = {
'blockquote': 0,
'body': 305,
'br': 2,
'button': 0,
'canvas': 0,
'caption': 0,
'cite': 0,
@ -1136,7 +1114,6 @@ html4.ELEMENTS = {
'table': 272,
'tbody': 273,
'td': 273,
'textarea': 8,
'tfoot': 1,
'th': 273,
'thead': 273,
@ -1171,7 +1148,6 @@ html4.ELEMENT_DOM_INTERFACES = {
'blockquote': 'HTMLQuoteElement',
'body': 'HTMLBodyElement',
'br': 'HTMLBRElement',
'button': 'HTMLButtonElement',
'canvas': 'HTMLCanvasElement',
'caption': 'HTMLTableCaptionElement',
'cite': 'HTMLElement',
@ -1259,7 +1235,6 @@ html4.ELEMENT_DOM_INTERFACES = {
'table': 'HTMLTableElement',
'tbody': 'HTMLTableSectionElement',
'td': 'HTMLTableDataCellElement',
'textarea': 'HTMLTextAreaElement',
'tfoot': 'HTMLTableSectionElement',
'th': 'HTMLTableHeaderCellElement',
'thead': 'HTMLTableSectionElement',

View File

@ -41,6 +41,8 @@ Discourse.KeyboardShortcuts = Ember.Object.createWithMixins({
},
FUNCTION_BINDINGS: {
'home': 'goToFirstPost',
'end': 'goToLastPost',
'j': 'selectDown',
'k': 'selectUp',
'u': 'goBack',
@ -56,6 +58,14 @@ Discourse.KeyboardShortcuts = Ember.Object.createWithMixins({
_.each(this.FUNCTION_BINDINGS, this._bindToFunction, this);
},
goToFirstPost: function() {
Discourse.__container__.lookup('controller:topic').send('jumpTop');
},
goToLastPost: function() {
Discourse.__container__.lookup('controller:topic').send('jumpBottom');
},
selectDown: function() {
this._moveSelection(1);
},
@ -77,7 +87,7 @@ Discourse.KeyboardShortcuts = Ember.Object.createWithMixins({
},
showHelpModal: function() {
Discourse.__container__.lookup('controller:application').send("showKeyboardShortcutsHelp");
Discourse.__container__.lookup('controller:application').send('showKeyboardShortcutsHelp');
},
_bindToPath: function(path, binding) {

View File

@ -333,14 +333,14 @@ Discourse.ComposerController = Discourse.Controller.extend({
cancelComposer: function() {
var self = this;
return Ember.Deferred.promise(function (promise) {
return new Ember.RSVP.Promise(function (resolve) {
if (self.get('model.hasMetaData') || self.get('model.replyDirty')) {
bootbox.confirm(I18n.t("post.abandon"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
if (result) {
self.destroyDraft();
self.get('model').clearState();
self.close();
promise.resolve();
resolve();
}
});
} else {
@ -348,7 +348,7 @@ Discourse.ComposerController = Discourse.Controller.extend({
self.destroyDraft();
self.get('model').clearState();
self.close();
promise.resolve();
resolve();
}
});
},

View File

@ -11,8 +11,8 @@ Discourse.SearchController = Em.ArrayController.extend(Discourse.Presence, {
// If we need to perform another search
newSearchNeeded: function() {
this.set('noResults', false);
var term = this.get('term');
if (term && term.length >= Discourse.SiteSettings.min_search_term_length) {
var term = (this.get('term') || '').trim();
if (term.length >= Discourse.SiteSettings.min_search_term_length) {
this.set('loading', true);
this.searchTerm(term, this.get('typeFilter'));
} else {
@ -57,6 +57,8 @@ Discourse.SearchController = Em.ArrayController.extend(Discourse.Presence, {
self.set('urls', urls);
}
self.set('loading', false);
}).catch(function() {
self.set('loading', false);
});
}, 300),

View File

@ -209,9 +209,14 @@ Discourse.Category.reopenClass({
},
findByIds: function(ids){
return ids.map(function(id){
return Discourse.Category.findById(id);
var categories = [];
_.each(ids, function(id){
var found = Discourse.Category.findById(id);
if(found){
categories.push(found);
}
});
return categories;
},
findBySlug: function(slug, parentSlug) {

View File

@ -31,7 +31,6 @@ Discourse.DiscoveryRoute = Discourse.Route.extend({
this.controllerFor('composer').open({
categoryId: topicsController.get('category.id'),
action: Discourse.Composer.CREATE_TOPIC,
draft: topicsController.get('draft'),
draftKey: topicsController.get('draft_key'),
draftSequence: topicsController.get('draft_sequence')
});

View File

@ -28,6 +28,17 @@ function buildTopicRoute(filter) {
Discourse.set('title', I18n.t('filters.with_topics', {filter: filterText}));
this.controllerFor('discoveryTopics').setProperties({ model: model, category: null, period: period });
// If there's a draft, open the create topic composer
if (model.draft) {
this.controllerFor('composer').open({
action: Discourse.Composer.CREATE_TOPIC,
draft: model.draft,
draftKey: model.draft_key,
draftSequence: model.draft_sequence
});
}
this.controllerFor('navigationDefault').set('canCreateTopic', model.get('can_create_topic'));
},

View File

@ -9,11 +9,13 @@
<table id='topic-list'>
<thead>
<tr>
{{#if currentUser}}
<th>
{{#if canBulkSelect}}
<button class='btn bulk-select' {{action toggleBulkSelect}} title="{{i18n topics.bulk.toggle}}"><i class='fa fa-list'></i></button>
{{/if}}
</th>
{{/if}}
{{#sortable-heading sortBy="default" sortOrder=sortOrder}}
{{i18n topic.title}}
{{/sortable-heading}}

View File

@ -216,6 +216,8 @@ class PostsController < ApplicationController
raise Discourse::InvalidParameters.new(:revision) if revision < 2
post_revision = PostRevision.where(post_id: post_id, number: revision).first
post_revision.post = find_post_from_params
guardian.ensure_can_see!(post_revision)
post_revision
end

View File

@ -41,6 +41,7 @@ module Jobs
return if seen_recently && !user.suspended?
# Load the post if present
email_args[:post] ||= Post.where(id: notification.data_hash[:original_post_id].to_i).first
email_args[:post] ||= notification.post
email_args[:notification] = notification

View File

@ -127,7 +127,7 @@ class UserNotifications < ActionMailer::Base
return unless @notification = opts[:notification]
return unless @post = opts[:post]
username = @notification.data_hash[:display_username]
username = @notification.data_hash[:original_username]
notification_type = opts[:notification_type] || Notification.types[@notification.notification_type].to_s
context = ""

View File

@ -140,6 +140,7 @@ class PostAlertObserver < ActiveRecord::Observer
end
original_post = post
original_username = opts[:display_username] || post.username
if collapsed
post = first_unread_post(user,post.topic) || post
@ -155,6 +156,8 @@ class PostAlertObserver < ActiveRecord::Observer
post_number: post.post_number,
post_action_id: opts[:post_action_id],
data: { topic_title: post.topic.title,
original_post_id: original_post.id,
original_username: original_username,
display_username: opts[:display_username] || post.user.username }.to_json)
end

View File

@ -33,7 +33,7 @@ UNICORN_PID=$!
echo "supervisor pid: $UNICORN_SUPERVISOR_PID unicorn pid: $UNICORN_PID"
while [ -e /proc/$UNICORN_PID ]
while kill -0 $UNICORN_PID
do
sleep 0.1
sleep 1
done

View File

@ -3,8 +3,12 @@ Topic.reset_column_information
Post.reset_column_information
if Topic.where('id NOT IN (SELECT topic_id from categories where topic_id is not null)').count == 0 && !Rails.env.test?
# seed welcome topic
puts "Seeding welcome topic"
puts "Seeding welcome topics"
welcome = File.read(Rails.root + 'docs/ADMIN-QUICK-START-GUIDE.md')
PostCreator.create(Discourse.system_user, raw: welcome, title: "Discourse Admin Quick Start Guide" ,skip_validations: true)
welcome = File.read(Rails.root + 'docs/WELCOME-TO-DISCOURSE.md')
post = PostCreator.create(Discourse.system_user, category: 'Meta', raw: welcome, title: "Welcome to Discourse", skip_validations: true)
post.topic.update_pinned(true)
end

View File

@ -0,0 +1 @@
This is a placeholder for the welcome topic, to be filled by @codinghorror

View File

@ -8,7 +8,7 @@ class Guardian
include CategoryGuardian
include PostGuardain
include TopicGuardian
class AnonymousUser
def blank?; true; end
def admin?; false; end

View File

@ -104,7 +104,9 @@ module PostGuardain
end
def can_see_post_revision?(post_revision)
post_revision.present? && (is_staff? || can_see_post?(post_revision.post))
return false if post_revision.nil?
return true if SiteSetting.edit_history_visible_to_public
authenticated? && (is_staff? || can_see_post?(post_revision.post))
end
def can_vote?(post, opts={})

View File

@ -236,12 +236,12 @@ module PrettyText
def self.make_all_links_absolute(html)
site_uri = nil
doc = Nokogiri::HTML.fragment(html)
doc.css("a").each do |l|
href = l["href"].to_s
doc.css("a").each do |link|
href = link["href"].to_s
begin
uri = URI(href)
site_uri ||= URI(Discourse.base_url)
l["href"] = "#{site_uri}#{l['href']}" unless uri.host.present?
link["href"] = "#{site_uri}#{link['href']}" unless uri.host.present?
rescue URI::InvalidURIError
# leave it
end

View File

@ -19,7 +19,7 @@ class SuggestedTopicsBuilder
# Only add results if we don't have those topic ids already
results = results.where('topics.id NOT IN (?)', @excluded_topic_ids)
.where(closed: false, archived: false, visible: true)
.where(visible: true)
.to_a
.reject { |topic| @category_topic_ids.include?(topic.id) }

View File

@ -121,8 +121,7 @@ class TopicQuery
end
def list_category(category)
create_list(:category, unordered: true) do |list|
list = list.where(category_id: category.id)
create_list(:category, unordered: true, category: category.id) do |list|
if @user
list.order(TopicQuerySQL.order_with_pinned_sql)
else
@ -132,10 +131,8 @@ class TopicQuery
end
def list_new_in_category(category)
create_list(:new_in_category, unordered: true) do |list|
list.where(category_id: category.id)
.by_newest
.first(25)
create_list(:new_in_category, unordered: true, category: category.id) do |list|
list.by_newest.first(25)
end
end
@ -242,6 +239,11 @@ class TopicQuery
result = result.listable_topics.includes(category: :topic_only_relative_url)
result = result.where('categories.name is null or categories.name <> ?', options[:exclude_category]).references(:categories) if options[:exclude_category]
# Don't include the category topic unless restricted to that category
if options[:category].blank?
result = result.where('COALESCE(categories.topic_id, 0) <> topics.id')
end
result = result.limit(options[:per_page]) unless options[:limit] == false
result = result.visible if options[:visible] || @user.nil? || @user.regular?
result = result.where.not(topics: {id: options[:except_topic_ids]}).references(:topics) if options[:except_topic_ids]
@ -309,7 +311,7 @@ class TopicQuery
end
def random_suggested(topic, count, excluded_topic_ids=[])
result = default_results(unordered: true, per_page: count)
result = default_results(unordered: true, per_page: count).where(closed: false, archived: false)
excluded_topic_ids += Category.pluck(:topic_id).compact
result = result.where("topics.id NOT IN (?)", excluded_topic_ids) unless excluded_topic_ids.empty?

View File

@ -83,14 +83,14 @@ describe SuggestedTopicsBuilder do
end
context "adding invalid status topics" do
context "adding topics that are not open" do
let!(:archived_topic) { Fabricate(:topic, archived: true)}
let!(:closed_topic) { Fabricate(:topic, closed: true)}
let!(:invisible_topic) { Fabricate(:topic, visible: false)}
it "doesn't add archived, closed or invisible topics" do
it "adds archived and closed, but not invisible topics" do
builder.add_results(Topic)
builder.size.should == 0
builder.size.should == 2
builder.should_not be_full
end
end

View File

@ -28,12 +28,12 @@ describe TopicQuery do
Topic.recent(10).count.should == 0
# mods can see every group and hidden topics
TopicQuery.new(moderator).list_latest.topics.count.should == 3
TopicQuery.new(moderator).list_latest.topics.count.should == 2
group.add(user)
group.save
TopicQuery.new(user).list_latest.topics.count.should == 2
TopicQuery.new(user).list_latest.topics.count.should == 1
end
@ -366,7 +366,7 @@ describe TopicQuery do
end
end
context "anonymously browswing with invisible, closed and archived" do
context "anonymously browsing with invisible, closed and archived" do
let!(:topic) { Fabricate(:topic) }
let!(:regular_topic) { Fabricate(:post, user: creator).topic }
let!(:closed_topic) { Fabricate(:topic, user: creator, closed: true) }
@ -394,12 +394,20 @@ describe TopicQuery do
let!(:closed_topic) { Fabricate(:topic, user: creator, closed: true) }
let!(:archived_topic) { Fabricate(:topic, user: creator, archived: true) }
let!(:invisible_topic) { Fabricate(:topic, user: creator, visible: false) }
let!(:fully_read_closed) { Fabricate(:post, user: creator).topic }
let!(:fully_read_archived) { Fabricate(:post, user: creator).topic }
before do
user.auto_track_topics_after_msecs = 0
user.save
TopicUser.update_last_read(user, partially_read.id, 0, 0)
TopicUser.update_last_read(user, fully_read.id, 1, 0)
TopicUser.update_last_read(user, fully_read_closed.id, 1, 0)
TopicUser.update_last_read(user, fully_read_archived.id, 1, 0)
fully_read_closed.closed = true
fully_read_closed.save
fully_read_archived.archived = true
fully_read_archived.save
end
it "won't return new or fully read if there are enough partially read topics" do
@ -407,14 +415,22 @@ describe TopicQuery do
suggested_topics.should == [partially_read.id]
end
it "won't fully read if there are enough partially read topics and new topics" do
SiteSetting.stubs(:suggested_topics).returns(2)
suggested_topics.should == [partially_read.id, new_topic.id]
it "won't return fully read if there are enough partially read topics and new topics" do
SiteSetting.stubs(:suggested_topics).returns(4)
suggested_topics[0].should == partially_read.id
suggested_topics[1,3].should include(new_topic.id)
suggested_topics[1,3].should include(closed_topic.id)
suggested_topics[1,3].should include(archived_topic.id)
end
it "returns unread, then new, then random" do
SiteSetting.stubs(:suggested_topics).returns(3)
suggested_topics.should == [partially_read.id, new_topic.id, fully_read.id]
SiteSetting.stubs(:suggested_topics).returns(7)
suggested_topics[0].should == partially_read.id
suggested_topics[1,3].should include(new_topic.id)
suggested_topics[1,3].should include(closed_topic.id)
suggested_topics[1,3].should include(archived_topic.id)
suggested_topics[4].should == fully_read.id
# random doesn't include closed and archived
end
end

View File

@ -2,7 +2,6 @@ require 'spec_helper'
describe PostsController do
describe 'short_link' do
it 'logs the incoming link once' do
IncomingLink.expects(:add).once.returns(true)
@ -386,4 +385,64 @@ describe PostsController do
end
end
describe "revisions" do
let(:post_revision) { Fabricate(:post_revision) }
it "throws an exception when revision is < 2" do
expect {
xhr :get, :revisions, post_id: post_revision.post_id, revision: 1
}.to raise_error(Discourse::InvalidParameters)
end
context "when edit history is not visible to the public" do
before { SiteSetting.stubs(:edit_history_visible_to_public).returns(false) }
it "ensures anonymous can not see the revisions" do
xhr :get, :revisions, post_id: post_revision.post_id, revision: post_revision.number
response.should be_forbidden
end
it "ensures staff can see the revisions" do
log_in(:admin)
xhr :get, :revisions, post_id: post_revision.post_id, revision: post_revision.number
response.should be_success
end
it "ensures poster can see the revisions" do
user = log_in(:active_user)
pr = Fabricate(:post_revision, user: user)
xhr :get, :revisions, post_id: pr.post_id, revision: pr.number
response.should be_success
end
end
context "when edit history is visible to everyone" do
before { SiteSetting.stubs(:edit_history_visible_to_public).returns(true) }
it "ensures anyone can see the revisions" do
xhr :get, :revisions, post_id: post_revision.post_id, revision: post_revision.number
response.should be_success
end
end
context "deleted post" do
let(:admin) { log_in(:admin) }
let(:deleted_post) { Fabricate(:post, user: admin) }
let(:deleted_post_revision) { Fabricate(:post_revision, user: admin, post: deleted_post) }
before { deleted_post.trash!(admin) }
it "also work on deleted post" do
xhr :get, :revisions, post_id: deleted_post_revision.post_id, revision: deleted_post_revision.number
response.should be_success
end
end
end
end

View File

@ -0,0 +1,8 @@
Fabricator(:post_revision) do
post
user
number 3
modifications do
{ "cooked" => ["<p>BEFORE</p>", "<p>AFTER</p>"], "raw" => ["BEFORE", "AFTER"] }
end
end

View File

@ -101,7 +101,16 @@ describe Jobs::UserEmail do
context 'notification' do
let(:post) { Fabricate(:post, user: user) }
let!(:notification) { Fabricate(:notification, user: user, topic: post.topic, post_number: post.post_number)}
let!(:notification) {
Fabricate(:notification,
user: user,
topic: post.topic,
post_number: post.post_number,
data: {
original_post_id: post.id
}.to_json
)
}
it 'passes a notification as an argument when a notification_id is present' do
Email::Sender.any_instance.expects(:send)
@ -131,11 +140,17 @@ describe Jobs::UserEmail do
before do
@pm_from_staff = Fabricate(:post, user: Fabricate(:moderator))
@pm_from_staff.topic.topic_allowed_users.create!(user_id: suspended.id)
@pm_notification = Fabricate(:notification, user: suspended, topic: @pm_from_staff.topic, post_number: @pm_from_staff.post_number)
@pm_notification = Fabricate(:notification,
user: suspended,
topic: @pm_from_staff.topic,
post_number: @pm_from_staff.post_number,
data: { original_post_id: @pm_from_staff.id }.to_json
)
UserNotifications.expects(:user_private_message).with(suspended, notification: @pm_notification, post: @pm_from_staff).returns(mailer)
end
subject(:execute_user_email_job) { Jobs::UserEmail.new.execute(type: :user_private_message, user_id: suspended.id, notification_id: @pm_notification.id) }
subject(:execute_user_email_job) {
Jobs::UserEmail.new.execute(type: :user_private_message, user_id: suspended.id, notification_id: @pm_notification.id) }
it "sends an email" do
execute_user_email_job

View File

@ -123,7 +123,7 @@ describe UserNotifications do
topic: post.topic,
notification_type: Notification.types[notification_type],
post_number: post.post_number,
data: {display_username: username}.to_json )
data: {original_username: username}.to_json )
end
describe '.user_mentioned' do

View File

@ -173,14 +173,14 @@ describe Notification do
user_id: user.id,
topic_id: 2,
post_number: 1,
data: '[]',
data: '{}',
notification_type: Notification.types[:private_message])
other = Notification.create!(read: false,
user_id: user.id,
topic_id: 2,
post_number: 1,
data: '[]',
data: '{}',
notification_type: Notification.types[:mentioned])
@ -197,9 +197,9 @@ describe Notification do
user = Fabricate(:user)
(1..3).map do |i|
Notification.create!(read: false, user_id: user.id, topic_id: 2, post_number: i, data: '[]', notification_type: 1)
Notification.create!(read: false, user_id: user.id, topic_id: 2, post_number: i, data: '{}', notification_type: 1)
end
Notification.create!(read: true, user_id: user.id, topic_id: 2, post_number: 4, data: '[]', notification_type: 1)
Notification.create!(read: true, user_id: user.id, topic_id: 2, post_number: 4, data: '{}', notification_type: 1)
Notification.mark_posts_read(user,2,[1,2,3,4]).should == 3
end

View File

@ -0,0 +1,9 @@
require 'spec_helper'
require_dependency 'post_revision'
describe PostRevision do
it { should belong_to :user }
it { should belong_to :post }
end

View File

@ -0,0 +1,9 @@
require 'spec_helper'
require_dependency 'topic_revision'
describe TopicRevision do
it { should belong_to :user }
it { should belong_to :topic }
end

View File

@ -349,6 +349,8 @@ test("sanitize", function() {
cooked("<iframe src=\"https://www.google.com/maps/embed?pb=!1m10!1m8!1m3!1d2624.9983685732213!2d2.29432085!3d48.85824149999999!3m2!1i1024!2i768!4f13.1!5e0!3m2!1sen!2s!4v1385737436368\" width=\"100\" height=\"42\"></iframe>",
"<iframe src=\"https://www.google.com/maps/embed?pb=!1m10!1m8!1m3!1d2624.9983685732213!2d2.29432085!3d48.85824149999999!3m2!1i1024!2i768!4f13.1!5e0!3m2!1sen!2s!4v1385737436368\" width=\"100\" height=\"42\"></iframe>",
"it allows iframe to google maps");
equal(sanitize("<textarea>hullo</textarea>"), "hullo");
equal(sanitize("<button>press me!</button>"), "press me!");
});
test("URLs in BBCode tags", function() {

View File

@ -39,6 +39,15 @@ test('findBySlug', function() {
blank(Discourse.Category.findBySlug('luke', 'leia'), 'luke is blank with an incorrect parent');
});
test('findByIds', function(){
var categories = [
Discourse.Category.create({id: 1}),
Discourse.Category.create({id: 2})];
this.stub(Discourse.Category, 'list').returns(categories);
deepEqual(Discourse.Category.findByIds([1,2,3]), categories);
});
test('postCountStats', function() {
var category1 = Discourse.Category.create({id: 1, slug: 'unloved', posts_year: 2, posts_month: 0, posts_week: 0, posts_day: 0}),
category2 = Discourse.Category.create({id: 2, slug: 'hasbeen', posts_year: 50, posts_month: 4, posts_week: 0, posts_day: 0}),

View File

@ -19,12 +19,12 @@ var $buo = function() {
// sam: my main concern here is mobile, but its an outlier, for now we support ie9, set conditionally and stuff with pushState
if (window.ie === "new" || (window.history && window.history.pushState && !badAndroid)) {
return;
return;
}
// we don't ask Googlebot to update their browser
if (ua.indexOf('Googlebot') >= 0) {
return;
if (ua.indexOf('Googlebot') >= 0 || ua.indexOf('Mediapartners') >= 0 || ua.indexOf('AdsBot') >= 0) {
return;
}
// retrieve localized browser upgrade text