Немного О Java Script В Клиенте (не Web)

alexas1

Lotus team
10.04.2014
734
149
#1
Обычно, JS в клиенте игнорируют. А зря.
Вот пример добавление на форму, практически, "дополнительного" onChange Event для произвольного количества обычных полей ввода, который позволяет очень просто работать с вводимыми данными OnFly.
Просто добавить маленький код в JS Header и прописать в нём контролируемые поля.
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">JS Header</div></div><div class="sp-body"><div class="sp-content">
Код:
var enterFields = ["field1", "field2", "field3"];
var f = document.forms[0];
//===============================================
function checkField ()
{
try{
for (i = 0; i < enterFields.length; ++i)	{ //просматриваем все поля ввода из списка "enterFields"
var tmpval = f[enterFields[i]].value.replace(/\./g,",") //замена точки на запятую
tmpval = String(tmpval.match(/-?\d*\,?\d*\n?/)) //любое кол-во цифр
// tmpval = String(tmpval.match(/-?\d?\d?\d?\d?,?\d?\d?\d?\n*/)) //макс. 7 цифр всего (макс. 3 знака после запятой)
if(tmpval.indexOf("\n")!=-1)	{ //если нажат ENTER
if (tmpval.charAt(tmpval.length-2)==","){tmpval = tmpval.slice(0,-2)}	//удаляем запятую, если после неё ничего нет
if(i < enterFields.length-1){f[enterFields[i+1]].focus()}; //переводим фокус на следующее поле если оно не последнее
tmpval = tmpval.replace(/\n/g,""); //убираем перевод строки
// f.MyButton.click();		//действия по ENTER-у кодом в "MyButton"
}
f[enterFields[i]].value = tmpval
}
}
catch(e){}
setTimeout('checkField ()', 100)	
}
checkField ()
field1-field3 - поля в которые добавили "ивент".
Пример на лету:
заменяет точку на запятую (юзер не задумывается о правильности ввода числа),
не даёт вводить ничего, кроме цифр и "минуса"
не даёт вводить перевод строки (по Enter переходит на следующее поле ввода).

Преимущества:
весь код форматирования/проверки в одном месте,
100% интерактив,
доступны все прелести RegExp - произвольное форматирование введённого "на лету",
просто дифференцировать нужные действия в полях с помощью switch case (в примере нет)

Пока глюков замечено не было. Пара десятков контролируемых полей плюс десяток открытых доков с этим функционалом клиент не нагружают никак (client v9). Уменьшение Timeout до 1мс. ничего не рушило.
=================================================
P.S.
Это просто иллюстрация техники.
Не используйте этот код в боевой базе - утечка памяти!!!
Ниже - код без бага.
 

lmike

нет, пердело совершенство
Lotus team
27.08.2008
6 599
277
#2
код маньячит по доку, по таймеру, не внимая отсут. изменений в полях?
может стоило закешировать содержимое и проверять на отсут. изменений...
 

erdi

Well-known member
20.08.2008
265
17
#3
JS в клиенте стараюсь использовать во временных(диалоговых) формах, т.к. если курсор будет находится долгое время(от 15-40 минут по разному бывало) в поле на форме, которую забудет закрыть пользователь, то тогда в клиенте вылетает ошибка JS и клиент начинает вообще чудить, игнорируя даже код на LS. Помогает только перегрузка клиента.

Для постоянной формы(у меня такая стартовая страница и на ней есть поле поиска сотрудников) я специально дополнил эту функцию счетчиком, которая делает итерацию при каждом вызове функции checkField () и если достигнут предел, то обнуляет счетчик и убирает фокус с этого поля, чтобы JS код больше не выполнялся
 

garrick

Lotus team
26.10.2009
911
61
#4
Ну, раз пошла такая пьянка, то и про CSS напиши что-нибудь.
 

savl

Lotus team
28.10.2011
2 136
105
#5
garrick
Не под web CSS можно использовать только для цвета в таблицах и глобально для формы цвет всех таблиц.
Игрался тут, пытался сделать разный шрифт - не работает :D
 

alexas1

Lotus team
10.04.2014
734
149
#6
... в клиенте вылетает ошибка JS и клиент начинает вообще чудить ...
Это утечка памяти.
100% у Вас в коде есть "замыкания", которые и приводят к утечкам. Это не проблема нотуса - это особенности JS.
Менеджер памяти в нотусах не работает полностью в RealTime - он чистит память с периодичностью примерно 30 минут.
Если утечки забили память до 50 Мб (примерно), а нотус не успел её освободить, клиент упадёт.
Что у Вас и происходит.
setInterval/setTimeout однозначно создают утечки:
при передаче функции в setInterval/setTimeout создаётся внутренняя ссылка на неё, через которую клиент(браузер) её будет запускать. Поэтому функция остаётся жить, даже если других ссылок на неё нет.
Для setTimeout — внутренняя ссылка должна исчезнуть после исполнения функции.
Для setInterval — ссылка должна исчезнуть при очистке таймера.
Но нотус НЕ ДЕЛАЕТ этого RealTime! Надо озаботиться этим самому.
Для setTimeout я нашёл решение проблемы в нотусах - необходимо чистить объект setTimeout перед каждым запуском. Причём делать это надо не там, где описана вызываемая функция, а, например, в коде кнопки (ХЗ, почему так :angry2: )
Для кода, который я предложил, чтобы полностью устранить утечки памяти, надо заменить setTimeout('checkField ()', 100) на f.repeatFunction.click()
А в кнопе, с HTML Name = repeatFunction, поместить скрипт:
Код:
clearTimeout(timeoutID)
delete timeoutID
timeoutID = setTimeout('checkField()', 100)
И, конечно, определить timeoutID, как глобальную переменную var timeoutID
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Скрипт БЕЗ утечек памяти</div></div><div class="sp-body"><div class="sp-content">
Код:
var enterFields = ["field1", "field2", "field3"];
var f = document.forms[0];
var timeoutID;
//===============================================
function checkField ()
{
try{
for (i = 0; i < enterFields.length; ++i)	{ //просматриваем все поля ввода из списка "enterFields"
var tmpval = f[enterFields[i]].value.replace(/\./g,",") //замена точки на запятую
tmpval = String(tmpval.match(/-?\d*\,?\d*\n?/)) //любое кол-во цифр
// tmpval = String(tmpval.match(/-?\d?\d?\d?\d?,?\d?\d?\d?\n*/)) //макс. 7 цифр всего (макс. 3 знака после запятой)
if(tmpval.indexOf("\n")!=-1)	{ //если нажат ENTER
if (tmpval.charAt(tmpval.length-2)==","){tmpval = tmpval.slice(0,-2)}	//удаляем запятую, если после неё ничего нет
if(i < enterFields.length-1){f[enterFields[i+1]].focus()}; //переводим фокус на следующее поле если оно не последнее
tmpval = tmpval.replace(/\n/g,""); //убираем перевод строки
// f.MyButton.click();		//действия по ENTER-у кодом в "MyButton"
}
f[enterFields[i]].value = tmpval
}
}
catch(e){}
f.repeatFunction.click() //!!! Тут убираем утечку памяти !!!///
}
checkField ()
Скрипт клиента не обрушит - утечек нет совсем. Проверьте. Для жёсткости, можете выставить Timeaut в 1 мс. :)
 
Симпатии: Понравилось kolka

alexas1

Lotus team
10.04.2014
734
149
#7
код маньячит по доку, по таймеру, не внимая отсут. изменений в полях?
может стоило закешировать содержимое и проверять на отсут. изменений...
Походу, это ничего не даст.
Самые большие накладные расходы, это чтение инфы из полей.
match и replace - выполняются мухой.
А ограничивать чтение из дока только полем в котором находится курсор - это задействовать штатные ивенты.
Прописывать ивенты у двух десятков полей - не comme il faut, от этого и хотелось уйти.
Быстродействие современных компов позволяет иногда халатно относиться к производительности скрипта. :angry2:
 

savl

Lotus team
28.10.2011
2 136
105
#8
Быстродействие современных компов позволяет иногда халатно относиться к производительности скрипта.
Заблуждение.
Если код перегружен, то даже самый быстрый комп будет тупить.
 

alexas1

Lotus team
10.04.2014
734
149
#9
Заблуждение.
Если код перегружен, то даже самый быстрый комп будет тупить.
Ключевое слово было - "иногда".
Я говорю об этом конкретном скрипте. А вообще, на производительность ВСЕГДА обращаю внимание.
К тому же он возник у меня случайно, в процессе обучения товарища и об оптимизации не думал.
Хотя, на вскидку, наверное, попробую использовать.
На моём Core 2 Duo 2.00 GHz нагрузка на проц - 8% (20 контролируемых полей с периодом 100 мс.) хороший вариант.
Сам скрипт жрёт всего 300 кб оперативки.
Утечки памяти нет.
 

garrick

Lotus team
26.10.2009
911
61
#10
garrick
Не под web CSS можно использовать только для цвета в таблицах и глобально для формы цвет всех таблиц.
Игрался тут, пытался сделать разный шрифт - не работает :angry2:
Это конечно "да", но тема сисек CSS осталась нераскрытой. :)
И, кстати, если таблицы Read Only, то можно их в виде HTML, с тем же CSS, положить в Computed Text. Можно сделать очень красиво.
А если у вас вся форма в таблице?
 

alexas1

Lotus team
10.04.2014
734
149
#11
Это конечно "да", но тема сисек CSS осталась нераскрытой....
С CSS я Вам уже не помогу - лень ковыряться :angry2:.
Сам стал писать хепаги, а там проблем в клиенте с CSS нет (ну, почти нет :) )
Хотя всякие интерфейсные фишки в классике иногда всплывают - в доработке старья. (вот как сейчас)
 

savl

Lotus team
28.10.2011
2 136
105
#13
C++:
window.setInterval("runRefreshWindow();", 100);
тоже создаст утечку памяти?
 

savl

Lotus team
28.10.2011
2 136
105
#15
JS Header
C++:
function runRefreshWindow()
{
var nr = "";
nr = window.document.forms[0].ndRefresh.value;
if (nr == "1") {window.document.forms[0].btnRefresh.click()}
}
onLoad
C++:
window.setInterval("runRefreshWindow();", 100);
Кнопка:
Код:
Sub Click(Source As Button)
If currUIDoc.EditMode Then
Call currDoc.ReplaceItemValue("ndRefresh","0")
Call currUIDoc.Refresh
End If
End Sub
currDoc и currUIDoc - глобальные объекты формы, получены в postOpen

Добавлено: Поколбалисо форум =)
Я не силен в JS, поэтому если можно улучшить, чтобы клиент вдруг не падал или что еще - буду благодарен.
 

ty3uk

Well-known member
31.03.2008
170
0
#16
я не помню поборол-ли я этот момент, но, вроде, поставил какой-то счётчик, и при подходе счётчика к топовым значениям, перезапускаю проверку.
Вот не помню, сделал-ли я такое, и помогло-ли. Но, думаю, идея понятна.
А, блин, выше-же описан данный вариант....
 

alexas1

Lotus team
10.04.2014
734
149
#17
... улучшить, чтобы клиент вдруг не падал или что еще ...
Сорри, за молчок - отпуск.
В нарисованном варианте, утечек не будет.
Только есть одно но: если будет запущенно 2 или больше setInterval с периодом 100 - клиент выдаст ошибку компиляции JS (через некоторое время).
Я бы сделал по-другому (из давней практики):
JS Header - пустой.
onLoad - setInterval('document.forms[0].btnRefresh.click()', 250) (на onLoad - потому, что при запуске из Header, кнопы на форме ещё нет)
В кнопе:
If currDoc.ndRefresh(0) = "1" Then
currDoc.ndRefresh = "0"
Call currUIDoc.Refresh
End If

Проверять EditMode смысла нет - на чтении ndRefresh просто не изменится.

button.click выполняется шустро, нет смысла его запускать по условию - быстродействие не пострадает.
Да и всю логику держать в одном месте наглядней (в кнопе)

250мс позволит запустить 5 одновременных сетинтервалов без гемора.
500 - соответственно 10 и тд.
Ну, или запрещать интерфейсно запуск нескольких setInterval (если маленькое время цикла), что не айс.
Тут проблема с возможным наложением обработки нотусом последовательного запуска функции из setInterval.

P.S.
Ещё момент, если скрипт в кнопе долгий, надо проверять выполнилась ли предыдущая итерация полностью.
Для doc.Refresh (если форма сложная и пересчёт полей может занять ощутимое время) можно завести, для контроля, служебное computed поле в самом низу формы в котором значение изменяется при рефреше (ну и чистить его после проверки в кнопе)
 

maliy

Well-known member
20.03.2007
168
2
#18
Пробую код в 6 посте. Код вставил в JS header формы.
Но выдает Error: ToObjectError: f.repeatFunction has no properties.
В чем проблема?
 

maliy

Well-known member
20.03.2007
168
2
#20
Да, кнопка есть HTML- > Name - repeatFunction
в ней код (Client, JavaScript):
clearTimeout(timeoutID)
delete timeoutID
timeoutID = setTimeout('checkField()', 100)