Pull to refresh

Аккорды с применением высоких технологий

Reading time14 min
Views1.2K
Задача заверстать аппликатуру весьма не тривиальна и от того довольно интересна. Я тоже не устоял перед искушением решить её так как считаю правильным.

Помимо стандартных требований типа кроссбраузерности, масштабираемости, печатаемости и компактности, хотелось бы добиться также и возможности просто тупо скопировать аппликатуру и вставить её, например, в текстовый документ. То есть в текстовом виде аккорд должен иметь примерно следующий вид:

Am
O - - -
O F - -
O - R -
O - M -
O - - -
X - - -


O — открытая струна, X — приглушённая, остальные буквы обозначают пальцы.

Чтобы добиться возможности копирования и обеспечить низкую связность между блоками, вёрстка получается несколько громоздкой: внутрь грифа помещаются струны, внутрь каждой — лады, а в ладах — блоки обозначающие либо прижатые пальцы, либо неприжатые. У всех блоков есть дополнительные параметры, задаваемые в виде hiqus-строки в аттрибуте class — это обеспечивает возможность привязывать к ним визуализацию, а также удобно модифицировать посредством яваскрипта используя соответствующую библиотеку.

Первым делом создадим банк аккордов.

<!DOCTYPE html><br><?xml-stylesheet type="text/xsl" href="styles.xsl?rev:123"?><br><html xmlns:ch="urn:markup:chords"><br>    <head><br>        <title>Все аккорды</title><br>        <link href="styles.css" type="text/css" rel="stylesheet" /><br>    </head><br>    <body><br><br>        <ch:fingerboard id="Am"><br>            <ch:title>Am</ch:title><br>            <br/><br>            <ch:string class=" number=1 "><br>                <ch:head> O </ch:head><br>                <ch:flet class=" number=1 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <ch:flet class=" number=2 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <ch:flet class=" number=3 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>            </ch:string><br>            <br/><br>            <ch:string class=" number=2 "><br>                <ch:head> O </ch:head><br>                <ch:flet class=" number=1 "><br>                    <ch:finger class=" name=fore "> F </ch:finger><br>                </ch:flet><br>                <ch:flet class=" number=2 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <ch:flet class=" number=3 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>            </ch:string><br>            <br/><br>            <ch:string class=" number=3 "><br>                <ch:head> O </ch:head><br>                <ch:flet class=" number=1 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <ch:flet class=" number=2 "><br>                    <ch:finger class=" name=ring "> R </ch:finger><br>                </ch:flet><br>                <ch:flet class=" number=3 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <br/><br>            </ch:string><br>            <ch:string class=" number=4 "><br>                <ch:head> O </ch:head><br>                <ch:flet class=" number=1 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <ch:flet class=" number=2 "><br>                    <ch:finger class=" name=middle "> M </ch:finger><br>                </ch:flet><br>                <ch:flet class=" number=3 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <br/><br>            </ch:string><br>            <ch:string class=" number=5 "><br>                <ch:head> O </ch:head><br>                <ch:flet class=" number=1 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <ch:flet class=" number=2 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <ch:flet class=" number=3 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <br/><br>            </ch:string><br>            <ch:string class=" number=6 mute=true "><br>                <ch:head> X </ch:head><br>                <ch:flet class=" number=1 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <ch:flet class=" number=2 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <ch:flet class=" number=3 "><br>                    <ch:clear> - </ch:clear><br>                </ch:flet><br>                <br/><br>            </ch:string><br>        </ch:fingerboard><br><br>    </body><br></html>

Тут всего один аккорд — остальные добавляются рядом. br-ки нужны для ие, иначе он выстраивает всё в одну строку. К сожалению Опера при копировании выстраивает всё в один столбец из-за использования инлайн блоков =(

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

  1. ch\:string {
  2.     border-bottom: 1pt solid black;
  3.     display: block;
  4.     margin: 0 0 1.3em 0;
  5.     white-space: nowrap;
  6.     padding-right: 2em;
  7. }
  8.  
  9. ch\:string.number\=1 {    border-width: 1.0pt }
  10. ch\:string.number\=2 {    border-width: 1.2pt }
  11. ch\:string.number\=3 {    border-width: 1.4pt }
  12. ch\:string.number\=4 {    border-width: 1.6pt }
  13. ch\:string.number\=5 {    border-width: 1.8pt }
  14. ch\:string.number\=6 {    border-width: 2.0pt }
  15.  
  16. ch\:string.mute\=true {
  17.     border-color: lightgray;
  18. }

Специальные модификаторы в корневом блоке позволяют подсвечивать струны и пальцы. Например:

  1. ch\:fingerboard.highlight\=finger\=\=thumb ch\:finger.name\=thumb,
  2. ch\:fingerboard.highlight\=finger\=\=fore ch\:finger.name\=fore,
  3. ch\:fingerboard.highlight\=finger\=\=middle ch\:finger.name\=middle,
  4. ch\:fingerboard.highlight\=finger\=\=ring ch\:finger.name\=ring,
  5. ch\:fingerboard.highlight\=finger\=\=little ch\:finger.name\=little {
  6.     background-color: red;
  7.     border-color: red;
  8. }

Теперь подключим к нашей странице аккорды из банка:

  1. <!DOCTYPE html>
  2. <?xml-stylesheet type="text/xsl" href="styles.xsl?rev:123"?>
  3. <html xmlns:ch="urn:markup:chords">
  4.     <head>
  5.         <title>Некоторые аккорды</title>
  6.         <link href="styles.css" type="text/css" rel="stylesheet" />
  7.     </head>
  8.     <body>
  9.         <ch:fingerboard src="chords.xml#Am" srctype="text/xml">
  10.             <a href="chords.xml#Am">Аккорд Am</a>
  11.         </ch:fingerboard>
  12.         <ch:fingerboard src="chords.xml#Am" srctype="text/xml" class=" highlight=string==1 highlight=string==2 ">
  13.             <a href="chords.xml#Am">Аккорд Am</a>
  14.         </ch:fingerboard>
  15.         <ch:fingerboard src="chords.xml#Dm" srctype="text/xml">
  16.             <a href="chords.xml#Dm">Аккорд Dm</a>
  17.         </ch:fingerboard>
  18.         <ch:fingerboard src="chords.xml#Dm" srctype="text/xml" class=" highlight=finger==fore highlight=finger==middle ">
  19.             <a href="chords.xml#Dm">Аккорд Dm</a>
  20.         </ch:fingerboard>
  21.     </body>
  22. </html>

Благодаря технологии xhtml-инклудов мы не грузим вёрстку для аккордов с каждой страницей, а единожды загружаем банк аккордов. Новая её реализация выехала в отдельный файл и поддерживает теперь также и загрузку фрагмента документа с указанным идентификатором:

  1. <t:template match=" *[ @src and contains( @srctype, 'xml' ) ] " mode="content">
  2.     <t:variable name="doc" select=" substring-before( @src, '#' ) " />
  3.     <t:variable name="id" select=" substring-after( @src, '#' ) " />
  4.     <t:choose>
  5.         <t:when test=" $id ">
  6.             <t:apply-templates select=" document( $doc ) // *[ @id = $id ][1] / node() " />
  7.         </t:when>
  8.         <t:otherwise>
  9.             <t:apply-templates select=" document( @src ) / * / node() " />
  10.         </t:otherwise>
  11.     </t:choose>
  12. </t:template>

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

  1. <t:template match=" body " mode="content">
  2.     <t:apply-templates select=" * " />
  3.     <script><![CDATA[
  4.         new function( ){
  5.             if( !document.getElementsByTagNameNS ) return;
  6.             var nsList= [ "urn:markup:chords" ];
  7.             for( var nsI= nsList.length; nsI--; ){
  8.                 var els= document.getElementsByTagNameNS( nsList[ nsI ], '*' );
  9.                 while( xel= els[0] ){
  10.                     var el= document.createElement( xel.nodeName );
  11.                     var node;
  12.                     while( node= xel.firstChild ) el.appendChild( node );
  13.                     var sa= xel.attributes;
  14.                     for( var i= 0; i<sa.length; ++i ){
  15.                         var node= sa.item(i);
  16.                         el.setAttribute( node.nodeName, node.nodeValue );
  17.                     };
  18.                     xel.parentNode.replaceChild( el, xel );
  19.                 };
  20.             };
  21.         };
  22.     ]]></script>
  23. </t:template>


Разумеется по прежнему можно отдавать страницу как text/html и вместо аппликатур пользователи увидят ссылки на соответствующие аккорды в банке.
Tags:
Hubs:
+26
Comments146

Articles

Change theme settings