2 марта 2011 в 13:27

Введение в Cappuccino



Фреймворк Cappuccino – уникальная технология, позволяющая создавать веб-приложения десктопного качества. Он абстрагирует DOM и вместо него предоставляет Cocoa-подобный API. Вместо того, чтобы возиться с CSS-версткой и кроссбраузерными проблемами, вы используете интерфейсы, специально созданные для разработки приложений, а не статических страниц, интерфейсы, взятые с платформ Mac OS X и iOS.

Я заметил, что на русском языке почти нет обучающих материалов о Cappuccino, и решил восполнить пробел. Этот очерк рассчитан на то, чтобы прочитав его, можно было сразу приступать к разработке своего первого Cappuccino приложения. Я познакомился с фреймворком, когда искал средство для реализации онлайновой среды разработки для своего проекта Akshell. Мне нужно было сделать полнофункциональную IDE, работающую в окне браузера, и Cappuccino отлично справился с поставленной задачей.

История


В 2008 году Франциско Толмаски, Том Робинсон и Росс Баучер (Франциско и Росс – бывшие сотрудники Apple) создали компанию 280 North и выпустили 280 Slides, веб-приложение для подготовки презентаций. Оно и сейчас впечатляет своим look and feel’ом, а тогда это было просто что-то нереальное. Причем 280 Slides не был самостоятельным продуктом, это была лишь демонстрация возможностей нового веб-фреймворка, Cappuccino.

4-го сентября того же года Cappuccino был опубликован под лицензией LGPL и тут же стал хитом на GitHub. Вокруг фреймворка образовалось сообщество программистов, использующих его в своих продуктах. С тех пор это сообщество только увеличивается и принимает все более активное участие в разработке Cappuccino.

В 2009 году 280 North анонсировала новый продукт, Atlas, и он также оказался прорывной технологией. Atlas – это аналог Interface Builder для веб-приложений, в нем вы можете рисовать интерфейсы мышкой, перетаскивая нужные компоненты из библиотеки. Пара минут работы дает более впечатляющий результат, чем день мучений с CSS. В отличие от Cappuccino, Atlas – закрытая платная программа, для скачивания бета-версии нужно заплатить $20. Этот очерк посвящен Cappuccino, поэтому я не буду описывать Atlas более подробно. Скажу только, что он действительно экономит кучу времени при создании интерфейсов, позволяет сосредоточиться на юзабилити, а не на борьбе с различными версиями браузеров.

Cappuccino и Atlas активно развивались, когда летом 2010 года Motorola купила 280 North со всеми ее активами, потратив на это, по слухам, 20 миллионов долларов. Официальная цель покупки – развитие технологий разработки на платформе Android. Многие злые языки начали поговаривать о смерти Cappuccino, однако с тех пор прошло уже полгода, фреймворк активно разрабатывается, а 23-го февраля состоялся релиз версии 0.9.

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

Теория


Главная особенность Cappuccino – это созданный специально для него язык Objective-J. Он является такой же надстройкой над JavaScript, как Objective-C – над C. Для меня, как и для многих, вначале было совершенно неочевидно, зачем делать объектно-ориентированную надстройку над языком, который сам по себе является объектно-ориентированным. Однако в этом есть большой смысл.

Во-первых, благодаря Objective-J Cappuccino полностью повторяет Cocoa API. Это не фантазия на тему и даже не творческая переработка, это именно повторение, вплоть до сигнатур функций. За счет этого программисты, работавшие на Mac OS X и iOS могут безболезненно перейти на веб-разработку. Удобство всех API проверено долговременными использованием на десктопе, начиная с ОС NeXTSTEP. И наконец, при использовании фреймворка можно успешно пользоваться документацией Cocoa, которая значительно превосходит по качеству и проработанности Doxygen документацию Cappuccino.

Во-вторых, отсутствие гибкости иногда является плюсом. Большинство программистов посчитает, что я сейчас высказал большую ересь, поэтому сразу начну оправдываться. Дизайнеры знают, что введение сеток и других искусственных ограничений может улучшить дизайн. Objective-J интерфейсы Cappuccino на первый взгляд кажутся неповоротливыми и допотопными по сравнению с тем, что можно было бы сделать на JavaScript. Вместо парадигмы Target-Action зачастую можно было бы использовать замыкания, вместо явных геттеров и сеттеров – __defineGetter__ и __defineSetter__, вместо квадратных скобок – привычные точки, в конце концов. И самое ужасное: Objective-J методы не являются объектами первого класса!

Поработав с Cappuccino, я понял достоинства такого подхода, и они являются прямыми следствиями недостатков. Более жесткая объектная модель позволяет четче структурировать код, не потонуть в каше вложенных друг в друга функций. Длинные содержательные имена позволяют справляться с иерархиями классов Cocoa, в который один класс обычно имеет многие десятки методов. Вездесущие геттеры и сеттеры позволяют реализовать Key-Value Coding, Key-Value Observing и Key-Value Binding, техники переворачивающие представление о создании сложных интерфейсов пользователя (к сожалению, в этом очерке не хватит места для их описания).

Я начал пользоваться Cappuccino потому, что меня привлек внешний вид приложений, созданных с его помощью. Теперь я понимаю, что настоящая сила заключается в его API, которые сначала казались мне ужасными. Поэтому я призываю вас осознать философию фреймворка прежде, чем сделать окончательное суждение о нем.

Приступим к обзору Objective-J. Главное, что он вносит в JavaScript – это классы. Они определяются с помощью ключевого слова @implementation:

@implementation Person : CPObject
{
    CPString name @accessors;
}

(id)initWithName:(CPString)aName
{
    if (self = [super init])
        name = aName;
    return self;
}

(Person)personWithName:(CPString)aName
{
    return [[Person alloc] initWithName:aName];
}

@end

Между @implementation и @end находится описание класса. Класс Person наследуется от CPObject, вершины иерархии классов Cappuccino. Затем в фигурных скобках объявляются переменные-члены класса. name – строковая переменная-член, для которой автоматически генерируются геттер и сеттер (благодаря указанию @accessors). Правило именования аксессоров в Objective-J несколько нестандартно – это name и setName:. Этого формата стоит придерживаться, т.к. на него полагаются внутренние механизмы Cappuccino.

Взаимодействие между Objective-J объектами происходит с помощью пересылки сообщений, впервые эта техника появилась в языке Smalltalk. Синтаксически это выглядит так:

[объект сообщение]
[объект сообщениеСПараметром:значение]
[объект сообщениеСПараметром1:значение1 параметром2:значение2]
...

Например, вызов геттеров и сеттеров объекта класса Person выглядит так:

var name = [aPerson name];
[aPerson setName:”Вася”];

Методы объявляются после переменных-членов, до ключевого слова @end. Методы класса начинаются на плюс, методы экземпляра класса – на минус.

Создание экземпляра класса в Objective-J происходит в два этапа: сначала метод alloc этого класса создает неинициализированный объект, а затем конструктор (init-метод) инициализирует его. Часто определяют методы класса, упрощающие этот процесс, personWithName: – пример такого метода.

Названия конструкторов в Objective-J принято начинать со слова init. Каждый конструктор должен сначала позаботится о вызове конструктора суперкласса, затем выполнить инициализацию и вернуть self. Ошибка конструирования сигнализируется возвратом значения nil (да, во времена создания Objective-C исключения еще не вошли в моду, поэтому Cocoa и, как следствие, Cappuccino обходятся без них).

Ради единства стиля Objective-J определяет три переменных, взятые из Objective-C, это nil, YES и NO. Они идентичны null, true и false, соответственно. Cappuccino Coding Style Guidelines рекомендуют использовать именно их.

Как и многие читающие это очерк, я никогда не использовал Objective-C, поэтому для меня было совершенно неочевидно, почему класс определяется ключевым словом @implementation, а не, например, @class. Специально для таких же любопытных: Objective-C, как надстройка над C, использует файлы объявлений (*.h от headers) и файлы определений (*.m от messages), поэтому классы должны объявляться (@interface) и определяться (@implementation). В Objective-J объявления не нужны, поэтому используется только @implementation.

Практика


Пора установить Cappuccino. Если вы используете Windows, сначала придется установить Cygwin (неприятное обстоятельство). Все остальные и те, кто все-таки решился на предыдущий шаг, просто скачивают Cappuccino Starter Package и запускают в нем скрипт bootstrap.sh.

После установки в системе должна появиться утилита capp. В качестве примера мы будем создавать (сюрприз!) приложение для поиска в твиттере. Сгенерируем его:

capp gen "Twitter Search"

В появившейся папке лежит куча файлов, нас интересуют index-debug.html и AppController.j (*.j – стандартное расширение файлов с Objective-J кодом).

Откроем index-debug.html. Строгая политика безопасности Google Chrome не позволяет Cappuccino загружать нужные ей файлы при работе с протоколом file://, требуется поднимать веб-сервер, во всех же остальных браузерах мы увидим работающее приложение Hello World! Cappuccino компилирует Objective-J код в JavaScript на лету, прямо в браузере, поэтому при разработке можно просто обновлять страницу и не заботиться о пересборке. «Боевую» версию приложения можно скомпилировать заранее, чтобы ускорить загрузку.

Приступим к разработке. В файле AppController.j определен класс AppController, в Objective-J принято размещать код каждого класса в одноименном файле. Cappuccino создает один экземпляр AppController при запуске, он должен инициализировать приложение и управлять его дальнейшей работой.

Перед определением класса импортируем Foundation и AppKit, две основных части Cappuccino. Foundation содержит классы для обеспечения бизнес-логики, а AppKit – это библиотека классов пользовательского интерфейса.

@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>

Ключевое слово @import подключает указанный файл. Как и в C, при указании пути в угловых скобках файл будет искаться в системных папах, при использовании двойных кавычек – в текущей папке.

Метод applicationDidFinishLaunching: вызывается у всех объектов непосредственно после запуска приложения. Содержательные имена методов Cappuccino делают код понятным даже для тех, кто не знаком с фреймворком, поэтому я буду давать пояснения только в неочевидных случаях. Cappuccino вряд ли сэкономит вам нажатия клавиш, так пусть хоть сэкономит их мне.

Для инициализации приложения мы создадим окно и текстовое поле:

var window = [[CPWindow alloc] initWithContentRect:CGRectMake(100, 100, 250, 70)
                                         styleMask:CPTitledWindowMask],
    contentView = [window contentView],
    textField = [[CPTextField alloc] initWithFrame:CGRectMake(25, 20, 200, 30)];

JavaScript функция CGRectMake(x, y, width, height) описывает прямоугольник, в котором будет располагаться элемент управления. Метод contentView возвращает представление внутренней области окна.

Раньше я был ярым сторонником ограничения длины строки 80-ю символами. Применение этого правила в Cappuccino превращает код в нечитаемую кашу, поэтому большинство разработчиков не ограничивают себя при работе как с Objective-J, так и с Objective-C. Единственным исключением являются гайдлайны Google, но на то он и Google.

Теперь сделаем текстовое поле редактируемым и добавим ему рамки:

[textField setEditable:YES];
[textField setBezeled:YES];

Установим Target и Action, т.е. объект и метод, который должен у него вызваться при нажатии кнопки Enter в поле:

[textField setTarget:self];
[textField setAction:@selector(didSubmitTextField:)];

@selector используется, чтобы превратить метод в передаваемое значение.

Добавляем поле к окну и фокусируем его:

[contentView addSubview:textField];
[window makeFirstResponder:textField];

И наконец, показываем окно:

[window center];
[window setTitle:"Twitter Search"];
[window orderFront:self];

С инициализацией приложения покончено, теперь определим его реакцию на нажатие Enter, т.е. метод didSubmitTextField:

- (void)didSubmitTextField:(CPTextField)textField
{
    var searchString = [textField stringValue];
    if (!searchString)
        return;
    [[[SearchWindowController alloc] initWithSearchString:searchString] showWindow:nil];
    [textField setStringValue:""];
    [[textField window] makeKeyAndOrderFront:nil];
}

Мы извлекаем значение текстового поля и, если оно не пусто, создаем экземпляр SearchWindowController, показываем его окно, опустошаем текстовое поле и выдвигаем его окно вперед. Дело за малым – разработать класс SearchWindowController.

Создадим файл SearchWindowController.j и отнаследуем наш класс от CPWindowController:

@implementation SearchWindowController : CPWindowController
{
}

@end

Определим конструктор, создающий окно и делающий запрос к твиттеру:

- (id)initWithSearchString:(CPString)searchString
{
    if (self = [super init]) {
        var window = [[CPWindow alloc] initWithContentRect:CGRectMake(10, 30, 300, 400)
                                                 styleMask:CPTitledWindowMask | CPClosableWindowMask | CPResizableWindowMask];
        [window setTitle:searchString];
        [self setWindow:window];
        var request = [CPURLRequest requestWithURL:"http://search.twitter.com/search.json?q=" + encodeURIComponent(searchString)];
        [CPJSONPConnection sendRequest:request callback:"callback" delegate:self];
    }
    return self;
}

И наконец, напишем обработчик ответа от твиттера:

- (void)connection:(CPJSONPConnection)connection didReceiveData:(Object)data
{
    var contentView = [[self window] contentView];

    if (data.results.length) {
        var bounds = [contentView bounds],
            collectionView = [[CPCollectionView alloc] initWithFrame:bounds];
        [collectionView setAutoresizingMask:CPViewWidthSizable];
        [collectionView setMaxNumberOfColumns:1];
        [collectionView setMinItemSize:CGSizeMake(200, 100)];
        [collectionView setMaxItemSize:CGSizeMake(10000, 100)];

        var itemPrototype = [[CPCollectionViewItem alloc] init];
        [itemPrototype setView:[TweetView new]];
        [collectionView setItemPrototype:itemPrototype];
        [collectionView setContent:data.results];

        var scrollView = [[CPScrollView alloc] initWithFrame:bounds];
        [scrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]
        [scrollView setDocumentView:collectionView];
        [contentView addSubview:scrollView];
    } else {
        var label = [CPTextField labelWithTitle:"No tweets"],
            boundsSize = [contentView boundsSize];
        [label setCenter:CGPointMake(boundsSize.width / 2, boundsSize.height / 2)];
        [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
        [contentView addSubview:label];
    }
}

Для отображения твитов он использует библиотечные классы CPCollectionView, CPCollectionViewItem и CPScrollView. А вот класс TweetView придется определить самостоятельно.

Наверное, вы заметили в коде несколько вызовов метода setAutoresizingMask:. Этот метод заставит вас навсегда проклясть позиционирование CSS, если, конечно, вы этого еще не сделали. Позиционирование элементов управления в Cappuccino настолько просто и элегантно, что с ним справится даже ребенок.

Осталось разобраться с классом TweetView:

@implementation TweetView : CPView
{
    CPImageView imageView;
    CPTextField userLabel;
    CPTextField tweetLabel;
}

- (void)setRepresentedObject:(id)tweet
{
    if (!imageView) {
        imageView = [[CPImageView alloc] initWithFrame:CGRectMake(10, 5, 48, 48)];
        [self addSubview:imageView];

        userLabel = [[CPTextField alloc] initWithFrame:CGRectMake(65, 0, -60, 18)];
        [userLabel setAutoresizingMask:CPViewWidthSizable];
        [userLabel setFont:[CPFont boldSystemFontOfSize:12]];
        [self addSubview:userLabel];

        tweetLabel = [[CPTextField alloc] initWithFrame:CGRectMake(65, 18, -60, 100)];
        [tweetLabel setAutoresizingMask:CPViewWidthSizable];
        [tweetLabel setLineBreakMode:CPLineBreakByWordWrapping];
        [self addSubview:tweetLabel];
    }
    [imageView setImage:[[CPImage alloc] initWithContentsOfFile:tweet.profile_image_url size:CGSizeMake(48, 48)]];
    [userLabel setStringValue:tweet.from_user];
    [tweetLabel setStringValue:tweet.text];
}

@end

Метод setRepresentedObject: создает изображение аватара и две метки, с именем пользователя и твитом.

Теперь снова откроем index-debug.html и поищем несколько слов. Результат должен получиться примерно такой:


Вы можете просмотреть полный код примера и протестировать его.

Что дальше?


Конечно, в этом очерке невозможно было описать и десятую долю функционала Cappuccino. Однако я уверен, что сейчас вы уже готовы начать разработку своих приложений, к чему вас и призываю. Для углубления знаний используйте документацию Cappuccino, также очень рекомендую набор скринкастов по теме. Надеюсь, что титанический труд Франциско, Тома и Росса, а также мой скромный очерк помогут кому-то из вас создать новое интересное веб-приложение.
+90
2287
195

Комментарии (53)

+4
kyrie #
Примеры приложений с их оффсайта —

280slides.com/ — PowerPoint online

gomockingbird.com/mockingbird/ — штука для создания карт

www.enstore.com/demo — магазин
+5
Kicker #
'штука для создания карт' — может штука для создания макетов?
0
toporov #
Спасибо за статью. Akshell тоже сделан на Cappuccino?
+5
korenyushkin #
Да. Я решил поделиться позитивным опытом.
0
cybd #
Отдельное спасибо за Akshell
0
korenyushkin #
Пожалуйста :)
+1
MpaK999 #
Выбирал недавно как раз фреймворк для web gui, Cappuccino тоже смотрел, но мне показалось, что именно удобен он будет тем кто писал под Mac OS, других программистов слезающих с JQuery, Prototype и ОО JavaScript будет только сковывать.

зы. в итоге выбрал ExtJS, не жалею.
+1
korenyushkin #
Я под Mac не писал, выбрал Cappuccino из-за красивого внешнего вида и под впечатлением от 280 Slides. Только в процессе использования понял, что Cocoa API – это очень круто.
0
MpaK999 #
Видимо мне просто не хватило времени, понял что изучать новый почти язык над JS нет времени и решил, что ExtJS мне всё прозрачнее показывает.
0
pluseg #
Удивительно, но все, кто использует objective-c тоже так говорят — сначала кажется неудобным, но когда распробуешь, понимаешь, насколько круто:)

Странно, что некоторые функции выглядят не по objective-c — я про круглые скобки:

var window = [[CPWindow alloc] initWithContentRect:CGRectMake(100, 100, 250, 70)
0
korenyushkin #
CGRectMake – обычная JavaScript функция. Это тоже скопировано с Cocoa, там CGRectMake – обычная C-шная функция.
0
Deranged #
Я человек далекий от веб программирования. Но я так понял, что такие сложности нужны только для того, чтобы не нужно было ставить дополнительных компонент для браузеров? Типа Silverlight, Java, Flash и т.д.?
0
marazm #
Чтобы переварить Objective-J код в html + css + js. На мой взгляд, затея не очень. Внешний вид – возможно.
0
korenyushkin #
Честно говоря, никогда не использовал эти технологии. Сложности Cappuccino связаны прежде всего с его мощностью: приложения могут использовать полноценную MVC архитектуру, за счет этого можно строить очень функциональные интерфейсы пользователя. Т.е. сложность изучения на начальном этапе окупает себя в дальнейшем.
0
Deranged #
Ну под Silverlight и не такое можно. Там используется C# и подмножество .NET Framework. Можно использовать хоть MVC, хоть MVVM, хоть напрямую к визуальному дереву обращайся. Плюс там много продвинутых фишек, позаимствованных из WPF — Data Binding, стили и шаблоны, Dependency Property и много чего еще, облегчающего управление поведением визуального дерева. Ну и недостатки есть конечно.
0
korenyushkin #
Все эти вещи, наверняка, очень мощны, но требуют изучения так же, как Cappuccino. В Cappuccino тоже есть продвинутые фишки, не описанные в очерке, например, Key-Value Binding (судя по названию, это аналог Data Binding). Думаю, что с WPF проще перейти на Silverlight, с Cocoa – на Cappuccino.

Большим плюсом Cappuccino по сравнению с Silverlight является то, что он не требует ничего, кроме современного браузера.
0
bagyr #
Этакий привет GWT.
А представление о Cocoa по этой вещи получить реально?
0
korenyushkin #
Конечно, я активно пользовался эппловской документацией – Cappuccino реализует большую часть API Cocoa.
–2
Deranged #
К слову, в опере не пашет. Вот вам и кроссбраузерность.
0
depporter #
хм, странно. у меня в опере заработало
0
cybd #
Что именно не заработало в опере?
0
Deranged #
Ну во первых Your browser isn't supported.
Если в быстрых настройках замаскировать под firefox, то открывается, но ничего напечатать нельзя.
+1
korenyushkin #
Видимо, речь идет про Akshell, а не про учебный пример. Опера не поддерживается не из-на Cappuccino, а из-за Mozilla Skywriter, текстового редактора. В ближайшее время я переведу Akshell на его наследника ACE, тогда все браузеры будут поддерживаться.
+1
korenyushkin #
Вообще Cappuccino поддерживает все браузеры. Например, gomockingbird.com/ работает в опере, я проверил. У просто у меня стояла не релизная версия фреймворка, а просто выкачанная из master, обновляться я поленился. Думаю проблема в этом, с Cappuccino 0.9 все должно работать отлично.
+2
azproduction #
При компиляции кода Cappuccino в JavaScript мы получим совершенно другой код. Полученный код будет не наш, мы не сможем его эффективно отладить как мы сможем отладить чистый JavaScript (будем отлаживать не то, что писали) это как писать на C, а отлаживать машинные команды в asm. Плюс ко всему из-за обертки над DOM JS CSS мы теряем контроль над конечным результатом и поэтому мы не сможем оптимизировать. Такая же проблема с CoffeeScript
+1
korenyushkin #
В принципе, компиляция Objective-J не такой уж хитрый процесс, самое главное, что в нем происходит – это замена отсылки сообщений через синтаксис квадратных скобок на вызовы функции objj_msgSend с соответствующими параметрами. Т.е. Cappuccino приложения вполне можно отлаживать в Firebug, мне приходилось. Не слишком удобно, конечно, но возможно.

Если требуются оптимизация или прямой доступ к DOM, в Cappuccino нужно создавать кастомный контрол и писать код на JavaScript. Контролы самого Cappuccino так и реализованы. Еще можно просто создать iframe.

Ну а потеря контроля над конечным результатом – следствие любой абстракции. Просто для многих приложений это приемлемо.
0
impwx #
Удручает практически полное отсутствие hover-эффектов. Ни в Mockingbird, ни в 280slides не заметил. Хоть бы курсор менялся при наведении.
+2
combdn #
Это называется осознанным проектированием интерфейса.

О чем сообщает hover-эффект? О том что курсор над объектом. Но мы же только что сами его туда передвинули, зачем об этом дополнительно сообщать?

Такие эффекты нужны только в ситуациях, когда курсор находится над объектом, от которого мы не ожидаем интерактивности.

Чем меньше сигналов пользователь получает, тем меньше он устает от работы и более сосредоточен на своей задаче. Интерфейс это необходимое зло, и должен привлекать к себе как можно меньше внимания.

P. S. Дизайнеры интерфейса виндоус, наверное, не догадываются о таких вещах.
+4
impwx #
Не согласен.

Возможно, это субъективное мнение, но интерфейс с hover-эффектами выглядит куда более отзывчивым и «живым», располагает к тому, чтобы с ним работали. Как правило, именно изменение внешнего вида при наведении намекает мне на то, что от этого объекта можно ожидать интерактивности: активная кнопка при наведении подсвечивается, а неактивная остается такой же.

И причем тут вообще «дизайнеры интерфейса виндоус»? Курсор с ручкой при наведении на ссылку тоже они придумали?
0
combdn #
Почему какие-то эффекты должны намекать, что я могу нажать на кнопку? Разве кнопки не предназначены для того, чтобы на них нажимать?

Неактивные кнопки просто делают блеклыми (прозрачными, неконтрастными).

Курсор на ссылке нужно менять потому, что HTML позволяет покрасить ссылку любым цветом, набрать любым шрифтом, с подчеркиванием и без и т. д. Т. е. человек на каждом сайте должен иметь одинаковое подтверждение, что именно это странно раскрашенное слово является ссылкой.

Интерфейс — это всегда помеха. Это то, что стоит между мной и тем, что я хочу сделать. И чем он более «живой», мигающий и т. п., тем больше он перетягивает на себя моего внимания. И если уж интерфейс мигнул, значит у него на то должна быть веская причина, потому что для программы не должно быть ничего важнее чем моя работа.
+3
impwx #
Тогда почему в контекстном меню элемент под мышкой-таки подсвечивается? Разве он не предназначен для того, чтобы его нажимали?
–1
combdn #
Потому что это не кнопка, а просто надпись, и ее нажимабельность не очевидна.

К тому же в меню могут быть длинные строки, которые делают его широким, и рядом с короткими пунктами появляется много пустого места. Подсветка показывает, что нажатие на этом пустом месте тоже активирует команду.
0
impwx #
Тогда давайте разберемся в том, какая функция интерфейса основная.

Если рабочая, то такая подсветка тоже будет отвлекать. Человек, который не хочет, чтобы интерфейс отвлекал его от важных дел, скорее всего знает, что щелчок на пустом месте в меню тоже вызовет действие — хотя бы потому, что ни одного интерфейс-тулкита, где клик разрешался бы только на тексте, мне неизвестно.

А если функция обучающая, тогда человек может с равной вероятностью не знать, что можно нажимать на пустое место рядом с пунктом меню или на кнопку. И вообще, кнопка в своем классическом понимании должна быть хотя бы выпуклой, что-ли. Картинка с текстом, никаким образом не выделенная и не подсвечивающаяся при наведении, очень субъективно напоминает что-то нажимаемое.
0
combdn #
Подсветка помогает понять, какому пункту меню принадлежит пустое место, на которое мы кликаем. Т. е. так намного легче целиться, иначе, чтобы точно не промахнуться, мы бы всегда нажимали на текст.

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

Картинка с текстом на тулбаре — это тоже соглашение из макоса. Здесь такие картинки всегда интерактивны. После нескольких минут работы человек привыкает, и отпадает необходимость в лишних сигналах.
+2
pluseg #
Дело в том, что ожидание hover'ов на веб-страницах уже настолько выдрессировано в нас, что ничего нельзя поделать. К тому же сколько бы близко веб-страница не приближалась к десктопному приложению, ощущение, что «это — браузер» и «это — страница» лично меня не покидают, поэтому хочется hover'ов!:)

Да и просто приятно, когда элемент немного подсвечивается.
0
combdn #
Мне кажется, что здесь сыграли свою роль и виндоус с линуксом. У меня после макоса подобных ощущений не возникает. Этому, конечно же, помогает и то, что все контролы скопированы отсюда :)
+2
rushman #
откройте для себя SproutCore. то же самое, но без издевательств над Javascript'ом
0
Riateche #
korenyushkin.github.com/
При вводе буквы в поле поиска фокус из поля пропадает, приходится щелкать в него и писать следующую букву.
Опера 11.01.
0
korenyushkin #
Да, проблема, вероятно, в том, что я взял нестабильную версию фреймворка. Вообще Cappuccino поддерживает все основные браузеры.
0
GreatRash #
korenyushkin.github.com/twitter-search/
Скролл в окне дико тормозит в ИЕ8. Фактически пользоваться колесом мышки нереально, да и перетаскивать ползунок проблематично.
0
korenyushkin #
Да, у Cappuccino пока есть проблемы со скроллингом в некоторых браузерах. Возможно, в новой версии это пофиксили.
0
andoriyu #
А можно я вас задолбаю вопросами в личку о Cappucino? Я давно хотел его начать использовать, но никак не мог найти годную документацию с примерами (спасибо, что сказали о том, что документация от apple подходит). Вот первый вопрос — как вы реализовали авторизацию в своем проекте? А то у меня маленько не получается перенести cocoa (я под ios пишу) в браузер.
0
korenyushkin #
Конечно, можно :)

Авторизация реализуется через Cookies, она обрабатывается на стороне сервера, т.е. клиентский код с ней дела почти не имеет. Единственное, что от него требуется – это отобразить имя пользователя, оно ему передается как глобальная JavaScript переменная, объявленая в HTML файле.
0
andoriyu #
А как клиент с сервером связывается? JSON/XML-RPC? Я сейчас просто пишу сервис где надо будет постоянно обмениваться с сервером информацией по средством json и отображать полученную информацию (например адресная книга), надо иметь возможность изменить информацию и отправить апдейт на сервер (в виде json). Я вот думаю на чем лучше это реализовать.
0
korenyushkin #
Клиент опрашивает сервер с помощью XMLHttpRequest, данные передаются в формате JSON. Но можно любой формат использовать, для Cappuccino это не важно. Для XMLHttpRequest'а и для JSONP в Cappuccino есть удобные «обертки».
0
VolCh #
А кастомизиция/темизация интерфейса какая-нибудь предусмотрена? Уж очень непривычно выглядит тот, что в примерах.
+1
korenyushkin #
Да, Cappuccino поддерживает темы. Но тема по умолчанию (Aristo) самая популярная и, на мой взгляд, самая симпатичная. Ее сделала дизайнерская фирма Sofa.
+1
VolCh #
Один крестик слева может отпугнуть 90% юзеров…
0
PapaBubaDiop #
спасибо и подскажите настолько он удобен для создания веб-приложений для iOS (например в случае не пропускания нативного приложения в appStore) и вдруг есть подводные камни.
0
korenyushkin #
Боюсь, тут я помочь не смогу – нет опыта. Но я помню, что эти вопросы обсуждались в группе Cappuccino, попробуйте поискать там.
0
aishek #
Огромное спасибо за статью! Хочу отметить, что у вас хороший слог: читается на одном дыхании
0
korenyushkin #
Всегда пожалуйста, спасибо за комплимент :)
0
vk2 #
Как, по Вашему ощущению, живет ли еще проект? Я видел относительно свежие новости в их блоге, но по общему ощущению наблюдается какая-то стагнация (что удивительно).

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.