• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

    На последнюю неделю приходится экзамен, где нужно будет показать свои навыки, взломав ряд уязвимых учебных сайтов, и добыть флаги. Успешно сдавшие экзамен получат сертификат.

    Запись на курс до 25 апреля. Получить промодоступ ...

Статья jQuery для Lotus Domino в простых примерах

В этой статье не пойдет речь о сложных вещах, а, скорей всего, о простых, но, которые забываются. Лично я, к проектам подхожу крайне редко, поскольку, однажды сделанное работает годами и через некоторое время уже не помнишь, чего же ты там написал. Для апологетов xPages есть специальная ветка, скажу только, что с помощью jQuery и на седьмом дизайнере 2009 года, вполне, можно создавать сайты любой сложности. А разговоры о смерти технологии Domino, вообще, пустые, покуда работают в интернетах CGI переменные, куки и волшебный Set ctx = ns.DocumentContext в Lotus Script (с). Коснемся немного общих вещей не связанных с jQuery, которые помогут новичками, и вспомнить тем, кто в теме. Итак, поехали...

1. Флажок доступа из WEB использовать JavaScript.

28216


По умолчанию генерит на формах по которым создаются документы вот такой код и открывает паразитный тег form, о котором говорилось здесь Удаление автоматического тега <form action="">.

Код:
<script language="JavaScript" type="text/javascript">
<!--
document._domino_target = "_self";
function _doClick(v, o, t, h) {
var form = document._Cart;
if (form.onsubmit) {
var retVal = form.onsubmit();
if (typeof retVal == "boolean" && retVal == false)
return false;
}
var target = document._domino_target;
if (o.href != null) {
if (o.target != null)
target = o.target;
} else {
if (t != null)
target = t;
}
form.target = target;
form.__Click.value = v;
if (h != null)
form.action += h;
form.submit();
return false;
}
// -->
</script>

Уберите эту галочку 'использовать JavaScript '. Она не нужна. На документах по форме добавьте в код страницы

<script>$(function() { $('body > form').remove(); });</script>
и на form?open тоже это пригодиться, чтобы прибить

<form><p><input type="submit" value="Отправить"></form>
в конце страницы.

2. Помните, что страницы и формы дизайна могут быть открыты как page?open по имени или алиасу. Если проектируете форму для web и notes, обзывайте их как MainTopicWEB | MainTopic - только для WEB и алиас MainTopic только для Notes. Если page будет страница - откроется страница, если форма, то форма, если агент, то агент.
28200

В этом примере по формам HomePage, MainTopic и Hand-Book создаются страницы сайта и формы имеют специальное поле SaveOptions="0", блокирующее создание по ?create и $V2AttachmentOptions="0", блокирующее показ аттачментов на вебе. По форме Feedback Anonymous может создавать документы, но дальше идёт проверка агентом по WQS и поле SaveOptions устанавливается в 1 или док сохраняется через .Save. В особенных случаях добавляйте поля влияющие на $Readers. Пример организации структуры базы .

3. Внутри объекта задавайте тип содержимого для AJAX доступа. Пример страницы для вывода json ответа.

28201


Код:
// Добавляем новый метод валидации checkEmail дополнительно к  https://jqueryvalidation.org/
$.validator.addMethod("checkForbiddenEmail", (function() {
var isEmailValid;
isEmailValid = false;
var url = 'doLookup?open&email=' + $("#Email").val();
$.ajax({
cache: false,
url: url,
type: 'post',
datatype: "application/json",
async: false,
success: function(resp) {
//alert ($("#Email").val() +" "+resp.email);
if (resp.email === 'forbidden') {
isEmailValid = false;
} else {
isEmailValid = true;
}
}
});
return isEmailValid;
}), "");


4. Если вам нужен доступ к полям Notes, то вместо страницы используйте форму, но открывайте ее как form?readform

28202


Тогда AJAX доступ будет такой
Код:
 $.get(url+"?readform&cat="+cat+"&start=1&count="+onimod_viewstart+"&max="+onimod_viewcount)
.success( function(html){
$(id).hide().fadeIn().html(html); //Load content to id


5. Просто вызывайте агенты как agentname?open, но помните, что его имя не должно конфликтовать со страницей, формой или другим элементом дизайна ибо контейнер открывает по имени.
Код:
 datarc = тут что-то собранное с формы
var url = 'doAddToCart?Open'+'&shopcart=' + shopcart;
$.ajax({
cache: false,
url: url,
type: 'post',
data: datarc, // в простом агенте вытаскивается как ctx.Request_Content(0)
datatype: "application/json",
success: function(resp){
if ( resp.update == '1' ) {

Где внутри Lotus Script

Код:
Dim web As New WebSession() ''http://tanny.ica.com/ICA/TKO/tkoblog.nsf/dx/websession-agent-class
argData = web.session.DocumentContext.Request_Content(0) ''Аргументы, переданные со страницы в datarc
username = web.session.DocumentContext.Remote_User(0) ' имя юзера, Anonymous = ""
shopcart = web.getQueryStringValue("shopcart") ''id корзины юзера _doExtractCookie('shopcart');

Items = explode(argData, "&")

Function explode(Byval strSource As String, delimiter As String) As Variant 'array of strings

    Dim values() As String, idxDelimiter As Integer, idx As Integer
    idx = 0
    idxDelimiter = Instr(strSource, delimiter)

    While (idxDelimiter > 0)
        Redim Preserve values(idx)
        values(idx) = Left(strSource, idxDelimiter - 1)
        strSource = Mid(strSource, idxDelimiter + Len(delimiter))
        idx = idx + 1
        idxDelimiter = Instr(strSource, delimiter)
    Wend

    Redim Preserve values(idx)
    values(idx) = strSource

    explode = values

End Function

и json ответ
Код:
 ''Ответ для $.ajax
Print |Content-type: application/json; charset=utf-8|
Print ||
Print |{"shopcart":"|+shopcart+|","user":"|+userflag+|","items":|+Cstr(countitems)+|,"cartitems":|+Cstr(orderCollectionCount)+|,"update":"|+Cstr(update)+|"}|

Можно не заморачиваться с классом WebSession() и писать просто
Код:
Set ctx = ns.DocumentContext
Msgbox "ctx.Request_Content(0)" +ctx.Request_Content(0)
Msgbox "sessionID " +shopcart
Msgbox "ctx.DBID(0) "+ctx.DBID(0)
Msgbox "ctx.Copy " + ctx.Copy(0)
Msgbox "ctx.Pseudo" + ctx.Pseudo(0)
Msgbox "ctx.CheckFile "+ctx.CheckFile(0)


6. Для обработки в агенте контекста документа содержимого формы HTML, объявляйте Notes поля на форме или подформе и пишите их HTML алиас - сильно упростите себе жизнь, особенно там, где Notes поля не позволяют написать расширенный HTML5 и форму отправки можно будет разместить в любом месте страницы не открытой на редактирование. Контекст этой формы feedback?create обрабатывается по аналогии п.5, но с особенностями описанными в п.7. Без объявления Notes поля, например, контекст ctx.Type(0) будет пустой.

28203


28205


7. Документы создаются командой form?create, где в форме можно указать запуск агента по WQS и передать дальше управление на поле $$Return или вывести json в самом агенте. Но в агентах запускаемых по WQS формы не работает json ответ оформляемый как 'Print |Content-type: application/json; charset=utf-8| 'Вываливается Error 200. Оформляйте его как text/html

Код:
Print |Content-type: text/html; charset=utf-8| ' success: function(html){var data = JSON.parse(html) alert (data.user);
Print ||
Print |{"shopcart":"|+sessionID+|","user":"|+ctx.Pseudo(0)+|","email":"|+ctx.Email (0)+|","checkboxcopy":"|+ctx.Copy(0)+|","msg":"|+ctxType+|","error":"|+ErrorMsg+|"}|
End If

Call AgentLog.Close

Exit Sub

ErrorHandler:
Call AgentLog.Close
'Print "Ошибк а #:" + Str(Err)+ " line: "+ Cstr(Erl)
'Print ErrorCode
Print |Content-type: text/html; charset=utf-8| ' success: function(html){var data = JSON.parse(html) alert (data.user);
Print ||
Print |{"error":"|+"Ошибк а #:" + Str(Err)+ " line: "+ Cstr(Erl) + " "+ ErrorCode +|"}|
Exit Sub

И обработка AJAX через JSON.parse

Код:
    url = feedback?create;
    formcontent = $(form).serialize(); // serializes the form elements such Notes form!
            //Length of a string literal    16,267 characters (32,000 bytes).
            cl = $('#Content').val().length;
             //$.toast('Размер содержимого '+ cl );
          if ( cl > 4000)  {
            $.msgbox('<span class=msgbox_rb>Очень большое сообщение длиной '+cl+'. Пожалуйста, сократите до 4000 </span>',4);
            }else{
            $(idmsg).html("<div id='"+idmsg+"_bar'><img src='images/lightbox-ico-loading.gif'></div>");  //loading bar
$.ajax({
url: url,
type: 'post',
cache: false,
data: formcontent, // в агенте WQS вытаскивается через Set ctx = ns.DocumentContext 
dataType: "html", //also in agent Print |Content-type: text/html; charset=utf-8|
success: function(html){
var data = JSON.parse(html); //работает !!!
//alert (data.user); //работает
if ( data.error=='0' ) {

Может быть я что-то упустил, но у меня по-другому пункт 7 не заработал.

8. Если есть возможность писать код <script language="JavaScript" type="text/javascript"> в HTML - пишите, так как в специальных секциях подформ он может не работать, также как и на формах с $$ типа $$ReturnGeneralError.

9. Используйсте скрытое поле $$HTMLFrontMatter и пишите в нем "<!DOCTYPE html>" чтобы убить по умолчанию в заголовке сервера <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

10. Используйте последнюю версию jQuery jq:="<script src=\" "></script>"; в содержимом заголовка HTML формы или в общем поле $$HTMLHead и да прибудет с вами сила.

Если в эту ветку еще подтянутся старшие товарищи — будет только хорошо.

ps: И еще. Не используйте конструкции открытия view через $$ViewBody на формах типа $$ViewTemplate for Viewname. Просто не используйте. На вебе вы не избавитесь от парзитного <meta name="robots" content="noindex"> и Гугл вам об этом скажет. Создайте страницу и грузаните туда что хотите через $(id).load(url + " #content")
 

rinsk

Lotus Team
12.11.2009
1 151
125
BIT
3
Чем хоршо в классик веб - можно быстренько накидать на форму полей, и вот оно - уже и работает. Причем работает очень шустро и под большой нагрузкой.
+ удобно делать конфиг БД ... у меня там например минимум 150 типов сущностей, и объем доков под 100к...
Согласен, что это уже анахронизм и нужно переходить на что то типа React+ бакэнд...
Но тут возникает интересный момент - если в классике бакэнд фактически нативно серелизует во фронт документы, то при
типа микросервисной архитектуре возникает прослойка нечто такого, что возвращает JSON например и нечто такое, что рисует это на морде лица.
В итоге получается медленнее @DbLookup в Select на форме...
 
  • Нравится
Реакции: NetWood

alexas1

Green Team
10.04.2014
1 202
225
BIT
36
можно быстренько накидать на форму полей, и вот оно - уже и работает
в икспейджЭ тоже самое - справа вверху, в дезигнере, список полей, дёргаешь на страницу драгдропом и всё работает и "бакэнд фактически нативно серелизует во фронт документы"
такшта, это кто к чему привык)
 

NetWood

Lotus Team
17.04.2008
545
93
BIT
8
бакэнд фактически нативно серелизует во фронт документы
хорошая замена $(form).serialize(), да. Только очень толстая и неповоротливая.

Посмотрел я один раз на xPages содержимое страницы HTML и до сих пор развидеть не могу. А почитаешь профильную ветку, так сплошь глюки и баги. Не хочу тратить на это время.
На LS, также как и на jQuery, написаны тонны кода. Адаптивных шаблонов тоже валом. Накидал полей, подключил плагины, стили и все. Только логику контейнера прикрутить. Не хватает 64G базы? OMG - раскидайте на несколько. И новые версии LN с Java8, вообще, рука-лицо.
 

alexas1

Green Team
10.04.2014
1 202
225
BIT
36
Все это хорошо со свежаком, но посмотрел я один раз на xPages содержимое страницы HTML и до сих пор развидеть не могу. А почитаешь профильную ветку, так сплошь глюки и баги. Не хочу тратить на это время.
Никто не мешает использовать икс Пейдж только как вход: дожо не нужно - отключаешь, жыквери / реакт нужен - подключаешь, не нравицца коре контролы с экстлибом - подключай какие хошь свои, но у тебя есть по умолчанию нотусёвые классы для джавы в бэке и фронт, какой закажешь....
Кста, ты никогда не смотрел страничку задизайненную на реакте? Ну так погляди))))
 

rinsk

Lotus Team
12.11.2009
1 151
125
BIT
3
в икспейджЭ тоже самое - справа вверху, в дезигнере, список полей, дёргаешь на страницу драгдропом и всё работает и "бакэнд фактически нативно серелизует во фронт документы"
такшта, это кто к чему привык)
Эт все хорошо конечно, но jsf жрёт память как не в себя. Если нужно state full на бакэнде, то можно и без jsf обойтись. Тестовая форма на 32 гб сервере и ок 800 юзверей поставила сервак в раскоряку.
Я не против xPage как такового - может просто я его не умею готовить, но точно след проекты попробую на реакте и тп..
 

NetWood

Lotus Team
17.04.2008
545
93
BIT
8
Сейчас, вообще, время всяких реактов, но хочу напомнить, что в этом топике идет речь о решении задачи таким образом, чтобы работало год, два, три, пять, десять на основе продуктов, имеющих сопоставимое или более продолжительное время жизни.

Давайте не будем устраивать очередной срач по поводу технологий, где каждая последующая версия несовместима с предыдущей в течение уже нескольких кварталов и требует привлечение уникальных специалистов за сто-пятьсот миллионов всяких единиц и сочиняющих диковинные интерфейсы, которые не продают или тупо не выполняют свою задачу, но круто написано. Для этого есть специальные ветки. Сайты на Domino реактивны уже сами по себе :). Если есть примеры по теме топика — пожалуйста, пишите.
 

rinsk

Lotus Team
12.11.2009
1 151
125
BIT
3
есть кой чего про автосгенерированный JS в п1.
Иногда он нужен - например накидать с десяток взаимосвязанных селектов и полей.
События ._doClick можно перехватить.
JavaScript:
if (!window._doClickNew && window._doClick) {
        window._doClickNew=window._doClick
        window._doClick=window.newDoClick
}
function newDoClick(v, o, t, h){
/// вот тут код который нифга не вставляется!!!
   fields_store(stored_content)
   window.sessionStorage.setItem('$RefreshPoz',$(document).scrollTop())
   
    return window._doClickNew(v, o, t,h)
}
у меня там при рефреше сохраняются "динамические" поля и убирается в диалогах "дергания интерфейса"
 
Последнее редактирование:

rinsk

Lotus Team
12.11.2009
1 151
125
BIT
3
Мое следующее имхо:
НЕ использовать агента на QS !
Оно срабатывает зачастую и без валидации форм.
Лучше поставить кнопку с display:hidden и кликать после валидатора
Можно сграбить его параметры после загрузки и грохнуть (стащить типа этого: return _doClick('C3257E0D0043402C.b942c759c1e64f5845258275003df35f/$Body/0.2E76', this, null) ).
формула кнопки типа -
@Do(@Command([ViewRefreshFields]);
@Command([RunAgent];"(QSEvent)"))
 

NetWood

Lotus Team
17.04.2008
545
93
BIT
8
Оно срабатывает зачастую и без валидации форм.
Не встречал, но в нем самом куча проверок, начинающихся, например, с
''Без argData не стартуем. DDOS Заглушка запуска агента напрямую из браузера, чтобы не наплодилось лишних доков
If Len(argData) = 0 Then
If Len(SessionID) < 32 Then
Или если капча не пройдена, то шлет в пеший тур хитрецов сабмитящих без скриптов.
А так, да. Параметров не хватает по WQS, но они заливаются в контексте без проблем. В п.6 DocUNID, например.

Опять же не светим имя агента, по возможности. Тот же jqueryvalidation срабатывает тупо по сабмиту и этого достаточно вполне. От этого в примере кнопка только сложная, а . Допиливается легко.

JavaScript:
/* Lotus Domino by NetWood code 2019*/
/* Проверяет валидацию полей и капчу на форме */
/* требует <script src='../jquery/dist/jquery.validate.js'></script><script src='js/jquery.dovalidateform.js'></script> */

// Валидация
//$(function() {  
//    doValidateForm('#Feedback','cart?create','#content_load');
//});

function doValidateForm(form,callurl,idmsg) {          
         var validator = $(form).validate({
            ignore: "",
            rules: {
                Pseudo: {
                    required: true,
                    minlength: 3
                },
                Email: {
                    required: true,
                    email: true,
                    checkForbiddenEmail: true
                },
                Type: "required",
                    Captcha: {
                         required: true
                    },
                Content: {
                    required: true,
                    minlength: 10
                }
            },
            errorPlacement: function(label, element) {
                // position error label after generated textarea
                if (element.is(":checkbox"))  {
                    label.insertAfter(element.next());
                } else {
                    label.insertAfter(element)
                }
            },
            messages: {
                Pseudo: {
                    required:  "Пожалуйста, назовитесь",
                    minlength: "Имя должно быть не менее 3-x символов"
                },
                Email: {
                     required:  "В этом поле нужен адрес электронной почты для обратной связи",
                     email: "Email должен быть в правильнои формате",
                    checkForbiddenEmail: "Этот Email забанен"      
                },
                Type: "Надо указать вид сообщения для смысла",
                Captcha: {
                    required:  "Число?",
                },
                Content: {
                    required:   "В этом поле надо написать что-нибудь для нас",          
                    minlength: "Желательное содержание не менее 10-и символов"
                }
            },
              submitHandler: function(form) {              
                        // Check captcha
                      var url = 'doCapcha?open&unid=' + $("#DocUNID").val()+'&captcha='+ $("#Captcha").val();
                      $.ajax({
                        cache: false,
                        url: url,
                        type: 'post',
                        datatype: "application/json",  
                        async: false,
                        success: function(resp) {
                          if (resp.confirm === "YES") {                        
                            doFormSubmit(form,callurl,idmsg); //собственно отправка формы
                            //$("#Captcha").attr("placeholder", "Ответ правильный");      //и далее перезагружаем капчу в doFormSubmit
                            $("#Captcha").removeClass('red');
   
                            //alert('valid form submitted');
                                //return true; //submit                
                             //return false; //отладочное stop            
                           
                              } else {
                            $.msgbox('<span class=msgbox_rb>Ответ на проверочный код неправильный</span>');

                            //$('input[name*="Captcha"]').val('');
                            document.getElementById('Captcha').value='';
                            $("#Captcha").attr("placeholder", resp.expression);
                            $("#Captcha").addClass('red'); //Add a class so that placeholder will be red.
                          }
                        }
                      });                                    
             }
         }); //validate
       
        validator.focusInvalid = function() {
            // put focus on submit validation field
            if (this.settings.focusInvalid) {
                try {
                    var toFocus = $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []);
                    toFocus.filter(":visible").focus();
                } catch (e) {
                    // ignore IE throwing errors when focusing hidden elements
                }
            }
        }
    };

// Добавляем новый метод валидации checkEmail
$.validator.addMethod("checkForbiddenEmail", (function() {
  var isEmailValid;
  isEmailValid = false;
  var url = 'doLookup?open&email=' + $("#Email").val();
  $.ajax({
    cache: false,
    url: url,
    type: 'post',
    datatype: "application/json",  
    async: false,
    success: function(resp) {
      //alert ($("#Email").val() +" "+resp.email);
       if (resp.email === 'forbidden') {
        isEmailValid = false;
     } else {
        isEmailValid = true;
      }
    }
  });
  return isEmailValid;
}), "");
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 940
609
BIT
210
Тестовая форма на 32 гб сервере и ок 800 юзверей поставила сервак в раскоряку.
вызывал хэпагу для передачи серверу бинарников (код выкладывал) в 100 потоков, 5К документов с вложениями, сервер не чихает даже, логи засрал, но это сам виноват - вывожу месюги в консоль
полагаю и обратно десериализовать - нет ограничений
на мой взгляд быстрее чем с ЛС агентом (замеры не проводил), хотя бы потому, что нет промежуточных сохранений файла

ссылка на код
 

rinsk

Lotus Team
12.11.2009
1 151
125
BIT
3
вызывал хэпагу для передачи серверу бинарников (код выкладывал) в 100 потоков, 5К документов с вложениями, сервер не чихает даже, логи засрал, но это сам виноват - вывожу месюги в консоль
полагаю и обратно десериализовать - нет ограничений
на мой взгляд быстрее чем с ЛС агентом (замеры не проводил), хотя бы потому, что нет промежуточных сохранений файла

ссылка на код
Не не - передача файлов - это не спортивно:) Есл понадобится, то так и сделаю - через xagent...
Речь идет о форме с десятком взаимосвязанных полей, много селектов, значения выбора и само их появление зависят друг от друга.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!