|
@ -8,7 +8,7 @@ import { search as searchCategoryTag } from 'discourse/lib/category-tag-search'
|
||||||
import { SEPARATOR } from 'discourse/lib/category-hashtags';
|
import { SEPARATOR } from 'discourse/lib/category-hashtags';
|
||||||
import { cook } from 'discourse/lib/text';
|
import { cook } from 'discourse/lib/text';
|
||||||
import { translations } from 'pretty-text/emoji/data';
|
import { translations } from 'pretty-text/emoji/data';
|
||||||
import { emojiSearch } from 'pretty-text/emoji';
|
import { emojiSearch, isSkinTonableEmoji } from 'pretty-text/emoji';
|
||||||
import { emojiUrlFor } from 'discourse/lib/text';
|
import { emojiUrlFor } from 'discourse/lib/text';
|
||||||
import { getRegister } from 'discourse-common/lib/get-owner';
|
import { getRegister } from 'discourse-common/lib/get-owner';
|
||||||
import { findRawTemplate } from 'discourse/lib/raw-templates';
|
import { findRawTemplate } from 'discourse/lib/raw-templates';
|
||||||
|
@ -337,6 +337,11 @@ export default Ember.Component.extend({
|
||||||
self.set('value', text);
|
self.set('value', text);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onKeyUp(text, cp) {
|
||||||
|
const subtext = text.substring(0, cp);
|
||||||
|
return subtext.match(/(:(?!:).?[\w-]*:?(?!:)(?:t\d?)?:?) ?$/gm);
|
||||||
|
},
|
||||||
|
|
||||||
transformComplete(v) {
|
transformComplete(v) {
|
||||||
if (v.code) {
|
if (v.code) {
|
||||||
return `${v.code}:`;
|
return `${v.code}:`;
|
||||||
|
@ -372,6 +377,20 @@ export default Ember.Component.extend({
|
||||||
return resolve([translations[full]]);
|
return resolve([translations[full]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const match = term.match(/^:?(.*?):t(\d)?$/);
|
||||||
|
if (match) {
|
||||||
|
let name = match[1];
|
||||||
|
let scale = match[2];
|
||||||
|
|
||||||
|
if (isSkinTonableEmoji(name)) {
|
||||||
|
if (scale) {
|
||||||
|
return resolve([`${name}:t${scale}`]);
|
||||||
|
} else {
|
||||||
|
return resolve([2, 3, 4, 5, 6].map(x => `${name}:t${x}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const options = emojiSearch(term, {maxResults: 5});
|
const options = emojiSearch(term, {maxResults: 5});
|
||||||
|
|
||||||
return resolve(options);
|
return resolve(options);
|
||||||
|
|
|
@ -360,8 +360,21 @@ export default function(options) {
|
||||||
|
|
||||||
var cp = caretPosition(me[0]);
|
var cp = caretPosition(me[0]);
|
||||||
|
|
||||||
if (options.key && completeStart === null && cp > 0) {
|
if (!options.key) return;
|
||||||
var key = me[0].value[cp-1];
|
|
||||||
|
const key = me[0].value[cp-1];
|
||||||
|
|
||||||
|
if (options.onKeyUp && key !== options.key) {
|
||||||
|
var match = options.onKeyUp(me.val(), cp);
|
||||||
|
if (match) {
|
||||||
|
completeStart = cp - match[0].length;
|
||||||
|
completeEnd = completeStart + match[0].length - 1;
|
||||||
|
let term = match[0].substring(1, match[0].length);
|
||||||
|
updateAutoComplete(dataSource(term, options));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (completeStart === null && cp > 0) {
|
||||||
if (key === options.key) {
|
if (key === options.key) {
|
||||||
var prevChar = me.val().charAt(cp-2);
|
var prevChar = me.val().charAt(cp-2);
|
||||||
if (checkTriggerRule() && (!prevChar || allowedLettersRegex.test(prevChar))) {
|
if (checkTriggerRule() && (!prevChar || allowedLettersRegex.test(prevChar))) {
|
||||||
|
@ -370,7 +383,7 @@ export default function(options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (completeStart !== null) {
|
} else if (completeStart !== null) {
|
||||||
var term = me.val().substring(completeStart + (options.key ? 1 : 0), cp);
|
let term = me.val().substring(completeStart + (options.key ? 1 : 0), cp);
|
||||||
updateAutoComplete(dataSource(term, options));
|
updateAutoComplete(dataSource(term, options));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { emoji, aliases, translations } from 'pretty-text/emoji/data';
|
import { emojis, aliases, translations, tonableEmojis } from 'pretty-text/emoji/data';
|
||||||
|
|
||||||
// bump up this number to expire all emojis
|
// bump up this number to expire all emojis
|
||||||
export const IMAGE_VERSION = "3";
|
export const IMAGE_VERSION = "5";
|
||||||
|
|
||||||
const extendedEmoji = {};
|
const extendedEmoji = {};
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ export function registerEmoji(code, url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function emojiList() {
|
export function emojiList() {
|
||||||
const result = emoji.slice(0);
|
const result = emojis.slice(0);
|
||||||
_.each(extendedEmoji, (v,k) => result.push(k));
|
_.each(extendedEmoji, (v,k) => result.push(k));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ export function emojiList() {
|
||||||
const emojiHash = {};
|
const emojiHash = {};
|
||||||
|
|
||||||
// add all default emojis
|
// add all default emojis
|
||||||
emoji.forEach(code => emojiHash[code] = true);
|
emojis.forEach(code => emojiHash[code] = true);
|
||||||
|
|
||||||
// and their aliases
|
// and their aliases
|
||||||
const aliasHash = {};
|
const aliasHash = {};
|
||||||
|
@ -30,7 +30,7 @@ Object.keys(aliases).forEach(name => {
|
||||||
export function performEmojiUnescape(string, opts) {
|
export function performEmojiUnescape(string, opts) {
|
||||||
// this can be further improved by supporting matches of emoticons that don't begin with a colon
|
// this can be further improved by supporting matches of emoticons that don't begin with a colon
|
||||||
if (string.indexOf(":") >= 0) {
|
if (string.indexOf(":") >= 0) {
|
||||||
return string.replace(/\B:[^\s:]+:?\B/g, m => {
|
return string.replace(/\B:[^\s:]+(?::t\d)?:?\B/g, m => {
|
||||||
const isEmoticon = !!translations[m];
|
const isEmoticon = !!translations[m];
|
||||||
const emojiVal = isEmoticon ? translations[m] : m.slice(1, m.length - 1);
|
const emojiVal = isEmoticon ? translations[m] : m.slice(1, m.length - 1);
|
||||||
const hasEndingColon = m.lastIndexOf(":") === m.length - 1;
|
const hasEndingColon = m.lastIndexOf(":") === m.length - 1;
|
||||||
|
@ -64,8 +64,9 @@ export function buildEmojiUrl(code, opts) {
|
||||||
url = opts.customEmoji[code];
|
url = opts.customEmoji[code];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!url && emojiHash.hasOwnProperty(code)) {
|
const noToneMatch = code.match(/(.?[\w-]*)?:?/);
|
||||||
url = opts.getURL(`/images/emoji/${opts.emojiSet}/${code}.png`);
|
if (noToneMatch && !url && (emojiHash.hasOwnProperty(noToneMatch[1]) || aliasHash.hasOwnProperty(noToneMatch[1]))) {
|
||||||
|
url = opts.getURL(`/images/emoji/${opts.emojiSet}/${code.replace(/:t/, '/')}.png`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
|
@ -77,7 +78,7 @@ export function buildEmojiUrl(code, opts) {
|
||||||
|
|
||||||
export function emojiExists(code) {
|
export function emojiExists(code) {
|
||||||
code = code.toLowerCase();
|
code = code.toLowerCase();
|
||||||
return !!(extendedEmoji.hasOwnProperty(code) || emojiHash.hasOwnProperty(code));
|
return !!(extendedEmoji.hasOwnProperty(code) || emojiHash.hasOwnProperty(code) || aliasHash.hasOwnProperty(code));
|
||||||
};
|
};
|
||||||
|
|
||||||
let toSearch;
|
let toSearch;
|
||||||
|
@ -113,3 +114,12 @@ export function emojiSearch(term, options) {
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function isSkinTonableEmoji(term) {
|
||||||
|
let match = term.match(/^:?(.*?):?$/);
|
||||||
|
if (match) {
|
||||||
|
return tonableEmojis.indexOf(match[1]) !== -1;
|
||||||
|
} else {
|
||||||
|
return tonableEmojis.indexOf(term) !== -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export const emoji = <%= Emoji.standard.map(&:name).flatten.inspect %>;
|
export const emojis = <%= Emoji.standard.map(&:name).flatten.inspect %>;
|
||||||
|
export const tonableEmojis = <%= Emoji.tonable_emojis.flatten.inspect %>;
|
||||||
export const aliases = <%= Emoji.aliases.inspect.gsub("=>", ":") %>;
|
export const aliases = <%= Emoji.aliases.inspect.gsub("=>", ":") %>;
|
||||||
export const translations = {
|
export const translations = {
|
||||||
':)' : 'slight_smile',
|
':)' : 'slight_smile',
|
||||||
|
|
|
@ -81,11 +81,17 @@ export function setup(helper) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple find and replace from our array
|
let between;
|
||||||
const between = text.slice(1, endPos);
|
const emojiNameMatch = text.match(/(?:.*?)(:(?!:).?[\w-]*(?::t\d)?:)/);
|
||||||
|
if (emojiNameMatch) {
|
||||||
|
between = emojiNameMatch[0].slice(1, -1);
|
||||||
|
} else {
|
||||||
|
between = text.slice(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
const contents = imageFor(between);
|
const contents = imageFor(between);
|
||||||
if (contents) {
|
if (contents) {
|
||||||
return [endPos+1, contents];
|
return [text.indexOf(between, 1) + between.length + 1, contents];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class Emoji
|
class Emoji
|
||||||
# update this to clear the cache
|
# update this to clear the cache
|
||||||
EMOJI_VERSION = "v3"
|
EMOJI_VERSION = "v5"
|
||||||
|
|
||||||
include ActiveModel::SerializerSupport
|
include ActiveModel::SerializerSupport
|
||||||
|
|
||||||
|
@ -23,13 +23,17 @@ class Emoji
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.aliases
|
def self.aliases
|
||||||
Discourse.cache.fetch(cache_key("aliases_emojis")) { load_aliases }
|
Discourse.cache.fetch(cache_key("aliases_emojis")) { db['aliases'] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.custom
|
def self.custom
|
||||||
Discourse.cache.fetch(cache_key("custom_emojis")) { load_custom }
|
Discourse.cache.fetch(cache_key("custom_emojis")) { load_custom }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.tonable_emojis
|
||||||
|
Discourse.cache.fetch(cache_key("tonable_emojis")) { db['tonableEmojis'] }
|
||||||
|
end
|
||||||
|
|
||||||
def self.exists?(name)
|
def self.exists?(name)
|
||||||
Emoji[name].present?
|
Emoji[name].present?
|
||||||
end
|
end
|
||||||
|
@ -63,32 +67,13 @@ class Emoji
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.db
|
def self.db
|
||||||
return @db if @db
|
@db ||= File.open(db_file, "r:UTF-8") { |f| JSON.parse(f.read) }
|
||||||
@db = File.open(db_file, "r:UTF-8") { |f| JSON.parse(f.read) }
|
|
||||||
|
|
||||||
# Small tweak to `emoji.json` from Emoji one
|
|
||||||
@db['emojis'] << {"code" => "1f44d", "name" => "+1", "filename" => "thumbsup"}
|
|
||||||
@db['emojis'] << {"code" => "1f44e", "name" => "-1", "filename" => "thumbsdown"}
|
|
||||||
|
|
||||||
@db
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.load_standard
|
def self.load_standard
|
||||||
db['emojis'].map {|e| Emoji.create_from_db_item(e) }
|
db['emojis'].map {|e| Emoji.create_from_db_item(e) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.load_aliases
|
|
||||||
return @aliases if @aliases
|
|
||||||
|
|
||||||
@aliases ||= db['aliases']
|
|
||||||
|
|
||||||
# Fix how `slightly_smiling` was mislabeled
|
|
||||||
@aliases['slight_smile'] ||= []
|
|
||||||
@aliases['slight_smile'] << 'slightly_smiling'
|
|
||||||
|
|
||||||
@aliases
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.load_custom
|
def self.load_custom
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
|
@ -159,11 +144,20 @@ class Emoji
|
||||||
def self.lookup_unicode(name)
|
def self.lookup_unicode(name)
|
||||||
@reverse_map ||= begin
|
@reverse_map ||= begin
|
||||||
map = {}
|
map = {}
|
||||||
|
|
||||||
db['emojis'].each do |e|
|
db['emojis'].each do |e|
|
||||||
next if e['name'] == 'tm'
|
next if e['name'] == 'tm'
|
||||||
code = replacement_code(e['code'])
|
code = replacement_code(e['code'])
|
||||||
map[e['name']] = code if code
|
map[e['name']] = code if code
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Emoji.aliases.each do |key, alias_names|
|
||||||
|
next unless alias_code = map[key]
|
||||||
|
alias_names.each do |alias_name|
|
||||||
|
map[alias_name] = alias_code
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
map
|
map
|
||||||
end
|
end
|
||||||
@reverse_map[name]
|
@reverse_map[name]
|
||||||
|
|
9823
lib/emoji/db.json
2754
lib/tasks/emoji.rake
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
BIN
public/images/emoji/apple/1st_place_medal.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
public/images/emoji/apple/2nd_place_medal.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/images/emoji/apple/3rd_place_medal.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
public/images/emoji/apple/afghanistan.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.3 KiB |
BIN
public/images/emoji/apple/aland_islands.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
public/images/emoji/apple/albania.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.4 KiB |
BIN
public/images/emoji/apple/algeria.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
public/images/emoji/apple/american_samoa.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
public/images/emoji/apple/andorra.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.5 KiB |
BIN
public/images/emoji/apple/angel/2.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
public/images/emoji/apple/angel/3.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
public/images/emoji/apple/angel/4.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
public/images/emoji/apple/angel/5.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
public/images/emoji/apple/angel/6.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
public/images/emoji/apple/angola.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
public/images/emoji/apple/anguilla.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
BIN
public/images/emoji/apple/antarctica.png
Normal file
After Width: | Height: | Size: 962 B |
BIN
public/images/emoji/apple/antigua_barbuda.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
BIN
public/images/emoji/apple/argentina.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
BIN
public/images/emoji/apple/armenia.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 875 B After Width: | Height: | Size: 876 B |
Before Width: | Height: | Size: 894 B After Width: | Height: | Size: 957 B |
Before Width: | Height: | Size: 900 B After Width: | Height: | Size: 976 B |
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 978 B |
Before Width: | Height: | Size: 912 B After Width: | Height: | Size: 934 B |
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 926 B |
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 993 B |
Before Width: | Height: | Size: 973 B After Width: | Height: | Size: 1007 B |
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 907 B After Width: | Height: | Size: 898 B |
Before Width: | Height: | Size: 914 B After Width: | Height: | Size: 891 B |
Before Width: | Height: | Size: 910 B After Width: | Height: | Size: 947 B |
Before Width: | Height: | Size: 929 B After Width: | Height: | Size: 1014 B |
Before Width: | Height: | Size: 897 B After Width: | Height: | Size: 933 B |
Before Width: | Height: | Size: 1000 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 872 B After Width: | Height: | Size: 930 B |
Before Width: | Height: | Size: 870 B After Width: | Height: | Size: 945 B |
Before Width: | Height: | Size: 814 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
public/images/emoji/apple/artificial_satellite.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
public/images/emoji/apple/aruba.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/images/emoji/apple/asterisk.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1001 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
public/images/emoji/apple/australia.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
public/images/emoji/apple/austria.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
public/images/emoji/apple/avocado.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
public/images/emoji/apple/azerbaijan.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1003 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
public/images/emoji/apple/baby/2.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/images/emoji/apple/baby/3.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/images/emoji/apple/baby/4.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/images/emoji/apple/baby/5.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
public/images/emoji/apple/baby/6.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |