├── .gitattributes ├── nene ├── PUAExt-Regular.ttf ├── PUAExt-Regular.woff ├── PUAExt-Regular.woff2 ├── NeneHanSeeker.htm └── seeker.js ├── release ├── PUAExt-Regular.ttf ├── PUAExt-Regular.woff ├── PUAExt-Regular.woff2 ├── HanSeeker_WithoutJS.html ├── seeker.js └── HanSeeker_WithoutData.html ├── gen_release.rb ├── README.md └── source ├── data_vt.txt ├── HanSeeker.htm └── corecode.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /nene/PUAExt-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButTaiwan/hanseeker/HEAD/nene/PUAExt-Regular.ttf -------------------------------------------------------------------------------- /nene/PUAExt-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButTaiwan/hanseeker/HEAD/nene/PUAExt-Regular.woff -------------------------------------------------------------------------------- /nene/PUAExt-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButTaiwan/hanseeker/HEAD/nene/PUAExt-Regular.woff2 -------------------------------------------------------------------------------- /release/PUAExt-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButTaiwan/hanseeker/HEAD/release/PUAExt-Regular.ttf -------------------------------------------------------------------------------- /release/PUAExt-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButTaiwan/hanseeker/HEAD/release/PUAExt-Regular.woff -------------------------------------------------------------------------------- /release/PUAExt-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButTaiwan/hanseeker/HEAD/release/PUAExt-Regular.woff2 -------------------------------------------------------------------------------- /gen_release.rb: -------------------------------------------------------------------------------- 1 | o1 = File.open('release/handata_uni.js', 'w:utf-8') 2 | o2 = File.open('release/handata_full.js', 'w:utf-8') 3 | 4 | o1.print 'var dt=[' 5 | f = File.open('source/data_nosupp.txt', 'r:utf-8') 6 | f.each { |s| 7 | s.chomp! 8 | o1.print "'" + s + "'," 9 | } 10 | f.close 11 | o1.puts '];' 12 | 13 | o2.print 'var dt=[' 14 | f = File.open('source/data_supp.txt', 'r:utf-8') 15 | f.each { |s| 16 | s.chomp! 17 | o2.print "'" + s + "'," 18 | } 19 | f.close 20 | o2.puts '];' 21 | 22 | o1.print 'var vt={' 23 | o2.print 'var vt={' 24 | f = File.open('source/data_vt.txt', 'r:utf-8') 25 | f.each { |s| 26 | s.chomp! 27 | a, b = s.split(/\t/, 2) 28 | o1.print "'" + a + "':'" + b + "'," 29 | o2.print "'" + a + "':'" + b + "'," 30 | } 31 | f.close 32 | o1.puts '};' 33 | o2.puts '};' 34 | o1.close 35 | o2.close 36 | 37 | o = File.open('release/seeker.js', 'w:utf-8') 38 | f = File.open('source/corecode.js', 'r:utf-8') 39 | f.each { |s| 40 | s.chomp! 41 | s.gsub!(/\/\/.*$/, '') 42 | s.gsub!(/\s+$/, '') 43 | next if s =~ /^\s*$/ 44 | o.puts if s =~ /^\S/ && s !~ /^\};?$/ 45 | o.print s.gsub(/\s+/, ' ').gsub(/^ /, '').gsub(/ ([\+\-=]) /, '\1').gsub('() {', '(){') 46 | } 47 | f.close 48 | o.close 49 | 50 | 51 | o1 = File.open('release/HanSeeker_WithoutJS.html', 'w:utf-8') 52 | o2 = File.open('release/HanSeeker_WithoutData.html', 'w:utf-8') 53 | o3 = File.open('release/HanSeeker_StandAlone_Unicode.html', 'w:utf-8') 54 | o4 = File.open('release/HanSeeker_StandAlone_All.html', 'w:utf-8') 55 | 56 | f = File.open('source/HanSeeker.htm', 'r:utf-8') 57 | f.each { |s| 58 | s.chomp! 59 | next if s =~ /^\<\!--##--\>/ 60 | 61 | if s != '' 62 | o1.puts s 63 | o2.puts s 64 | o3.puts s 65 | o4.puts s 66 | else 67 | o1.puts '' 68 | o2.puts '' 69 | o3.puts '' 81 | o2.puts '' 93 | o3.puts '' 94 | o4.puts '' 95 | end 96 | } 97 | f.close 98 | 99 | o1.close 100 | o2.close 101 | o3.close 102 | o4.close 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 漢字部件檢索 2 | 3 | 本程式改寫自 WFG 的「部件檢索」(http://fgwang.blogspot.com/2015/12/blog-post_30.html)。 4 | 5 | ## 修改說明 6 | 7 | 1. 效能修改:花幾天看懂程式後,其實相當讚歎 WFG 原始的演算法已經足夠簡潔,沒什麼可以加速提升效能的空間。不過在反覆測試以後,發現此工具操作時的卡頓感,其實不是來自於檢索本身,而是在於同步性。在每輸入、刪除一個字時,仍然需要等待上次的搜尋結果全部完成,才能處理下一次的搜尋,甚至鍵盤會失去反應,此種沒有回應、卡頓的感覺才是使用體驗不佳的主因。理想上,無論即時還是非即時搜尋,當使用者觸發新的查詢時,舊的查詢已經失去意義,應立刻中斷。本想試著讓查詢用平行執行緒來跑,可惜的是JavaScript是個用放棄平行處理來保證執行緒安全的語言,嘗試過各種方法,確定無法做到。最後想到的方法是將查詢碎片化,以分割來模擬多執行緒。將10萬字的資料庫切成100份,每50毫秒搜尋1000字,讓整個搜尋拉到最長5秒完成,比起原先在我的電腦上大約3秒比起來是慢了點,但換來的好處很多。首先當觸發新的查詢時,舊的查詢會即時結束,過時的查詢不再拖延使用效能。第二,分割的每個片段能即時顯示出目前已找到的結果,不是全部等數秒搜尋完才一次顯示,如此可提高互動性,使用者可以同時審視搜尋結果,減少等待的不耐感。第三,同時顯示出搜尋進度,讓使用者感受到系統的即時回饋,降低不確定感。經此修改,目前測試,即便是在手機搜尋,或許搜尋所要時間有些微增加,但使用時都有明顯更輕盈的感覺,不會感受到中斷。 8 | 2. 其中每個單位間隔50毫秒這個值相當難決定,例如我用兩三台不同機器測試,搜尋1000字所要的時間從10毫秒到60毫秒不等。完全與設備等級有關。目前我採取的方式是預設值50毫秒,但會在幾次搜尋之後根據實際執行情況動態加減速率。 9 | 3. 原始程式不知道為何,即使搜尋結果已經超過99/999字,仍然不會中途跳出(似乎是為了有精確符合文字的機會?),但這樣造成無論結果顯示99還是999字,只是差在畫面顯示的結果數量,程式實際上還是搜尋全部10萬字,這也是卡頓原因之一。已改成只搜尋到顯示字數+1字(多找1個字是為了判斷訊息是「超過」還是「總共」)。 10 | 4. 原程式的資料索引方式,是將Unicode漢字區平移到一個陣列中,並使用預先設定的偏移值去找到資料的位置。這樣的好處是索引速度理論上飛快,缺點則是程式裡必須維護許多偏移量的值,使資料集本身增修不易,改動資料集時,都必須調整程式碼內的偏移值,才能正確運作。並且PUA區域雖有大量未定義拆分的文字、未實際作為其他文字拆分結果,但都必須佔用資料量(使資料集字數虛胖)。我試著嘗試改用JavaScript物件形式索引,從程式移掉複雜的偏移量資訊,也讓資料集理論上更好維護。至於效能,只好相信JavaScript內部的雜湊運算速度夠快吧。另外,移除偏移量的同時,也將程式裡其它的switch case都改用list的方式。 11 | 5. 整理3個區域(鍵盤、結果、快捷列)的操作一致性:原本此3區域綁有各種事件,如滑鼠單擊、雙擊、右鍵等,或許用習慣後操作會很快,但全都記憶下來可能需要一段時間。此版本改以浮動視窗顯示所有功能,並且盡可能統一此3區域的功能定義,讓使用體驗一致。副作用是藉此找到適合顯示巨大文字的位置,結果看得更清楚,也因此可拿掉調整文字大小的功能。 12 | 6. 畫面設計以CSS重構:盡可能拿掉所有HTML tag上的style指定,讓HTML與CSS分離,修改外觀可幾乎只動CSS區域。鍵盤也同時改為全由程式自動生成,這樣調整鍵盤變得理論上更容易,也提高易維護性。我已經將WFG原先設計的兩種鍵盤都內建在一起,本來的鍵盤收合功能改為兩種鍵盤、關閉之間的3者切換。 13 | 7. 對於智慧型手機等平台的支援:調整後的CSS設計,我也都加入自適應性設計的概念,讓版面在手機上減少不必要的顯示內容,維持正常易用。不過由於手機沒有滑鼠經過的概念,浮動視窗只好調整為兩段式點擊。另外,在手機上,因為畫面大小的限制,顯示出鍵盤無論如何都會讓整個系統變得很不好用。實際上,手機上因為本來就有內建手寫輸入法,部件挑選鍵盤或許其實不太需要(基本的部件應該可以寫得出來)。但考慮到平板電腦的使用者、既有使用者的習慣,我目前不敢直接對小螢幕拿掉整個鍵盤,目前先嘗試讓鍵盤在小螢幕先預設為關閉,只是仍然留下一整列的鍵盤空列在那裡,還是有點很可惜。可能還要試著重新規劃畫面排列。 14 | 8. 原先改寫程式時,本著維持原始程式的初衷,為了容易客製化,將檢索系統的邏輯(Seeker)與外觀(UI)切割為兩個類別。然而在完成上述各項修改後,尤其是將鍵盤程式化、增加浮動視窗設計、將事件管理從HTML層抽出來後,因為程式對外觀的介入更深,可惜的是UI層也變得比較不易修改了。目前我能想到的只有盡量把可客製化項目另外拉出一個Config類別,保持一定程度的調整空間。但不可否認的是只有基礎HTML、JavaScript概念時,容易修改的彈性範圍大幅下降了,這是今後的課題,如何讓可客製化程度提高。 15 | 9. 因為大幅度改寫UI的事件模型,已經難以相容IE8(若要相容IE8,很多部份都必須寫兩份,會讓程式碼大幅增加)。目前執行需求是IE9以上版本,或是Chrome、Edge等其他瀏覽器。另外不知道為什麼,IE在開啟開發者工具時,分割搜尋的過程會極度笨重(猜測是開發者工具試圖監控每一個setTimeout),其它瀏覽器沒有這樣的情況。不過,關掉開發者工具時,IE9+的運作也是相當平順的,應該不是太大問題。 16 | * ps. 調整成明顯減少卡頓感後,我自己現在已經習慣隨時開著即時查詢功能,並沒有感受到明顯的反應遲鈍感。原先即時查詢可以自由開關、99/999的兩階段查詢數量設計,應該都是為了減少卡頓而生的。若卡頓已經不是個問題,我在想是否這兩個功能可以考慮移除,以降低系統複雜性。或許是個可以檢討的方向。不過這要看既有使用者是否能夠適應。 17 | 18 | # 檔案說明 19 | 20 | * source/corecode.js : JavaScript程式碼 (Seeker與UI類別) 21 | * source/data_supp.txt : 漢字拆分資料集 (Unicode至ExtG的全漢字與CNS11643所收錄之PUA漢字等,11萬餘字) 22 | * source/data_nosupp.txt : 漢字拆分資料集 (Unicode至ExtG的全漢字,PUA的文字只留下作為其他文字拆分用的最低限度,9萬餘字) 23 | * source/data_vt.txt : 搜尋時包容異體的異體對應關係 24 | * source/HanSeeker.htm : 執行用的HTML檔 25 | * gen_release.rb : 將 source 裡的檔案轉換為 release 版本 (Ruby程式) 26 | * release/HanSeeker_StandAlone_All.html : 可1個HTML檔獨立運作的釋出版本 (漢字拆分資料集11萬餘字) 27 | * release/HanSeeker_StandAlone_Unicode.html : 可1個HTML檔獨立運作的釋出版本 (漢字拆分資料集9萬餘字) 28 | * release/HanSeeker_WithoutData.html : 將資料集檔案區隔開來的HTML檔釋出版本,請與資料集放在同一個路徑使用 (預設handata_uni.js) 29 | * release/HanSeeker_WithoutJS.html : 將Javascript、資料集都區隔開來的單純HTML檔釋出版本,請與seeker.js、資料集放在同一個路徑使用 30 | * release/seeker.js : 壓縮過的JavaScript程式部份(corecode.js) 31 | * release/handata_full.js : 壓縮過的漢字拆分資料 (11萬餘字) 32 | * release/handata_uni.js : 壓縮過的漢字拆分資料 (9萬餘字) 33 | * release/PUAExt-Regular.ttf : 輸入鍵盤、PUA裡會用到之最低限需要漢字Webfont 34 | * release/PUAExt-Regular.woff : 同上(woff版本) 35 | * release/PUAExt-Regular.woff2 : 同上(woff2版本) 36 | 37 | 在此提供幾種不同釋出版本。 38 | 將HTML與JavaScript、資料JavaScript檔案切開,或許可以期待瀏覽器cache住資料檔,不用每次都下載1.5MB的資料。 39 | 40 | # 授權說明 41 | 42 | * 程式碼、HTML部分 43 | * 比照 WFG 「部件檢索」原始的授權規定:無條件提供授權給一切非商業營利,有助於學術研究、有益於教育學習、有利於閱讀大眾的網站或個人使用。 44 | * 拆分資料的來源由 WFG 整理自以下來源,依各授權規定聲明著作權資訊於此: 45 | * 中央研究院「漢字構形資料庫」 - GPL3授權 (https://cdp.sinica.edu.tw/cdphanzi/) 46 | * 漢字データベース「字形IDSデータ」 - GPL授權 (http://kanji-database.sourceforge.net/ids/ids.html) 47 | * 字型檔部分 48 | * 萃取自 WFG 的全宋體。其字型主要收錄自全字庫宋體等。適用政府資料開放授權條款-第1版。 49 | 50 | ## 備註 51 | 此版本是為了「字嗨!」網站的Unicode文字檢索功能而改寫的。 52 | https://zi-hi.com/sp/uni/CJKSeeker 53 | -------------------------------------------------------------------------------- /source/data_vt.txt: -------------------------------------------------------------------------------- 1 | ⺄ 乙 2 | ⺆ 冂 3 | ⺈ 刀 4 | ⺊ 卜 5 | ⺌ 小 6 | ⺕ 彐 7 | ⺗ 心 8 | ⺜ 冃 9 | ⺩ 玉 10 | ⺬ 示 11 | ⺳ 网 12 | ⺶ 羊 13 | ⺷ 羊 14 | ⺸ 羊 15 | ⺻ 聿 16 | ⺾ 艸 17 | ⻌ 辵 18 | ⻍ 辵 19 | ⻏ 邑 20 | ⻖ 阜 21 | ⻗ 雨 22 | ㇄ 乙 23 | ㇆ 𠃌 24 | ㇈ 乙 25 | ㇒ 丿 26 | 㐀 业 27 | 㑹 會 28 | 㓁 网 29 | 㔾 卩 30 | 㚆 复 31 | 㠩 巟 32 | 㣺 心 33 | 㥑 𢝊 34 | 㦮 戔 35 | 㬰 臾 36 | 㱿 𣪊 37 | 䏻 能 38 | 东 東 39 | 丢 丟 40 | 丬 爿 41 | 丯 丰 42 | 丷 八 43 | 乂 㐅 44 | 么 幺 45 | 义 叉 46 | 乌 烏 47 | 乚 乙 48 | 亀 龜 49 | 亇 个 50 | 争 爭 51 | 亏 于 52 | 亐 于 53 | 亻 人 54 | 亾 亡 55 | 儿 人 56 | 兂 旡 57 | 兑 兌 58 | 兦 亡 59 | 兪 俞 60 | 内 內 61 | 冈 网 62 | 冉 冄 63 | 册 冊 64 | 冖 冂 65 | 冫 仌 66 | 凢 凣 67 | 刂 刀 68 | 刄 刃 69 | 别 別 70 | 匀 勻 71 | 匸 匚 72 | 卝 艹 73 | 卤 鹵 74 | 卯 󰏞 75 | 卽 即 76 | 县 県 77 | 叐 犮 78 | 叜 叟 79 | 吕 呂 80 | 吞 呑 81 | 吴 吳 82 | 吿 告 83 | 呉 吳 84 | 啬 嗇 85 | 囘 回 86 | 囬 回 87 | 囱 囪 88 | 夀 壽 89 | 夊 夂 90 | 夐 敻 91 | 夹 夾 92 | 奂 奐 93 | 奥 奧 94 | 孑 子 95 | 宂 冗 96 | 宮 宫 97 | 寉 隺 98 | 尒 尔 99 | 尓 尔 100 | 尙 尚 101 | 尣 尢 102 | 川 巛 103 | 巳 己 104 | 巻 卷 105 | 巿 市 106 | 帇 聿 107 | 幵 开 108 | 幷 并 109 | 强 強 110 | 彑 彐 111 | 录 彔 112 | 彞 彝 113 | 彦 彥 114 | 忄 心 115 | 戋 戔 116 | 戯 戱 117 | 户 戶 118 | 戸 戶 119 | 戼 丣 120 | 扌 手 121 | 攵 攴 122 | 教 敎 123 | 斉 齊 124 | 旣 既 125 | 昜 𠃓 126 | 昷 𥁕 127 | 晋 晉 128 | 曰 日 129 | 月 ⺼ 130 | 朩 木 131 | 术 朮 132 | 朶 朵 133 | 来 來 134 | 桒 桑 135 | 歯 齒 136 | 歺 歹 137 | 殻 殼 138 | 毁 毀 139 | 毌 毋 140 | 氵 水 141 | 氺 水 142 | 灬 火 143 | 爫 爪 144 | 爲 為 145 | 牜 牛 146 | 犭 犬 147 | 玆 兹 148 | 王 玉 149 | 産 產 150 | 电 申 151 | 畱 留 152 | 皐 皋 153 | 眞 真 154 | 礻 示 155 | 秃 禿 156 | 竒 奇 157 | 粤 粵 158 | 糹 糸 159 | 絶 絕 160 | 纟 糸 161 | 罒 网 162 | 罓 网 163 | 羋 芈 164 | 聿 󰒆 165 | 肉 ⺼ 166 | 脱 脫 167 | 臯 皋 168 | 艹 艸 169 | 茲 兹 170 | 虗 虛 171 | 虚 虛 172 | 衆 眾 173 | 衞 衛 174 | 衤 衣 175 | 衮 袞 176 | 西 襾 177 | 覀 襾 178 | 见 見 179 | 訁 言 180 | 讠 言 181 | 贝 貝 182 | 軎 𨊥 183 | 车 車 184 | 辶 辵 185 | 鄕 鄉 186 | 釒 金 187 | 钅 金 188 | 镸 長 189 | 长 長 190 | 閲 閱 191 | 门 門 192 | 阝 阜 193 | 靑 青 194 | 靣 面 195 | 韦 韋 196 | 顔 顏 197 | 页 頁 198 | 风 風 199 | 飞 飛 200 | 飠 食 201 | 饣 食 202 | 马 馬 203 | 髙 高 204 | 鱼 魚 205 | 鸟 鳥 206 | 麦 麥 207 | 麽 麼 208 | 黄 黃 209 | 黒 黑 210 | 黾 黽 211 | 齐 齊 212 | 齿 齒 213 | 龙 龍 214 | 龟 龜 215 | 龰 止 216 | 龵 手 217 | 龺 𠦝 218 | 龻 䜌 219 | 𠀍 丗 220 | 𠀕 亙 221 | 𠁗 奭 222 | 𠁣 戶 223 | 𠂆 厂 224 | 𠂉 人 225 | 𠂊 刀 226 | 𠂔 𪩲 227 | 𠃛 戶 228 | 𠄌 亅 229 | 𠄏 了 230 | 𠄠 二 231 | 𠅃 衣 232 | 𠅘 亭 233 | 𠅙 亮 234 | 𠅢 毫 235 | 𠅷 𩫃 236 | 𠆆 𬙸 237 | 𠆢 人 238 | 𠊊 食 239 | 𠓛 亼 240 | 𠓠 𠓥 241 | 𠔉 龹 242 | 𠕁 冊 243 | 𠕋 冊 244 | 𠖇 冥 245 | 𠘨 几 246 | 𠤎 匕 247 | 𠦄 卉 248 | 𠧧 卥 249 | 𠮠 另 250 | 𡈼 壬 251 | 𡉚 㞷 252 | 𡉰 至 253 | 𡊮 袁 254 | 𡋡 袁 255 | 𡕒 㐄 256 | 𡖀 𤔿 257 | 𡝤 婁 258 | 𡥀 𣎼 259 | 𡦦 𤍨 260 | 𡨎 叟 261 | 𡨝 叟 262 | 𡭔 小 263 | 𡭗 尔 264 | 𡭴 𡭽 265 | 𡮂 𡭽 266 | 𡯄 𠠵 267 | 𡳿 㞢 268 | 𡴍 㞷 269 | 𡿫 巟 270 | 𡿬 巟 271 | 𢇁 絲 272 | 𢉖 鹿 273 | 𢏚 𠃬 274 | 𢦜 㦰 275 | 𢿌 敻 276 | 𣁋 𢼸 277 | 𣂚 㪿 278 | 𣆪 𣆉 279 | 𣍹 朕 280 | 𣎆 𦝠 281 | 𣎳 木 282 | 𣏂 杀 283 | 𣐽 𣓀 284 | 𣥠 癶 285 | 𤓰 瓜 286 | 𤔐 𤔔 287 | 𤔬 𤔔 288 | 𤕤 爽 289 | 𤛉 舝 290 | 𤣥 玄 291 | 𤣩 玉 292 | 𤲃 畢 293 | 𤴓 疋 294 | 𤴔 疋 295 | 𤼲 發 296 | 𤼵 發 297 | 𥃲 具 298 | 𥄂 直 299 | 𥄉 県 300 | 𥄕 󰊧 301 | 𥈠 睿 302 | 𥫗 竹 303 | 𥻔 𨤝 304 | 𦉰 网 305 | 𦋍 黽 306 | 𦍋 芈 307 | 𦍌 羊 308 | 𦎧 𬙸 309 | 𦎫 𬙸 310 | 𦔮 耴 311 | 𦘒 聿 312 | 𦟀 𦝠 313 | 𦣝 𦣞 314 | 𦤴 至 315 | 𦥑 臼 316 | 𦥔 申 317 | 𦦝 𦦡 318 | 𦦞 𦦡 319 | 𦦧 𦦡 320 | 𦩎 朕 321 | 𦬇 𦬠 322 | 𦭝 󰊧 323 | 𦰩 󰩮 324 | 𧓚 𧓂 325 | 𧰼 象 326 | 𧾷 足 327 | 𨐌 辛 328 | 𨤬 𦻍 329 | 𩙿 食 330 | 𩫏 𩫃 331 | 𩫖 𩫃 332 | 𩫗 𩫃 333 | 𩰲 䰜 334 | 𩵋 魚 335 | 𪓑 黽 336 | 𫡑 乑 337 | 𫩠 尚 338 | 𫭠 㞷 339 | 𫷄 芇 340 | 𫾦 𠓥 341 | 𬛳 臸 342 | 𬮈 閒 343 | 𬴘 𩫃 344 | 𬺞 龜 345 | 𬼈 缶 346 | 𬼉 𦈢 347 | 𭃂 冄 348 | 𭄘 劉 349 | 𭅲 卪 350 | 𭑃 夸 351 | 𭑈 㚘 352 | 𭕄 小 353 | 𭕆 𧴪 354 | 𭖒 㞷 355 | 𭘧 帶 356 | 𭟲 㦰 357 | 𭟼 戱 358 | 𭣢 攸 359 | 𭤨 㫃 360 | 𭥍 𠰞 361 | 𭥭 曷 362 | 𭦟 㬅 363 | 𭧂 暴 364 | 𭺛 瓦 365 | 𭺜 瓦 366 | 𮅕 算 367 | 𮊿 翏 368 | 𮌩 𦝠 369 | 𮍌 臣 370 | 𮓗 虍 371 | 𮠕 酉 372 | 𮥶 雚 373 | 𮧓 革 374 | 丸 丸 375 | 𠘺 充 376 | 冗 冗 377 | 匆 匆 378 | 卉 卉 379 | 呈 呈 380 | 善 善 381 | 善 善 382 | 売 壳 383 | 夢 夢 384 | 屮 屮 385 | 㠯 㠯 386 | 廾 廾 387 | 慈 慈 388 | 殺 殺 389 | 沿 沿 390 | 灷 灷 391 | 直 直 392 | 𥄳 眔 393 | 眞 真 394 | 穀 穀 395 | 育 育 396 | 豕 豕 397 | 賁 賁 398 | 黾 黽 399 | 鼻 鼻 400 | 𰀁 𠀆 401 | 𰀄 𰀂 402 | 𰁜 亦 403 | 𰃦 宀 404 | 𰆊 卩 405 | 𰮤 朕 406 | 𰲚 虒 407 | 󰉲 又 408 | 󰉹 女 409 | 󰉺 人 410 | 󰉼 人 411 | 󰉽 虍 412 | 󰉿 匕 413 | 󰊀 冓 414 | 󰊁 黽 415 | 󰊄 𠃑 416 | 󰊈 享 417 | 󰊌 𥆞 418 | 󰊍 𠃬 419 | 󰊎 象 420 | 󰊏 𬙸 421 | 󰊐 󰊢 422 | 󰊑 𬙸 423 | 󰊒 󰊮 424 | 󰊔 七 425 | 󰊖 辵 426 | 󰊝 𢍏 427 | 󰊞 󰒙 428 | 󰊟 󰒙 429 | 󰊠 󰑺 430 | 󰊡 󰒙 431 | 󰊢 亯 432 | 󰊣 鬲 433 | 󰊤 鬲 434 | 󰊥 󰒑 435 | 󰊦 󰊶 436 | 󰊨 萛 437 | 󰊫 󰊮 438 | 󰊰 曷 439 | 󰊲 凡 440 | 󰊺 水 441 | 󰊿 用 442 | 󰋀 虎 443 | 󰋁 𡇒 444 | 󰋃 𠷎 445 | 󰋈 彖 446 | 󰋉 翏 447 | 󰋊 咅 448 | 󰋋 󰋤 449 | 󰋌 𠂆 450 | 󰋎 󰋍 451 | 󰋑 賏 452 | 󰋒 𬀷 453 | 󰋔 㾜 454 | 󰋕 匧 455 | 󰋘 𪧇 456 | 󰋙 𣪊 457 | 󰋝 䍃 458 | 󰋠 󰋩 459 | 󰋡 㡭 460 | 󰋧 𠬶 461 | 󰋸 󰌟 462 | 󰌀 譱 463 | 󰌌 󰑅 464 | 󰌎 𠚏 465 | 󰌛 臼 466 | 󰌜 𣐺 467 | 󰌝 菐 468 | 󰌢 龜 469 | 󰌥 𣐺 470 | 󰌧 永 471 | 󰌪 󰌣 472 | 󰌴 𪚴 473 | 󰌶 󰌟 474 | 󰌷 󰌟 475 | 󰍄 云 476 | 󰍉 𤦡 477 | 󰍌 󰌟 478 | 󰍏 㕚 479 | 󰍕 𦣞 480 | 󰍗 丮 481 | 󰍚 𠀎 482 | 󰍛 冊 483 | 󰍝 甫 484 | 󰍟 冉 485 | 󰍩 索 486 | 󰍰 卑 487 | 󰍱 𠃬 488 | 󰍴 央 489 | 󰎒 臼 490 | 󰎓 㔺 491 | 󰎙 𠂂 492 | 󰎝 止 493 | 󰎞 矛 494 | 󰎠 舟 495 | 󰎤 子 496 | 󰎦 犭 497 | 󰎫 異 498 | 󰎯 兆 499 | 󰎶 󰑂 500 | 󰎼 𠃜 501 | 󰏈 甲 502 | 󰏎 𪚴 503 | 󰏠 冊 504 | 󰏡 冉 505 | 󰏤 𠦑 506 | 󰏱 弋 507 | 󰏷 水 508 | 󰏽 习 509 | 󰐅 𠕋 510 | 󰐋 󰑅 511 | 󰐐 虍 512 | 󰐕 󰓧 513 | 󰐖 ㇉ 514 | 󰐜 𠃬 515 | 󰐢 申 516 | 󰐣 丮 517 | 󰐤 虎 518 | 󰐦 舌 519 | 󰐧 ⺼ 520 | 󰐨 才 521 | 󰐩 𨸏 522 | 󰐪 舟 523 | 󰐫 幺 524 | 󰐬 匕 525 | 󰐭 止 526 | 󰐮 止 527 | 󰐱 〢 528 | 󰐶 肀 529 | 󰐷 彐 530 | 󰐹 𪚴 531 | 󰑇 刀 532 | 󰑊 戶 533 | 󰑕 未 534 | 󰑢 冎 535 | 󰑧 或 536 | 󰑨 𥆞 537 | 󰑩 𥆞 538 | 󰑫 臣 539 | 󰑬 ⺼ 540 | 󰑭 𡆧 541 | 󰑮 弓 542 | 󰑰 勹 543 | 󰑴 皀 544 | 󰑹 舁 545 | 󰑽 直 546 | 󰒂 冂 547 | 󰒉 󰐾 548 | 󰒊 襾 549 | 󰒏 申 550 | 󰒐 刀 551 | 󰒕 良 552 | 󰒖 产 553 | 󰒘 𬻂 554 | 󰒛 𪱙 555 | 󰒟 㒳 556 | 󰒡 卯 557 | 󰒤 県 558 | 󰒬 𰀂 559 | 󰒰 戈 560 | 󰒷 𢎥 561 | 󰒾 頁 562 | 󰒿 夨 563 | 󰓈 󰋏 564 | 󰓊 水 565 | 󰓏 石 566 | 󰓐 𡉉 567 | 󰓓 監 568 | 󰓛 㯥 569 | 󰓝 炗 570 | 󰓞 負 571 | 󰓠 业 572 | 󰓡 㞑 573 | 󰓣 𡧍 574 | 󰓤 丏 575 | 󰓦 宷 576 | 󰓨 臸 577 | 󰓩 單 578 | 󰓳 𠚣 579 | 󰓵 凿 580 | 󰓷 芇 581 | 󰓺 𦣻 582 | 󰓻 同 583 | 󰔲 叀 584 | 󰕀 爽 585 | 󰕇 𣥂 586 | 󰕊 臾 587 | 󰕋 冊 588 | 󰕹 𠠲 589 | 󰗈 仺 590 | 󰙮 巟 591 | 󰚦 弱 592 | 󰝼 犮 593 | 󰣄 肴 594 | 󰤩 示 595 | 󰪥 𢑩 596 | 󰬹 豪 597 | 󰱗 龜 598 | 󰲎 龜 599 | 󰳹 𠍳 600 | 󰸱 󰉻 601 | 󰹁 习 602 | 󰾣 夸 603 | 󱀇 賴 604 | 󵟼 朕 605 | 󵠠 癸 606 | 󵡫 𩫃 607 | 󵣖 仺 608 | 󵦠 毒 609 | 󶃗 𢎥 610 | 󶅠 𠫓 611 | 󶎨 𩫃 612 | 󶏓 丸 613 | 󶏔 戕 614 | 󶓭 鬼 615 | 󶘥 艹 616 | 󶘨 𠬞 617 | 󶚥 言 618 | 󷢌 絲 619 | 󷱕 庻 620 | 󸉰 卥 621 | 󹽪 絲 622 | 󹽬 絲 623 | 󺏤 龜 624 | 󺗊 真 625 | 󺞤 凾 626 | 󺬹 莽 627 | 󺮥 虎 628 | 󺹓 丰 629 | 令 令 630 | 留 留 631 | 益 益 632 | 祥 祥 633 | 羽 羽 634 | 爫 爪 635 | 者 者 636 | 奔 奔 637 | 敖 敖 638 | 殺 殺 639 | 荒 荒 640 | 龜 龜 641 | -------------------------------------------------------------------------------- /release/HanSeeker_WithoutJS.html: -------------------------------------------------------------------------------- 1 | 2 | 部件檢索 3 | 4 | 5 | 6 | 94 | 95 | 96 |
97 | 101 |
102 | 部件: 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
114 | 選項: 115 | 116 | 117 | 118 | 119 |
120 |
121 | 122 |
123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 |
132 |
133 | 134 |
135 |
136 | 138 | 基本 139 | A區 140 | B區 141 | C區 142 | D區 143 | E區 144 | F區 145 | G區 146 | 相容 147 | 補充 148 | 其它 149 | 150 |
151 |
152 |
153 |
154 | 155 | 156 | 輸入 157 | 前往頁面 158 | 替換查詢 159 | 複製此文字 160 | 161 | 加入快捷列 162 | 移出快捷列 163 | 164 |
165 | 166 | 167 | 216 | 217 | 218 | 219 |
220 | 改版版本: 221 | 改版發布網址:GitHub 222 | 原始核心版本:0.9.1.0 223 | 原始發布網址:部件檢索 (WFG製作) 224 | 漢字拆分資料:WFG漢字構形資料庫字形IDSデータ 225 |
226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /source/HanSeeker.htm: -------------------------------------------------------------------------------- 1 | 2 | 部件檢索 3 | 4 | 5 | 6 | 94 | 95 | 96 |
97 | 101 |
102 | 部件: 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
114 | 選項: 115 | 116 | 117 | 118 | 119 |
120 |
121 | 122 |
123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 |
132 |
133 | 134 |
135 |
136 | 138 | 基本 139 | A區 140 | B區 141 | C區 142 | D區 143 | E區 144 | F區 145 | G區 146 | 相容 147 | 補充 148 | 其它 149 | 150 |
151 |
152 |
153 |
154 | 155 | 156 | 輸入 157 | 前往頁面 158 | 替換查詢 159 | 複製此文字 160 | 161 | 加入快捷列 162 | 移出快捷列 163 | 164 |
165 | 166 | 167 | 216 | 217 | 218 | 219 |
220 | 改版版本: 221 | 改版發布網址:GitHub 222 | 原始核心版本:0.9.1.0 223 | 原始發布網址:部件檢索 (WFG製作) 224 | 漢字拆分資料:WFG漢字構形資料庫字形IDSデータ 225 |
226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /nene/NeneHanSeeker.htm: -------------------------------------------------------------------------------- 1 | 2 | 部件檢索 3 | 4 | 5 | 6 | 7 | 8 | 128 | 129 |
130 | 131 | 132 |
133 | 137 |
138 | 139 | 140 | 141 | 142 | 143 |
144 |
145 | 146 |
147 | 148 | 149 | 150 | 151 |
152 | 153 |
154 |
155 |
156 | 157 |
158 |
159 | 161 | 基本 162 | A區 163 | B區 164 | C區 165 | D區 166 | E區 167 | F區 168 | G區 169 | 相容 170 | 補充 171 | 其它 172 | 173 |
174 |
175 |
176 |
177 |
178 |
179 | 180 | 181 | 輸入 182 | 前往頁面 183 | 替換查詢 184 | 複製此文字 185 | 排除此文字 186 | 187 | 加入快捷列 188 | 移出快捷列 189 | 190 |
191 | 192 | 193 |
194 | 改版版本: 195 | 改版發布網址:GitHub 196 | 原始核心版本:0.9.1.0 197 | 原始發布網址:部件檢索 (WFG製作) 198 | 漢字拆分資料:WFG漢字構形資料庫字形IDSデータ 199 |
200 | 201 |
202 | 203 | 204 | 205 | 223 | 224 | 225 | -------------------------------------------------------------------------------- /release/seeker.js: -------------------------------------------------------------------------------- 1 | 2 | var Seeker={dataIndex: null, seg: 1000, interval: 50, totalmsec: 0, segcnt: 0, worker: null}; 3 | var UI={shortcuts: [], padType: null}; 4 | var _=function(id) { return document.getElementById(id); } 5 | var $_=_('input'); 6 | Seeker.getVersion=function(){return "0.9.3.0 (2021年01月)";}; 7 | Seeker.blockFlagMap={'@': 0x0001, 'A': 0x0002, 'B': 0x0004, 'C': 0x0008, 'D': 0x0010, 'E': 0x0020, 'F': 0x0040, 'G': 0x0080, 'X': 0x2000, 'Y': 0x4000, 'Z': 0x8000}; 8 | Seeker.blockMap={1: 0x0001, 2: 0x0002, 3: 0x0004, 4: 0x0008, 5: 0x0010, 6: 0x0020, 7: 0x0040, 8: 0x0080, 28: 0x2000, 29: 0x2000, 30: 0x4000}; 9 | Seeker.parts={'一':1,'丨':1,'丶':1,'丿':1,'乙':1,'亅':1,'乚':2,'㇄':3,'㇁':3,'㇂':3,'𠄌':3,'𠃊':3,'𠃋':3,'𡿨':3,'乛':3,'㇇':3,'𠃍':3,'㇏':3,'乀':3,'⺄':3,'𠃌':3,'㇆':3,'㇉':3,'𠃑':3,'㇊':3,'㇒':3,'㇣':3,'㇀':3,'二':1,'亠':1,'人':1,'儿':1,'入':1,'八':1,'冂':1,'冖':1,'冫':1,'几':1,'凵':1,'刀':1,'力':1,'勹':1,'匕':1,'匚':1,'匸':1,'十':1,'卜':1,'卩':1,'厂':1,'厶':1,'又':1,'亻':2,'𠆢':2,'丷':2,'刂':2,'⺈':2,'㔾':2,'讠':2,'𢎘':2,'𠂉':3,'〢':3,'𠂊':3,'𠂇':3,'㐅':3,'乂':3,'𠘧':3,'𠘨':3,'⺆':3,'丂':3,'𠀁':3,'龴':3,'𠂆':3,'𠄎':3,'㇋':3,'㇌':3,'⺀':3,'𠂈':3,'丩':3,'⺊':3,'丄':3,'丅':3,'丆':3,'𠃎':3,'𠄟':3,'𠄠':3,'𠄐':3,'𠃏':3,'乁':3,'𠙴':3,'七':4,'𠤎':4,'九':4,'口':1,'囗':1,'土':1,'士':1,'夂':1,'夊':1,'夕':1,'大':1,'女':1,'子':1,'宀':1,'寸':1,'小':1,'尢':1,'尸':1,'屮':1,'山':1,'巛':1,'工':1,'己':1,'巾':1,'干':1,'幺':1,'广':1,'廴':1,'廾':1,'弋':1,'弓':1,'彐':1,'彡':1,'彳':1,'川':2,'⺌':2,'𡭔':2,'䶹':2,'彑':2,'忄':2,'扌':2,'氵':2,'犭':2,'⺾':2,'阝':2,'⻖':2,'⻏':2,'⺕':2,'⻌':2,'丬':2,'纟':2,'飞':2,'饣':2,'䒑':3,'卄':3,'𭕄':3,'𠀆':3,'𠔼':3,'𠫓':3,'𣥂':3,'𡳾':3,'𠂎':3,'乇':3,'𫝀':3,'㐄':3,'𡕒':3,'乡':3,'𠚤':3,'习':3,'亼':3,'三':4,'丈':4,'也':4,'于':4,'上':4,'下':4,'兀':4,'丌':4,'卂':4,'亇':4,'万':4,'刄':4,'心':1,'戈':1,'戶':1,'手':1,'支':1,'攴':1,'文':1,'斗':1,'斤':1,'方':1,'无':1,'日':1,'曰':1,'月':1,'木':1,'欠':1,'止':1,'歹':1,'殳':1,'毋':1,'比':1,'毛':1,'氏':1,'气':1,'水':1,'火':1,'爪':1,'父':1,'爻':1,'爿':1,'片':1,'牙':1,'牛':1,'犬':1,'⺗':2,'攵':2,'朩':2,'毌':2,'灬':2,'爫':2,'爫':2,'牜':2,'𠂒':2,'尣':2,'⺩':2,'礻':2,'龰':2,'罓':2,'冈':2,'㓁':2,'⺼':2,'艹':2,'辶':2,'⻍':2,'耂':2,'⺳':3,'𦉪':3,'𠔿':3,'⺝':3,'艹':3,'卝':3,'龷':3,'廿':3,'丰':3,'丯':3,'𧘇':3,'𣎳':3,'𥘅':3,'龶':3,'⺜':3,'厃':3,'𠃜':3,'肀':3,'旡':3,'冘':3,'夬':3,'兂':3,'龵':3,'𦉫':3,'𠬝':3,'㸦':3,'𤓰':3,'𠃛':3,'夨':3,'仌':3,'王':4,'五':4,'六':4,'卅':4,'不':4,'丐':4,'及':4,'丑':4,'丹':4,'刅':4,'井':4,'开':4,'𠬛':4,'尺':4,'巨':4,'巴':4,'𣎴':4,'冃':4,'冄':4,'𠬞':4,'𠬜':4,'丮':4,'巿':4,'𠃚':4,'玄':1,'玉':1,'瓜':1,'瓦':1,'甘':1,'生':1,'用':1,'田':1,'疋':1,'疒':1,'癶':1,'白':1,'皮':1,'皿':1,'目':1,'矛':1,'矢':1,'石':1,'示':1,'禸':1,'禾':1,'穴':1,'立':1,'𤴓':2,'𤴔':2,'罒':2,'𦉰':2,'歺':2,'母':2,'氺':2,'衤':2,'⺬':2,'钅':2,'𢆉':3,'𦍍':3,'业':3,'𠀎':3,'㠯':3,'𠕁':3,'𡗗':3,'圥':3,'𠮠':3,'犮':3,'𢎨':3,'𦘒':3,'⺻':3,'龸':3,'𣦵':3,'丱':3,'𤕫':3,'𥝌':3,'𦫳':3,'𣎵':3,'屵':3,'𫇦':3,'四':4,'卌':4,'夗':4,'㐱':4,'乍':4,'乎':4,'冉':4,'册':4,'史':4,'央':4,'戉':4,'戊':4,'冋':4,'本':4,'民':4,'永':4,'北':4,'竹':1,'米':1,'糸':1,'缶':1,'网':1,'羊':1,'羽':1,'老':1,'而':1,'耒':1,'耳':1,'聿':1,'肉':1,'臣':1,'自':1,'至':1,'臼':1,'舌':1,'舛':1,'舟':1,'艮':1,'色':1,'艸':1,'虍':1,'虫':1,'血':1,'行':1,'衣':1,'襾':1,'𥫗':2,'糹':2,'𦍌':2,'⺶':2,'西':2,'覀':2,'齐':2,'冎':3,'龹':3,'𠂤':3,'𧰨':3,'乑':3,'𢦏':3,'产':3,'巩':3,'𦈢':3,'𠂭':3,'𠂢':3,'𠦃':3,'䇂':3,'㐆':3,'甶':3,'囟':3,'幵':3,'厽':3,'𠃨':3,'𠬪':3,'朿':4,'亙':4,'兆':4,'州':4,'年':4,'曲':4,'曳':4,'朱':4,'关':4,'見':1,'角':1,'言':1,'谷':1,'豆':1,'豕':1,'豸':1,'貝':1,'赤':1,'走':1,'足':1,'身':1,'車':1,'辛':1,'辰':1,'辵':1,'邑':1,'酉':1,'釆':1,'里':1,'訁':2,'𧮫':2,'𧾷':2,'𦥑':2,'镸':2,'⺸':3,'𦍋':3,'夋':3,'𦉶':3,'㒳':3,'㐬':3,'𠦒':3,'𦣞':3,'𦣝':3,'丣':3,'戼':3,'𠃬':3,'㕯':3,'㫃':3,'囧':3,'𦣻':3,'囱':3,'囪':3,'㡀':3,'严':3,'𠦑':3,'㳄':3,'我':4,'巠':4,'甹':4,'皀':4,'夆':4,'亜':4,'来':4,'金':1,'長':1,'門':1,'阜':1,'隶':1,'隹':1,'雨':1,'青':1,'非':1,'釒':2,'⻗':2,'靑':2,'飠':2,'叀':3,'亝':3,'𣏟':3,'㣇':3,'甾':3,'幷':3,'𨸏':3,'𣶒':3,'罙':4,'忝':4,'匋':4,'奄':4,'東':4,'疌':4,'黾':4,'靣':4,'面':1,'革':1,'韋':1,'韭':1,'音':1,'頁':1,'風':1,'飛':1,'食':1,'首':1,'香':1,'𩙿':2,'叚':3,'壴':3,'复':3,'亲':3,'枼':3,'昜':3,'亯':3,'𡿺':3,'𠧪':3,'県':3,'𥄉':3,'㲋':3,'𢑚':3,'㢴':3,'𢏚':3,'咢':4,'奐':4,'禺':4,'南':4,'馬':1,'骨':1,'高':1,'髟':1,'鬥':1,'鬯':1,'鬲':1,'鬼':1,'𤇾':3,'丵':3,'𠂹':3,'𣆪':3,'𩠐':3,'𡸁':3,'隺':4,'尃':4,'𧴪':4,'𥁕':4,'臽':4,'䍃':4,'芻':4,'皋':4,'魚':1,'鳥':1,'鹵':1,'鹿':1,'麥':1,'麻':1,'㒼':3,'𦰩':3,'𠦬':3,'𠁁':3,'桼':4,'啇':4,'袞':4,'翏':4,'啚':4,'悤':4,'粛':4,'黃':1,'黍':1,'黑':1,'黹':1,'菐':4,'巽':4,'粦':4,'尌':4,'朁':4,'尞':4,'厤':4,'肅':4,'𤔔':3,'𠥓':3,'黽':1,'鼎':1,'鼓':1,'鼠':1,'𦥯':3,'𦝠':3,'𢊁':3,'廌':3,'𠌶':3,'亶':4,'嗇':4,'睘':4,'鼻':1,'齊':1,'𨛜':3,'㥯':4,'熏':4,'齒':1,'嘼':3,'廛':4,'巤':4,'龍':1,'龜':1,'龠':1,'𩫖':3,'毚':4,'韱':4,'㇈':3,'󰎀':3,'󰋌':3,'󰊅':3,'󰊸':3,'󰕐':3,'𰀪':3,'巜':2,'󰓶':3,'󰒖':3,'󰓏':3,'󰒑':3,'󰋚':3,'󰓐':3,'󰒾':3,'𰃮':3,'龻':3,'󰓗':3,'󶃛':3,'󰒭':3,'󰒂':3,'󰒦':3,'󰊥':3,'󰊶':3,'󰓴':3,'󶏔':3,'󰑖':3,'󰑹':3,'󰑷':3,'㦰':3,'甲':4,'丙':4,'丁':4,'庚':4,'壬':4,'癸':4,'寅':4,'卯':4,'巳':4,'午':4,'未':4,'申':4,'戌':4,'亥':4,'󰑬':3,'󰐻':3,'丘':4,'𫶧':3,'󰑉':3,'虎':4,'󰒬':3,'󰊎':3,'󰐸':3,'󰐧':3,'󰐷':3,'刃':4,'𭤨':3,'𰀄':3,'吅':3,'从':3,'󰒊':3,'中':4,'󰑲':3,'󰩮':3,'𰀁':3,'𠂔':3,'𪩲':3,'亞':4}; 10 | UI.strokeKeyboard={vertical: true,className: 'strokeKB',groups: {'01畫': '一丨丶丿乙亅乚㇄㇁㇂𠄌𠃊𠃋𡿨乛㇇𠃍㇏乀⺄𠃌㇆㇉𠃑㇊㇒㇣㇀','02畫': '二亠人儿入八冂冖冫几凵刀力勹匕匚匸十卜卩厂厶又亻𠆢丷刂⺈㔾讠𢎘𠂉〢𠂊𠂇㐅乂𠘧𠘨⺆丂𠀁龴𠂆𠄎㇋㇌⺀𠂈丩⺊丄丅丆𠃎𠄟𠄠𠄐𠃏乁𠙴七𠤎九','03畫': '口囗土士夂夊夕大女子宀寸小尢尸屮山巛工己巾干幺广廴廾弋弓彐彡彳川⺌𡭔䶹彑忄扌氵犭⺾阝⻖⻏⺕⻌丬纟飞饣䒑卄𭕄𠀆𠔼𠫓𣥂𡳾𠂎乇𫝀㐄𡕒乡𠚤习亼三丈也于上下兀丌卂亇万刄','04畫': '心戈戶手支攴文斗斤方无日曰月木欠止歹殳毋比毛氏气水火爪父爻爿片牙牛犬⺗攵朩毌灬爫爫牜𠂒尣⺩礻龰罓冈㓁⺼艹辶⻍耂⺳𦉪𠔿⺝艹卝龷廿丰丯𧘇𣎳𥘅龶⺜厃𠃜肀旡冘夬兂龵𦉫𠬝㸦𤓰𠃛夨仌王五六卅不丐及丑丹刅井开𠬛尺巨巴𣎴冃冄𠬞𠬜丮巿𠃚','05畫': '玄玉瓜瓦甘生用田疋疒癶白皮皿目矛矢石示禸禾穴立𤴓𤴔罒𦉰歺母氺衤⺬钅𢆉𦍍业𠀎㠯𠕁𡗗圥𠮠犮𢎨𦘒⺻龸𣦵丱𤕫𥝌𦫳𣎵屵𫇦四卌夗㐱乍乎冉册史央戉戊冋本民永北','06畫': '竹米糸缶网羊羽老而耒耳聿肉臣自至臼舌舛舟艮色艸虍虫血行衣襾𥫗糹𦍌⺶西覀齐冎龹𠂤𧰨乑𢦏产巩𦈢𠂭𠂢𠦃䇂㐆甶囟幵厽𠃨𠬪朿亙兆州年曲曳朱关','07畫': '見角言谷豆豕豸貝赤走足身車辛辰辵邑酉釆里訁𧮫𧾷𦥑镸⺸𦍋夋𦉶㒳㐬𠦒𦣞𦣝丣戼𠃬㕯㫃囧𦣻囱囪㡀严𠦑㳄我巠甹皀夆亜来','08畫': '金長門阜隶隹雨青非釒⻗靑飠叀亝𣏟㣇甾幷𨸏𣶒罙忝匋奄東疌黾靣','09畫': '面革韋韭音頁風飛食首香𩙿叚壴复亲枼昜亯𡿺𠧪県𥄉㲋𢑚㢴𢏚咢奐禺南','其它': {'10畫': '馬骨高髟鬥鬯鬲鬼𤇾丵𠂹𣆪𩠐𡸁隺尃𧴪𥁕臽䍃芻皋','11畫': '魚鳥鹵鹿麥麻㒼𦰩𠦬𠁁桼啇袞翏啚悤粛','12畫': '黃黍黑黹菐巽粦尌朁尞厤肅𤔔𠥓','13畫': '黽鼎鼓鼠𦥯𦝠𢊁廌𠌶亶嗇睘','14畫': '鼻齊𨛜㥯熏','15畫': '齒嘼廛巤','16畫': '龍龜','17畫': '龠𩫖毚韱'}}}; 11 | UI.categoryKeyboard={vertical: false,className: 'categoryKB',groups: {'筆畫': '一丨丶,㇒丿㇀,㇈亅乚,㇄㇁㇂,𠄌𠃊𠃋,𠃎𠃍󰎀,𡿨乛㇇,㇏乀⺄,𠃌㇆󰋌,㇉𠃑㇊,㇣㐅乂,󰊅󰊸󰕐,𰀪⺀巜','字頭': '艹⺾艹䒑𥫗,⺈𠆢𠂉󰓶亠,⺌𭕄爫爫,𠂆厂广疒𤕫,厃产󰒖屵严,尸𠃜󰓏耂𠫓,罒㓁罓龷,覀⺜龶⺻,冖⺳宀龸󰒑,𤇾𫇦󰋚󰓐󰒾,癶龹𡗗,⻗𦥯𰃮龻󰓗,𠂒虍󶃛󰒭𦍌','包圍': '冂⺆,󰒂𠘨,凵𠙴,匚𠥓,匸󰒦,勹𦉶,󰊥󰊶,󰓴󶏔,󰑖󰑹,𢦏󰑷,㦰𦝠,囗','計數': '甲乙丙丁,戊己庚辛,壬癸,子丑寅卯,辰巳午未,申酉戌亥,一二三四,五六七丷,八九十廿,卄卅卌𠦃,万寸尺丈','自然': '日月,󰑬,風气,雨夕,金钅,釒,木朩,水氵,氺󰐻,火灬,土石,冫仌','地理': '山业,丘巛,川𫶧,穴谷,𣶒󰑉,州,皋𠂤,阜⻖,𨸏阝,邑⻏','動物': '鼠牛牜虎,毚㲋龍巴,虫馬羊⺶,⺸𦍋𦫳犭,犬犮豕𧰨,豸鹿𢊁廌,魚鳥隹嘼,黽黾龜貝,彐彑㣇,角羽毛巤,爪󰒬釆禸,习卂飞飛,隺󰊎','植物': '艸屮韭,竹禾𥝌,米𠂭麥,麻黍桼,豆瓜𤓰,朿𣎵本,𣎳𣏟支,丰󰐸丯,𢎘,𠧪𠂹丵','人體': '首頁𦣻𡿺囟,髟丱卝㐱彡,冉冄而口亼,舌牙㸦齒𧮫,𦣞𦣝目耳,鼻自面靣身,心忄⺗血骨,肉⺼⺝󰐧皮,手扌龵𠂇䶹,又⺕󰐷,𦥑廾𠬞𠬜,足𧾷疋𤴔止,龰丮𠃨','食飲': '食,飠,𩙿,饣,丣,鹵,鬯,甘,香,皀','衣飾': '衣𧘇,衤冃,巾巿,糸纟,糹黹,革韋,玉⺩,文','住居': '門,戶,囱,囪,几,囧,瓦,井,爿,丬,田,里','行旅': '行走,辵辶,⻌⻍,廴夂,𫝀夊,𡕒㐄,彳𣥂,𤴓,舟車,立至,入隶,冘','書樂': '聿,𦘒,肀,册,𠕁,史,鼓,龠,音','祭祀': '卜,⺊,爻,兆,示,⺬,礻,𥘅,鬼,甶,亯,用,夬','器物': '皿甾,缶𦈢,网𦉰,冈𠔿,𦉫𦉪,匕𠁁,斗臼,鬲鼎,丌耒','軍事': '刀刂,力刄,刃刅,斤弋,矢弓,矛干,戈戉,殳𠘧,卩㔾,攴攵,㫃𭤨,鬥','人稱': '人亻,𠂊乑,厶我,父母,儿女,𠦑士,王臣,氏民','生命': '生,老,歹,歺,𣦵,𰀄,𠤎,尢,尣,䇂','顏色': '青,靑,白,朱,赤,黑,玄,黃,色','動作': '言讠,訁曰,吅从,㕯工,見艮,欠夨,襾󰒊,𡳾𠂈','雜類': '上丄下丅長镸,大中小𡭔高𩫖,丆乁幺乡㇋𠄎,丂𠀁龴𠚤󰑲〢,𠔼冋冎㒳㡀㒼,兀无旡兂圥󰩮,方𠮠片𰀁𢆉𦍍,毋毌齊齐叚,㠯比𠃏丩𠂎乇,舛夗非开幵幷,𠂔𪩲巨亞亜戼,東西南北叀𠦒,𢑚𠃬𢏚㢴'}}; 12 | if (!Array.prototype.indexOf) {Array.prototype.indexOf=function (o, f) {var l=this.length;if (f == null) f=0;if (f < 0) f=Math.max(0, l+f);for (var i=f; i < l; i++) {if (this[i] === o) return i;}return -1;};} 13 | if (!String.prototype.codePointAt) {String.prototype.codePointAt=function(i) {var c=this.charCodeAt(i);if (c >= 0xD800 && c <= 0xDBFF) return (((c & 0x03FF) << 10) | (this.charCodeAt(i+1) & 0x03FF))+0x10000;return c;};} 14 | String.prototype.charPointAt=function(i) {var c=this.charCodeAt(i);if (c >= 0xD800 && c <= 0xDBFF) return this.charAt(i)+this.charAt(i+1);if (c >= 0xDC00 && c <= 0xDFFF) return this.charAt(i-1)+this.charAt(i);return this.charAt(i);}; 15 | Seeker.variant=function(w, v) {return v && vt[w] ? vt[w] : w;}; 16 | Seeker.arraylize=function(s, v, a) {var blockFlag=0;for (var i=0; i < s.length; i++) {var w=s.charPointAt(i);if (w.length > 1) i++;if (Seeker.blockFlagMap[w]) {blockFlag |= Seeker.blockFlagMap[w];} else {if (w.length == 1) {var c=w.charCodeAt(0);if (c >= 0x2FF0 && c <= 0x2FFB) break;}a.push(Seeker.variant(w, v));}}if (blockFlag == 0) blockFlag=0xFFFF;return blockFlag;}; 17 | Seeker.getCJKBlock=function(c) {if (c >= 0x4E00 && c <= 0x9FFC ) return 1;if (c >= 0x3400 && c <= 0x4DBF ) return 2;if (c >= 0x20000 && c <= 0x2A6DD) return 3;if (c >= 0x2A700 && c <= 0x2B734) return 4;if (c >= 0x2B740 && c <= 0x2B81D) return 5;if (c >= 0x2B820 && c <= 0x2CEA1) return 6;if (c >= 0x2CEB0 && c <= 0x2EBE0) return 7;if (c >= 0x30000 && c <= 0x3134A) return 8;if (c >= 0xF900 && c <= 0xFAD9 ) return 28;if (c >= 0x2F800 && c <= 0x2FA1D) return 29;if (c >= 0xF0270 && c <= 0xFAE7A) return 30;return 0;}; 18 | Seeker.getData=function(c, w) {if (Seeker.dataIndex == null) {Seeker.dataIndex={};for (var i in dt) {Seeker.dataIndex[dt[i].codePointAt(0)]=dt[i].substring(w.length);}}return Seeker.dataIndex[c];}; 19 | Seeker.eliminate=function(a, s, d, v) {var f=a.length == 1 && a[0] == "#";if (s == "@") {if (f) a.length=0;return 1;}var n=0;var k=0;var b=a.concat();for (var i=0; i < s.length; i++) {var w=s.charPointAt(i);if (w.length > 1) i++;if (w == "!" && !d) {if (f) a.length=0;return 1;}if (w == "@" || w == "!") {if (k) {if (!a.length || !n) break;a.length=0;for (var j=0; j < b.length; j++) a.push(b[j]);n=0;}k++;} else {if (!f && a.length) {var c=w.codePointAt(0);var m=a.indexOf(Seeker.variant(w, v));if (m < 0) {n += Seeker.getData(c, w) ? Seeker.eliminate(a, Seeker.getData(c, w), d, v) : 1;} else {a.splice(m, 1);}} else {n++;}}}return n;}; 20 | Seeker.stopMatch=function(){clearTimeout(Seeker.worker);}; 21 | Seeker.getMatch=function(s, v, d, m, h, z, r) {clearTimeout(Seeker.worker);var x=[];var blockFlag=Seeker.arraylize(s, v, x);x.sort();s=x.join('');var i=0;var a=[];var work=function(j) {if (a.length >= m+1) return;if (j+Seeker.seg < dt.length) Seeker.worker=setTimeout(function(){ work(j+Seeker.seg); }, Seeker.segcnt > 10 ? Math.floor(Seeker.totalmsec/Seeker.segcnt+5) : Seeker.interval);var st=new Date();var t=0;for (var i=j; i < j+Seeker.seg && i < dt.length; i++) {var y=x.concat();var w=dt[i].charPointAt(0);var c=w.codePointAt(0);if (blockFlag) {var f=Seeker.blockMap[Seeker.getCJKBlock(c)] || 0x8000;if (!(blockFlag & f)) continue;}var n=0;if (Seeker.variant(w, v) != s) {n=Seeker.eliminate(y, dt[i].slice(w.length), d, v);if (y.length) continue;}var l=h;l=l.replace("$CHR$", w);l=l.replace("$ENC$", encodeURI(w));l=l.replace("$UCD$", c.toString());l=l.replace("$UCh$", c.toString(16));l=l.replace("$UCH$", c.toString(16).toUpperCase());var p=z(w, c, n, l);if (p && (!n || (a.length <= m))) a.push(p);if (a.length >= m+1) break;}r(a, i, m);Seeker.totalmsec += new Date()-st;Seeker.segcnt++;};Seeker.worker=setTimeout(function(){ work(0); }, 10);}; 22 | Seeker.exhaust=function(s, d, m) {var t='';if (s.length) {var w=s.charPointAt(0);var c=w.codePointAt(0);var p=Seeker.getData(c, w).substring(w.length);var k=0;for (var i=0; i < p.length; i++) {w=p.charPointAt(i);if (w.length > 1) i++;if ((w == "!") && !d) break;if ((w == "@") || (w == "!")) {if (k) t += (m < 0) ? "┇" : "‖";k++;} else {t += w;if (m) {var q=Seeker.exhaust(w, d, -1);if (q.length) t += "("+q+")";}}}}return t;}; 23 | Seeker.getTree=function(s, d, z) {var a=[];if (s.length) {var w=s.charPointAt(0);var c=w.codePointAt(0);var m=0;var n=-1;var p=Seeker.exhaust(w, d, 1);do {n=p.indexOf("‖", m);var t=p.slice(m, (n < 0 ? p.length : n));t=z(w, c, -1, '', t.length ? t : "(不再分解)");if (t) a.push(t); m=n+1;} while (n >= 0);}return a;} 24 | UI.blockClasses={1: 'BSC', 2: 'ExA', 3: 'ExB', 4: 'ExC', 5: 'ExD', 6: 'ExE', 7: 'ExF', 8: 'ExG', 27: 'CMP', 28: 'CMP', 29: 'CMP', 30: 'SUP', 31: 'SUP'}; 25 | UI.isMobile=function(){return navigator.userAgent =~ /Android|iOS/i;}; 26 | UI.initKeyboard=function(kbType) {var html='';if (!kbType.vertical) {html += '';for (var g in kbType.groups) html += '';html += '';}for (var g in kbType.groups) {if (kbType.vertical) html += '';html += '';if (kbType.vertical) html += '';}html += '
'+g+'
'+g+'';if (typeof kbType.groups[g] == 'string') {for (var i=0; i < kbType.groups[g].length; i++) {var w=kbType.groups[g].charPointAt(i);if (w.length > 1) i++;if (w == ',') { html += '
'; continue; }var z=Seeker.parts[w];if (z) html += '';}} else {for (var gg in kbType.groups[g]) {html += ''+gg+'';for (var i=0; i 1) i++;if (w == ',') { html += '
'; continue; }var z=Seeker.parts[w];if (z) html += '';}html += '
';}}html += '
';_('keypad').innerHTML=html;}; 27 | UI.setClipboard=function(s) {s=decodeURI(s);if (window.clipboardData) {window.clipboardData.clearData();window.clipboardData.setData('Text', s);} else {var t=document.createElement('textarea');t.textContent=s;document.body.appendChild(t);t.select();document.execCommand('copy');document.body.removeChild(t);}}; 28 | UI.setCookie=function(n, v) {if (window.localStorage) window.localStorage.setItem(n, v);else document.cookie=n +"="+ v +"; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/";return v;}; 29 | UI.getCookie=function(n, v) {var s=null;if (window.localStorage) {s=window.localStorage.getItem(n);} else {var a=document.cookie.replace(/\s/g, '').split(';');for (var i in a) {if (a[i].indexOf(n+'=') == 0) {s=a[i].substring(n.length+1);break;}}}if (!s) return UI.setCookie(n, v);return s;}; 30 | UI.getPos=function(){$_.focus();return $_.selectionStart;}; 31 | UI.setPos=function(n) { $_.setSelectionRange(n, n); }; 32 | UI.getSel=function(){ return $_.value.substring($_.selectionStart, $_.selectionEnd); }; 33 | UI.delSel=function(){var m=$_.selectionStart;var n=$_.selectionEnd;if (m != n) {$_.value=$_.value.substring(0, m)+$_.value.substring(n);$_.setSelectionRange(m, m);}}; 34 | UI.key=function(w) {UI.delSel();var n=UI.getPos();var s=$_.value;$_.value=s.slice(0, n)+w+s.slice(n);UI.setPos(w.length > 1 ? n+2: n+1);UI.go();}; 35 | UI.clearFind=function(){$_.value='';$_.focus();UI.go(true);}; 36 | UI.backspace=function(){var n=UI.getPos();if (n > 0) {var s=$_.value;var c=s.codePointAt(n-2);var m=c >= 0x10000 ? n-2 : n-1;$_.value=s.slice(0, m)+s.slice(n);UI.setPos(m);UI.go();}}; 37 | UI.decompose=function(){var n=UI.getPos();if (n > 0) {var s=$_.value;var m=n-1;var w=s.charPointAt(m);if (w.length > 1) m--;var d=_('subdivide').checked;var t=Seeker.exhaust(w, d, 0);if (t.length) {$_.value=s.slice(0, m)+t+s.slice(n);UI.setPos(m+t.length);UI.go();}}}; 38 | UI.go=function(force) {if (UI.ime) return;$_.focus();if (!force && !_('onthefly').checked) return;UI.hidePop(true);var s=UI.getSel() || $_.value;if (!s) {Seeker.stopMatch();_('counter').innerHTML='';_('output').innerHTML='';} else {var d=_('subdivide').checked;if (s.charAt(0) == '\\') {_('output').innerHTML=Seeker.getTree(s.slice(1), d, Config.addCell);} else {var h='href="'+ Config.url +'"';var m=force ? Config.resultStep2 : Config.resultStep1;var l=Seeker.getMatch(s, _('variant').checked, d, m, h, Config.addCell, Config.setResult);}}}; 39 | UI.setMode=function(chk, key) {UI.setCookie(key, chk.checked ? '1' : '0');UI.go();}; 40 | UI.updatePad=function(init) {if (UI.padType === null) {UI.padType=UI.getCookie('keypad', UI.isMobile() ? false : 'stroke');} else if (UI.padType == 'categoty') {UI.padType=UI.setCookie('keypad', false);} else if (UI.padType) {UI.padType=UI.setCookie('keypad', 'categoty');} else if (!UI.padType) {UI.padType=UI.setCookie('keypad', 'stroke');}if (UI.padType == 'stroke') UI.initKeyboard(UI.strokeKeyboard);if (UI.padType == 'categoty') UI.initKeyboard(UI.categoryKeyboard);_('keypad').style.display=UI.padType ? 'block' : 'none';_('filters').style.display=UI.padType ? "" : 'none';UI.updateFilter(true);$_.focus();}; 41 | UI.updateFilter=function(init) {var f=document.getElementsByName('filter');if (!init) {for (var i=0; i= 20) UI.shortcuts.splice(0, 1);UI.shortcuts.push(w);}UI.setCookie('shortcuts', UI.shortcuts.join(' '));} else {var s=UI.getCookie('shortcuts', '');if (s) UI.shortcuts=s.split(/ /);}var html='⌘ ';for (var i in UI.shortcuts) html += '';_('scKey').innerHTML=html;}; 44 | UI.showPop=function(e) {var c=e.target;if (c.tagName.toUpperCase() != 'BUTTON' && c.tagName.toUpperCase() != 'A') return;var change=function(){var maxX=document.body.scrollWidth-70;var x=e.layerX < 150 ? 10 : Math.floor(e.layerX < maxX ? e.layerX-140 : maxX-140);_('popview').style.cssText='display:block;left:'+ x +'px;top:'+ Math.floor(e.layerY+5) +'px';_('bigchar').innerText=c.innerText;var u=c.innerText.codePointAt(0);_('codetag').innerText='U+'+u.toString(16).toUpperCase();var k=Seeker.getCJKBlock(u);_('bigchar').className=Config.useImage[k] ? 'han img' : 'han';_('bigchar').style.cssText=Config.useImage[k] ? 'background-image: url('+Config.glyphwiki+'u'+u.toString(16)+'.svg)' : '';UI.popTrigger=c;_('menu_key').style.display=c.tagName.toUpperCase() == 'BUTTON' ? 'block' : 'none';if (c.tagName.toUpperCase() == 'A') {_('menu_go').style.display=c.tagName.toUpperCase() == 'A' ? 'block' : 'none';_('menu_go').href=c.href;} else {_('menu_go').style.display='none';}_('menu_add').style.display='block';_('menu_del').style.display='none';if (c.parentElement && c.parentElement.id == 'scKey') {_('menu_add').style.display='none';_('menu_del').style.display='block';}};UI.popTimer=setTimeout(change, UI.popTrigger == null ? 0 : 100);}; 45 | UI.hidePop=function(e) {if (e !== true && e.target != UI.popTrigger) return;UI.popTimer=setTimeout(function (){_('popview').style.display='none';UI.popTrigger=null;}, 100);}; 46 | UI.eventMoniter=function(){$_.addEventListener('keydown', function(e) {if (e.code == 'Enter' || e.keyCode == 13) UI.go(true);if (e.code == 'Escape' || e.keyCode == 27) UI.clearFind();});_('popview').addEventListener('mouseenter', function(e) {clearTimeout(UI.popTimer);e.stopPropagation();}, false);_('popview').addEventListener('mouseleave', function(e) {e.stopPropagation();if (e.target != this) return;_('popview').style.display='none';UI.popTrigger=null;}, false);_('keypad').addEventListener('mouseover', function(e) { UI.showPop(e); }, false);_('keypad').addEventListener('mouseout', function(e) { UI.hidePop(e); }, false);_('scKey').addEventListener('mouseover', function(e) { UI.showPop(e); }, false);_('scKey').addEventListener('mouseout', function(e) { UI.hidePop(e); }, false);_('output').addEventListener('mouseover', function(e) { UI.showPop(e); }, false);_('output').addEventListener('mouseout', function(e) { UI.hidePop(e); }, false);_('output').addEventListener('click', function(e) { if (e.target.tagName == 'A') e.preventDefault() }, false);_('scKey').addEventListener('click', function(e) {if (e.target.tagName.toUpperCase() == 'BUTTON') UI.key(e.target.innerText);e.preventDefault();}, false);_('keypad').addEventListener('click', function(e) {if (e.target.tagName.toUpperCase() == 'BUTTON') UI.key(e.target.innerText);e.preventDefault();}, false);_('menu_go').addEventListener('click', function(e) { UI.popTrigger.click(); }, false);_('menu_key').addEventListener('click', function(e) { UI.key(UI.popTrigger.innerText); }, false);_('menu_copy').addEventListener('click', function(e) { UI.setClipboard(UI.popTrigger.innerText); }, false);_('menu_query').addEventListener('click', function(e) { UI.replaceFind(UI.popTrigger.innerText); }, false);_('menu_add').addEventListener('click', function(e) { UI.addShortcut(UI.popTrigger.innerText); }, false);_('menu_del').addEventListener('click', function(e) { UI.addShortcut(UI.popTrigger.innerText, true); }, false);$_.addEventListener('compositionstart', function(){ UI.ime=true; });$_.addEventListener('compositionend', function(){ setTimeout(function(){ UI.ime=false; UI.go(); }, 1); });}; 47 | UI.init=function(){_('version').innerHTML=Seeker.getVersion();var cnt=0;for (var i in dt) if (dt[i].substring(dt[i].length-1) != '╳') cnt++;_('datasize').innerText=cnt;_('variant').checked=UI.getCookie('variant', '1') == '1';_('onthefly').checked=UI.getCookie('onthefly', '1') == '1';_('subdivide').checked=UI.getCookie('subdivide', '0') == '1';UI.addShortcut();UI.eventMoniter();UI.updatePad(true);UI.updateFilter(true);}; 48 | window.onload=UI.init; -------------------------------------------------------------------------------- /nene/seeker.js: -------------------------------------------------------------------------------- 1 | var Seeker = {dataIndex: null, seg: 1000, interval: 50, totalmsec: 0, segcnt: 0, worker: null, result: null, groups: null}; 2 | var UI = {shortcuts: [], keypadMode: null}; 3 | var _ = function(id) { return document.getElementById(id); } 4 | var $_ = _('input'); 5 | 6 | //////////////////////////////////////// Configurations //////////////////////////////////////// 7 | 8 | Seeker.getVersion = function() {return "1.1.0.0 (2021年11月)";}; 9 | Seeker.blockFlagMap = {'#': 0x0001, 'A': 0x0002, 'B': 0x0004, 'C': 0x0008, 'D': 0x0010, 'E': 0x0020, 'F': 0x0040, 'G': 0x0080, 'X': 0x2000, 'Y': 0x4000, 'Z': 0x8000}; 10 | Seeker.blockMap = {1: 0x0001, 2: 0x0002, 3: 0x0004, 4: 0x0008, 5: 0x0010, 6: 0x0020, 7: 0x0040, 8: 0x0080, 28: 0x2000, 29: 0x2000, 30: 0x4000}; 11 | //Seeker.blockMap = {1: 0x0001, 2: 0x0002, 3: 0x0004, 4: 0x0008, 5: 0x0010, 6: 0x0020, 7: 0x0040, 8: 0x0080, 27: 0x2000, 28: 0x2000, 29: 0x2000, 30: 0x4000, 31: 0x4000}; 12 | //Seeker.dataIndexMap = {1: -0x4DCF, 2: 0x1E2E, 3: -0x19412, 4: -0x19434, 5: -0x1943F, 6: -0x19441, 7: -0x1944F, 8: -0x1A86E, 27: 0x71DD, 28: 0x71DB, 29: -0x18B4B, 30: -0xD939D, 31: -0xDD1D4}; 13 | 14 | Seeker.parts = { 15 | '一':1,'丨':1,'丶':1,'丿':1,'乙':1,'亅':1,'乚':2,'㇄':3,'㇁':3,'㇂':3,'𠄌':3,'𠃊':3,'𠃋':3,'𡿨':3,'乛':3,'㇇':3,'𠃍':3,'㇏':3, 16 | '乀':3,'⺄':3,'𠃌':3,'㇆':3,'㇉':3,'𠃑':3,'㇊':3,'㇒':3,'㇣':3,'㇀':3,'二':1,'亠':1,'人':1,'儿':1,'入':1,'八':1,'冂':1,'冖':1, 17 | '冫':1,'几':1,'凵':1,'刀':1,'力':1,'勹':1,'匕':1,'匚':1,'匸':1,'十':1,'卜':1,'卩':1,'厂':1,'厶':1,'又':1,'亻':2,'𠆢':2,'丷':2, 18 | '刂':2,'⺈':2,'㔾':2,'讠':2,'𢎘':2,'𠂉':3,'〢':3,'𠂊':3,'𠂇':3,'㐅':3,'乂':3,'𠘧':3,'𠘨':3,'⺆':3,'丂':3,'𠀁':3,'龴':3,'𠂆':3, 19 | '𠄎':3,'㇋':3,'㇌':3,'⺀':3,'𠂈':3,'丩':3,'⺊':3,'丄':3,'丅':3,'丆':3,'𠃎':3,'𠄟':3,'𠄠':3,'𠄐':3,'𠃏':3,'乁':3,'𠙴':3,'七':4, 20 | '𠤎':4,'九':4,'口':1,'囗':1,'土':1,'士':1,'夂':1,'夊':1,'夕':1,'大':1,'女':1,'子':1,'宀':1,'寸':1,'小':1,'尢':1,'尸':1,'屮':1, 21 | '山':1,'巛':1,'工':1,'己':1,'巾':1,'干':1,'幺':1,'广':1,'廴':1,'廾':1,'弋':1,'弓':1,'彐':1,'彡':1,'彳':1,'川':2,'⺌':2,'𡭔':2, 22 | '䶹':2,'彑':2,'忄':2,'扌':2,'氵':2,'犭':2,'⺾':2,'阝':2,'⻖':2,'⻏':2,'⺕':2,'⻌':2,'丬':2,'纟':2,'飞':2,'饣':2,'䒑':3,'卄':3, 23 | '𭕄':3,'𠀆':3,'𠔼':3,'𠫓':3,'𣥂':3,'𡳾':3,'𠂎':3,'乇':3,'𫝀':3,'㐄':3,'𡕒':3,'乡':3,'𠚤':3,'习':3,'亼':3,'三':4,'丈':4,'也':4, 24 | '于':4,'上':4,'下':4,'兀':4,'丌':4,'卂':4,'亇':4,'万':4,'刄':4,'心':1,'戈':1,'戶':1,'手':1,'支':1,'攴':1,'文':1,'斗':1,'斤':1, 25 | '方':1,'无':1,'日':1,'曰':1,'月':1,'木':1,'欠':1,'止':1,'歹':1,'殳':1,'毋':1,'比':1,'毛':1,'氏':1,'气':1,'水':1,'火':1,'爪':1, 26 | '父':1,'爻':1,'爿':1,'片':1,'牙':1,'牛':1,'犬':1,'⺗':2,'攵':2,'朩':2,'毌':2,'灬':2,'爫':2,'爫':2,'牜':2,'𠂒':2,'尣':2,'⺩':2, 27 | '礻':2,'龰':2,'罓':2,'冈':2,'㓁':2,'⺼':2,'艹':2,'辶':2,'⻍':2,'耂':2,'⺳':3,'𦉪':3,'𠔿':3,'⺝':3,'艹':3,'卝':3,'龷':3,'廿':3, 28 | '丰':3,'丯':3,'𧘇':3,'𣎳':3,'𥘅':3,'龶':3,'⺜':3,'厃':3,'𠃜':3,'肀':3,'旡':3,'冘':3,'夬':3,'兂':3,'龵':3,'𦉫':3,'𠬝':3,'㸦':3, 29 | '𤓰':3,'𠃛':3,'夨':3,'仌':3,'王':4,'五':4,'六':4,'卅':4,'不':4,'丐':4,'及':4,'丑':4,'丹':4,'刅':4,'井':4,'开':4,'𠬛':4,'尺':4, 30 | '巨':4,'巴':4,'𣎴':4,'冃':4,'冄':4,'𠬞':4,'𠬜':4,'丮':4,'巿':4,'𠃚':4,'玄':1,'玉':1,'瓜':1,'瓦':1,'甘':1,'生':1,'用':1,'田':1, 31 | '疋':1,'疒':1,'癶':1,'白':1,'皮':1,'皿':1,'目':1,'矛':1,'矢':1,'石':1,'示':1,'禸':1,'禾':1,'穴':1,'立':1,'𤴓':2,'𤴔':2,'罒':2, 32 | '𦉰':2,'歺':2,'母':2,'氺':2,'衤':2,'⺬':2,'钅':2,'𢆉':3,'𦍍':3,'业':3,'𠀎':3,'㠯':3,'𠕁':3,'𡗗':3,'圥':3,'𠮠':3,'犮':3,'𢎨':3, 33 | '𦘒':3,'⺻':3,'龸':3,'𣦵':3,'丱':3,'𤕫':3,'𥝌':3,'𦫳':3,'𣎵':3,'屵':3,'𫇦':3,'四':4,'卌':4,'夗':4,'㐱':4,'乍':4,'乎':4,'冉':4, 34 | '册':4,'史':4,'央':4,'戉':4,'戊':4,'冋':4,'本':4,'民':4,'永':4,'北':4,'竹':1,'米':1,'糸':1,'缶':1,'网':1,'羊':1,'羽':1,'老':1, 35 | '而':1,'耒':1,'耳':1,'聿':1,'肉':1,'臣':1,'自':1,'至':1,'臼':1,'舌':1,'舛':1,'舟':1,'艮':1,'色':1,'艸':1,'虍':1,'虫':1,'血':1, 36 | '行':1,'衣':1,'襾':1,'𥫗':2,'糹':2,'𦍌':2,'⺶':2,'西':2,'覀':2,'齐':2,'冎':3,'龹':3,'𠂤':3,'𧰨':3,'乑':3,'𢦏':3,'产':3,'巩':3, 37 | '𦈢':3,'𠂭':3,'𠂢':3,'𠦃':3,'䇂':3,'㐆':3,'甶':3,'囟':3,'幵':3,'厽':3,'𠃨':3,'𠬪':3,'朿':4,'亙':4,'兆':4,'州':4,'年':4,'曲':4, 38 | '曳':4,'朱':4,'关':4,'見':1,'角':1,'言':1,'谷':1,'豆':1,'豕':1,'豸':1,'貝':1,'赤':1,'走':1,'足':1,'身':1,'車':1,'辛':1,'辰':1, 39 | '辵':1,'邑':1,'酉':1,'釆':1,'里':1,'訁':2,'𧮫':2,'𧾷':2,'𦥑':2,'镸':2,'⺸':3,'𦍋':3,'夋':3,'𦉶':3,'㒳':3,'㐬':3,'𠦒':3,'𦣞':3, 40 | '𦣝':3,'丣':3,'戼':3,'𠃬':3,'㕯':3,'㫃':3,'囧':3,'𦣻':3,'囱':3,'囪':3,'㡀':3,'严':3,'𠦑':3,'㳄':3,'我':4,'巠':4,'甹':4,'皀':4, 41 | '夆':4,'亜':4,'来':4,'金':1,'長':1,'門':1,'阜':1,'隶':1,'隹':1,'雨':1,'青':1,'非':1,'釒':2,'⻗':2,'靑':2,'飠':2,'叀':3,'亝':3, 42 | '𣏟':3,'㣇':3,'甾':3,'幷':3,'𨸏':3,'𣶒':3,'罙':4,'忝':4,'匋':4,'奄':4,'東':4,'疌':4,'黾':4,'靣':4,'面':1,'革':1,'韋':1,'韭':1, 43 | '音':1,'頁':1,'風':1,'飛':1,'食':1,'首':1,'香':1,'𩙿':2,'叚':3,'壴':3,'复':3,'亲':3,'枼':3,'昜':3,'亯':3,'𡿺':3,'𠧪':3,'県':3, 44 | '𥄉':3,'㲋':3,'𢑚':3,'㢴':3,'𢏚':3,'咢':4,'奐':4,'禺':4,'南':4,'馬':1,'骨':1,'高':1,'髟':1,'鬥':1,'鬯':1,'鬲':1,'鬼':1,'𤇾':3, 45 | '丵':3,'𠂹':3,'𣆪':3,'𩠐':3,'𡸁':3,'隺':4,'尃':4,'𧴪':4,'𥁕':4,'臽':4,'䍃':4,'芻':4,'皋':4,'魚':1,'鳥':1,'鹵':1,'鹿':1,'麥':1, 46 | '麻':1,'㒼':3,'𦰩':3,'𠦬':3,'𠁁':3,'桼':4,'啇':4,'袞':4,'翏':4,'啚':4,'悤':4,'粛':4,'黃':1,'黍':1,'黑':1,'黹':1,'菐':4,'巽':4, 47 | '粦':4,'尌':4,'朁':4,'尞':4,'厤':4,'肅':4,'𤔔':3,'𠥓':3,'黽':1,'鼎':1,'鼓':1,'鼠':1,'𦥯':3,'𦝠':3,'𢊁':3,'廌':3,'𠌶':3,'亶':4, 48 | '嗇':4,'睘':4,'鼻':1,'齊':1,'𨛜':3,'㥯':4,'熏':4,'齒':1,'嘼':3,'廛':4,'巤':4,'龍':1,'龜':1,'龠':1,'𩫖':3,'毚':4,'韱':4, 49 | '㇈':3,'󰎀':3,'󰋌':3,'󰊅':3,'󰊸':3,'󰕐':3,'𰀪':3,'巜':2,'󰓶':3,'󰒖':3,'󰓏':3,'󰒑':3,'󰋚':3,'󰓐':3,'󰒾':3,'𰃮':3,'龻':3, 50 | '󰓗':3,'󶃛':3,'󰒭':3,'󰒂':3,'󰒦':3,'󰊥':3,'󰊶':3,'󰓴':3,'󶏔':3,'󰑖':3,'󰑹':3,'󰑷':3,'㦰':3,'甲':4,'丙':4,'丁':4,'庚':4, 51 | '壬':4,'癸':4,'寅':4,'卯':4,'巳':4,'午':4,'未':4,'申':4,'戌':4,'亥':4,'󰑬':3,'󰐻':3,'丘':4,'𫶧':3,'󰑉':3,'虎':4, 52 | '󰒬':3,'󰊎':3,'󰐸':3,'󰐧':3,'󰐷':3,'刃':4,'𭤨':3,'𰀄':3,'吅':3,'从':3,'󰒊':3,'中':4,'󰑲':3,'󰩮':3,'𰀁':3,'𠂔':3,'𪩲':3,'亞':4 53 | }; 54 | 55 | UI.strokeKeyboard = { 56 | vertical: true, 57 | className: 'strokeKB', 58 | groups: { 59 | '01畫': '一丨丶丿乙亅乚㇄㇁㇂𠄌𠃊𠃋𡿨乛㇇𠃍㇏乀⺄𠃌㇆㇉𠃑㇊㇒㇣㇀', 60 | '02畫': '二亠人儿入八冂冖冫几凵刀力勹匕匚匸十卜卩厂厶又亻𠆢丷刂⺈㔾讠𢎘𠂉〢𠂊𠂇㐅乂𠘧𠘨⺆丂𠀁龴𠂆𠄎㇋㇌⺀𠂈丩⺊丄丅丆𠃎𠄟𠄠𠄐𠃏乁𠙴七𠤎九', 61 | '03畫': '口囗土士夂夊夕大女子宀寸小尢尸屮山巛工己巾干幺广廴廾弋弓彐彡彳川⺌𡭔䶹彑忄扌氵犭⺾阝⻖⻏⺕⻌丬纟飞饣䒑卄𭕄𠀆𠔼𠫓𣥂𡳾𠂎乇𫝀㐄𡕒乡𠚤习亼三丈也于上下兀丌卂亇万刄', 62 | '04畫': '心戈戶手支攴文斗斤方无日曰月木欠止歹殳毋比毛氏气水火爪父爻爿片牙牛犬⺗攵朩毌灬爫爫牜𠂒尣⺩礻龰罓冈㓁⺼艹辶⻍耂⺳𦉪𠔿⺝艹卝龷廿丰丯𧘇𣎳𥘅龶⺜厃𠃜肀旡冘夬兂龵𦉫𠬝㸦𤓰𠃛夨仌王五六卅不丐及丑丹刅井开𠬛尺巨巴𣎴冃冄𠬞𠬜丮巿𠃚', 63 | '05畫': '玄玉瓜瓦甘生用田疋疒癶白皮皿目矛矢石示禸禾穴立𤴓𤴔罒𦉰歺母氺衤⺬钅𢆉𦍍业𠀎㠯𠕁𡗗圥𠮠犮𢎨𦘒⺻龸𣦵丱𤕫𥝌𦫳𣎵屵𫇦四卌夗㐱乍乎冉册史央戉戊冋本民永北', 64 | '06畫': '竹米糸缶网羊羽老而耒耳聿肉臣自至臼舌舛舟艮色艸虍虫血行衣襾𥫗糹𦍌⺶西覀齐冎龹𠂤𧰨乑𢦏产巩𦈢𠂭𠂢𠦃䇂㐆甶囟幵厽𠃨𠬪朿亙兆州年曲曳朱关', 65 | '07畫': '見角言谷豆豕豸貝赤走足身車辛辰辵邑酉釆里訁𧮫𧾷𦥑镸⺸𦍋夋𦉶㒳㐬𠦒𦣞𦣝丣戼𠃬㕯㫃囧𦣻囱囪㡀严𠦑㳄我巠甹皀夆亜来', 66 | '08畫': '金長門阜隶隹雨青非釒⻗靑飠叀亝𣏟㣇甾幷𨸏𣶒罙忝匋奄東疌黾靣', 67 | '09畫': '面革韋韭音頁風飛食首香𩙿叚壴复亲枼昜亯𡿺𠧪県𥄉㲋𢑚㢴𢏚咢奐禺南', 68 | '其它': { 69 | '10畫': '馬骨高髟鬥鬯鬲鬼𤇾丵𠂹𣆪𩠐𡸁隺尃𧴪𥁕臽䍃芻皋', 70 | '11畫': '魚鳥鹵鹿麥麻㒼𦰩𠦬𠁁桼啇袞翏啚悤粛', 71 | '12畫': '黃黍黑黹菐巽粦尌朁尞厤肅𤔔𠥓', 72 | '13畫': '黽鼎鼓鼠𦥯𦝠𢊁廌𠌶亶嗇睘', 73 | '14畫': '鼻齊𨛜㥯熏', 74 | '15畫': '齒嘼廛巤', 75 | '16畫': '龍龜', 76 | '17畫': '龠𩫖毚韱' 77 | } 78 | } 79 | }; 80 | 81 | //////////////////////////////////////// JavaScript Prototypes //////////////////////////////////////// 82 | 83 | if (!Array.prototype.indexOf) { 84 | Array.prototype.indexOf = function (o, f) { 85 | var l = this.length; 86 | if (f == null) f = 0; 87 | if (f < 0) f = Math.max(0, l + f); 88 | for (var i = f; i < l; i++) { 89 | if (this[i] === o) return i; 90 | } 91 | return -1; 92 | }; 93 | } 94 | 95 | if (!String.prototype.codePointAt) { 96 | String.prototype.codePointAt = function(i) { 97 | var c = this.charCodeAt(i); 98 | if (c >= 0xD800 && c <= 0xDBFF) return (((c & 0x03FF) << 10) | (this.charCodeAt(i+1) & 0x03FF)) + 0x10000; 99 | return c; 100 | }; 101 | } 102 | 103 | String.prototype.charPointAt = function(i) { 104 | var c = this.charCodeAt(i); 105 | if (c >= 0xD800 && c <= 0xDBFF) return this.charAt(i) + this.charAt(i+1); 106 | if (c >= 0xDC00 && c <= 0xDFFF) return this.charAt(i-1) + this.charAt(i); 107 | return this.charAt(i); 108 | }; 109 | 110 | //////////////////////////////////////// Core Logic //////////////////////////////////////// 111 | 112 | Seeker.variant = function(w, v) { 113 | return v && vt[w] ? vt[w] : w; 114 | }; 115 | 116 | Seeker.arraylize = function(s, v, a) { 117 | var blockFlag = 0; 118 | for (var i = 0; i < s.length; i++) { 119 | var w = s.charPointAt(i); 120 | if (w.length > 1) i++; 121 | if (Seeker.blockFlagMap[w]) { 122 | blockFlag |= Seeker.blockFlagMap[w]; 123 | } else { 124 | if (w.length == 1) { 125 | var c = w.charCodeAt(0); 126 | if (c >= 0x2FF0 && c <= 0x2FFB) break; // CJK description 127 | } 128 | a.push(Seeker.variant(w, v)); 129 | } 130 | } 131 | if (blockFlag == 0) blockFlag = 0xFFFF; 132 | return blockFlag; 133 | }; 134 | 135 | Seeker.getCJKBlock = function(c) { 136 | if (c >= 0x4E00 && c <= 0x9FFC ) return 1; 137 | if (c >= 0x3400 && c <= 0x4DBF ) return 2; 138 | if (c >= 0x20000 && c <= 0x2A6DD) return 3; 139 | if (c >= 0x2A700 && c <= 0x2B734) return 4; 140 | if (c >= 0x2B740 && c <= 0x2B81D) return 5; 141 | if (c >= 0x2B820 && c <= 0x2CEA1) return 6; 142 | if (c >= 0x2CEB0 && c <= 0x2EBE0) return 7; 143 | if (c >= 0x30000 && c <= 0x3134A) return 8; 144 | if (c >= 0xF900 && c <= 0xFAD9 ) return 28; 145 | if (c >= 0x2F800 && c <= 0x2FA1D) return 29; 146 | if (c >= 0xF0270 && c <= 0xFAE7A) return 30; 147 | return 0; 148 | }; 149 | 150 | Seeker.getData = function(c) { 151 | if (Seeker.dataIndex == null) { 152 | Seeker.dataIndex = {}; 153 | for (var i in dt) { 154 | var chr = dt[i].codePointAt(0); 155 | if (typeof(chr) != 'number') continue; 156 | Seeker.dataIndex[chr] = dt[i].substring(chr > 0xffff ? 2 : 1); 157 | } 158 | } 159 | return Seeker.dataIndex[c]; 160 | }; 161 | 162 | // 檢索遞迴運算 163 | Seeker.eliminate = function(query, str, groups, ignore, divide, variant) { 164 | // query: 搜尋字串的陣列(已排序) 165 | // str: 正要媒合的樹枝 166 | // divide: 硬拆 167 | // variant: 包容異體 168 | if (str == "@") return null; // 如果此字已無法再分解 169 | 170 | var backup = query.concat(); // b: 備份搜尋陣列a 171 | var res = false; 172 | for (var i = 0; i < str.length; i++) { // 針對拆分序列中的每個字 173 | var w = str.charPointAt(i); 174 | if (w.length > 1) i++; 175 | if (ignore && ignore.indexOf(w) >= 0) { 176 | continue; 177 | } 178 | 179 | if (w == "!" && !divide) break; // 若此字是無理拆分且非無理拆分模式 180 | if (w == "@" || w == "!") { // 某種拆分方式的起始 181 | if (!query.length) break; 182 | query.length = 0; // 從備份重建搜尋陣列 183 | for (var j = 0; j < backup.length; j++) query.push(backup[j]); 184 | 185 | } else if (query.length) { // 搜尋陣列還有值 186 | var c = w.codePointAt(0); 187 | var pos = query.indexOf(Seeker.variant(w, variant)); // 在搜尋陣列中尋找這個字的位置 188 | if (pos < 0) { // 找不到的話,把拆分字串再拆開遞迴一層 189 | if (Seeker.getData(c)) { 190 | if (Seeker.eliminate(query, Seeker.getData(c), groups, ignore, divide, variant)) { 191 | groups.unshift(w); 192 | res |= true; 193 | } 194 | } 195 | } else { 196 | query.splice(pos, 1); // 找到了:從搜尋陣列刪除這個字 197 | res |= true; 198 | } 199 | } 200 | } 201 | return res; 202 | }; 203 | 204 | Seeker.stopMatch = function() { 205 | clearTimeout(Seeker.worker); 206 | }; 207 | 208 | // setTimeout 分割版本 209 | Seeker.getMatch = function(s, ignore, variant, divide, force, urlSrc) { 210 | // string, variant?, divide?, max, href 211 | clearTimeout(Seeker.worker); 212 | 213 | var x = []; 214 | var blockFlag = Seeker.arraylize(s, variant, x); 215 | x.sort(); 216 | s = x.join(''); 217 | if (s == '') return; 218 | 219 | var found = []; 220 | var work = function(j) { 221 | if (j+Seeker.seg < dt.length) Seeker.worker = setTimeout(function() { work(j+Seeker.seg); }, Seeker.segcnt > 10 ? Math.floor(Seeker.totalmsec/Seeker.segcnt+5) : Seeker.interval); 222 | var st = new Date(); 223 | var t = 0; 224 | for (var i = j; i < j + Seeker.seg && i < dt.length; i++) { 225 | var query = x.concat(); // 複製陣列 (因為eliminate函式內會直接操作,故用concat的副作用進行複製) 226 | var w = dt[i].charPointAt(0); // 目前測試的字 227 | var c = w.codePointAt(0); // 的unicode 228 | var block = Seeker.getCJKBlock(c); 229 | if (ignore && ignore.indexOf(w) >= 0) continue; 230 | 231 | if (blockFlag) { // 篩選要包含的Unicode分區 232 | var f = Seeker.blockMap[block] || 0x8000; 233 | if (!(blockFlag & f)) continue; 234 | } 235 | 236 | //var n = 0; // 命中狀態 237 | var groups = []; 238 | if (Seeker.variant(w, variant) != s) { 239 | Seeker.eliminate(query, dt[i].slice(w.length), groups, ignore, divide, variant); 240 | if (query.length) continue; // 沒命中 241 | groups.unshift(w); 242 | } 243 | 244 | var url = urlSrc; 245 | url = url.replace("$CHR$", w); 246 | url = url.replace("$ENC$", encodeURI(w)); 247 | url = url.replace("$UCD$", c.toString()); 248 | url = url.replace("$UCh$", c.toString(16)); 249 | url = url.replace("$UCH$", c.toString(16).toUpperCase()); 250 | 251 | var hitData = {'char': w, 'unicode': c, 'groups': groups, 'order': found.length}; 252 | if (force || block == 1) found.push(hitData); 253 | if (!force && block != 1) { 254 | clearTimeout(Seeker.worker); 255 | UI.onFinished(found); 256 | break; // 新增超過m+1時break掉,雖然可能因此喪失精確命中結果,但可以明顯加速運算 257 | } 258 | } 259 | UI.setResult(found, i, force); 260 | Seeker.totalmsec += new Date()-st; 261 | Seeker.segcnt++; 262 | 263 | if (j+Seeker.seg >= dt.length) UI.onFinished(found); 264 | }; 265 | Seeker.worker = setTimeout(function() { work(0); }, 10); 266 | }; 267 | 268 | // 拆分 269 | Seeker.exhaust = function(s, divide, recursive) { 270 | var res = ''; 271 | if (s.length) { 272 | var w = s.charPointAt(0); 273 | var c = w.codePointAt(0); 274 | var def = Seeker.getData(c); //.substring(w.length); 275 | var k = 0; 276 | for (var i = 0; i < def.length; i++) { 277 | w = def.charPointAt(i); 278 | if (w.length > 1) i++; 279 | if ((w == "!") && !divide) break; 280 | if ((w == "@") || (w == "!")) { 281 | if (k) res += (recursive == -1) ? "┇" : "‖"; 282 | k++; 283 | } else { 284 | res += w; 285 | if (recursive) { 286 | var subRes = Seeker.exhaust(w, divide, -1); 287 | if (subRes.length) res += "(" + subRes + ")"; 288 | } 289 | } 290 | } 291 | } 292 | return res; 293 | }; 294 | 295 | // 解構模式 (:) 296 | Seeker.getTree = function(str, divide) { 297 | var html = ''; 298 | if (str.length) { 299 | var w = str.charPointAt(0); 300 | var c = w.codePointAt(0); 301 | var p = Seeker.exhaust(w, divide, true); 302 | p = p.replace(/([\ud800-\udbff][\udc00-\udfff]|[^\ud800-\udfff])\(/g, '$1(').replace(/\)/g, ')'); 303 | 304 | if (p == '') { 305 | html += UI.addCell({'char': w, 'unicode': c, 'text': '(無法再分解)'}); 306 | } else { 307 | var strs = p.split('‖'); 308 | for (var i in strs) { 309 | html += UI.addCell({'char': w, 'unicode': c, 'text': strs[i].length ? strs[i] : "(無法再分解)"}); 310 | } 311 | } 312 | } 313 | return html; 314 | } 315 | 316 | //////////////////////////////////////// User Interface //////////////////////////////////////// 317 | 318 | UI.blockClasses = {1: 'BSC', 2: 'ExA', 3: 'ExB', 4: 'ExC', 5: 'ExD', 6: 'ExE', 7: 'ExF', 8: 'ExG', 27: 'CMP', 28: 'CMP', 29: 'CMP', 30: 'SUP', 31: 'SUP'}; 319 | 320 | UI.isMobile = function() { 321 | return navigator.userAgent =~ /Android|iOS/i; 322 | }; 323 | 324 | UI.initKeyboard = function(kbType) { 325 | var html = ''; 326 | if (!kbType.vertical) { 327 | html += ''; 328 | for (var g in kbType.groups) html += ''; 329 | html += ''; 330 | } 331 | for (var g in kbType.groups) { 332 | if (kbType.vertical) html += ''; 333 | html += ''; 356 | if (kbType.vertical) html += ''; 357 | } 358 | html += '
' + g + '
' + g + ''; 334 | if (typeof kbType.groups[g] == 'string') { 335 | for (var i=0; i < kbType.groups[g].length; i++) { 336 | var w = kbType.groups[g].charPointAt(i); 337 | if (w.length > 1) i++; 338 | if (w == ',') { html += '
'; continue; } 339 | var z = Seeker.parts[w]; 340 | if (z) html += ''; 341 | } 342 | } else { 343 | for (var gg in kbType.groups[g]) { 344 | html += '' + gg + ''; 345 | for (var i=0; i 1) i++; 348 | if (w == ',') { html += '
'; continue; } 349 | var z = Seeker.parts[w]; 350 | if (z) html += ''; 351 | } 352 | html += '
'; 353 | } 354 | } 355 | html += '
'; 359 | $('#keypad').html(html); 360 | }; 361 | 362 | // 寫入剪貼簿 363 | UI.setClipboard = function(s) { 364 | s = decodeURI(s); 365 | if (window.clipboardData) { 366 | window.clipboardData.clearData(); 367 | window.clipboardData.setData('Text', s); 368 | } else { 369 | var t = document.createElement('textarea'); 370 | t.textContent = s; 371 | document.body.appendChild(t); 372 | t.select(); 373 | document.execCommand('copy'); 374 | document.body.removeChild(t); 375 | } 376 | }; 377 | 378 | // 設定 Cookie 379 | UI.setCookie = function(n, v) { 380 | if (window.localStorage) window.localStorage.setItem(n, v); 381 | else document.cookie = n +"="+ v +"; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/"; 382 | return v; 383 | }; 384 | 385 | // 讀取 Cookie 386 | UI.getCookie = function(n, v) { 387 | var s = null; 388 | if (window.localStorage) { 389 | s = window.localStorage.getItem(n); 390 | } else { 391 | var a = document.cookie.replace(/\s/g, '').split(';'); 392 | for (var i in a) { 393 | if (a[i].indexOf(n + '=') == 0) { 394 | s = a[i].substring(n.length+1); 395 | break; 396 | } 397 | } 398 | } 399 | if (!s) return UI.setCookie(n, v); 400 | return s; 401 | }; 402 | 403 | // 取得游標位置 404 | UI.getPos = function() { 405 | $_.focus(); 406 | return $_.selectionStart; 407 | }; 408 | 409 | // 設定游標位置 410 | UI.setPos = function(n) { $_.setSelectionRange(n, n); }; 411 | 412 | // 取得選擇文字 413 | UI.getSel = function() { return $_.value.substring($_.selectionStart, $_.selectionEnd); }; 414 | 415 | // 清除選擇文字 416 | UI.delSel = function() { 417 | var m = $_.selectionStart; 418 | var n = $_.selectionEnd; 419 | if (m != n) { 420 | $_.value = $_.value.substring(0, m) + $_.value.substring(n); 421 | $_.setSelectionRange(m, m); 422 | } 423 | }; 424 | 425 | UI.key = function(w) { 426 | UI.delSel(); 427 | var n = UI.getPos(); 428 | var s = $_.value; 429 | $_.value = s.slice(0, n) + w + s.slice(n); 430 | UI.setPos(w.length > 1 ? n+2: n+1); 431 | UI.go(); 432 | }; 433 | 434 | // 清除檢索 435 | UI.clearFind = function() { 436 | $_.value = ''; 437 | $_.focus(); 438 | UI.go(true); 439 | }; 440 | 441 | // 拆漢字 442 | UI.decompose = function() { 443 | var n = UI.getPos(); 444 | if (n > 0) { 445 | var s = $_.value; 446 | var m = n-1; 447 | var w = s.charPointAt(m); 448 | if (w == '\\') { 449 | m--; 450 | w = s.charPointAt(m); 451 | } 452 | if (w.length > 1) m--; 453 | 454 | var d = _('subdivide').checked; 455 | var t = Seeker.exhaust(w, d, false); 456 | if (t.length) { 457 | $_.value = s.slice(0, m) + t + s.slice(n).replace(/\\/g, ''); 458 | UI.setPos(m+t.length); 459 | UI.go(); 460 | } 461 | } 462 | }; 463 | 464 | // 部件檢索 465 | UI.go = function(force) { 466 | if (UI.ime) return; 467 | $_.focus(); 468 | //if (!force && !_('onthefly').checked) return; 469 | UI.hidePop(true); 470 | Seeker.groups = null; 471 | $('#groups').html('').hide(); 472 | Seeker.result = null; 473 | var s = UI.getSel() || $_.value; 474 | s = s.replace(/\s/g, ''); 475 | Seeker.stopMatch(); 476 | if (!s) { 477 | $('#counter').text(''); 478 | $('#output').text(''); 479 | } else { 480 | var divide = _('subdivide').checked; 481 | var variant = _('variant').checked; 482 | //var l = []; 483 | if (s.charAt(0) == ':') { 484 | $('#output').html(Seeker.getTree(s.slice(1), divide)); 485 | } else { 486 | var ignore = null; 487 | var tmp = s.split('-'); 488 | if (tmp.length == 2) { s = tmp[0]; ignore = tmp[1]; } 489 | 490 | var url = 'href="'+ Config.url +'"'; 491 | Seeker.getMatch(s, ignore, variant, divide, force, url); 492 | } 493 | } 494 | }; 495 | 496 | // 更新勾選框Cookie 497 | UI.setMode = function(chk, key) { 498 | UI.setCookie(key, chk.checked ? '1' : '0'); 499 | UI.go(); 500 | }; 501 | 502 | // 鍵盤開關改變 503 | UI.updatePad = function() { 504 | UI.keypadMode = $('#showkeypad:checked').length > 0; 505 | UI.setCookie('keypad', UI.keypadMode ? '1' : '0'); 506 | if (UI.keypadMode) { 507 | UI.initKeyboard(UI.strokeKeyboard); 508 | $('#keypad').show(); 509 | } else { 510 | $('#keypad').hide(); 511 | } 512 | $_.focus(); 513 | }; 514 | 515 | UI.replaceFind = function(s) { 516 | if (!UI.getSel()) $_.value = ''; 517 | UI.key(s); 518 | }; 519 | 520 | // 加入快捷按鈕 521 | UI.addShortcut = function(w, d) { 522 | if (w) { 523 | var ex = false; 524 | for (var i in UI.shortcuts) { 525 | if (UI.shortcuts[i] == w) { ex = true; if (d) UI.shortcuts.splice(i, 1); } 526 | } 527 | if (!ex) { 528 | if (UI.shortcuts.length >= 20) UI.shortcuts.splice(0, 1); 529 | UI.shortcuts.push(w); 530 | } 531 | UI.setCookie('shortcuts', UI.shortcuts.join(' ')); 532 | } else { 533 | var s = UI.getCookie('shortcuts', ''); 534 | if (s) UI.shortcuts = s.split(/ /); 535 | } 536 | var html = '⌘ '; 537 | for (var i in UI.shortcuts) html += UI.createTag(UI.shortcuts[i], 'button', 'han', null, true); 538 | $('#scKey').html(html); 539 | }; 540 | 541 | UI.showPop = function(e) { 542 | var c = e.target; 543 | if (c.tagName.toUpperCase() != 'BUTTON' && c.tagName.toUpperCase() != 'A') return; 544 | var change = function() { 545 | var maxX = document.body.scrollWidth - 70; 546 | //var x = e.pageX < 150 ? 10 : Math.floor(e.pageX < maxX ? e.pageX - 140 : maxX - 140); 547 | var rect = c.getBoundingClientRect(); 548 | var x = rect.left < 150 ? 10 : Math.floor(rect.left < maxX ? rect.left - 140 : maxX - 140); 549 | $('#popview').css({left: x, top: Math.floor(window.scrollY + rect.bottom-2)}).show(); 550 | var chr = $(c).attr('data-char') || c.innerText; 551 | var u = chr.codePointAt(0); 552 | var k = Seeker.getCJKBlock(u); 553 | $('#codetag').text('U+' + u.toString(16).toUpperCase()); 554 | $('#bigchar').text(chr).attr({'class': 'han', 'style': ''}); 555 | if (Config.useImage[k]) $('#bigchar').addClass('img').css({'background-image': 'url(' + Config.glyphwiki + 'u' + u.toString(16) + '.svg)'}); 556 | UI.popTrigger = c; 557 | $('#menu_key').toggle(c.tagName.toUpperCase() == 'BUTTON'); 558 | //_('menu_key').style.display = c.tagName.toUpperCase() == 'BUTTON' ? 'block' : 'none'; 559 | $('#menu_go').toggle(c.tagName.toUpperCase() == 'A').attr('href', c.href); 560 | if (c.tagName.toUpperCase() == 'A') $('#menu_go').attr('href', c.href); 561 | var inScKey = c.parentElement && c.parentElement.id == 'scKey'; // 因為動態呈現時,c.parentElement可能經常消失 562 | $('#menu_add').toggle(!inScKey); 563 | $('#menu_del').toggle(inScKey); 564 | }; 565 | UI.popTimer = setTimeout(change, UI.popTrigger == null ? 0 : 100); 566 | }; 567 | 568 | UI.hidePop = function(e) { 569 | if (e !== true && e.target != UI.popTrigger) return; 570 | UI.popTimer = setTimeout(function () { 571 | $('#popview').hide(); 572 | UI.popTrigger = null; 573 | }, 100); 574 | }; 575 | 576 | UI.setSkipChar = function(chr) { 577 | if ($_.value.indexOf('-') < 0) $_.value += '-'; 578 | $_.value += chr; 579 | UI.go(); 580 | }; 581 | 582 | UI.eventMoniter = function() { 583 | $_.addEventListener('keydown', function(e) { 584 | if (e.isComposing) return; 585 | if (e.code == 'Enter' || e.keyCode == 13) UI.go(true); 586 | if (e.code == 'Escape' || e.keyCode == 27) UI.clearFind(); 587 | }); 588 | 589 | $_.addEventListener('keyup', function(e) { 590 | if (e.isComposing) return; 591 | if (e.code == 'Backslash' || e.keyCode == 0x5C) UI.decompose(); 592 | }); 593 | 594 | $_.addEventListener('compositionstart', function() { UI.ime = true; }); 595 | $_.addEventListener('compositionend', function() { setTimeout(function() { UI.ime = false; UI.go(); }, 1); }); 596 | 597 | 598 | $($_).on('input', function() { UI.go(false); }); 599 | $('#buttClear').click(UI.clearFind); 600 | $('#buttDecompose').click(UI.decompose); 601 | $('#buttGo').click(function() { UI.go(true) }); 602 | 603 | $('#showkeypad').click(UI.updatePad); 604 | 605 | $('#popview').on('mouseenter', function(e) { 606 | clearTimeout(UI.popTimer); 607 | e.stopPropagation(); 608 | }); 609 | 610 | $('#popview').on('mouseleave', function(e) { 611 | e.stopPropagation(); 612 | $('#popview').hide(); 613 | UI.popTrigger = null; 614 | }); 615 | 616 | // mouse in/out 617 | $('#keypad').on('mouseover', 'button', UI.showPop).on('mouseout', 'button', UI.hidePop); 618 | $('#scKey').on('mouseover', 'button', UI.showPop).on('mouseout', 'button', UI.hidePop); 619 | $('#groups').on('mouseover', 'a', UI.showPop).on('mouseout', 'a', UI.hidePop); 620 | $('#output').on('mouseover', 'a', UI.showPop).on('mouseout', 'a', UI.hidePop); 621 | //_('output').addEventListener('click', function(e) { if (e.target.tagName == 'A') e.preventDefault() }, false); 622 | 623 | // click events 624 | $('#scKey, #keypad').on('click', 'button', function(e) { UI.key(e.target.innerText); e.preventDefault(); }); 625 | $('#groups').on('click', 'a.grp', function() { $(this).toggleClass('on'); UI.showOutput(); }); 626 | $('#output').on('click', 'a', function(e) { e.preventDefault() } ); 627 | 628 | $('#output').on('mouseover', '> span .line', function(e) { $(this).attr('class', 'line hover'); e.stopPropagation(); }); 629 | $('#output').on('mouseout', '> span .line', function(e) { $(this).attr('class', 'line'); }); 630 | 631 | $('#menu_go').click(function(e) { UI.popTrigger.click() }); 632 | $('#menu_key').click(function(e) { UI.key($(UI.popTrigger).data('char')) }); 633 | $('#menu_copy').click(function(e) { UI.setClipboard($(UI.popTrigger).data('char')) }); 634 | $('#menu_query').click(function(e) { UI.replaceFind($(UI.popTrigger).data('char')) }); 635 | $('#menu_skip').click(function(e) { UI.setSkipChar($(UI.popTrigger).data('char')) }); 636 | $('#menu_add').click(function(e) { UI.addShortcut($(UI.popTrigger).data('char')) }); 637 | $('#menu_del').click(function(e) { UI.addShortcut($(UI.popTrigger).data('char'), true) }); 638 | }; 639 | 640 | // 產生漢字按鈕 641 | UI.createTag = function(c, tag, cls, extra, hideChar, running) { 642 | var code = c.codePointAt(0); 643 | var tagBody = Config.useImage[Seeker.getCJKBlock(code)] && !running ? 644 | ' img" data-char="' + c + '" style="background-image: url(' + Config.glyphwiki + 'u' + code.toString(16) + '.svg)">' + (hideChar ? ' ' : c) : 645 | '" data-char="' + c + '">' + c; 646 | return '<' + tag + ' ' + (extra || '') + ' class="' + (cls || '') + tagBody + ''; 647 | }; 648 | 649 | // 產生Output框內的搜尋結果文字 650 | UI.addCell = function(entry, running) { 651 | var block = Seeker.getCJKBlock(entry.unicode); 652 | var cls = (UI.blockClasses[block] || 'OTH'); 653 | 654 | var url = Config.url; 655 | url = url.replace("$CHR$", entry.char); 656 | url = url.replace("$ENC$", encodeURI(entry.char)); 657 | url = url.replace("$UCD$", entry.unicode.toString()); 658 | url = url.replace("$UCh$", entry.unicode.toString(16)); 659 | url = url.replace("$UCH$", entry.unicode.toString(16).toUpperCase()); 660 | 661 | if (entry.text) { 662 | return '' + entry.text + ''; 663 | } else { 664 | return UI.createTag(entry.char, 'a', cls, 'target="_blank" href="'+ url +'"', false, running); 665 | } 666 | }; 667 | 668 | // 顯示查詢結果 669 | UI.setResult = function(founds, i, force) { 670 | Seeker.result = founds; 671 | var msg = force ? '' : '(基本) '; 672 | msg += Seeker.groups ? '總共找到 ' + founds.length + ' 字' : '目前找到 ' + founds.length + ' 字... ' + Math.floor(i*100 / dt.length) + '%'; 673 | $('#counter').html(msg); 674 | UI.showOutput(); 675 | }; 676 | 677 | // 顯示查詢結果 (Output部分) 678 | UI.showOutput = function() { 679 | var s = '', first = true, gstr, blk, lastBlock; 680 | for (var j in Seeker.result) Seeker.result[j].gflag = false; 681 | 682 | var glist = $('#groups a.on'); 683 | $(glist.get().reverse()).each( function(i, gx) { 684 | var g = $(gx).data('char'); 685 | gstr = UI.createTag(g, 'h3', '', '', false); 686 | for (var j in Seeker.result) { 687 | if (Seeker.result[j].gflag) continue; 688 | for (var gi in Seeker.result[j].groups) { 689 | if (Seeker.result[j].groups[gi] == g) { 690 | gstr += UI.addCell(Seeker.result[j], Seeker.groups == null); 691 | Seeker.result[j].gflag = true; 692 | break; 693 | } 694 | } 695 | } 696 | s = gstr + '
\n' + s; 697 | }); 698 | 699 | for (var j in Seeker.result) { 700 | if (Seeker.result[j].gflag) continue; 701 | blk = Seeker.getCJKBlock(Seeker.result[j].unicode); 702 | if (blk != lastBlock && !first) s += '
'; 703 | lastBlock = blk; 704 | 705 | s += UI.addCell(Seeker.result[j], Seeker.groups == null); 706 | first = false; 707 | } 708 | $('#output').html(s); 709 | }; 710 | 711 | UI.onFinished = function(founds) { 712 | Seeker.result = founds; 713 | var groups = {}; 714 | for (var j in founds) { 715 | if (founds[j].groups) { 716 | //if (!founds[j].groups.length) continue; 717 | for (var gi in founds[j].groups) { 718 | var g = founds[j].groups[gi]; 719 | if (!groups[g]) groups[g] = 0; 720 | groups[g]++; 721 | } 722 | } 723 | } 724 | Seeker.groups = []; 725 | for (var g in groups) if (groups[g] >= 3) Seeker.groups.push({'char': g, 'unicode': g.codePointAt(0), 'count': groups[g]}); 726 | Seeker.groups.sort(function(a, b) { return b.count - a.count; }); 727 | UI.showOutput(); 728 | 729 | var str = '', g, blk; 730 | for (var i in Seeker.groups) { 731 | g = Seeker.groups[i]; 732 | str += UI.createTag(g.char, 'a', 'grp', 'href="javascript:void(0)" data-count="' + g.count + '"', true); 733 | } 734 | if (str != '') $('#groups').html(str).slideDown(); 735 | }; 736 | 737 | // 初始化 738 | UI.init = function() { 739 | // UI 740 | $('#version').html(Seeker.getVersion()); 741 | 742 | var cnt = 0; 743 | for (var i in dt) if (dt[i].substring(dt[i].length-1) != '╳') cnt++; 744 | $('#datasize').text(cnt); 745 | 746 | // Status 747 | $('#variant').prop('checked', UI.getCookie('variant', '1') == '1'); 748 | $('#subdivide').prop('checked', UI.getCookie('subdivide', '0') == '1'); 749 | $('#showkeypad').prop('checked', UI.getCookie('keypad', '0') == '1'); 750 | UI.addShortcut(); 751 | 752 | // Events 753 | UI.eventMoniter(); 754 | UI.updatePad(); 755 | }; 756 | 757 | window.onload = UI.init; 758 | -------------------------------------------------------------------------------- /source/corecode.js: -------------------------------------------------------------------------------- 1 | var Seeker = {dataIndex: null, seg: 1000, interval: 50, totalmsec: 0, segcnt: 0, worker: null}; 2 | var UI = {shortcuts: [], padType: null}; 3 | var _ = function(id) { return document.getElementById(id); } 4 | var $_ = _('input'); 5 | 6 | //////////////////////////////////////// Configurations //////////////////////////////////////// 7 | 8 | Seeker.getVersion = function() {return "0.9.3.0 (2021年01月)";}; 9 | Seeker.blockFlagMap = {'@': 0x0001, 'A': 0x0002, 'B': 0x0004, 'C': 0x0008, 'D': 0x0010, 'E': 0x0020, 'F': 0x0040, 'G': 0x0080, 'X': 0x2000, 'Y': 0x4000, 'Z': 0x8000}; 10 | Seeker.blockMap = {1: 0x0001, 2: 0x0002, 3: 0x0004, 4: 0x0008, 5: 0x0010, 6: 0x0020, 7: 0x0040, 8: 0x0080, 28: 0x2000, 29: 0x2000, 30: 0x4000}; 11 | //Seeker.blockMap = {1: 0x0001, 2: 0x0002, 3: 0x0004, 4: 0x0008, 5: 0x0010, 6: 0x0020, 7: 0x0040, 8: 0x0080, 27: 0x2000, 28: 0x2000, 29: 0x2000, 30: 0x4000, 31: 0x4000}; 12 | //Seeker.dataIndexMap = {1: -0x4DCF, 2: 0x1E2E, 3: -0x19412, 4: -0x19434, 5: -0x1943F, 6: -0x19441, 7: -0x1944F, 8: -0x1A86E, 27: 0x71DD, 28: 0x71DB, 29: -0x18B4B, 30: -0xD939D, 31: -0xDD1D4}; 13 | 14 | Seeker.parts = { 15 | '一':1,'丨':1,'丶':1,'丿':1,'乙':1,'亅':1,'乚':2,'㇄':3,'㇁':3,'㇂':3,'𠄌':3,'𠃊':3,'𠃋':3,'𡿨':3,'乛':3,'㇇':3,'𠃍':3,'㇏':3, 16 | '乀':3,'⺄':3,'𠃌':3,'㇆':3,'㇉':3,'𠃑':3,'㇊':3,'㇒':3,'㇣':3,'㇀':3,'二':1,'亠':1,'人':1,'儿':1,'入':1,'八':1,'冂':1,'冖':1, 17 | '冫':1,'几':1,'凵':1,'刀':1,'力':1,'勹':1,'匕':1,'匚':1,'匸':1,'十':1,'卜':1,'卩':1,'厂':1,'厶':1,'又':1,'亻':2,'𠆢':2,'丷':2, 18 | '刂':2,'⺈':2,'㔾':2,'讠':2,'𢎘':2,'𠂉':3,'〢':3,'𠂊':3,'𠂇':3,'㐅':3,'乂':3,'𠘧':3,'𠘨':3,'⺆':3,'丂':3,'𠀁':3,'龴':3,'𠂆':3, 19 | '𠄎':3,'㇋':3,'㇌':3,'⺀':3,'𠂈':3,'丩':3,'⺊':3,'丄':3,'丅':3,'丆':3,'𠃎':3,'𠄟':3,'𠄠':3,'𠄐':3,'𠃏':3,'乁':3,'𠙴':3,'七':4, 20 | '𠤎':4,'九':4,'口':1,'囗':1,'土':1,'士':1,'夂':1,'夊':1,'夕':1,'大':1,'女':1,'子':1,'宀':1,'寸':1,'小':1,'尢':1,'尸':1,'屮':1, 21 | '山':1,'巛':1,'工':1,'己':1,'巾':1,'干':1,'幺':1,'广':1,'廴':1,'廾':1,'弋':1,'弓':1,'彐':1,'彡':1,'彳':1,'川':2,'⺌':2,'𡭔':2, 22 | '䶹':2,'彑':2,'忄':2,'扌':2,'氵':2,'犭':2,'⺾':2,'阝':2,'⻖':2,'⻏':2,'⺕':2,'⻌':2,'丬':2,'纟':2,'飞':2,'饣':2,'䒑':3,'卄':3, 23 | '𭕄':3,'𠀆':3,'𠔼':3,'𠫓':3,'𣥂':3,'𡳾':3,'𠂎':3,'乇':3,'𫝀':3,'㐄':3,'𡕒':3,'乡':3,'𠚤':3,'习':3,'亼':3,'三':4,'丈':4,'也':4, 24 | '于':4,'上':4,'下':4,'兀':4,'丌':4,'卂':4,'亇':4,'万':4,'刄':4,'心':1,'戈':1,'戶':1,'手':1,'支':1,'攴':1,'文':1,'斗':1,'斤':1, 25 | '方':1,'无':1,'日':1,'曰':1,'月':1,'木':1,'欠':1,'止':1,'歹':1,'殳':1,'毋':1,'比':1,'毛':1,'氏':1,'气':1,'水':1,'火':1,'爪':1, 26 | '父':1,'爻':1,'爿':1,'片':1,'牙':1,'牛':1,'犬':1,'⺗':2,'攵':2,'朩':2,'毌':2,'灬':2,'爫':2,'爫':2,'牜':2,'𠂒':2,'尣':2,'⺩':2, 27 | '礻':2,'龰':2,'罓':2,'冈':2,'㓁':2,'⺼':2,'艹':2,'辶':2,'⻍':2,'耂':2,'⺳':3,'𦉪':3,'𠔿':3,'⺝':3,'艹':3,'卝':3,'龷':3,'廿':3, 28 | '丰':3,'丯':3,'𧘇':3,'𣎳':3,'𥘅':3,'龶':3,'⺜':3,'厃':3,'𠃜':3,'肀':3,'旡':3,'冘':3,'夬':3,'兂':3,'龵':3,'𦉫':3,'𠬝':3,'㸦':3, 29 | '𤓰':3,'𠃛':3,'夨':3,'仌':3,'王':4,'五':4,'六':4,'卅':4,'不':4,'丐':4,'及':4,'丑':4,'丹':4,'刅':4,'井':4,'开':4,'𠬛':4,'尺':4, 30 | '巨':4,'巴':4,'𣎴':4,'冃':4,'冄':4,'𠬞':4,'𠬜':4,'丮':4,'巿':4,'𠃚':4,'玄':1,'玉':1,'瓜':1,'瓦':1,'甘':1,'生':1,'用':1,'田':1, 31 | '疋':1,'疒':1,'癶':1,'白':1,'皮':1,'皿':1,'目':1,'矛':1,'矢':1,'石':1,'示':1,'禸':1,'禾':1,'穴':1,'立':1,'𤴓':2,'𤴔':2,'罒':2, 32 | '𦉰':2,'歺':2,'母':2,'氺':2,'衤':2,'⺬':2,'钅':2,'𢆉':3,'𦍍':3,'业':3,'𠀎':3,'㠯':3,'𠕁':3,'𡗗':3,'圥':3,'𠮠':3,'犮':3,'𢎨':3, 33 | '𦘒':3,'⺻':3,'龸':3,'𣦵':3,'丱':3,'𤕫':3,'𥝌':3,'𦫳':3,'𣎵':3,'屵':3,'𫇦':3,'四':4,'卌':4,'夗':4,'㐱':4,'乍':4,'乎':4,'冉':4, 34 | '册':4,'史':4,'央':4,'戉':4,'戊':4,'冋':4,'本':4,'民':4,'永':4,'北':4,'竹':1,'米':1,'糸':1,'缶':1,'网':1,'羊':1,'羽':1,'老':1, 35 | '而':1,'耒':1,'耳':1,'聿':1,'肉':1,'臣':1,'自':1,'至':1,'臼':1,'舌':1,'舛':1,'舟':1,'艮':1,'色':1,'艸':1,'虍':1,'虫':1,'血':1, 36 | '行':1,'衣':1,'襾':1,'𥫗':2,'糹':2,'𦍌':2,'⺶':2,'西':2,'覀':2,'齐':2,'冎':3,'龹':3,'𠂤':3,'𧰨':3,'乑':3,'𢦏':3,'产':3,'巩':3, 37 | '𦈢':3,'𠂭':3,'𠂢':3,'𠦃':3,'䇂':3,'㐆':3,'甶':3,'囟':3,'幵':3,'厽':3,'𠃨':3,'𠬪':3,'朿':4,'亙':4,'兆':4,'州':4,'年':4,'曲':4, 38 | '曳':4,'朱':4,'关':4,'見':1,'角':1,'言':1,'谷':1,'豆':1,'豕':1,'豸':1,'貝':1,'赤':1,'走':1,'足':1,'身':1,'車':1,'辛':1,'辰':1, 39 | '辵':1,'邑':1,'酉':1,'釆':1,'里':1,'訁':2,'𧮫':2,'𧾷':2,'𦥑':2,'镸':2,'⺸':3,'𦍋':3,'夋':3,'𦉶':3,'㒳':3,'㐬':3,'𠦒':3,'𦣞':3, 40 | '𦣝':3,'丣':3,'戼':3,'𠃬':3,'㕯':3,'㫃':3,'囧':3,'𦣻':3,'囱':3,'囪':3,'㡀':3,'严':3,'𠦑':3,'㳄':3,'我':4,'巠':4,'甹':4,'皀':4, 41 | '夆':4,'亜':4,'来':4,'金':1,'長':1,'門':1,'阜':1,'隶':1,'隹':1,'雨':1,'青':1,'非':1,'釒':2,'⻗':2,'靑':2,'飠':2,'叀':3,'亝':3, 42 | '𣏟':3,'㣇':3,'甾':3,'幷':3,'𨸏':3,'𣶒':3,'罙':4,'忝':4,'匋':4,'奄':4,'東':4,'疌':4,'黾':4,'靣':4,'面':1,'革':1,'韋':1,'韭':1, 43 | '音':1,'頁':1,'風':1,'飛':1,'食':1,'首':1,'香':1,'𩙿':2,'叚':3,'壴':3,'复':3,'亲':3,'枼':3,'昜':3,'亯':3,'𡿺':3,'𠧪':3,'県':3, 44 | '𥄉':3,'㲋':3,'𢑚':3,'㢴':3,'𢏚':3,'咢':4,'奐':4,'禺':4,'南':4,'馬':1,'骨':1,'高':1,'髟':1,'鬥':1,'鬯':1,'鬲':1,'鬼':1,'𤇾':3, 45 | '丵':3,'𠂹':3,'𣆪':3,'𩠐':3,'𡸁':3,'隺':4,'尃':4,'𧴪':4,'𥁕':4,'臽':4,'䍃':4,'芻':4,'皋':4,'魚':1,'鳥':1,'鹵':1,'鹿':1,'麥':1, 46 | '麻':1,'㒼':3,'𦰩':3,'𠦬':3,'𠁁':3,'桼':4,'啇':4,'袞':4,'翏':4,'啚':4,'悤':4,'粛':4,'黃':1,'黍':1,'黑':1,'黹':1,'菐':4,'巽':4, 47 | '粦':4,'尌':4,'朁':4,'尞':4,'厤':4,'肅':4,'𤔔':3,'𠥓':3,'黽':1,'鼎':1,'鼓':1,'鼠':1,'𦥯':3,'𦝠':3,'𢊁':3,'廌':3,'𠌶':3,'亶':4, 48 | '嗇':4,'睘':4,'鼻':1,'齊':1,'𨛜':3,'㥯':4,'熏':4,'齒':1,'嘼':3,'廛':4,'巤':4,'龍':1,'龜':1,'龠':1,'𩫖':3,'毚':4,'韱':4, 49 | '㇈':3,'󰎀':3,'󰋌':3,'󰊅':3,'󰊸':3,'󰕐':3,'𰀪':3,'巜':2,'󰓶':3,'󰒖':3,'󰓏':3,'󰒑':3,'󰋚':3,'󰓐':3,'󰒾':3,'𰃮':3,'龻':3, 50 | '󰓗':3,'󶃛':3,'󰒭':3,'󰒂':3,'󰒦':3,'󰊥':3,'󰊶':3,'󰓴':3,'󶏔':3,'󰑖':3,'󰑹':3,'󰑷':3,'㦰':3,'甲':4,'丙':4,'丁':4,'庚':4, 51 | '壬':4,'癸':4,'寅':4,'卯':4,'巳':4,'午':4,'未':4,'申':4,'戌':4,'亥':4,'󰑬':3,'󰐻':3,'丘':4,'𫶧':3,'󰑉':3,'虎':4, 52 | '󰒬':3,'󰊎':3,'󰐸':3,'󰐧':3,'󰐷':3,'刃':4,'𭤨':3,'𰀄':3,'吅':3,'从':3,'󰒊':3,'中':4,'󰑲':3,'󰩮':3,'𰀁':3,'𠂔':3,'𪩲':3,'亞':4 53 | }; 54 | 55 | UI.strokeKeyboard = { 56 | vertical: true, 57 | className: 'strokeKB', 58 | groups: { 59 | '01畫': '一丨丶丿乙亅乚㇄㇁㇂𠄌𠃊𠃋𡿨乛㇇𠃍㇏乀⺄𠃌㇆㇉𠃑㇊㇒㇣㇀', 60 | '02畫': '二亠人儿入八冂冖冫几凵刀力勹匕匚匸十卜卩厂厶又亻𠆢丷刂⺈㔾讠𢎘𠂉〢𠂊𠂇㐅乂𠘧𠘨⺆丂𠀁龴𠂆𠄎㇋㇌⺀𠂈丩⺊丄丅丆𠃎𠄟𠄠𠄐𠃏乁𠙴七𠤎九', 61 | '03畫': '口囗土士夂夊夕大女子宀寸小尢尸屮山巛工己巾干幺广廴廾弋弓彐彡彳川⺌𡭔䶹彑忄扌氵犭⺾阝⻖⻏⺕⻌丬纟飞饣䒑卄𭕄𠀆𠔼𠫓𣥂𡳾𠂎乇𫝀㐄𡕒乡𠚤习亼三丈也于上下兀丌卂亇万刄', 62 | '04畫': '心戈戶手支攴文斗斤方无日曰月木欠止歹殳毋比毛氏气水火爪父爻爿片牙牛犬⺗攵朩毌灬爫爫牜𠂒尣⺩礻龰罓冈㓁⺼艹辶⻍耂⺳𦉪𠔿⺝艹卝龷廿丰丯𧘇𣎳𥘅龶⺜厃𠃜肀旡冘夬兂龵𦉫𠬝㸦𤓰𠃛夨仌王五六卅不丐及丑丹刅井开𠬛尺巨巴𣎴冃冄𠬞𠬜丮巿𠃚', 63 | '05畫': '玄玉瓜瓦甘生用田疋疒癶白皮皿目矛矢石示禸禾穴立𤴓𤴔罒𦉰歺母氺衤⺬钅𢆉𦍍业𠀎㠯𠕁𡗗圥𠮠犮𢎨𦘒⺻龸𣦵丱𤕫𥝌𦫳𣎵屵𫇦四卌夗㐱乍乎冉册史央戉戊冋本民永北', 64 | '06畫': '竹米糸缶网羊羽老而耒耳聿肉臣自至臼舌舛舟艮色艸虍虫血行衣襾𥫗糹𦍌⺶西覀齐冎龹𠂤𧰨乑𢦏产巩𦈢𠂭𠂢𠦃䇂㐆甶囟幵厽𠃨𠬪朿亙兆州年曲曳朱关', 65 | '07畫': '見角言谷豆豕豸貝赤走足身車辛辰辵邑酉釆里訁𧮫𧾷𦥑镸⺸𦍋夋𦉶㒳㐬𠦒𦣞𦣝丣戼𠃬㕯㫃囧𦣻囱囪㡀严𠦑㳄我巠甹皀夆亜来', 66 | '08畫': '金長門阜隶隹雨青非釒⻗靑飠叀亝𣏟㣇甾幷𨸏𣶒罙忝匋奄東疌黾靣', 67 | '09畫': '面革韋韭音頁風飛食首香𩙿叚壴复亲枼昜亯𡿺𠧪県𥄉㲋𢑚㢴𢏚咢奐禺南', 68 | '其它': { 69 | '10畫': '馬骨高髟鬥鬯鬲鬼𤇾丵𠂹𣆪𩠐𡸁隺尃𧴪𥁕臽䍃芻皋', 70 | '11畫': '魚鳥鹵鹿麥麻㒼𦰩𠦬𠁁桼啇袞翏啚悤粛', 71 | '12畫': '黃黍黑黹菐巽粦尌朁尞厤肅𤔔𠥓', 72 | '13畫': '黽鼎鼓鼠𦥯𦝠𢊁廌𠌶亶嗇睘', 73 | '14畫': '鼻齊𨛜㥯熏', 74 | '15畫': '齒嘼廛巤', 75 | '16畫': '龍龜', 76 | '17畫': '龠𩫖毚韱' 77 | } 78 | } 79 | }; 80 | 81 | UI.categoryKeyboard = { 82 | vertical: false, 83 | className: 'categoryKB', 84 | groups: { 85 | '筆畫': '一丨丶,㇒丿㇀,㇈亅乚,㇄㇁㇂,𠄌𠃊𠃋,𠃎𠃍󰎀,𡿨乛㇇,㇏乀⺄,𠃌㇆󰋌,㇉𠃑㇊,㇣㐅乂,󰊅󰊸󰕐,𰀪⺀巜', 86 | '字頭': '艹⺾艹䒑𥫗,⺈𠆢𠂉󰓶亠,⺌𭕄爫爫,𠂆厂广疒𤕫,厃产󰒖屵严,尸𠃜󰓏耂𠫓,罒㓁罓龷,覀⺜龶⺻,冖⺳宀龸󰒑,𤇾𫇦󰋚󰓐󰒾,癶龹𡗗,⻗𦥯𰃮龻󰓗,𠂒虍󶃛󰒭𦍌', 87 | '包圍': '冂⺆,󰒂𠘨,凵𠙴,匚𠥓,匸󰒦,勹𦉶,󰊥󰊶,󰓴󶏔,󰑖󰑹,𢦏󰑷,㦰𦝠,囗', 88 | '計數': '甲乙丙丁,戊己庚辛,壬癸,子丑寅卯,辰巳午未,申酉戌亥,一二三四,五六七丷,八九十廿,卄卅卌𠦃,万寸尺丈', 89 | '自然': '日月,󰑬,風气,雨夕,金钅,釒,木朩,水氵,氺󰐻,火灬,土石,冫仌', 90 | '地理': '山业,丘巛,川𫶧,穴谷,𣶒󰑉,州,皋𠂤,阜⻖,𨸏阝,邑⻏', 91 | '動物': '鼠牛牜虎,毚㲋龍巴,虫馬羊⺶,⺸𦍋𦫳犭,犬犮豕𧰨,豸鹿𢊁廌,魚鳥隹嘼,黽黾龜貝,彐彑㣇,角羽毛巤,爪󰒬釆禸,习卂飞飛,隺󰊎', 92 | '植物': '艸屮韭,竹禾𥝌,米𠂭麥,麻黍桼,豆瓜𤓰,朿𣎵本,𣎳𣏟支,丰󰐸丯,𢎘,𠧪𠂹丵', 93 | '人體': '首頁𦣻𡿺囟,髟丱卝㐱彡,冉冄而口亼,舌牙㸦齒𧮫,𦣞𦣝目耳,鼻自面靣身,心忄⺗血骨,肉⺼⺝󰐧皮,手扌龵𠂇䶹,又⺕󰐷,𦥑廾𠬞𠬜,足𧾷疋𤴔止,龰丮𠃨', 94 | '食飲': '食,飠,𩙿,饣,丣,鹵,鬯,甘,香,皀', 95 | '衣飾': '衣𧘇,衤冃,巾巿,糸纟,糹黹,革韋,玉⺩,文', 96 | '住居': '門,戶,囱,囪,几,囧,瓦,井,爿,丬,田,里', 97 | '行旅': '行走,辵辶,⻌⻍,廴夂,𫝀夊,𡕒㐄,彳𣥂,𤴓,舟車,立至,入隶,冘', 98 | '書樂': '聿,𦘒,肀,册,𠕁,史,鼓,龠,音', 99 | '祭祀': '卜,⺊,爻,兆,示,⺬,礻,𥘅,鬼,甶,亯,用,夬', 100 | '器物': '皿甾,缶𦈢,网𦉰,冈𠔿,𦉫𦉪,匕𠁁,斗臼,鬲鼎,丌耒', 101 | '軍事': '刀刂,力刄,刃刅,斤弋,矢弓,矛干,戈戉,殳𠘧,卩㔾,攴攵,㫃𭤨,鬥', 102 | '人稱': '人亻,𠂊乑,厶我,父母,儿女,𠦑士,王臣,氏民', 103 | '生命': '生,老,歹,歺,𣦵,𰀄,𠤎,尢,尣,䇂', 104 | '顏色': '青,靑,白,朱,赤,黑,玄,黃,色', 105 | '動作': '言讠,訁曰,吅从,㕯工,見艮,欠夨,襾󰒊,𡳾𠂈', 106 | '雜類': '上丄下丅長镸,大中小𡭔高𩫖,丆乁幺乡㇋𠄎,丂𠀁龴𠚤󰑲〢,𠔼冋冎㒳㡀㒼,兀无旡兂圥󰩮,方𠮠片𰀁𢆉𦍍,毋毌齊齐叚,㠯比𠃏丩𠂎乇,舛夗非开幵幷,𠂔𪩲巨亞亜戼,東西南北叀𠦒,𢑚𠃬𢏚㢴' 107 | } 108 | }; 109 | 110 | //////////////////////////////////////// JavaScript Prototypes //////////////////////////////////////// 111 | 112 | 113 | if (!Array.prototype.indexOf) { 114 | Array.prototype.indexOf = function (o, f) { 115 | var l = this.length; 116 | if (f == null) f = 0; 117 | if (f < 0) f = Math.max(0, l + f); 118 | for (var i = f; i < l; i++) { 119 | if (this[i] === o) return i; 120 | } 121 | return -1; 122 | }; 123 | } 124 | 125 | if (!String.prototype.codePointAt) { 126 | String.prototype.codePointAt = function(i) { 127 | var c = this.charCodeAt(i); 128 | if (c >= 0xD800 && c <= 0xDBFF) return (((c & 0x03FF) << 10) | (this.charCodeAt(i+1) & 0x03FF)) + 0x10000; 129 | return c; 130 | }; 131 | } 132 | 133 | String.prototype.charPointAt = function(i) { 134 | var c = this.charCodeAt(i); 135 | if (c >= 0xD800 && c <= 0xDBFF) return this.charAt(i) + this.charAt(i+1); 136 | if (c >= 0xDC00 && c <= 0xDFFF) return this.charAt(i-1) + this.charAt(i); 137 | return this.charAt(i); 138 | }; 139 | 140 | //////////////////////////////////////// Core Logic //////////////////////////////////////// 141 | 142 | Seeker.variant = function(w, v) { 143 | return v && vt[w] ? vt[w] : w; 144 | }; 145 | 146 | Seeker.arraylize = function(s, v, a) { 147 | var blockFlag = 0; 148 | for (var i = 0; i < s.length; i++) { 149 | var w = s.charPointAt(i); 150 | if (w.length > 1) i++; 151 | if (Seeker.blockFlagMap[w]) { 152 | blockFlag |= Seeker.blockFlagMap[w]; 153 | } else { 154 | if (w.length == 1) { 155 | var c = w.charCodeAt(0); 156 | if (c >= 0x2FF0 && c <= 0x2FFB) break; // CJK description 157 | } 158 | a.push(Seeker.variant(w, v)); 159 | } 160 | } 161 | if (blockFlag == 0) blockFlag = 0xFFFF; 162 | return blockFlag; 163 | }; 164 | 165 | Seeker.getCJKBlock = function(c) { 166 | if (c >= 0x4E00 && c <= 0x9FFC ) return 1; 167 | if (c >= 0x3400 && c <= 0x4DBF ) return 2; 168 | if (c >= 0x20000 && c <= 0x2A6DD) return 3; 169 | if (c >= 0x2A700 && c <= 0x2B734) return 4; 170 | if (c >= 0x2B740 && c <= 0x2B81D) return 5; 171 | if (c >= 0x2B820 && c <= 0x2CEA1) return 6; 172 | if (c >= 0x2CEB0 && c <= 0x2EBE0) return 7; 173 | if (c >= 0x30000 && c <= 0x3134A) return 8; 174 | if (c >= 0xF900 && c <= 0xFAD9 ) return 28; 175 | //if (c >= 0xFA70 && c <= 0xFAD9 ) return 28; 176 | if (c >= 0x2F800 && c <= 0x2FA1D) return 29; 177 | if (c >= 0xF0270 && c <= 0xFAE7A) return 30; 178 | //if (c >= 0xF5000 && c <= 0xFAE7A) return 31; 179 | return 0; 180 | }; 181 | 182 | // Seeker.getDataIndex = function(c) { 183 | // var n = Seeker.getCJKBlock(c); 184 | // if (Seeker.dataIndexMap[n]) { 185 | // return c + Seeker.dataIndexMap[n]; 186 | // } else if (n >= 30) { 187 | // for (var i = 0x16C63; i < dt.length; i++) { 188 | // if (c == dt[i].charPointAt(0)) break; 189 | // } 190 | // return i; 191 | // } else { 192 | // for (var i = 48; i > 0; i--) { 193 | // if (c == dt[i].charCodeAt(0)) break; 194 | // } 195 | // return i; 196 | // }//0x16C63 197 | // }; 198 | 199 | //Seeker.dataIndex = null; 200 | Seeker.getData = function(c, w) { 201 | if (Seeker.dataIndex == null) { 202 | Seeker.dataIndex = {}; 203 | for (var i in dt) { 204 | Seeker.dataIndex[dt[i].codePointAt(0)] = dt[i].substring(w.length); 205 | } 206 | } 207 | return Seeker.dataIndex[c]; 208 | }; 209 | 210 | // 檢索遞迴運算 211 | Seeker.eliminate = function(a, s, d, v) { 212 | // a: 搜尋字串的陣列(已排序) 213 | // s: 正要媒合的樹枝 214 | // d: 無理拆分 215 | // v: 包容異體 216 | var f = a.length == 1 && a[0] == "#"; // 獨體字模式 217 | if (s == "@") { // 如果此字已無法再分解 218 | if (f) a.length = 0; // 清空陣列 (=命中獨體字) 219 | return 1; 220 | } 221 | var n = 0; // n: 命中狀態 0=精確命中 >0=模糊命中 <0=漢字解構 222 | var k = 0; // k: 223 | var b = a.concat(); // b: 備份搜尋陣列a 224 | //console.log(' -> ' + s); 225 | for (var i = 0; i < s.length; i++) { // 針對拆分序列中的每個字 226 | var w = s.charPointAt(i); 227 | if (w.length > 1) i++; 228 | 229 | if (w == "!" && !d) { // 若此字是無理拆分且非無理拆分模式 230 | if (f) a.length = 0; // 清空陣列 (=命中獨體字) 231 | return 1; 232 | } 233 | 234 | if (w == "@" || w == "!") { // 某種拆分方式的起始 235 | if (k) { 236 | if (!a.length || !n) break; 237 | a.length = 0; // 從備份重建搜尋陣列 238 | for (var j = 0; j < b.length; j++) a.push(b[j]); 239 | n = 0; 240 | } 241 | k++; 242 | } else { 243 | if (!f && a.length) { // 非獨體字模式 搜尋陣列還有值 244 | var c = w.codePointAt(0); 245 | var m = a.indexOf(Seeker.variant(w, v)); // 在搜尋陣列中尋找這個字的位置 246 | if (m < 0) { // 找不到的話,把拆分字串再拆開遞迴一層 247 | n += Seeker.getData(c, w) ? Seeker.eliminate(a, Seeker.getData(c, w), d, v) : 1; 248 | } else { 249 | a.splice(m, 1); // 找到了:從搜尋陣列刪除這個字 250 | } 251 | } else { // 拆分字串裡還有剩餘的文字 (非精準拆分) 252 | n++; 253 | } 254 | } 255 | } 256 | return n; 257 | }; 258 | 259 | Seeker.stopMatch = function() { 260 | clearTimeout(Seeker.worker); 261 | }; 262 | 263 | // setTimeout 分割版本 264 | Seeker.getMatch = function(s, v, d, m, h, z, r) { 265 | // string, varient?, divide?, max, href 266 | clearTimeout(Seeker.worker); 267 | var x = []; 268 | var blockFlag = Seeker.arraylize(s, v, x); 269 | x.sort(); 270 | s = x.join(''); 271 | var i = 0; 272 | var a = []; 273 | //for (var ii = 1; ii < dt.length; ii++) { 274 | var work = function(j) { 275 | if (a.length >= m+1) return; 276 | //console.log(s, j); 277 | if (j+Seeker.seg < dt.length) Seeker.worker = setTimeout(function() { work(j+Seeker.seg); }, Seeker.segcnt > 10 ? Math.floor(Seeker.totalmsec/Seeker.segcnt+5) : Seeker.interval); 278 | //console.log(Seeker.segcnt > 10 ? Seeker.totalmsec/Seeker.segcnt+5 : Seeker.interval); 279 | var st = new Date(); 280 | var t = 0; 281 | for (var i = j; i < j + Seeker.seg && i < dt.length; i++) { 282 | //var i = (ii < dt.length - 48) ? (ii + 48) : (ii - dt.length + 49); 283 | var y = x.concat(); // 複製陣列 (因為eliminate函式內會直接操作,故用concat的副作用進行複製) 284 | var w = dt[i].charPointAt(0); // 目前測試的字 285 | var c = w.codePointAt(0); 286 | 287 | if (blockFlag) { // 篩選要包含的Unicode分區 288 | var f = Seeker.blockMap[Seeker.getCJKBlock(c)] || 0x8000; 289 | if (!(blockFlag & f)) continue; 290 | } 291 | 292 | var n = 0; // 命中狀態 293 | if (Seeker.variant(w, v) != s) { 294 | //console.log('> ' + w); 295 | n = Seeker.eliminate(y, dt[i].slice(w.length), d, v); 296 | if (y.length) continue; // 沒命中 297 | } 298 | 299 | var l = h; 300 | l = l.replace("$CHR$", w); 301 | l = l.replace("$ENC$", encodeURI(w)); 302 | l = l.replace("$UCD$", c.toString()); 303 | l = l.replace("$UCh$", c.toString(16)); 304 | l = l.replace("$UCH$", c.toString(16).toUpperCase()); 305 | 306 | var p = z(w, c, n, l); 307 | if (p && (!n || (a.length <= m))) a.push(p); 308 | if (a.length >= m+1) break; // 新增超過m+1時break掉,雖然可能因此喪失精確命中結果,但可以明顯加速運算 309 | } 310 | r(a, i, m); 311 | Seeker.totalmsec += new Date()-st; 312 | Seeker.segcnt++; 313 | }; 314 | Seeker.worker = setTimeout(function() { work(0); }, 10); 315 | //} 316 | //return a; 317 | }; 318 | 319 | // Seeker.getMatch = function(s, v, d, m, h, z) { 320 | // // string, varient?, divide?, max, href 321 | // var x = []; 322 | // var blockFlag = Seeker.arraylize(s, v, x); 323 | // x.sort(); 324 | // s = x.join(''); 325 | // var bak = $_.value; 326 | // var a = []; 327 | // for (var ii = 1; ii < dt.length; ii++) { 328 | // if (bak != $_.value) { 329 | // console.log('interupted at ' + ii); 330 | // break; 331 | // } 332 | 333 | // var i = (ii < dt.length - 48) ? (ii + 48) : (ii - dt.length + 49); 334 | // var y = x.concat(); // 複製陣列 (因為eliminate函式內會直接操作,故用concat的副作用進行複製) 335 | // var w = dt[i].charPointAt(0); // 目前測試的字 336 | // var c = w.codePointAt(0); 337 | 338 | // if (blockFlag) { // 篩選要包含的Unicode分區 339 | // var f = Seeker.blockMap[Seeker.getCJKBlock(c)] || 0x8000; 340 | // if (!(blockFlag & f)) continue; 341 | // } 342 | 343 | // var n = 0; // 命中狀態 344 | // if (Seeker.variant(w, v) != s) { 345 | // //console.log('> ' + w); 346 | // n = Seeker.eliminate(y, dt[i].slice(w.length), d, v); 347 | // if (y.length) continue; // 沒命中 348 | // } 349 | 350 | // h = h.replace("$CHR$", w); 351 | // h = h.replace("$ENC$", encodeURI(w)); 352 | // h = h.replace("$UCD$", c.toString()); 353 | // h = h.replace("$UCh$", c.toString(16)); 354 | // h = h.replace("$UCH$", c.toString(16).toUpperCase()); 355 | 356 | // var p = z(w, c, n, h); 357 | // if (p && (!n || (a.length <= m))) a.push(p); 358 | // if (a.length >= m+1) break; // 新增超過m+1時break掉,雖然可能因此喪失精確命中結果,但可以明顯加速運算 359 | // } 360 | // return a; 361 | // }; 362 | 363 | // 拆分 364 | Seeker.exhaust = function(s, d, m) { 365 | var t = ''; 366 | if (s.length) { 367 | var w = s.charPointAt(0); 368 | var c = w.codePointAt(0); 369 | //var p = dt[Seeker.getDataIndex(c)].slice(w.length); 370 | var p = Seeker.getData(c, w).substring(w.length); 371 | var k = 0; 372 | for (var i = 0; i < p.length; i++) { 373 | w = p.charPointAt(i); 374 | if (w.length > 1) i++; 375 | if ((w == "!") && !d) break; 376 | if ((w == "@") || (w == "!")) { 377 | if (k) t += (m < 0) ? "┇" : "‖"; 378 | k++; 379 | } else { 380 | t += w; 381 | if (m) { 382 | var q = Seeker.exhaust(w, d, -1); 383 | if (q.length) t += "(" + q + ")"; 384 | } 385 | } 386 | } 387 | } 388 | return t; 389 | }; 390 | 391 | // 解構模式 (\) 392 | Seeker.getTree = function(s, d, z) { 393 | var a = []; 394 | if (s.length) { 395 | var w = s.charPointAt(0); 396 | var c = w.codePointAt(0); 397 | var m = 0; 398 | var n = -1; 399 | var p = Seeker.exhaust(w, d, 1); 400 | 401 | do { 402 | n = p.indexOf("‖", m); 403 | var t = p.slice(m, (n < 0 ? p.length : n)); 404 | t = z(w, c, -1, '', t.length ? t : "(不再分解)"); 405 | if (t) a.push(t); m = n + 1; 406 | } while (n >= 0); 407 | } 408 | return a; 409 | } 410 | 411 | //////////////////////////////////////// User Interface //////////////////////////////////////// 412 | 413 | UI.blockClasses = {1: 'BSC', 2: 'ExA', 3: 'ExB', 4: 'ExC', 5: 'ExD', 6: 'ExE', 7: 'ExF', 8: 'ExG', 27: 'CMP', 28: 'CMP', 29: 'CMP', 30: 'SUP', 31: 'SUP'}; 414 | 415 | UI.isMobile = function() { 416 | return navigator.userAgent =~ /Android|iOS/i; 417 | }; 418 | 419 | UI.initKeyboard = function(kbType) { 420 | var html = ''; 421 | if (!kbType.vertical) { 422 | html += ''; 423 | for (var g in kbType.groups) html += ''; 424 | html += ''; 425 | } 426 | for (var g in kbType.groups) { 427 | if (kbType.vertical) html += ''; 428 | html += ''; 451 | if (kbType.vertical) html += ''; 452 | } 453 | html += '
' + g + '
' + g + ''; 429 | if (typeof kbType.groups[g] == 'string') { 430 | for (var i=0; i < kbType.groups[g].length; i++) { 431 | var w = kbType.groups[g].charPointAt(i); 432 | if (w.length > 1) i++; 433 | if (w == ',') { html += '
'; continue; } 434 | var z = Seeker.parts[w]; 435 | if (z) html += ''; 436 | } 437 | } else { 438 | for (var gg in kbType.groups[g]) { 439 | html += '' + gg + ''; 440 | for (var i=0; i 1) i++; 443 | if (w == ',') { html += '
'; continue; } 444 | var z = Seeker.parts[w]; 445 | if (z) html += ''; 446 | } 447 | html += '
'; 448 | } 449 | } 450 | html += '
'; 454 | _('keypad').innerHTML = html; 455 | }; 456 | 457 | // 寫入剪貼簿 458 | UI.setClipboard = function(s) { 459 | s = decodeURI(s); 460 | if (window.clipboardData) { 461 | window.clipboardData.clearData(); 462 | window.clipboardData.setData('Text', s); 463 | } else { 464 | var t = document.createElement('textarea'); 465 | t.textContent = s; 466 | document.body.appendChild(t); 467 | t.select(); 468 | document.execCommand('copy'); 469 | document.body.removeChild(t); 470 | } 471 | }; 472 | 473 | // 設定 Cookie 474 | UI.setCookie = function(n, v) { 475 | if (window.localStorage) window.localStorage.setItem(n, v); 476 | else document.cookie = n +"="+ v +"; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/"; 477 | return v; 478 | }; 479 | 480 | // 讀取 Cookie 481 | UI.getCookie = function(n, v) { 482 | var s = null; 483 | if (window.localStorage) { 484 | s = window.localStorage.getItem(n); 485 | } else { 486 | var a = document.cookie.replace(/\s/g, '').split(';'); 487 | for (var i in a) { 488 | if (a[i].indexOf(n + '=') == 0) { 489 | s = a[i].substring(n.length+1); 490 | break; 491 | } 492 | } 493 | } 494 | if (!s) return UI.setCookie(n, v); 495 | return s; 496 | }; 497 | 498 | // 取得游標位置 499 | UI.getPos = function() { 500 | $_.focus(); 501 | return $_.selectionStart; 502 | }; 503 | 504 | // 設定游標位置 505 | UI.setPos = function(n) { $_.setSelectionRange(n, n); }; 506 | 507 | // 取得選擇文字 508 | UI.getSel = function() { return $_.value.substring($_.selectionStart, $_.selectionEnd); }; 509 | 510 | // 清除選擇文字 511 | UI.delSel = function() { 512 | var m = $_.selectionStart; 513 | var n = $_.selectionEnd; 514 | if (m != n) { 515 | $_.value = $_.value.substring(0, m) + $_.value.substring(n); 516 | $_.setSelectionRange(m, m); 517 | } 518 | }; 519 | 520 | UI.key = function(w) { 521 | UI.delSel(); 522 | var n = UI.getPos(); 523 | var s = $_.value; 524 | $_.value = s.slice(0, n) + w + s.slice(n); 525 | UI.setPos(w.length > 1 ? n+2: n+1); 526 | UI.go(); 527 | }; 528 | 529 | // 清除檢索 530 | UI.clearFind = function() { 531 | $_.value = ''; 532 | $_.focus(); 533 | UI.go(true); 534 | }; 535 | 536 | // 倒退清除 537 | UI.backspace = function() { 538 | var n = UI.getPos(); 539 | if (n > 0) { 540 | var s = $_.value; 541 | var c = s.codePointAt(n-2); 542 | var m = c >= 0x10000 ? n-2 : n-1; 543 | $_.value = s.slice(0, m) + s.slice(n); 544 | UI.setPos(m); 545 | UI.go(); 546 | } 547 | }; 548 | 549 | // 解構漢字 550 | UI.decompose = function() { 551 | var n = UI.getPos(); 552 | if (n > 0) { 553 | var s = $_.value; 554 | var m = n-1; 555 | var w = s.charPointAt(m); 556 | if (w.length > 1) m--; 557 | 558 | var d = _('subdivide').checked; 559 | var t = Seeker.exhaust(w, d, 0); 560 | if (t.length) { 561 | $_.value = s.slice(0, m) + t + s.slice(n); 562 | UI.setPos(m+t.length); 563 | UI.go(); 564 | } 565 | } 566 | }; 567 | 568 | // 部件檢索 569 | UI.go = function(force) { 570 | if (UI.ime) return; 571 | $_.focus(); 572 | if (!force && !_('onthefly').checked) return; 573 | UI.hidePop(true); 574 | var s = UI.getSel() || $_.value; 575 | if (!s) { 576 | Seeker.stopMatch(); 577 | _('counter').innerHTML = ''; 578 | _('output').innerHTML = ''; 579 | } else { 580 | var d = _('subdivide').checked; 581 | //var l = []; 582 | if (s.charAt(0) == '\\') { 583 | _('output').innerHTML = Seeker.getTree(s.slice(1), d, Config.addCell); 584 | } else { 585 | var h = 'href="'+ Config.url +'"'; 586 | var m = force ? Config.resultStep2 : Config.resultStep1; 587 | var l = Seeker.getMatch(s, _('variant').checked, d, m, h, Config.addCell, Config.setResult); 588 | } 589 | } 590 | }; 591 | 592 | // 更新勾選框Cookie 593 | UI.setMode = function(chk, key) { 594 | UI.setCookie(key, chk.checked ? '1' : '0'); 595 | UI.go(); 596 | }; 597 | 598 | // 鍵盤開關改變 599 | //UI.padType = null; 600 | UI.updatePad = function(init) { 601 | if (UI.padType === null) { 602 | UI.padType = UI.getCookie('keypad', UI.isMobile() ? false : 'stroke'); 603 | } else if (UI.padType == 'categoty') { 604 | UI.padType = UI.setCookie('keypad', false); 605 | } else if (UI.padType) { 606 | UI.padType = UI.setCookie('keypad', 'categoty'); 607 | } else if (!UI.padType) { 608 | UI.padType = UI.setCookie('keypad', 'stroke'); 609 | } 610 | if (UI.padType == 'stroke') UI.initKeyboard(UI.strokeKeyboard); 611 | if (UI.padType == 'categoty') UI.initKeyboard(UI.categoryKeyboard); 612 | _('keypad').style.display = UI.padType ? 'block' : 'none'; 613 | _('filters').style.display = UI.padType ? "" : 'none'; 614 | UI.updateFilter(true); 615 | $_.focus(); 616 | }; 617 | 618 | // 分組開關改變 619 | UI.updateFilter = function(init) { 620 | var f = document.getElementsByName('filter'); 621 | if (!init) { 622 | for (var i=0; i= 20) UI.shortcuts.splice(0, 1); 651 | UI.shortcuts.push(w); 652 | } 653 | UI.setCookie('shortcuts', UI.shortcuts.join(' ')); 654 | } else { 655 | var s = UI.getCookie('shortcuts', ''); 656 | if (s) UI.shortcuts = s.split(/ /); 657 | } 658 | var html = '⌘ '; 659 | for (var i in UI.shortcuts) html += ''; 660 | _('scKey').innerHTML = html; 661 | }; 662 | 663 | UI.showPop = function(e) { 664 | var c = e.target; 665 | if (c.tagName.toUpperCase() != 'BUTTON' && c.tagName.toUpperCase() != 'A') return; 666 | var change = function() { 667 | var maxX = document.body.scrollWidth - 70; 668 | var x = e.layerX < 150 ? 10 : Math.floor(e.layerX < maxX ? e.layerX - 140 : maxX - 140); 669 | _('popview').style.cssText = 'display:block;left:'+ x +'px;top:'+ Math.floor(e.layerY+5) +'px'; 670 | //console.log(_('popview').style); 671 | _('bigchar').innerText = c.innerText; 672 | var u = c.innerText.codePointAt(0); 673 | _('codetag').innerText = 'U+' + u.toString(16).toUpperCase(); 674 | var k = Seeker.getCJKBlock(u); 675 | _('bigchar').className = Config.useImage[k] ? 'han img' : 'han'; 676 | _('bigchar').style.cssText = Config.useImage[k] ? 'background-image: url(' + Config.glyphwiki + 'u' + u.toString(16) + '.svg)' : ''; 677 | //('bigchar').innerText = c.innerText; 678 | UI.popTrigger = c; 679 | _('menu_key').style.display = c.tagName.toUpperCase() == 'BUTTON' ? 'block' : 'none'; 680 | if (c.tagName.toUpperCase() == 'A') { 681 | _('menu_go').style.display = c.tagName.toUpperCase() == 'A' ? 'block' : 'none'; 682 | _('menu_go').href = c.href; 683 | } else { 684 | _('menu_go').style.display = 'none'; 685 | } 686 | _('menu_add').style.display = 'block'; 687 | _('menu_del').style.display = 'none'; 688 | if (c.parentElement && c.parentElement.id == 'scKey') { // 因為動態呈現時,c.parentElement可能經常消失 689 | _('menu_add').style.display = 'none'; 690 | _('menu_del').style.display = 'block'; 691 | } 692 | }; 693 | UI.popTimer = setTimeout(change, UI.popTrigger == null ? 0 : 100); 694 | }; 695 | 696 | UI.hidePop = function(e) { 697 | if (e !== true && e.target != UI.popTrigger) return; 698 | UI.popTimer = setTimeout(function () { 699 | _('popview').style.display = 'none'; 700 | UI.popTrigger = null; 701 | }, 100); 702 | }; 703 | 704 | UI.eventMoniter = function() { 705 | $_.addEventListener('keydown', function(e) { 706 | if (e.code == 'Enter' || e.keyCode == 13) UI.go(true); 707 | if (e.code == 'Escape' || e.keyCode == 27) UI.clearFind(); 708 | }); 709 | 710 | _('popview').addEventListener('mouseenter', function(e) { 711 | clearTimeout(UI.popTimer); 712 | e.stopPropagation(); 713 | }, false); 714 | 715 | _('popview').addEventListener('mouseleave', function(e) { 716 | e.stopPropagation(); 717 | if (e.target != this) return; 718 | _('popview').style.display = 'none'; 719 | UI.popTrigger = null; 720 | }, false); 721 | 722 | _('keypad').addEventListener('mouseover', function(e) { UI.showPop(e); }, false); 723 | _('keypad').addEventListener('mouseout', function(e) { UI.hidePop(e); }, false); 724 | _('scKey').addEventListener('mouseover', function(e) { UI.showPop(e); }, false); 725 | _('scKey').addEventListener('mouseout', function(e) { UI.hidePop(e); }, false); 726 | _('output').addEventListener('mouseover', function(e) { UI.showPop(e); }, false); 727 | _('output').addEventListener('mouseout', function(e) { UI.hidePop(e); }, false); 728 | 729 | _('output').addEventListener('click', function(e) { if (e.target.tagName == 'A') e.preventDefault() }, false); 730 | 731 | _('scKey').addEventListener('click', function(e) { 732 | if (e.target.tagName.toUpperCase() == 'BUTTON') UI.key(e.target.innerText); 733 | e.preventDefault(); 734 | }, false); 735 | 736 | _('keypad').addEventListener('click', function(e) { 737 | if (e.target.tagName.toUpperCase() == 'BUTTON') UI.key(e.target.innerText); 738 | e.preventDefault(); 739 | }, false); 740 | 741 | _('menu_go').addEventListener('click', function(e) { UI.popTrigger.click(); }, false); 742 | _('menu_key').addEventListener('click', function(e) { UI.key(UI.popTrigger.innerText); }, false); 743 | _('menu_copy').addEventListener('click', function(e) { UI.setClipboard(UI.popTrigger.innerText); }, false); 744 | _('menu_query').addEventListener('click', function(e) { UI.replaceFind(UI.popTrigger.innerText); }, false); 745 | _('menu_add').addEventListener('click', function(e) { UI.addShortcut(UI.popTrigger.innerText); }, false); 746 | _('menu_del').addEventListener('click', function(e) { UI.addShortcut(UI.popTrigger.innerText, true); }, false); 747 | 748 | $_.addEventListener('compositionstart', function() { UI.ime = true; }); 749 | $_.addEventListener('compositionend', function() { setTimeout(function() { UI.ime = false; UI.go(); }, 1); }); 750 | }; 751 | 752 | // 初始化 753 | UI.init = function() { 754 | // UI 755 | _('version').innerHTML = Seeker.getVersion(); 756 | 757 | var cnt = 0; 758 | for (var i in dt) if (dt[i].substring(dt[i].length-1) != '╳') cnt++; 759 | _('datasize').innerText = cnt; 760 | 761 | // Status 762 | _('variant').checked = UI.getCookie('variant', '1') == '1'; 763 | _('onthefly').checked = UI.getCookie('onthefly', '1') == '1'; 764 | _('subdivide').checked = UI.getCookie('subdivide', '0') == '1'; 765 | UI.addShortcut(); 766 | 767 | // Events 768 | UI.eventMoniter(); 769 | 770 | //OnFnt(); 771 | UI.updatePad(true); 772 | UI.updateFilter(true); 773 | }; 774 | 775 | window.onload = UI.init; 776 | -------------------------------------------------------------------------------- /release/HanSeeker_WithoutData.html: -------------------------------------------------------------------------------- 1 | 2 | 部件檢索 3 | 4 | 5 | 6 | 94 | 95 | 96 |
97 | 101 |
102 | 部件: 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
114 | 選項: 115 | 116 | 117 | 118 | 119 |
120 |
121 | 122 |
123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 |
132 |
133 | 134 |
135 |
136 | 138 | 基本 139 | A區 140 | B區 141 | C區 142 | D區 143 | E區 144 | F區 145 | G區 146 | 相容 147 | 補充 148 | 其它 149 | 150 |
151 |
152 |
153 |
154 | 155 | 156 | 輸入 157 | 前往頁面 158 | 替換查詢 159 | 複製此文字 160 | 161 | 加入快捷列 162 | 移出快捷列 163 | 164 |
165 | 166 | 167 | 216 | 217 | 218 | 219 |
220 | 改版版本: 221 | 改版發布網址:GitHub 222 | 原始核心版本:0.9.1.0 223 | 原始發布網址:部件檢索 (WFG製作) 224 | 漢字拆分資料:WFG漢字構形資料庫字形IDSデータ 225 |
226 | 227 | 228 | 229 | 230 | 279 | 280 | 281 | --------------------------------------------------------------------------------