Обновить
50
Александр Десятьбитов@tenbits

Пользователь

7
Подписчики
Отправить сообщение
Да, Маска — model agnostic. И это к лучшему — модель может выглядеть как угодно — будь это данные из mongoose в node.js, или данные из localStorage, или обычный класс User на клиенте. Плюс для тестов это на порядок лучше.
Хотя маска и поддерживает такую запись — div > '~[:get("username")]', что бы достать данные из модели — но биндинги на данный момент работать не будут таким образом.
Спасибо! Но с событиями вы, наверное, делали что-то не так. В маске вы нигде на события(сигналы) не подписываетесь — всё довольно строго распределено — из любого контроллера или из любого дом элемента можно узнать, кто может / обрабатывает сигнал. В бэкбоне вы же наверняка подписываетесь на события? events: { «click .my-button»: «x»} — это называется «слушать разметку», а в этом есть большой недостаток — если есть иерархия контроллеров и каждый имеет свою разметку — тогда из предков, ни в коем случае нельзя «слушать разметку» детей. До этого, было как бы, два решения — первое, ребенок посылает «custom event», и второе, ребенок вызывает функции отца. Второе отпадает — из-за непозволительно большой связности. А «custom event» это уже лучше но лишние телодвижение — ребенок слушает свою разметку и посылает событие. Я же предлагаю выводить «событие»(сигнал) непосредственно в представление.

Модель:
В Backbone это именно модель
— вы, думаю, понимаете, что любые данные — это модель. Эти данные / состояния можно обернуть или скрыть в классах / структурах. И эти «обертки» собственно и называются domain model. Маска может работать и с тем, и с другим.

Да я видел, как люди использовали маску с бэкбоном, используя её как шаблонизатор. И постепенно создавали свои компоненты (обработчики тэгов). Биндинг в Маске реализoван привязками через defineProperty — согласитесь, иметь в конечном результате "model.someAttr" лучше, чем model.get("someAttr");. Если вы получаете данные по ajax запросу, вам их не надо расширять до бэкбоновской модели — а напрямую передавать во View.
Хорошие комментарии длинными не бывают, даже если занимают 10 скроллов)

  • С :datePicker-ом вы делаете, что то не то) Если вам надо до или после календаря вывести текст / кнопkи, так не обязательно помещать их в блок :datePicker —
       h4 > 'Title'
       :datePicker;
      button > 'X'
    

    • Шаблон — p ::name — у вас также шаблон зависит от модели, а если имеется ввиду, что это данные из контроллера — тогда контроллер, это чистой воды Presenter — который в свою очередь получает данные из модели. (см. статью)
      Наследование тоже самое что и MasterPages — layout
    • Контроллер — не понятно, как у вас определяются события. На узлы (DOM HTMLElements) всех компонент вешаются события клик (action)? А если надо не на весь элемент вешать обработчик, а только на кнопку 'OK' например, а если много кнопок?

      Наследование контроллеров в MaskJS устроено пока что, только как обычное наследование Javascript прототипов — а там уже мы можем, например, переопределить метод onRenderEnd подсунув там другой шаблон для компоненты.

    • Модель — точно также можно и в маске это сделать. Но мне нравится, что не обязательно!! создавать врапперы — маске подойдет любой объект.



На счёт array-like — исходить из того, что фреймворк и так догадается, не особо стоит, потому что порой мы передаём массив, но хотим, что бы не элементы выводились из него, а к примеру, только статистика по нему. И если у вас есть модель, где не только массив, а помимо и другие пропертя, поэтому нам всё равно нужно передавать его (массив) в шаблон / контроллеры — почему бы не через each?

Ну а так расширить MaskJS до вашего видения не составит труда — я попытался по максимуму упрастить всё — и по максимуму дать возможность расширять. И если у вас есть время, можете форкнуть и попробовать поиграться — а если будут вопросы, я вам помогу.
Дельный комментарий, спасибо — теперь по-пунктам:
  1. Сигналы — это не вызовы методов, а как бы именованные события, которые по дереву контроллеров или трубкам гуляют. А привязываться к модели из шаблонов вы как предлагаете по другому? Эту задачи в любом случае нужно кому-то делегировать. Если мы из конроллеров будем вставлять в дом данные — тогда контроллеры слишком толстые получатся. Здесь же шаблоны отвечают за свои задачи — вывести данные пользователю, а в случае сигналов — предают динамичности посылая «события». Мне кажется такое распределение вполне уместно. Или есть у вас другие идеи?
  2. :datePicker, это всего лишь обёртка над jQuery виджетом. И её реализация не подразумевает, что вы дополнительно в календарь свою разметку вставлять будете. Поэтому он просто это игнорирует. datePicker
  3. В отличии от других реализаций, разметка превращается в AST дерево. И реализовав свой билдер можно будет и на canvas рисовать
    rect dimension='0:0:100:100' color='red' {
        line from='0:0' to='5:5' size=5;
    }
    

    Ну смысл вы уловили.
  4. Вы убрали div — а если нам надо, что бы данные выводились в span? Сейчас data биндинги это лишь надстройка над MaskJS (не путать ~[name] и ~[bind: name]]), поэтому и синтаксиса специально для него нету. И из вашего примера, так будет через чур свободно, или?
    td > p > 'My name is $name'
    // vs
    td > p > 'My name is ~[name]'
    

    Хотя да, смотрится не плохо, но не зря все шаблонные движки выбирает немножко посложнее синтаксис для интерполяции.

Да я раньше туда отправлял реализацию, но тогда это был лишь шаблонизатор без разных «наворотов» и они приняли только как альтернативу. Сейчас я обновил приложение и может попробую ещё раз послать «request». Приложение здесь. Или более длинный путь:
  • установить nodejs / git / inlcudejs / libjs
  • > cd tempFolder && ijs template todoapp
Interning также относится и к инлайновым регуляркам. А в примере опечатка — хотел привести аналогию с тем, как вы «кешируете» regexp:
//..
var x = 'x';
return function(str) { return str + x; }
Это называется пулом (interning). Думаю ради производительности вы так не делаете:
var addX = (function(){
    var x = 'x';
    return function(str){ return str + 'x' }
}());


НО, такие вещи хорошо выносить в константы, и вовсе не в целях производительности.

пс. и результат будет совсем другим если использовать new RegExp(reg); jsperf/2
А скрипт на nodejs кого-то интересует? gist
О, typescript — отличная вещь, желаю вам всяческих успехов, надеюсь скоро ещё «услышимся». И главное не бросайте начатое!
1) Ну вы же дотнэтер, я так понимаю, и не мне вас убеждать, что для бизнес лейэр: один класс — один файл. Хорошо, javascript — не c#, но как минимум один модуль — один файл.
2) Можно для дебага и модули отдельно грузить — и вы не только номер строки видите, но и названия модуля/класса/файла, — и это уже плюс.
3) Сугубо субьективная оценка.
4,5) Файл-Модульная изоляция нужна для тестов, что бы тестировать внутренний апи который скрыт от внешнего доступа. Ведь вся библиотека в основном находится за замыканием, то как из тестов достать эти самые классы/модули?
6) Модульность вам же улучшает разработку. Решили создать другую реализацию для модуля — создали новый файл, создали модуль, собрали проект с новым модулем — вот и у вас уже новая бета, а человек решит — или хочет stable пользоваться, где ещё старый модуль, или взять бетку. Или другой пример — модуль с разными реализациями. Один только для современных браузеров, другой кроссбраузерный — с кучей polyfills и другими вещами. Разрабатывая мобильное приложение, я бы взял более легкую сборку.
Да, там много строк :) Просто, я более чем уверен, что в WebStorm не менее удобно и по файлам «прыгать». А преимущества налицо — видно сразу структуру проекта, но самое главное — изоляция модулей, а без этого покрывать тестами проект очень сложно. Ну и сборки можно разные делать.

А так, я вижу, проект уже не маленький, и в след. раз можно статью тоже побольше написать — с примерами, особенностями… Удачи!
Хотел посмотреть исходники, и скажите — вы и вправду весь код держите в одном файле js/jriapp.js? 1.5К строк можно было бы и по классам разложить, а потом собирать…
Отличное и элегантное решение. Можно даже в 140byt.es добавить…
Замечательное описание внедрение технологий. Интересно было бы ещё узнать, в какие сроки вам удалось вложиться.
Просто блоки с with() {} дорогие в плане производительности, так что если вам она хоть немножко важна — а я так понял, что — да, тогда нужно от «with» отказываться. Благо его заменить довольно просто. А так, скажу вам — занимаетесь хорошим делом — удачи!
А какие десктопные/мобильные браузеры поддерживает toolkitchen?
«Есть одно тёмное время — когда на свет рождаются самые уродливые строки когда, когда самые витиеватые хаки пробуждаются, когда сумерки опускаются над проектом. И это время кличут — мёртвой чертой. Программисту же все вокруг сочувствуют и сопереживают. В коридорах можно услышать шепот коллег -'Нет, нет — не трогайте его. У него сегодня дэдлайн ...' — и окончание фразы от страха и воспоминаний ещё долго висит в воздухе, ведь каждый переживал это время.»

  • emit/on — да, это почти тоже самое, что и сигналы: передаются по дереву, можем подписаться/отписаться. Различия только в а) семантике: оперировать понятиями event/signal, проще чем — event/custom event ( хотя это вполне субъективно и возможно проблема высосана мной из пальца только потому, что мне просто так больше нравится:)) и б) возможный декларативный биндинг — то есть как в случае с ng-click, в контроллере нам не нужно явного вызова .on(..), а все слоты мы складываем в объекте «slots» нашего контроллера. И еще один плюс в декларативном биндинге, что в контроллере мы явно разделаем «методы контроллера»/«слоты».
  • недостаток ng-click в том, что мы как бы исполняем выражение по событию непосредственно из view. То есть мы из view лезем в current scope и выполняем от туда метод контроллера. А это как-то грязновато, поэтому и называется «Model-View-Whatever»
  • :) this.slots('sendMail').disable() — a) слот мы не сможем вызвать (пока не .enable(...) ), и б) если слотов больше нет у сигнала в данном или выше по дереву контроллере, то соответствующей кнопке/пункту меню присвоится :disabled. И не надо создавать лишних биндингов к кнопке.


Но оговорюсь, что это все очень похоже друг с другом и возможно такие различия в нюансах важны только мне:) !?
Ваша правда, событие есть всегда и обработчик есть всегда. Но вот я пытаюсь абстрагироваться от «нативных» событий (clicked, changed ...) применяя qt философию signal/slot. В своем шаблонном движке переопределяю событие на сигнал.
 button x-signal="click: sendMail"; 

И контроллер реализует этот слот:
//...
slots: {
    sendMail: function() { },
    // ...
}

Надеюсь уже сразу понятно в чем здесь преимущества.
  • избавились от «безликих» событий
  • контроллер может ничего не знать о разметке/классах
  • сигнал, как и событие может передаваться по дереву контроллеров
  • из view может ещё N-колличество элементов посылать этот сигнал
  • по необходимости, мы можем сделать слот или сигнал не активным


В результате получили гибрид, смесь дом событий и ng-click=«handler». View не должен ничего знать о контроллере/(-ах), просто определяем какие сигналы он посылает — и это дает более целостное понимание представления. Да и в контроллере мы тоже чётко группируем функции.

Но повторюсь, что это все тот же «событие — обработчик» — только немного другая «философия» ;)

Информация

В рейтинге
Не участвует
Откуда
Leipzig, Sachsen, Германия
Дата рождения
Зарегистрирован
Активность