Merge branch 'next-minor' into develop
This commit is contained in:
commit
b319e0caa2
13 changed files with 86 additions and 65 deletions
|
|
@ -9,10 +9,14 @@
|
||||||
# 0.6.2.0
|
# 0.6.2.0
|
||||||
|
|
||||||
## Refactor
|
## Refactor
|
||||||
|
* Use string-direction gem for rtl detection [#7181](https://github.com/diaspora/diaspora/pull/7181)
|
||||||
|
* Reduce i18n.load side effects [#7184](https://github.com/diaspora/diaspora/pull/7184)
|
||||||
|
* Force jasmine fails on syntax errors [#7185](https://github.com/diaspora/diaspora/pull/7185)
|
||||||
|
|
||||||
## Bug fixes
|
## Bug fixes
|
||||||
* Fix fetching comments after fetching likes [#7167](https://github.com/diaspora/diaspora/pull/7167)
|
* Fix fetching comments after fetching likes [#7167](https://github.com/diaspora/diaspora/pull/7167)
|
||||||
* Hide 'reshare' button on already reshared posts [#7169](https://github.com/diaspora/diaspora/pull/7169)
|
* Hide 'reshare' button on already reshared posts [#7169](https://github.com/diaspora/diaspora/pull/7169)
|
||||||
|
* Only reload profile header when changing aspect memberships [#7183](https://github.com/diaspora/diaspora/pull/7183)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Show spinner when loading comments in the stream [#7170](https://github.com/diaspora/diaspora/pull/7170)
|
* Show spinner when loading comments in the stream [#7170](https://github.com/diaspora/diaspora/pull/7170)
|
||||||
|
|
|
||||||
4
Gemfile
4
Gemfile
|
|
@ -135,6 +135,10 @@ gem "twitter-text", "1.14.0"
|
||||||
gem "ruby-oembed", "0.10.1"
|
gem "ruby-oembed", "0.10.1"
|
||||||
gem "open_graph_reader", "0.6.1"
|
gem "open_graph_reader", "0.6.1"
|
||||||
|
|
||||||
|
# RTL support
|
||||||
|
|
||||||
|
gem "string-direction", "1.2.0"
|
||||||
|
|
||||||
# Security Headers
|
# Security Headers
|
||||||
|
|
||||||
gem "secure_headers", "3.5.0"
|
gem "secure_headers", "3.5.0"
|
||||||
|
|
|
||||||
|
|
@ -819,6 +819,8 @@ GEM
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
sprockets (>= 2.8, < 4.0)
|
sprockets (>= 2.8, < 4.0)
|
||||||
state_machine (1.2.0)
|
state_machine (1.2.0)
|
||||||
|
string-direction (1.2.0)
|
||||||
|
yard (~> 0.8)
|
||||||
swd (1.0.1)
|
swd (1.0.1)
|
||||||
activesupport (>= 3)
|
activesupport (>= 3)
|
||||||
attr_required (>= 0.0.5)
|
attr_required (>= 0.0.5)
|
||||||
|
|
@ -1031,6 +1033,7 @@ DEPENDENCIES
|
||||||
spring (= 2.0.0)
|
spring (= 2.0.0)
|
||||||
spring-commands-cucumber (= 1.0.1)
|
spring-commands-cucumber (= 1.0.1)
|
||||||
spring-commands-rspec (= 1.0.4)
|
spring-commands-rspec (= 1.0.4)
|
||||||
|
string-direction (= 1.2.0)
|
||||||
test_after_commit (= 1.1.0)
|
test_after_commit (= 1.1.0)
|
||||||
timecop (= 0.8.1)
|
timecop (= 0.8.1)
|
||||||
turbo_dev_assets (= 0.0.2)
|
turbo_dev_assets (= 0.0.2)
|
||||||
|
|
@ -1046,4 +1049,4 @@ DEPENDENCIES
|
||||||
will_paginate (= 3.1.5)
|
will_paginate (= 3.1.5)
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.13.5
|
1.13.6
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ app.pages.Profile = app.views.Base.extend({
|
||||||
this.streamCollection = _.has(opts, "streamCollection") ? opts.streamCollection : null;
|
this.streamCollection = _.has(opts, "streamCollection") ? opts.streamCollection : null;
|
||||||
this.streamViewClass = _.has(opts, "streamView") ? opts.streamView : null;
|
this.streamViewClass = _.has(opts, "streamView") ? opts.streamView : null;
|
||||||
|
|
||||||
this.model.on("change", this.render, this);
|
|
||||||
this.model.on("sync", this._done, this);
|
this.model.on("sync", this._done, this);
|
||||||
|
|
||||||
// bind to global events
|
// bind to global events
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ app.views.ProfileHeader = app.views.Base.extend({
|
||||||
initialize: function(opts) {
|
initialize: function(opts) {
|
||||||
this.photos = _.has(opts, 'photos') ? opts.photos : null;
|
this.photos = _.has(opts, 'photos') ? opts.photos : null;
|
||||||
this.contacts = _.has(opts, 'contacts') ? opts.contacts : null;
|
this.contacts = _.has(opts, 'contacts') ? opts.contacts : null;
|
||||||
|
this.model.on("change", this.render, this);
|
||||||
$("#mentionModal").on("modal:loaded", this.mentionModalLoaded.bind(this));
|
$("#mentionModal").on("modal:loaded", this.mentionModalLoaded.bind(this));
|
||||||
$("#mentionModal").on("hidden.bs.modal", this.mentionModalHidden);
|
$("#mentionModal").on("hidden.bs.modal", this.mentionModalHidden);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Diaspora.I18n = {
|
||||||
},
|
},
|
||||||
|
|
||||||
updateLocale: function(locale, data) {
|
updateLocale: function(locale, data) {
|
||||||
locale.data = $.extend(locale.data, data);
|
locale.data = $.extend({}, locale.data, data);
|
||||||
|
|
||||||
var rule = locale.data.pluralization_rule;
|
var rule = locale.data.pluralization_rule;
|
||||||
if (typeof rule !== "undefined") {
|
if (typeof rule !== "undefined") {
|
||||||
|
|
|
||||||
|
|
@ -2,36 +2,16 @@
|
||||||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||||
# licensed under the Affero General Public License version 3 or later. See
|
# licensed under the Affero General Public License version 3 or later. See
|
||||||
# the COPYRIGHT file.
|
# the COPYRIGHT file.
|
||||||
# Deeply inspired by https://gitorious.org/statusnet/mainline/blobs/master/plugins/DirectionDetector/DirectionDetectorPlugin.php
|
|
||||||
|
|
||||||
class String
|
class String
|
||||||
RTL_RANGES = [
|
|
||||||
[1536, 1791], # arabic, persian, urdu, kurdish, ...
|
|
||||||
[65136, 65279], # arabic peresent 2
|
|
||||||
[64336, 65023], # arabic peresent 1
|
|
||||||
[1424, 1535], # hebrew
|
|
||||||
[64256, 64335], # hebrew peresent
|
|
||||||
[1792, 1871], # syriac
|
|
||||||
[1920, 1983], # thaana
|
|
||||||
[1984, 2047], # nko
|
|
||||||
[11568, 11647] # tifinagh
|
|
||||||
]
|
|
||||||
RTL_CLEANER_REGEXES = [ /@[^ ]+|#[^ ]+/u, # mention, tag
|
RTL_CLEANER_REGEXES = [ /@[^ ]+|#[^ ]+/u, # mention, tag
|
||||||
/^RT[: ]{1}| RT | RT: |[♺♻:]/u # retweet
|
/^RT[: ]{1}| RT | RT: |[♺♻:]/u # retweet
|
||||||
]
|
]
|
||||||
|
|
||||||
def is_rtl?
|
def is_rtl?
|
||||||
return false if self.strip.empty?
|
return false if self.strip.empty?
|
||||||
count = 0
|
detector = StringDirection::Detector.new(:dominant)
|
||||||
self.split(" ").each do |word|
|
detector.rtl? self
|
||||||
if starts_with_rtl_char?(word)
|
|
||||||
count += 1
|
|
||||||
else
|
|
||||||
count -= 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true if count > 0 # more than half of the words are rtl words
|
|
||||||
return starts_with_rtl_char?(self) # otherwise let the first word decide
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Diaspora specific
|
# Diaspora specific
|
||||||
|
|
@ -42,14 +22,4 @@ class String
|
||||||
end
|
end
|
||||||
string.is_rtl?
|
string.is_rtl?
|
||||||
end
|
end
|
||||||
|
|
||||||
def starts_with_rtl_char?(string = self)
|
|
||||||
stripped = string.strip
|
|
||||||
return false if stripped.empty?
|
|
||||||
char = stripped.unpack('U*').first
|
|
||||||
RTL_RANGES.each do |limit|
|
|
||||||
return true if char >= limit[0] && char <= limit[1]
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,17 @@ describe("app.views.Help", function(){
|
||||||
beforeEach(function(){
|
beforeEach(function(){
|
||||||
gon.appConfig = {chat: {enabled: false}};
|
gon.appConfig = {chat: {enabled: false}};
|
||||||
this.locale = JSON.parse(spec.readFixture("locale_en_help_json"));
|
this.locale = JSON.parse(spec.readFixture("locale_en_help_json"));
|
||||||
|
Diaspora.I18n.reset();
|
||||||
Diaspora.I18n.load(this.locale, "en");
|
Diaspora.I18n.load(this.locale, "en");
|
||||||
this.view = new app.views.Help();
|
this.view = new app.views.Help();
|
||||||
Diaspora.Page = "HelpFaq";
|
Diaspora.Page = "HelpFaq";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
Diaspora.I18n.reset();
|
||||||
|
Diaspora.I18n.load(spec.defaultLocale);
|
||||||
|
});
|
||||||
|
|
||||||
describe("render", function(){
|
describe("render", function(){
|
||||||
beforeEach(function(){
|
beforeEach(function(){
|
||||||
this.view.render();
|
this.view.render();
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,34 @@ describe("app.views.ProfileHeader", function() {
|
||||||
loginAs(factory.userAttrs());
|
loginAs(factory.userAttrs());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("initialize", function() {
|
||||||
|
it("calls #render when the model changes", function() {
|
||||||
|
spyOn(app.views.ProfileHeader.prototype, "render");
|
||||||
|
this.view.initialize();
|
||||||
|
expect(app.views.ProfileHeader.prototype.render).not.toHaveBeenCalled();
|
||||||
|
this.view.model.trigger("change");
|
||||||
|
expect(app.views.ProfileHeader.prototype.render).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls #mentionModalLoaded on modal:loaded", function() {
|
||||||
|
spec.content().append("<div id='mentionModal'></div>");
|
||||||
|
spyOn(app.views.ProfileHeader.prototype, "mentionModalLoaded");
|
||||||
|
this.view.initialize();
|
||||||
|
expect(app.views.ProfileHeader.prototype.mentionModalLoaded).not.toHaveBeenCalled();
|
||||||
|
$("#mentionModal").trigger("modal:loaded");
|
||||||
|
expect(app.views.ProfileHeader.prototype.mentionModalLoaded).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls #mentionModalHidden on hidden.bs.modal", function() {
|
||||||
|
spec.content().append("<div id='mentionModal'></div>");
|
||||||
|
spyOn(app.views.ProfileHeader.prototype, "mentionModalHidden");
|
||||||
|
this.view.initialize();
|
||||||
|
expect(app.views.ProfileHeader.prototype.mentionModalHidden).not.toHaveBeenCalled();
|
||||||
|
$("#mentionModal").trigger("hidden.bs.modal");
|
||||||
|
expect(app.views.ProfileHeader.prototype.mentionModalHidden).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
context("#presenter", function() {
|
context("#presenter", function() {
|
||||||
it("contains necessary elements", function() {
|
it("contains necessary elements", function() {
|
||||||
expect(this.view.presenter()).toEqual(jasmine.objectContaining({
|
expect(this.view.presenter()).toEqual(jasmine.objectContaining({
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,28 @@ describe("Diaspora.I18n", function() {
|
||||||
|
|
||||||
expect(Diaspora.I18n.locale.data).toEqual(extended);
|
expect(Diaspora.I18n.locale.data).toEqual(extended);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("overrides existing translations", function() {
|
||||||
|
var oldLocale = {name: "Bob"};
|
||||||
|
var newLocale = {name: "Alice"};
|
||||||
|
Diaspora.I18n.load(oldLocale, "en");
|
||||||
|
expect(Diaspora.I18n.locale.data.name).toBe("Bob");
|
||||||
|
Diaspora.I18n.load(newLocale, "en");
|
||||||
|
expect(Diaspora.I18n.locale.data.name).toBe("Alice");
|
||||||
|
|
||||||
|
Diaspora.I18n.reset(oldLocale);
|
||||||
|
expect(Diaspora.I18n.locale.data.name).toBe("Bob");
|
||||||
|
Diaspora.I18n.load(newLocale, "en");
|
||||||
|
expect(Diaspora.I18n.locale.data.name).toBe("Alice");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't change locale objects given in ealier calls", function() {
|
||||||
|
var oldLocale = {name: "Bob"};
|
||||||
|
var newLocale = {name: "Alice"};
|
||||||
|
Diaspora.I18n.reset(oldLocale);
|
||||||
|
Diaspora.I18n.load(newLocale, "en");
|
||||||
|
expect(oldLocale.name).toBe("Bob");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("::t", function() {
|
describe("::t", function() {
|
||||||
|
|
|
||||||
7
spec/javascripts/onerror-fail.js
Normal file
7
spec/javascripts/onerror-fail.js
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
window.onerror = function(errorMsg, url, lineNumber) {
|
||||||
|
describe("Test suite", function() {
|
||||||
|
it("shouldn't skip tests because of syntax errors", function() {
|
||||||
|
fail(errorMsg + " in file " + url + " in line " + lineNumber);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -53,6 +53,7 @@ helpers:
|
||||||
# - **/*[sS]pec.js
|
# - **/*[sS]pec.js
|
||||||
#
|
#
|
||||||
spec_files:
|
spec_files:
|
||||||
|
- onerror-fail.js
|
||||||
- "**/**/*[sS]pec.js"
|
- "**/**/*[sS]pec.js"
|
||||||
|
|
||||||
# src_dir
|
# src_dir
|
||||||
|
|
|
||||||
|
|
@ -24,29 +24,6 @@ describe String do
|
||||||
let(:hebrew_arabic) { "#{hebrew} #{arabic}" }
|
let(:hebrew_arabic) { "#{hebrew} #{arabic}" }
|
||||||
|
|
||||||
|
|
||||||
describe "#stats_with_rtl_char?" do
|
|
||||||
it 'returns true or false correctly' do
|
|
||||||
expect(english.starts_with_rtl_char?).to be false
|
|
||||||
expect(chinese.starts_with_rtl_char?).to be false
|
|
||||||
expect(arabic.starts_with_rtl_char?).to be true
|
|
||||||
expect(hebrew.starts_with_rtl_char?).to be true
|
|
||||||
expect(hebrew_arabic.starts_with_rtl_char?).to be true
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'only looks at the first char' do
|
|
||||||
expect(english_chinese.starts_with_rtl_char?).to be false
|
|
||||||
expect(chinese_english.starts_with_rtl_char?).to be false
|
|
||||||
expect(english_arabic.starts_with_rtl_char?).to be false
|
|
||||||
expect(hebrew_english.starts_with_rtl_char?).to be true
|
|
||||||
expect(arabic_chinese.starts_with_rtl_char?).to be true
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'ignores whitespaces' do
|
|
||||||
expect(" \n \r \t".starts_with_rtl_char?).to be false
|
|
||||||
expect(" #{arabic} ".starts_with_rtl_char?).to be true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#is_rtl?" do
|
describe "#is_rtl?" do
|
||||||
it 'returns true or false correctly' do
|
it 'returns true or false correctly' do
|
||||||
expect(english.is_rtl?).to be false
|
expect(english.is_rtl?).to be false
|
||||||
|
|
@ -65,17 +42,16 @@ describe String do
|
||||||
expect("#{english} #{arabic} #{arabic}".is_rtl?).to be true
|
expect("#{english} #{arabic} #{arabic}".is_rtl?).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fallbacks to the first word if there's no majority" do
|
|
||||||
expect(hebrew_english.is_rtl?).to be true
|
|
||||||
expect(english_hebrew.is_rtl?).to be false
|
|
||||||
expect(arabic_english.is_rtl?).to be true
|
|
||||||
expect(english_arabic.is_rtl?).to be false
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'ignores whitespaces' do
|
it 'ignores whitespaces' do
|
||||||
expect(" \n \r \t".is_rtl?).to be false
|
expect(" \n \r \t".is_rtl?).to be false
|
||||||
expect(" #{arabic} ".is_rtl?).to be true
|
expect(" #{arabic} ".is_rtl?).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "ignores byte order marks" do
|
||||||
|
expect("\u{feff}".is_rtl?).to be false
|
||||||
|
expect("\u{feff}#{arabic}".is_rtl?).to be true
|
||||||
|
expect("\u{feff}#{english}".is_rtl?).to be false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#cleaned_is_rtl?' do
|
describe '#cleaned_is_rtl?' do
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue