Firefox тоже умеет ставить многоточие

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

Такие задачи являются, наверное единственным поводом, чтобы обычно ненавидащие Internet Explorer кодеры, сказали пару неласковых слов в сторону Firefox. А причина в том, что Explorer поддерживает (пока еще, но должно появиться в CSS3) нестандартное свойство text-overflow, а Firefox — нет (глюк № 312156). Даже Opera и Safari дают возможность воспользоваться нестандартной фичей.

Что за text-overflow

Для незнакомых с этим CSS-свойством товарищей скажу пару слов о нем. Известно, что задавая размеры какого-нибудь блокового элемента, все его содержимое, не влезающие в родительские размеры элементарно... торчат из него. А в CSS есть свойство (overflow), которым можно задать что делать с торчащими частями внутренных элементов. Варианта по-сути три: показывать поверх или снизу рядом расположенных элементов (visible, по-умолчанию), обрезать и не показывать ничего (hidden) и наконец — показать полосы прокрутки, чтобы пользователь все-таки смог увидеть что там (scroll и auto — подробности в описании свойства).

Все это конечно очень хорошо, но в случае, когда торчащие части скрыты, часто возникает очень неприятный эффект срезанной посередине буквы. Это должно быть видно в следующем примере (если строчка не обрезается по середине буквы — поиграйтесь с размерами окна браузера):

Пример 1: обрезание строки посередине буквы
<div style="width: 100%; white-space: nowrap; overflow: hidden;">
   Текстовая строка, которая не переносится и поэтому может быть обрезана родителем.
</div>

Подобное обрезание текста может быть расценено отрицательно как с эстетической точки зредия (некрасиво), так и с точки зрения целостности представления информации (нет подсказки пользователю, что это не весь текст). Очень простое решение применяется в различных операционных системах, когда необходимо отобразить длинное название файла, которое не помещается — строка обрезается и в конце (в Mac OS X ~посередине) появляются три точки (или знак многоточия). С одной стороны, визуально название не длиннее максимально возможного, с другой — дается подсказка пользователю, что совершив какие-то действия (наведя мышку на название, кликнув на него) можно узнать полностью всю строку.

Для того, чтобы сделать подобное в Internet Explorer (если не изменяет память еще со времен четвертой версии) существует специальное CSS-свойство text-overflow, которому можно задать значение ellipsis. Как это работает видно на следующем примере (не видите многоточие — уменьшите браузер):

Пример 2: обрезание строки с многоточием
<div class="ellipsis">
   Текстовая строка, которая не переносится и поэтому может быть обрезана родителем.
</div>

Как сделать обрезание многоточием

Во втором примере использовал класс ellipsis. В нем собраны все необходимые значения, которые позволяют добиться необходимого эффекта в максимальном количестве браузеров. Его определение выглядит так:

.ellipsis {
   width: 100%;
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
   -o-text-overflow: ellipsis;
   -moz-binding: url('/examples/text-overflow.xml#ellipsis');
}

Первые три строчки — подготовительная работа. Для того, чтобы обрезались буквы с многоточием, текст в блоке должен быть однострочным, т. е. текст не должен переноситься (02) и сами блок должен обрезаться (03-04). Ширину указываем для Internet Explorer, который не будет обрезать строку, если блок не переведен в т. н. layout mode (об этом в другой статье).

В четвертой строке указываем, что текст должен обрезаться многоточием для Internet Explorer и Safari, в пятой — для Opera (см. врезку «соблюдаем стандарты»).

Соблюдаем стандарты

Свойство text-overflow все еще не является стандартным и разного рода валидаторы по идее должны выдавать ошибку, встретив его в коде. Opera использует префикс «-o-» перед ним, поскольку это правильный метод для объявления нестандартных свойств в CSS. Safari тоже так умеет. И если вы озабочены тем, чтобы ваш код не только работал в разных браузерах, но и валидаторы при этом не ругались, то следует вынести четвертую строку в отдельное объявление стилей для Internet Explorer (комментарии с условиями), а для Safari использовать свойство -webkit-text-overflow, которое является синонимом, но при этом не считается ошибкой.

А вот задумка этой статьи заключена в седьмой строчке:

-moz-binding: url('/examples/text-overflow.xml#ellipsis');

В ней указано, что следует использовать специальную «обвязку» (binding), которая поддерживается Firefox. Правила обвязки описаны во внешнем XML-файле — в данном случае /examples/text-overflow.xml. Поскольку в одном XML-файле можно включить несколько обвязок, то нужная указывается якорем в конце — #ellipsis.

Содержимое файла /examples/text-overflow.xml

<?xml version="1.0"?>
<bindings
	xmlns="http://www.mozilla.org/xbl"
	xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
	<binding id="ellipsis">
		<content>
			<xul:label crop="end" style="width: 100%;"><children/></xul:label>
		</content>
		<implementation>
			<method name="setTextContentToValue">
				<body><![CDATA[
				var eDescription = document.getAnonymousNodes(this)[0];
				if (eDescription) eDescription.value = this.textContent;
				// ]]></body>
			</method>
			<constructor>setTextContentToValue();</constructor>
		</implementation>
		<handlers>
			<handler event="DOMSubtreeModified">setTextContentToValue();</handler>
		</handlers>
	</binding>
	<binding id="none">
		<content><children/></content>
	</binding>
</bindings>

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

Как работает обвязка

Обвязки элементов, это внешние файлы написанные с помощью XBL (XML Binding Language). Это такой аналог . htc-файлов, которые использует Internet Explorer (вероятность, что слышали про них — больше). Его даже предложили в качестве стандартного языка в W3C, но никто, кроме браузеров на основе Gecko, не поддерживает его.

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

Почему именно обвязка

Просто показалось, что это лучшее решение. Как минимум для большинства ситуаций, которые мне встречались в жизни (см. ниже какие ограничения). В качестве плюсов, могу перечислить: это решение исключительно для браузеров на базе Gecko; не задействованы сложные скрипты, за исключение тех, что уже встроены в оболочку; не обрабатываются недостаточно часто возникающие события типа onresize, что означает гладкая работа. Вообще, показывается все как надо.

Кстати, в правой колонке наверху есть ссылки на другие варианты обрезания, которые я нарыл в сети.

Итак, вкратце расскажу про XML-файл, в котором описывают обвязки. Он должен быть специального формата. Может содержать не только одну, но и несколько обвязок. Корневой элемент — <bindings/>, в котором располагаются собственно обвязки — элементы <binding/>. Должен быть способ обратиться к каждой из них, поэтому у каждой задается атрибут id, в котором и записано имя. Именно это имя используется в значении css-свойства после знака #.

В коде, который представлен ниже, видно, что задана одна обвязка с именем ellipsis. О ней пойдет речь в первую очередь.

<?xml version="1.0"?> 
<bindings xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 
   <binding id="ellipsis">
      <content>
         <xul:label crop="end" style="width: 100%;"><children /></xul:label>
      </content>
      <implementation>
         <method name="setTextContentToValue">
            <body><![CDATA[
            var eDescription = document. getAnonymousNodes(this)[0];
            if (eDescription) eDescription. value = this.textContent;
            // ]]></body>
         </method>
         <constructor>setTextContentToValue();</constructor>
      </implementation> 
      ...
   </binding> 
   ...
</bindings> 

Видно, что внутри обвязки расположены два элемента — <content> и <implementation>.

<content>

Элемент <content> содержит весь код, которым будет обрамлен обвязываемый элемент. Все элементы, которые перечислены в нем, будут отображаться браузером, как будто они там, но на самом деле они будут недоступны через DOM, т. е. их нельзя ни увидеть ни изменить с помощью скрипта на странице. Они — анонимные элементы. Единственный элемент, который будет доступен — это сам обвязываемый элемент, содержание которого можно вставить в обвязку с помощью элемента <children />. Именно в этом месте проще всего использовать элементы используемые в интерфейсе самого браузера — они описаны в языке XUL (XML User Interface Language) — чтобы они появились в обычной HTML-странице.

В нашем случае, мы заключаем элемент, чье содержание должно обрезаться многоточием, в элементе <xul:label>. На самом деле в XUL есть два элемента, которые умеют обрезать строку. Второй из них — <xul:description>. Я выбрал <xul:label> поскольку его название короче.

К сожалению есть одна небольшая особенность элементов <xul: label> и <xul: description> — они не умеют обрезать текст, который расположен внутри элемента в качестве дочерных узлов. Они умеют делать то, что нам нужно только с текстом, расположенным в атрибуте value.

<implementation>

Именно поэтому нам понадобиться второй элемент про который упоминалось ранее — <implementation>. В нем можно описать все методы, используемые обвязкой, а также можно задать конструктор — метод, который будет вызван сразу после создание всех элементов обвязки, в котором можно указать все дополнительные действия, недоступные синтаксису в <content>.

У нас как раз есть задача, которую нужно решить, для того, чтобы показать обрезанный текст правильно — необходимо поставить весь текст из обвязываемого элемена в атрибут value элемента <xul:label>. И для этой задачи определим метод, который будет делать требуемую операцию — setTextContentToValue. Потом этот метод можно будет вызывать из других методов обвязки как обычную JavaScript-функцию.

Метод пишется на языке JavaScript. Но к обычным функциям и методам здесь доступны еще методы для нахождения анонимных элементов, которые создаются в <content>. Один из этих методов — document. getAnonymousNodes — достает все анонимные узлы созданные для указаного в параметре обвязываемого элемента. Он возвращает список узлов (как например document. getElementsByTagName), а поскольку в нашем случае мы создали единственный анонимный элемент, то можем смело указать, что требуемый элемент — нулевой (см. стр. 10).

Если мы получили указатель на элемент <xul:label>, то уже можем задать значение для его атрибута value — взяв значение textContent у обвязываемого элемента (кто не знает, это аналог свойства innerText в Internet Explorer) (11).

Теперь остается только вызвать этого метода из конструктора. Коструктор расположен, как несложно догадаться в элементе <constructor>. И наша обвязка почти готова — ей уже можно пользоваться (см. пример 2).

Что еще не хватает

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

Поменять обрезанный текст

Первое, что понадобилось — возможность поменять текст строки. Элементарно поменял значение innerHTML для обвязываемого элемента. И сразу-же понял, что во всех браузерах все хорошо, а в Firefox ничего не происходит.

Понятно почему ничего не происходит. Просто конструктор вызывается только один раз, когда обвязка создается. Если мы хотим, чтобы метод setTextContentToValue вызывался еще и в случае изменения строки, необходимо все-таки перехватить событие.

К счастью, в XBL есть штатный способ перехвата любых событий. Для этого в обвязке необходимо добавить элемент <handlers> в котором создать обработчики. Каждый обработчик, это элемент <handler> в чьем атрибуте event нужно указать событие по которому он будет вызван. В нашем случае это DOMSubtreeModified. А внутри обработчика вызываем уже готовый метод:

   ...
   <handlers id="none">
      <handler event="DOMSubtreeModified">setTextContentToValue();</handler>
   </handlers>

После этого, любое изменение содержания элемента, т. е. изменение строки текста, которая обрезается будет отображаться правильно и в Firefox.

Убрать обрезание

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

Это сработает во всех браузерах, которые делают обрезание штатными средствами, но в Firefox анонимный элемент <xul:label> никуда не денется. И для того, чтобы его убрать, необходимо отменить обвязку.

К сожалению нельзя указать что-нибудь вроде:

.visible {
   -moz-binding: none;
}

Т. е. указать можно, но это не приведет к желаемом результате. Убрать обвязку можно, заменив ее на другую обвязку. Назвал ее другим именем — none и расположил в том-же файле в качестве еще одного элемента <binding>. В качестве содержания этой обвязки присутствует всего-лишь один элемент — <children />. Вставим его на месте 18 строки предыдущего примера:

...
<binding id="none"> 
   <content><children /></content>
</binding> 

Теперь, с его помощью можно убрать обвязку и показать строку полностью, например при наведение курсора мыши на строку:

div.show-on-hover: hover {
   position: relative;
   z-index: 2;
   overflow: visible;
   -moz-binding: url('/examples/text-overflow. xml#none');
}
 
div.show-on-hover: hover span {
   background: #333333;
   color: white;
}

Что получилось, можно увидеть в следующий пример (не работает в Internet Explorer до 8й версии, но этот недостаток не рассматривается в данной статье):

Пример 3: показ полной строки при наведении мыши
 
<div class="ellipsis show-on-hover"> 
   <span>Текстовая строка, которая не переносится и поэтому может быть обрезана родителем.</span>
</div> 

Какие ограничения накладывает это решение

Используя анонимный элемент <xul:label> мы теряем возможность выделять и копировать текст мышкой. Во многих случаях это не критично, тем более, что выделив кусок текста перед и после обрезанной строки, можно скопировать и текст, который мы перекрыли. Но тем не менее нельзя выделить кусок этого текста и выделяя текст всей странице эти строки останутся невыделенными.

Второе ограничение связано с тем, что в Firefox, в отличие от остальных браузерах, нельзя использовать строчные элементы в обрезаемом тексте. Любые оформления текста будут потеряны. Ссылки не будут работать. Это связано с тем, что текст копируется в атрибут value, где разметка не может работать.

Если выделение текста и вложенные элементы для вас не являются критическими — используйте вариант с XML-обвязкой.

Источник: leechy.ru

Оцени публикацию:
  • 1,5
Оценили человек: 1

Похожие статьи:

Справочники и учебники:


Предложения и пожелания:
Ваше имя:
Ваш E-mail:
Сколько будет Οдин + Τри
Главная
X

Новые заметки:

Про что мы забываем когда делаем оценку задачи по времени

Список вопросов для собеседования разработчика по телефону

Symfony2 авторизация без Doctrine2 для чайника

Phpstorm7 LiveEdit

Жесткий хабр или не хабр, тогда кто?

Яндекс.Деньги мошенничество

Как узнать какие страницы в поиске яндекса или это секрет

Последние комменты:

Yapro CMS:

Здравствуйте, Гость | Войти | Регистрация | Карта сайта | RSS ленты | Ошибка в тексте? Выделите её мышкой и нажмите: Ctrl + Enter

youtube.com/watch?v=7hFivbgIEqk

При полном или частичном использовании материалов данного сайта, ссылка на сайт "yapro.ru" обязательна как на источник информации.
Автоматический импорт материалов и информации с сайта запрещен.
Copyrights © 2007 - 2018 YaPro.Ru

Главная » Веб-мастеру » JavaScript »