import fonts.fontAwesome; import win.ui; /*DSG{{*/ winform = win.form(text="COCA 20000 词汇表";right=963;bottom=598;bgcolor=0xFFFFFF) winform.add( btnAskAi={cls="plus";text="问 AI";left=889;top=570;right=955;bottom=599;align="left";bgcolor=0xFFFFFF;color=0x3C3C3C;db=1;dr=1;font=LOGFONT(h=-13);iconColor=0x5757FF;iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF0AA';notify=1;textPadding={left=25};z=4}; btnPractice={cls="plus";text="练习";left=586;top=570;right=651;bottom=599;align="left";bgcolor=0xFFFFFF;color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconColor=0x5757FF;iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF02D';notify=1;textPadding={left=25};z=17}; btnSearch={cls="plus";left=851;top=570;right=881;bottom=596;align="left";border={bottom=1;color=0xFF969696};color=0x3C3C3C;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF002';notify=1;textPadding={left=25};z=14}; btnVoice={cls="plus";text="朗读";left=652;top=570;right=717;bottom=599;align="left";bgcolor=0xFFFFFF;color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconColor=0x008000;iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF028';notify=1;textPadding={left=25};z=5}; chkCet4={cls="checkbox";text="CET4";left=189;top=572;right=241;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=9}; chkCet6={cls="checkbox";text="CET6";left=242;top=572;right=294;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=10}; chkGk={cls="checkbox";text="高考";left=135;top=572;right=187;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=8}; chkGsl={cls="checkbox";text="通用";left=456;top=572;right=508;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=18}; chkIelts={cls="checkbox";text="雅思";left=296;top=572;right=348;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=11}; chkKy={cls="checkbox";text="考研";left=402;top=572;right=454;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=13}; chkMeaning={cls="checkbox";text="释义";left=20;top=572;right=72;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=6}; chkNewWords={cls="checkbox";text="生词本";left=509;top=572;right=573;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=16}; chkToefl={cls="checkbox";text="托福";left=349;top=572;right=401;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=12}; chkZk={cls="checkbox";text="中考";left=82;top=572;right=134;bottom=597;bgcolor=0xFFFFFF;db=1;dl=1;z=7}; custom={cls="custom";text="自定义控件";left=572;top=20;right=958;bottom=562;db=1;dr=1;dt=1;z=2}; editKeyword={cls="plus";left=706;top=570;right=851;bottom=596;align="right";border={bottom=1;color=0xFF969696};db=1;dl=1;dr=1;editable="edit";font=LOGFONT(h=-13);notify=1;textPadding={top=3;bottom=3};z=15}; listview={cls="vlistview";left=20;top=20;right=567;bottom=562;db=1;dl=1;dt=1;edge=1;fullRow=1;z=1}; splitter={cls="splitter";left=567;top=20;right=572;bottom=562;db=1;dr=1;dt=1;frame=1;z=3} ) /*}}*/ import table.coca20000; winform.listview.columns = [["词频",50],["单词",100],["音标",100],["释义",0],["分类",-1]] var fields = ["word","phonetic","meaning","tag"] //虚表 var dataset = table.coca20000; winform.listview.onGetDispItem = function(item,row,col){ if(col==1) return {text = tostring(row)}; return{ text=dataset[row][fields[col-1]]}; } import win.ui.grid; win.ui.grid(winform.listview);//双击显示文本框 import web.form.chat; var chatUi = web.form.chat(winform.custom); chatUi.doScript(" document.onmouseup = document.onselectionchange = function() { var text = ''; if (window.getSelection) { var selection = window.getSelection(); if (selection.rangeCount === 0) { return null; } text = selection.toString(); } else if (document.selection && document.selection.type != 'Control') { text = document.selection.createRange().text; } if(text) external.onSelectedText(text) };") winform.btnAskAi.skin({ color={ active=0xFF00FF00; default=0xFF3C3C3C; disabled=0xFF999999; hover=0xFFFF0000 } }) winform.btnAskAi.oncommand = function(id,event){ var word = winform.listview.selectedWord; if(!#word) return winform.msgboxErr("请先点选单词"); import win.dlg.flashDict; win.dlg.flashDict(winform,word).doModal(); } import com.wmPlayer; var soundUrlCache = table.cache(); var pronounce = function(word,site){ var url; if(site=="youdao"){ url = "https://dict.youdao.com/dictvoice?audio="+word+"&type=2" } else{ url = soundUrlCache[word] || ..thread.invokeAndWait( function(word){ import web.rest.htmlClient; var http = web.rest.htmlClient(); var webster = http.api("https://www.merriam-webster.com/dictionary/","GET"); var htmlDoc = webster[word].get();//抓取韦氏词典网页 var ele = htmlDoc.queryEle({"class":"play-pron-v2"});//获取指定 HTML 元素 var url; if(ele && ele["data-dir"] && ele["data-file"]){ //合成韦氏词典美式发音链接 url = "https://media.merriam-webster.com/audio/prons/en/us/mp3/" + ele["data-dir"] + "/" + ele["data-file"] + ".mp3" } else{ //合成柯林斯词典美式发音链接 url = "https://www.collinsdictionary.com/sounds/hwd_sounds/en_us_"+string.lower(word)+".mp3" } return url; } ,word ) soundUrlCache[word] = url; if(winform.btnVoice.disabledText) winform.btnVoice.disabledText = ['\uF026','\uF027','\uF028']; } com.wmPlayer.url = url; } import fsys.table; var config = fsys.table(io.appData("aardio/std/tools/coca2000.table"),{newWords={}}); import string.words; import string.fuzzyMatching; winform.listview.onSelChanged = function(selected,item,subItem,nmListView){ chatUi.cocaSentence = null; fsys.delete("\coca20000-sentence-tts.mp3"); var word = winform.listview.getItemText(item,2); var meaning = winform.listview.getItemText(item,4); if((winform.listview.selectedWord == winform.editKeyword.text) || !#winform.editKeyword.text){ winform.editKeyword.text = word; } winform.listview.selectedWord = word; winform.listview.selectedWordMeaning = '##### '+word + ' ' + winform.listview.getItemText(item,3) + '\r\n\r\n##### ' + meaning var meaning2 = string.words(word); if(meaning2) { meaning2 = string.replace(meaning2,"[,;]","\0 "); var fuzzyMatching = string.fuzzyMatching(meaning) if( fuzzyMatching.match(meaning2) < 0.5 ){ winform.listview.selectedWordMeaning = winform.listview.selectedWordMeaning + '\r\n\r\n##### ' + meaning2; } } var wordInfo = dataset[item] if(wordInfo && wordInfo.sentence){ winform.listview.selectedWordMeaning = winform.listview.selectedWordMeaning + '\r\n\r\n
例句:\r\n\r\n ' + string.replace(wordInfo.sentence,'\n',' 🔊\n
'); chatUi.cocaSentence = string.match(wordInfo.sentence,"(.+?)<::>?="); } if(!winform.btnAskAi.disabled){ var card = ` `+ '\r\n\r\n'+winform.listview.selectedWordMeaning + ( config.newWords[word] ? "":'\r\n\r\n---\r\n添加到生词本') chatUi.write(card) } pronounce(word,"youdao") } winform.splitter.split(winform.listview,winform.custom); winform.btnVoice.skin({ color={ active=0xFF00FF00; default=0xFF3C3C3C; disabled=0xFF999999; hover=0xFFFF0000 } }) import web.edgeTextToSpeech; import bass.channel; winform.btnVoice.oncommand = function(id,event){ var word = winform.listview.selectedWord; if(!word) return winform.msgboxErr("请先点选单词"); winform.btnVoice.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250']; pronounce(word,"webster"); thread.delay(1500); winform.btnVoice.disabledText = null; } winform.chkMeaning.oncommand = function(){ winform.listview.setRedraw(false); if(owner.checked){ winform.listview.setColumnWidth(0,5); winform.listview.fillParent(4); } else{ winform.listview.setColumnWidth(0,4); winform.listview.fillParent(5); } winform.listview.setRedraw(true); } var tip = /* - COCA(Corpus of Contemporary American English, 美国当代英语语料库)20000 词汇。 原表有 22000 个词,合并词性不同的重复条目并添加 NGSL 词汇后共计 17649 个词(区分大小写)。 按词频排序,单词使用频率越高则排序越是靠前。 - 点击单词会自动调用 AI 绘制单词卡片。 每个单词首次请求绘制卡片需要一些时间,服务器会缓存上次请求绘制的卡片。 拖动词卡片可置顶到屏幕。 - 点选单词调用有道词典发音,点选「朗读」按钮则调用韦氏词典加载真人发音。 - 点单词显示例句,点例句后的「🔊」可以仿真人语音朗读例句。 每个例句首次朗读时要略等一会,按住 Shift 键点「🔊」可以较慢速度朗读。 在 「🔊」链接获得焦点时也可以按 Enter 键朗读例句。 - 在释义与例句页面内双击选中单词可显示中文释义。 - 双击列表项可切换到编辑框模式。 - 列表项右键菜单 ☑ 勾选「生词本」可添加单词到生词本,也可点击「根据生词本生成例句」菜单项。 - 可勾选下方中考、高考、CET4、CET6、雅思、托福、考研等分类标签。 不勾选任何分类标签则显示全部词汇。 */ chatUi.write(tip); import win.ui.menu; winform.listview.onRightClick = function(item,subItem,nmListView){ var popmenu = win.ui.popmenu(winform); if(item){ var word = winform.listview.getItemText(item,2); var id = popmenu.add('生词本',function(id){ config.newWords[word] = !popmenu.checked(1) ? true : null; config.save(); winform.listview.redraw(); }); popmenu.check(1,!!config.newWords[word]); } popmenu.add(); popmenu.add('清空生词本',function(id){ config.newWords = {}; config.save(); winform.chkNewWords.oncommand(); }); popmenu.add('复制生词本',function(id){ var newWords = config.newWords; var words = [] for(i=1;#dataset;1){ if(newWords[dataset[i].word]){ table.push(words,i + " " +dataset[i].word); } } import win.clip; win.clip.write( string.join(words,'\r\n') ) }); popmenu.add(); popmenu.add('生词本练习',function(id){ winform.loadForm("/coca2000.practice.aardio") }); popmenu.popup(); } var filter = function(){ var p = [] if(winform.chkZk.checked) table.push(p,""); if(winform.chkGk.checked) table.push(p,""); if(winform.chkCet4.checked) table.push(p,""); if(winform.chkCet6.checked) table.push(p,""); if(winform.chkIelts.checked) table.push(p,""); if(winform.chkToefl.checked) table.push(p,""); if(winform.chkKy.checked) table.push(p,""); if(winform.chkGsl.checked) table.push(p,""); if(!#p){ dataset = table.coca20000; } else{ p = "!\w"+string.join(p,"|"); dataset = [] for(i,wordInfo in table.coca20000){ if(wordInfo.tag && string.find(wordInfo.tag,p)){ table.push(dataset,wordInfo); } } } if(winform.chkNewWords.checked){ var newWords = config.newWords; var dataset2 = [] for(i,v in dataset){ if(newWords[v.word]){ table.push(dataset2,v); } } dataset = dataset2; } winform.listview.count = #dataset; winform.listview.redraw(); } winform.chkZk.oncommand = filter; winform.chkGk.oncommand = filter; winform.chkCet4.oncommand = filter; winform.chkCet6.oncommand = filter; winform.chkIelts.oncommand = filter; winform.chkToefl.oncommand = filter; winform.chkKy.oncommand = filter; winform.chkGsl.oncommand = filter; winform.chkNewWords.oncommand = filter; winform.bindConfig( config,{ checkbox = "checked"; } ); winform.chkMeaning.oncommand(); filter(); winform.listview.onnotify = function(id,code,ptr){ if( code == 0xFFFFFFF4/*_NM_CUSTOMDRAW*/ ){ var lvcd = winform.listview.getNotifyCustomDraw(code,ptr); if( lvcd.nmcd.dwDrawStage == 0x10001/*_CDDS_ITEMPREPAINT*/) return 0x20/*_CDRF_NOTIFYSUBITEMDRAW*/ elseif( lvcd.nmcd.dwDrawStage == 1/*_CDDS_PREPAINT*/ ){ return 0x20/*_CDRF_NOTIFYITEMDRAW*/; } elseif( lvcd.nmcd.dwDrawStage == ( 0x10001/*_CDDS_ITEMPREPAINT*/ | 0x20000/*_CDDS_SUBITEM*/) ){ //注意这里 iSubItem 的索引自0开始( 其他函数通常自1开始 ) lvcd.clrText = 0x000000; var word = dataset[lvcd.nmcd.dwItemSpec+1][["word"]] if(word && config.newWords[word]){ lvcd.clrText = 0x0000FF; } lvcd.update(); return 0/*_CDRF_DODEFAULT*/ } } } import win.ui.mask; var mask = win.ui.mask(winform); mask.add( plus={cls="plus";marginBottom=20;marginLeft=550;width=370;height=400;color=0x008000; font=LOGFONT(h=-96;name='FontAwesome');valign="bottom"; }) import win.debounce; chatUi.external = { onDragImageStart = function(imageUrl){ winform.setTimeout( function(){ import key; key.press("ESC"); var frmImage = win.form(text="aardio form";right=359;bottom=359;border="none";max=false;topmost=1) frmImage.add( btnClose={cls="close";text="×";left=327;top=5;right=355;bottom=33;bgcolor=0xCC8B94;dr=1;dt=1;font=LOGFONT(h=-21);z=2}; plus={cls="plus";left=0;top=0;right=360;bottom=360;db=1;dl=1;dr=1;dt=1;repeat="scale";z=1} ) frmImage.btnClose.show(true); frmImage.btnClose.oncommand = function(id,event){ frmImage.close(); } frmImage.onMouseDown = function(wParam,lParam){ frmImage.hitCaption(); } import win.ui.shadow; win.ui.shadow(frmImage); import inet.http; frmImage.plus.background = imageUrl; frmImage.show(); frmImage.hitCaption(); chatUi.write(winform.listview.selectedWordMeaning); },1); }; newWords = function(){ config.newWords[winform.listview.selectedWord] = true; config.save(); }; onSelectedText = win.debounce(function(text,left,top,right,bottom){ import winex.tooltip; if(#text){ var meaning,word = string.words(text); if(meaning){ var x,y = win.getMessagePos(); y = y + winform.dpiScale(25) winex.tooltip.balloon(meaning,x,y); if(!winform.btnVoice.disabled){ pronounce(word,"youdao"); } return; } } winex.tooltip.balloon(false); },500); tts = function(){ if(chatUi.cocaSentence){ if(winform.btnVoice.disabledText) return; import key; var slower = key.getState("Shift"); var playMp3 = function(){ winform.btnVoice.disabledText = ['\uF026','\uF027','\uF028']; var audio = bass.channel.open(string.load("\coca20000-sentence-tts.mp3")); audio.syncCallback(function(data){ audio.free() winform.btnVoice.disabledText = null; },2/*_BASS_SYNC_END*/) if(slower){ audio.setSpeed(0.85); } audio.play() return; } if( io.exist("\coca20000-sentence-tts.mp3") ){ return playMp3(); } mask.show(); mask.plus.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250']; winform.btnVoice.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250']; var tts = web.edgeTextToSpeech(chatUi.cocaSentence,"\coca20000-sentence-tts.mp3") tts.voiceOptions.name = "en-US-AriaNeural" tts.voiceOptions.rate = "-10%" tts.OnResponseEnd = function(path){ mask.plus.disabledText = null; mask.show(false); return playMp3(); } tts.OnError = function(sender, e){ winform.btnVoice.disabledText = null; mask.plus.disabledText = null; mask.show(false); } //连接服务器,合成语音 tts.ConnectAsync(); return; } }; } winform.btnSearch.skin({ color={ active=0xFF00FF00; default=0xFF3C3C3C; disabled=0xFF6D6D6D; hover=0xFFFF0000 } }) winform.btnSearch.oncommand = function(id,event){ var p = string.trim(winform.editKeyword.text); if(!#p) { winform.msgboxErr("请输入搜索词,支持模式匹配语法!"); winform.editKeyword.setFocus(); return; } var count = winform.listview.count; var selIndex = winform.listview.selIndex; if(!selIndex || selIndex >= count ){ selIndex = 1; } else{ selIndex++; } for(i=selIndex;count;1){ var wordInfo = dataset[i] if(string.find(wordInfo.word,p)){ winform.listview.selIndex = i; winform.listview.ensureVisible(i); return; } } if(selIndex>2){ for(i=1;selIndex-2;1){ var wordInfo = dataset[i] if(string.find(wordInfo.word,p)){ winform.listview.selIndex = i; winform.listview.ensureVisible(i); return; } } } winform.msgboxErr("找不到下一个匹配的单词!"); winform.editKeyword.setFocus(); } winform.editKeyword.setCueBannerText("请输入搜索词,支持模式匹配语法"); winform.editKeyword.editBox.onOk = function(ctrl,alt,shift){ winform.btnSearch.oncommand(); return true; } winform.btnPractice.skin({ color={ active=0xFF00FF00; default=0xFF3C3C3C; disabled=0xFF6D6D6D; hover=0xFFFF0000 } }) winform.btnPractice.oncommand = function(id,event){ winform.loadForm("/coca2000.practice.aardio") } winform.editKeyword.editBox.disableInputMethod(); winform.show(3/*_SW_MAXIMIZE*/); import com.autoComplete; var aco = com.autoComplete(winform.editKeyword); var items = [] for(k,v in table.coca20000){ table.push(items,v.word); } aco.setStrings(items); win.loopMessage();