renovate webcomponents

This commit is contained in:
Ilya Kantor 2015-02-21 16:37:10 +03:00
parent 35081a779a
commit 0e62abbff8
21 changed files with 421 additions and 476 deletions

View file

@ -1,4 +1,4 @@
# Shadow DOM, шаблоны и стили # Shadow DOM
Спецификация [Shadow DOM](http://w3c.github.io/webcomponents/spec/shadow/) является отдельным стандартом. Частично он уже используется для обычных DOM-элементов, но также применяется для создания веб-компонентов. Спецификация [Shadow DOM](http://w3c.github.io/webcomponents/spec/shadow/) является отдельным стандартом. Частично он уже используется для обычных DOM-элементов, но также применяется для создания веб-компонентов.
@ -44,7 +44,7 @@ Shadow DOM можно создать внутри любого элемента
Например: Например:
```html ```html
<!--+ run autorun --> <!--+ run autorun="no-epub" -->
<p id="elem">Доброе утро, страна!</p> <p id="elem">Доброе утро, страна!</p>
<script> <script>
@ -60,7 +60,7 @@ Shadow DOM можно создать внутри любого элемента
Внутрь этого Shadow DOM, при желании, можно поместить обычное содержимое. Для этого нужно указать, куда. В Shadow DOM это делается через "точку вставки" (insertion point). Она объявляется при помощи тега `<content>`, например: Внутрь этого Shadow DOM, при желании, можно поместить обычное содержимое. Для этого нужно указать, куда. В Shadow DOM это делается через "точку вставки" (insertion point). Она объявляется при помощи тега `<content>`, например:
```html ```html
<!--+ run autorun --> <!--+ run autorun="no-epub" -->
<p id="elem">Доброе утро, страна!</p> <p id="elem">Доброе утро, страна!</p>
<script> <script>
@ -92,7 +92,7 @@ Shadow DOM примера выше в инструментах разработ
Например: Например:
```html ```html
<!--+ run autorun --> <!--+ run autorun="no-epub" -->
<section id="elem"> <section id="elem">
<h1>Новости</h1> <h1>Новости</h1>
@ -129,7 +129,7 @@ Shadow DOM примера выше в инструментах разработ
Если нужно работать с содержимым в Shadow DOM, то нужно перейти к нему через `elem.shadowRoot`. Можно и создать новое Shadow DOM-дерево из JavaScript, например: Если нужно работать с содержимым в Shadow DOM, то нужно перейти к нему через `elem.shadowRoot`. Можно и создать новое Shadow DOM-дерево из JavaScript, например:
```html ```html
<!--+ run autorun --> <!--+ run autorun="no-epub" -->
<p id="elem">Доброе утро, страна!</p> <p id="elem">Доброе утро, страна!</p>
<script> <script>
@ -157,335 +157,6 @@ Shadow DOM примера выше в инструментах разработ
На момент написания статьи `shadowRoot` можно получить только для Shadow DOM, созданного описанным выше способом, но не встроенного, как в элементах типа `<input type="date">`. На момент написания статьи `shadowRoot` можно получить только для Shadow DOM, созданного описанным выше способом, но не встроенного, как в элементах типа `<input type="date">`.
[/warn] [/warn]
## Шаблоны <template>
Элемент `<template>` предназначен для хранения "образца" разметки, невидимого и предназначенного для вставки куда-либо.
Конечно, есть много способов записать произвольный невидимый текст в HTML. В чём же особенность `<template>`?
Его отличие от обычных тегов в том, что его содержимое обрабатывается особым образом. Оно не только показывается, но и считается находящимся вообще "вне документа".
Однако, вместе с тем, оно всё же обрабатывается браузером (а значит должно быть корректным HTML) и записывается как `DocumentFragment` в свойство тега `content`. Предполагается, что мы, при необходимости, возьмём `content` и вставим, куда надо.
Пример вставки шаблона `tmpl` в Shadow DOM элемента `elem`:
```html
<!--+ run autorun -->
<p id="elem">Доброе утро, страна!</p>
<template id="tmpl">
<h3><content></content></h3>
<p>Привет из подполья!</p>
<script> document.write('...document.write:Новость!'); </script>
</template>
<script>
var root = elem.createShadowRoot();
root.appendChild( tmpl.content.cloneNode(true) );
</script>
```
У нас получилось, что:
<ol>
<li>В элементе `#elem` содержатся данные в некоторой оговорённой разметке.</li>
<li>Шаблон `#tmpl` указывает, как их отобразить, куда и в какие HTML-теги завернуть содержимое `#elem`.</li>
<li>Это содержимое добавляется в Shadow DOM тега. Технически, шаблон можно использовать и без Shadow DOM, но тогда не сработает тег `<content>`.</li>
</ol>
Важные детали:
<ul>
<li>В отличие от вставки через `innerHTML` и от обычного `DocumentFragment`, скрипт внутри шаблона выполнится при вставке. Содержимое шаблона изначально "вне документа" и "оживает", когда оно попадает в него. Это относится ко всему -- картинки начинают загружаться, видео -- проигрываться и т.п.</li>
<li>Мы вставляем не сам `tmpl.content`, а его клон. Это обычная практика, чтобы можно было использовать один шаблон много раз.</li>
</ul>
## Стили
Стилизация Shadow DOM покрывается более общей спецификацией ["CSS Scoping"](http://drafts.csswg.org/css-scoping/).
**По умолчанию стили внутри Shadow DOM относятся только к его содержимому.**
Например:
```html
<!--+ run autorun -->
<p>Жили мы тихо-мирно, и тут...</p>
<p id="elem">Доброе утро, страна!</p>
<template id="tmpl">
*!*
<style> p { color: red; } </style>
*/!*
<h3><content></content></h3>
<p>Привет из подполья!</p>
</template>
<script>
var root = elem.createShadowRoot();
root.appendChild( tmpl.content.cloneNode(true) );
</script>
```
При запуске окрашенным в красный цвет окажется только `<p>` внутри Shadow DOM.
...Но при помощи специальных селекторов переходить через эту границу!
### Извне стиль для Shadow DOM
Если нужно со страницы стилизовать или выбрать элементы внутри Shadow DOM, то можно использовать селекторы:
<ul>
<li>**`::shadow` -- выбирает корень Shadow DOM.**
Например, `#elem::shadow div` найдёт внутри Shadow DOM `#elem` элементы `div`.</li>
<li>**`/deep/` -- особого вида CSS-селектор для всех элементов Shadow DOM, который полностью игнорирует границы между DOM'ами, включая вложенные подэлементы, у которых тоже может быть свой Shadow DOM.**
Например, `#elem /deep/ span` найдёт все `span` внутри Shadow DOM `#elem`, но кроме того, если в `#elem` есть подэлементы, у которых свой Shadow DOM, то оно продолжит поиск в них.
Вот пример, когда внутри одного Shadow DOM есть `<input type="date">`, у которого тоже есть Shadow DOM:
```html
<!--+ run -->
<style>
##elem::shadow span {
/* для span только внутри Shadow DOM #elem */
text-decoration: underline;
}
##elem /deep/ span {
/* для span внутри Shadow DOM #elem и далее внутри input[type=date] */
color: red;
}
</style>
<p id="elem"></p>
<script>
var root = elem.createShadowRoot();
root.innerHTML = "<span>Текущее время:</span> <input type='date'>";
</script>
```
</li>
<li>Кроме того, на Shadow DOM действует CSS-наследование, если свойство поддерживает его по умолчанию.
В этом примере CSS-стили для `body` наследуются на внутренние элементы, включая Shadow DOM:
```html
<!--+ run autorun -->
<style>
body {
color: red;
font-style: italic;
}
</style>
<p id="elem"></p>
<script>
elem.createShadowRoot().innerHTML = "<span>Привет, мир!</span>";
</script>
```
Внутренний элемент станет красным курсивом.
</li>
</ul>
[warn header="Нельзя получить содержимое встроенных элементов"]
Описанные CSS-селекторы можно использовать не только в CSS, но и в `querySelector`.
Исключением являются встроенные элементы типа `<input type="date">`, для которых CSS-селекторы работают, но получить их содержимое нельзя.
Например:
```html
<!--+ run -->
<p id="elem"></p>
<script>
var root = elem.createShadowRoot();
root.innerHTML = "<span>Текущее время:</span> <input type='date'>";
// выберет только span из #elem
// вообще-то, должен выбрать и span из вложенных Shadow DOM,
// но в текущей браузерной реализации для встроенных элементов - не умеет
alert(document.querySelector('#elem /deep/ span').length); // 1
</script>
```
[/warn]
### Стиль Shadow DOM в зависимости от хозяина
Следующие селекторы позволяют выбрать элемент-хозяин:
<ul>
<li>**`:host` выбирает элемент-хозяин**, в котором, живёт Shadow DOM.</li>
<li>**`:host(селектор хозяина)` выбирает элемент-хозяин, если он подходит под селектор.**
Например:
```css
:host(.important) {
/* сработает, если хозяин имеет класс important */
}
```
Этот селектор используется для темизации хозяина "изнутри", в зависимости от его классов и атрибутов.
**Хозяин :host выбирается в именно в контексте Shadow DOM.**
То есть, это доступ не к внешнему элементу, а, скорее, к корню текущего Shadow DOM.
После `:host(...)` мы можем указать селекторы и стили, которые нужно применить, если хозяин удовлетворяет тому или иному условию, например:
```html
<style>
:host p { color: green; }
:host(.important) p { color: red; }
</style>
```
Эти селекторы сработают для `<p>` внутри Shadow DOM, причём второй -- только если у хозяина стоит класс `important`.
</li>
<li>**`:host-context(селектор хозяина)` выбирает элемент-хозяин, если какой-либо из его родителей удовлетворяет селектору.**
Например:
```css
:host-context(h1) p {
/* селектор сработает для p, если хозяин находится внутри h1 */
}
```
Это используется для расширенной темизации, теперь уже не только в зависимости от его атрибутов, но и от того, внутри каких элементов он находится.
</li>
</ul>
Пример использования селектора `:host()` для темизации содержимого:
```html
<!--+ run autorun -->
*!*
<p class="message info">Доброе утро, страна!</p>
*/!*
*!*
<p class="message warning">Внимание-внимание! Говорит информбюро!</p>
*/!*
<template id="tmpl">
<style>
.content {
min-height: 20px;
padding: 19px;
margin-bottom: 20px;
background-color: #f5f5f5;
border: 1px solid #e3e3e3;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
}
*!*
:host(.info) .content {
color: green;
}
:host(.warning) .content {
color: red;
}
*/!*
</style>
<div class="content"><content></content></div>
</template>
<script>
var elems = document.querySelectorAll('p.message');
elems[0].createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
elems[1].createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
</script>
```
### Стиль для содержимого <content>
Тег `<content>` не меняет DOM, а указывает, что где показывать. Поэтому если элемент изначально находится в элементе-хозяине -- внешний документ сохраняет к нему доступ.
К нему будут применены стили и сработают селекторы, всё как обычно.
Например, здесь применится стиль для `<span>`:
```html
<!--+ run -->
<style>
*!*
span { text-decoration: underline; }
*/!*
</style>
<p id="elem"><span>Доброе утро, страна!</span></p>
<template id="tmpl">
<h3><content></content></h3>
<p>Привет из подполья!</p>
</template>
<script>
elem.createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
</script>
```
В примере выше заголовок "Доброе утро, страна!", который пришёл как `<span>` из внешнего документа, будет подчёркнут,
...Но, поскольку эти узлы показываются внутри Shadow DOM, то ему тоже может понадобится к ним доступ.
**Для обращения к "содержимому" `<content>` используется псевдоэлемент `::content`.**
Например, `content[select="h1"]::content span` найдёт элемент `<content select="h1">` и его содержимом* отыщет `<span>`.
Селектор `::content` подразумевает `*::content`, так что `::content span` стилизует все `<span>` внутри всех `<content>`.
Например:
```html
<!--+ run -->
<style>
*!*
span { text-decoration: underline; }
*/!*
</style>
<p id="elem"><span>Доброе утро, страна!</span></p>
<template id="tmpl">
<style>
*!*
::content span { color: green; }
*/!*
</style>
<h3><content></content></h3>
<p>Привет из подполья!</p>
</template>
<script>
elem.createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
</script>
```
Если запустить пример выше, то текст внутри `<h3>` станет зелёным и подчёркнутым одновременно.
Приоритет селекторов расчитывается по [обычным правилам специфичности](http://www.w3.org/TR/css3-selectors/#specificity), если же приоритеты стилей на странице и в Shadow DOM и на странице равны, то, как описано в секции [Cascading](http://dev.w3.org/csswg/css-scoping/#cascading), побеждает страница, а для `!important`-стиля побеждает Shadow DOM.
</li>
</ul>
[summary]
Если обобщить -- инкапсуляция Shadow DOM имеет односторонний характер:
<ul>
<li>Изнутри Shadow DOM можно стилизовать только сам Shadow DOM и узлы, показываемые в `<content>`.</li>
<li>Со страницы можно иметь доступ и стилизовать элементы, изначально находящиеся внутри хозяина -- напрямую, а узлы внутри Shadow DOM -- при помощи селекторов `::shadow` и `/deep/`.</li>
</ul>
[/summary]
## Итого ## Итого
@ -493,16 +164,12 @@ Shadow DOM -- это средство для создания отдельног
<ul> <ul>
<li>Ряд браузерных элементов со сложной структурой уже имеют Shadow DOM.</li> <li>Ряд браузерных элементов со сложной структурой уже имеют Shadow DOM.</li>
<li>Можно создать Shadow DOM внутри любого элемента вызовом `elem.createShadowRoot()`. В дальнейшем его корень будет доступен как `elem.shadowRoot`.</li> <li>Можно создать Shadow DOM внутри любого элемента вызовом `elem.createShadowRoot()`. В дальнейшем его корень будет доступен как `elem.shadowRoot`. У встроенных элементов он недоступен.</li>
<li>Как только у элемента появляется Shadow DOM, его изначальное содержимое скрывается. Теперь показывается только Shadow DOM, который может указать, какое содержимое хозяина куда вставлять, при помощи элемента `<content>`. Можно указать селектор `<content select="селектор">` и размещать разное содержимое в разных местах Shadow DOM.</li> <li>Как только у элемента появляется Shadow DOM, его изначальное содержимое скрывается. Теперь показывается только Shadow DOM, который может указать, какое содержимое хозяина куда вставлять, при помощи элемента `<content>`. Можно указать селектор `<content select="селектор">` и размещать разное содержимое в разных местах Shadow DOM.</li>
<li>Стили и `querySelector`, объявленные внутри Shadow DOM, по умолчанию относятся только к его содержимому, могут обращаться к содержимому `<content>`, но не к основной странице.</li> <li>Элемент `<content>` перемещает содержимое исходного элемента в Shadow DOM только визуально, в структуре DOM оно остаётся на тех же местах.</li>
<li>Стили и `querySelector` с внешней страницы могут преодолевать границу между DOM при помощи селекторов `::shadow` и `/deep/`.</li>
</ul> </ul>
Спецификации, затрагивающие Shadow DOM: Подробнее спецификация описана по адресу [](http://w3c.github.io/webcomponents/spec/shadow/).
Далее мы рассмотрим работу с шаблонами, которые также являются частью платформы Web Components и не заменяют существующие шаблонные системы, но дополняют их важными встроенными в браузер возможностями.
<ul>
<li>[Shadow DOM](http://w3c.github.io/webcomponents/spec/shadow/) -- самая полная спецификация по свойствам и методам Shadow DOM, деталям обработки событий.</li>
<li>[Introduction to Web Components](http://w3c.github.io/webcomponents/explainer/) -- обо всём понемногу.</li>
<li>[CSS Scoping](http://drafts.csswg.org/css-scoping/) -- спецификация по CSS-селекторам, в том числе Shadow DOM.</li>
</ul>

View file

@ -1,4 +0,0 @@
<link rel="import" href="ui-tabs.html">
<link rel="import" href="ui-dialog.html">
...

View file

@ -1,4 +0,0 @@
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<script> alert('Библиотеки подключены!'); </script>

View file

@ -1,2 +0,0 @@
<link rel="import" href="libs.html">
...template и код для диалогов...

View file

@ -1,2 +0,0 @@
<link rel="import" href="libs.html">
...template и код для табов...

View file

@ -1,7 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<link rel="import" id="link" href="timer.html">
</head>
<body></body>
</html>

View file

@ -1,25 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<style>
#timer { color: red; }
</style>
</head>
<body>
<p id="timer">0</p>
<script>
var localDocument = document.currentScript.ownerDocument;
var timer = localDocument.getElementById('timer');
var timerId = setInterval(function() {
timer.innerHTML++;
}, 1000);
document.body.appendChild(timer);
</script>
</body>
</html>

View file

@ -0,0 +1,58 @@
# Шаблоны <template>
Элемент `<template>` предназначен для хранения "образца" разметки, невидимого и предназначенного для вставки куда-либо.
Конечно, есть много способов записать произвольный невидимый текст в HTML. В чём же особенность `<template>`?
Его отличие от обычных тегов в том, что его содержимое обрабатывается особым образом. Оно не только скрыто, но и считается находящимся вообще "вне документа". А при вставке автоматически "оживает", выполняются из него скрипты, начинает проигрываться видео и т.п.
[cut]
Содержимое тега `<template>`, в отличие, к примеру, от шаблонов или `<script type="неизвестный тип">`, обрабатывается браузером. А значит, должно быть корректным HTML.
Оно доступно как `DocumentFragment` в свойстве тега `content`. Предполагается, что мы, при необходимости, возьмём `content` и вставим, куда надо.
## Вставка шаблона
Пример вставки шаблона `tmpl` в Shadow DOM элемента `elem`:
```html
<!--+ run autorun="no-epub" -->
<p id="elem">Доброе утро, страна!</p>
<template id="tmpl">
<h3><content></content></h3>
<p>Привет из подполья!</p>
<script> document.write('...document.write:Новость!'); </script>
</template>
<script>
var root = elem.createShadowRoot();
root.appendChild( tmpl.content.cloneNode(true) );
</script>
```
У нас получилось, что:
<ol>
<li>В элементе `#elem` содержатся данные в некоторой оговорённой разметке.</li>
<li>Шаблон `#tmpl` указывает, как их отобразить, куда и в какие HTML-теги завернуть содержимое `#elem`.</li>
<li>Здесь шаблон показывается в Shadow DOM тега. Технически, это не обязательно, шаблон можно использовать и без Shadow DOM, но тогда не сработает тег `<content>`.</li>
</ol>
Можно также заметить, что в скрипт из шаблона выполнился. Это важнейшее отличие вставки шаблона от вставки HTML через `innerHTML` и от обычного `DocumentFragment`.
Также мы вставили не сам `tmpl.content`, а его клон. Это обычная практика, чтобы можно было использовать один шаблон много раз.
## Итого
Тег `<template>` не призван заменить системы шаблонизации. В нём нет хитрых операторов итерации, привязок к данным.
Его основная особенность -- это возможность вставки "живого" содержимого, вместе со скриптами.
И, конечно, мелочь, но удобно, что он не требует никаких библиотек.

View file

@ -0,0 +1,291 @@
# Стили и селекторы
Стилизация Shadow DOM покрывается более общей спецификацией ["CSS Scoping"](http://drafts.csswg.org/css-scoping/).
По умолчанию стили внутри Shadow DOM относятся только к его содержимому.
[cut]
Например:
```html
<!--+ run autorun="no-epub" -->
<p>Жили мы тихо-мирно, и тут...</p>
<p id="elem">Доброе утро, страна!</p>
<template id="tmpl">
*!*
<style> p { color: red; } </style>
*/!*
<h3><content></content></h3>
<p>Привет из подполья!</p>
</template>
<script>
var root = elem.createShadowRoot();
root.appendChild( tmpl.content.cloneNode(true) );
</script>
```
При запуске окрашенным в красный цвет окажется только `<p>` внутри Shadow DOM. Обратим внимание, окрасился именно тот элемент, который находится непосредственно в Shadow DOM. А элементы, которые отображены в Shadow DOM при помощи `<content>`, этот стиль не получили -- у них есть свои, заданные на внешней странице.
## Внешний стиль для Shadow DOM
Граница между Shadow DOM и основным DOM, хоть и существует, но при помощи специальных селекторов её можно переходить.
Если нужно с основной страницы стилизовать или выбрать элементы внутри Shadow DOM, то можно использовать селекторы:
<ul>
<li>**`::shadow` -- выбирает корень Shadow DOM.**
Выбранный элемент сам по себе не создаёт CSS box, но служит отправной точкой для дальшейшей выборки уже внутри дерева Shadow DOM.
Например, `#elem::shadow > div` найдёт внутри Shadow DOM `#elem` элементы `div` первого уровня.</li>
<li>**`>>>` -- особого вида CSS-селектор для всех элементов Shadow DOM, который полностью игнорирует границы между DOM'ами, включая вложенные подэлементы, у которых тоже может быть свой Shadow DOM.**
Например, `#elem >>> span` найдёт все `span` внутри Shadow DOM `#elem`, но кроме того, если в `#elem` есть подэлементы, у которых свой Shadow DOM, то оно продолжит поиск в них.
Вот пример, когда внутри одного Shadow DOM есть `<input type="date">`, у которого тоже есть Shadow DOM:
```html
<!--+ run -->
<style>
#elem::shadow span {
/* для span только внутри Shadow DOM #elem */
border-bottom: 1px dashed blue;
}
#elem >>> * {
/* для всех элементов внутри Shadow DOM #elem и далее внутри input[type=date] */
color: red;
}
</style>
<p id="elem"></p>
<script>
var root = elem.createShadowRoot();
root.innerHTML = "<span>Текущее время:</span> <input type='date'>";
</script>
```
</li>
<li>Кроме того, на Shadow DOM действует обычное CSS-наследование, если свойство поддерживает его по умолчанию.
В этом примере CSS-стили для `body` наследуются на внутренние элементы, включая Shadow DOM:
```html
<!--+ run autorun="no-epub" -->
<style>
body {
color: red;
font-style: italic;
}
</style>
<p id="elem"></p>
<script>
elem.createShadowRoot().innerHTML = "<span>Привет, мир!</span>";
</script>
```
Внутренний элемент станет красным курсивом.
</li>
</ul>
[warn header="Нельзя получить содержимое встроенных элементов"]
Описанные CSS-селекторы можно использовать не только в CSS, но и в `querySelector`.
Исключением являются встроенные элементы типа `<input type="date">`, для которых CSS-селекторы работают, но получить их содержимое нельзя.
Например:
```html
<!--+ run -->
<p id="elem"></p>
<script>
var root = elem.createShadowRoot();
root.innerHTML = "<span>Текущее время:</span> <input type='date'>";
// выберет только span из #elem
// вообще-то, должен выбрать span и из вложенных Shadow DOM,
// но для встроенных элементов - не умеет
alert(document.querySelectorAll('#elem::shadow span').length); // 1
</script>
```
[/warn]
## Стиль в зависимости от хозяина
Следующие селекторы позволяют изнутри Shadow DOM выбрать внешний элемент ("элемент-хозяин"):
<ul>
<li>`:host` выбирает элемент-хозяин, в котором, живёт Shadow DOM.
Хозяин :host выбирается в именно в контексте Shadow DOM.
То есть, это доступ не к внешнему элементу, а, скорее, к корню текущего Shadow DOM.
После `:host` мы можем указать селекторы и стили, которые нужно применить, если хозяин удовлетворяет тому или иному условию, например:
```html
<style>
:host > p { color: green; }
</style>
```
Этот селектор сработает для `<p>` первого уровня внутри Shadow DOM.
</li>
<li>`:host(селектор хозяина)` выбирает элемент-хозяин, если он подходит под селектор.
Этот селектор используется для темизации хозяина "изнутри", в зависимости от его классов и атрибутов. Он отлично добавляет просто `:host`, например:
```css
:host p { color: green; }
:host(.important) p { color: red; }
```
Здесь параграфы будут иметь `color:green`, но если у хозяина класс `.important`, то `color:red`.
</li>
<li>`:host-context(селектор хозяина)` выбирает элемент-хозяин, если какой-либо из его родителей удовлетворяет селектору, например:
```css
:host-context(h1) p {
/* селектор сработает для p, если хозяин находится внутри h1 */
}
```
Это используется для расширенной темизации, теперь уже не только в зависимости от его атрибутов, но и от того, внутри каких элементов он находится.
</li>
</ul>
Пример использования селектора `:host()` для разной расцветки Shadow DOM-сообщения, в зависимости от того, в каком оно `<p>`:
```html
<!--+ run autorun="no-epub" -->
*!*
<p class="message info">Доброе утро, страна!</p>
*/!*
*!*
<p class="message warning">Внимание-внимание! Говорит информбюро!</p>
*/!*
<template id="tmpl">
<style>
.content {
min-height: 20px;
padding: 19px;
margin-bottom: 20px;
background-color: #f5f5f5;
border: 1px solid #e3e3e3;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
}
*!*
:host(.info) .content {
color: green;
}
:host(.warning) .content {
color: red;
}
*/!*
</style>
<div class="content"><content></content></div>
</template>
<script>
var elems = document.querySelectorAll('p.message');
elems[0].createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
elems[1].createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
</script>
```
## Стиль для content
Тег `<content>` не меняет DOM, а указывает, что где показывать. Поэтому если элемент изначально находится в элементе-хозяине -- внешний документ сохраняет к нему доступ.
К нему будут применены стили и сработают селекторы, всё как обычно.
Например, здесь применится стиль для `<span>`:
```html
<!--+ run autorun="no-epub" -->
<style>
*!*
span { text-decoration: underline; }
*/!*
</style>
<p id="elem"><span>Доброе утро, страна!</span></p>
<template id="tmpl">
<h3><content></content></h3>
<p>Привет из подполья!</p>
</template>
<script>
elem.createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
</script>
```
В примере выше заголовок "Доброе утро, страна!", который пришёл как `<span>` из внешнего документа, будет подчёркнут,
Итак, стили основного DOM-дерева применяются, всё в порядке.
Но что, если Shadow DOM тоже "имеет виды" на `<content>` и хочет стилизовать вставленное? Это тоже возможно.
**Для обращения к "содержимому" `<content>` из стилей внутри Shadow DOM используется псевдоэлемент `::content`.**
Например, изнутри Shadow DOM селектор `content[select="h1"]::content span` найдёт элемент `<content select="h1">` и его содержимом* отыщет `<span>`.
В примере ниже селектор `::content span` стилизует все `<span>` внутри всех `<content>`:
```html
<!--+ run -->
<style>
*!*
span { text-decoration: underline; }
*/!*
</style>
<p id="elem"><span>Доброе утро, страна!</span></p>
<template id="tmpl">
<style>
*!*
::content span { color: green; }
*/!*
</style>
<h3><content></content></h3>
<span>Привет из подполья!</span>
</template>
<script>
elem.createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
</script>
```
Текст внутри `<h3>` -- зелёный и подчёркнутый одновременно, но стилизуется именно тот `<span>`, который показан в `<content>, а тот, который просто в Shadow DOM -- нет.
Приоритет селекторов расчитывается по [обычным правилам специфичности](http://www.w3.org/TR/css3-selectors/#specificity), если же приоритеты стилей на странице и в Shadow DOM и на странице равны, то, как описано в секции [Cascading](http://dev.w3.org/csswg/css-scoping/#cascading), побеждает страница, а для `!important`-стиля побеждает Shadow DOM.
## Итого
По умолчанию стили и селекторы из DOM-дерева действуют только на те элементы, в которых сами находятся.
Границу можно преодолевать, причём проще, естественно, от родителя к Shadow DOM, чем наоборот:
<ul>
<li>Снаружи можно выбирать и стилизовать элементы внутри Shadow DOM -- при помощи селекторов `::shadow` и `>>>`.</li>
<li>Изнутри Shadow DOM можно стилизовать не только то, что изначально в Shadow DOM, но и узлы, показываемые в `<content>`.</li>
<li>Также можно ставить стиль в зависимость от хозяиня при помощи селекторов `::host`, `::host-context`, но выбирать и стилизовать произвольные теги внутри хозяина нельзя.</li>
</ul>

View file

@ -1,2 +0,0 @@
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>

View file

@ -16,9 +16,11 @@
Это хорошо, когда нужно действительно в одной странице отобразить содержимое другой. Это хорошо, когда нужно действительно в одной странице отобразить содержимое другой.
А что, если нужно встроить другой документ как естественную часть текущего? С единым скриптовым пространством, едиными стилями. И желательно не иметь проблем с разными доменами: если уж мы действительно хотим подключить HTML с одного домена в страницу на другом -- мы должны иметь возможность это сделать без "плясок с бубном". А что, если нужно встроить другой документ как естественную часть текущего? С единым скриптовым пространством, едиными стилями, но при этом -- другой документ.
Именно для этого предназначен `<link rel="import" href="...">`. Например, это нужно для подгрузки внешних частей документа (веб-компонент) снаружи. И желательно не иметь проблем с разными доменами: если уж мы действительно хотим подключить HTML с одного домена в страницу на другом -- мы должны иметь возможность это сделать без "плясок с бубном".
Иначе говоря, `<link rel="import">` -- это аналог `<script>`, но для подключения не только скриптов, а документов, с шаблонами, библиотеками, веб-компонентами и т.п. Всё станет понятнее, когда мы посмотрим детали.
## Пример вставки ## Пример вставки
@ -29,7 +31,7 @@
``` ```
<ul> <ul>
<li>В отличие от `<iframe>` тег `<link rel="import">` может быть в любом месте документа.</li> <li>В отличие от `<iframe>` тег `<link rel="import">` может быть в любом месте документа, даже в `<head>`.</li>
<li>При вставке через `<iframe>` документ показывается внутри фрейма. В случае с `<link rel="import">` это не так, по умолчанию документ вообще не показывается.</li> <li>При вставке через `<iframe>` документ показывается внутри фрейма. В случае с `<link rel="import">` это не так, по умолчанию документ вообще не показывается.</li>
</ul> </ul>
@ -39,65 +41,43 @@
Мы сами решаем, где и когда его вставить. Мы сами решаем, где и когда его вставить.
Например:
[iframe src="import-show" link edit height="60" border="1"]
Основной документ: В примере ниже `<link rel="import" href="timer.html">` подключает документ `timer.html` и, после его загрузки, вызывает функцию `show`. Эта функция через `link.import.querySelector('time')` выбирает интересующую часть подгруженного документа и вставляет её в текущий:
```html ```html
<!--+ src="index.html" --> <!--+ src="import-show/index.html" -->
``` ```
Важные детали: В файле `timer.html` находится элемент и скрипт, который его "оживляет":
<ul>
<li>Загрузка осуществляется асинхронно, для того чтобы поймать момент загрузки -- используется событие `onload`, для ошибки -- `onerror`.</li>
<li>Подгруженный документ доступен как `link.import`. Это полноценный HTML-документ.</li>
</ul>
Файл `timer.html`:
```html ```html
<!--+ src="timer.html" --> <!--+ src="import-show/timer.html" -->
``` ```
[codetabs src="import-show" height=350]
Важные детали: Важные детали:
<ul> <ul>
<li>После загрузки все скрипты в подключённом `timer.html` выполняются в контексте основной страницы, так что `timer` и другие переменные станут глобальными переменными страницы.</li> <li>После загрузки все скрипты в подключённом `timer.html` выполняются в контексте основной страницы, так что `timer` и другие переменные станут глобальными переменными страницы.</li>
<li>Переменная `document` -- это документ основной страницы. Для доступа к импортированному, то есть текущему документу его можно получить как `document.currentScript.ownerDocument`.</li> <li>Переменная `document` -- это документ основной страницы. Для доступа к импортированному, то есть текущему документу изнутри `timer.html` его можно получить как `document.currentScript.ownerDocument`.</li>
<li>Таймер в загруженном документе начинает работать сразу, новый документ активен, хотя до переноса узлов в основной документ этого не видно.</li> <li>Таймер в загруженном документе начинает работать сразу, новый документ оживает сразу после загрузки, хотя до переноса узлов в основной документ этого может быть и не видно.</li>
</ul> </ul>
В примере выше содержимым импорта управлял основной документ, но `timer.html` мог бы и показать сам себя вызовом `document.body.appendChild(timer)` или вызвать функцию с внешнего документа, так как у них единая область видимости. Тогда не понадобился бы никакой `onload`. В примере выше содержимым импорта управлял основной документ, но `timer.html` мог бы и показать сам себя вызовом `document.body.appendChild(timer)` или вызвать функцию с внешнего документа, так как у них единая область видимости. Тогда не понадобился бы никакой `onload`.
Ещё пример вставки: Ещё пример вставки, на этот раз документ только подключает `<link>`, а таймер вставляет себя сам:
[iframe src="import-style" link edit height="60" border="1"] [codetabs src="import-style" height="200"]
Основной документ: Обратим внимание -- стили импорта попадают в контекст страницы. В примере выше импорт добавил и стиль для `#timer` и сам элемент.
```html
<!--+ src="index.html" -->
```
Сейчас он просто загружает `timer.html` и всё. А вставит себя импорт сам.
Файл `timer.html`:
```html
<!--+ src="timer.html" -->
```
**Обратим внимание -- стили импорта попадают в контекст страницы.**
В примере выше импорт добавил и стиль для `#timer` и сам элемент.
## Веб-компоненты ## Веб-компоненты
Импорт задуман как часть платформы веб-компонент. Импорт задуман как часть платформы Web Components.
Предполагается, что главный документ может импортировать файлы-определения, в которых будут все необходимые HTML, JS и CSS для элементов: Предполагается, что главный документ может импортировать файлы-определения, в которых будут все необходимые HTML, JS и CSS для элементов, а затем использовать их.
Файл `index.html`: Пример:
```html ```html
<link rel="import" href="ui-tabs.html"> <link rel="import" href="ui-tabs.html">
@ -115,15 +95,6 @@
Если файл `libs.html` импортирован два раза, то CSS и скрипты из него подключатся и выполнятся ровно один раз. Если файл `libs.html` импортирован два раза, то CSS и скрипты из него подключатся и выполнятся ровно один раз.
Файл `libs.html`:
```html
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<script> alert('Библиотеки подключены!'); </script>
```
Это можно использовать, чтобы не подгружать одинаковые зависимости много раз. И сама страница и её импорты, и их подимпорты, и так далее, могут подключать `libs.html` без опасения лишний раз перезагрузить и выполнить скрипты. Это можно использовать, чтобы не подгружать одинаковые зависимости много раз. И сама страница и её импорты, и их подимпорты, и так далее, могут подключать `libs.html` без опасения лишний раз перезагрузить и выполнить скрипты.
Например: Например:
@ -137,7 +108,7 @@
``` ```
</li> </li>
<li>`ui-tabs.html`: <li>`ui-tabs.html` подключает `libs.html`:
```html ```html
<link rel="import" href="libs.html"> <link rel="import" href="libs.html">
@ -146,7 +117,7 @@
</li> </li>
<li>`ui-dialog.html`: <li>`ui-dialog.html` также использует `libs.html`:
```html ```html
<link rel="import" href="libs.html"> <link rel="import" href="libs.html">
@ -156,9 +127,8 @@
</li> </li>
</ul> </ul>
[edit src="import-libs"/]
Открыв пример, вы увидите, что скрипты `libs.html` сработают один раз. Файл `libs.html` при этом будет подключен только один раз. Это позволяет не бояться лишнего дублирования библиотек, используемых при описании множества компонент.
## Итого ## Итого
@ -168,6 +138,6 @@
<li>Скриптовое пространство и стили со страницей будут общие.</li> <li>Скриптовое пространство и стили со страницей будут общие.</li>
<li>Документ DOM -- отдельный, он доступен как `link.import` снаружи, а из внутреннего скрипта -- через `document.currentScript.ownerDocument`. Можно без проблем переносить элементы из главного документа в импорт и наоборот.</li> <li>Документ DOM -- отдельный, он доступен как `link.import` снаружи, а из внутреннего скрипта -- через `document.currentScript.ownerDocument`. Можно без проблем переносить элементы из главного документа в импорт и наоборот.</li>
<li>Импорты могут содержать другие импорты.</li> <li>Импорты могут содержать другие импорты.</li>
<li>Если какой-то URL импортируется повторно -- подключается уже готовый документ, без повторного выполнения скриптов в нём. Это можно использовать для удобного управления зависимостями.</li> <li>Если какой-то URL импортируется повторно -- подключается уже готовый документ, без повторного выполнения скриптов в нём. Это позволяет избежать дублирования при использовании одной библиотеки во множестве мест.</li>
</ul> </ul>

View file

@ -5,8 +5,8 @@
<script> <script>
function show() { function show() {
var p = link.import.querySelector('p') var time = link.import.querySelector('time')
document.body.appendChild(p); document.body.appendChild(time);
}; };
</script> </script>

View file

@ -2,7 +2,7 @@
<html> <html>
<body> <body>
<p id="timer">0</p> <time id="timer">0</time>
<script> <script>
var localDocument = document.currentScript.ownerDocument; var localDocument = document.currentScript.ownerDocument;

View file

@ -1,6 +1,6 @@
# Веб-компонент в сборе # Веб-компонент в сборе
В этой главе мы посмотрим на расширенный пример веб-компонента, включающий в себя описанные ранее технологии: Custom Elements, Shadow DOM, CSS Scoping и, конечно же, Imports. В этой главе мы посмотрим на итоговый пример веб-компонента, включающий в себя описанные ранее технологии: Custom Elements, Shadow DOM, CSS Scoping и, конечно же, Imports.
[cut] [cut]
@ -31,7 +31,7 @@
Этот код ничем не отличается от использования обычного элемента, поэтому перейдём дальше, к содержимому `ui-message.html` Этот код ничем не отличается от использования обычного элемента, поэтому перейдём дальше, к содержимому `ui-message.html`
### Шаблон ## Шаблон для ui-message
Файл `ui-message.html` можно начать с шаблона: Файл `ui-message.html` можно начать с шаблона:
@ -64,21 +64,21 @@
</template> </template>
``` ```
Этот шаблон рисует `<div class="content">` и заполняет его содержимым элемента. Этот шаблон рисует `<div class="content">` и заполняет его содержимым элемента-хозяина.
Важные детали: Важные детали:
<ul> <ul>
<li>Самое важное правило здесь `:host { display:block }`. <li>Самое важное правило здесь `:host { display:block }`.
Оно обязательно! . Это правило задаёт, что элемент-хозяин, то есть `<ui-message>`, будет иметь `display:block`. По умолчанию у элементов стоит `display: inline`, а это значит, что ни ширину ни `margin` указать не получится Оно обязательно! . Это правило задаёт, что корень DOM-дерева будет иметь `display:block`. По умолчанию `:host` не создаёт CSS-блок, а это значит, что ни ширину ни отступы указать не получится.</li>
<li>Последующие правила `:host(.info) .content` и `:host(.warning) .content` стилизуют содержимое в зависимости от того, какой на хозяине класс.</li>
Обратим внимание -- `display` относится к базовым свойствам элемента, поэтому задаётся в Shadow DOM. Внешняя страница надстраивает свои свойства поверх "стандартных".</li>
<li>Последующие правила `:host(.info) .content` и `:host(.warning) .content` стилизуют уже не хозяина, а элемент `.content` в зависимости от того, какой на хозяине класс.</li>
</ul> </ul>
### Скрипт ## Скрипт для ui-message
<script> В файле `ui-message.html` мы создадим новый элемент `<ui-message>`:
```js
// (1) получить шаблон // (1) получить шаблон
var localDocument = document.currentScript.ownerDocument; var localDocument = document.currentScript.ownerDocument;
var tmpl = localDocument.getElementById('tmpl'); var tmpl = localDocument.getElementById('tmpl');
@ -95,8 +95,7 @@ MessageProto.createdCallback = function() {
document.registerElement('ui-message', { document.registerElement('ui-message', {
prototype: MessageProto prototype: MessageProto
}); });
</script> ```
[/html]
Все компоненты этого кода мы подробно разбирали ранее: Все компоненты этого кода мы подробно разбирали ранее:
@ -106,13 +105,15 @@ document.registerElement('ui-message', {
<li>С момента регистрации все уже существующие элементы `<ui-message>` будут превращены в описанные здесь. И будущие, конечно, тоже.</li> <li>С момента регистрации все уже существующие элементы `<ui-message>` будут превращены в описанные здесь. И будущие, конечно, тоже.</li>
</ol> </ol>
В действии: Компонент в действии:
[iframe src="message" border="1" edit link/] [codetabs src="message" height=200]
## Компонент ui-slider ## Компонент ui-slider с jQuery
Теперь создадим слайдер с использованием библиотеки [jQuery UI](http://jqueryui.com). Компонент может использовать и внешние библиотеки.
Для примера создадим слайдер с использованием библиотеки [jQuery UI](http://jqueryui.com).
Компонент `ui-slider` будет показывать слайдер с минимальным и максимальным значением из атрибутов `min/max` и генерировать событие `slide` при его перемещении. Компонент `ui-slider` будет показывать слайдер с минимальным и максимальным значением из атрибутов `min/max` и генерировать событие `slide` при его перемещении.
@ -132,7 +133,9 @@ document.registerElement('ui-message', {
<div id="value">0</div> <div id="value">0</div>
``` ```
Файл `ui-slider.html` мы разберём по частям. ## Файл компонента ui-slider
Файл `ui-slider.html`, задающий компонент, мы разберём по частям.
### Заголовок ### Заголовок
@ -153,22 +156,21 @@ document.registerElement('ui-message', {
Содержимое `jquery.html`: Содержимое `jquery.html`:
```html ```html
<script src="http://code.jquery.com/jquery-latest.js"></script> <!--+ src="ui-slider/jquery.html" -->
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
``` ```
### Шаблон ### Шаблон
Шаблон будет помещён в Shadow DOM. В нём должны быть стили и элементы, необходимые слайдеру. Шаблон будет помещён в Shadow DOM. В нём должны быть стили и элементы, необходимые слайдеру.
Конкретно для слайдера из разметки достаточно одного элемента `<div id="slider"></div>, который затем будет обработан jQuery UI. Конкретно для слайдера из разметки достаточно одного элемента `<div id="slider"></div>`, который затем будет обработан jQuery UI.
Кроме того, в шаблоне должны быть стили: Кроме того, в шаблоне должны быть стили:
```html ```html
<template id="tmpl"> <template id="tmpl">
<style> <style>
@import url(http://code.jquery.com/ui/1.10.4/themes/ui-lightness/jquery-ui.css); @import url(http://code.jquery.com/ui/1.11.3/themes/ui-lightness/jquery-ui.css);
:host { :host {
display: block; display: block;
@ -182,7 +184,7 @@ document.registerElement('ui-message', {
Скрипт для нового элемента похож на тот, что делали раньше, но теперь он использует jQuery UI для создания слайдера внутри своего Shadow DOM. Скрипт для нового элемента похож на тот, что делали раньше, но теперь он использует jQuery UI для создания слайдера внутри своего Shadow DOM.
Для его понимания желательно знать jQuery, но я намеренно свёл использование этой библиотеки к минимуму. Ниже будет описание по шагам. Для его понимания желательно знать jQuery, хотя в коде ниже я намеренно свёл использование этой библиотеки к минимуму.
```js ```js
var localDocument = document.currentScript.ownerDocument; var localDocument = document.currentScript.ownerDocument;
@ -230,7 +232,7 @@ document.registerElement('ui-slider', {
Полный код с примером: Полный код с примером:
[iframe src="ui-slider" edit link border="1"/] [codetabs src="ui-slider" height=300]
Его можно далее улучшать, например добавить геттер и сеттер для значения `value`: Его можно далее улучшать, например добавить геттер и сеттер для значения `value`:
@ -247,9 +249,9 @@ Object.defineProperty(SliderProto, 'value', {
Если добавить этот код, то к значению `<ui-slider>` можно будет обращаться как `elem.value`, аналогично всяким встроенным `<input>`. Если добавить этот код, то к значению `<ui-slider>` можно будет обращаться как `elem.value`, аналогично всяким встроенным `<input>`.
**Попробуйте пример выше. Он не совсем работает!** ## Проблема с jQuery
Слайдер прокручивается первый раз, но второй раз он как-то странно "прыгает". Попробуйте пример выше. Он не совсем работает. Слайдер прокручивается первый раз, но второй раз он как-то странно "прыгает".
Чтобы понять, почему это происходит, я заглянул в исходники jQuery UI и, после отладки происходящего, натолкнулся на проблемный код. Чтобы понять, почему это происходит, я заглянул в исходники jQuery UI и, после отладки происходящего, натолкнулся на проблемный код.
@ -270,7 +272,7 @@ if ( !jQuery.contains( elem.ownerDocument, elem ) ) {
Получилось, что элемент не в документе и одновременно он имеет размеры. Такого разработчики jQuery не предусмотрели. Получилось, что элемент не в документе и одновременно он имеет размеры. Такого разработчики jQuery не предусмотрели.
Можно, конечно, побежать исправлять jQuery, но давайте подумаем. Можно, конечно, побежать исправлять jQuery, но давайте подумаем, может быть так оно и должно быть?
С точки зрения здравого смысла, Shadow DOM является частью текущего документа. Это соответствует и духу [текущей спецификации](http://w3c.github.io/webcomponents/spec/shadow/), где shadow tree рассматривается в контексте document tree. С точки зрения здравого смысла, Shadow DOM является частью текущего документа. Это соответствует и духу [текущей спецификации](http://w3c.github.io/webcomponents/spec/shadow/), где shadow tree рассматривается в контексте document tree.
@ -278,18 +280,19 @@ if ( !jQuery.contains( elem.ownerDocument, elem ) ) {
Почему же `false`? Причина проста -- описанный в [другом стандарте](http://www.w3.org/TR/dom/#dom-node-contains) механизм работы `contains` по сути состоит в проходе вверх от `elem` по цепочке `parentNode`, пока либо встретим искомый элемент, тогда ответ `true`, а иначе `false`. В случае с Shadow DOM этот путь закончится на корне Shadow DOM-дерева, оно ведь не является потомком хозяина. Метод `contains` не знает ничего про саму возможность Shadow DOM, поэтому и выходит, что результат `false`. Почему же `false`? Причина проста -- описанный в [другом стандарте](http://www.w3.org/TR/dom/#dom-node-contains) механизм работы `contains` по сути состоит в проходе вверх от `elem` по цепочке `parentNode`, пока либо встретим искомый элемент, тогда ответ `true`, а иначе `false`. В случае с Shadow DOM этот путь закончится на корне Shadow DOM-дерева, оно ведь не является потомком хозяина. Метод `contains` не знает ничего про саму возможность Shadow DOM, поэтому и выходит, что результат `false`.
Так что срочно слать патчи в jQuery здесь рановато, скорее необходимо ещё подумать над стандартами. Это один из тех небольших, но важных нюансов, которые показывают, почему стандарты всё ещё в разработке.
## Итого ## Итого
<ul> <ul>
<li>С использованием современных технологий можно делать компоненты. Но это, всё же, дело будущего. Все стандарты находятся в процессе доработки, готовятся новые.</li> <li>С использованием современных технологий можно делать компоненты. Но это, всё же, дело будущего. Все стандарты находятся в процессе доработки, готовятся новые.</li>
<li>На текущий момент нельзя взять произвольную библиотеку, даже такую распространённую как jQuery, и работать с Shadow DOM с её использованием. Выше была продемонстрирована одна проблема, но возможны и другие.</li> <li>Можно использовать произвольную библиотеку, такую как jQuery, и работать с Shadow DOM с её использованием. Но возможны проблемки. Выше была продемонстрирована одна из них, могут быть и другие.</li>
</ul> </ul>
Самый известный из полифиллов на тему веб-компонент -- это [Polymer](http://www.polymer-project.org). Он старается их эмулировать по возможности кросс-браузерно, но пока что это довольно-таки сложно, в частности, необходима дополнительная разметка. Самый известный из полифиллов на тему веб-компонент -- это [Polymer](http://www.polymer-project.org). Он старается их эмулировать по возможности кросс-браузерно, но пока что это довольно-таки сложно, в частности, необходима дополнительная разметка.
Текущее состояние веб-стандартов -- "взгляд в будущее". Наверно, будет здорово, когда оно наступит :) Текущее состояние веб-стандартов -- "взгляд в будущее". Наверно, будет здорово, когда оно наступит.

View file

@ -0,0 +1,2 @@
<script src="http://code.jquery.com/jquery-2.1.3.js"></script>
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.js"></script>

View file

@ -7,7 +7,7 @@
<template id="tmpl"> <template id="tmpl">
<style> <style>
@import url(http://code.jquery.com/ui/1.10.4/themes/ui-lightness/jquery-ui.css); @import url(http://code.jquery.com/ui/1.11.3/themes/ui-lightness/jquery-ui.css);
:host { :host {
display: block; display: block;
@ -32,8 +32,8 @@ SliderProto.createdCallback = function() {
var self = this; var self = this;
this.$slider.slider({ this.$slider.slider({
min: this.getAttribute('min') || 0, min: +this.getAttribute('min') || 0,
max: this.getAttribute('max') || 100, max: +this.getAttribute('max') || 100,
value: this.getAttribute('value') || 0, value: this.getAttribute('value') || 0,
slide: function() { slide: function() {
var event = new CustomEvent("slide", { var event = new CustomEvent("slide", {