Code Monkey home page Code Monkey logo

noscript's People

Contributors

ab-5v avatar alexeyten avatar ashlkv avatar bacher avatar basvasilich avatar bt4r9 avatar chestozo avatar doochik avatar edoroshenko avatar eljusto avatar fresk-nc avatar i2r avatar iegit avatar just-boris avatar kizu avatar lapple avatar mishk0 avatar pasaran avatar pmyagkov avatar razetdinov avatar rebulus avatar rulexec avatar shirokoff avatar vitkarpov avatar yanann11 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

noscript's Issues

[no.updater] Формат json для наложения

Сейчас генерируется такой json:

{
    views: {
        app: {
            left: {
                block1: true
            },
            right: {
                block2: true
            }
        }
    },
    models: {},
    params: params,
    location: document.location
}

Все модели запихиваются в один объект

{
    'model.id': 'data'
}

У этого варианта есть существенный минус - нельзя записать две одинаковых моделей с разными ключами.

Мы используем такой формат:

{
    "block": [
        {
            "block": [
                {
                    "name": "block",
                    "lazy": false,
                    "handlersKeys": {
                        "handler1": 0,
                        "handler2": 0
                    },
                    "block": []
                }
            ],
            "handlersKeys": {
                "handler1": 0,
                "handler2": 1
            },
            "name": "app",
            "lazy": false,
            "params": {}
        }
    ],
    "handlers": [
        {
            "name": "handler1",
            "key": 0,
            "data": {}
        },
        {
            "name": "handler2",
            "key": 0,
            "data": {}
        },
        {
            "name": "handler2",
            "key": 1,
            "data": {}
        }
    ]
}
  • +Можно иметь две модели с разными параметрами, матчатся по "key"
  • +можно построить ключи для handlers для быстрого поиска из блока
  • -находясь в контексте handlers нельзя обратно получить доступ к блоку, чтобы, например, получить еще какие-то хендлеры по ключу.

Еще можно сделать вот так и запихать данные прямо к блоку.

{
    "block": [
        {
            "block": [
                {
                    "name": "block",
                    "lazy": false,
                    "handlersKeys": {
                        "handler1": {},
                        "handler2": {}
                    },
                    "block": []
                }
            ],
            "handlersKeys": {
                "handler1": {},
                "handler2": {}
            },
            "name": "app",
            "lazy": false,
            "params": {}
        }
    ]
}
  • +Можно иметь две модели с разными параметрами, матчатся по "key"
  • +в любом контексте можно получить доступ к текущему блоку как closest(.block)
  • -нельзя построить ключи для handlers для быстрого поиска из блока

Мысли, идеи?

Поменять корневой неймспейс

Видимо будет лучше, если noscript будет в каком-нибудь другом неймспейсе.
Например, ns..
А no. останется для модулей из nommon.

[no.layout] [no.box] [no.view] В box не может быть lazy-view (async)

Я уже, кажется, задавал этот вопрос. Но не помню к чему пришли. :)
Сейчас в боксе не может быть lazy-view, причем это ограничение приходит из-за того, что у box нет no.layout.view(), из которого можно узнать типы view внутри него.

  1. почему так?
  2. стоит ли исправить?
    1.1) если нет, то надо явно запретить это делать, потому что сейчас там некоторые специэфекты из-за этого

Создавать внутри бокса фейковые view только ради того, чтобы сделать lazy, мне кажется странным

Сделать no.page

Пока сделаем простой вариант для переходов по страницам

Константы

Сейчас у нас есть некие константные флаги в no.model.js.
Они реализованы как свойства no.Model.prototype.
Плюс от этого в том, что можно коротко писать в разных местах this.STATUS_FOO и т.д.
Минус -- невозможно эти флаги использовать вне методов модели. Ну, можно считать это типа инкапсуляцией...

У меня в no.layout.js тоже возникла нужда в кое-каких константах. В частности, для боксов, блоков и асинхронных блоков. Никаких прототипов у меня там нет, так что куда их запихать -- непонятно.
Можно написать так:

no.layout.BOX = 'box';
no.layout.VIEW = 'view';
...

Но длинновато выходит.

Я вот предлагаю такой вариант. Сделать один файлик no.consts.js
И положить туда все в таком виде:

//  Константы для моделей
no.M = {};
no.M.STATUS_FOO = 'foo';
...

//  Константы для лэйаутов.
no.L = {};
no.L.BOX = 'box';
//  альтернатива -- использовать подчеркивание:
no.L_VIEW = 'view';
...

...

У нас не так много сущностей в принципе: model, view, layout, request, update, ...
Вполне можно им однобуквенный префикс выдать.

/cc @doochik

Переделать формат деклараций

Сейчас есть такой формат

no.router.routes = [
    '/', '-> /inbox',
    '/inbox', 'messages',
    '/message/{mid:int}', 'message'
];

Вроде все ок, но мне не нравится плоский массив.

Можно переделать на хеш и надеятся на тот же порядок элементов в нем (что впринципе сейчас работает).

no.router.routes = {
    '/': '-> /inbox',
    '/inbox': 'messages',
    '/message/{mid:int}': 'message'
};

Можно переделать на двумерный массив

no.router.routes = [
    ['/', '-> /inbox'],
    ['/inbox', 'messages'],
    ['/message/{mid:int}', 'message']
];

Варианты для наследования лэйаутов

//  Базовый лэйаут.
no.layout.define('app', {
    'app': {
        'head': true,
        '@left': {
            'folders': true,
            'labels': true
        },
        '@right': {}
    }
});

//  Наследование.
no.layout.define('messages', {
    'app @right': {
        'messages': true
    }
}, 'app');

//  Альтернативный вариант (кажется, такой вариант хуже,
//  если будет вложенность побольше, то будет очень громоздко).
no.layout.define('messages', {
    'app': {
        '@right': {
            'messages': true
        }
    }
}, 'app');

//  Еще наследование, но уже с интерполяцией.
no.layout.define('setup', {
    'app @left': {
        'setup-menu': true
    },
    'app @right': {
        'setup-{ .tab }': true
    }
}, 'app');

//  Тоже самое, но с функцией.
no.layout.define('setup', {
    'app @left': {
        'setup-menu': true
    },
    'app @right': function(params) {
        if (params.tab) {
            return {
                //  FIXME: Не уверен, что тут нужна интерполяция.
                'setup-{ .tab }': true
            };
        }

        return {
            'setup-index': true
        };
    }
}, 'app');

Discuss.

[no.model] Сделать простой способ навешивания обработчиков на приход данных

Так как все работает через события, вроде как логично сделать по аналогии с событиями в no.view

no.Model.define('model', {
    events: {
        changed: [
             //  массив, потому что иногда приходится вешать несколько несвязных обработчиков
             function(){...},
             function(){...}
        ] 
    }
})

.jshintrc у каждого свой

Может уберём из репа общий .jshintrc?
А то сейчас там куча ошибок при анализе файлов.
А у меня стоит git hook для проверки всех js файлов изменённых jshint'ом при коммите.

Недоделанный update портит результат нового update-а

Бывает такое:

  1. перешли мы по ссылке:
    1.1. все синхронные блоки подгрузились
    1.2. начали грузиться асинхронные
    1.3. отрисовалась страница
  2. асинхронные блоки не успели догрузиться - а мы уже перешли на новый url!
    1.4. Данные для асинхронного блока пришли / запрос зафейлился: мы перерисоввываем страницу (старым update-ом) и затираем уже пришедшие новые данные!!!

Сейчас такое поведение было при листании фоток, когда не приходили комменты: вдруг фотка (текущая) заменялась предыдущей.

Можно сделать через проверку:
update.id < no.Update.update_counter - это будет означать, что текущий update - не последний созданный, а значит его не надо дальше выполнять.
Вопрос только: не будет ли у нас когда-то ситуации с несколькими update-ами на одной и той же странице.

Автоматически распиливать модель-коллекцию на набор моделей

Нужно задать:

  • На какие именно модели нужно распиливать коллекцию (конструтор, id, ...). Вопрос: должны ли быть коллекции всегда быть однородными (наверное, да).
  • Указать jpath, по которому будет располагаться массив с данными для моделей.
  • Указать, как именно доставать параметры моделей из этих кусков данных. Объект типа jresult.
  • Под какими индексами сохранять эти модели.

Приоритеты запросов no.request

из #8:
Если есть do-запрос, в котором есть дублирующий запрос другой модели, то этот запрос должен быть более приоритетный, чем первый. Пример, request1 = [model1], request2 = [do-action-with-model1, model1].

@pasaran предложил декларативно указывать do-моделям какие модели он инвалидирует при успешном запросе.

надо собрать разные варианты и подумать

[no.view] [no.model] Наследовать события

Кажется, надо добавить наследование событий.
Актуально как для no.View так и для no.Model.

Вообще есть мысль, что эти два объекта сильно похожи:

  • зависимость от params
  • у обоих есть key и какой-то кэш
  • оба экстендятся no.Eventsами

Возникает ощущение, что view это специфический тип модели со своими правилами кэширования, у вас нет?

/cc #52

Стандартные события типа htmlinit и их обработка

У многих блоков нужно делать что-то на htmlinit или show. Если я правильно поняла, для этого надо каждому из них добавлять в events такой кусок: 'htmlinit .': 'onhtmlinit' и тд. Может быть, сделать, чтобы стандартные методы биндились по умолчанию на эти события?

Отложенные view

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

[no.request] [no.model] Сделать bulkModel / bulkRequest ?

Есть балковые запросы. В первый запрос запрашиваем 100 ключей, в следующий запрашиваются тоже 100, но 90 из них пересекаются с первым запросом.
Хочется, чтобы во второй запрос ушли 10 уникальных ключей, но в ответ подклеились остальные 90 из кеша.

Обсуждаем...
@pasaran @shirokoff @artjock @chestozo @mmoo

Ключ view, построенный по параметрам модели

Сейчас у нас есть такой кейс:
если у view не заданы params мы строим ключ по параметрам его моделей.

Вопроса 2:

  1. если у модели есть дефольтное значение параметра — надо ли его включать в ключ?

  2. если у view 2 модели, у обеих есть параметр p (num_per_page какой-нибудь), но с разным дефольтным значением и в урле этот параметр не задан: какое значение должно попасть в ключ view? Если вообще должно попасть.

Пока писал вопрос номер 2 понял, что эти дефольтные параметры, видимо, не надо в ключ view прокидывать. Но вопрос оставлю, вдруг кто-то считает иначе.

/link #18

Правильно строить урлы

Надо как-то указывать root и уметь строить от него правильные урлы.

Если у меня приложение находится по адресу example.com/some-root-path/..., то no.page из location должен сам вынимать все, что после /some-root-path/, а после преобразований (редирект, например) правильно выстраивать его обратно.

`_` в именах переменных

Вот у нас по коду встречается разное:

var _a = {};
var b_ = {};

Давайте договоримся, что когда использовать.

К примеру, я помню такие правила:

  • если private свойство - называем this._p
  • если название переменной совпадает с ключевым словом называем window_

Но вот зачем писать внутри функции var _v = 42; я не понял.

Разновидность модели для балковых запросов с кешированием

Есть балковые запросы. В первый запрос запрашиваем 100 ключей, в следующий запрашиваются тоже 100, но 90 из них пересекаются с первым запросом.
Хочется, чтобы во второй запрос ушли 10 уникальных ключей, но в ответ подклеились остальные 90 из кеша.

Обсуждаем...
@pasaran @shirokoff @artjock @chestozo @mmoo

Счётчики в layout или / и во view

Пример:

no.layout.register('photo', {
  // ...
  'counters': {
    "div#preview a.original": {
      'click': { 'cid': 123, 'name': 'photo.original.click' },
      'show': { 'cid': 124, 'name': 'photo.original.show' [, 'element': '.contols-panel' ] }
    }
  }
});

Аналогично для no.View.register

Глобальные события: как сделать так, чтобы среагировали только нужные view?

Кейс такой:
есть фотка из альбома A
есть фотка из альбома B
когда показывается фотка из альбома A также показывается сам альбом A в слайдере

По клику на фотку -- нужно показать следующую фотку.
Это делает слайдер: он слушает глобальное событие photo:next и когда слышит его -- берёт следующую по очереди фотку и перезагружает страницу.

Если мы посмотрели вначале фотку из альбома A, а потом посмотрели фотку из альбома B у нас будет 2 слайдера на странице:
один текущий видимый по альбому B
второй скрытый по альбому A

Глобальное событие слушают оба.
Оба пролистнут на следущую фотку, когда услышат глобальное событие.

Решений вижу несколько:

  1. Глобальные события ограничиваются контекстами / namespace-ами.
    К примеру, генерировать не photo:next, а photo:album:3:next:. Проблему решает, но гемороя добавляет.
  2. Если view сейчас не активно -- оно не должно реагировать на глобальные события. Чревато багами...
  3. Когда view скрывается -- отписываться от глобальных событий / вообще от всех. Тут тоже, кажется, могут возникнуть непредвиденные ситуации.

Продумать схему алиасов

Сейчас роутер умееть только по урлу определить какой лейаут показывать. Этого не всегда достаточно. Хочется иметь алиасы для различных страниц.
Например,
/inbox хочется преобразовывать в /folder/<id>
/unread -> /folder/<id>/?filter=unread

Пока я себе это представляю, что page.go должен работать в два прохода, сначала алиасы (реврайты), потом уже router.
Причем эти алиасы могут работать по той же схеме и с такими же декларациями, что и роутер. Можно даже прямо в него это все зашить.

Реализация no.request

Модуль для запроса моделей с сервера.

Есть два типа запросов: get (запрос на чтение) / put (запрос на изменение, do-запрос).

no.request должен:

  1. контроллировать, что в один момент времени не запрашиваются две одинаковых моделей.
  2. перезапрашивать модели при неудачной загрузке
  3. добавлять xsrf-защиту для do-запросов
  4. если есть do-запрос, в котором есть дублирующий запрос другой модели, то этот запрос должен быть более приоритетный, чем первый. Пример, request1 = [model1], request2 = [do-action-with-model1, model1].

Несвязная коммуникация между блоками

Гипотетическая ситуация, но более-менее приближенная к реальной.

Вот есть к примеру три блока (условно): тулбар, список писем, письмо.
В тулбаре есть кнопки с действиями с письмами.
В списке писем хранится информация про выделенные письма.
Письмо (если оно открыто) -- какбэ тоже выделено.
Тулбар хочет в какой-то момент получить список выделенных писем. Как это сделать?

С ходу. Тулбар кидает глобальное событие get-selection. Список писем и письмо подписываются на него как get-selection@show -- тогда разные списки писем и письма не будут все на него отвечать, ответит только тот блок, который сейчас виден.
Как он может ответить? Ну можно делать no.events.trigger('get-selection', callback) -- вроде ок, но тут есть нюанс, если в данный момент нет вообще ни одного письма или списка писем, то никто не ответит и callback не будет вызван. Т.е. определить, что ничего не выбрано в этом случае не удастся.
Кидать в ответ событие и ловить его в тулбаре -- примерно так же.

Короче, нужно придумать простой способ запросить у какого-нибудь блока (не конкретного!) что-нибудь и либо получить этот ответ, либо сразу узнать, что ответа нет.

(да, конкретно в этом случае лучше, видимо, не запрашивать список выделенных, а кидать его сразу, при каждом изменении выделения, но не суть)

Контроль ошибок

  1. ошибки в запросе моделей, делать какое-то количество перезапросов
  2. проверять, что после запроса моделей в кеше оказались все данные (не инвалидировал ли их кто-нибудь)

Встреча 15.01.2013

Обработка ошибок

когда нет данных, или нет моделей
Нужно делать (issue #39)

Формат json'а дерева шаблонизации

issue #26
Cейчас это примерно такое дерево:

{
  models: {},
  layout: {},
  params: {}
}

Проблемы:

  1. В models кладуться все модели сплошным списком и проблема может возникнуть, когда там будет две модели с одним и тем же model.id.

  2. Ещё одна проблема, когда мы рендерим какую-то часть дерева и хотим обратиться к другой части дерева, но в контексте какой-то родительской ноды:

  • мы можем не знать, где именно в дереве мы находимся
  • мы можем знать, где мы, но не хотим идти по родителям вверх

Решения могут быть:

  • tunnelирование: какие-то переменные делаются глобальными
  • chroot: делаем какую-то часть глобального дерева текущим рутом (проблема с доступом к исходному дереву: поменялся root). Вызов будет такой: apply chroot(/.layout.view1) view1-template
  • special json: пытаемся разрулить это как-то через формат дерева шаблонизации. Но всё равно непонятен контекст
  • создавать новый json объект: самый универсальный вариант, но наиболее затратный. Суть в том, чтобы накладываться на json объект, создаваемый внутри шаблона, в который можно положить только нужные данные в известные места: apply { view: /.layout.view1, params: /.params } view1-template
Распил моделей

Почти сделано в (issue #21)
что-то про контексты и неймспейсы в событиях (issue #40)

Unique handler'ы

Может переименовать в bulk request (issue #33 )

Что делать

  • ревьюить код
  • брать какие-то issue из открытых и фигачить

Ключ view надо строить не по всем доступным params-ам

Иногда ключ view нужно строить по некоторому набору параметров из урла, а не по всему набору.

Пример:
есть view "слайдер с фотками"
В этом слайдере отображаются фотки из текущего контекста.
Контекстом может быть: альбом, или, к примеру, популярные фотки.

// view slider.
no.View.define('slider', {
  params: {
    context: null,
    author-login: null,
    album-id: null
  }
});

// Контекст альбома:
var url = '/user/vasya/album/3/view/77';
var slider_view_key = 'author-login=vasya&album-id=3'; // Ключ ок.

// В контексте популярных фоток.
var url = '/popular/user/vasya/album/3/view/77';
var slider_view_key = 'context=popular&author-login=vasya&album-id=3'; // Такой ключ -- это fail.
var slider_view_key_good = 'context=popular'; // Нужно так!

Сделать Action

Можно взять из Дарьи.

Экшены обрабатывают click, dblclick, mouseenter, mouseleave, submit.
class="no-action" data-action="name" data-params="foo=1&bar=2"

Надо сразу предусмотреть, чтобы иметь возможность получить инстанс View в рамках, которого вызван экшен (находится нода event.currentTarget).

Так же мы реализовали удобную возможность дергать счетчики Метрики при вызове. Сейчас это параметр metrika, но мне кажется надо это вынести в отдельный data-атрибут data-counter=""

Нужен метод типа view.getTree() и view.tmpl()

Или как угодно оно называется.
Сейчас есть приватный метод, который вызывается апдейтером.
Но ему нужно какой-то там tree передать, layout и т.д.

Я хочу быстро получить объект, который можно засунуть в шаблонизатор для этого блока. Со всеми делами -- параметрами страницы, моделями и т.д.

И более того, хочу так уметь писать:

var html = view.tmpl(mode) // mode -- опциональный параметр

при этом соберется нужное дерево, запустится шаблонизатор с нужной модой.

Неправильно удаляется блок с боксом

Предположим есть блок, в котором есть бокс. И в боксе лежат какие-то другие блоки.
Если мы по какой-то причине инвалидировали верхний блок, то для него будет сгенерен новый хтмл, но бокс не пересоздастся и не инвалидируется.
Т.е. бокс будет по-прежнему смотреть на старую ноду и перестанет работать (точнее он будет там где-то на детаченной ноде работать).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.