1. Друзья, в это тяжёлое и непонятное для всех нас время мы просим вас воздержаться от любых упоминаний политики на форуме, - этим ситуации не поможешь, а только возникнут ненужные ссоры и обиды. Это касается также шуток и юмора на тему конфликта. Пусть войны будут только виртуальными, а политики решают разногласия дипломатическим путём. С уважением, администрация Old-Games.RU.

    Скрыть объявление
  2. Если Вы видите это сообщение, значит, вы ещё не зарегистрировались на нашем форуме.

    Зарегистрируйтесь, если вы хотите принять участие в обсуждениях. Перед регистрацией примите к сведению:
    1. Не регистрируйтесь с никами типа asdfdadhgd, 354621 и тому подобными, не несущими смысловой нагрузки (ник должен быть читаемым!): такие пользователи будут сразу заблокированы!
    2. Не регистрируйте больше одной учётной записи. Если у вас возникли проблемы при регистрации, то вы можете воспользоваться формой обратной связи внизу страницы.
    3. Регистрируйтесь с реально существующими E-mail адресами, иначе вы не сможете завершить регистрацию.
    4. Обязательно ознакомьтесь с правилами поведения на нашем форуме, чтобы избежать дальнейших конфликтов и непонимания.
    С уважением, администрация форума Old-Games.RU
    Скрыть объявление

Ajax function v2

