diff --git a/.gitignore b/.gitignore index a23cf51e7..d4f687c7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,5 @@ .DS_Store +export/* public/* -!public/listeners/* -!public/styleguide/* -!public/patterns/**/* -!public/data/*.js -config.ini -latest-change.txt -*-ck.js +source/styleguide/* +vendor/* diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index 68a8afe7e..000000000 --- a/CHANGELOG +++ /dev/null @@ -1,76 +0,0 @@ -THIS CHANGELOG IS AN ATTEMPT TO DOCUMENT CHANGES TO THIS PROJECT. - -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 d7b86e68b..bd36c1262 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Brad Frost, http://bradfrostweb.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 fa0575503..04543132c 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,101 @@ -## About the PHP Version of Pattern Lab +![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, the PHP version of Pattern Lab strongly separates patterns, data, and presentation from build logic. The PHP version should be seen as a reference for other developers to improve upon as they build their own Pattern Lab Builders in their language of choice. +# 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 the PHP version of Pattern Lab at [demo.pattern-lab.info](http://demo.pattern-lab.info). +You can play with a demo of the front-end of Pattern Lab at [demo.patternlab.io](http://demo.patternlab.io). + +## 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 + +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). + +### Use Composer to create a project + +Pattern Lab uses [Composer](https://getcomposer.org/) to manage project dependencies. + +#### 1. Install Composer + +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). + +#### 2. Install the Standard Edition for Mustache + +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: + +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 $_` +3. When prompted, type `1` to install the demo StarterKit + +This will install the Standard Edition for Mustache along with the demo StarterKit into a directory called `patternlab2-example`. You will be automatically dropped into `patternlab2-example/` when the install is finished. + +**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 + +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. + +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 + +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. + +## Migrating from Pattern Lab 1 to Pattern Lab 2 + +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: -## Getting Started +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` -The PHP version of Pattern Lab should be relatively easy for anyone to get up and running. +Everything else should work without changes. -* [Requirements](http://pattern-lab.info/docs/requirements.html) -* [Installing the PHP Version of Pattern Lab](http://pattern-lab.info/docs/installation.html) -* [Generating the Pattern Lab Website for the First Time](http://pattern-lab.info/docs/first-run.html) -* [Editing the Pattern Lab Website Source Files](http://pattern-lab.info/docs/editing-source-files.html) -* [Using the Command-line Options](http://pattern-lab.info/docs/command-line.html) -* [Command Prompt on Windows](http://pattern-lab.info/docs/command-prompt-windows.html) +## Need Pattern Lab 1? -## Working with Patterns +The [source code for Pattern Lab 1](https://github.com/pattern-lab/patternlab-php/releases/tag/v1.1.0) is still available for download. -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. +## Packaged Components -* [How Patterns Are Organized](http://pattern-lab.info/docs/pattern-organization.html) -* [Adding New Patterns](http://pattern-lab.info/docs/pattern-add-new.html) -* [Reorganizing Patterns](http://pattern-lab.info/docs/pattern-reorganizing.html) -* [Converting Old Patterns](https://github.com/pattern-lab/patternlab-php/wiki/Converting-Old-Patterns) -* ["Hiding" Patterns in the Navigation](http://pattern-lab.info/docs/pattern-hiding.html) -* [Including One Pattern Within Another via Partials](http://pattern-lab.info/docs/pattern-including.html) -* [Linking Directly to a Pattern](http://pattern-lab.info/docs/pattern-linking.html) -* [Managing Assets for a Pattern: JavaScript, images, CSS, etc.](http://pattern-lab.info/docs/pattern-managing-assets.html) -* [Adding Annotations](http://pattern-lab.info/docs/pattern-adding-annotations.html) +The Standard Edition for Mustache installs the following components: -## Creating & Working With Dynamic Data for a Pattern +* `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) -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](https://github.com/pattern-lab/patternlab-php/wiki/Including-One-Pattern-Within-Another) 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. +## List All of the Available Commands and Their Options -* [Introduction to JSON & Mustache Variables](http://pattern-lab.info/docs/data-json-mustache.html) -* [Overriding the Central `data.json` Values with Pattern-specific Values](http://pattern-lab.info/docs/data-pattern-specific.html) -* [Linking to Patterns with Pattern Lab's Default `link` Variable](http://pattern-lab.info/docs/data-link-variable.html) -* [Creating Lists with Pattern Lab's Default `listItems` Variable](http://pattern-lab.info/docs/data-listitems.html) +To list all available commands type: -## Using Pattern Lab's Advanced Features + php core/console --help -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 the PHP version of Pattern Lab can make your development workflow a little smoother: +To list the options for a particular command type: -* [Watching for Changes and Auto-Regenerating Patterns](http://pattern-lab.info/docs/advanced-auto-regenerate.html) -* [Auto-Reloading the Browser Window When Changes Are Made](http://pattern-lab.info/docs/advanced-reload-browser.html) -* [Multi-browser & Multi-device Testing with Page Follow](http://pattern-lab.info/docs/advanced-page-follow.html) \ No newline at end of file + php core/console --help --[command] diff --git a/builder/builder.php b/builder/builder.php deleted file mode 100644 index b00f1d871..000000000 --- a/builder/builder.php +++ /dev/null @@ -1,82 +0,0 @@ -generate(true) : $g->generate(); - - print "your site has been generated...\n"; - - } else if (isset($args["w"])) { - - // initiate the w (watch) switch - - // iterate over the source directory and generate the site - $g = new Generatr(); - $g->generate(); - print "your site has been generated...\n"; - - // watch the source directory and regenerate any changed files - $w = new Watchr(); - print "watching your site for changes...\n"; - $w->watch(); - - } else { - - // when in doubt write out the usage - print "\n"; - print "Usage:\n\n"; - print " php ".$_SERVER["PHP_SELF"]." -g\n"; - print " Iterates over the 'source' directories & files and generates the entire site a single time.\n"; - print " It also cleans the 'public' directory.\n\n"; - print " php ".$_SERVER["PHP_SELF"]." -w\n"; - print " Generates the site like the -g flag and then watches for changes in the 'source' directories &\n"; - print " files. Will re-generate files if they've changed.\n\n"; - - } - -} else { - - print "The builder script can only be run from the command line."; - -} diff --git a/builder/lib/Mustache/Autoloader.php b/builder/lib/Mustache/Autoloader.php deleted file mode 100644 index df48536d0..000000000 --- a/builder/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/builder/lib/Mustache/Compiler.php b/builder/lib/Mustache/Compiler.php deleted file mode 100644 index a95c9194b..000000000 --- a/builder/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/builder/lib/Mustache/Context.php b/builder/lib/Mustache/Context.php deleted file mode 100644 index e7783b43c..000000000 --- a/builder/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/builder/lib/Mustache/Engine.php b/builder/lib/Mustache/Engine.php deleted file mode 100644 index 5f92d1948..000000000 --- a/builder/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/builder/lib/Mustache/Exception.php b/builder/lib/Mustache/Exception.php deleted file mode 100644 index b4f830046..000000000 --- a/builder/lib/Mustache/Exception.php +++ /dev/null @@ -1,18 +0,0 @@ -token = $token; - parent::__construct($msg); - } - - public function getToken() - { - return $this->token; - } -} diff --git a/builder/lib/Mustache/Exception/UnknownFilterException.php b/builder/lib/Mustache/Exception/UnknownFilterException.php deleted file mode 100644 index f5c0884d4..000000000 --- a/builder/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/builder/lib/Mustache/Exception/UnknownHelperException.php b/builder/lib/Mustache/Exception/UnknownHelperException.php deleted file mode 100644 index 98af13ebe..000000000 --- a/builder/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/builder/lib/Mustache/Exception/UnknownTemplateException.php b/builder/lib/Mustache/Exception/UnknownTemplateException.php deleted file mode 100644 index 141d372bd..000000000 --- a/builder/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/builder/lib/Mustache/HelperCollection.php b/builder/lib/Mustache/HelperCollection.php deleted file mode 100644 index e9911378a..000000000 --- a/builder/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/builder/lib/Mustache/LICENSE b/builder/lib/Mustache/LICENSE deleted file mode 100644 index 6db530008..000000000 --- a/builder/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/builder/lib/Mustache/LambdaHelper.php b/builder/lib/Mustache/LambdaHelper.php deleted file mode 100644 index dfd4659c4..000000000 --- a/builder/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/builder/lib/Mustache/Loader.php b/builder/lib/Mustache/Loader.php deleted file mode 100644 index f659a1d3a..000000000 --- a/builder/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/builder/lib/Mustache/Loader/CascadingLoader.php b/builder/lib/Mustache/Loader/CascadingLoader.php deleted file mode 100644 index 192edb97f..000000000 --- a/builder/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/builder/lib/Mustache/Loader/FilesystemLoader.php b/builder/lib/Mustache/Loader/FilesystemLoader.php deleted file mode 100644 index 71d7f1c8e..000000000 --- a/builder/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/builder/lib/Mustache/Loader/InlineLoader.php b/builder/lib/Mustache/Loader/InlineLoader.php deleted file mode 100644 index 1463bf8b5..000000000 --- a/builder/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/builder/lib/Mustache/Loader/MutableLoader.php b/builder/lib/Mustache/Loader/MutableLoader.php deleted file mode 100644 index 02bb207a9..000000000 --- a/builder/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); - return $this->templates[$name]; - } catch (Exception $e) { - print "The partial, ".$name.", wasn't found so a pattern failed to build.\n"; - } - } else { - 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) - { - //get pattern data - $pattern_data = $this->getPatternIncludeData($name); - - //get file path - $fileName = $this->getFileName($pattern_data['file']); - - //throw error if path is not found - if (!file_exists($fileName)) { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - //get file as string - $file_str = file_get_contents($fileName); - - //if pattern include was called with param, render param - if (isset($pattern_data['param'])) { - $file_str = $this->renderPattern($file_str, $pattern_data['param']); - } - - return $file_str; - } - - /** - * Helper function for getting a Mustache template file name. - * - * @param string $name - * - * @return string Template file name - */ - protected function getFileName($name) - { - $fileName = ""; - - // test to see what kind of path was supplied - $posDash = strpos($name,"-"); - $posSlash = strpos($name,"/"); - 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."/".$this->patternPaths[$patternType][$pattern]; - } else if (isset($this->patternPaths[$patternType])) { - foreach($this->patternPaths[$patternType] as $patternMatchKey=>$patternMatchValue) { - $pos = strpos($patternMatchKey,$pattern); - if ($pos !== false) { - $fileName = $this->baseDir."/".$patternMatchValue; - break; - } - } - } - - } else { - $fileName = $this->baseDir."/".$name; - } - - if (substr($fileName, 0 - strlen($this->extension)) !== $this->extension) { - $fileName .= $this->extension; - } - - return $fileName; - } - - /** - * Inspects pattern include call for param - * ex: - * {{ > patternType-pattern(param1: value, param2 ...) }} - * - * and returns pattern data array with the following elements - * - * string $file - the file name - * - * array|null $param - an associative array of param ex: param_name => $param_value... or null if none found - * - * @param string $pattern_include_call_str - * @return array returns pattern data array - * - */ - - protected function getPatternIncludeData($pattern_include_call_str) - { - //create an array to store pattern include data - - $pattern_data = array(); - - // $pattern_include_call_str contains pattern name - // followed by param, example: - // patterntype-pattern (param1: value, param2: value2) - - $p_inc_str = $pattern_include_call_str; - - //get param using regex - //first remove all line breaks from string - - $p_inc_str = preg_replace("/[\r\n]*/","",$p_inc_str); - - //now use regex to get everything between parentheses ( ) - //note: this regex call ignores escaped parenteses \( and \) - - $matches = preg_match('/\([^\(\\\\]*(?:\\\\.[^\)\\\\]*)*\)/s', $p_inc_str, $p_inc_param); - - //if no matches are found return file name only, and set - //param to null - - if(!$matches){ - - $pattern_data['file'] = $p_inc_str; - $pattern_data['param'] = null; - return $pattern_data; - } - - //otherwise strip param from string and set file - - else { - - //strip param and add [file] as the include file name - $pattern_data['file'] = trim(preg_replace('/\([^\(\\\\]*(?:\\\\.[^\)\\\\]*)*\)/s', '', $p_inc_str)); - } - - //remove spaces & parentheses from either end of param string - - $p_inc_param = trim($p_inc_param[0], '()'); - - //split param by commas , but ignore escaped commas - - $p_inc_param = preg_split('/(? $v) - { - //replace each instance of {{ param_name }} with actual value - - $pattern_string = preg_replace('/{{([\s]*'.$k .'[\s]*)}}/', $v, $pattern_string); - } - - //return new pattern string - - return $pattern_string; - } - - 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); - - } - -} diff --git a/builder/lib/Mustache/Loader/StringLoader.php b/builder/lib/Mustache/Loader/StringLoader.php deleted file mode 100644 index e73b3cdec..000000000 --- a/builder/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/builder/lib/Mustache/Logger.php b/builder/lib/Mustache/Logger.php deleted file mode 100644 index e08359a91..000000000 --- a/builder/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/builder/lib/Mustache/Logger/StreamLogger.php b/builder/lib/Mustache/Logger/StreamLogger.php deleted file mode 100644 index da771f90e..000000000 --- a/builder/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/builder/lib/Mustache/Parser.php b/builder/lib/Mustache/Parser.php deleted file mode 100644 index ab7db8463..000000000 --- a/builder/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/builder/lib/Mustache/Template.php b/builder/lib/Mustache/Template.php deleted file mode 100644 index aeee42d49..000000000 --- a/builder/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/builder/lib/Mustache/Tokenizer.php b/builder/lib/Mustache/Tokenizer.php deleted file mode 100644 index 56e8ba6b7..000000000 --- a/builder/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/builder/lib/builder.lib.php b/builder/lib/builder.lib.php deleted file mode 100644 index f058552fd..000000000 --- a/builder/lib/builder.lib.php +++ /dev/null @@ -1,976 +0,0 @@ - $value) { - - // if the variables are array-like make sure the properties are validated/trimmed/lowercased before saving - if (($key == "ie") || ($key == "id")) { - $values = explode(",",$value); - array_walk($values,'Buildr::trim'); - $this->$key = $values; - } else { - $this->$key = $value; - } - } - - // generate patternTypes as well as patternPaths - $this->gatherPatternPaths(); - - // generate patternLineages - $this->gatherLineages(); - - // get nav items - $this->gatherNavItems(); - - // 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 Mustache_Engine(array( - "loader" => new Mustache_Loader_PatternLoader(__DIR__.$this->sp,array("patternPaths" => $this->patternPaths)), - "partials_loader" => new Mustache_Loader_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 Mustache_Engine(array( - "loader" => new Mustache_Loader_FilesystemLoader(__DIR__."/../../source/_patternlab-files/"), - "partials_loader" => new Mustache_Loader_FilesystemLoader(__DIR__."/../../source/_patternlab-files/partials/") - )); - } - - /** - * Renders a given pattern file using Mustache and incorporating the provided data - * @param {String} the filename of the file to be rendered - * @param {Object} the instance of mustache to be used in the rendering - * - * @return {String} the mark-up as rendered by Mustache - */ - protected function renderPattern($f) { - - // 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($f,$d->patternSpecific)) { - $d = (object) array_merge((array) $d, (array) $d->patternSpecific->$f); - } - - return $this->mpl->render($f,$d); - - } - - /** - * Generates the index page and style guide - */ - protected function generateMainPages() { - - // make sure $this->mfs is refreshed - $this->loadMustacheFileSystemLoaderInstance(); - - // render out the main pages and move them to public - $this->navItems['contentsyncport'] = $this->contentSyncPort; - $this->navItems['navsyncport'] = $this->navSyncPort; - $this->navItems['patternpaths'] = json_encode($this->patternPaths); - $this->navItems['viewallpaths'] = json_encode($this->viewAllPaths); - $this->navItems['mqs'] = $this->gatherMQs(); - - // grab the partials into a data object for the style guide - $sd = $this->gatherPartials(); - - // sort partials by patternLink - usort($sd['partials'], "Buildr::sortPartials"); - - // render the "view all" pages - $this->generateViewAllPages(); - - // render the index page and the style guide - $r = $this->mfs->render('index',$this->navItems); - file_put_contents(__DIR__."/../../public/index.html",$r); - $s = $this->mfs->render('styleguide',$sd); - file_put_contents(__DIR__."/../../public/styleguide/html/styleguide.html",$s); - - } - - /** - * Generates all of the patterns and puts them in the public directory - */ - protected function generatePatterns() { - - // make sure $this->mpl is refreshed - $this->loadMustachePatternLoaderInstance(); - - // loop over the pattern paths to generate patterns for each - foreach($this->patternPaths as $patternType) { - - foreach($patternType as $pattern => $path) { - - $r = $this->generatePatternFile($path.".mustache"); - - // if the pattern directory doesn't exist create it - $path = str_replace("/","-",$path); - if (!is_dir(__DIR__.$this->pp.$path)) { - mkdir(__DIR__.$this->pp.$path); - file_put_contents(__DIR__.$this->pp.$path."/".$path.".html",$r); - } else { - file_put_contents(__DIR__.$this->pp.$path."/".$path.".html",$r); - } - - } - - } - - } - - /** - * Generates a pattern with a header & footer - * @param {String} the filename of the file to be rendered - * - * @return {String} the final rendered pattern including the standard header and footer for a pattern - */ - private function generatePatternFile($f) { - - $hr = file_get_contents(__DIR__.$this->sp."../_patternlab-files/pattern-header-footer/header.html"); - $rf = $this->renderPattern($f); - $fr = file_get_contents(__DIR__.$this->sp."../_patternlab-files/pattern-header-footer/footer.html"); - - // the footer isn't rendered as mustache but we have some variables there any way. find & replace. - $pp = $this->getPatternPartial($f); - $fr = str_replace("{{ patternPartial }}",$pp,$fr); - $fr = str_replace("{{ lineage }}",json_encode($this->patternLineages[$pp]),$fr); - $fr = str_replace("{{ patternHTML }}",$rf,$fr); - - // set-up the mark-up for CSS Rule Saver so it can figure out which rules to save - if ($this->enableCSS) { - $this->cssRuleSaver->loadHTML($rf,false); - $patternCSS = $this->cssRuleSaver->saveRules(); - $this->patternCSS[$pp] = $patternCSS; - $fr = str_replace("{{ patternCSS }}",$patternCSS,$fr); - } - - return $hr."\n".$rf."\n".$fr; - - } - - /** - * Generates the view all pages - */ - protected function generateViewAllPages() { - - // make sure $this->mfs is refreshed on each generation of view all. for some reason the mustache instance dies - $this->loadMustacheFileSystemLoaderInstance(); - - // add view all to each list - $i = 0; $k = 0; - foreach ($this->navItems['buckets'] as $bucket) { - - // make sure that the navItems index exists. catches issues with pages & templates - if (isset($bucket["navItems"])) { - - foreach ($bucket["navItems"] as $navItem) { - - // make sure the navSubItems index exists. catches issues with empty folders - if (isset($navItem["navSubItems"])) { - - foreach ($navItem["navSubItems"] 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 = $this->gatherPartialsByMatch($patternType, $patternSubType); - $sid["patternPartial"] = $subItem["patternPartial"]; - - // render the viewall template - $v = $this->mfs->render('viewall',$sid); - - // 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",$v); - } else { - file_put_contents(__DIR__.$this->pp.$patternPath."/index.html",$v); - } - - } - - } - - } - - } - - } - - $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->patternSpecific : holds attributes from the pattern-specific data files - * - * @return {Array} populates $this->d - */ - protected function gatherData() { - - // gather the data from the main source data.json - if (file_exists(__DIR__."/../../source/_data/_data.json")) { - $this->d = (object) array_merge(array(), (array) json_decode(file_get_contents(__DIR__."/../../source/_data/_data.json"))); - } - - // add list item data, makes 'listItems' a reserved word - if (file_exists(__DIR__."/../../source/_data/_listitems.json")) { - - $listItems = (array) json_decode(file_get_contents(__DIR__."/../../source/_data/_listitems.json")); - $numbers = array("one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"); - - $i = 0; - $k = 1; - $c = count($listItems)+1; - - $this->d->listItems = new stdClass(); - - while ($k < $c) { - - shuffle($listItems); - $itemsArray = array(); - $this->d->listItems->$numbers[$k-1] = new stdClass(); - - while ($i < $k) { - $itemsArray[] = $listItems[$i]; - $i++; - } - - $this->d->listItems->$numbers[$k-1] = $itemsArray; - - $i = 0; - $k++; - - } - - } - - // add the link names for easy reference, makes 'link' a reserved word - $this->d->link = new stdClass(); - foreach($this->patternPaths as $patternTypeName => $patterns) { - - foreach($patterns as $pattern => $path) { - $patternName = $patternTypeName."-".$pattern; - $path = str_replace("/","-",$path); - $this->d->link->$patternName = "../../patterns/".$path."/".$path.".html"; - } - - } - - // add pattern specific data so it can override when a pattern (not partial!) is rendered - // makes 'patternSpecific' a reserved word - $this->d->patternSpecific = new stdClass(); - foreach($this->patternTypes as $patternType) { - - // $this->d->patternSpecific["pattern-name-that-matches-render.mustache"] = array of data; - $patternTypeClean = $this->getPatternName($patternType,false); - - // find pattern data for pattern subtypes*/ - foreach(glob(__DIR__.$this->sp.$patternType."/*/*.json") as $filename) { - $path = $this->getPath($filename,"j"); - if (in_array($path,$this->patternPaths[$patternTypeClean])) { - $patternName = $path.".mustache"; - $this->d->patternSpecific->$patternName = (array) json_decode(file_get_contents(__DIR__."/../../source/_patterns/".$path.".json")); - } - } - - // find pattern data for pattern types that are flat (e.g. pages & templates) - foreach(glob(__DIR__.$this->sp.$patternType."/*.json") as $filename) { - $path = $this->getPath($filename,"j"); - if (in_array($path,$this->patternPaths[$patternTypeClean])) { - $patternName = $path.".mustache"; - $this->d->patternSpecific->$patternName = (array) json_decode(file_get_contents(__DIR__."/../../source/_patterns/".$path.".json")); - } - } - - } - - } - - /** - * Finds the Lineages for the patterns - * - * @return {Array} an array of patterns with their lineages - */ - protected function gatherLineages() { - $this->patternLineages = array(); - - foreach($this->patternPaths as $patternType => $patterns) { - - foreach ($patterns as $pattern => $filename) { - - $patternLineage = array(); - $foundLineages = $this->getLineage($filename); - - if (count($foundLineages) > 0) { - foreach ($foundLineages as $lineage) { - $patternBits = explode("-",$lineage,2); // BUG: this is making an assumption - $path = str_replace("/","-",$this->patternPaths[$patternBits[0]][$patternBits[1]]); - $patternLineage[] = array("lineagePattern" => $lineage, "lineagePath" => "../../patterns/".$path."/".$path.".html"); - } - } - - $this->patternLineages[$patternType."-".$pattern] = $patternLineage; - - } - - } - - } - - /** - * 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(__DIR__."/../../source/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; - - } - - /** - * Gathers the partials for the nav drop down in Pattern Lab - * - * @return {Array} populates $this->navItems - */ - protected function gatherNavItems() { - - $b = array("buckets" => array()); // the array that will contain the items - $bi = 0; // track the number for the bucket array - $ni = 0; // track the number for the nav items array - $incrementNavItem = true; // track nav item regeneration so we avoid rebuilding view all pages - - // iterate through each pattern type and add them as buckets - foreach($this->patternTypes as $patternType) { - - // get the bits for a bucket and check to see if the first bit is a number - $bucket = $this->getPatternName($patternType); // ok, it's not a pattern name but same functionality - - // add a new bucket - $b["buckets"][$bi] = array("bucketNameLC" => strtolower($bucket), - "bucketNameUC" => ucwords($bucket)); - - // see if a pattern has subtypes - $patternSubTypes = glob(__DIR__.$this->sp.$patternType."/*",GLOB_ONLYDIR); - if (count($patternSubTypes) == 0) { - - // find the patterns and add them to the nav - foreach(glob(__DIR__.$this->sp.$patternType."/*.mustache") as $pattern) { - - $patternPathBits = explode("/",$pattern); - if ($patternPathBits[count($patternPathBits) - 1][0] != "_") { - - // get the bits for a pattern and check to see if the first bit is a number - $patternClean = substr($pattern,strlen(__DIR__.$this->sp.$patternType."/")); - $patternClean = str_replace(".mustache","",$patternClean); - $patternFinal = $this->getPatternName($patternClean); - - // add a new pattern - $b["buckets"][$bi]["patternItems"][] = array("patternPath" => $patternType."-".$patternClean."/".$patternType."-".$patternClean.".html", - "patternName" => ucwords($patternFinal), - "patternPartial" => str_replace(" ","-",$bucket)."-".str_replace(" ","-",$patternFinal)); - } - - } - - // if all of the patterns for a given pattern type (e.g. atoms) were commented out we need to unset it - if (!isset($b["buckets"][$bi]["patternItems"])) { - unset($b["buckets"][$bi]); - $bi--; - } - - } else { - - // iterate over pattern sub-types - foreach($patternSubTypes as $dir) { - - // NOTE: clean items still include directory numbers, final items DO NOT. made sense at the time i originally wrote it - - // get the bits for a directory and check to see if the first bit is a number - $dirClean = substr($dir,strlen(__DIR__.$this->sp.$patternType."/")); - $dirFinal = $this->getPatternName($dirClean); // ok, it's not a pattern name but same functionality - - // add a new section - $b["buckets"][$bi]["navItems"][$ni] = array("sectionNameLC" => strtolower($dirFinal), - "sectionNameUC" => ucwords($dirFinal)); - - // iterate over patterns - foreach(glob(__DIR__.$this->sp.$patternType."/".$dirClean."/*.mustache") as $pattern) { - - $patternPathBits = explode("/",$pattern); - if ($patternPathBits[count($patternPathBits) - 1][0] != "_") { - - // get the bits for a pattern and check to see if the first bit is a number - $patternClean = substr($pattern,strlen(__DIR__.$this->sp.$patternType."/".$dirClean."/")); - $patternClean = str_replace(".mustache","",$patternClean); - $patternFinal = $this->getPatternName($patternClean); - - // add a new pattern - $b["buckets"][$bi]["navItems"][$ni]["navSubItems"][] = array("patternPath" => $patternType."-".$dirClean."-".$patternClean."/".$patternType."-".$dirClean."-".$patternClean.".html", - "patternName" => ucwords($patternFinal), - "patternPartial" => str_replace(" ","-",$bucket)."-".str_replace(" ","-",$patternFinal)); - - } - - // if all of the patterns for a given sub-type were commented out we need to unset it - if (!isset($b["buckets"][$bi]["navItems"][$ni]["navSubItems"])) { - unset($b["buckets"][$bi]["navItems"][$ni]); - $incrementNavItem = false; - } - - } - - // add a view all for the section - if (isset($b["buckets"][$bi]["navItems"][$ni]["navSubItems"])) { - $subItemsCount = count($b["buckets"][$bi]["navItems"][$ni]["navSubItems"]); - $vaBucket = str_replace(" ","-",$bucket); - $vaDirFinal = str_replace(" ","-",$dirFinal); - $b["buckets"][$bi]["navItems"][$ni]["navSubItems"][$subItemsCount] = array("patternPath" => $patternType."-".$dirClean."/index.html", - "patternName" => "View All", - "patternType" => $patternType, - "patternSubType" => $dirClean, - "patternPartial" => "viewall-".$vaBucket."-".$vaDirFinal); - $this->viewAllPaths[$vaBucket][$vaDirFinal] = $patternType."-".$dirClean; - } - - // this feels like such a hacky way of doing it - if (!$incrementNavItem) { - $incrementNavItem = true; - } else { - $ni++; - } - - } - } - - $bi++; - $ni = 0; - - } - - $this->navItems = $b; - - } - - /** - * Pulls together all of the pattern paths for use with mustache and the simplified partial matching - * - * @return {Array} populates $this->patternPaths - * @return {Array} populates $this->patternTypes - * @return {Array} populates $this->patternLineages - */ - protected function gatherPatternPaths() { - - // set-up vars - $this->patternPaths = array(); - $this->patternTypes = array(); - - // get the pattern types - foreach(glob(__DIR__.$this->sp."/*",GLOB_ONLYDIR) as $patternType) { - $this->patternTypes[] = substr($patternType,strlen(__DIR__.$this->sp)+1); - } - - // set-up the regex for getPath() - $this->getPatternTypesRegex(); - - // find the patterns for the types - foreach($this->patternTypes as $patternType) { - - $patternTypePaths = array(); - $patternTypeClean = $this->getPatternName($patternType, false); - - // find pattern paths for pattern subtypes - foreach(glob(__DIR__.$this->sp.$patternType."/*/*.mustache") as $filename) { - preg_match('/\/([A-z0-9-_]{1,})\.mustache$/',$filename,$matches); - $pattern = $this->getPatternName($matches[1], false); - if (($pattern[0] != "_") && (!isset($patternTypePaths[$pattern]))) { - $patternTypePaths[$pattern] = $this->getPath($filename); - } - } - - // find pattern paths for pattern types that are flat (e.g. pages & templates) - foreach(glob(__DIR__.$this->sp.$patternType."/*.mustache") as $filename) { - preg_match('/\/([A-z0-9-_]{1,})\.mustache$/',$filename,$matches); - $pattern = $this->getPatternName($matches[1], false); - if (($pattern[0] != "_") && (!isset($patternTypePaths[$pattern]))) { - $patternTypePaths[$pattern] = $this->getPath($filename); - } - } - - $this->patternPaths[$patternTypeClean] = $patternTypePaths; - - } - - } - - /** - * Renders the patterns in the source directory so they can be used in the default styleguide - * - * @return {Array} an array of rendered partials - */ - protected function gatherPartials() { - - // make sure $this->mpl is refreshed - $this->loadMustachePatternLoaderInstance(); - - $p = array("partials" => array()); - - // loop through pattern paths - foreach($this->patternPaths as $patternType => $patternTypeValues) { - - foreach($patternTypeValues as $pattern => $path) { - - if (substr_count($path,"/") == 2) { - - // double-check the file exists - if (file_exists(__DIR__."/".$this->sp.$path.".mustache")) { - - // create the pattern name & link, render the partial, and stick it all into the pattern array - $patternParts = explode("/",$path); - $patternName = $this->getPatternName($patternParts[2]); - $patternLink = str_replace("/","-",$path)."/".str_replace("/","-",$path).".html"; - $patternCode = $this->renderPattern($path.".mustache"); - $patternPartial = $this->getPatternPartial($path); - $patternLineageExists = (count($this->patternLineages[$patternPartial]) > 0) ? true : false; - $patternLineages = $this->patternLineages[$patternPartial]; - $patternCSSExists = $this->enableCSS; - $patternCSS = ($this->enableCSS) ? $this->patternCSS[$patternPartial] : ""; - - $p["partials"][] = array("patternName" => ucwords($patternName), - "patternLink" => $patternLink, - "patternPartialPath" => $patternType."-".$pattern, - "patternPartial" => $patternCode, - "patternCSS" => $patternCSS, - "patternLineageExists" => $patternLineageExists, - "patternLineages" => $patternLineages, - "patternCSSExists" => $patternCSSExists, - "patternCSS" => $patternCSS - ); - } - - } - - } - - } - - return $p; - - } - - /** - * Renders the patterns that match a given string so they can be used in the view all styleguides - * @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 gatherPartialsByMatch($patternType, $patternSubType) { - - // make sure $this->mpl is refreshed - $this->loadMustachePatternLoaderInstance(); - - $p = array("partials" => array()); - - $patternTypeClean = $this->getPatternName($patternType); - - // get matches based on pattern type and pattern sub-type - foreach(glob(__DIR__.$this->sp.$patternType."/".$patternSubType."/*.mustache") as $filename) { - - // get the directory match of the pattern - $path = $this->getPath($filename); - - // because we're globbing we need to check again to see if the pattern should be ignored - $patternParts = explode("/",$path); - if ($patternParts[2][0] != "_") { - - // create the pattern name & link, render the partial, and stick it all into the pattern array - $patternName = $this->getPatternName($patternParts[2]); - $patternLink = str_replace("/","-",$path)."/".str_replace("/","-",$path).".html"; - $patternCode = $this->renderPattern($path.".mustache"); - $patternPartial = $this->getPatternPartial($path); - $patternLineages = $this->patternLineages[$patternPartial]; - $patternLineageExists = (count($patternLineages) > 0) ? true : false; - $patternCSSExists = $this->enableCSS; - $patternCSS = ($this->enableCSS) ? $this->patternCSS[$patternPartial] : ""; - - $p["partials"][] = array("patternName" => ucwords($patternName), - "patternLink" => $patternLink, - "patternPartialPath" => str_replace(" ","-",$patternTypeClean)."-".str_replace(" ","-",$patternName), - "patternPartial" => $patternCode, - "patternCSS" => $patternCSS, - "patternLineageExists" => $patternLineageExists, - "patternLineages" => $patternLineages, - "patternCSSExists" => $patternCSSExists, - "patternCSS" => $patternCSS - ); - - } - - } - - return $p; - - } - - /** - * 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"); - if (preg_match_all('/{{>([ ]+)?([A-Za-z0-9-]+)([ ]+)?}}/',$data,$matches)) { - return $matches[2]; - } - return array(); - } - - /** - * 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]; - } - } - - /** - * 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; - } - - /** - * Get the pattern partial for a given file - * @param {String} the file name for a pattern - * - * @return {String} the pattern partial - */ - protected function getPatternPartial($fileName) { - - $fileName = str_replace(".mustache","",$fileName); - - foreach($this->patternPaths as $patternTypeKey => $patternTypeVals) { - - foreach($patternTypeVals as $pattern => $path) { - - if ($path == $fileName) { - return $patternTypeKey."-".$pattern; - } - - } - - } - - return false; - - } - - /** - * Create a regex based on $this->patternTypes - * - * @return {String} populates $this->patternTypesRegex - */ - protected function getPatternTypesRegex() { - - $i = 0; - $regex = "("; - foreach($this->patternTypes as $patternType) { - $regex .= ($i != 0) ? "|".$patternType : $patternType; - $i++; - } - $regex .= ")"; - - $this->patternTypesRegex = $regex; - - } - - /** - * 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(__DIR__."/../../public/")) { - file_put_contents(__DIR__."/../../public/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() { - - // find all of the patterns in public/. sort by the children first - $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__."/../../public/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(__DIR__."/../../source/*",GLOB_ONLYDIR); - $publicDirs = glob(__DIR__."/../../public/*",GLOB_ONLYDIR); - - // make sure some directories aren't deleted - $ignoreDirs = array("listeners","styleguide"); - foreach ($ignoreDirs as $ignoreDir) { - $key = array_search(__DIR__."/../../public/".$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(__DIR__."/../../source/","",$sourceDir); - if ($cleanDir[0] == "_") { - $key = array_search(__DIR__."/../../public/".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(__DIR__."/../../source/".$s)) { - copy(__DIR__."/../../source/".$s,__DIR__."/../../public/".$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() { - - $this->cssRuleSaver = new cssRuleSaver; - - foreach(glob(__DIR__."/../../source/css/*.css") as $filename) { - $this->cssRuleSaver->loadCSS($filename); - } - - } - - /** - * 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); - } - - /** - * Sort the partials generated for the styleguide so that any new ones show up in the correct place - * @param {Array} items from from one pattern to compare - * @param {Array} items from another pattern to compare - * - * @return {Integer} the result of the string comparison - */ - public function sortPartials($a,$b) { - return strcmp($a["patternLink"],$b["patternLink"]); - } - - /** - * 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/builder/lib/css-rule-saver/LICENSE b/builder/lib/css-rule-saver/LICENSE deleted file mode 100644 index 2e13f8ef8..000000000 --- a/builder/lib/css-rule-saver/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/builder/lib/css-rule-saver/css-rule-saver.php b/builder/lib/css-rule-saver/css-rule-saver.php deleted file mode 100644 index 061d11f5f..000000000 --- a/builder/lib/css-rule-saver/css-rule-saver.php +++ /dev/null @@ -1,267 +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/builder/lib/css-rule-saver/lib/php-selector/History.rdoc b/builder/lib/css-rule-saver/lib/php-selector/History.rdoc deleted file mode 100755 index 27ebf9014..000000000 --- a/builder/lib/css-rule-saver/lib/php-selector/History.rdoc +++ /dev/null @@ -1,20 +0,0 @@ - -=== 1.1.3 / 2009-07-17 - -* Added comma support - -=== 1.1.2 / 2009-07-17 - -* Supress annoying libxml warnings - -=== 1.1.1 / 2009-07-17 - -* Fixed attributes - -=== 1.1.0 / 2009-07-17 - -* Added SelectorDom - -=== 1.0.0 / 2009-07-17 - -* Initial Release \ No newline at end of file diff --git a/builder/lib/css-rule-saver/lib/php-selector/Readme.rdoc b/builder/lib/css-rule-saver/lib/php-selector/Readme.rdoc deleted file mode 100755 index e52f73232..000000000 --- a/builder/lib/css-rule-saver/lib/php-selector/Readme.rdoc +++ /dev/null @@ -1,78 +0,0 @@ -= PHP Selector - -Quick DOM query library I whipped up for an old -PHP data miner I had which needed more flexibility. - -Current supports most CSS3 selectors. - -Tested with php 5.4 - -== Examples - -Given the sample html: - - $html = << -

Article Name

-

Contents of article

- - - HTML; - -The following will return an array of elements: - - select_elements('div#article.large', $html); - select_elements('div > h2:contains(Article)', $html); - select_elements('div p + ul', $html); - select_elements('ul > li:first-child', $html); - select_elements('ul > li ~ li', $html); - select_elements('ul > li:last-child', $html); - select_elements('li a[href=#]', $html); - -== SelectorDOM - -Persistant object for element selection. - - $dom = new SelectorDOM($html); - $links = $dom->select('a'); - $list_links = $dom->select('ul li a'); - -== Contribution - -* Like it? use it? feel free to extend and add more CSS3 support, and - run test.selector.php - -== More Information - -* View the source :P - -== License - -(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. diff --git a/builder/lib/css-rule-saver/lib/php-selector/selector.php b/builder/lib/css-rule-saver/lib/php-selector/selector.php deleted file mode 100755 index af9044363..000000000 --- a/builder/lib/css-rule-saver/lib/php-selector/selector.php +++ /dev/null @@ -1,176 +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/builder/lib/css-rule-saver/lib/php-selector/test.selector.php b/builder/lib/css-rule-saver/lib/php-selector/test.selector.php deleted file mode 100755 index 00a65e07a..000000000 --- a/builder/lib/css-rule-saver/lib/php-selector/test.selector.php +++ /dev/null @@ -1,124 +0,0 @@ - bar', 'descendant-or-self::foo/bar'); -test('foo >bar', 'descendant-or-self::foo/bar'); -test('foo>bar', 'descendant-or-self::foo/bar'); -test('foo> bar', 'descendant-or-self::foo/bar'); -test('div#foo', 'descendant-or-self::div[@id="foo"]'); -test('#foo', 'descendant-or-self::*[@id="foo"]'); -test('div.foo', 'descendant-or-self::div[contains(concat(" ",@class," ")," foo ")]'); -test('.foo', 'descendant-or-self::*[contains(concat(" ",@class," ")," foo ")]'); -test('[id]', 'descendant-or-self::*[@id]'); -test('[id=bar]', 'descendant-or-self::*[@id="bar"]'); -test('foo[id=bar]', 'descendant-or-self::foo[@id="bar"]'); -test(':button', 'descendant-or-self::input[@type="button"]'); -test('textarea', 'descendant-or-self::textarea'); -test(':submit', 'descendant-or-self::input[@type="submit"]'); -test(':first-child', 'descendant-or-self::*/*[position()=1]'); -test('div:first-child', 'descendant-or-self::*/div[position()=1]'); -test(':last-child', 'descendant-or-self::*/*[position()=last()]'); -test('div:last-child', 'descendant-or-self::*/div[position()=last()]'); -test(':nth-child(2)', 'descendant-or-self::*/*[position()=2]'); -test('div:nth-child(2)', 'descendant-or-self::*/div[position()=2]'); -test('foo + bar', 'descendant-or-self::foo/following-sibling::bar[position()=1]'); -test('li:contains(Foo)', 'descendant-or-self::li[contains(string(.),"Foo")]'); -test('foo bar baz', 'descendant-or-self::foo/descendant::bar/descendant::baz'); -test('foo + bar + baz', 'descendant-or-self::foo/following-sibling::bar[position()=1]/following-sibling::baz[position()=1]'); -test('foo > bar > baz', 'descendant-or-self::foo/bar/baz'); -test('p ~ p ~ p', 'descendant-or-self::p/following-sibling::p/following-sibling::p'); -test('div#article p em', 'descendant-or-self::div[@id="article"]/descendant::p/descendant::em'); -test('div.foo:first-child', 'descendant-or-self::div[contains(concat(" ",@class," ")," foo ")][position()=1]'); -test('form#login > input[type=hidden]._method', 'descendant-or-self::form[@id="login"]/input[@type="hidden"][contains(concat(" ",@class," ")," _method ")]'); - -test_selector('*', 12); -test_selector('div', 1); -test_selector('div, p', 2); -test_selector('div , p', 2); -test_selector('div ,p', 2); -test_selector('div, p, ul li a', 3); -test_selector('div#article', 1); -test_selector('div#article.block', 1); -test_selector('div#article.large.block', 1); -test_selector('h2', 1); -test_selector('div h2', 1); -test_selector('div > h2', 1); -test_selector('ul li a', 1); -test_selector('ul > li > a', 1); -test_selector('a[href=#]', 1); -test_selector('a[href="#"]', 1); -test_selector('div[id="article"]', 1); -test_selector('h2:contains(Article)', 1); -test_selector('h2:contains(Article) + p', 1); -test_selector('h2:contains(Article) + p:contains(Contents)', 1); -test_selector('div p + ul', 1); -test_selector('li ~ li', 4); -test_selector('li ~ li ~ li', 3); -test_selector('li + li', 4); -test_selector('li + li + li', 3); -test_selector('li:first-child', 1); -test_selector('li:last-child', 1); -test_selector('li:contains(One):first-child', 1); -test_selector('li:nth-child(2)', 1); -test_selector('li:nth-child(3)', 1); -test_selector('li:nth-child(4)', 1); -test_selector('li:nth-child(6)', 0); -test_selector('.a', 2); - -$dom = new SelectorDom(get_test_html()); -print (count($dom->select('a')) == 1) - ? '.' - : 'SelectorDOM failed'; -print (count($dom->select('ul li a')) == 1) - ? '.' - : 'SelectorDOM failed'; - -$divs = $dom->select('div'); -print ($divs[0]['attributes']['id'] == 'article') - ? '.' - : 'Attributes failed'; - -print "\n"; - -function test_selector($selector, $count) { - $html = get_test_html(); - $actual = count(SelectorDOM::selectElements($selector, $html)); - print ($actual == $count) - ? '.' - : "\n '$selector' failed, expected $count but got $actual \n\n"; -} - -function test($selector, $expected) { - $actual = SelectorDOM::selectorToXpath($selector); - if ($web = 'cli' !== PHP_SAPI) { - echo '
';
-    }
-    assert($actual == $expected);
-    echo "\nExpected: $expected\n";
-    echo "Actual:   $actual\n";
-    echo str_repeat('-', 80)."\n";
-    if ($web) {
-        echo '
'; - } -} - -function get_test_html() { - return << -

Article Name

-

Contents of article

- - -HTML; -} diff --git a/builder/lib/generator.lib.php b/builder/lib/generator.lib.php deleted file mode 100644 index 4f1d66297..000000000 --- a/builder/lib/generator.lib.php +++ /dev/null @@ -1,125 +0,0 @@ -enableCSS = true; - - // initialize CSS rule saver - $this->initializeCSSRuleSaver(); - - print "CSS generation enabled. This could take a few seconds...\n"; - - } - - - - // clean the public directory to remove old files - $this->cleanPublic(); - - // gather data - $this->gatherData(); - - // render out the patterns and move them to public/patterns - $this->generatePatterns(); - - // render out the index and style guide - $this->generateMainPages(); - - // iterate over the data files and regenerate the entire site if they've changed - $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__."/../../source/_data/"), RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - $fileName = str_replace(__DIR__."/../../source/_data".DIRECTORY_SEPARATOR,"",$name); - if (($fileName[0] != "_") && $object->isFile()) { - $this->moveStaticFile("_data/".$fileName,"","_data","data"); - } - - } - - // iterate over all of the other files in the source directory - $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__."/../../source/"), 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(__DIR__."/../../source".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(__DIR__."/../../public/".$fileName)) { - mkdir(__DIR__."/../../public/".$fileName); - } - - // check to see if it's a new file or a file that has changed - if (!$ignoreDir && $object->isFile() && (!file_exists(__DIR__."/../../public/".$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(); - - if ($timePL) { - $mtime = microtime(); - $mtime = explode(" ",$mtime); - $mtime = $mtime[1] + $mtime[0]; - $endtime = $mtime; - $totaltime = ($endtime - $starttime); - print "PL site generation took ".$totaltime." seconds...\n"; - } - - } - -} \ No newline at end of file diff --git a/builder/lib/watcher.lib.php b/builder/lib/watcher.lib.php deleted file mode 100644 index 715f17237..000000000 --- a/builder/lib/watcher.lib.php +++ /dev/null @@ -1,248 +0,0 @@ -patterns = new stdClass(); - - // 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(__DIR__."/../../source/_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(__DIR__."/../../source/_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]; - if ($pattern[0] != "_") { - - // 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") { - $this->patternPaths[$patternParts[0]][$pattern] = str_replace(".mustache","",$fileName); - } - } 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"); - - } - - } elseif (isset($o->patterns->$fileNameClean)) { - - // the file was hidden so remove references to the item - $patternParts = explode(DIRECTORY_SEPARATOR,$fileNameClean); - $pattern = isset($patternParts[2]) ? $patternParts[2] : $patternParts[1]; - - unset($o->patterns->$fileNameClean); - unset($cp->$fileNameClean); - unset($this->patternPaths[$patternParts[0]][$pattern]); - $this->updateSite($fileNameClean,"hidden"); - - } - - } - - } - - // 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(__DIR__."/../../source/_data/"), RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - $fileName = str_replace(__DIR__."/../../source/_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 - $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__."/../../source/"), 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(__DIR__."/../../source".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(__DIR__."/../../public/".$fileName)) { - mkdir(__DIR__."/../../public/".$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(__DIR__."/../../public/".$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); - if (gc_enabled()) gc_collect_cycles(); - - // pause for .05 seconds to give the CPU a rest - usleep(50000); - - } - - } - - /** - * 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->gatherPatternPaths(); - $this->gatherNavItems(); - $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/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/.gitkeep b/config/.gitkeep new file mode 100644 index 000000000..d43780078 --- /dev/null +++ b/config/.gitkeep @@ -0,0 +1 @@ +After you generate Pattern Lab for the first time your configuration file will be placed here. \ No newline at end of file diff --git a/config/config.ini.default b/config/config.ini.default deleted file mode 100644 index 64050599e..000000000 --- a/config/config.ini.default +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Configuration Options for Pattern Lab - * If config.ini doesn't exist Pattern Lab will try to create a new version - */ - -// both the source and the public location of the patterns -sp = "/../../source/_patterns/"; -pp = "/../../public/patterns/"; - -// 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" - -// choose which ports the websocket services should run on -contentSyncPort = "8002" -navSyncPort = "8003" 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/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 @@ + false, "packagesRemove" => false, "suggestedStarterKits" => array(), "configOverrides" => array(), "patternLabPackages" => array()); + + /** + * Get any config overrides that may exist for the edition + * @param {Object} a script event object from composer + */ + public static function getConfigOverrides(Event $event) { + + $extra = $event->getComposer()->getPackage()->getExtra(); + if (isset($extra["patternlab"]) && isset($extra["patternlab"]["config"]) && is_array($extra["patternlab"]["config"])) { + self::$installerInfo["configOverrides"] = $extra["patternlab"]["config"]; + } + + } + + /** + * Get the package info from each patternlab-* package's composer.json + * @param {String} the type of event fired during the composer install + * @param {Object} a script event object from composer + */ + public static function getPackageInfo($type, $event) { + + $package = ($type == "update") ? $event->getOperation()->getTargetPackage() : $event->getOperation()->getPackage(); + $packageType = $package->getType(); + $packageExtra = $package->getExtra(); + $packageInfo = array(); + + // make sure we're only evaluating pattern lab packages + if (strpos($packageType,"patternlab-") !== false) { + + $packageInfo["name"] = $package->getName(); + $packageInfo["type"] = $packageType; + $packageInfo["pathBase"] = $event->getComposer()->getInstallationManager()->getInstallPath($package); + $packageInfo["pathDist"] = $packageInfo["pathBase"].DIRECTORY_SEPARATOR."dist".DIRECTORY_SEPARATOR; + $packageInfo["extra"] = (isset($packageExtra["patternlab"])) ? $packageExtra["patternlab"] : array(); + + self::$installerInfo["packages"][] = $packageInfo; + + } + + } + + /** + * Get the suggested starter kits from the root package composer.json + * @param {Object} a script event object from composer + */ + public static function getSuggestedStarterKits(Event $event) { + + $extra = $event->getComposer()->getPackage()->getExtra(); + if (isset($extra["patternlab"]) && isset($extra["patternlab"]["starterKitSuggestions"]) && is_array($extra["patternlab"]["starterKitSuggestions"])) { + self::$installerInfo["suggestedStarterKits"] = $extra["patternlab"]["starterKitSuggestions"]; + } + + } + + /** + * Run the centralized postInstallCmd + * @param {Object} a script event object from composer + */ + public static function postInstallCmd(Event $event) { + + InstallerUtil::postInstallCmd(self::$installerInfo, $event); + + } + + /** + * Run the centralized postUpdateCmd + * @param {Object} a script event object from composer + */ + public static function postUpdateCmd(Event $event) { + + InstallerUtil::postUpdateCmd(self::$installerInfo, $event); + + } + + /** + * Clean-up when a package is removed + * @param {Object} a script event object from composer + */ + public static function postPackageInstall(PackageEvent $event) { + + self::getPackageInfo("install", $event); + + } + + /** + * Clean-up when a package is removed + * @param {Object} a script event object from composer + */ + public static function postPackageUpdate(PackageEvent $event) { + + self::getPackageInfo("update", $event); + + } + + /** + * Clean-up when a package is removed + * @param {Object} a script event object from composer + */ + public static function prePackageUninstall(PackageEvent $event) { + + // make sure the postUpdateCmd doesnt actually do anything + self::setPackagesRemove(); + + // get the basic package info + $package = $event->getOperation()->getPackage(); + $packageType = $package->getType(); + $packageInfo = array(); + + // make sure we're only evaluating pattern lab packages. remove attributes related to them. + if (strpos($packageType,"patternlab-") !== false) { + + $packageInfo["name"] = $package->getName(); + $packageInfo["type"] = $packageType; + $packageInfo["pathBase"] = $event->getComposer()->getInstallationManager()->getInstallPath($package); + + InstallerUtil::packageRemove($packageInfo); + + } + + } + + /** + * Set the packages remove boolean to true + */ + public static function setPackagesRemove() { + + self::$installerInfo["packagesRemove"] = true; + + } + + /** + * Set the project install boolean to true + * @param {Object} a script event object from composer + */ + public static function setProjectInstall(Event $event) { + + self::$installerInfo["projectInstall"] = true; + + } + +} 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/listeners/contentSyncBroadcasterServer.php b/listeners/contentSyncBroadcasterServer.php deleted file mode 100644 index df6081108..000000000 --- a/listeners/contentSyncBroadcasterServer.php +++ /dev/null @@ -1,43 +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; -} - -$port = ($config) ? trim($config['contentSyncPort']) : '8002'; - -// start the content sync server -$server = new \Wrench\Server('ws://0.0.0.0:'.$port.'/', array()); - -// register the application -$server->registerApplication('contentsync', new \Wrench\Application\contentSyncBroadcasterApplication()); - -print "\n"; -print "Auto-reload Server Started...\n"; -print "Use CTRL+C to stop this service...\n"; - -// run it -$server->run(); diff --git a/listeners/lib/LICENSE b/listeners/lib/LICENSE deleted file mode 100755 index 5c93f4565..000000000 --- a/listeners/lib/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright (C) 2004 Sam Hocevar - - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/listeners/lib/SplClassLoader.php b/listeners/lib/SplClassLoader.php deleted file mode 100755 index 2bc31f04b..000000000 --- a/listeners/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/listeners/lib/Wrench/Application/Application.php b/listeners/lib/Wrench/Application/Application.php deleted file mode 100755 index 2132a8907..000000000 --- a/listeners/lib/Wrench/Application/Application.php +++ /dev/null @@ -1,34 +0,0 @@ -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; - } - } - - } - -} diff --git a/listeners/lib/Wrench/Application/navSyncBroadcasterApplication.php b/listeners/lib/Wrench/Application/navSyncBroadcasterApplication.php deleted file mode 100644 index 900343120..000000000 --- a/listeners/lib/Wrench/Application/navSyncBroadcasterApplication.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/listeners/lib/Wrench/BasicServer.php b/listeners/lib/Wrench/BasicServer.php deleted file mode 100755 index 88578a055..000000000 --- a/listeners/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/listeners/lib/Wrench/Client.php b/listeners/lib/Wrench/Client.php deleted file mode 100755 index 87e8f11ba..000000000 --- a/listeners/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/listeners/lib/Wrench/Connection.php b/listeners/lib/Wrench/Connection.php deleted file mode 100755 index 2538fc739..000000000 --- a/listeners/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/listeners/lib/Wrench/ConnectionManager.php b/listeners/lib/Wrench/ConnectionManager.php deleted file mode 100755 index 8a503de03..000000000 --- a/listeners/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/listeners/lib/Wrench/Exception/BadRequestException.php b/listeners/lib/Wrench/Exception/BadRequestException.php deleted file mode 100755 index 8b8a1591f..000000000 --- a/listeners/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/listeners/lib/Wrench/Frame/HybiFrame.php b/listeners/lib/Wrench/Frame/HybiFrame.php deleted file mode 100755 index da6377d7e..000000000 --- a/listeners/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/listeners/lib/Wrench/Listener/HandshakeRequestListener.php b/listeners/lib/Wrench/Listener/HandshakeRequestListener.php deleted file mode 100755 index 9b5b841ee..000000000 --- a/listeners/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/listeners/lib/Wrench/Listener/RateLimiter.php b/listeners/lib/Wrench/Listener/RateLimiter.php deleted file mode 100755 index 6ca0fe86e..000000000 --- a/listeners/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/listeners/lib/Wrench/Payload/HybiPayload.php b/listeners/lib/Wrench/Payload/HybiPayload.php deleted file mode 100755 index 92d4821ab..000000000 --- a/listeners/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/listeners/lib/Wrench/Payload/PayloadHandler.php b/listeners/lib/Wrench/Payload/PayloadHandler.php deleted file mode 100755 index 2be036ff1..000000000 --- a/listeners/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/listeners/lib/Wrench/Protocol/Hybi10Protocol.php b/listeners/lib/Wrench/Protocol/Hybi10Protocol.php deleted file mode 100755 index 33cfe15e3..000000000 --- a/listeners/lib/Wrench/Protocol/Hybi10Protocol.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) { - return true; - } - } -} \ No newline at end of file diff --git a/listeners/lib/Wrench/Protocol/HybiProtocol.php b/listeners/lib/Wrench/Protocol/HybiProtocol.php deleted file mode 100755 index 1d73c2fab..000000000 --- a/listeners/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/listeners/lib/Wrench/Protocol/Rfc6455Protocol.php b/listeners/lib/Wrench/Protocol/Rfc6455Protocol.php deleted file mode 100755 index b0f5c5289..000000000 --- a/listeners/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/listeners/lib/Wrench/Socket/ClientSocket.php b/listeners/lib/Wrench/Socket/ClientSocket.php deleted file mode 100755 index 9f5fbe293..000000000 --- a/listeners/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/listeners/lib/Wrench/Socket/ServerClientSocket.php b/listeners/lib/Wrench/Socket/ServerClientSocket.php deleted file mode 100755 index 61583f6cc..000000000 --- a/listeners/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/listeners/lib/Wrench/Socket/ServerSocket.php b/listeners/lib/Wrench/Socket/ServerSocket.php deleted file mode 100755 index facb89f86..000000000 --- a/listeners/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/listeners/lib/Wrench/Socket/Socket.php b/listeners/lib/Wrench/Socket/Socket.php deleted file mode 100755 index 97f6b28cc..000000000 --- a/listeners/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/listeners/lib/Wrench/Socket/UriSocket.php b/listeners/lib/Wrench/Socket/UriSocket.php deleted file mode 100755 index 8e1cbc047..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Application/EchoApplicationTest.php b/listeners/lib/Wrench/Tests/Application/EchoApplicationTest.php deleted file mode 100755 index bd32aeb33..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/BasicServerTest.php b/listeners/lib/Wrench/Tests/BasicServerTest.php deleted file mode 100755 index 20d004419..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/ClientTest.php b/listeners/lib/Wrench/Tests/ClientTest.php deleted file mode 100755 index 824774eef..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/ConnectionManagerTest.php b/listeners/lib/Wrench/Tests/ConnectionManagerTest.php deleted file mode 100755 index ed3de0b03..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/ConnectionTest.php b/listeners/lib/Wrench/Tests/ConnectionTest.php deleted file mode 100755 index 25d57ffbc..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php b/listeners/lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php deleted file mode 100755 index bcced6695..000000000 --- a/listeners/lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php +++ /dev/null @@ -1,29 +0,0 @@ -getFrameBuffer(); - } - - protected function getClass() - { - return 'Wrench\Tests\Frame\BadSubclassFrame'; - } -} diff --git a/listeners/lib/Wrench/Tests/Frame/FrameTest.php b/listeners/lib/Wrench/Tests/Frame/FrameTest.php deleted file mode 100755 index 848c7103e..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Frame/HybiFrameTest.php b/listeners/lib/Wrench/Tests/Frame/HybiFrameTest.php deleted file mode 100755 index 721429513..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Listener/OriginPolicyTest.php b/listeners/lib/Wrench/Tests/Listener/OriginPolicyTest.php deleted file mode 100755 index 103af9bfe..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Listener/RateLimiterTest.php b/listeners/lib/Wrench/Tests/Listener/RateLimiterTest.php deleted file mode 100755 index 602442308..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Payload/HybiPayloadTest.php b/listeners/lib/Wrench/Tests/Payload/HybiPayloadTest.php deleted file mode 100755 index 5dd2b2497..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Protocol/ProtocolTest.php b/listeners/lib/Wrench/Tests/Protocol/ProtocolTest.php deleted file mode 100755 index afba179da..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Protocol/Rfc6455ProtocolTest.php b/listeners/lib/Wrench/Tests/Protocol/Rfc6455ProtocolTest.php deleted file mode 100755 index ee329f31e..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/ServerTestHelper.php b/listeners/lib/Wrench/Tests/ServerTestHelper.php deleted file mode 100755 index 57dd1ec05..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Socket/ClientSocketTest.php b/listeners/lib/Wrench/Tests/Socket/ClientSocketTest.php deleted file mode 100755 index d64ea5df2..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Socket/ServerClientSocketTest.php b/listeners/lib/Wrench/Tests/Socket/ServerClientSocketTest.php deleted file mode 100755 index ca71983b5..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Socket/ServerSocketTest.php b/listeners/lib/Wrench/Tests/Socket/ServerSocketTest.php deleted file mode 100755 index a4d4251c5..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Socket/UriSocketTest.php b/listeners/lib/Wrench/Tests/Socket/UriSocketTest.php deleted file mode 100755 index d0b7f8bdc..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/Test.php b/listeners/lib/Wrench/Tests/Test.php deleted file mode 100755 index f9b421fd9..000000000 --- a/listeners/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/listeners/lib/Wrench/Tests/bootstrap.php b/listeners/lib/Wrench/Tests/bootstrap.php deleted file mode 100755 index 84bd83943..000000000 --- a/listeners/lib/Wrench/Tests/bootstrap.php +++ /dev/null @@ -1,11 +0,0 @@ -register(); \ No newline at end of file diff --git a/listeners/lib/Wrench/Tests/server.php b/listeners/lib/Wrench/Tests/server.php deleted file mode 100755 index 34d680622..000000000 --- a/listeners/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/listeners/lib/Wrench/Util/Configurable.php b/listeners/lib/Wrench/Util/Configurable.php deleted file mode 100755 index f1983d5e6..000000000 --- a/listeners/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/listeners/lib/Wrench/Util/Ssl.php b/listeners/lib/Wrench/Util/Ssl.php deleted file mode 100755 index e8cc8bd7e..000000000 --- a/listeners/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/listeners/navSyncBroadcasterServer.php b/listeners/navSyncBroadcasterServer.php deleted file mode 100755 index 1bb19be43..000000000 --- a/listeners/navSyncBroadcasterServer.php +++ /dev/null @@ -1,42 +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; -} - -$port = ($config) ? trim($config['navSyncPort']) : '8000'; - -// start the content sync server -$server = new \Wrench\Server('ws://0.0.0.0:'.$port.'/', array()); - -// register the application & run it -$server->registerApplication('navsync', new \Wrench\Application\navSyncBroadcasterApplication()); - -print "\n"; -print "Page Follow Server Started...\n"; -print "Use CTRL+C to stop this service...\n"; - -$server->run(); 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/WHAR_INDEX b/public/WHAR_INDEX deleted file mode 100644 index bf59a26ad..000000000 --- a/public/WHAR_INDEX +++ /dev/null @@ -1,3 +0,0 @@ -If you're seeing a listing of files rather than the main home page for Pattern Lab -then you probably forgot to generate the site first. Please go into scripts/ and -double-click generateSite.command. \ No newline at end of file diff --git a/public/data/README b/public/data/README deleted file mode 100644 index f9ae005af..000000000 --- a/public/data/README +++ /dev/null @@ -1 +0,0 @@ -JS files from source/_data that are meant to be publicly shared (e.g. annotations.js) are stored here. \ No newline at end of file diff --git a/public/listeners/synclisteners.js b/public/listeners/synclisteners.js deleted file mode 100644 index 5ca64dc75..000000000 --- a/public/listeners/synclisteners.js +++ /dev/null @@ -1,173 +0,0 @@ - -/*! - * Sync Listeners, v0.1 - * - * Copyright (c) 2013 Dave Olsen, http://dmolsen.com - * Licensed under the MIT license - * - * The JavaScript component of the WebSocket set-up that supports syncing - * navigation between browsers and content updates with the server. - * - * The WebSocket test is from Modernizr. It might be a little too strict for our purposes. - * https://github.com/Modernizr/Modernizr/blob/master/feature-detects/websockets.js - * - */ - -var wsn; -var wsnConnected = false; -var wsc; -var wscConnected = false; -var dataPrevious = 0; -var host = (window.location.host != "") ? window.location.host : "127.0.0.1"; - -// handle page updates from one browser to another -function connectNavSync() { - - if ('WebSocket' in window && window.WebSocket.CLOSING === 2) { - - var navSyncCopy = "Page Follow"; - wsn = new WebSocket("ws://"+host+":"+navSyncPort+"/navsync"); - - // when trying to open a connection to WebSocket update the pattern lab nav bar - wsn.onopen = function (event) { - wsnConnected = true; - $('#navSyncButton').attr("data-state","on"); - $('#navSyncButton').addClass("connected"); - $('#navSyncButton').addClass("active"); - $('#navSyncButton').html(navSyncCopy+' On'); - } - - // when closing a connection (or failing to make a connection) to WebSocket update the pattern lab nav bar - wsn.onclose = function (event) { - wsnConnected = false; - $('#navSyncButton').attr("data-state","off"); - if ($('#navSyncButton').hasClass("connected")) { - $('#navSyncButton').removeClass("connected"); - $('#navSyncButton').removeClass("active"); - } - $('#navSyncButton').html(navSyncCopy+' Disabled'); - } - - // when receiving a message from WebSocket update the iframe source - wsn.onmessage = function (event) { - - var data = JSON.parse(event.data); - var vpLocation = document.getElementById('sg-viewport').contentWindow.location.href; - var mLocation = "http://"+host+data.url; - - if (vpLocation != mLocation) { - - document.getElementById('sg-viewport').contentWindow.location.replace(mLocation); - - // make sure the pop doesn't fire and push the pattern - urlHandler.doPop = false; - urlHandler.pushPattern(data.patternpartial); - - // reset the defaults - urlHandler.doPop = true; - urlHandler.skipBack = false; - - } - } - - // when there's an error update the pattern lab nav bar - wsn.onerror = function (event) { - wsnConnected = false; - $('#navSyncButton').attr("data-state","off"); - if ($('#navSyncButton').hasClass("connected")) { - $('#navSyncButton').removeClass("connected"); - $('#navSyncButton').removeClass("active"); - } - $('#navSyncButton').html(navSyncCopy+' Disabled'); - } - - } - -} -connectNavSync(); - -// handle content updates generated by the watch -function connectContentSync() { - - if ('WebSocket' in window && window.WebSocket.CLOSING === 2) { - - var dc = true; - var contentSyncCopy = "Auto-reload"; - - wsc = new WebSocket("ws://"+host+":"+contentSyncPort+"/contentsync"); - - // when trying to open a connection to WebSocket update the pattern lab nav bar - wsc.onopen = function (event) { - wscConnected = true; - $('#contentSyncButton').attr("data-state","on"); - $('#contentSyncButton').addClass("connected"); - $('#contentSyncButton').addClass("active"); - $('#contentSyncButton').html(contentSyncCopy+' On'); - } - - // when closing a connection (or failing to make a connection) to WebSocket update the pattern lab nav bar - wsc.onclose = function (event) { - wscConnected = false; - $('#contentSyncButton').attr("data-state","off"); - if ($('#contentSyncButton').hasClass("connected")) { - $('#contentSyncButton').removeClass("connected"); - $('#contentSyncButton').removeClass("active"); - } - $('#contentSyncButton').html(contentSyncCopy+' Disabled'); - } - - // when receiving a message from WebSocket reload the current frame adding the received timestamp - // as a request var to, hopefully, bust caches... cachi(?) - wsc.onmessage = function (event) { - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - document.getElementById('sg-viewport').contentWindow.postMessage( { "reload": true }, targetOrigin); - } - - // when there's an error update the pattern lab nav bar - wsc.onerror = function (event) { - wscConnected = false; - $('#contentSyncButton').attr("data-state","off"); - if ($('#contentSyncButton').hasClass("connected")) { - $('#contentSyncButton').removeClass("connected"); - $('#contentSyncButton').removeClass("active"); - } - $('#contentSyncButton').html(contentSyncCopy+' Disabled'); - } - - } - -} -connectContentSync(); - -// handle when a user manually turns navSync and contentSync on & off -$('#navSyncButton').click(function() { - if ($(this).attr("data-state") == "on") { - wsn.close(); - $(this).attr("data-state","off"); - $(this).removeClass("connected"); - $(this).removeClass("active"); - $(this).html('Nav Sync Off'); - } else { - connectNavSync(); - $(this).attr("data-state","on"); - $(this).addClass("connected"); - $(this).addClass("active"); - $(this).html('Nav Sync On'); - } -}); - -$('#contentSyncButton').click(function() { - if ($(this).attr("data-state") == "on") { - wsc.close(); - $(this).attr("data-state","off"); - $(this).removeClass("connected"); - $(this).removeClass("active"); - $(this).html('Content Sync Off'); - } else { - connectContentSync(); - $(this).attr("data-state","on"); - $(this).addClass("connected"); - $(this).addClass("active"); - $(this).html('Content Sync On'); - } -}); diff --git a/public/patterns/README b/public/patterns/README deleted file mode 100755 index 86f41ee4e..000000000 --- a/public/patterns/README +++ /dev/null @@ -1 +0,0 @@ -Patterns saved here are coming from /source/patterns. Please edit there first! \ No newline at end of file diff --git a/public/styleguide/assets/icons.dev.svg b/public/styleguide/assets/icons.dev.svg deleted file mode 100644 index 1fff93785..000000000 --- a/public/styleguide/assets/icons.dev.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/public/styleguide/assets/icons.eot b/public/styleguide/assets/icons.eot deleted file mode 100644 index ba04dfea4..000000000 Binary files a/public/styleguide/assets/icons.eot and /dev/null differ diff --git a/public/styleguide/assets/icons.svg b/public/styleguide/assets/icons.svg deleted file mode 100644 index 4902a1bb0..000000000 --- a/public/styleguide/assets/icons.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/public/styleguide/assets/icons.ttf b/public/styleguide/assets/icons.ttf deleted file mode 100644 index f5d06ee2e..000000000 Binary files a/public/styleguide/assets/icons.ttf and /dev/null differ diff --git a/public/styleguide/assets/icons.woff b/public/styleguide/assets/icons.woff deleted file mode 100644 index a2423c261..000000000 Binary files a/public/styleguide/assets/icons.woff and /dev/null differ diff --git a/public/styleguide/css/prism.css b/public/styleguide/css/prism.css deleted file mode 100644 index 0b78bd0c4..000000000 --- a/public/styleguide/css/prism.css +++ /dev/null @@ -1,112 +0,0 @@ -/** - * okaidia theme for JavaScript, CSS and HTML - * Loosely based on Monokai textmate theme by http://www.monokai.nl/ - * @author ocodia - */ - -code[class*="language-"], -pre[class*="language-"] { - color: #f8f8f2; - text-shadow: 0 1px rgba(0,0,0,0.3); - font-family: Consolas, Monaco, 'Andale Mono', monospace; - direction: ltr; - text-align: left; - white-space: pre; - word-spacing: normal; - - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; -} - -/* Code blocks */ -pre[class*="language-"] { - padding: 1em; - margin: .5em 0; - overflow: auto; - border-radius: 0.3em; -} - -:not(pre) > code[class*="language-"], -pre[class*="language-"] { - background: #272822; -} - -/* Inline code */ -:not(pre) > code[class*="language-"] { - padding: .1em; - border-radius: .3em; -} - -.token.comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: slategray; -} - -.token.punctuation { - color: #f8f8f2; -} - -.namespace { - opacity: .7; -} - -.token.property, -.token.tag, -.token.constant, -.token.symbol { - color: #f92672; -} - -.token.boolean, -.token.number{ - color: #ae81ff; -} - -.token.selector, -.token.attr-name, -.token.string, -.token.builtin { - color: #a6e22e; -} - - -.token.operator, -.token.entity, -.token.url, -.language-css .token.string, -.style .token.string, -.token.variable { - color: #f8f8f2; -} - -.token.atrule, -.token.attr-value -{ - color: #e6db74; -} - - -.token.keyword{ -color: #66d9ef; -} - -.token.regex, -.token.important { - color: #fd971f; -} - -.token.important { - font-weight: bold; -} - -.token.entity { - cursor: help; -} diff --git a/public/styleguide/css/static.css b/public/styleguide/css/static.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/public/styleguide/css/static.scss b/public/styleguide/css/static.scss deleted file mode 100644 index 1fbb1bc27..000000000 --- a/public/styleguide/css/static.scss +++ /dev/null @@ -1,403 +0,0 @@ -/* -colors -red: $orange; rgb(229,24,55) -gray: #808080; -*/ - -$orange : #bededf; - -$max-width: 60em; - -/************Reset**************/ -* { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; -} -html, body, div, object, iframe, fieldset { - margin: 0; - padding: 0; - border: 0; -} -ol, ul { - list-style: none; - margin: 0; - padding: 0; -} -table { - border-collapse: collapse; - border-spacing: 0; -} -header, footer, nav, section, article, hgroup, figure { - display: block; -} -legend { - display: none; -} -/************End Reset**************/ - -/************Global**************/ -body { - background: #fff; - color: #000; - font: 100%/1.4 "HelveticaNeue", "Helvetica", "Arial", sans-serif; - padding: 0; - -webkit-text-size-adjust: 100%; - border-top: 20px solid #000; - border-bottom: 20px solid #000; -} -a { - color: #808080; - text-decoration: none; -} -a:hover, a:focus { - color: $orange; -} -p { - margin: 0 0 1em; -} -img, object, video { - max-width: 100%; - border: 0; -} -a img { - border: 0; - outline: 0; -} -h1 { - font-size: 3em; - line-height: 1; - letter-spacing: -0.02em; - margin-bottom: 0.2em; -} -h2 { - font-size: 2em; - line-height: 1.1; - margin-bottom: 0.2em; -} -h3 { - font-weight: normal; - line-height: 1.1; - padding-bottom: 0.4em; - border-bottom: 1px solid #ccc; -} -h1 a, h2 a, h3 a { - display: block; - color: #000; -} -h1 a:hover, h2 a:hover, h3 a:hover { - color: $orange; -} -blockquote { - border-left: 0.5em solid #ddd; - padding-left: 1em; - margin-left: 1em; -} -small { - color: $orange; -} -input[type=search] { - -webkit-appearance: none; - border-radius: 0; -} -::-webkit-input-placeholder { - color: #808080; -} -:-moz-placeholder { - color: #808080; -} -/************End Global**************/ - -/************Classes**************/ -.inactive { - color: #ddd; -} -/************End Classes**************/ - -/************Structure**************/ -.container { - max-width: $max-width; - margin: 0 auto; - padding: 0 1em; - overflow: hidden; -} - -[role=main] { - padding-bottom: 1em; -} - -/*Footer*/ -[role=contentinfo] { - color: #fff; - background: #000; - margin: 0 -1em; - position: relative; - z-index: 2; - - > div { - max-width: $max-width; - padding: 0 1em; - margin: 0 auto; - overflow: hidden; -} -/*End Footer*/ - -/*Grid*/ -.grid { - margin: 0 -1em; - overflow: hidden; -} -.grid:target { - -webkit-animation: fadeout 5s 1 ease-out; - -moz-animation: fadeout 5s 1 ease-out; - -o-animation: fadeout 5s 1 ease-out; - animation: fadeout 5s 1 ease-out; -} -.grid > h2 { - margin-left: 0.45em; -} -.grid > section { - padding: 1em 1em 0.5em; -} -.grid > section:target { - -webkit-animation: fadeout 5s 1 ease-out; - -moz-animation: fadeout 5s 1 ease-out; - -o-animation: fadeout 5s 1 ease-out; - animation: fadeout 5s 1 ease-out; -} -.grid ul { - overflow: hidden; -} -.grid ul li { - margin-bottom: 0.3em; -} -.featured:after { - content: "*"; - color: $orange; -} - -/*Fluid*/ -.fluid { - display: block; - margin: 0 auto; - max-width: 40em; -} - -/*Homepage*/ -.home h1 { - margin-bottom: 0.2em; -} -.intro { - font-size: 1.8em; - line-height: 1.2; - margin: 0 auto; -} -.intro a:hover ,.intro a:focus { - color: #000; - border-bottom-color: #000; -} - -.ani { - position: relative; - height: 15em; - margin: 1em 0 0; - width: 100%; - z-index: 0; -} -.ani div { - width: 100%; -} -.ani div b { - display: block; - position: absolute; - top: 5%; - right: 5%; - bottom: 5%; - left: 5%; - background: rgba(229,24,55,0.22); -} - - -/*Patterns*/ -.mod { - padding: 1em; -} -.pattern { - background: #f7f7f7; - border-bottom: 1px solid #808080; - margin-bottom: 1em; - overflow: hidden; -} -.pattern-description h1 { - font-size: 3.4em; - margin-bottom: 0.5em; -} -.pattern-description { - max-width: 40em; - margin: 0 auto; -} -.pattern-description ul, .pattern-description ol { - margin-bottom: 2em; -} -.pattern-description li { - margin-bottom: 1em; -} - - -/*Blog*/ -/*Blog Header*/ -.blog .container { - max-width: 62em; -} -.blog header[role=banner] { - overflow: hidden; - margin-bottom: 2em; - padding: 2em 0 1em; - border-bottom: 1px solid #000; -} -.blog-logo { - font-weight: normal; - font-size: 1.2em; - margin: 0 0 1em; -} -.blog-logo img { - width: 3.3em; -} -.blog-logo a { - color: #000; -} -.search-form { - width: 100%; - margin-bottom: 1em; -} -.search-field { - width: 100%; - padding: 0.5em 0; - border: 0; - border-bottom: 1px solid #808080; - outline: none; -} -.search-field:focus { - background: $orange; - color: #fff; -} -.search-field:focus::-webkit-input-placeholder { - color: #fff; -} - -.search-field:focus :-moz-placeholder { - color: #fff; -} - -.blog .nav { - clear: both; -} -.blog .nav a { - display: block; - font-weight: bold; - color: #000; -} -.blog .nav a:hover { - color: $orange; -} - -/*Posts*/ -.posts ol > li { - padding-bottom: 1em; - border-bottom: 1px solid #ccc; - margin-bottom: 1em; - overflow: hidden; -} -.posts h2 { - font-size: 1.4em; - margin: 0.28em 0 0.1em; - font-weight: normal; -} -.posts h2 a { - color: #000; -} -.posts h2 a:hover, .posts h2 a:focus { - color: $orange; -} -.permalink { - display: block; - font-size: 0.8em; - margin-bottom: 1.2em; -} -.post-body a { - border-bottom: 1px solid #ccc; -} -.posts blockquote { - margin: 0 0 1em; - color: #666; - border-left: 0.25em solid #ccc; - padding-left: 1em; -} -.tags { - float: left; -} -.tags li { - display: inline-block; - font-size: 0.8em; - margin-right: 0.5em; -} - -.posts ol > li .tags a, .permalink { - color: #ccc; - -webkit-transition: color 0.3s ease-out; - -moz-transition: color 0.3s ease-out; - -ms-transition: color 0.3s ease-out; - -o-transition: color 0.3s ease-out; - transition: color 0.3s ease-out; -} -.posts ol > li:hover .tags a, .posts ol > li:hover .permalink { - color: #808080; -} -.blog-nav { - text-align: center; - overflow: hidden; - padding: 1em 0; -} -.posts .blog-nav a { - border: 0; -} -.nav-next { - float: right; -} -.nav-prev { - float: left; -} - -/* Sidebar */ -.sidebar { - font-size: 0.8em; - padding-bottom: 1.4em; -} -.sidebar div { - margin-bottom: 2em; -} -.sidebar h3 { - font-weight: bold; - font-size: 0.9em; - line-height: 1; - border-bottom: 1px solid #000; -} -.sidebar a { - color: #808080; -} -.sidebar a:hover, .sidebar a:focus { - color: $orange; -} - - - - -.top { - clear: both; - display: block; - padding: 1em 0; -} -.top:before { - content: 'â–²'; -} - diff --git a/public/styleguide/css/styleguide.css b/public/styleguide/css/styleguide.css deleted file mode 100644 index 40ec4a27f..000000000 --- a/public/styleguide/css/styleguide.css +++ /dev/null @@ -1,615 +0,0 @@ -/*------------------------------------*\ - $STYLE GUIDE CONTAINER STYLES -\*------------------------------------*/ -/** - * NOTE: These styles are specific to the style guide container and should not be modified. - * Use style.scss for all content styles that don't pertain to the style guide container. - * - * Second note: Any important declarations are to prevent brand styles from overriding style guide - */ -/*------------------------------------*\ - $CONTENTS -\*------------------------------------*/ -/** - * STYLE GUIDE VARIABLES------------------Declarations of Sass variables - * -----Font - * -----Colors - * -----Typography - * -----Defaults - * -----Breakpoints - * MIXINS---------------------------------Sass mixins - * RESET----------------------------------Set reset defaults - * GLOBAL ELEMENTS------------------------Establish global styles - * -----Main - * -----Headings - * -----Text-related elements (p, blockquote, lists) - * -----Defaults - * -----Breakpoints - * STYLE GUIDE INTERFACE------------------CSS for the Style Guide Container. Should not influence the containing styles at all. - * -----Header - * -----Navigation - * -----Controls - * -----Main Container - * -----Viewport - * -----Section Headers - * -----Code View - */ -/*------------------------------------*\ - $STYLE GUIDE VARIABLES -\*------------------------------------*/ -/*Fonts*/ -/* Style Guide Interface Colors */ -/* Typography */ -/* Defaults */ -/* Dimensions */ -/* Breakpoints */ -/*------------------------------------*\ - $STYLE GUIDE MIXINS -\*------------------------------------*/ -/*------------------------------------*\ - $STYLE GUIDE INTERFACE -\*------------------------------------*/ -#patternlab-html, #patternlab-body { - margin: 0; - padding: 0; - background: #dddddd; - -webkit-text-size-adjust: 100%; } - -.sg-nav-wrapper { - overflow: hidden; - background: #dddddd; } - -.is-vishidden { - position: absolute !important; - overflow: hidden; - width: 1px; - height: 1px; - padding: 0; - border: 0; - clip: rect(1px, 1px, 1px, 1px); } - -/*------------------------------------*\ - $STYLE GUIDE HEADER -\*------------------------------------*/ -/* Header */ -.sg-header { - background: #222222; - color: white; - font-family: "HelveticaNeue", "Helvetica", "Arial", sans-serif; - text-transform: uppercase; - position: fixed; - top: 0; - left: 0; - z-index: 2; - width: 100%; - -webkit-box-shadow: inset 0 1px 0 #5f6164, inset 0 -1px 0 #2e2f2f, 0 1px 3px rgba(0, 0, 0, 0.3); - -moz-box-shadow: inset 0 1px 0 #5f6164, inset 0 -1px 0 #2e2f2f, 0 1px 3px rgba(0, 0, 0, 0.3); - box-shadow: inset 0 1px 0 #5f6164, inset 0 -1px 0 #2e2f2f, 0 1px 3px rgba(0, 0, 0, 0.3); } - .sg-header * { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; } - .sg-header ul, .sg-header ol { - padding: 0; - margin: 0; } - .sg-header li { - list-style: none; - border-bottom: 1px solid rgba(255, 255, 255, 0.05); } - .sg-header a { - font-size: 70%; - color: gray; - text-decoration: none; - display: block; - line-height: 1; - padding: 1em; - -webkit-transition: background 0.15s ease-out; - -moz-transition: background 0.15s ease-out; - -ms-transition: background 0.15s ease-out; - -o-transition: background 0.15s ease-out; - transition: background 0.15s ease-out; - -webkit-transition: color 0.15s ease-out; - -moz-transition: color 0.15s ease-out; - -ms-transition: color 0.15s ease-out; - -o-transition: color 0.15s ease-out; - transition: color 0.15s ease-out; } - .sg-header a:hover, .sg-header a:focus, .sg-header a.active { - color: white; - background: rgba(255, 255, 255, 0.05); } - .sg-header ol li ol li ol li a { - padding-left: 2em; - text-transform: none; } - -/* Navigation */ -.sg-header .sg-nav-toggle { - padding: 1em; - border-bottom: 1px solid rgba(0, 0, 0, 0); - position: relative; - z-index: 2; } - @media all and (min-width: 44em) { - .sg-header .sg-nav-toggle { - display: none; } } - -@media all and (max-width: 44em) { - .sg-nav-container { - overflow: hidden; - max-height: 0; - -webkit-transition: max-height 0.5s ease-out; - -moz-transition: max-height 0.5s ease-out; - -ms-transition: max-height 0.5s ease-out; - -o-transition: max-height 0.5s ease-out; - transition: max-height 0.5s ease-out; } - .sg-nav-container.active { - max-height: 50em; } } - -.sg-nav { - z-index: 1; - margin: 0; - padding: 0; - list-style: none; } - @media all and (min-width: 44em) { - .sg-nav > li { - border-bottom: 0; - border-right: 1px solid rgba(255, 255, 255, 0.05); - float: left; - position: relative; } - .sg-nav > li > ol { - position: absolute; - top: 2em; - left: 0; } } - -/* Accordion */ -.sg-acc-handle:after { - content: ' +'; - float: right; - font-size: 70%; } - @media all and (min-width: 44em) { - .sg-acc-handle:after { - float: none; } } -.sg-acc-handle.active { - color: white; - background: rgba(255, 255, 255, 0.05); } - .sg-acc-handle.active:after { - content: ' -'; } -.sg-acc-handle.sg-icon:after { - content: ""; } - -.sg-header .sg-icon { - width: auto; - font-size: 1rem; - padding: 0.5rem 1rem; } - -.sg-acc-panel { - overflow: hidden; - max-height: 0; - min-width: 10em; - background: #222222; - -webkit-transition: max-height 0.5s ease-out; - -moz-transition: max-height 0.5s ease-out; - -ms-transition: max-height 0.5s ease-out; - -o-transition: max-height 0.5s ease-out; - transition: max-height 0.5s ease-out; } - .sg-acc-panel.active { - max-height: 50em; } - .sg-acc-panel.sg-right { - position: absolute; - left: auto; - right: 0; } - -/* Controls (sizing, view mode) */ -.sg-controls { - border: 0; - position: absolute; - top: 0; - right: 0; - z-index: 2; } - .sg-controls .sg-acc-panel.active { - max-height: 17em; } - .sg-controls .sg-nav-phases .sg-acc-panel { - min-width: 0; } - .sg-controls .sg-nav-phases .sg-acc-panel.active { - max-height: none; } - -.sg-control-trigger { - border-bottom: 1px solid rgba(255, 255, 255, 0.05); } - @media all and (min-width: 44em) { - .sg-control-trigger { - border: 0; } } - @media all and (min-width: 65em) { - .sg-control-trigger { - float: left; - width: 6em; } } - -@media all and (min-width: 44em) { - .sg-control > li { - float: left; - border-bottom: 0; - border-left: 1px solid rgba(255, 255, 255, 0.05); } } - -.sg-control > li { - float: left; } -.sg-control .sg-input { - padding: 0.1em; - -webkit-transition: all 0.2s ease-out; - -moz-transition: all 0.2s ease-out; - -ms-transition: all 0.2s ease-out; - -o-transition: all 0.2s ease-out; - transition: all 0.2s ease-out; } - .sg-control .sg-input:active, .sg-control .sg-input:focus { - outline: 0; - background: #f7f7f7; - color: #000; } - -@media all and (max-width: 65em) { - .sg-quarter { - float: left; - width: 25%; - border-left: 1px solid rgba(255, 255, 255, 0.05); - text-align: center; } - .sg-quarter:first-child { - border-left: 0; } } - -@media all and (max-width: 65em) { - .sg-half { - float: left; - width: 50%; - border-left: 1px solid rgba(255, 255, 255, 0.05); - text-align: center; } - .sg-half:nth-child(odd) { - border-left: 0; } } - -.sg-current-size { - font-size: 70%; - color: gray; - padding: 0.8em 0.95em; } - .sg-current-size:hover .sg-input { - background: #f7f7f7; - color: #000; } - @media all and (min-width: 65em) { - .sg-current-size { - float: left; } } - -.sg-size-options { - max-width: 10em; } - @media all and (min-width: 65em) { - .sg-size-options { - position: static; - max-height: none; - max-width: none; } - .sg-size-options > li { - float: left; - border: 0; - border-left: 1px solid rgba(255, 255, 255, 0.05); } } - -#sg-form { - margin: 0; - border: 0; - padding: 0; } - -.sg-input { - margin: -2px 0 0 0; - padding: 0; - border: 1px solid #222; - background-color: #222; - color: gray; - width: 35px; - text-align: right; } - -.sg-input-active { - background-color: #fff; - color: #000; } - -.sg-view { - position: relative; } - .sg-view > ul { - position: absolute; - top: 2em; - left: 0; } - -.sg-checkbox:before { - display: inline-block; - margin-right: 0.4em; } - -/*------------------------------------*\ - $STYLE GUIDE VIEWPORT -\*------------------------------------*/ -/* Viewport */ -#sg-vp-wrap { - text-align: center; - width: 100%; } - @media all and (min-width: 44em) { - #sg-vp-wrap { - position: fixed; - top: 2em; - bottom: 0; - left: 0; - right: 0; - z-index: 0; } } - #sg-vp-wrap.wrap-animate { - -webkit-transition: left 0.3s ease-out; - -moz-transition: left 0.3s ease-out; - -ms-transition: left 0.3s ease-out; - -o-transition: left 0.3s ease-out; - transition: left 0.3s ease-out; } - -#sg-viewport { - border: 0; - x-margin: 0 auto; - height: 100%; - width: 100%; } - #sg-viewport.hay-mode { - -webkit-transition: all 40s linear; - -moz-transition: all 40s linear; - -ms-transition: all 40s linear; - -o-transition: all 40s linear; - transition: all 40s linear; } - -#sg-cover { - width: 100%; - height: 100%; - display: none; - position: absolute; - z-index: 20; - cursor: col-resize; } - -#sg-gen-container { - height: 100%; - text-align: center; - margin: 0 auto; } - #sg-gen-container.hay-mode { - -webkit-transition: all 40s linear; - -moz-transition: all 40s linear; - -ms-transition: all 40s linear; - -o-transition: all 40s linear; - transition: all 40s linear; } - -#sg-rightpull-container { - width: 10px; - float: right; - margin: 0; - height: 100%; - cursor: col-resize; } - -#sg-rightpull { - margin: 0; - width: 10px; - height: 100%; - background: #999; - -webkit-transition: background 0.2s ease-out; - -moz-transition: background 0.2s ease-out; - -ms-transition: background 0.2s ease-out; - -o-transition: background 0.2s ease-out; - transition: background 0.2s ease-out; } - #sg-rightpull:hover { - background: #666; } - #sg-rightpull:active { - cursor: col-resize; - background: #444; } - -.vp-animate { - -webkit-transition: width 0.8s ease-out; - -moz-transition: width 0.8s ease-out; - -ms-transition: width 0.8s ease-out; - -o-transition: width 0.8s ease-out; - transition: width 0.8s ease-out; } - -/*------------------------------------*\ - $STYLE GUIDE CONTENT -\*------------------------------------*/ -/* Section Pattern */ -.sg-pattern { - margin-bottom: 2em; - overflow: hidden; } - -/* Section Head */ -.sg-pattern-head { - margin: 2em 0; - font-family: "HelveticaNeue", "Helvetica", "Arial", sans-serif; - font-size: 70%; - font-weight: normal; - padding: 1em 0; - border-bottom: 1px solid gray; } - .sg-pattern-head a { - display: block; - color: gray; - text-decoration: none; - cursor: pointer; } - .sg-pattern-head a:hover { - color: #222222; } - -/* Clean View */ -.sg-clean .sg-main { - padding: 0; } - -.sg-code, .sg-annotations { - clear: both; - background: #dddddd; - color: #222222; - padding: 1em 0.5em; - margin: 1em 0; } - .sg-code a, .sg-annotations a { - text-decoration: underline; } - -.sg-code pre { - white-space: -moz-pre-line; - white-space: -pre-line; - white-space: -o-pre-line; - word-wrap: break-word; - white-space: pre-line; - border: 1px solid rgba(0, 0, 0, 0.1); - padding: 0.5em; } - -.sg-code-contains { - margin-bottom: 1rem; - font-size: 85%; - color: gray; } - .sg-code-contains code { - padding: 0.2em; - background: rgba(0, 0, 0, 0.3); - color: #f7f7f7; - position: relative; - top: -2px; } - -.sg-code-head { - color: gray; - font-size: 1em; } - -.demo { - overflow: hidden; - margin-bottom: 1rem; } - -.demo .gi, .demo .demo-block { - background: #dddddd; - color: gray; - text-align: center; - margin-bottom: 0.5em; - padding: 1em !important; } - .demo .gi:nth-of-type(2n), .demo .demo-block:nth-of-type(2n) { - color: #dddddd; - background: gray; } - .demo .gi .gi, .demo .demo-block .gi { - background: rgba(0, 0, 0, 0.1); - color: #dddddd; } - .demo .gi .gi:nth-of-type(2n), .demo .demo-block .gi:nth-of-type(2n) { - background: rgba(0, 0, 0, 0.3); } - -.demo-animate { - background: #dddddd; - padding: 1em; - margin-bottom: 1em; - text-align: center; } - -.animate-move { - position: relative; } - .animate-move .demo-shape { - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 20px; - background: gray; } - .animate-move:hover > .demo-shape { - left: 100%; - margin-left: -20px; } - -.sg-colors { - overflow: hidden; } - .sg-colors li { - overflow: hidden; - border: 1px solid #dddddd; - padding: 0.3em; - margin: 0 0.2em 0.2em 0; } - @media all and (min-width: 30em) { - .sg-colors li { - float: left; - width: 5em; } } - -.sg-swatch { - display: block; - height: 1.5em; - width: 50%; } - @media all and (max-width: 30em) { - .sg-swatch { - float: left; - margin-right: 0.3em; } } - @media all and (min-width: 30em) { - .sg-swatch { - width: 100%; - height: 4em; - margin-bottom: 0.2em; } } - -.sg-label { - line-height: 1; } - -#sg-annotation-container { - position: fixed; - bottom: 0; - left: 0; - z-index: 99; - width: 100%; - padding: 1em; } - -/* Annotations */ -#sg-annotation-container, #sg-code-container { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - font-family: "HelveticaNeue", "Helvetica", "Arial", sans-serif; - font-size: 90%; - background: #222222; - color: gray; - position: fixed; - top: auto; - padding: 1rem 1rem 4rem; - bottom: 0; - left: 0; - width: 100%; - z-index: 2; - -webkit-transition: bottom 0.3s ease-out; - -moz-transition: bottom 0.3s ease-out; - -webkit-transition: bottom 0.3s ease-out; - -ms-transition: bottom 0.3s ease-out; - -o-transition: bottom 0.3s ease-out; - transition: bottom 0.3s ease-out; } - #sg-annotation-container a, #sg-code-container a { - color: #dddddd; } - -#sg-code-container pre { - max-height: 300px; - padding: 0 1em; } - -#sg-code-container .with-css pre { - max-height: 200px; } - -#sg-annotation-close-btn, #sg-code-close-btn { - color: #fff; - position: absolute; - top: 1em; - right: 1em; - text-transform: uppercase; - text-decoration: none; - text-align: right; } - -.has-comment, .has-comment a { - cursor: help !important; } - -@font-face { - font-family: 'icons'; - src: url("../assets/icons.eot"); - src: url("../assets/icons.eot?#iefix") format("embedded-opentype"), url("../assets/icons.woff") format("woff"), url("../assets/icons.ttf") format("truetype"), url("../assets/icons.svg#icons") format("svg"); - font-weight: normal; - font-style: normal; } - -/* Pattern Lab icon fonts */ -.icon-reload, .icon-cog, .icon-minus, .icon-plus, .icon-menu, .sg-header .sg-nav-toggle, .icon-checkbox-unchecked, .sg-checkbox, .icon-checkbox-checked, .sg-checkbox.active, .icon-eye { - 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-reload:before { - content: "\e002"; } - -.icon-cog:before { - content: "\e000"; } - -.icon-minus:before { - content: "\e003"; } - -.icon-plus:before { - content: "\e004"; } - -.icon-menu:before, .sg-header .sg-nav-toggle:before { - content: "\e005"; } - -.icon-checkbox-unchecked:before, .sg-checkbox:before { - content: "\e006"; } - -.icon-checkbox-checked:before, .sg-checkbox.active:before { - content: "\e007"; } - -.icon-eye:before { - content: "\e001"; } diff --git a/public/styleguide/css/styleguide.scss b/public/styleguide/css/styleguide.scss deleted file mode 100644 index 80178908c..000000000 --- a/public/styleguide/css/styleguide.scss +++ /dev/null @@ -1,867 +0,0 @@ -/*------------------------------------*\ - $STYLE GUIDE CONTAINER STYLES -\*------------------------------------*/ -/** - * NOTE: These styles are specific to the style guide container and should not be modified. - * Use style.scss for all content styles that don't pertain to the style guide container. - * - * Second note: Any important declarations are to prevent brand styles from overriding style guide - */ - - -/*------------------------------------*\ - $CONTENTS -\*------------------------------------*/ -/** - * STYLE GUIDE VARIABLES------------------Declarations of Sass variables - * -----Font - * -----Colors - * -----Typography - * -----Defaults - * -----Breakpoints - * MIXINS---------------------------------Sass mixins - * RESET----------------------------------Set reset defaults - * GLOBAL ELEMENTS------------------------Establish global styles - * -----Main - * -----Headings - * -----Text-related elements (p, blockquote, lists) - * -----Defaults - * -----Breakpoints - * STYLE GUIDE INTERFACE------------------CSS for the Style Guide Container. Should not influence the containing styles at all. - * -----Header - * -----Navigation - * -----Controls - * -----Main Container - * -----Viewport - * -----Section Headers - * -----Code View - */ - - - - - -/*------------------------------------*\ - $STYLE GUIDE VARIABLES -\*------------------------------------*/ -/*Fonts*/ -$sg-font : "HelveticaNeue", "Helvetica", "Arial", sans-serif; - -/* Style Guide Interface Colors */ -$sg-primary : #222; -$sg-secondary : #808080; -$sg-tertiary : #ddd; -$sg-quaternary : #fff; -$sg-quinary : #f7f7f7; -$sg-tint : rgba(255,255,255,0.05); -$sg-tint-2 : rgba(255,255,255,0.25); -$sg-tone : rgba(0,0,0,0.1); -$sg-tone-2 : rgba(0,0,0,0.3); - -/* Typography */ -$sg-font-size-norm : 100%; -$sg-font-size-sm : 70%; -$sg-font-size-large : 120%; - -/* Defaults */ -$sg-space : 1em; -$sg-doublespace : $sg-space*2; -$sg-pad : 1em; -$sg-pad-half : $sg-pad/2; - -/* Dimensions */ -$offset-top: 2em; - -/* Breakpoints */ -$sg-bp-small : 24em; -$sg-bp-small-2 : 30em; -$sg-bp-med : 44em; -$sg-bp-large : 65em; -$sg-bp-xl : 80em; - -$animate-quick: 0.2s; - - - - - -/*------------------------------------*\ - $STYLE GUIDE MIXINS -\*------------------------------------*/ -@mixin sg-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; -} - - - - - - -/*------------------------------------*\ - $STYLE GUIDE INTERFACE -\*------------------------------------*/ - -#patternlab-html, #patternlab-body { - margin: 0; - padding: 0; - background: $sg-tertiary; - -webkit-text-size-adjust: 100%; -} - -.sg-nav-wrapper { - overflow: hidden; - background: $sg-tertiary; -} - -.is-vishidden { - position: absolute !important; - overflow: hidden; - width: 1px; - height: 1px; - padding: 0; - border: 0; - clip: rect(1px, 1px, 1px, 1px); -} - - - - -/*------------------------------------*\ - $STYLE GUIDE HEADER -\*------------------------------------*/ -/* Header */ -.sg-header { - background: $sg-primary; - color: $sg-quaternary; - font-family: $sg-font; - text-transform: uppercase; - position: fixed; - top: 0; - left: 0; - z-index: 2; - width: 100%; - - -webkit-box-shadow: inset 0 1px 0 #5f6164,inset 0 -1px 0 #2e2f2f,0 1px 3px rgba(0,0,0,0.3); - -moz-box-shadow: inset 0 1px 0 #5f6164,inset 0 -1px 0 #2e2f2f,0 1px 3px rgba(0,0,0,0.3); - box-shadow: inset 0 1px 0 #5f6164,inset 0 -1px 0 #2e2f2f,0 1px 3px rgba(0,0,0,0.3); - - * { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - } - - ul, ol { - padding: 0; - margin: 0; - } - - li { - list-style: none; - border-bottom: 1px solid $sg-tint; - } - a { - font-size: $sg-font-size-sm; - color: $sg-secondary; - text-decoration: none; - display: block; - line-height: 1; - padding: $sg-pad; - @include sg-transition(background,0.15s,ease-out); - @include sg-transition(color,0.15s,ease-out); - - &:hover, &:focus, &.active { - color: $sg-quaternary; - background: $sg-tint; - } - } - - ol{ - li{ - ol{ - li{ - ol{ - li{ - //3rd level nav item - a { - padding-left: 2em; - text-transform: none; - } - } - } - } - } - } - } - -} - - - -/* Navigation */ -.sg-header .sg-nav-toggle { - @extend .icon-menu; - padding: $sg-pad; - border-bottom: 1px solid rgba(0,0,0,0); - position: relative; - z-index: 2; - @media all and (min-width: $sg-bp-med) { - display: none; - } -} - -.sg-nav-container { - @media all and (max-width: $sg-bp-med) { - overflow: hidden; - max-height: 0; - @include sg-transition(max-height,0.5s,ease-out); - - &.active { - max-height: 50em; - } - } -} - -.sg-nav { - z-index: 1; - margin: 0; - padding: 0; - list-style: none; - - > li { - - @media all and (min-width: $sg-bp-med) { - border-bottom: 0; - border-right: 1px solid $sg-tint; - float: left; - position: relative; - - > ol { - position: absolute; - top: $offset-top; - left: 0; - } - - } - } -} - -/* Accordion */ -.sg-acc-handle { - &:after { - content: ' +'; - float: right; - font-size: $sg-font-size-sm; - - @media all and (min-width: $sg-bp-med) { - float: none; - } - } - - &.active { - color: $sg-quaternary; - background: $sg-tint; - &:after { - content: ' -'; - } - } - - &.sg-icon:after { - content: ""; - } -} - -.sg-header .sg-icon { - width: auto; - font-size: 1rem; - padding: 0.5rem 1rem; -} - -.sg-acc-panel { - overflow: hidden; - max-height: 0; - min-width: 10em; - background: $sg-primary; - @include sg-transition(max-height,0.5s,ease-out); - - &.active { - max-height: 50em; - } - - &.sg-right { - position: absolute; - left: auto; - right: 0; - } -} - -/* Controls (sizing, view mode) */ -.sg-controls { - border: 0; - position: absolute; - top: 0; - right: 0; - z-index: 2; - - .sg-acc-panel.active { - max-height: 17em; - } - - .sg-nav-phases .sg-acc-panel { - min-width: 0; - - &.active { - max-height: none; - } - } -} - -.sg-control-trigger { - border-bottom: 1px solid $sg-tint; - - @media all and (min-width: $sg-bp-med) { - border: 0; - } - - @media all and (min-width: $sg-bp-large) { - float: left; - width: 6em; - } -} - -.sg-control { - > li { - @media all and (min-width: $sg-bp-med) { - float: left; - border-bottom: 0; - border-left: 1px solid $sg-tint; - } - } -} - - - - -.sg-control { - > li { - float: left; - } - - .sg-input { - padding: 0.1em; - -webkit-transition: all $animate-quick ease-out; - -moz-transition: all $animate-quick ease-out; - -ms-transition: all $animate-quick ease-out; - -o-transition: all $animate-quick ease-out; - transition: all $animate-quick ease-out; - - &:active, &:focus { - outline: 0; - background: $sg-quinary; - color: #000; - } - } -} - -.sg-quarter { - @media all and (max-width: $sg-bp-large) { - float: left; - width: 25%; - border-left: 1px solid $sg-tint; - text-align: center; - - &:first-child { - border-left: 0; - } - } -} - -.sg-half { - @media all and (max-width: $sg-bp-large) { - float: left; - width: 50%; - border-left: 1px solid $sg-tint; - text-align: center; - - &:nth-child(odd) { - border-left: 0; - } - } -} - -.sg-current-size { - font-size: 70%; - color: $sg-secondary; - padding: 0.8em 0.95em; - - &:hover { - .sg-input { - background: $sg-quinary; - color: #000; - } - } - - @media all and (min-width: $sg-bp-large) { - float: left; - } - } - -.sg-size-options { - max-width: 10em; - - @media all and (min-width: $sg-bp-large) { - position: static; - max-height: none; - max-width: none; - - > li { - float: left; - border: 0; - border-left: 1px solid $sg-tint; - } - } -} - -#sg-form { - margin: 0; - border: 0; - padding: 0; -} -.sg-input { - margin: -2px 0 0 0; - padding: 0; - border: 1px solid #222; - background-color: #222; - color: gray; - width: 35px; - text-align: right; -} - -.sg-input-active { - background-color: #fff; - color: #000; -} - -.sg-view { - position: relative; - - > ul { - position: absolute; - top: $offset-top; - left: 0; - } -} - -//Checklist dropdown lists -.sg-checkbox { - @extend .icon-checkbox-unchecked; - - &:before { - display: inline-block; - margin-right: 0.4em; - } - - &.active { - @extend .icon-checkbox-checked; - } -} - - - -/*------------------------------------*\ - $STYLE GUIDE VIEWPORT -\*------------------------------------*/ - -/* Viewport */ -#sg-vp-wrap { - text-align: center; - width: 100%; - - @media all and (min-width: $sg-bp-med) { - position: fixed; - top: $offset-top; - bottom: 0; - left: 0; - right: 0; - z-index: 0; - } - - &.wrap-animate { - -webkit-transition: left 0.3s ease-out; - -moz-transition: left 0.3s ease-out; - -ms-transition: left 0.3s ease-out; - -o-transition: left 0.3s ease-out; - transition: left 0.3s ease-out; - } - -} - -#sg-viewport { - border: 0; - x-margin: 0 auto; - height: 100%; - width: 100%; - - &.hay-mode { - -webkit-transition: all 40s linear; - -moz-transition: all 40s linear; - -ms-transition: all 40s linear; - -o-transition: all 40s linear; - transition: all 40s linear; - } -} - -#sg-cover { - width: 100%; - height: 100%; - display: none; - position: absolute; - z-index: 20; - cursor: col-resize; -} - -#sg-gen-container { - height: 100%; - text-align: center; - margin: 0 auto; - - &.hay-mode { - -webkit-transition: all 40s linear; - -moz-transition: all 40s linear; - -ms-transition: all 40s linear; - -o-transition: all 40s linear; - transition: all 40s linear; - } -} - -#sg-rightpull-container { - width: 10px; - float: right; - margin: 0; - height: 100%; - cursor: col-resize; -} - -#sg-rightpull { - margin: 0; - width: 10px; - height: 100%; - background: #999; - -webkit-transition: background $animate-quick ease-out; - -moz-transition: background $animate-quick ease-out; - -ms-transition: background $animate-quick ease-out; - -o-transition: background $animate-quick ease-out; - transition: background $animate-quick ease-out; - - &:hover { - background: #666; - } - - &:active { - cursor: col-resize; - background: #444; - } -} - -.vp-animate { - -webkit-transition: width 0.8s ease-out; - -moz-transition: width 0.8s ease-out; - -ms-transition: width 0.8s ease-out; - -o-transition: width 0.8s ease-out; - transition: width 0.8s ease-out; -} - - - - - -/*------------------------------------*\ - $STYLE GUIDE CONTENT -\*------------------------------------*/ - -/* Section Pattern */ -.sg-pattern { - margin-bottom: $sg-doublespace; - overflow: hidden; -} - -/* Section Head */ -.sg-pattern-head { - margin: $sg-doublespace 0; - font-family: $sg-font; - font-size: $sg-font-size-sm; - font-weight: normal; - padding: $sg-pad 0; - border-bottom: 1px solid $sg-secondary; - - a { - display: block; - color: $sg-secondary; - text-decoration: none; - cursor: pointer; - - &:hover { - color: $sg-primary; - } - } -} - -/* Clean View */ -.sg-clean .sg-main { - padding: 0; -} - - -// Code View Blocks -.sg-code, .sg-annotations { - clear: both; - background: $sg-tertiary; - color: $sg-primary; - padding: $sg-pad $sg-pad-half; - margin: $sg-space 0; - - a { - text-decoration: underline; - } -} - -.sg-code { - pre { - white-space: -moz-pre-line; - white-space: -pre-line; - white-space: -o-pre-line; - word-wrap: break-word; - white-space: pre-line; - border: 1px solid $sg-tone; - padding: $sg-pad-half; - } -} - -.sg-code-contains { - margin-bottom: 1rem; - font-size: 85%; - color: $sg-secondary; - - code { - padding: 0.2em; - background: $sg-tone-2; - color: $sg-quinary; - position: relative; - top: -2px; - } -} - -.sg-code-head { - color: $sg-secondary; - font-size: 1em; -} - -// Demo to show grid system - in this stylesheet because it shouldn't be included in the production styles -.demo { - overflow: hidden; - margin-bottom: 1rem; -} -.demo .gi, .demo .demo-block { - background: $sg-tertiary; - color: $sg-secondary; - text-align: center; - margin-bottom: $sg-pad-half; - padding: 1em !important; - - &:nth-of-type(2n) { - color: $sg-tertiary; - background: $sg-secondary; - } - - .gi { - background: $sg-tone; - color: $sg-tertiary; - - &:nth-of-type(2n) { - background: $sg-tone-2; - } - } -} - -//Demo box for animation -.demo-animate { - background: $sg-tertiary; - padding: $sg-pad; - margin-bottom: $sg-space; - text-align: center; -} - -//Animate Demo to show -.animate-move { - position: relative; - - .demo-shape { - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 20px; - background: $sg-secondary; - } - - &:hover { - > .demo-shape { - left: 100%; - margin-left: -20px; - } - } -} - -// Style Guide color swatches -.sg-colors { - overflow: hidden; - - li { - overflow: hidden; - border: 1px solid $sg-tertiary; - padding: 0.3em; - margin: 0 0.2em 0.2em 0; - - @media all and (min-width: $sg-bp-small-2) { - float: left; - width: 5em; - } - } -} - -.sg-swatch { - display: block; - height: 1.5em; - width: 50%; - - @media all and (max-width: $sg-bp-small-2) { - float: left; - margin-right: 0.3em; - } - - @media all and (min-width: $sg-bp-small-2) { - width: 100%; - height: 4em; - margin-bottom: 0.2em; - } - -} - -.sg-label { - line-height: 1; -} - -//Annotation -#sg-annotation-container { - position: fixed; - bottom: 0; - left: 0; - z-index: 99; - width: 100%; - padding: $sg-pad; -} - - -/* Annotations */ -#sg-annotation-container, #sg-code-container { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - font-family: $sg-font; - font-size: 90%; - background: $sg-primary; - color: $sg-secondary; - position: fixed; - top: auto; - padding: 1rem 1rem 4rem; - bottom: 0; - left: 0; - width: 100%; - z-index: 2; - -webkit-transition: bottom 0.3s ease-out; - -moz-transition: bottom 0.3s ease-out; - -webkit-transition: bottom 0.3s ease-out; - -ms-transition: bottom 0.3s ease-out; - -o-transition: bottom 0.3s ease-out; - transition: bottom 0.3s ease-out; - - a { - color: $sg-tertiary; - } -} - -#sg-code-container pre { - max-height: 300px; - padding: 0 1em; -} - -#sg-code-container .with-css pre { - max-height: 200px; -} - -#sg-annotation-close-btn, #sg-code-close-btn { - color: #fff; - position: absolute; - top: 1em; - right: 1em; - text-transform: uppercase; - text-decoration: none; - text-align: right; -} - -.has-comment, .has-comment a { - cursor: help !important; -} - -// Icon Font - -@font-face { - font-family: 'icons'; - src:url('../assets/icons.eot'); - src:url('../assets/icons.eot?#iefix') format('embedded-opentype'), - url('../assets/icons.woff') format('woff'), - url('../assets/icons.ttf') format('truetype'), - url('../assets/icons.svg#icons') format('svg'); - font-weight: normal; - font-style: normal; -} - -/* Pattern Lab icon fonts */ -.icon-reload, .icon-cog, .icon-minus, .icon-plus, .icon-menu, .icon-checkbox-unchecked, .icon-checkbox-checked, .icon-eye { - 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-reload:before { - content: "\e002"; -} -.icon-cog:before { - content: "\e000"; -} -.icon-minus:before { - content: "\e003"; -} -.icon-plus:before { - content: "\e004"; -} -.icon-menu:before { - content: "\e005"; -} -.icon-checkbox-unchecked:before { - content: "\e006"; -} -.icon-checkbox-checked:before { - content: "\e007"; -} -.icon-eye:before { - content: "\e001"; -} \ No newline at end of file diff --git a/public/styleguide/html/README b/public/styleguide/html/README deleted file mode 100644 index 5b0c53819..000000000 --- a/public/styleguide/html/README +++ /dev/null @@ -1 +0,0 @@ -will hold the auto-generated styleguide.html \ No newline at end of file diff --git a/public/styleguide/js/annotations-pattern.js b/public/styleguide/js/annotations-pattern.js deleted file mode 100644 index 1855c7137..000000000 --- a/public/styleguide/js/annotations-pattern.js +++ /dev/null @@ -1,212 +0,0 @@ -/*! - * Annotations Support for Patterns - v0.3 - * - * Copyright (c) 2013 Dave Olsen, http://dmolsen.com - * Licensed under the MIT license - * - */ - -var annotationsPattern = { - - commentsOverlayActive: false, - commentsOverlay: false, - commentsOverlayElement: "", - commentsEmbeddedActive: false, - commentsEmbedded: false, - - /** - * add an onclick handler to each element in the pattern that has an annotation - */ - showComments: function() { - - // make sure this only added when we're on a pattern specific view - var body = document.getElementsByTagName("body"); - if (!body[0].classList.contains("sg-pattern-list")) { - for (comment in comments.comments) { - var item = comments.comments[comment]; - var els = document.querySelectorAll(item.el); - for (var i = 0; i < els.length; ++i) { - els[i].onclick = (function(item) { - return function(e) { - e.preventDefault(); - e.stopPropagation(); - var obj = {}; - - if (annotationsPattern.commentsOverlayActive && !annotationsPattern.commentsOverlay) { - - // if this is for an overlay and comments overlay is false set the payload to turn the overlay on - annotationsPattern.commentsOverlay = true; - obj = { "commentOverlay": "on", "swapOverlay": false, "el": item.el, "title": item.title, "comment": item.comment }; - - } else if (annotationsPattern.commentsOverlayActive && annotationsPattern.commentsOverlay) { - - if (item.el == annotationsPattern.commentsOverlayElement) { - - // if the last element was clicked again turn off the overlay - annotationsPattern.commentsOverlay = false; - obj = { "commentOverlay": "off" }; - - } else { - - // if an element was clicked on while the overlay was already on swap it - obj = { "commentOverlay": "on", "swapOverlay": true, "el": item.el, "title": item.title, "comment": item.comment }; - - } - - } - - annotationsPattern.commentsOverlayElement = item.el; - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - parent.postMessage(obj,targetOrigin); - - } - })(item); - } - } - } - - }, - - /** - * embed a comment by building the sg-annotations div (if necessary) and building an sg-annotation div - * @param {Object} element to check the parent node of - * @param {String} the title of the comment - * @param {String} the comment HTML - */ - embedComments: function (el,title,comment) { - - // build the annotation div and add the content to it - var annotationDiv = document.createElement("div"); - annotationDiv.classList.add("sg-annotation"); - - var h3 = document.createElement("h3"); - var p = document.createElement("p"); - h3.innerHTML = title; - p.innerHTML = comment; - - annotationDiv.appendChild(h3); - annotationDiv.appendChild(p); - - // find the parent element to attach things to - var parentEl = annotationsPattern.findParent(el); - - // see if a child with the class annotations exists - var els = parentEl.getElementsByClassName("sg-annotations"); - if (els.length > 0) { - els[0].appendChild(annotationDiv); - } else { - var annotationsDiv = document.createElement("div"); - annotationsDiv.classList.add("sg-annotations"); - annotationsDiv.appendChild(annotationDiv); - parentEl.appendChild(annotationsDiv); - } - - }, - - /** - * recursively find the parent of an element to see if it contains the sg-pattern class - * @param {Object} element to check the parent node of - */ - findParent: function(el) { - - if (el.parentNode.classList.contains("sg-pattern")) { - return el.parentNode; - } else { - var parentEl = annotationsPattern.findParent(el.parentNode); - } - - return parentEl; - - }, - - /** - * toggle the annotation feature on/off - * based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage - * @param {Object} event info - */ - receiveIframeMessage: function(event) { - - // does the origin sending the message match the current host? if not dev/null the request - if ((window.location.protocol != "file:") && (event.origin !== window.location.protocol+"//"+window.location.host)) { - return; - } - - if (event.data.commentToggle != undefined) { - - // if this is an overlay make sure it's active for the onclick event - annotationsPattern.commentsOverlayActive = false; - annotationsPattern.commentsEmbeddedActive = false; - - // see which flag to toggle based on if this is a styleguide or view-all page - var body = document.getElementsByTagName("body"); - if ((event.data.commentToggle == "on") && (body[0].classList.contains("sg-pattern-list"))) { - annotationsPattern.commentsEmbeddedActive = true; - } else if (event.data.commentToggle == "on") { - annotationsPattern.commentsOverlayActive = true; - } - - // if comments overlay is turned off make sure to remove the has-comment class and pointer - if (!annotationsPattern.commentsOverlayActive) { - var els = document.querySelectorAll(".has-comment"); - for (var i = 0; i < els.length; i++) { - els[i].classList.remove("has-comment"); - } - } - - // if comments embedding is turned off make sure to hide the annotations div - if (!annotationsPattern.commentsEmbeddedActive) { - var els = document.getElementsByClassName("sg-annotations"); - for (var i = 0; i < els.length; i++) { - els[i].style.display = "none"; - } - } - - // if comments overlay is turned on add the has-comment class and pointer - if (annotationsPattern.commentsOverlayActive) { - - for (comment in comments.comments) { - var item = comments.comments[comment]; - var els = document.querySelectorAll(item.el); - for (var i = 0; i < els.length; i++) { - els[i].classList.add("has-comment"); - } - } - - } else if (annotationsPattern.commentsEmbeddedActive && !annotationsPattern.commentsEmbedded) { - - // if comment embedding is turned on and comments haven't been embedded yet do it - for (comment in comments.comments) { - var item = comments.comments[comment]; - var els = document.querySelectorAll(item.el); - if (els.length > 0) { - annotationsPattern.embedComments(els[0],item.title,item.comment); - } - annotationsPattern.commentsEmbedded = true; - } - - } else if (annotationsPattern.commentsEmbeddedActive && annotationsPattern.commentsEmbedded) { - - // if comment embedding is turned on and comments have been embedded simply display them - var els = document.getElementsByClassName("sg-annotations"); - for (var i = 0; i < els.length; ++i) { - els[i].style.display = "block"; - } - - } - - } - - } - -}; - -// add the onclick handlers to the elements that have an annotations -annotationsPattern.showComments(); -window.addEventListener("message", annotationsPattern.receiveIframeMessage, false); - -// before unloading the iframe make sure any active overlay is turned off/closed -window.onbeforeunload = function() { - var obj = { "commentOverlay": "off" }; - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - parent.postMessage(obj,targetOrigin); -}; \ No newline at end of file diff --git a/public/styleguide/js/annotations-viewer.js b/public/styleguide/js/annotations-viewer.js deleted file mode 100644 index ea0fbea09..000000000 --- a/public/styleguide/js/annotations-viewer.js +++ /dev/null @@ -1,138 +0,0 @@ -/*! - * Annotations Support for the Viewer - v0.3 - * - * Copyright (c) 2013 Brad Frost, http://bradfrostweb.com & Dave Olsen, http://dmolsen.com - * Licensed under the MIT license - * - */ - -var annotationsViewer = { - - commentsActive: false, - sw: document.documentElement.clientWidth, - breakpoint: 650, - - onReady: function() { - - $('body').addClass('comments-ready'); - $('#sg-t-annotations').click(function(e) { - - e.preventDefault(); - - // make sure the code view overlay is off - $('#sg-t-code').removeClass('active'); - codeViewer.codeActive = false; - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - document.getElementById('sg-viewport').contentWindow.postMessage({ "codeToggle": "off" },targetOrigin); - codeViewer.slideCode(999); - - annotationsViewer.toggleComments(); - annotationsViewer.commentContainerInit(); - - }); - - }, - - toggleComments: function() { - - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - $('#sg-t-annotations').toggleClass('active'); - - if (!annotationsViewer.commentsActive) { - - annotationsViewer.commentsActive = true; - document.getElementById('sg-viewport').contentWindow.postMessage({ "commentToggle": "on" },targetOrigin); - - } else { - - annotationsViewer.commentsActive = false; - document.getElementById('sg-viewport').contentWindow.postMessage({ "commentToggle": "off" },targetOrigin); - annotationsViewer.slideComment(999); - - } - - }, - - commentContainerInit: function() { - - if (document.getElementById("sg-annotation-container") == undefined) { - $('').html('Close

Annotation Title

Here is some comment text
').appendTo('body').css('bottom',-$(document).outerHeight()); - } - - if (annotationsViewer.sw < annotationsViewer.breakpoint) { - $('#sg-annotation-container').hide(); - } else { - $('#sg-annotation-container').show(); - } - - $('body').delegate('#sg-annotation-close-btn','click',function(e) { - annotationsViewer.slideComment($('#sg-annotation-container').outerHeight()); - return false; - }); - - }, - - slideComment: function(pos) { - - $('#sg-annotation-container').show(); - - if (annotationsViewer.sw > annotationsViewer.breakpoint) { - $('#sg-annotation-container').css('bottom',-pos); - } else { - var offset = $('#sg-annotation-container').offset().top; - $('html,body').animate({scrollTop: offset}, 500); - } - - }, - - updateComment: function(el,title,msg) { - var $container = $('#sg-annotation-container'), - $title = $('#sg-annotation-title'), - $text = $('#sg-annotation-text'); - $title.text(title); - $text.html(msg); - annotationsViewer.slideComment(0); - }, - - /** - * toggle the comment pop-up based on a user clicking on the pattern - * based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage - * @param {Object} event info - */ - receiveIframeMessage: function(event) { - - // does the origin sending the message match the current host? if not dev/null the request - if ((window.location.protocol != "file:") && (event.origin !== window.location.protocol+"//"+window.location.host)) { - return; - } - - if (event.data.commentOverlay != undefined) { - if (event.data.commentOverlay == "on") { - - annotationsViewer.updateComment(event.data.el,event.data.title,event.data.comment); - - } else { - annotationsViewer.slideComment($('#sg-annotation-container').outerHeight()); - } - } - - } - -} - -$(document).ready(function() { annotationsViewer.onReady(); }); -window.addEventListener("message", annotationsViewer.receiveIframeMessage, false); - -// make sure if a new pattern or view-all is loaded that comments are turned on as appropriate -$('#sg-viewport').load(function() { - if (annotationsViewer.commentsActive) { - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - document.getElementById('sg-viewport').contentWindow.postMessage({ "commentToggle": "on" },targetOrigin); - } -}); - -// no idea why this has to be outside. there's something funky going on with the JS pattern -$('#sg-view li a').click(function() { - $(this).parent().parent().removeClass('active'); - $(this).parent().parent().parent().parent().removeClass('active'); -}); diff --git a/public/styleguide/js/code-pattern.js b/public/styleguide/js/code-pattern.js deleted file mode 100644 index 96bfd4ff8..000000000 --- a/public/styleguide/js/code-pattern.js +++ /dev/null @@ -1,79 +0,0 @@ -/*! - * Code View Support for Patterns - v0.3 - * - * Copyright (c) 2013 Dave Olsen, http://dmolsen.com - * Licensed under the MIT license - * - */ - -var codePattern = { - - codeOverlayActive: false, - codeEmbeddedActive: false, - - /** - * toggle the annotation feature on/off - * based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage - * @param {Object} event info - */ - receiveIframeMessage: function(event) { - - // does the origin sending the message match the current host? if not dev/null the request - if ((window.location.protocol != "file:") && (event.origin !== window.location.protocol+"//"+window.location.host)) { - return; - } - - if (event.data.codeToggle != undefined) { - - // if this is an overlay make sure it's active for the onclick event - codePattern.codeOverlayActive = false; - codePattern.codeEmbeddedActive = false; - - // see which flag to toggle based on if this is a styleguide or view-all page - var body = document.getElementsByTagName("body"); - if ((event.data.codeToggle == "on") && (body[0].classList.contains("sg-pattern-list"))) { - codePattern.codeEmbeddedActive = true; - } else if (event.data.codeToggle == "on") { - codePattern.codeOverlayActive = true; - } - - // if comments embedding is turned off make sure to hide the annotations div - if (!codePattern.codeEmbeddedActive && (body[0].classList.contains("sg-pattern-list"))) { - var els = document.getElementsByClassName("sg-code"); - for (var i = 0; i < els.length; i++) { - els[i].style.display = "none"; - } - } - - // if comments overlay is turned on add the has-comment class and pointer - if (codePattern.codeOverlayActive) { - - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - obj = { "codeOverlay": "on", "lineage": lineage, "html": document.getElementById("sg-pattern-html").textContent, "css": document.getElementById("sg-pattern-css").textContent }; - parent.postMessage(obj,targetOrigin); - - } else if (codePattern.codeEmbeddedActive) { - - // if code embedding is turned on simply display them - var els = document.getElementsByClassName("sg-code"); - for (var i = 0; i < els.length; ++i) { - els[i].style.display = "block"; - } - - } - - } - - } - -}; - -// add the onclick handlers to the elements that have an annotations -window.addEventListener("message", codePattern.receiveIframeMessage, false); - -// before unloading the iframe make sure any active overlay is turned off/closed -window.onbeforeunload = function() { - var obj = { "codeOverlay": "off" }; - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - parent.postMessage(obj,targetOrigin); -}; \ No newline at end of file diff --git a/public/styleguide/js/code-viewer.js b/public/styleguide/js/code-viewer.js deleted file mode 100644 index edb716944..000000000 --- a/public/styleguide/js/code-viewer.js +++ /dev/null @@ -1,161 +0,0 @@ -/*! - * Code View Support for the Viewer - v0.1 - * - * Copyright (c) 2013 Brad Frost, http://bradfrostweb.com & Dave Olsen, http://dmolsen.com - * Licensed under the MIT license - * - */ - -var codeViewer = { - - codeActive: false, - sw: document.documentElement.clientWidth, - breakpoint: 650, - - onReady: function() { - - $('body').addClass('code-ready'); - $('#sg-t-code').click(function(e) { - e.preventDefault(); - - // make sure the annotations overlay is off - $('#sg-t-annotations').removeClass('active'); - annotationsViewer.commentsActive = false; - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - document.getElementById('sg-viewport').contentWindow.postMessage({ "commentToggle": "off" },targetOrigin); - annotationsViewer.slideComment(999); - - codeViewer.toggleCode(); - codeViewer.codeContainerInit(); - - }); - - }, - - toggleCode: function() { - - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - $('#sg-t-code').toggleClass('active'); - - if (!codeViewer.codeActive) { - - codeViewer.codeActive = true; - document.getElementById('sg-viewport').contentWindow.postMessage({ "codeToggle": "on" },targetOrigin); - - } else { - - codeViewer.codeActive = false; - document.getElementById('sg-viewport').contentWindow.postMessage({ "codeToggle": "off" },targetOrigin); - codeViewer.slideCode(999); - - } - - }, - - codeContainerInit: function() { - - if (document.getElementById("sg-code-container") == undefined) { - $('').html('Close

HTML

').appendTo('body').css('bottom',-$(document).outerHeight()); - } - - if (codeViewer.sw < codeViewer.breakpoint) { - $('#sg-code-container').hide(); - } else { - $('#sg-code-container').show(); - } - - $('body').delegate('#sg-code-close-btn','click',function(e) { - codeViewer.slideCode($('#sg-code-container').outerHeight()); - return false; - }); - - }, - - slideCode: function(pos) { - - $('#sg-code-container').show(); - - if (codeViewer.sw > codeViewer.breakpoint) { - $('#sg-code-container').css('bottom',-pos); - } else { - var offset = $('#sg-code-container').offset().top; - $('html,body').animate({scrollTop: offset}, 500); - } - - }, - - updateCode: function(lineage,html,css) { - - // draw lineage - if (lineage.length != 0) { - $("#sg-code-lineage").css("display","block"); - var i = 0; - var lineageList = ""; - for (pattern in lineage) { - lineageList += (i == 0) ? "" : ", "; - lineageList += ""+lineage[pattern]["lineagePattern"]+""; - i++; - } - - $("#sg-code-lineage-fill").html(lineageList); - - $('#sg-code-lineage-fill a').on("click", function(e){ - e.preventDefault(); - document.getElementById("sg-viewport").contentWindow.postMessage( { "path": urlHandler.getFileName($(this).attr("data-patternpartial")) }, urlHandler.targetOrigin); - }); - } - - // draw html - $("#sg-code-html-fill").text(html); - Prism.highlightElement(document.getElementById("sg-code-html-fill")); - - // draw CSS - if (css.indexOf("{{ patternCSS }}") == -1) { - $("#sg-code-html").addClass("with-css"); - $("#sg-code-css").css("display","block"); - $("#sg-code-css-fill").text(css); - Prism.highlightElement(document.getElementById("sg-code-css-fill")); - } - - codeViewer.slideCode(0); - - }, - - /** - * toggle the comment pop-up based on a user clicking on the pattern - * based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage - * @param {Object} event info - */ - receiveIframeMessage: function(event) { - - // does the origin sending the message match the current host? if not dev/null the request - if ((window.location.protocol != "file:") && (event.origin !== window.location.protocol+"//"+window.location.host)) { - return; - } - - if (event.data.codeOverlay != undefined) { - if (event.data.codeOverlay == "on") { - - codeViewer.updateCode(event.data.lineage,event.data.html,event.data.css); - - } else { - - codeViewer.slideCode($('#sg-code-container').outerHeight()); - - } - } - - } - -} - -$(document).ready(function() { codeViewer.onReady(); }); -window.addEventListener("message", codeViewer.receiveIframeMessage, false); - -// make sure if a new pattern or view-all is loaded that comments are turned on as appropriate -$('#sg-viewport').load(function() { - if (codeViewer.codeActive) { - var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host; - document.getElementById('sg-viewport').contentWindow.postMessage({ "codeToggle": "on" },targetOrigin); - } -}); diff --git a/public/styleguide/js/data-saver.js b/public/styleguide/js/data-saver.js deleted file mode 100644 index e354e1e79..000000000 --- a/public/styleguide/js/data-saver.js +++ /dev/null @@ -1,169 +0,0 @@ -/*! - * jQuery Cookie Plugin v1.3 - * https://github.com/carhartl/jquery-cookie - * - * Copyright 2011, Klaus Hartl - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://www.opensource.org/licenses/mit-license.php - * http://www.opensource.org/licenses/GPL-2.0 - */ -(function ($, document, undefined) { - - var pluses = /\+/g; - - function raw(s) { - return s; - } - - function decoded(s) { - return decodeURIComponent(s.replace(pluses, ' ')); - } - - var config = $.cookie = function (key, value, options) { - - // write - if (value !== undefined) { - options = $.extend({}, config.defaults, options); - - if (value === null) { - options.expires = -1; - } - - if (typeof options.expires === 'number') { - var days = options.expires, t = options.expires = new Date(); - t.setDate(t.getDate() + days); - } - - value = config.json ? JSON.stringify(value) : String(value); - - return (document.cookie = [ - encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), - options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE - options.path ? '; path=' + options.path : '', - options.domain ? '; domain=' + options.domain : '', - options.secure ? '; secure' : '' - ].join('')); - } - - // read - var decode = config.raw ? raw : decoded; - var cookies = document.cookie.split('; '); - for (var i = 0, l = cookies.length; i < l; i++) { - var parts = cookies[i].split('='); - if (decode(parts.shift()) === key) { - var cookie = decode(parts.join('=')); - return config.json ? JSON.parse(cookie) : cookie; - } - } - - return null; - }; - - config.defaults = {}; - - $.removeCookie = function (key, options) { - if ($.cookie(key) !== null) { - $.cookie(key, null, options); - return true; - } - return false; - }; - -})(jQuery, document); - -/*! - * Data Saver - v0.1 - * - * Copyright (c) 2013 Dave Olsen, http://dmolsen.com - * Licensed under the MIT license - */ - -var DataSaver = { - - // the name of the cookie to store the data in - cookieName: "patternlab", - - /** - * Add a given value to the cookie - * @param {String} the name of the key - * @param {String} the value - */ - addValue: function (name,val) { - var cookieVal = $.cookie(this.cookieName); - if ((cookieVal == null) || (cookieVal == "")) { - cookieVal = name+"~"+val; - } else { - cookieVal = cookieVal+"|"+name+"~"+val; - } - $.cookie(this.cookieName,cookieVal); - }, - - /** - * Update a value found in the cookie. If the key doesn't exist add the value - * @param {String} the name of the key - * @param {String} the value - */ - updateValue: function (name,val) { - if (this.findValue(name)) { - var updateCookieVals = ""; - var cookieVals = $.cookie(this.cookieName).split("|"); - for (var i = 0; i < cookieVals.length; i++) { - var fieldVals = cookieVals[i].split("~"); - if (fieldVals[0] == name) { - fieldVals[1] = val; - } - if (i > 0) { - updateCookieVals += "|"+fieldVals[0]+"~"+fieldVals[1]; - } else { - updateCookieVals += fieldVals[0]+"~"+fieldVals[1]; - } - } - $.cookie(this.cookieName,updateCookieVals); - } else { - this.addValue(name,val); - } - }, - - /** - * Remove the given key - * @param {String} the name of the key - */ - removeValue: function (name) { - var updateCookieVals = ""; - var cookieVals = $.cookie(this.cookieName).split("|"); - var k = 0; - for (var i = 0; i < cookieVals.length; i++) { - var fieldVals = cookieVals[i].split("~"); - if (fieldVals[0] != name) { - if (k == 0) { - updateCookieVals += fieldVals[0]+"~"+fieldVals[1]; - } else { - updateCookieVals += "|"+fieldVals[0]+"~"+fieldVals[1]; - } - k++; - } - } - $.cookie(this.cookieName,updateCookieVals); - }, - - /** - * Find the value using the given key - * @param {String} the name of the key - * - * @return {String} the value of the key or false if the value isn't found - */ - findValue: function (name) { - if ($.cookie(this.cookieName)) { - var cookieVals = $.cookie(this.cookieName).split("|"); - var k = 0; - for (var i = 0; i < cookieVals.length; i++) { - var fieldVals = cookieVals[i].split("~"); - if (fieldVals[0] == name) { - return fieldVals[1]; - } - } - } - return false; - } - -}; diff --git a/public/styleguide/js/jquery.js b/public/styleguide/js/jquery.js deleted file mode 100644 index 50d1b22f2..000000000 --- a/public/styleguide/js/jquery.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.9.0 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license */(function(e,t){"use strict";function n(e){var t=e.length,n=st.type(e);return st.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}function r(e){var t=Tt[e]={};return st.each(e.match(lt)||[],function(e,n){t[n]=!0}),t}function i(e,n,r,i){if(st.acceptData(e)){var o,a,s=st.expando,u="string"==typeof n,l=e.nodeType,c=l?st.cache:e,f=l?e[s]:e[s]&&s;if(f&&c[f]&&(i||c[f].data)||!u||r!==t)return f||(l?e[s]=f=K.pop()||st.guid++:f=s),c[f]||(c[f]={},l||(c[f].toJSON=st.noop)),("object"==typeof n||"function"==typeof n)&&(i?c[f]=st.extend(c[f],n):c[f].data=st.extend(c[f].data,n)),o=c[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[st.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[st.camelCase(n)])):a=o,a}}function o(e,t,n){if(st.acceptData(e)){var r,i,o,a=e.nodeType,u=a?st.cache:e,l=a?e[st.expando]:st.expando;if(u[l]){if(t&&(r=n?u[l]:u[l].data)){st.isArray(t)?t=t.concat(st.map(t,st.camelCase)):t in r?t=[t]:(t=st.camelCase(t),t=t in r?[t]:t.split(" "));for(i=0,o=t.length;o>i;i++)delete r[t[i]];if(!(n?s:st.isEmptyObject)(r))return}(n||(delete u[l].data,s(u[l])))&&(a?st.cleanData([e],!0):st.support.deleteExpando||u!=u.window?delete u[l]:u[l]=null)}}}function a(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(Nt,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:wt.test(r)?st.parseJSON(r):r}catch(o){}st.data(e,n,r)}else r=t}return r}function s(e){var t;for(t in e)if(("data"!==t||!st.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function u(){return!0}function l(){return!1}function c(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function f(e,t,n){if(t=t||0,st.isFunction(t))return st.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return st.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=st.grep(e,function(e){return 1===e.nodeType});if(Wt.test(t))return st.filter(t,r,!n);t=st.filter(t,r)}return st.grep(e,function(e){return st.inArray(e,t)>=0===n})}function p(e){var t=zt.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function d(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function h(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function g(e){var t=nn.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function m(e,t){for(var n,r=0;null!=(n=e[r]);r++)st._data(n,"globalEval",!t||st._data(t[r],"globalEval"))}function y(e,t){if(1===t.nodeType&&st.hasData(e)){var n,r,i,o=st._data(e),a=st._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)st.event.add(t,n,s[n][r])}a.data&&(a.data=st.extend({},a.data))}}function v(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!st.support.noCloneEvent&&t[st.expando]){r=st._data(t);for(i in r.events)st.removeEvent(t,i,r.handle);t.removeAttribute(st.expando)}"script"===n&&t.text!==e.text?(h(t).text=e.text,g(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),st.support.html5Clone&&e.innerHTML&&!st.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Zt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}function b(e,n){var r,i,o=0,a=e.getElementsByTagName!==t?e.getElementsByTagName(n||"*"):e.querySelectorAll!==t?e.querySelectorAll(n||"*"):t;if(!a)for(a=[],r=e.childNodes||e;null!=(i=r[o]);o++)!n||st.nodeName(i,n)?a.push(i):st.merge(a,b(i,n));return n===t||n&&st.nodeName(e,n)?st.merge([e],a):a}function x(e){Zt.test(e.type)&&(e.defaultChecked=e.checked)}function T(e,t){if(t in e)return t;for(var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Nn.length;i--;)if(t=Nn[i]+n,t in e)return t;return r}function w(e,t){return e=t||e,"none"===st.css(e,"display")||!st.contains(e.ownerDocument,e)}function N(e,t){for(var n,r=[],i=0,o=e.length;o>i;i++)n=e[i],n.style&&(r[i]=st._data(n,"olddisplay"),t?(r[i]||"none"!==n.style.display||(n.style.display=""),""===n.style.display&&w(n)&&(r[i]=st._data(n,"olddisplay",S(n.nodeName)))):r[i]||w(n)||st._data(n,"olddisplay",st.css(n,"display")));for(i=0;o>i;i++)n=e[i],n.style&&(t&&"none"!==n.style.display&&""!==n.style.display||(n.style.display=t?r[i]||"":"none"));return e}function C(e,t,n){var r=mn.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function k(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;4>o;o+=2)"margin"===n&&(a+=st.css(e,n+wn[o],!0,i)),r?("content"===n&&(a-=st.css(e,"padding"+wn[o],!0,i)),"margin"!==n&&(a-=st.css(e,"border"+wn[o]+"Width",!0,i))):(a+=st.css(e,"padding"+wn[o],!0,i),"padding"!==n&&(a+=st.css(e,"border"+wn[o]+"Width",!0,i)));return a}function E(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=ln(e),a=st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=un(e,t,o),(0>i||null==i)&&(i=e.style[t]),yn.test(i))return i;r=a&&(st.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+k(e,t,n||(a?"border":"content"),r,o)+"px"}function S(e){var t=V,n=bn[e];return n||(n=A(e,t),"none"!==n&&n||(cn=(cn||st(" -
-
-
- - - - - - - {{> patternPaths }} - {{> viewAllPaths }} - - {{> websockets }} - - - - - - \ No newline at end of file diff --git a/source/_patternlab-files/partials/ishControls.mustache b/source/_patternlab-files/partials/ishControls.mustache deleted file mode 100644 index c2947f625..000000000 --- a/source/_patternlab-files/partials/ishControls.mustache +++ /dev/null @@ -1,50 +0,0 @@ - -
-
- - -
-
- \ No newline at end of file diff --git a/source/_patternlab-files/partials/patternNav.mustache b/source/_patternlab-files/partials/patternNav.mustache deleted file mode 100644 index 3a60f2ab9..000000000 --- a/source/_patternlab-files/partials/patternNav.mustache +++ /dev/null @@ -1,17 +0,0 @@ -
    - {{# buckets }} -
  1. {{ bucketNameUC }}
      - {{# navItems }} -
    1. {{ sectionNameUC }}
        - {{# navSubItems }} -
      1. {{ patternName }}
      2. - {{/ navSubItems }} -
    2. - {{/ navItems }} - {{# patternItems }} -
    3. {{ patternName }}
    4. - {{/ patternItems }} -
  2. - {{/ buckets }} -
  3. All
  4. -
diff --git a/source/_patternlab-files/partials/patternPaths.mustache b/source/_patternlab-files/partials/patternPaths.mustache deleted file mode 100644 index 3b8562337..000000000 --- a/source/_patternlab-files/partials/patternPaths.mustache +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/source/_patternlab-files/partials/viewAllPaths.mustache b/source/_patternlab-files/partials/viewAllPaths.mustache deleted file mode 100644 index b0e044d97..000000000 --- a/source/_patternlab-files/partials/viewAllPaths.mustache +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/source/_patternlab-files/partials/websockets.mustache b/source/_patternlab-files/partials/websockets.mustache deleted file mode 100644 index 139a9b254..000000000 --- a/source/_patternlab-files/partials/websockets.mustache +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/source/_patternlab-files/pattern-header-footer/README b/source/_patternlab-files/pattern-header-footer/README deleted file mode 100644 index 6c5a981ab..000000000 --- a/source/_patternlab-files/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/source/_patternlab-files/pattern-header-footer/footer.html b/source/_patternlab-files/pattern-header-footer/footer.html deleted file mode 100644 index ddc55618d..000000000 --- a/source/_patternlab-files/pattern-header-footer/footer.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/_patternlab-files/pattern-header-footer/header.html b/source/_patternlab-files/pattern-header-footer/header.html deleted file mode 100644 index 54a44f354..000000000 --- a/source/_patternlab-files/pattern-header-footer/header.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - Pattern Lab Pattern - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/_patternlab-files/styleguide.mustache b/source/_patternlab-files/styleguide.mustache deleted file mode 100644 index a3c7e437f..000000000 --- a/source/_patternlab-files/styleguide.mustache +++ /dev/null @@ -1,65 +0,0 @@ - - - - Pattern Lab Style Guide - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/_patternlab-files/viewall.mustache b/source/_patternlab-files/viewall.mustache deleted file mode 100644 index 5c2dc88ce..000000000 --- a/source/_patternlab-files/viewall.mustache +++ /dev/null @@ -1,65 +0,0 @@ - - - - Pattern Lab Sub-type Style Guide - - - - - - - - -
- - -
- {{# partials }} -
-

{{ patternName }}

-
- {{{ patternPartial }}} - -
-
- {{/ partials }} -
- -
- - - - - - - - - - \ No newline at end of file diff --git a/source/_patterns/00-atoms/00-global/00-colors.mustache b/source/_patterns/00-atoms/00-global/00-colors.mustache deleted file mode 100644 index 7f2653f8d..000000000 --- a/source/_patterns/00-atoms/00-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/source/_patterns/00-atoms/00-global/01-fonts.mustache b/source/_patterns/00-atoms/00-global/01-fonts.mustache deleted file mode 100644 index 26b4b7bb5..000000000 --- a/source/_patterns/00-atoms/00-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/source/_patterns/00-atoms/00-global/02-animations.mustache b/source/_patterns/00-atoms/00-global/02-animations.mustache deleted file mode 100644 index 7d3074575..000000000 --- a/source/_patterns/00-atoms/00-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/source/_patterns/00-atoms/00-global/03-visibility.mustache b/source/_patterns/00-atoms/00-global/03-visibility.mustache deleted file mode 100644 index 13e602122..000000000 --- a/source/_patterns/00-atoms/00-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/source/_patterns/00-atoms/01-text/00-headings.mustache b/source/_patterns/00-atoms/01-text/00-headings.mustache deleted file mode 100644 index 43f648c7f..000000000 --- a/source/_patterns/00-atoms/01-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/source/_patterns/00-atoms/01-text/01-subheadings.mustache b/source/_patterns/00-atoms/01-text/01-subheadings.mustache deleted file mode 100644 index 367c09a82..000000000 --- a/source/_patterns/00-atoms/01-text/01-subheadings.mustache +++ /dev/null @@ -1,6 +0,0 @@ -

Subheading Level 1

-

Subheading Level 2

-

Subheading Level 3

-

Subheading Level 4

-
Subheading Level 5
-
Subheading Level 6
\ No newline at end of file diff --git a/source/_patterns/00-atoms/01-text/02-headings-with-links.mustache b/source/_patterns/00-atoms/01-text/02-headings-with-links.mustache deleted file mode 100644 index 9540d4c23..000000000 --- a/source/_patterns/00-atoms/01-text/02-headings-with-links.mustache +++ /dev/null @@ -1,6 +0,0 @@ -

Heading 1 with link

-

Heading 2 with link

-

Heading 3 with link

-

Heading 4 with link

-
Heading 5 with link
-
Heading 6 with link
\ No newline at end of file diff --git a/source/_patterns/00-atoms/01-text/03-paragraph.mustache b/source/_patterns/00-atoms/01-text/03-paragraph.mustache deleted file mode 100644 index 01534936d..000000000 --- a/source/_patterns/00-atoms/01-text/03-paragraph.mustache +++ /dev/null @@ -1 +0,0 @@ -

{{ description }}

\ No newline at end of file diff --git a/source/_patterns/00-atoms/01-text/04-blockquote.mustache b/source/_patterns/00-atoms/01-text/04-blockquote.mustache deleted file mode 100644 index 2f11319b3..000000000 --- a/source/_patterns/00-atoms/01-text/04-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/source/_patterns/00-atoms/01-text/05-inline-elements.mustache b/source/_patterns/00-atoms/01-text/05-inline-elements.mustache deleted file mode 100644 index dd4ff1f39..000000000 --- a/source/_patterns/00-atoms/01-text/05-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 variarble element, such as x = y

-
\ No newline at end of file diff --git a/source/_patterns/00-atoms/01-text/06-time.mustache b/source/_patterns/00-atoms/01-text/06-time.mustache deleted file mode 100644 index 26cecc136..000000000 --- a/source/_patterns/00-atoms/01-text/06-time.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/00-atoms/01-text/07-preformatted-text.mustache b/source/_patterns/00-atoms/01-text/07-preformatted-text.mustache deleted file mode 100644 index 70de25e11..000000000 --- a/source/_patterns/00-atoms/01-text/07-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/source/_patterns/00-atoms/01-text/08-emphasis-colors.mustache b/source/_patterns/00-atoms/01-text/08-emphasis-colors.mustache deleted file mode 100644 index b2fae06d2..000000000 --- a/source/_patterns/00-atoms/01-text/08-emphasis-colors.mustache +++ /dev/null @@ -1,4 +0,0 @@ -

This is what error text looks like

-

This is what valid text looks like

-

This is what warning text looks like

-

This is what information text looks like.

\ No newline at end of file diff --git a/source/_patterns/00-atoms/01-text/09-hr.mustache b/source/_patterns/00-atoms/01-text/09-hr.mustache deleted file mode 100644 index 1d6667d2e..000000000 --- a/source/_patterns/00-atoms/01-text/09-hr.mustache +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/source/_patterns/00-atoms/01-text/10-caption.mustache b/source/_patterns/00-atoms/01-text/10-caption.mustache deleted file mode 100644 index 204437d16..000000000 --- a/source/_patterns/00-atoms/01-text/10-caption.mustache +++ /dev/null @@ -1 +0,0 @@ -

A caption can be applied to an image, quote, form field, etc.

\ No newline at end of file diff --git a/source/_patterns/00-atoms/02-lists/00-unordered.mustache b/source/_patterns/00-atoms/02-lists/00-unordered.mustache deleted file mode 100644 index 3f9de349f..000000000 --- a/source/_patterns/00-atoms/02-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/source/_patterns/00-atoms/02-lists/01-ordered.mustache b/source/_patterns/00-atoms/02-lists/01-ordered.mustache deleted file mode 100644 index e206c7b10..000000000 --- a/source/_patterns/00-atoms/02-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/source/_patterns/00-atoms/02-lists/02-definition.mustache b/source/_patterns/00-atoms/02-lists/02-definition.mustache deleted file mode 100644 index 0488e0812..000000000 --- a/source/_patterns/00-atoms/02-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/source/_patterns/00-atoms/03-images/00-logo.mustache b/source/_patterns/00-atoms/03-images/00-logo.mustache deleted file mode 100644 index 013837c2e..000000000 --- a/source/_patterns/00-atoms/03-images/00-logo.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/00-atoms/03-images/01-landscape-4x3.mustache b/source/_patterns/00-atoms/03-images/01-landscape-4x3.mustache deleted file mode 100644 index cf874ee9d..000000000 --- a/source/_patterns/00-atoms/03-images/01-landscape-4x3.mustache +++ /dev/null @@ -1 +0,0 @@ -{{ img.landscape-4x3.alt }} \ No newline at end of file diff --git a/source/_patterns/00-atoms/03-images/02-landscape-16x9.mustache b/source/_patterns/00-atoms/03-images/02-landscape-16x9.mustache deleted file mode 100644 index 9efc5eeb3..000000000 --- a/source/_patterns/00-atoms/03-images/02-landscape-16x9.mustache +++ /dev/null @@ -1 +0,0 @@ -{{ img.landscape-16x9.alt }} \ No newline at end of file diff --git a/source/_patterns/00-atoms/03-images/03-square.mustache b/source/_patterns/00-atoms/03-images/03-square.mustache deleted file mode 100644 index 805cce5f2..000000000 --- a/source/_patterns/00-atoms/03-images/03-square.mustache +++ /dev/null @@ -1 +0,0 @@ -{{ img.square.alt }} \ No newline at end of file diff --git a/source/_patterns/00-atoms/03-images/04-avatar.mustache b/source/_patterns/00-atoms/03-images/04-avatar.mustache deleted file mode 100644 index 6b79ad0c5..000000000 --- a/source/_patterns/00-atoms/03-images/04-avatar.mustache +++ /dev/null @@ -1 +0,0 @@ -Avatar \ No newline at end of file diff --git a/source/_patterns/00-atoms/03-images/05-icons.mustache b/source/_patterns/00-atoms/03-images/05-icons.mustache deleted file mode 100644 index 4e2512348..000000000 --- a/source/_patterns/00-atoms/03-images/05-icons.mustache +++ /dev/null @@ -1,12 +0,0 @@ -
    -
  • -
  • -
  • -
  • -
  • -
  • -
  • -
  • - -
  • -
\ No newline at end of file diff --git a/source/_patterns/00-atoms/03-images/06-loading-icon.mustache b/source/_patterns/00-atoms/03-images/06-loading-icon.mustache deleted file mode 100644 index 9a10165ab..000000000 --- a/source/_patterns/00-atoms/03-images/06-loading-icon.mustache +++ /dev/null @@ -1 +0,0 @@ -Loading \ No newline at end of file diff --git a/source/_patterns/00-atoms/03-images/07-favicon.mustache b/source/_patterns/00-atoms/03-images/07-favicon.mustache deleted file mode 100644 index 07e985d37..000000000 --- a/source/_patterns/00-atoms/03-images/07-favicon.mustache +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/_patterns/00-atoms/04-forms/00-text-fields.mustache b/source/_patterns/00-atoms/04-forms/00-text-fields.mustache deleted file mode 100644 index 90cbb7747..000000000 --- a/source/_patterns/00-atoms/04-forms/00-text-fields.mustache +++ /dev/null @@ -1,38 +0,0 @@ -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
\ No newline at end of file diff --git a/source/_patterns/00-atoms/04-forms/01-select-menu.mustache b/source/_patterns/00-atoms/04-forms/01-select-menu.mustache deleted file mode 100644 index 760c9199a..000000000 --- a/source/_patterns/00-atoms/04-forms/01-select-menu.mustache +++ /dev/null @@ -1,12 +0,0 @@ -
-
- - -
-
\ No newline at end of file diff --git a/source/_patterns/00-atoms/04-forms/02-checkbox.mustache b/source/_patterns/00-atoms/04-forms/02-checkbox.mustache deleted file mode 100644 index 017a8dc5c..000000000 --- a/source/_patterns/00-atoms/04-forms/02-checkbox.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
- Checkbox * -
    -
  • -
  • -
  • -
-
-
\ No newline at end of file diff --git a/source/_patterns/00-atoms/04-forms/03-radio-buttons.mustache b/source/_patterns/00-atoms/04-forms/03-radio-buttons.mustache deleted file mode 100644 index 68c83eaeb..000000000 --- a/source/_patterns/00-atoms/04-forms/03-radio-buttons.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
- Radio -
    -
  • -
  • -
  • -
-
-
\ No newline at end of file diff --git a/source/_patterns/00-atoms/04-forms/04-html5-inputs.mustache b/source/_patterns/00-atoms/04-forms/04-html5-inputs.mustache deleted file mode 100644 index 99c22cce7..000000000 --- a/source/_patterns/00-atoms/04-forms/04-html5-inputs.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
-
-
-
-
-
-
-
-
\ No newline at end of file diff --git a/source/_patterns/00-atoms/05-buttons/00-buttons.mustache b/source/_patterns/00-atoms/05-buttons/00-buttons.mustache deleted file mode 100644 index bdbeec360..000000000 --- a/source/_patterns/00-atoms/05-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/source/_patterns/00-atoms/06-tables/00-table.mustache b/source/_patterns/00-atoms/06-tables/00-table.mustache deleted file mode 100644 index 7df555fe7..000000000 --- a/source/_patterns/00-atoms/06-tables/00-table.mustache +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table Heading 1Table Heading 2Table Heading 3Table Heading 3Table Heading 4
Table Footer 1Table Footer 2Table Footer 3Table Footer 3Table Footer 4
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/source/_patterns/00-atoms/07-media/_00-video.mustache b/source/_patterns/00-atoms/07-media/_00-video.mustache deleted file mode 100644 index f28fcd7fc..000000000 --- a/source/_patterns/00-atoms/07-media/_00-video.mustache +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/00-atoms/07-media/_01-audio.mustache b/source/_patterns/00-atoms/07-media/_01-audio.mustache deleted file mode 100644 index 91c82135e..000000000 --- a/source/_patterns/00-atoms/07-media/_01-audio.mustache +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/01-molecules/00-text/00-byline-author-only.mustache b/source/_patterns/01-molecules/00-text/00-byline-author-only.mustache deleted file mode 100644 index 08366cabe..000000000 --- a/source/_patterns/01-molecules/00-text/00-byline-author-only.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/01-molecules/00-text/01-byline-author-time.mustache b/source/_patterns/01-molecules/00-text/01-byline-author-time.mustache deleted file mode 100644 index 5d61bc716..000000000 --- a/source/_patterns/01-molecules/00-text/01-byline-author-time.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/01-molecules/00-text/02-address.mustache b/source/_patterns/01-molecules/00-text/02-address.mustache deleted file mode 100644 index a13ea79fc..000000000 --- a/source/_patterns/01-molecules/00-text/02-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/source/_patterns/01-molecules/00-text/03-heading-group.mustache b/source/_patterns/01-molecules/00-text/03-heading-group.mustache deleted file mode 100644 index bf18f5ac4..000000000 --- a/source/_patterns/01-molecules/00-text/03-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/source/_patterns/01-molecules/00-text/04-blockquote-with-citation.mustache b/source/_patterns/01-molecules/00-text/04-blockquote-with-citation.mustache deleted file mode 100644 index b9b6c98fc..000000000 --- a/source/_patterns/01-molecules/00-text/04-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/source/_patterns/01-molecules/00-text/05-intro-text.mustache b/source/_patterns/01-molecules/00-text/05-intro-text.mustache deleted file mode 100644 index b2b1bdef8..000000000 --- a/source/_patterns/01-molecules/00-text/05-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/source/_patterns/01-molecules/00-text/06-pullquote.mustache b/source/_patterns/01-molecules/00-text/06-pullquote.mustache deleted file mode 100644 index dba015d32..000000000 --- a/source/_patterns/01-molecules/00-text/06-pullquote.mustache +++ /dev/null @@ -1,3 +0,0 @@ -
-

A pull quote is a quotation or excerpt from an article

-
\ No newline at end of file diff --git a/source/_patterns/01-molecules/01-layout/00-one-up.mustache b/source/_patterns/01-molecules/01-layout/00-one-up.mustache deleted file mode 100644 index eb58a0e24..000000000 --- a/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/source/_patterns/01-molecules/01-layout/01-two-up.mustache b/source/_patterns/01-molecules/01-layout/01-two-up.mustache deleted file mode 100644 index ff1553aee..000000000 --- a/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/source/_patterns/01-molecules/01-layout/02-three-up.mustache b/source/_patterns/01-molecules/01-layout/02-three-up.mustache deleted file mode 100644 index d68fb4854..000000000 --- a/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/source/_patterns/01-molecules/01-layout/03-four-up.mustache b/source/_patterns/01-molecules/01-layout/03-four-up.mustache deleted file mode 100644 index f7351c023..000000000 --- a/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/source/_patterns/01-molecules/02-blocks/00-media-block.mustache b/source/_patterns/01-molecules/02-blocks/00-media-block.mustache deleted file mode 100644 index a82a8ed50..000000000 --- a/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/source/_patterns/01-molecules/02-blocks/01-headline-byline.mustache b/source/_patterns/01-molecules/02-blocks/01-headline-byline.mustache deleted file mode 100644 index e6416f8a2..000000000 --- a/source/_patterns/01-molecules/02-blocks/01-headline-byline.mustache +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/01-molecules/02-blocks/02-block-hero.mustache b/source/_patterns/01-molecules/02-blocks/02-block-hero.mustache deleted file mode 100644 index c685176f8..000000000 --- a/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/source/_patterns/01-molecules/02-blocks/03-block-thumb-headline.mustache b/source/_patterns/01-molecules/02-blocks/03-block-thumb-headline.mustache deleted file mode 100644 index 9e13fb90d..000000000 --- a/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/source/_patterns/01-molecules/02-blocks/04-headline-only.mustache b/source/_patterns/01-molecules/02-blocks/04-headline-only.mustache deleted file mode 100644 index 5c0daded8..000000000 --- a/source/_patterns/01-molecules/02-blocks/04-headline-only.mustache +++ /dev/null @@ -1,5 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/01-molecules/02-blocks/05-inset-block.mustache b/source/_patterns/01-molecules/02-blocks/05-inset-block.mustache deleted file mode 100644 index e850e479d..000000000 --- a/source/_patterns/01-molecules/02-blocks/05-inset-block.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/01-molecules/03-media/00-figure-with-caption.mustache b/source/_patterns/01-molecules/03-media/00-figure-with-caption.mustache deleted file mode 100644 index 98e2b4435..000000000 --- a/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/source/_patterns/01-molecules/03-media/_map.mustache b/source/_patterns/01-molecules/03-media/_map.mustache deleted file mode 100644 index 9acb52b23..000000000 --- a/source/_patterns/01-molecules/03-media/_map.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/01-molecules/04-forms/00-search.mustache b/source/_patterns/01-molecules/04-forms/00-search.mustache deleted file mode 100644 index aa276315f..000000000 --- a/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/source/_patterns/01-molecules/04-forms/01-comment-form.mustache b/source/_patterns/01-molecules/04-forms/01-comment-form.mustache deleted file mode 100644 index 43d6cb368..000000000 --- a/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/source/_patterns/01-molecules/04-forms/02-newsletter.mustache b/source/_patterns/01-molecules/04-forms/02-newsletter.mustache deleted file mode 100644 index e23b2d5ae..000000000 --- a/source/_patterns/01-molecules/04-forms/02-newsletter.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/01-molecules/05-navigation/00-primary-nav.mustache b/source/_patterns/01-molecules/05-navigation/00-primary-nav.mustache deleted file mode 100644 index 09c70e8ca..000000000 --- a/source/_patterns/01-molecules/05-navigation/00-primary-nav.mustache +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/source/_patterns/01-molecules/05-navigation/01-footer-nav.mustache b/source/_patterns/01-molecules/05-navigation/01-footer-nav.mustache deleted file mode 100644 index 41d5f87f8..000000000 --- a/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/source/_patterns/01-molecules/05-navigation/02-breadcrumbs.mustache b/source/_patterns/01-molecules/05-navigation/02-breadcrumbs.mustache deleted file mode 100644 index 7d2eb525b..000000000 --- a/source/_patterns/01-molecules/05-navigation/02-breadcrumbs.mustache +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/source/_patterns/01-molecules/05-navigation/03-pagination.mustache b/source/_patterns/01-molecules/05-navigation/03-pagination.mustache deleted file mode 100644 index b23a01ab1..000000000 --- a/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/source/_patterns/01-molecules/05-navigation/04-tabs.mustache b/source/_patterns/01-molecules/05-navigation/04-tabs.mustache deleted file mode 100644 index 341817d40..000000000 --- a/source/_patterns/01-molecules/05-navigation/04-tabs.mustache +++ /dev/null @@ -1,7 +0,0 @@ -
- -
\ No newline at end of file diff --git a/source/_patterns/01-molecules/06-components/00-social-share.mustache b/source/_patterns/01-molecules/06-components/00-social-share.mustache deleted file mode 100644 index 71694aed1..000000000 --- a/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/source/_patterns/01-molecules/06-components/01-accordion.mustache b/source/_patterns/01-molecules/06-components/01-accordion.mustache deleted file mode 100644 index 253962dcb..000000000 --- a/source/_patterns/01-molecules/06-components/01-accordion.mustache +++ /dev/null @@ -1,19 +0,0 @@ -
- -
\ No newline at end of file diff --git a/source/_patterns/01-molecules/06-components/02-single-comment.mustache b/source/_patterns/01-molecules/06-components/02-single-comment.mustache deleted file mode 100644 index a7f56279a..000000000 --- a/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/source/_patterns/02-organisms/00-global/00-header.mustache b/source/_patterns/02-organisms/00-global/00-header.mustache deleted file mode 100644 index e4a73fb88..000000000 --- a/source/_patterns/02-organisms/00-global/00-header.mustache +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/source/_patterns/02-organisms/00-global/01-footer.mustache b/source/_patterns/02-organisms/00-global/01-footer.mustache deleted file mode 100644 index 63f6fa5ef..000000000 --- a/source/_patterns/02-organisms/00-global/01-footer.mustache +++ /dev/null @@ -1,7 +0,0 @@ - -
    -
    - -
    -
    - \ No newline at end of file diff --git a/source/_patterns/02-organisms/01-article/00-article-body.mustache b/source/_patterns/02-organisms/01-article/00-article-body.mustache deleted file mode 100644 index 7e95f0494..000000000 --- a/source/_patterns/02-organisms/01-article/00-article-body.mustache +++ /dev/null @@ -1,26 +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. -

    - -{{> molecules-pullquote }} - -

    Donec venenatis imperdiet tortor, vitae blandit odio interdum ut. Integer orci metus, lobortis id lacinia eget, rutrum vitae justo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In pretium fermentum justo nec pharetra. Maecenas eget dapibus justo. Ut quis est risus. Nullam et eros at odio commodo venenatis quis et augue. Sed sed augue at tortor porttitor hendrerit nec ut nibh. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Proin sollicitudin enim consectetur mi commodo quis cursus ante pretium. Nunc gravida cursus nisi in gravida. Suspendisse eget tortor sed urna consequat tincidunt. Etiam eget convallis lectus. Suspendisse cursus rutrum massa ac faucibus. -

    -

    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/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache b/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache deleted file mode 100644 index 6e150a137..000000000 --- a/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/source/_patterns/02-organisms/03-components/00-carousel.mustache b/source/_patterns/02-organisms/03-components/00-carousel.mustache deleted file mode 100644 index 4e8641ec8..000000000 --- a/source/_patterns/02-organisms/03-components/00-carousel.mustache +++ /dev/null @@ -1,10 +0,0 @@ -