<script type="text/javascript"> var txt=""; var ot=""; //попереднє значення input defnfnd var timer=0; //ідентифікатор таймеру var x=-1,y=0;//кординати select getObj("defnfnd").focus();
//функція обробки нажимання клавіші над елементами введення терміну (id="defnfnd") function PressKey(e){ e=e||window.event; var elem =(window.event) ? window.event.srcElement : e.currentTarget; // отримати об'єкт по якому був клік var g=getObj('variants');//отримати об'єкт select з підказками
if(x==-1&&y==0){// при першому зверненні розрахоувємо кординати x= pageX(elem); y= pageY(elem); g.style.top = y + elem.clientHeight + 1 + "px"; g.style.left = x + "px"; } if(e.keyCode==40){g.focus();g.selectedIndex=0;return;}// Down - віддати фокус селектору if(e.keyCode==13){startFind(e); return;} // якщо Enter if(ot==elem.value)return; // якщо значення не змінилося - нічого не робимо ot=elem.value; //отримаємо вибране значення if(timer){clearTimeout(timer);timer=0;}//timer - ідентифікатор таймеру, якщо запущений - відмінити if(ot.length<2){//якщо кількість літер менше 2 getObj('variants').style.visibility = 'hidden'; // ховаєм select return;} timer = window.setTimeout(getLiveFill,100); // через 100 мс буде викликана функція getLiveFill (http://learn.javascript.ru/settimeout-setinterval) } //функція обробки нажимання клавіші списку підказок (id="variants") function PressKey2(e){ // якщо нажата клавіша у вікні вибору e=e||window.event;// (http://javascript.ru/tutorial/events/properties) // отримати обєкт, для якого була викликана подія, //якщо window.event==true (Internet Explorer ) тоді t=window.event.srcElement інакше (інші браузери) t= e.currentTarget getObj('defnfnd').value = t.value; var t=(window.event) ? window.event.srcElement : e.currentTarget; if(e.keyCode==13){startFind(e);return;} // якщо Enter }
//функція призначена для заповнення селектору з підказками словами зі словника, //що починаються з набраних літер //викликається через 100 мс після нажимання останньої клавіші, якщо кількість літер>=2 function getLiveFill(){ timer=0;//обнуляємо таймер var o=getObj('variants');//отримати обєкт select з підказками o.options.length=0;// кількість елементів=0 (http://htmlbook.ru/html/select , http://www.tigir.com/javascript_select.htm) // вказуємо функцію звор виклику при позитивному результаті обробки серверу // в яку передається об'єкт defnstr з набором підказок (див. viewtopic.php?f=94&t=215) // відформатованим для select google.script.run.withSuccessHandler ( function (defnstr) {//alert (defnstr); document.getElementById('variants').innerHTML = defnstr; document.getElementById('variants').style.visibility = 'visible'; }) .withFailureHandler(function (err) {alert (err);})//зворотній виклик при помилці .liveFill (ot);//виклик функції серверу на заповнення підказок }
//функція призначена для пошуку значень в словнику function startFind (e){ e=e||window.event; var elem =(window.event) ? window.event.srcElement : e.currentTarget; //якщо викликано з вікна вибору додаткових варіантів або вибору підказок if ((elem.getAttribute('id')=="synonims") || (elem.getAttribute('id')=="variants")) {getObj('defnfnd').value = elem.value}//заповнити вікно вводу вибраним зі списку значенням
var dfn=getObj('defnfnd').value; if (!dfn ||(dfn.length <2)) {alert ("Дуже мало літер для пошуку (<2)!"); return}; getObj('variants').style.visibility = 'hidden'; // сховати селектор document.getElementById('startCmd').innerHTML = "Шукаю..." ; google.script.run.withSuccessHandler ( function (resp) {//функція звор виклику при позитивній обробці серверу document.getElementById('defnEN').innerHTML = resp.defnEN; document.getElementById('defnUA').innerHTML = resp.defnUA; document.getElementById('explnEN').innerHTML = resp.explnEN; document.getElementById('explnUA').innerHTML = resp.explnUA; document.getElementById('synonims').innerHTML = resp.syn; document.getElementById('refr').innerHTML = resp.refr; document.getElementById('img').innerHTML = resp.imgURL; document.getElementById('startCmd').innerHTML = "Шукати"; }) //функція звор виклику при помилковій обробці серверу .withFailureHandler(function (err) {alert (err);document.getElementById('startCmd').innerHTML = "Шукати";}) .findExpln (dfn);//виклик функції пошуку на сервері }
function getObj(objID){ if (document.getElementById) {return document.getElementById(objID);} else if (document.all) {return document.all[objID];} else if (document.layers) {return document.layers[objID];} }
// Визначення кординат елемента (рекурсивна бо працює // з батьківськими обєктами, поки не добереться до "найстаршого") function pageX(elem) { return elem.offsetParent ? elem.offsetLeft + pageX( elem.offsetParent ) : elem.offsetLeft; } function pageY(elem) { return elem.offsetParent ? elem.offsetTop + pageY( elem.offsetParent ) : elem.offsetTop; }
</script> </body> </html>
Код серверу:
//функція викликається http-запитом GET і відправляє html-сторінку браузеру //e1 - параметри http-запиту function doGet(e1) { try { if (e1.parameter.type=='fill') {//якщо запит з параметрами - для майбутнього використання MailApp.sendEmail ('******_***@ukr.net', 'запит fill',e.parameter.value); return 'hhhhh';} else { //якщо запит без параметрів //відсилаємо сторінку через змінну output var output = HtmlService.createHtmlOutputFromFile('defnEN.html'); //особливий режим обробки сриптів для Гугл HTML output.setSandboxMode(HtmlService.SandboxMode.EMULATED); return output; }; } catch (e1) { //при помилці відправити клієнту (браузеру) причину помилки return HtmlService.createHtmlOutput(e1.message) ; } }
//функція викликається клієнтом для формування списку підказок //у функцію передається набране в полі слово function liveFill (defn){ var str='', defnstr=''; //адреса Гугл-таблиці (спридшита зі словником) var dictISA = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/********************888'); var sheets = dictISA.getSheets();//отримуємо колекцію листів //видаляємо першу НЕлітеру defn = (defn[0].search(/[^A-Za-zйцукенгшщзхъїфіывапролджєэячсмитьбю]/)>=0) ? defn.substring(1,defn.length) : defn; var letter = defn[0].toUpperCase() ;//змінюємо першу літеру на прописну //для літер 'Z' та 'Y' лист називається 'Y-Z' letter = (letter == 'Z')||(letter == 'Y') ? 'Y-Z' : letter; //робота з кешем, якщо кеш на літеру пустий - заповнюємо кеш з таблиці var cashe = CacheService.getPublicCache();//отримуємо кеш, в якому кожне поле ідентифікується через літеру if (!cashe.get(letter)) {//якщо в кеші такої літери немає var sheet=dictISA.getSheetByName(letter);//отримаємо лист if (!sheet) return; var range=sheet.getRange(1, 1, sheet.getMaxRows());//всі комірки листа str= range.getValues().join('\u000a');//перетворюємо масив в рядок, розділений символами кінця cashe.put(letter, str);}//заганяємо все в кеш з іменем літери else str=cashe.get(letter);//якщо кеш не порожній - отримаємо його наповнення //шукаємо 10-ть співпадінь var defns=[]; var pos=0, cntfnd=0; while(true) { var foundPos = str.indexOf('\u000a'+defn, pos);//перше співпадіння з позиції pos if (foundPos < 1) break; //якщо не знайшли - вийти //шукаємо символ кінця, або якщо нема - то це останнє слово в кеші defns[cntfnd] = (str.indexOf('\u000a', foundPos+2)>0) ? str.substring (foundPos+1, str.indexOf('\u000a', foundPos+2)) : str.substring (foundPos+1) ; //формуємо список з підказками в форматі html defnstr= defnstr + "<option value='" + defns[cntfnd] + "'> " + defns[cntfnd] + "</option>"; pos = foundPos + 1; cntfnd++; if (cntfnd == 10 ) break;//максимум 10 живих підказок }; return defnstr; }
//інтерфейсна функція серверу для пошуку значень в словнику function findExpln (defn){ var resp=getRecords(defn); return resp; }
//функція для пошуку значень в словнику function getRecords (defn){ var defn1="", defn2=""; var fndsheet={}, fndrow=[]; var lngdefn ="EN"; var pathDict =""; // обєкт-відповідь з форматованими в форматі html полями var resp = {explnEN: "Не знайдено " + Date(), explnUA:"Не знайдено", defnEN:"Не знайдено", defnUA:"Не знайдено", imgURL:"", syn: "", refr: ""}; //видаляємо першу НЕлітеру defn = (defn[0].search(/[^A-Za-zйцукенгшщзхъїфіывапролджєэячсмитьбю]/)>=0) ? defn.substring(1,defn.length) : defn; var letter = defn[0].toUpperCase() ;//змінюємо першу літеру на прописну if (letter.search(/[A-Za-z]/)>=0){ lngdefn="EN"; pathDict=dictISA}//якщо перша літера латинська //для кирилиці поки заглушка else if (letter.search(/[ЙЦУКЕНГШЩЗХЇЪЫЭФІВАПРОЛДЖЄЯЧСМИТЬБЮ]/)>=0){ lngdefn="UK"; pathDict=dictISA;return} else return; //все в нижній регістр defn1= defn.toLowerCase().replace(/[^a-zйцукенгшщзхъїфіывапролджєэячсмитьбю]/gi,''); var dict = SpreadsheetApp.openByUrl(pathDict); switch (lngdefn) {//поки що тільки EN case "EN": var sheet=dict.getSheetByName('KEYS');//на даному листі зберігається типу індексних записів var values=sheet.getRange(1, 3, sheet.getMaxRows()).getValues();//стовпчик з індексами (слова без розділових знаків) //перебираємо усі індексні комірки for (var i=0; i<sheet.getMaxRows()-1 ; i++) { //порівнюємо слова в їх "безрозділовому" вигляді defn2=values[i][0].replace(/[^a-zйцукенгшщзхъїфіывапролджєэячсмитьбю]/gi,''); //якщо співпадають if (defn2==defn1) { //отримати потрібний лист (назва зберігається у 5-й колонці індексного листа) fndsheet=dict.getSheetByName(sheet.getRange(i+1,5,1,1).getValue()); //отримати рядок (номер зберігається у 6-й колонці індексного листа) fndrow=fndsheet.getRange( sheet.getRange(i+1,6,1,1).getValue(), 1, 1,6).getValues(); //заповнюємо відповідь з html форматуванням resp.defnEN = '<b>' +fndrow[0][0] + '</b>'; resp.explnEN = fndrow[0][1] ; resp.refr= '<a href="' + fndrow[0][2] + '"> Джерело на форумі АСУ в Україні </a>' + '<br> <a href="http://asu.in.ua/viewforum.php?f=104"> Свої варіанти перекладу пропонуйте в цьому розділі</a>' resp.imgURL= '<img src="' + fndrow[0][3] + '" alt=" рисунок відсутній "/>'; resp.defnUA = (fndrow[0][4].length>1) ? '<b>' + fndrow[0][4] + '</b>' : 'Переклад відсутній'; resp.explnUA = fndrow[0][5]; //якщо не воно - то може схоже (підрядок входить у визначення) } else if (defn2.search(defn1)>=0){ //тоді заповнюємо список додаткових варіантів resp.syn=resp.syn + "<option value='" + sheet.getRange(i+1,1,1,1).getValue() + "'> " + sheet.getRange(i+1,1,1,1).getValue() + "</option>"; } } break case "UK":break//поки заглушка } return resp; }
Тема повідомлення: Re: Розробка інтерактив. англо-українського словника:чернетка
Додано: 09 травня 2014, 23:47
Викладач
З нами з: 29 листопада 2013, 17:11 Повідомлення: 5033
Спочатку возився з клієнтською і серверною частиною (через Ajax), але на роботі через наявний http-проксі, схоже буферезуються всі запити від клієнта до серверу. Тому дану частину я залишив на пізніше. Перейшов до задачі наповнення бази даних, вже є певні результати. Вирішив поділитися, хоча б для того, щоб потім самому згадати. І так, поки що вже частково-робоча ідея така. 1) Серверна частина буде складатися з ява-сервлету, організованого через Гугл-Скриптс, який при старті або рестарті буде підгружати всю БД активних термінів та їх розміщення в ГуглШиті в пам'ять, щоб можна було швидко працювати. 2) Вся БД словника, яка реалізована в ГуглШиті, ділиться на листи, кожен з яких відповідає за свою літеру, крім Y-Z, яка відповідає за дві (історично так склалось, оскільки один лист тем форуму не помістив би всі теми, а це трохи не зручно ). Документ Гугл-таблиця доступна тільки мені, таким чином інтерфейс користувачів повністю буде проводитись через сервлет. 3) Я довго обудумував над варіантами заповнення БД. У останні моменти вирішував дилему: - наповнювати БД тільки один раз з форуму, а потім просто дублювати виправлення і переводи і в БД і в форумі; - наповнювати БД з форуму, і відновляти (наповнювати ще раз) при необхідності, але знову ж таки з форуму. Вирішив зупинитися на 2-му варіанті. Таким чином на форумі буде останній (живий) відтиск інформації. 4) 3-тє питання виставляє жорсткі вимоги до оформлення тем, оскільки крім англомовних термінів (виділених напівжирним) та їх пояснення, з'являться україномовні та їх локальне пояснення. Все це вимагає з одного боку зручного представлення такого повідомлення (поки що думаю про таблицю), а з іншого - зручної структури, з точки зору програмної обробки. Питання залишається відкритим, буду експерементувати і шукати нові BBCode, а можливо писати свої (чого вже тільки не навчився робити з цим форумом!). 5) Поки що без вирішення 4-го питання, якось заповнив БД новоствореном скриптом. Скрипт привязаний до Гугл-таблиці. Має дві основні функції - заповнення листа з літерою данними з теми форуму (SaveLetter), та функції оновлення необхідних листів (Saves) БД, яка в свою чергу викликає SaveLetter. Програма справляється зі своєю початковою задачою. Час оновлення всіх листів БД на даний момент складає біля 2 хвилин. Але є одне але (АЄОА): це час роботи скрипта, а Гугл-таблиця оновлюється повільніше (тормозить страшно). Ну і ще далеко не всі теми оброблені. Тим не менше, якщо таке оновлення буде проводитись раз в місяць(і те тільки для певних сторінок), то нічого страшного в цьому немає. Нижче, під спойлером, оба скрипти. Там є якісь комменти, але то радше для мене аніж для когось. Кого зацікавить - питайте. П.С. BBCode для скрипта просто жахливий, треба терміново шукати інший. ----------- на насутпний день Змінив BBCode, тому змінюю повідомлення.
//функція записує значення визначень по сторінці форуму для однієї літери function SaveLetter(Theme) { var Page='', PgText='', msg = 0, thmnmb=0; var SpdSheet = SpreadsheetApp.getActiveSpreadsheet(); var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(Theme.letter); //sheet.activate(); if (sheet.getMaxRows()>1) sheet.deleteRows(1, sheet.getMaxRows()-1); PgText=PgText.substring (PgText.search('<div id="pagecontent">')+'<div id="pagecontent">'.length); PgText=PgText.substring (PgText.search ('<table class="tablebg" width="100%" cellspacing="1"')+'<table class="tablebg" width="100%" cellspacing="1"'.length); PgText=PgText.substring (PgText.search ('<table class="tablebg" width="100%" cellspacing="1"')+'<table class="tablebg" width="100%" cellspacing="1"'.length);
var ResAll=''; var Posts = []; var Post=''; var Records = []; var i=0, j=0, startPost=1;
var divPostStart ='<div class="postbody">', divPostEnd='</div>'; var spanStart='<span style="font-weight: bold">', spanEnd='</span>'; var cntmsgStart = '<td class="gensmall" nowrap="nowrap"> ', cntmsgEnd = 'повідомлень'; var tmpstr='', tmpint=0; //'<table class="tablebg" width="100%" cellspacing="1"' var divStartID=0, divEndID=0, spanStartID=0, spanEndID=0, explnEndID=0, imgStartID=0;
// для кожної теми (літери) thmnmb=0; //кількість повідомлень на сторінці Page=UrlFetchApp.fetch(Theme.startURL+'&st=0&sk=t&sd=a&start=1'); PgText=Page.getContentText(); tmpint=PgText.search (cntmsgStart)+cntmsgStart.length ; Theme.msgCount = parseInt (PgText.substring (tmpint + 1 , tmpint + 5))
i=0; j=0, n=0; //перебор сторінок для теми (літери)------------------------------------------------------------------------ for (msg =1; msg<=Theme.msgCount; msg +=10 ) { Page=UrlFetchApp.fetch(Theme.startURL+'&st=0&sk=t&sd=a&start='+ msg); PgText=Page.getContentText();
do{//пошук всіх повідомлень на сторінці divStartID =PgText.search(divPostStart); if (divStartID>0) { i++; PgText=PgText.substring(divStartID); divEndID=PgText.search(divPostEnd); Posts[i]=PgText.substring(divPostStart.length,divEndID); PgText=PgText.substring(divEndID); //пошук термнів (виділені тегом span) та їх визнчення (після span до іншого span) Post= Posts[i];//повний текст повідомлення tmpstr=''; do{//поки не скінчаться всі визначення spanStartID = Post.search (spanStart);//початок визначення Post= Post.substring (spanStartID+spanStart.length-1); spanEndID = Post.search (spanEnd);//кінець визначення if (spanStartID >0) {//якщо визначення знайдене в тексті повідомлення j++; //новий запис Records[j]= {URL:Theme.startURL+'&st=0&sk=t&sd=a&start=' + i, defnEN:'', explnEN:'', imgURL: '', defnUA : '' , explnUA: '' }; explnEndID = Post.search ('<br />');//шукаємо новий абзац if (explnEndID<0) explnEndID = Post.search('<!--');//в кінці повідомлення є запис який починається з <!-- Records[j].defnEN= Post.substring(1, spanEndID); Records[j].explnEN = (explnEndID>0) ? Post.substring(spanEndID + 7,explnEndID) : Post.substring(spanEndID+7); //обробка посилань на рисунки imgStartID = Post.search ('<img src=');//шукаємо перше посилання на рисунок у повідомленні //якщо рисунок знайдений, то запамятовуємо посилання if (imgStartID>0) {tmpstr = Post.substring (imgStartID+10, Post.search ('alt="')-2);}; //якщо рисунок не знайдений, але посилання залишилось, то рисунок стосується попереднього визначення if ((imgStartID <= 0) && (tmpstr.length>0) ) {Records[j-1].imgURL=tmpstr;tmpstr=''}; }; } while (spanStartID>0); //якщо всі визначення закінчились а рисунок в буфері є, він стосується останнього визначення if (tmpstr.length>0) {Records[j].imgURL=tmpstr;tmpstr=''}; } }while (divStartID>0);
Тема повідомлення: Re: Розробка інтерактив. англо-українського словника:чернетка
Додано: 11 травня 2014, 00:34
Викладач
З нами з: 29 листопада 2013, 17:11 Повідомлення: 5033
Цитата:
Спочатку возився з клієнтською і серверною частиною (через Ajax), але на роботі через наявний http-проксі, схоже буферезуються всі запити від клієнта до серверу.
.Проблема була не з проксі, а з публікацією в ГуглСкриптс. Треба змінювати версію перед публікацією.
Тема повідомлення: Re: Розробка інтерактив. англо-українського словника:чернетка
Додано: 15 травня 2014, 18:48
Викладач
З нами з: 29 листопада 2013, 17:11 Повідомлення: 5033
Довго мучився з спілкуванням між клієнтом і сервером по Ajax, поки не зустрів таку фразу
Цитата:
XHR requests to the Google Apps Script server are forbidden, but you can use google.script.run to make AJAX-like requests to your script instead.
Отже відкрита технологія Ajax, яку я вже теоретично зрозумів, але практично до кінця не спробував залишається на майбутнє використання (наприклад для зв'язку з іншими інтернет-сервісами). Тим не менше для мене залишилося загадкою, чому сторінки завантажені з ГуглСкриптс серверу не працюють, а просто відкриті в браузері працюють принаймні частково (запити на сервер приходять, ідентифікуються). Переключаюся на Гугл-технологію google.script.run. Все що нас не вбиває, робить нас сильніше. (R) Ніцше
Зараз переглядають цей форум: Немає зареєстрованих користувачів і 1 гість
Ви не можете створювати нові теми у цьому форумі Ви не можете відповідати на теми у цьому форумі Ви не можете редагувати ваші повідомлення у цьому форумі Ви не можете видаляти ваші повідомлення у цьому форумі Ви не можете додавати файли у цьому форумі