Вопрос по-существу: Есть хотя бы надежды на то, что MDI вернётся? Его чуть-чуть допилить (а с Blick это не составит проблем) и будет очень удобная фича.
Да ладно ключик. Это опционально. Верните LMD+RMD (Fast forward) для заполнения форм, в том числе парольных.
Ну и заодно RMD+LMD (Fast backward) и остальные, а то я просто в шоке был когда эта комбинация не сработала.
Блин, а точно. Кнопка «Войти» (с ключиком которая) будет? А то в Хроме я даже в Gmail не могу войти, потому что логин уже введён и он ждёт от меня пароля, а Хром автоматически подставляет только если ввести логин.
Вот я всё время спотыкаюсь на это шаге.
Порезали большинство уникального для Оперы функционала и для чего? Старые пользователи от вас отвернутся, а новых чем будете заманивать, если есть Chrome и куча Chomium based браузеров?
А по поводу боковых панелей — их сильно недооценивают:
Окошко браузера специально сделал поменьше, чтобы скринщот не большой был
Посмотрите пожалуйста мои примеры приведённые в комментариях выше. В обоих примерах используется декларативный стиль. Селекторы, классы, идентификаторы, кастомные аттрибуты и т.д. не используются. И всё это сделано с использованием встроенных в браузер API, а при желании я могу сменить бэкенд на WebGL
Где, где у меня в коде классы или идентификаторы? Простите, но Вы код вообще смотрели? В демо jsfiddle.net/termi/4cF97/ всё обращение с DOM идёт через специальное (нативное для браузера) абстрактное API. Код максимально абстрагирован от DOM и может быть использован и с другим бэкендом, например с WebGL.
Вот ещё один пример: h123.ru/-/tests/KeyboardEvent/ — тут с шаблонизацией, но тоже проходной вариант, я просто игрался с DOM API.
В комментарии же, ссылку на который я дал, следующий уровень абстрагируемости от DOM.
Спасибо за объяснения. Действительно, с такими ограничениями всё кажется не так страшно.
Но мне всё равно не понятно
… куда удобнее держать их в отедельных файлах и собирать в один JS файл на этапе сборки проекта. А для разработки даже можно ничего не собирать...
Т.е. при разработки в js-коде будет написано `templateUrl: 'some.html'` а при сборке нужно это както заменить? Вручную? Или Ангулар самостоятельно пройдётся по js-файлам и заменит вхождение этой строки? Сомнительно.
habrahabr.ru/post/179359/#comment_6248559
Тут примерно вид шаблона, модели и контроллера. Это то, к чему я стремлюсь. На текущий же момент, можно написать такой код: jsfiddle.net/termi/4cF97/ — Этот пример максимально упрощен, из него вырезаны все вызовы фреймворка и оставлено только DOM API. Как вы можете видеть, никаких data-* или других кастомных атрибутов не используется, только стандартные.
Это только демонстрация возможностей, готового фреймворка пока нету.
Не в коем случае не говорю, что Angularjs плохая библиотека, просто, по моему, простые вещи в ней сделаны слишком сложно, а сложные ещё сложнее. Да и производительность страдает — я тестировал на большом количестве компонентов.
Как я себе это представляю:
1. Каждый компонент содержит набор свойств и модель по-умолчанию. Доступ к свойствам осуществляется через прослойку (backend). Для HTML, свойства — это DOM узлы. У каждого свойства есть шаблон по-умолчанию, это может быть просто вставка в innerHTML или аттрибут (src для тега img) или что-то сложнее.
2. К компоненту может быть привязана кастомная модель, которая переопределяет доступ к одному или нескольким свойствам, или переопределять шаблоны валидации всей модели или отдельных свойств.
3. У каждого компонента есть контроллер по-уломчанию, который может быть заменён или расширен кастомным конроллером.
4. Контроллеры компонента не имеют доступа к DOM API и не подписываются на DOM события.
Фреймворком должен быть определён набор сандартных событий в которые будут транслироваться DOM события, типа «active:start» (mousedown, touchstart), «active:end» (mouseup, touchend), «hover:start» (mouseenter), «hover:end» (mouseleave), «action» (click, submit) и т.д.
Обработчик события можно повесить только на свойство компонента.
5. Каждое свойство — это некий узел (Node для HTML backend) который может отлавливать события. При возникновении какого-либо события, класс с таким же именем устанавливаться/снимается на узел привязанный к свойству — Например, node.classList.add(«active») для «active:start» и node.classList.add(«remove») для «active:end».
6. К компоненту может быть привязан источник данных. Это может быть как и просто массив, так и класс имплиментирущий абстрактный интерфейс ModelDataView с методами получения/записи/фильтрации данных.
7. В модели описано, какие узлы array-like и какие одиночные, поэтому при применении данных на шаблон, array-like автоматически склонируются, и не нужно никаких each в коде шаблона
8. В шаблоне, на один узел может быть повешено более одного компонента.
Абстрактный шаблон компонента ImageGallery
используется псевдо-HTML
= section :ImageObject extend :MediaObject # '= ' - объявление компонента
p ::name
image ::contentURL
body
p ?::author # '?' - узел будет создан только если свойство присутствует в источнике данных
data ?::datePublished
= section :ImageGallery extend :CollectionPage
header
hx ::name
p ?::description
image ?::image
body #
::primaryImageOfPage[ :ImageObject ] # свойство суб-компонент типа ImageObject
footer
::associatedMedia[ :ImageObject ] # превьюшки, суб-компоненты типа ImageObject
Контроллер
class ImageObject_controller extend MediaObject_controller {
constructor(el) {
super(el);
this.model = _.getModel(el); // _ - глобальная переменная фреймворка
this._el = _(el); // обёртка над Node элементом (в случае html backend)
}
openImage(imageObject = 0) {
if ( Number.isInteger( imageObject ) ) {
imageObject = this.model.associatedMedia[ imageObject ];
}
if ( !imageObject ) return;
this.model.primaryImageOfPage = imageObject; //тут вызывается setter у модели
}
events: {
"associatedMedia action": function(event) {
let {target, metaKey} = event; // деструкруризация let target = event.target, type = event.type
if ( !metaKey ) {
this.openImage(target);
}
else { // Нажали Ctrl + click - открыти картинку в новом окне
let model = _.getModel(el)
, url
;
if ( model && (url = model.url) ) {
_.globalRouter.openInNewWindow(url);
}
}
}
}
}
Модель
class ImageObject_model extend MediaObject_model {
constructor(dataView) {
super(dataView);
this.dataView = dataView;
}
get associatedMedia() {
return this.dataView.get("associatedMedia");
}
set associatedMedia(singleOrArray) {
if ( !_.validate("associatedMedia", singleOrArray, this.validation ) {
throw new ValidationError(_.validate.lastError);
}
if ( Array.isArray(singleOrArray) ) { // Если массив значению
return this.dataView.replace("associatedMedia", singleOrArray); // заменяем всю коллекцию
}
// Если один объект
return this.dataView.add("associatedMedia", singleOrArray); // то добавляем его вколлекцию
}
// ... остальные свойства
validation: { // Валидация
":scope": function() { // ":scope" ссылка на "всю" модель
// ...
// валидация всей модели
}
"associatedMedia": function(obj) {
return obj.contentURL && obj.name;
}
}
}
Применение в шаблоне
!!!
html
head
js 'script/something.js'
body.image-gallery :ImageGallery /images/get/92188?from=0&to=10 # /images/get/* ссылка на источник данных
# Устанавливаем css класс и текст по-умолчанию
.image-gallery__author ::author ? "Автор не указан"
Отличная идея, но реализация, по-моему, неудачная, как и у всех других подобных проектах, которые в последнее время появляются в огромном количестве.
Что лично мне не понравилось:
1. #logout x-pipe-signal='click: user.logout' > button > 'Sign out'
или '~[bind: date.getDate() ]'
Вы тут предполагаете, что свойства «user»/«date» в некой js-модели будут всегда называться именно так. Т.е. при общей декларативности фреймворка вы привязываетесь к js-объектам.
2. Примеси/наследование компонентов непонятно как должно работать (должно ли вообще).
Т.е. в вашем примере я не смог «подмешать» компонент :customTag в конец компонента :datePicker, он постоянно оказывался вверху скопа. Возможно у вас есть какой-то другой синтаксис для этого?
3. Опять же, несмотря на декларативность фреймворка, вы привязываетесь в DOM дереву. Лично меня это всегда отпугивает от подобных декларативных фреймворков, потому, что, при желании, view backend можно писать и на WebGL/canvas.
4. Синтаксис избыточен. Т.е. вместо td > div > '~[bind:name]';
можно было бы сделать td > $name
div -тег по-умолчанию и его можно опустить. Префикс $ — указание на то, что данный «узел» является свойством модели.
В стандарте ES6 есть метод Array.prototype.find и наиболее продвинутые его уже используют.
Плохо расширять прототип, у вас повторяется ситуация которая была с Prototype — стандартные методы реализованные по спецификации конфликтовали с методами библиотеки.
Тем более у вас же в библиотеки проверяется наличие этого метода и если я подключу es6-shim или когда браузеры реализуют Array#find ваша библиотека перестанет работать.
Попробовал я CoffeScript и пока не впечатлился. Две вещи, которые я нашел странными в CS:
1. Нету тернарного оператора, конструкция на CS получается страшнее чем на JS:
healthy = if 200 > cholesterol then 1 else 0
Даже «замена» тернарного оператора не поддерживает элементарный синтаксис, который я не часто использую, но всё же использую.
let a = 1, b = a ? (console.log("good"), true) : false;
на CS выдаёт синтактическую ошибку:
a = 1; b = if a then (console.log "good", true) else false
2. Деструктуризация не реализована полностью. Пока я натолкнулся на то, что не поддерживаются разряженные массивы в качестве шаблона для деструктуризации:
У меня сейчас папки для оперы настроены в RAMDisk, удобно, быстро и SSD не калечится
В смысле боковую панель? Вот так что ли не может?Кстати, Хромиум умеет боковые вкладки после допиливания.
Update: посчитал пункты, понял, что вы имели ввиду анонимную вкладку. Обновил комментарий.
Ну и заодно RMD+LMD (Fast backward) и остальные, а то я просто в шоке был когда эта комбинация не сработала.
Вот я всё время спотыкаюсь на это шаге.
Надеюсь это только ранняя альфа
А по поводу боковых панелей — их сильно недооценивают:
Окошко браузера специально сделал поменьше, чтобы скринщот не большой был
Вот ещё один пример: h123.ru/-/tests/KeyboardEvent/ — тут с шаблонизацией, но тоже проходной вариант, я просто игрался с DOM API.
В комментарии же, ссылку на который я дал, следующий уровень абстрагируемости от DOM.
Спасибо за объяснения. Действительно, с такими ограничениями всё кажется не так страшно.
Но мне всё равно не понятно
Т.е. при разработки в js-коде будет написано `templateUrl: 'some.html'` а при сборке нужно это както заменить? Вручную? Или Ангулар самостоятельно пройдётся по js-файлам и заменит вхождение этой строки? Сомнительно.
Тут примерно вид шаблона, модели и контроллера. Это то, к чему я стремлюсь. На текущий же момент, можно написать такой код:
jsfiddle.net/termi/4cF97/ — Этот пример максимально упрощен, из него вырезаны все вызовы фреймворка и оставлено только DOM API. Как вы можете видеть, никаких data-* или других кастомных атрибутов не используется, только стандартные.
Это только демонстрация возможностей, готового фреймворка пока нету.
Не в коем случае не говорю, что Angularjs плохая библиотека, просто, по моему, простые вещи в ней сделаны слишком сложно, а сложные ещё сложнее. Да и производительность страдает — я тестировал на большом количестве компонентов.
HTML-шаблоны внутри js-кода?
Функции внутри разметки?
Мне лично не нравится.
td > :datePicker {
р4 > 'test'
:dualbind value='date' getter='getDate' setter='setDate';
__yield__
:customTag > button x-signal='click: clicked' > 'Click';
}
__________
Как я себе это представляю:
1. Каждый компонент содержит набор свойств и модель по-умолчанию. Доступ к свойствам осуществляется через прослойку (backend). Для HTML, свойства — это DOM узлы. У каждого свойства есть шаблон по-умолчанию, это может быть просто вставка в innerHTML или аттрибут (src для тега img) или что-то сложнее.
2. К компоненту может быть привязана кастомная модель, которая переопределяет доступ к одному или нескольким свойствам, или переопределять шаблоны валидации всей модели или отдельных свойств.
3. У каждого компонента есть контроллер по-уломчанию, который может быть заменён или расширен кастомным конроллером.
4. Контроллеры компонента не имеют доступа к DOM API и не подписываются на DOM события.
Фреймворком должен быть определён набор сандартных событий в которые будут транслироваться DOM события, типа «active:start» (mousedown, touchstart), «active:end» (mouseup, touchend), «hover:start» (mouseenter), «hover:end» (mouseleave), «action» (click, submit) и т.д.
Обработчик события можно повесить только на свойство компонента.
5. Каждое свойство — это некий узел (Node для HTML backend) который может отлавливать события. При возникновении какого-либо события, класс с таким же именем устанавливаться/снимается на узел привязанный к свойству — Например, node.classList.add(«active») для «active:start» и node.classList.add(«remove») для «active:end».
6. К компоненту может быть привязан источник данных. Это может быть как и просто массив, так и класс имплиментирущий абстрактный интерфейс ModelDataView с методами получения/записи/фильтрации данных.
7. В модели описано, какие узлы array-like и какие одиночные, поэтому при применении данных на шаблон, array-like автоматически склонируются, и не нужно никаких each в коде шаблона
8. В шаблоне, на один узел может быть повешено более одного компонента.
Прошу прощения за длинный комментарий
Что лично мне не понравилось:
1.
#logout x-pipe-signal='click: user.logout' > button > 'Sign out'
или
'~[bind: date.getDate() ]'
Вы тут предполагаете, что свойства «user»/«date» в некой js-модели будут всегда называться именно так. Т.е. при общей декларативности фреймворка вы привязываетесь к js-объектам.
2. Примеси/наследование компонентов непонятно как должно работать (должно ли вообще).
Т.е. в вашем примере я не смог «подмешать» компонент :customTag в конец компонента :datePicker, он постоянно оказывался вверху скопа. Возможно у вас есть какой-то другой синтаксис для этого?
3. Опять же, несмотря на декларативность фреймворка, вы привязываетесь в DOM дереву. Лично меня это всегда отпугивает от подобных декларативных фреймворков, потому, что, при желании, view backend можно писать и на WebGL/canvas.
4. Синтаксис избыточен. Т.е. вместо
td > div > '~[bind:name]';
можно было бы сделать
td > $name
div -тег по-умолчанию и его можно опустить. Префикс $ — указание на то, что данный «узел» является свойством модели.
Плохо расширять прототип, у вас повторяется ситуация которая была с Prototype — стандартные методы реализованные по спецификации конфликтовали с методами библиотеки.
Тем более у вас же в библиотеки проверяется наличие этого метода и если я подключу es6-shim или когда браузеры реализуют Array#find ваша библиотека перестанет работать.
Так работает
1. Нету тернарного оператора, конструкция на CS получается страшнее чем на JS:
Даже «замена» тернарного оператора не поддерживает элементарный синтаксис, который я не часто использую, но всё же использую.
на CS выдаёт синтактическую ошибку:
2. Деструктуризация не реализована полностью. Пока я натолкнулся на то, что не поддерживаются разряженные массивы в качестве шаблона для деструктуризации: