All streams
Search
Write a publication
Pull to refresh
52
0
Егор @termi

User

Send message
Вопрос по-существу: Есть хотя бы надежды на то, что MDI вернётся? Его чуть-чуть допилить (а с Blick это не составит проблем) и будет очень удобная фича.
+1
У меня сейчас папки для оперы настроены в RAMDisk, удобно, быстро и SSD не калечится
Другой вариант: прикрутить к новой Опере Диспетчер закладок из проекта Chromium, а Speed Dial сделать отдельной «папкой». Все будут довольны.
В смысле боковую панель? Вот так что ли не может?
Кстати, Хромиум умеет боковые вкладки после допиливания.


Update: посчитал пункты, понял, что вы имели ввиду анонимную вкладку. Обновил комментарий.
Да ладно ключик. Это опционально. Верните LMD+RMD (Fast forward) для заполнения форм, в том числе парольных.
Ну и заодно RMD+LMD (Fast backward) и остальные, а то я просто в шоке был когда эта комбинация не сработала.
Adblock Plus + Ghostery вам в помощь. Скорее всего проблема не в Опере
Блин, а точно. Кнопка «Войти» (с ключиком которая) будет? А то в Хроме я даже в 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 плохая библиотека, просто, по моему, простые вещи в ней сделаны слишком сложно, а сложные ещё сложнее. Да и производительность страдает — я тестировал на большом количестве компонентов.
Какой страшный этот ваш Angularjs.

HTML-шаблоны внутри js-кода?
template:"<input ng-model='hello'>{{hello}}"


Функции внутри разметки?
<span habra-habr some-attr="hello= a+b"></span> 


Мне лично не нравится.
И это плохо. Если раньше можно было экономить на трафике, но при этом полноценно пользоваться сайтом (весь js работает), то теперь это не так.
2. Можно ввести ключевое слово для вывода контента по-умолчанию. Например __yield__:
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. В шаблоне, на один узел может быть повешено более одного компонента.

Абстрактный шаблон компонента 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, он постоянно оказывался вверху скопа. Возможно у вас есть какой-то другой синтаксис для этого?
td > :datePicker {
      р4 > 'test'
            
      :dualbind value='date' getter='getDate' setter='setDate';
            
      :customTag > button x-signal='click: clicked' > 'Click';
}


3. Опять же, несмотря на декларативность фреймворка, вы привязываетесь в DOM дереву. Лично меня это всегда отпугивает от подобных декларативных фреймворков, потому, что, при желании, view backend можно писать и на WebGL/canvas.

4. Синтаксис избыточен. Т.е. вместо
td > div > '~[bind:name]';
можно было бы сделать
td > $name
div -тег по-умолчанию и его можно опустить. Префикс $ — указание на то, что данный «узел» является свойством модели.
В стандарте ES6 есть метод Array.prototype.find и наиболее продвинутые его уже используют.
Плохо расширять прототип, у вас повторяется ситуация которая была с Prototype — стандартные методы реализованные по спецификации конфликтовали с методами библиотеки.

Тем более у вас же в библиотеки проверяется наличие этого метода и если я подключу es6-shim или когда браузеры реализуют Array#find ваша библиотека перестанет работать.

Поправка по первому пункту:
Так работает
a = 1; b = if a then (console.log "good"; true) else false
Попробовал я 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. Деструктуризация не реализована полностью. Пока я натолкнулся на то, что не поддерживаются разряженные массивы в качестве шаблона для деструктуризации:
arr = [1,2,3]
[a, , b] = arr #тут ошибка

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity