From 23d67d21009964c636cd69c06fb99da8a666af08 Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Mon, 5 Jun 2017 18:00:15 +0200 Subject: [PATCH 001/279] Add includes image choice to advanced search ui. --- .../discourse/components/search-advanced-options.js.es6 | 3 ++- config/locales/client.en.yml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 index 0bc886a8178..1ffd1cdaead 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -14,7 +14,7 @@ const REGEXP_MIN_POST_COUNT_PREFIX = /^min_post_count:/ig; const REGEXP_POST_TIME_PREFIX = /^(before|after):/ig; const REGEXP_TAGS_REPLACE = /(^(tags?:|#(?=[a-z0-9\-]+::tag))|::tag\s?$)/ig; -const REGEXP_IN_MATCH = /^in:(posted|watching|tracking|bookmarks|first|pinned|unpinned|wiki|unseen)/ig; +const REGEXP_IN_MATCH = /^in:(posted|watching|tracking|bookmarks|first|pinned|unpinned|wiki|unseen|image)/ig; const REGEXP_SPECIAL_IN_LIKES_MATCH = /^in:likes/ig; const REGEXP_SPECIAL_IN_PRIVATE_MATCH = /^in:private/ig; const REGEXP_SPECIAL_IN_SEEN_MATCH = /^in:seen/ig; @@ -36,6 +36,7 @@ export default Em.Component.extend({ {name: I18n.t('search.advanced.filters.pinned'), value: "pinned"}, {name: I18n.t('search.advanced.filters.unpinned'), value: "unpinned"}, {name: I18n.t('search.advanced.filters.wiki'), value: "wiki"}, + {name: I18n.t('search.advanced.filters.images'), value: "image"}, ], statusOptions: [ {name: I18n.t('search.advanced.statuses.open'), value: "open"}, diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 52b4e5301f1..71532ab95d8 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1344,6 +1344,7 @@ en: seen: I've read unseen: I've not read wiki: are wiki + images: includes image statuses: label: Where topics open: are open From 8f7d81fde64a756a227e46746af22b99fa922bbc Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Tue, 6 Jun 2017 14:39:53 +0200 Subject: [PATCH 002/279] Add rspec test for searching posts with images. --- config/locales/client.en.yml | 2 +- spec/components/search_spec.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 71532ab95d8..c2268368f51 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1344,7 +1344,7 @@ en: seen: I've read unseen: I've not read wiki: are wiki - images: includes image + images: includes image(s) statuses: label: Where topics open: are open diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index d215c8835c3..069f602065d 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -628,6 +628,16 @@ describe Search do end + it 'can find posts with images' do + post_uploaded = Fabricate(:post_with_uploaded_image) + post_with_image_urls = Fabricate(:post_with_image_urls) + Fabricate(:post) + TopicLink.extract_from(post_uploaded) + TopicLink.extract_from(post_with_image_urls) + + expect(Search.execute('in:image').posts.map(&:id).sort).to eq([post_uploaded.id, post_with_image_urls.id].sort) + end + it 'can find by latest' do topic1 = Fabricate(:topic, title: 'I do not like that Sam I am') post1 = Fabricate(:post, topic: topic1) From 76712da16697abc24e78bf5748bbb180172f8d3d Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Wed, 7 Jun 2017 20:13:36 +0200 Subject: [PATCH 003/279] Add backend code for searching posts with images. --- lib/search.rb | 4 ++++ spec/components/search_spec.rb | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/search.rb b/lib/search.rb index 543149b18e2..156c30c77a3 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -338,6 +338,10 @@ class Search end end + advanced_filter(/in:image/) do |posts| + posts.where("posts.image_url IS NOT NULL") + end + advanced_filter(/category:(.+)/) do |posts,match| exact = false diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index 069f602065d..2f9f32b07b8 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -632,8 +632,9 @@ describe Search do post_uploaded = Fabricate(:post_with_uploaded_image) post_with_image_urls = Fabricate(:post_with_image_urls) Fabricate(:post) - TopicLink.extract_from(post_uploaded) - TopicLink.extract_from(post_with_image_urls) + + CookedPostProcessor.new(post_uploaded).update_post_image + CookedPostProcessor.new(post_with_image_urls).update_post_image expect(Search.execute('in:image').posts.map(&:id).sort).to eq([post_uploaded.id, post_with_image_urls.id].sort) end From 4c22f3a0e2cf85acc82860ed02fc81d01590e037 Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Fri, 9 Jun 2017 13:56:18 +0200 Subject: [PATCH 004/279] Add file extension column to TopicLinks. --- db/migrate/20170609115401_add_extension_to_topic_links.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 db/migrate/20170609115401_add_extension_to_topic_links.rb diff --git a/db/migrate/20170609115401_add_extension_to_topic_links.rb b/db/migrate/20170609115401_add_extension_to_topic_links.rb new file mode 100644 index 00000000000..8360b0ef082 --- /dev/null +++ b/db/migrate/20170609115401_add_extension_to_topic_links.rb @@ -0,0 +1,5 @@ +class AddExtensionToTopicLinks < ActiveRecord::Migration + def change + add_column :topic_links, :extension, :string, limit: 5 + end +end From bf002e0873b75ec5a6f252187b61bbaf299caaa7 Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Fri, 9 Jun 2017 13:16:50 +0200 Subject: [PATCH 005/279] Add extraction of image_url for oneboxed images. Fix search by images filter name. --- .../components/search-advanced-options.js.es6 | 16 +++++++++++----- lib/cooked_post_processor.rb | 8 ++++---- lib/search.rb | 2 +- spec/components/cooked_post_processor_spec.rb | 4 ++-- spec/components/search_spec.rb | 2 +- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 index 1ffd1cdaead..bc345a5977a 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -8,13 +8,13 @@ const REGEXP_CATEGORY_PREFIX = /^(category:|#)/ig; const REGEXP_GROUP_PREFIX = /^group:/ig; const REGEXP_BADGE_PREFIX = /^badge:/ig; const REGEXP_TAGS_PREFIX = /^(tags?:|#(?=[a-z0-9\-]+::tag))/ig; -const REGEXP_IN_PREFIX = /^in:/ig; +const REGEXP_IN_PREFIX = /^(in|with):/ig; const REGEXP_STATUS_PREFIX = /^status:/ig; const REGEXP_MIN_POST_COUNT_PREFIX = /^min_post_count:/ig; const REGEXP_POST_TIME_PREFIX = /^(before|after):/ig; const REGEXP_TAGS_REPLACE = /(^(tags?:|#(?=[a-z0-9\-]+::tag))|::tag\s?$)/ig; -const REGEXP_IN_MATCH = /^in:(posted|watching|tracking|bookmarks|first|pinned|unpinned|wiki|unseen|image)/ig; +const REGEXP_IN_MATCH = /^(in|with):(posted|watching|tracking|bookmarks|first|pinned|unpinned|wiki|unseen|image)/ig; const REGEXP_SPECIAL_IN_LIKES_MATCH = /^in:likes/ig; const REGEXP_SPECIAL_IN_PRIVATE_MATCH = /^in:private/ig; const REGEXP_SPECIAL_IN_SEEN_MATCH = /^in:seen/ig; @@ -23,6 +23,8 @@ const REGEXP_CATEGORY_SLUG = /^(\#[a-zA-Z0-9\-:]+)/ig; const REGEXP_CATEGORY_ID = /^(category:[0-9]+)/ig; const REGEXP_POST_TIME_WHEN = /^(before|after)/ig; +const IN_OPTIONS_MAPPING = {'images': 'with'}; + export default Em.Component.extend({ classNames: ['search-advanced-options'], @@ -36,7 +38,7 @@ export default Em.Component.extend({ {name: I18n.t('search.advanced.filters.pinned'), value: "pinned"}, {name: I18n.t('search.advanced.filters.unpinned'), value: "unpinned"}, {name: I18n.t('search.advanced.filters.wiki'), value: "wiki"}, - {name: I18n.t('search.advanced.filters.images'), value: "image"}, + {name: I18n.t('search.advanced.filters.images'), value: "images"}, ], statusOptions: [ {name: I18n.t('search.advanced.statuses.open'), value: "open"}, @@ -392,13 +394,17 @@ export default Em.Component.extend({ updateSearchTermForIn() { const match = this.filterBlocks(REGEXP_IN_MATCH); const inFilter = this.get('searchedTerms.in'); + let keyword = 'in'; + if(inFilter in IN_OPTIONS_MAPPING) { + keyword = IN_OPTIONS_MAPPING[inFilter]; + } let searchTerm = this.get('searchTerm') || ''; if (inFilter) { if (match.length !== 0) { - searchTerm = searchTerm.replace(match[0], `in:${inFilter}`); + searchTerm = searchTerm.replace(match[0], `${keyword}:${inFilter}`); } else { - searchTerm += ` in:${inFilter}`; + searchTerm += ` ${keyword}:${inFilter}`; } this.set('searchTerm', searchTerm.trim()); diff --git a/lib/cooked_post_processor.rb b/lib/cooked_post_processor.rb index 48f1d38b494..43bb9567719 100644 --- a/lib/cooked_post_processor.rb +++ b/lib/cooked_post_processor.rb @@ -76,8 +76,6 @@ class CookedPostProcessor limit_size!(img) convert_to_link!(img) end - - update_post_image end def extract_images @@ -98,8 +96,6 @@ class CookedPostProcessor @doc.css("img[src]") - # minus, emojis @doc.css("img.emoji") - - # minus, image inside oneboxes - oneboxed_images - # minus, images inside quotes @doc.css(".quote img") end @@ -283,6 +279,8 @@ class CookedPostProcessor def update_post_image img = extract_images_for_post.first + return if img.blank? + if img["src"].present? @post.update_column(:image_url, img["src"][0...255]) # post @post.topic.update_column(:image_url, img["src"][0...255]) if @post.is_first_post? # topic @@ -301,6 +299,8 @@ class CookedPostProcessor Oneboxer.onebox(url, args) end + update_post_image + # make sure we grab dimensions for oneboxed images oneboxed_images.each { |img| limit_size!(img) } diff --git a/lib/search.rb b/lib/search.rb index 156c30c77a3..b3f886af59b 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -338,7 +338,7 @@ class Search end end - advanced_filter(/in:image/) do |posts| + advanced_filter(/with:images/) do |posts| posts.where("posts.image_url IS NOT NULL") end diff --git a/spec/components/cooked_post_processor_spec.rb b/spec/components/cooked_post_processor_spec.rb index cc0f5f4467e..dc58e4b8551 100644 --- a/spec/components/cooked_post_processor_spec.rb +++ b/spec/components/cooked_post_processor_spec.rb @@ -249,7 +249,7 @@ describe CookedPostProcessor do it "adds a topic image if there's one in the first post" do FastImage.stubs(:size) expect(post.topic.image_url).to eq(nil) - cpp.post_process_images + cpp.update_post_image post.topic.reload expect(post.topic.image_url).to be_present end @@ -262,7 +262,7 @@ describe CookedPostProcessor do it "adds a post image if there's one in the post" do FastImage.stubs(:size) expect(reply.image_url).to eq(nil) - cpp.post_process_images + cpp.update_post_image reply.reload expect(reply.image_url).to be_present end diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index 2f9f32b07b8..c5357481676 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -636,7 +636,7 @@ describe Search do CookedPostProcessor.new(post_uploaded).update_post_image CookedPostProcessor.new(post_with_image_urls).update_post_image - expect(Search.execute('in:image').posts.map(&:id).sort).to eq([post_uploaded.id, post_with_image_urls.id].sort) + expect(Search.execute('with:images').posts.map(&:id)).to contain_exactly(post_uploaded.id, post_with_image_urls.id) end it 'can find by latest' do From eaf46431d49aebda75a8ef5eba0e2b7e4ede082b Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Mon, 19 Jun 2017 17:09:54 +0200 Subject: [PATCH 006/279] Add extraction of file extension in TopicLink and related rspec tests. --- app/models/topic_link.rb | 4 +++- spec/models/topic_link_spec.rb | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/models/topic_link.rb b/app/models/topic_link.rb index 12ae7dcaab0..c9abf160c42 100644 --- a/app/models/topic_link.rb +++ b/app/models/topic_link.rb @@ -164,6 +164,7 @@ SQL added_urls << url unless TopicLink.exists?(topic_id: post.topic_id, post_id: post.id, url: url) + file_extension = File.extname(parsed.path)[1..5].downcase unless File.extname(parsed.path).empty? begin TopicLink.create!(post_id: post.id, user_id: post.user_id, @@ -173,7 +174,8 @@ SQL internal: internal, link_topic_id: topic_id, link_post_id: reflected_post.try(:id), - quote: link.is_quote) + quote: link.is_quote, + extension: file_extension) rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation # it's fine end diff --git a/spec/models/topic_link_spec.rb b/spec/models/topic_link_spec.rb index 9ee96750f24..f9f0c9d3099 100644 --- a/spec/models/topic_link_spec.rb +++ b/spec/models/topic_link_spec.rb @@ -193,7 +193,7 @@ http://b.com/#{'a'*500} end context "link to a local attachments" do - let(:post) { topic.posts.create(user: user, raw: 'ruby.rb') } + let(:post) { topic.posts.create(user: user, raw: 'ruby.rb') } it "extracts the link" do TopicLink.extract_from(post) @@ -203,9 +203,11 @@ http://b.com/#{'a'*500} # is set to internal expect(link).to be_internal # has the correct url - expect(link.url).to eq("/uploads/default/208/87bb3d8428eb4783.rb") + expect(link.url).to eq("/uploads/default/208/87bb3d8428eb4783.rb?foo=bar") # should not be the reflection expect(link).not_to be_reflection + # should have file extension + expect(link.extension).to eq('rb') end end @@ -224,6 +226,8 @@ http://b.com/#{'a'*500} expect(link.url).to eq("//s3.amazonaws.com/bucket/2104a0211c9ce41ed67989a1ed62e9a394c1fbd1446.rb") # should not be the reflection expect(link).not_to be_reflection + # should have file extension + expect(link.extension).to eq('rb') end end From 67ce4b70a67ccefb03874375bf73e904f9d6cb8e Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Tue, 20 Jun 2017 13:01:31 +0200 Subject: [PATCH 007/279] Add index to extension column in TopicLink. --- db/migrate/20170609115401_add_extension_to_topic_links.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/db/migrate/20170609115401_add_extension_to_topic_links.rb b/db/migrate/20170609115401_add_extension_to_topic_links.rb index 8360b0ef082..fbe8b9c1843 100644 --- a/db/migrate/20170609115401_add_extension_to_topic_links.rb +++ b/db/migrate/20170609115401_add_extension_to_topic_links.rb @@ -1,5 +1,6 @@ class AddExtensionToTopicLinks < ActiveRecord::Migration def change add_column :topic_links, :extension, :string, limit: 5 + add_index :topic_links, :extension end end From f87d32ac6d6636912d0b8d559493333f4768abd7 Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Tue, 20 Jun 2017 21:20:06 +0200 Subject: [PATCH 008/279] Add backend code for searching by filetypes. --- lib/search.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/search.rb b/lib/search.rb index 543149b18e2..f3ea5ccd824 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -456,6 +456,15 @@ class Search )", tags) end + advanced_filter(/filetypes?:([a-zA-Z0-9,\-_]+)/) do |posts, match| + file_extensions = match.split(",") + + posts.where("posts.id IN ( + SELECT post_id FROM topic_links + WHERE extension IN (?) + )", file_extensions) + end + private From aad1c9bef2851d5dcc13ba4dddd40d818eb49424 Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Tue, 20 Jun 2017 21:21:56 +0200 Subject: [PATCH 009/279] Add rspec tests for searching by a filetype. --- spec/components/search_spec.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index d215c8835c3..c7c2c5609e4 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -703,6 +703,24 @@ describe Search do expect(Search.execute('green tags:eggs').posts.map(&:id)).to eq([post2.id]) expect(Search.execute('green tags:plants').posts.size).to eq(0) end + + it "can find posts which contains filetypes" do + # Must be posts with real images + post1 = Fabricate(:post, + raw: "https://www.discourse.org/a/img/favicon.png") + post2 = Fabricate(:post, + raw: "Discourse logo\n"\ + "https://www.discourse.org/a/img/favicon.png\n"\ + "https://www.discourse.org/a/img/trust-1x.jpg") + Fabricate(:post) + + TopicLink.extract_from(post1) + TopicLink.extract_from(post2) + + expect(Search.execute('filetype:jpg').posts.map(&:id)).to eq([post2.id]) + expect(Search.execute('filetype:png').posts.map(&:id)).to contain_exactly(post1.id, post2.id) + expect(Search.execute('logo filetype:jpg').posts.map(&:id)).to eq([post2.id]) + end end it 'can parse complex strings using ts_query helper' do From bb392973ca6b57510d26ad4a6ae44356b84b1233 Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Mon, 3 Jul 2017 19:06:54 +0200 Subject: [PATCH 010/279] Add migration with extension column to uploads. --- .../20170609115401_add_extension_to_topic_links.rb | 2 +- db/migrate/20170703115216_add_extension_to_uploads.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20170703115216_add_extension_to_uploads.rb diff --git a/db/migrate/20170609115401_add_extension_to_topic_links.rb b/db/migrate/20170609115401_add_extension_to_topic_links.rb index fbe8b9c1843..7c05a12d1a1 100644 --- a/db/migrate/20170609115401_add_extension_to_topic_links.rb +++ b/db/migrate/20170609115401_add_extension_to_topic_links.rb @@ -1,6 +1,6 @@ class AddExtensionToTopicLinks < ActiveRecord::Migration def change - add_column :topic_links, :extension, :string, limit: 5 + add_column :topic_links, :extension, :string, limit: 10 add_index :topic_links, :extension end end diff --git a/db/migrate/20170703115216_add_extension_to_uploads.rb b/db/migrate/20170703115216_add_extension_to_uploads.rb new file mode 100644 index 00000000000..76aa08fa113 --- /dev/null +++ b/db/migrate/20170703115216_add_extension_to_uploads.rb @@ -0,0 +1,11 @@ +class AddExtensionToUploads < ActiveRecord::Migration + def up + add_column :uploads, :extension, :string, limit: 10 + execute "CREATE INDEX index_uploads_on_extension ON uploads(lower(extension))" + end + + def down + remove_column :uploads, :extension + execute "DROP INDEX index_uploads_on_extension" + end +end From f0a674d620587af1cb2dae802d2520827c193af8 Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Mon, 3 Jul 2017 19:08:59 +0200 Subject: [PATCH 011/279] Add extraction of upload extension. Add rspec test for search of post with upload by extension. --- app/models/topic_link.rb | 2 +- lib/upload_creator.rb | 1 + spec/components/search_spec.rb | 6 ++++-- spec/fabricators/upload_fabricator.rb | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/models/topic_link.rb b/app/models/topic_link.rb index c9abf160c42..48c7c279c02 100644 --- a/app/models/topic_link.rb +++ b/app/models/topic_link.rb @@ -164,7 +164,7 @@ SQL added_urls << url unless TopicLink.exists?(topic_id: post.topic_id, post_id: post.id, url: url) - file_extension = File.extname(parsed.path)[1..5].downcase unless File.extname(parsed.path).empty? + file_extension = File.extname(parsed.path)[1..10].downcase unless File.extname(parsed.path).empty? begin TopicLink.create!(post_id: post.id, user_id: post.user_id, diff --git a/lib/upload_creator.rb b/lib/upload_creator.rb index a00b13f08fc..503c0fadefa 100644 --- a/lib/upload_creator.rb +++ b/lib/upload_creator.rb @@ -73,6 +73,7 @@ class UploadCreator @upload.sha1 = sha1 @upload.url = "" @upload.origin = @opts[:origin][0...1000] if @opts[:origin] + @upload.extension = File.extname(@filename)[1..10] if FileHelper.is_image?(@filename) @upload.width, @upload.height = ImageSizer.resize(*@image_info.size) diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index c7c2c5609e4..7faf1bac437 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -712,14 +712,16 @@ describe Search do raw: "Discourse logo\n"\ "https://www.discourse.org/a/img/favicon.png\n"\ "https://www.discourse.org/a/img/trust-1x.jpg") + post_with_upload = Fabricate(:post) + post_with_upload.uploads = [Fabricate(:upload)] Fabricate(:post) TopicLink.extract_from(post1) TopicLink.extract_from(post2) expect(Search.execute('filetype:jpg').posts.map(&:id)).to eq([post2.id]) - expect(Search.execute('filetype:png').posts.map(&:id)).to contain_exactly(post1.id, post2.id) - expect(Search.execute('logo filetype:jpg').posts.map(&:id)).to eq([post2.id]) + expect(Search.execute('filetype:png').posts.map(&:id)).to contain_exactly(post1.id, post2.id, post_with_upload.id) + expect(Search.execute('logo filetype:png').posts.map(&:id)).to eq([post2.id]) end end diff --git a/spec/fabricators/upload_fabricator.rb b/spec/fabricators/upload_fabricator.rb index a2afdf7af0a..7d0c7f43be6 100644 --- a/spec/fabricators/upload_fabricator.rb +++ b/spec/fabricators/upload_fabricator.rb @@ -6,6 +6,7 @@ Fabricator(:upload) do width 100 height 200 url { sequence(:url) { |n| "/uploads/default/#{n}/1234567890123456.png" } } + extension "png" end Fabricator(:upload_s3, from: :upload) do From 8c445e9f17f6ba51a5698a3e948ad46d339615ee Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Tue, 4 Jul 2017 17:50:08 +0200 Subject: [PATCH 012/279] Fix backend code for searching by a filetype as a combination of uploads and topic links. Add rspec test for extracting file extension in upload. --- app/models/upload.rb | 4 ---- lib/file_store/base_store.rb | 2 +- lib/search.rb | 6 +++++- spec/models/upload_spec.rb | 5 +++++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/models/upload.rb b/app/models/upload.rb index d6e1916c720..f0eae0896ba 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -52,10 +52,6 @@ class Upload < ActiveRecord::Base end end - def extension - File.extname(original_filename) - end - def self.generate_digest(path) Digest::SHA1.file(path).hexdigest end diff --git a/lib/file_store/base_store.rb b/lib/file_store/base_store.rb index b79282fe681..b4c8bfe47c6 100644 --- a/lib/file_store/base_store.rb +++ b/lib/file_store/base_store.rb @@ -95,7 +95,7 @@ module FileStore end def get_path_for_upload(upload) - get_path_for("original".freeze, upload.id, upload.sha1, upload.extension) + get_path_for("original".freeze, upload.id, upload.sha1, File.extname(upload.original_filename)) end def get_path_for_optimized_image(optimized_image) diff --git a/lib/search.rb b/lib/search.rb index f3ea5ccd824..159de71b8d0 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -462,7 +462,11 @@ class Search posts.where("posts.id IN ( SELECT post_id FROM topic_links WHERE extension IN (?) - )", file_extensions) + UNION + SELECT post_uploads.post_id FROM uploads + JOIN post_uploads ON post_uploads.upload_id = uploads.id + WHERE lower(uploads.extension) IN (?) + )", file_extensions, file_extensions) end private diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb index c187ddbe675..ceef5bf669b 100644 --- a/spec/models/upload_spec.rb +++ b/spec/models/upload_spec.rb @@ -46,6 +46,11 @@ describe Upload do end + it "extracts file extension" do + created_upload = UploadCreator.new(image, image_filename).create_for(user_id) + expect(created_upload.extension).to eq("png") + end + context ".get_from_url" do let(:url) { "/uploads/default/original/3X/1/0/10f73034616a796dfd70177dc54b6def44c4ba6f.png" } let(:upload) { Fabricate(:upload, url: url) } From 5b11391588b2cf17c4c528ef86770e93ea71ba3c Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Fri, 7 Jul 2017 11:11:43 -0400 Subject: [PATCH 013/279] Add a nil check on the connection before attempting to exec it --- script/import_scripts/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/import_scripts/base.rb b/script/import_scripts/base.rb index 616a534a5d8..5d85af80167 100644 --- a/script/import_scripts/base.rb +++ b/script/import_scripts/base.rb @@ -203,7 +203,7 @@ class ImportScripts::Base return true end ensure - connection.exec('DROP TABLE import_ids') + connection.exec('DROP TABLE import_ids') unless connection.nil? end def created_user(user) From 677267ae786bae753655039d7c2e3deba58b0077 Mon Sep 17 00:00:00 2001 From: Jakub Macina Date: Thu, 6 Jul 2017 19:11:32 +0200 Subject: [PATCH 014/279] Add onceoff job for uploads migration of column extension. Simplify filetype search and related rspec tests. --- app/jobs/onceoff/migrate_upload_extensions.rb | 11 +++++++++++ lib/file_store/base_store.rb | 2 +- lib/search.rb | 8 ++++---- spec/components/search_spec.rb | 12 +++++------- 4 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 app/jobs/onceoff/migrate_upload_extensions.rb diff --git a/app/jobs/onceoff/migrate_upload_extensions.rb b/app/jobs/onceoff/migrate_upload_extensions.rb new file mode 100644 index 00000000000..38bcd3a1eab --- /dev/null +++ b/app/jobs/onceoff/migrate_upload_extensions.rb @@ -0,0 +1,11 @@ +module Jobs + + class MigrateUploadExtensions < Jobs::Onceoff + def execute_onceoff(args) + Upload.find_each do |upload| + upload.extension = File.extname(upload.original_filename)[1..10] + upload.save + end + end + end +end diff --git a/lib/file_store/base_store.rb b/lib/file_store/base_store.rb index b4c8bfe47c6..7b17fb2d852 100644 --- a/lib/file_store/base_store.rb +++ b/lib/file_store/base_store.rb @@ -95,7 +95,7 @@ module FileStore end def get_path_for_upload(upload) - get_path_for("original".freeze, upload.id, upload.sha1, File.extname(upload.original_filename)) + get_path_for("original".freeze, upload.id, upload.sha1, "."+upload.extension) end def get_path_for_optimized_image(optimized_image) diff --git a/lib/search.rb b/lib/search.rb index 159de71b8d0..5a6c1c2d783 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -457,16 +457,16 @@ class Search end advanced_filter(/filetypes?:([a-zA-Z0-9,\-_]+)/) do |posts, match| - file_extensions = match.split(",") + file_extensions = match.split(",").map(&:downcase) posts.where("posts.id IN ( SELECT post_id FROM topic_links - WHERE extension IN (?) + WHERE extension IN (:file_extensions) UNION SELECT post_uploads.post_id FROM uploads JOIN post_uploads ON post_uploads.upload_id = uploads.id - WHERE lower(uploads.extension) IN (?) - )", file_extensions, file_extensions) + WHERE lower(uploads.extension) IN (:file_extensions) + )", {file_extensions: file_extensions}) end private diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index 7faf1bac437..c09e3f8d436 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -705,21 +705,19 @@ describe Search do end it "can find posts which contains filetypes" do - # Must be posts with real images post1 = Fabricate(:post, - raw: "https://www.discourse.org/a/img/favicon.png") + raw: "http://example.com/image.png") post2 = Fabricate(:post, raw: "Discourse logo\n"\ - "https://www.discourse.org/a/img/favicon.png\n"\ - "https://www.discourse.org/a/img/trust-1x.jpg") - post_with_upload = Fabricate(:post) - post_with_upload.uploads = [Fabricate(:upload)] + "http://example.com/logo.png\n"\ + "http://example.com/vector_image.svg") + post_with_upload = Fabricate(:post, uploads: [Fabricate(:upload)]) Fabricate(:post) TopicLink.extract_from(post1) TopicLink.extract_from(post2) - expect(Search.execute('filetype:jpg').posts.map(&:id)).to eq([post2.id]) + expect(Search.execute('filetype:svg').posts).to eq([post2]) expect(Search.execute('filetype:png').posts.map(&:id)).to contain_exactly(post1.id, post2.id, post_with_upload.id) expect(Search.execute('logo filetype:png').posts.map(&:id)).to eq([post2.id]) end From c29b7aa65d0f456903d7b430ac138f6d18b6d0e2 Mon Sep 17 00:00:00 2001 From: awesomerobot Date: Sun, 11 Jun 2017 22:20:14 -0400 Subject: [PATCH 015/279] initial pass at color simplification --- .../stylesheets/common/admin/admin_base.scss | 68 +++++++++---------- .../stylesheets/common/admin/customize.scss | 3 +- .../stylesheets/common/base/_topic-list.scss | 14 ++-- app/assets/stylesheets/common/base/alert.scss | 6 +- .../stylesheets/common/base/colorpicker.scss | 2 +- .../stylesheets/common/base/combobox.scss | 6 +- .../stylesheets/common/base/compose.scss | 18 ++--- .../stylesheets/common/base/directory.scss | 10 +-- .../stylesheets/common/base/discourse.scss | 12 ++-- app/assets/stylesheets/common/base/group.scss | 12 ++-- .../stylesheets/common/base/groups.scss | 6 +- .../stylesheets/common/base/header.scss | 12 ++-- .../stylesheets/common/base/lightbox.scss | 2 +- .../stylesheets/common/base/menu-panel.scss | 14 ++-- app/assets/stylesheets/common/base/modal.scss | 16 ++--- .../stylesheets/common/base/onebox.scss | 2 +- .../stylesheets/common/base/search.scss | 4 +- .../common/base/topic-admin-menu.scss | 2 +- .../stylesheets/common/base/topic-post.scss | 18 ++--- app/assets/stylesheets/common/base/topic.scss | 6 +- .../stylesheets/common/base/user-badges.scss | 8 +-- app/assets/stylesheets/common/base/user.scss | 6 +- .../stylesheets/common/components/badges.scss | 12 ++-- .../common/components/buttons.scss | 6 +- .../stylesheets/common/components/navs.scss | 6 +- app/assets/stylesheets/common/d-editor.scss | 12 ++-- .../stylesheets/common/foundation/base.scss | 2 +- .../stylesheets/common/foundation/mixins.scss | 2 +- .../common/foundation/variables.scss | 30 ++++++++ app/assets/stylesheets/common/input_tip.scss | 2 +- .../stylesheets/common/topic-entrance.scss | 2 +- .../stylesheets/desktop/category-list.scss | 4 +- app/assets/stylesheets/desktop/compose.scss | 26 +++---- app/assets/stylesheets/desktop/discourse.scss | 14 ++-- app/assets/stylesheets/desktop/group.scss | 2 +- app/assets/stylesheets/desktop/history.scss | 8 +-- app/assets/stylesheets/desktop/modal.scss | 2 +- .../stylesheets/desktop/queued-posts.scss | 3 +- .../stylesheets/desktop/topic-list.scss | 4 +- .../stylesheets/desktop/topic-post.scss | 40 +++++------ app/assets/stylesheets/desktop/topic.scss | 10 +-- app/assets/stylesheets/desktop/user-card.scss | 2 +- app/assets/stylesheets/desktop/user.scss | 24 +++---- app/assets/stylesheets/embed.scss | 8 +-- app/assets/stylesheets/mobile/compose.scss | 8 +-- app/assets/stylesheets/mobile/directory.scss | 6 +- app/assets/stylesheets/mobile/discourse.scss | 4 +- app/assets/stylesheets/mobile/history.scss | 2 +- app/assets/stylesheets/mobile/topic-list.scss | 8 +-- app/assets/stylesheets/mobile/topic-post.scss | 16 ++--- app/assets/stylesheets/mobile/topic.scss | 10 +-- app/assets/stylesheets/mobile/user.scss | 20 +++--- app/assets/stylesheets/vendor/pikaday.scss | 20 +++--- 53 files changed, 296 insertions(+), 266 deletions(-) diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss index a25115a6912..9a6107139f8 100644 --- a/app/assets/stylesheets/common/admin/admin_base.scss +++ b/app/assets/stylesheets/common/admin/admin_base.scss @@ -36,8 +36,8 @@ $mobile-breakpoint: 700px; tr {text-align: left;} td, th {padding: 8px;} td { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; + border-top: 1px solid $primary-low; } th { text-align: left; @@ -94,11 +94,11 @@ td.flaggers td { .site-text { cursor: pointer; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; margin-bottom: 0.5em; &.overridden { - background-color: dark-light-diff($highlight, $secondary, 50%, -60%); + background-color: $highlight-medium; } h3 { @@ -112,7 +112,7 @@ td.flaggers td { .site-text-value { margin: 0.5em 5em 0.5em 0; max-height: 100px; - color: dark-light-diff($primary, $secondary, 40%, -10%); + color: $primary-medium; } } @@ -136,7 +136,7 @@ td.flaggers td { font-size: 0.857em; float: right; margin-right: 10px; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; padding: 2px 5px; border-radius: 5px; color: $primary; @@ -222,16 +222,16 @@ td.flaggers td { } .admin-controls { - background-color: dark-light-diff($primary, $secondary, 90%, -65%); + background-color: $primary-low; padding: 10px 10px 3px 0; @include clearfix; .nav.nav-pills { li.active { a { - border-color: dark-light-diff($primary, $secondary, 90%, -90%); - background-color: dark-light-diff($primary, $secondary, 40%, -10%); + border-color: $primary-low; + background-color: $primary-medium; &:hover { - background-color: dark-light-diff($primary, $secondary, 40%, -10%); + background-color: $primary-medium; } } } @@ -385,7 +385,7 @@ td.flaggers td { // Todo: set this properly - it needs to be >= the menu height min-height: 875px; margin-left: 0; - border-left: solid 1px dark-light-diff($primary, $secondary, 90%, -60%); + border-left: solid 1px $primary-low; padding: 30px 0 30px 30px; @media (max-width: $mobile-breakpoint) { padding: 30px 0; @@ -464,7 +464,7 @@ td.flaggers td { } padding: 1px; background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; border-radius: 3px; box-shadow: inset 0 1px 1px rgba(51, 51, 51, 0.3); transition: border linear 0.2s, box-shadow linear 0.2s; @@ -521,7 +521,7 @@ td.flaggers td { .setting.overridden.string { input[type=text] { - background-color: dark-light-diff($highlight, $secondary, 50%, -60%); + background-color: $highlight-medium; } } } @@ -532,7 +532,7 @@ section.details { color: $primary; padding: 5px 10px; margin: 30px 0 5px 0; - border-bottom: 5px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 5px solid $primary-low; } } @@ -575,7 +575,7 @@ section.details { &.highlight-danger { background-color: scale-color($danger, $lightness: 50%); } - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; &:before, &:after { display: table; content: ""; @@ -695,14 +695,14 @@ section.details { font-size: 1em; line-height: 16px; padding: 4px; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } .badge-query-plan { font-size: 0.857em; line-height: 13px; padding: 4px; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } .count-warning { @@ -765,8 +765,8 @@ section.details { background-color: scale-color($danger, $lightness: 70%); } - .message { background-color: dark-light-diff($highlight, $secondary, 50%, -70%); } - .message:hover { background-color: dark-light-diff($highlight, $secondary, 60%, -60%); } + .message { background-color: $highlight-medium; } + .message:hover { background-color: $highlight-low; } .flagged-post-avatar { margin-right: 10px; @@ -901,7 +901,7 @@ table.api-keys { th { font-weight: normal; text-align: center; - background: dark-light-diff($primary, $secondary, 80%, -65%); + background: $primary-low; } th.title { text-align: left; @@ -951,7 +951,7 @@ table.api-keys { } &.detected-problems { - background: dark-light-diff($primary, $secondary, 90%, -75%); + background: $primary-low; margin-bottom: 20px; .look-here { @@ -976,7 +976,7 @@ table.api-keys { text-align: right; } .btn { - background: dark-light-diff($primary, $secondary, 80%, -85%); + background: $primary-low; } ul { margin-left: 0; @@ -1026,7 +1026,7 @@ table.api-keys { } .commits-widget { - border: solid 1px dark-light-diff($primary, $secondary, 90%, -60%); + border: solid 1px $primary-low; height: 180px; margin-bottom: 36px; @@ -1049,7 +1049,7 @@ table.api-keys { color: $primary; font-weight: bold; height: 30px; - background: dark-light-diff($primary, $secondary, 80%, -75%); + background: $primary-low; cursor: pointer; h1 { @@ -1072,7 +1072,7 @@ table.api-keys { @extend .clearfix; line-height: 1.0em; padding: 6px 8px; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; .left { float: left; } @@ -1082,7 +1082,7 @@ table.api-keys { img { margin-top: 2px; - border: solid 1px dark-light-diff($primary, $secondary, 90%, -60%); + border: solid 1px $primary-low; padding: 2px; background-color: $secondary; } @@ -1113,11 +1113,11 @@ table.api-keys { width: 6px; } ::-webkit-scrollbar-thumb { - background: dark-light-diff($primary, $secondary, 90%, -75%); + background: $primary-low; -webkit-border-radius: 3px; } ::-webkit-scrollbar-track { - border-left: solid 1px dark-light-diff($primary, $secondary, 90%, -60%); + border-left: solid 1px $primary-low; } } @@ -1292,7 +1292,7 @@ table.api-keys { color: $primary; &:hover { color: $primary; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } @@ -1322,7 +1322,7 @@ table.api-keys { .heading-container { width: 100%; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } .col.heading { font-weight: bold; @@ -1338,7 +1338,7 @@ table.api-keys { .ember-list-item-view { width: 100%; - border-top: solid 1px dark-light-diff($primary, $secondary, 90%, -60%); + border-top: solid 1px $primary-low; } } @@ -1528,7 +1528,7 @@ tr.not-activated { .user-field { padding: 10px; margin-bottom: 10px; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; .form-display { width: 25%; @@ -1918,11 +1918,11 @@ table#user-badges { .dbox20 { background: dark-light-diff($primary, $secondary, 20%, -20%); } .dbox30 { background: dark-light-diff($primary, $secondary, 30%, -30%); } .dbox40 { background: dark-light-diff($primary, $secondary, 40%, -40%); } -.dbox50 { background: dark-light-diff($primary, $secondary, 50%, -50%); } +.dbox50 { background: blend-primary-secondary(50%); } .dbox60 { background: dark-light-diff($primary, $secondary, 60%, -60%); } .dbox70 { background: dark-light-diff($primary, $secondary, 70%, -70%); } .dbox80 { background: dark-light-diff($primary, $secondary, 80%, -80%); } -.dbox90 { background: dark-light-diff($primary, $secondary, 90%, -90%); } +.dbox90 { background: $primary-low; } .dbox100 { background: dark-light-diff($primary, $secondary, 100%, -100%); } .dbox5 { background: dark-light-diff($primary, $secondary, 5%, -5%); } .dbox15 { background: dark-light-diff($primary, $secondary, 15%, -15%); } diff --git a/app/assets/stylesheets/common/admin/customize.scss b/app/assets/stylesheets/common/admin/customize.scss index 9a62dcff919..b550f65b3fb 100644 --- a/app/assets/stylesheets/common/admin/customize.scss +++ b/app/assets/stylesheets/common/admin/customize.scss @@ -10,7 +10,7 @@ .field-error { margin-top: 10px; margin-bottom: 10px; - background-color: dark-light-diff($quaternary, $secondary, 70%, -70%); + background-color: $quaternary-low; padding: 5px; } @@ -210,4 +210,3 @@ margin-top: 20px; } } - diff --git a/app/assets/stylesheets/common/base/_topic-list.scss b/app/assets/stylesheets/common/base/_topic-list.scss index cb1bccb1fc9..6a202efceab 100644 --- a/app/assets/stylesheets/common/base/_topic-list.scss +++ b/app/assets/stylesheets/common/base/_topic-list.scss @@ -16,8 +16,8 @@ } } -html.anon .topic-list a.title:visited:not(.badge-notification) {color: dark-light-diff($primary, $secondary, 45%, -30%);} -.topic-list a.title.visited:not(.badge-notification) {color: dark-light-diff($primary, $secondary, 45%, -30%);} +html.anon .topic-list a.title:visited:not(.badge-notification) {color: $primary-medium; } +.topic-list a.title.visited:not(.badge-notification) {color: $primary-medium; } .topic-list { width: 100%; @@ -28,7 +28,7 @@ html.anon .topic-list a.title:visited:not(.badge-notification) {color: dark-ligh vertical-align: top; margin-top: 2px; } - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-bottom: 1px solid $primary-low; &.last-visit { border-bottom: none; @@ -58,7 +58,7 @@ html.anon .topic-list a.title:visited:not(.badge-notification) {color: dark-ligh } > tbody > tr:first-of-type { - border-top: 3px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-top: 3px solid $primary-low; } th, @@ -238,7 +238,7 @@ ol.category-breadcrumb { overflow-x: hidden; overflow-y: auto; position: absolute; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; background-color: $secondary; z-index: 100; @@ -300,7 +300,7 @@ ol.category-breadcrumb { @include unselectable; font-size: 1.2em; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; padding: 5px; background: $secondary; position: absolute; @@ -326,7 +326,7 @@ ol.category-breadcrumb { font-size: 0.8em; } &:hover { - background-color: dark-light-diff($highlight, $secondary, 50%, -70%); + background-color: $highlight-medium; } } } diff --git a/app/assets/stylesheets/common/base/alert.scss b/app/assets/stylesheets/common/base/alert.scss index 2afb3d10ed2..892151a3b26 100644 --- a/app/assets/stylesheets/common/base/alert.scss +++ b/app/assets/stylesheets/common/base/alert.scss @@ -30,15 +30,15 @@ -webkit-appearance: none; } &.alert-success { - background-color: dark-light-diff($success, $secondary, 50%, -60%); + background-color: $success-low; color: $primary; } &.alert-error { - background-color: rgba(dark-light-diff($danger, $secondary, 50%, -60%), .5); + background-color: rgba($danger-low, .5); color: $primary; } &.alert-info { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; color: $primary; &.clickable { color: $tertiary; diff --git a/app/assets/stylesheets/common/base/colorpicker.scss b/app/assets/stylesheets/common/base/colorpicker.scss index 6bcf8ae659d..83f29f78537 100644 --- a/app/assets/stylesheets/common/base/colorpicker.scss +++ b/app/assets/stylesheets/common/base/colorpicker.scss @@ -18,7 +18,7 @@ max-width: 300px; .colorpicker { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; margin-right: 2px; width: 16px; height: 16px; diff --git a/app/assets/stylesheets/common/base/combobox.scss b/app/assets/stylesheets/common/base/combobox.scss index cd9f44b52ca..e9c2fcda7b4 100644 --- a/app/assets/stylesheets/common/base/combobox.scss +++ b/app/assets/stylesheets/common/base/combobox.scss @@ -1,5 +1,5 @@ .select2-results .select2-highlighted { - background: dark-light-diff($highlight, $secondary, 50%, -80%); + background: $highlight-medium; color: $primary; } @@ -36,7 +36,7 @@ .select2-container { border-radius: 3px; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; min-width: 200px; &.select2-dropdown-open { @@ -71,7 +71,7 @@ border-color: $tertiary; } .select2-drop { - color: dark-light-diff($primary, $secondary, -50%, 50%); + color: $primary; } .select2-drop-active { border: 1px solid $tertiary; diff --git a/app/assets/stylesheets/common/base/compose.scss b/app/assets/stylesheets/common/base/compose.scss index 9f86c23d94f..d0079f72346 100644 --- a/app/assets/stylesheets/common/base/compose.scss +++ b/app/assets/stylesheets/common/base/compose.scss @@ -3,7 +3,7 @@ position: absolute; width: 240px; background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; ul { list-style: none; padding: 0; @@ -15,7 +15,7 @@ padding: 0 2px; } - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; a { padding: 5px; @@ -32,10 +32,10 @@ vertical-align: middle; } &.selected { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; } @include hover { - background-color: dark-light-diff($highlight, $secondary, 90%, -80%); + background-color: $highlight-low; text-decoration: none; } } @@ -52,11 +52,13 @@ .d-editor-button-bar { -moz-box-sizing: border-box; box-sizing: border-box; - margin: 0px; padding: 5px; - border-bottom: 2px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 2px solid $primary-low; height: 33px; + .btn:hover { + color: $primary-low; + } } textarea { @@ -88,7 +90,7 @@ div.ac-wrap div.item a.remove, .remove-link { border-radius: 12px; width: 10px; display: inline-block; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; &:hover { background-color: scale-color($danger, $lightness: 75%); border: 1px solid scale-color($danger, $lightness: 30%); @@ -101,7 +103,7 @@ div.ac-wrap { overflow: auto; max-height: 150px; background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; padding: 5px 4px 1px 4px; div.item { float: left; diff --git a/app/assets/stylesheets/common/base/directory.scss b/app/assets/stylesheets/common/base/directory.scss index 6af69033aa6..b0c7ae08983 100644 --- a/app/assets/stylesheets/common/base/directory.scss +++ b/app/assets/stylesheets/common/base/directory.scss @@ -12,7 +12,7 @@ float: right; } .total-rows { - color: dark-light-diff($primary, $secondary, 50%, -50%); + color: blend-primary-secondary(50%); text-align: right; } .spinner { @@ -26,17 +26,17 @@ td, th { padding: 0.5em; text-align: left; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; .number, .time-read { font-size: 1.4em; - color: dark-light-diff($primary, $secondary, 50%, -20%); + color: $primary-medium; } } tr.me { td { - background-color: dark-light-diff($highlight, $secondary, 70%, -80%); + background-color: $highlight-low; .username a, .name, .title, .number, .time-read { color: dark-light-choose(scale-color($highlight, $lightness: -50%), scale-color($highlight, $lightness: 50%)); @@ -58,7 +58,7 @@ } &:hover { - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } } } diff --git a/app/assets/stylesheets/common/base/discourse.scss b/app/assets/stylesheets/common/base/discourse.scss index 1aeaf7cfe3a..1960f4b6033 100644 --- a/app/assets/stylesheets/common/base/discourse.scss +++ b/app/assets/stylesheets/common/base/discourse.scss @@ -314,7 +314,7 @@ body { animation: rotate-forever 1s infinite linear; height: 30px; width: 30px; - border: 4px solid dark-light-diff($primary, $secondary, 50%, -50%); + border: 4px solid blend-primary-secondary(50%); border-right-color: transparent; border-radius: 50%; @@ -329,7 +329,7 @@ body { .content-list { h3 { - color: dark-light-diff($primary, $secondary, 50%, -20%); + color: $primary-medium; font-size: 1.071em; padding-left: 5px; margin-bottom: 10px; @@ -340,10 +340,10 @@ body { margin: 0; li:first-of-type { - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; } li { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } li a { @@ -352,7 +352,7 @@ body { color: $primary; &:hover { - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; color: $primary; } @@ -380,7 +380,7 @@ span.relative-date { @keyframes background-fade-highlight { 0% { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; } 100% { background-color: transparent; diff --git a/app/assets/stylesheets/common/base/group.scss b/app/assets/stylesheets/common/base/group.scss index 5287a777c3b..6c55db08f14 100644 --- a/app/assets/stylesheets/common/base/group.scss +++ b/app/assets/stylesheets/common/base/group.scss @@ -51,7 +51,7 @@ table.group-logs { width: 100%; th, tr { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } th { @@ -67,7 +67,7 @@ table.group-logs { cursor: pointer; i { - color: dark-light-diff($primary, $secondary, 50%, -50%); + color: blend-primary-secondary(50%); } } } @@ -77,7 +77,7 @@ table.group-members { table-layout: fixed; tr { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } th:first-child { @@ -90,7 +90,7 @@ table.group-members { } th { - border-bottom: 3px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 3px solid $primary-low; text-align: center; padding: 5px 0px 5px 5px; color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); @@ -104,7 +104,7 @@ table.group-members { &:hover { cursor: pointer; - background-color: dark-light-diff($primary, $secondary, 90%, -75%); + background-color: $primary-low; } } @@ -119,7 +119,7 @@ table.group-members { td { text-align: center; - color: dark-light-diff($primary, $secondary, 50%, -50%); + color: blend-primary-secondary(50%); padding: 0.8em 0; } } diff --git a/app/assets/stylesheets/common/base/groups.scss b/app/assets/stylesheets/common/base/groups.scss index f40697b01c2..6dae404db0d 100644 --- a/app/assets/stylesheets/common/base/groups.scss +++ b/app/assets/stylesheets/common/base/groups.scss @@ -8,16 +8,16 @@ width: 100%; th { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; padding: 5px 0px; text-align: left; } tr { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; td { - color: dark-light-diff($primary, $secondary, 50%, -50%); + color: blend-primary-secondary(50%); padding: 0.8em 0; } diff --git a/app/assets/stylesheets/common/base/header.scss b/app/assets/stylesheets/common/base/header.scss index 19917997670..4a674e8d1f9 100644 --- a/app/assets/stylesheets/common/base/header.scss +++ b/app/assets/stylesheets/common/base/header.scss @@ -69,14 +69,14 @@ &:hover { color: $primary; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; border-top: 1px solid transparent; border-left: 1px solid transparent; border-right: 1px solid transparent; } &:active { color: $primary; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } } .drop-down-visible & { @@ -85,9 +85,9 @@ color: #7b7b7b; background-color: $secondary; cursor: default; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); - border-left: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); - border-right: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; + border-left: 1px solid $primary-low; + border-right: 1px solid $primary-low; .badge-notification { top: -10px; @@ -147,7 +147,7 @@ .highlight-strong { - background-color: dark-light-diff($highlight, $secondary, 40%, -45%); + background-color: $highlight-medium; } .search-highlight { diff --git a/app/assets/stylesheets/common/base/lightbox.scss b/app/assets/stylesheets/common/base/lightbox.scss index 61a93372f28..2570034d60d 100644 --- a/app/assets/stylesheets/common/base/lightbox.scss +++ b/app/assets/stylesheets/common/base/lightbox.scss @@ -42,7 +42,7 @@ .informations { margin: 6px; padding-right: 20px; - color: dark-light-diff($primary, $secondary, 50%, -50%); + color: blend-primary-secondary(50%); font-size: 1em; } diff --git a/app/assets/stylesheets/common/base/menu-panel.scss b/app/assets/stylesheets/common/base/menu-panel.scss index deb79628d5c..0e19a8a1175 100644 --- a/app/assets/stylesheets/common/base/menu-panel.scss +++ b/app/assets/stylesheets/common/base/menu-panel.scss @@ -18,7 +18,7 @@ } .menu-panel { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; box-shadow: 0 2px 2px rgba(0,0,0, .25); background-color: $secondary; z-index: 1100; @@ -60,7 +60,7 @@ padding: 0.25em 0.5em; display: block; &:hover { - background-color: dark-light-diff($highlight, $secondary, 50%, -55%); + background-color: $highlight-medium; } } @@ -191,7 +191,7 @@ } &:hover a:not(.badge-notification) { - background-color: dark-light-diff($highlight, $secondary, 50%, -55%); + background-color: $highlight-medium; } button {margin-left: 5px;} @@ -210,7 +210,7 @@ .fa { color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); } .icon { color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%)); } li { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; padding: 0.25em 0.5em; i { float: left; @@ -218,7 +218,7 @@ padding-top: 2px; } span { color: $primary; } - &:hover { background-color: dark-light-diff($highlight, $secondary, 50%, -55%); } + &:hover { background-color: $highlight-medium; } a { padding: 0; } p { margin: 0; @@ -256,7 +256,7 @@ .notifications .logout { padding: 0.25em; &:hover { - background-color: dark-light-diff($highlight, $secondary, 50%, -55%); + background-color: $highlight-medium; } } @@ -269,7 +269,7 @@ div.menu-links-header { display: table-row; } a:hover { - background-color: dark-light-diff($highlight, $secondary, 50%, -55%); + background-color: $highlight-medium; } a { padding: 0.5em; diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index c69d4a40583..89259bf3ec1 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -13,11 +13,11 @@ .input-hint-text { margin-left: 0.5em; - color: dark-light-diff($secondary, $primary, 30%, -35%); + color: $secondary-medium; } .modal-header { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } .modal-backdrop { @@ -96,7 +96,7 @@ } .modal-footer { padding: 14px 15px 15px; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; } .modal-footer:before, .modal-footer:after { @@ -118,11 +118,11 @@ .modal { .nav { padding: 10px 30px 10px 15px; - background-color: dark-light-diff($secondary, $primary, 10%, -15%); + background-color: $secondary; li > a { font-size: 1em; } - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } @@ -230,7 +230,7 @@ font-weight: normal; } &.btn-reply-here { - background: dark-light-diff($primary, $secondary, 90%, -60%); + background: $primary-low; text-shadow: none; color: $primary; } @@ -351,7 +351,7 @@ font-weight: bold; } &:focus { - outline: 2px solid dark-light-diff($primary, $secondary, 90%, -60%); + outline: 2px solid $primary-low; } } .incoming-email-tabs { @@ -362,7 +362,7 @@ textarea, .incoming-email-html-part { height: 95%; border: none; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; padding-top: 10px; } textarea { diff --git a/app/assets/stylesheets/common/base/onebox.scss b/app/assets/stylesheets/common/base/onebox.scss index 5b718047c75..86e505e6226 100644 --- a/app/assets/stylesheets/common/base/onebox.scss +++ b/app/assets/stylesheets/common/base/onebox.scss @@ -89,7 +89,7 @@ a.loading-onebox { } aside.onebox { - border: 5px solid dark-light-diff($primary, $secondary, 90%, -85%); + border: 5px solid $primary-low; padding: 12px 25px 12px 12px; font-size: 1em; diff --git a/app/assets/stylesheets/common/base/search.scss b/app/assets/stylesheets/common/base/search.scss index 7fa038db9c1..eeb82c5d045 100644 --- a/app/assets/stylesheets/common/base/search.scss +++ b/app/assets/stylesheets/common/base/search.scss @@ -108,7 +108,7 @@ } .search-advanced-options { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -75%); + border: 1px solid $primary-low; padding: 10px; .control-group.pull-left { @@ -147,7 +147,7 @@ } margin: 10px 0 15px; max-width: 780px; - border-bottom: 3px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-bottom: 3px solid $primary-low; width: 100%; .sort-by { .desc { diff --git a/app/assets/stylesheets/common/base/topic-admin-menu.scss b/app/assets/stylesheets/common/base/topic-admin-menu.scss index acabe8664a0..0abb6b52057 100644 --- a/app/assets/stylesheets/common/base/topic-admin-menu.scss +++ b/app/assets/stylesheets/common/base/topic-admin-menu.scss @@ -12,7 +12,7 @@ background-color: $secondary; width: 205px; padding: 10px; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; z-index: 999; ul { diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index aa739f782ab..f0f8c5ddf4e 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -1,6 +1,6 @@ .placeholder-avatar { display: inline-block; - background-color: dark-light-diff($primary, $secondary, 90%, -75%); + background-color: $primary-low; width: 45px; height: 45px; border-radius: 50%; @@ -8,7 +8,7 @@ .placeholder-text { display: inline-block; - background-color: dark-light-diff($primary, $secondary, 90%, -75%); + background-color: $primary-low; width: 100%; height: 1.5em; margin-bottom: 0.6em; @@ -92,7 +92,7 @@ aside.quote { } .cooked .highlight { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; padding: 2px; margin: -2px; } @@ -137,7 +137,7 @@ aside.quote { .quote-button { display: none; position: absolute; - background-color: dark-light-diff($primary, $secondary, 50%, -50%); + background-color: blend-primary-secondary(50%); color: dark-light-choose($secondary, $primary); padding: 10px; z-index: 401; @@ -149,7 +149,7 @@ aside.quote { } &:hover { - background-color: dark-light-diff($primary, $secondary, 40%, -40%); + background-color: $primary-medium; cursor: pointer; } } @@ -273,7 +273,7 @@ pre { kbd { background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; border-radius: 3px; box-shadow: 0 1px 0 rgba(0,0,0, .8); color: $primary; @@ -395,15 +395,15 @@ table.md-table { .topic-body { .cooked { font-style: italic; - color: dark-light-diff($primary, $secondary, 55%, -40%); + color: $primary-medium; } } } a.mention, a.mention-group { padding: 2px 4px; - color: dark-light-diff($primary, $secondary, 30%, -20%); - background: dark-light-diff($primary, $secondary, 95%, -60%); + color: $primary-medium; + background: $primary-low; border-radius: 8px; font-weight: bold; font-size: 0.93em; diff --git a/app/assets/stylesheets/common/base/topic.scss b/app/assets/stylesheets/common/base/topic.scss index 196aa05e2e7..0e9a19ba28e 100644 --- a/app/assets/stylesheets/common/base/topic.scss +++ b/app/assets/stylesheets/common/base/topic.scss @@ -66,7 +66,7 @@ .has-pending-posts { padding: 0.5em; - background-color: dark-light-diff($highlight, $secondary, 50%, -70%); + background-color: $highlight-medium; a[href] { float: right; } @@ -118,7 +118,7 @@ .post-links { margin-top: 1em; padding-top: 1em; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); + border-top: 1px solid $primary-low; } .expand-links { @@ -160,7 +160,7 @@ &:hover { color: $tertiary; i { - background: dark-light-diff($tertiary, $secondary, 85%, -65%); + background: $tertiary-low; } } } diff --git a/app/assets/stylesheets/common/base/user-badges.scss b/app/assets/stylesheets/common/base/user-badges.scss index 7c25c2652a0..7e98f3c2c08 100644 --- a/app/assets/stylesheets/common/base/user-badges.scss +++ b/app/assets/stylesheets/common/base/user-badges.scss @@ -2,7 +2,7 @@ .user-badge { padding: 3px 8px; color: $primary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); + border: 1px solid $primary-low; line-height: 19px; display: inline-block; background-color: $secondary; @@ -126,7 +126,7 @@ .badge-card { position: relative; display: inline-block; - background-color: dark-light-diff($primary, $secondary, 95%, -65%); + background-color: $primary-low; margin-right: 5px; margin-bottom: 10px; box-shadow: 1px 1px 3px rgba(0.0, 0.0, 0.0, 0.2); @@ -142,7 +142,7 @@ right: 5px; top: 5px; font-weight: bold; - color: dark-light-diff($primary, $secondary, 50%, -15%); + color: $primary-medium; font-size: 1.2em; } @@ -156,7 +156,7 @@ display: flex; align-items: center; justify-content: center; - background-color: dark-light-diff($primary, $secondary, 92%, -60%); + background-color: $primary-low; font-size: 3em; img { diff --git a/app/assets/stylesheets/common/base/user.scss b/app/assets/stylesheets/common/base/user.scss index 365fc9a3c83..b5a665dbf0d 100644 --- a/app/assets/stylesheets/common/base/user.scss +++ b/app/assets/stylesheets/common/base/user.scss @@ -236,7 +236,7 @@ } .label { - color: dark-light-diff($primary, $secondary, 50%, -50%); + color: blend-primary-secondary(50%); } } @@ -248,7 +248,7 @@ } li { - border-left: dark-light-diff($primary, $secondary, 90%, -65%) solid 2px; + border-left: $primary-low solid 2px; padding: 5px 8px; margin: 10px 0; } @@ -288,7 +288,7 @@ and (max-width : 600px) { } .user-preferences .tags .select2-container-multi { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; width: 540px; border-radius: 0; .select2-choices { diff --git a/app/assets/stylesheets/common/components/badges.scss b/app/assets/stylesheets/common/components/badges.scss index 8273d97c8b4..c160fc53538 100644 --- a/app/assets/stylesheets/common/components/badges.scss +++ b/app/assets/stylesheets/common/components/badges.scss @@ -169,12 +169,12 @@ } li.bar>.badge-category { - background: dark-light-diff($primary, $secondary, 90%, -65%) !important; + background: $primary-low !important; color: $primary !important; } li.bullet>.badge-category { - background: dark-light-diff($primary, $secondary, 90%, -65%) !important; + background: $primary-low !important; color: $primary !important; .badge-category-bg { @@ -279,9 +279,9 @@ &.clicks { font-weight: normal; - background-color: dark-light-diff($primary, $secondary, 88%, -60%); + background-color: $primary-low; top: -1px; - color: dark-light-diff($primary, $secondary, 40%, -20%); + color: $primary-medium; position: relative; margin-left: 2px; border: none; @@ -308,8 +308,8 @@ padding: 4px 5px 2px 5px; color: $primary; text-shadow: 0 1px 0 rgba($primary, 0.1); - background-color: dark-light-diff($primary, $secondary, 90%, -65%); - border-color: dark-light-diff($primary, $secondary, 90%, -65%); + background-color: $primary-low; + border-color: $primary-low; font-size: 0.857em; box-shadow: inset 0 1px 0 rgba(0,0,0, 0.22); } diff --git a/app/assets/stylesheets/common/components/buttons.scss b/app/assets/stylesheets/common/components/buttons.scss index a1a3f4bc6db..f94de4060d9 100644 --- a/app/assets/stylesheets/common/components/buttons.scss +++ b/app/assets/stylesheets/common/components/buttons.scss @@ -46,17 +46,17 @@ border: none; color: $primary; font-weight: normal; - background: dark-light-diff($primary, $secondary, 90%, -65%); + background: $primary-low; &[href] { color: $primary; } &:hover { - background: dark-light-diff($primary, $secondary, 65%, -75%); + background: $primary-medium; color: $secondary; } &[disabled], &.disabled { - background: dark-light-diff($primary, $secondary, 90%, -60%); + background: $primary-low; &:hover { color: dark-light-choose(scale-color($primary, $lightness: 70%), scale-color($secondary, $lightness: 30%)); } cursor: not-allowed; } diff --git a/app/assets/stylesheets/common/components/navs.scss b/app/assets/stylesheets/common/components/navs.scss index 59a34aad62c..6beae3c5917 100644 --- a/app/assets/stylesheets/common/components/navs.scss +++ b/app/assets/stylesheets/common/components/navs.scss @@ -32,7 +32,7 @@ transition: background .15s; &:hover { color: $quaternary; - background-color: dark-light-diff($quaternary, $secondary, 70%, -70%); + background-color: $quaternary-low; } } &.active > a, > a.active { @@ -49,9 +49,9 @@ @extend %nav; padding: 0; overflow: hidden; - background: dark-light-diff($primary, $secondary, 90%, -75%); + background: $primary-low; li { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 80%, -60%); + border-bottom: 1px solid $primary-low; position: relative; &:last-of-type { border-bottom: 0; diff --git a/app/assets/stylesheets/common/d-editor.scss b/app/assets/stylesheets/common/d-editor.scss index 8d3d6183902..b1a97021b0d 100644 --- a/app/assets/stylesheets/common/d-editor.scss +++ b/app/assets/stylesheets/common/d-editor.scss @@ -1,5 +1,5 @@ .d-editor { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; } .d-editor-container { @@ -22,7 +22,7 @@ min-width: 400px; position: absolute; background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; padding: 1em; top: 25px; @@ -71,7 +71,7 @@ height: 20px; margin-right: 8px; margin-left: 5px; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; display: inline-block; float: left; } @@ -82,13 +82,13 @@ height: 200px; &:disabled { - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } } .d-editor-preview { color: $primary; - border: 1px dashed dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px dashed $primary-low; overflow: auto; cursor: default; margin-top: 8px; @@ -110,7 +110,7 @@ .composing-whisper { .d-editor-preview { font-style: italic; - color: dark-light-diff($primary, $secondary, 55%, -40%) !important; + color: $primary-medium !important; } } diff --git a/app/assets/stylesheets/common/foundation/base.scss b/app/assets/stylesheets/common/foundation/base.scss index 35b0418187d..651a2c01d0a 100644 --- a/app/assets/stylesheets/common/foundation/base.scss +++ b/app/assets/stylesheets/common/foundation/base.scss @@ -41,7 +41,7 @@ hr { height: 1px; margin: 1em 0; border: 0; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; padding: 0; } diff --git a/app/assets/stylesheets/common/foundation/mixins.scss b/app/assets/stylesheets/common/foundation/mixins.scss index f9c3ca2a5a0..ed55c8f5227 100644 --- a/app/assets/stylesheets/common/foundation/mixins.scss +++ b/app/assets/stylesheets/common/foundation/mixins.scss @@ -97,7 +97,7 @@ // Stuff we repeat @mixin post-aside { - border-left: 5px solid dark-light-diff($primary, $secondary, 90%, -85%); + border-left: 5px solid $primary-low; background-color: blend-primary-secondary(5%); } diff --git a/app/assets/stylesheets/common/foundation/variables.scss b/app/assets/stylesheets/common/foundation/variables.scss index 43eb44cdb2d..2d7c6186bbb 100644 --- a/app/assets/stylesheets/common/foundation/variables.scss +++ b/app/assets/stylesheets/common/foundation/variables.scss @@ -78,3 +78,33 @@ $base-font-family: Helvetica, Arial, sans-serif !default; @return $dark-theme-result; } } + +// standard color transformations, use these if possible, and add any new dark-light-diffs here + +//primary +$primary-low: dark-light-diff($primary, $secondary, 90%, -65%); +$primary-medium: dark-light-diff($primary, $secondary, 50%, -20%); + +//secondary +$secondary-low: dark-light-diff($secondary, $primary, 50%, -50%); +$secondary-medium: dark-light-diff($secondary, $primary, 30%, -35%); + +//tertiary +$tertiary-low: dark-light-diff($tertiary, $secondary, 85%, -65%); + +//quaternary +$quaternary-low: dark-light-diff($quaternary, $secondary, 70%, -70%); + +//highlight +$highlight-low: dark-light-diff($highlight, $secondary, 70%, -80%); +$highlight-medium: dark-light-diff($highlight, $secondary, 50%, -55%); + +//danger +$danger-low: dark-light-diff($danger, $secondary, 50%, -40%); +$danger-medium: dark-light-diff($danger, $secondary, 30%, -60%); + +//success +$success-low: dark-light-diff($success, $secondary, 50%, -60%); + +//love +$love-low: dark-light-diff($love, $secondary, 85%, -60%); diff --git a/app/assets/stylesheets/common/input_tip.scss b/app/assets/stylesheets/common/input_tip.scss index fae0176e2a7..5f02aeb1118 100644 --- a/app/assets/stylesheets/common/input_tip.scss +++ b/app/assets/stylesheets/common/input_tip.scss @@ -7,7 +7,7 @@ padding: 5px 10px; z-index: 101; &.bad { - background: dark-light-diff($danger, $secondary, 20%, -40%); + background: $danger-medium; color: white; box-shadow: 1px 1px 5px rgba(0,0,0, .7); } diff --git a/app/assets/stylesheets/common/topic-entrance.scss b/app/assets/stylesheets/common/topic-entrance.scss index 847edc46a86..6e9e1aa2099 100644 --- a/app/assets/stylesheets/common/topic-entrance.scss +++ b/app/assets/stylesheets/common/topic-entrance.scss @@ -1,6 +1,6 @@ #topic-entrance { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; padding: 5px; background: $secondary; box-shadow: 0 0px 2px rgba(0,0,0, .2); diff --git a/app/assets/stylesheets/desktop/category-list.scss b/app/assets/stylesheets/desktop/category-list.scss index d33120135f9..c76519a6f8f 100644 --- a/app/assets/stylesheets/desktop/category-list.scss +++ b/app/assets/stylesheets/desktop/category-list.scss @@ -90,9 +90,9 @@ tbody { tr { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-bottom: 1px solid $primary-low; &:first-of-type { - border-top: 3px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-top: 3px solid $primary-low; } } diff --git a/app/assets/stylesheets/desktop/compose.scss b/app/assets/stylesheets/desktop/compose.scss index c8aa5306ea0..b3fdf423bb8 100644 --- a/app/assets/stylesheets/desktop/compose.scss +++ b/app/assets/stylesheets/desktop/compose.scss @@ -36,14 +36,14 @@ padding: 10px; box-shadow: 3px 3px 3px rgba(0,0,0, 0.34); - background: dark-light-diff($highlight, $secondary, 50%, -80%); + background: $highlight-medium; &.urgent { - background: dark-light-diff($danger, $secondary, 50%, -40%); + background: $danger-low; } &.education-message { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; } h3 { @@ -79,17 +79,17 @@ } .custom-body { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; p { max-width: 98%; } } .similar-topics { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; a[href] { - color: dark-light-diff($primary, $secondary, -10%, 10%); + color: $primary-medium; } .posts-count { @@ -140,7 +140,7 @@ width: 100%; z-index: 999; height: 0; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; bottom: 0; font-size: 1em; position: fixed; @@ -184,7 +184,7 @@ &.draft { height: 40px !important; cursor: pointer; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; .draft-text { display: block; @@ -201,7 +201,7 @@ } &.saving { height: 40px !important; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; .saving-text { display: block; } @@ -299,7 +299,7 @@ margin-right: 10px; float: left; &:disabled { - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } } #topic-featured-link { @@ -308,14 +308,14 @@ width: 400px; } .d-editor-input:disabled { - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } .d-editor-input, .d-editor-preview { color: $primary; } .d-editor-preview { - border: 1px dashed dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px dashed $primary-low; overflow: auto; visibility: visible; cursor: default; @@ -353,7 +353,7 @@ .show-admin-options { vertical-align: top; margin-top: 8px; - background: dark-light-diff($primary, $secondary, 90%, -60%); + background: $primary-low; &:hover { color: $secondary; background: $primary; diff --git a/app/assets/stylesheets/desktop/discourse.scss b/app/assets/stylesheets/desktop/discourse.scss index 20e1ebc1ee6..aac66f0295a 100644 --- a/app/assets/stylesheets/desktop/discourse.scss +++ b/app/assets/stylesheets/desktop/discourse.scss @@ -31,7 +31,7 @@ body { } #main { a.star { - color: dark-light-diff($secondary, $primary, 80%, -20%); + color: $secondary-medium; &:before { font-family: "FontAwesome"; content: "\f005"; @@ -213,14 +213,14 @@ body { width: 210px; height: auto; background-color:$secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; border-radius: 3px; box-shadow: inset 0 1px 1px rgba(0,0,0, .3); } input { &[type="text"], &[type="password"], &[type="datetime"], &[type="datetime-local"], &[type="date"], &[type="month"], &[type="time"], &[type="week"], &[type="number"], &[type="email"], &[type="url"], &[type="search"], &[type="tel"], &[type="color"] { background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; border-radius: 3px; box-shadow: inset 0 1px 1px rgba(0,0,0, .3); } @@ -244,7 +244,7 @@ body { select { width: 220px; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; &[multiple], &[size] { height: auto; } @@ -272,8 +272,8 @@ body { } input[disabled], select[disabled], textarea[disabled], input[readonly], select[readonly], textarea[readonly] { cursor: not-allowed; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); - border-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; + border-color: $primary-low; } input { &[type="radio"][disabled], &[type="checkbox"][disabled], &[type="radio"][readonly], &[type="checkbox"][readonly] { @@ -372,7 +372,7 @@ body { text-align: center; vertical-align: middle; background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; } .input-prepend .add-on, .input-append .add-on, .input-prepend .btn, .input-append .btn { margin-left: -1px; diff --git a/app/assets/stylesheets/desktop/group.scss b/app/assets/stylesheets/desktop/group.scss index 5c913eef7f3..5bd0b3b9e6b 100644 --- a/app/assets/stylesheets/desktop/group.scss +++ b/app/assets/stylesheets/desktop/group.scss @@ -48,7 +48,7 @@ } .group-edit { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; padding: 10px; .form-horizontal { diff --git a/app/assets/stylesheets/desktop/history.scss b/app/assets/stylesheets/desktop/history.scss index 858796f21b0..4519450e1aa 100644 --- a/app/assets/stylesheets/desktop/history.scss +++ b/app/assets/stylesheets/desktop/history.scss @@ -12,10 +12,10 @@ .btn[disabled] { cursor: not-allowed; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; } .btn-danger[disabled] { - background-color: dark-light-diff($danger, $secondary, 30%, -60%); + background-color: $danger-medium; } } #display-modes { @@ -25,7 +25,7 @@ .btn { background-color:inherit; - color: dark-light-diff($primary, $secondary, 50%, -50%); + color: blend-primary-secondary(50%); } .btn-primary { color: $primary; @@ -35,7 +35,7 @@ #revision-details { padding: 5px; margin-top: 10px; - border-bottom: 3px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 3px solid $primary-low; } #revisions { word-wrap: break-word; diff --git a/app/assets/stylesheets/desktop/modal.scss b/app/assets/stylesheets/desktop/modal.scss index c345acd0cd1..35b4f4d6f1c 100644 --- a/app/assets/stylesheets/desktop/modal.scss +++ b/app/assets/stylesheets/desktop/modal.scss @@ -16,7 +16,7 @@ height: auto; margin: -250px 0 0 -305px; background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; box-shadow: 0 3px 7px rgba(0,0,0, .8); background-clip: padding-box; diff --git a/app/assets/stylesheets/desktop/queued-posts.scss b/app/assets/stylesheets/desktop/queued-posts.scss index 6d306bae6ee..363eca2dc8a 100644 --- a/app/assets/stylesheets/desktop/queued-posts.scss +++ b/app/assets/stylesheets/desktop/queued-posts.scss @@ -31,7 +31,7 @@ } } .post-title { - color: dark-light-diff($primary, $secondary, 20%, -60%); + color: $primary-medium; font-weight: bold; .badge-wrapper { @@ -41,4 +41,3 @@ } } - diff --git a/app/assets/stylesheets/desktop/topic-list.scss b/app/assets/stylesheets/desktop/topic-list.scss index c59373c6edd..b9b8056b1db 100644 --- a/app/assets/stylesheets/desktop/topic-list.scss +++ b/app/assets/stylesheets/desktop/topic-list.scss @@ -63,7 +63,7 @@ padding: 0; background: transparent; &:hover { - color: dark-light-diff($primary, $secondary, 90%, -60%); + color: $primary-low; } } @@ -115,7 +115,7 @@ .sortable { cursor: pointer; &:hover { - background-color: dark-light-diff($primary, $secondary, 90%, -75%); + background-color: $primary-low; } @include unselectable; } diff --git a/app/assets/stylesheets/desktop/topic-post.scss b/app/assets/stylesheets/desktop/topic-post.scss index 871e42c0d7b..381c5d881ba 100644 --- a/app/assets/stylesheets/desktop/topic-post.scss +++ b/app/assets/stylesheets/desktop/topic-post.scss @@ -94,7 +94,7 @@ nav.post-controls { font-size: inherit; span.badge-posts {color: dark-light-choose(scale-color($primary, $lightness: 60%), scale-color($secondary, $lightness: 40%)); } &:hover { - background: dark-light-diff($primary, $secondary, 90%, -65%); + background: $primary-low; span.badge-posts {color: $primary;} } i { @@ -122,7 +122,7 @@ nav.post-controls { margin-left: 3px; &.d-hover { - background: dark-light-diff($primary, $secondary, 90%, -60%); + background: $primary-low; color: $primary; } @@ -144,7 +144,7 @@ nav.post-controls { &.like.d-hover { color: $love; - background: dark-light-diff($love, $secondary, 85%, -60%) + background: $love-low; } &.has-like {color: $love;} @@ -179,7 +179,7 @@ nav.post-controls { background-color: $secondary; width: 205px; padding: 10px; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; position: absolute; text-align: left; bottom: -2px; @@ -288,11 +288,11 @@ a.star { .topic-map { margin: 20px 0 0 0; background: blend-primary-secondary(5%); - border: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); + border: 1px solid $primary-low; border-top: none; // would cause double top border section { - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); + border-top: 1px solid $primary-low; } h3 { @@ -402,11 +402,11 @@ a.star { padding: 0 23px; color: dark-light-choose(scale-color($primary, $lightness: 60%), scale-color($secondary, $lightness: 40%)); background: blend-primary-secondary(5%); - border-left: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); + border-left: 1px solid $primary-low; + border-top: 1px solid $primary-low; &:hover { color: $primary; - background: dark-light-diff($primary, $secondary, 90%, -80%); + background: $primary-low; } &.collapsed { @@ -567,7 +567,7 @@ video { .moderator { .topic-body { - background-color: dark-light-diff($highlight, $secondary, 70%, -80%); + background-color: $highlight-low; } } @@ -617,7 +617,7 @@ blockquote { aside { .quote, .title, blockquote, .onebox, .onebox-result { background: blend-primary-secondary(5%); - border-left: 5px solid dark-light-diff($primary, $secondary, 90%, -65%); + border-left: 5px solid $primary-low; } aside.quote>blockquote, aside.quote>.title { @@ -637,12 +637,12 @@ $topic-avatar-width: 45px; float: left; position: relative; z-index: 2; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-top: 1px solid $primary-low; padding: 12px $topic-body-width-padding 15px $topic-body-width-padding; } .topic-avatar { - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-top: 1px solid $primary-low; padding-top: 15px; width: $topic-avatar-width; float: left; @@ -655,7 +655,7 @@ $topic-avatar-width: 45px; .small-action { max-width: 755px; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-top: 1px solid $primary-low; } .small-action.deleted { @@ -698,7 +698,7 @@ $topic-avatar-width: 45px; margin: 1px 0 0; list-style: none; background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; box-shadow: 0 1px 5px rgba(0,0,0, .4); background-clip: padding-box; span { @@ -730,7 +730,7 @@ $topic-avatar-width: 45px; .dropdown-menu .active > a:hover { color: $primary; text-decoration: none; - background-color: dark-light-diff($highlight, $secondary, 50%, -70%); + background-color: $highlight-medium; } @@ -738,7 +738,7 @@ $topic-avatar-width: 45px; .dropdown-menu .disabled > a:hover { text-decoration: none; color: $primary; - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; cursor: default; } @@ -757,7 +757,7 @@ $topic-avatar-width: 45px; width: 200px; position: fixed; z-index: 1000; - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; border: 1px solid $tertiary; padding: 5px; margin-bottom: 5px; @@ -876,7 +876,7 @@ a.attachment:before { display: block; position: absolute; left: 767px; - color: rgba(dark-light-diff($primary, $secondary, 90%, -65%) , .8); + color: rgba($primary-low, .8); font: 6.429em/1 FontAwesome; content: "\f014"; z-index: -5; @@ -911,7 +911,7 @@ a.attachment:before { } span.highlighted { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; } .username.new-user a { diff --git a/app/assets/stylesheets/desktop/topic.scss b/app/assets/stylesheets/desktop/topic.scss index bd4b0c9f5f0..17cd74d1bdf 100644 --- a/app/assets/stylesheets/desktop/topic.scss +++ b/app/assets/stylesheets/desktop/topic.scss @@ -80,7 +80,7 @@ } .topic-status-info { - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-top: 1px solid $primary-low; padding-top: 10px; height: 20px; max-width: 757px; @@ -99,7 +99,7 @@ } #topic-progress-expanded { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; padding: 5px; background: $secondary; @@ -149,7 +149,7 @@ } background-color: $secondary; color: $tertiary; - border: 1px solid dark-light-diff($tertiary, $secondary, 85%, -65%); + border: 1px solid $tertiary-low; border-bottom: none; width: 145px; height: 34px; @@ -183,8 +183,8 @@ top: 0; bottom: 0; width: 0; - border-right: 1px solid dark-light-diff($tertiary, $secondary, 85%, -65%); - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + border-right: 1px solid $tertiary-low; + background-color: $tertiary-low; transition: width .75s; } } diff --git a/app/assets/stylesheets/desktop/user-card.scss b/app/assets/stylesheets/desktop/user-card.scss index 2d48ec8e003..7df68033a89 100644 --- a/app/assets/stylesheets/desktop/user-card.scss +++ b/app/assets/stylesheets/desktop/user-card.scss @@ -226,7 +226,7 @@ $user_card_background: $secondary; .user-badge { background: scale-color($user_card_background, $lightness: -5%); - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; color: $user_card_primary; } diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss index f22c226d5ce..d5b7eebccb2 100644 --- a/app/assets/stylesheets/desktop/user.scss +++ b/app/assets/stylesheets/desktop/user.scss @@ -160,7 +160,7 @@ th { text-align: left; - border-bottom: 3px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 3px solid $primary-low; padding: 0 0 10px 0; color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); font-weight: normal; @@ -168,7 +168,7 @@ td { padding: 10px 0 10px 0; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } } @@ -180,7 +180,7 @@ } .user-invite-controls { - background-color: dark-light-diff($primary, $secondary, 90%, -75%); + background-color: $primary-low; padding: 5px 10px 0px 0; height: 35px; } @@ -212,8 +212,8 @@ .secondary { background: scale-color($secondary, $lightness: -5%); - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; + border-bottom: 1px solid $primary-low; font-size: 0.929em; .btn { padding: 3px 12px; } @@ -250,7 +250,7 @@ } dt { - color: dark-light-diff($secondary, $primary, 50%, -40%); + color: $secondary-medium; margin: 0; } } @@ -262,8 +262,8 @@ transition: margin .15s linear; blockquote { - background-color: dark-light-diff($secondary, $primary, 30%, -70%); - border-left-color: dark-light-diff($secondary, $primary, 50%, -50%); + background-color: $secondary-low; + border-left-color: $secondary-low; } h1 { @@ -390,7 +390,7 @@ padding: 0 0 2px 0; margin-top: 0; background: rgba($secondary, .85); - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; .bio { display: none; } .primary { @@ -434,7 +434,7 @@ color: $primary; } .item.moderator-action { - background-color: dark-light-diff($highlight, $secondary, 50%, -10%); + background-color: $highlight-medium; } .item.deleted { opacity: 0.8; @@ -447,7 +447,7 @@ .item { padding: 20px 8px 15px 8px; background-color: $secondary; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } .type { color: $primary; @@ -491,7 +491,7 @@ } .notification { &.unread { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + background-color: $tertiary-low; } li { display: inline-block; } diff --git a/app/assets/stylesheets/embed.scss b/app/assets/stylesheets/embed.scss index 66af74d3d0b..6e46de47b19 100644 --- a/app/assets/stylesheets/embed.scss +++ b/app/assets/stylesheets/embed.scss @@ -16,8 +16,8 @@ article.post { } .quote .title { - border-left: 5px solid darken(dark-light-diff($primary, $secondary, 97%, -45%), 10%); - background-color: dark-light-diff($primary, $secondary, 97%, -45%); + border-left: 5px solid darken($primary-low, 10%); + background-color: $primary-low; padding: 10px 10px 0 12px; .avatar { margin-right: 7px; } } @@ -29,8 +29,8 @@ article.post { blockquote { padding: 10px 8px 10px 13px; margin: 0 0 10px 0; - background-color: dark-light-diff($primary, $secondary, 97%, -45%); - border-left: 5px solid darken(dark-light-diff($primary, $secondary, 97%, -45%), 10%); + background-color: $primary-low; + border-left: 5px solid darken($primary-low, 97%, -45%), 10%); p { margin: 0 0 10px 0; } diff --git a/app/assets/stylesheets/mobile/compose.scss b/app/assets/stylesheets/mobile/compose.scss index 405349f46d1..da6b7016d2b 100644 --- a/app/assets/stylesheets/mobile/compose.scss +++ b/app/assets/stylesheets/mobile/compose.scss @@ -19,7 +19,7 @@ input { padding: 4px; border-radius: 3px; box-shadow: inset 0 1px 1px rgba(0,0,0, .3); - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; } input[type=radio], input[type=checkbox] { box-shadow: none; @@ -38,7 +38,7 @@ input[type=radio], input[type=checkbox] { width: 100%; z-index: 1039; height: 0; - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; bottom: 0; font-size: 1em; position: fixed; @@ -97,7 +97,7 @@ input[type=radio], input[type=checkbox] { &.draft { height: 35px !important; cursor: pointer; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; .draft-text { display: block; position: absolute; @@ -120,7 +120,7 @@ input[type=radio], input[type=checkbox] { } &.saving { height: 40px !important; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; .saving-text { display: block; } diff --git a/app/assets/stylesheets/mobile/directory.scss b/app/assets/stylesheets/mobile/directory.scss index bbdbf8cf02b..ba1617ea54a 100644 --- a/app/assets/stylesheets/mobile/directory.scss +++ b/app/assets/stylesheets/mobile/directory.scss @@ -18,12 +18,12 @@ } .directory .user { - border-top: 1px solid dark-light-diff($primary, $secondary, 80%, -20%); + border-top: 1px solid $primary-low; padding: 1em; &.me { - background-color: dark-light-diff($highlight, $secondary, 70%, -80%); + background-color: $highlight-low; .username a, .name, .title, .number, .time-read, .user-stat .label { color: scale-color($highlight, $lightness: -50%); @@ -38,7 +38,7 @@ } .label { margin-left: 0.2em; - color: dark-light-diff($primary, $secondary, 50%, -50%); + color: blend-primary-secondary(50%); } i.fa-heart { color: $love; diff --git a/app/assets/stylesheets/mobile/discourse.scss b/app/assets/stylesheets/mobile/discourse.scss index 97c23d24271..39162e34a05 100644 --- a/app/assets/stylesheets/mobile/discourse.scss +++ b/app/assets/stylesheets/mobile/discourse.scss @@ -73,7 +73,7 @@ blockquote { display: inline-block; .topic-status { i { - color: dark-light-diff($secondary, $primary, 40%, -20%); + color: $secondary-medium; } } } @@ -123,7 +123,7 @@ h2#site-text-logo } margin: 0; padding: 0; - background: dark-light-diff($primary, $secondary, 90%, -65%); + background: $primary-low; list-style: none; overflow: visible; position: relative; diff --git a/app/assets/stylesheets/mobile/history.scss b/app/assets/stylesheets/mobile/history.scss index 0f52dbb84a4..395f8ca956f 100644 --- a/app/assets/stylesheets/mobile/history.scss +++ b/app/assets/stylesheets/mobile/history.scss @@ -9,7 +9,7 @@ line-height: 2em; } #revision-details { - background-color: dark-light-diff($primary, $secondary, 90%, -60%); + background-color: $primary-low; padding: 5px; margin-top: 10px; } diff --git a/app/assets/stylesheets/mobile/topic-list.scss b/app/assets/stylesheets/mobile/topic-list.scss index d66aa8115ac..5c1d3e2bddf 100644 --- a/app/assets/stylesheets/mobile/topic-list.scss +++ b/app/assets/stylesheets/mobile/topic-list.scss @@ -26,7 +26,7 @@ position: relative; } .nav-pills .drop { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); + border: 1px solid $primary-low; position: absolute; z-index: 1000; background-color: $secondary; @@ -47,7 +47,7 @@ } .nav-pills > li { - background: dark-light-diff($primary, $secondary, 90%, -65%); + background: $primary-low; i.fa-caret-down { margin-left: 8px; } @@ -146,9 +146,9 @@ tbody { tr { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-bottom: 1px solid $primary-low; &:first-of-type { - border-top: 3px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-top: 3px solid $primary-low; } } .category { diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index 453f863efd8..5cd5e733130 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -3,7 +3,7 @@ } .small-action { - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; color: lighten($primary, 50%); padding-bottom: 3px; text-transform: uppercase; @@ -28,7 +28,7 @@ } .topic-post article { - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-top: 1px solid $primary-low; padding: 8px 0; } @@ -109,7 +109,7 @@ nav.post-controls { background-color: $secondary; width: 205px; padding: 10px; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; position: absolute; text-align: left; bottom: 0; @@ -181,11 +181,11 @@ a.star { margin: 10px 0; background: blend-primary-secondary(5%); - border: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); + border: 1px solid $primary-low; border-top: none; // would cause double top border section { - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); + border-top: 1px solid $primary-low; } h3 { @@ -300,8 +300,8 @@ a.star { padding: 0 15px; color: dark-light-choose(scale-color($primary, $lightness: 60%), scale-color($secondary, $lightness: 40%)); background: blend-primary-secondary(5%); - border-left: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); + border-left: 1px solid $primary-low; + border-top: 1px solid $primary-low; .fa { margin: 0; font-size: 1.286em; @@ -386,7 +386,7 @@ span.post-count { } .moderator .topic-body { - background-color: dark-light-diff($highlight, $secondary, 70%, -80%); + background-color: $highlight-low; } .quote-button.visible { diff --git a/app/assets/stylesheets/mobile/topic.scss b/app/assets/stylesheets/mobile/topic.scss index 2354605a9bb..1c5ab946d74 100644 --- a/app/assets/stylesheets/mobile/topic.scss +++ b/app/assets/stylesheets/mobile/topic.scss @@ -45,7 +45,7 @@ .topic-status-info { padding-left: 10px; - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -75%); + border-top: 1px solid $primary-low; padding-top: 10px; h3 { margin: 0; @@ -66,7 +66,7 @@ } #topic-progress-expanded { - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border: 1px solid $primary-low; padding: 5px; background: $secondary; @@ -113,7 +113,7 @@ } background-color: $secondary; color: $tertiary; - border: 1px solid dark-light-diff($tertiary, $secondary, 85%, -65%); + border: 1px solid $tertiary-low; border-bottom: none; width: 145px; height: 34px; @@ -144,8 +144,8 @@ top: 0; bottom: 0; width: 0; - border-right: 1px solid dark-light-diff($tertiary, $secondary, 85%, -65%); - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + border-right: 1px solid $tertiary-low; + background-color: $tertiary-low; transition: width .75s; } } diff --git a/app/assets/stylesheets/mobile/user.scss b/app/assets/stylesheets/mobile/user.scss index 7136d89613c..3bcb6fb7454 100644 --- a/app/assets/stylesheets/mobile/user.scss +++ b/app/assets/stylesheets/mobile/user.scss @@ -159,11 +159,11 @@ th { padding: 0.5em; text-align: right; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } td { padding: 0.5em; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; img { margin-right: 10px; } @@ -196,13 +196,13 @@ th { text-align: left; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; padding: 5px; } td { padding: 5px; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } } } @@ -215,7 +215,7 @@ color: $secondary; .secondary { - background: dark-light-diff($primary, $secondary, 90%, -65%); + background: $primary-low; font-size: 0.929em; .btn { padding: 3px 12px; } @@ -241,7 +241,7 @@ } dt { - color: dark-light-diff($secondary, $primary, 50%, -40%); + color: $secondary-medium; margin: 0; } } @@ -251,8 +251,8 @@ background: rgba($secondary, .85); blockquote { - background-color: dark-light-diff($secondary, $primary, 30%, -70%); - border-left-color: dark-light-diff($secondary, $primary, 50%, -50%); + background-color: $secondary-low; + border-left-color: $secondary-low; } h1 { @@ -399,7 +399,7 @@ color: $primary; } .item.moderator-action { - background-color: dark-light-diff($highlight, $secondary, 50%, -10%); + background-color: $highlight-medium; } .item.deleted { opacity: 0.8; @@ -412,7 +412,7 @@ .item { padding: 20px 0 15px 0; background-color: $secondary; - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + border-bottom: 1px solid $primary-low; } .type { color: $primary; diff --git a/app/assets/stylesheets/vendor/pikaday.scss b/app/assets/stylesheets/vendor/pikaday.scss index 8465631879a..7880b8bc657 100644 --- a/app/assets/stylesheets/vendor/pikaday.scss +++ b/app/assets/stylesheets/vendor/pikaday.scss @@ -14,20 +14,20 @@ $pd-text-color: $primary !default; $pd-title-color: $primary !default; $pd-title-bg: $secondary !default; $pd-picker-bg: $secondary !default; -$pd-picker-border: dark-light-diff($secondary, $primary, -20%, 20%) !default; -$pd-picker-border-bottom: dark-light-diff($secondary, $primary, -30%, 30%) !default; +$pd-picker-border: $primary-low !default; +$pd-picker-border-bottom: $primary-low !default; $pd-picker-shadow: rgba(0,0,0,.5) !default; -$pd-th-color: dark-light-diff($primary, $secondary, -20%, 20%) !default; -$pd-day-color: dark-light-diff($primary, $secondary, -30%, 30%) !default; -$pd-day-bg: dark-light-diff($primary, $secondary, 90%, -90%) !default; -$pd-day-hover-color: $secondary !default; -$pd-day-hover-bg: dark-light-diff($tertiary, $secondary, 30%, -30%) !default; +$pd-th-color: $primary !default; +$pd-day-color: $primary !default; +$pd-day-bg: $secondary !default; +$pd-day-hover-color: $primary !default; +$pd-day-hover-bg: $tertiary-low !default; $pd-day-today-color: $tertiary !default; $pd-day-selected-color: $secondary !default; $pd-day-selected-bg: $tertiary !default; -$pd-day-selected-shadow: dark-light-diff($tertiary, $secondary, 50%, -50%) !default; -$pd-day-disabled-color: dark-light-diff($primary, $secondary, -20%, 20%) !default; -$pd-week-color: dark-light-diff($primary, $secondary, -20%, 20%) !default; +$pd-day-selected-shadow: $tertiary-low !default; +$pd-day-disabled-color: $primary !default; +$pd-week-color: $primary !default; // Font $pd-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !default; From 38daa61fc7ef6edfd2eca1478939998a022573f5 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 18 Jul 2017 10:55:51 -0400 Subject: [PATCH 016/279] FEATURE: libv8 upgraded to version 5.7 corresponds more or less with Chrome 57 --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ac8f70d4497..71ca9db1b06 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -137,7 +137,7 @@ GEM thor (>= 0.14, < 2.0) jwt (1.5.6) kgio (2.11.0) - libv8 (5.3.332.38.5) + libv8 (5.7.492.65.1) listen (3.1.5) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) @@ -156,8 +156,8 @@ GEM mime-types (2.99.3) mini_mime (0.1.3) mini_portile2 (2.2.0) - mini_racer (0.1.10) - libv8 (~> 5.3) + mini_racer (0.1.11) + libv8 (~> 5.7) minitest (5.10.2) mocha (1.2.1) metaclass (~> 0.0.1) From b92e181390f90a807d9175963a3bb12b77a8a1f0 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 18 Jul 2017 12:09:27 -0400 Subject: [PATCH 017/279] FEATURE: rake plugin:install_all_official use this task to quickly install all official plugins GIT_WRITE=1 to enable write access to repos (discourse staff only) --- lib/plugin/metadata.rb | 8 +++++++- lib/tasks/plugin.rake | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/plugin/metadata.rb b/lib/plugin/metadata.rb index bcf8954d2bd..123fccc396b 100644 --- a/lib/plugin/metadata.rb +++ b/lib/plugin/metadata.rb @@ -25,7 +25,13 @@ class Plugin::Metadata "poll", "discourse-plugin-linkedin-auth", "discourse-plugin-office365-auth", - "discourse-oauth2-basic" + "discourse-oauth2-basic", + "discourse-math", + "discourse-bbcode-color", + "discourse-bbcode", + "discourse-affiliate", + "discourse-translator", + "discourse-patreon" ]) FIELDS ||= [:name, :about, :version, :authors, :url, :required_version] diff --git a/lib/tasks/plugin.rake b/lib/tasks/plugin.rake index acb8e5b1d7c..141c6472f38 100644 --- a/lib/tasks/plugin.rake +++ b/lib/tasks/plugin.rake @@ -1,5 +1,47 @@ directory 'plugins' +desc 'install all official plugins' +task 'plugin:install_all_official' do + skip = Set.new([ + 'customer-flair', + 'discourse-nginx-performance-report', + 'hosted-site', + 'lazyYT', + 'poll', + ]) + + map = { + 'Canned Replies' => 'https://github.com/discourse/discourse-canned-replies', + 'Spoiler Alert!' => 'https://github.com/discourse/discourse-spoiler-alert', + 'staff-notes' => 'https://github.com/discourse/discourse-staff-notes', + 'GitHub badges' => 'https://github.com/discourse/github_badges', + } + + #require 'plugin/metadata' + Plugin::Metadata::OFFICIAL_PLUGINS.each do |name| + next if skip.include? name + repo = map[name] || "https://github.com/discourse/#{name}" + dir = repo.split('/').last + path = File.expand_path('plugins/' + dir) + + if Dir.exist? path + STDERR.puts "Skipping #{dir} cause it already exists!" + next + end + + if ENV['GIT_WRITE'] + STDERR.puts "Allowing write to all repos!" + repo.gsub!("https://github.com/", "git@github.com:") + repo << ".git" + end + + status = system("git clone #{repo} #{path}") + unless status + abort("Failed to clone #{repo}") + end + end +end + desc 'install plugin' task 'plugin:install', :repo do |t, args| repo = ENV['REPO'] || ENV['repo'] || args[:repo] From 7c7f22565c06bb3482c64b79ebcf5a998ce555ae Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 18 Jul 2017 12:31:32 -0400 Subject: [PATCH 018/279] correct bench code --- script/benchmarks/markdown/bench.rb | 47 ++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/script/benchmarks/markdown/bench.rb b/script/benchmarks/markdown/bench.rb index a27158eeec6..a1e0cda2851 100644 --- a/script/benchmarks/markdown/bench.rb +++ b/script/benchmarks/markdown/bench.rb @@ -9,7 +9,6 @@ tests = [ ["lots of mentions", File.read("lots_of_mentions.md")] ] -SiteSetting.enable_experimental_markdown_it = true PrettyText.cook("") PrettyText.v8.eval("window.commonmark = window.markdownit('commonmark')") @@ -27,19 +26,9 @@ PrettyText.v8.eval("window.commonmark = window.markdownit('commonmark')") Benchmark.ips do |x| [true,false].each do |sanitize| - { - "markdown js" => - lambda{SiteSetting.enable_experimental_markdown_it = false}, - - "markdown it" => - lambda{SiteSetting.enable_experimental_markdown_it = true} - }.each do |name, before| - before.call - - tests.each do |test, text| - x.report("#{name} #{test} sanitize: #{sanitize}") do - PrettyText.markdown(text, sanitize: sanitize) - end + tests.each do |test, text| + x.report("#{test} sanitize: #{sanitize}") do + PrettyText.markdown(text, sanitize: sanitize) end end end @@ -52,3 +41,33 @@ Benchmark.ips do |x| end end + +# 18-07-2017 - Sam's NUC + +# Calculating ------------------------------------- +# tiny post sanitize: true +# 162.766 (±13.5%) i/s - 812.000 in 5.101429s +# giant post sanitize: true +# 133.957 (±11.2%) i/s - 663.000 in 5.029386s +# most features sanitize: true +# 55.319 (±10.8%) i/s - 276.000 in 5.054290s +# lots of mentions sanitize: true +# 0.313 (± 0.0%) i/s - 2.000 in 6.394343s +# tiny post sanitize: false +# 456.209 (±13.6%) i/s - 2.288k in 5.117314s +# giant post sanitize: false +# 331.357 (±10.9%) i/s - 1.650k in 5.046322s +# most features sanitize: false +# 77.038 (±10.4%) i/s - 385.000 in 5.055062s +# lots of mentions sanitize: false +# 0.312 (± 0.0%) i/s - 2.000 in 6.430657s +# markdown it no extensions commonmark tiny post +# 6.916k (± 5.5%) i/s - 34.540k in 5.010354s +# markdown it no extensions commonmark giant post +# 1.044k (± 9.3%) i/s - 5.247k in 5.090534s +# markdown it no extensions commonmark most features +# 1.457k (± 5.0%) i/s - 7.314k in 5.034401s +# markdown it no extensions commonmark lots of mentions +# 2.004k (± 5.2%) i/s - 10.192k in 5.100657s +# sam@ubuntu markdown % +# From 93e5112dfa22f68e230486e4f37a3253fafc7a92 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 18 Jul 2017 14:31:22 -0400 Subject: [PATCH 019/279] correct poll specs --- plugins/poll/plugin.rb | 8 +++---- .../spec/controllers/posts_controller_spec.rb | 23 ++++++++++--------- .../spec/integration/poll_endpoints_spec.rb | 2 +- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/plugins/poll/plugin.rb b/plugins/poll/plugin.rb index 3b764043b6d..4903f762b3b 100644 --- a/plugins/poll/plugin.rb +++ b/plugins/poll/plugin.rb @@ -157,14 +157,14 @@ after_initialize do # extract attributes p.attributes.values.each do |attribute| if attribute.name.start_with?(DATA_PREFIX) - poll[attribute.name[DATA_PREFIX.length..-1]] = attribute.value + poll[attribute.name[DATA_PREFIX.length..-1]] = CGI::escapeHTML(attribute.value || "") end end # extract options p.css("li[#{DATA_PREFIX}option-id]").each do |o| - option_id = o.attributes[DATA_PREFIX + "option-id"].value - poll["options"] << { "id" => option_id, "html" => o.inner_html, "votes" => 0 } + option_id = CGI::escapeHTML(o.attributes[DATA_PREFIX + "option-id"].value || "") + poll["options"] << { "id" => option_id, "html" => CGI::escapeHTML(o.inner_html), "votes" => 0 } end # add the poll @@ -260,7 +260,7 @@ after_initialize do result = [] - users = User.where(id: user_ids).map do |user| + User.where(id: user_ids).map do |user| result << UserNameSerializer.new(user).serializable_hash end end diff --git a/plugins/poll/spec/controllers/posts_controller_spec.rb b/plugins/poll/spec/controllers/posts_controller_spec.rb index d5bf98b157b..7d1b253a2db 100644 --- a/plugins/poll/spec/controllers/posts_controller_spec.rb +++ b/plugins/poll/spec/controllers/posts_controller_spec.rb @@ -29,23 +29,23 @@ describe PostsController do end it "should have different options" do - xhr :post, :create, { title: title, raw: "[poll]\n- A\n- A[/poll]" } + xhr :post, :create, { title: title, raw: "[poll]\n- A\n- A\n[/poll]" } expect(response).not_to be_success json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.default_poll_must_have_different_options")) end it "should have at least 2 options" do - xhr :post, :create, { title: title, raw: "[poll]\n- A[/poll]" } + xhr :post, :create, { title: title, raw: "[poll]\n- A\n[/poll]" } expect(response).not_to be_success json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.default_poll_must_have_at_least_2_options")) end it "should have at most 'SiteSetting.poll_maximum_options' options" do - raw = "[poll]" + raw = "[poll]\n" (SiteSetting.poll_maximum_options + 1).times { |n| raw << "\n- #{n}" } - raw << "[/poll]" + raw << "\n[/poll]" xhr :post, :create, { title: title, raw: raw } @@ -55,7 +55,7 @@ describe PostsController do end it "should have valid parameters" do - xhr :post, :create, { title: title, raw: "[poll type=multiple min=5]\n- A\n- B[/poll]" } + xhr :post, :create, { title: title, raw: "[poll type=multiple min=5]\n- A\n- B\n[/poll]" } expect(response).not_to be_success json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.default_poll_with_multiple_choices_has_invalid_parameters")) @@ -66,7 +66,8 @@ describe PostsController do expect(response).to be_success json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") - expect(json["polls"]["<script>alert(xss)</script>"]).to be + expect(json["cooked"]).to include("<script>") + expect(json["polls"]["<script>alert('xss')</script>"]).to be end it "also works whe there is a link starting with '[poll'" do @@ -116,9 +117,9 @@ describe PostsController do describe "after the poll edit window has expired" do - let(:poll) { "[poll]\n- A\n- B[/poll]" } - let(:new_option) { "[poll]\n- A\n- C[/poll]" } - let(:updated) { "before\n\n[poll]\n- A\n- B[/poll]\n\nafter" } + let(:poll) { "[poll]\n- A\n- B\n[/poll]" } + let(:new_option) { "[poll]\n- A\n- C\n[/poll]" } + let(:updated) { "before\n\n[poll]\n- A\n- B\n[/poll]\n\nafter" } let(:post_id) do Timecop.freeze(6.minutes.ago) do @@ -220,14 +221,14 @@ describe PostsController do describe "named polls" do it "should have different options" do - xhr :post, :create, { title: title, raw: "[poll name=""foo""]\n- A\n- A[/poll]" } + xhr :post, :create, { title: title, raw: "[poll name=""foo""]\n- A\n- A\n[/poll]" } expect(response).not_to be_success json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.named_poll_must_have_different_options", name: "foo")) end it "should have at least 2 options" do - xhr :post, :create, { title: title, raw: "[poll name='foo']\n- A[/poll]" } + xhr :post, :create, { title: title, raw: "[poll name='foo']\n- A\n[/poll]" } expect(response).not_to be_success json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.named_poll_must_have_at_least_2_options", name: "foo")) diff --git a/plugins/poll/spec/integration/poll_endpoints_spec.rb b/plugins/poll/spec/integration/poll_endpoints_spec.rb index d2c5a4caacd..47c6080585d 100644 --- a/plugins/poll/spec/integration/poll_endpoints_spec.rb +++ b/plugins/poll/spec/integration/poll_endpoints_spec.rb @@ -89,7 +89,7 @@ describe "DiscoursePoll endpoints" do end context "number poll" do - let(:post) { Fabricate(:post, raw: '[poll type=number min=1 max=20 step=1 public=true][/poll]') } + let(:post) { Fabricate(:post, raw: "[poll type=number min=1 max=20 step=1 public=true]\n[/poll]") } it 'should return the right response' do post From 660d5e0a351945db845ad0738a0d9232efc66d44 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 18 Jul 2017 14:44:49 -0400 Subject: [PATCH 020/279] fix broken spec --- .../spec/components/pretty_text_spec.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/discourse-details/spec/components/pretty_text_spec.rb b/plugins/discourse-details/spec/components/pretty_text_spec.rb index 5c2ad81e100..cd03a2fb6ba 100644 --- a/plugins/discourse-details/spec/components/pretty_text_spec.rb +++ b/plugins/discourse-details/spec/components/pretty_text_spec.rb @@ -4,9 +4,17 @@ require 'pretty_text' describe PrettyText do it "supports details tag" do - cooked_html = "
foo\n\n

bar

\n\n
" + cooked_html = "
foobar
" expect(PrettyText.cook("
foobar
")).to match_html(cooked_html) - expect(PrettyText.cook("[details=foo]bar[/details]")).to match_html(cooked_html) + + cooked_html = <<~HTML +
+ + foo +

bar

+
+ HTML + expect(PrettyText.cook("[details=foo]\nbar\n[/details]")).to eq(cooked_html.strip) end end From b7f58fe88006e88a593194db79917d100ecab308 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 18 Jul 2017 14:52:58 -0400 Subject: [PATCH 021/279] regression polls could not be closed properly --- .../assets/javascripts/lib/discourse-markdown/poll.js.es6 | 5 ++++- plugins/poll/spec/controllers/polls_controller_spec.rb | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 b/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 index 76ebf8cdc18..20b0dee7c3b 100644 --- a/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 +++ b/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 @@ -113,7 +113,10 @@ const rule = { // default poll attributes const attributes = [["class", "poll"]]; - attributes.push([DATA_PREFIX + "status", "open"]); + + if (!attrs['status']) { + attributes.push([DATA_PREFIX + "status", "open"]); + } WHITELISTED_ATTRIBUTES.forEach(name => { if (attrs[name]) { diff --git a/plugins/poll/spec/controllers/polls_controller_spec.rb b/plugins/poll/spec/controllers/polls_controller_spec.rb index 9e8e0196443..677a72d6098 100644 --- a/plugins/poll/spec/controllers/polls_controller_spec.rb +++ b/plugins/poll/spec/controllers/polls_controller_spec.rb @@ -79,8 +79,8 @@ describe ::DiscoursePoll::PollsController do end it "ensures poll is open" do - closed_poll = Fabricate(:post, raw: "[poll status=closed]\n- A\n- B\n[/poll]") - xhr :put, :vote, { post_id: closed_poll.id, poll_name: "poll", options: ["A"] } + closed_poll = create_post(raw: "[poll status=closed]\n- A\n- B\n[/poll]") + xhr :put, :vote, { post_id: closed_poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"] } expect(response).not_to be_success json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.poll_must_be_open_to_vote")) From 14c2439473e52b467ac24504eaf1e617ff255df8 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 18 Jul 2017 15:45:23 -0400 Subject: [PATCH 022/279] correct specs so they run on latest --- .../discourse_narrative_bot/advanced_user_narrative_spec.rb | 6 +++--- .../spec/discourse_narrative_bot/new_user_narrative_spec.rb | 2 +- .../spec/discourse_narrative_bot/track_selector_spec.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb index f6af336c206..a3dd4e826ca 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb @@ -348,7 +348,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do describe 'when reply contains the skip trigger' do it 'should create the right reply' do parent_category = Fabricate(:category, name: 'a') - category = Fabricate(:category, parent_category: parent_category, name: 'b') + _category = Fabricate(:category, parent_category: parent_category, name: 'b') post.update!(raw: skip_trigger) described_class.any_instance.expects(:enqueue_timeout_job).with(user) @@ -382,7 +382,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do describe 'when user recovers a post in the right topic' do it 'should create the right reply' do parent_category = Fabricate(:category, name: 'a') - category = Fabricate(:category, parent_category: parent_category, name: 'b') + _category = Fabricate(:category, parent_category: parent_category, name: 'b') post PostDestroyer.new(user, post).destroy @@ -652,7 +652,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do end it 'should create the right reply' do - post.update!(raw: "[details=\"This is a test\"]wooohoo[/details]") + post.update!(raw: "[details=\"This is a test\"]\nwooohoo\n[/details]") narrative.input(:reply, user, post: post) expect(Post.offset(1).last.raw).to eq(I18n.t( diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb index 3c712876b86..b234519ed9f 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb @@ -612,7 +612,7 @@ describe DiscourseNarrativeBot::NewUserNarrative do it 'should create the right reply' do post.update!( - raw: '[quote="#{post.user}, post:#{post.post_number}, topic:#{topic.id}"]\n:monkey: :fries:\n[/quote]' + raw: "[quote=\"#{post.user}, post:#{post.post_number}, topic:#{topic.id}\"]\n:monkey: :fries:\n[/quote]" ) narrative.expects(:enqueue_timeout_job).with(user) diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb index 0aa1dde7787..b6166ccfcfe 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb @@ -562,7 +562,7 @@ describe DiscourseNarrativeBot::TrackSelector do describe 'when roll dice command is present inside a quote' do it 'should ignore the command' do user - post.update!(raw: '[quote="Donkey, post:6, topic:1"]@discobot roll 2d1[/quote]') + post.update!(raw: "[quote=\"Donkey, post:6, topic:1\"]\n@discobot roll 2d1\n[/quote]") expect { described_class.new(:reply, user, post_id: post.id).select } .to_not change { Post.count } @@ -599,7 +599,7 @@ describe DiscourseNarrativeBot::TrackSelector do describe 'when quote command is present inside a onebox or quote' do it 'should ignore the command' do user - post.update!(raw: '[quote="Donkey, post:6, topic:1"]@discobot quote[/quote]') + post.update!(raw: "[quote=\"Donkey, post:6, topic:1\"]\n@discobot quote\n[/quote]") expect { described_class.new(:reply, user, post_id: post.id).select } .to_not change { Post.count } From 87a1ff15fdf7584e67e0fa9cc9d8780ac7435a5a Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 19 Jul 2017 10:25:13 +0900 Subject: [PATCH 023/279] Treat URL as loaded when loading script with tag. --- app/assets/javascripts/discourse/lib/load-script.js.es6 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index ab67a3a880a..d40b17c6639 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -38,9 +38,9 @@ export default function loadScript(url, opts) { $('script').each((i, tag) => { const src = tag.getAttribute('src'); - // For some reason, a script tag with `url` as the source is appended into - // the head tag while loading the script. - if (src && src !== url) _loaded[tag.getAttribute('src')] = true; + if (src && (opts.scriptTag || src !== url)) { + _loaded[tag.getAttribute('src')] = true; + } }); From 6de258d4cf639a2ca25df127af0e2f109f8920fb Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 11 Jul 2017 17:51:53 +0200 Subject: [PATCH 024/279] FEATURE: Introduces new emoji-picker --- app/assets/javascripts/application.js | 2 - .../discourse/components/d-editor.js.es6 | 38 +- .../discourse/components/emoji-picker.js.es6 | 448 ++ .../discourse/lib/emoji/groups.js.es6 | 1555 ----- .../discourse/lib/emoji/toolbar.js.es6 | 208 - .../templates/components/d-editor.hbs | 2 + .../templates/components/emoji-picker.hbs | 2 + .../templates/emoji-picker-recent.raw.hbs | 5 + .../templates/emoji-picker.raw.hbs.erb | 88 + .../discourse/templates/emoji-toolbar.raw.hbs | 45 - .../{emoji.js.es6 => emoji.js.es6.erb} | 18 +- app/assets/stylesheets/common/base/emoji.scss | 273 +- app/assets/stylesheets/mobile/emoji.scss | 10 - app/models/emoji.rb | 12 +- config/locales/client.en.yml | 12 + lib/emoji/groups.json | 6047 +++++++++++++++++ lib/tasks/emoji.rake | 18 +- .../acceptance/emoji-picker-test.js.es6 | 259 + test/stylesheets/test_helper.css | 8 - 19 files changed, 7068 insertions(+), 1982 deletions(-) create mode 100644 app/assets/javascripts/discourse/components/emoji-picker.js.es6 delete mode 100644 app/assets/javascripts/discourse/lib/emoji/groups.js.es6 delete mode 100644 app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/components/emoji-picker.hbs create mode 100644 app/assets/javascripts/discourse/templates/emoji-picker-recent.raw.hbs create mode 100644 app/assets/javascripts/discourse/templates/emoji-picker.raw.hbs.erb delete mode 100644 app/assets/javascripts/discourse/templates/emoji-toolbar.raw.hbs rename app/assets/javascripts/pretty-text/{emoji.js.es6 => emoji.js.es6.erb} (90%) delete mode 100644 app/assets/stylesheets/mobile/emoji.scss create mode 100644 lib/emoji/groups.json create mode 100644 test/javascripts/acceptance/emoji-picker-test.js.es6 diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 632ad9d8f94..61c5442a930 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -69,8 +69,6 @@ //= require ./discourse/components/notifications-button //= require ./discourse/lib/link-mentions //= require ./discourse/components/site-header -//= require ./discourse/lib/emoji/groups -//= require ./discourse/lib/emoji/toolbar //= require ./discourse/components/d-editor //= require ./discourse/lib/screen-track //= require ./discourse/routes/discourse diff --git a/app/assets/javascripts/discourse/components/d-editor.js.es6 b/app/assets/javascripts/discourse/components/d-editor.js.es6 index 289d5ee4f19..e2c22e9ef09 100644 --- a/app/assets/javascripts/discourse/components/d-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/d-editor.js.es6 @@ -1,6 +1,5 @@ /*global Mousetrap:true */ import { default as computed, on, observes } from 'ember-addons/ember-computed-decorators'; -import { showSelector } from "discourse/lib/emoji/toolbar"; import Category from 'discourse/models/category'; import { categoryHashtagTriggerRule } from 'discourse/lib/category-hashtags'; import { TAG_HASHTAG_POSTFIX } from 'discourse/lib/tag-hashtags'; @@ -346,20 +345,8 @@ export default Ember.Component.extend({ if (v.code) { return `${v.code}:`; } else { - showSelector({ - appendTo: self.$(), - register, - onSelect: title => { - // Remove the previously type characters when a new emoji is selected from the selector. - let selected = self._getSelected(); - let newPre = selected.pre.replace(/:[^:]+$/, ":"); - let numOfRemovedChars = selected.pre.length - newPre.length; - selected.pre = newPre; - selected.start -= numOfRemovedChars; - selected.end -= numOfRemovedChars; - self._addText(selected, `${title}:`); - } - }); + $editorInput.autocomplete({cancel: true}); + self.set('emojiPickerIsActive', true); return ""; } }, @@ -614,6 +601,21 @@ export default Ember.Component.extend({ }, actions: { + emojiSelected(code) { + let selected = this._getSelected(); + const captures = selected.pre.match(/\B:(\w*)$/); + + if(_.isEmpty(captures)) { + this._addText(selected, `:${code}:`); + } else { + let numOfRemovedChars = selected.pre.length - captures[1].length; + selected.pre = selected.pre.slice(0, selected.pre.length - captures[1].length); + selected.start -= numOfRemovedChars; + selected.end -= numOfRemovedChars; + this._addText(selected, `${code}:`); + } + }, + toolbarButton(button) { const selected = this._getSelected(button.trimLeading); const toolbarEvent = { @@ -692,11 +694,7 @@ export default Ember.Component.extend({ }, emoji() { - showSelector({ - appendTo: this.$(), - register: this.register, - onSelect: title => this._addText(this._getSelected(), `:${title}:`) - }); + this.set('emojiPickerIsActive', !this.get('emojiPickerIsActive')); } } }); diff --git a/app/assets/javascripts/discourse/components/emoji-picker.js.es6 b/app/assets/javascripts/discourse/components/emoji-picker.js.es6 new file mode 100644 index 00000000000..939fce6d385 --- /dev/null +++ b/app/assets/javascripts/discourse/components/emoji-picker.js.es6 @@ -0,0 +1,448 @@ +import { observes } from "ember-addons/ember-computed-decorators"; +import { findRawTemplate } from "discourse/lib/raw-templates"; +import { emojiUrlFor } from "discourse/lib/text"; +import KeyValueStore from "discourse/lib/key-value-store"; +import { emojis } from "pretty-text/emoji/data"; +import { extendedEmojiList, isSkinTonableEmoji } from "pretty-text/emoji"; + +const recentTemplate = findRawTemplate("emoji-picker-recent"); +const pickerTemplate = findRawTemplate("emoji-picker"); +export const keyValueStore = new KeyValueStore("discourse_emojis_"); +export const EMOJI_USAGE = "emojiUsage"; +export const EMOJI_SCROLL_Y = "emojiScrollY"; +export const EMOJI_SELECTED_DIVERSITY = "emojiSelectedDiversity"; +const PER_ROW = 11; + +export default Ember.Component.extend({ + customEmojis: _.map(_.keys(extendedEmojiList()), function(code) { + return { code, src: emojiUrlFor(code) }; + }), + + $picker: Ember.computed("active", function() { + return this.$(".emoji-picker"); + }), + + $filter: Ember.computed("$picker", function() { + return this.get("$picker").find(".filter"); + }), + + $results: Ember.computed("$picker", function() { + return this.get("$picker").find(".results"); + }), + + $list: Ember.computed("$picker", function() { + return this.get("$picker").find(".list"); + }), + + willDestroyElement() { + this._super(); + this._unbindEvents(); + }, + + didInsertElement() { + this._super(); + + if (!keyValueStore.getObject(EMOJI_USAGE)) { + keyValueStore.setObject({ key: EMOJI_USAGE, value: {} }); + } + + this.set("selectedDiversity", keyValueStore.getObject(EMOJI_SELECTED_DIVERSITY) || 1); + }, + + didUpdateAttrs() { + this._super(); + + if (this.get("active")) { + this.show(); + } else { + this.close(); + } + }, + + @observes("filter") + filterChanged() { + this.get("$filter").find(".clear-filter").toggle(!_.isEmpty(this.get("filter"))); + Ember.run.debounce(this, this._filterEmojisList, 250); + }, + + @observes("selectedDiversity") + selectedDiversityChanged() { + keyValueStore.setObject({key: EMOJI_SELECTED_DIVERSITY, value: this.get("selectedDiversity")}); + + $.each(this.get("$list").find(".emoji.diversity[src!='']"), (_, icon) => { + this._updateIconSrc(icon); + }); + + if(this.get("filter") !== "") { + $.each(this.get("$results").find(".emoji.diversity"), (_, icon) => { + this._updateIconSrc(icon); + }); + } + }, + + @observes("recentEmojis") + recentEmojisChanged() { + const $recentSection = this.get("$list").find(".section[data-section='recent']"); + const $recentSectionGroup = $recentSection.find(".section-group"); + const $recentCategory = this.get("$picker").find(".category-icon a[title='recent']").parent(); + if(_.isEmpty(this.get("recentEmojis"))) { + $recentCategory.hide(); + $recentSection.css("height", 0).hide(); + } else { + $recentCategory.show(); + $recentSection.css("height", "auto").show(); + } + + const recentEmojis = _.map(this.get("recentEmojis"), function(emoji) { + return { code: emoji.title, src: emojiUrlFor(emoji.title) }; + }); + const model = { recentEmojis }; + const template = recentTemplate(model); + $recentSectionGroup.html(template); + this._bindHover($recentSectionGroup.find("a")); + }, + + close() { + this.get("$picker") + .css({width: "", left: "", bottom: ""}) + .empty(); + this.$(".emoji-picker-modal").removeClass("fadeIn"); + + this._unbindEvents(); + }, + + show() { + const model = { customEmojis: this.get("customEmojis") }; + const template = pickerTemplate(model); + this.get("$picker").html(template); + + this._bindEvents(); + + Ember.run.later(this, function() { + this._setDiversity(); + this._positionPicker(); + this._scrollTo(); + this.recentEmojisChanged(); + }); + }, + + _bindEvents() { + this._bindDiversityClick(); + this._bindSectionsScroll(); + this._bindEmojiClick(); + this._bindClearRecentEmojisGroup(); + this._bindResizing(); + this._bindHover(); + this._bindCategoryClick(); + this._bindModalClick(); + this._bindFilterInput(); + this._bindEscape(); + }, + + _bindEscape() { + this.$().on("keydown", e => { + if (e.which === 27) { + this.set("active", false); + return false; + } + }); + }, + + _bindModalClick() { + this.$(".emoji-picker-modal").on("click", () => { + this.set("active", false); + }); + }, + + _unbindEvents() { + this.$(window).off("resize"); + this.$(".emoji-picker-modal").off("click"); + Ember.$("#reply-control").off("div-resized"); + this.$().off("keydown"); + }, + + _filterEmojisList() { + const $filter = this.get("$picker").find(".filter"); + + if (this.get("filter") === "") { + $filter.find("input[name='filter']").val(""); + this.get("$results").empty().hide(); + this.get("$list").show(); + } else { + const regexp = new RegExp(this.get("filter"), "g"); + const filteredCodes = _.filter(emojis, code => regexp.test(code)).slice(0, 30); + this.get("$results").empty().html( + _.map(filteredCodes, (code) => { + const hasDiversity = isSkinTonableEmoji(code); + const diversity = hasDiversity ? "diversity" : ""; + const scaledCode = this._codeWithDiversity(code, hasDiversity); + return ` + + `; + }) + ).show(); + this._bindHover(this.get("$results").find("a")); + this._bindEmojiClick(this.get("$results")); + this.get("$list").hide(); + } + }, + + _bindFilterInput() { + const $filter = this.get("$picker").find(".filter"); + const $input = $filter.find("input"); + + $input.on("input", (event) => { + this.set("filter", event.currentTarget.value); + }); + + $filter.find(".clear-filter").on("click", () => { + $input.val("").focus(); + this.set("filter", ""); + return false; + }); + }, + + _bindCategoryClick() { + this.get("$picker").find(".category-icon").on("click", "a", (event) => { + this.set("filter", ""); + this.get("$results").empty(); + this.get("$list").show(); + + const section = $(event.currentTarget).attr("title"); + const $section = this.get("$list").find(`.section[data-section="${section}"]`); + const scrollTop = this.get("$list").scrollTop() + + ( $section.offset().top - this.get("$list").offset().top ); + + this._scrollTo(scrollTop); + return false; + }); + }, + + _bindHover(hoverables) { + const replaceInfoContent = (html) => { + this.get("$picker").find(".footer .info").html(html || ""); + } + + (hoverables || this.$(".section-group a")).hover(event => { + const $a = $(event.currentTarget); + const code = this._codeWithDiversity($a.attr("title"), $a.find("img").hasClass("diversity")); + const html = ` :${code}:`; + replaceInfoContent(html); + }, + () => replaceInfoContent() + ); + }, + + _bindResizing() { + this.$(window).on("resize", () => { + Ember.run.debounce(this, this._positionPicker, 100); + }); + + Ember.$("#reply-control").on("div-resized", () => { + Ember.run.debounce(this, this._positionPicker, 100); + }); + }, + + _bindClearRecentEmojisGroup() { + const $recent = this.get("$picker").find(".section[data-section='recent'] .clear-recent"); + $recent.on("click", () => { + keyValueStore.setObject({ key: EMOJI_USAGE, value: {} }); + this.set("recentEmojis", {}); + this._scrollTo(0); + return false; + }); + }, + + _bindEmojiClick(emojisContainer) { + const $emojisContainer = emojisContainer || this.get("$list").find(".section-group"); + $emojisContainer.off("click").on("click", "a", e => { + const $icon = $(e.currentTarget); + const title = $icon.attr("title"); + const code = this._codeWithDiversity(title, $icon.find("img").hasClass("diversity")); + + this._trackEmojiUsage(code); + + if(this._isSmallViewport()) { + this.set("active", false); + } + + return false; + }); + }, + + _bindSectionsScroll() { + this.get("$list").on("scroll", () => { + Ember.run.debounce(this, this._checkVisibleSection, 150); + Ember.run.debounce(this, this._storeScrollPosition, 50); + }); + }, + + _checkVisibleSection() { + const $sections = this.get("$list").find(".section"); + const sections = []; + let cumulatedHeight = 0; + + $.each($sections, (_, section) => { + const $section = $(section); + sections.push({$section, cumulatedHeight}); + cumulatedHeight += $section.innerHeight(); + }); + + let selectedSection; + const currentScrollTop = this.get("$list").scrollTop() + if (!_.isEmpty(this.get("recentEmojis")) && currentScrollTop === 0) { + selectedSection = _.first(sections); + } else if (!_.isEmpty(this.get("customEmojis")) && + currentScrollTop === this.get("$list")[0].scrollHeight - this.get("$list").innerHeight()) + { + selectedSection = _.last(sections); + } else { + selectedSection = _.last(_.reject(sections, (section) => { + return section.cumulatedHeight > currentScrollTop; + })); + } + + if(selectedSection) { + this.get("$picker").find(".category-icon").removeClass("current"); + this.get("$picker").find(`.category-icon a[title='${selectedSection.$section.data("section")}']`) + .parent() + .addClass("current"); + + if(!selectedSection.$section.hasClass("loaded")) { + selectedSection.$section.addClass("loaded"); + this._loadVisibleEmojis(selectedSection.$section.find(".emoji[src='']")); + } + + //preload surrounding sections + const selectedSectionIndex = sections.indexOf(selectedSection); + const preloadedSection = sections[selectedSectionIndex + 1] || sections[selectedSectionIndex - 1]; + if(preloadedSection && !preloadedSection.$section.hasClass("loaded")) { + preloadedSection.$section.addClass("loaded"); + const $visibleEmojis = preloadedSection.$section.find(".emoji[src='']"); + Ember.run.later(() => { this._loadVisibleEmojis($visibleEmojis) }, 1500); + } + } + }, + + _bindDiversityClick() { + const $diversityScales = this.get("$picker").find(".diversity-picker .diversity-scale"); + $diversityScales.on("click", (event) => { + const $selectedDiversity = $(event.currentTarget); + $diversityScales.removeClass("selected"); + $selectedDiversity.addClass("selected"); + this.set("selectedDiversity", parseInt($selectedDiversity.data("level"))); + return false; + }); + }, + + _setDiversity() { + this.get("$picker") + .find(`.diversity-picker .diversity-scale[data-level="${this.get("selectedDiversity")}"]`) + .addClass("selected"); + }, + + _isSmallViewport() { + return this.site.isMobileDevice || this.$(window).width() <= 1024 || this.$(window).height() <= 768; + }, + + _positionPicker(){ + if(!this.get("active")) { return; } + + let isLargePreview = this.$(window).height() - + Ember.$(".d-header").height() - + Ember.$("#reply-control").height() < + this.get("$picker").height() + 16; + + if(this._isSmallViewport()) { + this.$(".emoji-picker-modal").addClass("fadeIn"); + this.get("$picker").css({ + width: this.site.isMobileDevice ? this.$(window).width() - 10 : 340, + marginLeft: this.site.isMobileDevice ? -(this.$(window).width() - 10)/2 : -170, + marginTop: -150, + left: "50%", + top: "50%" + }) + } else { + this.$(".emoji-picker-modal").removeClass("fadeIn"); + + let cssAttributes = { width: 400, marginLeft: "", marginTop: "", left: "", top: "" }; + if(isLargePreview) { + cssAttributes.left = (Ember.$("#reply-control").width() - Ember.$(".d-editor").width() ) / 2 + Ember.$(".d-editor-preview-wrapper").position().left; + cssAttributes.bottom = 32; + } else { + cssAttributes.left = (Ember.$("#reply-control").width() - Ember.$(".d-editor").width() ) / 2 + Ember.$(".d-editor").position().left; + cssAttributes.bottom = Ember.$("#reply-control").height() - 48; + } + + this.get("$picker").css(cssAttributes); + } + + const infoMaxWidth = this.get("$picker").width() - + this.get("$picker").find(".categories-column").width() - + this.get("$picker").find(".diversity-picker").width() - + 32; + this.get("$picker").find(".info").css("max-width", infoMaxWidth); + }, + + _loadVisibleEmojis($visibleEmojis) { + $.each($visibleEmojis, (_, icon) => { + const $icon = $(icon); + const code = this._codeWithDiversity($icon.parents("a").attr("title"), $icon.hasClass("diversity")) + $icon.attr("src", emojiUrlFor(code)); + }); + }, + + _codeWithDiversity(code, diversity) { + if(diversity && this.get("selectedDiversity") !== 1) { + return `${code}:t${this.get("selectedDiversity")}`; + } else { + return code; + } + }, + + _storeScrollPosition() { + keyValueStore.setObject({ + key: EMOJI_SCROLL_Y, + value: this.get("$list").scrollTop() + }); + }, + + _trackEmojiUsage(code) { + const recent = keyValueStore.getObject(EMOJI_USAGE) || {}; + + if (!recent[code]) { + // keeping title here for legacy reasons, might migrate later + recent[code] = { title: code, usage: 0 }; + } + recent[code]["usage"]++; + + keyValueStore.setObject({ key: EMOJI_USAGE, value: recent }); + + this.set("recentEmojis", _.map(recent).sort(this._sortByUsage).slice(0, PER_ROW)); + + this.sendAction("emojiSelected", code); + }, + + _sortByUsage(a, b) { + if (a.usage > b.usage) { return -1; } + if (b.usage > a.usage) { return 1; } + return a.title.localeCompare(b.title); + }, + + _scrollTo(y) { + const yPosition = _.isUndefined(y) ? keyValueStore.getObject(EMOJI_SCROLL_Y) : y; + + this.get("$list").scrollTop(yPosition); + + // if we don’t actually scroll we need to force it + if(yPosition === 0) { + this.get("$list").scroll(); + } + }, + + _updateIconSrc(icon) { + const $icon = $(icon); + const code = this._codeWithDiversity($icon.parents("a").attr("title"), true) + $icon.attr("src", emojiUrlFor(code)); + }, +}); diff --git a/app/assets/javascripts/discourse/lib/emoji/groups.js.es6 b/app/assets/javascripts/discourse/lib/emoji/groups.js.es6 deleted file mode 100644 index 6f2eaf28028..00000000000 --- a/app/assets/javascripts/discourse/lib/emoji/groups.js.es6 +++ /dev/null @@ -1,1555 +0,0 @@ -// This file is generated by emoji.rake do not modify directly - -// note that these categories are copied from Slack -const groups = [ - { - "name": "people", - "fullname": "People", - "tabicon": "grinning", - "icons": [ - "grinning", - "grin", - "joy", - "rofl", - "smiley", - "smile", - "sweat_smile", - "laughing", - "wink", - "blush", - "yum", - "sunglasses", - "heart_eyes", - "kissing_heart", - "kissing", - "kissing_smiling_eyes", - "kissing_closed_eyes", - "relaxed", - "slightly_smiling_face", - "hugs", - "star_struck", - "thinking", - "face_with_raised_eyebrow", - "neutral_face", - "expressionless", - "no_mouth", - "roll_eyes", - "smirk", - "persevere", - "disappointed_relieved", - "open_mouth", - "zipper_mouth_face", - "hushed", - "sleepy", - "tired_face", - "sleeping", - "relieved", - "stuck_out_tongue", - "stuck_out_tongue_winking_eye", - "stuck_out_tongue_closed_eyes", - "drooling_face", - "unamused", - "sweat", - "pensive", - "confused", - "upside_down_face", - "money_mouth_face", - "astonished", - "frowning_face", - "slightly_frowning_face", - "confounded", - "disappointed", - "worried", - "triumph", - "cry", - "sob", - "frowning", - "anguished", - "fearful", - "weary", - "exploding_head", - "grimacing", - "cold_sweat", - "scream", - "flushed", - "crazy_face", - "dizzy_face", - "rage", - "angry", - "face_with_symbols_over_mouth", - "mask", - "face_with_thermometer", - "face_with_head_bandage", - "nauseated_face", - "face_vomiting", - "sneezing_face", - "innocent", - "cowboy_hat_face", - "clown_face", - "lying_face", - "sushing_face", - "face_with_hand_over_mouth", - "face_with_monocle", - "nerd_face", - "smiling_imp", - "imp", - "japanese_ogre", - "japanese_goblin", - "skull", - "skull_and_crossbones", - "ghost", - "alien", - "space_invader", - "robot", - "poop", - "smiley_cat", - "smile_cat", - "joy_cat", - "heart_eyes_cat", - "smirk_cat", - "kissing_cat", - "scream_cat", - "crying_cat_face", - "pouting_cat", - "see_no_evil", - "hear_no_evil", - "speak_no_evil", - "baby", - "child", - "boy", - "girl", - "adult", - "man", - "woman", - "older_adult", - "older_man", - "older_woman", - "man_health_worker", - "woman_health_worker", - "man_student", - "woman_student", - "man_teacher", - "woman_teacher", - "man_judge", - "woman_judge", - "man_farmer", - "woman_farmer", - "man_cook", - "woman_cook", - "man_mechanic", - "woman_mechanic", - "man_factory_worker", - "woman_factory_worker", - "man_office_worker", - "woman_office_worker", - "man_scientist", - "woman_scientist", - "man_technologist", - "woman_technologist", - "man_singer", - "woman_singer", - "man_artist", - "woman_artist", - "man_pilot", - "woman_pilot", - "man_astronaut", - "woman_astronaut", - "man_firefighter", - "woman_firefighter", - "policeman", - "policewoman", - "male_detective", - "female_detective", - "guardsman", - "guardswoman", - "construction_worker_man", - "construction_worker_woman", - "prince", - "princess", - "man_with_turban", - "woman_with_turban", - "man_with_gua_pi_mao", - "woman_with_headscarf", - "bearded_person", - "blonde_man", - "blonde_woman", - "man_in_tuxedo", - "bride_with_veil", - "pregnant_woman", - "breast_feeding", - "angel", - "santa", - "mrs_claus", - "mage", - "fairy", - "vampire", - "merperson", - "elf", - "genie", - "zombie", - "frowning_woman", - "frowning_man", - "pouting_woman", - "pouting_man", - "no_good_woman", - "no_good_man", - "ok_woman", - "ok_man", - "tipping_hand_woman", - "tipping_hand_man", - "raising_hand_woman", - "raising_hand_man", - "bowing_man", - "bowing_woman", - "man_facepalming", - "woman_facepalming", - "man_shrugging", - "woman_shrugging", - "couple", - "two_men_holding_hands", - "two_women_holding_hands", - "couplekiss_man_woman", - "couplekiss_man_man", - "couplekiss_woman_woman", - "couple_with_heart_woman_man", - "couple_with_heart_man_man", - "couple_with_heart_woman_woman", - "family_man_woman_boy", - "family_man_woman_girl", - "family_man_woman_girl_boy", - "family_man_woman_boy_boy", - "family_man_woman_girl_girl", - "family_man_man_boy", - "family_man_man_girl", - "family_man_man_girl_boy", - "family_man_man_boy_boy", - "family_man_man_girl_girl", - "family_woman_woman_boy", - "family_woman_woman_girl", - "family_woman_woman_girl_boy", - "family_woman_woman_boy_boy", - "family_woman_woman_girl_girl", - "family_man_boy", - "family_man_boy_boy", - "family_man_girl", - "family_man_girl_boy", - "family_man_girl_girl", - "family_woman_boy", - "family_woman_boy_boy", - "family_woman_girl", - "family_woman_girl_boy", - "family_woman_girl_girl", - "selfie", - "muscle", - "point_left", - "point_right", - "point_up", - "point_up_2", - "fu", - "point_down", - "v", - "crossed_fingers", - "vulcan_salute", - "metal", - "call_me_hand", - "raised_hand_with_fingers_splayed", - "raised_hand", - "ok_hand", - "+1", - "-1", - "fist", - "facepunch", - "fist_left", - "fist_right", - "raised_back_of_hand", - "wave", - "love_you_gesture", - "writing_hand", - "clap", - "open_hands", - "raised_hands", - "palms_up_together", - "pray", - "handshake", - "nail_care", - "ear", - "nose", - "footprints", - "eyes", - "eye", - "brain", - "tongue", - "lips" - ] - }, - { - "name": "nature", - "fullname": "Nature", - "tabicon": "evergreen_tree", - "icons": [ - "monkey_face", - "monkey", - "gorilla", - "dog", - "dog2", - "poodle", - "wolf", - "fox_face", - "cat", - "cat2", - "lion", - "tiger", - "tiger2", - "leopard", - "horse", - "racehorse", - "unicorn", - "zebra", - "deer", - "cow", - "ox", - "water_buffalo", - "cow2", - "pig", - "pig2", - "boar", - "pig_nose", - "ram", - "sheep", - "goat", - "dromedary_camel", - "camel", - "giraffe", - "elephant", - "rhinoceros", - "mouse", - "mouse2", - "rat", - "hamster", - "rabbit", - "rabbit2", - "chipmunk", - "hedgehog", - "bat", - "bear", - "koala", - "panda_face", - "paw_prints", - "turkey", - "chicken", - "rooster", - "hatching_chick", - "baby_chick", - "hatched_chick", - "bird", - "penguin", - "dove", - "eagle", - "duck", - "owl", - "frog", - "crocodile", - "turtle", - "lizard", - "snake", - "dragon_face", - "dragon", - "sauropod", - "t_rex", - "whale", - "whale2", - "dolphin", - "fish", - "tropical_fish", - "blowfish", - "shark", - "octopus", - "shell", - "crab", - "shrimp", - "squid", - "snail", - "butterfly", - "bug", - "ant", - "honeybee", - "beetle", - "cricket", - "spider", - "spider_web", - "scorpion", - "bouquet", - "cherry_blossom", - "white_flower", - "rosette", - "rose", - "wilted_flower", - "hibiscus", - "sunflower", - "blossom", - "tulip", - "seedling", - "evergreen_tree", - "deciduous_tree", - "palm_tree", - "cactus", - "ear_of_rice", - "herb", - "shamrock", - "four_leaf_clover", - "maple_leaf", - "fallen_leaf", - "leaves", - "new_moon", - "waxing_crescent_moon", - "first_quarter_moon", - "waxing_gibbous_moon", - "full_moon", - "waning_gibbous_moon", - "last_quarter_moon", - "waning_crescent_moon", - "crescent_moon", - "new_moon_with_face", - "first_quarter_moon_with_face", - "last_quarter_moon_with_face", - "thermometer", - "sunny", - "full_moon_with_face", - "sun_with_face", - "star", - "star2", - "stars", - "cloud", - "partly_sunny", - "cloud_with_lightning_and_rain", - "sun_behind_small_cloud", - "sun_behind_large_cloud", - "sun_behind_rain_cloud", - "cloud_with_rain", - "cloud_with_snow", - "cloud_with_lightning", - "tornado", - "fog", - "wind_face", - "cyclone", - "rainbow", - "closed_umbrella", - "open_umbrella", - "umbrella", - "parasol_on_ground", - "zap", - "snowflake", - "snowman_with_snow", - "snowman", - "comet", - "fire", - "droplet", - "ocean" - ] - }, - { - "name": "food", - "fullname": "Food & Drink", - "tabicon": "hamburger", - "icons": [ - "grapes", - "melon", - "watermelon", - "tangerine", - "lemon", - "banana", - "pineapple", - "apple", - "green_apple", - "pear", - "peach", - "cherries", - "strawberry", - "kiwi_fruit", - "tomato", - "coconut", - "avocado", - "eggplant", - "potato", - "carrot", - "corn", - "hot_pepper", - "cucumber", - "broccoli", - "mushroom", - "peanuts", - "chestnut", - "bread", - "croissant", - "baguette_bread", - "pretzel", - "pancakes", - "cheese", - "meat_on_bone", - "poultry_leg", - "cut_of_meat", - "bacon", - "hamburger", - "fries", - "pizza", - "hotdog", - "sandwich", - "taco", - "burrito", - "stuffed_flatbread", - "egg", - "fried_egg", - "shallow_pan_of_food", - "stew", - "bowl_with_spoon", - "green_salad", - "popcorn", - "canned_food", - "bento", - "rice_cracker", - "rice_ball", - "rice", - "curry", - "ramen", - "spaghetti", - "sweet_potato", - "oden", - "sushi", - "fried_shrimp", - "fish_cake", - "dango", - "dumpling", - "fortune_cookie", - "takeout_box", - "icecream", - "shaved_ice", - "ice_cream", - "doughnut", - "cookie", - "birthday", - "cake", - "pie", - "chocolate_bar", - "candy", - "lollipop", - "custard", - "honey_pot", - "baby_bottle", - "milk_glass", - "coffee", - "tea", - "sake", - "champagne", - "wine_glass", - "cocktail", - "tropical_drink", - "beer", - "beers", - "clinking_glasses", - "tumbler_glass", - "cup_with_straw", - "chopsticks", - "plate_with_cutlery", - "fork_and_knife", - "spoon", - "hocho", - "amphora" - ] - }, - { - "name": "celebration", - "fullname": "Celebration", - "tabicon": "gift", - "icons": [ - "jack_o_lantern", - "christmas_tree", - "fireworks", - "sparkler", - "sparkles", - "balloon", - "tada", - "confetti_ball", - "tanabata_tree", - "bamboo", - "dolls", - "flags", - "wind_chime", - "rice_scene", - "ribbon", - "gift", - "reminder_ribbon", - "tickets", - "ticket", - "kiss", - "cupid", - "heart", - "heartbeat", - "broken_heart", - "two_hearts", - "sparkling_heart", - "heartpulse", - "blue_heart", - "green_heart", - "yellow_heart", - "orange_heart", - "purple_heart", - "black_heart", - "gift_heart", - "revolving_hearts", - "heart_decoration", - "heavy_heart_exclamation", - "love_letter", - "zzz", - "anger", - "bomb", - "boom", - "sweat_drops", - "dash", - "dizzy", - "speech_balloon", - "left_speech_bubble", - "right_anger_bubble", - "thought_balloon", - "hole" - ] - }, - { - "name": "activity", - "fullname": "Activities", - "tabicon": "soccer", - "icons": [ - "massage_woman", - "massage_man", - "haircut_woman", - "haircut_man", - "walking_man", - "walking_woman", - "running_man", - "running_woman", - "dancer", - "man_dancing", - "dancing_women", - "dancing_men", - "person_in_steamy_room", - "person_climbing", - "person_in_lotus_position", - "bath", - "sleeping_bed", - "business_suit_levitating", - "speaking_head", - "bust_in_silhouette", - "busts_in_silhouette", - "person_fencing", - "horse_racing", - "skier", - "snowboarder", - "golfing_man", - "golfing_woman", - "surfing_man", - "surfing_woman", - "rowing_man", - "rowing_woman", - "swimming_man", - "swimming_woman", - "basketball_man", - "basketball_woman", - "weight_lifting_man", - "weight_lifting_woman", - "biking_man", - "biking_woman", - "mountain_biking_man", - "mountain_biking_woman", - "racing_car", - "motorcycle", - "man_cartwheeling", - "woman_cartwheeling", - "men_wrestling", - "women_wrestling", - "man_playing_water_polo", - "woman_playing_water_polo", - "man_playing_handball", - "woman_playing_handball", - "man_juggling", - "woman_juggling", - "soccer", - "baseball", - "basketball", - "volleyball", - "football", - "rugby_football", - "tennis", - "8ball", - "bowling", - "cricket_bat_and_ball", - "field_hockey", - "ice_hockey", - "ping_pong", - "badminton", - "boxing_glove", - "martial_arts_uniform", - "goal_net", - "dart", - "golf", - "ice_skate", - "fishing_pole_and_fish", - "running_shirt_with_sash", - "ski", - "sled", - "curling_stone", - "video_game", - "joystick", - "game_die", - "spades", - "hearts", - "diamonds", - "clubs", - "black_joker", - "mahjong", - "flower_playing_cards", - "musical_score", - "musical_note", - "notes", - "studio_microphone", - "level_slider", - "control_knobs", - "microphone", - "headphones", - "radio", - "saxophone", - "guitar", - "musical_keyboard", - "trumpet", - "violin", - "drum" - ] - }, - { - "name": "travel", - "fullname": "Travel & Places", - "tabicon": "airplane", - "icons": [ - "earth_africa", - "earth_americas", - "earth_asia", - "globe_with_meridians", - "world_map", - "japan", - "mountain_snow", - "mountain", - "volcano", - "mount_fuji", - "camping", - "beach_umbrella", - "desert", - "desert_island", - "national_park", - "stadium", - "classical_building", - "building_construction", - "houses", - "cityscape", - "derelict_house", - "house", - "house_with_garden", - "office", - "post_office", - "european_post_office", - "hospital", - "bank", - "hotel", - "love_hotel", - "convenience_store", - "school", - "department_store", - "factory", - "japanese_castle", - "european_castle", - "wedding", - "tokyo_tower", - "statue_of_liberty", - "church", - "mosque", - "synagogue", - "shinto_shrine", - "kaaba", - "fountain", - "tent", - "foggy", - "night_with_stars", - "sunrise_over_mountains", - "sunrise", - "city_sunset", - "city_sunrise", - "bridge_at_night", - "hotsprings", - "milky_way", - "carousel_horse", - "ferris_wheel", - "roller_coaster", - "barber", - "circus_tent", - "performing_arts", - "framed_picture", - "art", - "slot_machine", - "steam_locomotive", - "railway_car", - "bullettrain_side", - "bullettrain_front", - "train2", - "metro", - "light_rail", - "station", - "tram", - "monorail", - "mountain_railway", - "train", - "bus", - "oncoming_bus", - "trolleybus", - "minibus", - "ambulance", - "fire_engine", - "police_car", - "oncoming_police_car", - "taxi", - "oncoming_taxi", - "red_car", - "oncoming_automobile", - "blue_car", - "truck", - "articulated_lorry", - "tractor", - "bike", - "kick_scooter", - "motor_scooter", - "busstop", - "motorway", - "railway_track", - "fuelpump", - "rotating_light", - "traffic_light", - "vertical_traffic_light", - "construction", - "stop_sign", - "anchor", - "sailboat", - "canoe", - "speedboat", - "passenger_ship", - "ferry", - "motor_boat", - "ship", - "airplane", - "small_airplane", - "flight_departure", - "flight_arrival", - "seat", - "helicopter", - "suspension_railway", - "mountain_cableway", - "aerial_tramway", - "artificial_satellite", - "rocket", - "flying_saucer", - "bellhop_bell", - "door", - "bed", - "couch_and_lamp", - "toilet", - "shower", - "bathtub", - "checkered_flag", - "triangular_flag_on_post", - "crossed_flags", - "black_flag", - "white_flag", - "rainbow_flag", - "ascension_island", - "andorra", - "united_arab_emirates", - "afghanistan", - "antigua_barbuda", - "anguilla", - "albania", - "armenia", - "angola", - "antarctica", - "argentina", - "american_samoa", - "austria", - "australia", - "aruba", - "aland_islands", - "azerbaijan", - "bosnia_herzegovina", - "barbados", - "bangladesh", - "belgium", - "burkina_faso", - "bulgaria", - "bahrain", - "burundi", - "benin", - "st_barthelemy", - "bermuda", - "brunei", - "bolivia", - "caribbean_netherlands", - "brazil", - "bahamas", - "bhutan", - "bouvet_island", - "botswana", - "belarus", - "belize", - "canada", - "cocos_islands", - "congo_kinshasa", - "central_african_republic", - "congo_brazzaville", - "switzerland", - "cote_divoire", - "cook_islands", - "chile", - "cameroon", - "cn", - "colombia", - "clipperton_island", - "costa_rica", - "cuba", - "cape_verde", - "curacao", - "christmas_island", - "cyprus", - "czech_republic", - "de", - "diego_garcia", - "djibouti", - "denmark", - "dominica", - "dominican_republic", - "algeria", - "ceuta_and_melilla", - "ecuador", - "estonia", - "egypt", - "western_sahara", - "eritrea", - "es", - "ethiopia", - "eu", - "finland", - "fiji", - "falkland_islands", - "micronesia", - "faroe_islands", - "fr", - "gabon", - "uk", - "grenada", - "georgia", - "french_guiana", - "guernsey", - "ghana", - "gibraltar", - "greenland", - "gambia", - "guinea", - "guadeloupe", - "equatorial_guinea", - "greece", - "south_georgia_south_sandwich_islands", - "guatemala", - "guam", - "guinea_bissau", - "guyana", - "hong_kong", - "heard_and_mc_donald_islands", - "honduras", - "croatia", - "haiti", - "hungary", - "canary_islands", - "indonesia", - "ireland", - "israel", - "isle_of_man", - "india", - "british_indian_ocean_territory", - "iraq", - "iran", - "iceland", - "it", - "jersey", - "jamaica", - "jordan", - "jp", - "kenya", - "kyrgyzstan", - "cambodia", - "kiribati", - "comoros", - "st_kitts_nevis", - "north_korea", - "kr", - "kuwait", - "cayman_islands", - "kazakhstan", - "laos", - "lebanon", - "st_lucia", - "liechtenstein", - "sri_lanka", - "liberia", - "lesotho", - "lithuania", - "luxembourg", - "latvia", - "libya", - "morocco", - "monaco", - "moldova", - "montenegro", - "st_martin", - "madagascar", - "marshall_islands", - "macedonia", - "mali", - "myanmar", - "mongolia", - "macau", - "northern_mariana_islands", - "martinique", - "mauritania", - "montserrat", - "malta", - "mauritius", - "maldives", - "malawi", - "mexico", - "malaysia", - "mozambique", - "namibia", - "new_caledonia", - "niger", - "norfolk_island", - "nigeria", - "nicaragua", - "netherlands", - "norway", - "nepal", - "nauru", - "niue", - "new_zealand", - "oman", - "panama", - "peru", - "french_polynesia", - "papua_new_guinea", - "philippines", - "pakistan", - "poland", - "st_pierre_miquelon", - "pitcairn_islands", - "puerto_rico", - "palestinian_territories", - "portugal", - "palau", - "paraguay", - "qatar", - "reunion", - "romania", - "serbia", - "ru", - "rwanda", - "saudi_arabia", - "solomon_islands", - "seychelles", - "sudan", - "sweden", - "singapore", - "st_helena", - "slovenia", - "svalbard_and_jan_mayen", - "slovakia", - "sierra_leone", - "san_marino", - "senegal", - "somalia", - "suriname", - "south_sudan", - "sao_tome_principe", - "el_salvador", - "sint_maarten", - "syria", - "swaziland", - "tristan_da_cunha", - "turks_caicos_islands", - "chad", - "french_southern_territories", - "togo", - "thailand", - "tajikistan", - "tokelau", - "timor_leste", - "turkmenistan", - "tunisia", - "tonga", - "tr", - "trinidad_tobago", - "tuvalu", - "taiwan", - "tanzania", - "ukraine", - "uganda", - "us_outlying_islands", - "united_nations", - "us", - "uruguay", - "uzbekistan", - "vatican_city", - "st_vincent_grenadines", - "venezuela", - "british_virgin_islands", - "us_virgin_islands", - "vietnam", - "vanuatu", - "wallis_futuna", - "samoa", - "kosovo", - "yemen", - "mayotte", - "south_africa", - "zambia", - "zimbabwe" - ] - }, - { - "name": "objects", - "fullname": "Objects & Symbols", - "tabicon": "eyeglasses", - "icons": [ - "eyeglasses", - "dark_sunglasses", - "necktie", - "tshirt", - "jeans", - "scarf", - "gloves", - "coat", - "socks", - "dress", - "kimono", - "bikini", - "womans_clothes", - "purse", - "handbag", - "pouch", - "shopping", - "school_satchel", - "mans_shoe", - "athletic_shoe", - "high_heel", - "sandal", - "boot", - "crown", - "womans_hat", - "tophat", - "mortar_board", - "billed_cap", - "rescue_worker_helmet", - "prayer_beads", - "lipstick", - "ring", - "gem", - "medal_military", - "trophy", - "medal_sports", - "1st_place_medal", - "2nd_place_medal", - "3rd_place_medal", - "mute", - "speaker", - "sound", - "loud_sound", - "loudspeaker", - "mega", - "postal_horn", - "bell", - "no_bell", - "iphone", - "calling", - "phone", - "telephone_receiver", - "pager", - "fax", - "battery", - "electric_plug", - "computer", - "desktop_computer", - "printer", - "keyboard", - "computer_mouse", - "trackball", - "minidisc", - "floppy_disk", - "cd", - "dvd", - "movie_camera", - "film_strip", - "film_projector", - "clapper", - "tv", - "camera", - "camera_flash", - "video_camera", - "vhs", - "mag", - "mag_right", - "microscope", - "telescope", - "satellite", - "candle", - "bulb", - "flashlight", - "izakaya_lantern", - "notebook_with_decorative_cover", - "closed_book", - "open_book", - "green_book", - "blue_book", - "orange_book", - "books", - "notebook", - "ledger", - "page_with_curl", - "scroll", - "page_facing_up", - "newspaper", - "newspaper_roll", - "bookmark_tabs", - "bookmark", - "label", - "moneybag", - "yen", - "dollar", - "euro", - "pound", - "money_with_wings", - "credit_card", - "chart", - "currency_exchange", - "heavy_dollar_sign", - "email", - "e-mail", - "incoming_envelope", - "envelope_with_arrow", - "outbox_tray", - "inbox_tray", - "package", - "mailbox", - "mailbox_closed", - "mailbox_with_mail", - "mailbox_with_no_mail", - "postbox", - "ballot_box", - "pencil2", - "black_nib", - "fountain_pen", - "pen", - "paintbrush", - "crayon", - "memo", - "briefcase", - "file_folder", - "open_file_folder", - "card_index_dividers", - "date", - "calendar", - "spiral_notepad", - "spiral_calendar", - "card_index", - "chart_with_upwards_trend", - "chart_with_downwards_trend", - "bar_chart", - "clipboard", - "pushpin", - "round_pushpin", - "paperclip", - "paperclips", - "straight_ruler", - "triangular_ruler", - "scissors", - "card_file_box", - "file_cabinet", - "wastebasket", - "lock", - "unlock", - "lock_with_ink_pen", - "closed_lock_with_key", - "key", - "old_key", - "hammer", - "pick", - "hammer_and_pick", - "hammer_and_wrench", - "dagger", - "crossed_swords", - "gun", - "bow_and_arrow", - "shield", - "wrench", - "nut_and_bolt", - "gear", - "clamp", - "alembic", - "balance_scale", - "link", - "chains", - "syringe", - "pill", - "smoking", - "coffin", - "funeral_urn", - "moyai", - "oil_drum", - "crystal_ball", - "shopping_cart", - "atm", - "put_litter_in_its_place", - "potable_water", - "wheelchair", - "mens", - "womens", - "restroom", - "baby_symbol", - "wc", - "passport_control", - "customs", - "baggage_claim", - "left_luggage", - "warning", - "children_crossing", - "no_entry", - "no_entry_sign", - "no_bicycles", - "no_smoking", - "do_not_litter", - "non-potable_water", - "no_pedestrians", - "no_mobile_phones", - "underage", - "radioactive", - "biohazard", - "arrow_up", - "arrow_upper_right", - "arrow_right", - "arrow_lower_right", - "arrow_down", - "arrow_lower_left", - "arrow_left", - "arrow_upper_left", - "arrow_up_down", - "left_right_arrow", - "leftwards_arrow_with_hook", - "arrow_right_hook", - "arrow_heading_up", - "arrow_heading_down", - "arrows_clockwise", - "arrows_counterclockwise", - "back", - "end", - "on", - "soon", - "top", - "place_of_worship", - "atom_symbol", - "om", - "star_of_david", - "wheel_of_dharma", - "yin_yang", - "latin_cross", - "orthodox_cross", - "star_and_crescent", - "peace_symbol", - "menorah", - "six_pointed_star", - "aries", - "taurus", - "gemini", - "cancer", - "leo", - "virgo", - "libra", - "scorpius", - "sagittarius", - "capricorn", - "aquarius", - "pisces", - "ophiuchus", - "twisted_rightwards_arrows", - "repeat", - "repeat_one", - "arrow_forward", - "fast_forward", - "next_track_button", - "play_or_pause_button", - "arrow_backward", - "rewind", - "previous_track_button", - "arrow_up_small", - "arrow_double_up", - "arrow_down_small", - "arrow_double_down", - "pause_button", - "stop_button", - "record_button", - "cinema", - "low_brightness", - "high_brightness", - "signal_strength", - "vibration_mode", - "mobile_phone_off", - "recycle", - "fleur_de_lis", - "trident", - "name_badge", - "beginner", - "o", - "white_check_mark", - "ballot_box_with_check", - "heavy_check_mark", - "heavy_multiplication_x", - "x", - "negative_squared_cross_mark", - "heavy_plus_sign", - "heavy_minus_sign", - "heavy_division_sign", - "curly_loop", - "loop", - "part_alternation_mark", - "eight_spoked_asterisk", - "eight_pointed_black_star", - "sparkle", - "bangbang", - "interrobang", - "question", - "grey_question", - "grey_exclamation", - "exclamation", - "wavy_dash", - "copyright", - "registered", - "tm", - "hash", - "asterisk", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "keycap_ten", - "100", - "capital_abcd", - "abcd", - "1234", - "symbols", - "abc", - "a", - "ab", - "b", - "cl", - "cool", - "free", - "information_source", - "id", - "m", - "new", - "ng", - "o2", - "ok", - "parking", - "sos", - "up", - "vs", - "koko", - "sa", - "u6708", - "u6709", - "u6307", - "ideograph_advantage", - "u5272", - "u7121", - "u7981", - "accept", - "u7533", - "u5408", - "u7a7a", - "congratulations", - "secret", - "u55b6", - "u6e80", - "black_small_square", - "white_small_square", - "white_medium_square", - "black_medium_square", - "white_medium_small_square", - "black_medium_small_square", - "black_large_square", - "white_large_square", - "large_orange_diamond", - "large_blue_diamond", - "small_orange_diamond", - "small_blue_diamond", - "small_red_triangle", - "small_red_triangle_down", - "diamond_shape_with_a_dot_inside", - "radio_button", - "black_square_button", - "white_square_button", - "white_circle", - "black_circle", - "red_circle", - "large_blue_circle", - "hourglass", - "hourglass_flowing_sand", - "watch", - "alarm_clock", - "stopwatch", - "timer_clock", - "mantelpiece_clock", - "clock12", - "clock1230", - "clock1", - "clock130", - "clock2", - "clock230", - "clock3", - "clock330", - "clock4", - "clock430", - "clock5", - "clock530", - "clock6", - "clock630", - "clock7", - "clock730", - "clock8", - "clock830", - "clock9", - "clock930", - "clock10", - "clock1030", - "clock11", - "clock1130" - ] - } -]; - -export default groups; diff --git a/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 b/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 deleted file mode 100644 index 9ef409b3d4c..00000000000 --- a/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 +++ /dev/null @@ -1,208 +0,0 @@ -import groups from 'discourse/lib/emoji/groups'; -import KeyValueStore from "discourse/lib/key-value-store"; -import { emojiList, isSkinTonableEmoji } from 'pretty-text/emoji'; -import { emojiUrlFor } from 'discourse/lib/text'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; - -const keyValueStore = new KeyValueStore("discourse_emojis_"); -const EMOJI_USAGE = "emojiUsage"; - -let PER_ROW = 12; -const PER_PAGE = 60; - -let ungroupedIcons, recentlyUsedIcons; -let selectedSkinTone = keyValueStore.getObject('selectedSkinTone') || 1; - -if (!keyValueStore.getObject(EMOJI_USAGE)) { - keyValueStore.setObject({key: EMOJI_USAGE, value: {}}); -} - -function closeSelector() { - $('.emoji-modal, .emoji-modal-wrapper').remove(); - $('body, textarea').off('keydown.emoji'); -} - -function initializeUngroupedIcons() { - const groupedIcons = {}; - - groups.forEach(group => { - group.icons.forEach(icon => groupedIcons[icon] = true); - }); - - ungroupedIcons = []; - const emojis = emojiList(); - emojis.forEach(emoji => { - if (groupedIcons[emoji] !== true) { - ungroupedIcons.push(emoji); - } - }); - - if (ungroupedIcons.length) { - groups.push({name: 'ungrouped', icons: ungroupedIcons}); - } -} - -function trackEmojiUsage(title) { - const recent = keyValueStore.getObject(EMOJI_USAGE) || {}; - - if (!recent[title]) { recent[title] = { title: title, usage: 0 }; } - recent[title]["usage"]++; - - keyValueStore.setObject({key: EMOJI_USAGE, value: recent}); - - // clear the cache - recentlyUsedIcons = null; -} - -function sortByUsage(a, b) { - if (a.usage > b.usage) { return -1; } - if (b.usage > a.usage) { return 1; } - return a.title.localeCompare(b.title); -} - -function initializeRecentlyUsedIcons() { - recentlyUsedIcons = []; - - const usage = _.map(keyValueStore.getObject(EMOJI_USAGE)).sort(sortByUsage); - const recent = usage.slice(0, PER_ROW); - - if (recent.length > 0) { - - recent.forEach(emoji => recentlyUsedIcons.push(emoji.title)); - - const recentGroup = groups.findBy('name', 'recent'); - if (recentGroup) { - recentGroup.icons = recentlyUsedIcons; - } else { - groups.push({ name: 'recent', icons: recentlyUsedIcons }); - } - } -} - -function toolbar(selected) { - if (!ungroupedIcons) { initializeUngroupedIcons(); } - if (!recentlyUsedIcons) { initializeRecentlyUsedIcons(); } - - return groups.map((g, i) => { - let icon = g.tabicon; - let title = g.fullname; - if (g.name === "recent") { - icon = "star"; - title = "Recent"; - } else if (g.name === "ungrouped") { - icon = g.icons[0]; - title = "Custom"; - } - - return { src: emojiUrlFor(icon), - title, - groupId: i, - selected: i === selected }; - }); -} - -function bindEvents(page, offset, options) { - $('.emoji-page a').click(e => { - const title = $(e.currentTarget).attr('title'); - trackEmojiUsage(title); - options.onSelect(title); - closeSelector(); - return false; - }).hover(e => { - const title = $(e.currentTarget).attr('title'); - const html = " :" + title + ":"; - $('.emoji-modal .info').html(html); - }, () => $('.emoji-modal .info').html("")); - - $('.emoji-modal .nav .next a').click(() => render(page, offset+PER_PAGE, options)); - $('.emoji-modal .nav .prev a').click(() => render(page, offset-PER_PAGE, options)); - - $('.emoji-modal .toolbar a').click(function(){ - const p = parseInt($(this).data('group-id')); - render(p, 0, options); - return false; - }); - - $('.emoji-modal .tones-button').click(function(){ - selectedSkinTone = parseInt($(this).data('skin-tone')); - keyValueStore.setObject({key: 'selectedSkinTone', value: selectedSkinTone}); - render(page, offset, options); - return false; - }); -} - -function render(page, offset, options) { - keyValueStore.set({key: "emojiPage", value: page}); - keyValueStore.set({key: "emojiOffset", value: offset}); - - const toolbarItems = toolbar(page); - const rows = []; - let row = []; - const icons = groups[page].icons; - const max = offset + PER_PAGE; - - for(let i=offset; i icons.length, - modalClass: options.modalClass - }; - - $('.emoji-modal', options.appendTo).remove(); - const template = findRawTemplate('emoji-toolbar'); - options.appendTo.append(template(model)); - - bindEvents(page, offset, options); -} - -function showSelector(options) { - options = options || {}; - options.appendTo = options.appendTo || $('body'); - - options.appendTo.append('
'); - $('.emoji-modal-wrapper').click(() => closeSelector()); - - if (Discourse.Site.currentProp('mobileView')) { PER_ROW = 9; } - const page = options.page ? _.findIndex(groups, (g) => { return g.name === options.page; }) - : keyValueStore.getInt("emojiPage", 0); - const offset = keyValueStore.getInt("emojiOffset", 0); - - render(page, offset, options); - - $('body, textarea').on('keydown.emoji', e => { - if (e.which === 27) { - closeSelector(); - return false; - } - }); -} - -export { showSelector }; diff --git a/app/assets/javascripts/discourse/templates/components/d-editor.hbs b/app/assets/javascripts/discourse/templates/components/d-editor.hbs index 78d00be8745..961b63c6efd 100644 --- a/app/assets/javascripts/discourse/templates/components/d-editor.hbs +++ b/app/assets/javascripts/discourse/templates/components/d-editor.hbs @@ -33,3 +33,5 @@ {{plugin-outlet name="editor-preview"}} + +{{emoji-picker active=emojiPickerIsActive emojiSelected=(action 'emojiSelected')}} diff --git a/app/assets/javascripts/discourse/templates/components/emoji-picker.hbs b/app/assets/javascripts/discourse/templates/components/emoji-picker.hbs new file mode 100644 index 00000000000..a5a525b4f12 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/emoji-picker.hbs @@ -0,0 +1,2 @@ +
+
diff --git a/app/assets/javascripts/discourse/templates/emoji-picker-recent.raw.hbs b/app/assets/javascripts/discourse/templates/emoji-picker-recent.raw.hbs new file mode 100644 index 00000000000..4f309612fbe --- /dev/null +++ b/app/assets/javascripts/discourse/templates/emoji-picker-recent.raw.hbs @@ -0,0 +1,5 @@ +{{#each recentEmojis as |emoji|}} + + + +{{/each}} diff --git a/app/assets/javascripts/discourse/templates/emoji-picker.raw.hbs.erb b/app/assets/javascripts/discourse/templates/emoji-picker.raw.hbs.erb new file mode 100644 index 00000000000..990f94b4762 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/emoji-picker.raw.hbs.erb @@ -0,0 +1,88 @@ +
+
+ + + +
+ + <% JSON.parse(File.read("lib/emoji/groups.json")).each.with_index do |group, group_index| %> +
+ + + +
+ <% end %> + + <% if !Emoji.custom.blank? %> +
+ + + +
+ <% end %> +
+ +
+
+ + +
+ +
+ +
+
+
+ {{i18n 'emoji_picker.recent'}} + {{fa-icon 'trash'}} +
+
+
+ + <% JSON.parse(File.read("lib/emoji/groups.json")).each.with_index do |group, group_index| %> +
+
+ {{i18n 'emoji_picker.<%= group["name"] %>'}} +
+ +
+ <% end %> + + {{#if customEmojis.length}} +
+
+ {{i18n 'emoji_picker.custom'}} +
+
+ {{#each customEmojis as |emoji|}} + + + + {{/each}} +
+
+ {{/if}} +
+ +
diff --git a/app/assets/javascripts/discourse/templates/emoji-toolbar.raw.hbs b/app/assets/javascripts/discourse/templates/emoji-toolbar.raw.hbs deleted file mode 100644 index fb684b57d67..00000000000 --- a/app/assets/javascripts/discourse/templates/emoji-toolbar.raw.hbs +++ /dev/null @@ -1,45 +0,0 @@ -
-
    - {{#each toolbarItems as |item|}}
  • {{/each}} -
-
- - {{#each rows as |row|}} - - {{#each row as |item|}} - - {{/each}} - - {{/each}} -
-
- - - -
-
diff --git a/app/assets/javascripts/pretty-text/emoji.js.es6 b/app/assets/javascripts/pretty-text/emoji.js.es6.erb similarity index 90% rename from app/assets/javascripts/pretty-text/emoji.js.es6 rename to app/assets/javascripts/pretty-text/emoji.js.es6.erb index 2946f35109b..136c2904261 100644 --- a/app/assets/javascripts/pretty-text/emoji.js.es6 +++ b/app/assets/javascripts/pretty-text/emoji.js.es6.erb @@ -1,7 +1,7 @@ import { emojis, aliases, translations, tonableEmojis } from 'pretty-text/emoji/data'; // bump up this number to expire all emojis -export const IMAGE_VERSION = "5"; +export const IMAGE_VERSION = "<%= Emoji::EMOJI_VERSION %>"; const extendedEmoji = {}; @@ -10,10 +10,8 @@ export function registerEmoji(code, url) { extendedEmoji[code] = url; } -export function emojiList() { - const result = emojis.slice(0); - _.each(extendedEmoji, (v,k) => result.push(k)); - return result; +export function extendedEmojiList() { + return extendedEmoji; } const emojiHash = {}; @@ -54,8 +52,7 @@ export function isCustomEmoji(code, opts) { export function buildEmojiUrl(code, opts) { let url; - code = code.toLowerCase(); - + code = String(code).toLowerCase(); if (extendedEmoji.hasOwnProperty(code)) { url = extendedEmoji[code]; } @@ -116,10 +113,9 @@ export function emojiSearch(term, options) { }; export function isSkinTonableEmoji(term) { - let match = term.match(/^:?(.*?):?$/); + const match = _.compact(term.split(":"))[0]; if (match) { - return tonableEmojis.indexOf(match[1]) !== -1; - } else { - return tonableEmojis.indexOf(term) !== -1; + return tonableEmojis.indexOf(match) !== -1; } + return false; } diff --git a/app/assets/stylesheets/common/base/emoji.scss b/app/assets/stylesheets/common/base/emoji.scss index 10b1a6812b4..f3b93889c39 100644 --- a/app/assets/stylesheets/common/base/emoji.scss +++ b/app/assets/stylesheets/common/base/emoji.scss @@ -1,128 +1,115 @@ -body img.emoji { - width: 20px; - height: 20px; - vertical-align: middle; -} - -.wmd-emoji-button:before { - content: "\f118"; -} - -.emoji-modal { +.emoji-picker { + background-color: #fff; + border: 1px solid #e9e9e9; + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background-clip: padding-box; z-index: 10000; position: fixed; - left: 50%; - top: 50%; - width: 445px; - min-height: 264px; - margin-top: -132px; - margin-left: -222px; background-color: dark-light-choose(#dadada, blend-primary-secondary(5%)); display: flex; + flex-direction: row; + height: 300px; + border-radius: 3px; +} + +.emoji-picker .categories-column { + display: flex; + flex-direction: column; + background: white; + flex: 1; + align-items: center; + justify-content: space-between; + border-right: 1px solid #e9e9e9; + min-width: 36px; +} + +.emoji-picker .category-icon { + display: block; + margin: 4px auto; + -webkit-filter: grayscale(100%); + filter: grayscale(100%); +} + +.emoji-picker .category-icon.current, .emoji-picker .category-icon:hover { + -webkit-filter: grayscale(0%); + filter: grayscale(0%); +} + +.emoji-picker .main-column { + display: flex; + flex-direction: column; + background: white; + flex: 20; +} + +.emoji-picker .list { + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + padding: 0px; + flex: 1; flex-direction: column; } -table.emoji-page td { - border: 1px solid transparent; - background-color: dark-light-choose(white, $secondary); - padding: 0 !important; +.emoji-picker .list .emoji { + margin: 5px; } -.emoji-page a { +.emoji-picker .section-header { padding: 8px; - display: block; - border-radius: 20px; + margin-bottom: 4px; + padding-bottom: 4px; + border-bottom: 1px solid #e9e9e9; + justify-content: space-between; + display: flex; + align-items: center; } -.emoji-page a:hover { - background-color: dark-light-choose(rgb(210, 236, 252), rgb(45, 19, 3)); +.emoji-picker .section-header .title { } -.emoji-table-wrapper { - min-width: 442px; - min-height: 185px; - background-color: $secondary; +.emoji-picker .section-header .clear-recent .fa{ + margin: 0; } -.emoji-modal-wrapper { - z-index: 9999; - position: fixed; - left: 0; - top: 0; - width: 100%; - height: 100%; - opacity: dark-light-choose(0.8, 0.5); - background-color: black; +.section-group { + flex-wrap: wrap; + display: flex; + align-items: center; + justify-content: flex-start; + padding: 4px; } -.emoji-modal .toolbar { - margin: 8px 0 5px; -} - -.emoji-modal .toolbar li { - display: inline; - padding-right: 1px; -} - -.emoji-modal .toolbar li a { - padding: 8px; - background-color: dark-light-choose(#dadada, blend-primary-secondary(5%)); -} - -.emoji-modal .toolbar li a.selected { - background-color: $secondary; -} - -.emoji-modal .nav span { - color: dark-light-choose(#aaa, #555); -} - -.emoji-modal .nav span.next { - margin-left: 10px; -} - -.emoji-modal .nav a { - color: dark-light-choose(#333, #ccc); -} - -.emoji-shortname { +.section-group a:hover, .results a:hover { display: inline-block; - max-width: 200px; - text-overflow: ellipsis; - overflow: hidden; - vertical-align: middle; + vertical-align: top; + border-radius: 50%; + background-color: #d1f0ff; } -.emoji-modal .footer { - display: flex; +.emoji-picker .footer { align-items: center; + display: flex; justify-content: space-between; - flex-direction: row; - flex-grow: 2; + border-top: 1px solid #e9e9e9; +} + +.emoji-picker .info { + text-overflow: ellipsis; + max-width: 232px; + padding-left: 8px; + white-space: nowrap; + overflow: hidden; + font-weight: 700; + max-width: 125px; +} + +.emoji-picker .diversity-picker { + display: flex; + justify-content: flex-end; padding: 8px; } -.emoji-modal .info { - flex: 10; -} - -.emoji-modal .info span { - margin-left: 5px; - font-weight: bold; - color: $primary; -} - -.emoji-modal .nav { - margin-left: 10px; -} - -.emoji-modal .tones { - display: flex; - align-items: center; - justify-content: space-between; -} - -.emoji-modal .tones-button { +.emoji-picker .diversity-picker .diversity-scale { width: 20px; height: 20px; margin-left: 5px; @@ -133,14 +120,88 @@ table.emoji-page td { justify-content: center; cursor: pointer; } -.emoji-modal .tones-button.default { background: #ffcc4d; } -.emoji-modal .tones-button.light { background: #f7dece; } -.emoji-modal .tones-button.medium-light { background: #f3d2a2; } -.emoji-modal .tones-button.medium { background: #d5ab88; } -.emoji-modal .tones-button.medium-dark { background: #af7e57; } -.emoji-modal .tones-button.dark { background: #7c533e; } +.emoji-picker .diversity-picker .diversity-scale.default { background: #ffcc4d; } +.emoji-picker .diversity-picker .diversity-scale.light { background: #f7dece; } +.emoji-picker .diversity-picker .diversity-scale.medium-light { background: #f3d2a2; } +.emoji-picker .diversity-picker .diversity-scale.medium { background: #d5ab88; } +.emoji-picker .diversity-picker .diversity-scale.medium-dark { background: #af7e57; } +.emoji-picker .diversity-picker .diversity-scale.dark { background: #7c533e; } -.emoji-modal .tones-button i.fa { +.emoji-picker .diversity-picker .diversity-scale.selected i { + display: block; +} + +.emoji-picker .diversity-picker i { + display: none; +} + +.emoji-picker .diversity-picker i.fa { color: #fff; + font-size: 12px; text-shadow: 0.5px 1.5px 0 rgba(0,0,0,0.3); } + +body img.emoji { + width: 20px; + height: 20px; + vertical-align: middle; +} + +.wmd-emoji-button:before { + content: "\f118"; +} + +.emoji-picker-modal.fadeIn { + z-index: 9999; + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + opacity: .8; + background-color: black; +} + +.emoji-picker .filter { + background-color: #e9e9e9; + border-bottom: 1px solid #e9e9e9; + padding: 5px; + display: flex; + position: relative; +} + +.emoji-picker .filter input { + height: 24px; + margin: 0; + flex: 1; + border: 1px solid #e9e9e9; + padding-right: 24px; +} + +.emoji-picker .results { + display: none; + flex-wrap: wrap; + align-items: center; + justify-content: flex-start; + padding: 4px; + flex: 1; +} + +.emoji-picker .results .emoji { + margin: 5px; +} + +.emoji-picker .filter .clear-filter { + position: absolute; + right: 10px; + top: 12px; + border: 0; + background: none; + color: $primary; + outline: none; + display: none; + + &:hover { + color: $tertiary; + } +} diff --git a/app/assets/stylesheets/mobile/emoji.scss b/app/assets/stylesheets/mobile/emoji.scss deleted file mode 100644 index 6d944937561..00000000000 --- a/app/assets/stylesheets/mobile/emoji.scss +++ /dev/null @@ -1,10 +0,0 @@ -.emoji-table-wrapper { - min-width: 320px; -} - -.emoji-modal { - width: 340px; - margin-top: -132px; - margin-left: -170px; - background-color: dark-light-choose(#dadada, blend-primary-secondary(5%)); -} diff --git a/app/models/emoji.rb b/app/models/emoji.rb index 0e81f2aa0fc..42bc93f83ae 100644 --- a/app/models/emoji.rb +++ b/app/models/emoji.rb @@ -1,6 +1,6 @@ class Emoji # update this to clear the cache - EMOJI_VERSION = "v5" + EMOJI_VERSION = "5" FITZPATRICK_SCALE ||= [ "1f3fb", "1f3fc", "1f3fd", "1f3fe", "1f3ff" ] @@ -46,15 +46,19 @@ class Emoji def self.create_from_db_item(emoji) name = emoji["name"] - filename = "#{emoji['filename'] || name}.png" + filename = emoji['filename'] || name Emoji.new.tap do |e| e.name = name - e.url = "#{Discourse.base_uri}/images/emoji/#{SiteSetting.emoji_set}/#{filename}" + e.url = Emoji.url_for(filename) end end + def self.url_for(name) + "#{Discourse.base_uri}/images/emoji/#{SiteSetting.emoji_set}/#{name}.png?v=5" + end + def self.cache_key(name) - "#{name}:#{EMOJI_VERSION}:#{Plugin::CustomEmoji.cache_key}" + "#{name}:v#{EMOJI_VERSION}:#{Plugin::CustomEmoji.cache_key}" end def self.clear_cache diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 6c80ba69c20..baf9d14f6df 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1134,6 +1134,18 @@ en: ctrl: 'Ctrl' alt: 'Alt' + emoji_picker: + filter_placeholder: Search an emoji + people: People + nature: Nature + food: Food + activity: Activity + travel: Travel + objects: Objects + celebration: Celebration + custom: Custom emojis + recent: Recently used emojis + composer: emoji: "Emoji :)" more_emoji: "more..." diff --git a/lib/emoji/groups.json b/lib/emoji/groups.json new file mode 100644 index 00000000000..7d1e3a0a56e --- /dev/null +++ b/lib/emoji/groups.json @@ -0,0 +1,6047 @@ +[ + { + "name": "people", + "fullname": "People", + "tabicon": "grinning", + "icons": [ + { + "name": "grinning", + "diversity": false + }, + { + "name": "grin", + "diversity": false + }, + { + "name": "joy", + "diversity": false + }, + { + "name": "rofl", + "diversity": false + }, + { + "name": "smiley", + "diversity": false + }, + { + "name": "smile", + "diversity": false + }, + { + "name": "sweat_smile", + "diversity": false + }, + { + "name": "laughing", + "diversity": false + }, + { + "name": "wink", + "diversity": false + }, + { + "name": "blush", + "diversity": false + }, + { + "name": "yum", + "diversity": false + }, + { + "name": "sunglasses", + "diversity": false + }, + { + "name": "heart_eyes", + "diversity": false + }, + { + "name": "kissing_heart", + "diversity": false + }, + { + "name": "kissing", + "diversity": false + }, + { + "name": "kissing_smiling_eyes", + "diversity": false + }, + { + "name": "kissing_closed_eyes", + "diversity": false + }, + { + "name": "relaxed", + "diversity": false + }, + { + "name": "slightly_smiling_face", + "diversity": false + }, + { + "name": "hugs", + "diversity": false + }, + { + "name": "star_struck", + "diversity": false + }, + { + "name": "thinking", + "diversity": false + }, + { + "name": "face_with_raised_eyebrow", + "diversity": false + }, + { + "name": "neutral_face", + "diversity": false + }, + { + "name": "expressionless", + "diversity": false + }, + { + "name": "no_mouth", + "diversity": false + }, + { + "name": "roll_eyes", + "diversity": false + }, + { + "name": "smirk", + "diversity": false + }, + { + "name": "persevere", + "diversity": false + }, + { + "name": "disappointed_relieved", + "diversity": false + }, + { + "name": "open_mouth", + "diversity": false + }, + { + "name": "zipper_mouth_face", + "diversity": false + }, + { + "name": "hushed", + "diversity": false + }, + { + "name": "sleepy", + "diversity": false + }, + { + "name": "tired_face", + "diversity": false + }, + { + "name": "sleeping", + "diversity": false + }, + { + "name": "relieved", + "diversity": false + }, + { + "name": "stuck_out_tongue", + "diversity": false + }, + { + "name": "stuck_out_tongue_winking_eye", + "diversity": false + }, + { + "name": "stuck_out_tongue_closed_eyes", + "diversity": false + }, + { + "name": "drooling_face", + "diversity": false + }, + { + "name": "unamused", + "diversity": false + }, + { + "name": "sweat", + "diversity": false + }, + { + "name": "pensive", + "diversity": false + }, + { + "name": "confused", + "diversity": false + }, + { + "name": "upside_down_face", + "diversity": false + }, + { + "name": "money_mouth_face", + "diversity": false + }, + { + "name": "astonished", + "diversity": false + }, + { + "name": "frowning_face", + "diversity": false + }, + { + "name": "slightly_frowning_face", + "diversity": false + }, + { + "name": "confounded", + "diversity": false + }, + { + "name": "disappointed", + "diversity": false + }, + { + "name": "worried", + "diversity": false + }, + { + "name": "triumph", + "diversity": false + }, + { + "name": "cry", + "diversity": false + }, + { + "name": "sob", + "diversity": false + }, + { + "name": "frowning", + "diversity": false + }, + { + "name": "anguished", + "diversity": false + }, + { + "name": "fearful", + "diversity": false + }, + { + "name": "weary", + "diversity": false + }, + { + "name": "exploding_head", + "diversity": false + }, + { + "name": "grimacing", + "diversity": false + }, + { + "name": "cold_sweat", + "diversity": false + }, + { + "name": "scream", + "diversity": false + }, + { + "name": "flushed", + "diversity": false + }, + { + "name": "crazy_face", + "diversity": false + }, + { + "name": "dizzy_face", + "diversity": false + }, + { + "name": "rage", + "diversity": false + }, + { + "name": "angry", + "diversity": false + }, + { + "name": "face_with_symbols_over_mouth", + "diversity": false + }, + { + "name": "mask", + "diversity": false + }, + { + "name": "face_with_thermometer", + "diversity": false + }, + { + "name": "face_with_head_bandage", + "diversity": false + }, + { + "name": "nauseated_face", + "diversity": false + }, + { + "name": "face_vomiting", + "diversity": false + }, + { + "name": "sneezing_face", + "diversity": false + }, + { + "name": "innocent", + "diversity": false + }, + { + "name": "cowboy_hat_face", + "diversity": false + }, + { + "name": "clown_face", + "diversity": false + }, + { + "name": "lying_face", + "diversity": false + }, + { + "name": "sushing_face", + "diversity": false + }, + { + "name": "face_with_hand_over_mouth", + "diversity": false + }, + { + "name": "face_with_monocle", + "diversity": false + }, + { + "name": "nerd_face", + "diversity": false + }, + { + "name": "smiling_imp", + "diversity": false + }, + { + "name": "imp", + "diversity": false + }, + { + "name": "japanese_ogre", + "diversity": false + }, + { + "name": "japanese_goblin", + "diversity": false + }, + { + "name": "skull", + "diversity": false + }, + { + "name": "skull_and_crossbones", + "diversity": false + }, + { + "name": "ghost", + "diversity": false + }, + { + "name": "alien", + "diversity": false + }, + { + "name": "space_invader", + "diversity": false + }, + { + "name": "robot", + "diversity": false + }, + { + "name": "poop", + "diversity": false + }, + { + "name": "smiley_cat", + "diversity": false + }, + { + "name": "smile_cat", + "diversity": false + }, + { + "name": "joy_cat", + "diversity": false + }, + { + "name": "heart_eyes_cat", + "diversity": false + }, + { + "name": "smirk_cat", + "diversity": false + }, + { + "name": "kissing_cat", + "diversity": false + }, + { + "name": "scream_cat", + "diversity": false + }, + { + "name": "crying_cat_face", + "diversity": false + }, + { + "name": "pouting_cat", + "diversity": false + }, + { + "name": "see_no_evil", + "diversity": false + }, + { + "name": "hear_no_evil", + "diversity": false + }, + { + "name": "speak_no_evil", + "diversity": false + }, + { + "name": "baby", + "diversity": true + }, + { + "name": "child", + "diversity": false + }, + { + "name": "boy", + "diversity": true + }, + { + "name": "girl", + "diversity": true + }, + { + "name": "adult", + "diversity": false + }, + { + "name": "man", + "diversity": true + }, + { + "name": "woman", + "diversity": true + }, + { + "name": "older_adult", + "diversity": false + }, + { + "name": "older_man", + "diversity": true + }, + { + "name": "older_woman", + "diversity": true + }, + { + "name": "man_health_worker", + "diversity": true + }, + { + "name": "woman_health_worker", + "diversity": true + }, + { + "name": "man_student", + "diversity": true + }, + { + "name": "woman_student", + "diversity": true + }, + { + "name": "man_teacher", + "diversity": true + }, + { + "name": "woman_teacher", + "diversity": true + }, + { + "name": "man_judge", + "diversity": true + }, + { + "name": "woman_judge", + "diversity": true + }, + { + "name": "man_farmer", + "diversity": true + }, + { + "name": "woman_farmer", + "diversity": true + }, + { + "name": "man_cook", + "diversity": true + }, + { + "name": "woman_cook", + "diversity": true + }, + { + "name": "man_mechanic", + "diversity": true + }, + { + "name": "woman_mechanic", + "diversity": true + }, + { + "name": "man_factory_worker", + "diversity": true + }, + { + "name": "woman_factory_worker", + "diversity": true + }, + { + "name": "man_office_worker", + "diversity": true + }, + { + "name": "woman_office_worker", + "diversity": true + }, + { + "name": "man_scientist", + "diversity": true + }, + { + "name": "woman_scientist", + "diversity": true + }, + { + "name": "man_technologist", + "diversity": true + }, + { + "name": "woman_technologist", + "diversity": true + }, + { + "name": "man_singer", + "diversity": true + }, + { + "name": "woman_singer", + "diversity": true + }, + { + "name": "man_artist", + "diversity": true + }, + { + "name": "woman_artist", + "diversity": true + }, + { + "name": "man_pilot", + "diversity": true + }, + { + "name": "woman_pilot", + "diversity": true + }, + { + "name": "man_astronaut", + "diversity": true + }, + { + "name": "woman_astronaut", + "diversity": true + }, + { + "name": "man_firefighter", + "diversity": true + }, + { + "name": "woman_firefighter", + "diversity": true + }, + { + "name": "policeman", + "diversity": true + }, + { + "name": "policewoman", + "diversity": true + }, + { + "name": "male_detective", + "diversity": true + }, + { + "name": "female_detective", + "diversity": false + }, + { + "name": "guardsman", + "diversity": true + }, + { + "name": "guardswoman", + "diversity": true + }, + { + "name": "construction_worker_man", + "diversity": true + }, + { + "name": "construction_worker_woman", + "diversity": true + }, + { + "name": "prince", + "diversity": true + }, + { + "name": "princess", + "diversity": true + }, + { + "name": "man_with_turban", + "diversity": true + }, + { + "name": "woman_with_turban", + "diversity": true + }, + { + "name": "man_with_gua_pi_mao", + "diversity": true + }, + { + "name": "woman_with_headscarf", + "diversity": false + }, + { + "name": "bearded_person", + "diversity": false + }, + { + "name": "blonde_man", + "diversity": true + }, + { + "name": "blonde_woman", + "diversity": true + }, + { + "name": "man_in_tuxedo", + "diversity": true + }, + { + "name": "bride_with_veil", + "diversity": true + }, + { + "name": "pregnant_woman", + "diversity": true + }, + { + "name": "breast_feeding", + "diversity": false + }, + { + "name": "angel", + "diversity": true + }, + { + "name": "santa", + "diversity": true + }, + { + "name": "mrs_claus", + "diversity": true + }, + { + "name": "mage", + "diversity": false + }, + { + "name": "fairy", + "diversity": false + }, + { + "name": "vampire", + "diversity": false + }, + { + "name": "merperson", + "diversity": false + }, + { + "name": "elf", + "diversity": false + }, + { + "name": "genie", + "diversity": false + }, + { + "name": "zombie", + "diversity": false + }, + { + "name": "frowning_woman", + "diversity": true + }, + { + "name": "frowning_man", + "diversity": true + }, + { + "name": "pouting_woman", + "diversity": true + }, + { + "name": "pouting_man", + "diversity": true + }, + { + "name": "no_good_woman", + "diversity": true + }, + { + "name": "no_good_man", + "diversity": true + }, + { + "name": "ok_woman", + "diversity": true + }, + { + "name": "ok_man", + "diversity": true + }, + { + "name": "tipping_hand_woman", + "diversity": true + }, + { + "name": "tipping_hand_man", + "diversity": true + }, + { + "name": "raising_hand_woman", + "diversity": true + }, + { + "name": "raising_hand_man", + "diversity": true + }, + { + "name": "bowing_man", + "diversity": true + }, + { + "name": "bowing_woman", + "diversity": true + }, + { + "name": "man_facepalming", + "diversity": true + }, + { + "name": "woman_facepalming", + "diversity": true + }, + { + "name": "man_shrugging", + "diversity": true + }, + { + "name": "woman_shrugging", + "diversity": true + }, + { + "name": "couple", + "diversity": false + }, + { + "name": "two_men_holding_hands", + "diversity": false + }, + { + "name": "two_women_holding_hands", + "diversity": false + }, + { + "name": "couplekiss_man_woman", + "diversity": false + }, + { + "name": "couplekiss_man_man", + "diversity": false + }, + { + "name": "couplekiss_woman_woman", + "diversity": false + }, + { + "name": "couple_with_heart_woman_man", + "diversity": false + }, + { + "name": "couple_with_heart_man_man", + "diversity": false + }, + { + "name": "couple_with_heart_woman_woman", + "diversity": false + }, + { + "name": "family_man_woman_boy", + "diversity": false + }, + { + "name": "family_man_woman_girl", + "diversity": false + }, + { + "name": "family_man_woman_girl_boy", + "diversity": false + }, + { + "name": "family_man_woman_boy_boy", + "diversity": false + }, + { + "name": "family_man_woman_girl_girl", + "diversity": false + }, + { + "name": "family_man_man_boy", + "diversity": false + }, + { + "name": "family_man_man_girl", + "diversity": false + }, + { + "name": "family_man_man_girl_boy", + "diversity": false + }, + { + "name": "family_man_man_boy_boy", + "diversity": false + }, + { + "name": "family_man_man_girl_girl", + "diversity": false + }, + { + "name": "family_woman_woman_boy", + "diversity": false + }, + { + "name": "family_woman_woman_girl", + "diversity": false + }, + { + "name": "family_woman_woman_girl_boy", + "diversity": false + }, + { + "name": "family_woman_woman_boy_boy", + "diversity": false + }, + { + "name": "family_woman_woman_girl_girl", + "diversity": false + }, + { + "name": "family_man_boy", + "diversity": false + }, + { + "name": "family_man_boy_boy", + "diversity": false + }, + { + "name": "family_man_girl", + "diversity": false + }, + { + "name": "family_man_girl_boy", + "diversity": false + }, + { + "name": "family_man_girl_girl", + "diversity": false + }, + { + "name": "family_woman_boy", + "diversity": false + }, + { + "name": "family_woman_boy_boy", + "diversity": false + }, + { + "name": "family_woman_girl", + "diversity": false + }, + { + "name": "family_woman_girl_boy", + "diversity": false + }, + { + "name": "family_woman_girl_girl", + "diversity": false + }, + { + "name": "selfie", + "diversity": true + }, + { + "name": "muscle", + "diversity": true + }, + { + "name": "point_left", + "diversity": true + }, + { + "name": "point_right", + "diversity": true + }, + { + "name": "point_up", + "diversity": true + }, + { + "name": "point_up_2", + "diversity": true + }, + { + "name": "fu", + "diversity": true + }, + { + "name": "point_down", + "diversity": true + }, + { + "name": "v", + "diversity": true + }, + { + "name": "crossed_fingers", + "diversity": true + }, + { + "name": "vulcan_salute", + "diversity": true + }, + { + "name": "metal", + "diversity": true + }, + { + "name": "call_me_hand", + "diversity": true + }, + { + "name": "raised_hand_with_fingers_splayed", + "diversity": true + }, + { + "name": "raised_hand", + "diversity": true + }, + { + "name": "ok_hand", + "diversity": true + }, + { + "name": "+1", + "diversity": true + }, + { + "name": "-1", + "diversity": true + }, + { + "name": "fist", + "diversity": true + }, + { + "name": "facepunch", + "diversity": true + }, + { + "name": "fist_left", + "diversity": true + }, + { + "name": "fist_right", + "diversity": true + }, + { + "name": "raised_back_of_hand", + "diversity": true + }, + { + "name": "wave", + "diversity": true + }, + { + "name": "love_you_gesture", + "diversity": false + }, + { + "name": "writing_hand", + "diversity": true + }, + { + "name": "clap", + "diversity": true + }, + { + "name": "open_hands", + "diversity": true + }, + { + "name": "raised_hands", + "diversity": true + }, + { + "name": "palms_up_together", + "diversity": false + }, + { + "name": "pray", + "diversity": true + }, + { + "name": "handshake", + "diversity": false + }, + { + "name": "nail_care", + "diversity": true + }, + { + "name": "ear", + "diversity": true + }, + { + "name": "nose", + "diversity": true + }, + { + "name": "footprints", + "diversity": false + }, + { + "name": "eyes", + "diversity": false + }, + { + "name": "eye", + "diversity": false + }, + { + "name": "brain", + "diversity": false + }, + { + "name": "tongue", + "diversity": false + }, + { + "name": "lips", + "diversity": false + } + ] + }, + { + "name": "nature", + "fullname": "Nature", + "tabicon": "evergreen_tree", + "icons": [ + { + "name": "monkey_face", + "diversity": false + }, + { + "name": "monkey", + "diversity": false + }, + { + "name": "gorilla", + "diversity": false + }, + { + "name": "dog", + "diversity": false + }, + { + "name": "dog2", + "diversity": false + }, + { + "name": "poodle", + "diversity": false + }, + { + "name": "wolf", + "diversity": false + }, + { + "name": "fox_face", + "diversity": false + }, + { + "name": "cat", + "diversity": false + }, + { + "name": "cat2", + "diversity": false + }, + { + "name": "lion", + "diversity": false + }, + { + "name": "tiger", + "diversity": false + }, + { + "name": "tiger2", + "diversity": false + }, + { + "name": "leopard", + "diversity": false + }, + { + "name": "horse", + "diversity": false + }, + { + "name": "racehorse", + "diversity": false + }, + { + "name": "unicorn", + "diversity": false + }, + { + "name": "zebra", + "diversity": false + }, + { + "name": "deer", + "diversity": false + }, + { + "name": "cow", + "diversity": false + }, + { + "name": "ox", + "diversity": false + }, + { + "name": "water_buffalo", + "diversity": false + }, + { + "name": "cow2", + "diversity": false + }, + { + "name": "pig", + "diversity": false + }, + { + "name": "pig2", + "diversity": false + }, + { + "name": "boar", + "diversity": false + }, + { + "name": "pig_nose", + "diversity": false + }, + { + "name": "ram", + "diversity": false + }, + { + "name": "sheep", + "diversity": false + }, + { + "name": "goat", + "diversity": false + }, + { + "name": "dromedary_camel", + "diversity": false + }, + { + "name": "camel", + "diversity": false + }, + { + "name": "giraffe", + "diversity": false + }, + { + "name": "elephant", + "diversity": false + }, + { + "name": "rhinoceros", + "diversity": false + }, + { + "name": "mouse", + "diversity": false + }, + { + "name": "mouse2", + "diversity": false + }, + { + "name": "rat", + "diversity": false + }, + { + "name": "hamster", + "diversity": false + }, + { + "name": "rabbit", + "diversity": false + }, + { + "name": "rabbit2", + "diversity": false + }, + { + "name": "chipmunk", + "diversity": false + }, + { + "name": "hedgehog", + "diversity": false + }, + { + "name": "bat", + "diversity": false + }, + { + "name": "bear", + "diversity": false + }, + { + "name": "koala", + "diversity": false + }, + { + "name": "panda_face", + "diversity": false + }, + { + "name": "paw_prints", + "diversity": false + }, + { + "name": "turkey", + "diversity": false + }, + { + "name": "chicken", + "diversity": false + }, + { + "name": "rooster", + "diversity": false + }, + { + "name": "hatching_chick", + "diversity": false + }, + { + "name": "baby_chick", + "diversity": false + }, + { + "name": "hatched_chick", + "diversity": false + }, + { + "name": "bird", + "diversity": false + }, + { + "name": "penguin", + "diversity": false + }, + { + "name": "dove", + "diversity": false + }, + { + "name": "eagle", + "diversity": false + }, + { + "name": "duck", + "diversity": false + }, + { + "name": "owl", + "diversity": false + }, + { + "name": "frog", + "diversity": false + }, + { + "name": "crocodile", + "diversity": false + }, + { + "name": "turtle", + "diversity": false + }, + { + "name": "lizard", + "diversity": false + }, + { + "name": "snake", + "diversity": false + }, + { + "name": "dragon_face", + "diversity": false + }, + { + "name": "dragon", + "diversity": false + }, + { + "name": "sauropod", + "diversity": false + }, + { + "name": "t_rex", + "diversity": false + }, + { + "name": "whale", + "diversity": false + }, + { + "name": "whale2", + "diversity": false + }, + { + "name": "dolphin", + "diversity": false + }, + { + "name": "fish", + "diversity": false + }, + { + "name": "tropical_fish", + "diversity": false + }, + { + "name": "blowfish", + "diversity": false + }, + { + "name": "shark", + "diversity": false + }, + { + "name": "octopus", + "diversity": false + }, + { + "name": "shell", + "diversity": false + }, + { + "name": "crab", + "diversity": false + }, + { + "name": "shrimp", + "diversity": false + }, + { + "name": "squid", + "diversity": false + }, + { + "name": "snail", + "diversity": false + }, + { + "name": "butterfly", + "diversity": false + }, + { + "name": "bug", + "diversity": false + }, + { + "name": "ant", + "diversity": false + }, + { + "name": "honeybee", + "diversity": false + }, + { + "name": "beetle", + "diversity": false + }, + { + "name": "cricket", + "diversity": false + }, + { + "name": "spider", + "diversity": false + }, + { + "name": "spider_web", + "diversity": false + }, + { + "name": "scorpion", + "diversity": false + }, + { + "name": "bouquet", + "diversity": false + }, + { + "name": "cherry_blossom", + "diversity": false + }, + { + "name": "white_flower", + "diversity": false + }, + { + "name": "rosette", + "diversity": false + }, + { + "name": "rose", + "diversity": false + }, + { + "name": "wilted_flower", + "diversity": false + }, + { + "name": "hibiscus", + "diversity": false + }, + { + "name": "sunflower", + "diversity": false + }, + { + "name": "blossom", + "diversity": false + }, + { + "name": "tulip", + "diversity": false + }, + { + "name": "seedling", + "diversity": false + }, + { + "name": "evergreen_tree", + "diversity": false + }, + { + "name": "deciduous_tree", + "diversity": false + }, + { + "name": "palm_tree", + "diversity": false + }, + { + "name": "cactus", + "diversity": false + }, + { + "name": "ear_of_rice", + "diversity": false + }, + { + "name": "herb", + "diversity": false + }, + { + "name": "shamrock", + "diversity": false + }, + { + "name": "four_leaf_clover", + "diversity": false + }, + { + "name": "maple_leaf", + "diversity": false + }, + { + "name": "fallen_leaf", + "diversity": false + }, + { + "name": "leaves", + "diversity": false + }, + { + "name": "new_moon", + "diversity": false + }, + { + "name": "waxing_crescent_moon", + "diversity": false + }, + { + "name": "first_quarter_moon", + "diversity": false + }, + { + "name": "waxing_gibbous_moon", + "diversity": false + }, + { + "name": "full_moon", + "diversity": false + }, + { + "name": "waning_gibbous_moon", + "diversity": false + }, + { + "name": "last_quarter_moon", + "diversity": false + }, + { + "name": "waning_crescent_moon", + "diversity": false + }, + { + "name": "crescent_moon", + "diversity": false + }, + { + "name": "new_moon_with_face", + "diversity": false + }, + { + "name": "first_quarter_moon_with_face", + "diversity": false + }, + { + "name": "last_quarter_moon_with_face", + "diversity": false + }, + { + "name": "thermometer", + "diversity": false + }, + { + "name": "sunny", + "diversity": false + }, + { + "name": "full_moon_with_face", + "diversity": false + }, + { + "name": "sun_with_face", + "diversity": false + }, + { + "name": "star", + "diversity": false + }, + { + "name": "star2", + "diversity": false + }, + { + "name": "stars", + "diversity": false + }, + { + "name": "cloud", + "diversity": false + }, + { + "name": "partly_sunny", + "diversity": false + }, + { + "name": "cloud_with_lightning_and_rain", + "diversity": false + }, + { + "name": "sun_behind_small_cloud", + "diversity": false + }, + { + "name": "sun_behind_large_cloud", + "diversity": false + }, + { + "name": "sun_behind_rain_cloud", + "diversity": false + }, + { + "name": "cloud_with_rain", + "diversity": false + }, + { + "name": "cloud_with_snow", + "diversity": false + }, + { + "name": "cloud_with_lightning", + "diversity": false + }, + { + "name": "tornado", + "diversity": false + }, + { + "name": "fog", + "diversity": false + }, + { + "name": "wind_face", + "diversity": false + }, + { + "name": "cyclone", + "diversity": false + }, + { + "name": "rainbow", + "diversity": false + }, + { + "name": "closed_umbrella", + "diversity": false + }, + { + "name": "open_umbrella", + "diversity": false + }, + { + "name": "umbrella", + "diversity": false + }, + { + "name": "parasol_on_ground", + "diversity": false + }, + { + "name": "zap", + "diversity": false + }, + { + "name": "snowflake", + "diversity": false + }, + { + "name": "snowman_with_snow", + "diversity": false + }, + { + "name": "snowman", + "diversity": false + }, + { + "name": "comet", + "diversity": false + }, + { + "name": "fire", + "diversity": false + }, + { + "name": "droplet", + "diversity": false + }, + { + "name": "ocean", + "diversity": false + } + ] + }, + { + "name": "food", + "fullname": "Food & Drink", + "tabicon": "hamburger", + "icons": [ + { + "name": "grapes", + "diversity": false + }, + { + "name": "melon", + "diversity": false + }, + { + "name": "watermelon", + "diversity": false + }, + { + "name": "tangerine", + "diversity": false + }, + { + "name": "lemon", + "diversity": false + }, + { + "name": "banana", + "diversity": false + }, + { + "name": "pineapple", + "diversity": false + }, + { + "name": "apple", + "diversity": false + }, + { + "name": "green_apple", + "diversity": false + }, + { + "name": "pear", + "diversity": false + }, + { + "name": "peach", + "diversity": false + }, + { + "name": "cherries", + "diversity": false + }, + { + "name": "strawberry", + "diversity": false + }, + { + "name": "kiwi_fruit", + "diversity": false + }, + { + "name": "tomato", + "diversity": false + }, + { + "name": "coconut", + "diversity": false + }, + { + "name": "avocado", + "diversity": false + }, + { + "name": "eggplant", + "diversity": false + }, + { + "name": "potato", + "diversity": false + }, + { + "name": "carrot", + "diversity": false + }, + { + "name": "corn", + "diversity": false + }, + { + "name": "hot_pepper", + "diversity": false + }, + { + "name": "cucumber", + "diversity": false + }, + { + "name": "broccoli", + "diversity": false + }, + { + "name": "mushroom", + "diversity": false + }, + { + "name": "peanuts", + "diversity": false + }, + { + "name": "chestnut", + "diversity": false + }, + { + "name": "bread", + "diversity": false + }, + { + "name": "croissant", + "diversity": false + }, + { + "name": "baguette_bread", + "diversity": false + }, + { + "name": "pretzel", + "diversity": false + }, + { + "name": "pancakes", + "diversity": false + }, + { + "name": "cheese", + "diversity": false + }, + { + "name": "meat_on_bone", + "diversity": false + }, + { + "name": "poultry_leg", + "diversity": false + }, + { + "name": "cut_of_meat", + "diversity": false + }, + { + "name": "bacon", + "diversity": false + }, + { + "name": "hamburger", + "diversity": false + }, + { + "name": "fries", + "diversity": false + }, + { + "name": "pizza", + "diversity": false + }, + { + "name": "hotdog", + "diversity": false + }, + { + "name": "sandwich", + "diversity": false + }, + { + "name": "taco", + "diversity": false + }, + { + "name": "burrito", + "diversity": false + }, + { + "name": "stuffed_flatbread", + "diversity": false + }, + { + "name": "egg", + "diversity": false + }, + { + "name": "fried_egg", + "diversity": false + }, + { + "name": "shallow_pan_of_food", + "diversity": false + }, + { + "name": "stew", + "diversity": false + }, + { + "name": "bowl_with_spoon", + "diversity": false + }, + { + "name": "green_salad", + "diversity": false + }, + { + "name": "popcorn", + "diversity": false + }, + { + "name": "canned_food", + "diversity": false + }, + { + "name": "bento", + "diversity": false + }, + { + "name": "rice_cracker", + "diversity": false + }, + { + "name": "rice_ball", + "diversity": false + }, + { + "name": "rice", + "diversity": false + }, + { + "name": "curry", + "diversity": false + }, + { + "name": "ramen", + "diversity": false + }, + { + "name": "spaghetti", + "diversity": false + }, + { + "name": "sweet_potato", + "diversity": false + }, + { + "name": "oden", + "diversity": false + }, + { + "name": "sushi", + "diversity": false + }, + { + "name": "fried_shrimp", + "diversity": false + }, + { + "name": "fish_cake", + "diversity": false + }, + { + "name": "dango", + "diversity": false + }, + { + "name": "dumpling", + "diversity": false + }, + { + "name": "fortune_cookie", + "diversity": false + }, + { + "name": "takeout_box", + "diversity": false + }, + { + "name": "icecream", + "diversity": false + }, + { + "name": "shaved_ice", + "diversity": false + }, + { + "name": "ice_cream", + "diversity": false + }, + { + "name": "doughnut", + "diversity": false + }, + { + "name": "cookie", + "diversity": false + }, + { + "name": "birthday", + "diversity": false + }, + { + "name": "cake", + "diversity": false + }, + { + "name": "pie", + "diversity": false + }, + { + "name": "chocolate_bar", + "diversity": false + }, + { + "name": "candy", + "diversity": false + }, + { + "name": "lollipop", + "diversity": false + }, + { + "name": "custard", + "diversity": false + }, + { + "name": "honey_pot", + "diversity": false + }, + { + "name": "baby_bottle", + "diversity": false + }, + { + "name": "milk_glass", + "diversity": false + }, + { + "name": "coffee", + "diversity": false + }, + { + "name": "tea", + "diversity": false + }, + { + "name": "sake", + "diversity": false + }, + { + "name": "champagne", + "diversity": false + }, + { + "name": "wine_glass", + "diversity": false + }, + { + "name": "cocktail", + "diversity": false + }, + { + "name": "tropical_drink", + "diversity": false + }, + { + "name": "beer", + "diversity": false + }, + { + "name": "beers", + "diversity": false + }, + { + "name": "clinking_glasses", + "diversity": false + }, + { + "name": "tumbler_glass", + "diversity": false + }, + { + "name": "cup_with_straw", + "diversity": false + }, + { + "name": "chopsticks", + "diversity": false + }, + { + "name": "plate_with_cutlery", + "diversity": false + }, + { + "name": "fork_and_knife", + "diversity": false + }, + { + "name": "spoon", + "diversity": false + }, + { + "name": "hocho", + "diversity": false + }, + { + "name": "amphora", + "diversity": false + } + ] + }, + { + "name": "celebration", + "fullname": "Celebration", + "tabicon": "gift", + "icons": [ + { + "name": "jack_o_lantern", + "diversity": false + }, + { + "name": "christmas_tree", + "diversity": false + }, + { + "name": "fireworks", + "diversity": false + }, + { + "name": "sparkler", + "diversity": false + }, + { + "name": "sparkles", + "diversity": false + }, + { + "name": "balloon", + "diversity": false + }, + { + "name": "tada", + "diversity": false + }, + { + "name": "confetti_ball", + "diversity": false + }, + { + "name": "tanabata_tree", + "diversity": false + }, + { + "name": "bamboo", + "diversity": false + }, + { + "name": "dolls", + "diversity": false + }, + { + "name": "flags", + "diversity": false + }, + { + "name": "wind_chime", + "diversity": false + }, + { + "name": "rice_scene", + "diversity": false + }, + { + "name": "ribbon", + "diversity": false + }, + { + "name": "gift", + "diversity": false + }, + { + "name": "reminder_ribbon", + "diversity": false + }, + { + "name": "tickets", + "diversity": false + }, + { + "name": "ticket", + "diversity": false + }, + { + "name": "kiss", + "diversity": false + }, + { + "name": "cupid", + "diversity": false + }, + { + "name": "heart", + "diversity": false + }, + { + "name": "heartbeat", + "diversity": false + }, + { + "name": "broken_heart", + "diversity": false + }, + { + "name": "two_hearts", + "diversity": false + }, + { + "name": "sparkling_heart", + "diversity": false + }, + { + "name": "heartpulse", + "diversity": false + }, + { + "name": "blue_heart", + "diversity": false + }, + { + "name": "green_heart", + "diversity": false + }, + { + "name": "yellow_heart", + "diversity": false + }, + { + "name": "orange_heart", + "diversity": false + }, + { + "name": "purple_heart", + "diversity": false + }, + { + "name": "black_heart", + "diversity": false + }, + { + "name": "gift_heart", + "diversity": false + }, + { + "name": "revolving_hearts", + "diversity": false + }, + { + "name": "heart_decoration", + "diversity": false + }, + { + "name": "heavy_heart_exclamation", + "diversity": false + }, + { + "name": "love_letter", + "diversity": false + }, + { + "name": "zzz", + "diversity": false + }, + { + "name": "anger", + "diversity": false + }, + { + "name": "bomb", + "diversity": false + }, + { + "name": "boom", + "diversity": false + }, + { + "name": "sweat_drops", + "diversity": false + }, + { + "name": "dash", + "diversity": false + }, + { + "name": "dizzy", + "diversity": false + }, + { + "name": "speech_balloon", + "diversity": false + }, + { + "name": "left_speech_bubble", + "diversity": false + }, + { + "name": "right_anger_bubble", + "diversity": false + }, + { + "name": "thought_balloon", + "diversity": false + }, + { + "name": "hole", + "diversity": false + } + ] + }, + { + "name": "activity", + "fullname": "Activities", + "tabicon": "soccer", + "icons": [ + { + "name": "massage_woman", + "diversity": true + }, + { + "name": "massage_man", + "diversity": true + }, + { + "name": "haircut_woman", + "diversity": true + }, + { + "name": "haircut_man", + "diversity": true + }, + { + "name": "walking_man", + "diversity": true + }, + { + "name": "walking_woman", + "diversity": true + }, + { + "name": "running_man", + "diversity": true + }, + { + "name": "running_woman", + "diversity": true + }, + { + "name": "dancer", + "diversity": true + }, + { + "name": "man_dancing", + "diversity": true + }, + { + "name": "dancing_women", + "diversity": false + }, + { + "name": "dancing_men", + "diversity": false + }, + { + "name": "person_in_steamy_room", + "diversity": false + }, + { + "name": "person_climbing", + "diversity": false + }, + { + "name": "person_in_lotus_position", + "diversity": false + }, + { + "name": "bath", + "diversity": true + }, + { + "name": "sleeping_bed", + "diversity": true + }, + { + "name": "business_suit_levitating", + "diversity": true + }, + { + "name": "speaking_head", + "diversity": false + }, + { + "name": "bust_in_silhouette", + "diversity": false + }, + { + "name": "busts_in_silhouette", + "diversity": false + }, + { + "name": "person_fencing", + "diversity": false + }, + { + "name": "horse_racing", + "diversity": true + }, + { + "name": "skier", + "diversity": false + }, + { + "name": "snowboarder", + "diversity": true + }, + { + "name": "golfing_man", + "diversity": true + }, + { + "name": "golfing_woman", + "diversity": false + }, + { + "name": "surfing_man", + "diversity": true + }, + { + "name": "surfing_woman", + "diversity": true + }, + { + "name": "rowing_man", + "diversity": true + }, + { + "name": "rowing_woman", + "diversity": true + }, + { + "name": "swimming_man", + "diversity": true + }, + { + "name": "swimming_woman", + "diversity": true + }, + { + "name": "basketball_man", + "diversity": true + }, + { + "name": "basketball_woman", + "diversity": false + }, + { + "name": "weight_lifting_man", + "diversity": true + }, + { + "name": "weight_lifting_woman", + "diversity": false + }, + { + "name": "biking_man", + "diversity": true + }, + { + "name": "biking_woman", + "diversity": true + }, + { + "name": "mountain_biking_man", + "diversity": true + }, + { + "name": "mountain_biking_woman", + "diversity": true + }, + { + "name": "racing_car", + "diversity": false + }, + { + "name": "motorcycle", + "diversity": false + }, + { + "name": "man_cartwheeling", + "diversity": true + }, + { + "name": "woman_cartwheeling", + "diversity": true + }, + { + "name": "men_wrestling", + "diversity": false + }, + { + "name": "women_wrestling", + "diversity": false + }, + { + "name": "man_playing_water_polo", + "diversity": true + }, + { + "name": "woman_playing_water_polo", + "diversity": true + }, + { + "name": "man_playing_handball", + "diversity": true + }, + { + "name": "woman_playing_handball", + "diversity": true + }, + { + "name": "man_juggling", + "diversity": true + }, + { + "name": "woman_juggling", + "diversity": true + }, + { + "name": "soccer", + "diversity": false + }, + { + "name": "baseball", + "diversity": false + }, + { + "name": "basketball", + "diversity": false + }, + { + "name": "volleyball", + "diversity": false + }, + { + "name": "football", + "diversity": false + }, + { + "name": "rugby_football", + "diversity": false + }, + { + "name": "tennis", + "diversity": false + }, + { + "name": "8ball", + "diversity": false + }, + { + "name": "bowling", + "diversity": false + }, + { + "name": "cricket_bat_and_ball", + "diversity": false + }, + { + "name": "field_hockey", + "diversity": false + }, + { + "name": "ice_hockey", + "diversity": false + }, + { + "name": "ping_pong", + "diversity": false + }, + { + "name": "badminton", + "diversity": false + }, + { + "name": "boxing_glove", + "diversity": false + }, + { + "name": "martial_arts_uniform", + "diversity": false + }, + { + "name": "goal_net", + "diversity": false + }, + { + "name": "dart", + "diversity": false + }, + { + "name": "golf", + "diversity": false + }, + { + "name": "ice_skate", + "diversity": false + }, + { + "name": "fishing_pole_and_fish", + "diversity": false + }, + { + "name": "running_shirt_with_sash", + "diversity": false + }, + { + "name": "ski", + "diversity": false + }, + { + "name": "sled", + "diversity": false + }, + { + "name": "curling_stone", + "diversity": false + }, + { + "name": "video_game", + "diversity": false + }, + { + "name": "joystick", + "diversity": false + }, + { + "name": "game_die", + "diversity": false + }, + { + "name": "spades", + "diversity": false + }, + { + "name": "hearts", + "diversity": false + }, + { + "name": "diamonds", + "diversity": false + }, + { + "name": "clubs", + "diversity": false + }, + { + "name": "black_joker", + "diversity": false + }, + { + "name": "mahjong", + "diversity": false + }, + { + "name": "flower_playing_cards", + "diversity": false + }, + { + "name": "musical_score", + "diversity": false + }, + { + "name": "musical_note", + "diversity": false + }, + { + "name": "notes", + "diversity": false + }, + { + "name": "studio_microphone", + "diversity": false + }, + { + "name": "level_slider", + "diversity": false + }, + { + "name": "control_knobs", + "diversity": false + }, + { + "name": "microphone", + "diversity": false + }, + { + "name": "headphones", + "diversity": false + }, + { + "name": "radio", + "diversity": false + }, + { + "name": "saxophone", + "diversity": false + }, + { + "name": "guitar", + "diversity": false + }, + { + "name": "musical_keyboard", + "diversity": false + }, + { + "name": "trumpet", + "diversity": false + }, + { + "name": "violin", + "diversity": false + }, + { + "name": "drum", + "diversity": false + } + ] + }, + { + "name": "travel", + "fullname": "Travel & Places", + "tabicon": "airplane", + "icons": [ + { + "name": "earth_africa", + "diversity": false + }, + { + "name": "earth_americas", + "diversity": false + }, + { + "name": "earth_asia", + "diversity": false + }, + { + "name": "globe_with_meridians", + "diversity": false + }, + { + "name": "world_map", + "diversity": false + }, + { + "name": "japan", + "diversity": false + }, + { + "name": "mountain_snow", + "diversity": false + }, + { + "name": "mountain", + "diversity": false + }, + { + "name": "volcano", + "diversity": false + }, + { + "name": "mount_fuji", + "diversity": false + }, + { + "name": "camping", + "diversity": false + }, + { + "name": "beach_umbrella", + "diversity": false + }, + { + "name": "desert", + "diversity": false + }, + { + "name": "desert_island", + "diversity": false + }, + { + "name": "national_park", + "diversity": false + }, + { + "name": "stadium", + "diversity": false + }, + { + "name": "classical_building", + "diversity": false + }, + { + "name": "building_construction", + "diversity": false + }, + { + "name": "houses", + "diversity": false + }, + { + "name": "cityscape", + "diversity": false + }, + { + "name": "derelict_house", + "diversity": false + }, + { + "name": "house", + "diversity": false + }, + { + "name": "house_with_garden", + "diversity": false + }, + { + "name": "office", + "diversity": false + }, + { + "name": "post_office", + "diversity": false + }, + { + "name": "european_post_office", + "diversity": false + }, + { + "name": "hospital", + "diversity": false + }, + { + "name": "bank", + "diversity": false + }, + { + "name": "hotel", + "diversity": false + }, + { + "name": "love_hotel", + "diversity": false + }, + { + "name": "convenience_store", + "diversity": false + }, + { + "name": "school", + "diversity": false + }, + { + "name": "department_store", + "diversity": false + }, + { + "name": "factory", + "diversity": false + }, + { + "name": "japanese_castle", + "diversity": false + }, + { + "name": "european_castle", + "diversity": false + }, + { + "name": "wedding", + "diversity": false + }, + { + "name": "tokyo_tower", + "diversity": false + }, + { + "name": "statue_of_liberty", + "diversity": false + }, + { + "name": "church", + "diversity": false + }, + { + "name": "mosque", + "diversity": false + }, + { + "name": "synagogue", + "diversity": false + }, + { + "name": "shinto_shrine", + "diversity": false + }, + { + "name": "kaaba", + "diversity": false + }, + { + "name": "fountain", + "diversity": false + }, + { + "name": "tent", + "diversity": false + }, + { + "name": "foggy", + "diversity": false + }, + { + "name": "night_with_stars", + "diversity": false + }, + { + "name": "sunrise_over_mountains", + "diversity": false + }, + { + "name": "sunrise", + "diversity": false + }, + { + "name": "city_sunset", + "diversity": false + }, + { + "name": "city_sunrise", + "diversity": false + }, + { + "name": "bridge_at_night", + "diversity": false + }, + { + "name": "hotsprings", + "diversity": false + }, + { + "name": "milky_way", + "diversity": false + }, + { + "name": "carousel_horse", + "diversity": false + }, + { + "name": "ferris_wheel", + "diversity": false + }, + { + "name": "roller_coaster", + "diversity": false + }, + { + "name": "barber", + "diversity": false + }, + { + "name": "circus_tent", + "diversity": false + }, + { + "name": "performing_arts", + "diversity": false + }, + { + "name": "framed_picture", + "diversity": false + }, + { + "name": "art", + "diversity": false + }, + { + "name": "slot_machine", + "diversity": false + }, + { + "name": "steam_locomotive", + "diversity": false + }, + { + "name": "railway_car", + "diversity": false + }, + { + "name": "bullettrain_side", + "diversity": false + }, + { + "name": "bullettrain_front", + "diversity": false + }, + { + "name": "train2", + "diversity": false + }, + { + "name": "metro", + "diversity": false + }, + { + "name": "light_rail", + "diversity": false + }, + { + "name": "station", + "diversity": false + }, + { + "name": "tram", + "diversity": false + }, + { + "name": "monorail", + "diversity": false + }, + { + "name": "mountain_railway", + "diversity": false + }, + { + "name": "train", + "diversity": false + }, + { + "name": "bus", + "diversity": false + }, + { + "name": "oncoming_bus", + "diversity": false + }, + { + "name": "trolleybus", + "diversity": false + }, + { + "name": "minibus", + "diversity": false + }, + { + "name": "ambulance", + "diversity": false + }, + { + "name": "fire_engine", + "diversity": false + }, + { + "name": "police_car", + "diversity": false + }, + { + "name": "oncoming_police_car", + "diversity": false + }, + { + "name": "taxi", + "diversity": false + }, + { + "name": "oncoming_taxi", + "diversity": false + }, + { + "name": "red_car", + "diversity": false + }, + { + "name": "oncoming_automobile", + "diversity": false + }, + { + "name": "blue_car", + "diversity": false + }, + { + "name": "truck", + "diversity": false + }, + { + "name": "articulated_lorry", + "diversity": false + }, + { + "name": "tractor", + "diversity": false + }, + { + "name": "bike", + "diversity": false + }, + { + "name": "kick_scooter", + "diversity": false + }, + { + "name": "motor_scooter", + "diversity": false + }, + { + "name": "busstop", + "diversity": false + }, + { + "name": "motorway", + "diversity": false + }, + { + "name": "railway_track", + "diversity": false + }, + { + "name": "fuelpump", + "diversity": false + }, + { + "name": "rotating_light", + "diversity": false + }, + { + "name": "traffic_light", + "diversity": false + }, + { + "name": "vertical_traffic_light", + "diversity": false + }, + { + "name": "construction", + "diversity": false + }, + { + "name": "stop_sign", + "diversity": false + }, + { + "name": "anchor", + "diversity": false + }, + { + "name": "sailboat", + "diversity": false + }, + { + "name": "canoe", + "diversity": false + }, + { + "name": "speedboat", + "diversity": false + }, + { + "name": "passenger_ship", + "diversity": false + }, + { + "name": "ferry", + "diversity": false + }, + { + "name": "motor_boat", + "diversity": false + }, + { + "name": "ship", + "diversity": false + }, + { + "name": "airplane", + "diversity": false + }, + { + "name": "small_airplane", + "diversity": false + }, + { + "name": "flight_departure", + "diversity": false + }, + { + "name": "flight_arrival", + "diversity": false + }, + { + "name": "seat", + "diversity": false + }, + { + "name": "helicopter", + "diversity": false + }, + { + "name": "suspension_railway", + "diversity": false + }, + { + "name": "mountain_cableway", + "diversity": false + }, + { + "name": "aerial_tramway", + "diversity": false + }, + { + "name": "artificial_satellite", + "diversity": false + }, + { + "name": "rocket", + "diversity": false + }, + { + "name": "flying_saucer", + "diversity": false + }, + { + "name": "bellhop_bell", + "diversity": false + }, + { + "name": "door", + "diversity": false + }, + { + "name": "bed", + "diversity": false + }, + { + "name": "couch_and_lamp", + "diversity": false + }, + { + "name": "toilet", + "diversity": false + }, + { + "name": "shower", + "diversity": false + }, + { + "name": "bathtub", + "diversity": false + }, + { + "name": "checkered_flag", + "diversity": false + }, + { + "name": "triangular_flag_on_post", + "diversity": false + }, + { + "name": "crossed_flags", + "diversity": false + }, + { + "name": "black_flag", + "diversity": false + }, + { + "name": "white_flag", + "diversity": false + }, + { + "name": "rainbow_flag", + "diversity": false + }, + { + "name": "ascension_island", + "diversity": false + }, + { + "name": "andorra", + "diversity": false + }, + { + "name": "united_arab_emirates", + "diversity": false + }, + { + "name": "afghanistan", + "diversity": false + }, + { + "name": "antigua_barbuda", + "diversity": false + }, + { + "name": "anguilla", + "diversity": false + }, + { + "name": "albania", + "diversity": false + }, + { + "name": "armenia", + "diversity": false + }, + { + "name": "angola", + "diversity": false + }, + { + "name": "antarctica", + "diversity": false + }, + { + "name": "argentina", + "diversity": false + }, + { + "name": "american_samoa", + "diversity": false + }, + { + "name": "austria", + "diversity": false + }, + { + "name": "australia", + "diversity": false + }, + { + "name": "aruba", + "diversity": false + }, + { + "name": "aland_islands", + "diversity": false + }, + { + "name": "azerbaijan", + "diversity": false + }, + { + "name": "bosnia_herzegovina", + "diversity": false + }, + { + "name": "barbados", + "diversity": false + }, + { + "name": "bangladesh", + "diversity": false + }, + { + "name": "belgium", + "diversity": false + }, + { + "name": "burkina_faso", + "diversity": false + }, + { + "name": "bulgaria", + "diversity": false + }, + { + "name": "bahrain", + "diversity": false + }, + { + "name": "burundi", + "diversity": false + }, + { + "name": "benin", + "diversity": false + }, + { + "name": "st_barthelemy", + "diversity": false + }, + { + "name": "bermuda", + "diversity": false + }, + { + "name": "brunei", + "diversity": false + }, + { + "name": "bolivia", + "diversity": false + }, + { + "name": "caribbean_netherlands", + "diversity": false + }, + { + "name": "brazil", + "diversity": false + }, + { + "name": "bahamas", + "diversity": false + }, + { + "name": "bhutan", + "diversity": false + }, + { + "name": "bouvet_island", + "diversity": false + }, + { + "name": "botswana", + "diversity": false + }, + { + "name": "belarus", + "diversity": false + }, + { + "name": "belize", + "diversity": false + }, + { + "name": "canada", + "diversity": false + }, + { + "name": "cocos_islands", + "diversity": false + }, + { + "name": "congo_kinshasa", + "diversity": false + }, + { + "name": "central_african_republic", + "diversity": false + }, + { + "name": "congo_brazzaville", + "diversity": false + }, + { + "name": "switzerland", + "diversity": false + }, + { + "name": "cote_divoire", + "diversity": false + }, + { + "name": "cook_islands", + "diversity": false + }, + { + "name": "chile", + "diversity": false + }, + { + "name": "cameroon", + "diversity": false + }, + { + "name": "cn", + "diversity": false + }, + { + "name": "colombia", + "diversity": false + }, + { + "name": "clipperton_island", + "diversity": false + }, + { + "name": "costa_rica", + "diversity": false + }, + { + "name": "cuba", + "diversity": false + }, + { + "name": "cape_verde", + "diversity": false + }, + { + "name": "curacao", + "diversity": false + }, + { + "name": "christmas_island", + "diversity": false + }, + { + "name": "cyprus", + "diversity": false + }, + { + "name": "czech_republic", + "diversity": false + }, + { + "name": "de", + "diversity": false + }, + { + "name": "diego_garcia", + "diversity": false + }, + { + "name": "djibouti", + "diversity": false + }, + { + "name": "denmark", + "diversity": false + }, + { + "name": "dominica", + "diversity": false + }, + { + "name": "dominican_republic", + "diversity": false + }, + { + "name": "algeria", + "diversity": false + }, + { + "name": "ceuta_and_melilla", + "diversity": false + }, + { + "name": "ecuador", + "diversity": false + }, + { + "name": "estonia", + "diversity": false + }, + { + "name": "egypt", + "diversity": false + }, + { + "name": "western_sahara", + "diversity": false + }, + { + "name": "eritrea", + "diversity": false + }, + { + "name": "es", + "diversity": false + }, + { + "name": "ethiopia", + "diversity": false + }, + { + "name": "eu", + "diversity": false + }, + { + "name": "finland", + "diversity": false + }, + { + "name": "fiji", + "diversity": false + }, + { + "name": "falkland_islands", + "diversity": false + }, + { + "name": "micronesia", + "diversity": false + }, + { + "name": "faroe_islands", + "diversity": false + }, + { + "name": "fr", + "diversity": false + }, + { + "name": "gabon", + "diversity": false + }, + { + "name": "uk", + "diversity": false + }, + { + "name": "grenada", + "diversity": false + }, + { + "name": "georgia", + "diversity": false + }, + { + "name": "french_guiana", + "diversity": false + }, + { + "name": "guernsey", + "diversity": false + }, + { + "name": "ghana", + "diversity": false + }, + { + "name": "gibraltar", + "diversity": false + }, + { + "name": "greenland", + "diversity": false + }, + { + "name": "gambia", + "diversity": false + }, + { + "name": "guinea", + "diversity": false + }, + { + "name": "guadeloupe", + "diversity": false + }, + { + "name": "equatorial_guinea", + "diversity": false + }, + { + "name": "greece", + "diversity": false + }, + { + "name": "south_georgia_south_sandwich_islands", + "diversity": false + }, + { + "name": "guatemala", + "diversity": false + }, + { + "name": "guam", + "diversity": false + }, + { + "name": "guinea_bissau", + "diversity": false + }, + { + "name": "guyana", + "diversity": false + }, + { + "name": "hong_kong", + "diversity": false + }, + { + "name": "heard_and_mc_donald_islands", + "diversity": false + }, + { + "name": "honduras", + "diversity": false + }, + { + "name": "croatia", + "diversity": false + }, + { + "name": "haiti", + "diversity": false + }, + { + "name": "hungary", + "diversity": false + }, + { + "name": "canary_islands", + "diversity": false + }, + { + "name": "indonesia", + "diversity": false + }, + { + "name": "ireland", + "diversity": false + }, + { + "name": "israel", + "diversity": false + }, + { + "name": "isle_of_man", + "diversity": false + }, + { + "name": "india", + "diversity": false + }, + { + "name": "british_indian_ocean_territory", + "diversity": false + }, + { + "name": "iraq", + "diversity": false + }, + { + "name": "iran", + "diversity": false + }, + { + "name": "iceland", + "diversity": false + }, + { + "name": "it", + "diversity": false + }, + { + "name": "jersey", + "diversity": false + }, + { + "name": "jamaica", + "diversity": false + }, + { + "name": "jordan", + "diversity": false + }, + { + "name": "jp", + "diversity": false + }, + { + "name": "kenya", + "diversity": false + }, + { + "name": "kyrgyzstan", + "diversity": false + }, + { + "name": "cambodia", + "diversity": false + }, + { + "name": "kiribati", + "diversity": false + }, + { + "name": "comoros", + "diversity": false + }, + { + "name": "st_kitts_nevis", + "diversity": false + }, + { + "name": "north_korea", + "diversity": false + }, + { + "name": "kr", + "diversity": false + }, + { + "name": "kuwait", + "diversity": false + }, + { + "name": "cayman_islands", + "diversity": false + }, + { + "name": "kazakhstan", + "diversity": false + }, + { + "name": "laos", + "diversity": false + }, + { + "name": "lebanon", + "diversity": false + }, + { + "name": "st_lucia", + "diversity": false + }, + { + "name": "liechtenstein", + "diversity": false + }, + { + "name": "sri_lanka", + "diversity": false + }, + { + "name": "liberia", + "diversity": false + }, + { + "name": "lesotho", + "diversity": false + }, + { + "name": "lithuania", + "diversity": false + }, + { + "name": "luxembourg", + "diversity": false + }, + { + "name": "latvia", + "diversity": false + }, + { + "name": "libya", + "diversity": false + }, + { + "name": "morocco", + "diversity": false + }, + { + "name": "monaco", + "diversity": false + }, + { + "name": "moldova", + "diversity": false + }, + { + "name": "montenegro", + "diversity": false + }, + { + "name": "st_martin", + "diversity": false + }, + { + "name": "madagascar", + "diversity": false + }, + { + "name": "marshall_islands", + "diversity": false + }, + { + "name": "macedonia", + "diversity": false + }, + { + "name": "mali", + "diversity": false + }, + { + "name": "myanmar", + "diversity": false + }, + { + "name": "mongolia", + "diversity": false + }, + { + "name": "macau", + "diversity": false + }, + { + "name": "northern_mariana_islands", + "diversity": false + }, + { + "name": "martinique", + "diversity": false + }, + { + "name": "mauritania", + "diversity": false + }, + { + "name": "montserrat", + "diversity": false + }, + { + "name": "malta", + "diversity": false + }, + { + "name": "mauritius", + "diversity": false + }, + { + "name": "maldives", + "diversity": false + }, + { + "name": "malawi", + "diversity": false + }, + { + "name": "mexico", + "diversity": false + }, + { + "name": "malaysia", + "diversity": false + }, + { + "name": "mozambique", + "diversity": false + }, + { + "name": "namibia", + "diversity": false + }, + { + "name": "new_caledonia", + "diversity": false + }, + { + "name": "niger", + "diversity": false + }, + { + "name": "norfolk_island", + "diversity": false + }, + { + "name": "nigeria", + "diversity": false + }, + { + "name": "nicaragua", + "diversity": false + }, + { + "name": "netherlands", + "diversity": false + }, + { + "name": "norway", + "diversity": false + }, + { + "name": "nepal", + "diversity": false + }, + { + "name": "nauru", + "diversity": false + }, + { + "name": "niue", + "diversity": false + }, + { + "name": "new_zealand", + "diversity": false + }, + { + "name": "oman", + "diversity": false + }, + { + "name": "panama", + "diversity": false + }, + { + "name": "peru", + "diversity": false + }, + { + "name": "french_polynesia", + "diversity": false + }, + { + "name": "papua_new_guinea", + "diversity": false + }, + { + "name": "philippines", + "diversity": false + }, + { + "name": "pakistan", + "diversity": false + }, + { + "name": "poland", + "diversity": false + }, + { + "name": "st_pierre_miquelon", + "diversity": false + }, + { + "name": "pitcairn_islands", + "diversity": false + }, + { + "name": "puerto_rico", + "diversity": false + }, + { + "name": "palestinian_territories", + "diversity": false + }, + { + "name": "portugal", + "diversity": false + }, + { + "name": "palau", + "diversity": false + }, + { + "name": "paraguay", + "diversity": false + }, + { + "name": "qatar", + "diversity": false + }, + { + "name": "reunion", + "diversity": false + }, + { + "name": "romania", + "diversity": false + }, + { + "name": "serbia", + "diversity": false + }, + { + "name": "ru", + "diversity": false + }, + { + "name": "rwanda", + "diversity": false + }, + { + "name": "saudi_arabia", + "diversity": false + }, + { + "name": "solomon_islands", + "diversity": false + }, + { + "name": "seychelles", + "diversity": false + }, + { + "name": "sudan", + "diversity": false + }, + { + "name": "sweden", + "diversity": false + }, + { + "name": "singapore", + "diversity": false + }, + { + "name": "st_helena", + "diversity": false + }, + { + "name": "slovenia", + "diversity": false + }, + { + "name": "svalbard_and_jan_mayen", + "diversity": false + }, + { + "name": "slovakia", + "diversity": false + }, + { + "name": "sierra_leone", + "diversity": false + }, + { + "name": "san_marino", + "diversity": false + }, + { + "name": "senegal", + "diversity": false + }, + { + "name": "somalia", + "diversity": false + }, + { + "name": "suriname", + "diversity": false + }, + { + "name": "south_sudan", + "diversity": false + }, + { + "name": "sao_tome_principe", + "diversity": false + }, + { + "name": "el_salvador", + "diversity": false + }, + { + "name": "sint_maarten", + "diversity": false + }, + { + "name": "syria", + "diversity": false + }, + { + "name": "swaziland", + "diversity": false + }, + { + "name": "tristan_da_cunha", + "diversity": false + }, + { + "name": "turks_caicos_islands", + "diversity": false + }, + { + "name": "chad", + "diversity": false + }, + { + "name": "french_southern_territories", + "diversity": false + }, + { + "name": "togo", + "diversity": false + }, + { + "name": "thailand", + "diversity": false + }, + { + "name": "tajikistan", + "diversity": false + }, + { + "name": "tokelau", + "diversity": false + }, + { + "name": "timor_leste", + "diversity": false + }, + { + "name": "turkmenistan", + "diversity": false + }, + { + "name": "tunisia", + "diversity": false + }, + { + "name": "tonga", + "diversity": false + }, + { + "name": "tr", + "diversity": false + }, + { + "name": "trinidad_tobago", + "diversity": false + }, + { + "name": "tuvalu", + "diversity": false + }, + { + "name": "taiwan", + "diversity": false + }, + { + "name": "tanzania", + "diversity": false + }, + { + "name": "ukraine", + "diversity": false + }, + { + "name": "uganda", + "diversity": false + }, + { + "name": "us_outlying_islands", + "diversity": false + }, + { + "name": "united_nations", + "diversity": false + }, + { + "name": "us", + "diversity": false + }, + { + "name": "uruguay", + "diversity": false + }, + { + "name": "uzbekistan", + "diversity": false + }, + { + "name": "vatican_city", + "diversity": false + }, + { + "name": "st_vincent_grenadines", + "diversity": false + }, + { + "name": "venezuela", + "diversity": false + }, + { + "name": "british_virgin_islands", + "diversity": false + }, + { + "name": "us_virgin_islands", + "diversity": false + }, + { + "name": "vietnam", + "diversity": false + }, + { + "name": "vanuatu", + "diversity": false + }, + { + "name": "wallis_futuna", + "diversity": false + }, + { + "name": "samoa", + "diversity": false + }, + { + "name": "kosovo", + "diversity": false + }, + { + "name": "yemen", + "diversity": false + }, + { + "name": "mayotte", + "diversity": false + }, + { + "name": "south_africa", + "diversity": false + }, + { + "name": "zambia", + "diversity": false + }, + { + "name": "zimbabwe", + "diversity": false + } + ] + }, + { + "name": "objects", + "fullname": "Objects & Symbols", + "tabicon": "eyeglasses", + "icons": [ + { + "name": "eyeglasses", + "diversity": false + }, + { + "name": "dark_sunglasses", + "diversity": false + }, + { + "name": "necktie", + "diversity": false + }, + { + "name": "tshirt", + "diversity": false + }, + { + "name": "jeans", + "diversity": false + }, + { + "name": "scarf", + "diversity": false + }, + { + "name": "gloves", + "diversity": false + }, + { + "name": "coat", + "diversity": false + }, + { + "name": "socks", + "diversity": false + }, + { + "name": "dress", + "diversity": false + }, + { + "name": "kimono", + "diversity": false + }, + { + "name": "bikini", + "diversity": false + }, + { + "name": "womans_clothes", + "diversity": false + }, + { + "name": "purse", + "diversity": false + }, + { + "name": "handbag", + "diversity": false + }, + { + "name": "pouch", + "diversity": false + }, + { + "name": "shopping", + "diversity": false + }, + { + "name": "school_satchel", + "diversity": false + }, + { + "name": "mans_shoe", + "diversity": false + }, + { + "name": "athletic_shoe", + "diversity": false + }, + { + "name": "high_heel", + "diversity": false + }, + { + "name": "sandal", + "diversity": false + }, + { + "name": "boot", + "diversity": false + }, + { + "name": "crown", + "diversity": false + }, + { + "name": "womans_hat", + "diversity": false + }, + { + "name": "tophat", + "diversity": false + }, + { + "name": "mortar_board", + "diversity": false + }, + { + "name": "billed_cap", + "diversity": false + }, + { + "name": "rescue_worker_helmet", + "diversity": false + }, + { + "name": "prayer_beads", + "diversity": false + }, + { + "name": "lipstick", + "diversity": false + }, + { + "name": "ring", + "diversity": false + }, + { + "name": "gem", + "diversity": false + }, + { + "name": "medal_military", + "diversity": false + }, + { + "name": "trophy", + "diversity": false + }, + { + "name": "medal_sports", + "diversity": false + }, + { + "name": "1st_place_medal", + "diversity": false + }, + { + "name": "2nd_place_medal", + "diversity": false + }, + { + "name": "3rd_place_medal", + "diversity": false + }, + { + "name": "mute", + "diversity": false + }, + { + "name": "speaker", + "diversity": false + }, + { + "name": "sound", + "diversity": false + }, + { + "name": "loud_sound", + "diversity": false + }, + { + "name": "loudspeaker", + "diversity": false + }, + { + "name": "mega", + "diversity": false + }, + { + "name": "postal_horn", + "diversity": false + }, + { + "name": "bell", + "diversity": false + }, + { + "name": "no_bell", + "diversity": false + }, + { + "name": "iphone", + "diversity": false + }, + { + "name": "calling", + "diversity": false + }, + { + "name": "phone", + "diversity": false + }, + { + "name": "telephone_receiver", + "diversity": false + }, + { + "name": "pager", + "diversity": false + }, + { + "name": "fax", + "diversity": false + }, + { + "name": "battery", + "diversity": false + }, + { + "name": "electric_plug", + "diversity": false + }, + { + "name": "computer", + "diversity": false + }, + { + "name": "desktop_computer", + "diversity": false + }, + { + "name": "printer", + "diversity": false + }, + { + "name": "keyboard", + "diversity": false + }, + { + "name": "computer_mouse", + "diversity": false + }, + { + "name": "trackball", + "diversity": false + }, + { + "name": "minidisc", + "diversity": false + }, + { + "name": "floppy_disk", + "diversity": false + }, + { + "name": "cd", + "diversity": false + }, + { + "name": "dvd", + "diversity": false + }, + { + "name": "movie_camera", + "diversity": false + }, + { + "name": "film_strip", + "diversity": false + }, + { + "name": "film_projector", + "diversity": false + }, + { + "name": "clapper", + "diversity": false + }, + { + "name": "tv", + "diversity": false + }, + { + "name": "camera", + "diversity": false + }, + { + "name": "camera_flash", + "diversity": false + }, + { + "name": "video_camera", + "diversity": false + }, + { + "name": "vhs", + "diversity": false + }, + { + "name": "mag", + "diversity": false + }, + { + "name": "mag_right", + "diversity": false + }, + { + "name": "microscope", + "diversity": false + }, + { + "name": "telescope", + "diversity": false + }, + { + "name": "satellite", + "diversity": false + }, + { + "name": "candle", + "diversity": false + }, + { + "name": "bulb", + "diversity": false + }, + { + "name": "flashlight", + "diversity": false + }, + { + "name": "izakaya_lantern", + "diversity": false + }, + { + "name": "notebook_with_decorative_cover", + "diversity": false + }, + { + "name": "closed_book", + "diversity": false + }, + { + "name": "open_book", + "diversity": false + }, + { + "name": "green_book", + "diversity": false + }, + { + "name": "blue_book", + "diversity": false + }, + { + "name": "orange_book", + "diversity": false + }, + { + "name": "books", + "diversity": false + }, + { + "name": "notebook", + "diversity": false + }, + { + "name": "ledger", + "diversity": false + }, + { + "name": "page_with_curl", + "diversity": false + }, + { + "name": "scroll", + "diversity": false + }, + { + "name": "page_facing_up", + "diversity": false + }, + { + "name": "newspaper", + "diversity": false + }, + { + "name": "newspaper_roll", + "diversity": false + }, + { + "name": "bookmark_tabs", + "diversity": false + }, + { + "name": "bookmark", + "diversity": false + }, + { + "name": "label", + "diversity": false + }, + { + "name": "moneybag", + "diversity": false + }, + { + "name": "yen", + "diversity": false + }, + { + "name": "dollar", + "diversity": false + }, + { + "name": "euro", + "diversity": false + }, + { + "name": "pound", + "diversity": false + }, + { + "name": "money_with_wings", + "diversity": false + }, + { + "name": "credit_card", + "diversity": false + }, + { + "name": "chart", + "diversity": false + }, + { + "name": "currency_exchange", + "diversity": false + }, + { + "name": "heavy_dollar_sign", + "diversity": false + }, + { + "name": "email", + "diversity": false + }, + { + "name": "e-mail", + "diversity": false + }, + { + "name": "incoming_envelope", + "diversity": false + }, + { + "name": "envelope_with_arrow", + "diversity": false + }, + { + "name": "outbox_tray", + "diversity": false + }, + { + "name": "inbox_tray", + "diversity": false + }, + { + "name": "package", + "diversity": false + }, + { + "name": "mailbox", + "diversity": false + }, + { + "name": "mailbox_closed", + "diversity": false + }, + { + "name": "mailbox_with_mail", + "diversity": false + }, + { + "name": "mailbox_with_no_mail", + "diversity": false + }, + { + "name": "postbox", + "diversity": false + }, + { + "name": "ballot_box", + "diversity": false + }, + { + "name": "pencil2", + "diversity": false + }, + { + "name": "black_nib", + "diversity": false + }, + { + "name": "fountain_pen", + "diversity": false + }, + { + "name": "pen", + "diversity": false + }, + { + "name": "paintbrush", + "diversity": false + }, + { + "name": "crayon", + "diversity": false + }, + { + "name": "memo", + "diversity": false + }, + { + "name": "briefcase", + "diversity": false + }, + { + "name": "file_folder", + "diversity": false + }, + { + "name": "open_file_folder", + "diversity": false + }, + { + "name": "card_index_dividers", + "diversity": false + }, + { + "name": "date", + "diversity": false + }, + { + "name": "calendar", + "diversity": false + }, + { + "name": "spiral_notepad", + "diversity": false + }, + { + "name": "spiral_calendar", + "diversity": false + }, + { + "name": "card_index", + "diversity": false + }, + { + "name": "chart_with_upwards_trend", + "diversity": false + }, + { + "name": "chart_with_downwards_trend", + "diversity": false + }, + { + "name": "bar_chart", + "diversity": false + }, + { + "name": "clipboard", + "diversity": false + }, + { + "name": "pushpin", + "diversity": false + }, + { + "name": "round_pushpin", + "diversity": false + }, + { + "name": "paperclip", + "diversity": false + }, + { + "name": "paperclips", + "diversity": false + }, + { + "name": "straight_ruler", + "diversity": false + }, + { + "name": "triangular_ruler", + "diversity": false + }, + { + "name": "scissors", + "diversity": false + }, + { + "name": "card_file_box", + "diversity": false + }, + { + "name": "file_cabinet", + "diversity": false + }, + { + "name": "wastebasket", + "diversity": false + }, + { + "name": "lock", + "diversity": false + }, + { + "name": "unlock", + "diversity": false + }, + { + "name": "lock_with_ink_pen", + "diversity": false + }, + { + "name": "closed_lock_with_key", + "diversity": false + }, + { + "name": "key", + "diversity": false + }, + { + "name": "old_key", + "diversity": false + }, + { + "name": "hammer", + "diversity": false + }, + { + "name": "pick", + "diversity": false + }, + { + "name": "hammer_and_pick", + "diversity": false + }, + { + "name": "hammer_and_wrench", + "diversity": false + }, + { + "name": "dagger", + "diversity": false + }, + { + "name": "crossed_swords", + "diversity": false + }, + { + "name": "gun", + "diversity": false + }, + { + "name": "bow_and_arrow", + "diversity": false + }, + { + "name": "shield", + "diversity": false + }, + { + "name": "wrench", + "diversity": false + }, + { + "name": "nut_and_bolt", + "diversity": false + }, + { + "name": "gear", + "diversity": false + }, + { + "name": "clamp", + "diversity": false + }, + { + "name": "alembic", + "diversity": false + }, + { + "name": "balance_scale", + "diversity": false + }, + { + "name": "link", + "diversity": false + }, + { + "name": "chains", + "diversity": false + }, + { + "name": "syringe", + "diversity": false + }, + { + "name": "pill", + "diversity": false + }, + { + "name": "smoking", + "diversity": false + }, + { + "name": "coffin", + "diversity": false + }, + { + "name": "funeral_urn", + "diversity": false + }, + { + "name": "moyai", + "diversity": false + }, + { + "name": "oil_drum", + "diversity": false + }, + { + "name": "crystal_ball", + "diversity": false + }, + { + "name": "shopping_cart", + "diversity": false + }, + { + "name": "atm", + "diversity": false + }, + { + "name": "put_litter_in_its_place", + "diversity": false + }, + { + "name": "potable_water", + "diversity": false + }, + { + "name": "wheelchair", + "diversity": false + }, + { + "name": "mens", + "diversity": false + }, + { + "name": "womens", + "diversity": false + }, + { + "name": "restroom", + "diversity": false + }, + { + "name": "baby_symbol", + "diversity": false + }, + { + "name": "wc", + "diversity": false + }, + { + "name": "passport_control", + "diversity": false + }, + { + "name": "customs", + "diversity": false + }, + { + "name": "baggage_claim", + "diversity": false + }, + { + "name": "left_luggage", + "diversity": false + }, + { + "name": "warning", + "diversity": false + }, + { + "name": "children_crossing", + "diversity": false + }, + { + "name": "no_entry", + "diversity": false + }, + { + "name": "no_entry_sign", + "diversity": false + }, + { + "name": "no_bicycles", + "diversity": false + }, + { + "name": "no_smoking", + "diversity": false + }, + { + "name": "do_not_litter", + "diversity": false + }, + { + "name": "non-potable_water", + "diversity": false + }, + { + "name": "no_pedestrians", + "diversity": false + }, + { + "name": "no_mobile_phones", + "diversity": false + }, + { + "name": "underage", + "diversity": false + }, + { + "name": "radioactive", + "diversity": false + }, + { + "name": "biohazard", + "diversity": false + }, + { + "name": "arrow_up", + "diversity": false + }, + { + "name": "arrow_upper_right", + "diversity": false + }, + { + "name": "arrow_right", + "diversity": false + }, + { + "name": "arrow_lower_right", + "diversity": false + }, + { + "name": "arrow_down", + "diversity": false + }, + { + "name": "arrow_lower_left", + "diversity": false + }, + { + "name": "arrow_left", + "diversity": false + }, + { + "name": "arrow_upper_left", + "diversity": false + }, + { + "name": "arrow_up_down", + "diversity": false + }, + { + "name": "left_right_arrow", + "diversity": false + }, + { + "name": "leftwards_arrow_with_hook", + "diversity": false + }, + { + "name": "arrow_right_hook", + "diversity": false + }, + { + "name": "arrow_heading_up", + "diversity": false + }, + { + "name": "arrow_heading_down", + "diversity": false + }, + { + "name": "arrows_clockwise", + "diversity": false + }, + { + "name": "arrows_counterclockwise", + "diversity": false + }, + { + "name": "back", + "diversity": false + }, + { + "name": "end", + "diversity": false + }, + { + "name": "on", + "diversity": false + }, + { + "name": "soon", + "diversity": false + }, + { + "name": "top", + "diversity": false + }, + { + "name": "place_of_worship", + "diversity": false + }, + { + "name": "atom_symbol", + "diversity": false + }, + { + "name": "om", + "diversity": false + }, + { + "name": "star_of_david", + "diversity": false + }, + { + "name": "wheel_of_dharma", + "diversity": false + }, + { + "name": "yin_yang", + "diversity": false + }, + { + "name": "latin_cross", + "diversity": false + }, + { + "name": "orthodox_cross", + "diversity": false + }, + { + "name": "star_and_crescent", + "diversity": false + }, + { + "name": "peace_symbol", + "diversity": false + }, + { + "name": "menorah", + "diversity": false + }, + { + "name": "six_pointed_star", + "diversity": false + }, + { + "name": "aries", + "diversity": false + }, + { + "name": "taurus", + "diversity": false + }, + { + "name": "gemini", + "diversity": false + }, + { + "name": "cancer", + "diversity": false + }, + { + "name": "leo", + "diversity": false + }, + { + "name": "virgo", + "diversity": false + }, + { + "name": "libra", + "diversity": false + }, + { + "name": "scorpius", + "diversity": false + }, + { + "name": "sagittarius", + "diversity": false + }, + { + "name": "capricorn", + "diversity": false + }, + { + "name": "aquarius", + "diversity": false + }, + { + "name": "pisces", + "diversity": false + }, + { + "name": "ophiuchus", + "diversity": false + }, + { + "name": "twisted_rightwards_arrows", + "diversity": false + }, + { + "name": "repeat", + "diversity": false + }, + { + "name": "repeat_one", + "diversity": false + }, + { + "name": "arrow_forward", + "diversity": false + }, + { + "name": "fast_forward", + "diversity": false + }, + { + "name": "next_track_button", + "diversity": false + }, + { + "name": "play_or_pause_button", + "diversity": false + }, + { + "name": "arrow_backward", + "diversity": false + }, + { + "name": "rewind", + "diversity": false + }, + { + "name": "previous_track_button", + "diversity": false + }, + { + "name": "arrow_up_small", + "diversity": false + }, + { + "name": "arrow_double_up", + "diversity": false + }, + { + "name": "arrow_down_small", + "diversity": false + }, + { + "name": "arrow_double_down", + "diversity": false + }, + { + "name": "pause_button", + "diversity": false + }, + { + "name": "stop_button", + "diversity": false + }, + { + "name": "record_button", + "diversity": false + }, + { + "name": "cinema", + "diversity": false + }, + { + "name": "low_brightness", + "diversity": false + }, + { + "name": "high_brightness", + "diversity": false + }, + { + "name": "signal_strength", + "diversity": false + }, + { + "name": "vibration_mode", + "diversity": false + }, + { + "name": "mobile_phone_off", + "diversity": false + }, + { + "name": "recycle", + "diversity": false + }, + { + "name": "fleur_de_lis", + "diversity": false + }, + { + "name": "trident", + "diversity": false + }, + { + "name": "name_badge", + "diversity": false + }, + { + "name": "beginner", + "diversity": false + }, + { + "name": "o", + "diversity": false + }, + { + "name": "white_check_mark", + "diversity": false + }, + { + "name": "ballot_box_with_check", + "diversity": false + }, + { + "name": "heavy_check_mark", + "diversity": false + }, + { + "name": "heavy_multiplication_x", + "diversity": false + }, + { + "name": "x", + "diversity": false + }, + { + "name": "negative_squared_cross_mark", + "diversity": false + }, + { + "name": "heavy_plus_sign", + "diversity": false + }, + { + "name": "heavy_minus_sign", + "diversity": false + }, + { + "name": "heavy_division_sign", + "diversity": false + }, + { + "name": "curly_loop", + "diversity": false + }, + { + "name": "loop", + "diversity": false + }, + { + "name": "part_alternation_mark", + "diversity": false + }, + { + "name": "eight_spoked_asterisk", + "diversity": false + }, + { + "name": "eight_pointed_black_star", + "diversity": false + }, + { + "name": "sparkle", + "diversity": false + }, + { + "name": "bangbang", + "diversity": false + }, + { + "name": "interrobang", + "diversity": false + }, + { + "name": "question", + "diversity": false + }, + { + "name": "grey_question", + "diversity": false + }, + { + "name": "grey_exclamation", + "diversity": false + }, + { + "name": "exclamation", + "diversity": false + }, + { + "name": "wavy_dash", + "diversity": false + }, + { + "name": "copyright", + "diversity": false + }, + { + "name": "registered", + "diversity": false + }, + { + "name": "tm", + "diversity": false + }, + { + "name": "hash", + "diversity": false + }, + { + "name": "asterisk", + "diversity": false + }, + { + "name": "zero", + "diversity": false + }, + { + "name": "one", + "diversity": false + }, + { + "name": "two", + "diversity": false + }, + { + "name": "three", + "diversity": false + }, + { + "name": "four", + "diversity": false + }, + { + "name": "five", + "diversity": false + }, + { + "name": "six", + "diversity": false + }, + { + "name": "seven", + "diversity": false + }, + { + "name": "eight", + "diversity": false + }, + { + "name": "nine", + "diversity": false + }, + { + "name": "keycap_ten", + "diversity": false + }, + { + "name": "100", + "diversity": false + }, + { + "name": "capital_abcd", + "diversity": false + }, + { + "name": "abcd", + "diversity": false + }, + { + "name": "1234", + "diversity": false + }, + { + "name": "symbols", + "diversity": false + }, + { + "name": "abc", + "diversity": false + }, + { + "name": "a", + "diversity": false + }, + { + "name": "ab", + "diversity": false + }, + { + "name": "b", + "diversity": false + }, + { + "name": "cl", + "diversity": false + }, + { + "name": "cool", + "diversity": false + }, + { + "name": "free", + "diversity": false + }, + { + "name": "information_source", + "diversity": false + }, + { + "name": "id", + "diversity": false + }, + { + "name": "m", + "diversity": false + }, + { + "name": "new", + "diversity": false + }, + { + "name": "ng", + "diversity": false + }, + { + "name": "o2", + "diversity": false + }, + { + "name": "ok", + "diversity": false + }, + { + "name": "parking", + "diversity": false + }, + { + "name": "sos", + "diversity": false + }, + { + "name": "up", + "diversity": false + }, + { + "name": "vs", + "diversity": false + }, + { + "name": "koko", + "diversity": false + }, + { + "name": "sa", + "diversity": false + }, + { + "name": "u6708", + "diversity": false + }, + { + "name": "u6709", + "diversity": false + }, + { + "name": "u6307", + "diversity": false + }, + { + "name": "ideograph_advantage", + "diversity": false + }, + { + "name": "u5272", + "diversity": false + }, + { + "name": "u7121", + "diversity": false + }, + { + "name": "u7981", + "diversity": false + }, + { + "name": "accept", + "diversity": false + }, + { + "name": "u7533", + "diversity": false + }, + { + "name": "u5408", + "diversity": false + }, + { + "name": "u7a7a", + "diversity": false + }, + { + "name": "congratulations", + "diversity": false + }, + { + "name": "secret", + "diversity": false + }, + { + "name": "u55b6", + "diversity": false + }, + { + "name": "u6e80", + "diversity": false + }, + { + "name": "black_small_square", + "diversity": false + }, + { + "name": "white_small_square", + "diversity": false + }, + { + "name": "white_medium_square", + "diversity": false + }, + { + "name": "black_medium_square", + "diversity": false + }, + { + "name": "white_medium_small_square", + "diversity": false + }, + { + "name": "black_medium_small_square", + "diversity": false + }, + { + "name": "black_large_square", + "diversity": false + }, + { + "name": "white_large_square", + "diversity": false + }, + { + "name": "large_orange_diamond", + "diversity": false + }, + { + "name": "large_blue_diamond", + "diversity": false + }, + { + "name": "small_orange_diamond", + "diversity": false + }, + { + "name": "small_blue_diamond", + "diversity": false + }, + { + "name": "small_red_triangle", + "diversity": false + }, + { + "name": "small_red_triangle_down", + "diversity": false + }, + { + "name": "diamond_shape_with_a_dot_inside", + "diversity": false + }, + { + "name": "radio_button", + "diversity": false + }, + { + "name": "black_square_button", + "diversity": false + }, + { + "name": "white_square_button", + "diversity": false + }, + { + "name": "white_circle", + "diversity": false + }, + { + "name": "black_circle", + "diversity": false + }, + { + "name": "red_circle", + "diversity": false + }, + { + "name": "large_blue_circle", + "diversity": false + }, + { + "name": "hourglass", + "diversity": false + }, + { + "name": "hourglass_flowing_sand", + "diversity": false + }, + { + "name": "watch", + "diversity": false + }, + { + "name": "alarm_clock", + "diversity": false + }, + { + "name": "stopwatch", + "diversity": false + }, + { + "name": "timer_clock", + "diversity": false + }, + { + "name": "mantelpiece_clock", + "diversity": false + }, + { + "name": "clock12", + "diversity": false + }, + { + "name": "clock1230", + "diversity": false + }, + { + "name": "clock1", + "diversity": false + }, + { + "name": "clock130", + "diversity": false + }, + { + "name": "clock2", + "diversity": false + }, + { + "name": "clock230", + "diversity": false + }, + { + "name": "clock3", + "diversity": false + }, + { + "name": "clock330", + "diversity": false + }, + { + "name": "clock4", + "diversity": false + }, + { + "name": "clock430", + "diversity": false + }, + { + "name": "clock5", + "diversity": false + }, + { + "name": "clock530", + "diversity": false + }, + { + "name": "clock6", + "diversity": false + }, + { + "name": "clock630", + "diversity": false + }, + { + "name": "clock7", + "diversity": false + }, + { + "name": "clock730", + "diversity": false + }, + { + "name": "clock8", + "diversity": false + }, + { + "name": "clock830", + "diversity": false + }, + { + "name": "clock9", + "diversity": false + }, + { + "name": "clock930", + "diversity": false + }, + { + "name": "clock10", + "diversity": false + }, + { + "name": "clock1030", + "diversity": false + }, + { + "name": "clock11", + "diversity": false + }, + { + "name": "clock1130", + "diversity": false + } + ] + } +] \ No newline at end of file diff --git a/lib/tasks/emoji.rake b/lib/tasks/emoji.rake index e1efd1ef739..a601dbc3c87 100644 --- a/lib/tasks/emoji.rake +++ b/lib/tasks/emoji.rake @@ -4,7 +4,7 @@ require "json" require "nokogiri" require "open-uri" -EMOJI_GROUPS_PATH ||= "app/assets/javascripts/discourse/lib/emoji/groups.js.es6" +EMOJI_GROUPS_PATH ||= "lib/emoji/groups.json" EMOJI_DB_PATH ||= "lib/emoji/db.json" @@ -432,7 +432,7 @@ def fix_incomplete_sets(emojis) end end -def generate_emoji_groups(emojis) +def generate_emoji_groups(keywords) puts "Generating groups..." list = open(EMOJI_ORDERING_URL).read @@ -453,8 +453,8 @@ def generate_emoji_groups(emojis) emoji_char = code_to_emoji(emoji_code) - if emoji = emojis[emoji_char] - group["icons"] << emoji["name"] + if emoji = keywords[emoji_char] + group["icons"] << { name: emoji["name"], diversity: emoji["fitzpatrick_scale"] } end end end @@ -518,15 +518,7 @@ def write_js_groups(emojis, groups) confirm_overwrite(EMOJI_GROUPS_PATH) - template = <