За последние 24 часа нас посетили 55114 программистов и 1784 робота. Сейчас ищут 880 программистов ...

text 2 JSON

Тема в разделе "JavaScript и AJAX", создана пользователем Koc, 2 май 2009.

  1. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    Есть форма отправки файлов, через iframe.
    по окончании загрузки этого iframe берется его содержимое. Его нужно преобразовать в JSON.

    Простой eval('('+ данные из iftame + ')') подходит, но только для очень примитивных объектов. Когда в одном из них хранится html, преобразовать в JSON не получается.

    Я решил делать немного по-другому. Выводить в iframe не просто JSON а его base64 строку. Потом ее декодировать и сделать eval. Из недостатков - отсутствие нормальной поддержки кириллицы.

    Тогда перед тем как делать на сервере base64 encode я конвертирую строку из win1251 в utf8. На клиентской стороне это дело дешифруется и декодируется.


    Внимание вопрос: можно ли это сделать по-другому, без плясок с бубном как сейчас?
     
  2. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    На сервере делай escape кавычек, которые используются в javascript
     
  3. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Юзай jQuery =)
     
  4. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    [vs]
    ну собсно говоря я так и делаю.
    Покажи более нормальное решение сабжа
     
  5. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Делал я как-то аякс-интерфейс добавления объявления о продаже автомобиля, вот кусок:
    [js] new Ajax_upload('#car-foto-upload1',
    {
    action: '/system/php/document8110.php?uploadcarfoto=1&edit=' + document.getElementById('OnEdit').value,
    name: 'foto',

    onSubmit: function(file, extension) {
    },

    onComplete: function(file, response) {
    //$('#debug').html(response);
    var resp = eval('(' + response + ')');
    var fotoId = resp['id'];
    $("#car-small-foto1").attr('src', '/files/8088/small_sale_' + fotoId + '_foto.jpg?' + Math.round(Math.random()*100000));
    $("#showFoto1").attr('href', '/files/8088/sale_' + fotoId + '_foto.jpg?' + Math.round(Math.random()*100000));
    $("#car-foto-upload1").attr('value','Изменить...');
    $("#showFoto1").attr('alt', "Просмотреть");
    $("#saleId").attr('value', fotoId);
    $("#car-foto-upload2").attr('disabled',0);
    }
    }
    );[/js]
    В response, как видно, забирается ответ сервера на загрузку. Про функцию json_encode я незнал (а может её еще небыло тогда), поэтому написал класс для формирования JSON, все работало нормально, без разницы - с html в ответе или без.
     
  6. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    у меня на сервере почти json_encode. Почти потому что стандартный неплохо так обрезал часть информации, поэтому взял json_encode из комментов.

    ну а у меня сейчас:
    [js]
    // ...
    if(o.files) {
    o.onBeforeSend.call();
    // это мы создаем фрейм, если его нет
    if($('#jqfu').html()==null)
    $('<iframe id="jqfu" name="jqfu" src="#"></iframe>').appendTo('body');
    $('#jqfu').hide();
    // меняем target у формы на фрейм
    form.attr('target', 'jqfu')
    // назначаем что делать после того как фрейм загрузится
    $('#jqfu').load(function() {
    var json = $('#jqfu').contents().find('body').html();
    // если убрать Base64.decode то все посыпется
    json = '(' + Base64.decode(json) + ')';
    //console.log(json);
    json = eval(json);
    //console.log(json);
    o.onSuccess.call(null, json);
    });
    // возвращаем true для того что бы произошла отправка формы
    return true;
    }
    // ...
    [/js]
     
  7. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    ...забыл ajax_upload приложить, его в самом jQuery нету:
    [js]/**
    * Ajax upload plugin for jQuery
    * Project page - http://valums.com/ajax-upload/
    * Copyright (c) 2008 Andris Valums, http://valums.com
    * Licensed under the MIT license (http://valums.com/mit-license/)
    */
    (function($){
    // we need jQuery to run
    if ( ! $) return;

    /**
    * Function generates unique id
    */
    var get_uid = function(){
    var uid = 0;
    return function(){
    return uid++;
    }
    }();

    /**
    * button - jQuery element
    * option - hash of options :
    * action - URL which iframe will use to post data
    * name - file input name
    * data - extra data hash to post within the file
    * onSubmit - callback to fire on file submit
    * onComplete - callback to fire when iframe has finished loading
    */
    window.Ajax_upload = function(button, options){
    // make sure it is jquery object
    button = $(button);

    if (button.size() != 1 ){
    console.error('You passed ', button.size(),' elements to ajax_upload at once');
    return false;
    }

    this.button = button;

    this.wrapper = null;
    this.form = null;
    this.input = null;
    this.iframe = null;

    this.disabled = false;
    this.submitting = false;

    this.settings = {
    // Location of the server-side upload script
    action: 'upload.php',
    // File upload name
    name: 'userfile',
    // Additional data to send
    data: {},
    // Callback to fire when user selects file
    // You can return false to cancel upload
    onSubmit: function(file, extension) {},
    // Fired when file upload is completed
    onComplete: function(file, response) {}
    };

    // Merge the users options with our defaults
    $.extend(this.settings, options);

    this.create_wrapper();
    this.create_input();

    if (jQuery.browser.msie){
    // fix ie transparent background bug
    this.make_parent_opaque();
    }

    this.create_iframe();
    }

    // assigning methods to our class
    Ajax_upload.prototype = {
    set_data : function(data){
    this.settings.data = data;
    },
    disable : function(){
    this.disabled = true;
    if ( ! this.submitting){
    this.input.attr('disabled', true);
    this.button.removeClass('hover');
    }
    },
    enable : function(){
    this.disabled = false;
    this.input.attr('disabled', false);
    },
    /**
    * Creates wrapper for button and invisible file input
    */
    create_wrapper : function(){
    // Shorten names
    var button = this.button, wrapper;

    wrapper = this.wrapper = $('<div></div>')
    .insertAfter(button)
    .append(button);

    // wait a bit because of FF bug
    // it can't properly calculate the outerHeight
    setTimeout(function(){
    wrapper.css({
    position: 'relative'
    ,display: 'block'
    ,overflow: 'hidden'

    // we need dimensions because of ie bug that allows to move
    // input outside even if overflow set to hidden
    /*,height: button.outerHeight(true)
    ,width: button.outerWidth(true)*/
    });
    }, 1);

    var self = this;
    wrapper.mousemove(function(e){
    // Move the input with the mouse, so the user can't misclick it
    if (!self.input) {
    return;
    }

    self.input.css({
    top: e.pageY - wrapper.offset().top - 5 + 'px'
    ,left: e.pageX - wrapper.offset().left - 150 + 'px'
    });
    });


    },
    /**
    * Creates invisible file input above the button
    */
    create_input : function(){
    var self = this;

    this.input =
    $('<input type="file" />')
    .attr('name', this.settings.name)
    .css({
    'position' : 'absolute'
    ,'margin': 0
    ,'padding': 0
    ,'width': '200px'
    ,'height': '10px'
    ,'opacity': 0
    })
    .change(function(){
    if ($(this).val() == ''){
    // there is no file
    return;
    }

    // we need to lock "disable" method
    self.submitting = true;

    // Submit form when value is changed
    self.submit();

    if (self.disabled){
    self.disable();
    }
    // unlock "disable" method
    self.submitting = false;
    })
    .appendTo(this.wrapper)

    // Emulate button hover effect
    .hover(
    function(){self.button.addClass('hover');}
    ,function(){self.button.removeClass('hover');}
    );

    if (this.disabled){
    this.input.attr('disabled', true);
    }

    },
    /**
    * Creates iframe with unique name
    */
    create_iframe : function(){
    // unique name
    // We cannot use getTime, because it sometimes return
    // same value in safari :(
    var id = 'valums97hhu' + get_uid();

    // create iframe, so we dont need to refresh page
    this.iframe =
    $('<iframe id="' + id + '" name="' + id + '"></iframe>')
    .css('display', 'none')
    .appendTo('body');
    },
    /**
    * Upload file without refreshing the page
    */
    submit : function(){
    var self = this, settings = this.settings;

    // get filename from input
    var file = this.file_from_path(this.input.val());

    // execute user event
    if (settings.onSubmit.call(this, file, this.get_ext(file)) === false){
    // Do not continue if user function returns false
    return;
    }

    this.create_form();
    this.input.appendTo(this.form);
    this.form.submit();

    this.input.remove(); this.input = null;
    this.form.remove(); this.form = null;

    this.submitting = false;

    // create new input
    this.create_input();

    var iframe = this.iframe;
    iframe.load(function(){
    var response = iframe.contents().find('body').html();

    settings.onComplete.call(self, file, response);
    /// Workaround for FF2 bug, which causes cursor to be in busy state after post.
    setTimeout(function(){
    iframe.remove();
    }, 1);
    });

    // Create new iframe, so we can have multiple uploads at once
    this.create_iframe();
    },
    /**
    * Creates form, that will be submitted to iframe
    */
    create_form : function(){
    // method, enctype must be specified here
    // because changing this attr on the fly is not allowed in IE 6/7
    this.form =
    $('<form method="post" enctype="multipart/form-data"></form>')
    .attr({
    "action" : this.settings.action
    ,"target" : this.iframe.attr('name')
    })
    .appendTo('body');

    // Create hidden input element for each data key
    for (var i in this.settings.data){
    $('<input type="hidden" />')
    .appendTo(this.form)
    .attr({
    'name': i
    ,'value': this.settings.data
    });
    }
    },
    file_from_path : function(file){
    return file.replace(/.*(\/|\\)/, "");
    },
    get_ext : function(file){
    return (/[.]/.exec(file)) ? /[^.]+$/.exec(file.toLowerCase()) : '';
    },
    make_parent_opaque : function(){
    // ie transparent background bug
    this.button.add(this.button.parents()).each(function(){
    var color = $(this).css('backgroundColor');
    var image = $(this).css('backgroundImage');

    if ( color != 'transparent' || image != 'none'){
    $(this).css('opacity', 1);
    return false;
    }
    });
    }

    };
    })(jQuery);[/js]
    Этот плагин всё делает за тебя :)
     
  8. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    та я про этот ajax-upload в курсе, по тексту, увидел

    из плагина:
    var response = iframe.contents().find('body').html();
    то, что я писал:
    var json = $('#jqfu').contents().find('body').html();

    бу-го-го, дык действия что у меня что у чувака-создателя плагина идентичные.
     
  9. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Koc
    У меня подозрение, что JSON-строка с объектами, включающими HTML, просто некорректно генерится, потому и в eval не выполняется.
     
  10. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    если отсылать через jquery.ajax и принимать тип json то все ок. А вот когда берем содержимое iframe между тегами body - получаются проблемы.


    вот ф-ция json которой я кодирую.
    PHP:
    1. <?php
    2. function json($a = false)
    3. {
    4.     if(is_null($a))
    5.         return 'null';
    6.     if($a === false)
    7.         return 'false';
    8.     if($a === true)
    9.         return 'true';
    10.    
    11.     if(is_scalar($a)) {
    12.         if(is_float($a)) {
    13.             // Always use "." for floats.
    14.             return floatval(str_replace(",", ".", strval($a)));
    15.         }
    16.  
    17.         if(is_string($a)) {
    18.             static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'),
    19.                 array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
    20.             return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $a) . '"';
    21.         } else
    22.             return $a;
    23.     }
    24.     $isList = true;
    25.     for($i = 0, reset($a); $i < count($a); $i++, next($a)) {
    26.         if(key($a) !== $i) {
    27.             $isList = false;
    28.             break;
    29.         }
    30.     }
    31.     $result = array();
    32.     if($isList) {
    33.         foreach($a as $v)
    34.             $result[] = json($v);
    35.         return '[' . join(',', $result) . ']';
    36.    
    37.     } else {
    38.         foreach($a as $k => $v)
    39.             $result[] = json($k) . ':' . json($v);
    40.         return '{' . join(',', $result) . '}';
    41.     }
    42. }
    43. ?>
     
  11. DragonLand

    DragonLand Активный пользователь

    С нами с:
    20 янв 2010
    Сообщения:
    1
    Симпатии:
    0
    народ покажите готовый пример как все свяать чтобы работало .... заранее спасибо