FEATURE: support for emoji sets
Added following emoji sets - Apple/International - Emoji One (default) - Android/Google - Twitter FIX: translations from plugins weren't properly merged with default translations FEATURE: new 'site_setting_changed' event
|
@ -7,6 +7,11 @@ class SiteSetting < ActiveRecord::Base
|
|||
validates_presence_of :name
|
||||
validates_presence_of :data_type
|
||||
|
||||
after_save do |site_setting|
|
||||
DiscourseEvent.trigger(:site_setting_saved, site_setting)
|
||||
true
|
||||
end
|
||||
|
||||
def self.load_settings(file)
|
||||
SiteSettings::YamlLoader.new(file).load do |category, name, default, opts|
|
||||
if opts.delete(:client)
|
||||
|
@ -19,8 +24,10 @@ class SiteSetting < ActiveRecord::Base
|
|||
|
||||
load_settings(File.join(Rails.root, 'config', 'site_settings.yml'))
|
||||
|
||||
Dir[File.join(Rails.root, "plugins", "*", "config", "settings.yml")].each do |file|
|
||||
load_settings(file)
|
||||
unless Rails.env.test? && ENV['LOAD_PLUGINS'] != "1"
|
||||
Dir[File.join(Rails.root, "plugins", "*", "config", "settings.yml")].each do |file|
|
||||
load_settings(file)
|
||||
end
|
||||
end
|
||||
|
||||
client_settings << :available_locales
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
class FixEmojiPath < ActiveRecord::Migration
|
||||
BASE_URL = '/plugins/emoji/images/'
|
||||
|
||||
def up
|
||||
execute <<-SQL
|
||||
UPDATE posts
|
||||
SET cooked = REPLACE(cooked, '#{BASE_URL}', '#{BASE_URL}emoji_one/')
|
||||
WHERE cooked LIKE '%#{BASE_URL}%'
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
execute <<-SQL
|
||||
UPDATE posts
|
||||
SET cooked = REPLACE(cooked, '#{BASE_URL}emoji_one/', '#{BASE_URL}')
|
||||
WHERE cooked LIKE '%#{BASE_URL}emoji_one/%'
|
||||
SQL
|
||||
end
|
||||
end
|
|
@ -13,6 +13,7 @@ module JsLocaleHelper
|
|||
Dir["#{Rails.root}/plugins/*/config/locales/client.#{locale_str}.yml"].each do |file|
|
||||
plugin_translations.deep_merge! YAML::load(File.open(file))
|
||||
end
|
||||
|
||||
# merge translations (plugin translations overwrite default translations)
|
||||
translations[locale_str]['js'].deep_merge!(plugin_translations[locale_str]['js']) if translations[locale_str] && plugin_translations[locale_str] && plugin_translations[locale_str]['js']
|
||||
|
||||
|
@ -22,7 +23,7 @@ module JsLocaleHelper
|
|||
# For now, let's leave it split out in the translation file in case we want to split
|
||||
# it again later, so we'll merge the JSON ourselves.
|
||||
admin_contents = translations[locale_str].delete('admin_js')
|
||||
translations[locale_str]['js'].merge!(admin_contents) if admin_contents.present?
|
||||
translations[locale_str]['js'].deep_merge!(admin_contents) if admin_contents.present?
|
||||
translations[locale_str]['js'].deep_merge!(plugin_translations[locale_str]['admin_js']) if translations[locale_str] && plugin_translations[locale_str] && plugin_translations[locale_str]['admin_js']
|
||||
message_formats = strip_out_message_formats!(translations[locale_str]['js'])
|
||||
|
||||
|
|
|
@ -95,6 +95,11 @@ class Plugin::Instance
|
|||
end
|
||||
end
|
||||
|
||||
def listen_for(event_name)
|
||||
return unless self.respond_to?(event_name)
|
||||
DiscourseEvent.on(event_name, &self.method(event_name))
|
||||
end
|
||||
|
||||
def register_css(style)
|
||||
@styles ||= []
|
||||
@styles << style
|
||||
|
|
|
@ -177,7 +177,6 @@ module SiteSettingExtension
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
def ensure_listen_for_changes
|
||||
unless @subscribed
|
||||
MessageBus.subscribe("/site_settings") do |message|
|
||||
|
@ -273,7 +272,7 @@ module SiteSettingExtension
|
|||
}
|
||||
value = domain_array.join("|")
|
||||
end
|
||||
return value
|
||||
value
|
||||
end
|
||||
|
||||
def set(name, value)
|
||||
|
@ -356,7 +355,6 @@ module SiteSettingExtension
|
|||
|
||||
|
||||
def setup_methods(name, current_value)
|
||||
|
||||
clean_name = name.to_s.sub("?", "")
|
||||
|
||||
eval "define_singleton_method :#{clean_name} do
|
||||
|
@ -388,8 +386,7 @@ module SiteSettingExtension
|
|||
url = "http://#{url}" if URI.parse(url).scheme.nil?
|
||||
url = URI.parse(url).host
|
||||
end
|
||||
return url
|
||||
url
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#!/usr/bin/env rake
|
||||
require "bundler/gem_tasks"
|
||||
require "rspec/core/rake_task"
|
||||
|
||||
RSpec::Core::RakeTask.new(:test) do |spec|
|
||||
spec.pattern = 'spec/*_spec.rb'
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
require 'enum_site_setting'
|
||||
|
||||
class EmojiSetSiteSetting < EnumSiteSetting
|
||||
|
||||
def self.valid_value?(val)
|
||||
values.any? { |v| v[:value] == val.to_s }
|
||||
end
|
||||
|
||||
def self.values
|
||||
@values ||= [
|
||||
{ name: 'apple_international', value: 'apple' },
|
||||
{ name: 'google', value: 'google' },
|
||||
{ name: 'twitter', value: 'twitter' },
|
||||
{ name: 'emoji_one', value: 'emoji_one' },
|
||||
]
|
||||
end
|
||||
|
||||
def self.translate_names?
|
||||
true
|
||||
end
|
||||
|
||||
end
|
|
@ -1,25 +1,26 @@
|
|||
|
||||
// TODO: Make this a proper ES6 import
|
||||
var ComposerView = require('discourse/views/composer').default;
|
||||
|
||||
ComposerView.on("initWmdEditor", function(){
|
||||
if (!Discourse.SiteSettings.enable_emoji) { return; }
|
||||
|
||||
var template = Handlebars.compile("<div class='autocomplete'>" +
|
||||
"<ul>" +
|
||||
"{{#each options}}" +
|
||||
"<li>" +
|
||||
"<a href='#'>" +
|
||||
"<img src='{{src}}' class='emoji'> " +
|
||||
"{{code}}</a>" +
|
||||
"</li>" +
|
||||
"{{/each}}" +
|
||||
"</ul>" +
|
||||
"</div>");
|
||||
var template = Handlebars.compile(
|
||||
"<div class='autocomplete'>" +
|
||||
"<ul>" +
|
||||
"{{#each options}}" +
|
||||
"<li>" +
|
||||
"<a href='#'><img src='{{src}}' class='emoji'> {{code}}</a>" +
|
||||
"</li>" +
|
||||
"{{/each}}" +
|
||||
"</ul>" +
|
||||
"</div>"
|
||||
);
|
||||
|
||||
$('#wmd-input').autocomplete({
|
||||
template: template,
|
||||
key: ":",
|
||||
transformComplete: function(v){ return v.code + ":"; },
|
||||
transformComplete: function(v){ return v.code + ":"; },
|
||||
dataSource: function(term){
|
||||
return new Ember.RSVP.Promise(function(resolve) {
|
||||
var full = ":" + term;
|
||||
|
|
|
@ -1,54 +1,55 @@
|
|||
|
||||
var groups = [
|
||||
{
|
||||
name: "emoticons",
|
||||
icons: ["smile","smiley","grinning","blush","relaxed","wink","heart_eyes","kissing_heart","kissing_closed_eyes","kissing","kissing_smiling_eyes","stuck_out_tongue_winking_eye","stuck_out_tongue_closed_eyes","stuck_out_tongue","flushed","grin","pensive","relieved","unamused","disappointed","persevere","cry","joy","sob","sleepy","disappointed_relieved","cold_sweat","sweat_smile","sweat","weary","tired_face","fearful","scream","angry","rage","triumph","confounded","laughing","yum","mask","sunglasses","sleeping","dizzy_face","astonished","worried","frowning","anguished","smiling_imp","imp","open_mouth","grimacing","neutral_face","confused","hushed","no_mouth","innocent","smirk","expressionless","man_with_gua_pi_mao","man_with_turban","cop","construction_worker","guardsman","baby","boy","girl","man","woman","older_man","older_woman","person_with_blond_hair","angel","princess","smiley_cat","smile_cat","heart_eyes_cat","kissing_cat","smirk_cat","scream_cat","crying_cat_face","joy_cat","pouting_cat","japanese_ogre","japanese_goblin","see_no_evil","hear_no_evil","speak_no_evil","skull","alien","poop","fire","sparkles","star2","dizzy","boom","anger","sweat_drops","droplet","zzz","dash","ear","eyes","nose","tongue","lips","thumbsup","thumbsdown","ok_hand","punch","fist","v","wave","raised_hand","open_hands","point_up_2","point_down","point_right","point_left","raised_hands","pray","point_up","clap","muscle","walking","runner","dancer","couple","family","two_men_holding_hands","two_women_holding_hands","couplekiss","couple_with_heart","dancers","ok_woman","no_good","information_desk_person","raising_hand","massage","haircut","nail_care","bride_with_veil","person_with_pouting_face","person_frowning","bow","tophat","crown","womans_hat","athletic_shoe","mans_shoe","sandal","high_heel","boot","shirt","necktie","womans_clothes","dress","running_shirt_with_sash","jeans","kimono","bikini","briefcase","handbag","pouch","purse","eyeglasses","ribbon","closed_umbrella","lipstick","yellow_heart","blue_heart","purple_heart","green_heart","heart","broken_heart","heartpulse","heartbeat","two_hearts","sparkling_heart","revolving_hearts","cupid","love_letter","kiss","ring","gem","bust_in_silhouette","busts_in_silhouette","speech_balloon","footprints","thought_balloon"]
|
||||
},
|
||||
{
|
||||
name: "nature",
|
||||
icons: ["dog","wolf","cat","mouse","hamster","rabbit","frog","tiger","koala","bear","pig","pig_nose","cow","boar","monkey_face","monkey","horse","sheep","elephant","panda_face","penguin","bird","baby_chick","hatched_chick","hatching_chick","chicken","snake","turtle","bug","bee","ant","beetle","snail","octopus","shell","tropical_fish","fish","dolphin","whale","whale2","cow2","ram","rat","water_buffalo","tiger2","rabbit2","dragon","racehorse","goat","rooster","dog2","pig2","mouse2","ox","dragon_face","blowfish","crocodile","camel","dromedary_camel","leopard","cat2","poodle","feet","bouquet","cherry_blossom","tulip","four_leaf_clover","rose","sunflower","hibiscus","maple_leaf","leaves","fallen_leaf","herb","ear_of_rice","mushroom","cactus","palm_tree","evergreen_tree","deciduous_tree","chestnut","seedling","blossom","globe_with_meridians","sun_with_face","full_moon_with_face","new_moon_with_face","new_moon","waxing_crescent_moon","first_quarter_moon","waxing_gibbous_moon","full_moon","waning_gibbous_moon","last_quarter_moon","waning_crescent_moon","last_quarter_moon_with_face","first_quarter_moon_with_face","crescent_moon","earth_africa","earth_americas","earth_asia","volcano","milky_way","stars","star","sunny","partly_sunny","cloud","zap","umbrella","snowflake","snowman","cyclone","foggy","rainbow","ocean"]
|
||||
},
|
||||
{
|
||||
name: "objects",
|
||||
icons: ["bamboo","gift_heart","dolls","school_satchel","mortar_board","flags","fireworks","sparkler","wind_chime","rice_scene","jack_o_lantern","ghost","santa","christmas_tree","gift","tanabata_tree","tada","confetti_ball","balloon","crossed_flags","crystal_ball","movie_camera","camera","video_camera","vhs","cd","dvd","minidisc","floppy_disk","computer","iphone","telephone","telephone_receiver","pager","fax","satellite","tv","radio","loud_sound","sound","speaker","mute","bell","no_bell","loudspeaker","mega","hourglass_flowing_sand","hourglass","alarm_clock","watch","unlock","lock","lock_with_ink_pen","closed_lock_with_key","key","mag_right","bulb","flashlight","high_brightness","low_brightness","electric_plug","battery","mag","bathtub","bath","shower","toilet","wrench","nut_and_bolt","hammer","door","smoking","bomb","gun","knife","pill","syringe","moneybag","yen","dollar","pound","euro","credit_card","money_with_wings","calling","e-mail","inbox_tray","outbox_tray","envelope","envelope_with_arrow","incoming_envelope","postal_horn","mailbox","mailbox_closed","mailbox_with_mail","mailbox_with_no_mail","postbox","package","pencil","page_facing_up","page_with_curl","bookmark_tabs","bar_chart","chart_with_upwards_trend","chart_with_downwards_trend","scroll","clipboard","date","calendar","card_index","file_folder","open_file_folder","scissors","pushpin","paperclip","black_nib","pencil2","straight_ruler","triangular_ruler","closed_book","green_book","blue_book","orange_book","notebook","notebook_with_decorative_cover","ledger","books","book","bookmark","name_badge","microscope","telescope","newspaper","art","clapper","microphone","headphones","musical_score","musical_note","notes","musical_keyboard","violin","trumpet","saxophone","guitar","space_invader","video_game","black_joker","flower_playing_cards","mahjong","game_die","dart","football","basketball","soccer","baseball","tennis","8ball","rugby_football","bowling","golf","mountain_bicyclist","bicyclist","checkered_flag","horse_racing","trophy","ski","snowboarder","swimmer","surfer","fishing_pole_and_fish"]
|
||||
},
|
||||
{
|
||||
name: "foods",
|
||||
icons: ["coffee","tea","sake","baby_bottle","beer","beers","cocktail","tropical_drink","wine_glass","fork_and_knife","pizza","hamburger","fries","poultry_leg","meat_on_bone","spaghetti","curry","fried_shrimp","bento","sushi","fish_cake","rice_ball","rice_cracker","rice","ramen","stew","oden","dango","egg","bread","doughnut","custard","icecream","ice_cream","shaved_ice","birthday","cake","cookie","chocolate_bar","candy","lollipop","honey_pot","apple","green_apple","tangerine","lemon","cherries","grapes","watermelon","strawberry","peach","melon","banana","pear","pineapple","sweet_potato","eggplant","tomato","corn"]
|
||||
},
|
||||
{
|
||||
name: "places",
|
||||
icons: ["house","house_with_garden","school","office","post_office","hospital","bank","convenience_store","love_hotel","hotel","wedding","church","department_store","european_post_office","city_sunset","city_dusk","japanese_castle","european_castle","tent","factory","tokyo_tower","japan","mount_fuji","sunrise_over_mountains","sunrise","night_with_stars","statue_of_liberty","bridge_at_night","carousel_horse","ferris_wheel","fountain","roller_coaster","ship","sailboat","speedboat","rowboat","anchor","rocket","airplane","seat","helicopter","steam_locomotive","tram","station","mountain_railway","train2","bullettrain_side","bullettrain_front","light_rail","metro","monorail","train","railway_car","trolleybus","bus","oncoming_bus","blue_car","oncoming_automobile","red_car","taxi","oncoming_taxi","articulated_lorry","truck","rotating_light","police_car","oncoming_police_car","fire_engine","ambulance","minibus","bike","aerial_tramway","suspension_railway","mountain_cableway","tractor","barber","busstop","ticket","vertical_traffic_light","traffic_light","warning","construction","beginner","fuelpump","izakaya_lantern","slot_machine","hotsprings","moyai","circus_tent","performing_arts","round_pushpin","triangular_flag_on_post","cn","us","in","jp","br","ru","de","ng","gb","fr","mx","kr","id","ph","eg","vn","tr","it","es","ca","pl","ar","co","ir","za","my","pk","au","th","ma","tw","nl","ua","sa","ke","ve","pe","ro","cl","uz","bd","kz","be","se","cz","sd","hu","pt","ch","at","tz"]
|
||||
},
|
||||
{
|
||||
name: "symbols",
|
||||
icons: ["hash","one","two","three","four","five","six","seven","eight","nine","zero","keycap_ten","1234","symbols","arrow_up","arrow_down","arrow_left","arrow_right","capital_abcd","abcd","abc","arrow_upper_right","arrow_upper_left","arrow_lower_right","arrow_lower_left","left_right_arrow","arrow_up_down","arrows_counterclockwise","arrow_backward","arrow_forward","arrow_up_small","arrow_down_small","leftwards_arrow_with_hook","arrow_right_hook","information_source","rewind","fast_forward","arrow_double_up","arrow_double_down","arrow_heading_down","arrow_heading_up","ok","twisted_rightwards_arrows","repeat","repeat_one","new","up","cool","free","ng","signal_strength","cinema","koko","u6307","u7a7a","u6e80","u5408","u7981","ideograph_advantage","u5272","u55b6","u6709","u7121","restroom","mens","womens","baby_symbol","wc","potable_water","put_litter_in_its_place","parking","wheelchair","no_smoking","u6708","u7533","sa","m","passport_control","baggage_claim","left_luggage","customs","accept","secret","congratulations","cl","sos","id","no_entry_sign","underage","no_mobile_phones","do_not_litter","non-potable_water","no_bicycles","no_pedestrians","children_crossing","no_entry","eight_spoked_asterisk","sparkle","negative_squared_cross_mark","white_check_mark","eight_pointed_black_star","heart_decoration","vs","vibration_mode","mobile_phone_off","a","b","ab","o2","diamond_shape_with_a_dot_inside","loop","recycle","aries","taurus","gemini","cancer","leo","virgo","libra","scorpius","sagittarius","capricorn","aquarius","pisces","ophiuchus","six_pointed_star","atm","chart","heavy_dollar_sign","currency_exchange","copyright","registered","tm","part_alternation_mark","wavy_dash","top","end","back","on","soon","x","o","exclamation","question","grey_exclamation","grey_question","bangbang","interrobang","arrows_clockwise","clock12","clock1230","clock1","clock130","clock2","clock230","clock3","clock330","clock4","clock430","clock5","clock530","clock6","clock7","clock8","clock9","clock10","clock11","clock630","clock730","clock830","clock930","clock1030","clock1130","heavy_multiplication_x","heavy_plus_sign","heavy_minus_sign","heavy_division_sign","spades","hearts","clubs","diamonds","white_flower","100","heavy_check_mark","ballot_box_with_check","radio_button","link","curly_loop","trident","black_square_button","white_square_button","black_medium_square","white_medium_square","black_medium_small_square","white_medium_small_square","black_small_square","white_small_square","small_red_triangle","white_large_square","black_large_square","black_circle","white_circle","red_circle","large_blue_circle","small_red_triangle_down","large_orange_diamond","large_blue_diamond","small_orange_diamond","small_blue_diamond"]
|
||||
}];
|
||||
var _groups = [
|
||||
{
|
||||
name: "emoticons",
|
||||
icons: ["smile","smiley","grinning","blush","relaxed","wink","heart_eyes","kissing_heart","kissing_closed_eyes","kissing","kissing_smiling_eyes","stuck_out_tongue_winking_eye","stuck_out_tongue_closed_eyes","stuck_out_tongue","flushed","grin","pensive","relieved","unamused","disappointed","persevere","cry","joy","sob","sleepy","disappointed_relieved","cold_sweat","sweat_smile","sweat","weary","tired_face","fearful","scream","angry","rage","triumph","confounded","laughing","yum","mask","sunglasses","sleeping","dizzy_face","astonished","worried","frowning","anguished","smiling_imp","imp","open_mouth","grimacing","neutral_face","confused","hushed","no_mouth","innocent","smirk","expressionless","man_with_gua_pi_mao","man_with_turban","cop","construction_worker","guardsman","baby","boy","girl","man","woman","older_man","older_woman","person_with_blond_hair","angel","princess","smiley_cat","smile_cat","heart_eyes_cat","kissing_cat","smirk_cat","scream_cat","crying_cat_face","joy_cat","pouting_cat","japanese_ogre","japanese_goblin","see_no_evil","hear_no_evil","speak_no_evil","skull","alien","poop","fire","sparkles","star2","dizzy","boom","anger","sweat_drops","droplet","zzz","dash","ear","eyes","nose","tongue","lips","thumbsup","thumbsdown","ok_hand","punch","fist","v","wave","raised_hand","open_hands","point_up_2","point_down","point_right","point_left","raised_hands","pray","point_up","clap","muscle","walking","runner","dancer","couple","family","two_men_holding_hands","two_women_holding_hands","couplekiss","couple_with_heart","dancers","ok_woman","no_good","information_desk_person","raising_hand","massage","haircut","nail_care","bride_with_veil","person_with_pouting_face","person_frowning","bow","tophat","crown","womans_hat","athletic_shoe","mans_shoe","sandal","high_heel","boot","shirt","necktie","womans_clothes","dress","running_shirt_with_sash","jeans","kimono","bikini","briefcase","handbag","pouch","purse","eyeglasses","ribbon","closed_umbrella","lipstick","yellow_heart","blue_heart","purple_heart","green_heart","heart","broken_heart","heartpulse","heartbeat","two_hearts","sparkling_heart","revolving_hearts","cupid","love_letter","kiss","ring","gem","bust_in_silhouette","busts_in_silhouette","speech_balloon","footprints","thought_balloon"]
|
||||
},
|
||||
{
|
||||
name: "nature",
|
||||
icons: ["dog","wolf","cat","mouse","hamster","rabbit","frog","tiger","koala","bear","pig","pig_nose","cow","boar","monkey_face","monkey","horse","sheep","elephant","panda_face","penguin","bird","baby_chick","hatched_chick","hatching_chick","chicken","snake","turtle","bug","bee","ant","beetle","snail","octopus","shell","tropical_fish","fish","dolphin","whale","whale2","cow2","ram","rat","water_buffalo","tiger2","rabbit2","dragon","racehorse","goat","rooster","dog2","pig2","mouse2","ox","dragon_face","blowfish","crocodile","camel","dromedary_camel","leopard","cat2","poodle","feet","bouquet","cherry_blossom","tulip","four_leaf_clover","rose","sunflower","hibiscus","maple_leaf","leaves","fallen_leaf","herb","ear_of_rice","mushroom","cactus","palm_tree","evergreen_tree","deciduous_tree","chestnut","seedling","blossom","globe_with_meridians","sun_with_face","full_moon_with_face","new_moon_with_face","new_moon","waxing_crescent_moon","first_quarter_moon","waxing_gibbous_moon","full_moon","waning_gibbous_moon","last_quarter_moon","waning_crescent_moon","last_quarter_moon_with_face","first_quarter_moon_with_face","crescent_moon","earth_africa","earth_americas","earth_asia","volcano","milky_way","stars","star","sunny","partly_sunny","cloud","zap","umbrella","snowflake","snowman","cyclone","foggy","rainbow","ocean"]
|
||||
},
|
||||
{
|
||||
name: "objects",
|
||||
icons: ["bamboo","gift_heart","dolls","school_satchel","mortar_board","flags","fireworks","sparkler","wind_chime","rice_scene","jack_o_lantern","ghost","santa","christmas_tree","gift","tanabata_tree","tada","confetti_ball","balloon","crossed_flags","crystal_ball","movie_camera","camera","video_camera","vhs","cd","dvd","minidisc","floppy_disk","computer","iphone","telephone","telephone_receiver","pager","fax","satellite","tv","radio","loud_sound","sound","speaker","mute","bell","no_bell","loudspeaker","mega","hourglass_flowing_sand","hourglass","alarm_clock","watch","unlock","lock","lock_with_ink_pen","closed_lock_with_key","key","mag_right","bulb","flashlight","high_brightness","low_brightness","electric_plug","battery","mag","bathtub","bath","shower","toilet","wrench","nut_and_bolt","hammer","door","smoking","bomb","gun","knife","pill","syringe","moneybag","yen","dollar","pound","euro","credit_card","money_with_wings","calling","e-mail","inbox_tray","outbox_tray","envelope","envelope_with_arrow","incoming_envelope","postal_horn","mailbox","mailbox_closed","mailbox_with_mail","mailbox_with_no_mail","postbox","package","pencil","page_facing_up","page_with_curl","bookmark_tabs","bar_chart","chart_with_upwards_trend","chart_with_downwards_trend","scroll","clipboard","date","calendar","card_index","file_folder","open_file_folder","scissors","pushpin","paperclip","black_nib","pencil2","straight_ruler","triangular_ruler","closed_book","green_book","blue_book","orange_book","notebook","notebook_with_decorative_cover","ledger","books","book","bookmark","name_badge","microscope","telescope","newspaper","art","clapper","microphone","headphones","musical_score","musical_note","notes","musical_keyboard","violin","trumpet","saxophone","guitar","space_invader","video_game","black_joker","flower_playing_cards","mahjong","game_die","dart","football","basketball","soccer","baseball","tennis","8ball","rugby_football","bowling","golf","mountain_bicyclist","bicyclist","checkered_flag","horse_racing","trophy","ski","snowboarder","swimmer","surfer","fishing_pole_and_fish"]
|
||||
},
|
||||
{
|
||||
name: "foods",
|
||||
icons: ["coffee","tea","sake","baby_bottle","beer","beers","cocktail","tropical_drink","wine_glass","fork_and_knife","pizza","hamburger","fries","poultry_leg","meat_on_bone","spaghetti","curry","fried_shrimp","bento","sushi","fish_cake","rice_ball","rice_cracker","rice","ramen","stew","oden","dango","egg","bread","doughnut","custard","icecream","ice_cream","shaved_ice","birthday","cake","cookie","chocolate_bar","candy","lollipop","honey_pot","apple","green_apple","tangerine","lemon","cherries","grapes","watermelon","strawberry","peach","melon","banana","pear","pineapple","sweet_potato","eggplant","tomato","corn"]
|
||||
},
|
||||
{
|
||||
name: "places",
|
||||
icons: ["house","house_with_garden","school","office","post_office","hospital","bank","convenience_store","love_hotel","hotel","wedding","church","department_store","european_post_office","city_sunset","city_dusk","japanese_castle","european_castle","tent","factory","tokyo_tower","japan","mount_fuji","sunrise_over_mountains","sunrise","night_with_stars","statue_of_liberty","bridge_at_night","carousel_horse","ferris_wheel","fountain","roller_coaster","ship","sailboat","speedboat","rowboat","anchor","rocket","airplane","seat","helicopter","steam_locomotive","tram","station","mountain_railway","train2","bullettrain_side","bullettrain_front","light_rail","metro","monorail","train","railway_car","trolleybus","bus","oncoming_bus","blue_car","oncoming_automobile","red_car","taxi","oncoming_taxi","articulated_lorry","truck","rotating_light","police_car","oncoming_police_car","fire_engine","ambulance","minibus","bike","aerial_tramway","suspension_railway","mountain_cableway","tractor","barber","busstop","ticket","vertical_traffic_light","traffic_light","warning","construction","beginner","fuelpump","izakaya_lantern","slot_machine","hotsprings","moyai","circus_tent","performing_arts","round_pushpin","triangular_flag_on_post","cn","us","in","jp","br","ru","de","ng","gb","fr","mx","kr","id","ph","eg","vn","tr","it","es","ca","pl","ar","co","ir","za","my","pk","au","th","ma","tw","nl","ua","sa","ke","ve","pe","ro","cl","uz","bd","kz","be","se","cz","sd","hu","pt","ch","at","tz"]
|
||||
},
|
||||
{
|
||||
name: "symbols",
|
||||
icons: ["hash","one","two","three","four","five","six","seven","eight","nine","zero","keycap_ten","1234","symbols","arrow_up","arrow_down","arrow_left","arrow_right","capital_abcd","abcd","abc","arrow_upper_right","arrow_upper_left","arrow_lower_right","arrow_lower_left","left_right_arrow","arrow_up_down","arrows_counterclockwise","arrow_backward","arrow_forward","arrow_up_small","arrow_down_small","leftwards_arrow_with_hook","arrow_right_hook","information_source","rewind","fast_forward","arrow_double_up","arrow_double_down","arrow_heading_down","arrow_heading_up","ok","twisted_rightwards_arrows","repeat","repeat_one","new","up","cool","free","ng","signal_strength","cinema","koko","u6307","u7a7a","u6e80","u5408","u7981","ideograph_advantage","u5272","u55b6","u6709","u7121","restroom","mens","womens","baby_symbol","wc","potable_water","put_litter_in_its_place","parking","wheelchair","no_smoking","u6708","u7533","sa","m","passport_control","baggage_claim","left_luggage","customs","accept","secret","congratulations","cl","sos","id","no_entry_sign","underage","no_mobile_phones","do_not_litter","non-potable_water","no_bicycles","no_pedestrians","children_crossing","no_entry","eight_spoked_asterisk","sparkle","negative_squared_cross_mark","white_check_mark","eight_pointed_black_star","heart_decoration","vs","vibration_mode","mobile_phone_off","a","b","ab","o2","diamond_shape_with_a_dot_inside","loop","recycle","aries","taurus","gemini","cancer","leo","virgo","libra","scorpius","sagittarius","capricorn","aquarius","pisces","ophiuchus","six_pointed_star","atm","chart","heavy_dollar_sign","currency_exchange","copyright","registered","tm","part_alternation_mark","wavy_dash","top","end","back","on","soon","x","o","exclamation","question","grey_exclamation","grey_question","bangbang","interrobang","arrows_clockwise","clock12","clock1230","clock1","clock130","clock2","clock230","clock3","clock330","clock4","clock430","clock5","clock530","clock6","clock7","clock8","clock9","clock10","clock11","clock630","clock730","clock830","clock930","clock1030","clock1130","heavy_multiplication_x","heavy_plus_sign","heavy_minus_sign","heavy_division_sign","spades","hearts","clubs","diamonds","white_flower","100","heavy_check_mark","ballot_box_with_check","radio_button","link","curly_loop","trident","black_square_button","white_square_button","black_medium_square","white_medium_square","black_medium_small_square","white_medium_small_square","black_small_square","white_small_square","small_red_triangle","white_large_square","black_large_square","black_circle","white_circle","red_circle","large_blue_circle","small_red_triangle_down","large_orange_diamond","large_blue_diamond","small_orange_diamond","small_blue_diamond"]
|
||||
}
|
||||
];
|
||||
|
||||
// scrub groups
|
||||
groups.forEach(function(group){
|
||||
_groups.forEach(function(group){
|
||||
group.icons = _.reject(group.icons, function(obj){
|
||||
return !Discourse.Emoji.exists(obj);
|
||||
});
|
||||
});
|
||||
|
||||
// export so others can modify
|
||||
Discourse.Emoji.groups = groups;
|
||||
Discourse.Emoji.groups = _groups;
|
||||
|
||||
var closeSelector = function(){
|
||||
$('.emoji-modal, .emoji-modal-wrapper').remove();
|
||||
$('body, textarea').off('keydown.emoji');
|
||||
};
|
||||
|
||||
var ungroupedIcons;
|
||||
var _ungroupedIcons;
|
||||
|
||||
var toolbar = function(selected){
|
||||
|
||||
if(!ungroupedIcons){
|
||||
ungroupedIcons = [];
|
||||
if(!_ungroupedIcons){
|
||||
_ungroupedIcons = [];
|
||||
var groupedIcons = {};
|
||||
|
||||
_.each(groups, function(group){
|
||||
_.each(_groups, function(group){
|
||||
_.each(group.icons, function(icon){
|
||||
groupedIcons[icon] = true;
|
||||
});
|
||||
|
@ -57,16 +58,16 @@ var toolbar = function(selected){
|
|||
var emojis = Discourse.Emoji.list();
|
||||
_.each(emojis,function(emoji){
|
||||
if(groupedIcons[emoji] !== true){
|
||||
ungroupedIcons.push(emoji);
|
||||
_ungroupedIcons.push(emoji);
|
||||
}
|
||||
});
|
||||
|
||||
if(ungroupedIcons.length > 0){
|
||||
groups.push({name: 'ungrouped', icons: ungroupedIcons});
|
||||
if(_ungroupedIcons.length > 0){
|
||||
_groups.push({name: 'ungrouped', icons: _ungroupedIcons});
|
||||
}
|
||||
}
|
||||
|
||||
return _.map(groups, function(g, i){
|
||||
return _.map(_groups, function(g, i){
|
||||
var row = {src: Discourse.Emoji.urlFor(g.icons[0]), groupId: i};
|
||||
if(i===selected){
|
||||
row.selected = true;
|
||||
|
@ -75,31 +76,29 @@ var toolbar = function(selected){
|
|||
});
|
||||
};
|
||||
|
||||
var perRow=12, perPage=60;
|
||||
var PER_ROW = 12, PER_PAGE = 60;
|
||||
|
||||
var bindEvents = function(page,offset){
|
||||
|
||||
var composerController = Discourse.__container__.lookup('controller:composer');
|
||||
|
||||
$('.emoji-page a').click(function(){
|
||||
composerController.appendTextAtCursor(":" + $(this).attr('title') + ":", {space: true});
|
||||
closeSelector();
|
||||
return false;
|
||||
}).hover(function(){
|
||||
var title = $(this).attr('title');
|
||||
$('.emoji-modal .info')
|
||||
.html("<img src='" + Discourse.Emoji.urlFor(title) +
|
||||
"' class='emoji'> <span>:" + title + ":<span>");
|
||||
|
||||
var html = "<img src='" + Discourse.Emoji.urlFor(title) + "' class='emoji'> <span>:" + title + ":<span>";
|
||||
$('.emoji-modal .info').html(html);
|
||||
},function(){
|
||||
$('.emoji-modal .info').html("");
|
||||
});
|
||||
|
||||
$('.emoji-modal .nav .next a').click(function(){
|
||||
render(page, offset+perPage);
|
||||
render(page, offset+PER_PAGE);
|
||||
});
|
||||
|
||||
$('.emoji-modal .nav .prev a').click(function(){
|
||||
render(page, offset-perPage);
|
||||
render(page, offset-PER_PAGE);
|
||||
});
|
||||
|
||||
$('.emoji-modal .toolbar a').click(function(){
|
||||
|
@ -112,13 +111,11 @@ var bindEvents = function(page,offset){
|
|||
var render = function(page, offset){
|
||||
var rows = [];
|
||||
var row = [];
|
||||
var icons = groups[page].icons;
|
||||
var icons = _groups[page].icons;
|
||||
|
||||
for(var i=offset; i<(offset+perPage); i++){
|
||||
if(!icons[i]){
|
||||
break;
|
||||
}
|
||||
if(row.length === perRow){
|
||||
for(var i=offset; i<(offset+PER_PAGE); i++){
|
||||
if(!icons[i]){ break; }
|
||||
if(row.length === PER_ROW){
|
||||
rows.push(row);
|
||||
row = [];
|
||||
}
|
||||
|
@ -130,7 +127,7 @@ var render = function(page, offset){
|
|||
toolbarItems: toolbar(page),
|
||||
rows: rows,
|
||||
prevDisabled: offset === 0,
|
||||
nextDisabled: (offset + perPage + 1) > icons.length
|
||||
nextDisabled: (offset + PER_PAGE + 1) > icons.length
|
||||
};
|
||||
|
||||
$('body .emoji-modal').remove();
|
||||
|
@ -140,9 +137,7 @@ var render = function(page, offset){
|
|||
bindEvents(page,offset);
|
||||
};
|
||||
|
||||
|
||||
var showSelector = function(){
|
||||
|
||||
$('body').append('<div class="emoji-modal-wrapper"></div>');
|
||||
|
||||
$('.emoji-modal-wrapper').click(function(){
|
||||
|
@ -151,7 +146,6 @@ var showSelector = function(){
|
|||
|
||||
render(0,0);
|
||||
|
||||
|
||||
$('body, textarea').on('keydown.emoji', function(e){
|
||||
if(e.which === 27){
|
||||
closeSelector();
|
||||
|
|
|
@ -3,7 +3,7 @@ Discourse.Emoji = {};
|
|||
// bump up this number to expire all emojis
|
||||
Discourse.Emoji.ImageVersion = "0"
|
||||
|
||||
var emoji = <%= Dir.glob(File.expand_path("../../../public/images/*.png", __FILE__)).map{|f| File.basename(f).split(".")[0]}.inspect %>;
|
||||
var _emoji = <%= Emoji.all.map { |e| e["aliases"] }.flatten.inspect %>;
|
||||
|
||||
var _extendedEmoji = {};
|
||||
Discourse.Dialect.registerEmoji = function(code, url) {
|
||||
|
@ -11,41 +11,39 @@ Discourse.Dialect.registerEmoji = function(code, url) {
|
|||
};
|
||||
|
||||
Discourse.Emoji.list = function(){
|
||||
var copy = emoji.slice(0);
|
||||
var copy = _emoji.slice(0);
|
||||
_.each(_extendedEmoji, function(v,k){
|
||||
copy.push(k);
|
||||
});
|
||||
return copy;
|
||||
};
|
||||
|
||||
var toSearch;
|
||||
var _toSearch;
|
||||
|
||||
var search = function(term, options) {
|
||||
var maxResults = (options && options["maxResults"]) || -1;
|
||||
|
||||
toSearch = toSearch || emoji.concat(Object.keys(_extendedEmoji));
|
||||
_toSearch = _toSearch || _emoji.concat(Object.keys(_extendedEmoji));
|
||||
|
||||
if(maxResults === 0) {
|
||||
return [];
|
||||
}
|
||||
if(maxResults === 0) { return []; }
|
||||
|
||||
var results = [];
|
||||
var i, results = [];
|
||||
|
||||
var done = function(){
|
||||
return maxResults > 0 && results.length >= maxResults;
|
||||
}
|
||||
|
||||
for (i=0; i < toSearch.length; i++) {
|
||||
if (toSearch[i].indexOf(term) === 0) {
|
||||
results.push(toSearch[i]);
|
||||
for (i=0; i < _toSearch.length; i++) {
|
||||
if (_toSearch[i].indexOf(term) === 0) {
|
||||
results.push(_toSearch[i]);
|
||||
if(done()) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
if(!done()){
|
||||
for (i=0; i < toSearch.length; i++) {
|
||||
if (toSearch[i].indexOf(term) > 0) {
|
||||
results.push(toSearch[i]);
|
||||
for (i=0; i < _toSearch.length; i++) {
|
||||
if (_toSearch[i].indexOf(term) > 0) {
|
||||
results.push(_toSearch[i]);
|
||||
if(done()) { break; }
|
||||
}
|
||||
}
|
||||
|
@ -56,20 +54,20 @@ var search = function(term, options) {
|
|||
|
||||
Discourse.Emoji.search = search;
|
||||
|
||||
|
||||
var emojiHash = {};
|
||||
emoji.forEach(function(code){
|
||||
emojiHash[code] = true;
|
||||
var _emojiHash = {};
|
||||
_emoji.forEach(function(code){
|
||||
_emojiHash[code] = true;
|
||||
});
|
||||
|
||||
var urlFor = function(code) {
|
||||
var url;
|
||||
var url, set = Discourse.SiteSettings.emoji_set;
|
||||
|
||||
if(_extendedEmoji.hasOwnProperty(code)) {
|
||||
url = _extendedEmoji[code];
|
||||
}
|
||||
|
||||
if(!url && emojiHash.hasOwnProperty(code)) {
|
||||
url = Discourse.getURL('/plugins/emoji/images/' + code + '.png');
|
||||
if(!url && _emojiHash.hasOwnProperty(code)) {
|
||||
url = Discourse.getURL('/plugins/emoji/images/' + set + '/' + code + '.png');
|
||||
}
|
||||
|
||||
if(url && url[0] !== 'h' && Discourse.CDN) {
|
||||
|
@ -85,15 +83,14 @@ var urlFor = function(code) {
|
|||
|
||||
Discourse.Emoji.urlFor = urlFor;
|
||||
|
||||
|
||||
Discourse.Emoji.exists = function(code){
|
||||
return !!(_extendedEmoji.hasOwnProperty(code) || emojiHash.hasOwnProperty(code));
|
||||
return !!(_extendedEmoji.hasOwnProperty(code) || _emojiHash.hasOwnProperty(code));
|
||||
}
|
||||
|
||||
function imageFor(code) {
|
||||
var url = urlFor(code);
|
||||
if (url) {
|
||||
return ['img', {href: url, title: ':' + code + ':', 'class': 'emoji', alt: code}];
|
||||
return ['img', { href: url, title: ':' + code + ':', 'class': 'emoji', alt: code }];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,6 +188,4 @@ Discourse.Dialect.registerInline(':', function(text, match, prev) {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
Discourse.Markdown.whiteListTag('img', 'class', 'emoji');
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env ruby
|
||||
# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
|
||||
|
||||
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
||||
ENGINE_PATH = File.expand_path('../../lib/emoji/engine', __FILE__)
|
||||
|
||||
require 'rails/all'
|
||||
require 'rails/engine/commands'
|
|
@ -2,6 +2,12 @@ en:
|
|||
js:
|
||||
composer:
|
||||
emoji: "Emoji :smile: CTRL+ E"
|
||||
|
||||
apple_international: "Apple/International"
|
||||
google: "Google"
|
||||
twitter: "Twitter"
|
||||
emoji_one: "Emoji One"
|
||||
|
||||
admin_js:
|
||||
admin:
|
||||
site_settings:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
en:
|
||||
site_settings:
|
||||
enable_emoji: "Enable the emoji plugin"
|
||||
emoji_set: "How would you like your emoji?"
|
||||
|
|
|
@ -2,3 +2,7 @@ plugins:
|
|||
enable_emoji:
|
||||
default: true
|
||||
client: true
|
||||
emoji_set:
|
||||
default: 'emoji_one'
|
||||
client: true
|
||||
enum: 'EmojiSetSiteSetting'
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
require "emoji/engine"
|
||||
|
||||
module Emoji
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
module Emoji
|
||||
class Engine < ::Rails::Engine
|
||||
isolate_namespace Emoji
|
||||
end
|
||||
|
||||
def self.all
|
||||
return @all if defined?(@all)
|
||||
@all = parse_db
|
||||
end
|
||||
|
||||
def self.db_file
|
||||
File.expand_path('../../../db.json', __FILE__)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.parse_db
|
||||
File.open(db_file, "r:UTF-8") { |f| JSON.parse(f.read) }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
module Emoji
|
||||
VERSION = "0.0.1"
|
||||
end
|
|
@ -1,7 +1,9 @@
|
|||
# name: emoji
|
||||
# about: emoji support for Discourse
|
||||
# version: 0.1
|
||||
# authors: Sam Saffron, Robin Ward
|
||||
# version: 0.2
|
||||
# authors: Sam Saffron, Robin Ward, Régis Hanol
|
||||
|
||||
load File.expand_path('../lib/emoji/engine.rb', __FILE__)
|
||||
|
||||
register_asset('javascripts/emoji.js.erb', :server_side)
|
||||
register_asset('javascripts/emoji-autocomplete.js', :composer)
|
||||
|
@ -9,9 +11,23 @@ register_asset('javascripts/discourse/templates/emoji-toolbar.raw.hbs', :compose
|
|||
register_asset('javascripts/emoji-toolbar.js', :composer)
|
||||
register_asset('stylesheets/emoji.css')
|
||||
|
||||
after_initialize do
|
||||
def site_setting_saved(site_setting)
|
||||
return unless site_setting.name.to_s == "emoji_set"
|
||||
return unless site_setting.value_changed?
|
||||
before = "/plugins/emoji/images/#{site_setting.value_was}/"
|
||||
after = "/plugins/emoji/images/#{site_setting.value}/"
|
||||
Scheduler::Defer.later "Fix Emoji Links" do
|
||||
Post.exec_sql("UPDATE posts SET cooked = REPLACE(cooked, :before, :after) WHERE cooked LIKE :like",
|
||||
before: before,
|
||||
after: after,
|
||||
like: "%#{before}%"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
listen_for(:site_setting_saved)
|
||||
|
||||
after_initialize do
|
||||
# whitelist emojis so that new user can post emojis
|
||||
Post::white_listed_image_classes << "emoji"
|
||||
|
||||
end
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
unicode/1f44d.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f44e.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f4af.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f522.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f3b1.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f170.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f18e.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f524.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f521.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f251.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f6a1.png
|
|
@ -1 +0,0 @@
|
|||
unicode/2708.png
|
|
@ -1 +0,0 @@
|
|||
unicode/23f0.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f47d.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f691.png
|
|
@ -1 +0,0 @@
|
|||
unicode/2693.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f47c.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f4a2.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f620.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f627.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f41c.png
|
|
@ -1 +0,0 @@
|
|||
unicode/1f34e.png
|
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1.9 KiB |