[
Показаны сообщения с ярлыком javascript. Показать все сообщения
Показаны сообщения с ярлыком javascript. Показать все сообщения

вторник, 13 марта 2012 г.

Пометка элемента как просмотренного с jquery

Скрипт-игра. не скажу где используется и на что похоже;) Но это чудо эффективно может определить виден ли элемент клиенту (в текущем viewport'е) и как-то его отметить.

Собственно, листинг тестовой версии:

<html>
<head>
<title>TEST :: is element visible in viewport</title>

<script language="javascript" type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

<script>
/*
 * Получение текущего вьюпорта:  координаты верхнего левого угла и ширина с высотой
 */
function current_viewport()
{
 var w = $(window);
 
 return {
  "left": w.scrollLeft(),
  "top": w.scrollTop(),
  "width": w.width(),
  "height": w.height()
 };
}


/*
 * Проверка находится ли объект во вьюпорте
 *
 * paddings = {
 *     "left": ...,
 *     "top": ..., 
 *     "right": ...,
 *     "bottom": ...
 * }
 * эффективно увеличивают размеры объекта. по умолчанию 0
 */
function in_viewport(selector, paddings)
{
 var el = $(selector);
 var off = el.offset();
 var dim = {
  "width": el.width(),
  "height": el.height()
 };
 
 if(!paddings)
 {
  paddings = {
   "left": 0,
   "top": 0,
      "right": 0,
      "bottom": 0
  };
 }
 
 var viewport = current_viewport();
 
 return (
  (off.top - paddings.top) >= viewport.top &&
  (off.left - paddings.left) >= viewport.left &&
  (off.top + dim.height + paddings.bottom) <= (viewport.top + viewport.height) &&
        (off.left + dim.width + paddings.right) <= (viewport.left + viewport.width)
 );
}

/*
 * Помечает объект-ответ, как прочтенный
 */
function mark_as_read(obj)
{
    $(obj).css({
        "border": "1px solid #eeeeee"
    });
    $(obj).data('is_read', true);
}


$(document).ready(function() {
 
 // паддинги для проверки попадает ли объект во вьюпорт
 var paddings = {
        "left": 0,
        "top": 0,
        "right": 0,
        "bottom": 0
    };
 
 for(var i = 0; i < 40; i++)
 {
  $('<div class="ticket_reply"></div>').css({
   "height": "100px",
   "margin-bottom": "20px",
   "border": "1px solid blue"
  }).appendTo('body');
 }
 
 var replies = $('.ticket_reply');
 
 replies.each(function(i) {
  // отметим видимые при загрузке
  if( in_viewport(this, paddings) )
     mark_as_read(this);
 });
 
 // зарегистрируем проверку прочтения сообщений по скроллингу
 $(window).scroll(function() {
  replies.each(function(i) {
   if( !$(this).data('is_read') && in_viewport(this, paddings) )
       mark_as_read(this);
  });
 });
 
});
</script>

</head>
<body>

</body>
</html>

За основу взят вот этот пост на stackoverflow: http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport

понедельник, 11 июля 2011 г.

Программное создание Dojo формы из JSON

Понедельник утро... самое время собрать мозги в кучу!

На этот раз расскажу об одной интересной наработке - как я программно создаю форму Dojo из JSON. Задумав сие я стал бродить по интернету и наткнулся на весьма интересный пост. Он то и послужил основой для моего класса.

Прежде всего, для затравки, покажу как выводится форма:

dojo.xhrGet({
    url: '/path/to/form/json/',
    handleAs: 'json',
    load: function(data) {
        var form = new JSONForm(data);
        dojo.byId('container').innerHTML = form.generate();
    }
});

Сгенерированный HTML код формы будет размещен в контейнере c ID container. Просто и быстро.

JSON код (основной) формы в моем случае выглядит так:
{ 

  "id" : "form_id", /* ID формы */
  "params" :  /* Параметры формы */
    { 
      "action" : "/path/to/form/post/",
      "encType" : "multipart/form-data",
      "method" : ""
    },
  "fields" : /* Массив полей */
    [ 
      { 
        "name" : "field_name", /* Название поля в формы */
        "widget" : "TextInput", /* Тип виджета */
        "params" : /* Параметры, передаются конструктору виджета Dojo */
          { 
            "id" : "field1_id", /* ID виджета Dojo (domeNode) */
            "label" : "Подпись:", /* Подпись поля */
            "name" : "widget_name" /* Название HTML элемента формы */
            /* любые другие параметры для виджета */
          }
      }
    ]
}

Тут стоит рассказать о нескольких моментах:

  1. в отличии поста на stackoverflow.org, я передаю не класс Dojo виджета в параметре widget, а, вообще говоря, ключ по которому мой класс JSONForm делает отображение на класс Dojo виджета
  2. у поля есть два свойства name: одно непосредственно в объекте field, а другое в объекте params. Дело в том, что форма на сервере (а я использую Django forms) помимо названия полей имеет еще и префикс для того, чтобы можно было скомбинировать несколько форм с одинаковыми именами полей под одним тегом формы. Так что field.name - это имя поля в форме, а field.params.name - имя поля в HTML коде.

Теперь, когда понятно в каком виде приходит форма с сервера и как она выводится, перейдем к классу JSONForm. Безусловно он написан с помощью классов Dojo.

dojo.declare('JSONForm', null, {
    
    /*
     * Отображение типов виджетов, пришедших с сервера на Dojo воджеты
     */
    _widget2dijit: {
        'Textarea': dijit.form.Textarea,
        'PasswordInput': dijit.form.ValidationTextBox,
        ...
    },

    /*
     * Конструктор
     */
    constructor: function(/* JSON Form Object */json) {
        // параметры формы
        this.id = json.id;
        this.params = json.params;
        this.params['id'] = this.id; // надо для создания виджета

        // создадим форму
        this.form = new dijit.form.Form(this.params);
        
        // поля формы
        this.fields = [];
        // поля формы с ключем по имени поля
        this.fields_dict = {};

        // создадим поля
        dojo.forEach(json.fields, function(item, index){
            this.fields[index] = this._get_dijit(item);
            this.fields_dict[item.name] = this.fields[index];
        }, this);
    },

    /*
     * Получим класс Dijit'a
     */
    _get_dijit: function(field) {
        var widget = this._widgit2dijit[field.widget];
        return widget(field.params);
    },

    /*
     * Генерация формы
     */
    generate: function() {
        // получим тег формы
        var form = this.form.domNode;

        // добавим поля
        dojo.forEach(this.fields, function(item, index){
            dojo.place(item.domNode, form);
        }, this);

        // добавим кнопку submit
        var submit = new dijit.form.Button({
            type: "submit",
            label: "Отправить"
        });
        dojo.place(submit.domNode, form);
        
        // вернем HTML нашей формы
        return form.domNode.innerHTML;
    }
});

Этого достаточно для создания и простейшего отображения полей.

Что с этим делать дальше? Это только часть кода (и весьма упрощенная), которую я использую у себя в классе, однако, дальше развитие может пойти так:

  1. Шаблоны с _Templated  для большего контроля отображения формы.
  2. AJAX валидация полей - следующее чем хочу поделиться.
  3. AJAX отправка формы.
Если на стороне клиента есть необходимость отлавливать события полей, то это легко можно сделать с помощью dojo.connect (или dijit.connect):

dojo.xhrGet({
    url: '/path/to/form/json/',
    handleAs: 'json',
    load: function(data) {
        // создадим форму
        var form = new JSONForm(data);

        // присоединимся к событию onFocus поля "field1"
        form.fields_dict["field1"].connect(form.fields_dict["field1"],
            "onFocus", function(){ alert('Фокус!'); });

        // отобразим форму
        dojo.byId('container').innerHTML = form.generate();
    }
});

Ну как? надеюсь был полезен.