Автор: Helmut · 20 июл 2020 · ·
  1. Другой вариант обертки Аякса. Вместо создания собственной разметки ответов и, соответственно, парсера для нее, попробуем использовать JSON с соответствующим функционалом.

    Структура будет иметь следующий вид:
    Код:
    {
        "element": [
            {
                "target": "test1",
                "property": "innerHTML",
                "method": "getElementById",
                "overwrite": "false",
                "html": {
                    "text": "text 1",
                    "array": null
                },
                "script": "alert('test1 alert')"
            },
            {
                "target": "test2",
                "property": "innerHTML",
                "method": "getElementById",
                "overwrite": "false",
                "html": {
                    "text": "",
                    "array": [
                        {"name": "new 1", "value": 1},
                        {"name": "new 2", "value": 2}
                    ]
                }
            }
        ],
        "cookie": [
            {"name": "cookie 1", "value": 1}
        ],
        "script": "alert('all alert')"
    }
    
    Значения свойств элементов оставляем почти все те же:
    target - id цели или CSS3 селектор;
    property - изменяемое свойство цели. По умолчанию - innerHTML;
    method - метод выборки цели. По умолчанию - getElementById. Поддерживаются методы getElementsByTagName, getElementsByName, getElementsByClassName, querySelector и querySelectorAll;
    overwrite - (true/false) указывает, перезаписывать или дополнять содержимое цели. По умолчанию true.
    html.text - собственно, html код, передающийся указанному свойству указанного элемента.
    html.object - а здесь пишем код для элементов, требующих js конструктор на стороне клиента. Например, элементы select или свойства style, setAttribute, classList.
    script - js скрипт, отправляемый на выполнение. Исполняется сразу после изменения свойств цели, в блоке которой был указан.
    bscript - на всякий случай. То же самое, только выполнится перед изменением свойств указанной цели.

    Кроме того, возможно указание общих для всех элементов функций:
    cookie - создаст указанную куки.
    script - js скрипт, исполняющийся после изменения свойств всех элементов.
    bscript - js скрипт, исполняющийся в самом начале, перед изменением свойств всех элементов.

    Все элементы структуры могут быть представлены как в виде массивов, так и в виде одиночных значений.

    На перловой стороне код будет выглядеть так:
    1. Инициализируем кодер json
    Код:
    #!/usr/bin/perl
    use JSON::XS;
    
    $coder = JSON::XS->new->utf8;
    my $json;
    @{$json->{element}} = ();
    
    2. Добавим куда-нибудь подпрограммы - конструкторы элементов. Для простоты.
    Код:
    sub html_element {
        my $el;
        $el->{target} = ($_[0]) ? $_[0] : '';
        $el->{property} = ($_[1]) ? $_[1] : 'innerHTML';
        $el->{method} = ($_[2]) ? $_[2] : 'getElementById';
        $el->{overwrite} = ($_[3]) ? $_[3] : 'true';
        $el->{html}->{text} = ($_[4]) ? $_[4] : '';
        $el->{html}->{object} = ();
        return $el;
    }
    sub html_select {
        my $el;
        $el->{'value'} = $_[0];
        $el->{'text'} = $_[1];
        if ($_[2] eq 'true') {
            $el->{'selected'} = true;
        }
        return $el;
    }
    sub html_attrib {
        my $el;
        $el->{'name'} = $_[0];
        $el->{'value'} = $_[1];
        return $el;
    }
    sub html_cookie {
        my $el;
        my %hash = @_;
        foreach my $key (keys %hash) {
            $el->{$key} = $hash{$key};
        }
        return $el;
    }
    
    3. Создаем, собственно, сами элементы
    Код:
    $element = html_element('div1');
    $element->{html}->{text} = $text1;
    $element->{script} = "alert('div1 alert')";
    push @{$json->{element}}, $element;
    
    $element = html_element('div1_class');
    $element->{property} = 'style';
    $element->{method} = 'getElementsByClassName';
    push @{$element->{html}->{object}}, html_attrib('width', '100px');
    push @{$json->{element}}, $element;
    
    $element = html_element('input1');
    $element->{property} = 'value';
    $element->{overwrite} = false;
    $element->{html}->{text} = $text2;
    push @{$json->{element}}, $element;
    
    $element = html_element('select1');
    push @{$element->{html}->{object}}, html_select(1, 'option 1');
    push @{$element->{html}->{object}}, html_select(2, 'option 2', true);
    push @{$json->{element}}, $element;
    
    $element = html_element('select1');
    $element->{property} = 'className';
    $element->{html}->{text} = 'class1';
    push @{$json->{element}}, $element;
    
    $element = html_element('select1');
    $element->{property} = 'classList';
    push @{$element->{html}->{object}}, html_attrib('add', 'newclass');
    push @{$element->{html}->{object}}, html_attrib('delete', 'oldclass');
    push @{$element->{html}->{object}}, html_attrib('toggle', 'class_2');
    push @{$json->{element}}, $element;
    
    $element = html_element('select1');
    $element->{property} = 'setAttribute';
    push @{$element->{html}->{object}}, html_attrib('src', 'aaa.bbb.ru');
    push @{$json->{element}}, $element;
    
    $json->{script} = "alert('all elements finish')";
    
    @{$json->{cookie}} = ();
    my $ctime = time + 600; #время актуальности +- секунды
    push @{$json->{cookie}}, html_cookie('name' => 'sid', 'value' => $val, 'expires' => $ctime);
    
    4. ну и отправляем все это в браузер
    Код:
    print "Content-Type: application/json\n\n";
    print $coder->encode($json);
    
    В браузере всю эту байду распарсит и применит должным образом такая вот функция:
    Код:
    function SendURL(url, frm, asp) {
       var data = SendURLattrib.form(frm);
       var xmlHttp = new XMLHttpRequest();
       var syn = (!asp || asp == '' || asp == 0) ? true : false; // 1 - синхронный
       xmlHttp.open("POST", url, syn);
       xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
       xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4) {
             var response = xmlHttp.responseText;
             if (xmlHttp.status == 200) {
                 try {var json = JSON.parse(response)}
                    catch {
                     console.log('Incorrect JSON response from '+url);
                     return;
                 }
                 SendURLattrib.eval(json.bscript);
                 if (json.element) {
                     var element = SendURLattrib.array(json.element);
                        for (var i = 0; i < element.length; i++) {
                            if (!element[i].target || element[i].target == '') continue;
                            if (!element[i].method || element[i].method == '') element[i].method = 'getElementById';
                            var obj = document[element[i].method](element[i].target);
                            if (obj) {
                                SendURLattrib.eval(json.element[i].bscript);
                                obj = SendURLattrib.array(obj);
                                if (!element[i].property || element[i].property == '') element[i].property = 'innerHTML';
                                if (!element[i].overwrite || element[i].overwrite != 'false') element[i].overwrite = 'true';
                                if (obj.length == 0) console.log('Not found targets for ' + element[i].target);
                                for (var j = 0; j < obj.length; j++) {
                                    if (!obj[j]) continue;
                                    if (obj[j].type == "textarea" && element[i].property == 'innerHTML') element[i].html.text = element[i].html.text.replace(/\\n/g, '\n');
                                    if (element[i].property == 'style' || element[i].property == 'setAttribute' || element[i].property == 'classList') SendURLattrib.attrib(obj[j], element[i]);
                                    else if (obj[j].type == "select-one" && element[i].property == 'innerHTML') SendURLattrib.select(obj[j], element[i]);
                                    else if ((element[i].property == 'innerHTML' || element[i].property == 'value') && element[i].overwrite == 'false') obj[j][element[i].property] += element[i].html.text;
                                    else obj[j][element[i].property] = element[i].html.text;
                                }
                                SendURLattrib.eval(json.element[i].script);
                            } else console.log('Error target for '+element[i].target);
                        }
                    }
                 SendURLattrib.eval(json.script);
                    if (json.cookie) {
                        var cookie = SendURLattrib.array(json.cookie);
                        for (var i = 0; i < cookie.length; i++) {
                            if (!cookie[i].name || !cookie[i].value) continue;
                            var ck = cookie[i].name + '=' + encodeURIComponent(cookie[i].value) + ';';
                            for (var pos in cookie[i]) {
                                if (pos == 'name' || pos == 'value') continue;
                                if (pos == 'expires') cookie[i][pos] = new Date(cookie[i][pos] * 1000).toUTCString();
                                ck += (' ' + pos + '=' + cookie[i][pos] + ';');
                            }
                            document.cookie = ck;
                        }
                    }
             } else console.log('Error Ajax request: '+xmlHttp.status+' from '+url);
          }
       }
       xmlHttp.send(data);
    }
    var SendURLattrib = {
        array(obj) {
            return (obj instanceof Array) ? obj : [obj];
        },
        eval(obj) {
            if (!obj) return;
            var scr = this.array(obj);
            for (var i = 0; i < scr.length; i++) eval(scr[i]);
        },
        form(frm) {
            var data = new FormData();
            //data.append('refer', document.getElementById('refer').value); //добавляем к каждому запросу
            if (document.cookie.length > 0) {
                var pairs = document.cookie.split(";");
                for (var i = 0; i < pairs.length; i++){
                    var pair = pairs[i].split("=");
                    data.append(pair[0], decodeURIComponent(pair[1]));
                }
            }
            data.append('random', Math.random());
            if (!frm || frm == '') return data;
            var arr = this.array(frm);
            for (var j = 0; j < arr.length; j++) {
                var elements = document.forms[arr[j]].querySelectorAll('input, select, textarea');
                for (var i = 0; i < elements.length; i++) {
                    if (!elements[i].name || elements[i].name == '') continue;
                    if (["text", "hidden", "password", "textarea"].includes(elements[i].type)) {
                        data.append(elements[i].name, elements[i].value);
                    }
                    if (elements[i].type == "radio" || elements[i].type == "checkbox") {
                        if (elements[i].checked) data.append(elements[i].name, elements[i].value);
                    }
                    if (elements[i].type == "select-one" && elements[i].selectedIndex >= 0) {
                        data.append(elements[i].name, elements[i].options[elements[i].selectedIndex].value);
                    }
                    if (elements[i].type == "file" && elements[i].files.length > 0) {
                        if (elements[i].getAttribute('multiple') == null) {
                            data.append(elements[i].name, elements[i].files[0]);
                        } else {
                            for (var e = 0; e < elements[i].files.length; e++) {
                                data.append((elements[i].name+'_'+e), elements[i].files[e]);
                            }
                        }
                    }
                }
            }
            return data;
        },
        attrib(obj, elem) {
            var res = this.array(elem.html.object);
            for (var i = 0; i < res.length; i++) {
                if (!res[i].name || !res[i].value) continue;
                if (elem.property == 'style') obj.style[res[i].name] = res[i].value;
                if (elem.property == 'classList') obj.classList[res[i].name](res[i].value);
                if (elem.property == 'setAttribute') obj.setAttribute(res[i].name, res[i].value);
            }
        },
        select(obj, elem) {
            var res = this.array(elem.html.object);
            if (elem.overwrite == 'true') obj.options.length = 0;
            for (var i = 0; i < res.length; i++) {
                if (!res[i].value || !res[i].text) continue;
                var opt = document.createElement("option");
                opt.appendChild(document.createTextNode(res[i].text));
                opt.setAttribute("value", res[i].value);
                if (res[i].selected && res[i].selected == 'true') opt.selected = true;
                obj.appendChild(opt);
            }
        }
    }
    
    Напоследок, надо на всякий случай отметить, что читать входящие данные в перле следует гибридным образом:
    Код:
    use CGI ':standard';
    
    my $buffer = $ENV{'QUERY_STRING'};
    my @pairs = split(/&/, $buffer);
    foreach $pair(@pairs) {
       my ($name, $value) = split(/=/, $pair);
       $value =~ tr/+/ /;
       $value =~ s/%([a-fA-F0-9][a-fA-f0-9])/chr(hex($1))/eg;
       $input{$name} = $value;
    }
    for my $name (CGI::param()) {
       for my $value (scalar CGI::param($name)) {
           $input{$name} = $value;
       }
    }
    
    kreol нравится это.

Комментарии

  1. HimeJVT
    Вот так не из буханки, даже, а из перловки можно сделать троллейбус. Но зачем?
    1. Helmut
      Надо.
Чтобы оставить комментарий просто зарегистрируйтесь и станьте участником!
  1. На этом сайте используются файлы cookie, чтобы персонализировать содержимое, хранить Ваши предпочтения и держать Вас авторизованным в системе, если Вы зарегистрировались.
    Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie.
    Скрыть объявление