Merge branch 'main' into mobile/bridge-components
* main:
Fix that caching should be disabled in dev by default. References 3cf841d463.
Revert "Add CJK (Chinese, Japanese, Korean) search support"
Account for new button sizes on mobile
Bump filter z-index when filters are open
Use a dedicated resource for showing cards in draft mode
Refactor popup.css styles for focus state
Add Segoe UI Variable Fizzy font face configuration comments
Update @layer name to `base` in font-face definition for "Segoe UI Variable Fizzy"
Fix font-face `src` reference for "Segoe UI Variable Fizzy" to correct local font lookup
Adjust font-weight range for "Segoe UI Variable Fizzy" to include 800-900
Update --font-sans and related font-face references to "Segoe UI Variable Fizzy" for consistency
Add "Segoe UI fizzy" to --font-sans and define custom font faces
Update --font-sans to include "Segoe UI Variable" for improved text rendering
Add margin to details inside popup styles
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
--block-space-double: calc(var(--block-space) * 2);
|
||||
|
||||
/* Text */
|
||||
--font-sans: "Adwaita Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
--font-sans: "Adwaita Sans", -apple-system, BlinkMacSystemFont, "Segoe UI Variable Fizzy", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
--font-serif: ui-serif, serif;
|
||||
--font-mono: ui-monospace, monospace;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
--comment-padding-block: var(--block-space-half);
|
||||
--comment-padding-inline: var(--inline-space-double);
|
||||
--comment-max: 70ch;
|
||||
--reaction-size: 1.6875rem;
|
||||
--reaction-size: 2rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -15,6 +15,10 @@
|
||||
@media (min-width: 160ch) {
|
||||
padding-inline: var(--tray-size);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
--reaction-size: 1.6875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.comments__subscribers {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
--input-background: var(--color-canvas);
|
||||
}
|
||||
|
||||
&:has(dialog[open]),
|
||||
&:has([data-controller~="tooltip"]:hover) {
|
||||
z-index: calc(var(--z-nav) + 1);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
@layer base {
|
||||
/*
|
||||
Segoe UI Variable Fizzy font face configuration.
|
||||
|
||||
1. Segoe UI Variable (Weights 100-700):
|
||||
Leverages variable font features to:
|
||||
- Automatically adjust Weight (wght) dynamically within the 100-700 range.
|
||||
- Automatically manage Optical Size (opsz) based on font-size.
|
||||
|
||||
2. Segoe UI Black (Weights 800-900):
|
||||
Used as a fallback because Segoe UI Variable does not natively support 900 weight.
|
||||
This ensures a consistent bold experience across all weights.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: "Segoe UI Variable Fizzy";
|
||||
src: local("Segoe UI Variable");
|
||||
font-weight: 100 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Segoe UI Variable Fizzy";
|
||||
src: local("Segoe UI Variable");
|
||||
font-weight: 100 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Segoe UI Variable Fizzy";
|
||||
src: local("Segoe UI Black");
|
||||
font-weight: 800 900;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Segoe UI Variable Fizzy";
|
||||
src: local("Segoe UI Black Italic");
|
||||
font-weight: 800 900;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
@@ -155,6 +155,10 @@
|
||||
max-inline-size: 100%;
|
||||
padding: var(--inline-space-half) var(--popup-item-padding-inline);
|
||||
text-align: start;
|
||||
|
||||
&:focus-visible {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.popup__icon {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
flex-wrap: wrap;
|
||||
gap: var(--inline-space-half);
|
||||
inline-size: 100%;
|
||||
margin-block-start: calc(var(--block-space-half) / 2);
|
||||
margin-block-start: var(--block-space-half);
|
||||
margin-inline: calc(var(--column-gap) / -1);
|
||||
|
||||
&:has([open]) {
|
||||
@@ -44,6 +44,7 @@
|
||||
}
|
||||
|
||||
.reactions__trigger {
|
||||
--btn-size: var(--reaction-size);
|
||||
--btn-border-color: var(--reaction-border-color);
|
||||
|
||||
img {
|
||||
@@ -115,11 +116,13 @@
|
||||
|
||||
/* Make the avatar and delete buttons fit nicely within the reaction */
|
||||
.reaction__avatar,
|
||||
.reaction__avatar .avatar,
|
||||
.reaction__form-label,
|
||||
.reaction form {
|
||||
block-size: var(--btn-size);
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
|
||||
.reaction__delete {
|
||||
display: none;
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
class Cards::DraftsController < ApplicationController
|
||||
include CardScoped
|
||||
|
||||
before_action :redirect_if_published
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
private
|
||||
def redirect_if_published
|
||||
redirect_to @card unless @card.drafted?
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,8 @@ class Cards::PublishesController < ApplicationController
|
||||
@card.publish
|
||||
|
||||
if add_another_param?
|
||||
redirect_to @board.cards.create!, notice: "Card added"
|
||||
card = @board.cards.create!(status: :drafted)
|
||||
redirect_to card_draft_path(card), notice: "Card added"
|
||||
else
|
||||
redirect_to @card.board
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@ class CardsController < ApplicationController
|
||||
|
||||
before_action :set_board, only: %i[ create ]
|
||||
before_action :set_card, only: %i[ show edit update destroy ]
|
||||
before_action :redirect_if_drafted, only: :show
|
||||
before_action :ensure_permission_to_administer_card, only: %i[ destroy ]
|
||||
|
||||
def index
|
||||
@@ -13,7 +14,7 @@ class CardsController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
card = Current.user.draft_new_card_in(@board)
|
||||
redirect_to card
|
||||
redirect_to card_draft_path(card)
|
||||
end
|
||||
|
||||
format.json do
|
||||
@@ -56,6 +57,10 @@ class CardsController < ApplicationController
|
||||
@card = Current.user.accessible_cards.find_by!(number: params[:id])
|
||||
end
|
||||
|
||||
def redirect_if_drafted
|
||||
redirect_to card_draft_path(@card) if @card.drafted?
|
||||
end
|
||||
|
||||
def ensure_permission_to_administer_card
|
||||
head :forbidden unless Current.user.can_administer_card?(@card)
|
||||
end
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
module Search
|
||||
CJK_PATTERN = /\p{Han}|\p{Hiragana}|\p{Katakana}|\p{Hangul}/
|
||||
|
||||
def self.table_name_prefix
|
||||
"search_"
|
||||
end
|
||||
|
||||
@@ -13,14 +13,8 @@ class Search::Highlighter
|
||||
result = text.dup
|
||||
|
||||
terms.each do |term|
|
||||
if term.match?(Search::CJK_PATTERN)
|
||||
result.gsub!(/(#{Regexp.escape(term)})/i) do |match|
|
||||
"#{OPENING_MARK}#{match}#{CLOSING_MARK}"
|
||||
end
|
||||
else
|
||||
result.gsub!(/\b(#{Regexp.escape(term)}\w*)\b/i) do |match|
|
||||
"#{OPENING_MARK}#{match}#{CLOSING_MARK}"
|
||||
end
|
||||
result.gsub!(/\b(#{Regexp.escape(term)}\w*)\b/i) do |match|
|
||||
"#{OPENING_MARK}#{match}#{CLOSING_MARK}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ class Search::Query < ApplicationRecord
|
||||
end
|
||||
|
||||
def remove_invalid_search_characters(terms)
|
||||
terms.gsub(/[^\p{L}\p{N}_"]/, " ")
|
||||
terms.gsub(/[^\w"]/, " ")
|
||||
end
|
||||
|
||||
def remove_unbalanced_quotes(terms)
|
||||
|
||||
@@ -8,10 +8,9 @@ module Search::Record::SQLite
|
||||
has_one :search_records_fts, -> { with_rowid },
|
||||
class_name: "Search::Record::SQLite::Fts", foreign_key: :rowid, primary_key: :id, dependent: :destroy
|
||||
|
||||
before_save :stem_content
|
||||
after_save :upsert_to_fts5_table
|
||||
|
||||
scope :matching, ->(query, account_id) { joins(:search_records_fts).where("search_records_fts MATCH ?", Search::Stemmer.stem(query.to_s)) }
|
||||
scope :matching, ->(query, account_id) { joins(:search_records_fts).where("search_records_fts MATCH ?", query) }
|
||||
end
|
||||
|
||||
class_methods do
|
||||
@@ -43,11 +42,6 @@ module Search::Record::SQLite
|
||||
end
|
||||
|
||||
private
|
||||
def stem_content
|
||||
self.title = Search::Stemmer.stem(title) if title_changed?
|
||||
self.content = Search::Stemmer.stem(content) if content_changed?
|
||||
end
|
||||
|
||||
def escape_fts_highlight(html)
|
||||
return nil unless html.present?
|
||||
|
||||
|
||||
@@ -5,43 +5,9 @@ module Search::Stemmer
|
||||
|
||||
def stem(value)
|
||||
if value.present?
|
||||
tokenize(value).join(" ")
|
||||
value.gsub(/[^\w\s]/, "").split(/\s+/).map { |word| STEMMER.stem(word.downcase) }.join(" ")
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def tokenize(value)
|
||||
tokens = []
|
||||
current_word = +""
|
||||
|
||||
value.each_char do |char|
|
||||
if cjk_character?(char)
|
||||
if current_word.present?
|
||||
tokens << stem_word(current_word)
|
||||
current_word = +""
|
||||
end
|
||||
tokens << char
|
||||
elsif char =~ /[\p{L}\p{N}_]/
|
||||
current_word << char
|
||||
else
|
||||
if current_word.present?
|
||||
tokens << stem_word(current_word)
|
||||
current_word = +""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tokens << stem_word(current_word) if current_word.present?
|
||||
tokens
|
||||
end
|
||||
|
||||
def cjk_character?(char)
|
||||
char.match?(Search::CJK_PATTERN)
|
||||
end
|
||||
|
||||
def stem_word(word)
|
||||
STEMMER.stem(word.downcase)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -37,11 +37,5 @@
|
||||
|
||||
<% if card.published? %>
|
||||
<%= render "cards/container/footer/published", card: card %>
|
||||
<% elsif card.drafted? %>
|
||||
<% if Fizzy.saas? %>
|
||||
<%= render "cards/container/footer/saas/create", card: card %>
|
||||
<% else %>
|
||||
<%= render "cards/container/footer/create", card: card %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<section id="<%= dom_id(card, :card_container) %>" class="card-perma" style="--card-color: <%= card.color %>;">
|
||||
<% cache card do %>
|
||||
<div class="card-perma__actions card-perma__actions--left">
|
||||
<%= render "cards/container/image", card: card %>
|
||||
</div>
|
||||
|
||||
<div class="card-perma__bg">
|
||||
<%= card_article_tag card, class: "card" do %>
|
||||
<header class="card__header">
|
||||
<%= render "cards/display/perma/board", card: card %>
|
||||
<%= render "cards/display/perma/tags", card: card %>
|
||||
</header>
|
||||
|
||||
<div class="card__body justify-space-between">
|
||||
<div class="card__content">
|
||||
<%= render "cards/container/content", card: card %>
|
||||
<%= render "cards/display/perma/steps", card: card %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="card__footer full-width flex align-start gap">
|
||||
<%= render "cards/display/perma/meta", card: card %>
|
||||
<%= render "cards/display/perma/background", card: card %>
|
||||
</footer>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if Fizzy.saas? %>
|
||||
<%= render "cards/container/footer/saas/create", card: card %>
|
||||
<% else %>
|
||||
<%= render "cards/container/footer/create", card: card %>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -0,0 +1,16 @@
|
||||
<% @page_title = @card.title %>
|
||||
<% @header_class = "header--card" %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<div class="header__actions header__actions--start">
|
||||
<%= link_back_to_board(@card.board) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div data-controller="beacon lightbox" data-beacon-url-value="<%= card_reading_path(@card) %>">
|
||||
<%= render "cards/drafts/container", card: @card %>
|
||||
|
||||
<%= render "layouts/lightbox" do %>
|
||||
<%= button_to_remove_card_image(@card) if @card.image.attached? %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<div data-controller="beacon lightbox" data-beacon-url-value="<%= card_reading_path(@card) %>">
|
||||
<%= render "cards/container", card: @card %>
|
||||
<%= render "cards/messages", card: @card unless @card.drafted? %>
|
||||
<%= render "cards/messages", card: @card %>
|
||||
|
||||
<%= render "layouts/lightbox" do %>
|
||||
<%= button_to_remove_card_image(@card) if @card.image.attached? %>
|
||||
|
||||
@@ -26,7 +26,7 @@ Rails.application.configure do
|
||||
config.cache_store = :memory_store
|
||||
config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{2.days.to_i}" }
|
||||
else
|
||||
config.action_controller.perform_caching = true
|
||||
config.action_controller.perform_caching = false
|
||||
|
||||
config.cache_store = :null_store
|
||||
end
|
||||
|
||||
@@ -71,6 +71,7 @@ Rails.application.routes.draw do
|
||||
|
||||
resources :cards do
|
||||
scope module: :cards do
|
||||
resource :draft, only: :show
|
||||
resource :board
|
||||
resource :closure
|
||||
resource :column
|
||||
|
||||
@@ -10,7 +10,7 @@ class Account::Subscriptions::CardCreationTest < ActionDispatch::IntegrationTest
|
||||
test "admin sees nearing card limit notice" do
|
||||
accounts(:initech).update_column(:cards_count, 950)
|
||||
|
||||
get card_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
get card_draft_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
|
||||
assert_response :success
|
||||
assert_match /upgrade to unlimited/i, response.body
|
||||
@@ -19,7 +19,7 @@ class Account::Subscriptions::CardCreationTest < ActionDispatch::IntegrationTest
|
||||
test "admin sees nearing storage limit notice" do
|
||||
Account.any_instance.stubs(:bytes_used).returns(600.megabytes)
|
||||
|
||||
get card_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
get card_draft_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
|
||||
assert_response :success
|
||||
assert_match /upgrade to get more/i, response.body
|
||||
@@ -30,7 +30,7 @@ class Account::Subscriptions::CardCreationTest < ActionDispatch::IntegrationTest
|
||||
test "admin sees exceeding card limit notice" do
|
||||
accounts(:initech).update_column(:cards_count, 1001)
|
||||
|
||||
get card_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
get card_draft_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
|
||||
assert_response :success
|
||||
assert_match /you’ve used your.*free cards/i, response.body
|
||||
@@ -39,7 +39,7 @@ class Account::Subscriptions::CardCreationTest < ActionDispatch::IntegrationTest
|
||||
test "admin sees exceeding storage limit notice" do
|
||||
Account.any_instance.stubs(:bytes_used).returns(1.1.gigabytes)
|
||||
|
||||
get card_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
get card_draft_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
|
||||
assert_response :success
|
||||
assert_match /you’ve run out of.*free storage/i, response.body
|
||||
@@ -64,7 +64,7 @@ class Account::Subscriptions::CardCreationTest < ActionDispatch::IntegrationTest
|
||||
test "comped account under limits sees no notices" do
|
||||
accounts(:initech).comp
|
||||
|
||||
get card_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
get card_draft_path(cards(:unfinished_thoughts), script_name: accounts(:initech).slug)
|
||||
|
||||
assert_response :success
|
||||
assert_no_match /upgrade/i, response.body
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
require "test_helper"
|
||||
|
||||
class Cards::DraftsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in_as :kevin
|
||||
end
|
||||
|
||||
test "show" do
|
||||
card = boards(:writebook).cards.create!(creator: users(:kevin), status: :drafted)
|
||||
|
||||
get card_draft_path(card)
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "show redirects to card when published" do
|
||||
card = cards(:logo)
|
||||
|
||||
get card_draft_path(card)
|
||||
assert_redirected_to card
|
||||
end
|
||||
end
|
||||
@@ -28,6 +28,6 @@ class Cards::PublishesControllerTest < ActionDispatch::IntegrationTest
|
||||
|
||||
new_card = Card.last
|
||||
assert new_card.drafted?
|
||||
assert_redirected_to new_card
|
||||
assert_redirected_to card_draft_path(new_card)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -21,7 +21,7 @@ class CardsControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
card = Card.last
|
||||
assert_redirected_to card
|
||||
assert_redirected_to card_draft_path(card)
|
||||
|
||||
assert card.drafted?
|
||||
end
|
||||
@@ -31,10 +31,17 @@ class CardsControllerTest < ActionDispatch::IntegrationTest
|
||||
|
||||
assert_no_difference -> { Card.count } do
|
||||
post board_cards_path(boards(:writebook))
|
||||
assert_redirected_to draft
|
||||
assert_redirected_to card_draft_path(draft)
|
||||
end
|
||||
end
|
||||
|
||||
test "show redirects to draft when card is drafted" do
|
||||
card = boards(:writebook).cards.create!(creator: users(:kevin), status: :drafted)
|
||||
|
||||
get card_path(card)
|
||||
assert_redirected_to card_draft_path(card)
|
||||
end
|
||||
|
||||
test "show" do
|
||||
get card_path(cards(:logo))
|
||||
assert_response :success
|
||||
|
||||
@@ -82,34 +82,6 @@ class Search::HighlighterTest < ActiveSupport::TestCase
|
||||
assert_equal "<script>#{mark('test')}</script>", result
|
||||
end
|
||||
|
||||
test "highlight Chinese characters" do
|
||||
highlighter = Search::Highlighter.new("测试")
|
||||
result = highlighter.highlight("这是一个测试文本")
|
||||
|
||||
assert_equal "这是一个#{mark('测试')}文本", result
|
||||
end
|
||||
|
||||
test "highlight Japanese characters" do
|
||||
highlighter = Search::Highlighter.new("テスト")
|
||||
result = highlighter.highlight("これはテストです")
|
||||
|
||||
assert_equal "これは#{mark('テスト')}です", result
|
||||
end
|
||||
|
||||
test "highlight Korean characters" do
|
||||
highlighter = Search::Highlighter.new("테스트")
|
||||
result = highlighter.highlight("이것은 테스트입니다")
|
||||
|
||||
assert_equal "이것은 #{mark('테스트')}입니다", result
|
||||
end
|
||||
|
||||
test "highlight mixed CJK and English" do
|
||||
highlighter = Search::Highlighter.new("world 世界")
|
||||
result = highlighter.highlight("hello world 你好世界")
|
||||
|
||||
assert_equal "hello #{mark('world')} 你好#{mark('世界')}", result
|
||||
end
|
||||
|
||||
private
|
||||
def mark(text)
|
||||
"#{Search::Highlighter::OPENING_MARK}#{text}#{Search::Highlighter::CLOSING_MARK}"
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class Search::QueryTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@account = accounts(:"37s")
|
||||
Current.account = @account
|
||||
end
|
||||
|
||||
test "sanitize preserves ASCII words" do
|
||||
query = build_query("hello world")
|
||||
|
||||
assert_equal "hello world", query.terms
|
||||
end
|
||||
|
||||
test "sanitize preserves Chinese characters" do
|
||||
query = build_query("测试文本")
|
||||
|
||||
assert_equal "测试文本", query.terms
|
||||
end
|
||||
|
||||
test "sanitize preserves Japanese characters" do
|
||||
query = build_query("テスト")
|
||||
|
||||
assert_equal "テスト", query.terms
|
||||
end
|
||||
|
||||
test "sanitize preserves Korean characters" do
|
||||
query = build_query("테스트")
|
||||
|
||||
assert_equal "테스트", query.terms
|
||||
end
|
||||
|
||||
test "sanitize preserves mixed CJK and English" do
|
||||
query = build_query("hello 世界 test")
|
||||
|
||||
assert_equal "hello 世界 test", query.terms
|
||||
end
|
||||
|
||||
test "sanitize removes special characters but preserves CJK" do
|
||||
query = build_query("测试@文本")
|
||||
|
||||
assert_equal "测试 文本", query.terms
|
||||
end
|
||||
|
||||
test "sanitize preserves quoted phrases with CJK" do
|
||||
query = build_query('"你好世界"')
|
||||
|
||||
assert_equal '"你好世界"', query.terms
|
||||
end
|
||||
|
||||
private
|
||||
def build_query(terms)
|
||||
query = Search::Query.wrap(terms)
|
||||
query.validate
|
||||
query
|
||||
end
|
||||
end
|
||||
@@ -12,40 +12,4 @@ class Search::StemmerTest < ActiveSupport::TestCase
|
||||
|
||||
assert_equal "test run jump walk", result
|
||||
end
|
||||
|
||||
test "split Chinese characters for FTS indexing" do
|
||||
result = Search::Stemmer.stem("测试")
|
||||
|
||||
assert_equal "测 试", result
|
||||
end
|
||||
|
||||
test "split Japanese characters for FTS indexing" do
|
||||
result = Search::Stemmer.stem("テスト")
|
||||
|
||||
assert_equal "テ ス ト", result
|
||||
end
|
||||
|
||||
test "split Korean characters for FTS indexing" do
|
||||
result = Search::Stemmer.stem("테스트")
|
||||
|
||||
assert_equal "테 스 트", result
|
||||
end
|
||||
|
||||
test "mixed CJK and English" do
|
||||
result = Search::Stemmer.stem("running 测试 test")
|
||||
|
||||
assert_equal "run 测 试 test", result
|
||||
end
|
||||
|
||||
test "mixed CJK and English without spaces" do
|
||||
result = Search::Stemmer.stem("hello世界test")
|
||||
|
||||
assert_equal "hello 世 界 test", result
|
||||
end
|
||||
|
||||
test "CJK punctuation is treated as separator" do
|
||||
result = Search::Stemmer.stem("你好。世界")
|
||||
|
||||
assert_equal "你 好 世 界", result
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user