added detection of rtl languages on every user based input
This commit is contained in:
parent
e4db8c7a36
commit
a7a8da2f75
17 changed files with 153 additions and 11 deletions
|
|
@ -280,4 +280,8 @@ module ApplicationHelper
|
|||
|
||||
defaults
|
||||
end
|
||||
|
||||
def rtl?(string)
|
||||
return (string.cleaned_is_rtl?) ? 'rtl' : ''
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@
|
|||
%time.timeago{:datetime => comment.created_at}
|
||||
= comment.created_at ? timeago(comment.created_at) : timeago(Time.now)
|
||||
|
||||
%p
|
||||
%p{ :class => rtl?(comment.text) }
|
||||
= markdownify(comment.text, :youtube_maps => comment.youtube_titles)
|
||||
|
|
|
|||
|
|
@ -14,5 +14,6 @@
|
|||
.content
|
||||
.from
|
||||
= person_link(comment.author)
|
||||
= markdownify(comment.text, :youtube_maps => comment[:youtube_titles])
|
||||
%p{ :class => rtl?(comment.text) }
|
||||
= markdownify(comment.text, :youtube_maps => comment[:youtube_titles])
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
.message_count
|
||||
= conversation.messages.size
|
||||
|
||||
= conversation.subject[0..30]
|
||||
%div{ :class => rtl?(conversation.subject) }
|
||||
= conversation.subject[0..30]
|
||||
|
||||
.last_author
|
||||
.timestamp
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
.span-16.last
|
||||
.conversation_participants
|
||||
.span-9
|
||||
%h3
|
||||
%h3{ :class => rtl?(conversation.subject) }
|
||||
= conversation.subject
|
||||
|
||||
.conversation_controls
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@
|
|||
%time.timeago{:datetime => message.created_at}
|
||||
= how_long_ago(message)
|
||||
|
||||
%p
|
||||
%p{ :class => rtl?(message.text) }
|
||||
= markdownify(message.text)
|
||||
|
||||
|
|
|
|||
|
|
@ -41,12 +41,14 @@
|
|||
%li
|
||||
%h4
|
||||
=t('.bio')
|
||||
= markdownify(person.profile.bio, :newlines => true)
|
||||
%div{ :class => rtl?(person.profile.bio) }
|
||||
= markdownify(person.profile.bio, :newlines => true)
|
||||
- unless person.profile.location.blank?
|
||||
%li
|
||||
%h4
|
||||
=t('.location')
|
||||
= markdownify(person.profile.location, :newlines => true)
|
||||
%div{ :class => rtl?(person.profile.location) }
|
||||
= markdownify(person.profile.location, :newlines => true)
|
||||
|
||||
%li.span-8.last
|
||||
.span-4
|
||||
|
|
|
|||
|
|
@ -14,5 +14,5 @@
|
|||
- for photo in photos[1..photos.size]
|
||||
= link_to (image_tag photo.url(:thumb_small), :class => 'thumb_small'), photo_path(photo)
|
||||
|
||||
%p
|
||||
%p{ :class => rtl?(post.text) }
|
||||
= markdownify(post.text, :youtube_maps => post[:youtube_titles])
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ javascripts:
|
|||
- public/javascripts/widgets/alert.js
|
||||
- public/javascripts/widgets/embedder.js
|
||||
- public/javascripts/widgets/timeago.js
|
||||
- public/javascripts/widgets/directionDetector.js
|
||||
- public/javascripts/view.js
|
||||
- public/javascripts/stream.js
|
||||
- public/javascripts/application.js
|
||||
|
|
|
|||
55
config/initializers/direction_detector.rb
Normal file
55
config/initializers/direction_detector.rb
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# Copyright (c) 2010, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
# Deeply inspired by https://gitorious.org/statusnet/mainline/blobs/master/plugins/DirectionDetector/DirectionDetectorPlugin.php
|
||||
|
||||
class String
|
||||
|
||||
def is_rtl?
|
||||
count = 0
|
||||
self.strip.split(" ").each do |word|
|
||||
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.strip) # otherwise let the first word decide
|
||||
end
|
||||
|
||||
# Diaspora specific
|
||||
def cleaned_is_rtl?
|
||||
string = String.new(self)
|
||||
[ /@[^ ]+|#[^ ]+/u, # mention, tag
|
||||
/^RT[: ]{1}| RT | RT: |[♺♻:]/u, # retweet
|
||||
/[ \r\t\n]+/ # whitespaces
|
||||
].each do |cleaner|
|
||||
string.gsub!(cleaner, '')
|
||||
end
|
||||
string.is_rtl?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def starts_with_rtl_char?(string)
|
||||
string = self.strip
|
||||
return false if string.empty?
|
||||
char = string.unpack('U*').first
|
||||
limits = [
|
||||
[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
|
||||
]
|
||||
limits.each do |limit|
|
||||
return true if char >= limit[0] && char <= limit[1]
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
|
@ -25,10 +25,10 @@ $(document).ready(function() {
|
|||
.css("display", "block");
|
||||
}
|
||||
Diaspora.widgets.timeago.updateTimeAgo();
|
||||
Diaspora.widgets.directionDetector.updateBinds();
|
||||
});
|
||||
|
||||
|
||||
|
||||
$("a.paginate").live("click", function() {
|
||||
$(this).css("display", "none");
|
||||
|
||||
|
|
|
|||
|
|
@ -6,13 +6,17 @@
|
|||
$(document).ready(function(){
|
||||
|
||||
$('a.conversation').live('click', function(){
|
||||
$.getScript(this.href);
|
||||
$.getScript(this.href, function() {
|
||||
Diaspora.widgets.directionDetector.updateBinds();
|
||||
});
|
||||
history.pushState(null, "", this.href);
|
||||
return false;
|
||||
});
|
||||
|
||||
$(window).bind("popstate", function(){
|
||||
$.getScript(location.href);
|
||||
$.getScript(location.href, function() {
|
||||
Diaspora.widgets.directionDetector.updateBinds();
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ var Stream = {
|
|||
$(".status_message_delete").tipsy({trigger: 'hover', gravity: 'n'});
|
||||
|
||||
Diaspora.widgets.timeago.updateTimeAgo();
|
||||
Diaspora.widgets.directionDetector.updateBinds();
|
||||
$stream.not(".show").delegate("a.show_post_comments", "click", Stream.toggleComments);
|
||||
//audio linx
|
||||
Stream.setUpAudioLinks();
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ var View = {
|
|||
$.facebox.settings.closeImage = '/images/facebox/closelabel.png'
|
||||
$.facebox.settings.loadingImage = '/images/facebox/loading.gif'
|
||||
$('a[rel*=facebox]').facebox();
|
||||
$(document).bind('reveal.facebox', function() {
|
||||
Diaspora.widgets.directionDetector.updateBinds();
|
||||
});
|
||||
|
||||
/* facebox 'done' buttons */
|
||||
$("a[rel*=close]").live('click', function(){ $.facebox.close() });
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ var WebSocketReceiver = {
|
|||
}
|
||||
|
||||
Diaspora.widgets.timeago.updateTimeAgo();
|
||||
Diaspora.widgets.directionDetector.updateBinds();
|
||||
},
|
||||
|
||||
processLike: function(postId, html) {
|
||||
|
|
@ -157,6 +158,7 @@ var WebSocketReceiver = {
|
|||
showMessage();
|
||||
}
|
||||
Diaspora.widgets.timeago.updateTimeAgo();
|
||||
Diaspora.widgets.directionDetector.updateBinds();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
64
public/javascripts/widgets/directionDetector.js
Normal file
64
public/javascripts/widgets/directionDetector.js
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* Copyright (c) 2010, Diaspora Inc. This file is
|
||||
* licensed under the Affero General Public License version 3 or later. See
|
||||
* the COPYRIGHT file.
|
||||
*/
|
||||
/* Modified version of https://gitorious.org/statusnet/mainline/blobs/master/plugins/DirectionDetector/jquery.DirectionDetector.js */
|
||||
|
||||
Diaspora.widgets.add("directionDetector", function() {
|
||||
|
||||
this.start = function() {
|
||||
Diaspora.widgets.directionDetector.updateBinds();
|
||||
};
|
||||
|
||||
this.isRTL = function(str) {
|
||||
if(typeof str != typeof "" || str.length<1)
|
||||
return false;
|
||||
var cc = str.charCodeAt(0);
|
||||
if(cc>=1536 && cc<=1791) // arabic, persian, ...
|
||||
return true;
|
||||
if(cc>=65136 && cc<=65279) // arabic peresent 2
|
||||
return true;
|
||||
if(cc>=64336 && cc<=65023) // arabic peresent 1
|
||||
return true;
|
||||
if(cc>=1424 && cc<=1535) // hebrew
|
||||
return true;
|
||||
if(cc>=64256 && cc<=64335) // hebrew peresent
|
||||
return true;
|
||||
if(cc>=1792 && cc<=1871) // Syriac
|
||||
return true;
|
||||
if(cc>=1920 && cc<=1983) // Thaana
|
||||
return true;
|
||||
if(cc>=1984 && cc<=2047) // NKo
|
||||
return true;
|
||||
if(cc>=11568 && cc<=11647) // Tifinagh
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
this.cleaner = new RegExp('@[^ ]+|^RT[: ]{1}| RT | RT: |[♺♻:]+', 'g');
|
||||
|
||||
this.binds = [];
|
||||
|
||||
this.updateBinds = function() {
|
||||
$.each(Diaspora.widgets.directionDetector.binds, function(i, v) {v.unbind('keyup', Diaspora.widgets.directionDetector.updateDirection);});
|
||||
Diaspora.widgets.directionDetector.binds = [];
|
||||
|
||||
$("textarea").each(Diaspora.widgets.directionDetector.bind);
|
||||
$("input[type='text']").each(Diaspora.widgets.directionDetector.bind);
|
||||
$("input[type='search']").each(Diaspora.widgets.directionDetector.bind);
|
||||
};
|
||||
|
||||
this.bind = function() {
|
||||
$(this).one('keyup', Diaspora.widgets.directionDetector.updateDirection);
|
||||
Diaspora.widgets.directionDetector.binds.push($(this));
|
||||
};
|
||||
|
||||
this.updateDirection = function() {
|
||||
tArea = $(this);
|
||||
var cleaned = tArea.val().replace(Diaspora.widgets.directionDetector.cleaner, '').replace(/^[ ]+/, '');
|
||||
if(Diaspora.widgets.directionDetector.isRTL(cleaned))
|
||||
tArea.css('direction', 'rtl');
|
||||
else
|
||||
tArea.css('direction', 'ltr');
|
||||
};
|
||||
});
|
||||
|
|
@ -47,6 +47,10 @@ form
|
|||
:font
|
||||
:size auto
|
||||
|
||||
.rtl
|
||||
:direction rtl
|
||||
:text-align right
|
||||
|
||||
.hidden
|
||||
:display none
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue