diff --git a/.gitignore b/.gitignore index cfc3838ca..d4f687c7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ .DS_Store +export/* public/* -source/* -config.ini -latest-change.txt -*-ck.js -*.sass-cache/ \ No newline at end of file +source/styleguide/* +vendor/* diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index d79db913a..000000000 --- a/CHANGELOG +++ /dev/null @@ -1,205 +0,0 @@ -THIS CHANGELOG IS AN ATTEMPT TO DOCUMENT CHANGES TO THIS PROJECT. - -PL-v0.7.12 - - FIX: making sure only the hostname shows up for the websocket servers. no ports. - - THX: thanks to @levito for the pull request - -PL-v0.7.11 - - FIX: migrator now orders migrations properly for ubuntu - - THX: thanks to @krulik for reporting the issue & @paulovieira for confirming the fix - -PL-v0.7.10 - - ADD: more responsive pull bar - - THX: thanks to @crohrer for the pull request making the pull bar more responsive - -PL-v0.7.9 - - ADD: .sass-cache now ignored by default - - ADD: configuration options to disable loading of page follow & auto-reload - - ADD: configuration option to set cacheBuster to 0 - - ADD: configuration option to enable QR code feature - - ADD: configuration option to set minimum & maximum widths for the viewport resizer - - ADD: command line flag for generating only the patterns - - ADD: command line flag to set cacheBuster to 0 - - ADD: better handling of missing required directories in public/ - - ADD: added a styleguide-specific.css to better manage classes - - FIX: updated the console help output - - FIX: removed everything in public/ except the README - - FIX: removed the CDN version of jQuery - - FIX: toolbar styles updated - - FIX: icon font for the toolbar is no longer influencing the icon font of the patterns - - FIX: updated the styles for the "find a pattern" field - - FIX: code/annotations views now properly hide on resizing - - FIX: states.css removed and those styles loaded into styleguide.css - - FIX: default images updated - - FIX: removed hay mode from the tool bar by default. can be added back in by editing config.ini - - FIX: general pattern clean-up and re-styling to better match pattern lab's capabilities - - THX: thanks to @illepic for the .sass-cache PR - -PL-v0.7.8 - - ADD: can show annotations on view-all pages by default - - FIX: can target pattern divs and apply annotations - -PL-v0.7.7 - - ADD: can hide all of the patterns for a given pattern type from being shown on the styleguide. good for nested pages/templates - - FIX: the MQ menu is hidden on smaller viewports - -PL-v0.7.6 - - FIX: pattern search now searches the entire name of a pattern - - FIX: the MQ menu lines up with the navigation item - -PL-v0.7.5 - - ADD: a quick pattern search using typeahead - - ADD: keyboard shortcuts for a bunch of features using jwerty - - ADD: using cmd+a/ctrl+a when in code view selects the contents of the currently active tab - - ADD: code and annotation views can be opened automatically on load via query string params - - ADD: can use the config to remove items from pattern nav - - ADD: check for json support now that certain flavors of PHP 5.5.3 don't come with it - - ADD: can use boolean vars to enable/disable sections via pattern parameters - - ADD: pattern states for tracking progress on individual patterns - - FIX: updated icomoon icons - - FIX: code view has tabs - - FIX: code view shows mustache versions of a pattern - - FIX: patterns are properly sorted in style guide and view all views - - FIX: pattern lab-specific JS & CSS is only loaded when in the iframe - - FIX: classlist polyfill for better IE9 support - - FIX: stringified the postmessage messages for better IE9 support - - FIX: make sure history is only used by browsers that support it (e.g. IE9 doesn't) - - FIX: using watcher-launched auto-reload server now works on Windows - - FIX: various bugs with lineage - - FIX: vendored third-party JS and CSS - - FIX: infinite refresh bug squashed - - THX: thanks to @joshrcook for some styling fixes and hitting on the cause of the start-up issues on ubuntu - - THX: thanks to @tylersticka for lots of ideas: pattern states, cmd+a, boolean pattern parameters and the feedback on the watcher - - THX: thanks to @nikvm for the fix for properly sorting the styleguide view - - THX: thanks to @aarongustafson for the idea to only load the JS when it's in the iframe - -PL-v0.7.2 - - FIX: proper support for Windows with the changes that happened in v0.7.0 - - THX: thanks to @chriskevin and @MattKohnen for reporting the issue - -PL-v0.7.1 - - FIX: annotation event should only fire when overlay is active - - FIX: styleguide should properly sort patterns - - THX: thanks to @jplhomer for the heads up on the annotations issue - - THX: thanks to @tylersticka for the heads up on the styleguide issue - -PL-v0.7.0 - - ADD: auto-reload server can be started directly from the watcher - - ADD: pattern parameter support - - ADD: styleModifier support - - ADD: pseudo-pattern support - - ADD: RAM usage now outputted when generating the site - - ADD: an easter egg - - ADD: configuration flag for cleanPublic - - ADD: dedicated pattern header and footer files - - ADD: QR code generator to make mobile testing easier - - ADD: reverse lineages to see where a pattern is used - - ADD: if _data.json contains a reserved keyword an error is thrown - - ADD: closer to being PSR-0 and PSR-1 compatible - - ADD: migrator class to handle file moves/updates between versions - - ADD: configurer class to handle managing the configuration file - - FIX: ran JS hint against project JavaScript - - FIX: attempted to add better cache busting - - FIX: reorganized the project for better upgradeability by moving lots to core/ - - FIX: malformed JSON throws error and gives file name - - FIX: code view styles - - FIX: annotation styles and functionality are now more robust - - FIX: mobile styles are more robust including scrolling on iOS7 - - FIX: drop down interaction - - FIX: refactored how patterns and view all pages are gathered and generated - - FIX: lineage list now hidden if pattern doesn't have a lineage - - FIX: listitems.json and data.json default attributes match - - FIX: an existing config.ini file is automatically updated with new version - - FIX: pull bar now works in Firefox - - FIX: history now works in Firefox - - FIX: renamed the websocket servers - - THX: thanks to @faustgertz for some fixes with the new watcher class - - THX: thanks to @coding-stuff for the original idea and original code for pattern parameters - - THX: thanks to @mattwellss for inspiring the PSR compliant changes as well as changes to the configuration - -PL-v0.6.4 - - FIX: using # for a link won't cause a jump - - THX: thanks to @tylersticka for the heads up - -PL-v0.6.3 - - FIX: making sure code view is properly encoded - - THX: thanks to @tylersticka for the heads up - -PL-v0.6.2 - - FIX: a few small sass and styling tweaks - - THX: thanks to @griffinartworks for the sass and styling fixes - -PL-v0.6.1 - - FIX: fixed the height of the HTML pre element on the pattern detail view - - ADD: added in support for viewing the generated CSS on the pattern detail view - -PL-v0.6.0 - - ADD: a UI list of the current media query widths from the CSS - - ADD: a pattern's "lineage" now displays in the UI under code view - - ADD: annotations can be added to DOM elements of patterns - - ADD: separate annotation views on the list view and pattern details views - - ADD: generate() now "cleans" public/ before generating the site by deleting most everything - - ADD: added support for the css rule saver library - - ADD: can use a flag to generate the specific CSS that is used in a pattern. shows on code view when available. - - ADD: mark-up for a pattern is now included in the UI under code view - - FIX: can open the "raw" version of a pattern in a new window - - FIX: frame resizing bar properly supports decimals - - FIX: the checkboxes for the websocket-based features, page follow & auto-reload, now work - - FIX: postmessage calls now centralized and refactored - - FIX: units appear in the toolbar when using Hay! mode - - FIX: patterns shouldn't be cached - - THX: thanks to @benedfit for the MQ idea which he originally named "phases" - - THX: thanks to @alienlebarge for the "clean public/" idea - -PL-v0.3.6 - - FIX: added a delay to the watcher so the CPU doesn't get maxed - - THX: thanks to martin berglund for the heads up - -PL-v0.3.5 - - ADD: an explicit MIT license - - FIX: updated .gitignore so that it's more flexible - - THX: thanks to @alienlebarge for the .gitignore fix - -PL-v0.3.4 - - FIX: Generator class renamed because it's a reserved name in PHP 5.5 - - THX: thanks to @faustgertz for the heads up - -PL-v0.3.3 - - FIX: links created with {{ link.pattern }} now have the correct path - - FIX: links within a pattern now properly update the history - - FIX: simplified the history updates from a pattern - - THX: thanks to @kevin-heil for the fix for {{ link.pattern }} - -PL-v0.3.2 - - ADD: added .svn to the ignore dirs listing when checking the source dir - - FIX: top-level ignored dirs are now found properly - - THX: thanks to @alienlebarge for the heads up regarding .svn dirs - -PL-v0.3.1 - - FIX: made sure the command scripts work in directories that contain spaces - - THX: thanks to @mattsims for the heads up - -PL-v0.3.0 - - ADD: added "all" link to the nav that takes the user back to the style guide - - ADD: title tag updates when switching patterns - - FIX: if a pattern type or pattern sub-type doesn't have any patterns it's removed from the nav - - FIX: added styleguide.css to the pattern header - - FIX: commented out the video & audio patterns to address an issue w/ Chrome 29, frames, & History API - - FIX: reduced the number of comments called in the comment-thread pattern - - FIX: patterns won't try to auto-reload if viewed directly - - THX: thanks to @bmuenzenmeyer for the "all link" suggestion - -PL-v0.2.0 - - ADD: better styling in the overall navigation (via @geibi) - - FIX: better windows support for the generator and watcher - - FIX: more comprehensive "apache-less" support - - FIX: debian linux path issue when loading mustache - - FIX: pattern fix which mis-used an ID - - FIX: widths in 'ish are now properly updated onload - - THX: thanks to @benedfit & @bmuenzenmeyer for the help w/ windows - - THX: thanks to @geibi for the pull request with the improved nav style - - THX: thanks to @juanmi007 for alerting me to issues on debian - - THX: thanks to @lewisnyman for the pattern fix - -PL-v0.1.0 - - ADD: re-launch of the PHP version of Pattern Lab \ No newline at end of file diff --git a/LICENSE b/LICENSE index 43b93f974..bd36c1262 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-14 Brad Frost, http://bradfrost.com & Dave Olsen, http://dmolsen.com +Copyright (c) 2013-2016 Brad Frost, http://bradfrostweb.com & Dave Olsen, http://dmolsen.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index 4b3621f82..4e6bbb238 100644 --- a/README.md +++ b/README.md @@ -1,137 +1,100 @@ -## About Pattern Lab -- [Pattern Lab Website](http://patternlab.io/) -- [About Pattern Lab](http://patternlab.io/about.html) -- [Documentation](http://patternlab.io/docs/index.html) -- [Demo](http://demo.patternlab.io/) +![license](https://img.shields.io/github/license/pattern-lab/patternlab-php.svg) +[![Packagist](https://img.shields.io/packagist/v/pattern-lab/edition-mustache-standard.svg)](https://packagist.org/packages/pattern-lab/edition-mustache-standard) [![Gitter](https://img.shields.io/gitter/room/pattern-lab/php.svg)](https://gitter.im/pattern-lab/php) -The PHP version of Pattern Lab is, at its core, a static site generator. It combines platform-agnostic assets, like the [Mustache](http://mustache.github.io/)-based patterns and the JavaScript-based viewer, with a PHP-based "builder" that transforms and dynamically builds the Pattern Lab site. By making it a static site generator, Pattern Lab strongly separates patterns, data, and presentation from build logic. +# Pattern Lab Standard Edition for Mustache + +The Pattern Lab Standard Edition for Mustache is the evolution of Pattern Lab 1. Pattern Lab is still, at its core, a prototyping tool focused on encouraging communication between content creators, designers, devs, and clients. It combines platform-agnostic assets, like the [Mustache](http://mustache.github.io/)-based patterns, with a PHP-based "builder." Pattern Lab 2 introduces [the beginnings of an ecosystem](http://patternlab.io/docs/advanced-ecosystem-overview.html) that will allow teams to mix, match and extend Pattern Lab to meet their specific needs. It will also make it easier for the Pattern Lab team to push out new features. Pattern Lab Standard Edition for Mustache is just [one of the four PHP-based Editions currently available](http://patternlab.io/docs/installation.html). ## Demo You can play with a demo of the front-end of Pattern Lab at [demo.patternlab.io](http://demo.patternlab.io). -## Getting Started +## Requirements + +To use the basic features of Pattern Lab to compile patterns, you must have **PHP 5.4+** installed. On Mac OS X Pattern Lab should work "out of the box." If you're on Windows you can [download PHP from PHP.net](http://windows.php.net/download/). Pattern Lab comes with its own built-in web server. + +Pattern Lab uses [Composer](https://getcomposer.org/) to manage project dependencies. It's required if you want to install Pattern Lab using Composer's `create-project` command or if you want to upgrade Pattern Lab in the future. + +## Installing + +There are two methods for downloading and installing the Standard Edition for Mustache: + +* Download a pre-built project +* Create a project based on this Edition with Composer + +### Download a pre-built project -* [Requirements](http://patternlab.io/docs/requirements.html) -* [Installing the PHP Version of Pattern Lab](http://patternlab.io/docs/installation.html) -* [Upgrading the PHP Version of Pattern Lab](http://patternlab.io/docs/upgrading.html) -* [Generating the Pattern Lab Website for the First Time](http://patternlab.io/docs/first-run.html) -* [Editing the Pattern Lab Website Source Files](http://patternlab.io/docs/editing-source-files.html) -* [Using the Command-line Options](http://patternlab.io/docs/command-line.html) -* [Command Prompt on Windows](http://patternlab.io/docs/command-prompt-windows.html) +The fastest way to get started with Pattern Lab's Standard Edition for Mustache is to download the latest pre-built version from the [releases page](https://github.com/pattern-lab/patternlab-php/releases/latest). -## Working with Patterns +### Use Composer to create a project -Patterns are the core element of Pattern Lab. Understanding how they work is the key to getting the most out of the system. Patterns use [Mustache](http://mustache.github.io/) so please read [Mustache's docs](http://mustache.github.io/mustache.5.html) as well. +Pattern Lab uses [Composer](https://getcomposer.org/) to manage project dependencies. -* [How Patterns Are Organized](http://patternlab.io/docs/pattern-organization.html) -* [Adding New Patterns](http://patternlab.io/docs/pattern-add-new.html) -* [Reorganizing Patterns](http://patternlab.io/docs/pattern-reorganizing.html) -* [Including One Pattern Within Another via Partials](http://patternlab.io/docs/pattern-including.html) -* [Managing Assets for a Pattern: JavaScript, images, CSS, etc.](http://patternlab.io/docs/pattern-managing-assets.html) -* [Modifying the Pattern Header and Footer](http://patternlab.io/docs/pattern-header-footer.html) -* [Using Pseudo-Patterns](http://patternlab.io/docs/pattern-pseudo-patterns.html) -* [Using Pattern Parameters](http://patternlab.io/docs/pattern-parameters.html) -* [Using Pattern State](http://patternlab.io/docs/pattern-states.html) -* ["Hiding" Patterns in the Navigation](http://patternlab.io/docs/pattern-hiding.html) -* [Adding Annotations](http://patternlab.io/docs/pattern-adding-annotations.html) -* [Viewing Patterns on a Mobile Device](http://patternlab.io/docs/pattern-mobile-view.html) +#### 1. Install Composer -## Creating & Working With Dynamic Data for a Pattern +Please follow the directions for [installing Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx) on the Composer website. We recommend you [install it globally](https://getcomposer.org/doc/00-intro.md#globally). -The PHP version of Pattern Lab utilizes Mustache as the template language for patterns. In addition to allowing for the [inclusion of one pattern within another](http://patternlab.io/docs/pattern-including.html) it also gives pattern developers the ability to include variables. This means that attributes like image sources can be centralized in one file for easy modification across one or more patterns. The PHP version of Pattern Lab uses a JSON file, `source/_data/data.json`, to centralize many of these attributes. +#### 2. Install the Standard Edition for Mustache -* [Introduction to JSON & Mustache Variables](http://patternlab.io/docs/data-json-mustache.html) -* [Overriding the Central `data.json` Values with Pattern-specific Values](http://patternlab.io/docs/data-pattern-specific.html) -* [Linking to Patterns with Pattern Lab's Default `link` Variable](http://patternlab.io/docs/data-link-variable.html) -* [Creating Lists with Pattern Lab's Default `listItems` Variable](http://patternlab.io/docs/data-listitems.html) +Use Composer's [`create-project` command](https://getcomposer.org/doc/03-cli.md#create-project) to install the Standard Edition for Mustache into a location of your choosing. To create a project do the following: -## Using Pattern Lab's Advanced Features +1. In a terminal window navigate to where you want to install Pattern Lab +2. Type `composer create-project pattern-lab/edition-mustache-standard patternlab2-example && cd $_` -By default, the Pattern Lab assets can be manually generated and the Pattern Lab site manually refreshed but who wants to waste time doing that? Here are some ways that Pattern Lab can make your development workflow a little smoother: +This will install the Standard Edition for Mustache into a directory called `patternlab2-example` in your install location. When prompted choose the "demo" StarterKit. You will be automatically dropped into the project directory after the process is finished. -* [Watching for Changes and Auto-Regenerating Patterns](http://patternlab.io/docs/advanced-auto-regenerate.html) -* [Auto-Reloading the Browser Window When Changes Are Made](http://patternlab.io/docs/advanced-reload-browser.html) -* [Multi-browser & Multi-device Testing with Page Follow](http://patternlab.io/docs/advanced-page-follow.html) -* [Keyboard Shortcuts](http://patternlab.io/docs/advanced-keyboard-shortcuts.html) -* [Special Pattern Lab-specific Query String Variables ](http://patternlab.io/docs/pattern-linking.html) -* [Preventing the Cleaning of public/](http://patternlab.io/docs/advanced-clean-public.html) -* [Generating CSS](http://patternlab.io/docs/advanced-generating-css.html) -* [Modifying the Pattern Lab Nav](http://patternlab.io/docs/advanced-pattern-lab-nav.html) -* [Editing the config.ini Options](http://patternlab.io/docs/advanced-config-options.html) -* [Integration with Compass](http://patternlab.io/docs/advanced-integration-with-compass.html) +**Note:** If you clone or download this repository and use `composer install` to install the project dependencies you'll need to type the following to install the demo StarterKit: + composer install-demo +Otherwise you'll have a very bare set-up of Pattern Lab. -------------------- +## Get Up and Running -## Translations of this document -- [Portuguese](https://github.com/pattern-lab/patternlab-php#sobre-pattern-lab) +After installing do the following to start and view Pattern Lab: -------------------- +1. In a terminal window navigate to the root of your project if you aren't there already +2. Type `php core/console --server --with-watch` +You should now be able to open [http://localhost:8080](http://localhost:8080) to see your generated site. Any changes you make in `./source/` will automatically rebuild your site and reload your browser. -## Sobre Pattern Lab -- [Site Pattern Lab](http://patternlab.io/) -- [Sobre Pattern Lab](http://patternlab.io/about.html) -- [Documentation](http://patternlab.io/docs/index.html) -- [Demo](http://demo.patternlab.io/) +As you get more comfortable with Pattern Lab you can [integrate it with a Gulp or Grunt workflow](http://patternlab.io/docs/advanced-integration-with-grunt.html) and drop some of the native Pattern Lab features like automatic browser reload. You can also check out [the list of plugins](http://patternlab.io/download.html). +## More Documentation -A versão de PHP Pattern Lab é , em sua essência, um gerador de site estático . Ele combina ativos independentes de plataforma , como os [ Mustache] ( http://mustache.github.io/ ) baseados em padrões e o visualizador baseado em JavaScript , com um " construtor " baseado em PHP que transforma e constroi dinamicamente o Pattern Lab Base. Ao torná-lo um gerador de site estático , Pattern Lab separa fortemente padrões , dados e apresentação da lógica de construção. +Obviously Pattern Lab is deeper than the install process. [Check out the documentation](https://patternlab.io/docs/) to learn about how to use patterns, how to modify the data used to populate those patterns, and about some advanced features. -## Demonstração +## Migrating from Pattern Lab 1 to Pattern Lab 2 -Você pode ver a demonstração em [demo.patternlab.io](http://demo.patternlab.io). +Pattern Lab 2 was a complete rewrite and reorganization of Pattern Lab 1. [Learn about the changes](http://patternlab.io/docs/changes-1-to-2.html). After installing the Standard Edition for Mustache do the following to migrate from Pattern Lab 1 to Pattern Lab 2: -## VAMOS COMEÇAR +1. Copy `./source` from your old project to your new install +2. Copy `./source/_patterns/00-atoms/00-meta/_00-head.mustache` to `./source/_meta/_00-head.mustache` +3. Copy `./source/_patterns/00-atoms/00-meta/_01-foot.mustache` to `./source/_meta/_00-foot.mustache` +4. Copy `./source/_data/annotations.js` to `./source/_annotations/annotations.js` -* [Requisitos](http://patternlab.io/docs/requirements.html) -* [Instalação de versão do PHP de Pattern Lab](http://patternlab.io/docs/installation.html) -* [Atualização da versão do PHP para Pattern Lab](http://patternlab.io/docs/upgrading.html) -* [Gerando Pattern Lab site pela primeira vez](http://patternlab.io/docs/first-run.html) -* [Editando os Arquivos Fontes do Pattern Lab Website ](http://patternlab.io/docs/editing-source-files.html) -* [Usando os Comando de linha](http://patternlab.io/docs/command-line.html) -* [Comandos Prompt no Windows](http://patternlab.io/docs/command-prompt-windows.html) +Everything else should work without changes. -## Trabalhando com Padrões +## Need Pattern Lab 1? -Os padrões são o elemento central do Pattern Lab. Entender como elas funcionam é a chave para obter o máximo proveito do sistema. padrões de usar[Mustache](http://mustache.github.io/) apenas leia por favor [Mustache's docs](http://mustache.github.io/mustache.5.html) também. +The [source code for Pattern Lab 1](https://github.com/pattern-lab/patternlab-php/releases/tag/v1.1.0) is still available for download. -* [Como Organizar os Padrões](http://patternlab.io/docs/pattern-organization.html) -* [Adicionando Um Novo Padrão](http://patternlab.io/docs/pattern-add-new.html) -* [Reorganizando os Padrões](http://patternlab.io/docs/pattern-reorganizing.html) -* [Incluindo Um Padrão Dentro Outra Via Partials](http://patternlab.io/docs/pattern-including.html) -* [Gerenciando Assets para Pattern: JavaScript, images, CSS, etc.](http://patternlab.io/docs/pattern-managing-assets.html) -* [Modificando Header and Footer do Padrão](http://patternlab.io/docs/pattern-header-footer.html) -* [Usando Pseudo-Padrões](http://patternlab.io/docs/pattern-pseudo-patterns.html) -* [Usando Parametros Padrões](http://patternlab.io/docs/pattern-parameters.html) -* [Usando Estados de Padrões](http://patternlab.io/docs/pattern-states.html) -* ["Ocultando" Padrões na Navegação](http://patternlab.io/docs/pattern-hiding.html) -* [Adicionando Anotações](http://patternlab.io/docs/pattern-adding-annotations.html) -* [Vendo Padrões nos Dispositivos Mobile](http://patternlab.io/docs/pattern-mobile-view.html) +## Packaged Components -## Criando e Trabalhando com dados dinâmicos para um Padrão +The Standard Edition for Mustache installs the following components: -A versão de PHP Pattern Lab utiliza Mustache como o modelo de linguagem de padrões . Além de permitir que para a[iinclusão de um padrão dentro de outro](http://patternlab.io/docs/pattern-including.html) ele também dá aos desenvolvedores a capacidade padrão para incluir variáveis. Isto significa que atributos como fontes de imagem pode ser centralizado em um único arquivo para facilitar a modificação em uma ou mais padrões. A versão de PHP Pattern Lab utiliza arquivos JSON ', `source/_data/data.json`, para centralizar muitos desses atributos. +* `pattern-lab/core`: [GitHub](https://github.com/pattern-lab/patternlab-php-core), [Packagist](https://packagist.org/packages/pattern-lab/core) +* `pattern-lab/patternengine-mustache`: [documentation](https://github.com/pattern-lab/patternengine-php-mustache#mustache-patternengine-for-pattern-lab-php), [GitHub](https://github.com/pattern-lab/patternengine-php-mustache), [Packagist](https://packagist.org/packages/pattern-lab/patternengine-mustache) +* `pattern-lab/plugin-reload`: [GitHub](https://github.com/pattern-lab/plugin-php-reload), [Packagist](https://packagist.org/packages/pattern-lab/plugin-reload) +* `pattern-lab/styleguidekit-assets-default`: [GitHub](https://github.com/pattern-lab/styleguidekit-assets-default), [Packagist](https://packagist.org/packages/pattern-lab/styleguidekit-assets-default) +* `pattern-lab/styleguidekit-mustache-default`: [GitHub](https://github.com/pattern-lab/styleguidekit-mustache-default), [Packagist](https://packagist.org/packages/pattern-lab/styleguidekit-mustache-default) -* [Introdução JSON & Variaves Mustache ](http://patternlab.io/docs/data-json-mustache.html) -* [Substituindo o Central `data.json` com valores específicos do Padrão](http://patternlab.io/docs/data-pattern-specific.html) -* [Vinculando a Patterns com Pattern Lab's Padrão Variaveis `link` ](http://patternlab.io/docs/data-link-variable.html) -* [Criação de listas com Pattern Lab's Padrão `listItems` ](http://patternlab.io/docs/data-listitems.html) +## List All of the Available Commands and Their Options -##Usando Padrão de Laboratório Recursos Avançados +To list all available commands type: + php core/console --help -Por padrão , os ativos Padrão Lab podem ser gerados manualmente eo site Lab Padrão atualizado manualmente mas quem quer perder tempo fazendo isso? Aqui estão algumas maneiras que Pattern Lab pode fazer o seu fluxo de trabalho de desenvolvimento um pouco mais suave : +To list the options for a particular command type: -* [Prestando atenção para mudanças e padrões Regenerar ](http://patternlab.io/docs/advanced-auto-regenerate.html) -* [Atualização automatica da janela do navegador quando são feitas alterações](http://patternlab.io/docs/advanced-reload-browser.html) -* [Multi- navegador & Testing multi- dispositivo com página ](http://patternlab.io/docs/advanced-page-follow.html) -* [Atalhos do teclado](http://patternlab.io/docs/advanced-keyboard-shortcuts.html) -* [Padrão especial específico - Lab Variáveis ​​string query ](http://patternlab.io/docs/pattern-linking.html) -* [Impedindo a limpeza de public/](http://patternlab.io/docs/advanced-clean-public.html) -* [Gerenciando CSS](http://patternlab.io/docs/advanced-generating-css.html) -* [Modificado os Padrões de Navegação](http://patternlab.io/docs/advanced-pattern-lab-nav.html) -* [Editando as opções config.ini ](http://patternlab.io/docs/advanced-config-options.html) -* [Interação com Compass](http://patternlab.io/docs/advanced-integration-with-compass.html) + php core/console --help --[command] diff --git a/composer.json b/composer.json new file mode 100644 index 000000000..f5106e938 --- /dev/null +++ b/composer.json @@ -0,0 +1,68 @@ +{ + "name": "pattern-lab/edition-mustache-standard", + "description": "The Standard Edition of Pattern Lab for Mustache. Installs all Mustache-related dependencies.", + "keywords": ["pattern lab", "mustache"], + "homepage": "http://patternlab.io", + "license": "MIT", + "type": "project", + "authors": [ + { + "name": "Dave Olsen", + "email": "dmolsen@gmail.com", + "homepage": "http://dmolsen.com", + "role": "Lead Developer" + } + ], + "support": { + "issues": "https://github.com/pattern-lab/patternlab-php/issues", + "wiki": "http://patternlab.io/docs/", + "source": "https://github.com/pattern-lab/patternlab-php/releases" + }, + "autoload": { + "psr-0": { + "PatternLab": "core/src/" + } + }, + "require": { + "php": ">=5.4", + "pattern-lab/core": "^2.0.0", + "pattern-lab/patternengine-mustache": "^2.0.0", + "pattern-lab/styleguidekit-mustache-default": "^3.0.0", + "pattern-lab/plugin-reload": "^2.0.0" + }, + "scripts": { + "server": "php core/console --server", + "generate": "php core/console --generate", + "watch": "php core/console --watch", + "start": "php core/console --server --with-watch", + "install-demo": "php core/console --starterkit --install pattern-lab/starterkit-mustache-demo", + "post-install-cmd": [ + "PatternLab\\Installer::postInstallCmd" + ], + "post-update-cmd": [ + "PatternLab\\Installer::postUpdateCmd" + ], + "post-root-package-install": [ + "PatternLab\\Installer::setProjectInstall", + "PatternLab\\Installer::getSuggestedStarterKits", + "PatternLab\\Installer::getConfigOverrides" + ], + "post-package-install": [ + "PatternLab\\Installer::postPackageInstall" + ], + "post-package-update": [ + "PatternLab\\Installer::postPackageUpdate" + ], + "pre-package-uninstall": [ + "PatternLab\\Installer::prePackageUninstall" + ] + }, + "extra": { + "patternlab": { + "starterKitSuggestions": [ + "pattern-lab/starterkit-mustache-demo", + "pattern-lab/starterkit-mustache-base" + ] + } + } +} diff --git a/config/README b/config/.gitkeep similarity index 100% rename from config/README rename to config/.gitkeep diff --git a/core/autoReloadServer.php b/core/autoReloadServer.php deleted file mode 100755 index 9c3ede53b..000000000 --- a/core/autoReloadServer.php +++ /dev/null @@ -1,45 +0,0 @@ -register(); - -// parse the main config for the content sync port -if (!($config = @parse_ini_file(__DIR__."/../config/config.ini"))) { - print "Missing the configuration file. Please build it using the Pattern Lab builder.\n"; - exit; -} - -// give it a default port -$port = ($config) ? trim($config['autoReloadPort']) : '8001'; -$args = getopt("s"); -$newlines = (isset($args["s"])) ? true : false; - -// start the content sync server -$server = new \Wrench\Server('ws://0.0.0.0:'.$port.'/', array()); - -// register the application -$server->registerApplication('autoreload', new \Wrench\Application\AutoReloadApplication($newlines)); - -if (!isset($args["s"])) { - print "\n"; - print "Auto-reload Server Started...\n"; - print "Use CTRL+C to stop this service...\n"; -} - -// run it -$server->run(); diff --git a/core/builder.php b/core/builder.php deleted file mode 100644 index 925adf98e..000000000 --- a/core/builder.php +++ /dev/null @@ -1,116 +0,0 @@ -register(); - -$loader = new SplClassLoader('Mustache', __DIR__.'/lib'); -$loader->setNamespaceSeparator("_"); -$loader->register(); - - -/******************************* - * Console Set-up - *******************************/ - -$console = new PatternLab\Console; - -// set-up the generate command and options -$console->setCommand("g","generate","Generate Pattern Lab","The generate command generates an entire site a single time. By default it removes old content in public/, compiles the patterns and moves content from source/ into public/"); -$console->setCommandOption("g","p","patternsonly","Generate only the patterns. Does NOT clean public/.","To generate only the patterns:"); -$console->setCommandOption("g","n","nocache","Set the cacheBuster value to 0.","To turn off the cacheBuster:"); -$console->setCommandOption("g","c","enablecss","Generate CSS for each pattern. Resource intensive.","To run and generate the CSS for each pattern:"); - -// set-up an alias for the generate command -$console->setCommand("b","build","Alias for the generate command","Alias for the generate command. Please refer to it's help for full options."); - -// set-up the watch command and options -$console->setCommand("w","watch","Watch for changes and regenerate","The watch command builds Pattern Lab, watches for changes in source/ and regenerates Pattern Lab when there are any."); -$console->setCommandOption("w","p","patternsonly","Watches only the patterns. Does NOT clean public/.","To watch and generate only the patterns:"); -$console->setCommandOption("w","n","nocache","Set the cacheBuster value to 0.","To turn off the cacheBuster:"); -$console->setCommandOption("w","r","autoreload","Turn on the auto-reload service.","To turn on auto-reload:"); - -// set-up the version command -$console->setCommand("v","version","Print the version number","The version command prints out the current version of Pattern Lab."); - - -/******************************* - * Figure out what to run - *******************************/ - -// get what was passed on the command line -$console->getArguments(); - -if ($console->findCommand("h|help") && ($command = $console->getCommand())) { - - // write the usage & help for a specific command - $console->writeHelpCommand($command); - -} else if ($command = $console->getCommand()) { - - // run commands - - // load Pattern Lab's config, if first time set-up move files appropriately too - $configurer = new PatternLab\Configurer; - $config = $configurer->getConfig(); - - // set-up required vars - $enableCSS = ($console->findCommandOption("c|enablecss")) ? true : false; - $moveStatic = ($console->findCommandOption("p|patternsonly")) ? false : true; - $noCacheBuster = ($console->findCommandOption("n|nocache")) ? true : false; - $autoReload = ($console->findCommandOption("r|autoreload")) ? true : false; - - if (($command == "g") || ($command == "b")) { - - // load the generator - $g = new PatternLab\Generator($config); - $g->generate($enableCSS,$moveStatic,$noCacheBuster); - $g->printSaying(); - - } else if ($command == "w") { - - // CSS feature should't be used with watch - $enableCSS = false; - - // load the generator - $g = new PatternLab\Generator($config); - $g->generate($enableCSS,$moveStatic,$noCacheBuster); - - // load the watcher - $w = new PatternLab\Watcher($config); - $w->watch($autoReload,$moveStatic,$noCacheBuster); - - } else if ($command == "v") { - - // write out the version number - print "You're running v".$config["v"]." of the PHP version of Pattern Lab.\n"; - exit; - - } - -} else { - - // write the generic help - $console->writeHelp(); - -} diff --git a/core/config/config.ini.default b/core/config/config.ini.default deleted file mode 100644 index a5d8a5807..000000000 --- a/core/config/config.ini.default +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Configuration Options for Pattern Lab - * If config.ini doesn't exist Pattern Lab will try to create a new version - */ - -v = "0.7.12" - -// file extensions to ignore when building or watching the source dir, separate with a comma -ie = "scss,DS_Store,less" - -// directories and files to ignore when building or watching the source dir, separate with a comma -id = "scss,.svn,.sass-cache" - -// choose if these services should be loaded in the nav and their ports -autoReloadNav = "true" -autoReloadPort = "8002" -pageFollowNav = "true" -pageFollowPort = "8003" - -// whether the qr code generator should be loaded automatically in the nav -qrCodeGeneratorOn = "false" - -// pattern lab's xip host if you have it configured, to be used with the QR code generator -xipHostname = "http://patternlab.*.xip.io" - -// whether the public directory should be cleaned when generating your site -cleanPublic = "true" - -// the minimum and maximum for the viewport resizer -ishMinimum = "240" -ishMaximum = "2600" - -// which, if any, controls to hide in the nav, separate with a comma -ishControlsHide = "hay" - -// the order of pattern states, css class names -patternStates = "inprogress,inreview,complete" - -// the pattern types that shouldn't be included in the style guide, useful if you nest pages/templates -styleGuideExcludes = "" - -// should the cache buster be on, set to false to set the cacheBuster value to 0 -cacheBusterOn = "true" diff --git a/core/console b/core/console new file mode 100644 index 000000000..51e4c0d14 --- /dev/null +++ b/core/console @@ -0,0 +1,46 @@ +dispatch("config.configLoadEnd"); + +// run the console +Console::run(); diff --git a/core/lib/CSSRuleSaver/CSSRuleSaver.php b/core/lib/CSSRuleSaver/CSSRuleSaver.php deleted file mode 100644 index 412e17f4c..000000000 --- a/core/lib/CSSRuleSaver/CSSRuleSaver.php +++ /dev/null @@ -1,266 +0,0 @@ -ruleSets and $this->atRules arrays - * @param {String} the filename of the CSS file - */ - public function loadCSS($file) { - - if (!file_exists($file)) { - $this->error("The CSS file you supplied doesn't seem to exist. Check the path."); - } - - $commentOpen = false; - $atRuleOpen = false; - $declarationBlockOpen = false; - $fontFaceRuleOpen = false; - - $atRule = ""; - $declarationBlock = ""; - $selectors = ""; - - // iterate over the given file and parse it into at-rules, selectors and their given declaration blocks - $fp = fopen($file, "r"); - while(!feof($fp)) { - $current_line = fgets($fp); - if (!feof($fp)) { - - if ((strpos($current_line, "/*") !== false) && (strpos($current_line, "*/") === false)) { - - // matched a comment that *didn't* close on the same line - $commentOpen = true; - - } else if (strpos($current_line, "*/") !== false) { - - // comment closed - $commentOpen = false; - - } else if ($commentOpen) { - - // skip this line of the CSS file because we're inside a comment - - } else if (strpos($current_line, "@") !== false) { - - // matched an at-rule like a media query - $atRuleOpen = true; - $atRule = trim(str_replace("{","",$current_line)); - - // handle the weird case of the @font-face at-rule - if (strpos($current_line, "@font-face") !== false) { - $declarationBlock = ""; - $declarationBlockOpen = true; - $fontFaceRuleOpen = true; - } - - } else if (strpos($current_line, "{") !== false) { - - // matched the opening of a declaration block - $declarationBlock = ""; - $declarationBlockOpen = true; - $selectors = trim(str_replace("{","",$current_line)); - - } else if (strpos($current_line, "}") !== false) { - - // matched the closing of a declaration block or at-rule - if ($atRuleOpen && !$declarationBlockOpen) { - - // it was an at-rule. close it up - $atRuleOpen = false; - - } else { - - // it was a declaration block. close it up. - $declarationBlockOpen = false; - $declarationBlock .= "\t".trim(str_replace("}","",$current_line)); - - // if we're within an at-rule assign all the styles to it (e.g. styles under a media query) - if ($atRuleOpen) { - if (!array_key_exists($atRule,$this->atRules)) { - $this->atRules[$atRule] = array(); - } - $this->atRules[$atRule][$selectors] = !array_key_exists($selectors,$this->atRules[$atRule]) ? "\t".trim($declarationBlock) : $this->atRules[$atRule][$selectors]."\n\t".trim($declarationBlock); - } else { - $this->ruleSets[$selectors] = !array_key_exists($selectors,$this->ruleSets) ? "\t".trim($declarationBlock) : $this->ruleSets[$selectors]."\n\t".trim($declarationBlock); - } - - // wait, a font-face rule was open. close it all up - if ($fontFaceRuleOpen) { - $fontFaceRuleOpen = false; - $atRuleOpen = false; - } else if (substr_count($current_line, "}") > 1) { - - // oops, someone closed the at-rule on the same line as the declaration block - // *shakes fist at sass* - $atRuleOpen = false; - } - } - } else if ($declarationBlockOpen) { - - // declaration block is open so keep reading it in - $declarationBlock .= "\t".ltrim($current_line); - - } - } - } - fclose($fp); - - } - - /** - * Load the HTML data - * @param {String} the filename of the HTML file - */ - public function loadHTML($file,$load = true) { - if ($load) { - if (file_exists($file)) { - $this->htmlData = file_get_contents($file); - } else { - $this->error("The HTML file you supplied doesn't seem to exist. Check the path."); - } - } else { - $this->htmlData = $file; - } - } - - /** - * Save the CSS rules that match between the given CSS file and the HTML file - * - * @return {String} the rules that match between the given CSS file and HTML file - */ - public function saveRules() { - - // make sure data exists to compare - if (($this->htmlData == "") || (count($this->ruleSets) == 0)) { - $this->error("This would work better if there was CSS or HTML data."); - } - - // set-up the selector DOM to compare - $this->dom = new SelectorDOM($this->htmlData); - - // iterate over the default rule sets and test them against the given mark-up - $statements = ""; - foreach ($this->ruleSets as $selector => $declarationBlock) { - $statements .= $this->buildRuleSet($selector,$declarationBlock); - } - - // iterate over the at-rules - foreach ($this->atRules as $atRule => $ruleSets) { - - // iterate over the rule sets in the at-rules and test them against the given mark-up - $atRuleSets = ""; - foreach ($ruleSets as $selector => $declarationBlock) { - $atRuleSets .= $this->buildRuleSet($selector,$declarationBlock,"\t"); - } - - if ($atRuleSets != "") { - - // only write-out the at-rule if it contains at least one rule set - $statements .= $atRule." {\n"; - $statements .= $atRuleSets."\n"; - $statements .= "}\n\n"; - - } else if ($atRule == "@font-face") { - - // if the at-rule is a @font-face write it out no matter what - foreach ($ruleSets as $selector => $ruleSet) { - $statements .= $atRule." {\n"; - $statements .= $ruleSet."\n"; - $statements .= "}\n\n"; - } - - } - } - - unset($this->dom); - - return $statements; - - } - - /** - * Compare the given selector(s) against the DOM. Return the rule set if it matches - * @param {String} the selector(s) to test against the xPath - * @param {String} the declaration block that goes with the selector - * @param {String} any indent characters that might need to be added to the final output - * - * @return {String} if the selector(s) matched return the entire rule set with matches - */ - protected function buildRuleSet($selector,$declarationBlock,$indent = "") { - - // trap the selectors that are found - $foundSelectors = array(); - - // a given selector may have multiple parts (e.g. h1, h2, h3 ) break it up so each can be tested. - $selectors = explode(",",$selector); - - // iterate over each selector - foreach ($selectors as $selector) { - - $selector = trim($selector); - - // save the original selector and strip off bad pseudo-classes for matching purposes - $selectorOrig = $selector; - $badPseudoClasses = array(":first-child",":last-child",":after",":before",":nth-of",":visited",":hover",":focus","::"); - foreach ($badPseudoClasses as $badPseudoClass) { - $pos = strpos($selector,$badPseudoClass); - if ($pos !== false) { - $selector = substr($selector,0,$pos-strlen($selector)); - break; - } - } - - // match the selector against the DOM. if result is found save the original selector format - if (count($this->dom->select($selector)) > 0) { - $foundSelectors[] = $selectorOrig; - } - } - - // if the given selectors matched against the DOM build the rule set - if (count($foundSelectors) > 0) { - - // combine selectors that share a rule set - $i = 0; - $selectorList = ""; - foreach ($foundSelectors as $selector) { - $selectorList .= ($i > 0) ? ", ".$selector : $selector; - $i++; - } - - // write out the rule set & return it - $text = $indent.$selectorList." { \n"; - $text .= str_replace($indent,$indent.$indent,$declarationBlock)."\n"; - $text .= $indent."}\n\n"; - return $text; - - } - - } - - /** - * Print the error message. Yes, I should be using exception handling but I'm being lazy for now - * @param {String} the message to spit out - */ - protected function error($msg) { - print $msg."\n"; - exit; - } - -} diff --git a/core/lib/CSSRuleSaver/LICENSE b/core/lib/CSSRuleSaver/LICENSE deleted file mode 100644 index 2e13f8ef8..000000000 --- a/core/lib/CSSRuleSaver/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Dave Olsen, http://dmolsen.com - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/core/lib/CSSRuleSaver/LICENSE.SelectorDOM b/core/lib/CSSRuleSaver/LICENSE.SelectorDOM deleted file mode 100644 index 55c4aabe3..000000000 --- a/core/lib/CSSRuleSaver/LICENSE.SelectorDOM +++ /dev/null @@ -1,22 +0,0 @@ -(The MIT License) - -Copyright (c) 2008 - 2009 TJ Holowaychuk - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/core/lib/CSSRuleSaver/SelectorDOM.php b/core/lib/CSSRuleSaver/SelectorDOM.php deleted file mode 100755 index 342148559..000000000 --- a/core/lib/CSSRuleSaver/SelectorDOM.php +++ /dev/null @@ -1,178 +0,0 @@ - MIT Licensed - * - * Persitant object for selecting elements. - * - * $dom = new SelectorDOM($html); - * $links = $dom->select('a'); - * $list_links = $dom->select('ul li a'); - * - */ -class SelectorDOM { - - const VERSION = '1.1.3'; - - /** - * @var DOMXPath - */ - protected $xpath; - - /** - * Map of regexes to convert CSS selector to XPath - * - * @var array - */ - public static $regexMap = array( - '/\s*,\s*/' => '|descendant-or-self::', - '/:(button|submit|file|checkbox|radio|image|reset|text|password)/' => 'input[@type="\1"]', - '/\[(\w+)\]/' => '*[@\1]', # [id] - '/\[(\w+)=[\'"]?(.*?)[\'"]?\]/' => '[@\1="\2"]', # foo[id=foo] - '/^\[/' => '*[', # [id=foo] - '/([\w\-]+)\#([\w\-]+)/' => '\1[@id="\2"]', # div#foo - '/\#([\w\-]+)/' => '*[@id="\1"]', # #foo - '/([\w\-]+)\.([\w\-]+)/' => '\1[contains(concat(" ",@class," ")," \2 ")]', # div.foo - '/\.([\w\-]+)/' => '*[contains(concat(" ",@class," ")," \1 ")]', # .foo - '/([\w\-]+):first-child/' => '*/\1[position()=1]', - '/([\w\-]+):last-child/' => '*/\1[position()=last()]', - '/:first-child/' => '*/*[position()=1]', - '/:last-child/' => '*/*[position()=last()]', - '/([\w\-]+):nth-child\((\d+)\)/' => '*/\1[position()=\2]', - '/:nth-child\((\d+)\)/' => '*/*[position()=\1]', - '/([\w\-]+):contains\((.*?)\)/' => '\1[contains(string(.),"\2")]', - '/\s*>\s*/' => '/', # > - '/\s*~\s*/' => '/following-sibling::', # ~ - '/\s*\+\s*([\w\-]+)/' => '/following-sibling::\1[position()=1]', # + - '/\]\*/' => ']', - '/\]\/\*/' => ']', - ); - - /** - * Load $data into the object - * - * @param string|DOMDocument $data - * @param array $errors A by-ref capture for libxml error messages. - */ - public function __construct($data, &$errors = null) { - # Wrap this with libxml errors off - # this both sets the new value, and returns the previous. - $lib_xml_errors = libxml_use_internal_errors(true); - - if (is_a($data, 'DOMDocument')) { - $this->xpath = new \DOMXpath($data); - } else { - $dom = new \DOMDocument(); - $dom->loadHTML($data); - $this->xpath = new \DOMXpath($dom); - } - - # Clear any errors and restore the original value - $errors = libxml_get_errors(); - libxml_clear_errors(); - libxml_use_internal_errors($lib_xml_errors); - } - - /** - * Select elements from the loaded HTML using the css $selector. - * When $as_array is true elements and their children will - * be converted to array's containing the following keys (defaults to true): - * - * - name : element name - * - text : element text - * - children : array of children elements - * - attributes : attributes array - * - * Otherwise regular DOMElement's will be returned. - * - * @param string $selector CSS Selector - * @param boolean $as_array Whether to return an array or DOMElement - */ - public function select($selector, $as_array = true) { - $elements = $this->xpath->evaluate(self::selectorToXpath($selector)); - return $as_array ? self::elementsToArray($elements) : $elements; - } - - /** - * This allows a static access to the class, in the same way as the - * `select_elements` function did. - * - * @see $this->select() - * @param string $html - * @param string $selector CSS Selector - */ - public static function selectElements($selector, $html, $as_array = true) { - $dom = new SelectorDOM($html); - return $dom->select($selector, $as_array); - } - - /** - * Convert $elements to an array. - * - * @param DOMNodeList $elements - */ - public function elementsToArray($elements) { - $array = array(); - for ($i = 0, $length = $elements->length; $i < $length; ++$i) { - if ($elements->item($i)->nodeType == XML_ELEMENT_NODE) { - array_push($array, self::elementToArray($elements->item($i))); - } - } - return $array; - } - - /** - * Convert $element to an array. - */ - public function elementToArray($element) { - $array = array( - 'name' => $element->nodeName, - 'attributes' => array(), - 'text' => $element->textContent, - 'children' => self::elementsToArray($element->childNodes), - ); - if ($element->attributes->length) { - foreach($element->attributes as $key => $attr) { - $array['attributes'][$key] = $attr->value; - } - } - return $array; - } - - /** - * Convert $selector into an XPath string. - */ - public static function selectorToXpath($selector) { - // remove spaces around operators - $selector = preg_replace('/\s*(>|~|\+|,)\s*/', '$1', $selector); - $selectors = preg_split("/\s+/", $selector); - // Process all regular expressions to convert selector to XPath - foreach ($selectors as &$selector) { - foreach (self::$regexMap as $regex => $replacement) { - $selector = preg_replace($regex, $replacement, $selector); - } - } - $selector = implode('/descendant::', $selectors); - $selector = 'descendant-or-self::' . $selector; - return $selector; - } - -} - -# -# Procedural components -# - -define('SELECTOR_VERSION', SelectorDOM::VERSION); - -/** - * Provides a procedural function to select use SelectorDOM::select() - * on some HTML. - */ -function select_elements($selector, $html, $as_array = true) { - return SelectorDOM::selectElements($selector, $html, $as_array); -} - diff --git a/core/lib/Mustache/Autoloader.php b/core/lib/Mustache/Autoloader.php deleted file mode 100644 index df48536d0..000000000 --- a/core/lib/Mustache/Autoloader.php +++ /dev/null @@ -1,69 +0,0 @@ -baseDir = dirname(__FILE__).'/..'; - } else { - $this->baseDir = rtrim($baseDir, '/'); - } - } - - /** - * Register a new instance as an SPL autoloader. - * - * @param string $baseDir Mustache library base directory (default: dirname(__FILE__).'/..') - * - * @return Mustache_Autoloader Registered Autoloader instance - */ - public static function register($baseDir = null) - { - $loader = new self($baseDir); - spl_autoload_register(array($loader, 'autoload')); - - return $loader; - } - - /** - * Autoload Mustache classes. - * - * @param string $class - */ - public function autoload($class) - { - if ($class[0] === '\\') { - $class = substr($class, 1); - } - - if (strpos($class, 'Mustache') !== 0) { - return; - } - - $file = sprintf('%s/%s.php', $this->baseDir, str_replace('_', '/', $class)); - if (is_file($file)) { - require $file; - } - } -} diff --git a/core/lib/Mustache/Compiler.php b/core/lib/Mustache/Compiler.php deleted file mode 100644 index a95c9194b..000000000 --- a/core/lib/Mustache/Compiler.php +++ /dev/null @@ -1,475 +0,0 @@ -pragmas = array(); - $this->sections = array(); - $this->source = $source; - $this->indentNextLine = true; - $this->customEscape = $customEscape; - $this->charset = $charset; - $this->strictCallables = $strictCallables; - - return $this->writeCode($tree, $name); - } - - /** - * Helper function for walking the Mustache token parse tree. - * - * @throws Mustache_Exception_SyntaxException upon encountering unknown token types. - * - * @param array $tree Parse tree of Mustache tokens - * @param int $level (default: 0) - * - * @return string Generated PHP source code - */ - private function walk(array $tree, $level = 0) - { - $code = ''; - $level++; - foreach ($tree as $node) { - switch ($node[Mustache_Tokenizer::TYPE]) { - case Mustache_Tokenizer::T_PRAGMA: - $this->pragmas[$node[Mustache_Tokenizer::NAME]] = true; - break; - - case Mustache_Tokenizer::T_SECTION: - $code .= $this->section( - $node[Mustache_Tokenizer::NODES], - $node[Mustache_Tokenizer::NAME], - $node[Mustache_Tokenizer::INDEX], - $node[Mustache_Tokenizer::END], - $node[Mustache_Tokenizer::OTAG], - $node[Mustache_Tokenizer::CTAG], - $level - ); - break; - - case Mustache_Tokenizer::T_INVERTED: - $code .= $this->invertedSection( - $node[Mustache_Tokenizer::NODES], - $node[Mustache_Tokenizer::NAME], - $level - ); - break; - - case Mustache_Tokenizer::T_PARTIAL: - case Mustache_Tokenizer::T_PARTIAL_2: - $code .= $this->partial( - $node[Mustache_Tokenizer::NAME], - isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '', - $level - ); - break; - - case Mustache_Tokenizer::T_UNESCAPED: - case Mustache_Tokenizer::T_UNESCAPED_2: - $code .= $this->variable($node[Mustache_Tokenizer::NAME], false, $level); - break; - - case Mustache_Tokenizer::T_COMMENT: - break; - - case Mustache_Tokenizer::T_ESCAPED: - $code .= $this->variable($node[Mustache_Tokenizer::NAME], true, $level); - break; - - case Mustache_Tokenizer::T_TEXT: - $code .= $this->text($node[Mustache_Tokenizer::VALUE], $level); - break; - - default: - throw new Mustache_Exception_SyntaxException(sprintf('Unknown token type: %s', $node[Mustache_Tokenizer::TYPE]), $node); - } - } - - return $code; - } - - const KLASS = 'lambdaHelper = new Mustache_LambdaHelper($this->mustache, $context); - $buffer = \'\'; - %s - - return $buffer; - } - %s - }'; - - const KLASS_NO_LAMBDAS = 'walk($tree); - $sections = implode("\n", $this->sections); - $klass = empty($this->sections) ? self::KLASS_NO_LAMBDAS : self::KLASS; - $callable = $this->strictCallables ? $this->prepare(self::STRICT_CALLABLE) : ''; - - return sprintf($this->prepare($klass, 0, false, true), $name, $callable, $code, $sections); - } - - const SECTION_CALL = ' - // %s section - $buffer .= $this->section%s($context, $indent, $context->%s(%s)); - '; - - const SECTION = ' - private function section%s(Mustache_Context $context, $indent, $value) - { - $buffer = \'\'; - if (%s) { - $source = %s; - $buffer .= $this->mustache - ->loadLambda((string) call_user_func($value, $source, $this->lambdaHelper)%s) - ->renderInternal($context, $indent); - } elseif (!empty($value)) { - $values = $this->isIterable($value) ? $value : array($value); - foreach ($values as $value) { - $context->push($value);%s - $context->pop(); - } - } - - return $buffer; - }'; - - /** - * Generate Mustache Template section PHP source. - * - * @param array $nodes Array of child tokens - * @param string $id Section name - * @param int $start Section start offset - * @param int $end Section end offset - * @param string $otag Current Mustache opening tag - * @param string $ctag Current Mustache closing tag - * @param int $level - * - * @return string Generated section PHP source code - */ - private function section($nodes, $id, $start, $end, $otag, $ctag, $level) - { - $method = $this->getFindMethod($id); - $id = var_export($id, true); - $source = var_export(substr($this->source, $start, $end - $start), true); - $callable = $this->getCallable(); - - if ($otag !== '{{' || $ctag !== '}}') { - $delims = ', '.var_export(sprintf('{{= %s %s =}}', $otag, $ctag), true); - } else { - $delims = ''; - } - - $key = ucfirst(md5($delims."\n".$source)); - - if (!isset($this->sections[$key])) { - $this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $delims, $this->walk($nodes, 2)); - } - - return sprintf($this->prepare(self::SECTION_CALL, $level), $id, $key, $method, $id); - } - - const INVERTED_SECTION = ' - // %s inverted section - $value = $context->%s(%s); - if (empty($value)) { - %s - }'; - - /** - * Generate Mustache Template inverted section PHP source. - * - * @param array $nodes Array of child tokens - * @param string $id Section name - * @param int $level - * - * @return string Generated inverted section PHP source code - */ - private function invertedSection($nodes, $id, $level) - { - $method = $this->getFindMethod($id); - $id = var_export($id, true); - - return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $this->walk($nodes, $level)); - } - - const PARTIAL = ' - if ($partial = $this->mustache->loadPartial(%s)) { - $buffer .= $partial->renderInternal($context, %s); - } - '; - - /** - * Generate Mustache Template partial call PHP source. - * - * @param string $id Partial name - * @param string $indent Whitespace indent to apply to partial - * @param int $level - * - * @return string Generated partial call PHP source code - */ - private function partial($id, $indent, $level) - { - return sprintf( - $this->prepare(self::PARTIAL, $level), - var_export($id, true), - var_export($indent, true) - ); - } - - const VARIABLE = ' - $value = $this->resolveValue($context->%s(%s), $context, $indent);%s - $buffer .= %s%s; - '; - - /** - * Generate Mustache Template variable interpolation PHP source. - * - * @param string $id Variable name - * @param boolean $escape Escape the variable value for output? - * @param int $level - * - * @return string Generated variable interpolation PHP source - */ - private function variable($id, $escape, $level) - { - $filters = ''; - - if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) { - list($id, $filters) = $this->getFilters($id, $level); - } - - $method = $this->getFindMethod($id); - $id = ($method !== 'last') ? var_export($id, true) : ''; - $value = $escape ? $this->getEscape() : '$value'; - - return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $filters, $this->flushIndent(), $value); - } - - /** - * Generate Mustache Template variable filtering PHP source. - * - * @param string $id Variable name - * @param int $level - * - * @return string Generated variable filtering PHP source - */ - private function getFilters($id, $level) - { - $filters = array_map('trim', explode('|', $id)); - $id = array_shift($filters); - - return array($id, $this->getFilter($filters, $level)); - } - - const FILTER = ' - $filter = $context->%s(%s); - if (!(%s)) { - throw new Mustache_Exception_UnknownFilterException(%s); - } - $value = call_user_func($filter, $value);%s - '; - - /** - * Generate PHP source for a single filter. - * - * @param array $filters - * @param int $level - * - * @return string Generated filter PHP source - */ - private function getFilter(array $filters, $level) - { - if (empty($filters)) { - return ''; - } - - $name = array_shift($filters); - $method = $this->getFindMethod($name); - $filter = ($method !== 'last') ? var_export($name, true) : ''; - $callable = $this->getCallable('$filter'); - $msg = var_export($name, true); - - return sprintf($this->prepare(self::FILTER, $level), $method, $filter, $callable, $msg, $this->getFilter($filters, $level)); - } - - const LINE = '$buffer .= "\n";'; - const TEXT = '$buffer .= %s%s;'; - - /** - * Generate Mustache Template output Buffer call PHP source. - * - * @param string $text - * @param int $level - * - * @return string Generated output Buffer call PHP source - */ - private function text($text, $level) - { - if ($text === "\n") { - $this->indentNextLine = true; - - return $this->prepare(self::LINE, $level); - } else { - return sprintf($this->prepare(self::TEXT, $level), $this->flushIndent(), var_export($text, true)); - } - } - - /** - * Prepare PHP source code snippet for output. - * - * @param string $text - * @param int $bonus Additional indent level (default: 0) - * @param boolean $prependNewline Prepend a newline to the snippet? (default: true) - * @param boolean $appendNewline Append a newline to the snippet? (default: false) - * - * @return string PHP source code snippet - */ - private function prepare($text, $bonus = 0, $prependNewline = true, $appendNewline = false) - { - $text = ($prependNewline ? "\n" : '').trim($text); - if ($prependNewline) { - $bonus++; - } - if ($appendNewline) { - $text .= "\n"; - } - - return preg_replace("/\n( {8})?/", "\n".str_repeat(" ", $bonus * 4), $text); - } - - const DEFAULT_ESCAPE = 'htmlspecialchars(%s, ENT_COMPAT, %s)'; - const CUSTOM_ESCAPE = 'call_user_func($this->mustache->getEscape(), %s)'; - - /** - * Get the current escaper. - * - * @param string $value (default: '$value') - * - * @return string Either a custom callback, or an inline call to `htmlspecialchars` - */ - private function getEscape($value = '$value') - { - if ($this->customEscape) { - return sprintf(self::CUSTOM_ESCAPE, $value); - } else { - return sprintf(self::DEFAULT_ESCAPE, $value, var_export($this->charset, true)); - } - } - - /** - * Select the appropriate Context `find` method for a given $id. - * - * The return value will be one of `find`, `findDot` or `last`. - * - * @see Mustache_Context::find - * @see Mustache_Context::findDot - * @see Mustache_Context::last - * - * @param string $id Variable name - * - * @return string `find` method name - */ - private function getFindMethod($id) - { - if ($id === '.') { - return 'last'; - } elseif (strpos($id, '.') === false) { - return 'find'; - } else { - return 'findDot'; - } - } - - const IS_CALLABLE = '!is_string(%s) && is_callable(%s)'; - const STRICT_IS_CALLABLE = 'is_object(%s) && is_callable(%s)'; - - private function getCallable($variable = '$value') - { - $tpl = $this->strictCallables ? self::STRICT_IS_CALLABLE : self::IS_CALLABLE; - - return sprintf($tpl, $variable, $variable); - } - - const LINE_INDENT = '$indent . '; - - /** - * Get the current $indent prefix to write to the buffer. - * - * @return string "$indent . " or "" - */ - private function flushIndent() - { - if ($this->indentNextLine) { - $this->indentNextLine = false; - - return self::LINE_INDENT; - } else { - return ''; - } - } -} diff --git a/core/lib/Mustache/Context.php b/core/lib/Mustache/Context.php deleted file mode 100644 index e7783b43c..000000000 --- a/core/lib/Mustache/Context.php +++ /dev/null @@ -1,149 +0,0 @@ -stack = array($context); - } - } - - /** - * Push a new Context frame onto the stack. - * - * @param mixed $value Object or array to use for context - */ - public function push($value) - { - array_push($this->stack, $value); - } - - /** - * Pop the last Context frame from the stack. - * - * @return mixed Last Context frame (object or array) - */ - public function pop() - { - return array_pop($this->stack); - } - - /** - * Get the last Context frame. - * - * @return mixed Last Context frame (object or array) - */ - public function last() - { - return end($this->stack); - } - - /** - * Find a variable in the Context stack. - * - * Starting with the last Context frame (the context of the innermost section), and working back to the top-level - * rendering context, look for a variable with the given name: - * - * * If the Context frame is an associative array which contains the key $id, returns the value of that element. - * * If the Context frame is an object, this will check first for a public method, then a public property named - * $id. Failing both of these, it will try `__isset` and `__get` magic methods. - * * If a value named $id is not found in any Context frame, returns an empty string. - * - * @param string $id Variable name - * - * @return mixed Variable value, or '' if not found - */ - public function find($id) - { - return $this->findVariableInStack($id, $this->stack); - } - - /** - * Find a 'dot notation' variable in the Context stack. - * - * Note that dot notation traversal bubbles through scope differently than the regular find method. After finding - * the initial chunk of the dotted name, each subsequent chunk is searched for only within the value of the previous - * result. For example, given the following context stack: - * - * $data = array( - * 'name' => 'Fred', - * 'child' => array( - * 'name' => 'Bob' - * ), - * ); - * - * ... and the Mustache following template: - * - * {{ child.name }} - * - * ... the `name` value is only searched for within the `child` value of the global Context, not within parent - * Context frames. - * - * @param string $id Dotted variable selector - * - * @return mixed Variable value, or '' if not found - */ - public function findDot($id) - { - $chunks = explode('.', $id); - $first = array_shift($chunks); - $value = $this->findVariableInStack($first, $this->stack); - - foreach ($chunks as $chunk) { - if ($value === '') { - return $value; - } - - $value = $this->findVariableInStack($chunk, array($value)); - } - - return $value; - } - - /** - * Helper function to find a variable in the Context stack. - * - * @see Mustache_Context::find - * - * @param string $id Variable name - * @param array $stack Context stack - * - * @return mixed Variable value, or '' if not found - */ - private function findVariableInStack($id, array $stack) - { - for ($i = count($stack) - 1; $i >= 0; $i--) { - if (is_object($stack[$i]) && !$stack[$i] instanceof Closure) { - if (method_exists($stack[$i], $id)) { - return $stack[$i]->$id(); - } elseif (isset($stack[$i]->$id)) { - return $stack[$i]->$id; - } - } elseif (is_array($stack[$i]) && array_key_exists($id, $stack[$i])) { - return $stack[$i][$id]; - } - } - - return ''; - } -} diff --git a/core/lib/Mustache/Engine.php b/core/lib/Mustache/Engine.php deleted file mode 100644 index 5f92d1948..000000000 --- a/core/lib/Mustache/Engine.php +++ /dev/null @@ -1,729 +0,0 @@ - '__MyTemplates_', - * - * // A cache directory for compiled templates. Mustache will not cache templates unless this is set - * 'cache' => dirname(__FILE__).'/tmp/cache/mustache', - * - * // Override default permissions for cache files. Defaults to using the system-defined umask. It is - * // *strongly* recommended that you configure your umask properly rather than overriding permissions here. - * 'cache_file_mode' => 0666, - * - * // A Mustache template loader instance. Uses a StringLoader if not specified. - * 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'), - * - * // A Mustache loader instance for partials. - * 'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views/partials'), - * - * // An array of Mustache partials. Useful for quick-and-dirty string template loading, but not as - * // efficient or lazy as a Filesystem (or database) loader. - * 'partials' => array('foo' => file_get_contents(dirname(__FILE__).'/views/partials/foo.mustache')), - * - * // An array of 'helpers'. Helpers can be global variables or objects, closures (e.g. for higher order - * // sections), or any other valid Mustache context value. They will be prepended to the context stack, - * // so they will be available in any template loaded by this Mustache instance. - * 'helpers' => array('i18n' => function($text) { - * // do something translatey here... - * }), - * - * // An 'escape' callback, responsible for escaping double-mustache variables. - * 'escape' => function($value) { - * return htmlspecialchars($buffer, ENT_COMPAT, 'UTF-8'); - * }, - * - * // Character set for `htmlspecialchars`. Defaults to 'UTF-8'. Use 'UTF-8'. - * 'charset' => 'ISO-8859-1', - * - * // A Mustache Logger instance. No logging will occur unless this is set. Using a PSR-3 compatible - * // logging library -- such as Monolog -- is highly recommended. A simple stream logger implementation is - * // available as well: - * 'logger' => new Mustache_Logger_StreamLogger('php://stderr'), - * - * // Only treat Closure instances and invokable classes as callable. If true, values like - * // `array('ClassName', 'methodName')` and `array($classInstance, 'methodName')`, which are traditionally - * // "callable" in PHP, are not called to resolve variables for interpolation or section contexts. This - * // helps protect against arbitrary code execution when user input is passed directly into the template. - * // This currently defaults to false, but will default to true in v3.0. - * 'strict_callables' => true, - * ); - * - * @throws Mustache_Exception_InvalidArgumentException If `escape` option is not callable. - * - * @param array $options (default: array()) - */ - public function __construct(array $options = array()) - { - if (isset($options['template_class_prefix'])) { - $this->templateClassPrefix = $options['template_class_prefix']; - } - - if (isset($options['cache'])) { - $this->cache = $options['cache']; - } - - if (isset($options['cache_file_mode'])) { - $this->cacheFileMode = $options['cache_file_mode']; - } - - if (isset($options['loader'])) { - $this->setLoader($options['loader']); - } - - if (isset($options['partials_loader'])) { - $this->setPartialsLoader($options['partials_loader']); - } - - if (isset($options['partials'])) { - $this->setPartials($options['partials']); - } - - if (isset($options['helpers'])) { - $this->setHelpers($options['helpers']); - } - - if (isset($options['escape'])) { - if (!is_callable($options['escape'])) { - throw new Mustache_Exception_InvalidArgumentException('Mustache Constructor "escape" option must be callable'); - } - - $this->escape = $options['escape']; - } - - if (isset($options['charset'])) { - $this->charset = $options['charset']; - } - - if (isset($options['logger'])) { - $this->setLogger($options['logger']); - } - - if (isset($options['strict_callables'])) { - $this->strictCallables = $options['strict_callables']; - } - } - - /** - * Shortcut 'render' invocation. - * - * Equivalent to calling `$mustache->loadTemplate($template)->render($context);` - * - * @see Mustache_Engine::loadTemplate - * @see Mustache_Template::render - * - * @param string $template - * @param mixed $context (default: array()) - * - * @return string Rendered template - */ - public function render($template, $context = array()) - { - return $this->loadTemplate($template)->render($context); - } - - /** - * Get the current Mustache escape callback. - * - * @return mixed Callable or null - */ - public function getEscape() - { - return $this->escape; - } - - /** - * Get the current Mustache character set. - * - * @return string - */ - public function getCharset() - { - return $this->charset; - } - - /** - * Set the Mustache template Loader instance. - * - * @param Mustache_Loader $loader - */ - public function setLoader(Mustache_Loader $loader) - { - $this->loader = $loader; - } - - /** - * Get the current Mustache template Loader instance. - * - * If no Loader instance has been explicitly specified, this method will instantiate and return - * a StringLoader instance. - * - * @return Mustache_Loader - */ - public function getLoader() - { - if (!isset($this->loader)) { - $this->loader = new Mustache_Loader_StringLoader; - } - - return $this->loader; - } - - /** - * Set the Mustache partials Loader instance. - * - * @param Mustache_Loader $partialsLoader - */ - public function setPartialsLoader(Mustache_Loader $partialsLoader) - { - $this->partialsLoader = $partialsLoader; - } - - /** - * Get the current Mustache partials Loader instance. - * - * If no Loader instance has been explicitly specified, this method will instantiate and return - * an ArrayLoader instance. - * - * @return Mustache_Loader - */ - public function getPartialsLoader() - { - if (!isset($this->partialsLoader)) { - $this->partialsLoader = new Mustache_Loader_ArrayLoader; - } - - return $this->partialsLoader; - } - - /** - * Set partials for the current partials Loader instance. - * - * @throws Mustache_Exception_RuntimeException If the current Loader instance is immutable - * - * @param array $partials (default: array()) - */ - public function setPartials(array $partials = array()) - { - if (!isset($this->partialsLoader)) { - $this->partialsLoader = new Mustache_Loader_ArrayLoader; - } - - if (!$this->partialsLoader instanceof Mustache_Loader_MutableLoader) { - throw new Mustache_Exception_RuntimeException('Unable to set partials on an immutable Mustache Loader instance'); - } - - $this->partialsLoader->setTemplates($partials); - } - - /** - * Set an array of Mustache helpers. - * - * An array of 'helpers'. Helpers can be global variables or objects, closures (e.g. for higher order sections), or - * any other valid Mustache context value. They will be prepended to the context stack, so they will be available in - * any template loaded by this Mustache instance. - * - * @throws Mustache_Exception_InvalidArgumentException if $helpers is not an array or Traversable - * - * @param array|Traversable $helpers - */ - public function setHelpers($helpers) - { - if (!is_array($helpers) && !$helpers instanceof Traversable) { - throw new Mustache_Exception_InvalidArgumentException('setHelpers expects an array of helpers'); - } - - $this->getHelpers()->clear(); - - foreach ($helpers as $name => $helper) { - $this->addHelper($name, $helper); - } - } - - /** - * Get the current set of Mustache helpers. - * - * @see Mustache_Engine::setHelpers - * - * @return Mustache_HelperCollection - */ - public function getHelpers() - { - if (!isset($this->helpers)) { - $this->helpers = new Mustache_HelperCollection; - } - - return $this->helpers; - } - - /** - * Add a new Mustache helper. - * - * @see Mustache_Engine::setHelpers - * - * @param string $name - * @param mixed $helper - */ - public function addHelper($name, $helper) - { - $this->getHelpers()->add($name, $helper); - } - - /** - * Get a Mustache helper by name. - * - * @see Mustache_Engine::setHelpers - * - * @param string $name - * - * @return mixed Helper - */ - public function getHelper($name) - { - return $this->getHelpers()->get($name); - } - - /** - * Check whether this Mustache instance has a helper. - * - * @see Mustache_Engine::setHelpers - * - * @param string $name - * - * @return boolean True if the helper is present - */ - public function hasHelper($name) - { - return $this->getHelpers()->has($name); - } - - /** - * Remove a helper by name. - * - * @see Mustache_Engine::setHelpers - * - * @param string $name - */ - public function removeHelper($name) - { - $this->getHelpers()->remove($name); - } - - /** - * Set the Mustache Logger instance. - * - * @throws Mustache_Exception_InvalidArgumentException If logger is not an instance of Mustache_Logger or Psr\Log\LoggerInterface. - * - * @param Mustache_Logger|Psr\Log\LoggerInterface $logger - */ - public function setLogger($logger = null) - { - if ($logger !== null && !($logger instanceof Mustache_Logger || is_a($logger, 'Psr\\Log\\LoggerInterface'))) { - throw new Mustache_Exception_InvalidArgumentException('Expected an instance of Mustache_Logger or Psr\\Log\\LoggerInterface.'); - } - - $this->logger = $logger; - } - - /** - * Get the current Mustache Logger instance. - * - * @return Mustache_Logger|Psr\Log\LoggerInterface - */ - public function getLogger() - { - return $this->logger; - } - - /** - * Set the Mustache Tokenizer instance. - * - * @param Mustache_Tokenizer $tokenizer - */ - public function setTokenizer(Mustache_Tokenizer $tokenizer) - { - $this->tokenizer = $tokenizer; - } - - /** - * Get the current Mustache Tokenizer instance. - * - * If no Tokenizer instance has been explicitly specified, this method will instantiate and return a new one. - * - * @return Mustache_Tokenizer - */ - public function getTokenizer() - { - if (!isset($this->tokenizer)) { - $this->tokenizer = new Mustache_Tokenizer; - } - - return $this->tokenizer; - } - - /** - * Set the Mustache Parser instance. - * - * @param Mustache_Parser $parser - */ - public function setParser(Mustache_Parser $parser) - { - $this->parser = $parser; - } - - /** - * Get the current Mustache Parser instance. - * - * If no Parser instance has been explicitly specified, this method will instantiate and return a new one. - * - * @return Mustache_Parser - */ - public function getParser() - { - if (!isset($this->parser)) { - $this->parser = new Mustache_Parser; - } - - return $this->parser; - } - - /** - * Set the Mustache Compiler instance. - * - * @param Mustache_Compiler $compiler - */ - public function setCompiler(Mustache_Compiler $compiler) - { - $this->compiler = $compiler; - } - - /** - * Get the current Mustache Compiler instance. - * - * If no Compiler instance has been explicitly specified, this method will instantiate and return a new one. - * - * @return Mustache_Compiler - */ - public function getCompiler() - { - if (!isset($this->compiler)) { - $this->compiler = new Mustache_Compiler; - } - - return $this->compiler; - } - - /** - * Helper method to generate a Mustache template class. - * - * @param string $source - * - * @return string Mustache Template class name - */ - public function getTemplateClassName($source) - { - return $this->templateClassPrefix . md5(sprintf( - 'version:%s,escape:%s,charset:%s,strict_callables:%s,source:%s', - self::VERSION, - isset($this->escape) ? 'custom' : 'default', - $this->charset, - $this->strictCallables ? 'true' : 'false', - $source - )); - } - - /** - * Load a Mustache Template by name. - * - * @param string $name - * - * @return Mustache_Template - */ - public function loadTemplate($name) - { - return $this->loadSource($this->getLoader()->load($name)); - } - - /** - * Load a Mustache partial Template by name. - * - * This is a helper method used internally by Template instances for loading partial templates. You can most likely - * ignore it completely. - * - * @param string $name - * - * @return Mustache_Template - */ - public function loadPartial($name) - { - try { - if (isset($this->partialsLoader)) { - $loader = $this->partialsLoader; - } elseif (isset($this->loader) && !$this->loader instanceof Mustache_Loader_StringLoader) { - $loader = $this->loader; - } else { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - return $this->loadSource($loader->load($name)); - } catch (Mustache_Exception_UnknownTemplateException $e) { - // If the named partial cannot be found, log then return null. - $this->log( - Mustache_Logger::WARNING, - 'Partial not found: "{name}"', - array('name' => $e->getTemplateName()) - ); - } - } - - /** - * Load a Mustache lambda Template by source. - * - * This is a helper method used by Template instances to generate subtemplates for Lambda sections. You can most - * likely ignore it completely. - * - * @param string $source - * @param string $delims (default: null) - * - * @return Mustache_Template - */ - public function loadLambda($source, $delims = null) - { - if ($delims !== null) { - $source = $delims . "\n" . $source; - } - - return $this->loadSource($source); - } - - /** - * Instantiate and return a Mustache Template instance by source. - * - * @see Mustache_Engine::loadTemplate - * @see Mustache_Engine::loadPartial - * @see Mustache_Engine::loadLambda - * - * @param string $source - * - * @return Mustache_Template - */ - private function loadSource($source) - { - $className = $this->getTemplateClassName($source); - - if (!isset($this->templates[$className])) { - if (!class_exists($className, false)) { - if ($fileName = $this->getCacheFilename($source)) { - if (!is_file($fileName)) { - $this->log( - Mustache_Logger::DEBUG, - 'Writing "{className}" class to template cache: "{fileName}"', - array('className' => $className, 'fileName' => $fileName) - ); - - $this->writeCacheFile($fileName, $this->compile($source)); - } - - require_once $fileName; - } else { - $this->log( - Mustache_Logger::WARNING, - 'Template cache disabled, evaluating "{className}" class at runtime', - array('className' => $className) - ); - - eval('?>'.$this->compile($source)); - } - } - - $this->log( - Mustache_Logger::DEBUG, - 'Instantiating template: "{className}"', - array('className' => $className) - ); - - $this->templates[$className] = new $className($this); - } - - return $this->templates[$className]; - } - - /** - * Helper method to tokenize a Mustache template. - * - * @see Mustache_Tokenizer::scan - * - * @param string $source - * - * @return array Tokens - */ - private function tokenize($source) - { - return $this->getTokenizer()->scan($source); - } - - /** - * Helper method to parse a Mustache template. - * - * @see Mustache_Parser::parse - * - * @param string $source - * - * @return array Token tree - */ - private function parse($source) - { - return $this->getParser()->parse($this->tokenize($source)); - } - - /** - * Helper method to compile a Mustache template. - * - * @see Mustache_Compiler::compile - * - * @param string $source - * - * @return string generated Mustache template class code - */ - private function compile($source) - { - $tree = $this->parse($source); - $name = $this->getTemplateClassName($source); - - $this->log( - Mustache_Logger::INFO, - 'Compiling template to "{className}" class', - array('className' => $name) - ); - - return $this->getCompiler()->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables); - } - - /** - * Helper method to generate a Mustache Template class cache filename. - * - * @param string $source - * - * @return string Mustache Template class cache filename - */ - private function getCacheFilename($source) - { - if ($this->cache) { - return sprintf('%s/%s.php', $this->cache, $this->getTemplateClassName($source)); - } - } - - /** - * Helper method to dump a generated Mustache Template subclass to the file cache. - * - * @throws Mustache_Exception_RuntimeException if unable to create the cache directory or write to $fileName. - * - * @param string $fileName - * @param string $source - * - * @codeCoverageIgnore - */ - private function writeCacheFile($fileName, $source) - { - $dirName = dirname($fileName); - if (!is_dir($dirName)) { - $this->log( - Mustache_Logger::INFO, - 'Creating Mustache template cache directory: "{dirName}"', - array('dirName' => $dirName) - ); - - @mkdir($dirName, 0777, true); - if (!is_dir($dirName)) { - throw new Mustache_Exception_RuntimeException(sprintf('Failed to create cache directory "%s".', $dirName)); - } - - } - - $this->log( - Mustache_Logger::DEBUG, - 'Caching compiled template to "{fileName}"', - array('fileName' => $fileName) - ); - - $tempFile = tempnam($dirName, basename($fileName)); - if (false !== @file_put_contents($tempFile, $source)) { - if (@rename($tempFile, $fileName)) { - $mode = isset($this->cacheFileMode) ? $this->cacheFileMode : (0666 & ~umask()); - @chmod($fileName, $mode); - - return; - } - - $this->log( - Mustache_Logger::ERROR, - 'Unable to rename Mustache temp cache file: "{tempName}" -> "{fileName}"', - array('tempName' => $tempFile, 'fileName' => $fileName) - ); - } - - throw new Mustache_Exception_RuntimeException(sprintf('Failed to write cache file "%s".', $fileName)); - } - - /** - * Add a log record if logging is enabled. - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - */ - private function log($level, $message, array $context = array()) - { - if (isset($this->logger)) { - $this->logger->log($level, $message, $context); - } - } -} diff --git a/core/lib/Mustache/Exception.php b/core/lib/Mustache/Exception.php deleted file mode 100644 index b4f830046..000000000 --- a/core/lib/Mustache/Exception.php +++ /dev/null @@ -1,18 +0,0 @@ -token = $token; - parent::__construct($msg); - } - - public function getToken() - { - return $this->token; - } -} diff --git a/core/lib/Mustache/Exception/UnknownFilterException.php b/core/lib/Mustache/Exception/UnknownFilterException.php deleted file mode 100644 index f5c0884d4..000000000 --- a/core/lib/Mustache/Exception/UnknownFilterException.php +++ /dev/null @@ -1,29 +0,0 @@ -filterName = $filterName; - parent::__construct(sprintf('Unknown filter: %s', $filterName)); - } - - public function getFilterName() - { - return $this->filterName; - } -} diff --git a/core/lib/Mustache/Exception/UnknownHelperException.php b/core/lib/Mustache/Exception/UnknownHelperException.php deleted file mode 100644 index 98af13ebe..000000000 --- a/core/lib/Mustache/Exception/UnknownHelperException.php +++ /dev/null @@ -1,29 +0,0 @@ -helperName = $helperName; - parent::__construct(sprintf('Unknown helper: %s', $helperName)); - } - - public function getHelperName() - { - return $this->helperName; - } -} diff --git a/core/lib/Mustache/Exception/UnknownTemplateException.php b/core/lib/Mustache/Exception/UnknownTemplateException.php deleted file mode 100644 index 141d372bd..000000000 --- a/core/lib/Mustache/Exception/UnknownTemplateException.php +++ /dev/null @@ -1,29 +0,0 @@ -templateName = $templateName; - parent::__construct(sprintf('Unknown template: %s', $templateName)); - } - - public function getTemplateName() - { - return $this->templateName; - } -} diff --git a/core/lib/Mustache/HelperCollection.php b/core/lib/Mustache/HelperCollection.php deleted file mode 100644 index e9911378a..000000000 --- a/core/lib/Mustache/HelperCollection.php +++ /dev/null @@ -1,170 +0,0 @@ - $helper` pairs. - * - * @throws Mustache_Exception_InvalidArgumentException if the $helpers argument isn't an array or Traversable - * - * @param array|Traversable $helpers (default: null) - */ - public function __construct($helpers = null) - { - if ($helpers !== null) { - if (!is_array($helpers) && !$helpers instanceof Traversable) { - throw new Mustache_Exception_InvalidArgumentException('HelperCollection constructor expects an array of helpers'); - } - - foreach ($helpers as $name => $helper) { - $this->add($name, $helper); - } - } - } - - /** - * Magic mutator. - * - * @see Mustache_HelperCollection::add - * - * @param string $name - * @param mixed $helper - */ - public function __set($name, $helper) - { - $this->add($name, $helper); - } - - /** - * Add a helper to this collection. - * - * @param string $name - * @param mixed $helper - */ - public function add($name, $helper) - { - $this->helpers[$name] = $helper; - } - - /** - * Magic accessor. - * - * @see Mustache_HelperCollection::get - * - * @param string $name - * - * @return mixed Helper - */ - public function __get($name) - { - return $this->get($name); - } - - /** - * Get a helper by name. - * - * @throws Mustache_Exception_UnknownHelperException If helper does not exist. - * - * @param string $name - * - * @return mixed Helper - */ - public function get($name) - { - if (!$this->has($name)) { - throw new Mustache_Exception_UnknownHelperException($name); - } - - return $this->helpers[$name]; - } - - /** - * Magic isset(). - * - * @see Mustache_HelperCollection::has - * - * @param string $name - * - * @return boolean True if helper is present - */ - public function __isset($name) - { - return $this->has($name); - } - - /** - * Check whether a given helper is present in the collection. - * - * @param string $name - * - * @return boolean True if helper is present - */ - public function has($name) - { - return array_key_exists($name, $this->helpers); - } - - /** - * Magic unset(). - * - * @see Mustache_HelperCollection::remove - * - * @param string $name - */ - public function __unset($name) - { - $this->remove($name); - } - - /** - * Check whether a given helper is present in the collection. - * - * @throws Mustache_Exception_UnknownHelperException if the requested helper is not present. - * - * @param string $name - */ - public function remove($name) - { - if (!$this->has($name)) { - throw new Mustache_Exception_UnknownHelperException($name); - } - - unset($this->helpers[$name]); - } - - /** - * Clear the helper collection. - * - * Removes all helpers from this collection - */ - public function clear() - { - $this->helpers = array(); - } - - /** - * Check whether the helper collection is empty. - * - * @return boolean True if the collection is empty - */ - public function isEmpty() - { - return empty($this->helpers); - } -} diff --git a/core/lib/Mustache/LICENSE b/core/lib/Mustache/LICENSE deleted file mode 100644 index 6db530008..000000000 --- a/core/lib/Mustache/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) -Copyright (c) 2010 Justin Hileman - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE -OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/core/lib/Mustache/LambdaHelper.php b/core/lib/Mustache/LambdaHelper.php deleted file mode 100644 index dfd4659c4..000000000 --- a/core/lib/Mustache/LambdaHelper.php +++ /dev/null @@ -1,49 +0,0 @@ -mustache = $mustache; - $this->context = $context; - } - - /** - * Render a string as a Mustache template with the current rendering context. - * - * @param string $string - * - * @return Rendered template. - */ - public function render($string) - { - return $this->mustache - ->loadLambda((string) $string) - ->renderInternal($this->context); - } -} diff --git a/core/lib/Mustache/Loader.php b/core/lib/Mustache/Loader.php deleted file mode 100644 index f659a1d3a..000000000 --- a/core/lib/Mustache/Loader.php +++ /dev/null @@ -1,28 +0,0 @@ - '{{ bar }}', - * 'baz' => 'Hey {{ qux }}!' - * ); - * - * $tpl = $loader->load('foo'); // '{{ bar }}' - * - * The ArrayLoader is used internally as a partials loader by Mustache_Engine instance when an array of partials - * is set. It can also be used as a quick-and-dirty Template loader. - */ -class Mustache_Loader_ArrayLoader implements Mustache_Loader, Mustache_Loader_MutableLoader -{ - - /** - * ArrayLoader constructor. - * - * @param array $templates Associative array of Template source (default: array()) - */ - public function __construct(array $templates = array()) - { - $this->templates = $templates; - } - - /** - * Load a Template. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - if (!isset($this->templates[$name])) { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - return $this->templates[$name]; - } - - /** - * Set an associative array of Template sources for this loader. - * - * @param array $templates - */ - public function setTemplates(array $templates) - { - $this->templates = $templates; - } - - /** - * Set a Template source by name. - * - * @param string $name - * @param string $template Mustache Template source - */ - public function setTemplate($name, $template) - { - $this->templates[$name] = $template; - } -} diff --git a/core/lib/Mustache/Loader/CascadingLoader.php b/core/lib/Mustache/Loader/CascadingLoader.php deleted file mode 100644 index 192edb97f..000000000 --- a/core/lib/Mustache/Loader/CascadingLoader.php +++ /dev/null @@ -1,69 +0,0 @@ -loaders = array(); - foreach ($loaders as $loader) { - $this->addLoader($loader); - } - } - - /** - * Add a Loader instance. - * - * @param Mustache_Loader $loader A Mustache Loader instance - */ - public function addLoader(Mustache_Loader $loader) - { - $this->loaders[] = $loader; - } - - /** - * Load a Template by name. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - foreach ($this->loaders as $loader) { - try { - return $loader->load($name); - } catch (Mustache_Exception_UnknownTemplateException $e) { - // do nothing, check the next loader. - } - } - - throw new Mustache_Exception_UnknownTemplateException($name); - } -} diff --git a/core/lib/Mustache/Loader/FilesystemLoader.php b/core/lib/Mustache/Loader/FilesystemLoader.php deleted file mode 100644 index 71d7f1c8e..000000000 --- a/core/lib/Mustache/Loader/FilesystemLoader.php +++ /dev/null @@ -1,120 +0,0 @@ -load('foo'); // equivalent to `file_get_contents(dirname(__FILE__).'/views/foo.mustache'); - * - * This is probably the most useful Mustache Loader implementation. It can be used for partials and normal Templates: - * - * $m = new Mustache(array( - * 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'), - * 'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views/partials'), - * )); - */ -class Mustache_Loader_FilesystemLoader implements Mustache_Loader -{ - private $baseDir; - private $extension = '.mustache'; - private $templates = array(); - - /** - * Mustache filesystem Loader constructor. - * - * Passing an $options array allows overriding certain Loader options during instantiation: - * - * $options = array( - * // The filename extension used for Mustache templates. Defaults to '.mustache' - * 'extension' => '.ms', - * ); - * - * @throws Mustache_Exception_RuntimeException if $baseDir does not exist. - * - * @param string $baseDir Base directory containing Mustache template files. - * @param array $options Array of Loader options (default: array()) - */ - public function __construct($baseDir, array $options = array()) - { - $this->baseDir = rtrim(realpath($baseDir), '/'); - - if (!is_dir($this->baseDir)) { - throw new Mustache_Exception_RuntimeException(sprintf('FilesystemLoader baseDir must be a directory: %s', $baseDir)); - } - - if (array_key_exists('extension', $options)) { - if (empty($options['extension'])) { - $this->extension = ''; - } else { - $this->extension = '.' . ltrim($options['extension'], '.'); - } - } - } - - /** - * Load a Template by name. - * - * $loader = new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'); - * $loader->load('admin/dashboard'); // loads "./views/admin/dashboard.mustache"; - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - if (!isset($this->templates[$name])) { - $this->templates[$name] = $this->loadFile($name); - } - - return $this->templates[$name]; - } - - /** - * Helper function for loading a Mustache file by name. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - protected function loadFile($name) - { - $fileName = $this->getFileName($name); - - if (!file_exists($fileName)) { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - return file_get_contents($fileName); - } - - /** - * Helper function for getting a Mustache template file name. - * - * @param string $name - * - * @return string Template file name - */ - protected function getFileName($name) - { - $fileName = $this->baseDir . '/' . $name; - if (substr($fileName, 0 - strlen($this->extension)) !== $this->extension) { - $fileName .= $this->extension; - } - - return $fileName; - } -} diff --git a/core/lib/Mustache/Loader/InlineLoader.php b/core/lib/Mustache/Loader/InlineLoader.php deleted file mode 100644 index 1463bf8b5..000000000 --- a/core/lib/Mustache/Loader/InlineLoader.php +++ /dev/null @@ -1,121 +0,0 @@ -load('hello'); - * $goodbye = $loader->load('goodbye'); - * - * __halt_compiler(); - * - * @@ hello - * Hello, {{ planet }}! - * - * @@ goodbye - * Goodbye, cruel {{ planet }} - * - * Templates are deliniated by lines containing only `@@ name`. - * - * The InlineLoader is well-suited to micro-frameworks such as Silex: - * - * $app->register(new MustacheServiceProvider, array( - * 'mustache.loader' => new Mustache_Loader_InlineLoader(__FILE__, __COMPILER_HALT_OFFSET__) - * )); - * - * $app->get('/{name}', function() use ($app) { - * return $app['mustache']->render('hello', compact('name')); - * }) - * ->value('name', 'world'); - * - * __halt_compiler(); - * - * @@ hello - * Hello, {{ name }}! - * - */ -class Mustache_Loader_InlineLoader implements Mustache_Loader -{ - protected $fileName; - protected $offset; - protected $templates; - - /** - * The InlineLoader requires a filename and offset to process templates. - * The magic constants `__FILE__` and `__COMPILER_HALT_OFFSET__` are usually - * perfectly suited to the job: - * - * $loader = new Mustache_Loader_InlineLoader(__FILE__, __COMPILER_HALT_OFFSET__); - * - * Note that this only works if the loader is instantiated inside the same - * file as the inline templates. If the templates are located in another - * file, it would be necessary to manually specify the filename and offset. - * - * @param string $fileName The file to parse for inline templates - * @param int $offset A string offset for the start of the templates. - * This usually coincides with the `__halt_compiler` - * call, and the `__COMPILER_HALT_OFFSET__`. - */ - public function __construct($fileName, $offset) - { - if (!is_file($fileName)) { - throw new Mustache_Exception_InvalidArgumentException('InlineLoader expects a valid filename.'); - } - - if (!is_int($offset) || $offset < 0) { - throw new Mustache_Exception_InvalidArgumentException('InlineLoader expects a valid file offset.'); - } - - $this->fileName = $fileName; - $this->offset = $offset; - } - - /** - * Load a Template by name. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - $this->loadTemplates(); - - if (!array_key_exists($name, $this->templates)) { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - return $this->templates[$name]; - } - - /** - * Parse and load templates from the end of a source file. - */ - protected function loadTemplates() - { - if ($this->templates === null) { - $this->templates = array(); - $data = file_get_contents($this->fileName, false, null, $this->offset); - foreach (preg_split("/^@@(?= [\w\d\.]+$)/m", $data, -1) as $chunk) { - if (trim($chunk)) { - list($name, $content) = explode("\n", $chunk, 2); - $this->templates[trim($name)] = trim($content); - } - } - } - } -} diff --git a/core/lib/Mustache/Loader/MutableLoader.php b/core/lib/Mustache/Loader/MutableLoader.php deleted file mode 100644 index 02bb207a9..000000000 --- a/core/lib/Mustache/Loader/MutableLoader.php +++ /dev/null @@ -1,32 +0,0 @@ -load('foo'); // equivalent to `file_get_contents(dirname(__FILE__).'/views/foo.mustache'); - * - * This is probably the most useful Mustache Loader implementation. It can be used for partials and normal Templates: - * - * $m = new Mustache(array( - * 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'), - * 'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views/partials'), - * )); - */ -class Mustache_Loader_PatternLoader implements Mustache_Loader -{ - private $baseDir; - private $extension = '.mustache'; - private $templates = array(); - private $patternPaths = array(); - - /** - * Mustache filesystem Loader constructor. - * - * Passing an $options array allows overriding certain Loader options during instantiation: - * - * $options = array( - * // The filename extension used for Mustache templates. Defaults to '.mustache' - * 'extension' => '.ms', - * ); - * - * @throws Mustache_Exception_RuntimeException if $baseDir does not exist. - * - * @param string $baseDir Base directory containing Mustache template files. - * @param array $options Array of Loader options (default: array()) - */ - public function __construct($baseDir, array $options = array()) - { - $this->baseDir = rtrim(realpath($baseDir), '/'); - - if (!is_dir($this->baseDir)) { - throw new Mustache_Exception_RuntimeException(sprintf('FilesystemLoader baseDir must be a directory: %s', $baseDir)); - } - - if (array_key_exists('extension', $options)) { - if (empty($options['extension'])) { - $this->extension = ''; - } else { - $this->extension = '.' . ltrim($options['extension'], '.'); - } - } - - if (array_key_exists('patternPaths', $options)) { - $this->patternPaths = $options['patternPaths']; - } - - } - - /** - * Load a Template by name. - * - * $loader = new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'); - * $loader->load('admin/dashboard'); // loads "./views/admin/dashboard.mustache"; - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - if (!isset($this->templates[$name])) { - try { - $this->templates[$name] = $this->loadFile($name); - } catch (Exception $e) { - print "The partial, ".$name.", wasn't found so a pattern failed to build.\n"; - } - } - - return (isset($this->templates[$name])) ? $this->templates[$name] : false; - - } - - /** - * Helper function for loading a Mustache file by name. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - protected function loadFile($name) - { - - // get pattern data - list($partialName,$styleModifier,$parameters) = $this->getPartialInfo($name); - - // get the real file path for the pattern - $fileName = $this->getFileName($partialName); - //print $fileName."\n"; - // throw error if path is not found - if (!file_exists($fileName)) { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - // get the file data - $fileData = file_get_contents($fileName); - - // if the pattern name had a style modifier find & replace it - if (count($styleModifier) > 0) { - $fileData = $this->findReplaceParameters($fileData, $styleModifier); - } - - // if the pattern name had parameters find & replace them - if (count($parameters) > 0) { - $fileData = $this->findReplaceParameters($fileData, $parameters); - } - - return $fileData; - - } - - /** - * Helper function for getting a Mustache template file name. - * @param {String} the pattern type for the pattern - * @param {String} the pattern sub-type - * - * @return {Array} an array of rendered partials that match the given path - */ - protected function getFileName($name) - { - - $fileName = ""; - $dirSep = DIRECTORY_SEPARATOR; - - // test to see what kind of path was supplied - $posDash = strpos($name,"-"); - $posSlash = strpos($name,$dirSep); - if (($posSlash === false) && ($posDash !== false)) { - - list($patternType,$pattern) = $this->getPatternInfo($name); - - // see if the pattern is an exact match for patternPaths. if not iterate over patternPaths to find a likely match - if (isset($this->patternPaths[$patternType][$pattern])) { - $fileName = $this->baseDir.$dirSep.$this->patternPaths[$patternType][$pattern]["patternSrcPath"]; - } else if (isset($this->patternPaths[$patternType])) { - foreach($this->patternPaths[$patternType] as $patternMatchKey=>$patternMatchValue) { - $pos = strpos($patternMatchKey,$pattern); - if ($pos !== false) { - $fileName = $this->baseDir.$dirSep.$patternMatchValue["patternSrcPath"]; - break; - } - } - } - - } else { - $fileName = $this->baseDir.$dirSep.$name; - } - - if (substr($fileName, 0 - strlen($this->extension)) !== $this->extension) { - $fileName .= $this->extension; - } - - return $fileName; - - } - - /** - * Helper function to return the parts of a partial name - * @param {String} the name of the partial - * - * @return {Array} the pattern type and the name of the pattern - */ - private function getPatternInfo($name) - { - - $patternBits = explode("-",$name); - - $i = 1; - $k = 2; - $c = count($patternBits); - $patternType = $patternBits[0]; - while (!isset($this->patternPaths[$patternType]) && ($i < $c)) { - $patternType .= "-".$patternBits[$i]; - $i++; - $k++; - } - - $patternBits = explode("-",$name,$k); - $pattern = $patternBits[count($patternBits)-1]; - - return array($patternType, $pattern); - - } - - /** - * Helper function for finding if a partial name has style modifier or parameters - * @param {String} the pattern name - * - * @return {Array} an array containing just the partial name, a style modifier, and any parameters - */ - protected function getPartialInfo($partial) - { - - $styleModifier = array(); - $parameters = array(); - - if (strpos($partial, "(") !== false) { - $partialBits = explode("(",$partial,2); - $partial = trim($partialBits[0]); - $parametersString = substr($partialBits[1],0,(strlen($partialBits[1]) - strlen(strrchr($partialBits[1],")")))); - $parameters = $this->parseParameters($parametersString); - } - - if (strpos($partial, ":") !== false) { - $partialBits = explode(":",$partial,2); - $partial = $partialBits[0]; - $styleModifier = array("styleModifier" => $partialBits[1]); - } - - return array($partial,$styleModifier,$parameters); - - } - - /** - * Helper function to find and replace the given parameters in a particular partial before handing it back to Mustache - * @param {String} the file contents - * @param {Array} an array of paramters to match - * - * @return {String} the modified file contents - */ - private function findReplaceParameters($fileData, $parameters) - { - foreach ($parameters as $k => $v) { - if ($v == "true") { - $fileData = preg_replace('/{{\#([\s]*'.$k .'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','$2',$fileData); // {{# asdf }}STUFF{{/ asdf}} - $fileData = preg_replace('/{{\^([\s]*'.$k .'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','',$fileData); // {{^ asdf }}STUFF{{/ asdf}} - } else if ($v == "false") { - $fileData = preg_replace('/{{\^([\s]*'.$k .'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','$2',$fileData); // {{# asdf }}STUFF{{/ asdf}} - $fileData = preg_replace('/{{\#([\s]*'.$k .'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','',$fileData); // {{^ asdf }}STUFF{{/ asdf}} - } else { - $fileData = preg_replace('/{{([\s]*'.$k .'[\s]*)}}/', $v, $fileData); // {{ asdf }} - } - } - return $fileData; - } - - /** - * Helper function to parse the parameters and return them as an array - * @param {String} tbe parameter string - * - * @return {Array} the keys and values for the parameters - */ - private function parseParameters($string) - { - - $parameters = array(); - $betweenSQuotes = false; - $betweenDQuotes = false; - $inKey = true; - $inValue = false; - $char = ""; - $buffer = ""; - $keyBuffer = ""; - $strLength = strlen($string); - - for ($i = 0; $i < $strLength; $i++) { - - $previousChar = $char; - $char = $string[$i]; - - if ($inKey && !$betweenDQuotes && !$betweenSQuotes && (($char == "\"") || ($char == "'"))) { - // if inKey, a quote, and betweenQuotes is false ignore quote, set betweenQuotes to true and empty buffer to kill spaces - ($char == "\"") ? ($betweenDQuotes = true) : ($betweenSQuotes = true); - } else if ($inKey && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'"))) && ($previousChar == "\\")) { - // if inKey, a quote, betweenQuotes is true, and previous character is \ add to buffer - $buffer .= $char; - } else if ($inKey && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'")))) { - // if inKey, a quote, betweenQuotes is true set betweenQuotes to false, save as key buffer, empty buffer set inKey false - $keyBuffer = $buffer; - $buffer = ""; - $inKey = false; - $betweenSQuotes = false; - $betweenDQuotes = false; - } else if ($inKey && !$betweenDQuotes && !$betweenSQuotes && ($char == ":")) { - // if inKey, a colon, betweenQuotes is false, save as key buffer, empty buffer, set inKey false set inValue true - $keyBuffer = $buffer; - $buffer = ""; - $inKey = false; - $inValue = true; - } else if ($inKey) { - // if inKey add to buffer - $buffer .= $char; - } else if (!$inKey && !$inValue && ($char == ":")) { - // if inKey is false, inValue false, and a colon set inValue true - $inValue = true; - } else if ($inValue && !$betweenDQuotes && !$betweenSQuotes && (($char == "\"") || ($char == "'"))) { - // if inValue, a quote, and betweenQuote is false set betweenQuotes to true and empty buffer to kill spaces - ($char == "\"") ? ($betweenDQuotes = true) : ($betweenSQuotes = true); - } else if ($inValue && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'"))) && ($previousChar == "\\")) { - // if inValue, a quote, betweenQuotes is true, and previous character is \ add to buffer - $buffer .= $char; - } else if ($inValue && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'")))) { - // if inValue, a quote, betweenQuotes is true set betweenQuotes to false, save to parameters array, empty buffer, set inValue false - $buffer = str_replace("\\\"","\"",$buffer); - $buffer = str_replace('\\\'','\'',$buffer); - $parameters[trim($keyBuffer)] = trim($buffer); - $buffer = ""; - $inValue = false; - $betweenSQuotes = false; - $betweenDQuotes = false; - } else if ($inValue && !$betweenDQuotes && !$betweenSQuotes && ($char == ",")) { - // if inValue, a comman, betweenQuotes is false, save to parameters array, empty buffer, set inValue false, set inKey true - $parameters[trim($keyBuffer)] = trim($buffer); - $buffer = ""; - $inValue = false; - $inKey = true; - } else if ($inValue && (($i + 1) == $strLength)) { - // if inValue and end of the string add to buffer, save to parameters array - $buffer .= $char; - $parameters[trim($keyBuffer)] = trim($buffer); - } else if ($inValue) { - // if inValue add to buffer - $buffer .= $char; - } else if (!$inValue && !$inKey && ($char == ",")) { - // if inValue is false, inKey false, and a comma set inKey true - $inKey = true; - } - } - - return $parameters; - - } - -} diff --git a/core/lib/Mustache/Loader/StringLoader.php b/core/lib/Mustache/Loader/StringLoader.php deleted file mode 100644 index e73b3cdec..000000000 --- a/core/lib/Mustache/Loader/StringLoader.php +++ /dev/null @@ -1,40 +0,0 @@ -load('{{ foo }}'); // '{{ foo }}' - * - * This is the default Template Loader instance used by Mustache: - * - * $m = new Mustache; - * $tpl = $m->loadTemplate('{{ foo }}'); - * echo $tpl->render(array('foo' => 'bar')); // "bar" - */ -class Mustache_Loader_StringLoader implements Mustache_Loader -{ - - /** - * Load a Template by source. - * - * @param string $name Mustache Template source - * - * @return string Mustache Template source - */ - public function load($name) - { - return $name; - } -} diff --git a/core/lib/Mustache/Logger.php b/core/lib/Mustache/Logger.php deleted file mode 100644 index e08359a91..000000000 --- a/core/lib/Mustache/Logger.php +++ /dev/null @@ -1,135 +0,0 @@ -log(Mustache_Logger::EMERGENCY, $message, $context); - } - - /** - * Action must be taken immediately. - * - * Example: Entire website down, database unavailable, etc. This should - * trigger the SMS alerts and wake you up. - * - * @param string $message - * @param array $context - */ - public function alert($message, array $context = array()) - { - $this->log(Mustache_Logger::ALERT, $message, $context); - } - - /** - * Critical conditions. - * - * Example: Application component unavailable, unexpected exception. - * - * @param string $message - * @param array $context - */ - public function critical($message, array $context = array()) - { - $this->log(Mustache_Logger::CRITICAL, $message, $context); - } - - /** - * Runtime errors that do not require immediate action but should typically - * be logged and monitored. - * - * @param string $message - * @param array $context - */ - public function error($message, array $context = array()) - { - $this->log(Mustache_Logger::ERROR, $message, $context); - } - - /** - * Exceptional occurrences that are not errors. - * - * Example: Use of deprecated APIs, poor use of an API, undesirable things - * that are not necessarily wrong. - * - * @param string $message - * @param array $context - */ - public function warning($message, array $context = array()) - { - $this->log(Mustache_Logger::WARNING, $message, $context); - } - - /** - * Normal but significant events. - * - * @param string $message - * @param array $context - */ - public function notice($message, array $context = array()) - { - $this->log(Mustache_Logger::NOTICE, $message, $context); - } - - /** - * Interesting events. - * - * Example: User logs in, SQL logs. - * - * @param string $message - * @param array $context - */ - public function info($message, array $context = array()) - { - $this->log(Mustache_Logger::INFO, $message, $context); - } - - /** - * Detailed debug information. - * - * @param string $message - * @param array $context - */ - public function debug($message, array $context = array()) - { - $this->log(Mustache_Logger::DEBUG, $message, $context); - } -} diff --git a/core/lib/Mustache/Logger/StreamLogger.php b/core/lib/Mustache/Logger/StreamLogger.php deleted file mode 100644 index da771f90e..000000000 --- a/core/lib/Mustache/Logger/StreamLogger.php +++ /dev/null @@ -1,193 +0,0 @@ - 100, - self::INFO => 200, - self::NOTICE => 250, - self::WARNING => 300, - self::ERROR => 400, - self::CRITICAL => 500, - self::ALERT => 550, - self::EMERGENCY => 600, - ); - - protected $stream = null; - protected $url = null; - - /** - * @throws InvalidArgumentException if the logging level is unknown. - * - * @param string $stream Resource instance or URL - * @param integer $level The minimum logging level at which this handler will be triggered - */ - public function __construct($stream, $level = Mustache_Logger::ERROR) - { - $this->setLevel($level); - - if (is_resource($stream)) { - $this->stream = $stream; - } else { - $this->url = $stream; - } - } - - /** - * Close stream resources. - */ - public function __destruct() - { - if (is_resource($this->stream)) { - fclose($this->stream); - } - } - - /** - * Set the minimum logging level. - * - * @throws Mustache_Exception_InvalidArgumentException if the logging level is unknown. - * - * @param integer $level The minimum logging level which will be written - */ - public function setLevel($level) - { - if (!array_key_exists($level, self::$levels)) { - throw new Mustache_Exception_InvalidArgumentException(sprintf('Unexpected logging level: %s', $level)); - } - - $this->level = $level; - } - - /** - * Get the current minimum logging level. - * - * @return integer - */ - public function getLevel() - { - return $this->level; - } - - /** - * Logs with an arbitrary level. - * - * @throws Mustache_Exception_InvalidArgumentException if the logging level is unknown. - * - * @param mixed $level - * @param string $message - * @param array $context - */ - public function log($level, $message, array $context = array()) - { - if (!array_key_exists($level, self::$levels)) { - throw new Mustache_Exception_InvalidArgumentException(sprintf('Unexpected logging level: %s', $level)); - } - - if (self::$levels[$level] >= self::$levels[$this->level]) { - $this->writeLog($level, $message, $context); - } - } - - /** - * Write a record to the log. - * - * @throws Mustache_Exception_LogicException If neither a stream resource nor url is present. - * @throws Mustache_Exception_RuntimeException If the stream url cannot be opened. - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - */ - protected function writeLog($level, $message, array $context = array()) - { - if (!is_resource($this->stream)) { - if (!isset($this->url)) { - throw new Mustache_Exception_LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); - } - - $this->stream = fopen($this->url, 'a'); - if (!is_resource($this->stream)) { - // @codeCoverageIgnoreStart - throw new Mustache_Exception_RuntimeException(sprintf('The stream or file "%s" could not be opened.', $this->url)); - // @codeCoverageIgnoreEnd - } - } - - fwrite($this->stream, self::formatLine($level, $message, $context)); - } - - /** - * Gets the name of the logging level. - * - * @throws InvalidArgumentException if the logging level is unknown. - * - * @param integer $level - * - * @return string - */ - protected static function getLevelName($level) - { - return strtoupper($level); - } - - /** - * Format a log line for output. - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - * - * @return string - */ - protected static function formatLine($level, $message, array $context = array()) - { - return sprintf( - "%s: %s\n", - self::getLevelName($level), - self::interpolateMessage($message, $context) - ); - } - - /** - * Interpolate context values into the message placeholders. - * - * @param string $message - * @param array $context - * - * @return string - */ - protected static function interpolateMessage($message, array $context = array()) - { - if (strpos($message, '{') === false) { - return $message; - } - - // build a replacement array with braces around the context keys - $replace = array(); - foreach ($context as $key => $val) { - $replace['{' . $key . '}'] = $val; - } - - // interpolate replacement values into the the message and return - return strtr($message, $replace); - } -} diff --git a/core/lib/Mustache/Parser.php b/core/lib/Mustache/Parser.php deleted file mode 100644 index ab7db8463..000000000 --- a/core/lib/Mustache/Parser.php +++ /dev/null @@ -1,91 +0,0 @@ -buildTree(new ArrayIterator($tokens)); - } - - /** - * Helper method for recursively building a parse tree. - * - * @throws Mustache_Exception_SyntaxException when nesting errors or mismatched section tags are encountered. - * - * @param ArrayIterator $tokens Stream of Mustache tokens - * @param array $parent Parent token (default: null) - * - * @return array Mustache Token parse tree - */ - private function buildTree(ArrayIterator $tokens, array $parent = null) - { - $nodes = array(); - - do { - $token = $tokens->current(); - $tokens->next(); - - if ($token === null) { - continue; - } else { - switch ($token[Mustache_Tokenizer::TYPE]) { - case Mustache_Tokenizer::T_SECTION: - case Mustache_Tokenizer::T_INVERTED: - $nodes[] = $this->buildTree($tokens, $token); - break; - - case Mustache_Tokenizer::T_END_SECTION: - if (!isset($parent)) { - $msg = sprintf('Unexpected closing tag: /%s', $token[Mustache_Tokenizer::NAME]); - throw new Mustache_Exception_SyntaxException($msg, $token); - } - - if ($token[Mustache_Tokenizer::NAME] !== $parent[Mustache_Tokenizer::NAME]) { - $msg = sprintf('Nesting error: %s vs. %s', $parent[Mustache_Tokenizer::NAME], $token[Mustache_Tokenizer::NAME]); - throw new Mustache_Exception_SyntaxException($msg, $token); - } - - $parent[Mustache_Tokenizer::END] = $token[Mustache_Tokenizer::INDEX]; - $parent[Mustache_Tokenizer::NODES] = $nodes; - - return $parent; - break; - - default: - $nodes[] = $token; - break; - } - } - - } while ($tokens->valid()); - - if (isset($parent)) { - $msg = sprintf('Missing closing tag: %s', $parent[Mustache_Tokenizer::NAME]); - throw new Mustache_Exception_SyntaxException($msg, $parent); - } - - return $nodes; - } -} diff --git a/core/lib/Mustache/Template.php b/core/lib/Mustache/Template.php deleted file mode 100644 index aeee42d49..000000000 --- a/core/lib/Mustache/Template.php +++ /dev/null @@ -1,177 +0,0 @@ -mustache = $mustache; - } - - /** - * Mustache Template instances can be treated as a function and rendered by simply calling them: - * - * $m = new Mustache_Engine; - * $tpl = $m->loadTemplate('Hello, {{ name }}!'); - * echo $tpl(array('name' => 'World')); // "Hello, World!" - * - * @see Mustache_Template::render - * - * @param mixed $context Array or object rendering context (default: array()) - * - * @return string Rendered template - */ - public function __invoke($context = array()) - { - return $this->render($context); - } - - /** - * Render this template given the rendering context. - * - * @param mixed $context Array or object rendering context (default: array()) - * - * @return string Rendered template - */ - public function render($context = array()) - { - return $this->renderInternal($this->prepareContextStack($context)); - } - - /** - * Internal rendering method implemented by Mustache Template concrete subclasses. - * - * This is where the magic happens :) - * - * NOTE: This method is not part of the Mustache.php public API. - * - * @param Mustache_Context $context - * @param string $indent (default: '') - * - * @return string Rendered template - */ - abstract public function renderInternal(Mustache_Context $context, $indent = ''); - - /** - * Tests whether a value should be iterated over (e.g. in a section context). - * - * In most languages there are two distinct array types: list and hash (or whatever you want to call them). Lists - * should be iterated, hashes should be treated as objects. Mustache follows this paradigm for Ruby, Javascript, - * Java, Python, etc. - * - * PHP, however, treats lists and hashes as one primitive type: array. So Mustache.php needs a way to distinguish - * between between a list of things (numeric, normalized array) and a set of variables to be used as section context - * (associative array). In other words, this will be iterated over: - * - * $items = array( - * array('name' => 'foo'), - * array('name' => 'bar'), - * array('name' => 'baz'), - * ); - * - * ... but this will be used as a section context block: - * - * $items = array( - * 1 => array('name' => 'foo'), - * 'banana' => array('name' => 'bar'), - * 42 => array('name' => 'baz'), - * ); - * - * @param mixed $value - * - * @return boolean True if the value is 'iterable' - */ - protected function isIterable($value) - { - if (is_object($value)) { - return $value instanceof Traversable; - } elseif (is_array($value)) { - $i = 0; - foreach ($value as $k => $v) { - if ($k !== $i++) { - return false; - } - } - - return true; - } else { - return false; - } - } - - /** - * Helper method to prepare the Context stack. - * - * Adds the Mustache HelperCollection to the stack's top context frame if helpers are present. - * - * @param mixed $context Optional first context frame (default: null) - * - * @return Mustache_Context - */ - protected function prepareContextStack($context = null) - { - $stack = new Mustache_Context; - - $helpers = $this->mustache->getHelpers(); - if (!$helpers->isEmpty()) { - $stack->push($helpers); - } - - if (!empty($context)) { - $stack->push($context); - } - - return $stack; - } - - /** - * Resolve a context value. - * - * Invoke the value if it is callable, otherwise return the value. - * - * @param mixed $value - * @param Mustache_Context $context - * @param string $indent - * - * @return string - */ - protected function resolveValue($value, Mustache_Context $context, $indent = '') - { - if (($this->strictCallables ? is_object($value) : !is_string($value)) && is_callable($value)) { - return $this->mustache - ->loadLambda((string) call_user_func($value)) - ->renderInternal($context, $indent); - } - - return $value; - } -} diff --git a/core/lib/Mustache/Tokenizer.php b/core/lib/Mustache/Tokenizer.php deleted file mode 100644 index 56e8ba6b7..000000000 --- a/core/lib/Mustache/Tokenizer.php +++ /dev/null @@ -1,315 +0,0 @@ -'; - const T_PARTIAL_2 = '<'; - const T_DELIM_CHANGE = '='; - const T_ESCAPED = '_v'; - const T_UNESCAPED = '{'; - const T_UNESCAPED_2 = '&'; - const T_TEXT = '_t'; - const T_PRAGMA = '%'; - - // Valid token types - private static $tagTypes = array( - self::T_SECTION => true, - self::T_INVERTED => true, - self::T_END_SECTION => true, - self::T_COMMENT => true, - self::T_PARTIAL => true, - self::T_PARTIAL_2 => true, - self::T_DELIM_CHANGE => true, - self::T_ESCAPED => true, - self::T_UNESCAPED => true, - self::T_UNESCAPED_2 => true, - self::T_PRAGMA => true, - ); - - // Interpolated tags - private static $interpolatedTags = array( - self::T_ESCAPED => true, - self::T_UNESCAPED => true, - self::T_UNESCAPED_2 => true, - ); - - // Token properties - const TYPE = 'type'; - const NAME = 'name'; - const OTAG = 'otag'; - const CTAG = 'ctag'; - const INDEX = 'index'; - const END = 'end'; - const INDENT = 'indent'; - const NODES = 'nodes'; - const VALUE = 'value'; - - private $pragmas; - private $state; - private $tagType; - private $tag; - private $buffer; - private $tokens; - private $seenTag; - private $lineStart; - private $otag; - private $ctag; - - /** - * Scan and tokenize template source. - * - * @param string $text Mustache template source to tokenize - * @param string $delimiters Optionally, pass initial opening and closing delimiters (default: null) - * - * @return array Set of Mustache tokens - */ - public function scan($text, $delimiters = null) - { - $this->reset(); - - if ($delimiters = trim($delimiters)) { - list($otag, $ctag) = explode(' ', $delimiters); - $this->otag = $otag; - $this->ctag = $ctag; - } - - $len = strlen($text); - for ($i = 0; $i < $len; $i++) { - switch ($this->state) { - case self::IN_TEXT: - if ($this->tagChange($this->otag, $text, $i)) { - $i--; - $this->flushBuffer(); - $this->state = self::IN_TAG_TYPE; - } else { - $char = substr($text, $i, 1); - if ($char == "\n") { - $this->filterLine(); - } else { - $this->buffer .= $char; - } - } - break; - - case self::IN_TAG_TYPE: - - $i += strlen($this->otag) - 1; - $char = substr($text, $i + 1, 1); - if (isset(self::$tagTypes[$char])) { - $tag = $char; - $this->tagType = $tag; - } else { - $tag = null; - $this->tagType = self::T_ESCAPED; - } - - if ($this->tagType === self::T_DELIM_CHANGE) { - $i = $this->changeDelimiters($text, $i); - $this->state = self::IN_TEXT; - } elseif ($this->tagType === self::T_PRAGMA) { - $i = $this->addPragma($text, $i); - $this->state = self::IN_TEXT; - } else { - if ($tag !== null) { - $i++; - } - $this->state = self::IN_TAG; - } - $this->seenTag = $i; - break; - - default: - if ($this->tagChange($this->ctag, $text, $i)) { - $this->tokens[] = array( - self::TYPE => $this->tagType, - self::NAME => trim($this->buffer), - self::OTAG => $this->otag, - self::CTAG => $this->ctag, - self::INDEX => ($this->tagType == self::T_END_SECTION) ? $this->seenTag - strlen($this->otag) : $i + strlen($this->ctag) - ); - - $this->buffer = ''; - $i += strlen($this->ctag) - 1; - $this->state = self::IN_TEXT; - if ($this->tagType == self::T_UNESCAPED) { - if ($this->ctag == '}}') { - $i++; - } else { - // Clean up `{{{ tripleStache }}}` style tokens. - $lastName = $this->tokens[count($this->tokens) - 1][self::NAME]; - if (substr($lastName, -1) === '}') { - $this->tokens[count($this->tokens) - 1][self::NAME] = trim(substr($lastName, 0, -1)); - } - } - } - } else { - $this->buffer .= substr($text, $i, 1); - } - break; - } - } - - $this->filterLine(true); - - foreach ($this->pragmas as $pragma) { - array_unshift($this->tokens, array( - self::TYPE => self::T_PRAGMA, - self::NAME => $pragma, - )); - } - - return $this->tokens; - } - - /** - * Helper function to reset tokenizer internal state. - */ - private function reset() - { - $this->state = self::IN_TEXT; - $this->tagType = null; - $this->tag = null; - $this->buffer = ''; - $this->tokens = array(); - $this->seenTag = false; - $this->lineStart = 0; - $this->otag = '{{'; - $this->ctag = '}}'; - $this->pragmas = array(); - } - - /** - * Flush the current buffer to a token. - */ - private function flushBuffer() - { - if (!empty($this->buffer)) { - $this->tokens[] = array(self::TYPE => self::T_TEXT, self::VALUE => $this->buffer); - $this->buffer = ''; - } - } - - /** - * Test whether the current line is entirely made up of whitespace. - * - * @return boolean True if the current line is all whitespace - */ - private function lineIsWhitespace() - { - $tokensCount = count($this->tokens); - for ($j = $this->lineStart; $j < $tokensCount; $j++) { - $token = $this->tokens[$j]; - if (isset(self::$tagTypes[$token[self::TYPE]])) { - if (isset(self::$interpolatedTags[$token[self::TYPE]])) { - return false; - } - } elseif ($token[self::TYPE] == self::T_TEXT) { - if (preg_match('/\S/', $token[self::VALUE])) { - return false; - } - } - } - - return true; - } - - /** - * Filter out whitespace-only lines and store indent levels for partials. - * - * @param bool $noNewLine Suppress the newline? (default: false) - */ - private function filterLine($noNewLine = false) - { - $this->flushBuffer(); - if ($this->seenTag && $this->lineIsWhitespace()) { - $tokensCount = count($this->tokens); - for ($j = $this->lineStart; $j < $tokensCount; $j++) { - if ($this->tokens[$j][self::TYPE] == self::T_TEXT) { - if (isset($this->tokens[$j+1]) && $this->tokens[$j+1][self::TYPE] == self::T_PARTIAL) { - $this->tokens[$j+1][self::INDENT] = $this->tokens[$j][self::VALUE]; - } - - $this->tokens[$j] = null; - } - } - } elseif (!$noNewLine) { - $this->tokens[] = array(self::TYPE => self::T_TEXT, self::VALUE => "\n"); - } - - $this->seenTag = false; - $this->lineStart = count($this->tokens); - } - - /** - * Change the current Mustache delimiters. Set new `otag` and `ctag` values. - * - * @param string $text Mustache template source - * @param int $index Current tokenizer index - * - * @return int New index value - */ - private function changeDelimiters($text, $index) - { - $startIndex = strpos($text, '=', $index) + 1; - $close = '='.$this->ctag; - $closeIndex = strpos($text, $close, $index); - - list($otag, $ctag) = explode(' ', trim(substr($text, $startIndex, $closeIndex - $startIndex))); - $this->otag = $otag; - $this->ctag = $ctag; - - return $closeIndex + strlen($close) - 1; - } - - private function addPragma($text, $index) - { - $end = strpos($text, $this->ctag, $index); - $this->pragmas[] = trim(substr($text, $index + 2, $end - $index - 2)); - - return $end + strlen($this->ctag) - 1; - } - - /** - * Test whether it's time to change tags. - * - * @param string $tag Current tag name - * @param string $text Mustache template source - * @param int $index Current tokenizer index - * - * @return boolean True if this is a closing section tag - */ - private function tagChange($tag, $text, $index) - { - return substr($text, $index, strlen($tag)) === $tag; - } - - public function returnTokens() - { - return $this->tokens; - } -} diff --git a/core/lib/PatternLab/Builder.php b/core/lib/PatternLab/Builder.php deleted file mode 100644 index f9391cb16..000000000 --- a/core/lib/PatternLab/Builder.php +++ /dev/null @@ -1,1362 +0,0 @@ - $value) { - - // if the variables are array-like make sure the properties are validated/trimmed/lowercased before saving - $arrayKeys = array("ie","id","patternStates","styleGuideExcludes"); - if (in_array($key,$arrayKeys)) { - $values = explode(",",$value); - array_walk($values,'PatternLab\Builder::trim'); - $this->$key = $values; - } else if ($key == "ishControlsHide") { - $this->$key = new \stdClass(); - if ($value != "") { - $values = explode(",",$value); - foreach($values as $value2) { - $value2 = trim($value2); - $this->$key->$value2 = true; - } - } - if ($this->pageFollowNav == "false") { - $value = "tools-follow"; - $this->$key->$value = true; - } - if ($this->autoReloadNav == "false") { - $value = "tools-reload"; - $this->$key->$value = true; - } - } else { - $this->$key = $value; - } - - } - - // set-up the source & public dirs - $this->sp = "/../../../source/_patterns".DIRECTORY_SEPARATOR; - $this->pp = "/../../../public/patterns".DIRECTORY_SEPARATOR; - $this->sd = __DIR__."/../../../source"; - $this->pd = __DIR__."/../../../public"; - - // provide the default for enable CSS. performance hog so it should be run infrequently - $this->enableCSS = false; - $this->patternCSS = array(); - - } - - /** - * Load a new Mustache instance that uses the Pattern Loader - * - * @return {Object} an instance of the Mustache engine - */ - protected function loadMustachePatternLoaderInstance() { - $this->mpl = new Engine(array( - "loader" => new PatternLoader(__DIR__.$this->sp,array("patternPaths" => $this->patternPaths)), - "partials_loader" => new PatternLoader(__DIR__.$this->sp,array("patternPaths" => $this->patternPaths)) - )); - } - - /** - * Load a new Mustache instance that uses the File System Loader - * - * @return {Object} an instance of the Mustache engine - */ - protected function loadMustacheFileSystemLoaderInstance() { - $this->mfs = new Engine(array( - "loader" => new FilesystemLoader(__DIR__."/../../templates/"), - "partials_loader" => new FilesystemLoader(__DIR__."/../../templates/partials/") - )); - } - - /** - * Load a new Mustache instance that uses the File System Loader - * - * @return {Object} an instance of the Mustache engine - */ - protected function loadMustacheVanillaInstance() { - $this->mv = new Engine; - } - - /** - * Renders a given pattern file using Mustache and incorporating the provided data - * @param {String} the filename of the file to be rendered - * @param {String} the pattern partial - * - * @return {String} the mark-up as rendered by Mustache - */ - protected function renderPattern($f,$p) { - - // if there is pattern-specific data make sure to override the default in $this->d - $d = $this->d; - - if (isset($d["patternSpecific"]) && array_key_exists($p,$d["patternSpecific"])) { - - if (!empty($d["patternSpecific"][$p]["data"])) { - $d = array_replace_recursive($d, $d["patternSpecific"][$p]["data"]); - } - - if (!empty($d["patternSpecific"][$p]["listItems"])) { - - $numbers = array("one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"); - - $k = 0; - $c = count($d["patternSpecific"][$p]["listItems"]); - - while ($k < $c) { - $section = $numbers[$k]; - $d["listItems"][$section] = array_replace_recursive( $d["listItems"][$section], $d["patternSpecific"][$p]["listItems"][$section]); - $k++; - } - - } - - } - - $pattern = $this->mpl->render($f,$d); - $escaped = htmlentities($pattern); - - if ($this->addPatternHF) { - $patternHead = $this->mv->render($this->patternHead,$d); - $patternFoot = $this->mv->render($this->patternFoot,$d); - $pattern = $patternHead.$pattern.$patternFoot; - } - - return array($pattern,$escaped); - - } - - /** - * Generates the index page and style guide - */ - protected function generateMainPages() { - - // make sure $this->mfs & $this->mv are refreshed - $this->loadMustacheFileSystemLoaderInstance(); - $this->loadMustacheVanillaInstance(); - - // get the source pattern paths - $patternPathDests = array(); - foreach($this->patternPaths as $patternType => $patterns) { - $patternPathDests[$patternType] = array(); - foreach ($patterns as $pattern => $patternInfo) { - if ($patternInfo["render"]) { - $patternPathDests[$patternType][$pattern] = $patternInfo["patternDestPath"]; - } - } - } - - // render out the main pages and move them to public - $this->navItems['autoreloadnav'] = $this->autoReloadNav; - $this->navItems['autoreloadport'] = $this->autoReloadPort; - $this->navItems['pagefollownav'] = $this->pageFollowNav; - $this->navItems['pagefollowport'] = $this->pageFollowPort; - $this->navItems['patternpaths'] = json_encode($patternPathDests); - $this->navItems['viewallpaths'] = json_encode($this->viewAllPaths); - $this->navItems['mqs'] = $this->gatherMQs(); - $this->navItems['qrcodegeneratoron'] = $this->qrCodeGeneratorOn; - $this->navItems['ipaddress'] = getHostByName(getHostName()); - $this->navItems['xiphostname'] = $this->xipHostname; - $this->navItems['ishminimum'] = $this->ishMinimum; - $this->navItems['ishmaximum'] = $this->ishMaximum; - $this->navItems['ishControlsHide'] = $this->ishControlsHide; - - // grab the partials into a data object for the style guide - $sd = array("partials" => array()); - foreach ($this->patternPartials as $patternSubtypes) { - foreach ($patternSubtypes as $patterns) { - $sd["partials"][] = $patterns; - } - } - - // render the "view all" pages - $this->generateViewAllPages(); - - // add cacheBuster info - $this->navItems['cacheBuster'] = $this->cacheBuster; - $sd['cacheBuster'] = $this->cacheBuster; - - // render the index page - $r = $this->mfs->render('index',$this->navItems); - file_put_contents($this->pd."/index.html",$r); - - // render the style guide - $sd = array_replace_recursive($this->d,$sd); - $styleGuideHead = $this->mv->render($this->mainPageHead,$sd); - $styleGuideFoot = $this->mv->render($this->mainPageFoot,$sd); - $styleGuidePage = $styleGuideHead.$this->mfs->render('viewall',$sd).$styleGuideFoot; - - if (!file_exists($this->pd."/styleguide/html/styleguide.html")) { - print "ERROR: the main style guide wasn't written out. make sure public/styleguide exists. can copy core/styleguide\n"; - } else { - file_put_contents($this->pd."/styleguide/html/styleguide.html",$styleGuidePage); - } - - } - - /** - * Generates all of the patterns and puts them in the public directory - */ - protected function generatePatterns() { - - // make sure patterns exists - if (!is_dir($this->pd."/patterns")) { - mkdir($this->pd."/patterns"); - } - - // make sure the pattern header & footer are added - $this->addPatternHF = true; - - // make sure $this->mpl & $this->mv are refreshed - $this->loadMustachePatternLoaderInstance(); - $this->loadMustacheVanillaInstance(); - - // loop over the pattern paths to generate patterns for each - foreach($this->patternPaths as $patternType) { - - foreach($patternType as $pattern => $pathInfo) { - - // make sure this pattern should be rendered - if ($pathInfo["render"]) { - - // get the rendered, escaped, and mustache pattern - $this->generatePatternFile($pathInfo["patternSrcPath"].".mustache",$pathInfo["patternPartial"],$pathInfo["patternDestPath"],$pathInfo["patternState"]); - - } - - } - - } - - } - - /** - * Generates a pattern with a header & footer, the escaped version of a pattern, the msutache template, and the css if appropriate - * @param {String} the filename of the file to be rendered - * @param {String} the pattern partial - * @param {String} path where the files need to be written too - * @param {String} pattern state - */ - private function generatePatternFile($f,$p,$path,$state) { - - // render the pattern and return it as well as the encoded version - list($rf,$e) = $this->renderPattern($f,$p); - - // the core footer isn't rendered as mustache but we have some variables there any way. find & replace. - $rf = str_replace("{% patternPartial %}",$p,$rf); - $rf = str_replace("{% lineage %}",json_encode($this->patternLineages[$p]),$rf); - $rf = str_replace("{% lineageR %}",json_encode($this->patternLineagesR[$p]),$rf); - $rf = str_replace("{% patternState %}",$state,$rf); - - // figure out what to put in the css section - $c = $this->enableCSS && isset($this->patternCSS[$p]) ? "true" : "false"; - $rf = str_replace("{% cssEnabled %}",$c,$rf); - - // get the original mustache template - $m = htmlentities(file_get_contents(__DIR__.$this->sp.$f)); - - // if the pattern directory doesn't exist create it - if (!is_dir(__DIR__.$this->pp.$path)) { - mkdir(__DIR__.$this->pp.$path); - } - - // write out the various pattern files - file_put_contents(__DIR__.$this->pp.$path."/".$path.".html",$rf); - file_put_contents(__DIR__.$this->pp.$path."/".$path.".escaped.html",$e); - file_put_contents(__DIR__.$this->pp.$path."/".$path.".mustache",$m); - if ($this->enableCSS && isset($this->patternCSS[$p])) { - file_put_contents(__DIR__.$this->pp.$path."/".$path.".css",htmlentities($this->patternCSS[$p])); - } - - } - - /** - * Generates the view all pages - */ - protected function generateViewAllPages() { - - // make sure $this->mfs & $this->mv are refreshed on each generation of view all - $this->loadMustacheFileSystemLoaderInstance(); - $this->loadMustacheVanillaInstance(); - - // add view all to each list - $i = 0; $k = 0; - foreach ($this->navItems['patternTypes'] as $bucket) { - - // make sure that the navItems index exists. catches issues with pages & templates - if (isset($bucket["patternTypeItems"])) { - - foreach ($bucket["patternTypeItems"] as $navItem) { - - // make sure the navSubItems index exists. catches issues with empty folders - if (isset($navItem["patternSubtypeItems"])) { - - foreach ($navItem["patternSubtypeItems"] as $subItem) { - - if ($subItem["patternName"] == "View All") { - - // get the pattern parts - $patternType = $subItem["patternType"]; - $patternSubType = $subItem["patternSubtype"]; - - // get all the rendered partials that match - $sid = array("partials" => $this->patternPartials[$this->getPatternName($patternType,false)."-".$this->getPatternName($patternSubType,false)]); - $sid["patternPartial"] = $subItem["patternPartial"]; - $sid["cacheBuster"] = $this->cacheBuster; - $sid = array_replace_recursive($this->d,$sid); - - // render the viewall template - $viewAllHead = $this->mv->render($this->mainPageHead,$sid); - $viewAllFoot = $this->mv->render($this->mainPageFoot,$sid); - $viewAllPage = $viewAllHead.$this->mfs->render('viewall',$sid).$viewAllFoot; - - // if the pattern directory doesn't exist create it - $patternPath = $patternType."-".$patternSubType; - if (!is_dir(__DIR__.$this->pp.$patternPath)) { - mkdir(__DIR__.$this->pp.$patternPath); - file_put_contents(__DIR__.$this->pp.$patternPath."/index.html",$viewAllPage); - } else { - file_put_contents(__DIR__.$this->pp.$patternPath."/index.html",$viewAllPage); - } - - } - - } - - } - - } - - } - - $i++; - $k = 0; - - } - - } - - /** - * Gather data from source/_data/_data.json, source/_data/_listitems.json, and pattern-specific json files - * - * Reserved attributes: - * - $this->d["listItems"] : listItems from listitems.json, duplicated into separate arrays for $this->d->listItems->one, $this->d->listItems->two, $this->d->listItems->three... etc. - * - $this->d["link"] : the links to each pattern - * - $this->d["cacheBuster"] : the cache buster value to be appended to URLs - * - $this->d["patternSpecific"] : holds attributes from the pattern-specific data files - * - * @return {Array} populates $this->d - */ - protected function gatherData() { - - // set the cacheBuster - $this->cacheBuster = ($this->noCacheBuster || ($this->cacheBusterOn == "false")) ? 0 : time(); - - // gather the data from the main source data.json - if (file_exists($this->sd."/_data/_data.json")) { - $this->d = json_decode(file_get_contents($this->sd."/_data/_data.json"),true); - $this->jsonLastErrorMsg("_data/_data.json"); - } else { - print "Missing a required file, source/_data/_data.json. Aborting.\n"; - exit; - } - - $reservedKeys = array("listItems","cacheBuster","link","patternSpecific"); - foreach ($reservedKeys as $reservedKey) { - if (array_key_exists($reservedKey,$this->d)) { - print "\"".$reservedKey."\" is a reserved key in Pattern Lab. The data using that key in _data.json will be overwritten. Please choose a new key.\n"; - } - } - - - $this->d["listItems"] = $this->getListItems($this->sd."/_data/_listitems.json"); - $this->d["cacheBuster"] = $this->cacheBuster; - $this->d["link"] = array(); - $this->d["patternSpecific"] = array(); - - } - - /** - * Finds the regular and reverse lineages for the patterns - * - * @return {Array} an array of patterns with their lineages - */ - protected function gatherLineages() { - - $this->patternLineages = array(); - $this->patternLineagesR = array(); - $foundLineages = array(); - - // check for the regular lineages - foreach($this->patternPaths as $patternType => $patterns) { - - foreach ($patterns as $pattern => $patternInfo) { - - $patternLineage = array(); - $filename = $patternInfo["patternSrcPath"]; - - // if a file doesn't exist it assumes it's a pseudo-pattern and will use the last lineage found - if (file_exists(__DIR__.$this->sp.$filename.".mustache")) { - $foundLineages = array_unique($this->getLineage($filename)); - } - - if (count($foundLineages) > 0) { - foreach ($foundLineages as $lineage) { - $patternBits = $this->getPatternInfo($lineage); - if ((count($patternBits) == 2) && isset($this->patternPaths[$patternBits[0]][$patternBits[1]])) { - $path = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternDestPath"]; - $patternLineage[] = array("lineagePattern" => $lineage, - "lineagePath" => "../../patterns/".$path."/".$path.".html"); - } else { - if (strpos($lineage, '/') === false) { - print "You may have a typo in ".$patternInfo["patternSrcPath"].". {{> ".$lineage." }} is not a valid pattern.\n"; - } - } - } - } - - $this->patternLineages[$patternType."-".$pattern] = $patternLineage; - - } - - } - - // check for the reverse lineages - foreach ($this->patternLineages as $needlePartial => $needleLineages) { - - $patternLineageR = array(); - - foreach ($this->patternLineages as $haystackPartial => $haystackLineages) { - - foreach ($haystackLineages as $haystackLineage) { - - if ($haystackLineage["lineagePattern"] == $needlePartial) { - - $foundAlready = false; - foreach ($patternLineageR as $patternCheck) { - if ($patternCheck["lineagePattern"] == $haystackPartial) { - $foundAlready = true; - break; - } - } - - if (!$foundAlready) { - $patternBits = $this->getPatternInfo($haystackPartial); - if (isset($this->patternPaths[$patternBits[0]][$patternBits[1]])) { - $path = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternDestPath"]; - $patternLineageR[] = array("lineagePattern" => $haystackPartial, - "lineagePath" => "../../patterns/".$path."/".$path.".html"); - } - } - - } - - } - - } - - $this->patternLineagesR[$needlePartial] = $patternLineageR; - - } - - } - - /** - * Finds Media Queries in CSS files in the source/css/ dir - * - * @return {Array} an array of the appropriate MQs - */ - protected function gatherMQs() { - - $mqs = array(); - - foreach(glob($this->sd."/css/*.css") as $filename) { - $data = file_get_contents($filename); - preg_match_all("/(min|max)-width:([ ]+)?(([0-9]{1,5})(\.[0-9]{1,20}|)(px|em))/",$data,$matches); - foreach ($matches[3] as $match) { - if (!in_array($match,$mqs)) { - $mqs[] = $match; - } - } - } - - sort($mqs); - return $mqs; - - } - - /** - * Refactoring the pattern path stuff - */ - protected function gatherPatternInfo() { - - // make sure the pattern header & footer aren't added - $this->addPatternHF = false; - - // set-up the defaults - $patternType = ""; - $patternSubtype = ""; - $patternSubtypeSet = false; - $dirSep = DIRECTORY_SEPARATOR; - - // initialize various arrays - $this->navItems = array(); - $this->navItems["patternTypes"] = array(); - $this->patternPaths = array(); - $this->patternTypes = array(); - $this->patternLineages = array(); - $this->patternPartials = array(); - $this->viewAllPaths = array(); - - // iterate over the patterns & related data and regenerate the entire site if they've changed - $patternObjects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__.$this->sp), \RecursiveIteratorIterator::SELF_FIRST); - $patternObjects->setFlags(\FilesystemIterator::SKIP_DOTS); - - $patternObjects = iterator_to_array($patternObjects); - ksort($patternObjects); - - foreach($patternObjects as $name => $object) { - - $name = str_replace(__DIR__.$this->sp,"",$name); - $depth = substr_count($name,$dirSep); - - // track old types and subtypes for increment purposes - - if ($object->isDir() && ($depth == 0)) { - - /************************************* - * This section is for: - * The pattern type directory - *************************************/ - - // is this the first bucket to be set? - $bi = (count($this->navItems["patternTypes"]) == 0) ? 0 : $bi + 1; - - // set-up the names - $patternType = $name; // 00-atoms - $patternTypeDash = $this->getPatternName($name,false); // atoms - $patternTypeClean = str_replace("-"," ",$patternTypeDash); // atoms (dashes replaced with spaces) - - // add to pattern types & pattern paths - $this->patternTypes[] = $patternType; - $this->patternPaths[$patternTypeDash] = array(); - - // add a new patternType to the nav - $this->navItems["patternTypes"][$bi] = array("patternTypeLC" => strtolower($patternTypeClean), - "patternTypeUC" => ucwords($patternTypeClean), - "patternType" => $patternType, - "patternTypeDash" => $patternTypeDash); - - // starting a new set of pattern types. it might not have any pattern subtypes - $patternSubtypeSet = false; - - } else if ($object->isDir() && ($depth == 1)) { - - /************************************* - * This section is for: - * The pattern sub-type directory - *************************************/ - - // is this the first bucket to be set? - $ni = (!$patternSubtypeSet) ? 0 : $ni + 1; - - // set-up the names - $patternSubtype = $object->getFilename(); // 02-blocks - $patternSubtypeDash = $this->getPatternName($object->getFilename(),false); // blocks - $patternSubtypeClean = str_replace("-"," ",$patternSubtypeDash); // blocks (dashes replaced with spaces) - - // add to patternPartials - $this->patternPartials[$patternTypeDash."-".$patternSubtypeDash] = array(); - - // add a new patternSubtype to the nav - $this->navItems["patternTypes"][$bi]["patternTypeItems"][$ni] = array("patternSubtypeLC" => strtolower($patternSubtypeClean), - "patternSubtypeUC" => ucwords($patternSubtypeClean), - "patternSubtype" => $patternSubtype, - "patternSubtypeDash" => $patternSubtypeDash); - - // starting a new set of pattern types. it might not have any pattern subtypes - $patternSubtypeSet = true; - - } else if ($object->isFile() && ($object->getExtension() == "mustache")) { - - /************************************* - * This section is for: - * Mustache patterns - *************************************/ - - $patternFull = $object->getFilename(); // 00-colors.mustache - $pattern = str_replace(".mustache","",$patternFull); // 00-colors - - // check for pattern state - $patternState = ""; - if (strpos($pattern,"@") !== false) { - $patternBits = explode("@",$pattern,2); - $pattern = $patternBits[0]; - $patternState = $patternBits[1]; - } - - if ($patternSubtypeSet) { - $patternPath = $patternType.$dirSep.$patternSubtype.$dirSep.$pattern; // 00-atoms/01-global/00-colors - $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-01-global-00-colors (file path) - } else { - $patternPath = $patternType.$dirSep.$pattern; // 00-atoms/00-colors - $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-00-colors (file path) - } - - // track to see if this pattern should get rendered - $render = false; - - // make sure the pattern isn't hidden - if ($patternFull[0] != "_") { - - // set-up the names - $patternDash = $this->getPatternName($pattern,false); // colors - $patternClean = str_replace("-"," ",$patternDash); // colors (dashes replaced with spaces) - $patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors - - // set-up the info for the nav - $patternInfo = array("patternPath" => $patternPathDash."/".$patternPathDash.".html", - "patternSrcPath" => str_replace(__DIR__.$this->sp,"",$object->getPathname()), - "patternName" => ucwords($patternClean), - "patternState" => $patternState, - "patternPartial" => $patternPartial); - - // add to the nav - if ($depth == 1) { - $this->navItems["patternTypes"][$bi]["patternItems"][] = $patternInfo; - } else { - $this->navItems["patternTypes"][$bi]["patternTypeItems"][$ni]["patternSubtypeItems"][] = $patternInfo; - } - - // add to the link var for inclusion in patterns - $this->d["link"][$patternPartial] = "../../patterns/".$patternPathDash."/".$patternPathDash.".html"; - - // yup, this pattern should get rendered - $render = true; - - } else { - - // replace the underscore to generate a good file pattern name - $patternDash = $this->getPatternName(str_replace("_","",$pattern),false); // colors - $patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors - - } - - // add all patterns to patternPaths - $patternSrcPath = str_replace(__DIR__.$this->sp,"",str_replace(".mustache","",$object->getPathname())); - $patternDestPath = $patternPathDash; - $this->patternPaths[$patternTypeDash][$patternDash] = array("patternSrcPath" => $patternSrcPath, - "patternDestPath" => $patternDestPath, - "patternPartial" => $patternPartial, - "patternState" => $patternState, - "patternType" => $patternTypeDash, - "render" => $render); - - } else if ($object->isFile() && ($object->getExtension() == "json") && (strpos($object->getFilename(),"~") !== false)) { - - /************************************* - * This section is for: - * JSON pseudo-patterns - *************************************/ - - $patternSubtypeInclude = ($patternSubtypeSet) ? $patternSubtype."-" : ""; - $patternFull = $object->getFilename(); - - if ($patternFull[0] != "_") { - - // check for a pattern state - $patternState = ""; - $patternBits = explode("@",$patternFull,2); - if (isset($patternBits[1])) { - $patternState = str_replace(".json","",$patternBits[1]); - $patternFull = preg_replace("/@(.*?)\./",".",$patternFull); - } - - // set-up the names - // $patternFull is defined above 00-colors.mustache - $patternBits = explode("~",$patternFull); - $patternBase = $patternBits[0].".mustache"; // 00-homepage.mustache - $patternBaseDash = $this->getPatternName($patternBits[0],false); // homepage - $patternBaseJSON = $patternBits[0].".json"; // 00-homepage.json - $stripJSON = str_replace(".json","",$patternBits[1]); - $patternBitClean = preg_replace("/@(.*?)/","",$patternBits[0]); - $pattern = $patternBitClean."-".$stripJSON; // 00-homepage-00-emergency - $patternInt = $patternBitClean."-".$this->getPatternName($stripJSON, false); // 00-homepage-emergency - $patternDash = $this->getPatternName($patternInt,false); // homepage-emergency - $patternClean = str_replace("-"," ",$patternDash); // homepage emergency - $patternPartial = $patternTypeDash."-".$patternDash; // pages-homepage-emergency - - // add to patternPaths - if ($patternSubtypeSet) { - $patternPath = $patternType.$dirSep.$patternSubtype.$dirSep.$pattern; // 00-atoms/01-global/00-colors - $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-01-global-00-colors (file path) - } else { - $patternPath = $patternType.$dirSep.$pattern; // 00-atoms/00-colors - $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-00-colors (file path) - } - - // add all patterns to patternPaths - $patternSrcPath = $this->patternPaths[$patternTypeDash][$patternBaseDash]["patternSrcPath"]; - $patternDestPath = $patternPathDash; - $this->patternPaths[$patternTypeDash][$patternDash] = array("patternSrcPath" => $patternSrcPath, - "patternDestPath" => $patternDestPath, - "patternPartial" => $patternPartial, - "patternState" => $patternState, - "patternType" => $patternTypeDash, - "render" => true); - - // set-up the info for the nav - $patternInfo = array("patternPath" => $patternPathDash."/".$patternPathDash.".html", - "patternSrcPath" => str_replace(__DIR__.$this->sp,"",preg_replace("/\~(.*)\.json/",".mustache",$object->getPathname())), - "patternName" => ucwords($patternClean), - "patternState" => $patternState, - "patternPartial" => $patternPartial); - - // add to the nav - if ($depth == 1) { - $this->navItems["patternTypes"][$bi]["patternItems"][] = $patternInfo; - } else { - $this->navItems["patternTypes"][$bi]["patternTypeItems"][$ni]["patternSubtypeItems"][] = $patternInfo; - } - - // add to the link var for inclusion in patterns - $this->d["link"][$patternPartial] = "../../patterns/".$patternPathDash."/".$patternPathDash.".html"; - - // get the base data - $patternDataBase = array(); - if (file_exists($object->getPath()."/".$patternBaseJSON)) { - $patternDataBase = json_decode(file_get_contents($object->getPath()."/".$patternBaseJSON),true); - $this->jsonLastErrorMsg($patternBaseJSON); - } - - // get the special pattern data - $patternData = (array) json_decode(file_get_contents($object->getPathname()),true); - $this->jsonLastErrorMsg($object->getFilename()); - - // merge them for the file - if (!isset($this->d["patternSpecific"][$patternPartial])) { - $this->d["patternSpecific"][$patternPartial] = array(); - $this->d["patternSpecific"][$patternPartial]["data"] = array(); - $this->d["patternSpecific"][$patternPartial]["listItems"] = array(); - } - if (is_array($patternDataBase) && is_array($patternData)) { - $this->d["patternSpecific"][$patternPartial]["data"] = array_replace_recursive($patternDataBase, $patternData); - } - } - - } else if ($object->isFile() && ($object->getExtension() == "json")) { - - /************************************* - * This section is for: - * JSON data - *************************************/ - $patternFull = $object->getFilename(); // 00-colors.mustache - $pattern = str_replace(".listitems","",str_replace(".json","",$patternFull)); // 00-colors - $patternDash = $this->getPatternName($pattern,false); // colors - $patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors - - if ($patternFull[0] != "_") { - - if (!isset($this->d["patternSpecific"][$patternPartial])) { - $this->d["patternSpecific"][$patternPartial] = array(); - $this->d["patternSpecific"][$patternPartial]["data"] = array(); - $this->d["patternSpecific"][$patternPartial]["listItems"] = array(); - } - - if (strpos($object->getFilename(),".listitems.json") !== false) { - $patternData = $this->getListItems($object->getPathname()); - $this->d["patternSpecific"][$patternPartial]["listItems"] = $patternData; - } else { - $patternData = json_decode(file_get_contents($object->getPathname()),true); - $this->jsonLastErrorMsg($patternFull); - $this->d["patternSpecific"][$patternPartial]["data"] = $patternData; - } - - } - - } - - } - - // get all of the lineages - $this->gatherLineages(); - - // check on the states of the patterns - $patternStateLast = count($this->patternStates) - 1; - foreach($this->patternPaths as $patternType => $patterns) { - - foreach ($patterns as $pattern => $patternInfo) { - - $patternState = $this->patternPaths[$patternType][$pattern]["patternState"]; - - // make sure the pattern has a given state - if ($patternState != "") { - - $patternStateDigit = array_search($patternState, $this->patternStates); - if ($patternStateDigit !== false) { - // iterate over each of the reverse lineages for a given pattern to update their state - foreach ($this->patternLineagesR[$patternType."-".$pattern] as $patternCheckInfo) { - $patternBits = $this->getPatternInfo($patternCheckInfo["lineagePattern"]); - if (($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] == "") && ($patternStateDigit != $patternStateLast)) { - $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] = $patternState; - } else { - $patternStateCheck = array_search($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"], $this->patternStates); - if ($patternStateDigit < $patternStateCheck) { - $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] = $patternState; - } - } - } - - } - - } - - } - - } - - // make sure we update the lineages with the pattern state if appropriate - foreach($this->patternLineages as $pattern => $patternLineages) { - foreach($patternLineages as $key => $patternLineageInfo) { - $patternBits = $this->getPatternInfo($patternLineageInfo["lineagePattern"]); - $patternState = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"]; - if (($patternState != "") && ($patternState != null)) { - $this->patternLineages[$pattern][$key]["lineageState"] = $patternState; - } - } - } - - foreach($this->patternLineagesR as $pattern => $patternLineages) { - foreach($patternLineages as $key => $patternLineageInfo) { - $patternBits = $this->getPatternInfo($patternLineageInfo["lineagePattern"]); - $patternState = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"]; - if (($patternState != "") && ($patternState != null)) { - $this->patternLineagesR[$pattern][$key]["lineageState"] = $patternState; - } - } - } - - // make sure $this->mpl is refreshed - $this->loadMustachePatternLoaderInstance(); - - // run through the nav items and generate pattern partials and the view all pages - foreach ($this->navItems["patternTypes"] as $patternTypeKey => $patternTypeValues) { - - $patternType = $patternTypeValues["patternType"]; - $patternTypeDash = $patternTypeValues["patternTypeDash"]; - - // if this has a second level of patterns check them out (means we don't process pages & templates) - if (isset($patternTypeValues["patternTypeItems"]) && (!in_array($patternType,$this->styleGuideExcludes))) { - - $arrayReset = false; - - foreach ($patternTypeValues["patternTypeItems"] as $patternSubtypeKey => $patternSubtypeValues) { - - // if there are no sub-items in a section remove it, else do a bunch of other stuff - if (!isset($patternSubtypeValues["patternSubtypeItems"])) { - - unset($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]); - $arrayReset = true; - - } else { - - $patternSubtype = $patternSubtypeValues["patternSubtype"]; - $patternSubtypeDash = $patternSubtypeValues["patternSubtypeDash"]; - $subItemsCount = count($patternSubtypeValues["patternSubtypeItems"]); - - // add a view all link - $this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$subItemsCount] = array( - "patternPath" => $patternType."-".$patternSubtype."/index.html", - "patternName" => "View All", - "patternType" => $patternType, - "patternSubtype" => $patternSubtype, - "patternPartial" => "viewall-".$patternTypeDash."-".$patternSubtypeDash); - - // add to the view all paths - $this->viewAllPaths[$patternTypeDash][$patternSubtypeDash] = $patternType."-".$patternSubtype; - - // add patterns to $this->patternPartials - foreach ($patternSubtypeValues["patternSubtypeItems"] as $patternSubtypeItemKey => $patternSubtypeItem) { - - $patternCode = $this->renderPattern($patternSubtypeItem["patternSrcPath"],$patternSubtypeItem["patternPartial"]); - $patternCodeRaw = $patternCode[0]; - $patternCodeEncoded = $patternCode[1]; - $patternLineageExists = (count($this->patternLineages[$patternSubtypeItem["patternPartial"]]) > 0) ? true : false; - $patternLineages = $this->patternLineages[$patternSubtypeItem["patternPartial"]]; - - // set-up the mark-up for CSS Rule Saver so it can figure out which rules to save - $patternCSSExists = $this->enableCSS; - $patternCSS = ""; - if ($this->enableCSS) { - $this->cssRuleSaver->loadHTML($patternCodeRaw,false); - $patternCSS = $this->cssRuleSaver->saveRules(); - $this->patternCSS[$patternSubtypeItem["patternPartial"]] = $patternCSS; - } - - $this->patternPartials[$patternTypeDash."-".$patternSubtypeDash][] = array("patternName" => $patternSubtypeItem["patternName"], - "patternLink" => $patternSubtypeItem["patternPath"], - "patternPartial" => $patternSubtypeItem["patternPartial"], - "patternPartialCode" => $patternCodeRaw, - "patternPartialCodeE" => $patternCodeEncoded, - "patternCSSExists" => $patternCSSExists, - "patternCSS" => $patternCSS, - "patternLineageExists" => $patternLineageExists, - "patternLineages" => $patternLineages - ); - - // set the pattern state - $patternBits = $this->getPatternInfo($patternSubtypeItem["patternPartial"]); - if (($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] != "") && (isset($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"]))) { - $this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"] = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"]; - } - - } - - } - - } - - // reset the items to take into account removed items affecting the index - if ($arrayReset) { - $this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"] = array_values($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"]); - $arrayReset = false; - } - - } elseif (isset($patternTypeValues["patternItems"])) { - - foreach ($patternTypeValues["patternItems"] as $patternSubtypeKey => $patternSubtypeItem) { - // set the pattern state - $patternBits = $this->getPatternInfo($patternSubtypeItem["patternPartial"]); - if ($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] != "") { - $this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"]; - } - } - } - - } - - // load pattern-lab's resources - $htmlHead = file_get_contents(__DIR__."/../../templates/pattern-header-footer/header.html"); - $htmlFoot = file_get_contents(__DIR__."/../../templates/pattern-header-footer/footer.html"); - $extraFoot = file_get_contents(__DIR__."/../../templates/pattern-header-footer/footer-pattern.html"); - - // gather the user-defined header and footer information - $patternHeadPath = __DIR__.$this->sp."00-atoms/00-meta/_00-head.mustache"; - $patternFootPath = __DIR__.$this->sp."00-atoms/00-meta/_01-foot.mustache"; - $patternHead = (file_exists($patternHeadPath)) ? file_get_contents($patternHeadPath) : ""; - $patternFoot = (file_exists($patternFootPath)) ? file_get_contents($patternFootPath) : ""; - - // add pattern lab's resource to the user-defined files - $this->patternHead = str_replace("{% pattern-lab-head %}",$htmlHead,$patternHead); - $this->patternFoot = str_replace("{% pattern-lab-foot %}",$extraFoot.$htmlFoot,$patternFoot); - $this->mainPageHead = $this->patternHead; - $this->mainPageFoot = str_replace("{% pattern-lab-foot %}",$htmlFoot,$patternFoot); - - } - - /** - * Get the lineage for a given pattern by parsing it and matching mustache partials - * @param {String} the filename for the pattern to be parsed - * - * @return {Array} a list of patterns - */ - protected function getLineage($filename) { - $data = file_get_contents(__DIR__.$this->sp.$filename.".mustache"); - //$data = file_get_contents($filename); - if (preg_match_all('/{{>([ ]+)?([A-Za-z0-9-]+)(?:\:[A-Za-z0-9-]+)?(?:(| )\(.*)?([ ]+)}}/',$data,$matches)) { - return $matches[2]; - } - return array(); - } - - /** - * Get the lineage for a given pattern by parsing it and matching mustache partials - * @param {String} the filename for the pattern to be parsed - * - * @return {Array} the final set of list items - */ - protected function getListItems($filepath) { - - $listItems = array(); - - // add list item data, makes 'listItems' a reserved word - if (file_exists($filepath)) { - - $listItemsJSON = json_decode(file_get_contents($filepath), true); - $this->jsonLastErrorMsg(str_replace($this->sd."/","",$filepath)); - - $numbers = array("one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"); - - $i = 0; - $k = 1; - $c = count($listItemsJSON)+1; - - while ($k < $c) { - - shuffle($listItemsJSON); - $itemsArray = array(); - //$listItems[$numbers[$k-1]] = array(); - - while ($i < $k) { - $itemsArray[] = $listItemsJSON[$i]; - $i++; - } - - $listItems[$numbers[$k-1]] = $itemsArray; - - $i = 0; - $k++; - - } - - } - - return $listItems; - - } - - /** - * Get the directory path for a given pattern or json file by parsing the file path - * @param {String} the filepath for a directory that contained the match - * @param {String} the type of match for the pattern matching, defaults to mustache - * - * @return {String} the directory for the pattern - */ - protected function getPath($filepath,$type = "m") { - $file = ($type == 'm') ? '\.mustache' : '\.json'; - if (preg_match('/\/('.$this->patternTypesRegex.'\/(([A-z0-9-]{1,})\/|)([A-z0-9-]{1,}))'.$file.'$/',$filepath,$matches)) { - return $matches[1]; - } - } - - /** - * Helper function to return the parts of a partial name - * @param {String} the name of the partial - * - * @return {Array} the pattern type and the name of the pattern - */ - private function getPatternInfo($name) { - - $patternBits = explode("-",$name); - - $i = 1; - $k = 2; - $c = count($patternBits); - $patternType = $patternBits[0]; - while (!isset($this->patternPaths[$patternType]) && ($i < $c)) { - $patternType .= "-".$patternBits[$i]; - $i++; - $k++; - } - - $patternBits = explode("-",$name,$k); - $pattern = $patternBits[count($patternBits)-1]; - - return array($patternType, $pattern); - - } - - /** - * Get the name for a given pattern sans any possible digits used for reordering - * @param {String} the pattern based on the filesystem name - * @param {Boolean} whether or not to strip slashes from the pattern name - * - * @return {String} a lower-cased version of the pattern name - */ - protected function getPatternName($pattern, $clean = true) { - $patternBits = explode("-",$pattern,2); - $patternName = (((int)$patternBits[0] != 0) || ($patternBits[0] == '00')) ? $patternBits[1] : $pattern; - return ($clean) ? (str_replace("-"," ",$patternName)) : $patternName; - } - - protected function setPatternState($patternState, $patternPartial) { - - // set-up some defaults - $patternState = array_search($patternState, $this->patternStates); - - // iterate over each of the reverse lineages for a given pattern to update their state - foreach ($this->patternLineagesR[$patternPartial] as $patternCheckInfo) { - - // run through all of the navitems to find what pattern states match. this feels, and is, overkill - foreach ($this->navItems["patternTypes"] as $patternTypeKey => $patternTypeValues) { - - if (isset($patternTypeValues["patternTypeItems"])) { - - foreach ($patternTypeValues["patternTypeItems"] as $patternSubtypeKey => $patternSubtypeValues) { - - // add patterns to $this->patternPartials - foreach ($patternSubtypeValues["patternSubtypeItems"] as $patternSubtypeItemKey => $patternSubtypeItem) { - - if ($patternSubtypeItem["patternPartial"] == $patternPartial) { - - if ($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"] == "") { - $f = $patternState; - } else { - $patternCheckState = array_search($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"], $this->patternStates); - if ($patternState < $patternCheckState) { - $this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"] = $patternState; - } - } - - } - - } - - } - - } else { - - foreach ($patternTypeValues["patternItems"] as $patternSubtypeKey => $patternSubtypeItem) { - - if ($patternSubtypeItem["patternPartial"] == $patternPartial) { - - if ($this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] == "") { - $this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] = $patternState; - } else { - $patternCheckState = array_search($this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"], $this->patternStates); - if ($patternState < $patternCheckState) { - $this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] = $patternState; - } - } - - } - - } - - } - - } - - } - - } - - /** - * Write out the time tracking file so the content sync service will work. A holdover - * from how I put together the original AJAX polling set-up. - */ - protected function updateChangeTime() { - - if (is_dir($this->pd."/")) { - file_put_contents($this->pd."/latest-change.txt",time()); - } else { - print "Either the public directory for Pattern Lab doesn't exist or the builder is in the wrong location. Please fix."; - exit; - } - - } - - /** - * Delete patterns and user-created directories and files in public/ - */ - protected function cleanPublic() { - - // make sure patterns exists before trying to clean it - if (is_dir($this->pd."/patterns")) { - - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->pd."/patterns/"), \RecursiveIteratorIterator::CHILD_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - // for each file figure out what to do with it - foreach($objects as $name => $object) { - - if ($object->isDir()) { - // if this is a directory remove it - rmdir($name); - } else if ($object->isFile() && ($object->getFilename() != "README")) { - // if this is a file remove it - unlink($name); - } - - } - - } - - // scan source/ & public/ to figure out what directories might need to be cleaned up - $sourceDirs = glob($this->sd."/*",GLOB_ONLYDIR); - $publicDirs = glob($this->pd."/*",GLOB_ONLYDIR); - - // make sure some directories aren't deleted - $ignoreDirs = array("styleguide"); - foreach ($ignoreDirs as $ignoreDir) { - $key = array_search($this->pd."/".$ignoreDir,$publicDirs); - if ($key !== false){ - unset($publicDirs[$key]); - } - } - - // compare source dirs against public. remove those dirs w/ an underscore in source/ from the public/ list - foreach ($sourceDirs as $sourceDir) { - $cleanDir = str_replace($this->sd."/","",$sourceDir); - if ($cleanDir[0] == "_") { - $key = array_search($this->pd."/".str_replace("_","",$cleanDir),$publicDirs); - if ($key !== false){ - unset($publicDirs[$key]); - } - } - } - - // for the remaining dirs in public delete them and their files - foreach ($publicDirs as $dir) { - - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::CHILD_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - if ($object->isDir()) { - rmdir($name); - } else if ($object->isFile()) { - unlink($name); - } - - } - - rmdir($dir); - - } - - } - - /** - * Copies a file from the given source path to the given public path. - * THIS IS NOT FOR PATTERNS - * @param {String} the source file - * @param {String} the public file - */ - protected function moveFile($s,$p) { - if (file_exists($this->sd."/".$s)) { - copy($this->sd."/".$s,$this->pd."/".$p); - } - } - - /** - * Moves static files that aren't directly related to Pattern Lab - * @param {String} file name to be moved - * @param {String} copy for the message to be printed out - * @param {String} part of the file name to be found for replacement - * @param {String} the replacement - */ - protected function moveStaticFile($fileName,$copy = "", $find = "", $replace = "") { - $this->moveFile($fileName,str_replace($find, $replace, $fileName)); - $this->updateChangeTime(); - if ($copy != "") { - print $fileName." ".$copy."...\n"; - } - } - - /** - * Check to see if a given filename is in a directory that should be ignored - * @param {String} file name to be checked - * - * @return {Boolean} whether the directory should be ignored - */ - protected function ignoreDir($fileName) { - foreach($this->id as $dir) { - $pos = strpos(DIRECTORY_SEPARATOR.$fileName,DIRECTORY_SEPARATOR.$dir.DIRECTORY_SEPARATOR); - if ($pos !== false) { - return true; - } - } - return false; - } - - /** - * Loads the CSS from source/css/ into CSS Rule Saver to be used for code view - */ - protected function initializeCSSRuleSaver() { - - $loader = new \SplClassLoader('CSSRuleSaver', __DIR__.'/../../lib'); - $loader->register(); - - $this->cssRuleSaver = new \CSSRuleSaver\CSSRuleSaver; - - foreach(glob($this->sd."/css/*.css") as $filename) { - $this->cssRuleSaver->loadCSS($filename); - } - - } - - /** - * Returns the last error message when building a JSON file. Mimics json_last_error_msg() from PHP 5.5 - * @param {String} the file that generated the error - */ - protected function jsonLastErrorMsg($file) { - $errors = array( - JSON_ERROR_NONE => null, - JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', - JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch', - JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', - JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', - JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded' - ); - $error = json_last_error(); - $errorMessage = array_key_exists($error, $errors) ? $errors[$error] : "Unknown error ({$error})"; - if ($errorMessage != null) { - print "The JSON file, ".$file.", wasn't loaded. The error: ".$errorMessage."\n"; - } - } - - /** - * Print out the data var. For debugging purposes - * - * @return {String} the formatted version of the d object - */ - public function printData() { - print_r($this->d); - } - - /** - * Trim a given string. Used in the array_walk() function in __construct as a sanity check - * @param {String} an entry from one of the list-based config entries - * - * @return {String} trimmed version of the given $v var - */ - public function trim(&$v) { - $v = trim($v); - } - - /** - * Lowercase the given string. Used in the array_walk() function in __construct as a sanity check - * @param {String} an entry from one of the list-based config entries - * - * @return {String} lowercased version of the given $v var - */ - public function strtolower(&$v) { - $v = strtolower($v); - } - -} diff --git a/core/lib/PatternLab/Configurer.php b/core/lib/PatternLab/Configurer.php deleted file mode 100644 index 292c66507..000000000 --- a/core/lib/PatternLab/Configurer.php +++ /dev/null @@ -1,113 +0,0 @@ -userConfigPath = __DIR__."/../../../config/config.ini"; - $this->plConfigPath = __DIR__."/../../config/config.ini.default"; - - } - - /** - * Returns the appropriate config. If it's an old version it updates the config and runs migrations - * @param {String} the version number for Pattern Lab from builder.php - * - * @return {Array} the configuration - */ - public function getConfig() { - - // make sure migrate doesn't happen by default - $migrate = false; - $diffVersion = false; - - // double-check the default config file exists - if (!file_exists($this->plConfigPath)) { - print "Please make sure config.ini.default exists before trying to have Pattern Lab build the config.ini file automagically.\n"; - exit; - } - - // set the default config using the pattern lab config - $config = parse_ini_file($this->plConfigPath); - $defaultConfig = $config; - - // check to see if the user config exists, if not create it - print "configuring pattern lab...\n"; - if (!file_exists($this->userConfigPath)) { - $migrate = true; - } else { - $config = parse_ini_file($this->userConfigPath); - } - - // compare version numbers - $diffVersion = ($config["v"] != $defaultConfig["v"]) ? true : false; - - // run an upgrade and migrations if necessary - if ($migrate || $diffVersion) { - print "upgrading your version of pattern lab...\n"; - print "checking for migrations...\n"; - $m = new Migrator; - $m->migrate(true); - if ($migrate) { - if (!@copy($this->plConfigPath, $this->userConfigPath)) { - print "Please make sure that Pattern Lab can write a new config to config/.\n"; - exit; - } - } else { - $config = $this->writeNewConfig($config,$defaultConfig); - } - } - - return $config; - - } - - /** - * Use the default config as a base and update it with old config options. Write out a new user config. - * @param {Array} the old configuration file options - * @param {Array} the default configuration file options - * - * @return {Array} the new configuration - */ - protected function writeNewConfig($oldConfig,$defaultConfig) { - - // iterate over the old config and replace values in the new config - foreach ($oldConfig as $key => $value) { - if ($key != "v") { - $defaultConfig[$key] = $value; - } - } - - // create the output data - $configOutput = ""; - foreach ($defaultConfig as $key => $value) { - $configOutput .= $key." = \"".$value."\"\n"; - } - - // write out the new config file - file_put_contents($this->userConfigPath,$configOutput); - - return $defaultConfig; - - } - -} diff --git a/core/lib/PatternLab/Console.php b/core/lib/PatternLab/Console.php deleted file mode 100644 index def64cdce..000000000 --- a/core/lib/PatternLab/Console.php +++ /dev/null @@ -1,275 +0,0 @@ -self = $_SERVER["PHP_SELF"]; - } - - /** - * Get the arguments that have been passed to the script via the commmand line - */ - public function getArguments() { - if (php_sapi_name() != 'cli') { - print "The builder script can only be run from the command line.\n"; - exit; - } - $this->options = getopt($this->optionsShort,$this->optionsLong); - } - - /** - * See if a particular command was passed to the script via the command line. Can either be the short or long version - * @param {String} list of arguments to check - * - * @return {Boolean} if the command has been passed to the script via the command line - */ - public function findCommand($args) { - $args = explode("|",$args); - foreach ($args as $arg) { - if (isset($this->options[$arg])) { - return true; - } - } - return false; - } - - /** - * Return the command that was given in the command line arguments - * - * @return {String} the command. passes false if no command was found - */ - public function getCommand() { - foreach ($this->commands as $command => $attributes) { - if (isset($this->options[$command]) || isset($this->options[$attributes["commandLong"]])) { - return $command; - } - } - return false; - } - - /** - * Set-up the command so it can be used from the command line - * @param {String} the single character version of the command - * @param {String} the long version of the command - * @param {String} the description to be used in the "available commands" section of writeHelp() - * @param {String} the description to be used in the "help" section of writeHelpCommand() - */ - public function setCommand($short,$long,$desc,$help) { - $this->optionsShort .= $short; - $this->optionsLong[] = $long; - $this->commands[$short] = array("commandShort" => $short, "commandLong" => $long, "commandLongLength" => strlen($long), "commandDesc" => $desc, "commandHelp" => $help, "commandOptions" => array()); - } - - /** - * See if a particular option was passed to the script via the command line. Can either be the short or long version - * @param {String} list of arguments to check - * - * @return {Boolean} if the command has been passed to the script via the command line - */ - public function findCommandOption($args) { - $args = explode("|",$args); - foreach ($args as $arg) { - if (isset($this->options[$arg])) { - return true; - } - } - return false; - } - - /** - * Set-up an option for a given command so it can be used from the command line - * @param {String} the single character of the command that this option is related to - * @param {String} the single character version of the option - * @param {String} the long version of the option - * @param {String} the description to be used in the "available options" section of writeHelpCommand() - * @param {String} the sample to be used in the "sample" section of writeHelpCommand() - */ - public function setCommandOption($command,$short,$long,$desc,$sample) { - if (strpos($this->optionsShort,$short) === false) { - $this->optionsShort .= $short; - } - if (!in_array($long,$this->optionsLong)) { - $this->optionsLong[] = $long; - } - $this->commands[$command]["commandOptions"][$short] = array("optionShort" => $short, "optionLong" => $long, "optionLongLength" => strlen($long), "optionDesc" => $desc, "optionSample" => $sample); - } - - /** - * Write out the generic help - */ - public function writeHelp() { - - /* - - The generic help follows this format: - - Pattern Lab Console Options - - Usage: - php core/console command [options] - - Available commands: - --build (-b) Build Pattern Lab - --watch (-w) Build Pattern Lab and watch for changes and rebuild as necessary - --version (-v) Display the version number - --help (-h) Display this help message. - - */ - - // find length of longest command - $lengthLong = 0; - foreach ($this->commands as $command => $attributes) { - $lengthLong = ($attributes["commandLongLength"] > $lengthLong) ? $attributes["commandLongLength"] : $lengthLong; - } - - // write out the generic usage info - $this->writeLine("Pattern Lab Console Options",true); - $this->writeLine("Usage:"); - $this->writeLine(" php ".$this->self." command [options]",true); - $this->writeLine("Available commands:"); - - // write out the commands - foreach ($this->commands as $command => $attributes) { - $spacer = $this->getSpacer($lengthLong,$attributes["commandLongLength"]); - $this->writeLine(" --".$attributes["commandLong"].$spacer."(-".$attributes["commandShort"].") ".$attributes["commandDesc"]); - } - - $this->writeLine(""); - - } - - /** - * Write out the command-specific help - * @param {String} the single character of the command that this option is related to - */ - public function writeHelpCommand($command = "") { - - /* - - The command help follows this format: - - Build Command Options - - Usage: - php core/console --build [--patternsonly|-p] [--nocache|-n] [--enablecss|-c] - - Available options: - --patternsonly (-p) Build only the patterns. Does NOT clean public/. - --nocache (-n) Set the cacheBuster value to 0. - --enablecss (-c) Generate CSS for each pattern. Resource intensive. - --help (-h) Display this help message. - - Help: - The build command builds an entire site a single time. It compiles the patterns and moves content from source/ into public/ - - Samples: - - To run and generate the CSS for each pattern: - php core/console build -c - - To build only the patterns and not move other files from source/ to public/ - php core/console build -p - - To turn off the cacheBuster - php core/console build -n - */ - - // if given an empty command or the command doesn't exist in the lists give the generic help - if (empty($command)) { - $this->writeHelp(); - return; - } - - $commandShort = $this->commands[$command]["commandShort"]; - $commandLong = $this->commands[$command]["commandLong"]; - $commandHelp = $this->commands[$command]["commandHelp"]; - $commandOptions = $this->commands[$command]["commandOptions"]; - - $commandLongUC = ucfirst($commandLong); - - // write out the option list and get the longest item - $optionList = ""; - $lengthLong = 0; - foreach ($commandOptions as $option => $attributes) { - $optionList .= "[--".$attributes["optionLong"]."|-".$attributes["optionShort"]."] "; - $lengthLong = ($attributes["optionLongLength"] > $lengthLong) ? $attributes["optionLongLength"] : $lengthLong; - } - - // write out the generic usage info - $this->writeLine($commandLongUC." Command Options",true); - $this->writeLine("Usage:"); - $this->writeLine(" php ".$this->self." --".$commandLong."|-".$commandShort." ".$optionList,true); - - // write out the available options - if (count($commandOptions) > 0) { - $this->writeLine("Available options:"); - foreach ($commandOptions as $option => $attributes) { - $spacer = $this->getSpacer($lengthLong,$attributes["optionLongLength"]); - $this->writeLine(" --".$attributes["optionLong"].$spacer."(-".$attributes["optionShort"].") ".$attributes["optionDesc"]); - } - $this->writeLine(""); - } - - $this->writeLine("Help:"); - $this->writeLine(" ".$commandHelp,true); - - // write out the samples - if (count($commandOptions) > 0) { - $this->writeLine(" Samples:",true); - foreach ($commandOptions as $option => $attributes) { - $this->writeLine(" ".$attributes["optionSample"]); - $this->writeLine(" php ".$this->self." --".$commandLong." --".$attributes["optionLong"]); - $this->writeLine(" php ".$this->self." -".$commandShort." -".$attributes["optionShort"],true); - } - } - - } - - /** - * Write out a line of the help - * @param {Boolean} handle double-break - */ - protected function writeLine($line,$doubleBreak = false) { - $break = ($doubleBreak) ? "\n\n" : "\n"; - print $line.$break; - } - - /** - * Make sure the space is properly set between long command options and short command options - * @param {Integer} the longest length of the command's options - * @param {Integer} the character length of the given option - */ - protected function getSpacer($lengthLong,$itemLongLength) { - $i = 0; - $spacer = " "; - $spacerLength = $lengthLong - $itemLongLength; - while ($i < $spacerLength) { - $spacer .= " "; - $i++; - } - return $spacer; - } - -} diff --git a/core/lib/PatternLab/Generator.php b/core/lib/PatternLab/Generator.php deleted file mode 100644 index 60d65cb30..000000000 --- a/core/lib/PatternLab/Generator.php +++ /dev/null @@ -1,174 +0,0 @@ -noCacheBuster = $noCacheBuster; - - if ($enableCSS) { - - // enable CSS globally throughout PL - $this->enableCSS = true; - - // initialize CSS rule saver - $this->initializeCSSRuleSaver(); - print "CSS generation enabled. This could take a few seconds...\n"; - - } - - // gather up all of the data to be used in patterns - $this->gatherData(); - - // gather all of the various pattern info - $this->gatherPatternInfo(); - - // clean the public directory to remove old files - if (($this->cleanPublic == "true") && $moveStatic) { - $this->cleanPublic(); - } - - // render out the patterns and move them to public/patterns - $this->generatePatterns(); - - // render out the index and style guide - $this->generateMainPages(); - - // make sure data exists - if (!is_dir($this->pd."/data")) { - mkdir($this->pd."/data"); - } - - // iterate over the data files and regenerate the entire site if they've changed - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/_data/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - $fileName = str_replace($this->sd."/_data".DIRECTORY_SEPARATOR,"",$name); - if (($fileName[0] != "_") && $object->isFile()) { - $this->moveStaticFile("_data/".$fileName,"","_data","data"); - } - - } - - // move all of the files unless pattern only is set - if ($moveStatic) { - - // iterate over all of the other files in the source directory - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored - $fileName = str_replace($this->sd.DIRECTORY_SEPARATOR,"",$name); - if (($fileName[0] != "_") && (!in_array($object->getExtension(),$this->ie)) && (!in_array($object->getFilename(),$this->id))) { - - // catch directories that have the ignored dir in their path - $ignoreDir = $this->ignoreDir($fileName); - - // check to see if it's a new directory - if (!$ignoreDir && $object->isDir() && !is_dir($this->pd."/".$fileName)) { - mkdir($this->pd."/".$fileName); - } - - // check to see if it's a new file or a file that has changed - if (!$ignoreDir && $object->isFile() && (!file_exists($this->pd."/".$fileName))) { - $this->moveStaticFile($fileName); - } - - } - - } - - } - - // update the change time so the auto-reload will fire (doesn't work for the index and style guide) - $this->updateChangeTime(); - - print "your site has been generated...\n"; - - // print out how long it took to generate the site - if ($timePL) { - $mtime = microtime(); - $mtime = explode(" ",$mtime); - $mtime = $mtime[1] + $mtime[0]; - $endtime = $mtime; - $totaltime = ($endtime - $starttime); - $mem = round((memory_get_peak_usage(true)/1024)/1024,2); - print "site generation took ".$totaltime." seconds and used ".$mem."MB of memory...\n"; - } - - } - - /** - * Randomly prints a saying after the generate is complete - */ - public function printSaying() { - - $randomNumber = rand(0,60); - $sayings = array( - "have fun storming the castle", - "be well, do good work, and keep in touch", - "may the sun shine, all day long", - "smile", - "namaste", - "walk as if you are kissing the earth with your feet", - "to be beautiful means to be yourself", - "i was thinking of the immortal words of socrates, who said \"...i drank what?\"", - "let me take this moment to compliment you on your fashion sense, particularly your slippers", - "42", - "he who controls the spice controls the universe", - "the greatest thing you'll ever learn is just to love and be loved in return", - "nice wand", - "i don't have time for a grudge match with every poseur in a parka" - ); - if (isset($sayings[$randomNumber])) { - print $sayings[$randomNumber]."...\n"; - } - - } - -} \ No newline at end of file diff --git a/core/lib/PatternLab/Migrator.php b/core/lib/PatternLab/Migrator.php deleted file mode 100644 index 7d61b847e..000000000 --- a/core/lib/PatternLab/Migrator.php +++ /dev/null @@ -1,141 +0,0 @@ -getFilename(); - if (!$migration->isDot() && $migration->isFile() && ($filename[0] != "_")) { - $migrationsValid[] = $filename; - } - } - - asort($migrationsValid); - - foreach ($migrationsValid as $filename) { - - $basePath = __DIR__."/../../../"; - $migrationData = json_decode(file_get_contents(__DIR__."/../../migrations/".$filename)); - $checkType = $migrationData->checkType; - $sourcePath = ($checkType == "fileExists") ? $basePath.$migrationData->sourcePath : $basePath.$migrationData->sourcePath.DIRECTORY_SEPARATOR; - $destinationPath = ($checkType == "fileExists") ? $basePath.$migrationData->destinationPath : $basePath.$migrationData->destinationPath.DIRECTORY_SEPARATOR; - - if ($checkType == "dirEmpty") { - - $emptyDir = true; - $objects = new \DirectoryIterator($destinationPath); - foreach ($objects as $object) { - if (!$object->isDot() && ($object->getFilename() != "README") && ($object->getFilename() != ".DS_Store")) { - $emptyDir = false; - } - } - - if ($emptyDir) { - $this->runMigration($filename, $sourcePath, $destinationPath, false); - } - - } else if ($checkType == "dirExists") { - - if (!is_dir($destinationPath)) { - mkdir($destinationPath); - } - - } else if ($checkType == "fileExists") { - - if (!file_exists($destinationPath)) { - $this->runMigration($filename, $sourcePath, $destinationPath, true); - } - - } else if (($checkType == "versionDiffDir") && $diffVersion) { - - // make sure the destination path exists - if (!is_dir($destinationPath)) { - mkdir($destinationPath); - } - - $this->runMigration($filename, $sourcePath, $destinationPath, false); - - } else if (($checkType == "versionDiffFile") && $diffVersion) { - - $this->runMigration($filename, $sourcePath, $destinationPath, true); - - } else { - - print "Pattern Lab doesn't recognize a checkType of ".$checkType.". The migrator class is pretty thin at the moment.\n"; - exit; - - } - - } - - } - - /** - * Run any migrations found in core/migrations that match the approved types - * @param {String} the filename of the migration - * @param {String} the path of the source directory - * @param {String} the path to the destination - * @param {Boolean} moving a single file or a directory - */ - protected function runMigration($filename, $sourcePath, $destinationPath, $singleFile) { - - $filename = str_replace(".json","",$filename); - print " Starting the ".$filename." migration...\n"; - - if ($singleFile) { - - copy($sourcePath.$fileName,$destinationPath.$fileName); - - } else { - - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($sourcePath), \RecursiveIteratorIterator::SELF_FIRST); - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach ($objects as $object) { - - // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored - $fileName = str_replace($sourcePath,"",$object->getPathname()); - - // check to see if it's a new directory - if ($object->isDir() && !is_dir($destinationPath.$fileName)) { - mkdir($destinationPath.$fileName); - } else if ($object->isFile()) { - copy($sourcePath.$fileName,$destinationPath.$fileName); - } - - } - - } - - print " Completed the ".$filename." migration...\n"; - - } - -} diff --git a/core/lib/PatternLab/Watcher.php b/core/lib/PatternLab/Watcher.php deleted file mode 100644 index 03ead7e40..000000000 --- a/core/lib/PatternLab/Watcher.php +++ /dev/null @@ -1,267 +0,0 @@ -noCacheBuster = $noCacheBuster; - - $c = false; // track that one loop through the pattern file listing has completed - $o = new \stdClass(); // create an object to hold the properties - $cp = new \stdClass(); // create an object to hold a clone of $o - - $o->patterns = new \stdClass(); - - print "watching your site for changes...\n"; - - // run forever - while (true) { - - // clone the patterns so they can be checked in case something gets deleted - $cp = clone $o->patterns; - - // iterate over the patterns & related data and regenerate the entire site if they've changed - $patternObjects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/_patterns/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $patternObjects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($patternObjects as $name => $object) { - - // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored - $fileName = str_replace($this->sd."/_patterns".DIRECTORY_SEPARATOR,"",$name); - $fileNameClean = str_replace(DIRECTORY_SEPARATOR."_",DIRECTORY_SEPARATOR,$fileName); - - if ($object->isFile() && (($object->getExtension() == "mustache") || ($object->getExtension() == "json"))) { - - // make sure this isn't a hidden pattern - $patternParts = explode(DIRECTORY_SEPARATOR,$fileName); - $pattern = isset($patternParts[2]) ? $patternParts[2] : $patternParts[1]; - - - // make sure the pattern still exists in source just in case it's been deleted during the iteration - if (file_exists($name)) { - - $mt = $object->getMTime(); - if (isset($o->patterns->$fileName) && ($o->patterns->$fileName != $mt)) { - $o->patterns->$fileName = $mt; - $this->updateSite($fileName,"changed"); - } else if (!isset($o->patterns->$fileName) && $c) { - $o->patterns->$fileName = $mt; - $this->updateSite($fileName,"added"); - if ($object->getExtension() == "mustache") { - $patternSrcPath = str_replace(".mustache","",$fileName); - $patternDestPath = str_replace("/","-",$patternSrcPath); - $render = ($pattern[0] != "_") ? true : false; - $this->patternPaths[$patternParts[0]][$pattern] = array("patternSrcPath" => $patternSrcPath, "patternDestPath" => $patternDestPath, "render" => $render); - } - } else if (!isset($o->patterns->$fileName)) { - $o->patterns->$fileName = $mt; - } - - if ($c && isset($o->patterns->$fileName)) { - unset($cp->$fileName); - } - - } else { - - // the file was removed during the iteration so remove references to the item - unset($o->patterns->$fileName); - unset($cp->$fileName); - unset($this->patternPaths[$patternParts[0]][$pattern]); - $this->updateSite($fileName,"removed"); - - } - - } - - } - - // make sure old entries are deleted - // will throw "pattern not found" errors if an entire directory is removed at once but that shouldn't be a big deal - if ($c) { - - foreach($cp as $fileName => $mt) { - - unset($o->patterns->$fileName); - $patternParts = explode(DIRECTORY_SEPARATOR,$fileName); - $pattern = isset($patternParts[2]) ? $patternParts[2] : $patternParts[1]; - - unset($this->patternPaths[$patternParts[0]][$pattern]); - $this->updateSite($fileName,"removed"); - - } - - } - - // iterate over the data files and regenerate the entire site if they've changed - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/_data/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - $fileName = str_replace($this->sd."/_data".DIRECTORY_SEPARATOR,"",$name); - $mt = $object->getMTime(); - - if (!isset($o->$fileName)) { - $o->$fileName = $mt; - if (($fileName[0] != "_") && $object->isFile()) { - $this->moveStaticFile("_data/".$fileName,"","_data","data"); - } - } else if ($o->$fileName != $mt) { - $o->$fileName = $mt; - $this->updateSite($fileName,"changed"); - if (($fileName[0] != "_") && $object->isFile()) { - $this->moveStaticFile("_data/".$fileName,"","_data","data"); - } - } - - } - - // iterate over all of the other files in the source directory and move them if their modified time has changed - if ($moveStatic) { - - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored - $fileName = str_replace($this->sd.DIRECTORY_SEPARATOR,"",$name); - if (($fileName[0] != "_") && (!in_array($object->getExtension(),$this->ie)) && (!in_array($object->getFilename(),$this->id))) { - - // catch directories that have the ignored dir in their path - $ignoreDir = $this->ignoreDir($fileName); - - // check to see if it's a new directory - if (!$ignoreDir && $object->isDir() && !isset($o->$fileName) && !is_dir($this->pd."/".$fileName)) { - mkdir($this->pd."/".$fileName); - $o->$fileName = "dir created"; // placeholder - print $fileName."/ directory was created...\n"; - } - - // check to see if it's a new file or a file that has changed - if (file_exists($name)) { - - $mt = $object->getMTime(); - if (!$ignoreDir && $object->isFile() && !isset($o->$fileName) && !file_exists($this->pd."/".$fileName)) { - $o->$fileName = $mt; - $this->moveStaticFile($fileName,"added"); - if ($object->getExtension() == "css") { - $this->updateSite($fileName,"changed",0); // make sure the site is updated for MQ reasons - } - } else if (!$ignoreDir && $object->isFile() && isset($o->$fileName) && ($o->$fileName != $mt)) { - $o->$fileName = $mt; - $this->moveStaticFile($fileName,"changed"); - if ($object->getExtension() == "css") { - $this->updateSite($fileName,"changed",0); // make sure the site is updated for MQ reasons - } - } else if (!isset($o->fileName)) { - $o->$fileName = $mt; - } - - } else { - unset($o->$fileName); - } - - } - - } - - } - - - $c = true; - - // taking out the garbage. basically killing mustache after each run. - unset($this->mpl); - unset($this->msf); - unset($this->mv); - if (gc_enabled()) gc_collect_cycles(); - - // output anything the reload server might send our way - if ($reload) { - $output = fgets($fp, 100); - if ($output != "\n") print $output; - } - - // pause for .05 seconds to give the CPU a rest - usleep(50000); - - } - - // close the auto-reload process, this shouldn't do anything - fclose($fp); - - } - - /** - * Updates the Pattern Lab Website and prints the appropriate message - * @param {String} file name to included in the message - * @param {String} a switch for decided which message isn't printed - * - * @return {String} the final message - */ - private function updateSite($fileName,$message,$verbose = true) { - $this->gatherData(); - $this->gatherPatternInfo(); - $this->generatePatterns(); - $this->generateViewAllPages(); - $this->updateChangeTime(); - $this->generateMainPages(); - if ($verbose) { - if ($message == "added") { - print $fileName." was added to Pattern Lab. Reload the website to see this change in the navigation...\n"; - } elseif ($message == "removed") { - print $fileName." was removed from Pattern Lab. Reload the website to see this change reflected in the navigation...\n"; - } elseif ($message == "hidden") { - print $fileName." was hidden from Pattern Lab. Reload the website to see this change reflected in the navigation...\n"; - } else { - print $fileName." changed...\n"; - } - } - } - -} diff --git a/core/lib/SplClassLoader.php b/core/lib/SplClassLoader.php deleted file mode 100644 index 2bc31f04b..000000000 --- a/core/lib/SplClassLoader.php +++ /dev/null @@ -1,136 +0,0 @@ -register(); - * - * @author Jonathan H. Wage - * @author Roman S. Borschel - * @author Matthew Weier O'Phinney - * @author Kris Wallsmith - * @author Fabien Potencier - */ -class SplClassLoader -{ - private $_fileExtension = '.php'; - private $_namespace; - private $_includePath; - private $_namespaceSeparator = '\\'; - - /** - * Creates a new SplClassLoader that loads classes of the - * specified namespace. - * - * @param string $ns The namespace to use. - */ - public function __construct($ns = null, $includePath = null) - { - $this->_namespace = $ns; - $this->_includePath = $includePath; - } - - /** - * Sets the namespace separator used by classes in the namespace of this class loader. - * - * @param string $sep The separator to use. - */ - public function setNamespaceSeparator($sep) - { - $this->_namespaceSeparator = $sep; - } - - /** - * Gets the namespace seperator used by classes in the namespace of this class loader. - * - * @return void - */ - public function getNamespaceSeparator() - { - return $this->_namespaceSeparator; - } - - /** - * Sets the base include path for all class files in the namespace of this class loader. - * - * @param string $includePath - */ - public function setIncludePath($includePath) - { - $this->_includePath = $includePath; - } - - /** - * Gets the base include path for all class files in the namespace of this class loader. - * - * @return string $includePath - */ - public function getIncludePath() - { - return $this->_includePath; - } - - /** - * Sets the file extension of class files in the namespace of this class loader. - * - * @param string $fileExtension - */ - public function setFileExtension($fileExtension) - { - $this->_fileExtension = $fileExtension; - } - - /** - * Gets the file extension of class files in the namespace of this class loader. - * - * @return string $fileExtension - */ - public function getFileExtension() - { - return $this->_fileExtension; - } - - /** - * Installs this class loader on the SPL autoload stack. - */ - public function register() - { - spl_autoload_register(array($this, 'loadClass')); - } - - /** - * Uninstalls this class loader from the SPL autoloader stack. - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - } - - /** - * Loads the given class or interface. - * - * @param string $className The name of the class to load. - * @return void - */ - public function loadClass($className) - { - if (null === $this->_namespace || $this->_namespace.$this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace.$this->_namespaceSeparator))) { - $fileName = ''; - $namespace = ''; - if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator))) { - $namespace = substr($className, 0, $lastNsPos); - $className = substr($className, $lastNsPos + 1); - $fileName = str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR; - } - $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension; - - require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName; - } - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Application/Application.php b/core/lib/Wrench/Application/Application.php deleted file mode 100755 index 2132a8907..000000000 --- a/core/lib/Wrench/Application/Application.php +++ /dev/null @@ -1,34 +0,0 @@ -newlines = $newlines; - - if (file_exists(__DIR__."/../../../../public/latest-change.txt")) { - $this->savedTimestamp = file_get_contents(__DIR__."/../../../../public/latest-change.txt"); - } else { - $this->savedTimestamp = time(); - } - - } - - /** - * When a client connects add it to the list of connected clients - */ - public function onConnect($client) { - $id = $client->getId(); - $this->clients[$id] = $client; - } - - /** - * When a client disconnects remove it from the list of connected clients - */ - public function onDisconnect($client) { - $id = $client->getId(); - unset($this->clients[$id]); - } - - /** - * Dead function in this instance - */ - public function onData($data, $client) { - // function not in use - } - - /** - * Sends out a message once a second to all connected clients containing the contents of latest-change.txt - */ - public function onUpdate() { - - if (file_exists(__DIR__."/../../../../public/latest-change.txt")) { - $readTimestamp = file_get_contents(__DIR__."/../../../../public/latest-change.txt"); - if ($readTimestamp != $this->savedTimestamp) { - print "pattern lab updated. alerting connected browsers...\n"; - foreach ($this->clients as $sendto) { - $sendto->send($readTimestamp); - } - $this->savedTimestamp = $readTimestamp; - } else { - if ($this->newlines) print "\n"; - } - } - - } - -} diff --git a/core/lib/Wrench/Application/PageFollowApplication.php b/core/lib/Wrench/Application/PageFollowApplication.php deleted file mode 100644 index 9306b64e7..000000000 --- a/core/lib/Wrench/Application/PageFollowApplication.php +++ /dev/null @@ -1,71 +0,0 @@ -getId(); - $this->clients[$id] = $client; - if ($this->data != null) { - $client->send(json_encode($this->data)); - } - } - - /** - * When a client disconnects remove it from the list of connected clients - */ - public function onDisconnect($client) { - $id = $client->getId(); - unset($this->clients[$id]); - } - - /** - * When receiving a message from a client, strip it to avoid cross-domain issues and send it to all clients except the one who sent it - * Also store the address as the current address for any new clients that attach - */ - public function onData($data, $client) { - - $dataDecoded = json_decode($data); - - $dataDecoded->url = "/".$dataDecoded->url; - $dataEncoded = json_encode($dataDecoded); - $testId = $client->getId(); - foreach ($this->clients as $sendto) { - if ($testId != $sendto->getId()) { - $sendto->send($dataEncoded); - } - } - - $this->data = $dataDecoded; - - } - - /** - * Dead function in this instance - */ - public function onUpdate() { - // not using for this application - } - -} diff --git a/core/lib/Wrench/BasicServer.php b/core/lib/Wrench/BasicServer.php deleted file mode 100755 index 88578a055..000000000 --- a/core/lib/Wrench/BasicServer.php +++ /dev/null @@ -1,70 +0,0 @@ -configureRateLimiter(); - $this->configureOriginPolicy(); - } - - /** - * @see Wrench.Server::configure() - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'check_origin' => true, - 'allowed_origins' => array(), - 'origin_policy_class' => 'Wrench\Listener\OriginPolicy', - 'rate_limiter_class' => 'Wrench\Listener\RateLimiter' - ), $options); - - parent::configure($options); - } - - protected function configureRateLimiter() - { - $class = $this->options['rate_limiter_class']; - $this->rateLimiter = new $class(); - $this->rateLimiter->listen($this); - } - - /** - * Configures the origin policy - */ - protected function configureOriginPolicy() - { - $class = $this->options['origin_policy_class']; - $this->originPolicy = new $class($this->options['allowed_origins']); - - if ($this->options['check_origin']) { - $this->originPolicy->listen($this); - } - } - - /** - * Adds an allowed origin - * - * @param array $origin - */ - public function addAllowedOrigin($origin) - { - $this->originPolicy->addAllowedOrigin($origin); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Client.php b/core/lib/Wrench/Client.php deleted file mode 100755 index 87e8f11ba..000000000 --- a/core/lib/Wrench/Client.php +++ /dev/null @@ -1,265 +0,0 @@ - - */ - protected $received = array(); - - /** - * Constructor - * - * @param string $uri - * @param string $origin The origin to include in the handshake (required - * in later versions of the protocol) - * @param array $options (optional) Array of options - * - socket => Socket instance (otherwise created) - * - protocol => Protocol - */ - public function __construct($uri, $origin, array $options = array()) - { - parent::__construct($options); - - $uri = (string)$uri; - if (!$uri) { - throw new InvalidArgumentException('No URI specified'); - } - $this->uri = $uri; - - $origin = (string)$origin; - if (!$origin) { - throw new InvalidArgumentException('No origin specified'); - } - $this->origin = $origin; - - $this->protocol->validateUri($this->uri); - $this->protocol->validateOriginUri($this->origin); - - $this->configureSocket(); - $this->configurePayloadHandler(); - } - - /** - * Configure options - * - * @param array $options - * @return void - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'socket_class' => 'Wrench\\Socket\\ClientSocket', - 'on_data_callback' => null - ), $options); - - parent::configure($options); - } - - /** - * Configures the client socket - */ - protected function configureSocket() - { - $class = $this->options['socket_class']; - $this->socket = new $class($this->uri); - } - - /** - * Configures the payload handler - */ - protected function configurePayloadHandler() - { - $this->payloadHandler = new PayloadHandler(array($this, 'onData'), $this->options); - } - - /** - * Payload receiver - * - * Public because called from our PayloadHandler. Don't call us, we'll call - * you (via the on_data_callback option). - * - * @param Payload $payload - */ - public function onData(Payload $payload) - { - $this->received[] = $payload; - if (($callback = $this->options['on_data_callback'])) { - call_user_func($callback, $payload); - } - } - - /** - * Adds a request header to be included in the initial handshake - * - * For example, to include a Cookie header - * - * @param string $name - * @param string $value - * @return void - */ - public function addRequestHeader($name, $value) - { - $this->headers[$name] = $value; - } - - /** - * Sends data to the socket - * - * @param string $data - * @param string $type Payload type - * @param boolean $masked - * @return boolean Success - */ - public function sendData($data, $type = Protocol::TYPE_TEXT, $masked = true) - { - if (is_string($type) && isset(Protocol::$frameTypes[$type])) { - $type = Protocol::$frameTypes[$type]; - } - - $payload = $this->protocol->getPayload(); - - $payload->encode( - $data, - $type, - $masked - ); - - return $payload->sendToSocket($this->socket); - } - - /** - * Receives data sent by the server - * - * @param callable $callback - * @return array Payload received since the last call to receive() - */ - public function receive() - { - if (!$this->isConnected()) { - return false; - } - - $data = $this->socket->receive(); - - if (!$data) { - return $data; - } - - $old = $this->received; - $this->payloadHandler->handle($data); - return array_diff($this->received, $old); - } - - /** - * Connect to the Wrench server - * - * @return boolean Whether a new connection was made - */ - public function connect() - { - if ($this->isConnected()) { - return false; - } - - $this->socket->connect(); - - $key = $this->protocol->generateKey(); - $handshake = $this->protocol->getRequestHandshake( - $this->uri, - $key, - $this->origin, - $this->headers - ); - - $this->socket->send($handshake); - $response = $this->socket->receive(self::MAX_HANDSHAKE_RESPONSE); - return ($this->connected = - $this->protocol->validateResponseHandshake($response, $key)); - } - - /** - * Whether the client is currently connected - * - * @return boolean - */ - public function isConnected() - { - return $this->connected; - } - - /** - * @todo Bug: what if connect has been called twice. The first socket never - * gets closed. - */ - public function disconnect() - { - if ($this->socket) { - $this->socket->disconnect(); - } - $this->connected = false; - } - - -} diff --git a/core/lib/Wrench/Connection.php b/core/lib/Wrench/Connection.php deleted file mode 100755 index 2538fc739..000000000 --- a/core/lib/Wrench/Connection.php +++ /dev/null @@ -1,538 +0,0 @@ - 'value' - * - * @var array - */ - protected $queryParams = null; - - /** - * Connection ID - * - * @var string|null - */ - protected $id = null; - - /** - * @var PayloadHandler - */ - protected $payloadHandler; - - /** - * Constructor - * - * @param Server $server - * @param ServerClientSocket $socket - * @param array $options - * @throws InvalidArgumentException - */ - public function __construct( - ConnectionManager $manager, - ServerClientSocket $socket, - array $options = array() - ) { - $this->manager = $manager; - $this->socket = $socket; - - - parent::__construct($options); - - $this->configureClientInformation(); - $this->configurePayloadHandler(); - - $this->log('Connected'); - } - - /** - * Gets the connection manager of this connection - * - * @return \Wrench\ConnectionManager - */ - public function getConnectionManager() - { - return $this->manager; - } - - /** - * @see Wrench\Util.Configurable::configure() - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'connection_id_secret' => 'asu5gj656h64Da(0crt8pud%^WAYWW$u76dwb', - 'connection_id_algo' => 'sha512', - ), $options); - - parent::configure($options); - } - - protected function configurePayloadHandler() - { - $this->payloadHandler = new PayloadHandler( - array($this, 'handlePayload'), - $this->options - ); - } - - /** - * @throws RuntimeException - */ - protected function configureClientInformation() - { - $this->ip = $this->socket->getIp(); - $this->port = $this->socket->getPort(); - $this->configureClientId(); - } - - /** - * Configures the client ID - * - * We hash the client ID to prevent leakage of information if another client - * happens to get a hold of an ID. The secret *must* be lengthy, and must - * be kept secret for this to work: otherwise it's trivial to search the space - * of possible IP addresses/ports (well, if not trivial, at least very fast). - */ - protected function configureClientId() - { - $message = sprintf( - '%s:uri=%s&ip=%s&port=%s', - $this->options['connection_id_secret'], - rawurlencode($this->manager->getUri()), - rawurlencode($this->ip), - rawurlencode($this->port) - ); - - $algo = $this->options['connection_id_algo']; - - if (extension_loaded('gmp')) { - $hash = hash($algo, $message); - $hash = gmp_strval(gmp_init('0x' . $hash, 16), 62); - } else { - // @codeCoverageIgnoreStart - $hash = hash($algo, $message); - // @codeCoverageIgnoreEnd - } - - $this->id = $hash; - } - - /** - * Data receiver - * - * Called by the connection manager when the connection has received data - * - * @param string $data - */ - public function onData($data) - { - if (!$this->handshaked) { - return $this->handshake($data); - } - return $this->handle($data); - } - - /** - * Performs a websocket handshake - * - * @param string $data - * @throws BadRequestException - * @throws HandshakeException - * @throws WrenchException - */ - public function handshake($data) - { - try { - list($path, $origin, $key, $extensions, $protocol, $headers, $params) - = $this->protocol->validateRequestHandshake($data); - - $this->headers = $headers; - $this->queryParams = $params; - - $this->application = $this->manager->getApplicationForPath($path); - if (!$this->application) { - throw new BadRequestException('Invalid application'); - } - - $this->manager->getServer()->notify( - Server::EVENT_HANDSHAKE_REQUEST, - array($this, $path, $origin, $key, $extensions) - ); - - $response = $this->protocol->getResponseHandshake($key); - - if (!$this->socket->isConnected()) { - throw new HandshakeException('Socket is not connected'); - } - - if ($this->socket->send($response) === false) { - throw new HandshakeException('Could not send handshake response'); - } - - $this->handshaked = true; - - $this->log(sprintf( - 'Handshake successful: %s:%d (%s) connected to %s', - $this->getIp(), - $this->getPort(), - $this->getId(), - $path - ), 'info'); - - $this->manager->getServer()->notify( - Server::EVENT_HANDSHAKE_SUCCESSFUL, - array($this) - ); - - if (method_exists($this->application, 'onConnect')) { - $this->application->onConnect($this); - } - } catch (WrenchException $e) { - $this->log('Handshake failed: ' . $e, 'err'); - $this->close($e); - } - } - - /** - * Returns a string export of the given binary data - * - * @param string $data - * @return string - */ - protected function export($data) - { - $export = ''; - foreach (str_split($data) as $chr) { - $export .= '\\x' . ord($chr); - } - } - - /** - * Handle data received from the client - * - * The data passed in may belong to several different frames across one or - * more protocols. It may not even contain a single complete frame. This method - * manages slotting the data into separate payload objects. - * - * @todo An endpoint MUST be capable of handling control frames in the - * middle of a fragmented message. - * @param string $data - * @return void - */ - public function handle($data) - { - $this->payloadHandler->handle($data); - } - - /** - * Handle a complete payload received from the client - * - * Public because called from our PayloadHandler - * - * @param string $payload - */ - public function handlePayload(Payload $payload) - { - $app = $this->getClientApplication(); - - $this->log('Handling payload: ' . $payload->getPayload(), 'debug'); - - switch ($type = $payload->getType()) { - case Protocol::TYPE_TEXT: - if (method_exists($app, 'onData')) { - $app->onData($payload, $this); - } - return; - - case Protocol::TYPE_BINARY: - if(method_exists($app, 'onBinaryData')) { - $app->onBinaryData($payload, $this); - } else { - $this->close(1003); - } - break; - - case Protocol::TYPE_PING: - $this->log('Ping received', 'notice'); - $this->send($payload->getPayload(), Protocol::TYPE_PONG); - $this->log('Pong!', 'debug'); - break; - - /** - * A Pong frame MAY be sent unsolicited. This serves as a - * unidirectional heartbeat. A response to an unsolicited Pong - * frame is not expected. - */ - case Protocol::TYPE_PONG: - $this->log('Received unsolicited pong', 'info'); - break; - - case Protocol::TYPE_CLOSE: - $this->log('Close frame received', 'notice'); - $this->close(); - $this->log('Disconnected', 'info'); - break; - - default: - throw new ConnectionException('Unhandled payload type'); - } - } - - /** - * Sends the payload to the connection - * - * @param string $payload - * @param string $type - * @throws HandshakeException - * @throws ConnectionException - * @return boolean - */ - public function send($data, $type = Protocol::TYPE_TEXT) - { - if (!$this->handshaked) { - throw new HandshakeException('Connection is not handshaked'); - } - - $payload = $this->protocol->getPayload(); - - // Servers don't send masked payloads - $payload->encode($data, $type, false); - - if (!$payload->sendToSocket($this->socket)) { - $this->log('Could not send payload to client', 'warn'); - throw new ConnectionException('Could not send data to connection: ' . $this->socket->getLastError()); - } - - return true; - } - - /** - * Processes data on the socket - * - * @throws CloseException - */ - public function process() - { - $data = $this->socket->receive(); - $bytes = strlen($data); - - if ($bytes === 0 || $data === false) { - throw new CloseException('Error reading data from socket: ' . $this->socket->getLastError()); - } - - $this->onData($data); - } - - /** - * Closes the connection according to the WebSocket protocol - * - * If an endpoint receives a Close frame and that endpoint did not - * previously send a Close frame, the endpoint MUST send a Close frame - * in response. It SHOULD do so as soon as is practical. An endpoint - * MAY delay sending a close frame until its current message is sent - * (for instance, if the majority of a fragmented message is already - * sent, an endpoint MAY send the remaining fragments before sending a - * Close frame). However, there is no guarantee that the endpoint which - * has already sent a Close frame will continue to process data. - - * After both sending and receiving a close message, an endpoint - * considers the WebSocket connection closed, and MUST close the - * underlying TCP connection. The server MUST close the underlying TCP - * connection immediately; the client SHOULD wait for the server to - * close the connection but MAY close the connection at any time after - * sending and receiving a close message, e.g. if it has not received a - * TCP close from the server in a reasonable time period. - * - * @param int|Exception $statusCode - * @return boolean - */ - public function close($code = Protocol::CLOSE_NORMAL) - { - try { - if (!$this->handshaked) { - $response = $this->protocol->getResponseError($code); - $this->socket->send($response); - } else { - $response = $this->protocol->getCloseFrame($code); - $this->socket->send($response); - } - } catch (Exception $e) { - $this->log('Unable to send close message', 'warning'); - } - - if ($this->application && method_exists($this->application, 'onDisconnect')) { - $this->application->onDisconnect($this); - } - - $this->socket->disconnect(); - $this->manager->removeConnection($this); - } - - /** - * Logs a message - * - * @param string $message - * @param string $priority - */ - public function log($message, $priority = 'info') - { - $this->manager->log(sprintf( - '%s: %s:%d (%s): %s', - __CLASS__, - $this->getIp(), - $this->getPort(), - $this->getId(), - $message - ), $priority); - } - - /** - * Gets the IP address of the connection - * - * @return string Usually dotted quad notation - */ - public function getIp() - { - return $this->ip; - } - - /** - * Gets the port of the connection - * - * @return int - */ - public function getPort() - { - return $this->port; - } - - /** - * Gets the non-web-sockets headers included with the original request - * - * @return array - */ - public function getHeaders() - { - return $this->headers; - } - - /** - * Gets the query parameters included with the original request - * - * @return array - */ - public function getQueryParams() - { - return $this->queryParams; - } - - /** - * Gets the connection ID - * - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * Gets the socket object - * - * @return Socket\ServerClientSocket - */ - public function getSocket() - { - return $this->socket; - } - - /** - * Gets the client application - * - * @return Application - */ - public function getClientApplication() - { - return (isset($this->application)) ? $this->application : false; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/ConnectionManager.php b/core/lib/Wrench/ConnectionManager.php deleted file mode 100755 index 8a503de03..000000000 --- a/core/lib/Wrench/ConnectionManager.php +++ /dev/null @@ -1,332 +0,0 @@ - Connection> - */ - protected $connections = array(); - - /** - * An array of raw socket resources, corresponding to connections, roughly - * - * @var array resource> - */ - protected $resources = array(); - - /** - * Constructor - * - * @param Server $server - * @param array $options - */ - public function __construct(Server $server, array $options = array()) - { - $this->server = $server; - - parent::__construct($options); - } - - /** - * @see Countable::count() - */ - public function count() - { - return count($this->connections); - } - - /** - * @see Wrench\Socket.Socket::configure() - * Options include: - * - timeout_select => int, seconds, default 0 - * - timeout_select_microsec => int, microseconds (NB: not milli), default: 200000 - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'socket_master_class' => 'Wrench\Socket\ServerSocket', - 'socket_master_options' => array(), - 'socket_client_class' => 'Wrench\Socket\ServerClientSocket', - 'socket_client_options' => array(), - 'connection_class' => 'Wrench\Connection', - 'connection_options' => array(), - 'timeout_select' => self::TIMEOUT_SELECT, - 'timeout_select_microsec' => self::TIMEOUT_SELECT_MICROSEC - ), $options); - - parent::configure($options); - - $this->configureMasterSocket(); - } - - /** - * Gets the application associated with the given path - * - * @param string $path - */ - public function getApplicationForPath($path) - { - $path = ltrim($path, '/'); - return $this->server->getApplication($path); - } - - /** - * Configures the main server socket - * - * @param string $uri - */ - protected function configureMasterSocket() - { - $class = $this->options['socket_master_class']; - $options = $this->options['socket_master_options']; - $this->socket = new $class($this->server->getUri(), $options); - } - - /** - * Listens on the main socket - * - * @return void - */ - public function listen() - { - $this->socket->listen(); - $this->resources[$this->socket->getResourceId()] = $this->socket->getResource(); - } - - /** - * Gets all resources - * - * @return array resource) - */ - protected function getAllResources() - { - return array_merge($this->resources, array( - $this->socket->getResourceId() => $this->socket->getResource() - )); - } - - /** - * Returns the Connection associated with the specified socket resource - * - * @param resource $socket - * @return Connection - */ - protected function getConnectionForClientSocket($socket) - { - if (!isset($this->connections[$this->resourceId($socket)])) { - return false; - } - return $this->connections[$this->resourceId($socket)]; - } - - /** - * Select and process an array of resources - * - * @param array $resources - */ - public function selectAndProcess() - { - $read = $this->resources; - $unused_write = null; - $unsued_exception = null; - - stream_select( - $read, - $unused_write, - $unused_exception, - $this->options['timeout_select'], - $this->options['timeout_select_microsec'] - ); - - foreach ($read as $socket) { - if ($socket == $this->socket->getResource()) { - $this->processMasterSocket(); - } else { - $this->processClientSocket($socket); - } - } - } - - /** - * Process events on the master socket ($this->socket) - * - * @return void - */ - protected function processMasterSocket() - { - $new = null; - - try { - $new = $this->socket->accept(); - } catch (Exception $e) { - $this->server->log('Socket error: ' . $e, 'err'); - return; - } - - $connection = $this->createConnection($new); - $this->server->notify(Server::EVENT_SOCKET_CONNECT, array($new, $connection)); - } - - /** - * Creates a connection from a socket resource - * - * The create connection object is based on the options passed into the - * constructor ('connection_class', 'connection_options'). This connection - * instance and its associated socket resource are then stored in the - * manager. - * - * @param resource $resource A socket resource - * @return Connection - */ - protected function createConnection($resource) - { - if (!$resource || !is_resource($resource)) { - throw new InvalidArgumentException('Invalid connection resource'); - } - - $socket_class = $this->options['socket_client_class']; - $socket_options = $this->options['socket_client_options']; - - $connection_class = $this->options['connection_class']; - $connection_options = $this->options['connection_options']; - - $socket = new $socket_class($resource, $socket_options); - $connection = new $connection_class($this, $socket, $connection_options); - - $id = $this->resourceId($resource); - $this->resources[$id] = $resource; - $this->connections[$id] = $connection; - - return $connection; - } - - /** - * Process events on a client socket - * - * @param resource $socket - */ - protected function processClientSocket($socket) - { - $connection = $this->getConnectionForClientSocket($socket); - - if (!$connection) { - $this->log('No connection for client socket', 'warning'); - return; - } - - try { - $connection->process(); - } catch (CloseException $e) { - $this->log('Client connection closed: ' . $e, 'notice'); - $connection->close($e); - } catch (WrenchException $e) { - $this->log('Error on client socket: ' . $e, 'warning'); - $connection->close($e); - } - } - - /** - * This server makes an explicit assumption: PHP resource types may be cast - * to a integer. Furthermore, we assume this is bijective. Both seem to be - * true in most circumstances, but may not be guaranteed. - * - * This method (and $this->getResourceId()) exist to make this assumption - * explicit. - * - * This is needed on the connection manager as well as on resources - * - * @param resource $resource - */ - protected function resourceId($resource) - { - return (int)$resource; - } - - /** - * Gets the connection manager's listening URI - * - * @return string - */ - public function getUri() - { - return $this->server->getUri(); - } - - /** - * Logs a message - * - * @param string $message - * @param string $priority - */ - public function log($message, $priority = 'info') - { - $this->server->log(sprintf( - '%s: %s', - __CLASS__, - $message - ), $priority); - } - - /** - * @return \Wrench\Server - */ - public function getServer() - { - return $this->server; - } - - /** - * Removes a connection - * - * @param Connection $connection - */ - public function removeConnection(Connection $connection) - { - $socket = $connection->getSocket(); - - if ($socket->getResource()) { - $index = $socket->getResourceId(); - } else { - $index = array_search($connection, $this->connections); - } - - if (!$index) { - $this->log('Could not remove connection: not found', 'warning'); - } - - unset($this->connections[$index]); - unset($this->resources[$index]); - - $this->server->notify( - Server::EVENT_SOCKET_DISCONNECT, - array($connection->getSocket(), $connection) - ); - } -} diff --git a/core/lib/Wrench/Exception/BadRequestException.php b/core/lib/Wrench/Exception/BadRequestException.php deleted file mode 100755 index 8b8a1591f..000000000 --- a/core/lib/Wrench/Exception/BadRequestException.php +++ /dev/null @@ -1,22 +0,0 @@ -buffer) { - return false; - } - - try { - return $this->getBufferLength() >= $this->getExpectedBufferLength(); - } catch (FrameException $e) { - return false; - } - } - - /** - * Receieves data into the frame - * - * @param string $buffer - */ - public function receiveData($data) - { - $this->buffer .= $data; - } - - /** - * Gets the remaining number of bytes before this frame will be complete - * - * @return number - */ - public function getRemainingData() - { - try { - return $this->getExpectedBufferLength() - $this->getBufferLength(); - } catch (FrameException $e) { - return null; - } - } - - /** - * Whether this frame is waiting for more data - * - * @return boolean - */ - public function isWaitingForData() - { - return $this->getRemainingData() > 0; - } - - /** - * Gets the contents of the frame payload - * - * The frame must be complete to call this method. - * - * @return string - */ - public function getFramePayload() - { - if (!$this->isComplete()) { - throw new FrameException('Cannot get payload: frame is not complete'); - } - - if (!$this->payload && $this->buffer) { - $this->decodeFramePayloadFromBuffer(); - } - - return $this->payload; - } - - /** - * Gets the contents of the frame buffer - * - * This is the encoded value, receieved into the frame with receiveData(). - * - * @throws FrameException - * @return string binary - */ - public function getFrameBuffer() - { - if (!$this->buffer && $this->payload) { - throw new FrameException('Cannot get frame buffer'); - } - return $this->buffer; - } - - /** - * Gets the expected length of the frame payload - * - * @return int - */ - protected function getBufferLength() - { - return strlen($this->buffer); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Frame/HybiFrame.php b/core/lib/Wrench/Frame/HybiFrame.php deleted file mode 100755 index da6377d7e..000000000 --- a/core/lib/Wrench/Frame/HybiFrame.php +++ /dev/null @@ -1,376 +0,0 @@ -= 0 - */ - public function encode($payload, $type = Protocol::TYPE_TEXT, $masked = false) - { - if (!is_int($type) || !in_array($type, Protocol::$frameTypes)) { - throw new InvalidArgumentException('Invalid frame type'); - } - - $this->type = $type; - $this->masked = $masked; - $this->payload = $payload; - $this->length = strlen($this->payload); - $this->offset_mask = null; - $this->offset_payload = null; - - $this->buffer = "\x00\x00"; - - $this->buffer[self::BYTE_HEADER] = chr( - (self::BITFIELD_TYPE & $this->type) - | (self::BITFIELD_FINAL & PHP_INT_MAX) - ); - - $masked_bit = (self::BITFIELD_MASKED & ($this->masked ? PHP_INT_MAX : 0)); - - if ($this->length <= 125) { - $this->buffer[self::BYTE_INITIAL_LENGTH] = chr( - (self::BITFIELD_INITIAL_LENGTH & $this->length) | $masked_bit - ); - } elseif ($this->length <= 65536) { - $this->buffer[self::BYTE_INITIAL_LENGTH] = chr( - (self::BITFIELD_INITIAL_LENGTH & 126) | $masked_bit - ); - $this->buffer .= pack('n', $this->length); - } else { - $this->buffer[self::BYTE_INITIAL_LENGTH] = chr( - (self::BITFIELD_INITIAL_LENGTH & 127) | $masked_bit - ); - - if (PHP_INT_MAX > 2147483647) { - $this->buffer .= pack('NN', $this->length >> 32, $this->length); - // $this->buffer .= pack('I', $this->length); - } else { - $this->buffer .= pack('NN', 0, $this->length); - } - } - - if ($this->masked) { - $this->mask = $this->generateMask(); - $this->buffer .= $this->mask; - $this->buffer .= $this->mask($this->payload); - } else { - $this->buffer .= $this->payload; - } - - $this->offset_mask = $this->getMaskOffset(); - $this->offset_payload = $this->getPayloadOffset(); - - return $this; - } - - /** - * Masks/Unmasks the frame - * - * @param string $payload - * @return string - */ - protected function mask($payload) - { - $length = strlen($payload); - $mask = $this->getMask(); - - $unmasked = ''; - for ($i = 0; $i < $length; $i++) { - $unmasked .= $payload[$i] ^ $mask[$i % 4]; - } - - return $unmasked; - } - - /** - * Masks a payload - * - * @param string $payload - * @return string - */ - protected function unmask($payload) - { - return $this->mask($payload); - } - - public function receiveData($data) - { - if ($this->getBufferLength() <= self::BYTE_INITIAL_LENGTH) { - $this->length = null; - $this->offset_payload = null; - } - parent::receiveData($data); - } - - /** - * Gets the mask - * - * @throws FrameException - * @return string - */ - protected function getMask() - { - if (!isset($this->mask)) { - if (!$this->isMasked()) { - throw new FrameException('Cannot get mask: frame is not masked'); - } - $this->mask = substr($this->buffer, $this->getMaskOffset(), $this->getMaskSize()); - } - return $this->mask; - } - - /** - * Generates a suitable masking key - * - * @return string - */ - protected function generateMask() - { - if (extension_loaded('openssl')) { - return openssl_random_pseudo_bytes(4); - } else { - // SHA1 is 128 bit (= 16 bytes) - // So we pack it into 32 bits - return pack('N', sha1(spl_object_hash($this) . mt_rand(0, PHP_INT_MAX) . uniqid('', true), true)); - } - } - - /** - * Whether the frame is masked - * - * @return boolean - */ - public function isMasked() - { - if (!isset($this->masked)) { - if (!isset($this->buffer[1])) { - throw new FrameException('Cannot tell if frame is masked: not enough frame data received'); - } - $this->masked = (boolean)(ord($this->buffer[1]) & self::BITFIELD_MASKED); - } - return $this->masked; - } - - /** - * @see Wrench\Frame.Frame::getExpectedDataLength() - */ - protected function getExpectedBufferLength() - { - return $this->getLength() + $this->getPayloadOffset(); - } - - /** - * Gets the offset of the payload in the frame - * - * @return int - */ - protected function getPayloadOffset() - { - if (!isset($this->offset_payload)) { - $offset = $this->getMaskOffset(); - $offset += $this->getMaskSize(); - - $this->offset_payload = $offset; - } - return $this->offset_payload; - } - - /** - * Gets the offset in the frame to the masking bytes - * - * @return int - */ - protected function getMaskOffset() - { - if (!isset($this->offset_mask)) { - $offset = self::BYTE_INITIAL_LENGTH + 1; - $offset += $this->getLengthSize(); - - $this->offset_mask = $offset; - } - return $this->offset_mask; - } - - /** - * @see Wrench\Frame.Frame::getLength() - */ - public function getLength() - { - if (!$this->length) { - $initial = $this->getInitialLength(); - - if ($initial < 126) { - $this->length = $initial; - } elseif ($initial >= 126) { - // Extended payload length: 2 or 8 bytes - $start = self::BYTE_INITIAL_LENGTH + 1; - $end = self::BYTE_INITIAL_LENGTH + $this->getLengthSize(); - - if ($end > $this->getBufferLength()) { - throw new FrameException('Cannot get extended length: need more data'); - } - - $length = 0; - for ($i = $start; $i <= $end; $i++) { - $length <<= 8; - $length += ord($this->buffer[$i]); - } - - $this->length = $length; - } - } - return $this->length; - } - - /** - * Gets the inital length value, stored in the first length byte - * - * This determines how the rest of the length value is parsed out of the - * frame. - * - * @return int - */ - protected function getInitialLength() - { - if (!isset($this->buffer[self::BYTE_INITIAL_LENGTH])) { - throw new FrameException('Cannot yet tell expected length'); - } - $a = (int)(ord($this->buffer[self::BYTE_INITIAL_LENGTH]) & self::BITFIELD_INITIAL_LENGTH); - - return (int)(ord($this->buffer[self::BYTE_INITIAL_LENGTH]) & self::BITFIELD_INITIAL_LENGTH); - } - - /** - * Returns the byte size of the length part of the frame - * - * Not including the initial 7 bit part - * - * @return int - */ - protected function getLengthSize() - { - $initial = $this->getInitialLength(); - - if ($initial < 126) { - return 0; - } elseif ($initial === 126) { - return 2; - } elseif ($initial === 127) { - return 8; - } - } - - /** - * Returns the byte size of the mask part of the frame - * - * @return int - */ - protected function getMaskSize() - { - if ($this->isMasked()) { - return 4; - } - return 0; - } - - /** - * @see Wrench\Frame.Frame::decodeFramePayloadFromBuffer() - */ - protected function decodeFramePayloadFromBuffer() - { - $payload = substr($this->buffer, $this->getPayloadOffset()); - - if ($this->isMasked()) { - $payload = $this->unmask($payload); - } - - $this->payload = $payload; - } - - /** - * @see Wrench\Frame.Frame::isFinal() - */ - public function isFinal() - { - if (!isset($this->buffer[self::BYTE_HEADER])) { - throw new FrameException('Cannot yet tell if frame is final'); - } - return (boolean)(ord($this->buffer[self::BYTE_HEADER]) & self::BITFIELD_FINAL); - } - - /** - * @throws FrameException - * @see Wrench\Frame.Frame::getType() - */ - public function getType() - { - if (!isset($this->buffer[self::BYTE_HEADER])) { - throw new FrameException('Cannot yet tell type of frame'); - } - - $type = (int)(ord($this->buffer[self::BYTE_HEADER]) & self::BITFIELD_TYPE); - - if (!in_array($type, Protocol::$frameTypes)) { - throw new FrameException('Invalid payload type'); - } - - return $type; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Listener/HandshakeRequestListener.php b/core/lib/Wrench/Listener/HandshakeRequestListener.php deleted file mode 100755 index 9b5b841ee..000000000 --- a/core/lib/Wrench/Listener/HandshakeRequestListener.php +++ /dev/null @@ -1,19 +0,0 @@ -allowed = $allowed; - } - - /** - * Handshake request listener - * - * Closes the connection on handshake from an origin that isn't allowed - * - * @param Connection $connection - * @param string $path - * @param string $origin - * @param string $key - * @param array $extensions - */ - public function onHandshakeRequest(Connection $connection, $path, $origin, $key, $extensions) - { - if (!$this->isAllowed($origin)) { - $connection->close(new InvalidOriginException('Origin not allowed')); - } - } - - /** - * Whether the specified origin is allowed under this policy - * - * @param string $origin - * @return boolean - */ - public function isAllowed($origin) - { - $scheme = parse_url($origin, PHP_URL_SCHEME); - $host = parse_url($origin, PHP_URL_HOST) ?: $origin; - - foreach ($this->allowed as $allowed) { - $allowed_scheme = parse_url($allowed, PHP_URL_SCHEME); - - if ($allowed_scheme && $scheme != $allowed_scheme) { - continue; - } - - $allowed_host = parse_url($allowed, PHP_URL_HOST) ?: $allowed; - - if ($host != $allowed_host) { - continue; - } - - return true; - } - - return false; - } - - /** - * @param Server $server - */ - public function listen(Server $server) - { - $server->addListener( - Server::EVENT_HANDSHAKE_REQUEST, - array($this, 'onHandshakeRequest') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Listener/RateLimiter.php b/core/lib/Wrench/Listener/RateLimiter.php deleted file mode 100755 index 6ca0fe86e..000000000 --- a/core/lib/Wrench/Listener/RateLimiter.php +++ /dev/null @@ -1,230 +0,0 @@ - - */ - protected $ips = array(); - - /** - * Request tokens per IP address - * - * @var array> - */ - protected $requests = array(); - - /** - * Constructor - * - * @param array $options - */ - public function __construct(array $options = array()) - { - parent::__construct($options); - } - - /** - * @param array $options - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'connections' => 200, // Total - 'connections_per_ip' => 5, // At once - 'requests_per_minute' => 200 // Per connection - ), $options); - - parent::configure($options); - } - - /** - * @see Wrench\Listener.Listener::listen() - */ - public function listen(Server $server) - { - $this->server = $server; - - $server->addListener( - Server::EVENT_SOCKET_CONNECT, - array($this, 'onSocketConnect') - ); - - $server->addListener( - Server::EVENT_SOCKET_DISCONNECT, - array($this, 'onSocketDisconnect') - ); - - $server->addListener( - Server::EVENT_CLIENT_DATA, - array($this, 'onClientData') - ); - } - - /** - * Event listener - * - * @param resource $socket - * @param Connection $connection - */ - public function onSocketConnect($socket, $connection) - { - $this->checkConnections($connection); - $this->checkConnectionsPerIp($connection); - } - - /** - * Event listener - * - * @param resource $socket - * @param Connection $connection - */ - public function onSocketDisconnect($socket, $connection) - { - $this->releaseConnection($connection); - } - - /** - * Event listener - * - * @param resource $socket - * @param Connection $connection - */ - public function onClientData($socket, $connection) - { - $this->checkRequestsPerMinute($connection); - } - - /** - * Idempotent - * - * @param Connection $connection - */ - protected function checkConnections($connection) - { - $connections = $connection->getConnectionManager()->count(); - - if ($connections > $this->options['connections']) { - $this->limit($connection, 'Max connections'); - } - } - - /** - * NOT idempotent, call once per connection - * - * @param Connection $connection - */ - protected function checkConnectionsPerIp($connection) - { - $ip = $connection->getIp(); - - if (!$ip) { - $this->log('Cannot check connections per IP', 'warning'); - return; - } - - if (!isset($this->ips[$ip])) { - $this->ips[$ip] = 1; - } else { - $this->ips[$ip] = min( - $this->options['connections_per_ip'], - $this->ips[$ip] + 1 - ); - } - - if ($this->ips[$ip] > $this->options['connections_per_ip']) { - $this->limit($connection, 'Connections per IP'); - } - } - - /** - * NOT idempotent, call once per disconnection - * - * @param Connection $connection - */ - protected function releaseConnection($connection) - { - $ip = $connection->getIp(); - - if (!$ip) { - $this->log('Cannot release connection', 'warning'); - return; - } - - if (!isset($this->ips[$ip])) { - $this->ips[$ip] = 0; - } else { - $this->ips[$ip] = max(0, $this->ips[$ip] - 1); - } - - unset($this->requests[$connection->getId()]); - } - - /** - * NOT idempotent, call once per data - * - * @param Connection $connection - */ - protected function checkRequestsPerMinute($connection) - { - $id = $connection->getId(); - - if (!isset($this->requests[$id])) { - $this->requests[$id] = array(); - } - - // Add current token - $this->requests[$id][] = time(); - - // Expire old tokens - while (reset($this->requests[$id]) < time() - 60) { - array_shift($this->requests[$id]); - } - - if (count($this->requests[$id]) > $this->options['requests_per_minute']) { - $this->limit($connection, 'Requests per minute'); - } - } - - /** - * Limits the given connection - * - * @param Connection $connection - * @param string $limit Reason - */ - protected function limit($connection, $limit) - { - $this->log(sprintf( - 'Limiting connection %s: %s', - $connection->getIp(), - $limit - ), 'notice'); - - $connection->close(new RateLimiterException($limit)); - } - - /** - * Logger - * - * @param string $message - * @param string $priority - */ - public function log($message, $priority = 'info') - { - $this->server->log('RateLimiter: ' . $message, $priority); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Payload/HybiPayload.php b/core/lib/Wrench/Payload/HybiPayload.php deleted file mode 100755 index 92d4821ab..000000000 --- a/core/lib/Wrench/Payload/HybiPayload.php +++ /dev/null @@ -1,22 +0,0 @@ - - */ - protected $frames = array(); - - /** - * Gets the current frame for the payload - * - * @return mixed - */ - protected function getCurrentFrame() - { - if (empty($this->frames)) { - array_push($this->frames, $this->getFrame()); - } - return end($this->frames); - } - - /** - * Gets the frame into which data should be receieved - * - * @throws PayloadException - * @return Frame - */ - protected function getReceivingFrame() - { - $current = $this->getCurrentFrame(); - - if ($current->isComplete()) { - if ($current->isFinal()) { - throw new PayloadException('Payload cannot receieve data: it is already complete'); - } else { - $current = array_push($this->frames, $this->getFrame()); - } - } - - return $current; - } - - /** - * Get a frame object - * - * @return Frame - */ - abstract protected function getFrame(); - - /** - * Whether the payload is complete - * - * @return boolean - */ - public function isComplete() - { - return $this->getCurrentFrame()->isComplete() && $this->getCurrentFrame()->isFinal(); - } - - /** - * Encodes a payload - * - * @param string $data - * @param int $type - * @param boolean $masked - * @return Payload - * @todo No splitting into multiple frames just yet - */ - public function encode($data, $type = Protocol::TYPE_TEXT, $masked = false) - { - $this->frames = array(); - - $frame = $this->getFrame(); - array_push($this->frames, $frame); - - $frame->encode($data, $type, $masked); - - return $this; - } - - /** - * Gets the number of remaining bytes before this payload will be - * complete - * - * May return 0 (no more bytes required) or null (unknown number of bytes - * required). - * - * @return number|NULL - */ - public function getRemainingData() - { - if ($this->isComplete()) { - return 0; - } - - try { - if ($this->getCurrentFrame()->isFinal()) { - return $this->getCurrentFrame()->getRemainingData(); - } - } catch (FrameException $e) { - return null; - } - - return null; - } - - /** - * Whether this payload is waiting for more data - * - * @return boolean - */ - public function isWaitingForData() - { - return $this->getRemainingData() > 0; - } - - /** - * @param Socket $socket - * @return boolean - */ - public function sendToSocket(Socket $socket) - { - $success = true; - foreach ($this->frames as $frame) { - $success = $success && ($socket->send($frame->getFrameBuffer()) !== false); - } - return $success; - } - - /** - * Receive raw data into the payload - * - * @param string $data - * @return void - */ - public function receiveData($data) - { - while ($data) { - $frame = $this->getReceivingFrame(); - - $size = strlen($data); - $remaining = $frame->getRemainingData(); - - if ($remaining === null) { - $chunk_size = 2; - } elseif ($remaining > 0) { - $chunk_size = $remaining; - } - - $chunk_size = min(strlen($data), $chunk_size); - $chunk = substr($data, 0, $chunk_size); - $data = substr($data, $chunk_size); - - $frame->receiveData($chunk); - } - } - - /** - * @return string - */ - public function getPayload() - { - $this->buffer = ''; - - foreach ($this->frames as $frame) { - $this->buffer .= $frame->getFramePayload(); - } - - return $this->buffer; - } - - /** - * @return string - */ - public function __toString() - { - try { - return $this->getPayload(); - } catch (\Exception $e) { - // __toString must not throw an exception - return ''; - } - } - - /** - * Gets the type of the payload - * - * The type of a payload is taken from its first frame - * - * @throws PayloadException - * @return int - */ - public function getType() - { - if (!isset($this->frames[0])) { - throw new PayloadException('Cannot tell payload type yet'); - } - return $this->frames[0]->getType(); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Payload/PayloadHandler.php b/core/lib/Wrench/Payload/PayloadHandler.php deleted file mode 100755 index 2be036ff1..000000000 --- a/core/lib/Wrench/Payload/PayloadHandler.php +++ /dev/null @@ -1,110 +0,0 @@ -callback = $callback; - } - - /** - * Handles the raw socket data given - * - * @param string $data - */ - public function handle($data) - { - if (!$this->payload) { - $this->payload = $this->protocol->getPayload(); - } - - while ($data) { // Each iteration pulls off a single payload chunk - $size = strlen($data); - $remaining = $this->payload->getRemainingData(); - - // If we don't yet know how much data is remaining, read data into - // the payload in two byte chunks (the size of a WebSocket frame - // header to get the initial length) - // - // Then re-loop. For extended lengths, this will happen once or four - // times extra, as the extended length is read in. - if ($remaining === null) { - $chunk_size = 2; - } elseif ($remaining > 0) { - $chunk_size = $remaining; - } elseif ($remaining === 0) { - $chunk_size = 0; - } - - $chunk_size = min(strlen($data), $chunk_size); - $chunk = substr($data, 0, $chunk_size); - $data = substr($data, $chunk_size); - - $this->payload->receiveData($chunk); - - if ($remaining !== 0 && !$this->payload->isComplete()) { - continue; - } - - if ($this->payload->isComplete()) { - $this->emit($this->payload); - $this->payload = $this->protocol->getPayload(); - } else { - throw new PayloadException('Payload will not complete'); - } - } - } - - /** - * Get the current payload - * - * @return Payload - */ - public function getCurrent() - { - return $this->getPayloadHandler->getCurrent(); - } - - /** - * Emits a complete payload to the callback - * - * @param Payload $payload - */ - protected function emit(Payload $payload) - { - call_user_func($this->callback, $payload); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Protocol/Hybi10Protocol.php b/core/lib/Wrench/Protocol/Hybi10Protocol.php deleted file mode 100755 index 33cfe15e3..000000000 --- a/core/lib/Wrench/Protocol/Hybi10Protocol.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) { - return true; - } - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Protocol/HybiProtocol.php b/core/lib/Wrench/Protocol/HybiProtocol.php deleted file mode 100755 index 1d73c2fab..000000000 --- a/core/lib/Wrench/Protocol/HybiProtocol.php +++ /dev/null @@ -1,24 +0,0 @@ - - */ - protected static $schemes = array( - self::SCHEME_WEBSOCKET, - self::SCHEME_WEBSOCKET_SECURE, - self::SCHEME_UNDERLYING, - self::SCHEME_UNDERLYING_SECURE - ); - - /** - * Close status codes - * - * @var array string> - */ - public static $closeReasons = array( - self::CLOSE_NORMAL => 'normal close', - self::CLOSE_GOING_AWAY => 'going away', - self::CLOSE_PROTOCOL_ERROR => 'protocol error', - self::CLOSE_DATA_INVALID => 'data invalid', - self::CLOSE_DATA_INCONSISTENT => 'data inconsistent', - self::CLOSE_POLICY_VIOLATION => 'policy violation', - self::CLOSE_MESSAGE_TOO_BIG => 'message too big', - self::CLOSE_EXTENSION_NEEDED => 'extension needed', - self::CLOSE_UNEXPECTED => 'unexpected error', - self::CLOSE_RESERVED => null, // Don't use these! - self::CLOSE_RESERVED_NONE => null, - self::CLOSE_RESERVED_ABNORM => null, - self::CLOSE_RESERVED_TLS => null - ); - - /** - * Frame types - * - * @todo flip values and keys? - * @var array int> - */ - public static $frameTypes = array( - 'continuation' => self::TYPE_CONTINUATION, - 'text' => self::TYPE_TEXT, - 'binary' => self::TYPE_BINARY, - 'close' => self::TYPE_CLOSE, - 'ping' => self::TYPE_PING, - 'pong' => self::TYPE_PONG - ); - - /** - * HTTP errors - * - * @var array string> - */ - public static $httpResponses = array( - self::HTTP_SWITCHING_PROTOCOLS => 'Switching Protocols', - self::HTTP_BAD_REQUEST => 'Bad Request', - self::HTTP_UNAUTHORIZED => 'Unauthorized', - self::HTTP_FORBIDDEN => 'Forbidden', - self::HTTP_NOT_FOUND => 'Not Found', - self::HTTP_NOT_IMPLEMENTED => 'Not Implemented', - self::HTTP_RATE_LIMITED => 'Enhance Your Calm' - ); - - /** - * Gets a version number - * - * @return - */ - abstract public function getVersion(); - - /** - * Subclasses should implement this method and return a boolean to the given - * version string, as to whether they would like to accept requests from - * user agents that specify that version. - * - * @return boolean - */ - abstract public function acceptsVersion($version); - - /** - * Gets a payload instance, suitable for use in decoding/encoding protocol - * frames - * - * @return Payload - */ - abstract public function getPayload(); - - /** - * Generates a key suitable for use in the protocol - * - * This base implementation returns a 16-byte (128 bit) random key as a - * binary string. - * - * @return string - */ - public function generateKey() - { - if (extension_loaded('openssl')) { - $key = openssl_random_pseudo_bytes(16); - } else { - // SHA1 is 128 bit (= 16 bytes) - $key = sha1(spl_object_hash($this) . mt_rand(0, PHP_INT_MAX) . uniqid('', true), true); - } - - return base64_encode($key); - } - - /** - * Gets request handshake string - * - * The leading line from the client follows the Request-Line format. - * The leading line from the server follows the Status-Line format. The - * Request-Line and Status-Line productions are defined in [RFC2616]. - * - * An unordered set of header fields comes after the leading line in - * both cases. The meaning of these header fields is specified in - * Section 4 of this document. Additional header fields may also be - * present, such as cookies [RFC6265]. The format and parsing of - * headers is as defined in [RFC2616]. - * - * @param string $uri WebSocket URI, e.g. ws://example.org:8000/chat - * @param string $key 16 byte binary string key - * @param string $origin Origin of the request - * @return string - */ - public function getRequestHandshake( - $uri, - $key, - $origin, - array $headers = array() - ) { - if (!$uri || !$key || !$origin) { - throw new InvalidArgumentException('You must supply a URI, key and origin'); - } - - list($scheme, $host, $port, $path) = self::validateUri($uri); - - $handshake = array( - sprintf(self::REQUEST_LINE_FORMAT, $path) - ); - - $headers = array_merge( - $this->getDefaultRequestHeaders( - $host . ':' . $port, $key, $origin - ), - $headers - ); - - foreach ($headers as $name => $value) { - $handshake[] = sprintf(self::HEADER_LINE_FORMAT, $name, $value); - } - return implode($handshake, "\r\n") . "\r\n\r\n"; - } - - /** - * Gets a handshake response body - * - * @param string $key - * @param array $headers - */ - public function getResponseHandshake($key, array $headers = array()) - { - $headers = array_merge( - $this->getSuccessResponseHeaders( - $key - ), - $headers - ); - - return $this->getHttpResponse(self::HTTP_SWITCHING_PROTOCOLS, $headers); - } - - /** - * Gets a response to an error in the handshake - * - * @param int|Exception $e Exception or HTTP error - * @param array $headers - */ - public function getResponseError($e, array $headers = array()) - { - $code = false; - - if ($e instanceof Exception) { - $code = $e->getCode(); - } elseif (is_numeric($e)) { - $code = (int)$e; - } - - if (!$code || $code < 400 || $code > 599) { - $code = self::HTTP_SERVER_ERROR; - } - - return $this->getHttpResponse($code, $headers); - } - - /** - * Gets an HTTP response - * - * @param int $status - * @param array $headers - */ - protected function getHttpResponse($status, array $headers = array()) - { - if (array_key_exists($status, self::$httpResponses)) { - $response = self::$httpResponses[$status]; - } else { - $response = self::$httpResponses[self::HTTP_NOT_IMPLEMENTED]; - } - - $handshake = array( - sprintf(self::RESPONSE_LINE_FORMAT, $status, $response) - ); - - foreach ($headers as $name => $value) { - $handshake[] = sprintf(self::HEADER_LINE_FORMAT, $name, $value); - } - - return implode($handshake, "\r\n") . "\r\n\r\n"; - } - - /** - * @todo better header handling - * @todo throw exception - * @param unknown_type $response - * @param unknown_type $key - * @return boolean - */ - public function validateResponseHandshake($response, $key) - { - if (!$response) { - return false; - } - - $headers = $this->getHeaders($response); - - if (!isset($headers[self::HEADER_ACCEPT])) { - throw new HandshakeException('No accept header receieved on handshake response'); - } - - $accept = $headers[self::HEADER_ACCEPT]; - - if (!$accept) { - throw new HandshakeException('Invalid accept header'); - } - - $expected = $this->getAcceptValue($key); - - preg_match('#Sec-WebSocket-Accept:\s(.*)$#mU', $response, $matches); - $keyAccept = trim($matches[1]); - - return ($keyAccept === $this->getEncodedHash($key)) ? true : false; - } - - /** - * Gets an encoded hash for a key - * - * @param string $key - * @return string - */ - public function getEncodedHash($key) - { - return base64_encode(pack('H*', sha1($key . self::MAGIC_GUID))); - } - - /** - * Validates a request handshake - * - * @param string $request - * @throws BadRequestException - */ - public function validateRequestHandshake( - $request - ) { - if (!$request) { - return false; - } - - list($request, $headers) = $this->getRequestHeaders($request); - // make a copy of the headers array to store all extra headers - $extraHeaders = $headers; - - // parse the resulting url to separate query parameters from the path - $url = parse_url($this->validateRequestLine($request)); - $path = isset($url['path']) ? $url['path'] : null; - $urlParams = array(); - if (isset($url['query'])) { - parse_str($url['query'], $urlParams); - } - - if (empty($headers[self::HEADER_ORIGIN])) { - throw new BadRequestException('No origin header'); - } else { - unset($extraHeaders[self::HEADER_ORIGIN]); - } - - $origin = $headers[self::HEADER_ORIGIN]; - - if (!isset($headers[self::HEADER_UPGRADE]) - || strtolower($headers[self::HEADER_UPGRADE]) != self::UPGRADE_VALUE - ) { - throw new BadRequestException('Invalid upgrade header'); - } else { - unset($extraHeaders[self::HEADER_UPGRADE]); - } - - if (!isset($headers[self::HEADER_CONNECTION]) - || stripos($headers[self::HEADER_CONNECTION], self::CONNECTION_VALUE) === false - ) { - throw new BadRequestException('Invalid connection header'); - } else { - unset($extraHeaders[self::HEADER_CONNECTION]); - } - - if (!isset($headers[self::HEADER_HOST])) { - // @todo Validate host == listening socket? Or would that break - // TCP proxies? - throw new BadRequestException('No host header'); - } else { - unset($extraHeaders[self::HEADER_HOST]); - } - - if (!isset($headers[self::HEADER_VERSION])) { - throw new BadRequestException('No version header received on handshake request'); - } - - if (!$this->acceptsVersion($headers[self::HEADER_VERSION])) { - throw new BadRequestException('Unsupported version: ' . $version); - } else { - unset($extraHeaders[self::HEADER_VERSION]); - } - - if (!isset($headers[self::HEADER_KEY])) { - throw new BadRequestException('No key header received'); - } - - $key = trim($headers[self::HEADER_KEY]); - - if (!$key) { - throw new BadRequestException('Invalid key'); - } else { - unset($extraHeaders[self::HEADER_KEY]); - } - - // Optional - $protocol = null; - if (isset($headers[self::HEADER_PROTOCOL])) { - $protocol = $headers[self::HEADER_PROTOCOL]; - unset($extraHeaders[self::HEADER_PROTOCOL]); - } - - $extensions = array(); - if (!empty($headers[self::HEADER_EXTENSIONS])) { - $extensions = $headers[self::HEADER_EXTENSIONS]; - if (is_scalar($extensions)) { - $extensions = array($extensions); - } - } - unset($extraHeaders[self::HEADER_EXTENSIONS]); - - return array($path, $origin, $key, $extensions, $protocol, $extraHeaders, $urlParams); - } - - /** - * Gets a suitable WebSocket close frame - * - * @param Exception|int $e - */ - public function getCloseFrame($e) - { - $code = false; - - if ($e instanceof Exception) { - $code = $e->getCode(); - } elseif (is_numeric($e)) { - $code = (int)$e; - } - - if (!$code || !key_exists($code, self::$closeReasons)) { - $code = self::CLOSE_UNEXPECTED; - } - - $body = pack('n', $code) . self::$closeReasons[$code]; - - $payload = $this->getPayload(); - return $payload->encode($body, self::TYPE_CLOSE); - } - - /** - * Validates a WebSocket URI - * - * @param string $uri - * @return array(string $scheme, string $host, int $port, string $path) - */ - public function validateUri($uri) - { - $uri = (string)$uri; - if (!$uri) { - throw new InvalidArgumentException('Invalid URI'); - } - - $scheme = parse_url($uri, PHP_URL_SCHEME); - $this->validateScheme($scheme); - - $host = parse_url($uri, PHP_URL_HOST); - if (!$host) { - throw new InvalidArgumentException("Invalid host"); - } - - $port = parse_url($uri, PHP_URL_PORT); - if (!$port) { - $port = $this->getPort($scheme); - } - - $path = parse_url($uri, PHP_URL_PATH); - if (!$path) { - throw new InvalidArgumentException('Invalid path'); - } - - return array($scheme, $host, $port, $path); - } - - /** - * Validates a socket URI - * - * @param string $uri - * @throws InvalidArgumentException - * @return array(string $scheme, string $host, string $port) - */ - public function validateSocketUri($uri) - { - $uri = (string)$uri; - if (!$uri) { - throw new InvalidArgumentException('Invalid URI'); - } - - $scheme = parse_url($uri, PHP_URL_SCHEME); - $scheme = $this->validateScheme($scheme); - - $host = parse_url($uri, PHP_URL_HOST); - if (!$host) { - throw new InvalidArgumentException("Invalid host"); - } - - $port = parse_url($uri, PHP_URL_PORT); - if (!$port) { - $port = $this->getPort($scheme); - } - - return array($scheme, $host, $port); - } - - /** - * Validates an origin URI - * - * @param string $origin - * @throws InvalidArgumentException - * @return string - */ - public function validateOriginUri($origin) - { - $origin = (string)$origin; - if (!$origin) { - throw new InvalidArgumentException('Invalid URI'); - } - - $scheme = parse_url($origin, PHP_URL_SCHEME); - if (!$scheme) { - throw new InvalidArgumentException('Invalid scheme'); - } - - $host = parse_url($origin, PHP_URL_HOST); - if (!$host) { - throw new InvalidArgumentException("Invalid host"); - } - - return $origin; - } - - /** - * Validates a request line - * - * @param string $line - * @throws BadRequestException - */ - protected function validateRequestLine($line) - { - $matches = array(0 => null, 1 => null); - - if (!preg_match(self::REQUEST_LINE_REGEX, $line, $matches) || !$matches[1]) { - throw new BadRequestException('Invalid request line', 400); - } - - return $matches[1]; - } - - /** - * Gets the expected accept value for a handshake response - * - * Note that the protocol calls for the base64 encoded value to be hashed, - * not the original 16 byte random key. - * - * @see http://tools.ietf.org/html/rfc6455#section-4.2.2 - * @param string $key - */ - protected function getAcceptValue($encoded_key) - { - return base64_encode(sha1($encoded_key . self::MAGIC_GUID, true)); - } - - /** - * Gets the headers from a full response - * - * @param string $response - * @return array() - * @throws InvalidArgumentException - */ - protected function getHeaders($response, &$request_line = null) - { - $parts = explode("\r\n\r\n", $response, 2); - - if (count($parts) != 2) { - $parts = array($parts, ''); - } - - list($headers, $body) = $parts; - - $return = array(); - foreach (explode("\r\n", $headers) as $header) { - $parts = explode(': ', $header, 2); - if (count($parts) == 2) { - list($name, $value) = $parts; - if (!isset($return[$name])) { - $return[$name] = $value; - } else { - if (is_array($return[$name])) { - $return[$name][] = $value; - } else { - $return[$name] = array($return[$name], $value); - } - } - } - } - - return $return; - } - - /** - * Gets request headers - * - * @param string $response - * @return array> The request line, and an array of - * headers - * @throws InvalidArgumentException - */ - protected function getRequestHeaders($response) - { - $eol = stripos($response, "\r\n"); - - if ($eol === false) { - throw new InvalidArgumentException('Invalid request line'); - } - - $request = substr($response, 0, $eol); - $headers = $this->getHeaders(substr($response, $eol + 2)); - - return array($request, $headers); - } - - /** - * Validates a scheme - * - * @param string $scheme - * @return string Underlying scheme - * @throws InvalidArgumentException - */ - protected function validateScheme($scheme) - { - if (!$scheme) { - throw new InvalidArgumentException('No scheme specified'); - } - if (!in_array($scheme, self::$schemes)) { - throw new InvalidArgumentException( - 'Unknown socket scheme: ' . $scheme - ); - } - - if ($scheme == self::SCHEME_WEBSOCKET_SECURE) { - return self::SCHEME_UNDERLYING_SECURE; - } - return self::SCHEME_UNDERLYING; - } - - /** - * Gets the default request headers - * - * @param string $host - * @param string $key - * @param string $origin - * @param int $version - * @return multitype:unknown string NULL - */ - protected function getDefaultRequestHeaders($host, $key, $origin) - { - return array( - self::HEADER_HOST => $host, - self::HEADER_UPGRADE => self::UPGRADE_VALUE, - self::HEADER_CONNECTION => self::CONNECTION_VALUE, - self::HEADER_KEY => $key, - self::HEADER_ORIGIN => $origin, - self::HEADER_VERSION => $this->getVersion() - ); - } - - /** - * Gets the default response headers - * - * @param string $key - */ - protected function getSuccessResponseHeaders($key) - { - return array( - self::HEADER_UPGRADE => self::UPGRADE_VALUE, - self::HEADER_CONNECTION => self::CONNECTION_VALUE, - self::HEADER_ACCEPT => $this->getAcceptValue($key) - ); - } - - /** - * Gets the default port for a scheme - * - * By default, the WebSocket Protocol uses port 80 for regular WebSocket - * connections and port 443 for WebSocket connections tunneled over - * Transport Layer Security - * - * @param string $uri - * @return int - */ - protected function getPort($scheme) - { - if ($scheme == self::SCHEME_WEBSOCKET) { - return 80; - } elseif ($scheme == self::SCHEME_WEBSOCKET_SECURE) { - return 443; - } elseif ($scheme == self::SCHEME_UNDERLYING) { - return 80; - } elseif ($scheme == self::SCHEME_UNDERLYING_SECURE) { - return 443; - } else { - throw new InvalidArgumentException('Unknown websocket scheme'); - } - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Protocol/Rfc6455Protocol.php b/core/lib/Wrench/Protocol/Rfc6455Protocol.php deleted file mode 100755 index b0f5c5289..000000000 --- a/core/lib/Wrench/Protocol/Rfc6455Protocol.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @author Simon Samtleben - * @author Dominic Scheirlinck - */ -class Server extends Configurable -{ - /**#@+ - * Events - * - * @var string - */ - const EVENT_SOCKET_CONNECT = 'socket_connect'; - const EVENT_SOCKET_DISCONNECT = 'socket_disconnect'; - const EVENT_HANDSHAKE_REQUEST = 'handshake_request'; - const EVENT_HANDSHAKE_SUCCESSFUL = 'handshake_successful'; - const EVENT_CLIENT_DATA = 'client_data'; - /**#@-*/ - - /** - * The URI of the server - * - * @var string - */ - protected $uri; - - /** - * Options - * - * @var array - */ - protected $options = array(); - - /** - * A logging callback - * - * The default callback simply prints to stdout. You can pass your own logger - * in the options array. It should take a string message and string priority - * as parameters. - * - * @var Closure - */ - protected $logger; - - /** - * Event listeners - * - * Add listeners using the addListener() method. - * - * @var array array> - */ - protected $listeners = array(); - - /** - * Connection manager - * - * @var ConnectionManager - */ - protected $connectionManager; - - /** - * Applications - * - * @var array Application> - */ - protected $applications = array(); - - /** - * Constructor - * - * @param string $uri Websocket URI, e.g. ws://localhost:8000/, path will - * be ignored - * @param array $options (optional) See configure - */ - public function __construct($uri, array $options = array()) - { - $this->uri = $uri; - - parent::__construct($options); - - $this->log('Server initialized', 'info'); - } - - /** - * Configure options - * - * Options include - * - socket_class => The socket class to use, defaults to ServerSocket - * - socket_options => An array of socket options - * - logger => Closure($message, $priority = 'info'), used - * for logging - * - * @param array $options - * @return void - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'connection_manager_class' => 'Wrench\ConnectionManager', - 'connection_manager_options' => array() - ), $options); - - parent::configure($options); - - $this->configureConnectionManager(); - $this->configureLogger(); - } - - /** - * Configures the logger - * - * @return void - */ - protected function configureLogger() - { - // Default logger - if (!isset($this->options['logger'])) { - $this->options['logger'] = function ($message, $priority = 'info') { - printf("%s: %s%s", $priority, $message, PHP_EOL); - }; - } - $this->setLogger($this->options['logger']); - } - - /** - * Configures the connection manager - * - * @return void - */ - protected function configureConnectionManager() - { - $class = $this->options['connection_manager_class']; - $options = $this->options['connection_manager_options']; - $this->connectionManager = new $class($this, $options); - } - - /** - * Gets the connection manager - * - * @return \Wrench\ConnectionManager - */ - public function getConnectionManager() - { - return $this->connectionManager; - } - - /** - * @return string - */ - public function getUri() - { - return $this->uri; - } - - /** - * Sets a logger - * - * @param Closure $logger - * @return void - */ - public function setLogger($logger) - { - if (!is_callable($logger)) { - throw new \InvalidArgumentException('Logger must be callable'); - } - $this->logger = $logger; - } - - /** - * Main server loop - * - * @return void This method does not return! - */ - public function run() - { - $this->connectionManager->listen(); - - while (true) { - /* - * If there's nothing changed on any of the sockets, the server - * will sleep and other processes will have a change to run. Control - * this behaviour with the timeout options. - */ - $this->connectionManager->selectAndProcess(); - - /* - * If the application wants to perform periodic operations or queries and push updates to clients based on the result then that logic can be implemented in the 'onUpdate' method. - */ - foreach($this->applications as $application) { - if(method_exists($application, 'onUpdate')) { - $application->onUpdate(); - } - } - } - } - - /** - * Logs a message to the server log - * - * The default logger simply prints the message to stdout. You can provide - * a logging closure. This is useful, for instance, if you've daemonized - * and closed STDOUT. - * - * @param string $message Message to display. - * @param string $type Type of message. - * @return void - */ - public function log($message, $priority = 'info') - { - call_user_func($this->logger, $message, $priority); - } - - /** - * Notifies listeners of an event - * - * @param string $event - * @param array $arguments Event arguments - * @return void - */ - public function notify($event, array $arguments = array()) - { - if (!isset($this->listeners[$event])) { - return; - } - - foreach ($this->listeners[$event] as $listener) { - call_user_func_array($listener, $arguments); - } - } - - /** - * Adds a listener - * - * Provide an event (see the Server::EVENT_* constants) and a callback - * closure. Some arguments may be provided to your callback, such as the - * connection the caused the event. - * - * @param string $event - * @param Closure $callback - * @return void - * @throws InvalidArgumentException - */ - public function addListener($event, $callback) - { - if (!isset($this->listeners[$event])) { - $this->listeners[$event] = array(); - } - - if (!is_callable($callback)) { - throw new InvalidArgumentException('Invalid listener'); - } - - $this->listeners[$event][] = $callback; - } - - /** - * Returns a server application. - * - * @param string $key Name of application. - * @return Application The application object. - */ - public function getApplication($key) - { - if (empty($key)) { - return false; - } - - if (array_key_exists($key, $this->applications)) { - return $this->applications[$key]; - } - - return false; - } - - /** - * Adds a new application object to the application storage. - * - * @param string $key Name of application. - * @param object $application The application object - * @return void - */ - public function registerApplication($key, $application) - { - $this->applications[$key] = $application; - } -} diff --git a/core/lib/Wrench/Socket/ClientSocket.php b/core/lib/Wrench/Socket/ClientSocket.php deleted file mode 100755 index 9f5fbe293..000000000 --- a/core/lib/Wrench/Socket/ClientSocket.php +++ /dev/null @@ -1,105 +0,0 @@ - int, seconds, default 2 - */ -class ClientSocket extends UriSocket -{ - /** - * Default connection timeout - * - * @var int seconds - */ - const TIMEOUT_CONNECT = 2; - - /** - * @see Wrench\Socket.Socket::configure() - * Options include: - * - ssl_verify_peer => boolean, whether to perform peer verification - * of SSL certificate used - * - ssl_allow_self_signed => boolean, whether ssl_verify_peer allows - * self-signed certs - * - timeout_connect => int, seconds, default 2 - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'timeout_connect' => self::TIMEOUT_CONNECT, - 'ssl_verify_peer' => false, - 'ssl_allow_self_signed' => true - ), $options); - - parent::configure($options); - } - - /** - * Connects to the given socket - */ - public function connect() - { - if ($this->isConnected()) { - return true; - } - - $errno = null; - $errstr = null; - - $this->socket = stream_socket_client( - $this->getUri(), - $errno, - $errstr, - $this->options['timeout_connect'], - STREAM_CLIENT_CONNECT, - $this->getStreamContext() - ); - - if (!$this->socket) { - throw new \Wrench\Exception\ConnectionException(sprintf( - 'Could not connect to socket: %s (%d)', - $errstr, - $errno - )); - } - - stream_set_timeout($this->socket, $this->options['timeout_socket']); - - return ($this->connected = true); - } - - public function reconnect() - { - $this->disconnect(); - $this->connect(); - } - - /** - * @see Wrench\Socket.UriSocket::getSocketStreamContextOptions() - */ - protected function getSocketStreamContextOptions() - { - $options = array(); - return $options; - } - - /** - * @see Wrench\Socket.UriSocket::getSslStreamContextOptions() - */ - protected function getSslStreamContextOptions() - { - $options = array(); - - if ($this->options['ssl_verify_peer']) { - $options['verify_peer'] = true; - } - - if ($this->options['ssl_allow_self_signed']) { - $options['allow_self_signed'] = true; - } - - return $options; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Socket/ServerClientSocket.php b/core/lib/Wrench/Socket/ServerClientSocket.php deleted file mode 100755 index 61583f6cc..000000000 --- a/core/lib/Wrench/Socket/ServerClientSocket.php +++ /dev/null @@ -1,25 +0,0 @@ -connect() or whatnot. - * - * @param resource $accepted_socket - * @param array $options - */ - public function __construct($accepted_socket, array $options = array()) - { - parent::__construct($options); - - $this->socket = $accepted_socket; - $this->connected = (boolean)$accepted_socket; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Socket/ServerSocket.php b/core/lib/Wrench/Socket/ServerSocket.php deleted file mode 100755 index facb89f86..000000000 --- a/core/lib/Wrench/Socket/ServerSocket.php +++ /dev/null @@ -1,126 +0,0 @@ - int, used to limit the number of outstanding - * connections in the socket's listen queue - * - ssl_cert_file => string, server SSL certificate - * file location. File should contain - * certificate and private key - * - ssl_passphrase => string, passphrase for the key - * - timeout_accept => int, seconds, default 5 - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'backlog' => 50, - 'ssl_cert_file' => null, - 'ssl_passphrase' => null, - 'ssl_allow_self_signed' => false, - 'timeout_accept' => self::TIMEOUT_ACCEPT - ), $options); - - parent::configure($options); - } - - /** - * Listens - * - * @throws ConnectionException - */ - public function listen() - { - $this->socket = stream_socket_server( - $this->getUri(), - $errno, - $errstr, - STREAM_SERVER_BIND|STREAM_SERVER_LISTEN. - $this->getStreamContext() - ); - - if (!$this->socket) { - throw new ConnectionException(sprintf( - 'Could not listen on socket: %s (%d)', - $errstr, - $errno - )); - } - - $this->listening = true; - } - - /** - * Accepts a new connection on the socket - * - * @throws ConnectionException - * @return resource - */ - public function accept() - { - $new = stream_socket_accept( - $this->socket, - $this->options['timeout_accept'] - ); - - if (!$new) { - throw new ConnectionException(socket_strerror(socket_last_error($new))); - } - - return $new; - } - - /** - * @see Wrench\Socket.UriSocket::getSocketStreamContextOptions() - */ - protected function getSocketStreamContextOptions() - { - $options = array(); - - if ($this->options['backlog']) { - $options['backlog'] = $this->options['backlog']; - } - - return $options; - } - - /** - * @see Wrench\Socket.UriSocket::getSslStreamContextOptions() - */ - protected function getSslStreamContextOptions() - { - $options = array(); - - if ($this->options['server_ssl_cert_file']) { - $options['local_cert'] = $this->options['server_ssl_cert_file']; - if ($this->options['server_ssl_passphrase']) { - $options['passphrase'] = $this->options['server_ssl_passphrase']; - } - } - - return $options; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Socket/Socket.php b/core/lib/Wrench/Socket/Socket.php deleted file mode 100755 index 97f6b28cc..000000000 --- a/core/lib/Wrench/Socket/Socket.php +++ /dev/null @@ -1,322 +0,0 @@ - int, seconds, default 2 - * - timeout_socket => int, seconds, default 5 - * - * @param array $options - * @return void - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'timeout_socket' => self::TIMEOUT_SOCKET, - ), $options); - - parent::configure($options); - } - - /** - * Gets the name of the socket - */ - protected function getName() - { - if (!isset($this->name) || !$this->name) { - $this->name = @stream_socket_get_name($this->socket, true); - } - return $this->name; - } - - /** - * Gets part of the name of the socket - * - * PHP seems to return IPV6 address/port combos like this: - * ::1:1234, where ::1 is the address and 1234 the port - * So, the part number here is either the last : delimited section (the port) - * or all the other sections (the whole initial part, the address). - * - * @param string $name (from $this->getName() usually) - * @param int<0, 1> $part - * @return string - * @throws SocketException - */ - public static function getNamePart($name, $part) - { - if (!$name) { - throw new InvalidArgumentException('Invalid name'); - } - - $parts = explode(':', $name); - - if (count($parts) < 2) { - throw new SocketException('Could not parse name parts: ' . $name); - } - - if ($part == self::NAME_PART_PORT) { - return end($parts); - } elseif ($part == self::NAME_PART_IP) { - return implode(':', array_slice($parts, 0, -1)); - } else { - throw new InvalidArgumentException('Invalid name part'); - } - - return null; - } - - /** - * Gets the IP address of the socket - * - * @return string - */ - public function getIp() - { - $name = $this->getName(); - - if ($name) { - return self::getNamePart($name, self::NAME_PART_IP); - } else { - throw new SocketException('Cannot get socket IP address'); - } - } - - /** - * Gets the port of the socket - * - * @return int - */ - public function getPort() - { - $name = $this->getName(); - - if ($name) { - return self::getNamePart($name, self::NAME_PART_PORT); - } else { - throw new SocketException('Cannot get socket IP address'); - } - } - - /** - * Get the last error that occurred on the socket - * - * @return int|string - */ - public function getLastError() - { - if ($this->isConnected() && $this->socket) { - $err = @socket_last_error($this->socket); - if ($err) { - $err = socket_strerror($err); - } - if (!$err) { - $err = 'Unknown error'; - } - return $err; - } else { - return 'Not connected'; - } - } - - /** - * Whether the socket is currently connected - * - * @return boolean - */ - public function isConnected() - { - return $this->connected; - } - - /** - * Disconnect the socket - * - * @return void - */ - public function disconnect() - { - if ($this->socket) { - stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR); - } - $this->socket = null; - $this->connected = false; - } - - /** - * @see Wrench.Resource::getResource() - */ - public function getResource() - { - return $this->socket; - } - - /** - * @see Wrench.Resource::getResourceId() - */ - public function getResourceId() - { - return (int)$this->socket; - } - - /** - * @param unknown_type $data - * @throws SocketException - * @return boolean|int The number of bytes sent or false on error - */ - public function send($data) - { - if (!$this->isConnected()) { - throw new SocketException('Socket is not connected'); - } - - $length = strlen($data); - - if ($length == 0) { - return 0; - } - - for ($i = $length; $i > 0; $i -= $written) { - $written = @fwrite($this->socket, substr($data, -1 * $i)); - - if ($written === false) { - return false; - } elseif ($written === 0) { - return false; - } - } - - return $length; - } - - /** - * Receive data from the socket - * - * @param int $length - * @return string - */ - public function receive($length = self::DEFAULT_RECEIVE_LENGTH) - { - $remaining = $length; - - $buffer = ''; - $metadata['unread_bytes'] = 0; - - do { - if (feof($this->socket)) { - return $buffer; - } - - $result = fread($this->socket, $length); - - if ($result === false) { - return $buffer; - } - - $buffer .= $result; - - if (feof($this->socket)) { - return $buffer; - } - - $continue = false; - - if ($this->firstRead == true && strlen($result) == 1) { - // Workaround Chrome behavior (still needed?) - $continue = true; - } - $this->firstRead = false; - - if (strlen($result) == $length) { - $continue = true; - } - - // Continue if more data to be read - $metadata = stream_get_meta_data($this->socket); - if ($metadata && isset($metadata['unread_bytes']) && $metadata['unread_bytes']) { - $continue = true; - $length = $metadata['unread_bytes']; - } - } while ($continue); - - return $buffer; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Socket/UriSocket.php b/core/lib/Wrench/Socket/UriSocket.php deleted file mode 100755 index 8e1cbc047..000000000 --- a/core/lib/Wrench/Socket/UriSocket.php +++ /dev/null @@ -1,118 +0,0 @@ - Wrench\Protocol object, latest protocol - * version used if not specified - * - timeout_socket => int, seconds, default 5 - * - server_ssl_cert_file => string, server SSL certificate - * file location. File should contain - * certificate and private key - * - server_ssl_passphrase => string, passphrase for the key - * - server_ssl_allow_self_signed => boolean, whether to allows self- - * signed certs - */ - public function __construct($uri, array $options = array()) - { - parent::__construct($options); - - list($this->scheme, $this->host, $this->port) - = $this->protocol->validateSocketUri($uri); - } - - /** - * Gets the canonical/normalized URI for this socket - * - * @return string - */ - protected function getUri() - { - return sprintf( - '%s://%s:%d', - $this->scheme, - $this->host, - $this->port - ); - } - - /** - * @todo DNS lookup? Override getIp()? - * @see Wrench\Socket.Socket::getName() - */ - protected function getName() - { - return sprintf('%s:%s', $this->host, $this->port); - } - - /** - * Gets the host name - */ - public function getHost() - { - return $this->host; - } - - /** - * @see Wrench\Socket.Socket::getPort() - */ - public function getPort() - { - return $this->port; - } - - /** - * Gets a stream context - */ - protected function getStreamContext($listen = false) - { - $options = array(); - - if ($this->scheme == Protocol::SCHEME_UNDERLYING_SECURE - || $this->scheme == Protocol::SCHEME_UNDERLYING) { - $options['socket'] = $this->getSocketStreamContextOptions(); - } - - if ($this->scheme == Protocol::SCHEME_UNDERLYING_SECURE) { - $options['ssl'] = $this->getSslStreamContextOptions(); - } - - return stream_context_create( - $options, - array() - ); - } - - /** - * Returns an array of socket stream context options - * - * See http://php.net/manual/en/context.socket.php - * - * @return array - */ - abstract protected function getSocketStreamContextOptions(); - - /** - * Returns an array of ssl stream context options - * - * See http://php.net/manual/en/context.ssl.php - * - * @return array - */ - abstract protected function getSslStreamContextOptions(); -} diff --git a/core/lib/Wrench/Tests/Application/EchoApplicationTest.php b/core/lib/Wrench/Tests/Application/EchoApplicationTest.php deleted file mode 100755 index bd32aeb33..000000000 --- a/core/lib/Wrench/Tests/Application/EchoApplicationTest.php +++ /dev/null @@ -1,57 +0,0 @@ -assertInstanceOfClass($this->getInstance()); - } - - /** - * @param unknown_type $payload - * @dataProvider getValidPayloads - */ - public function testOnData($payload) - { - $connection = $this->getMockBuilder('Wrench\Connection') - ->disableOriginalConstructor() - ->getMock(); - - $connection - ->expects($this->once()) - ->method('send') - ->with($this->equalTo($payload), $this->equalTo(Protocol::TYPE_TEXT)) - ->will($this->returnValue(true)); - - $this->getInstance()->onData($payload, $connection); - } - - /** - * Data provider - * - * @return array> - */ - public function getValidPayloads() - { - return array( - array('asdkllakdaowidoaw noaoinosdna nwodinado ndsnd aklndiownd'), - array(' ') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/BasicServerTest.php b/core/lib/Wrench/Tests/BasicServerTest.php deleted file mode 100755 index 20d004419..000000000 --- a/core/lib/Wrench/Tests/BasicServerTest.php +++ /dev/null @@ -1,119 +0,0 @@ -getInstance('ws://localhost:8000', array( - 'allowed_origins' => $allowed, - 'logger' => array($this, 'log') - )); - - $connection = $this->getMockBuilder('Wrench\Connection') - ->disableOriginalConstructor() - ->getMock(); - - $connection - ->expects($this->never()) - ->method('close') - ->will($this->returnValue(true)); - - $server->notify( - Server::EVENT_HANDSHAKE_REQUEST, - array($connection, '', $origin, '', array()) - ); - } - - /** - * @param array $allowed - * @param string $origin - * @dataProvider getInvalidOrigins - */ - public function testInvalidOriginPolicy(array $allowed, $origin) - { - $server = $this->getInstance('ws://localhost:8000', array( - 'allowed_origins' => $allowed, - 'logger' => array($this, 'log') - )); - - $connection = $this->getMockBuilder('Wrench\Connection') - ->disableOriginalConstructor() - ->getMock(); - - $connection - ->expects($this->once()) - ->method('close') - ->will($this->returnValue(true)); - - $server->notify( - Server::EVENT_HANDSHAKE_REQUEST, - array($connection, '', $origin, '', array()) - ); - } - - /** - * @see Wrench\Tests.ServerTest::getValidConstructorArguments() - */ - public function getValidConstructorArguments() - { - return array_merge(parent::getValidConstructorArguments(), array( - array( - 'ws://localhost:8000', - array('logger' => function () {}) - ) - )); - } - - /** - * Data provider - * - * @return array> - */ - public function getValidOrigins() - { - return array( - array(array('localhost'), 'localhost'), - array(array('somewhere.com'), 'somewhere.com'), - ); - } - - /** - * Data provider - * - * @return array> - */ - public function getInvalidOrigins() - { - return array( - array(array('localhost'), 'blah'), - array(array('somewhere.com'), 'somewhereelse.com'), - array(array('somewhere.com'), 'subdomain.somewhere.com') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/ClientTest.php b/core/lib/Wrench/Tests/ClientTest.php deleted file mode 100755 index 824774eef..000000000 --- a/core/lib/Wrench/Tests/ClientTest.php +++ /dev/null @@ -1,173 +0,0 @@ -assertInstanceOfClass( - $client = new Client( - 'ws://localhost/test', 'http://example.org/' - ), - 'ws:// scheme, default socket' - ); - - $this->assertInstanceOfClass( - $client = new Client( - 'ws://localhost/test', 'http://example.org/', - array('socket' => $this->getMockSocket()) - ), - 'ws:// scheme, socket specified' - ); - } - - /** - * Gets a mock socket - * - * @return Socket - */ - protected function getMockSocket() - { - return $this->getMock('Wrench\Socket\ClientSocket', array(), array('wss://localhost:8000')); - } - - /** - * @expectedException PHPUnit_Framework_Error - */ - public function testConstructorSocketUnspecified() - { - $w = new Client(); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriInvalid() - { - $w = new Client('invalid uri', 'http://www.example.com/'); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriEmpty() - { - $w = new Client(null, 'http://www.example.com/'); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriPathUnspecified() - { - $w = new Client('ws://localhost', 'http://www.example.com/'); - } - - /** - * @expectedException PHPUnit_Framework_Error - */ - public function testConstructorOriginUnspecified() - { - $w = new Client('ws://localhost'); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorOriginEmpty() - { - $w = new Client('wss://localhost', null); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorOriginInvalid() - { - $w = new Client('ws://localhost:8000', 'NOTAVALIDURI'); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testSendInvalidType() - { - $client = new Client('ws://localhost/test', 'http://example.org/'); - $client->sendData('blah', 9999); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testSendInvalidTypeString() - { - $client = new Client('ws://localhost/test', 'http://example.org/'); - $client->sendData('blah', 'fooey'); - } - - public function testSend() - { - try { - $helper = new ServerTestHelper(); - $helper->setUp(); - - /* @var $instance Wrench\Client */ - $instance = $this->getInstance($helper->getEchoConnectionString(), 'http://www.example.com/send'); - $instance->addRequestHeader('X-Test', 'Custom Request Header'); - - $this->assertFalse($instance->receive(), 'Receive before connect'); - - $success = $instance->connect(); - $this->assertTrue($success, 'Client can connect to test server'); - $this->assertTrue($instance->isConnected()); - - $this->assertFalse($instance->connect(), 'Double connect'); - - $this->assertFalse((boolean)$instance->receive(), 'No data'); - - $bytes = $instance->sendData('foobar', 'text'); - $this->assertTrue($bytes >= 6, 'sent text frame'); - sleep(1); - - $bytes = $instance->sendData('baz', Protocol::TYPE_TEXT); - $this->assertTrue($bytes >= 3, 'sent text frame'); - sleep(1); - - $responses = $instance->receive(); - $this->assertTrue(is_array($responses)); - $this->assertCount(2, $responses); - $this->assertInstanceOf('Wrench\\Payload\\Payload', $responses[0]); - $this->assertInstanceOf('Wrench\\Payload\\Payload', $responses[1]); - - $instance->disconnect(); - - $this->assertFalse($instance->isConnected()); - } catch (\Exception $e) { - $helper->tearDown(); - throw $e; - } - - $helper->tearDown(); - } -} diff --git a/core/lib/Wrench/Tests/ConnectionManagerTest.php b/core/lib/Wrench/Tests/ConnectionManagerTest.php deleted file mode 100755 index ed3de0b03..000000000 --- a/core/lib/Wrench/Tests/ConnectionManagerTest.php +++ /dev/null @@ -1,101 +0,0 @@ -assertInstanceOfClass( - $instance = $this->getInstance( - $server, - $options - ), - 'Valid constructor arguments' - ); - } - - /** - * Tests the constructor - */ - public function testConstructor() - { - $this->assertInstanceOfClass( - $instance = $this->getInstance( - $this->getMockServer(), - array() - ), - 'Constructor' - ); - return $instance; - } - - /** - * @depends testConstructor - * @param ConnectionManager $instance - */ - public function testCount($instance) - { - $this->assertTrue(is_numeric($instance->count())); - } - - /** - * Data provider - */ - public function getValidConstructorArguments() - { - return array( - array($this->getMockServer(), array()) - ); - } - - /** - * Gets a mock server - */ - protected function getMockServer() - { - $server = $this->getMock('Wrench\Server', array(), array(), '', false); - - $server->registerApplication('/echo', $this->getMockApplication()); - - $server->expects($this->any()) - ->method('getUri') - ->will($this->returnValue('ws://localhost:8000/')); - - return $server; - } - - /** - * Gets a mock application - * - * @return EchoApplication - */ - protected function getMockApplication() - { - return new EchoApplication(); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/ConnectionTest.php b/core/lib/Wrench/Tests/ConnectionTest.php deleted file mode 100755 index 25d57ffbc..000000000 --- a/core/lib/Wrench/Tests/ConnectionTest.php +++ /dev/null @@ -1,386 +0,0 @@ -assertInstanceOfClass( - $instance = $this->getInstance( - $manager, - $socket, - $options - ), - 'Valid constructor arguments' - ); - - return $instance; - } - - /** - * @dataProvider getValidCloseCodes - */ - public function testClose($code) - { - $socket = $this->getMockSocket(); - - $socket->expects($this->any()) - ->method('getIp') - ->will($this->returnValue('127.0.0.1')); - - $socket->expects($this->any()) - ->method('getPort') - ->will($this->returnValue(mt_rand(1025, 50000))); - - $manager = $this->getMockConnectionManager(); - - $connection = $this->getInstance($manager, $socket); - $connection->close($code); - } - - /** - * @dataProvider getValidHandshakeData - */ - public function testHandshake($path, $request) - { - $connection = $this->getConnectionForHandshake( - $this->getConnectedSocket(), - $path, - $request - ); - $connection->handshake($request); - $connection->onData('somedata'); - $this->assertTrue($connection->send('someotherdata')); - return $connection; - } - - /** - * @dataProvider getValidHandshakeData - * @expectedException Wrench\Exception\HandshakeException - */ - public function testHandshakeBadSocket($path, $request) - { - $connection = $this->getConnectionForHandshake( - $this->getNotConnectedSocket(), - $path, - $request - ); - $connection->handshake($request); - } - - /** - * Because expectation is that only $path application is available - * - * @dataProvider getWrongPathHandshakeData - * @expectedException PHPUnit_Framework_ExpectationFailedException - */ - public function testWrongPathHandshake($path, $request) - { - $connection = $this->getConnectionForHandshake( - $this->getConnectedSocket(), - $path, - $request - ); - $connection->handshake($request); - } - - /** - * @dataProvider getValidHandleData - */ - public function testHandle($path, $request_handshake, array $requests, array $counts) - { - $connection = $this->getConnectionForHandle( - $this->getConnectedSocket(), - $path, - $request_handshake, - $counts - ); - - $connection->handshake($request_handshake); - - foreach ($requests as $request) { - $connection->handle($request); - } - - return $connection; - } - - /** - * @return Socket - */ - protected function getConnectedSocket() - { - $socket = $this->getMockSocket(); - - $socket->expects($this->any()) - ->method('isConnected') - ->will($this->returnValue(true)); - - return $socket; - } - - /** - * @return Socket - */ - protected function getNotConnectedSocket() - { - $socket = $this->getMockSocket(); - - $socket->expects($this->any()) - ->method('isConnected') - ->will($this->returnValue(false)); - - return $socket; - } - - protected function getConnectionForHandshake($socket, $path, $request) - { - $manager = $this->getMockConnectionManager(); - - $application = $this->getMockApplication(); - - $server = $this->getMock('Wrench\Server', array(), array(), '', false); - $server->registerApplication($path, $application); - - $manager->expects($this->any()) - ->method('getApplicationForPath') - ->with($path) - ->will($this->returnValue($application)); - - $manager->expects($this->any()) - ->method('getServer') - ->will($this->returnValue($server)); - - $connection = $this->getInstance($manager, $socket); - - return $connection; - } - - protected function getConnectionForHandle($socket, $path, $handshake, array $counts) - { - $connection = $this->getConnectionForHandshake($socket, $path, $handshake); - - $manager = $this->getMockConnectionManager(); - - $application = $this->getMockApplication(); - - $application->expects($this->exactly(isset($counts['onData']) ? $counts['onData'] : 0)) - ->method('onData') - ->will($this->returnValue(true)); - - $server = $this->getMock('Wrench\Server', array(), array(), '', false); - $server->registerApplication($path, $application); - - $manager->expects($this->any()) - ->method('getApplicationForPath') - ->with($path) - ->will($this->returnValue($application)); - - $manager->expects($this->exactly(isset($counts['removeConnection']) ? $counts['removeConnection'] : 0)) - ->method('removeConnection'); - - $manager->expects($this->any()) - ->method('getServer') - ->will($this->returnValue($server)); - - $connection = $this->getInstance($manager, $socket); - - return $connection; - } - - /** - * @return ConnectionManager - */ - protected function getMockConnectionManager() - { - return $this->getMock('Wrench\ConnectionManager', array(), array(), '', false); - } - - /** - * Gets a mock socket - * - * @return Socket - */ - protected function getMockSocket() - { - return $this->getMock('Wrench\Socket\ServerClientSocket', array(), array(), '', false); - } - - /** - * Gets a mock application - * - * @return EchoApplication - */ - protected function getMockApplication() - { - return $this->getMock('Wrench\Application\EchoApplication'); - } - - /** - * Data provider - * - * @return array> - */ - public function getValidCloseCodes() - { - $arguments = array(); - foreach (Protocol::$closeReasons as $code => $reason) { - $arguments[] = array($code); - } - return $arguments; - } - - /** - * Data provider - * - * @return array> - */ - public function getValidConstructorArguments() - { - $socket = $this->getMockSocket(); - - $socket->expects($this->any()) - ->method('getIp') - ->will($this->returnValue('127.0.0.1')); - - $socket->expects($this->any()) - ->method('getPort') - ->will($this->returnValue(mt_rand(1025, 50000))); - - $manager = $this->getMockConnectionManager(); - - return array( - array( - $manager, - $socket, - array('logger' => function() {}) - ), - array( - $manager, - $socket, - array('logger' => function () {}, - 'connection_id_algo' => 'sha512') - ) - ); - } - - /** - * Data provider - * - * Uses this awkward valid request array so that splitting of payloads - * across multiple calls to handle can be tested - * - * testHandle($path, $request_handshake, array $requests, array $counts) - */ - public function getValidHandleData() - { - $valid_requests = array( - array( - 'data' => array( - "\x81\xad\x2e\xab\x82\xac\x6f\xfe\xd6\xe4\x14\x8b\xf9\x8c\x0c" - ."\xde\xf1\xc9\x5c\xc5\xe3\xc1\x4b\x89\xb8\x8c\x0c\xcd\xed\xc3" - ."\x0c\x87\xa2\x8e\x5e\xca\xf1\xdf\x59\xc4\xf0\xc8\x0c\x91\xa2" - ."\x8e\x4c\xca\xf0\x8e\x53\x81\xad\xd4\xfd\x81\xfe\x95\xa8\xd5" - ."\xb6\xee\xdd\xfa\xde\xf6\x88\xf2\x9b\xa6\x93\xe0\x93\xb1\xdf" - ."\xbb\xde\xf6\x9b\xee\x91\xf6\xd1\xa1\xdc\xa4\x9c\xf2\x8d\xa3" - ."\x92\xf3\x9a\xf6\xc7\xa1\xdc\xb6\x9c\xf3\xdc\xa9\x81\x80\x8e" - ."\x12\xcd\x8e\x81\x8c\xf6\x8a\xf0\xee\x9a\xeb\x83\x9a\xd6\xe7" - ."\x95\x9d\x85\xeb\x97\x8b" // Four text frames - ), - 'counts' => array( - 'onData' => 4 - ) - ), - array( - 'data' => array( - "\x88\x80\xdc\x8e\xa2\xc5" // Close frame - ), - 'counts' => array( - 'removeConnection' => 1 - ) - ) - ); - - $data = array(); - - $handshakes = $this->getValidHandshakeData(); - - foreach ($handshakes as $handshake) { - foreach ($valid_requests as $handle_args) { - $arguments = $handshake; - $arguments[] = $handle_args['data']; - $arguments[] = $handle_args['counts']; - - $data[] = $arguments; - } - } - - return $data; - } - - /** - * Data provider - */ - public function getValidHandshakeData() - { - return array( - array( - '/chat', -"GET /chat HTTP/1.1\r -Host: server.example.com\r -Upgrade: websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://example.com\r -Sec-WebSocket-Version: 13\r\n\r\n" - ) - ); - } - - /** - * Data provider - */ - public function getWrongPathHandshakeData() - { - return array( - array( - '/foobar', -"GET /chat HTTP/1.1\r -Host: server.example.com\r -Upgrade: websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://example.com\r -Sec-WebSocket-Version: 13\r\n\r\n" - ), - ); - } -} diff --git a/core/lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php b/core/lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php deleted file mode 100755 index bcced6695..000000000 --- a/core/lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php +++ /dev/null @@ -1,29 +0,0 @@ -getFrameBuffer(); - } - - protected function getClass() - { - return 'Wrench\Tests\Frame\BadSubclassFrame'; - } -} diff --git a/core/lib/Wrench/Tests/Frame/FrameTest.php b/core/lib/Wrench/Tests/Frame/FrameTest.php deleted file mode 100755 index 848c7103e..000000000 --- a/core/lib/Wrench/Tests/Frame/FrameTest.php +++ /dev/null @@ -1,168 +0,0 @@ -frame = $this->getNewFrame(); - } - - protected function getNewFrame() - { - $class = $this->getClass(); - return new $class(); - } - - /** - * @see PHPUnit_Framework_TestCase::tearDown() - */ - protected function tearDown() - { - parent::tearDown(); - unset($this->frame); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testBijection($type, $payload, $masked) - { - // Encode the payload - $this->frame->encode($payload, $type, $masked); - - // Get the resulting buffer - $buffer = $this->frame->getFrameBuffer(); - $this->assertTrue((boolean)$buffer, 'Got raw frame buffer'); - - // And feed it back into a new frame - $frame = $this->getNewFrame(); - $frame->receiveData($buffer); - - // Check the properties of the new frame against the old, all match - $this->assertEquals( - $this->frame->getType(), - $frame->getType(), - 'Types match after encode -> receiveData' - ); - - $this->assertEquals( - $this->frame->getFramePayload(), - $frame->getFramePayload(), - 'Payloads match after encode -> receiveData' - ); - - // Masking key should not be different, because we read the buffer in directly - $this->assertEquals( - $this->frame->getFrameBuffer(), - $frame->getFrameBuffer(), - 'Raw buffers match too' - ); - - // This time, we create a new frame and read the data in with encode - $frame = $this->getNewFrame(); - $frame->encode($this->frame->getFramePayload(), $type, $masked); - - // These still match - $this->assertEquals( - $this->frame->getType(), - $frame->getType(), - 'Types match after encode -> receiveData -> encode' - ); - - $this->assertEquals( - $this->frame->getFramePayload(), - $frame->getFramePayload(), - 'Payloads match after encode -> receiveData -> encode' - ); - - // But the masking key should be different, thus, so are the buffers - if ($masked) { - $this->assertNotEquals( - $this->frame->getFrameBuffer(), - $frame->getFrameBuffer(), - 'Raw buffers don\'t match because of masking' - ); - } else { - $this->assertEquals( - $this->frame->getFramePayload(), - $frame->getFramePayload(), - 'Payloads match after encode -> receiveData -> encode' - ); - } - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodeTypeReflection($type, $payload, $masked) - { - $this->frame->encode($payload, $type); - $this->assertEquals(Protocol::TYPE_TEXT, $this->frame->getType(), 'Encode retains type information'); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodeLengthReflection($type, $payload, $masked) - { - $this->frame->encode($payload, $type); - $this->assertEquals(strlen($payload), $this->frame->getLength(), 'Encode does not alter payload length'); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodePayloadReflection($type, $payload, $masked) - { - $this->frame->encode($payload, $type, $masked); - $this->assertEquals($payload, $this->frame->getFramePayload(), 'Encode retains payload information'); - } - - /** - * Data provider - * - * @return array - */ - public function getValidEncodePayloads() - { - return array( - array( - Protocol::TYPE_TEXT, - "123456\x007890!@#$%^&*()qwe\trtyuiopQWERTYUIOPasdfghjklASFGH\n - JKLzxcvbnmZXCVBNM,./<>?;[]{}-=_+\|'asdad0x11\aasdassasdasasdsd", - true - ), - array( - Protocol::TYPE_TEXT, - pack('CCCCCCC', 0x00, 0x01, 0x02, 0x03, 0x04, 0xff, 0xf0), - true - ), - array(Protocol::TYPE_TEXT, ' ', true) - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Frame/HybiFrameTest.php b/core/lib/Wrench/Tests/Frame/HybiFrameTest.php deleted file mode 100755 index 721429513..000000000 --- a/core/lib/Wrench/Tests/Frame/HybiFrameTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getMock('Wrench\Server', array(), array(), '', false); - - $instance->listen($server); - } - - abstract public function testConstructor(); -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Listener/OriginPolicyTest.php b/core/lib/Wrench/Tests/Listener/OriginPolicyTest.php deleted file mode 100755 index 103af9bfe..000000000 --- a/core/lib/Wrench/Tests/Listener/OriginPolicyTest.php +++ /dev/null @@ -1,110 +0,0 @@ -getInstance(array()); - $this->assertInstanceOfClass($instance, 'No constructor arguments'); - return $instance; - } - - /** - * @dataProvider getValidArguments - * @param array $allowed - * @param string $domain - */ - public function testValidAllowed($allowed, $domain) - { - $instance = $this->getInstance($allowed); - $this->assertTrue($instance->isAllowed($domain)); - } - - /** - * @dataProvider getValidArguments - * @param array $allowed - * @param string $domain - */ - public function testValidHandshake($allowed, $domain) - { - $instance = $this->getInstance($allowed); - - $connection = $this->getMock('Wrench\Connection', array(), array(), '', false); - - $connection - ->expects($this->never()) - ->method('close'); - - $instance->onHandshakeRequest($connection, '/', $domain, 'abc', array()); - } - - /** - * @dataProvider getInvalidArguments - * @param array $allowed - * @param string $bad_domain - */ - public function testInvalidAllowed($allowed, $bad_domain) - { - $instance = $this->getInstance($allowed); - $this->assertFalse($instance->isAllowed($bad_domain)); - } - - /** - * @dataProvider getInvalidArguments - * @param array $allowed - * @param string $domain - */ - public function testInvalidHandshake($allowed, $bad_domain) - { - $instance = $this->getInstance($allowed); - - $connection = $this->getMock('Wrench\Connection', array(), array(), '', false); - - $connection - ->expects($this->once()) - ->method('close'); - - $instance->onHandshakeRequest($connection, '/', $bad_domain, 'abc', array()); - } - - /** - * Data provider - */ - public function getValidArguments() - { - return array( - array(array('localhost'), 'http://localhost'), - array(array('foobar.com'), 'https://foobar.com'), - array(array('https://foobar.com'), 'https://foobar.com') - ); - } - - /** - * Data provider - */ - public function getInvalidArguments() - { - return array( - array(array('localhost'), 'localdomain'), - array(array('foobar.com'), 'foobar.org'), - array(array('https://foobar.com'), 'http://foobar.com'), - array(array('http://foobar.com'), 'foobar.com') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Listener/RateLimiterTest.php b/core/lib/Wrench/Tests/Listener/RateLimiterTest.php deleted file mode 100755 index 602442308..000000000 --- a/core/lib/Wrench/Tests/Listener/RateLimiterTest.php +++ /dev/null @@ -1,67 +0,0 @@ -getInstance(); - $this->assertInstanceOfClass($instance, 'No constructor arguments'); - return $instance; - } - - public function testOnSocketConnect() - { - $this->getInstance()->onSocketConnect(null, $this->getConnection()); - } - - public function testOnSocketDisconnect() - { - $this->getInstance()->onSocketDisconnect(null, $this->getConnection()); - } - - public function testOnClientData() - { - $this->getInstance()->onClientData(null, $this->getConnection()); - } - - protected function getConnection() - { - $connection = $this->getMock('Wrench\Connection', array(), array(), '', false); - - $connection - ->expects($this->any()) - ->method('getIp') - ->will($this->returnValue('127.0.0.1')); - - $connection - ->expects($this->any()) - ->method('getId') - ->will($this->returnValue('abcdef01234567890')); - - $manager = $this->getMock('Wrench\ConnectionManager', array(), array(), '', false); - $manager->expects($this->any())->method('count')->will($this->returnValue(5)); - - $connection - ->expects($this->any()) - ->method('getConnectionManager') - ->will($this->returnValue($manager)); - - return $connection; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Payload/HybiPayloadTest.php b/core/lib/Wrench/Tests/Payload/HybiPayloadTest.php deleted file mode 100755 index 5dd2b2497..000000000 --- a/core/lib/Wrench/Tests/Payload/HybiPayloadTest.php +++ /dev/null @@ -1,14 +0,0 @@ -payload = $this->getInstance(); - } - - /** - * Tests the constructor - */ - public function testConstructor() - { - $this->assertInstanceOfClass($this->getInstance()); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testBijection($type, $payload) - { - // Encode the payload - $this->payload->encode($payload, $type); - - // Create a new payload and read the data in with encode - $payload = $this->getInstance(); - $payload->encode($this->payload->getPayload(), $type); - - // These still match - $this->assertEquals( - $this->payload->getType(), - $payload->getType(), - 'Types match after encode -> receiveData' - ); - - $this->assertEquals( - $this->payload->getPayload(), - $payload->getPayload(), - 'Payloads match after encode -> receiveData' - ); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodeTypeReflection($type, $payload) - { - $this->payload->encode($payload, Protocol::TYPE_TEXT); - $this->assertEquals(Protocol::TYPE_TEXT, $this->payload->getType(), 'Encode retains type information'); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodePayloadReflection($type, $payload) - { - $this->payload->encode($payload, Protocol::TYPE_TEXT); - $this->assertEquals($payload, $this->payload->getPayload(), 'Encode retains payload information'); - } - - /** - * Tests sending to a socket - * @dataProvider getValidEncodePayloads - */ - public function testSendToSocket($type, $payload) - { - $successfulSocket = $this->getMock('Wrench\Socket\ClientSocket', array(), array('wss://localhost:8000')); - $failedSocket = clone $successfulSocket; - - $successfulSocket->expects($this->any()) - ->method('send') - ->will($this->returnValue(true)); - - $failedSocket->expects($this->any()) - ->method('send') - ->will($this->returnValue(false)); - - $this->payload->encode($payload, $type); - - $this->assertTrue($this->payload->sendToSocket($successfulSocket)); - $this->assertFalse($this->payload->sendToSocket($failedSocket)); - } - - /** - * Tests receiving data - * @dataProvider getValidEncodePayloads - */ - public function testReceieveData($type, $payload) - { - $payload = $this->getInstance(); - $payload->receiveData($payload); - } - - /** - * Data provider - * - * @return array - */ - public function getValidEncodePayloads() - { - return array( - array( - Protocol::TYPE_TEXT, - "123456\x007890!@#$%^&*()qwe\trtyuiopQWERTYUIOPasdfghjklASFGH\n - JKLzxcvbnmZXCVBNM,./<>?;[]{}-=_+\|'asdad0x11\aasdassasdasasdsd" - ), - array( - Protocol::TYPE_TEXT, - pack('CCCCCCC', 0x00, 0x01, 0x02, 0x03, 0x04, 0xff, 0xf0) - ), - array(Protocol::TYPE_TEXT, ' ') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Protocol/ProtocolTest.php b/core/lib/Wrench/Tests/Protocol/ProtocolTest.php deleted file mode 100755 index afba179da..000000000 --- a/core/lib/Wrench/Tests/Protocol/ProtocolTest.php +++ /dev/null @@ -1,180 +0,0 @@ -getInstance()->validateRequestHandshake($request); - - $this->assertEquals('/chat', $path); - $this->assertEquals('http://example.com', $origin); - $this->assertEquals('dGhlIHNhbXBsZSBub25jZQ==', $key); - $this->assertTrue(is_array($extensions), 'Extensions returned as array'); - $this->assertEquals(array('x-test', 'x-test2'), $extensions, 'Extensions match'); - $this->assertEquals('chat, superchat', $protocol); - } catch (Exception $e) { - $this->fail($e); - } - } - - /** - * @dataProvider getValidHandshakeResponses - */ - public function testValidateHandshakeResponseValid($response, $key) - { - try { - $valid = $this->getInstance()->validateResponseHandshake($response, $key); - $this->assertTrue(is_bool($valid), 'Validation return value is boolean'); - $this->assertTrue($valid, 'Handshake response validates'); - } catch (Exception $e) { - $this->fail('Validated valid response handshake as invalid'); - } - } - - /** - * @dataProvider getValidHandshakeResponses - */ - public function testGetResponseHandsake($unused, $key) - { - try { - $response = $this->getInstance()->getResponseHandshake($key); - $this->assertHttpResponse($response); - } catch (Exception $e) { - $this->fail('Unable to get handshake response: ' . $e); - } - } - - /** - * Asserts the string response is an HTTP response - * - * @param string $response - */ - protected function assertHttpResponse($response, $message = '') - { - $this->assertStringStartsWith('HTTP', $response, $message . ' - response starts well'); - $this->assertStringEndsWith("\r\n", $response, $message . ' - response ends well'); - } - - public function testGetVersion() - { - $version = $this->getInstance()->getVersion(); - $this->assertTrue(is_int($version)); - } - - public function testGetResponseError() - { - $response = $this->getInstance()->getResponseError(400); - $this->assertHttpResponse($response, 'Code as int'); - - $response = $this->getInstance()->getResponseError(new Exception('Some message', 500)); - $this->assertHttpResponse($response, 'Code in Exception'); - - $response = $this->getInstance()->getResponseError(888); - $this->assertHttpResponse($response, 'Invalid code produces unimplemented response'); - } - - /** - * @dataProvider getValidOriginUris - */ - public function testValidateOriginUriValid($uri) - { - try { - $this->getInstance()->validateOriginUri($uri); - } catch (\Exception $e) { - $this->fail('Valid URI validated as invalid: ' . $e); - } - } - - /** - * @dataProvider getInvalidOriginUris - * @expectedException InvalidArgumentException - */ - public function testValidateOriginUriInvalid($uri) - { - $this->getInstance()->validateOriginUri($uri); - } - - public function getValidOriginUris() - { - return array( - array('http://www.example.org'), - array('http://www.example.com/some/page'), - array('https://localhost/') - ); - } - - public function getInvalidOriginUris() - { - return array( - array(false), - array(true), - array(''), - array('blah') - ); - } - - public function getValidHandshakeRequests() - { - $cases = array(); - - - $cases[] = array("GET /chat HTTP/1.1\r -Host: server.example.com\r -Upgrade: websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://example.com\r -Sec-WebSocket-Extensions: x-test\r -Sec-WebSocket-Extensions: x-test2\r -Sec-WebSocket-Protocol: chat, superchat\r -Sec-WebSocket-Version: 13\r -\r\n"); - - $cases[] = array("GET /chat HTTP/1.1\r -Host: server.example.com\r -Upgrade: Websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://example.com\r -Sec-WebSocket-Extensions: x-test\r -Sec-WebSocket-Extensions: x-test2\r -Sec-WebSocket-Protocol: chat, superchat\r -Sec-WebSocket-Version: 13\r -\r\n"); - - return $cases; - } - - public function getValidHandshakeResponses() - { - $cases = array(); - - for ($i = 10; $i > 0; $i--) { - $key = sha1(time() . uniqid('', true)); - $response = "Sec-WebSocket-Accept: " - . base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)) - . "\r\n\r\n"; - - $cases[] = array($response, $key); - } - - return $cases; - } -} diff --git a/core/lib/Wrench/Tests/Protocol/Rfc6455ProtocolTest.php b/core/lib/Wrench/Tests/Protocol/Rfc6455ProtocolTest.php deleted file mode 100755 index ee329f31e..000000000 --- a/core/lib/Wrench/Tests/Protocol/Rfc6455ProtocolTest.php +++ /dev/null @@ -1,14 +0,0 @@ -assertInstanceOfClass( - $this->getInstance($url, $options), - 'Valid constructor arguments' - ); - } - - /** - * Tests logging - */ - public function testLogging() - { - $test = $this; - $logged = false; - - $server = $this->getInstance('ws://localhost:8000', array( - 'logger' => function ($message, $priority) use ($test, &$logged) { - $test->assertTrue(is_string($message), 'Log had a string message'); - $test->assertTrue(is_string($priority), 'Log had a string priority'); - $logged = true; - } - )); - - $this->assertTrue($logged, 'The log callback was hit'); - } - - /** - * Data provider - * - * @return array> - */ - public function getValidConstructorArguments() - { - return array( - array( - 'ws://localhost:8000', - array('logger' => array($this, 'log')) - ), - array( - 'ws://localhost', - array('logger' => array($this, 'log')) - ) - ); - } - -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/ServerTestHelper.php b/core/lib/Wrench/Tests/ServerTestHelper.php deleted file mode 100755 index 57dd1ec05..000000000 --- a/core/lib/Wrench/Tests/ServerTestHelper.php +++ /dev/null @@ -1,144 +0,0 @@ -tearDown(); - } - - /** - * @return string - */ - public function getConnectionString() - { - return 'ws://localhost:' . $this->port; - } - - /** - * @return string - */ - public function getEchoConnectionString() - { - return $this->getConnectionString() . '/echo'; - } - - /** - * Sets up the server process and sleeps for a few seconds while - * it wakes up - */ - public function setUp() - { - $this->port = self::getNextPort(); - - $this->process = proc_open( - $this->getCommand(), - array( - 0 => array('file', '/dev/null', 'r'), - 1 => array('file', __DIR__ . '/../../../build/server.log', 'a+'), - 2 => array('file', __DIR__ . '/../../../build/server.err.log', 'a+') - ), - $this->pipes, - __DIR__ . '../' - ); - - sleep(3); - } - - /** - * Tears down the server process - * - * This method *must* be called - */ - public function tearDown() - { - if ($this->process) { - foreach ($this->pipes as &$pipe) { - fclose($pipe); - } - $this->pipes = null; - - // Sigh - $status = proc_get_status($this->process); - - if ($status && isset($status['pid']) && $status['pid']) { - // More sigh, this is the pid of the parent sh process, we want - // to terminate the server directly - $this->log('Command: /bin/ps -ao pid,ppid | /usr/bin/col | /usr/bin/tail -n +2 | /bin/grep \' ' . $status['pid'] . "'", 'info'); - exec('/bin/ps -ao pid,ppid | /usr/bin/col | /usr/bin/tail -n +2 | /bin/grep \' ' . $status['pid'] . "'", $processes, $return); - - if ($return === 0) { - foreach ($processes as $process) { - list($pid, $ppid) = explode(' ', str_replace(' ', ' ', $process)); - if ($pid) { - $this->log('Killing ' . $pid, 'info'); - exec('/bin/kill ' . $pid . ' > /dev/null 2>&1'); - } - } - } else { - $this->log('Unable to find child processes', 'warning'); - } - - sleep(1); - - $this->log('Killing ' . $status['pid'], 'info'); - exec('/bin/kill ' . $status['pid'] . ' > /dev/null 2>&1'); - - sleep(1); - } - - proc_close($this->process); - $this->process = null; - } - } - - /** - * Gets the server command - * - * @return string - */ - protected function getCommand() - { - return sprintf('/usr/bin/env php %s/server.php %d', __DIR__, $this->port); - } - - /** - * Logs a message - * - * @param string $message - * @param string $priority - */ - public function log($message, $priority = 'info') - { - //echo $message . "\n"; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Socket/ClientSocketTest.php b/core/lib/Wrench/Tests/Socket/ClientSocketTest.php deleted file mode 100755 index d64ea5df2..000000000 --- a/core/lib/Wrench/Tests/Socket/ClientSocketTest.php +++ /dev/null @@ -1,167 +0,0 @@ -assertInstanceOfClass( - new ClientSocket('ws://localhost/'), - 'ws:// scheme, default port' - ); - - $this->assertInstanceOfClass( - new ClientSocket('ws://localhost/some-arbitrary-path'), - 'with path' - ); - - $this->assertInstanceOfClass( - new ClientSocket('wss://localhost/test', array()), - 'empty options' - ); - - $this->assertInstanceOfClass( - new ClientSocket('ws://localhost:8000/foo'), - 'specified port' - ); - - return $instance; - } - - public function testOptions() - { - $socket = null; - - $this->assertInstanceOfClass( - $socket = new ClientSocket( - 'ws://localhost:8000/foo', array( - 'timeout_connect' => 10 - ) - ), - 'connect timeout' - ); - - $this->assertInstanceOfClass( - $socket = new ClientSocket( - 'ws://localhost:8000/foo', array( - 'timeout_socket' => 10 - ) - ), - 'socket timeout' - ); - - $this->assertInstanceOfClass( - $socket = new ClientSocket( - 'ws://localhost:8000/foo', array( - 'protocol' => new Rfc6455Protocol() - ) - ), - 'protocol' - ); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testProtocolTypeError() - { - $socket = new ClientSocket( - 'ws://localhost:8000/foo', array( - 'protocol' => new stdClass() - ) - ); - } - - /** - * @expectedException PHPUnit_Framework_Error - */ - public function testConstructorUriUnspecified() - { - $w = new ClientSocket(); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriEmpty() - { - $w = new ClientSocket(null); - } - - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriInvalid() - { - $w = new ClientSocket('Bad argument'); - } - - - /** - * @depends testConstructor - * @expectedException Wrench\Exception\SocketException - */ - public function testSendTooEarly($instance) - { - $instance->send('foo'); - } - - /** - * Test the connect, send, receive method - */ - public function testConnect() - { - try { - $helper = new ServerTestHelper(); - $helper->setUp(); - - $instance = $this->getInstance($helper->getConnectionString()); - $success = $instance->connect(); - - $this->assertTrue($success, 'Client socket can connect to test server'); - - $sent = $instance->send("GET /echo HTTP/1.1\r -Host: localhost\r -Upgrade: websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://localhost\r -Sec-WebSocket-Version: 13\r\n\r\n"); - $this->assertNotEquals(false, $sent, 'Client socket can send to test server'); - - $response = $instance->receive(); - $this->assertStringStartsWith('HTTP', $response, 'Response looks like HTTP handshake response'); - - } catch (\Exception $e) { - $helper->tearDown(); - throw $e; - } - - $helper->tearDown(); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Socket/ServerClientSocketTest.php b/core/lib/Wrench/Tests/Socket/ServerClientSocketTest.php deleted file mode 100755 index ca71983b5..000000000 --- a/core/lib/Wrench/Tests/Socket/ServerClientSocketTest.php +++ /dev/null @@ -1,42 +0,0 @@ -getInstance($resource); - $this->assertInstanceOfClass($instance); - return $instance; - } - - /** - * @expectedException Wrench\Exception\SocketException - * @depends testConstructor - */ - public function testGetIpTooSoon($instance) - { - $instance->getIp(); - } - - /** - * @expectedException Wrench\Exception\SocketException - * @depends testConstructor - */ - public function testGetPortTooSoon($instance) - { - $instance->getPort(); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Socket/ServerSocketTest.php b/core/lib/Wrench/Tests/Socket/ServerSocketTest.php deleted file mode 100755 index a4d4251c5..000000000 --- a/core/lib/Wrench/Tests/Socket/ServerSocketTest.php +++ /dev/null @@ -1,13 +0,0 @@ -isConnected(); - $this->assertTrue(is_bool($connected), 'isConnected returns boolean'); - $this->assertFalse($connected); - } - - /** - * @dataProvider getValidNames - * @param string $name - */ - public function testGetNamePart($name, $ip, $port) - { - $this->assertEquals($ip, Socket::getNamePart($name, Socket::NAME_PART_IP), 'splits ip correctly'); - $this->assertEquals($port, Socket::getNamePart($name, Socket::NAME_PART_PORT), 'splits port correctly'); - } - - /** - * Data provider - */ - public function getValidNames() - { - return array( - array('127.0.0.1:52339', '127.0.0.1', '52339'), - array('255.255.255.255:1025', '255.255.255.255', '1025'), - array('::1:56670', '::1', '56670') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Socket/UriSocketTest.php b/core/lib/Wrench/Tests/Socket/UriSocketTest.php deleted file mode 100755 index d0b7f8bdc..000000000 --- a/core/lib/Wrench/Tests/Socket/UriSocketTest.php +++ /dev/null @@ -1,56 +0,0 @@ -getInstance('ws://localhost:8000'); - $this->assertInstanceOfClass($instance); - return $instance; - } - - /** - * @dataProvider getInvalidConstructorArguments - * @expectedException InvalidArgumentException - */ - public function testInvalidConstructor($uri) - { - $this->getInstance($uri); - } - - /** - * @depends testConstructor - */ - public function testGetIp($instance) - { - $this->assertStringStartsWith('localhost', $instance->getIp(), 'Correct host'); - } - - /** - * @depends testConstructor - */ - public function testGetPort($instance) - { - $this->assertEquals(8000, $instance->getPort(), 'Correct port'); - } - - /** - * Data provider - */ - public function getInvalidConstructorArguments() - { - return array( - array(false), - array('http://www.google.com/'), - array('ws:///'), - array(':::::'), - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Test.php b/core/lib/Wrench/Tests/Test.php deleted file mode 100755 index f9b421fd9..000000000 --- a/core/lib/Wrench/Tests/Test.php +++ /dev/null @@ -1,61 +0,0 @@ -assertInstanceOf( - $this->getClass(), - $instance, - $message - ); - } - - /** - * Gets an instance of the class under test - * - * @param mixed Normal constructor arguments - * @magic This method accepts a variable number of arguments - * @return object Of type given by getClass() - */ - public function getInstance(/* ... */) - { - $reflection = new ReflectionClass($this->getClass()); - return $reflection->newInstanceArgs(func_get_args()); - } - - /** - * Logging function - * - * Passed into some classes under test as a callable - * - * @param string $message - * @param string $priority - * @return void - */ - public function log($message, $priority = 'info') - { - // nothing - } -} diff --git a/core/lib/Wrench/Tests/bootstrap.php b/core/lib/Wrench/Tests/bootstrap.php deleted file mode 100755 index 84bd83943..000000000 --- a/core/lib/Wrench/Tests/bootstrap.php +++ /dev/null @@ -1,11 +0,0 @@ -register(); \ No newline at end of file diff --git a/core/lib/Wrench/Tests/server.php b/core/lib/Wrench/Tests/server.php deleted file mode 100755 index 34d680622..000000000 --- a/core/lib/Wrench/Tests/server.php +++ /dev/null @@ -1,16 +0,0 @@ -register(); - -$server = new Wrench\Server('ws://localhost:' . $port); -$server->registerApplication('echo', new Wrench\Application\EchoApplication()); -$server->run(); \ No newline at end of file diff --git a/core/lib/Wrench/Util/Configurable.php b/core/lib/Wrench/Util/Configurable.php deleted file mode 100755 index f1983d5e6..000000000 --- a/core/lib/Wrench/Util/Configurable.php +++ /dev/null @@ -1,67 +0,0 @@ - Wrench\Protocol object, latest protocol - * version used if not specified - */ - public function __construct( - array $options = array() - ) { - $this->configure($options); - $this->configureProtocol(); - } - - /** - * Configures the options - * - * @param array $options - */ - protected function configure(array $options) - { - $this->options = array_merge(array( - 'protocol' => new Rfc6455Protocol() - ), $options); - } - - /** - * Configures the protocol option - * - * @throws InvalidArgumentException - */ - protected function configureProtocol() - { - $protocol = $this->options['protocol']; - - if (!$protocol || !($protocol instanceof Protocol)) { - throw new InvalidArgumentException('Invalid protocol option'); - } - - $this->protocol = $protocol; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Util/Ssl.php b/core/lib/Wrench/Util/Ssl.php deleted file mode 100755 index e8cc8bd7e..000000000 --- a/core/lib/Wrench/Util/Ssl.php +++ /dev/null @@ -1,51 +0,0 @@ - $country_name, - 'stateOrProvinceName' => $state_or_province_name, - 'localityName' => $locality_name, - 'organizationName' => $organization_name, - 'organizationalUnitName' => $organizational_unit_name, - 'commonName' => $common_name, - 'emailAddress' => $email_address - ); - - $privkey = openssl_pkey_new(); - $cert = openssl_csr_new($dn, $privkey); - $cert = openssl_csr_sign($cert, null, $privkey, 365); - - $pem = array(); - - openssl_x509_export($cert, $pem[0]); - - if ($pem_passphrase !== null) { - openssl_pkey_export($privkey, $pem[1], $pem_passphrase); - } - - $pem = implode($pem); - file_put_contents($pem_file, $pem); - } -} \ No newline at end of file diff --git a/core/migrations/001-move-source.json b/core/migrations/001-move-source.json deleted file mode 100644 index 08bfd4d28..000000000 --- a/core/migrations/001-move-source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "core/source", - "destinationPath": "source", - "checkType": "dirEmpty" -} \ No newline at end of file diff --git a/core/migrations/002-check-public-styleguide-exists.json b/core/migrations/002-check-public-styleguide-exists.json deleted file mode 100644 index d6c0392ce..000000000 --- a/core/migrations/002-check-public-styleguide-exists.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "", - "destinationPath": "public/styleguide", - "checkType": "dirExists" -} \ No newline at end of file diff --git a/core/migrations/003-move-styleguide.json b/core/migrations/003-move-styleguide.json deleted file mode 100644 index 9f96dd1ee..000000000 --- a/core/migrations/003-move-styleguide.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "core/styleguide", - "destinationPath": "public/styleguide", - "checkType": "versionDiffDir" -} \ No newline at end of file diff --git a/core/migrations/004-check-meta-exists.json b/core/migrations/004-check-meta-exists.json deleted file mode 100644 index de94846c8..000000000 --- a/core/migrations/004-check-meta-exists.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "", - "destinationPath": "source/_patterns/00-atoms/00-meta", - "checkType": "dirExists" -} \ No newline at end of file diff --git a/core/migrations/005-move-pattern-header-footer.json b/core/migrations/005-move-pattern-header-footer.json deleted file mode 100644 index 31e082f99..000000000 --- a/core/migrations/005-move-pattern-header-footer.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "core/source/_patterns/00-atoms/00-meta", - "destinationPath": "source/_patterns/00-atoms/00-meta", - "checkType": "dirEmpty" -} \ No newline at end of file diff --git a/core/migrations/006-check-public-data-exists.json b/core/migrations/006-check-public-data-exists.json deleted file mode 100644 index cac1ae51c..000000000 --- a/core/migrations/006-check-public-data-exists.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "", - "destinationPath": "public/data", - "checkType": "dirExists" -} \ No newline at end of file diff --git a/core/migrations/007-check-public-patterns-exists.json b/core/migrations/007-check-public-patterns-exists.json deleted file mode 100644 index dcb6c5471..000000000 --- a/core/migrations/007-check-public-patterns-exists.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "", - "destinationPath": "public/patterns", - "checkType": "dirExists" -} \ No newline at end of file diff --git a/core/pageFollowServer.php b/core/pageFollowServer.php deleted file mode 100755 index bd579087d..000000000 --- a/core/pageFollowServer.php +++ /dev/null @@ -1,40 +0,0 @@ -register(); - -// parse the main config for the content sync port -if (!($config = @parse_ini_file(__DIR__."/../config/config.ini"))) { - print "Missing the configuration file. Please build it using the Pattern Lab builder.\n"; - exit; -} - -// give it a default port -$port = ($config) ? trim($config['pageFollowPort']) : '8000'; - -// start the content sync server -$server = new \Wrench\Server('ws://0.0.0.0:'.$port.'/', array()); - -// register the application & run it -$server->registerApplication('pagefollow', new \Wrench\Application\PageFollowApplication()); - -print "\n"; -print "Page Follow Server Started...\n"; -print "Use CTRL+C to stop this service...\n"; - -$server->run(); diff --git a/core/scripts/README b/core/scripts/README deleted file mode 100644 index 95dca5ed7..000000000 --- a/core/scripts/README +++ /dev/null @@ -1,6 +0,0 @@ -These are Mac OS X-compatible files to open up select command line scripts. Simply double-click on a file and it should run -the appropriate shell command. If you receive a permissions error you will need to use the command line to fix it. -Simply go to the command line, cd to the scripts/php directory and type chmod +x [filename]. Replace [filename] with the -appropriate filenames. - -That's confusing. \ No newline at end of file diff --git a/core/scripts/generateSite.command b/core/scripts/generateSite.command deleted file mode 100755 index c339b935a..000000000 --- a/core/scripts/generateSite.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../builder.php" -g \ No newline at end of file diff --git a/core/scripts/generateSiteWithCSS.command b/core/scripts/generateSiteWithCSS.command deleted file mode 100755 index b97af439e..000000000 --- a/core/scripts/generateSiteWithCSS.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../builder.php" -gc \ No newline at end of file diff --git a/core/scripts/startAutoReloadServer.command b/core/scripts/startAutoReloadServer.command deleted file mode 100755 index 934877ba6..000000000 --- a/core/scripts/startAutoReloadServer.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../autoReloadServer.php" \ No newline at end of file diff --git a/core/scripts/startPageFollowServer.command b/core/scripts/startPageFollowServer.command deleted file mode 100755 index e3a1e362f..000000000 --- a/core/scripts/startPageFollowServer.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../pageFollowServer.php" \ No newline at end of file diff --git a/core/scripts/startWatcher.command b/core/scripts/startWatcher.command deleted file mode 100755 index 08c37f182..000000000 --- a/core/scripts/startWatcher.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../builder.php" -w \ No newline at end of file diff --git a/core/scripts/startWatcherWithAutoReload.command b/core/scripts/startWatcherWithAutoReload.command deleted file mode 100755 index 14e251966..000000000 --- a/core/scripts/startWatcherWithAutoReload.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../builder.php" -wr \ No newline at end of file diff --git a/core/server/router.php b/core/server/router.php new file mode 100644 index 000000000..02bc4c232 --- /dev/null +++ b/core/server/router.php @@ -0,0 +1,41 @@ +

Further reading: Optimizing Web Experiences for High Resolution Screens

" - }, - { - "el": "#nav", - "title" : "Navigation", - "comment": "

Navigation for adaptive web experiences can be tricky. Top navigations are typical on desktop sites, but mobile screen sizes don't give us the luxury of space. We're dealing with this situation by creating a simple menu anchor that toggles the main navigation on small screens. This is just one method. Bagcheck and Contents Magazine add an anchor in the header that jumps users to the navigation which is placed in the footer. This solution works well because it doesn't require any Javascript in order to work. Other methods exist too. For example, ESPN's mobile navigation overlays the main content of the page.

The nav is only hidden when a certain level of javascript is supported in order to ensure that users with little/poor javascript support can still access the navigation. Once the screen size is large enough to accommodate the nav, we show the main navigation links and hide the menu anchor.

See also: Responsive Navigation Patterns

" - }, - { - "el": ".search-form", - "title" : "Search", - "comment": "

Search is an incredibly important priority, especially for mobile. It is a great idea to give users the ability to jump directly to what they are looking for without forcing them to wade through your site's navigation. Check out the Burton and Yelp mobile sites for great examples of experiences that prioritize search.

We're also using the HTML5 search input type, which is great for mobile devices that can bring up the appropriate virtual keyboard for many smartphones. And like the main header navigation, we're hiding the search form on small screens to save space. Clicking the search anchor toggles the form.

" - }, - { - "el": ".article-header h1", - "title" : "Article Header", - "comment": "

The article header should be no more than 140 characters.

" - }, - { - "el": ".block-hero", - "title" : "Hero", - "comment": "

The hero area highlights one major story using a large image and a captivating headline.

" - } -] -}; \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/00-meta/_00-head.mustache b/core/source/_patterns/00-atoms/00-meta/_00-head.mustache deleted file mode 100644 index 938c0d2db..000000000 --- a/core/source/_patterns/00-atoms/00-meta/_00-head.mustache +++ /dev/null @@ -1,16 +0,0 @@ - - - - {{ title }} - - - - - - - {% pattern-lab-head %} - - - - - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/00-meta/_01-foot.mustache b/core/source/_patterns/00-atoms/00-meta/_01-foot.mustache deleted file mode 100644 index 5bd39a972..000000000 --- a/core/source/_patterns/00-atoms/00-meta/_01-foot.mustache +++ /dev/null @@ -1,6 +0,0 @@ - - - {% pattern-lab-foot %} - - - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/01-global/00-colors.mustache b/core/source/_patterns/00-atoms/01-global/00-colors.mustache deleted file mode 100644 index 7f2653f8d..000000000 --- a/core/source/_patterns/00-atoms/01-global/00-colors.mustache +++ /dev/null @@ -1,38 +0,0 @@ -
    -
  • - - #ff0000 -
  • -
  • - - #00ff00 -
  • -
  • - - #0000ff -
  • -
  • - - #ffff00 -
  • -
  • - - #00ffff -
  • -
  • - - #ff00ff -
  • -
  • - - #ffffff -
  • -
  • - - #808080 -
  • -
  • - - #000000 -
  • -
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/01-global/01-fonts.mustache b/core/source/_patterns/00-atoms/01-global/01-fonts.mustache deleted file mode 100644 index 26b4b7bb5..000000000 --- a/core/source/_patterns/00-atoms/01-global/01-fonts.mustache +++ /dev/null @@ -1,6 +0,0 @@ -

Primary font: "HelveticaNeue", "Helvetica", "Arial", sans-serif;

-

Primary font italic: "HelveticaNeue", "Helvetica", "Arial", sans-serif;

-

Primary font bold: "HelveticaNeue", "Helvetica", "Arial", sans-serif;

-

Secondary font: Georgia, Times, "Times New Roman", serif;

-

Secondary font italic: Georgia, Times, "Times New Roman", serif;

-

Secondary font bold: Georgia, Times, "Times New Roman", serif;

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/01-global/02-animations.mustache b/core/source/_patterns/00-atoms/01-global/02-animations.mustache deleted file mode 100644 index 7d3074575..000000000 --- a/core/source/_patterns/00-atoms/01-global/02-animations.mustache +++ /dev/null @@ -1,3 +0,0 @@ -
Fade: Duration: 0.3s Easing: ease-out (Hover to see effect)
- -
Movement: Duration: 0.8s Easing: ease-in-out; (Hover to see effect)
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/01-global/03-visibility.mustache b/core/source/_patterns/00-atoms/01-global/03-visibility.mustache deleted file mode 100644 index 13e602122..000000000 --- a/core/source/_patterns/00-atoms/01-global/03-visibility.mustache +++ /dev/null @@ -1,11 +0,0 @@ -

This text is hidden on smaller screens

- -

This text is only visible on smaller screens

- -

This text is hidden on medium screens only

- -

This text is only visible on medium screens

- -

This text is hidden on large screens

- -

This text is only visible on large screens

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/00-headings.mustache b/core/source/_patterns/00-atoms/02-text/00-headings.mustache deleted file mode 100644 index 43f648c7f..000000000 --- a/core/source/_patterns/00-atoms/02-text/00-headings.mustache +++ /dev/null @@ -1,6 +0,0 @@ -

Heading Level 1

-

Heading Level 2

-

Heading Level 3

-

Heading Level 4

-
Heading Level 5
-
Heading Level 6
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/01-paragraph.mustache b/core/source/_patterns/00-atoms/02-text/01-paragraph.mustache deleted file mode 100644 index 4ed3f6c01..000000000 --- a/core/source/_patterns/00-atoms/02-text/01-paragraph.mustache +++ /dev/null @@ -1 +0,0 @@ -

A paragraph (from the Greek paragraphos, "to write beside" or "written beside") is a self-contained unit of a discourse in writing dealing with a particular point or idea. A paragraph consists of one or more sentences. Though not required by the syntax of any language, paragraphs are usually an expected part of formal writing, used to organize longer prose.

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/02-blockquote.mustache b/core/source/_patterns/00-atoms/02-text/02-blockquote.mustache deleted file mode 100644 index 2f11319b3..000000000 --- a/core/source/_patterns/00-atoms/02-text/02-blockquote.mustache +++ /dev/null @@ -1,3 +0,0 @@ -
-

A block quotation (also known as a long quotation or extract) is a quotation in a written document, that is set off from the main text as a paragraph, or block of text, and typically distinguished visually using indentation and a different typeface or smaller size quotation.

-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/03-inline-elements.mustache b/core/source/_patterns/00-atoms/02-text/03-inline-elements.mustache deleted file mode 100644 index 47aaa8928..000000000 --- a/core/source/_patterns/00-atoms/02-text/03-inline-elements.mustache +++ /dev/null @@ -1,41 +0,0 @@ -
-

This is a text link

- -

Strong is used to indicate strong importance

- -

This text has added emphasis

- -

The b element is stylistically different text from normal text, without any special importance

- -

The i element is text that is set off from the normal text

- -

The u element is text with an unarticulated, though explicitly rendered, non-textual annotation

- -

This text is deleted and This text is inserted

- -

This text has a strikethrough

- -

Superscript®

- -

Subscript for things like H2O

- -

This small text is small for for fine print, etc.

- -

Abbreviation: HTML

- -

Keybord input: Cmd

- -

This text is a short inline quotation

- -

This is a citation - -

The dfn element indicates a definition.

- -

The mark element indicates a highlight

- -

This is what inline code looks like.

- -

This is sample output from a computer program

- -

The variable element, such as x = y

-
diff --git a/core/source/_patterns/00-atoms/02-text/04-time.mustache b/core/source/_patterns/00-atoms/02-text/04-time.mustache deleted file mode 100644 index 26cecc136..000000000 --- a/core/source/_patterns/00-atoms/02-text/04-time.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/05-preformatted-text.mustache b/core/source/_patterns/00-atoms/02-text/05-preformatted-text.mustache deleted file mode 100644 index 70de25e11..000000000 --- a/core/source/_patterns/00-atoms/02-text/05-preformatted-text.mustache +++ /dev/null @@ -1,9 +0,0 @@ -
  	
-P R E F O R M A T T E D T E X T
-! " # $ % & ' ( ) * + , - . /
-0 1 2 3 4 5 6 7 8 9 : ; < = > ?
-@ A B C D E F G H I J K L M N O
-P Q R S T U V W X Y Z [ \ ] ^ _
-` a b c d e f g h i j k l m n o
-p q r s t u v w x y z { | } ~ 
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/06-hr.mustache b/core/source/_patterns/00-atoms/02-text/06-hr.mustache deleted file mode 100644 index 1d6667d2e..000000000 --- a/core/source/_patterns/00-atoms/02-text/06-hr.mustache +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/03-lists/00-unordered.mustache b/core/source/_patterns/00-atoms/03-lists/00-unordered.mustache deleted file mode 100644 index 3f9de349f..000000000 --- a/core/source/_patterns/00-atoms/03-lists/00-unordered.mustache +++ /dev/null @@ -1,14 +0,0 @@ -
-
    -
  • This is a list item in an unordered list
  • -
  • An unordered list is a list in which the sequence of items is not important. Sometimes, an unordered list is a bulleted list. And this is a long list item in an unordered list that can wrap onto a new line.
  • -
  • - Lists can be nested inside of each other -
      -
    • This is a nested list item
    • -
    • This is another nested list item in an unordered list
    • -
    -
  • -
  • This is the last list item
  • -
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/03-lists/01-ordered.mustache b/core/source/_patterns/00-atoms/03-lists/01-ordered.mustache deleted file mode 100644 index e206c7b10..000000000 --- a/core/source/_patterns/00-atoms/03-lists/01-ordered.mustache +++ /dev/null @@ -1,14 +0,0 @@ -
-
    -
  1. This is a list item in an ordered list
  2. -
  3. An ordered list is a list in which the sequence of items is important. An ordered list does not necessarily contain sequence characters.
  4. -
  5. - Lists can be nested inside of each other -
      -
    1. This is a nested list item
    2. -
    3. This is another nested list item in an ordered list
    4. -
    -
  6. -
  7. This is the last list item
  8. -
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/03-lists/02-definition.mustache b/core/source/_patterns/00-atoms/03-lists/02-definition.mustache deleted file mode 100644 index 0488e0812..000000000 --- a/core/source/_patterns/00-atoms/03-lists/02-definition.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
Definition List
-
A number of connected items or names written or printed consecutively, typically one below the other.
-
This is a term.
-
This is the definition of that term, which both live in a dl.
-
Here is another term.
-
And it gets a definition too, which is this line.
-
Here is term that shares a definition with the term below.
-
And it gets a definition too, which is this line.
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/00-logo.mustache b/core/source/_patterns/00-atoms/04-images/00-logo.mustache deleted file mode 100644 index c0f431f98..000000000 --- a/core/source/_patterns/00-atoms/04-images/00-logo.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/01-landscape-4x3.mustache b/core/source/_patterns/00-atoms/04-images/01-landscape-4x3.mustache deleted file mode 100644 index cf874ee9d..000000000 --- a/core/source/_patterns/00-atoms/04-images/01-landscape-4x3.mustache +++ /dev/null @@ -1 +0,0 @@ -{{ img.landscape-4x3.alt }} \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/02-landscape-16x9.mustache b/core/source/_patterns/00-atoms/04-images/02-landscape-16x9.mustache deleted file mode 100644 index 9efc5eeb3..000000000 --- a/core/source/_patterns/00-atoms/04-images/02-landscape-16x9.mustache +++ /dev/null @@ -1 +0,0 @@ -{{ img.landscape-16x9.alt }} \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/03-square.mustache b/core/source/_patterns/00-atoms/04-images/03-square.mustache deleted file mode 100644 index 805cce5f2..000000000 --- a/core/source/_patterns/00-atoms/04-images/03-square.mustache +++ /dev/null @@ -1 +0,0 @@ -{{ img.square.alt }} \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/04-avatar.mustache b/core/source/_patterns/00-atoms/04-images/04-avatar.mustache deleted file mode 100644 index 6b79ad0c5..000000000 --- a/core/source/_patterns/00-atoms/04-images/04-avatar.mustache +++ /dev/null @@ -1 +0,0 @@ -Avatar \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/05-icons.mustache b/core/source/_patterns/00-atoms/04-images/05-icons.mustache deleted file mode 100644 index 4e2512348..000000000 --- a/core/source/_patterns/00-atoms/04-images/05-icons.mustache +++ /dev/null @@ -1,12 +0,0 @@ -
    -
  • -
  • -
  • -
  • -
  • -
  • -
  • -
  • - -
  • -
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/06-loading-icon.mustache b/core/source/_patterns/00-atoms/04-images/06-loading-icon.mustache deleted file mode 100644 index 9a10165ab..000000000 --- a/core/source/_patterns/00-atoms/04-images/06-loading-icon.mustache +++ /dev/null @@ -1 +0,0 @@ -Loading \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/07-favicon.mustache b/core/source/_patterns/00-atoms/04-images/07-favicon.mustache deleted file mode 100644 index 07e985d37..000000000 --- a/core/source/_patterns/00-atoms/04-images/07-favicon.mustache +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/00-text-fields.mustache b/core/source/_patterns/00-atoms/05-forms/00-text-fields.mustache deleted file mode 100644 index 644ab826c..000000000 --- a/core/source/_patterns/00-atoms/05-forms/00-text-fields.mustache +++ /dev/null @@ -1,38 +0,0 @@ -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/01-select-menu.mustache b/core/source/_patterns/00-atoms/05-forms/01-select-menu.mustache deleted file mode 100644 index 760c9199a..000000000 --- a/core/source/_patterns/00-atoms/05-forms/01-select-menu.mustache +++ /dev/null @@ -1,12 +0,0 @@ -
-
- - -
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/02-checkbox.mustache b/core/source/_patterns/00-atoms/05-forms/02-checkbox.mustache deleted file mode 100644 index 017a8dc5c..000000000 --- a/core/source/_patterns/00-atoms/05-forms/02-checkbox.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
- Checkbox * -
    -
  • -
  • -
  • -
-
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/03-radio-buttons.mustache b/core/source/_patterns/00-atoms/05-forms/03-radio-buttons.mustache deleted file mode 100644 index 68c83eaeb..000000000 --- a/core/source/_patterns/00-atoms/05-forms/03-radio-buttons.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
- Radio -
    -
  • -
  • -
  • -
-
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/04-html5-inputs.mustache b/core/source/_patterns/00-atoms/05-forms/04-html5-inputs.mustache deleted file mode 100644 index 99c22cce7..000000000 --- a/core/source/_patterns/00-atoms/05-forms/04-html5-inputs.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
-
-
-
-
-
-
-
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/06-buttons/00-buttons.mustache b/core/source/_patterns/00-atoms/06-buttons/00-buttons.mustache deleted file mode 100644 index bdbeec360..000000000 --- a/core/source/_patterns/00-atoms/06-buttons/00-buttons.mustache +++ /dev/null @@ -1,4 +0,0 @@ -

Button

-

Alternate Button

-

Disabled Button

-

Text Button

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/07-tables/00-table.mustache b/core/source/_patterns/00-atoms/07-tables/00-table.mustache deleted file mode 100644 index 53153d519..000000000 --- a/core/source/_patterns/00-atoms/07-tables/00-table.mustache +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table Heading 1Table Heading 2Table Heading 3Table Heading 4Table Heading 5
Table Footer 1Table Footer 2Table Footer 3Table Footer 4Table Footer 5
Table Cell 1Table Cell 2Table Cell 3Table Cell 4Table Cell 5
Table Cell 1Table Cell 2Table Cell 3Table Cell 4Table Cell 5
Table Cell 1Table Cell 2Table Cell 3Table Cell 4Table Cell 5
Table Cell 1Table Cell 2Table Cell 3Table Cell 4Table Cell 5
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/08-media/_00-video.mustache b/core/source/_patterns/00-atoms/08-media/_00-video.mustache deleted file mode 100644 index f28fcd7fc..000000000 --- a/core/source/_patterns/00-atoms/08-media/_00-video.mustache +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/08-media/_01-audio.mustache b/core/source/_patterns/00-atoms/08-media/_01-audio.mustache deleted file mode 100644 index 91c82135e..000000000 --- a/core/source/_patterns/00-atoms/08-media/_01-audio.mustache +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/00-byline.mustache b/core/source/_patterns/01-molecules/00-text/00-byline.mustache deleted file mode 100644 index 08366cabe..000000000 --- a/core/source/_patterns/01-molecules/00-text/00-byline.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/01-address.mustache b/core/source/_patterns/01-molecules/00-text/01-address.mustache deleted file mode 100644 index a13ea79fc..000000000 --- a/core/source/_patterns/01-molecules/00-text/01-address.mustache +++ /dev/null @@ -1,11 +0,0 @@ -
-
Company Name
-
-
1234 Main St.
- Anywhere, - 101010, - CA -
U.S.A
-
-
+1.888.123.4567
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/02-heading-group.mustache b/core/source/_patterns/01-molecules/00-text/02-heading-group.mustache deleted file mode 100644 index bf18f5ac4..000000000 --- a/core/source/_patterns/01-molecules/00-text/02-heading-group.mustache +++ /dev/null @@ -1,4 +0,0 @@ -
-

This is the heading group's main heading

-

This is the heading group's subheading

-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/03-blockquote-with-citation.mustache b/core/source/_patterns/01-molecules/00-text/03-blockquote-with-citation.mustache deleted file mode 100644 index b9b6c98fc..000000000 --- a/core/source/_patterns/01-molecules/00-text/03-blockquote-with-citation.mustache +++ /dev/null @@ -1,4 +0,0 @@ -
-

A block quotation (also known as a long quotation or extract) is a quotation in a written document, that is set off from the main text as a paragraph, or block of text, and typically distinguished visually using indentation and a different typeface or smaller size quotation.

- Quote Source -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/04-intro-text.mustache b/core/source/_patterns/01-molecules/00-text/04-intro-text.mustache deleted file mode 100644 index b2b1bdef8..000000000 --- a/core/source/_patterns/01-molecules/00-text/04-intro-text.mustache +++ /dev/null @@ -1 +0,0 @@ -

The intro text may be a lead-in to the passage of text, or it may just be used to create a visual distinction between the rest of the passage of text.

\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/01-layout/00-one-up.mustache b/core/source/_patterns/01-molecules/01-layout/00-one-up.mustache deleted file mode 100644 index eb58a0e24..000000000 --- a/core/source/_patterns/01-molecules/01-layout/00-one-up.mustache +++ /dev/null @@ -1,7 +0,0 @@ -
- -
-
1/1
-
- -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/01-layout/01-two-up.mustache b/core/source/_patterns/01-molecules/01-layout/01-two-up.mustache deleted file mode 100644 index ff1553aee..000000000 --- a/core/source/_patterns/01-molecules/01-layout/01-two-up.mustache +++ /dev/null @@ -1,7 +0,0 @@ -
- -
-
1/2
-
1/2
-
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/01-layout/02-three-up.mustache b/core/source/_patterns/01-molecules/01-layout/02-three-up.mustache deleted file mode 100644 index d68fb4854..000000000 --- a/core/source/_patterns/01-molecules/01-layout/02-three-up.mustache +++ /dev/null @@ -1,8 +0,0 @@ -
- -
-
1/3
-
1/3
-
1/3
-
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/01-layout/03-four-up.mustache b/core/source/_patterns/01-molecules/01-layout/03-four-up.mustache deleted file mode 100644 index f7351c023..000000000 --- a/core/source/_patterns/01-molecules/01-layout/03-four-up.mustache +++ /dev/null @@ -1,9 +0,0 @@ -
- -
-
1/4
-
1/4
-
1/4
-
1/4
-
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/00-media-block.mustache b/core/source/_patterns/01-molecules/02-blocks/00-media-block.mustache deleted file mode 100644 index 4bb4e162e..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/00-media-block.mustache +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/01-block-headline-byline.mustache b/core/source/_patterns/01-molecules/02-blocks/01-block-headline-byline.mustache deleted file mode 100644 index df763126c..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/01-block-headline-byline.mustache +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/02-block-hero.mustache b/core/source/_patterns/01-molecules/02-blocks/02-block-hero.mustache deleted file mode 100644 index 39aa02a34..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/02-block-hero.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/03-block-thumb-headline.mustache b/core/source/_patterns/01-molecules/02-blocks/03-block-thumb-headline.mustache deleted file mode 100644 index 1ef071877..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/03-block-thumb-headline.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/04-block-headline.mustache b/core/source/_patterns/01-molecules/02-blocks/04-block-headline.mustache deleted file mode 100644 index 5a32707f3..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/04-block-headline.mustache +++ /dev/null @@ -1,5 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/05-block-inset.mustache b/core/source/_patterns/01-molecules/02-blocks/05-block-inset.mustache deleted file mode 100644 index 45817ccf8..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/05-block-inset.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/03-media/00-figure-with-caption.mustache b/core/source/_patterns/01-molecules/03-media/00-figure-with-caption.mustache deleted file mode 100644 index 98e2b4435..000000000 --- a/core/source/_patterns/01-molecules/03-media/00-figure-with-caption.mustache +++ /dev/null @@ -1,4 +0,0 @@ -
- {{> atoms-landscape-4x3 }} -
This is an example of an image with a caption. Photo captions, also known as cutlines, are a few lines of text used to explain or elaborate on published photographs.
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/04-forms/00-search.mustache b/core/source/_patterns/01-molecules/04-forms/00-search.mustache deleted file mode 100644 index 604b6125f..000000000 --- a/core/source/_patterns/01-molecules/04-forms/00-search.mustache +++ /dev/null @@ -1,11 +0,0 @@ -
-
- Search - - - -
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/04-forms/01-comment-form.mustache b/core/source/_patterns/01-molecules/04-forms/01-comment-form.mustache deleted file mode 100644 index e4360727b..000000000 --- a/core/source/_patterns/01-molecules/04-forms/01-comment-form.mustache +++ /dev/null @@ -1,20 +0,0 @@ -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/04-forms/02-newsletter.mustache b/core/source/_patterns/01-molecules/04-forms/02-newsletter.mustache deleted file mode 100644 index 041e2319e..000000000 --- a/core/source/_patterns/01-molecules/04-forms/02-newsletter.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/05-navigation/00-primary-nav.mustache b/core/source/_patterns/01-molecules/05-navigation/00-primary-nav.mustache deleted file mode 100644 index 84942ffb7..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/00-primary-nav.mustache +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/core/source/_patterns/01-molecules/05-navigation/01-footer-nav.mustache b/core/source/_patterns/01-molecules/05-navigation/01-footer-nav.mustache deleted file mode 100644 index d46a36b0c..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/01-footer-nav.mustache +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/05-navigation/02-breadcrumbs.mustache b/core/source/_patterns/01-molecules/05-navigation/02-breadcrumbs.mustache deleted file mode 100644 index 3b5c15351..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/02-breadcrumbs.mustache +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/05-navigation/03-pagination.mustache b/core/source/_patterns/01-molecules/05-navigation/03-pagination.mustache deleted file mode 100644 index 8b6de64a3..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/03-pagination.mustache +++ /dev/null @@ -1,9 +0,0 @@ -
    -
  1. 1
  2. -
  3. 2
  4. -
  5. 3
  6. -
  7. 4
  8. -
  9. 5
  10. -
  11. 6
  12. -
  13. 7
  14. -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/05-navigation/04-tabs.mustache b/core/source/_patterns/01-molecules/05-navigation/04-tabs.mustache deleted file mode 100644 index 8e4ec10e2..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/04-tabs.mustache +++ /dev/null @@ -1,7 +0,0 @@ -
- -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/06-components/00-social-share.mustache b/core/source/_patterns/01-molecules/06-components/00-social-share.mustache deleted file mode 100644 index 120527d78..000000000 --- a/core/source/_patterns/01-molecules/06-components/00-social-share.mustache +++ /dev/null @@ -1,8 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/06-components/01-accordion.mustache b/core/source/_patterns/01-molecules/06-components/01-accordion.mustache deleted file mode 100644 index 253962dcb..000000000 --- a/core/source/_patterns/01-molecules/06-components/01-accordion.mustache +++ /dev/null @@ -1,19 +0,0 @@ -
- -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/06-components/02-single-comment.mustache b/core/source/_patterns/01-molecules/06-components/02-single-comment.mustache deleted file mode 100644 index 094229a86..000000000 --- a/core/source/_patterns/01-molecules/06-components/02-single-comment.mustache +++ /dev/null @@ -1,9 +0,0 @@ -
  • -
    - {{> atoms-avatar }} -

    {{ name.first }} {{ name.last }}

    -
    -
    -

    {{ description }}

    -
    -
  • \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/07-messaging/00-alert.mustache b/core/source/_patterns/01-molecules/07-messaging/00-alert.mustache deleted file mode 100644 index 50f390a85..000000000 --- a/core/source/_patterns/01-molecules/07-messaging/00-alert.mustache +++ /dev/null @@ -1,3 +0,0 @@ -
    - {{ excerpt.short }} -
    \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/00-global/00-header.mustache b/core/source/_patterns/02-organisms/00-global/00-header.mustache deleted file mode 100644 index e4a73fb88..000000000 --- a/core/source/_patterns/02-organisms/00-global/00-header.mustache +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/00-global/01-footer.mustache b/core/source/_patterns/02-organisms/00-global/01-footer.mustache deleted file mode 100644 index 63f6fa5ef..000000000 --- a/core/source/_patterns/02-organisms/00-global/01-footer.mustache +++ /dev/null @@ -1,7 +0,0 @@ - -
    -
    - -
    -
    - \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/01-article/00-article-body.mustache b/core/source/_patterns/02-organisms/01-article/00-article-body.mustache deleted file mode 100644 index 9d9b27806..000000000 --- a/core/source/_patterns/02-organisms/01-article/00-article-body.mustache +++ /dev/null @@ -1,22 +0,0 @@ -

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer fringilla sem a urna porttitor fringilla. Nulla eget justo felis.

    - -

    Aliquam erat volutpat. Mauris vulputate scelerisque feugiat. Cras a erat a diam venenatis aliquam. Sed tempus, purus ac pretium varius, risus orci sagittis purus, quis auctor libero magna nec magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas eros dolor, rutrum eu sollicitudin eu, commodo at leo. Suspendisse potenti. Sed eu nibh sit amet quam auctor feugiat vel et risus. Maecenas eu urna adipiscing neque dictum mollis suscipit in augue. Praesent pulvinar condimentum sagittis. Maecenas laoreet neque non eros consectetur fringilla. Donec vitae risus leo, vitae pharetra ipsum. Sed placerat eros eget elit iaculis semper. Aliquam congue blandit orci ac pretium.

    - -{{> atoms-landscape-16x9 }} - -

    Aliquam ultrices cursus mauris, eget volutpat justo mattis nec. Sed a orci turpis. Aliquam aliquet placerat dui, consectetur tincidunt leo tristique et. Vivamus enim nisi, blandit a venenatis quis, convallis et arcu. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris libero sapien, placerat in sodales eu, tempor quis dui. Vivamus egestas faucibus pulvinar. Maecenas eget diam nunc. Phasellus at sem eros, ac suscipit neque. Phasellus sollicitudin libero a odio dignissim scelerisque. Aliquam purus nulla, tempor eget ullamcorper quis, rhoncus non dui. -

    - -{{> atoms-blockquote }} - -

    Cras at fringilla ipsum. Donec nec libero eget est blandit dignissim a eu ante. Morbi augue nulla, luctus eu sagittis vel, malesuada ut felis. Aliquam erat volutpat. Morbi malesuada augue ac massa hendrerit fermentum. Integer scelerisque lacus a dolor convallis lobortis. Curabitur mollis ante in massa ultricies dignissim. -

    - -{{> atoms-unordered }} - -{{> atoms-ordered }} - -

    Donec posuere fringilla nunc, vitae venenatis diam scelerisque vel. Nullam vitae mauris magna. Mauris et diam quis justo volutpat tincidunt congue nec magna. Curabitur vitae orci elit. Ut mollis massa id magna vestibulum consequat. Proin rutrum lectus justo, sit amet tincidunt est. Vivamus vitae lacinia risus. -

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reiciendis, suscipit repellendus nulla accusantium deserunt sed explicabo voluptate sapiente ratione inventore molestiae nihil earum repellat quia odit vitae perspiciatis aliquam amet?

    \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache b/core/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache deleted file mode 100644 index 4901f2bb2..000000000 --- a/core/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache +++ /dev/null @@ -1,12 +0,0 @@ -
    -
    -

    59 Comments

    - {{> molecules-comment-form }} -
      - {{# listItems.five }} - {{> molecules-single-comment }} - {{/ listItems.five }} -
    -
    - {{> molecules-pagination }} -
    \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/03-sections/00-latest-posts.mustache b/core/source/_patterns/02-organisms/03-sections/00-latest-posts.mustache deleted file mode 100644 index 42f32dfa9..000000000 --- a/core/source/_patterns/02-organisms/03-sections/00-latest-posts.mustache +++ /dev/null @@ -1,11 +0,0 @@ -
    -

    Latest Posts

    -
      -
    • {{> molecules-media-block }}
    • -
    • {{> molecules-media-block }}
    • -
    • {{> molecules-media-block }}
    • -
    • {{> molecules-media-block }}
    • -
    • {{> molecules-media-block }}
    • -
    - View more posts -
    \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/03-sections/01-recent-tweets.mustache b/core/source/_patterns/02-organisms/03-sections/01-recent-tweets.mustache deleted file mode 100644 index edd6d568d..000000000 --- a/core/source/_patterns/02-organisms/03-sections/01-recent-tweets.mustache +++ /dev/null @@ -1,12 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/03-sections/02-related-posts.mustache b/core/source/_patterns/02-organisms/03-sections/02-related-posts.mustache deleted file mode 100644 index b4a75cbed..000000000 --- a/core/source/_patterns/02-organisms/03-sections/02-related-posts.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/03-templates/00-homepage.mustache b/core/source/_patterns/03-templates/00-homepage.mustache deleted file mode 100644 index 8d26c6ba0..000000000 --- a/core/source/_patterns/03-templates/00-homepage.mustache +++ /dev/null @@ -1,40 +0,0 @@ -
    - {{> organisms-header }} -
    - {{# emergency }} - {{> molecules-alert:error }} - {{/ emergency }} - {{# hero }} - {{> molecules-block-hero }} - {{/ hero}} - -
    - {{# touts}} -
    - {{> molecules-block-inset }} -
    - {{/ touts}} -
    - -
    - -
    -
    -
    -

    Latest Posts

    -
      - {{# latest-posts }} -
    • {{> molecules-media-block }}
    • - {{/ latest-posts }} -
    - View more posts -
    -
    - - -
    -
    - {{> organisms-footer }} -
    \ No newline at end of file diff --git a/core/source/_patterns/03-templates/01-blog.mustache b/core/source/_patterns/03-templates/01-blog.mustache deleted file mode 100644 index b55a9ba23..000000000 --- a/core/source/_patterns/03-templates/01-blog.mustache +++ /dev/null @@ -1,17 +0,0 @@ -
    - {{> organisms-header }} -
    -

    Our Outdoor Blog

    -
    -
    - {{> organisms-latest-posts }} - {{> molecules-pagination }} -
    - - -
    -
    - {{> organisms-footer }} -
    \ No newline at end of file diff --git a/core/source/_patterns/03-templates/02-article.mustache b/core/source/_patterns/03-templates/02-article.mustache deleted file mode 100644 index 5886df59a..000000000 --- a/core/source/_patterns/03-templates/02-article.mustache +++ /dev/null @@ -1,24 +0,0 @@ -
    - {{> organisms-header }} -
    -
    -
    -
    -
    -

    Article Headline Lorem ipsum dolor sit aweofij

    - {{> molecules-byline }} -
    - {{> organisms-article-body }} -
    - {{> molecules-social-share }} - {{> organisms-comment-thread }} -
    - - -
    -
    - {{> organisms-footer }} -
    \ No newline at end of file diff --git a/core/source/_patterns/04-pages/00-homepage.json b/core/source/_patterns/04-pages/00-homepage.json deleted file mode 100644 index b42aa6061..000000000 --- a/core/source/_patterns/04-pages/00-homepage.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "title" : "Home Page", - "bodyClass": "home", - "emergency" : false, - "hero" : [ - { - "img": { - "landscape-16x9": { - "src": "../../images/sample/landscape-16x9-mountains.jpg", - "alt": "Mountains" - } - }, - "headline" : { - "medium" : "Top 10 mountain ranges for hiking" - } - } - ], - "touts" : [ - { - "img": { - "landscape-4x3": { - "src": "../../images/sample/tout-4x3-climber.jpg", - "alt": "Climber" - } - }, - "headline" : { - "short" : "Extreme climbing tips" - } - }, - { - "img": { - "landscape-4x3": { - "src": "../../images/sample/tout-4x3-stream.jpg", - "alt": "Stream hiking" - } - }, - "headline" : { - "short" : "Stream hiking" - } - }, - { - "img": { - "landscape-4x3": { - "src": "../../images/sample/tout-4x3-climbers.jpg", - "alt": "Explore hiking trails" - } - }, - "headline" : { - "short" : "Explore hiking trails" - } - } - ], - "latest-posts" : [ - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-river.jpg", - "alt": "Post Thumbnail" - } - }, - "headline" : { - "short" : "Navigate the Allegheny River" - }, - "exerpt" : { - "medium" : "The Allegheny River is a principal tributary of the Ohio River; it is located in the Eastern United States. The Allegheny River joins with the Monongahela River to form the Ohio River at the Point of Point State Park in Downtown Pittsburgh, Pennsylvania." - } - }, - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-ivy.jpg", - "alt": "Ivy" - } - }, - "headline" : { - "short" : "How to detect and avoid poison ivy" - }, - "exerpt" : { - "medium" : "Toxicodendron radicans, commonly known as poison ivy is a poisonous North American plant that is well known for its production of urushiol" - } - }, - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-yosemite.jpg", - "alt": "Yosemite" - } - }, - "headline" : { - "short" : "Top 10 hiking mountains" - }, - "exerpt" : { - "medium" : "Yosemite National Park is a United States National Park spanning eastern portions of Tuolumne, Mariposa and Madera counties in the central eastern portion of the U.S. state of California." - } - }, - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-fire.jpg", - "alt": "Fire" - } - }, - "headline" : { - "short" : "How to build a campfire" - }, - "exerpt" : { - "medium" : "A campfire is a fire lit at a campsite, to serve the following functions: light, warmth, a beacon, an insect and/or apex predator deterrent, to cook, and for a psychological sense of security. " - } - }, - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-gear.jpg", - "alt": "Camping Gear" - } - }, - "headline" : { - "short" : "Pick the right camping gear" - }, - "exerpt" : { - "medium" : "The equipment used in camping varies with the particular type of camping. For instance, in survival camping the equipment consists of small items which have the purpose of helping the camper in providing food, heat and safety." - } - } - ], - "inset-blocks" : [ - { - "headline" : "This is the headline for the inset block" - } - ], - "latest-block" : [ - { - "headline" : "This is the headline for the latest block" - } - ] -} \ No newline at end of file diff --git a/core/source/_patterns/04-pages/00-homepage.mustache b/core/source/_patterns/04-pages/00-homepage.mustache deleted file mode 100644 index 68a930daa..000000000 --- a/core/source/_patterns/04-pages/00-homepage.mustache +++ /dev/null @@ -1 +0,0 @@ -{{> templates-homepage }} \ No newline at end of file diff --git a/core/source/_patterns/04-pages/00-homepage~emergency.json b/core/source/_patterns/04-pages/00-homepage~emergency.json deleted file mode 100644 index 2167094b8..000000000 --- a/core/source/_patterns/04-pages/00-homepage~emergency.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "emergency": { - "alertClass" : "error", - "excerpt" : { - "short" : "Emergency! This is a variation of the core homepage template." - } - } -} \ No newline at end of file diff --git a/core/source/_patterns/04-pages/01-blog.json b/core/source/_patterns/04-pages/01-blog.json deleted file mode 100644 index a4d03ba08..000000000 --- a/core/source/_patterns/04-pages/01-blog.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "title" : "Blog", - "bodyClass": "blog", - "latest-posts" : [ - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-river.jpg", - "alt": "Post Thumbnail" - } - }, - "headline" : { - "short" : "Navigate the Allegheny River" - }, - "exerpt" : { - "medium" : "The Allegheny River is a principal tributary of the Ohio River; it is located in the Eastern United States. The Allegheny River joins with the Monongahela River to form the Ohio River at the Point of Point State Park in Downtown Pittsburgh, Pennsylvania." - } - }, - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-ivy.jpg", - "alt": "Ivy" - } - }, - "headline" : { - "short" : "How to detect and avoid poison ivy" - }, - "exerpt" : { - "medium" : "Toxicodendron radicans, commonly known as poison ivy is a poisonous North American plant that is well known for its production of urushiol" - } - }, - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-yosemite.jpg", - "alt": "Yosemite" - } - }, - "headline" : { - "short" : "Top 10 hiking mountains" - }, - "exerpt" : { - "medium" : "Yosemite National Park is a United States National Park spanning eastern portions of Tuolumne, Mariposa and Madera counties in the central eastern portion of the U.S. state of California." - } - }, - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-fire.jpg", - "alt": "Fire" - } - }, - "headline" : { - "short" : "How to build a campfire" - }, - "exerpt" : { - "medium" : "A campfire is a fire lit at a campsite, to serve the following functions: light, warmth, a beacon, an insect and/or apex predator deterrent, to cook, and for a psychological sense of security. " - } - }, - { - "img": { - "square": { - "src": "../../images/sample/thumb-square-gear.jpg", - "alt": "Camping Gear" - } - }, - "headline" : { - "short" : "Pick the right camping gear" - }, - "exerpt" : { - "medium" : "The equipment used in camping varies with the particular type of camping. For instance, in survival camping the equipment consists of small items which have the purpose of helping the camper in providing food, heat and safety." - } - } - ], - "inset-blocks" : [ - { - "headline" : "This is the headline for the inset block" - } - ], - "latest-block" : [ - { - "headline" : "This is the headline for the latest block" - } - ] -} \ No newline at end of file diff --git a/core/source/_patterns/04-pages/01-blog.mustache b/core/source/_patterns/04-pages/01-blog.mustache deleted file mode 100644 index 6d8e26c15..000000000 --- a/core/source/_patterns/04-pages/01-blog.mustache +++ /dev/null @@ -1,25 +0,0 @@ -
    - {{> organisms-header }} -
    -

    Our Outdoor Blog

    -
    -
    -
    - -
      - {{# latest-posts}} -
    • {{> molecules-media-block }}
    • - {{/ latest-posts}} -
    - View more posts -
    - {{> molecules-pagination }} -
    - - -
    -
    - {{> organisms-footer }} -
    \ No newline at end of file diff --git a/core/source/_patterns/04-pages/02-article.json b/core/source/_patterns/04-pages/02-article.json deleted file mode 100644 index 86c4c95d2..000000000 --- a/core/source/_patterns/04-pages/02-article.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title" : "Top 10 Trails You Have To Hike Before You Die", - "bodyClass": "article", - "author" : { - "first-name" : "Julianne", - "last-name" : "McCormick" - }, - "img": { - "landscape-4x3": { - "src": "../../images/sample/landscape-16x9-mountains.jpg", - "alt": "Mountains" - }, - "landscape-16x9": { - "src": "../../images/sample/landscape-16x9-mountains.jpg", - "alt": "Mountains" - } - }, - "inset-blocks" : [ - { - "headline" : "This is the headline for the inset block" - } - ], - "latest-block" : [ - { - "headline" : "This is the headline for the latest block" - } - ] -} \ No newline at end of file diff --git a/core/source/_patterns/04-pages/02-article.mustache b/core/source/_patterns/04-pages/02-article.mustache deleted file mode 100644 index 0449d165c..000000000 --- a/core/source/_patterns/04-pages/02-article.mustache +++ /dev/null @@ -1 +0,0 @@ -{{> templates-article }} \ No newline at end of file diff --git a/core/source/css/scss/base/_animation.scss b/core/source/css/scss/base/_animation.scss deleted file mode 100644 index d28bc9136..000000000 --- a/core/source/css/scss/base/_animation.scss +++ /dev/null @@ -1,13 +0,0 @@ -.animate-fade { - @include transition(opacity, 0.3s, ease-out); - - &:hover { - opacity: 0; - } -} - -.animate-move { - > .demo-shape { - @include transition(all, 0.8s, ease-in-out); - } -} \ No newline at end of file diff --git a/core/source/css/scss/base/_forms.scss b/core/source/css/scss/base/_forms.scss deleted file mode 100644 index 1c02c6a83..000000000 --- a/core/source/css/scss/base/_forms.scss +++ /dev/null @@ -1,111 +0,0 @@ -/*------------------------------------*\ - $FORMS -\*------------------------------------*/ -form ol, form ul { - list-style: none; - margin-left: 0; -} - -fieldset { - border: 0; - padding: 0; - margin: 0; -} - -label { - display: block; - padding-bottom: $space-half; -} - -button, input, select, textarea { - font-family: inherit; - font-size: 100%; - margin: 0 1px 0; -} - -input, textarea { - width: 100%; - border: 1px solid $gray; - padding: $pad-half 0.65rem; -} - -input[type=text], input[type=search], input[type=url], input[type=number], textarea { - -webkit-appearance: none; -} - -button, input[type="submit"] { - padding: $pad-half; - background: $gray-dark; - border: 1px solid $gray; - cursor: pointer; -} - -input[type="checkbox"], -input[type="radio"] { - width: auto; - margin-right: 0.3em; -} - -input[type="search"] { - -webkit-appearance: none; - border-radius: 0; -} - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -//Form Field Container -.field-container { - margin-bottom: $space; -} - -.inline-form { - fieldset, .inline-container { - position: relative; - } - - input[type=submit], button, .btn { - font-size: $font-size-small-2; - padding: 0.65rem 1.3rem; - background: $gray-dark; - position: absolute; - top: 0; - right: 0; - z-index: 1; - width: auto; - - &:hover, &:focus { - background: $gray; - color: $white; - } - } -} - -/* Validation */ -.has-error { - border-color: $error; -} -.is-valid { - border-color: $valid; -} - - - - -/*------------------------------------*\ - $SPECIFIC FORMS -\*------------------------------------*/ - -/* Search Form */ -.search-field { - padding-right: 3em; -} -.inline-form .search-submit { - background: none; - padding: 0.78em 1em; - border: 0; - border-left: 1px solid $gray; - color: $gray; -} diff --git a/core/source/css/scss/base/_global-classes.scss b/core/source/css/scss/base/_global-classes.scss deleted file mode 100644 index 2e13f8858..000000000 --- a/core/source/css/scss/base/_global-classes.scss +++ /dev/null @@ -1,104 +0,0 @@ -/*------------------------------------*\ - $GLOBAL CLASSES -\*------------------------------------*/ - -/* Clearfix */ -.cf { - *zoom: 1; -} -.cf:before, .cf:after { - content: " "; /* 1 */ - display: table; /* 2 */ -} - -.cf:after { - clear: both; -} - -/* Completely remove from the flow and screen readers. */ -.is-hidden { - display: none !important; - visibility: hidden !important; -} - -/* Completely remove from the flow but leave available to screen readers. */ -.is-vishidden { - position: absolute !important; - overflow: hidden; - width: 1px; - height: 1px; - padding: 0; - border: 0; - clip: rect(1px, 1px, 1px, 1px); -} - -/* Floats */ -.right { - float: right; - padding: 0 0 $pad $pad; -} - -.right-search { - float: right; - padding: 0 0 $pad 0; -} - -.left { - float: left; - padding: 0 $pad $pad 0; -} - -/* Text-Align */ -.align-right { - text-align: right; -} - -.align-center { - text-align: center; -} - -.align-left { - text-align: left; -} - -/* Display Classes */ -.hide-small { - @media all and (max-width: $bp-med) { - display: none; - } -} - -.hide-med { - @media all and (min-width: $bp-med) and (max-width: $bp-large) { - display: none; - } -} - -.hide-large { - @media all and (min-width: $bp-large) { - display: none; - } -} - -//States -.valid { - color: $valid; -} - -.error { - color: $error; -} - -.warning { - color: $warning; -} - -.information { - color: $information; -} - -.font-secondary { - font-family: $font-secondary; -} - - diff --git a/core/source/css/scss/base/_headings.scss b/core/source/css/scss/base/_headings.scss deleted file mode 100644 index 5f2433645..000000000 --- a/core/source/css/scss/base/_headings.scss +++ /dev/null @@ -1,31 +0,0 @@ -/* Headings */ -/*Further Reading: http:/csswizardry.com/2012/02/pragmatic-practical-font-sizing-in-css/ */ -h1, .alpha { - line-height: 1.2; -} - -h2, .beta { - line-height: 1.2; -} - -h3, .gamma { - line-height: 1.2; -} - -h4, .delta { - -} - -h5, .epsilon { - -} - -h6, .zeta { - -} - -/* Subheadings */ -.subheading { - font-family: $font-secondary; - font-weight: normal; -} diff --git a/core/source/css/scss/base/_links.scss b/core/source/css/scss/base/_links.scss deleted file mode 100644 index d70545d76..000000000 --- a/core/source/css/scss/base/_links.scss +++ /dev/null @@ -1,10 +0,0 @@ -/* Links */ -a { - color: $gray-dark; - text-decoration: none; - outline: 0; - - &:hover, &:focus { - color: $gray; - } -} \ No newline at end of file diff --git a/core/source/css/scss/base/_lists.scss b/core/source/css/scss/base/_lists.scss deleted file mode 100644 index 4ceb7cf5c..000000000 --- a/core/source/css/scss/base/_lists.scss +++ /dev/null @@ -1,19 +0,0 @@ -ol, ul { - margin: 0; - padding: 0; - list-style: none; -} - -/* Definition Lists */ -dl { - overflow: hidden; - margin: 0 0 $space; -} - -dt { - font-weight: bold; -} - -dd { - margin-left: 0; -} \ No newline at end of file diff --git a/core/source/css/scss/base/_main.scss b/core/source/css/scss/base/_main.scss deleted file mode 100644 index f92fd1b34..000000000 --- a/core/source/css/scss/base/_main.scss +++ /dev/null @@ -1,6 +0,0 @@ -body { - background: $white; - font: 100%/1.5 $font; - -webkit-text-size-adjust: 100%; - color: $gray-dark; -} \ No newline at end of file diff --git a/core/source/css/scss/base/_media.scss b/core/source/css/scss/base/_media.scss deleted file mode 100644 index ec74c8ffc..000000000 --- a/core/source/css/scss/base/_media.scss +++ /dev/null @@ -1,23 +0,0 @@ -/*------------------------------------*\ - $MEDIA ELEMENTS -\*------------------------------------*/ - -/* Flexible Media */ -img, video, object { - max-width: 100%; - height: auto; -} - -iframe { - margin-bottom: $space; -} - -figure { - margin-bottom: $space; - img { - margin-bottom: $space-half; - } -} -figcaption { - font-style: italic; -} \ No newline at end of file diff --git a/core/source/css/scss/base/_tables.scss b/core/source/css/scss/base/_tables.scss deleted file mode 100644 index 1b2a2b2c4..000000000 --- a/core/source/css/scss/base/_tables.scss +++ /dev/null @@ -1,18 +0,0 @@ -/*------------------------------------*\ - $Table -\*------------------------------------*/ -table { - border-collapse: collapse; - border-spacing: 0; - border: 1px solid $gray; - width: 100%; -} -th { - text-align: left; - border: 1px solid $gray; - padding: 0.2em; -} -td { - border: 1px solid $gray; - padding: 0.2em; -} \ No newline at end of file diff --git a/core/source/css/scss/base/_text.scss b/core/source/css/scss/base/_text.scss deleted file mode 100644 index de17e3ec6..000000000 --- a/core/source/css/scss/base/_text.scss +++ /dev/null @@ -1,26 +0,0 @@ -/* Text-Related Elements */ -p { - margin-bottom: $space; -} - -/* Blockquote */ -blockquote { - font-style:italic; - border-left: 1px solid $gray; - color: $gray; - padding-left: $pad; - margin-bottom: $space; -} - -/* Horizontal Rule */ -hr { - border: 0; - height: 2px; - background: $gray-light-2; - margin: $space-double 0; -} - -abbr { - border-bottom: 1px dotted $gray; - cursor: help; -} \ No newline at end of file diff --git a/core/source/css/scss/generic/_mixins.scss b/core/source/css/scss/generic/_mixins.scss deleted file mode 100644 index 14d8a2a3d..000000000 --- a/core/source/css/scss/generic/_mixins.scss +++ /dev/null @@ -1,23 +0,0 @@ -/*------------------------------------*\ - $MIXINS -\*------------------------------------*/ - -/* CSS Transition - Usage: @include transition(width,0.3s,ease-out); - */ -@mixin transition($transition-property, $transition-time, $method) { - -webkit-transition: $transition-property $transition-time $method; - -moz-transition: $transition-property $transition-time $method; - -ms-transition: $transition-property $transition-time $method; - -o-transition: $transition-property $transition-time $method; - transition: $transition-property $transition-time $method; -} - -/* Rem Unit font sizes with relative fallback http:/seesparkbox.com/foundry/scss_rem_mixin_now_with_a_better_fallback - Usage: @include font-size(1, large); -*/ -@mixin font-size( $decimal-size, $keyword: null ) { - @if $keyword{ font-size: $keyword; } - @else { font-size: $decimal-size * $base-font-multiplier * 16px;} - font-size: $decimal-size * 1rem; -} \ No newline at end of file diff --git a/core/source/css/scss/generic/_reset.scss b/core/source/css/scss/generic/_reset.scss deleted file mode 100644 index e7807ec72..000000000 --- a/core/source/css/scss/generic/_reset.scss +++ /dev/null @@ -1,17 +0,0 @@ -/*------------------------------------*\ - $RESET -\*------------------------------------*/ - -/* Border-Box http:/paulirish.com/2012/box-sizing-border-box-ftw/ */ -* { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; -} -html, body, div, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, ol, ul, li, form, legend, label, table, header, footer, nav, section, figure { - margin: 0; - padding: 0; -} -header, footer, nav, section, article, hgroup, figure { - display: block; -} \ No newline at end of file diff --git a/core/source/css/scss/generic/_variables.scss b/core/source/css/scss/generic/_variables.scss deleted file mode 100644 index 3e7ccbcba..000000000 --- a/core/source/css/scss/generic/_variables.scss +++ /dev/null @@ -1,65 +0,0 @@ -/*------------------------------------*\ - $VARIABLES -\*------------------------------------*/ - -//Colors -$gray : #808080; -$gray-light : #f9f9f9; -$gray-light-2 : #eee; -$gray-light-3 : #ddd; -$gray-med : #666; -$gray-dark : #333; -$gray-dark-2 : #131313; -$white : #fff; -$black : #000; -$dim : rgba(0,0,0,0.5); -$error : #f00; -$valid : #089e00; -$warning : #fff664; -$information : #000db5; - - -//Typography -$font : "HelveticaNeue", "Helvetica", "Arial", sans-serif; -$font-secondary : Georgia, Times, "Times New Roman", serif; - -$font-size-small : 0.75em; -$font-size-small-2 : 0.875em; -$font-size-med : 1em; -$font-size-med-2: 1.0625em; -$font-size-large : 1.4375em; - - -//Layout -$max-width: 72em; - -//Defaults -$space : 1em; -$space-and-half : $space*1.5; -$space-double : $space*2; -$space-quad : $space*4; -$space-half : $space/2; -$pad : 1em; -$pad-and-half : $pad*1.5; -$pad-double : $pad*2; -$pad-half : $pad/2; -$pad-quarter :$pad/4; - -//Borders -$border-med: 3px; -$border-thick: 7px; - - -//Breakpoints -$bp-small : 24em; -$bp-small-2 : 29.75em; -$bp-small-3 : 39.8em; -$bp-med : 46.8em; -$bp-med-2 : 48em; -$bp-large : 50em; -$bp-large-2 : 66em; -$bp-xl : 73em; -$bp-xxl : 89em; -$bp-xxxl : 93em; - -// \ No newline at end of file diff --git a/core/source/css/scss/objects/_accordion.scss b/core/source/css/scss/objects/_accordion.scss deleted file mode 100644 index 3423544c9..000000000 --- a/core/source/css/scss/objects/_accordion.scss +++ /dev/null @@ -1,33 +0,0 @@ -.accordion { - margin-bottom: $space; -} - -.acc-handle { - background: $gray-dark-2; - color: $white; - font-family: $font-secondary; - font-weight: bold; - display: block; - position: relative; - padding: $pad-half; - border-bottom: 1px solid $gray-light-3; - - &:after { - content:"+"; - float: right; - } - - &:hover { - color: $white; - background: $gray-dark; - - } - - &.active { - background: $gray-dark; - - &:after { - content:"-"; - } - } -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_article.scss b/core/source/css/scss/objects/_article.scss deleted file mode 100644 index 55387309e..000000000 --- a/core/source/css/scss/objects/_article.scss +++ /dev/null @@ -1,34 +0,0 @@ -//Article -.article-header { - h1 { - font-size: 2.5em; - } -} - -.byline { - font-size: $font-size-small-2; - font-style: italic; - margin-bottom: $space-half; -} - -//Social Share -.social-share { - overflow: hidden; - margin-bottom: $space; - - li { - float: left; - margin-right: $space-half; - } - - a { - background: $gray-dark; - color: $white; - display: block; - padding: $pad-half; - - &:hover { - background: $gray; - } - } -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_blocks.scss b/core/source/css/scss/objects/_blocks.scss deleted file mode 100644 index 160963bd6..000000000 --- a/core/source/css/scss/objects/_blocks.scss +++ /dev/null @@ -1,138 +0,0 @@ -/* Generic Placeholder Brick: REMOVE FOR PRODUCTION */ -.brick { - background: #dcdddc; - padding: $pad-double; - text-align: center; - font-weight: bold; - border-bottom: 1px solid $gray-light-2; -} - -/* Block */ -.block { - overflow: hidden; - - p:last-child { - margin-bottom: 0; - } -} - -.headline { - line-height: 1.2; -} - -/* Hero Block */ -.block-hero { - margin-bottom: $space-half; - - .b-thumb { - img { - display: block; - } - } - - @media all and (min-width: $bp-large) { - position: relative; - - .b-text { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - background: $dim; - color: $white; - padding: $pad-and-half; - } - } -} - -/* Block Thumbnail with Headline */ -.block-thumb { - display: table; - width: 100%; - border-collapse: collapse; - - .b-inner { - display: table-row; - vertical-align: top; - overflow: hidden; - } - - .b-thumb { - @media all and (min-width: $bp-small-2) { - display: table-cell; - vertical-align: top; - width: 30%; - max-width: 10em; - - img { - display: block; - width: 100%; - height: auto; - } - } - } - - .b-text { - @media all and (min-width: $bp-small-2) { - display: table-cell; - width: 70%; - padding: 0 $pad; - } - } -} - - -/* Block Headline Summary */ -.block-headline-summary { - a { - display: block; - padding: $pad-half; - } -} - -/* Block Inset */ -.block-inset { - position: relative; - - .b-thumb { - position: relative; - z-index: 0; - - img { - display: block; - } - } -} - -/* Hero Block */ -.block-inset { - margin-bottom: $space-half; - position: relative; - - .headline { - font-size: 1.1em; - } - - .b-text { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - background: $dim; - color: $white; - padding: $pad-half; - } -} - -/* Block Thumb with Summary */ -.block-thumb-summary { - .b-thumb { - float: left; - width: 50%; - } - - .b-text { - margin-left: 50%; - padding: $pad-half; - } -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_buttons.scss b/core/source/css/scss/objects/_buttons.scss deleted file mode 100644 index 0ae2805e1..000000000 --- a/core/source/css/scss/objects/_buttons.scss +++ /dev/null @@ -1,40 +0,0 @@ -/*------------------------------------*\ - $BUTTONS -\*------------------------------------*/ -.btn { - display: inline-block; - background: $gray-dark; - color: $white; - line-height: 1; - font-weight: bold; - padding: $pad; - border: 0; - text-align: center; - - &:hover, &:focus { - background: $gray; - color: $white; - } - - &.disabled { - background: $gray-light-2; - color: $gray; - } -} - -.btn-small { - padding: $pad-half; -} - -.btn-large { - padding: $pad-half; - text-transform: uppercase; - background: $gray; - font-size: 1.4rem; - font-weight: normal; -} - - -.text-btn { - font-style: italic; -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_carousels.scss b/core/source/css/scss/objects/_carousels.scss deleted file mode 100644 index 77e3f197b..000000000 --- a/core/source/css/scss/objects/_carousels.scss +++ /dev/null @@ -1,38 +0,0 @@ -/* Horizontal Carousel */ -.carousel-horizontal { - margin-bottom: $space; - overflow: hidden; - position: relative; -} - -.carousel-island-container { - overflow: hidden; -} - -.carousel-container { - position: relative; -} - -.carousel-list { - -} - -.carousel-controls { - display: table; - width: 100%; - margin: (-$space-half) 0 $space; - - a, div { - display: table-cell; - padding: $pad-half; - } - - .carousel-pagination { - text-align: center; - } - - .carousel-next { - text-align: right; - } - -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_comments.scss b/core/source/css/scss/objects/_comments.scss deleted file mode 100644 index 9959b7abf..000000000 --- a/core/source/css/scss/objects/_comments.scss +++ /dev/null @@ -1,30 +0,0 @@ -.comments { - li { - margin-bottom: $space; - } -} - -.comment-container { - overflow: hidden; - margin-bottom: $space; - list-style: none; -} - -.comment-meta { - float: left; - width: 6.5em; - - img { - display: block; - border: 1px solid $gray-light-2; - margin-bottom: $space-half; - } -} - -.comment-name { - font-size: $font-size-small; -} - -.comment-text { - margin-left: 9em; -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_footer.scss b/core/source/css/scss/objects/_footer.scss deleted file mode 100644 index 850f94bf4..000000000 --- a/core/source/css/scss/objects/_footer.scss +++ /dev/null @@ -1,39 +0,0 @@ -/*------------------------------------*\ - $FOOTER -\*------------------------------------*/ -.footer { - clear: both; - overflow: hidden; - background: $gray-dark-2; - color: $white; - line-height: 1.2; - - a { - color: $gray-light; - } -} - -//Footer Nav -.nav-footer { - margin: (-$pad) (-$pad) $space; - - li { - border-bottom: 1px solid $gray-dark; - - @media all and (min-width: $bp-med) { - border: 0; - float: left; - } - } - - a { - display: block; - padding: $pad; - } -} - -.copyright { - @media all and (min-width: $bp-med) { - float: right; - } -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_header.scss b/core/source/css/scss/objects/_header.scss deleted file mode 100644 index 8fb78d7ce..000000000 --- a/core/source/css/scss/objects/_header.scss +++ /dev/null @@ -1,45 +0,0 @@ -.header { - background: $white; - padding: 0; - border-bottom: 1px solid #dbdbdb; - @extend .lc; -} - -.logo { - float: left; - max-width: 8rem; - margin: 0.4rem; - - @media all and (min-width: $bp-med) { - max-width: 9rem; - } -} - -.nav-toggle { - float: right; - display: block; - padding: 0.9rem 1rem 0.7rem; - font-size: 1.3rem; - line-height: 1; - border-left: 1px solid #dbdbdb; - - @media all and (min-width: $bp-med) { - display: none; - } - - @media all and (max-width: 17em) { - padding-left: 0.2rem; - padding-right: 0.2rem; - } -} - -.search-form { - overflow: hidden; - max-height: 0; - - @media all and (min-width: $bp-med) { - float: right; - max-height: none; - margin: 0.65em 0.5em 0 0; - } -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_icons.scss b/core/source/css/scss/objects/_icons.scss deleted file mode 100644 index cacbf1fbd..000000000 --- a/core/source/css/scss/objects/_icons.scss +++ /dev/null @@ -1,125 +0,0 @@ - -/* Icon Font */ -@font-face { - font-family: 'icons'; - src:url('../fonts/icons.eot'); - src:url('../fonts/icons.eot?#iefix') format('embedded-opentype'), - url('../fonts/icons.woff') format('woff'), - url('../fonts/icons.ttf') format('truetype'), - url('../fonts/icons.svg#icons') format('svg'); - font-weight: normal; - font-style: normal; -} - -/* Use the following CSS code if you want to use data attributes for inserting your icons */ -[data-icon]:before { - font-family: 'icons'; - content: attr(data-icon); - speak: none; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; -} - -.icon-twitter:before, .icon-stumbleupon:before, .icon-pinterest:before, .icon-linkedin:before, .icon-google-plus:before, .icon-search:before, .icon-play:before, .icon-menu:before, .icon-arrow-left:before, .icon-arrow-right:before, .icon-bubble:before, .icon-facebook:before, .icon-feed:before, .icon-youtube:before, .icon-tag:before, .icon-tumblr:before, .icon-instagram, .icon-podcast, .icon-apple,.icon-android, .icon-arrow:after, .icon-envelope:before { - font-family: 'icons'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - -webkit-font-smoothing: antialiased; -} -.icon-twitter:before { - content: "\74"; -} -.icon-stumbleupon:before { - content: "\75"; -} -.icon-pinterest:before { - content: "\70"; -} -.icon-linkedin:before { - content: "\69"; -} -.icon-google-plus:before { - content: "\67"; -} -.icon-search:before { - content: "\73"; -} -.icon-play:before { - content: "\61"; -} -.icon-menu:before { - content: "\21"; -} -.icon-arrow-left:before { - content: "\23"; -} -.icon-arrow-right:before { - content: "\24"; -} -.icon-bubble:before { - content: "\25"; -} -.icon-facebook:before { - content: "\66"; -} -.icon-feed:before { - content: "\27"; -} -.icon-youtube:before { - content: "\79"; -} -.icon-tag:before { - content: "\28"; -} -.icon-tumblr:before { - content: "\6d"; -} -.icon-instagram:before { - content: "\22"; -} -.icon-podcast:before { - content: "\26"; -} -.icon-android:before { - content: "\29"; -} -.icon-apple:before { - content: "\2a"; -} -.icon-envelope:before { - content: "\2b"; -} - - -.icon-arrow:after { - content: "\61"; - display: inline-block; - -webkit-transform: rotate(90deg); - -moz-transform: rotate(90deg); - -ms-transform: rotate(90deg); - -o-transform: rotate(90deg); - transform: rotate(90deg); -} - -.icon-play:before { - font-size: 0.7rem; - padding-left: 0.2em; -} - -.icon-play-box { - display: block; - margin-left: $pad-double; -} - -.icon-play-box:before { - padding: $pad-quarter; - background: $gray; - color: $white; - margin-left: -1.7rem; - margin-right: $pad-half; -} diff --git a/core/source/css/scss/objects/_layout.scss b/core/source/css/scss/objects/_layout.scss deleted file mode 100644 index 4929d28e3..000000000 --- a/core/source/css/scss/objects/_layout.scss +++ /dev/null @@ -1,288 +0,0 @@ -/*------------------------------------*\ - $LAYOUT -\*------------------------------------*/ - -/* Layout Container */ -.lc { - max-width: $max-width; - margin: 0 auto; - padding: $pad-half; -} - -/*------------------------------------*\ - $TEMPLATES -\*------------------------------------*/ - -/* Two Column Layout */ -.l-two-col { - @extend .cf; - - .l-main { - @media all and (min-width: $bp-large) { - float: left; - width: 70%; - padding-right: $pad; - } - } - - .l-sidebar { - @media all and (max-width: $bp-large) { - clear: both; - } - - @media all and (min-width: $bp-large) { - float: left; - width: 30%; - padding: 0 0 0 $pad; - } - } -} - - -/*------------------------------------*\ - $GRIDS -\*------------------------------------*/ - -/* Grid Container */ -.g { - overflow: hidden; - margin: 0 (-$pad-half); -} - -/* Grid Item */ -.gi { - padding: $pad-half; - - img { - display: block; - } - - @media all and (min-width: $bp-med) { - float: left; - } -} - -/* Grid 1up */ -.g-1up { - .gi { - width: 100%; - } -} - -/* Grid 2up */ -.g-2up { - @media all and (min-width: $bp-med) { - > .gi { - float: left; - width: 50%; - - &:nth-of-type(odd) { - clear: left; - } - } - } -} - -/* Grid Half (Always displayed side by side) */ -.g-half { - > .gi { - float: left; - width: 50%; - - &:nth-of-type(odd) { - clear: left; - } - } -} - -/* Grid 3up */ -.g-3up { - @media all and (min-width: $bp-med) { - > .gi { - float: left; - width: 50%; - - &:nth-of-type(2n+1) { - clear: left; - } - } - } - - @media all and (min-width: $bp-large) { - > .gi { - width: 33.3333333%; - - &:nth-of-type(2n+1) { - clear: none; - } - - &:nth-of-type(3n+1) { - clear: left; - } - } - } -} - -/* Grid 4up */ -.g-4up { - @media all and (min-width: $bp-med) { - >.gi { - float: left; - width: 50%; - - &:nth-of-type(2n+1) { - clear: both; - } - } - } - - @media all and (min-width: $bp-large) { - >.gi { - width: 25%; - - &:nth-of-type(2n+1) { - clear: none; - } - - &:nth-of-type(4n+1) { - clear: left; - } - } - } -} - -/* Grid Quarter (Always displayed side by side) */ -.g-quarter { - > .gi { - float: left; - width: 24%; - - &:nth-of-type(4n+1) { - clear: left; - } - } -} - -.g-max4 { - - @media all and (min-width: $bp-small-2) { - >.gi { - float: left; - width: 50%; - - &:nth-of-type(2n+1) { - clear: both; - } - } - } - - @media all and (min-width: $bp-small-3) { - >.gi { - width: 33.3333333%; - - &:nth-of-type(2n+1) { - clear: none; - } - - &:nth-of-type(3n+1) { - clear: left; - } - } - } - - @media all and (min-width: $bp-large) { - >.gi { - width: 25%; - - &:nth-of-type(3n+1) { - clear: none; - } - - &:nth-of-type(4n+1) { - clear: left; - } - } - } -} - -/* Grid 5up */ -.g-max5 { - - >.gi { - float: left; - width: 50%; - - &:nth-of-type(2n+1) { - clear: both; - } - } - - @media all and (min-width: $bp-small-3) { - >.gi { - width: 33.3333333%; - - &:nth-of-type(2n+1) { - clear: none; - } - - &:nth-of-type(3n+1) { - clear: left; - } - } - } - - @media all and (min-width: $bp-med) { - >.gi { - width: 25%; - - &:nth-of-type(3n+1) { - clear: none; - } - - &:nth-of-type(4n+1) { - clear: left; - } - } - } - - @media all and (min-width: $bp-med-2) { - >.gi { - width: 20%; - - &:nth-of-type(4n+1) { - clear: none; - } - - &:nth-of-type(5n+1) { - clear: left; - } - } - } -} - -/* Grid 2/3 */ -.gi-2-3 { - @media all and (min-width: $bp-med) { - float: left; - width: 66.666666%; - } -} - -.gi-1-3 { - @media all and (min-width: $bp-med) { - float: left; - width: 33.333333%; - } -} - -/* Grid 4up block */ -.g-opposites { - .gi { - float: left; - - &:last-child { - float: right; - text-align: right; - } - } -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_lists.scss b/core/source/css/scss/objects/_lists.scss deleted file mode 100644 index 0c4e8beaa..000000000 --- a/core/source/css/scss/objects/_lists.scss +++ /dev/null @@ -1,63 +0,0 @@ -.inline-list { - li { - display: inline-block; - } -} - -/* Social List */ -.social-list { - li { - margin: 0 0.4rem $space 0; - } - - a { - font-size: 1.6em; - } -} - - -/* Headline List */ -.headline-list { - margin-bottom: $space; - - &.flush { - margin: 0; - } - - h4 { - font-weight: normal; - } - - li { - padding: $pad-quarter 0; - border-top: 1px solid $gray-light-3; - } -} - -/* Post List */ -.post-list { - li { - margin-bottom: $space; - } -} - -/* Bullet List */ -.bullet-list { - list-style: square; - margin: 0 0 1em 1.2em; - line-height: 1.3; - - li { - margin-bottom: $space; - } -} - -/* Text List */ -.text-list { - margin: 0 0 1em; - line-height: 1.3; - - li { - margin-bottom: $space; - } -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_main.scss b/core/source/css/scss/objects/_main.scss deleted file mode 100644 index 592c01dea..000000000 --- a/core/source/css/scss/objects/_main.scss +++ /dev/null @@ -1,9 +0,0 @@ -/*------------------------------------*\ - $MAIN CONTENT AREA -\*------------------------------------*/ -[role=main] { - padding: $pad-half $pad-half $pad-double; - overflow: hidden; - @extend .lc; - @extend .cf; -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_messaging.scss b/core/source/css/scss/objects/_messaging.scss deleted file mode 100644 index a2d31a92e..000000000 --- a/core/source/css/scss/objects/_messaging.scss +++ /dev/null @@ -1,18 +0,0 @@ -/*------------------------------------*\ - $MESSAGING -\*------------------------------------*/ - -// Alerts -.alert { - text-align: center; - padding: $pad; - margin-bottom: $space-half; - border: 1px solid $gray; - background: $gray-light; -} - -.alert-error { - color: $error; - border-color: $error; - background: #ffbebe; -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_nav.scss b/core/source/css/scss/objects/_nav.scss deleted file mode 100644 index b98e3300e..000000000 --- a/core/source/css/scss/objects/_nav.scss +++ /dev/null @@ -1,52 +0,0 @@ -/*------------------------------------*\ - $NAVIGATION -\*------------------------------------*/ - -.nav { - clear: both; - overflow: hidden; - max-height: 0; - - a { - display: block; - padding: $pad; - border-top: 1px solid $gray-light-2; - } - - &.active { - max-height: 40em; - } - - @media all and (min-width: $bp-med) { - max-height: none; - float: right; - clear: none; - - li { - float: left; - } - - a { - border: 0; - } - - } -} - -//Pagination -.pagination { - overflow: hidden; - - li { - float: left; - border-right: 1px solid $gray-light-2; - - &:last-child { - border: 0; - } - } - - a { - padding: $pad; - } -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_sections.scss b/core/source/css/scss/objects/_sections.scss deleted file mode 100644 index 7235af263..000000000 --- a/core/source/css/scss/objects/_sections.scss +++ /dev/null @@ -1,7 +0,0 @@ -.section { - margin: 0 0 $space; -} - -.section-title { - margin-bottom: $space-half; -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_tabs.scss b/core/source/css/scss/objects/_tabs.scss deleted file mode 100644 index b22ca7438..000000000 --- a/core/source/css/scss/objects/_tabs.scss +++ /dev/null @@ -1,33 +0,0 @@ -.tabs { - overflow: hidden; - - ul { - display: table; - width: 100%; - } - - li { - display: table-cell; - text-align: center; - border-right: 1px solid $gray-light-3; - - &:last-child { - border-right: 0; - } - } - - a { - display: block; - padding: $pad-half; - background: $gray; - - &:hover, &:focus { - background: $gray-light-3; - } - - &.active { - background: $gray-dark; - color: $white; - } - } -} \ No newline at end of file diff --git a/core/source/css/scss/objects/_text.scss b/core/source/css/scss/objects/_text.scss deleted file mode 100644 index d645f5646..000000000 --- a/core/source/css/scss/objects/_text.scss +++ /dev/null @@ -1,41 +0,0 @@ -//Intro text -.intro { - font-size: $font-size-med-2; - font-weight: bold; -} - -//Pullquote -.pullquote { - font-family: $font-secondary; - font-size: $font-size-large; -} - -//Caption -.caption { - font-style: italic; -} - -//Passages of text -.text { - a { - text-decoration: underline; - } - - ul { - list-style: disc; - margin: 0 0 $space 1.2em; - - ul { - margin-bottom: 0; - } - } - - ol { - list-style: decimal; - margin: 0 0 $space 1.5em; - - ol { - margin-bottom: 0; - } - } -} diff --git a/core/source/css/scss/objects/_tooltip.scss b/core/source/css/scss/objects/_tooltip.scss deleted file mode 100644 index e0fdd95da..000000000 --- a/core/source/css/scss/objects/_tooltip.scss +++ /dev/null @@ -1,42 +0,0 @@ -.tooltip-container { - display: inline-block; - position: relative; - - &:hover { - .tooltip { - display: block; - } - } -} - -.tooltip-link { - background: $gray-light; -} - -.tooltip { - display: none; - position: absolute; - top: 1.5em; - left: 0; - width: 18em; - padding: $pad; - background: $white; - border: 1px solid $gray; - box-shadow: 0.3em 0.3em 1em 0 rgba(0,0,0,0.2); - - h2 { - margin-top: 0; - } - - @media all and (min-width: $bp-small) { - width: 22em; - } - - @media all and (min-width: $bp-small-2) { - width: 27em; - } - - @media all and (min-width: $bp-small-3) { - width: 30em; - } -} \ No newline at end of file diff --git a/core/source/css/style.css b/core/source/css/style.css deleted file mode 100644 index 67f12faf0..000000000 --- a/core/source/css/style.css +++ /dev/null @@ -1,1103 +0,0 @@ -/* - ,, ,, ,, - .M"""bgd mm db `7MM mm mm `7MM OO OO OO -,MI "Y MM MM MM MM MM 88 88 88 -`MMb. mmMMmm ,pW"Wq.`7MMpdMAo. `7Mb,od8 `7MM .P"Ybmmm MMpMMMb.mmMMmm mmMMmm MMpMMMb. .gP"Ya `7Mb,od8 .gP"Ya || || || - `YMMNq. MM 6W' `Wb MM `Wb MM' "' MM :MI I8 MM MM MM MM MM MM ,M' Yb MM' "',M' Yb || || || -. `MM MM 8M M8 MM M8 MM MM WmmmP" MM MM MM MM MM MM 8M"""""" MM 8M"""""" `' `' `' -Mb dM MM YA. ,A9 MM ,AP MM MM 8M MM MM MM MM MM MM YM. , MM YM. , ,, ,, ,, -P"Ybmmd" `Mbmo`Ybmd9' MMbmmd' .JMML. .JMML.YMMMMMb .JMML JMML.`Mbmo `Mbmo.JMML JMML.`Mbmmd'.JMML. `Mbmmd' db db db - MM 6' dP - .JMML. Ybmmmd' - -Pattern Lab doesn't have any CSS requirements, which means you can write your styles however you want. Hooray! -You can use Sass, Less, vanilla CSS, or some other crazy thing I haven't heard of yet. -So please don't use these styles. They're just here to put together the demo, and nothing more. -They're intentionally gray, boring, and crappy because you're supposed to do this stuff yourself. - -Atomic design is philosophically complimentary with these CSS approaches: - -* SMACSS by Jonathan Snook http://smacss.com/ -* OOCSS by Nicole Sullivan http://oocss.org/ -* BEM CSS Methology : http://bem.info/method/ -* CSS Guidelines by Harry Roberts : https://github.com/csswizardry/CSS-Guidelines - -So feel free to use any of these approaches. Or don't. It's totally up to you. - -*/ -/*------------------------------------*\ - $TABLE OF CONTENTS - based generally on Harry Roberts excellent CSS Guidelines https://github.com/csswizardry/CSS-Guidelines -\*------------------------------------*/ -/** - * VARIABLES..............................Declarations of Sass variables - * .....Colors - * .....Typography - * .....Layout - * .....Defaults - * .....Breakpoints - * MIXINS.................................Sass mixins - * RESET..................................Set reset defaults - * GLOBAL CLASSES.........................Set reset defaults - * GLOBAL ELEMENTS........................Establish global styles - * .....Main - * .....Headings - * .....Text-related elements (p, blockquote, lists) - * .....Defaults - * .....Breakpoints - * TYPOGRAPHY------------------------------ - * MEDIA------------------------------ - * LAYOUT------------------------------ - * NAVIGATION------------------------------ - * TOC To Be Continued - */ -/*------------------------------------*\ - $VARIABLES -\*------------------------------------*/ -/*------------------------------------*\ - $MIXINS -\*------------------------------------*/ -/* CSS Transition - Usage: @include transition(width,0.3s,ease-out); - */ -/* Rem Unit font sizes with relative fallback http:/seesparkbox.com/foundry/scss_rem_mixin_now_with_a_better_fallback - Usage: @include font-size(1, large); -*/ -/*------------------------------------*\ - $RESET -\*------------------------------------*/ -/* Border-Box http:/paulirish.com/2012/box-sizing-border-box-ftw/ */ -* { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; } - -html, body, div, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, ol, ul, li, form, legend, label, table, header, footer, nav, section, figure { - margin: 0; - padding: 0; } - -header, footer, nav, section, article, hgroup, figure { - display: block; } - -/*------------------------------------*\ - $GLOBAL ELEMENTS -\*------------------------------------*/ -/*------------------------------------*\ - $GLOBAL CLASSES -\*------------------------------------*/ -/* Clearfix */ -.cf, .l-two-col, [role=main] { - *zoom: 1; } - -.cf:before, .l-two-col:before, [role=main]:before, .cf:after, .l-two-col:after, [role=main]:after { - content: " "; - /* 1 */ - display: table; - /* 2 */ } - -.cf:after, .l-two-col:after, [role=main]:after { - clear: both; } - -/* Completely remove from the flow and screen readers. */ -.is-hidden { - display: none !important; - visibility: hidden !important; } - -/* Completely remove from the flow but leave available to screen readers. */ -.is-vishidden { - position: absolute !important; - overflow: hidden; - width: 1px; - height: 1px; - padding: 0; - border: 0; - clip: rect(1px, 1px, 1px, 1px); } - -/* Floats */ -.right { - float: right; - padding: 0 0 1em 1em; } - -.right-search { - float: right; - padding: 0 0 1em 0; } - -.left { - float: left; - padding: 0 1em 1em 0; } - -/* Text-Align */ -.align-right { - text-align: right; } - -.align-center { - text-align: center; } - -.align-left { - text-align: left; } - -/* Display Classes */ -@media all and (max-width: 46.8em) { - .hide-small { - display: none; } } - -@media all and (min-width: 46.8em) and (max-width: 50em) { - .hide-med { - display: none; } } - -@media all and (min-width: 50em) { - .hide-large { - display: none; } } - -.valid { - color: #089e00; } - -.error { - color: red; } - -.warning { - color: #fff664; } - -.information { - color: #000db5; } - -.font-secondary { - font-family: Georgia, Times, "Times New Roman", serif; } - -body { - background: white; - font: 100%/1.5 "HelveticaNeue", "Helvetica", "Arial", sans-serif; - -webkit-text-size-adjust: 100%; - color: #333333; } - -/* Links */ -a { - color: #333333; - text-decoration: none; - outline: 0; } - a:hover, a:focus { - color: gray; } - -/* Headings */ -/*Further Reading: http:/csswizardry.com/2012/02/pragmatic-practical-font-sizing-in-css/ */ -h1, .alpha { - line-height: 1.2; } - -h2, .beta { - line-height: 1.2; } - -h3, .gamma { - line-height: 1.2; } - -/* Subheadings */ -.subheading { - font-family: Georgia, Times, "Times New Roman", serif; - font-weight: normal; } - -/* Text-Related Elements */ -p { - margin-bottom: 1em; } - -/* Blockquote */ -blockquote { - font-style: italic; - border-left: 1px solid gray; - color: gray; - padding-left: 1em; - margin-bottom: 1em; } - -/* Horizontal Rule */ -hr { - border: 0; - height: 2px; - background: #eeeeee; - margin: 2em 0; } - -abbr { - border-bottom: 1px dotted gray; - cursor: help; } - -ol, ul { - margin: 0; - padding: 0; - list-style: none; } - -/* Definition Lists */ -dl { - overflow: hidden; - margin: 0 0 1em; } - -dt { - font-weight: bold; } - -dd { - margin-left: 0; } - -/*------------------------------------*\ - $MEDIA ELEMENTS -\*------------------------------------*/ -/* Flexible Media */ -img, video, object { - max-width: 100%; - height: auto; } - -iframe { - margin-bottom: 1em; } - -figure { - margin-bottom: 1em; } - figure img { - margin-bottom: 0.5em; } - -figcaption { - font-style: italic; } - -/*------------------------------------*\ - $FORMS -\*------------------------------------*/ -form ol, form ul { - list-style: none; - margin-left: 0; } - -fieldset { - border: 0; - padding: 0; - margin: 0; } - -label { - display: block; - padding-bottom: 0.5em; } - -button, input, select, textarea { - font-family: inherit; - font-size: 100%; - margin: 0 1px 0; } - -input, textarea { - width: 100%; - border: 1px solid gray; - padding: 0.5em 0.65rem; } - -input[type=text], input[type=search], input[type=url], input[type=number], textarea { - -webkit-appearance: none; } - -button, input[type="submit"] { - padding: 0.5em; - background: #333333; - border: 1px solid gray; - cursor: pointer; } - -input[type="checkbox"], -input[type="radio"] { - width: auto; - margin-right: 0.3em; } - -input[type="search"] { - -webkit-appearance: none; - border-radius: 0; } - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; } - -.field-container { - margin-bottom: 1em; } - -.inline-form fieldset, .inline-form .inline-container { - position: relative; } -.inline-form input[type=submit], .inline-form button, .inline-form .btn { - font-size: 0.875em; - padding: 0.65rem 1.3rem; - background: #333333; - position: absolute; - top: 0; - right: 0; - z-index: 1; - width: auto; } - .inline-form input[type=submit]:hover, .inline-form input[type=submit]:focus, .inline-form button:hover, .inline-form button:focus, .inline-form .btn:hover, .inline-form .btn:focus { - background: gray; - color: white; } - -/* Validation */ -.has-error { - border-color: red; } - -.is-valid { - border-color: #089e00; } - -/*------------------------------------*\ - $SPECIFIC FORMS -\*------------------------------------*/ -/* Search Form */ -.search-field { - padding-right: 3em; } - -.inline-form .search-submit { - background: none; - padding: 0.78em 1em; - border: 0; - border-left: 1px solid gray; - color: gray; } - -/*------------------------------------*\ - $Table -\*------------------------------------*/ -table { - border-collapse: collapse; - border-spacing: 0; - border: 1px solid gray; - width: 100%; } - -th { - text-align: left; - border: 1px solid gray; - padding: 0.2em; } - -td { - border: 1px solid gray; - padding: 0.2em; } - -.animate-fade { - -webkit-transition: opacity 0.3s ease-out; - -moz-transition: opacity 0.3s ease-out; - -ms-transition: opacity 0.3s ease-out; - -o-transition: opacity 0.3s ease-out; - transition: opacity 0.3s ease-out; } - .animate-fade:hover { - opacity: 0; } - -.animate-move > .demo-shape { - -webkit-transition: all 0.8s ease-in-out; - -moz-transition: all 0.8s ease-in-out; - -ms-transition: all 0.8s ease-in-out; - -o-transition: all 0.8s ease-in-out; - transition: all 0.8s ease-in-out; } - -/*------------------------------------*\ - $LAYOUT -\*------------------------------------*/ -/*------------------------------------*\ - $LAYOUT -\*------------------------------------*/ -/* Layout Container */ -.lc, .header, [role=main] { - max-width: 72em; - margin: 0 auto; - padding: 0.5em; } - -/*------------------------------------*\ - $TEMPLATES -\*------------------------------------*/ -/* Two Column Layout */ -@media all and (min-width: 50em) { - .l-two-col .l-main { - float: left; - width: 70%; - padding-right: 1em; } } -@media all and (max-width: 50em) { - .l-two-col .l-sidebar { - clear: both; } } -@media all and (min-width: 50em) { - .l-two-col .l-sidebar { - float: left; - width: 30%; - padding: 0 0 0 1em; } } - -/*------------------------------------*\ - $GRIDS -\*------------------------------------*/ -/* Grid Container */ -.g { - overflow: hidden; - margin: 0 -0.5em; } - -/* Grid Item */ -.gi { - padding: 0.5em; } - .gi img { - display: block; } - @media all and (min-width: 46.8em) { - .gi { - float: left; } } - -/* Grid 1up */ -.g-1up .gi { - width: 100%; } - -/* Grid 2up */ -@media all and (min-width: 46.8em) { - .g-2up > .gi { - float: left; - width: 50%; } - .g-2up > .gi:nth-of-type(odd) { - clear: left; } } - -/* Grid Half (Always displayed side by side) */ -.g-half > .gi { - float: left; - width: 50%; } - .g-half > .gi:nth-of-type(odd) { - clear: left; } - -/* Grid 3up */ -@media all and (min-width: 46.8em) { - .g-3up > .gi { - float: left; - width: 50%; } - .g-3up > .gi:nth-of-type(2n+1) { - clear: left; } } -@media all and (min-width: 50em) { - .g-3up > .gi { - width: 33.3333333%; } - .g-3up > .gi:nth-of-type(2n+1) { - clear: none; } - .g-3up > .gi:nth-of-type(3n+1) { - clear: left; } } - -/* Grid 4up */ -@media all and (min-width: 46.8em) { - .g-4up > .gi { - float: left; - width: 50%; } - .g-4up > .gi:nth-of-type(2n+1) { - clear: both; } } -@media all and (min-width: 50em) { - .g-4up > .gi { - width: 25%; } - .g-4up > .gi:nth-of-type(2n+1) { - clear: none; } - .g-4up > .gi:nth-of-type(4n+1) { - clear: left; } } - -/* Grid Quarter (Always displayed side by side) */ -.g-quarter > .gi { - float: left; - width: 24%; } - .g-quarter > .gi:nth-of-type(4n+1) { - clear: left; } - -@media all and (min-width: 29.75em) { - .g-max4 > .gi { - float: left; - width: 50%; } - .g-max4 > .gi:nth-of-type(2n+1) { - clear: both; } } -@media all and (min-width: 39.8em) { - .g-max4 > .gi { - width: 33.3333333%; } - .g-max4 > .gi:nth-of-type(2n+1) { - clear: none; } - .g-max4 > .gi:nth-of-type(3n+1) { - clear: left; } } -@media all and (min-width: 50em) { - .g-max4 > .gi { - width: 25%; } - .g-max4 > .gi:nth-of-type(3n+1) { - clear: none; } - .g-max4 > .gi:nth-of-type(4n+1) { - clear: left; } } - -/* Grid 5up */ -.g-max5 > .gi { - float: left; - width: 50%; } - .g-max5 > .gi:nth-of-type(2n+1) { - clear: both; } -@media all and (min-width: 39.8em) { - .g-max5 > .gi { - width: 33.3333333%; } - .g-max5 > .gi:nth-of-type(2n+1) { - clear: none; } - .g-max5 > .gi:nth-of-type(3n+1) { - clear: left; } } -@media all and (min-width: 46.8em) { - .g-max5 > .gi { - width: 25%; } - .g-max5 > .gi:nth-of-type(3n+1) { - clear: none; } - .g-max5 > .gi:nth-of-type(4n+1) { - clear: left; } } -@media all and (min-width: 48em) { - .g-max5 > .gi { - width: 20%; } - .g-max5 > .gi:nth-of-type(4n+1) { - clear: none; } - .g-max5 > .gi:nth-of-type(5n+1) { - clear: left; } } - -/* Grid 2/3 */ -@media all and (min-width: 46.8em) { - .gi-2-3 { - float: left; - width: 66.666666%; } } - -@media all and (min-width: 46.8em) { - .gi-1-3 { - float: left; - width: 33.333333%; } } - -/* Grid 4up block */ -.g-opposites .gi { - float: left; } - .g-opposites .gi:last-child { - float: right; - text-align: right; } - -/*------------------------------------*\ - $PAGE STRUCTURE -\*------------------------------------*/ -.header { - background: white; - padding: 0; - border-bottom: 1px solid #dbdbdb; } - -.logo { - float: left; - max-width: 8rem; - margin: 0.4rem; } - @media all and (min-width: 46.8em) { - .logo { - max-width: 9rem; } } - -.nav-toggle { - float: right; - display: block; - padding: 0.9rem 1rem 0.7rem; - font-size: 1.3rem; - line-height: 1; - border-left: 1px solid #dbdbdb; } - @media all and (min-width: 46.8em) { - .nav-toggle { - display: none; } } - @media all and (max-width: 17em) { - .nav-toggle { - padding-left: 0.2rem; - padding-right: 0.2rem; } } - -.search-form { - overflow: hidden; - max-height: 0; } - @media all and (min-width: 46.8em) { - .search-form { - float: right; - max-height: none; - margin: 0.65em 0.5em 0 0; } } - -/*------------------------------------*\ - $NAVIGATION -\*------------------------------------*/ -.nav { - clear: both; - overflow: hidden; - max-height: 0; } - .nav a { - display: block; - padding: 1em; - border-top: 1px solid #eeeeee; } - .nav.active { - max-height: 40em; } - @media all and (min-width: 46.8em) { - .nav { - max-height: none; - float: right; - clear: none; } - .nav li { - float: left; } - .nav a { - border: 0; } } - -.pagination { - overflow: hidden; } - .pagination li { - float: left; - border-right: 1px solid #eeeeee; } - .pagination li:last-child { - border: 0; } - .pagination a { - padding: 1em; } - -/*------------------------------------*\ - $MAIN CONTENT AREA -\*------------------------------------*/ -[role=main] { - padding: 0.5em 0.5em 2em; - overflow: hidden; } - -/*------------------------------------*\ - $FOOTER -\*------------------------------------*/ -.footer { - clear: both; - overflow: hidden; - background: #131313; - color: white; - line-height: 1.2; } - .footer a { - color: #f9f9f9; } - -.nav-footer { - margin: -1em -1em 1em; } - .nav-footer li { - border-bottom: 1px solid #333333; } - @media all and (min-width: 46.8em) { - .nav-footer li { - border: 0; - float: left; } } - .nav-footer a { - display: block; - padding: 1em; } - -@media all and (min-width: 46.8em) { - .copyright { - float: right; } } - -/*------------------------------------*\ - $TEXT Styles -\*------------------------------------*/ -.intro { - font-size: 1.0625em; - font-weight: bold; } - -.pullquote { - font-family: Georgia, Times, "Times New Roman", serif; - font-size: 1.4375em; } - -.caption { - font-style: italic; } - -.text a { - text-decoration: underline; } -.text ul { - list-style: disc; - margin: 0 0 1em 1.2em; } - .text ul ul { - margin-bottom: 0; } -.text ol { - list-style: decimal; - margin: 0 0 1em 1.5em; } - .text ol ol { - margin-bottom: 0; } - -/*------------------------------------*\ - $COMPONENTS -\*------------------------------------*/ -/* Icon Font */ -@font-face { - font-family: 'icons'; - src: url("../fonts/icons.eot"); - src: url("../fonts/icons.eot?#iefix") format("embedded-opentype"), url("../fonts/icons.woff") format("woff"), url("../fonts/icons.ttf") format("truetype"), url("../fonts/icons.svg#icons") format("svg"); - font-weight: normal; - font-style: normal; } - -/* Use the following CSS code if you want to use data attributes for inserting your icons */ -[data-icon]:before { - font-family: 'icons'; - content: attr(data-icon); - speak: none; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; } - -.icon-twitter:before, .icon-stumbleupon:before, .icon-pinterest:before, .icon-linkedin:before, .icon-google-plus:before, .icon-search:before, .icon-play:before, .icon-menu:before, .icon-arrow-left:before, .icon-arrow-right:before, .icon-bubble:before, .icon-facebook:before, .icon-feed:before, .icon-youtube:before, .icon-tag:before, .icon-tumblr:before, .icon-instagram, .icon-podcast, .icon-apple, .icon-android, .icon-arrow:after, .icon-envelope:before { - font-family: 'icons'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - -webkit-font-smoothing: antialiased; } - -.icon-twitter:before { - content: "\74"; } - -.icon-stumbleupon:before { - content: "\75"; } - -.icon-pinterest:before { - content: "\70"; } - -.icon-linkedin:before { - content: "\69"; } - -.icon-google-plus:before { - content: "\67"; } - -.icon-search:before { - content: "\73"; } - -.icon-play:before { - content: "\61"; } - -.icon-menu:before { - content: "\21"; } - -.icon-arrow-left:before { - content: "\23"; } - -.icon-arrow-right:before { - content: "\24"; } - -.icon-bubble:before { - content: "\25"; } - -.icon-facebook:before { - content: "\66"; } - -.icon-feed:before { - content: "\27"; } - -.icon-youtube:before { - content: "\79"; } - -.icon-tag:before { - content: "\28"; } - -.icon-tumblr:before { - content: "\6d"; } - -.icon-instagram:before { - content: "\22"; } - -.icon-podcast:before { - content: "\26"; } - -.icon-android:before { - content: "\29"; } - -.icon-apple:before { - content: "\2a"; } - -.icon-envelope:before { - content: "\2b"; } - -.icon-arrow:after { - content: "\61"; - display: inline-block; - -webkit-transform: rotate(90deg); - -moz-transform: rotate(90deg); - -ms-transform: rotate(90deg); - -o-transform: rotate(90deg); - transform: rotate(90deg); } - -.icon-play:before { - font-size: 0.7rem; - padding-left: 0.2em; } - -.icon-play-box { - display: block; - margin-left: 2em; } - -.icon-play-box:before { - padding: 0.25em; - background: gray; - color: white; - margin-left: -1.7rem; - margin-right: 0.5em; } - -/*------------------------------------*\ - $BUTTONS -\*------------------------------------*/ -.btn { - display: inline-block; - background: #333333; - color: white; - line-height: 1; - font-weight: bold; - padding: 1em; - border: 0; - text-align: center; } - .btn:hover, .btn:focus { - background: gray; - color: white; } - .btn.disabled { - background: #eeeeee; - color: gray; } - -.btn-small { - padding: 0.5em; } - -.btn-large { - padding: 0.5em; - text-transform: uppercase; - background: gray; - font-size: 1.4rem; - font-weight: normal; } - -.text-btn { - font-style: italic; } - -/* Generic Placeholder Brick: REMOVE FOR PRODUCTION */ -.brick { - background: #dcdddc; - padding: 2em; - text-align: center; - font-weight: bold; - border-bottom: 1px solid #eeeeee; } - -/* Block */ -.block { - overflow: hidden; } - .block p:last-child { - margin-bottom: 0; } - -.headline { - line-height: 1.2; } - -/* Hero Block */ -.block-hero { - margin-bottom: 0.5em; } - .block-hero .b-thumb img { - display: block; } - @media all and (min-width: 50em) { - .block-hero { - position: relative; } - .block-hero .b-text { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - background: rgba(0, 0, 0, 0.5); - color: white; - padding: 1.5em; } } - -/* Block Thumbnail with Headline */ -.block-thumb { - display: table; - width: 100%; - border-collapse: collapse; } - .block-thumb .b-inner { - display: table-row; - vertical-align: top; - overflow: hidden; } - @media all and (min-width: 29.75em) { - .block-thumb .b-thumb { - display: table-cell; - vertical-align: top; - width: 30%; - max-width: 10em; } - .block-thumb .b-thumb img { - display: block; - width: 100%; - height: auto; } } - @media all and (min-width: 29.75em) { - .block-thumb .b-text { - display: table-cell; - width: 70%; - padding: 0 1em; } } - -/* Block Headline Summary */ -.block-headline-summary a { - display: block; - padding: 0.5em; } - -/* Block Inset */ -.block-inset { - position: relative; } - .block-inset .b-thumb { - position: relative; - z-index: 0; } - .block-inset .b-thumb img { - display: block; } - -/* Hero Block */ -.block-inset { - margin-bottom: 0.5em; - position: relative; } - .block-inset .headline { - font-size: 1.1em; } - .block-inset .b-text { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - background: rgba(0, 0, 0, 0.5); - color: white; - padding: 0.5em; } - -/* Block Thumb with Summary */ -.block-thumb-summary .b-thumb { - float: left; - width: 50%; } -.block-thumb-summary .b-text { - margin-left: 50%; - padding: 0.5em; } - -.inline-list li { - display: inline-block; } - -/* Social List */ -.social-list li { - margin: 0 0.4rem 1em 0; } -.social-list a { - font-size: 1.6em; } - -/* Headline List */ -.headline-list { - margin-bottom: 1em; } - .headline-list.flush { - margin: 0; } - .headline-list h4 { - font-weight: normal; } - .headline-list li { - padding: 0.25em 0; - border-top: 1px solid #dddddd; } - -/* Post List */ -.post-list li { - margin-bottom: 1em; } - -/* Bullet List */ -.bullet-list { - list-style: square; - margin: 0 0 1em 1.2em; - line-height: 1.3; } - .bullet-list li { - margin-bottom: 1em; } - -/* Text List */ -.text-list { - margin: 0 0 1em; - line-height: 1.3; } - .text-list li { - margin-bottom: 1em; } - -.tooltip-container { - display: inline-block; - position: relative; } - .tooltip-container:hover .tooltip { - display: block; } - -.tooltip-link { - background: #f9f9f9; } - -.tooltip { - display: none; - position: absolute; - top: 1.5em; - left: 0; - width: 18em; - padding: 1em; - background: white; - border: 1px solid gray; - box-shadow: 0.3em 0.3em 1em 0 rgba(0, 0, 0, 0.2); } - .tooltip h2 { - margin-top: 0; } - @media all and (min-width: 24em) { - .tooltip { - width: 22em; } } - @media all and (min-width: 29.75em) { - .tooltip { - width: 27em; } } - @media all and (min-width: 39.8em) { - .tooltip { - width: 30em; } } - -.accordion { - margin-bottom: 1em; } - -.acc-handle { - background: #131313; - color: white; - font-family: Georgia, Times, "Times New Roman", serif; - font-weight: bold; - display: block; - position: relative; - padding: 0.5em; - border-bottom: 1px solid #dddddd; } - .acc-handle:after { - content: "+"; - float: right; } - .acc-handle:hover { - color: white; - background: #333333; } - .acc-handle.active { - background: #333333; } - .acc-handle.active:after { - content: "-"; } - -.tabs { - overflow: hidden; } - .tabs ul { - display: table; - width: 100%; } - .tabs li { - display: table-cell; - text-align: center; - border-right: 1px solid #dddddd; } - .tabs li:last-child { - border-right: 0; } - .tabs a { - display: block; - padding: 0.5em; - background: gray; } - .tabs a:hover, .tabs a:focus { - background: #dddddd; } - .tabs a.active { - background: #333333; - color: white; } - -.section { - margin: 0 0 1em; } - -.section-title { - margin-bottom: 0.5em; } - -.article-header h1 { - font-size: 2.5em; } - -.byline { - font-size: 0.875em; - font-style: italic; - margin-bottom: 0.5em; } - -.social-share { - overflow: hidden; - margin-bottom: 1em; } - .social-share li { - float: left; - margin-right: 0.5em; } - .social-share a { - background: #333333; - color: white; - display: block; - padding: 0.5em; } - .social-share a:hover { - background: gray; } - -.comments li { - margin-bottom: 1em; } - -.comment-container { - overflow: hidden; - margin-bottom: 1em; - list-style: none; } - -.comment-meta { - float: left; - width: 6.5em; } - .comment-meta img { - display: block; - border: 1px solid #eeeeee; - margin-bottom: 0.5em; } - -.comment-name { - font-size: 0.75em; } - -.comment-text { - margin-left: 9em; } - -/*------------------------------------*\ - $MESSAGING -\*------------------------------------*/ -.alert { - text-align: center; - padding: 1em; - margin-bottom: 0.5em; - border: 1px solid gray; - background: #f9f9f9; } - -.alert-error { - color: red; - border-color: red; - background: #ffbebe; } diff --git a/core/source/css/style.scss b/core/source/css/style.scss deleted file mode 100644 index b749f20f7..000000000 --- a/core/source/css/style.scss +++ /dev/null @@ -1,121 +0,0 @@ -/* - ,, ,, ,, - .M"""bgd mm db `7MM mm mm `7MM OO OO OO -,MI "Y MM MM MM MM MM 88 88 88 -`MMb. mmMMmm ,pW"Wq.`7MMpdMAo. `7Mb,od8 `7MM .P"Ybmmm MMpMMMb.mmMMmm mmMMmm MMpMMMb. .gP"Ya `7Mb,od8 .gP"Ya || || || - `YMMNq. MM 6W' `Wb MM `Wb MM' "' MM :MI I8 MM MM MM MM MM MM ,M' Yb MM' "',M' Yb || || || -. `MM MM 8M M8 MM M8 MM MM WmmmP" MM MM MM MM MM MM 8M"""""" MM 8M"""""" `' `' `' -Mb dM MM YA. ,A9 MM ,AP MM MM 8M MM MM MM MM MM MM YM. , MM YM. , ,, ,, ,, -P"Ybmmd" `Mbmo`Ybmd9' MMbmmd' .JMML. .JMML.YMMMMMb .JMML JMML.`Mbmo `Mbmo.JMML JMML.`Mbmmd'.JMML. `Mbmmd' db db db - MM 6' dP - .JMML. Ybmmmd' - -Pattern Lab doesn't have any CSS requirements, which means you can write your styles however you want. Hooray! -You can use Sass, Less, vanilla CSS, or some other crazy thing I haven't heard of yet. -So please don't use these styles. They're just here to put together the demo, and nothing more. -They're intentionally gray, boring, and crappy because you're supposed to do this stuff yourself. - -Atomic design is philosophically complimentary with these CSS approaches: - -* SMACSS by Jonathan Snook http://smacss.com/ -* OOCSS by Nicole Sullivan http://oocss.org/ -* BEM CSS Methology : http://bem.info/method/ -* CSS Guidelines by Harry Roberts : https://github.com/csswizardry/CSS-Guidelines - -So feel free to use any of these approaches. Or don't. It's totally up to you. - -*/ - -/*------------------------------------*\ - $TABLE OF CONTENTS - based generally on Harry Roberts excellent CSS Guidelines https://github.com/csswizardry/CSS-Guidelines -\*------------------------------------*/ -/** - * VARIABLES..............................Declarations of Sass variables - * .....Colors - * .....Typography - * .....Layout - * .....Defaults - * .....Breakpoints - * MIXINS.................................Sass mixins - * RESET..................................Set reset defaults - * GLOBAL CLASSES.........................Set reset defaults - * GLOBAL ELEMENTS........................Establish global styles - * .....Main - * .....Headings - * .....Text-related elements (p, blockquote, lists) - * .....Defaults - * .....Breakpoints - * TYPOGRAPHY------------------------------ - * MEDIA------------------------------ - * LAYOUT------------------------------ - * NAVIGATION------------------------------ - * TOC To Be Continued - */ - - - -@import "scss/generic/variables"; -@import "scss/generic/mixins"; -@import "scss/generic/reset"; - - - - - -/*------------------------------------*\ - $GLOBAL ELEMENTS -\*------------------------------------*/ -@import "scss/base/global-classes"; -@import "scss/base/main"; -@import "scss/base/links"; -@import "scss/base/headings"; -@import "scss/base/text"; -@import "scss/base/lists"; -@import "scss/base/media"; -@import "scss/base/forms"; -@import "scss/base/tables"; -@import "scss/base/animation"; - - - - - -/*------------------------------------*\ - $LAYOUT -\*------------------------------------*/ -@import "scss/objects/layout"; - - -/*------------------------------------*\ - $PAGE STRUCTURE -\*------------------------------------*/ -@import "scss/objects/header"; -@import "scss/objects/nav"; -@import "scss/objects/main"; -@import "scss/objects/footer"; - - - -/*------------------------------------*\ - $TEXT Styles -\*------------------------------------*/ -@import "scss/objects/text"; - - -/*------------------------------------*\ - $COMPONENTS -\*------------------------------------*/ -@import "scss/objects/icons"; -@import "scss/objects/buttons"; -@import "scss/objects/blocks"; -@import "scss/objects/lists"; -@import "scss/objects/tooltip"; -@import "scss/objects/accordion"; -@import "scss/objects/tabs"; -@import "scss/objects/sections"; -@import "scss/objects/article"; -@import "scss/objects/comments"; -@import "scss/objects/messaging"; - - diff --git a/core/source/favicon.ico b/core/source/favicon.ico deleted file mode 100644 index eee4aa78f..000000000 Binary files a/core/source/favicon.ico and /dev/null differ diff --git a/core/source/fonts/icons.dev.svg b/core/source/fonts/icons.dev.svg deleted file mode 100644 index ca8e49e3a..000000000 --- a/core/source/fonts/icons.dev.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/core/source/fonts/icons.eot b/core/source/fonts/icons.eot deleted file mode 100644 index 81a314b08..000000000 Binary files a/core/source/fonts/icons.eot and /dev/null differ diff --git a/core/source/fonts/icons.svg b/core/source/fonts/icons.svg deleted file mode 100644 index 3c64026b6..000000000 --- a/core/source/fonts/icons.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/core/source/fonts/icons.ttf b/core/source/fonts/icons.ttf deleted file mode 100644 index e6bff0814..000000000 Binary files a/core/source/fonts/icons.ttf and /dev/null differ diff --git a/core/source/fonts/icons.woff b/core/source/fonts/icons.woff deleted file mode 100644 index 10e663234..000000000 Binary files a/core/source/fonts/icons.woff and /dev/null differ diff --git a/core/source/images/ajax-loader.gif b/core/source/images/ajax-loader.gif deleted file mode 100644 index f2a1bc0c6..000000000 Binary files a/core/source/images/ajax-loader.gif and /dev/null differ diff --git a/core/source/images/favicon_16x16.jpg b/core/source/images/favicon_16x16.jpg deleted file mode 100644 index 05e744965..000000000 Binary files a/core/source/images/favicon_16x16.jpg and /dev/null differ diff --git a/core/source/images/favicon_32x32.jpg b/core/source/images/favicon_32x32.jpg deleted file mode 100644 index 0970980b7..000000000 Binary files a/core/source/images/favicon_32x32.jpg and /dev/null differ diff --git a/core/source/images/fpo_16x9.png b/core/source/images/fpo_16x9.png deleted file mode 100644 index 013949dcc..000000000 Binary files a/core/source/images/fpo_16x9.png and /dev/null differ diff --git a/core/source/images/fpo_4x3.png b/core/source/images/fpo_4x3.png deleted file mode 100644 index 7ff84b81b..000000000 Binary files a/core/source/images/fpo_4x3.png and /dev/null differ diff --git a/core/source/images/fpo_avatar.png b/core/source/images/fpo_avatar.png deleted file mode 100644 index e666a40ed..000000000 Binary files a/core/source/images/fpo_avatar.png and /dev/null differ diff --git a/core/source/images/fpo_square.png b/core/source/images/fpo_square.png deleted file mode 100644 index ce8a1e4e6..000000000 Binary files a/core/source/images/fpo_square.png and /dev/null differ diff --git a/core/source/images/logo.png b/core/source/images/logo.png deleted file mode 100644 index 93db733d2..000000000 Binary files a/core/source/images/logo.png and /dev/null differ diff --git a/core/source/images/sample/landscape-16x9-mountains.jpg b/core/source/images/sample/landscape-16x9-mountains.jpg deleted file mode 100644 index 3c0d92b29..000000000 Binary files a/core/source/images/sample/landscape-16x9-mountains.jpg and /dev/null differ diff --git a/core/source/images/sample/thumb-square-fire.jpg b/core/source/images/sample/thumb-square-fire.jpg deleted file mode 100644 index 20a5c5ed6..000000000 Binary files a/core/source/images/sample/thumb-square-fire.jpg and /dev/null differ diff --git a/core/source/images/sample/thumb-square-gear.jpg b/core/source/images/sample/thumb-square-gear.jpg deleted file mode 100644 index 052a52a17..000000000 Binary files a/core/source/images/sample/thumb-square-gear.jpg and /dev/null differ diff --git a/core/source/images/sample/thumb-square-ivy.jpg b/core/source/images/sample/thumb-square-ivy.jpg deleted file mode 100644 index 64183a7a3..000000000 Binary files a/core/source/images/sample/thumb-square-ivy.jpg and /dev/null differ diff --git a/core/source/images/sample/thumb-square-river.jpg b/core/source/images/sample/thumb-square-river.jpg deleted file mode 100644 index f19018689..000000000 Binary files a/core/source/images/sample/thumb-square-river.jpg and /dev/null differ diff --git a/core/source/images/sample/thumb-square-yosemite.jpg b/core/source/images/sample/thumb-square-yosemite.jpg deleted file mode 100644 index 8f388d798..000000000 Binary files a/core/source/images/sample/thumb-square-yosemite.jpg and /dev/null differ diff --git a/core/source/images/sample/tout-4x3-climber.jpg b/core/source/images/sample/tout-4x3-climber.jpg deleted file mode 100644 index 1348cd7e7..000000000 Binary files a/core/source/images/sample/tout-4x3-climber.jpg and /dev/null differ diff --git a/core/source/images/sample/tout-4x3-climbers.jpg b/core/source/images/sample/tout-4x3-climbers.jpg deleted file mode 100644 index d8461a191..000000000 Binary files a/core/source/images/sample/tout-4x3-climbers.jpg and /dev/null differ diff --git a/core/source/images/sample/tout-4x3-stream.jpg b/core/source/images/sample/tout-4x3-stream.jpg deleted file mode 100644 index 8e091d1d0..000000000 Binary files a/core/source/images/sample/tout-4x3-stream.jpg and /dev/null differ diff --git a/core/source/js/fitvids.js b/core/source/js/fitvids.js deleted file mode 100644 index e2c5fbe7f..000000000 --- a/core/source/js/fitvids.js +++ /dev/null @@ -1,77 +0,0 @@ -/*global jQuery */ -/*! -* FitVids 1.0 -* -* Copyright 2011, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com -* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ -* Released under the WTFPL license - http://sam.zoy.org/wtfpl/ -* -* Date: Thu Sept 01 18:00:00 2011 -0500 -*/ - -(function( $ ){ - - $.fn.fitVids = function( options ) { - var settings = { - customSelector: null - } - - var div = document.createElement('div'), - ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0]; - - div.className = 'fit-vids-style'; - div.innerHTML = '­'; - - ref.parentNode.insertBefore(div,ref); - - if ( options ) { - $.extend( settings, options ); - } - - return this.each(function(){ - var selectors = [ - "iframe[src*='player.vimeo.com']", - "iframe[src*='www.youtube.com']", - "iframe[src*='www.kickstarter.com']", - "object", - "embed" - ]; - - if (settings.customSelector) { - selectors.push(settings.customSelector); - } - - var $allVideos = $(this).find(selectors.join(',')); - - $allVideos.each(function(){ - var $this = $(this); - if (this.tagName.toLowerCase() == 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } - var height = ( this.tagName.toLowerCase() == 'object' || $this.attr('height') ) ? $this.attr('height') : $this.height(), - width = $this.attr('width') ? $this.attr('width') : $this.width(), - aspectRatio = height / width; - if(!$this.attr('id')){ - var videoID = 'fitvid' + Math.floor(Math.random()*999999); - $this.attr('id', videoID); - } - $this.wrap('
    ').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%"); - $this.removeAttr('height').removeAttr('width'); - }); - }); - } -})( jQuery ); \ No newline at end of file diff --git a/core/source/js/init.js b/core/source/js/init.js deleted file mode 100644 index fe973aa86..000000000 --- a/core/source/js/init.js +++ /dev/null @@ -1,26 +0,0 @@ -(function(w){ - var sw = document.body.clientWidth, - sh = document.body.clientHeight; - - $(w).resize(function(){ //Update dimensions on resize - sw = document.body.clientWidth; - sh = document.body.clientHeight; - - //updateAds(); - }); - - - //Navigation toggle - $('.nav-toggle-menu').click(function(e) { - e.preventDefault(); - $(this).toggleClass('active'); - $('.nav').toggleClass('active'); - }); - - //Navigation toggle - $('.nav-toggle-search').click(function(e) { - e.preventDefault(); - $(this).toggleClass('active'); - $('.header .search-form').toggleClass('active'); - }); -})(this); \ No newline at end of file diff --git a/core/source/js/jquery-2.0.0b2.js b/core/source/js/jquery-2.0.0b2.js deleted file mode 100644 index af8b3b87a..000000000 --- a/core/source/js/jquery-2.0.0b2.js +++ /dev/null @@ -1,8690 +0,0 @@ -/*! - * jQuery JavaScript Library v2.0.0b2 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2013-3-1 - */ -(function( window, undefined ) { - -// Can't do this because several apps including ASP.NET trace -// the stack via arguments.caller.callee and Firefox dies if -// you try to trace through "use strict" call chains. (#13335) -// Support: Firefox 18+ -//"use strict"; -var - // A central reference to the root jQuery(document) - rootjQuery, - - // The deferred used on DOM ready - readyList, - - // Support: IE9 - // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined` - core_strundefined = typeof undefined, - - // Use the correct document accordingly with window argument (sandbox) - location = window.location, - document = window.document, - docElem = document.documentElement, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // [[Class]] -> type pairs - class2type = {}, - - // List of deleted data cache ids, so we can reuse them - core_deletedIds = [], - - core_version = "2.0.0b2", - - // Save a reference to some core methods - core_concat = core_deletedIds.concat, - core_push = core_deletedIds.push, - core_slice = core_deletedIds.slice, - core_indexOf = core_deletedIds.indexOf, - core_toString = class2type.toString, - core_hasOwn = class2type.hasOwnProperty, - core_trim = core_version.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, - - // Used for splitting on whitespace - core_rnotwhite = /\S+/g, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }, - - // The ready event handler and self cleanup method - completed = function() { - document.removeEventListener( "DOMContentLoaded", completed, false ); - window.removeEventListener( "load", completed, false ); - jQuery.ready(); - }; - -jQuery.fn = jQuery.prototype = { - // The current version of jQuery being used - jquery: core_version, - - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - - // scripts is true for back-compat - jQuery.merge( this, jQuery.parseHTML( - match[1], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - ret.context = this.context; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), - - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - if ( obj == null ) { - return String( obj ); - } - // Support: Safari <=5.1 (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ core_toString.call(obj) ] || "object" : - typeof obj; - }, - - isPlainObject: function( obj ) { - // Not plain objects: - // - Any object or value whose internal [[Class]] property is not "[object Object]" - // - DOM nodes - // - window - if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - // Support: Firefox >16 - // The try/catch suppresses exceptions thrown when attempting to access - // the "constructor" property of certain host objects, ie. |window.location| - try { - if ( obj.constructor && - !core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { - return false; - } - } catch ( e ) { - return false; - } - - // If the function hasn't returned already, we're confident that - // |obj| is a plain object, created by {} or constructed with new Object - return true; - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // keepScripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, keepScripts ) { - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - keepScripts = context; - context = false; - } - context = context || document; - - var parsed = rsingleTag.exec( data ), - scripts = !keepScripts && []; - - // Single tag - if ( parsed ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ); - - if ( scripts ) { - jQuery( scripts ).remove(); - } - - return jQuery.merge( [], parsed.childNodes ); - }, - - parseJSON: JSON.parse, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE9 - try { - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - globalEval: function( data ) { - var indirect = eval; - if ( jQuery.trim( data ) ) { - indirect( data + ";" ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var value, - i = 0, - length = obj.length, - isArray = isArraylike( obj ); - - if ( args ) { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } - } - - return obj; - }, - - trim: function( text ) { - return text == null ? "" : core_trim.call( text ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArraylike( Object(arr) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - core_push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : core_indexOf.call( arr, elem, i ); - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, - i = 0, - length = elems.length, - isArray = isArraylike( elems ), - ret = []; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return core_concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - length = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < length; i++ ) { - fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); - } - } - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: Date.now -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the browser event has already occurred. - // we once tried to use readyState "interactive" here, but it caused issues like the one - // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready ); - - } else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed, false ); - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -function isArraylike( obj ) { - var length = obj.length, - type = jQuery.type( obj ); - - if ( jQuery.isWindow( obj ) ) { - return false; - } - - if ( obj.nodeType === 1 && length ) { - return true; - } - - return type === "array" || type !== "function" && - ( length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj ); -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - var type = jQuery.type( arg ); - if ( type === "function" ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && type !== "string" ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); - }, - // Remove all callbacks from the list - empty: function() { - list = []; - firingLength = 0; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ](function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); - } - }); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] - deferred[ tuple[0] ] = function() { - deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); - return this; - }; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function( support ) { - var input = document.createElement("input"), - fragment = document.createDocumentFragment(), - div = document.createElement("div"), - select = document.createElement("select"), - opt = select.appendChild( document.createElement("option") ); - - // Finish early in limited environments - if ( !input.type ) { - return support; - } - - input.type = "checkbox"; - - // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere) - support.checkOn = input.value === ""; - - // Must access the parent to make an option select properly - // Support: IE9, IE10 - support.optSelected = opt.selected; - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - support.boxModel = document.compatMode === "CSS1Compat"; - - // Will be defined later - support.reliableMarginRight = true; - support.boxSizingReliable = true; - support.pixelPosition = false; - - // Make sure checked status is properly cloned - // Support: IE9, IE10 - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Check if an input maintains its value after becoming a radio - // Support: IE9, IE10, Opera - input = document.createElement("input"); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "checked", "t" ); - input.setAttribute( "name", "t" ); - - fragment.appendChild( input ); - - // old WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: Firefox 17+ - // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) - support.focusinBubbles = "onfocusin" in window; - - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - // Run tests that need a body at doc ready - jQuery(function() { - var container, marginDiv, - divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", - body = document.getElementsByTagName("body")[ 0 ]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; - - // Check box-sizing and margin behavior - body.appendChild( container ).appendChild( div ); - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - - support.boxSizing = div.offsetWidth === 4; - support.doesNotIncludeMarginInBodyOffset = body.offsetTop !== 1; - - // Use window.getComputedStyle because jsdom on node.js will break without it. - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. (#3333) - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = div.appendChild( document.createElement("div") ); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - body.removeChild( container ); - }); - - return support; -})( {} ); - -/* - Implementation Summary - - 1. Enforce API surface and semantic compatibility with 1.9.x branch - 2. Improve the module's maintainability by reducing the storage - paths to a single mechanism. - 3. Use the same single mechanism to support "private" and "user" data. - 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) - 5. Avoid exposing implementation details on user objects (eg. expando properties) - 6. Provide a clear path for implementation upgrade to WeakMap in 2014 -*/ -var data_user, data_priv, - rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, - rmultiDash = /([A-Z])/g; - -function Data() { - this.cache = {}; - this.expando = jQuery.expando + Math.random(); -} - -Data.uid = 1; - -Data.prototype = { - key: function( owner ) { - var descriptor = {}, - // Check if the owner object already has a cache key - unlock = owner[ this.expando ]; - - // If not, create one - if ( !unlock ) { - unlock = Data.uid++; - descriptor[ this.expando ] = { value: unlock }; - - // Secure it in a non-enumerable, non-writable property - try { - Object.defineProperties( owner, descriptor ); - - // Support: Android<4 - // Fallback to a less secure definition - } catch ( e ) { - descriptor[ this.expando ] = unlock; - jQuery.extend( owner, descriptor ); - } - } - - // Ensure the cache object - if ( !this.cache[ unlock ] ) { - this.cache[ unlock ] = {}; - } - - return unlock; - }, - set: function( owner, data, value ) { - var prop, - // There may be an unlock assigned to this node, - // if there is no entry for this "owner", create one inline - // and set the unlock as though an owner entry had always existed - unlock = this.key( owner ), - cache = this.cache[ unlock ]; - - // Handle: [ owner, key, value ] args - if ( typeof data === "string" ) { - cache[ data ] = value; - - // Handle: [ owner, { properties } ] args - } else { - // Support an expectation from the old data system where plain - // objects used to initialize would be set to the cache by - // reference, instead of having properties and values copied. - // Note, this will kill the connection between - // "this.cache[ unlock ]" and "cache" - if ( jQuery.isEmptyObject( cache ) ) { - this.cache[ unlock ] = data; - // Otherwise, copy the properties one-by-one to the cache object - } else { - for ( prop in data ) { - cache[ prop ] = data[ prop ]; - } - } - } - - return this; - }, - get: function( owner, key ) { - // Either a valid cache is found, or will be created. - // New caches will be created and the unlock returned, - // allowing direct access to the newly created - // empty data object. - var cache = this.cache[ this.key( owner ) ]; - - return key === undefined ? - cache : cache[ key ]; - }, - access: function( owner, key, value ) { - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ((key && typeof key === "string") && value === undefined) ) { - return this.get( owner, key ); - } - - // [*]When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, name, - unlock = this.key( owner ), - cache = this.cache[ unlock ]; - - if ( key === undefined ) { - this.cache[ unlock ] = {}; - } else { - // Support array or space separated string of keys - if ( jQuery.isArray( key ) ) { - // If "name" is an array of keys... - // When data is initially created, via ("key", "val") signature, - // keys will be converted to camelCase. - // Since there is no way to tell _how_ a key was added, remove - // both plain key and camelCase key. #12786 - // This will only penalize the array argument path. - name = key.concat( key.map( jQuery.camelCase ) ); - } else { - // Try the string as a key before any manipulation - if ( key in cache ) { - name = [ key ]; - } else { - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - name = jQuery.camelCase( key ); - name = name in cache ? - [ name ] : ( name.match( core_rnotwhite ) || [] ); - } - } - - i = name.length; - while ( i-- ) { - delete cache[ name[i] ]; - } - } - }, - hasData: function( owner ) { - return !jQuery.isEmptyObject( - this.cache[ this.key( owner ) ] - ); - }, - discard: function( owner ) { - delete this.cache[ this.key( owner ) ]; - } -}; - -// This will be used by remove()/cleanData() in manipulation to sever -// remaining references to node objects. One day we'll replace the dual -// arrays with a WeakMap and this won't be an issue. -// (Splices the data objects out of the internal cache arrays) -function data_discard( owner ) { - data_user.discard( owner ); - data_priv.discard( owner ); -} - -// These may be used throughout the jQuery core codebase -data_user = new Data(); -data_priv = new Data(); - - -jQuery.extend({ - // This is no longer relevant to jQuery core, but must remain - // supported for the sake of jQuery 1.9.x API surface compatibility. - acceptData: function() { - return true; - }, - - hasData: function( elem ) { - return data_user.hasData( elem ) || data_priv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return data_user.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - return data_user.remove( elem, name ); - }, - - // TODO: Replace all calls to _data and _removeData with direct - // calls to - // - // data_priv.access( elem, name, data ); - // - // data_priv.remove( elem, name ); - // - _data: function( elem, name, data ) { - return data_priv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - return data_priv.remove( elem, name ); - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var attrs, name, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = data_user.get( elem ); - - if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) { - attrs = elem.attributes; - for ( ; i < attrs.length; i++ ) { - name = attrs[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - dataAttr( elem, name, data[ name ] ); - } - } - data_priv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - data_user.set( this, key ); - }); - } - - return jQuery.access( this, function( value ) { - var data, - camelKey = jQuery.camelCase( key ); - - // Get the Data... - if ( value === undefined ) { - - // Attempt to get data from the cache - // with the key as-is - data = data_user.get( elem, key ); - if ( data !== undefined ) { - return data; - } - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key, undefined ); - if ( data !== undefined ) { - return data; - } - - // As a last resort, attempt to find - // the data by checking AGAIN, but with - // a camelCased key. - data = data_user.get( elem, camelKey ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return undefined; - } - - // Set the data... - this.each(function() { - // First, attempt to store a copy or reference of any - // data that might've been store with a camelCased key. - var data = data_user.get( this, camelKey ); - - // For HTML5 data-* attribute interop, we have to - // store property names with dashes in a camelCase form. - // This might not apply to all properties...* - data_user.set( this, camelKey, value ); - - // *... In the case of properties that might ACTUALLY - // have dashes, we need to also store a copy of that - // unchanged property. - if ( /-/.test( key ) && data !== undefined ) { - data_user.set( this, key, value ); - } - }); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each(function() { - data_user.remove( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? - JSON.parse( data ) : data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - data_user.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - hooks.cur = fn; - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery._removeData( elem, type + "queue" ); - jQuery._removeData( elem, key ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - tmp = jQuery._data( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rfocusable = /^(?:input|select|textarea|button|object)$/i, - rclickable = /^(?:a|area)$/i, - rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classes, elem, cur, clazz, j, - i = 0, - len = this.length, - proceed = typeof value === "string" && value; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call( this, j, this.className ) ); - }); - } - - if ( proceed ) { - // The disjunction here is for better compressibility (see removeClass) - classes = ( value || "" ).match( core_rnotwhite ) || []; - - for ( ; i < len; i++ ) { - elem = this[ i ]; - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - " " - ); - - if ( cur ) { - j = 0; - while ( (clazz = classes[j++]) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - elem.className = jQuery.trim( cur ); - - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, clazz, j, - i = 0, - len = this.length, - proceed = arguments.length === 0 || typeof value === "string" && value; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call( this, j, this.className ) ); - }); - } - if ( proceed ) { - classes = ( value || "" ).match( core_rnotwhite ) || []; - - for ( ; i < len; i++ ) { - elem = this[ i ]; - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - "" - ); - - if ( cur ) { - j = 0; - while ( (clazz = classes[j++]) ) { - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - elem.className = value ? jQuery.trim( cur ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.match( core_rnotwhite ) || []; - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - // Toggle whole class name - } else if ( type === core_strundefined || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // If the element has a class name or if we're passed "false", - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, option, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one" || index < 0, - values = one ? null : [], - max = one ? index + 1 : options.length, - i = index < 0 ? - max : - one ? index : 0; - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // oldIE doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - // Don't return options that are disabled or in a disabled optgroup - ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && - ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - attr: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === core_strundefined ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - - } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, value + "" ); - return value; - } - - } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - // In IE9+, Flash objects don't have .getAttribute (#12945) - // Support: IE9+ - if ( typeof elem.getAttribute !== core_strundefined ) { - ret = elem.getAttribute( name ); - } - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var name, propName, - i = 0, - attrNames = value && value.match( core_rnotwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( (name = attrNames[i++]) ) { - propName = jQuery.propFix[ name ] || name; - - // Boolean attributes get special treatment (#10870) - // Set corresponding property to false for boolean attributes - if ( rboolean.test( name ) ) { - elem[ propName ] = false; - } - - elem.removeAttribute( name ); - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to default in case type is set after value during creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - return elem.getAttribute( name ) !== null ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); - -// IE9/10 do not see a selected option inside an optgroup unless you access it -// Support: IE9, IE10 -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - } - }); -} -var rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = data_priv.get( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !(events = elemData.events) ) { - events = elemData.events = {}; - } - if ( !(eventHandle = elemData.handle) ) { - eventHandle = elemData.handle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( core_rnotwhite ) || [""]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !(handlers = events[ type ]) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = data_priv.hasData( elem ) && data_priv.get( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( core_rnotwhite ) || [""]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery._removeData( elem, "events" ); - } - }, - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, - eventPath = [ elem || document ], - type = core_hasOwn.call( event, "type" ) ? event.type : event, - namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf(".") >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf(":") < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join("."); - event.namespace_re = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === (elem.ownerDocument || document) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event ); - - var i, j, ret, matched, handleObj, - handlerQueue = [], - args = core_slice.call( arguments ), - handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( (event.result = ret) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, matches, sel, handleObj, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - // Black-hole SVG instance trees (#13180) - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { - - for ( ; cur != this; cur = cur.parentNode || this ) { - - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.disabled !== true || event.type !== "click" ) { - matches = []; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matches[ sel ] === undefined ) { - matches[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) >= 0 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matches[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, handlers: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( delegateCount < handlers.length ) { - handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); - } - - return handlerQueue; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, copy, - type = event.type, - originalEvent = event, - fixHook = this.fixHooks[ type ]; - - if ( !fixHook ) { - this.fixHooks[ type ] = fixHook = - rmouseEvent.test( type ) ? this.mouseHooks : - rkeyEvent.test( type ) ? this.keyHooks : - {}; - } - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = new jQuery.Event( originalEvent ); - - i = copy.length; - while ( i-- ) { - prop = copy[ i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Support: Chrome 23+, Safari? - // Target should not be a text node (#504, #13143) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - click: { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { - this.click(); - return false; - } - } - }, - focus: { - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== document.activeElement && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === document.activeElement && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 10+ - if ( event.result !== undefined ) { - event.originalEvent.returnValue = event.result; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -jQuery.removeEvent = function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } -}; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && e.preventDefault ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && e.stopPropagation ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - } -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -// Support: Chrome 15+ -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// Create "bubbling" focus and blur events -// Support: Firefox 10+ -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - var elem = this[0]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2013 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var i, - cachedruns, - Expr, - getText, - isXML, - compile, - outermostContext, - recompare, - sortInput, - - // Local document vars - setDocument, - document, - docElem, - documentIsXML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + -(new Date()), - preferredDoc = window.document, - support = {}, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - hasDuplicate = false, - sortOrder = function() { return 0; }, - - // General-purpose constants - strundefined = typeof undefined, - MAX_NEGATIVE = 1 << 31, - - // Array methods - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf if we can't use a native one - indexOf = arr.indexOf || function( elem ) { - var i = 0, - len = this.length; - for ( ; i < len; i++ ) { - if ( this[i] === elem ) { - return i; - } - } - return -1; - }, - - - // Regular expressions - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - - // Prefer arguments quoted, - // then not containing pseudos/brackets, - // then attribute selectors/non-parenthetical expressions, - // then anything else - // These preferences are here to reduce the number of selectors - // needing tokenize in the PSEUDO preFilter - pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - - rnative = /^[^{]+\{\s*\[native code/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - - // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, - funescape = function( _, escaped ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - return high !== high ? - escaped : - // BMP codepoint - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }; - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -/** - * For feature detection - * @param {Function} fn The function to test for native support - */ -function isNative( fn ) { - return rnative.test( fn + "" ); -} - -/** - * Create key-value caches of limited size - * @returns {Function(string, Object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var cache, - keys = []; - - return (cache = function( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key += " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key ] = value); - }); -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created div and expects a boolean result - */ -function assert( fn ) { - var div = document.createElement("div"); - - try { - return !!fn( div ); - } catch (e) { - return false; - } finally { - // release memory in IE - div = null; - } -} - -function Sizzle( selector, context, results, seed ) { - var match, elem, m, nodeType, - // QSA vars - i, groups, old, nid, newContext, newSelector; - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - - context = context || document; - results = results || []; - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !documentIsXML && !seed ) { - - // Shortcuts - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) { - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // QSA path - if ( support.qsa && !rbuggyQSA.test(selector) ) { - old = true; - nid = expando; - newContext = context; - newSelector = nodeType === 9 && selector; - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - groups = tokenize( selector ); - - if ( (old = context.getAttribute("id")) ) { - nid = old.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - nid = "[id='" + nid + "'] "; - - i = groups.length; - while ( i-- ) { - groups[i] = nid + toSelector( groups[i] ); - } - newContext = rsibling.test( selector ) && context.parentNode || context; - newSelector = groups.join(","); - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Detect xml - * @param {Element|Object} elem An element or a document - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var doc = node ? node.ownerDocument || node : preferredDoc; - - // If no document and documentElement is available, return - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Set our document - document = doc; - docElem = doc.documentElement; - - // Support tests - documentIsXML = isXML( doc ); - - // Check if getElementsByTagName("*") returns only elements - support.tagNameNoComments = assert(function( div ) { - div.appendChild( doc.createComment("") ); - return !div.getElementsByTagName("*").length; - }); - - // Check if attributes should be retrieved by attribute nodes - support.attributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }); - - // Check if getElementsByClassName can be trusted - support.getByClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { - return false; - } - - // Safari 3.2 caches class attributes and doesn't catch changes - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length === 2; - }); - - // Check if getElementsByName privileges form controls or returns elements by ID - // If so, assume (for broader support) that getElementById returns elements by name - support.getByName = assert(function( div ) { - // Inject content - div.id = expando + 0; - // Support: Windows 8 Native Apps - // Assigning innerHTML with "name" attributes throws uncatchable exceptions - // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx - div.appendChild( document.createElement("a") ).setAttribute( "name", expando ); - div.appendChild( document.createElement("i") ).setAttribute( "name", expando ); - docElem.appendChild( div ); - - // Test - var pass = doc.getElementsByName && - // buggy browsers will return fewer than the correct 2 - doc.getElementsByName( expando ).length === 2 + - // buggy browsers will return more than the correct 0 - doc.getElementsByName( expando + 0 ).length; - - // Cleanup - docElem.removeChild( div ); - - return pass; - }); - - // Support: Webkit<537.32 - // Detached nodes confoundingly follow *each other* - support.sortDetached = assert(function( div1 ) { - return div1.compareDocumentPosition && - // Should return 1, but Webkit returns 4 (following) - (div1.compareDocumentPosition( document.createElement("div") ) & 1); - }); - - // IE6/7 return modified attributes - Expr.attrHandle = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }) ? - {} : - { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; - - // ID find and filter - if ( support.getByName ) { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== strundefined && !documentIsXML ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - } else { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== strundefined && !documentIsXML ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - } - - // Tag - Expr.find["TAG"] = support.tagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var elem, - tmp = [], - i = 0, - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Name - Expr.find["NAME"] = support.getByName && function( tag, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; - - // Class - Expr.find["CLASS"] = support.getByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) { - return context.getElementsByClassName( className ); - } - }; - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21), - // no need to also add to buggyMatches since matches checks buggyQSA - // A support test would require too much code (would include document ready) - rbuggyQSA = [ ":focus" ]; - - if ( (support.qsa = isNative(doc.querySelectorAll)) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explictly - // setting a boolean content attribute, - // since its presence should be enough - // http://bugs.jquery.com/ticket/12359 - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE8 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = ""; - if ( div.querySelectorAll("[i^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - div.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( div, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - // Element contains another - // Purposefully does not implement inclusive descendent - // As in, an element does not contain itself - contains = isNative(docElem.contains) || docElem.compareDocumentPosition ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - // Document order sorting - sortOrder = docElem.compareDocumentPosition ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b ); - - if ( compare ) { - // Disconnected nodes - if ( compare & 1 || - (recompare && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === doc || contains(preferredDoc, a) ) { - return -1; - } - if ( b === doc || contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } - - // Not directly comparable, sort on existence of method - return a.compareDocumentPosition ? -1 : 1; - } : - function( a, b ) { - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Parentless nodes are either documents or disconnected - } else if ( !aup || !bup ) { - return a === doc ? -1 : - b === doc ? 1 : - aup ? -1 : - bup ? 1 : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyQSA always contains :focus, so no need for an existence check - if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, document, null, [elem] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - var val; - - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - if ( !documentIsXML ) { - name = name.toLowerCase(); - } - if ( (val = Expr.attrHandle[ name ]) ) { - return val( elem ); - } - if ( documentIsXML || support.attributes ) { - return elem.getAttribute( name ); - } - return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ? - name : - val && val.specified ? val.value : null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - // Compensate for sort limitations - recompare = !support.sortDetached; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - return results; -}; - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns Returns -1 if a precedes b, 1 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -// Returns a function to use in pseudos for input types -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -// Returns a function to use in pseudos for buttons -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -// Returns a function to use in pseudos for positionals -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[5] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[4] ) { - match[2] = match[4]; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - - nodeName = nodeName.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, outerCache, node, diff, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - // Seek `elem` from a previously-cached index - outerCache = parent[ expando ] || (parent[ expando ] = {}); - cache = outerCache[ type ] || []; - nodeIndex = cache[0] === dirruns && cache[1]; - diff = cache[0] === dirruns && cache[2]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - outerCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - // Use previously-cached element index if available - } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { - diff = cache[1]; - - // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) - } else { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { - // Cache the index of each encountered element - if ( useCache ) { - (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf.call( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifider - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsXML ? - elem.getAttribute("xml:lang") || elem.getAttribute("lang") : - elem.lang) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -function tokenize( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( tokens = [] ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push( { - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - } ); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push( { - value: matched, - type: type, - matches: match - } ); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -} - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - checkNonElements = base && dir === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var data, cache, outerCache, - dirkey = dirruns + " " + doneName; - - // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { - if ( (data = cache[1]) === true || data === cachedruns ) { - return data === true; - } - } else { - cache = outerCache[ dir ] = [ dirkey ]; - cache[1] = matcher( elem, context, xml ) || cachedruns; - if ( cache[1] === true ) { - return true; - } - } - } - } - } - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf.call( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - // A counter to specify which element is currently being matched - var matcherCachedRuns = 0, - bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, expandContext ) { - var elem, j, matcher, - setMatched = [], - matchedCount = 0, - i = "0", - unmatched = seed && [], - outermost = expandContext != null, - contextBackup = outermostContext, - // We must always have either seed elements or context - elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); - - if ( outermost ) { - outermostContext = context !== document && context; - cachedruns = matcherCachedRuns; - } - - // Add elements passing elementMatchers directly to results - // Keep `i` a string if there are no elements so `matchedCount` will be "00" below - for ( ; (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context, xml ) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - cachedruns = ++matcherCachedRuns; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // Apply set filters to unmatched elements - matchedCount += i; - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !group ) { - group = tokenize( selector ); - } - i = group.length; - while ( i-- ) { - cached = matcherFromTokens( group[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - } - return cached; -}; - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function select( selector, context, results, seed ) { - var i, tokens, token, type, find, - match = tokenize( selector ); - - if ( !seed ) { - // Try to minimize operations if there is only one group - if ( match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && !documentIsXML && - Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && context.parentNode || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - } - - // Compile and execute a filtering function - // Provide `match` to avoid retokenization if we modified the selector above - compile( selector, match )( - seed, - context, - documentIsXML, - results, - rsibling.test( selector ) - ); - return results; -} - -// Deprecated -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -// Check sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Initialize with the default document -setDocument(); - -// Always assume the presence of duplicates if sort doesn't -// pass them to our comparison function (as in Google Chrome). -[0, 0].sort( sortOrder ); -support.detectDuplicates = hasDuplicate; - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var self, matched, i, - l = this.length; - - if ( typeof selector !== "string" ) { - self = this; - return this.pushStack( jQuery( selector ).filter(function() { - for ( i = 0; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }) ); - } - - matched = []; - for ( i = 0; i < l; i++ ) { - jQuery.find( selector, this[ i ], matched ); - } - - // Needed because $( selector, context ) becomes $( context ).find( selector ) - matched = this.pushStack( l > 1 ? jQuery.unique( matched ) : matched ); - matched.selector = ( this.selector ? this.selector + " " : "" ) + selector; - return matched; - }, - - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter(function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false) ); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true) ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[ 0 ] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - pos = ( rneedsContext.test( selectors ) || typeof selectors !== "string" ) ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { - // Always skip document fragments - if ( cur.nodeType < 11 && (pos ? - pos.index(cur) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector(cur, selectors)) ) { - - cur = matched.push( cur ); - break; - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return core_indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return core_indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( jQuery.unique(all) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -function sibling( cur, dir ) { - while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {} - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - if ( !guaranteedUnique[ name ] ) { - jQuery.unique( matched ); - } - - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector( elems[ 0 ], expr ) ? [ elems[ 0 ] ] : [] : - jQuery.find.matches( expr, elems ); - }, - - dir: function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; - }, - - sibling: function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - var filtered; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - } - - if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem ) { - return ( elem === qualifier ) === keep; - }); - } - - if ( typeof qualifier === "string" ) { - filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, filtered, !keep ); - } - - qualifier = jQuery.filter( qualifier, filtered ); - } - - return jQuery.grep(elements, function( elem ) { - return ( core_indexOf.call( qualifier, elem ) >= 0 ) === keep; - }); -} -var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rhtml = /<|&#?\w+;/, - rnoInnerhtml = /<(?:script|style|link)/i, - manipulation_rcheckableType = /^(?:checkbox|radio)$/i, - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /^$|\/(?:java|ecma)script/i, - rscriptTypeMasked = /^true\/(.*)/, - rcleanScript = /^\s*\s*$/g, - - // We have to close these tags to support XHTML (#13200) - wrapMap = { - - // Support: IE 9 - option: [ 1, "" ], - - thead: [ 1, "", "
    " ], - tr: [ 2, "", "
    " ], - td: [ 3, "", "
    " ], - - _default: [ 0, "", "" ] - }; - -// Support: IE 9 -wrapMap.optgroup = wrapMap.option; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.col = wrapMap.thead; -wrapMap.th = wrapMap.td; - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - var wrap; - - if ( jQuery.isFunction( html ) ) { - return this.each(function( i ) { - jQuery( this ).wrapAll( html.call(this, i) ); - }); - } - - if ( this[ 0 ] ) { - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function( i ) { - jQuery( this ).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function( i ) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - return this.domManip(arguments, false, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - }); - }, - - after: function() { - return this.domManip(arguments, false, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - }); - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0, - l = this.length; - - for ( ; i < l; i++ ) { - elem = this[ i ]; - - if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem ) ); - } - - if ( elem.parentNode ) { - if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { - setGlobalEval( getAll( elem, "script" ) ); - } - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0, - l = this.length; - - for ( ; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - var isFunction = jQuery.isFunction( value ); - - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( !isFunction && typeof value !== "string" ) { - value = jQuery( value ).not( this ).detach(); - } - - return value !== "" ? - this.domManip( [ value ], true, function( elem ) { - var next = this.nextSibling, - parent = this.parentNode; - - if ( parent ) { - jQuery( this ).remove(); - parent.insertBefore( elem, next ); - } - }) : - this.remove(); - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = core_concat.apply( [], args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = this.length, - set = this, - iNoClone = l - 1, - value = args[ 0 ], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { - return this.each(function( index ) { - var self = set.eq( index ); - if ( isFunction ) { - args[ 0 ] = value.call( this, index, table ? self.html() : undefined ); - } - self.domManip( args, table, callback ); - }); - } - - if ( l ) { - fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - // Support: QtWebKit - // jQuery.merge because core_push.apply(_, arraylike) throws - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( - table && jQuery.nodeName( this[ i ], "table" ) ? - findOrAppend( this[ i ], "tbody" ) : - this[ i ], - node, - i - ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) { - - if ( node.src ) { - // Hope ajax is available... - jQuery.ajax({ - url: node.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) ); - } - } - } - } - } - } - - return this; - } -}); - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: QtWebKit - // .get() because core_push.apply(_, arraylike) throws - core_push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -}); - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); - - // Support: IE >=9 - // Fix Cloning issues - if ( !jQuery.support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - buildFragment: function( elems, context, scripts, selection ) { - var elem, tmp, tag, wrap, contains, j, - i = 0, - l = elems.length, - fragment = context.createDocumentFragment(), - nodes = []; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - // Support: QtWebKit - // jQuery.merge because core_push.apply(_, arraylike) throws - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement("div") ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || ["", ""] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.firstChild; - } - - // Support: QtWebKit - // jQuery.merge because core_push.apply(_, arraylike) throws - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Fixes #12346 - // Support: Webkit, IE - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( (elem = nodes[ i++ ]) ) { - - // #4087 - If origin and destination elements are the same, and this is - // that element, do not do anything - if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( (elem = tmp[ j++ ]) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var data, elem, type, - l = elems.length, - i = 0, - special = jQuery.event.special; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( acceptData || jQuery.acceptData( elem ) ) { - - data = data_priv.access( elem ); - - if ( data ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - } - // Discard any remaining `private` and `user` data - data_discard( elem ); - } - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[ 0 ] || elem.appendChild( elem.ownerDocument.createElement(tag) ); -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - var attr = elem.getAttributeNode("type"); - elem.type = ( attr && attr.specified ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - - if ( match ) { - elem.type = match[ 1 ]; - } else { - elem.removeAttribute("type"); - } - - return elem; -} - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var l = elems.length, - i = 0; - - for ( ; i < l; i++ ) { - data_priv.set( - elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" ) - ); - } -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( data_priv.hasData( src ) ) { - pdataOld = data_priv.access( src ); - pdataCur = jQuery.extend( {}, pdataOld ); - events = pdataOld.events; - - data_priv.set( dest, pdataCur ); - - if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( data_user.hasData( src ) ) { - udataOld = data_user.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - data_user.set( dest, udataCur ); - } -} - - -function getAll( context, tag ) { - var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) : - context.querySelectorAll ? context.querySelectorAll( tag || "*" ) : - []; - - return tag === undefined || tag && jQuery.nodeName( context, tag ) ? - jQuery.merge( [ context ], ret ) : - ret; -} - -// Support: IE >= 9 -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} -var curCSS, iframe, - // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" - // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), - elemdisplay = { BODY: "block" }, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - // isHidden might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -// NOTE: we've included the "window" in window.getComputedStyle -// because jsdom on node.js will break without it. -function getStyles( elem ) { - return window.getComputedStyle( elem, null ); -} - -function showHide( elements, show ) { - var display, elem, hidden, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - values[ index ] = jQuery._data( elem, "olddisplay" ); - display = elem.style.display; - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - - if ( !values[ index ] ) { - hidden = isHidden( elem ); - - if ( display && display !== "none" || !hidden ) { - jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); - } - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( jQuery.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - var bool = typeof state === "boolean"; - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "columnCount": true, - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": "cssFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // Fixes #8908, it can be done more correctly by specifying setters in cssHooks, - // but it would mean to define eight (for every problematic property) identical functions - if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - style[ name ] = value; - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -curCSS = function( elem, name, _computed ) { - var width, minWidth, maxWidth, - computed = _computed || getStyles( elem ), - - // Support: IE9 - // getPropertyValue is only needed for .css('filter') in IE9, see #12537 - ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, - style = elem.style; - - if ( computed ) { - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // Support: Chrome <17, Safari 5.1 - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; -}; - - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); - } - - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } else { - // at this point, extra isn't content, so add padding - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var valueIsBorderBox = true, - val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - styles = getStyles( elem ), - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // some non-html elements return undefined for offsetWidth, so check for null/undefined - // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 - // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 - if ( val <= 0 || val == null ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name, styles ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles - ) - ) + "px"; -} - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - var doc = document, - display = elemdisplay[ nodeName ]; - - if ( !display ) { - display = actualDisplay( nodeName, doc ); - - // If the simple way fails, read from inside an iframe - if ( display === "none" || !display ) { - // Use the already-created iframe if possible - iframe = ( iframe || - jQuery(" -
    -
    -
    - - - - - - - - - - - - - - - - - {{> ipAddress }} - {{> patternPaths }} - {{> viewAllPaths }} - - - - - - - {{> websockets }} - - - \ No newline at end of file diff --git a/core/templates/partials/ipAddress.mustache b/core/templates/partials/ipAddress.mustache deleted file mode 100644 index b62f309ce..000000000 --- a/core/templates/partials/ipAddress.mustache +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/core/templates/partials/ishControls.mustache b/core/templates/partials/ishControls.mustache deleted file mode 100644 index 4a9ae5cb7..000000000 --- a/core/templates/partials/ishControls.mustache +++ /dev/null @@ -1,65 +0,0 @@ - -
    -
    -
      -
    • -
      -
      - Size px / - em -
      -
      -
        - {{^ ishControlsHide.s }}
      • S
      • {{/ ishControlsHide.s }} - {{^ ishControlsHide.m }}
      • M
      • {{/ ishControlsHide.m }} - {{^ ishControlsHide.l }}
      • L
      • {{/ ishControlsHide.l }} - {{^ ishControlsHide.full }}
      • Full
      • {{/ ishControlsHide.full }} - {{^ ishControlsHide.random }}
      • Random
      • {{/ ishControlsHide.random }} - {{^ ishControlsHide.disco }}
      • Disco
      • {{/ ishControlsHide.disco }} - {{^ ishControlsHide.hay }}
      • Hay!
      • {{/ ishControlsHide.hay }} -
      -
    • - {{^ ishControlsHide.mqs }} -
    • - MQ -
        - {{# mqs }} -
      • {{ . }}
      • - {{/ mqs }} -
      -
    • - {{/ ishControlsHide.mqs }} - {{^ ishControlsHide.find }} -
    • - Search Patterns -
        -
      • -
      -
    • - {{/ ishControlsHide.find }} - {{^ ishControlsHide.views-all }} -
    • - View -
        - {{^ ishControlsHide.views-annotations }}
      • Annotations
      • {{/ ishControlsHide.views-annotations }} - {{^ ishControlsHide.views-code }}
      • Code
      • {{/ ishControlsHide.views-code }} - {{^ ishControlsHide.views-new }}
      • Open in new window
      • {{/ ishControlsHide.views-new }} -
      -
    • - {{/ ishControlsHide.views-all }} - {{^ ishControlsHide.tools-all }} -
    • - Tools -
        - {{^ ishControlsHide.tools-follow }}
      • Page Follow
      • {{/ ishControlsHide.tools-follow }} - {{^ ishControlsHide.tools-reload }}
      • Auto-reload
      • {{/ ishControlsHide.tools-reload }} - {{^ ishControlsHide.tools-shortcuts }}
      • Keyboard Shortcuts{{/ ishControlsHide.tools-shortcuts }} - {{^ ishControlsHide.tools-docs }}
      • Pattern Lab Docs{{/ ishControlsHide.tools-docs }} -
      -
    • - {{/ ishControlsHide.tools-all }} -
    - -
    -
    - \ No newline at end of file diff --git a/core/templates/partials/patternNav.mustache b/core/templates/partials/patternNav.mustache deleted file mode 100644 index ae337de31..000000000 --- a/core/templates/partials/patternNav.mustache +++ /dev/null @@ -1,17 +0,0 @@ -
      - {{# patternTypes }} -
    1. {{ patternTypeUC }}
        - {{# patternTypeItems }} -
      1. {{ patternSubtypeUC }}
          - {{# patternSubtypeItems }} -
        1. {{ patternName }}
        2. - {{/ patternSubtypeItems }} -
      2. - {{/ patternTypeItems }} - {{# patternItems }} -
      3. {{ patternName }}
      4. - {{/ patternItems }} -
    2. - {{/ patternTypes }} -
    3. All
    4. -
    diff --git a/core/templates/partials/patternPaths.mustache b/core/templates/partials/patternPaths.mustache deleted file mode 100644 index 3b8562337..000000000 --- a/core/templates/partials/patternPaths.mustache +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/core/templates/partials/viewAllPaths.mustache b/core/templates/partials/viewAllPaths.mustache deleted file mode 100644 index b0e044d97..000000000 --- a/core/templates/partials/viewAllPaths.mustache +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/core/templates/partials/websockets.mustache b/core/templates/partials/websockets.mustache deleted file mode 100644 index 65af3be1c..000000000 --- a/core/templates/partials/websockets.mustache +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/core/templates/pattern-header-footer/README b/core/templates/pattern-header-footer/README deleted file mode 100644 index 6c5a981ab..000000000 --- a/core/templates/pattern-header-footer/README +++ /dev/null @@ -1 +0,0 @@ -This is not a real pattern. It's simply the header and footer that patterns get sandwiched between when they're processed by the builder. \ No newline at end of file diff --git a/core/templates/pattern-header-footer/footer-pattern.html b/core/templates/pattern-header-footer/footer-pattern.html deleted file mode 100644 index 86143b407..000000000 --- a/core/templates/pattern-header-footer/footer-pattern.html +++ /dev/null @@ -1,10 +0,0 @@ - - - \ No newline at end of file diff --git a/core/templates/pattern-header-footer/footer.html b/core/templates/pattern-header-footer/footer.html deleted file mode 100644 index d36ac9880..000000000 --- a/core/templates/pattern-header-footer/footer.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - diff --git a/core/templates/pattern-header-footer/header.html b/core/templates/pattern-header-footer/header.html deleted file mode 100644 index ec9904f70..000000000 --- a/core/templates/pattern-header-footer/header.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/core/templates/styleguide.mustache b/core/templates/styleguide.mustache deleted file mode 100644 index 88fca2338..000000000 --- a/core/templates/styleguide.mustache +++ /dev/null @@ -1,47 +0,0 @@ - - - - - diff --git a/core/templates/viewall.mustache b/core/templates/viewall.mustache deleted file mode 100644 index 20c7943e8..000000000 --- a/core/templates/viewall.mustache +++ /dev/null @@ -1,49 +0,0 @@ - - -
    - - -
    - {{# partials }} -
    -

    {{ patternName }}

    -
    - {{{ patternPartialCode }}} - -
    -
    - {{/ partials }} -
    - -
    - - - - diff --git a/extras/apache/README b/extras/apache/README deleted file mode 100644 index 4a58f3819..000000000 --- a/extras/apache/README +++ /dev/null @@ -1,37 +0,0 @@ -# How to Set-up Apache on Mac OS X - -This document reviews how to (hopefully) easily set-up Apache on Mac OS X to support Pattern Lab. You'll need to open Terminal. Note that PHP may flake out with the default Apache install. I can modify directions in the future to account for that. - -## 1. Modify hosts - -First, you'll want to modify your hosts file so that you can use a specific hostname for the site rather than just `127.0.0.1` or `localhost`. To do so do the following: - -1. In Terminal type `sudo vi /etc/hosts` -2. When prompted, enter the password you use to log-in -3. When the file loads type `i` -4. Using the arrow keys get to the end of the last line -5. Hit `return` and type `127.0.0.1 patternlab.localhost` -6. Hit the `esc` key and type `:wq` - -Your hosts should now be saved. - -## 2. Modify Apache - -Second, you'll want to add an Apache `VirtualHost` so that Apache will know to listen for your application at the correct hostname. - -1. In Terminal type `sudo vi /etc/apache2/extra/httpd-vhosts.conf` -2. When prompted, enter the password you use to log-in -3. When the file loads type `i` -4. Using the arrow keys get to the end of the last line -5. Hit `return` twice -6. Copy and paste the info from the `vhost.txt` file in this directory. -7. Modify `DocumentRoot` path to match the location of the your install of Pattern Lab -7. Hit the `esc` key and type `:wq` - -## 3. Restart Apache - -Last, you'll want to restart Apache so your changes take effect. Simply open System Preferences and go to the "Sharing" panel. Untick the "Web Sharing" checkbox and tick it again to restart Apache. - -## 4. Test By Visiting patternlab.localhost - -In a browser try to visit http://patternlab.localhost. You should get the Pattern Lab styleguide by default. If you get Google Search results just make sure you enter the http:// \ No newline at end of file diff --git a/extras/apache/vhost.txt b/extras/apache/vhost.txt deleted file mode 100644 index e4431fc02..000000000 --- a/extras/apache/vhost.txt +++ /dev/null @@ -1,5 +0,0 @@ - - DocumentRoot "/Users/dmolsen/Sites/patternlab/public" - ServerName patternlab.localhost - ServerAlias patternlab.*.xip.io - \ No newline at end of file diff --git a/public/.gitkeep b/public/.gitkeep new file mode 100644 index 000000000..96c97655f --- /dev/null +++ b/public/.gitkeep @@ -0,0 +1 @@ +Holding file for public/ directory diff --git a/public/README b/public/README deleted file mode 100644 index 5c889f2d5..000000000 --- a/public/README +++ /dev/null @@ -1,3 +0,0 @@ -To populate this directory you need to generate the PHP version of Pattern Lab for the first time. -To do so either run "php core/builder.php -g" at the command line or, if you're on a Mac, double-click -on "core/scripts/generateSite.command". \ No newline at end of file diff --git a/source/README b/source/.gitkeep similarity index 100% rename from source/README rename to source/.gitkeep