├── .gitignore ├── .pk-config.yml ├── CHANGELOG-1.x.md ├── README.md ├── SERVICES.md ├── composer.json ├── index.php ├── resources ├── fixtures │ ├── cat.jpg │ ├── company-colors.sg.md │ ├── foo.docs.yaml │ ├── foo2.docs.json │ ├── get-started.sg.md │ ├── image.docs.yaml │ ├── image.json │ ├── image.twig │ ├── index.sg.md │ ├── test.docs.md │ ├── test.docs.yaml │ ├── test.json │ └── test.twig └── templates │ ├── _pattern-kit-app.twig │ ├── basic-html.twig │ ├── basic.twig │ ├── csscomponent.twig │ ├── display-just-schema-editor.twig │ ├── display-schema.twig │ ├── display-sg.twig │ ├── docs.twig │ ├── editor-accordion.twig │ ├── editor-tabs.twig │ ├── iframe-holder.twig │ ├── jsonrender.twig │ ├── navigation.twig │ ├── secondary-nav.twig │ └── webcomponent.twig ├── src ├── PatternKit │ ├── ApiControllerProvider.php │ ├── Controllers │ │ └── SchemaController.php │ ├── Factory │ │ └── PatternFactory.php │ ├── Model │ │ └── PatternModel.php │ ├── RoutesLoader.php │ ├── SchemaControllerProvider.php │ ├── StyleGuideControllerProvider.php │ └── TestsControllerProvider.php └── app.php ├── storage ├── cache │ └── .gitkeep └── logs │ └── .gitkeep └── web ├── css └── json-editor.css ├── img └── icon-drag.svg └── js ├── json-editor.js ├── lzstring.js └── schema_editor.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | storage/logs/*.log 4 | composer.lock 5 | vendor 6 | -------------------------------------------------------------------------------- /.pk-config.yml: -------------------------------------------------------------------------------- 1 | title: Pattern Kit 2 | 3 | paths: 4 | data: 5 | - /resources/fixtures 6 | test_data: 7 | - /resources/fixtures 8 | schemas: 9 | - /resources/fixtures 10 | templates: 11 | - /resources/fixtures 12 | docs: 13 | - /resources/fixtures 14 | sg: 15 | - /resources/fixtures 16 | extensions: 17 | data: .docs.json 18 | test_data: .test.json 19 | schemas: .json 20 | templates: .twig 21 | docs: .docs.md 22 | sg: .sg.md 23 | categories: 24 | - Page 25 | - Pattern 26 | - Subpattern 27 | - Layout 28 | - Component 29 | - Atom 30 | body_attr: 31 | assets: 32 | css: 33 | js: 34 | footer_js: 35 | dev: true 36 | 37 | -------------------------------------------------------------------------------- /CHANGELOG-1.x.md: -------------------------------------------------------------------------------- 1 | ## 1.6 Update WYSIWYG editor version 2 | Tag: [1.6](https://github.com/PatternBuilder/pattern-kit/releases/tag/V1.6) 3 | 4 | - Updated sceditor to version 3.1.1 5 | 6 | ## 1.5 Additional config features 7 | Tag: [1.5](https://github.com/PatternBuilder/pattern-kit/releases/tag/V1.5) 8 | 9 | - Add support for body attributes in the config 10 | - Update documentation 11 | - Update styles for squishy-window indicators for usability 12 | 13 | ## 1.4 Code refactor and changes to allow assets to track with the module. 14 | Tag: [1.4](https://github.com/PatternBuilder/pattern-kit/releases/tag/V1.4) 15 | 16 | Refactor of pattern kit, additions to component renderer 17 | - Factored methods out of large controllers. 18 | - Removed redundant code 19 | - Added a pattern model class to abstract the patterns a bit. 20 | - Modified the way webcomponent renderer works. 21 | - Added style component server. 22 | - Changed from lzstring to pako for more portability across platforms (lzstring sucks at reproducibility cross-platform) 23 | - Add support for csscomponent, web component, page and html render endpoints 24 | - Refactor the route controller to make it easier to read. 25 | 26 | ## 1.3 Documentation style updates 27 | Tag: [1.3](https://github.com/PatternBuilder/pattern-kit/releases/tag/V1.3) 28 | 29 | - Add font family, colors, spacing, etc. to styleguide. Cleaned up some extra scrollbars, set a max width on the content area of the docs area. 30 | 31 | ## 1.2 Minor style tweaks and functionality additions (2017-03-09) 32 | 33 | Tag: [1.2](https://github.com/PatternBuilder/pattern-kit/releases/tag/V1.2) 34 | 35 | - Change rendering of the styleguide documentation to lean on bootstrap column grid 36 | - Add logic to render only the tabs that work for a particular atom based on what data is present 37 | - Add alert messaging for atoms in the preview area to flag that it will not render 38 | - Reduce and organize CSS with section comments for clarity 39 | - Add color to the nesting of the schema editor 40 | - Increase size of buttons for better accessibility for those of us with poor vision :D 41 | - Add ability to designate order on documentation in the markdown and render the secondary nav in that order 42 | - Update jQuery package to reference CDN for consistency 43 | 44 | 45 | ## 1.0 support-at-data-and-yaml (2016-08-01) 46 | 47 | Tag: [1.0](https://github.com/PatternBuilder/pattern-kit/tree/V1.1) 48 | 49 | Now supporting YAML files for docs using the same basename as JSON. Also supporting @data to reference other component's doc data file. So @component would import component.docs.json or component.docs.yaml into your data file. 50 | 51 | 52 | ## 1.0 Initial Release (2016-06-13) 53 | 54 | Tag: [1.0](https://github.com/PatternBuilder/pattern-kit/tree/V1.0) 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pattern Kit 2 | 3 | Pattern Kit is an application that lets you preview your library of templates and manipulate their content by interacting with a form built from the schemas. It is both a development tool and a public-facing pattern library. 4 | 5 | For a demo check out [Pattern Kit Demo](https://webrh-patternkit.int.open.paas.redhat.com/). 6 | 7 | # Installation 8 | 9 | Note, by following these instructions you do _not_ need to clone this git repository. 10 | 11 | ## Create composer.json at pattern library root and require pattern kit 12 | 13 | ``` 14 | "require": { 15 | "pattern-builder/pattern-kit": "@dev" 16 | }, 17 | "repositories": [ 18 | { 19 | "type": "vcs", 20 | "url": "https://github.com/PatternBuilder/pattern-kit" 21 | } 22 | ] 23 | ``` 24 | 25 | ## Add index.php at pattern library root 26 | ``` 27 | run(); 33 | 34 | ``` 35 | 36 | ## Add .pk-config.yml at pattern library root 37 | 38 | - Create arrays of paths to your data, schema, template, docs and styleguide files (relative to config) 39 | - Set the file extensions for each file type 40 | - List categories in order you'd like them to appear in navigation 41 | - Add any attributes you want printed on the body tag using `body_attr` 42 | - Create arrays of assets for css, js and footer js (including live reload if necessary) 43 | 44 | ``` 45 | title: Project Title 46 | 47 | paths: # relative to your pattern library root 48 | data: 49 | - path/to/sample/data 50 | schemas: 51 | - path/to/schemas 52 | templates: 53 | - path/to/templates 54 | docs: 55 | - path/to/schemas-docs 56 | sg: 57 | - path/to/stylelguide/docs 58 | extensions: 59 | data: .docs.json 60 | schemas: .json 61 | templates: .twig 62 | docs: .docs.md 63 | sg: .sg.md 64 | categories: 65 | - Pattern 66 | - Sub Pattern 67 | - Layout 68 | - Component 69 | - Atom 70 | body_attr: 71 | - unresolved 72 | - class: 73 | - foo 74 | - bar 75 | assets: 76 | css: 77 | - path/to/css 78 | - path/to/othercss 79 | js: 80 | - path/to/js 81 | - path/to/otherjs 82 | footer_js: 83 | - path/to/footer_js 84 | - path/to/otherfooter_js 85 | - //localhost:1336/livereload.js 86 | ``` 87 | 88 | In your terminal, 89 | 90 | ``` 91 | $ cd [pattern library root] 92 | $ composer install 93 | ``` 94 | 95 | # Use Pattern Kit 96 | 97 | Point MAMP or local PHP server at your `index.php` file 98 | 99 | `php -S 0:9001 -t ./` 100 | -------------------------------------------------------------------------------- /SERVICES.md: -------------------------------------------------------------------------------- 1 | # Patternkit REST API 2 | 3 | ``` 4 | /api/patterns 5 | ``` 6 | 7 | Simple GET request will return a full list of patterns. 8 | 9 | example subset of return below: 10 | ``` 11 | { 12 | "band": { 13 | "category": "layout", 14 | "title": "Band", 15 | "version": "1.0" 16 | }, 17 | "band_group": { 18 | "category": "layout", 19 | "title": "Band Group", 20 | "version": "1.0" 21 | }, 22 | ... 23 | } 24 | ``` 25 | 26 | ``` 27 | /api/render/* 28 | ``` 29 | All queries under this path can accept GET or POST, and may optionally specify a pattern at the end of the url to use default values for all parameters. 30 | 31 | When using GET, you can use either of the following parameters to specify values 32 | * jsondata - a urlified json object. Simple to read and edit dynamically. 33 | * data - A base64 encoded, gzdeflated json object. Obfuscated, and smaller in size. 34 | 35 | When using POST, you must use JSON. 36 | 37 | The JSON object will resemble the following, and only the name property is required. 38 | 39 | ``` 40 | { 41 | "name": "link", 42 | "asset_host_prefix": "Something something, rabbits.", 43 | "arbitrary_property1": "It's a sailboat!", 44 | "arbitrary_property2": "The missing link was an href all along", 45 | "arbitrary_property3": 34982347918271923 46 | } 47 | ``` 48 | 49 | * name - the machine name of the pattern as returned from /api/patterns 50 | * asset_host_prefix - A prefix to add to all asset urls should you want them to be served from a different host. (they are normally served from patternkit otherwise) You may provide an empty string. 51 | 52 | 53 | ``` 54 | /api/render/json 55 | ``` 56 | Uses jsonrender.twig (to render the body property) 57 | 58 | Note that this endpoint provides a wealth of metadata about the pattern. 59 | 60 | ``` 61 | /api/render/page 62 | ``` 63 | Uses basic.twig and renders a full page, suitable for use in an iframe. 64 | 65 | ``` 66 | /api/render/html 67 | ``` 68 | 69 | Uses basic-html.twig, renders only the fragment of interest. Useful for wrapping with angular, react, etc. 70 | 71 | ``` 72 | /api/render/webcomponent 73 | ``` 74 | 75 | Uses webcomponent.twig to deliver an import rel style web component. 76 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pattern-builder/pattern-kit", 3 | "authors": [ 4 | { 5 | "name": "Micah Godbolt", 6 | "email": "micahgodbolt@gmail.com" 7 | }, 8 | { 9 | "name": "castastrophe", 10 | "homepage": "https://www.castastrophe.com", 11 | "role": "Front-end developer" 12 | } 13 | ], 14 | "license": "MIT", 15 | "require": { 16 | "php": ">=7.2", 17 | "deralex/yaml-config-service-provider": "1.0.x-dev", 18 | "erusev/parsedown": "^1.6", 19 | "justinrainbow/json-schema": "~1.4", 20 | "mnapoli/front-yaml": "^1.5", 21 | "monolog/monolog": "~1.6", 22 | "nesbot/carbon": "~1.6", 23 | "psr/log": "^1.0", 24 | "silex/silex": "1.2.5", 25 | "symfony/twig-bridge": "^2.3", 26 | "symfony/yaml": "^2.6", 27 | "twig/twig": "^1.38" 28 | }, 29 | "require-dev": { 30 | "squizlabs/php_codesniffer": "3.*", 31 | "kherge/box": "2.*", 32 | "phpunit/phpunit": "9.*" 33 | }, 34 | "autoload": { 35 | "psr-0": { 36 | "PatternKit\\": "src" 37 | } 38 | }, 39 | "config": { 40 | "sort-packages": true 41 | }, 42 | "scripts": { 43 | "phar": "box build .", 44 | "cs": "phpcs --standard=PSR2 -n src", 45 | "cbf": "phpcbf --standard=PSR2 -n src", 46 | "unit": "phpunit --colors=always < /dev/tty", 47 | "test": [ 48 | "@unit", 49 | "@cs" 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | run(); 7 | -------------------------------------------------------------------------------- /resources/fixtures/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatternBuilder/pattern-kit/4650aeaca9afd01115e117c1b7b0344bcbee3f3f/resources/fixtures/cat.jpg -------------------------------------------------------------------------------- /resources/fixtures/company-colors.sg.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Brand Colors 3 | --- 4 | 5 | `$brand-primary` 6 |
`#c00` 7 |
8 | -------------------------------------------------------------------------------- /resources/fixtures/foo.docs.yaml: -------------------------------------------------------------------------------- 1 | bar: abc 2 | baz: def 3 | -------------------------------------------------------------------------------- /resources/fixtures/foo2.docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "bar": "123", 3 | "baz": "456" 4 | } 5 | -------------------------------------------------------------------------------- /resources/fixtures/get-started.sg.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: How to get set up 3 | --- 4 | 5 | This is how to get set up 6 | -------------------------------------------------------------------------------- /resources/fixtures/image.docs.yaml: -------------------------------------------------------------------------------- 1 | src: /resources/fixtures/cat.jpg 2 | alt: This is a photo 3 | -------------------------------------------------------------------------------- /resources/fixtures/image.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Image", 4 | "category": "atom", 5 | "type": "object", 6 | "format": "grid", 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "default": "image", 11 | "options": { 12 | "hidden": true 13 | } 14 | }, 15 | "src": { 16 | "type": "string" 17 | }, 18 | "alt": { 19 | "type": "string" 20 | } 21 | }, 22 | "required": ["name"], 23 | "additionalProperties": false 24 | } 25 | -------------------------------------------------------------------------------- /resources/fixtures/image.twig: -------------------------------------------------------------------------------- 1 | {{alt}} 2 | -------------------------------------------------------------------------------- /resources/fixtures/index.sg.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Get Started 3 | --- 4 | 5 | This is the getting started Docs 6 | -------------------------------------------------------------------------------- /resources/fixtures/test.docs.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | ## Docs 5 | hello there 6 | -------------------------------------------------------------------------------- /resources/fixtures/test.docs.yaml: -------------------------------------------------------------------------------- 1 | name: test 2 | quotation: We think of Red Hat as one of just a handful of superior engineering and support organizations in the United States. 3 | attribution_name: John Defeo 4 | attribution_title: President of Infrastructure, CIGNA 5 | image: @image 6 | foo: 7 | - @foo 8 | - @foo2 9 | 10 | -------------------------------------------------------------------------------- /resources/fixtures/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Quote", 4 | "category": "component", 5 | "type": "object", 6 | "format": "grid", 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "default": "test", 11 | "options": { 12 | "hidden": true 13 | } 14 | }, 15 | "quotation": { 16 | "title": "Quote Text", 17 | "type": "string", 18 | "format": "textarea" 19 | }, 20 | "attribution_name": { 21 | "title": "Attribution", 22 | "description": "Who said it?", 23 | "type": "string" 24 | }, 25 | "attribution_title": { 26 | "title": "Attribution Title", 27 | "description": "What is their job title?", 28 | "type": "string" 29 | }, 30 | "image": { 31 | "$ref": "image.json" 32 | }, 33 | "foo": { 34 | "type": "array", 35 | "items": { 36 | "type": "object", 37 | "properties": { 38 | "bar": { 39 | "type": "string" 40 | }, 41 | "baz": { 42 | "type": "string" 43 | } 44 | } 45 | } 46 | } 47 | }, 48 | "required": ["name", "quotation", "attribution_name"], 49 | "additionalProperties": false 50 | } 51 | -------------------------------------------------------------------------------- /resources/fixtures/test.twig: -------------------------------------------------------------------------------- 1 |
2 | {% include 'image.twig' with image only %} 3 |
4 |

{{quotation}}

5 | 8 |
9 |
10 | 11 | 12 | {% for item in foo %} 13 | {{item.bar}}
14 | {{item.baz}}

15 | {% endfor %} 16 | -------------------------------------------------------------------------------- /resources/templates/_pattern-kit-app.twig: -------------------------------------------------------------------------------- 1 | {% if app_config.dev == true %} 2 | {% set vendor_path = "/" %} 3 | {% else %} 4 | {% set vendor_path = "/vendor/pattern-builder/pattern-kit/" %} 5 | {% endif %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | {% block navigation %} 33 | {% endblock %} 34 | 35 |
36 |
37 | {% if block( 'secondary_nav' ) %} 38 | 41 | {% endif %} 42 | 43 | {% if block( 'left' ) %} 44 |
45 | {% block left %}{% endblock %} 46 |
47 | {% endif %} 48 | 49 | {% if block( 'right' ) %} 50 |
51 | {% block right %}{% endblock %} 52 |
53 | {% endif %} 54 | 55 |
56 |
57 | 58 | {% block footer %}{% endblock %} 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /resources/templates/basic-html.twig: -------------------------------------------------------------------------------- 1 |
2 | {% if (name) or (template) %} 3 | {% include template ?: name ~ '.twig' %} 4 | {% else %} 5 |

Data does not include required "name" property

6 | {% endif %} 7 |
8 | -------------------------------------------------------------------------------- /resources/templates/basic.twig: -------------------------------------------------------------------------------- 1 | {% set body_props %} 2 | {%- if app_config.body_attr -%} 3 | {% for attr in app_config.body_attr -%} 4 | {% if attr is iterable -%} 5 | {% for key in attr|keys %} 6 | {% if attr[key] is iterable -%} 7 | {% set items %} 8 | {% for item in attr[key] %} {{ item }}{% endfor %} 9 | {% endset %} 10 | {% elseif attr[key] is same as(false) or attr[key] is same as(true) %} 11 | {% set items = attr[key] ? "true" : "false" %} 12 | {% else %}{% set items = attr[key]|trim %}{% endif %} 13 | {{ key }}="{{ items|trim }}" 14 | {% endfor %} 15 | {% else %} {{ attr }}{% endif %} 16 | {%- endfor %} 17 | {% endif -%} 18 | {% endset -%} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {% for css in app_config.assets.css %} 27 | 28 | {% endfor %} 29 | 30 | {% for js in app_config.assets.js %} 31 | 32 | {% endfor %} 33 | 34 | 35 |
36 | {% if (name) or (template) %} 37 | {% include template ?: name ~ '.twig' %} 38 | {% else %} 39 |

Data does not include required "name" property

40 | {% endif %} 41 |
42 | {% for js in app_config.assets.footer_js %} 43 | 44 | {% endfor %} 45 | 46 | 47 | -------------------------------------------------------------------------------- /resources/templates/csscomponent.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /resources/templates/display-just-schema-editor.twig: -------------------------------------------------------------------------------- 1 | {% extends '_pattern-kit-app.twig' %} 2 | 3 | {% block left %} 4 | {% include 'iframe-holder.twig' %} 5 | {% endblock %} 6 | 7 | 8 | {% block right %} 9 | 10 | {% set json_data %} 11 |
12 |

Data

13 |
14 |

15 |         
16 | {% endset %} 17 | 18 | {% set twig_template %} 19 |
{{ template_markup }}
20 | {% endset %} 21 | 22 | {% set docs %} 23 | {% include 'docs.twig' with { 24 | "meta": docs_yaml, 25 | "content": docs_content, 26 | "data": docs_json 27 | } only %} 28 | {% endset %} 29 | 30 |
31 | 32 |
33 |
34 |
35 |
36 | 37 | 40 | 41 | {% endblock %} 42 | 43 | {% block footer %} 44 | 76 | {% endblock %} 77 | -------------------------------------------------------------------------------- /resources/templates/display-schema.twig: -------------------------------------------------------------------------------- 1 | {% extends '_pattern-kit-app.twig' %} 2 | 3 | {% block navigation %} 4 | {% include 'navigation.twig' with nav only %} 5 | {% endblock %} 6 | 7 | {% block left %} 8 | {% include 'iframe-holder.twig' %} 9 | {% endblock %} 10 | 11 | {% block right %} 12 | {% set json_data %} 13 |
14 |

Data

15 |
16 |

17 |         
18 | {% endset %} 19 | 20 | {% set twig_template %} 21 |
{{ template_markup }}
22 | {% endset %} 23 | 24 | {% set docs %} 25 | {% include 'docs.twig' with { 26 | "meta": docs_yaml, 27 | "content": docs_content, 28 | "data": docs_json 29 | } only %} 30 | {% endset %} 31 | 32 | {% set tabs_data = {} %} 33 | {% if raw_schema.category == "atom" %} 34 | {% if template_markup %} 35 | {% set twig = { 36 | 'title': 'Twig template', 37 | 'content': twig_template, 38 | 'active': false 39 | } %} 40 | {% endif %} 41 | {% if json_data %} 42 | {% set json = { 43 | 'title': 'JSON data', 44 | 'content': json_data, 45 | 'active': false 46 | } %} 47 | {% endif %} 48 | {% set tabs_data = { 49 | 'tabs': [{ 50 | 'title': 'Docs', 51 | 'content': docs, 52 | 'active': true 53 | }, { 54 | 'title': 'Editor', 55 | 'content': '
', 56 | 'active': false 57 | }] | merge([ twig ]) | merge([ json_data ]) 58 | } %} 59 | {% else %} 60 | {% set tabs_data = { 61 | 'tabs': [{ 62 | 'title': 'Docs', 63 | 'content': docs, 64 | 'active': true 65 | },{ 66 | 'title': 'Editor', 67 | 'content': '
', 68 | 'active': false 69 | },{ 70 | 'title': 'JSON data', 71 | 'content': json_data, 72 | 'active': false 73 | },{ 74 | 'title': 'Twig template', 75 | 'content': twig_template, 76 | 'active': false 77 | }] 78 | } %} 79 | {% endif %} 80 | 81 | {% include 'editor-tabs.twig' with tabs_data %} 82 | 83 | 87 | {% endblock %} 88 | 89 | {% block footer %} 90 | 95 | {% endblock %} 96 | -------------------------------------------------------------------------------- /resources/templates/display-sg.twig: -------------------------------------------------------------------------------- 1 | {% extends '_pattern-kit-app.twig' %} 2 | 3 | 4 | {% block navigation %} 5 | {% include 'navigation.twig' with nav only %} 6 | {% endblock %} 7 | 8 | {% block secondary_nav %} 9 | {% include 'secondary-nav.twig' %} 10 | {% endblock %} 11 | 12 | {% block left %} 13 |
14 |

{{sg_yaml.title}}

15 | 16 | {{sg_content|raw}} 17 |
18 | {% endblock %} 19 | 20 | 21 | {% block footer %} 22 | 23 | {% endblock %} 24 | -------------------------------------------------------------------------------- /resources/templates/docs.twig: -------------------------------------------------------------------------------- 1 |
{{ content|raw }}
2 | -------------------------------------------------------------------------------- /resources/templates/editor-accordion.twig: -------------------------------------------------------------------------------- 1 |
2 | {% for tab in tabs %} 3 |
4 | 11 |
12 |
13 | {{tab.content|raw}} 14 |
15 |
16 |
17 | {% endfor %} 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /resources/templates/editor-tabs.twig: -------------------------------------------------------------------------------- 1 |
2 | 3 | 8 | 9 | 10 |
11 | {% for tab in tabs %} 12 |
13 | {{ tab.content|raw }} 14 |
15 | {% endfor %} 16 |
17 |
18 | -------------------------------------------------------------------------------- /resources/templates/iframe-holder.twig: -------------------------------------------------------------------------------- 1 |
2 | 6 |
7 | {% if raw_schema.category != "atom" %} 8 |
9 |
10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 | {% else %} 18 |
19 |

Atoms do not contain styles or often markup and thus cannot be previewed in this space.

20 |
21 | {% endif %} 22 | -------------------------------------------------------------------------------- /resources/templates/jsonrender.twig: -------------------------------------------------------------------------------- 1 |
2 | {% include template ?: name ~ '.twig' %} 3 |
4 | -------------------------------------------------------------------------------- /resources/templates/navigation.twig: -------------------------------------------------------------------------------- 1 | 37 | -------------------------------------------------------------------------------- /resources/templates/secondary-nav.twig: -------------------------------------------------------------------------------- 1 | 32 | -------------------------------------------------------------------------------- /resources/templates/webcomponent.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% set moduleName = (name ~ '-pattern') %} 4 | {% set camelCased = moduleName | title | replace({' ': '', '-': ''}) %} 5 | 6 | {% for css in app_config.assets.custom.css.shared %} 7 | 8 | {% endfor %} 9 | 10 | 11 | 26 | 27 | 88 | -------------------------------------------------------------------------------- /src/PatternKit/ApiControllerProvider.php: -------------------------------------------------------------------------------- 1 | post( 36 | '/render/{target}', 37 | function (Request $request, $target) use ($app) { 38 | return $this->render_pattern($app, $request, $target); 39 | } 40 | ) 41 | ->assert('target', ".*") 42 | ->method('GET|POST'); 43 | 44 | // Render callback. 45 | $controllers->get( 46 | '/serve/csscomponent/{pattern_name}/{style_name}', 47 | function (Request $request, $pattern_name, $style_name) use ($app) { 48 | return $this->render_csscomponent( 49 | $app, 50 | $request, 51 | $pattern_name, 52 | $style_name 53 | ); 54 | } 55 | )->method('GET|POST'); 56 | 57 | // JSON validation endpoint. 58 | $controllers->post( 59 | '/validate', 60 | function (Request $request) use ($app) { 61 | if (0 === strpos( 62 | $request->headers->get('Content-Type'), 63 | 'application/json' 64 | ) 65 | ) { 66 | 67 | /** 68 | * @param $data 69 | * @param $to_test 70 | * @param int $i 71 | * @param string $path 72 | */ 73 | function traverse($data, &$to_test, $i = 0, $path = "root") 74 | { 75 | foreach ($data as $array_name => &$value) { 76 | if (is_array($value)) { 77 | foreach ($value as $key => $item) { 78 | if (is_object($item)) { 79 | if ($item->name) { 80 | $location = $path.".".$array_name.".".$key; 81 | $to_test[] = [ 82 | "depth" => $i, 83 | "obj" => $item, 84 | "path" => $location, 85 | ]; 86 | } 87 | traverse( 88 | $item, 89 | $to_test, 90 | $i + 1, 91 | $location 92 | ); 93 | } 94 | } 95 | } 96 | } 97 | usort( 98 | $to_test, 99 | function ($a, $b) { 100 | return $b['depth'] - $a['depth']; 101 | } 102 | ); 103 | } 104 | 105 | /** 106 | * Validate JSON schema against the indicated schema. 107 | * 108 | * @param array $data 109 | * Array of items to validate. 110 | * @param string $reply 111 | * HTML ready string containing the list of errors or success. 112 | */ 113 | function test($data, &$reply) 114 | { 115 | $retriever = new \JsonSchema\Uri\UriRetriever; 116 | $refResolver = new \JsonSchema\RefResolver( 117 | $retriever 118 | ); 119 | $refResolver::$maxDepth = 9999; 120 | $validator = new \JsonSchema\Validator(); 121 | 122 | foreach ($data as $item) { 123 | $patternObj = new PatternModel($item['obj']->name); 124 | $schema = $patternObj->getSchema(); 125 | 126 | //Validate 127 | $validator->check($item['obj'], $schema); 128 | 129 | if (!$validator->isValid()) { 130 | foreach ($validator->getErrors() as $error) { 131 | $path = $item['path']; 132 | $name = $item['obj']->name; 133 | $property = $error['property']; 134 | $message = $error['message']; 135 | $reply .= sprintf( 136 | "Error at %s:
%s [%s] %s\n

", 137 | $path, 138 | $name, 139 | $property, 140 | $message 141 | ); 142 | } 143 | break; 144 | } 145 | } 146 | } 147 | 148 | // Parse the data coming from the POST. 149 | $data = (object)json_decode($request->getContent()); 150 | 151 | if (empty($data->name)) { 152 | $reply['status'] = 'FAILED'; 153 | $reply['message'] = "The supplied JSON failed to validate."; 154 | 155 | return json_encode($reply); 156 | } 157 | 158 | $patternObj = PatternFactory::getPattern($data->name); 159 | 160 | $to_test = []; 161 | $reply = []; 162 | $validator = new \JsonSchema\Validator(); 163 | 164 | 165 | // Load the schema for this element. 166 | $schema = $patternObj->getSchema(); 167 | 168 | //Validate 169 | $validator->check($data, $schema); 170 | 171 | if ($validator->isValid()) { 172 | $reply['status'] = 'OK'; 173 | $reply['message'] = "The supplied JSON validates against the schema.\n"; 174 | $reply['gzconfig'] = base64_encode( 175 | gzcompress(json_encode($data)) 176 | ); 177 | } else { 178 | $to_test[] = [ 179 | "depth" => 0, 180 | "obj" => $data, 181 | "path" => "root", 182 | ]; 183 | traverse($data, $to_test); 184 | test($to_test, $reply); 185 | } 186 | 187 | return json_encode($reply); 188 | } 189 | } 190 | ); 191 | 192 | // Pattern list callback. 193 | $controllers->get( 194 | '/patterns', 195 | function () use ($app) { 196 | $list = listPatterns(); 197 | $response = new JsonResponse($list); 198 | $response->headers->set('Content-Type', 'application/json'); 199 | 200 | return $response; 201 | } 202 | ); 203 | 204 | return $controllers; 205 | } 206 | 207 | 208 | /** 209 | * Render a pattern of interest. 210 | * 211 | * @param \Silex\Application $app 212 | * The reference to the app. 213 | * @param \Symfony\Component\HttpFoundation\Request $request 214 | * The request object. 215 | * @param string $target 216 | * The pattern name of interest. 217 | * 218 | * @return string|\Symfony\Component\HttpFoundation\Response 219 | */ 220 | public function render_pattern(Application $app, Request $request, $target) 221 | { 222 | $patternObj = null; 223 | $contents = []; 224 | $pattern = null; 225 | 226 | // If there's a slash in the url, assume pattern has been passed. 227 | if (strpos($target, '/') !== false) { 228 | list($target, $pattern) = explode('/', $target); 229 | $contents['name'] = $pattern; 230 | } 231 | 232 | switch ($request->getMethod()) { 233 | case 'POST': 234 | // Read the POST data (if available). 235 | $contents = json_decode($request->getContent(), true); 236 | break; 237 | 238 | case 'GET': 239 | $params = $request->query->all(); 240 | 241 | // Use the target and data parameters (if available) to generate config. 242 | if (!empty($params['template']) || !empty($pattern)) { 243 | $pattern = !empty($pattern) ? $pattern : $params['template']; 244 | $patternObj = PatternFactory::getPattern( 245 | $pattern 246 | ); 247 | $contents = $patternObj->getSeedData(); 248 | } 249 | 250 | // If configuration data is supplied, unencode and apply. 251 | if (!empty($params['data'])) { 252 | $decoded = base64_decode($params['data']); 253 | $contents = (array)json_decode(zlib_decode($decoded)); 254 | } 255 | 256 | // If configuration is provided as JSON, apply 257 | if (!empty($params['jsondata'])) { 258 | $contents = (array)json_decode($params['jsondata']); 259 | } 260 | break; 261 | } 262 | 263 | // You must provide a name or template to render. 264 | if (empty($pattern) && empty($contents['name']) && empty($contents['template'])) { 265 | // We should provide more information about the failure here. 266 | // Left as is to avoid disrupting existing dependencies. (if any) 267 | return "Sorry: Unable to determine the pattern requested."; 268 | } 269 | 270 | $orig_contents = $contents; 271 | 272 | if (empty($pattern)) { 273 | $pattern = !empty($contents['name']) ? $contents['name'] : $contents['template']; 274 | } 275 | if (empty($patternObj)) { 276 | $patternObj = PatternFactory::getPattern($pattern); 277 | } 278 | 279 | // Add global configuration. 280 | if (isset($app['config'])) { 281 | $contents["app_config"] = $app['config']; 282 | } 283 | 284 | $asset_path = trim(dirname(get_asset_path($pattern, 'assets')), '.'); 285 | 286 | // If a host asset prefix was not specified, set empty value. 287 | if (empty($contents['asset_host_prefix'])) { 288 | 289 | if (!empty($contents['app_config']['pkhost'])) { 290 | $contents['asset_host_prefix'] = $contents['app_config']['pkhost'] . $asset_path; 291 | } else { 292 | $protocol = (isset($_SERVER['HTTPS']) && (strcasecmp( 293 | 'off', 294 | $_SERVER['HTTPS'] 295 | ) !== 0)) ? 'https' : 'http'; 296 | $hostname = $_SERVER['SERVER_ADDR']; 297 | $port = $_SERVER['SERVER_PORT']; 298 | $contents['asset_host_prefix'] = "$protocol://$hostname:$port".$asset_path; 299 | } 300 | // $contents['asset_host_prefix'] = $asset_path; 301 | } 302 | 303 | // So that we have a record of the legacy stuff. 304 | $contents['app_config']['global_assets'] = $contents['app_config']['assets']; 305 | 306 | // Get the asset data (if available). 307 | $asset_data = $patternObj->getAssetData(); 308 | // If we have asset data, feed that to the renderer instead of global. 309 | if (!empty($asset_data)) { 310 | 311 | // Override globals - allows backward compatibility in templates. 312 | $contents['app_config']['assets']['js'] = array_merge( 313 | $asset_data['js']['early'], 314 | $asset_data['js']['deferred'] 315 | ); 316 | $contents['app_config']['assets']['css'] = $asset_data['css']['list']; 317 | 318 | // If there is shared css, add it to the legacy list. 319 | if (!empty($asset_data['css']['shared'])) { 320 | foreach ($asset_data['css']['shared'] as $idx => $shared) { 321 | $contents['app_config']['assets']['css'][] = $shared['src']; 322 | } 323 | } 324 | 325 | // Walk the list of css files and add appropriate prefixes. 326 | if (!empty($contents['app_config']['assets']['css'])) { 327 | foreach ($contents['app_config']['assets']['css'] as $idx => $filename) { 328 | $contents['app_config']['assets']['css'][$idx] = preg_replace('/^\\.\\//', $contents['asset_host_prefix'] .'/', $filename); 329 | } 330 | } 331 | // Walk the list of js files and add appropriate prefixes. 332 | if (!empty($contents['app_config']['assets']['js'])) { 333 | foreach ($contents['app_config']['assets']['js'] as $idx => $filename) { 334 | $contents['app_config']['assets']['js'][$idx] = preg_replace('/^\\.\\//', $contents['asset_host_prefix'] .'/', $filename); 335 | } 336 | } 337 | 338 | // Add all the asset data to the config array. 339 | $contents['app_config']['assets']['custom'] = $asset_data; 340 | } 341 | 342 | switch ($target) { 343 | case "page": 344 | return $app['twig']->render("basic.twig", $contents); 345 | break; 346 | 347 | case "html": 348 | return $app['twig']->render("basic-html.twig", $contents); 349 | break; 350 | 351 | case 'json': 352 | // Get the rendered body of the twig template for the response. 353 | $page_content = $app['twig']->render( 354 | "jsonrender.twig", 355 | $contents 356 | ); 357 | 358 | // Return a JSON object with all information necessary to render. 359 | $json = json_encode( 360 | (object)[ 361 | 'pattern' => $contents['name'], 362 | 'host_prefix' => $contents['asset_host_prefix'], 363 | 'path' => $asset_path, 364 | 'assets' => $contents["app_config"]['assets']['custom'] ?? [], 365 | 'global_assets' => $contents["app_config"]['global_assets'] ?? [], 366 | 'config' => $orig_contents, 367 | 'gzconfig' => base64_encode( 368 | gzcompress(json_encode($orig_contents)) 369 | ), 370 | 'body' => $page_content, 371 | ], 372 | JSON_HEX_QUOT | JSON_HEX_TAG 373 | ); 374 | 375 | return new Response( 376 | $json, 377 | 200, 378 | [ 379 | 'Content-Type' => 'application/json', 380 | ] 381 | ); 382 | break; 383 | 384 | case 'webcomponent': 385 | 386 | $contents['host'] = $request->getSchemeAndHttpHost(); 387 | $contents['cssPrefix'] = '/api/serve/csscomponent'; 388 | $contents['pattern'] = $pattern; 389 | $contents['embeddedCSS'] = ''; 390 | 391 | $module_path = dirname(get_asset_path($pattern, 'assets')); 392 | if (!empty($asset_data['css']['list'])) { 393 | foreach ($asset_data['css']['list'] as $cssfile) { 394 | if (substr($cssfile, 0, 4) == 'http') { 395 | continue; 396 | } 397 | 398 | if (substr($cssfile, 0, 2) == './') { 399 | $cssfile = $module_path.'/'.substr($cssfile, 2); 400 | } 401 | $contents['embeddedCSS'] .= file_get_contents($cssfile); 402 | } 403 | } 404 | 405 | $contents['dynamicProperties'] = []; 406 | // If we have dynamic properties, apply them. 407 | if (!empty($asset_data['dynamic_properties'])) { 408 | foreach ($asset_data['dynamic_properties'] as $property) { 409 | $contents['dynamicProperties'][$property] = !empty($contents[$property]) ? $contents[$property] : ''; 410 | //$contents[$property] = "[[$property]]"; 411 | $contents[$property] = "{{{$property}}}"; 412 | } 413 | } 414 | 415 | $contents['componentPolyfill'] = $contents['app_config']['support_assets']['component_polyfill']; 416 | $page_content = $app['twig']->render( 417 | "webcomponent.twig", 418 | $contents 419 | ); 420 | 421 | return $page_content; 422 | break; 423 | } 424 | 425 | if (!empty($contents["template"])) { 426 | return $app['twig']->render($contents["template"], $contents); 427 | } else { 428 | return $app['twig']->render( 429 | $contents["name"].'.twig', 430 | $contents 431 | ); 432 | } 433 | } 434 | 435 | /** 436 | * Render a css component of interest. 437 | * 438 | * @param \Silex\Application $app 439 | * The reference to the app. 440 | * @param \Symfony\Component\HttpFoundation\Request $request 441 | * The request object. 442 | * @param string $pattern_name 443 | * The machine name of the pattern containing the style. 444 | * @param string $style_name 445 | * The machine name of the style (from manifest). 446 | * 447 | * @return string|\Symfony\Component\HttpFoundation\Response 448 | */ 449 | public function render_csscomponent( 450 | Application $app, 451 | Request $request, 452 | $pattern_name, 453 | $style_name 454 | ) { 455 | $patternObj = null; 456 | $contents = []; 457 | $cssBody = '/* Something went wrong. File could not be loaded. */'; 458 | 459 | $patternObj = PatternFactory::getPattern($pattern_name); 460 | $asset_data = $patternObj->getAssetData(); 461 | $module_path = dirname(get_asset_path($pattern_name, 'assets')); 462 | 463 | foreach ($asset_data['css']['shared'] as $asset) { 464 | if ($style_name == $asset['name']) { 465 | $filename = $module_path . '/' . trim($asset['src'], './'); 466 | $cssBody = file_get_contents($filename); 467 | } 468 | } 469 | 470 | $contents['moduleName'] = "shared-style-$style_name"; 471 | $contents['cssBody'] = $cssBody; 472 | $contents['componentPolyfill'] = $app['config']['support_assets']['component_polyfill']; 473 | 474 | return $app['twig']->render("csscomponent.twig", $contents); 475 | } 476 | } 477 | -------------------------------------------------------------------------------- /src/PatternKit/Controllers/SchemaController.php: -------------------------------------------------------------------------------- 1 | schemaService = $service; 21 | // } 22 | 23 | // public function getAll() 24 | // { 25 | // return new JsonResponse($this->schemaService->getAll()); 26 | // } 27 | 28 | // public function save(Request $request) 29 | // { 30 | 31 | // $note = $this->getDataFromRequest($request); 32 | // return new JsonResponse(array("id" => $this->schemaService->save($note))); 33 | 34 | // } 35 | 36 | // public function update($id, Request $request) 37 | // { 38 | // $note = $this->getDataFromRequest($request); 39 | // $this->schemaService->update($id, $note); 40 | // return new JsonResponse($note); 41 | 42 | // } 43 | 44 | // public function delete($id) 45 | // { 46 | 47 | // return new JsonResponse($this->schemaService->delete($id)); 48 | 49 | // } 50 | 51 | // public function getDataFromRequest(Request $request) 52 | // { 53 | // return $note = array( 54 | // "note" => $request->request->get("note") 55 | // ); 56 | // } 57 | } 58 | -------------------------------------------------------------------------------- /src/PatternKit/Factory/PatternFactory.php: -------------------------------------------------------------------------------- 1 | patterns = array(); 24 | } 25 | 26 | 27 | /** 28 | * Get an instance of the PatternFactory. 29 | * 30 | * @return PatternModel 31 | */ 32 | public static function getPattern($pattern) 33 | { 34 | static $instance; 35 | if ($instance === null) { 36 | $instance = new static(); 37 | } 38 | 39 | $patternObj = $instance->getPatternObj($pattern); 40 | 41 | return $patternObj; 42 | } 43 | 44 | /** 45 | * Load a pattern object, using caching if appropriate. 46 | * 47 | * @param string $pattern 48 | * The pattern of interest. 49 | * 50 | * @return PatternModel 51 | */ 52 | public function getPatternObj($pattern) 53 | { 54 | // If we've already got it, return it. 55 | if (!empty($this->patterns[$pattern])) { 56 | return $this->patterns[$pattern]; 57 | } 58 | 59 | // Do the work to generate this pattern. 60 | $this->patterns['pattern'] = new PatternModel($pattern); 61 | 62 | return $this->patterns['pattern']; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/PatternKit/Model/PatternModel.php: -------------------------------------------------------------------------------- 1 | pattern = $pattern; 44 | } 45 | 46 | /** 47 | * Load the seed data for a specific pattern. 48 | * 49 | * @return array|mixed 50 | */ 51 | public function getSeedData() 52 | { 53 | if (!empty($this->seed_data)) { 54 | return $this->seed_data; 55 | } 56 | 57 | $seed_path = get_asset_path($this->pattern, 'data'); 58 | 59 | if ($seed_path) { 60 | $seed_file = file_get_contents( 61 | 'file://'.realpath($seed_path) 62 | ); 63 | if (($pathinfo = pathinfo( 64 | $seed_path 65 | )) && isset($pathinfo['extension']) && $pathinfo['extension'] == 'yaml') { 66 | $this->seed_data = Yaml::parse($seed_file); 67 | } elseif (!empty($seed_file)) { 68 | $this->seed_data = json_decode($seed_file, true); 69 | } else { 70 | $this->seed_data = array(); 71 | } 72 | data_replace($this->seed_data); 73 | } else { 74 | $this->seed_data = array(); 75 | } 76 | 77 | return $this->seed_data; 78 | } 79 | 80 | /** 81 | * Load the docs data for a specific pattern. 82 | * 83 | * @return \Mni\FrontYAML\Document 84 | */ 85 | public function getDocsData() 86 | { 87 | if (!empty($this->docs_data)) { 88 | return $this->docs_data; 89 | } 90 | 91 | $docs_path = get_asset_path($this->pattern, 'docs'); 92 | 93 | $docs_file = file_get_contents('file://'.realpath($docs_path)); 94 | $parser = new \Mni\FrontYAML\Parser; 95 | $this->docs_data = $parser->parse($docs_file); 96 | 97 | return $this->docs_data; 98 | } 99 | 100 | /** 101 | * Load the docs assets for a specific pattern. 102 | * 103 | * @return array 104 | */ 105 | public function getAssetData() 106 | { 107 | if (!empty($this->asset_data)) { 108 | return $this->asset_data; 109 | } 110 | 111 | $asset_path = get_asset_path($this->pattern, 'assets'); 112 | $asset_file = file_get_contents('file://'.realpath($asset_path)); 113 | 114 | $this->asset_data = YAML::parse($asset_file, false); 115 | 116 | return $this->asset_data; 117 | } 118 | 119 | /** 120 | * Load schema for a specific pattern. 121 | */ 122 | public function getSchema() 123 | { 124 | if (!empty($this->schema)) { 125 | return $this->schema; 126 | } 127 | 128 | // Define data necessary to fetch the schema. 129 | $retriever = new \JsonSchema\Uri\UriRetriever; 130 | $path = get_asset_path($this->pattern, 'schemas'); 131 | 132 | // Load the schema file. 133 | $this->schema = $retriever->retrieve('file://'.realpath($path)); 134 | 135 | // Resolve any nested schemas that need to be loaded. 136 | $refResolver = new \JsonSchema\RefResolver($retriever); 137 | $refResolver::$maxDepth = 9999; 138 | $refResolver->resolve($this->schema); 139 | 140 | return $this->schema; 141 | } 142 | 143 | /** 144 | * Load the raw schema for a specific pattern. 145 | * 146 | * @return mixed 147 | */ 148 | public function getRawSchema() 149 | { 150 | if (!empty($this->raw_schema)) { 151 | return $this->raw_schema; 152 | } 153 | 154 | $path = get_asset_path($this->pattern, 'schemas'); 155 | $this->raw_schema = json_decode(file_get_contents($path), true); 156 | 157 | return $this->raw_schema; 158 | } 159 | 160 | /** 161 | * Load template for a specific pattern. 162 | */ 163 | public function getTemplate() 164 | { 165 | if (!empty($this->template)) { 166 | return $this->template; 167 | } 168 | 169 | $template_path = get_asset_path($this->pattern, 'templates'); 170 | 171 | if ($template_path) { 172 | $this->template = file_get_contents( 173 | 'file://'.realpath($template_path) 174 | ); 175 | } 176 | 177 | return $this->template; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/PatternKit/RoutesLoader.php: -------------------------------------------------------------------------------- 1 | app = $app; 27 | $this->instantiateControllers(); 28 | } 29 | 30 | /** 31 | * Bind the route to the controllers. 32 | */ 33 | public function bindRoutesToControllers() 34 | { 35 | $api = $this->app["controllers_factory"]; 36 | 37 | $api->get('/tests/{name}/{data_array}', "schema.controller:getTests"); 38 | 39 | $this->app->mount('/', $api); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/PatternKit/SchemaControllerProvider.php: -------------------------------------------------------------------------------- 1 | get( 32 | '/{pattern}', 33 | function ($pattern) use ($app) { 34 | $patternObj = PatternFactory::getPattern($pattern); 35 | $data = array(); 36 | 37 | // Navigation 38 | $data['nav'] = getNav($pattern); 39 | if (array_key_exists('sg', $app["config"]["paths"])) { 40 | $data['nav']['sg_active'] = true; 41 | } 42 | 43 | // Pull global app config (if available). 44 | if (isset($app['config'])) { 45 | $data["app_config"] = $app['config']; 46 | } 47 | 48 | $data['docs_yaml'] = $patternObj->getDocsData()->getYAML(); 49 | $data['docs_content'] = $patternObj->getDocsData()->getContent(); 50 | $data['schema'] = json_encode($patternObj->getSchema()); 51 | $data['docs_json'] = (array)$patternObj->getSeedData(); 52 | $data['starting'] = json_encode($patternObj->getSeedData()); 53 | $data['raw_schema'] = (array)$patternObj->getRawSchema(); 54 | 55 | 56 | if ($patternObj->getTemplate()) { 57 | $data['template_markup'] = $patternObj->getTemplate(); 58 | } 59 | 60 | return $app['twig']->render("display-schema.twig", $data); 61 | } 62 | )->bind('schema'); 63 | 64 | $controllers->match( 65 | '/editor/{pattern}', 66 | function (Request $request, $pattern) use ($app) { 67 | $data = []; 68 | 69 | $patternObj = PatternFactory::getPattern($pattern); 70 | 71 | $schema = $patternObj->getSchema(); 72 | 73 | // Navigation 74 | $data['nav'] = getNav($pattern); 75 | if (array_key_exists('sg', $app["config"]["paths"])) { 76 | $data['nav']['sg_active'] = true; 77 | } 78 | // end navigation 79 | 80 | 81 | // Get the default values for the various config elements. 82 | $seed_data = $patternObj->getSeedData(); 83 | 84 | // Use the values provided (if available) to override defaults. 85 | $raw_json = $request->getContent(); 86 | if (!empty($raw_json)) { 87 | $seed_data = $raw_json; 88 | } 89 | 90 | // Apply global configuration. 91 | if (isset($app['config'])) { 92 | $data["app_config"] = $app['config']; 93 | } 94 | 95 | $docs_data = $patternObj->getDocsData(); 96 | $data['docs_yaml'] = $docs_data->getYAML(); 97 | $data['docs_content'] = $docs_data->getContent(); 98 | 99 | $data['schema'] = json_encode($schema); 100 | $data['docs_json'] = (array)$seed_data; 101 | $data['starting'] = json_encode($seed_data); 102 | $data['raw_schema'] = (array)$patternObj->getRawSchema(); 103 | 104 | if ($patternObj->getTemplate()) { 105 | $data['template_markup'] = $patternObj->getTemplate(); 106 | } 107 | 108 | return $app['twig']->render( 109 | "display-just-schema-editor.twig", 110 | $data 111 | ); 112 | } 113 | ) 114 | // Supporting GET/POST for easier debugging. 115 | ->method('GET|POST') 116 | ->bind('schema-editor'); 117 | 118 | return $controllers; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/PatternKit/StyleGuideControllerProvider.php: -------------------------------------------------------------------------------- 1 | get( 31 | '/', 32 | function ($pattern) use ($app) { 33 | return $this->renderer($app, $pattern); 34 | } 35 | )->value('pattern', "index")->bind('styleguide-home'); 36 | 37 | $controllers->get( 38 | '/{pattern}', 39 | function ($pattern) use ($app) { 40 | return $this->renderer($app, $pattern); 41 | } 42 | )->bind('styleguide'); 43 | 44 | return $controllers; 45 | } 46 | 47 | /** 48 | * Renders the style guide requested. 49 | * 50 | * @param Application $app 51 | * Reference to the application object. 52 | * @param string $pattern 53 | * The pattern of interest. 54 | * 55 | * @return mixed 56 | * Rendered output. 57 | */ 58 | public function renderer(Application $app, $pattern) 59 | { 60 | $sg_path = get_asset_path($pattern, 'sg'); 61 | $sg_file = file_get_contents('file://'.realpath($sg_path)); 62 | 63 | $parser = new Parser(); 64 | $sg_data = $parser->parse($sg_file); 65 | 66 | if (isset($app['config'])) { 67 | $data["app_config"] = $app['config']; 68 | } 69 | 70 | $data['secondary_nav'] = getDocNav($pattern); 71 | $data['nav'] = getNav($pattern); 72 | $data['sg_yaml'] = $sg_data->getYAML(); 73 | $data['sg_content'] = $sg_data->getContent(); 74 | 75 | return $app['twig']->render("display-sg.twig", $data); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/PatternKit/TestsControllerProvider.php: -------------------------------------------------------------------------------- 1 | get( 30 | '/{name}/{data_array}', 31 | function ($name, $data_array) use ($app) { 32 | $data_path = get_asset_path($name, "test_data"); 33 | 34 | if (file_exists($data_path)) { 35 | $file_data = json_decode(file_get_contents($data_path), true); 36 | } else { 37 | trigger_error( 38 | $name." is missing an associated data file. Create ".$name.".tests.json in the ".$name."/library folder.

" 39 | ); 40 | exit; 41 | } 42 | 43 | // Test if this is an array of tests data. 44 | if (array_keys($file_data) == range(0, count($file_data) - 1)) { 45 | $file_data = $file_data[$data_array]["data"]; 46 | } 47 | 48 | if ($file_data['name'] || $file_data['template']) { 49 | if (isset($app['config'])) { 50 | $file_data["app_config"] = $app['config']; 51 | } 52 | 53 | return $app['twig']->render("basic.twig", $file_data); 54 | } else { 55 | trigger_error( 56 | $name.".tests.json is missing a name or template value.

" 57 | ); 58 | exit; 59 | } 60 | } 61 | )->value('data_array', 0); 62 | 63 | return $controllers; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/app.php: -------------------------------------------------------------------------------- 1 | register(new YamlConfigServiceProvider("./.pk-config.yml")); 27 | $app->register(new Silex\Provider\UrlGeneratorServiceProvider()); 28 | 29 | // Handling CORS preflight request. 30 | $app->before(function (Request $request) { 31 | if ($request->getMethod() === "OPTIONS") { 32 | $response = new Response(); 33 | $response->headers->set("Access-Control-Allow-Origin", "*"); 34 | $response->headers->set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS"); 35 | $response->headers->set("Access-Control-Allow-Headers", "Content-Type"); 36 | $response->setStatusCode(200); 37 | return $response->send(); 38 | } 39 | return null; 40 | }, Application::EARLY_EVENT); 41 | 42 | // Handling CORS response with right headers. 43 | $app->after(function (Request $request, Response $response) { 44 | $response->headers->set("Access-Control-Allow-Origin", "*"); 45 | $response->headers->set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS"); 46 | }); 47 | 48 | $app->register(new ServiceControllerServiceProvider()); 49 | 50 | $app->register(new HttpCacheServiceProvider(), array("http_cache.cache_dir" => ROOT_PATH . "/storage/cache",)); 51 | 52 | $app['debug'] = false; 53 | 54 | /* 55 | * Set Up Twig Template Paths. 56 | */ 57 | 58 | // Initialize an empty array to collect the templates. 59 | $twig_template_paths = array(); 60 | 61 | // Add the templates used by patternkit itself. 62 | array_push($twig_template_paths, ROOT_PATH . '/resources/templates'); 63 | 64 | // If there is a single template in config, it'll be a string, array otherwise. 65 | if (is_string($app['config']['paths']['templates'])) { 66 | array_push($twig_template_paths, realpath('./' . $app['config']['paths']['templates'])); 67 | } elseif (is_array($app['config']['paths']['templates'])) { 68 | foreach ($app['config']['paths']['templates'] as $value) { 69 | array_push($twig_template_paths, realpath('./' . $value)); 70 | } 71 | } 72 | 73 | // Register Twig. 74 | $app->register(new Silex\Provider\TwigServiceProvider(), array( 75 | 'twig.path' => $twig_template_paths, 76 | 'twig.options' => array( 77 | 'strict_variables' => false, 78 | ), 79 | )); 80 | 81 | /* 82 | * Custom Functions 83 | */ 84 | 85 | /** 86 | * Recursively loads or parses YAML/JSON file data into PHP structures. 87 | * 88 | * @param $data 89 | * 90 | * @return mixed 91 | */ 92 | function data_replace(&$data) 93 | { 94 | if (is_array($data)) { 95 | foreach ($data as &$value) { 96 | if (is_array($value)) { 97 | data_replace($value); 98 | } elseif (is_string($value) && $value[0] == '@') { 99 | $patternObj = new \PatternKit\Model\PatternModel($value); 100 | $file_path = 'file://' . realpath( 101 | $patternObj->get_asset_path($value, 'data') 102 | ); 103 | if (($pathinfo = pathinfo($file_path)) && isset($pathinfo['extension']) && $pathinfo['extension'] == 'yaml') { 104 | $data_replace_with = Yaml::parse(file_get_contents($file_path)); 105 | } else { 106 | $data_replace_with = json_decode(file_get_contents($file_path), true); 107 | } 108 | 109 | $value = data_replace($data_replace_with); 110 | } 111 | } 112 | } 113 | return $data; 114 | } 115 | 116 | /** 117 | * Get path to matching asset 118 | * 119 | * @param string $name 120 | * The name of the asset. 121 | * @param string $type 122 | * The type of data to find (eg templates, data, etc). 123 | * 124 | * @return null|string 125 | * Path to the asset of interest. 126 | * @throws \Exception 127 | * Exception thrown if type is not supported. 128 | */ 129 | function get_asset_path($name, $type) 130 | { 131 | global $app; 132 | 133 | switch ($type) { 134 | case "templates": 135 | case "data": 136 | case "schemas": 137 | case "docs": 138 | case "sg": 139 | case "test_data": 140 | $return = null; 141 | // Fetch the path from the global configuration. 142 | $paths = $app['config']['paths'][$type]; 143 | 144 | // If there's an array of paths, we should visit each in reverse. 145 | if (is_array($paths)) { 146 | $paths = array_reverse($paths); 147 | } 148 | 149 | // If paths are set, iterate over them. 150 | if ($paths) { 151 | foreach ($paths as $path) { 152 | $extension = $app['config']['extensions'][$type]; 153 | $yaml_extension = str_replace( 154 | '.json', 155 | '.yaml', 156 | $extension 157 | ); 158 | $dir = './'.$path; 159 | $file_path = "{$dir}/{$name}{$extension}"; 160 | $yaml_file_path = "{$dir}/{$name}{$yaml_extension}"; 161 | 162 | if (is_dir($dir) && is_readable($file_path)) { 163 | $return = $file_path; 164 | break; 165 | } else { 166 | if (is_dir($dir) && is_readable($yaml_file_path)) { 167 | $return = $yaml_file_path; 168 | break; 169 | } 170 | } 171 | } 172 | } 173 | 174 | return $return; 175 | break; 176 | 177 | case 'assets': 178 | // Default the path to empty. 179 | $path = ''; 180 | 181 | $asset_path = $app['config']['paths'][$type][0]; 182 | // Fetch the path from the global configuration. 183 | $dir = "./".$asset_path; 184 | 185 | $file_path = "{$dir}/{$name}/{$name}.manifest.yaml"; 186 | 187 | if (is_dir($dir) && is_readable($file_path)) { 188 | $path = $file_path; 189 | } 190 | 191 | return $path; 192 | 193 | break; 194 | 195 | default: 196 | throw new Exception( 197 | $type.' is not equal to template, data or schema' 198 | ); 199 | } 200 | } 201 | 202 | /** 203 | * Create Primary Navigation for pattern library 204 | * 205 | * @param $pattern 206 | * 207 | * @return array 208 | */ 209 | function getNav($pattern) 210 | { 211 | global $app; 212 | $categories = $app['config']['categories']; 213 | $schema_paths = array(); 214 | $nav = array(); 215 | $nav['title'] = $app['config']['title']; 216 | 217 | foreach ($app['config']['paths']['schemas'] as $path) { 218 | $files = scandir("./" . $path); 219 | 220 | $schema_paths[] = array( 221 | 'location' => $path, 222 | 'files' => $files, 223 | ); 224 | } 225 | 226 | if ($categories) { 227 | foreach ($categories as $category) { 228 | $value = strtolower(str_replace(' ', '_', $category)); 229 | 230 | $nav['categories'][$value] = array(); 231 | $nav['categories'][$value]['title'] = $category; 232 | $nav['categories'][$value]['path'] = '/' . $value; 233 | } 234 | } 235 | 236 | foreach ($schema_paths as $path) { 237 | foreach ($path['files'] as $file) { 238 | if (strpos($file, 'json') !== false) { 239 | $nav_item = array(); 240 | $contents = json_decode(file_get_contents('./' . $path['location'] . "/" . $file), true); 241 | 242 | $contents['name'] = substr($file, 0, -5); 243 | $category = isset($contents['category']) ? $contents['category'] : false; 244 | $nav_item['title'] = isset($contents['title']) ? $contents['title'] : $contents['name']; 245 | $nav_item['path'] = $contents['name']; 246 | if ($contents['name'] == $pattern) { 247 | $nav_item['active'] = true; 248 | } 249 | if ($category) { 250 | $nav['categories'][$category]['items'][] = $nav_item; 251 | } 252 | } 253 | } 254 | } 255 | return $nav; 256 | } 257 | 258 | /** 259 | * Create secondary navigation for styleguide. 260 | * 261 | * @param $pattern 262 | * 263 | * @return array 264 | */ 265 | function getDocNav($pattern) 266 | { 267 | global $app; 268 | $nav = array(); 269 | $parser = new Parser(); 270 | 271 | foreach ($app['config']['paths']['sg'] as $path) { 272 | $files = glob('./' . $path . '/*' . $app['config']['extensions']['sg']); 273 | foreach ($files as $value) { 274 | $value_parts = str_split(basename($value), strpos(basename($value), ".")); 275 | $nav_item = array(); 276 | $sg_file = file_get_contents($value); 277 | $sg_data = $parser->parse($sg_file); 278 | $data['sg_yaml'] = $sg_data->getYAML(); 279 | $nav_item['title'] = $data['sg_yaml']['title']; 280 | $nav_item['order'] = $data['sg_yaml']['order']; 281 | $nav_item['path'] = $value_parts[0]; 282 | if ($value_parts[0] == $pattern) { 283 | $nav_item['active'] = true; 284 | } 285 | if ($value_parts[0] == 'index') { 286 | $nav_item['path'] = null; 287 | array_unshift($nav, $nav_item); 288 | } else { 289 | $nav[] = $nav_item; 290 | } 291 | } 292 | } 293 | 294 | return $nav; 295 | } 296 | 297 | /** 298 | * Create list of patterns for REST interface. 299 | * 300 | * @return array 301 | * Nested array of details for each of the patterns on this system. 302 | */ 303 | function listPatterns() 304 | { 305 | global $app; 306 | $schema_paths = array(); 307 | $list = array(); 308 | 309 | // Read configuration and collect the list of schema folders. 310 | foreach ($app['config']['paths']['schemas'] as $path) { 311 | $files = scandir("./" . $path); 312 | 313 | $schema_paths[] = array( 314 | 'location' => $path, 315 | 'files' => $files, 316 | ); 317 | } 318 | 319 | // Iterate over the schema paths to find all schema. 320 | foreach ($schema_paths as $path) { 321 | // For each file in the schema folder(s). 322 | foreach ($path['files'] as $raw_filename) { 323 | $file = strtolower($raw_filename); 324 | // Only look at the JSON files. 325 | if (strpos($file, 'json') !== false) { 326 | $pattern = array(); 327 | // Load the schema and decode for the list. 328 | $contents = json_decode(file_get_contents('./' . $path['location'] . "/" . $file), true); 329 | 330 | $contents['name'] = substr($file, 0, -5); 331 | $pattern['category'] = isset($contents['category']) ? $contents['category'] : false; 332 | $pattern['title'] = isset($contents['title']) ? $contents['title'] : $contents['name']; 333 | 334 | // Default to 1.0 for version of json for legacy support. 335 | $pattern['version'] = !empty($contents['version']) ? $contents['version'] : '1.0'; 336 | 337 | $list[$contents['name']] = (object)$pattern; 338 | } 339 | } 340 | } 341 | return $list; 342 | } 343 | 344 | // Mount Routes. 345 | $app->mount('/schema', new PatternKit\SchemaControllerProvider()); 346 | $app->mount('/api', new PatternKit\ApiControllerProvider()); 347 | $app->mount('/tests', new PatternKit\TestsControllerProvider()); 348 | $app->mount('/sg', new PatternKit\StyleGuideControllerProvider()); 349 | 350 | // Default route (landing page). 351 | $app->get('/', function () use ($app) { 352 | $data = array(); 353 | $data['nav'] = getNav('/'); 354 | return $app['twig']->render("display-schema.twig", $data); 355 | }); 356 | 357 | return $app; 358 | -------------------------------------------------------------------------------- /storage/cache/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatternBuilder/pattern-kit/4650aeaca9afd01115e117c1b7b0344bcbee3f3f/storage/cache/.gitkeep -------------------------------------------------------------------------------- /storage/logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatternBuilder/pattern-kit/4650aeaca9afd01115e117c1b7b0344bcbee3f3f/storage/logs/.gitkeep -------------------------------------------------------------------------------- /web/css/json-editor.css: -------------------------------------------------------------------------------- 1 | /* Define Overpass font */ 2 | @font-face { 3 | font-family: Overpass; 4 | src: url("/resources/fixtures/fonts/overpass_regular-web.eot"); 5 | src: url("/resources/fixtures/fonts/overpass_regular-web.eot?#iefix") format("eot"), 6 | url("/resources/fixtures/fonts/overpass_regular-web.woff") format("woff"), 7 | url("/resources/fixtures/fonts/overpass_regular-web.ttf") format("truetype"), 8 | url("/resources/fixtures/fonts/overpass_regular-web.svg#webfontLTZe4IYH") format("svg"); 9 | font-weight: 600; 10 | font-style: normal; 11 | } 12 | 13 | @font-face { 14 | font-family: Overpass; 15 | src: url("/resources/fixtures/fonts/overpass_bold-web.eot"); 16 | src: url("/resources/fixtures/fonts/overpass_bold-web.eot?#iefix") format("eot"), 17 | url("/resources/fixtures/fonts/overpass_bold-web.woff") format("woff"), 18 | url("/resources/fixtures/fonts/overpass_bold-web.ttf") format("truetype"), 19 | url("/resources/fixtures/fonts/overpass_bold-web.svg#webfontzAU82Ltw") format("svg"); 20 | font-weight: 800; 21 | font-style: normal; 22 | } 23 | 24 | @font-face { 25 | font-family: Overpass; 26 | src: url("/resources/fixtures/fonts/overpass_light-webfont.eot"); 27 | src: url("/resources/fixtures/fonts/overpass_light-webfont.eot?#iefix") format("eot"), 28 | url("/resources/fixtures/fonts/overpass_light-webfont.woff") format("woff"), 29 | url("/resources/fixtures/fonts/overpass_light-webfont.ttf") format("truetype"), 30 | url("/resources/fixtures/fonts/overpass_light-webfont.svg#webfontzAU82Ltw") format("svg"); 31 | font-weight: 400; 32 | font-style: normal; 33 | } 34 | body { 35 | font-size: 16px; 36 | font-family: "Overpass", Overpass, Helvetica, helvetica, arial, sans-serif; 37 | font-weight: 100; 38 | } 39 | 40 | h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { 41 | font-family: "Overpass", Overpass, Helvetica, helvetica, arial, sans-serif; 42 | color: #017EA3; 43 | font-weight: 400; 44 | } 45 | h1, .h1 { 46 | color: #02546d; 47 | } 48 | h1, .h1, h2, .h2 { 49 | font-weight: 600; 50 | } 51 | a { 52 | color: #017EA3; 53 | } 54 | a:hover, a:focus { 55 | color: #0eb3e4; 56 | } 57 | 58 | 59 | .resize-overlay { 60 | pointer-events: none; 61 | position: relative; 62 | } 63 | /* Styles for the navbar */ 64 | .navbar-inverse .navbar-nav > li > a { 65 | color: #fff; 66 | font-weight: 400; 67 | font-size: 16px; 68 | } 69 | .navbar-inverse .navbar-header .navbar-brand:hover { 70 | cursor: default; 71 | color: #999; 72 | } 73 | 74 | /* Styles for the pattern preview tool */ 75 | #schema_holder .page-header { 76 | padding-left: 60px; 77 | } 78 | #schema_holder + .alert { 79 | margin: 20px 60px; 80 | } 81 | #display_holder { 82 | width: 100%; 83 | border: 0; 84 | } 85 | .sg-snippet-preview { 86 | position: relative; 87 | margin: 20px auto; 88 | } 89 | 90 | .sg-snippet-resize-handle { 91 | height: 100px; 92 | width: 30px; 93 | margin-top: -50px; 94 | position: absolute; 95 | top: 50%; 96 | -webkit-transition: all .4s; 97 | -moz-transition: all .4s; 98 | transition: all .4s; 99 | } 100 | 101 | .sg-snippet-resize-handle:before { 102 | background: url('../img/icon-drag.svg') no-repeat; 103 | position: absolute; 104 | top: 50%; 105 | content: ''; 106 | height: 17px; 107 | margin-top: -8px; 108 | width: 11px 109 | } 110 | 111 | .sg-snippet-resize-handle.pos-right, 112 | .sg-snippet-resize-handle.pos-left { 113 | background: rgba(192, 194, 196, 0.2); 114 | height: 100%; 115 | top: 0; 116 | margin: 0; 117 | } 118 | 119 | .sg-snippet-resize-handle.pos-right::before, 120 | .sg-snippet-resize-handle.pos-left::before { 121 | top: min(50%, 50vh); 122 | } 123 | 124 | .sg-snippet-resize-handle.pos-right { 125 | border-right: 1px solid #ccc; 126 | left: -40px; 127 | cursor: e-resize; 128 | } 129 | 130 | .sg-snippet-resize-handle.pos-right::before { 131 | left: 10px 132 | } 133 | 134 | .sg-snippet-resize-handle.pos-left { 135 | border-left: 1px solid #ccc; 136 | right: -40px; 137 | cursor: w-resize; 138 | } 139 | 140 | .sg-snippet-resize-handle.pos-left:before { 141 | right: 10px 142 | } 143 | 144 | .sg-snippet:hover .sg-snippet-resize-handle { 145 | opacity: 1; 146 | visibility: visible 147 | } 148 | 149 | 150 | @-webkit-keyframes androidBugfix { from { padding: 0; } to { padding: 0; } } 151 | body { -webkit-animation: androidBugfix infinite 1s; } 152 | /* Layout styles for extra large browsers, side-by-side preview + data */ 153 | @media (min-width:1800px) { 154 | body, html { 155 | height: 100%; 156 | } 157 | .left { 158 | width: 50%; 159 | float: left; 160 | height: 100%; 161 | overflow: scroll; 162 | } 163 | .right { 164 | padding: 0 1%; 165 | height: 100%; 166 | left: 50%; 167 | overflow: scroll; 168 | } 169 | } 170 | 171 | /* Styles specific to the schema content */ 172 | .right { 173 | background: white; 174 | padding-top: 10px; 175 | } 176 | .right > * { 177 | margin-left: 10px; 178 | margin-right: 10px; 179 | margin-bottom: 10px; 180 | } 181 | .right .nav-tabs { 182 | margin-bottom: 30px; 183 | padding: 0 80px; 184 | } 185 | @media (min-width: 1800px) { 186 | .right > .container-fluid { 187 | margin-top: 50px; 188 | } 189 | .right .nav-tabs { 190 | padding-left: 10px; 191 | } 192 | } 193 | 194 | /* Styles specific to the interactive schema preview */ 195 | code { 196 | color: #000000; 197 | background-color: #f3e3e8; 198 | } 199 | #editor_holder { 200 | font-size: 14px; 201 | } 202 | 203 | #editor_holder .btn { 204 | font-size: 12px; 205 | padding: 4px 8px; 206 | } 207 | 208 | #editor_holder .well > .form-control { 209 | background-color: #fff !important; 210 | font-size: 1.2em; 211 | color: #017EA3; /* aqua */ 212 | font-weight: bold !important; 213 | -webkit-font-smoothing: antialiased; 214 | -moz-osx-font-smoothing: grayscale; 215 | } 216 | 217 | 218 | #editor_holder .list-group-item { 219 | padding: 6px 6px; 220 | } 221 | 222 | #editor_holder .panel-title { 223 | float: left; 224 | } 225 | 226 | .page-header { 227 | padding-bottom: 9px; 228 | margin: 40px 10px 0px; 229 | border-bottom: 1px solid #eee; 230 | } 231 | 232 | #editor_holder h1 { 233 | font-size: 24px; 234 | margin: 5px 0; 235 | } 236 | 237 | #editor_holder h2 { 238 | font-size: 20px; 239 | margin: 8px 0; 240 | } 241 | 242 | #editor_holder h3 { 243 | font-size: 15px; 244 | margin: 5px 0; 245 | } 246 | 247 | #editor_holder p { 248 | margin-bottom: 5px; 249 | } 250 | .help-block { 251 | color: #3e3e3e; 252 | } 253 | 254 | .json-editor-btn-collapse { 255 | background: transparent; 256 | border: 0; 257 | padding: 1px 3px; 258 | line-height: 0; 259 | } 260 | .json-editor-btn-collapse:hover { 261 | background: transparent; 262 | } 263 | #editor_holder [data-schematype="array"]:hover > h3 .btn-group .json-editor-btn-collapse i , 264 | #editor_holder [data-schematype="object"]:hover > h3 .btn-group .json-editor-btn-collapse i , 265 | .json-editor-btn-collapse:hover i:before { 266 | color: #017EA3; /* #276edc;*/ 267 | } 268 | .json-editor-btn-collapse i { 269 | font-size: 1.7em; 270 | } 271 | 272 | 273 | #editor_holder .well { 274 | margin-bottom: 10px; 275 | } 276 | #editor_holder [data-schematype="object"] > .well, 277 | #editor_holder [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well, 278 | #editor_holder [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well, 279 | #editor_holder [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well { 280 | background-color: #e6ecf0; /* soft sky */ 281 | } 282 | #editor_holder [data-schematype="object"] > .well [data-schematype="object"] > .well, 283 | #editor_holder [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well, 284 | #editor_holder [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well .well, 285 | #editor_holder [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well [data-schematype="object"] > .well { 286 | background-color: #fff; 287 | } 288 | #editor_holder [data-schematype="array"] .well { 289 | background: transparent;; 290 | } 291 | 292 | #editor_holder [data-schematype="array"] > .well { 293 | padding: 0; 294 | border: 0; 295 | } 296 | #editor_holder [data-schematype="array"] > .well > div > .well { 297 | margin: 0 0 15px; 298 | padding-bottom: 10px !important; 299 | border: 3px solid #FFF; 300 | border-radius: 0; 301 | background-color: rgba(205, 233, 219, 0.3); /* sage */ 302 | } 303 | #editor_holder [data-schematype="array"] > .well > div > .well:last-child { 304 | padding-bottom: 0 !important; 305 | } 306 | #editor_holder [data-schematype="array"] > .well > div > .well label { 307 | font-size: 14px; 308 | } 309 | #editor_holder [data-schematype="array"] > .well > div > .well > .btn-group { 310 | margin: 10px 10px 10px 0; 311 | } 312 | #editor_holder [data-schematype="array"] > .well > .btn-group { 313 | margin: 10px; 314 | } 315 | #editor_holder [data-schematype="object"] > h3 span { 316 | font-weight: 800; 317 | color: #212121; 318 | } 319 | #editor_holder [data-schematype="object"]:hover > h3 > span, 320 | #editor_holder [data-schematype="object"] .well .well .well:hover h3 span { 321 | color: #017EA3; /* aqua */ 322 | } 323 | #editor_holder [data-schematype="array"] > h3 span { 324 | font-weight: 800; 325 | color: #3E4551; 326 | }, 327 | #editor_holder [data-schematype="array"] label { 328 | font-weight: 600; 329 | } 330 | #editor_holder [data-schematype="array"] > .well > div > [data-schematype="object"] { 331 | border-bottom: 2px solid #fff; 332 | } 333 | #editor_holder [data-schematype="array"] > .well > div > [data-schematype="object"] > h3 { 334 | font-size: 14px; 335 | padding-left: 10px; 336 | padding-top: 5px; 337 | } 338 | #editor_holder [data-schematype="array"] > .well > div > [data-schematype="object"] > h3 span { 339 | display: inline-block !important; 340 | } 341 | #editor_holder [data-schematype="array"] > .well > div > [data-schematype="object"] > .well { 342 | margin-bottom: 0; 343 | } 344 | 345 | #json_holder { 346 | display: block; 347 | max-width: 1400px; 348 | margin: 0 auto; 349 | 350 | } 351 | #json_holder pre { 352 | font-size: 14px; 353 | font-family: monospace; 354 | } 355 | 356 | #json_holder .valid { 357 | font-size: 14px; 358 | margin-bottom: 5px; 359 | } 360 | #json_holder .valid.alert-danger > br:first-child { 361 | display: none; 362 | } 363 | .ace_editor { 364 | height: 300px !important; 365 | } 366 | .sceditor-container *{ 367 | box-sizing: content-box; 368 | -moz-box-sizing: border-box; 369 | } 370 | .background { 371 | display: none; 372 | position: fixed; 373 | top: 0; 374 | width: 100%; 375 | height: 100%; 376 | z-index: 10; 377 | background: rgba(255,255,255,.5); 378 | } 379 | .well .table-bordered { 380 | border: 0px; 381 | } 382 | .well .table-bordered>thead>tr>th, 383 | .well .table-bordered>tbody>tr>td { 384 | border: 0px; 385 | } 386 | 387 | .well .table-bordered>thead>tr>th , 388 | .well .table-bordered>tbody>tr~tr { 389 | border-top: 1px #dedede solid; 390 | } 391 | .navbar { 392 | margin-bottom: 0; 393 | } 394 | .navbar + .container-fluid { 395 | margin-right: 15px; 396 | margin-left: 15px; 397 | margin-top: 15px; 398 | } 399 | 400 | /* Styles specific to styleguide / documentation */ 401 | .docs-wrapper { 402 | font-size: 1.1em; 403 | max-width: 800px; 404 | } 405 | .right, .left { 406 | overflow: auto; 407 | } 408 | .docs-wrapper a { 409 | text-decoration: underline; 410 | } 411 | .docs-wrapper li { 412 | margin-top: 3px; 413 | margin-bottom: 8px; 414 | } 415 | .docs-wrapper li li { 416 | margin-top: 3px; 417 | margin-bottom: 1px; 418 | } 419 | .docs-wrapper th, td { 420 | border: solid 1px #ccc; 421 | padding: 5px; 422 | } 423 | 424 | .secondary-nav { 425 | max-width: 300px; 426 | } 427 | .secondary-nav + .left > *:first-child { 428 | margin-top: 0; 429 | } 430 | .secondary-nav .nav>li { 431 | margin: 0; 432 | } 433 | .secondary-nav .nav>li>a { 434 | border-bottom: 1px solid #ddd; 435 | padding: 7px 3px; 436 | } 437 | code { 438 | white-space: normal; 439 | } 440 | a[href="#top"] { 441 | margin-top: -50px; 442 | float: right; 443 | } 444 | hr { 445 | border-top: 1px solid #bbb; 446 | margin-top: 30px; 447 | margin-bottom: 30px; 448 | } 449 | -------------------------------------------------------------------------------- /web/img/icon-drag.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /web/js/lzstring.js: -------------------------------------------------------------------------------- 1 | 2 | /* pako 1.0.5 nodeca/pako */ 3 | !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.pako=t()}}(function(){return function t(e,a,i){function n(s,o){if(!a[s]){if(!e[s]){var l="function"==typeof require&&require;if(!o&&l)return l(s,!0);if(r)return r(s,!0);var h=new Error("Cannot find module '"+s+"'");throw h.code="MODULE_NOT_FOUND",h}var d=a[s]={exports:{}};e[s][0].call(d.exports,function(t){var a=e[s][1][t];return n(a?a:t)},d,d.exports,t,e,a,i)}return a[s].exports}for(var r="function"==typeof require&&require,s=0;s0?e.windowBits=-e.windowBits:e.gzip&&e.windowBits>0&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new f,this.strm.avail_out=0;var a=o.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(a!==b)throw new Error(d[a]);if(e.header&&o.deflateSetHeader(this.strm,e.header),e.dictionary){var n;if(n="string"==typeof e.dictionary?h.string2buf(e.dictionary):"[object ArrayBuffer]"===_.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,a=o.deflateSetDictionary(this.strm,n),a!==b)throw new Error(d[a]);this._dict_set=!0}}function n(t,e){var a=new i(e);if(a.push(t,!0),a.err)throw a.msg||d[a.err];return a.result}function r(t,e){return e=e||{},e.raw=!0,n(t,e)}function s(t,e){return e=e||{},e.gzip=!0,n(t,e)}var o=t("./zlib/deflate"),l=t("./utils/common"),h=t("./utils/strings"),d=t("./zlib/messages"),f=t("./zlib/zstream"),_=Object.prototype.toString,u=0,c=4,b=0,g=1,m=2,w=-1,p=0,v=8;i.prototype.push=function(t,e){var a,i,n=this.strm,r=this.options.chunkSize;if(this.ended)return!1;i=e===~~e?e:e===!0?c:u,"string"==typeof t?n.input=h.string2buf(t):"[object ArrayBuffer]"===_.call(t)?n.input=new Uint8Array(t):n.input=t,n.next_in=0,n.avail_in=n.input.length;do{if(0===n.avail_out&&(n.output=new l.Buf8(r),n.next_out=0,n.avail_out=r),a=o.deflate(n,i),a!==g&&a!==b)return this.onEnd(a),this.ended=!0,!1;0!==n.avail_out&&(0!==n.avail_in||i!==c&&i!==m)||("string"===this.options.to?this.onData(h.buf2binstring(l.shrinkBuf(n.output,n.next_out))):this.onData(l.shrinkBuf(n.output,n.next_out)))}while((n.avail_in>0||0===n.avail_out)&&a!==g);return i===c?(a=o.deflateEnd(this.strm),this.onEnd(a),this.ended=!0,a===b):i!==m||(this.onEnd(b),n.avail_out=0,!0)},i.prototype.onData=function(t){this.chunks.push(t)},i.prototype.onEnd=function(t){t===b&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=l.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},a.Deflate=i,a.deflate=n,a.deflateRaw=r,a.gzip=s},{"./utils/common":3,"./utils/strings":4,"./zlib/deflate":8,"./zlib/messages":13,"./zlib/zstream":15}],2:[function(t,e,a){"use strict";function i(t){if(!(this instanceof i))return new i(t);this.options=o.assign({chunkSize:16384,windowBits:0,to:""},t||{});var e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&0===(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new f,this.strm.avail_out=0;var a=s.inflateInit2(this.strm,e.windowBits);if(a!==h.Z_OK)throw new Error(d[a]);this.header=new _,s.inflateGetHeader(this.strm,this.header)}function n(t,e){var a=new i(e);if(a.push(t,!0),a.err)throw a.msg||d[a.err];return a.result}function r(t,e){return e=e||{},e.raw=!0,n(t,e)}var s=t("./zlib/inflate"),o=t("./utils/common"),l=t("./utils/strings"),h=t("./zlib/constants"),d=t("./zlib/messages"),f=t("./zlib/zstream"),_=t("./zlib/gzheader"),u=Object.prototype.toString;i.prototype.push=function(t,e){var a,i,n,r,d,f,_=this.strm,c=this.options.chunkSize,b=this.options.dictionary,g=!1;if(this.ended)return!1;i=e===~~e?e:e===!0?h.Z_FINISH:h.Z_NO_FLUSH,"string"==typeof t?_.input=l.binstring2buf(t):"[object ArrayBuffer]"===u.call(t)?_.input=new Uint8Array(t):_.input=t,_.next_in=0,_.avail_in=_.input.length;do{if(0===_.avail_out&&(_.output=new o.Buf8(c),_.next_out=0,_.avail_out=c),a=s.inflate(_,h.Z_NO_FLUSH),a===h.Z_NEED_DICT&&b&&(f="string"==typeof b?l.string2buf(b):"[object ArrayBuffer]"===u.call(b)?new Uint8Array(b):b,a=s.inflateSetDictionary(this.strm,f)),a===h.Z_BUF_ERROR&&g===!0&&(a=h.Z_OK,g=!1),a!==h.Z_STREAM_END&&a!==h.Z_OK)return this.onEnd(a),this.ended=!0,!1;_.next_out&&(0!==_.avail_out&&a!==h.Z_STREAM_END&&(0!==_.avail_in||i!==h.Z_FINISH&&i!==h.Z_SYNC_FLUSH)||("string"===this.options.to?(n=l.utf8border(_.output,_.next_out),r=_.next_out-n,d=l.buf2string(_.output,n),_.next_out=r,_.avail_out=c-r,r&&o.arraySet(_.output,_.output,n,r,0),this.onData(d)):this.onData(o.shrinkBuf(_.output,_.next_out)))),0===_.avail_in&&0===_.avail_out&&(g=!0)}while((_.avail_in>0||0===_.avail_out)&&a!==h.Z_STREAM_END);return a===h.Z_STREAM_END&&(i=h.Z_FINISH),i===h.Z_FINISH?(a=s.inflateEnd(this.strm),this.onEnd(a),this.ended=!0,a===h.Z_OK):i!==h.Z_SYNC_FLUSH||(this.onEnd(h.Z_OK),_.avail_out=0,!0)},i.prototype.onData=function(t){this.chunks.push(t)},i.prototype.onEnd=function(t){t===h.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=o.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},a.Inflate=i,a.inflate=n,a.inflateRaw=r,a.ungzip=n},{"./utils/common":3,"./utils/strings":4,"./zlib/constants":6,"./zlib/gzheader":9,"./zlib/inflate":11,"./zlib/messages":13,"./zlib/zstream":15}],3:[function(t,e,a){"use strict";var i="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;a.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var a=e.shift();if(a){if("object"!=typeof a)throw new TypeError(a+"must be non-object");for(var i in a)a.hasOwnProperty(i)&&(t[i]=a[i])}}return t},a.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var n={arraySet:function(t,e,a,i,n){if(e.subarray&&t.subarray)return void t.set(e.subarray(a,a+i),n);for(var r=0;r=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;o[254]=o[254]=1,a.string2buf=function(t){var e,a,i,r,s,o=t.length,l=0;for(r=0;r>>6,e[s++]=128|63&a):a<65536?(e[s++]=224|a>>>12,e[s++]=128|a>>>6&63,e[s++]=128|63&a):(e[s++]=240|a>>>18,e[s++]=128|a>>>12&63,e[s++]=128|a>>>6&63,e[s++]=128|63&a);return e},a.buf2binstring=function(t){return i(t,t.length)},a.binstring2buf=function(t){for(var e=new n.Buf8(t.length),a=0,i=e.length;a4)h[n++]=65533,a+=s-1;else{for(r&=2===s?31:3===s?15:7;s>1&&a1?h[n++]=65533:r<65536?h[n++]=r:(r-=65536,h[n++]=55296|r>>10&1023,h[n++]=56320|1023&r)}return i(h,n)},a.utf8border=function(t,e){var a;for(e=e||t.length,e>t.length&&(e=t.length),a=e-1;a>=0&&128===(192&t[a]);)a--;return a<0?e:0===a?e:a+o[t[a]]>e?a:e}},{"./common":3}],5:[function(t,e,a){"use strict";function i(t,e,a,i){for(var n=65535&t|0,r=t>>>16&65535|0,s=0;0!==a;){s=a>2e3?2e3:a,a-=s;do n=n+e[i++]|0,r=r+n|0;while(--s);n%=65521,r%=65521}return n|r<<16|0}e.exports=i},{}],6:[function(t,e,a){"use strict";e.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],7:[function(t,e,a){"use strict";function i(){for(var t,e=[],a=0;a<256;a++){t=a;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[a]=t}return e}function n(t,e,a,i){var n=r,s=i+a;t^=-1;for(var o=i;o>>8^n[255&(t^e[o])];return t^-1}var r=i();e.exports=n},{}],8:[function(t,e,a){"use strict";function i(t,e){return t.msg=D[e],e}function n(t){return(t<<1)-(t>4?9:0)}function r(t){for(var e=t.length;--e>=0;)t[e]=0}function s(t){var e=t.state,a=e.pending;a>t.avail_out&&(a=t.avail_out),0!==a&&(R.arraySet(t.output,e.pending_buf,e.pending_out,a,t.next_out),t.next_out+=a,e.pending_out+=a,t.total_out+=a,t.avail_out-=a,e.pending-=a,0===e.pending&&(e.pending_out=0))}function o(t,e){C._tr_flush_block(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,s(t.strm)}function l(t,e){t.pending_buf[t.pending++]=e}function h(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function d(t,e,a,i){var n=t.avail_in;return n>i&&(n=i),0===n?0:(t.avail_in-=n,R.arraySet(e,t.input,t.next_in,n,a),1===t.state.wrap?t.adler=N(t.adler,e,n,a):2===t.state.wrap&&(t.adler=O(t.adler,e,n,a)),t.next_in+=n,t.total_in+=n,n)}function f(t,e){var a,i,n=t.max_chain_length,r=t.strstart,s=t.prev_length,o=t.nice_match,l=t.strstart>t.w_size-ft?t.strstart-(t.w_size-ft):0,h=t.window,d=t.w_mask,f=t.prev,_=t.strstart+dt,u=h[r+s-1],c=h[r+s];t.prev_length>=t.good_match&&(n>>=2),o>t.lookahead&&(o=t.lookahead);do if(a=e,h[a+s]===c&&h[a+s-1]===u&&h[a]===h[r]&&h[++a]===h[r+1]){r+=2,a++;do;while(h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&r<_);if(i=dt-(_-r),r=_-dt,i>s){if(t.match_start=e,s=i,i>=o)break;u=h[r+s-1],c=h[r+s]}}while((e=f[e&d])>l&&0!==--n);return s<=t.lookahead?s:t.lookahead}function _(t){var e,a,i,n,r,s=t.w_size;do{if(n=t.window_size-t.lookahead-t.strstart,t.strstart>=s+(s-ft)){R.arraySet(t.window,t.window,s,s,0),t.match_start-=s,t.strstart-=s,t.block_start-=s,a=t.hash_size,e=a;do i=t.head[--e],t.head[e]=i>=s?i-s:0;while(--a);a=s,e=a;do i=t.prev[--e],t.prev[e]=i>=s?i-s:0;while(--a);n+=s}if(0===t.strm.avail_in)break;if(a=d(t.strm,t.window,t.strstart+t.lookahead,n),t.lookahead+=a,t.lookahead+t.insert>=ht)for(r=t.strstart-t.insert,t.ins_h=t.window[r],t.ins_h=(t.ins_h<t.pending_buf_size-5&&(a=t.pending_buf_size-5);;){if(t.lookahead<=1){if(_(t),0===t.lookahead&&e===I)return vt;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var i=t.block_start+a;if((0===t.strstart||t.strstart>=i)&&(t.lookahead=t.strstart-i,t.strstart=i,o(t,!1),0===t.strm.avail_out))return vt;if(t.strstart-t.block_start>=t.w_size-ft&&(o(t,!1),0===t.strm.avail_out))return vt}return t.insert=0,e===F?(o(t,!0),0===t.strm.avail_out?yt:xt):t.strstart>t.block_start&&(o(t,!1),0===t.strm.avail_out)?vt:vt}function c(t,e){for(var a,i;;){if(t.lookahead=ht&&(t.ins_h=(t.ins_h<=ht)if(i=C._tr_tally(t,t.strstart-t.match_start,t.match_length-ht),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=ht){t.match_length--;do t.strstart++,t.ins_h=(t.ins_h<=ht&&(t.ins_h=(t.ins_h<4096)&&(t.match_length=ht-1)),t.prev_length>=ht&&t.match_length<=t.prev_length){n=t.strstart+t.lookahead-ht,i=C._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-ht),t.lookahead-=t.prev_length-1,t.prev_length-=2;do++t.strstart<=n&&(t.ins_h=(t.ins_h<=ht&&t.strstart>0&&(n=t.strstart-1,i=s[n],i===s[++n]&&i===s[++n]&&i===s[++n])){r=t.strstart+dt;do;while(i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&nt.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=ht?(a=C._tr_tally(t,1,t.match_length-ht),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(a=C._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),a&&(o(t,!1),0===t.strm.avail_out))return vt}return t.insert=0,e===F?(o(t,!0),0===t.strm.avail_out?yt:xt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?vt:kt}function m(t,e){for(var a;;){if(0===t.lookahead&&(_(t),0===t.lookahead)){if(e===I)return vt;break}if(t.match_length=0,a=C._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,a&&(o(t,!1),0===t.strm.avail_out))return vt}return t.insert=0,e===F?(o(t,!0),0===t.strm.avail_out?yt:xt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?vt:kt}function w(t,e,a,i,n){this.good_length=t,this.max_lazy=e,this.nice_length=a,this.max_chain=i,this.func=n}function p(t){t.window_size=2*t.w_size,r(t.head),t.max_lazy_match=Z[t.level].max_lazy,t.good_match=Z[t.level].good_length,t.nice_match=Z[t.level].nice_length,t.max_chain_length=Z[t.level].max_chain,t.strstart=0,t.block_start=0,t.lookahead=0,t.insert=0,t.match_length=t.prev_length=ht-1,t.match_available=0,t.ins_h=0}function v(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=V,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new R.Buf16(2*ot),this.dyn_dtree=new R.Buf16(2*(2*rt+1)),this.bl_tree=new R.Buf16(2*(2*st+1)),r(this.dyn_ltree),r(this.dyn_dtree),r(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new R.Buf16(lt+1),this.heap=new R.Buf16(2*nt+1),r(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new R.Buf16(2*nt+1),r(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function k(t){var e;return t&&t.state?(t.total_in=t.total_out=0,t.data_type=Q,e=t.state,e.pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=e.wrap?ut:wt,t.adler=2===e.wrap?0:1,e.last_flush=I,C._tr_init(e),H):i(t,K)}function y(t){var e=k(t);return e===H&&p(t.state),e}function x(t,e){return t&&t.state?2!==t.state.wrap?K:(t.state.gzhead=e,H):K}function z(t,e,a,n,r,s){if(!t)return K;var o=1;if(e===Y&&(e=6),n<0?(o=0,n=-n):n>15&&(o=2,n-=16),r<1||r>$||a!==V||n<8||n>15||e<0||e>9||s<0||s>W)return i(t,K);8===n&&(n=9);var l=new v;return t.state=l,l.strm=t,l.wrap=o,l.gzhead=null,l.w_bits=n,l.w_size=1<L||e<0)return t?i(t,K):K;if(o=t.state,!t.output||!t.input&&0!==t.avail_in||o.status===pt&&e!==F)return i(t,0===t.avail_out?P:K);if(o.strm=t,a=o.last_flush,o.last_flush=e,o.status===ut)if(2===o.wrap)t.adler=0,l(o,31),l(o,139),l(o,8),o.gzhead?(l(o,(o.gzhead.text?1:0)+(o.gzhead.hcrc?2:0)+(o.gzhead.extra?4:0)+(o.gzhead.name?8:0)+(o.gzhead.comment?16:0)),l(o,255&o.gzhead.time),l(o,o.gzhead.time>>8&255),l(o,o.gzhead.time>>16&255),l(o,o.gzhead.time>>24&255),l(o,9===o.level?2:o.strategy>=G||o.level<2?4:0),l(o,255&o.gzhead.os),o.gzhead.extra&&o.gzhead.extra.length&&(l(o,255&o.gzhead.extra.length),l(o,o.gzhead.extra.length>>8&255)),o.gzhead.hcrc&&(t.adler=O(t.adler,o.pending_buf,o.pending,0)),o.gzindex=0,o.status=ct):(l(o,0),l(o,0),l(o,0),l(o,0),l(o,0),l(o,9===o.level?2:o.strategy>=G||o.level<2?4:0),l(o,zt),o.status=wt);else{var _=V+(o.w_bits-8<<4)<<8,u=-1;u=o.strategy>=G||o.level<2?0:o.level<6?1:6===o.level?2:3,_|=u<<6,0!==o.strstart&&(_|=_t),_+=31-_%31,o.status=wt,h(o,_),0!==o.strstart&&(h(o,t.adler>>>16),h(o,65535&t.adler)),t.adler=1}if(o.status===ct)if(o.gzhead.extra){for(d=o.pending;o.gzindex<(65535&o.gzhead.extra.length)&&(o.pending!==o.pending_buf_size||(o.gzhead.hcrc&&o.pending>d&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending!==o.pending_buf_size));)l(o,255&o.gzhead.extra[o.gzindex]),o.gzindex++;o.gzhead.hcrc&&o.pending>d&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),o.gzindex===o.gzhead.extra.length&&(o.gzindex=0,o.status=bt)}else o.status=bt;if(o.status===bt)if(o.gzhead.name){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindexd&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.gzindex=0,o.status=gt)}else o.status=gt;if(o.status===gt)if(o.gzhead.comment){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindexd&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.status=mt)}else o.status=mt;if(o.status===mt&&(o.gzhead.hcrc?(o.pending+2>o.pending_buf_size&&s(t),o.pending+2<=o.pending_buf_size&&(l(o,255&t.adler),l(o,t.adler>>8&255),t.adler=0,o.status=wt)):o.status=wt),0!==o.pending){if(s(t),0===t.avail_out)return o.last_flush=-1,H}else if(0===t.avail_in&&n(e)<=n(a)&&e!==F)return i(t,P);if(o.status===pt&&0!==t.avail_in)return i(t,P);if(0!==t.avail_in||0!==o.lookahead||e!==I&&o.status!==pt){var c=o.strategy===G?m(o,e):o.strategy===X?g(o,e):Z[o.level].func(o,e);if(c!==yt&&c!==xt||(o.status=pt),c===vt||c===yt)return 0===t.avail_out&&(o.last_flush=-1),H;if(c===kt&&(e===U?C._tr_align(o):e!==L&&(C._tr_stored_block(o,0,0,!1),e===T&&(r(o.head),0===o.lookahead&&(o.strstart=0,o.block_start=0,o.insert=0))),s(t),0===t.avail_out))return o.last_flush=-1,H}return e!==F?H:o.wrap<=0?j:(2===o.wrap?(l(o,255&t.adler),l(o,t.adler>>8&255),l(o,t.adler>>16&255),l(o,t.adler>>24&255),l(o,255&t.total_in),l(o,t.total_in>>8&255),l(o,t.total_in>>16&255),l(o,t.total_in>>24&255)):(h(o,t.adler>>>16),h(o,65535&t.adler)),s(t),o.wrap>0&&(o.wrap=-o.wrap),0!==o.pending?H:j)}function E(t){var e;return t&&t.state?(e=t.state.status,e!==ut&&e!==ct&&e!==bt&&e!==gt&&e!==mt&&e!==wt&&e!==pt?i(t,K):(t.state=null,e===wt?i(t,M):H)):K}function A(t,e){var a,i,n,s,o,l,h,d,f=e.length;if(!t||!t.state)return K;if(a=t.state,s=a.wrap,2===s||1===s&&a.status!==ut||a.lookahead)return K;for(1===s&&(t.adler=N(t.adler,e,f,0)),a.wrap=0,f>=a.w_size&&(0===s&&(r(a.head),a.strstart=0,a.block_start=0,a.insert=0),d=new R.Buf8(a.w_size),R.arraySet(d,e,f-a.w_size,a.w_size,0),e=d,f=a.w_size),o=t.avail_in,l=t.next_in,h=t.input,t.avail_in=f,t.next_in=0,t.input=e,_(a);a.lookahead>=ht;){i=a.strstart,n=a.lookahead-(ht-1);do a.ins_h=(a.ins_h<>>24,b>>>=y,g-=y,y=k>>>16&255,0===y)A[o++]=65535&k;else{if(!(16&y)){if(0===(64&y)){k=m[(65535&k)+(b&(1<>>=y,g-=y),g<15&&(b+=E[r++]<>>24,b>>>=y,g-=y,y=k>>>16&255,!(16&y)){if(0===(64&y)){k=w[(65535&k)+(b&(1<d){t.msg="invalid distance too far back",a.mode=i;break t}if(b>>>=y,g-=y,y=o-l,z>y){if(y=z-y,y>_&&a.sane){t.msg="invalid distance too far back",a.mode=i;break t}if(B=0,S=c,0===u){if(B+=f-y,y2;)A[o++]=S[B++],A[o++]=S[B++],A[o++]=S[B++],x-=3;x&&(A[o++]=S[B++],x>1&&(A[o++]=S[B++]))}else{B=o-z;do A[o++]=A[B++],A[o++]=A[B++],A[o++]=A[B++],x-=3;while(x>2);x&&(A[o++]=A[B++],x>1&&(A[o++]=A[B++]))}break}}break}}while(r>3,r-=x,g-=x<<3,b&=(1<>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function n(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new w.Buf16(320),this.work=new w.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function r(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=T,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new w.Buf32(bt),e.distcode=e.distdyn=new w.Buf32(gt),e.sane=1,e.back=-1,Z):N}function s(t){var e;return t&&t.state?(e=t.state,e.wsize=0,e.whave=0,e.wnext=0,r(t)):N}function o(t,e){var a,i;return t&&t.state?(i=t.state,e<0?(a=0,e=-e):(a=(e>>4)+1,e<48&&(e&=15)),e&&(e<8||e>15)?N:(null!==i.window&&i.wbits!==e&&(i.window=null),i.wrap=a,i.wbits=e,s(t))):N}function l(t,e){var a,i;return t?(i=new n,t.state=i,i.window=null,a=o(t,e),a!==Z&&(t.state=null),a):N}function h(t){return l(t,wt)}function d(t){if(pt){var e;for(g=new w.Buf32(512),m=new w.Buf32(32),e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(y(z,t.lens,0,288,g,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;y(B,t.lens,0,32,m,0,t.work,{bits:5}),pt=!1}t.lencode=g,t.lenbits=9,t.distcode=m,t.distbits=5}function f(t,e,a,i){var n,r=t.state;return null===r.window&&(r.wsize=1<=r.wsize?(w.arraySet(r.window,e,a-r.wsize,r.wsize,0),r.wnext=0,r.whave=r.wsize):(n=r.wsize-r.wnext,n>i&&(n=i),w.arraySet(r.window,e,a-i,n,r.wnext),i-=n,i?(w.arraySet(r.window,e,a-i,i,0),r.wnext=i,r.whave=r.wsize):(r.wnext+=n,r.wnext===r.wsize&&(r.wnext=0),r.whave>>8&255,a.check=v(a.check,Et,2,0),_=0,u=0,a.mode=F;break}if(a.flags=0,a.head&&(a.head.done=!1),!(1&a.wrap)||(((255&_)<<8)+(_>>8))%31){t.msg="incorrect header check",a.mode=_t;break}if((15&_)!==U){t.msg="unknown compression method",a.mode=_t;break}if(_>>>=4,u-=4,yt=(15&_)+8,0===a.wbits)a.wbits=yt;else if(yt>a.wbits){t.msg="invalid window size",a.mode=_t;break}a.dmax=1<>8&1),512&a.flags&&(Et[0]=255&_,Et[1]=_>>>8&255,a.check=v(a.check,Et,2,0)),_=0,u=0,a.mode=L;case L:for(;u<32;){if(0===l)break t;l--,_+=n[s++]<>>8&255,Et[2]=_>>>16&255,Et[3]=_>>>24&255,a.check=v(a.check,Et,4,0)),_=0,u=0,a.mode=H;case H:for(;u<16;){if(0===l)break t;l--,_+=n[s++]<>8),512&a.flags&&(Et[0]=255&_,Et[1]=_>>>8&255,a.check=v(a.check,Et,2,0)),_=0,u=0,a.mode=j;case j:if(1024&a.flags){for(;u<16;){if(0===l)break t;l--,_+=n[s++]<>>8&255,a.check=v(a.check,Et,2,0)),_=0,u=0}else a.head&&(a.head.extra=null);a.mode=K;case K:if(1024&a.flags&&(g=a.length,g>l&&(g=l),g&&(a.head&&(yt=a.head.extra_len-a.length,a.head.extra||(a.head.extra=new Array(a.head.extra_len)),w.arraySet(a.head.extra,n,s,g,yt)),512&a.flags&&(a.check=v(a.check,n,g,s)),l-=g,s+=g,a.length-=g),a.length))break t;a.length=0,a.mode=M;case M:if(2048&a.flags){if(0===l)break t;g=0;do yt=n[s+g++],a.head&&yt&&a.length<65536&&(a.head.name+=String.fromCharCode(yt));while(yt&&g>9&1,a.head.done=!0),t.adler=a.check=0,a.mode=X;break;case q:for(;u<32;){if(0===l)break t;l--,_+=n[s++]<>>=7&u,u-=7&u,a.mode=ht;break}for(;u<3;){if(0===l)break t;l--,_+=n[s++]<>>=1,u-=1,3&_){case 0:a.mode=J;break;case 1:if(d(a),a.mode=at,e===A){_>>>=2,u-=2;break t}break;case 2:a.mode=$;break;case 3:t.msg="invalid block type",a.mode=_t}_>>>=2,u-=2;break;case J:for(_>>>=7&u,u-=7&u;u<32;){if(0===l)break t;l--,_+=n[s++]<>>16^65535)){t.msg="invalid stored block lengths",a.mode=_t;break}if(a.length=65535&_,_=0,u=0,a.mode=Q,e===A)break t;case Q:a.mode=V;case V:if(g=a.length){if(g>l&&(g=l),g>h&&(g=h),0===g)break t;w.arraySet(r,n,s,g,o),l-=g,s+=g,h-=g,o+=g,a.length-=g;break}a.mode=X;break;case $: 4 | for(;u<14;){if(0===l)break t;l--,_+=n[s++]<>>=5,u-=5,a.ndist=(31&_)+1,_>>>=5,u-=5,a.ncode=(15&_)+4,_>>>=4,u-=4,a.nlen>286||a.ndist>30){t.msg="too many length or distance symbols",a.mode=_t;break}a.have=0,a.mode=tt;case tt:for(;a.have>>=3,u-=3}for(;a.have<19;)a.lens[At[a.have++]]=0;if(a.lencode=a.lendyn,a.lenbits=7,zt={bits:a.lenbits},xt=y(x,a.lens,0,19,a.lencode,0,a.work,zt),a.lenbits=zt.bits,xt){t.msg="invalid code lengths set",a.mode=_t;break}a.have=0,a.mode=et;case et:for(;a.have>>24,mt=St>>>16&255,wt=65535&St,!(gt<=u);){if(0===l)break t;l--,_+=n[s++]<>>=gt,u-=gt,a.lens[a.have++]=wt;else{if(16===wt){for(Bt=gt+2;u>>=gt,u-=gt,0===a.have){t.msg="invalid bit length repeat",a.mode=_t;break}yt=a.lens[a.have-1],g=3+(3&_),_>>>=2,u-=2}else if(17===wt){for(Bt=gt+3;u>>=gt,u-=gt,yt=0,g=3+(7&_),_>>>=3,u-=3}else{for(Bt=gt+7;u>>=gt,u-=gt,yt=0,g=11+(127&_),_>>>=7,u-=7}if(a.have+g>a.nlen+a.ndist){t.msg="invalid bit length repeat",a.mode=_t;break}for(;g--;)a.lens[a.have++]=yt}}if(a.mode===_t)break;if(0===a.lens[256]){t.msg="invalid code -- missing end-of-block",a.mode=_t;break}if(a.lenbits=9,zt={bits:a.lenbits},xt=y(z,a.lens,0,a.nlen,a.lencode,0,a.work,zt),a.lenbits=zt.bits,xt){t.msg="invalid literal/lengths set",a.mode=_t;break}if(a.distbits=6,a.distcode=a.distdyn,zt={bits:a.distbits},xt=y(B,a.lens,a.nlen,a.ndist,a.distcode,0,a.work,zt),a.distbits=zt.bits,xt){t.msg="invalid distances set",a.mode=_t;break}if(a.mode=at,e===A)break t;case at:a.mode=it;case it:if(l>=6&&h>=258){t.next_out=o,t.avail_out=h,t.next_in=s,t.avail_in=l,a.hold=_,a.bits=u,k(t,b),o=t.next_out,r=t.output,h=t.avail_out,s=t.next_in,n=t.input,l=t.avail_in,_=a.hold,u=a.bits,a.mode===X&&(a.back=-1);break}for(a.back=0;St=a.lencode[_&(1<>>24,mt=St>>>16&255,wt=65535&St,!(gt<=u);){if(0===l)break t;l--,_+=n[s++]<>pt)],gt=St>>>24,mt=St>>>16&255,wt=65535&St,!(pt+gt<=u);){if(0===l)break t;l--,_+=n[s++]<>>=pt,u-=pt,a.back+=pt}if(_>>>=gt,u-=gt,a.back+=gt,a.length=wt,0===mt){a.mode=lt;break}if(32&mt){a.back=-1,a.mode=X;break}if(64&mt){t.msg="invalid literal/length code",a.mode=_t;break}a.extra=15&mt,a.mode=nt;case nt:if(a.extra){for(Bt=a.extra;u>>=a.extra,u-=a.extra,a.back+=a.extra}a.was=a.length,a.mode=rt;case rt:for(;St=a.distcode[_&(1<>>24,mt=St>>>16&255,wt=65535&St,!(gt<=u);){if(0===l)break t;l--,_+=n[s++]<>pt)],gt=St>>>24,mt=St>>>16&255,wt=65535&St,!(pt+gt<=u);){if(0===l)break t;l--,_+=n[s++]<>>=pt,u-=pt,a.back+=pt}if(_>>>=gt,u-=gt,a.back+=gt,64&mt){t.msg="invalid distance code",a.mode=_t;break}a.offset=wt,a.extra=15&mt,a.mode=st;case st:if(a.extra){for(Bt=a.extra;u>>=a.extra,u-=a.extra,a.back+=a.extra}if(a.offset>a.dmax){t.msg="invalid distance too far back",a.mode=_t;break}a.mode=ot;case ot:if(0===h)break t;if(g=b-h,a.offset>g){if(g=a.offset-g,g>a.whave&&a.sane){t.msg="invalid distance too far back",a.mode=_t;break}g>a.wnext?(g-=a.wnext,m=a.wsize-g):m=a.wnext-g,g>a.length&&(g=a.length),bt=a.window}else bt=r,m=o-a.offset,g=a.length;g>h&&(g=h),h-=g,a.length-=g;do r[o++]=bt[m++];while(--g);0===a.length&&(a.mode=it);break;case lt:if(0===h)break t;r[o++]=a.length,h--,a.mode=it;break;case ht:if(a.wrap){for(;u<32;){if(0===l)break t;l--,_|=n[s++]<=1&&0===j[N];N--);if(O>N&&(O=N),0===N)return b[g++]=20971520,b[g++]=20971520,w.bits=1,0;for(C=1;C0&&(t===o||1!==N))return-1;for(K[1]=0,Z=1;Zr||t===h&&T>s)return 1;for(;;){B=Z-I,m[R]z?(S=M[P+m[R]],E=L[H+m[R]]):(S=96,E=0),p=1<>I)+v]=B<<24|S<<16|E|0;while(0!==v);for(p=1<>=1;if(0!==p?(F&=p-1,F+=p):F=0,R++,0===--j[Z]){if(Z===N)break;Z=e[a+m[R]]}if(Z>O&&(F&y)!==k){for(0===I&&(I=O),x+=C,D=Z-I,U=1<r||t===h&&T>s)return 1;k=F&y,b[k]=O<<24|D<<16|x-g|0}}return 0!==F&&(b[x+F]=Z-I<<24|64<<16|0),w.bits=O,0}},{"../utils/common":3}],13:[function(t,e,a){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],14:[function(t,e,a){"use strict";function i(t){for(var e=t.length;--e>=0;)t[e]=0}function n(t,e,a,i,n){this.static_tree=t,this.extra_bits=e,this.extra_base=a,this.elems=i,this.max_length=n,this.has_stree=t&&t.length}function r(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}function s(t){return t<256?lt[t]:lt[256+(t>>>7)]}function o(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function l(t,e,a){t.bi_valid>W-a?(t.bi_buf|=e<>W-t.bi_valid,t.bi_valid+=a-W):(t.bi_buf|=e<>>=1,a<<=1;while(--e>0);return a>>>1}function f(t){16===t.bi_valid?(o(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}function _(t,e){var a,i,n,r,s,o,l=e.dyn_tree,h=e.max_code,d=e.stat_desc.static_tree,f=e.stat_desc.has_stree,_=e.stat_desc.extra_bits,u=e.stat_desc.extra_base,c=e.stat_desc.max_length,b=0;for(r=0;r<=X;r++)t.bl_count[r]=0;for(l[2*t.heap[t.heap_max]+1]=0,a=t.heap_max+1;ac&&(r=c,b++),l[2*i+1]=r,i>h||(t.bl_count[r]++,s=0,i>=u&&(s=_[i-u]),o=l[2*i],t.opt_len+=o*(r+s),f&&(t.static_len+=o*(d[2*i+1]+s)));if(0!==b){do{for(r=c-1;0===t.bl_count[r];)r--;t.bl_count[r]--,t.bl_count[r+1]+=2,t.bl_count[c]--,b-=2}while(b>0);for(r=c;0!==r;r--)for(i=t.bl_count[r];0!==i;)n=t.heap[--a],n>h||(l[2*n+1]!==r&&(t.opt_len+=(r-l[2*n+1])*l[2*n],l[2*n+1]=r),i--)}}function u(t,e,a){var i,n,r=new Array(X+1),s=0;for(i=1;i<=X;i++)r[i]=s=s+a[i-1]<<1;for(n=0;n<=e;n++){var o=t[2*n+1];0!==o&&(t[2*n]=d(r[o]++,o))}}function c(){var t,e,a,i,r,s=new Array(X+1);for(a=0,i=0;i>=7;i8?o(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0}function m(t,e,a,i){g(t),i&&(o(t,a),o(t,~a)),N.arraySet(t.pending_buf,t.window,e,a,t.pending),t.pending+=a}function w(t,e,a,i){var n=2*e,r=2*a;return t[n]>1;a>=1;a--)p(t,r,a);n=l;do a=t.heap[1],t.heap[1]=t.heap[t.heap_len--],p(t,r,1),i=t.heap[1],t.heap[--t.heap_max]=a,t.heap[--t.heap_max]=i,r[2*n]=r[2*a]+r[2*i],t.depth[n]=(t.depth[a]>=t.depth[i]?t.depth[a]:t.depth[i])+1,r[2*a+1]=r[2*i+1]=n,t.heap[1]=n++,p(t,r,1);while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],_(t,e),u(r,h,t.bl_count)}function y(t,e,a){var i,n,r=-1,s=e[1],o=0,l=7,h=4;for(0===s&&(l=138,h=3),e[2*(a+1)+1]=65535,i=0;i<=a;i++)n=s,s=e[2*(i+1)+1],++o=3&&0===t.bl_tree[2*nt[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}function B(t,e,a,i){var n;for(l(t,e-257,5),l(t,a-1,5),l(t,i-4,4),n=0;n>>=1)if(1&a&&0!==t.dyn_ltree[2*e])return D;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return I;for(e=32;e0?(t.strm.data_type===U&&(t.strm.data_type=S(t)),k(t,t.l_desc),k(t,t.d_desc),s=z(t),n=t.opt_len+3+7>>>3,r=t.static_len+3+7>>>3,r<=n&&(n=r)):n=r=a+5,a+4<=n&&e!==-1?A(t,e,a,i):t.strategy===O||r===n?(l(t,(F<<1)+(i?1:0),3),v(t,st,ot)):(l(t,(L<<1)+(i?1:0),3),B(t,t.l_desc.max_code+1,t.d_desc.max_code+1,s+1),v(t,t.dyn_ltree,t.dyn_dtree)),b(t),i&&g(t)}function C(t,e,a){return t.pending_buf[t.d_buf+2*t.last_lit]=e>>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&a,t.last_lit++,0===e?t.dyn_ltree[2*a]++:(t.matches++,e--,t.dyn_ltree[2*(ht[a]+M+1)]++,t.dyn_dtree[2*s(e)]++),t.last_lit===t.lit_bufsize-1}var N=t("../utils/common"),O=4,D=0,I=1,U=2,T=0,F=1,L=2,H=3,j=258,K=29,M=256,P=M+1+K,Y=30,q=19,G=2*P+1,X=15,W=16,J=7,Q=256,V=16,$=17,tt=18,et=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],at=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],it=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],nt=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],rt=512,st=new Array(2*(P+2));i(st);var ot=new Array(2*Y);i(ot);var lt=new Array(rt);i(lt);var ht=new Array(j-H+1);i(ht);var dt=new Array(K);i(dt);var ft=new Array(Y);i(ft);var _t,ut,ct,bt=!1;a._tr_init=E,a._tr_stored_block=A,a._tr_flush_block=R,a._tr_tally=C,a._tr_align=Z},{"../utils/common":3}],15:[function(t,e,a){"use strict";function i(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}e.exports=i},{}],"/":[function(t,e,a){"use strict";var i=t("./lib/utils/common").assign,n=t("./lib/deflate"),r=t("./lib/inflate"),s=t("./lib/zlib/constants"),o={};i(o,n,r,s),e.exports=o},{"./lib/deflate":1,"./lib/inflate":2,"./lib/utils/common":3,"./lib/zlib/constants":6}]},{},[])("/")}); -------------------------------------------------------------------------------- /web/js/schema_editor.js: -------------------------------------------------------------------------------- 1 | handleHeights = function () { 2 | var iframes = $("iframe"), 3 | len = iframes.length, 4 | index, 5 | snippet, 6 | overflow, 7 | overflowData, 8 | height; 9 | 10 | for (index = 0; index < len; index++) { 11 | // Element for height measurement. 12 | snippet = $(iframes[index]).contents().find("#snippet"); 13 | overflow = snippet.css("overflow"); 14 | overflowData = snippet.attr("data-default-overflow"); 15 | if (overflowData !== undefined && overflowData !== "") { 16 | overflow = overflowData; 17 | } 18 | else { 19 | // Sets default after first check, so temp value does not get picked on resize iterations. 20 | snippet.attr("data-default-overflow", overflow); 21 | } 22 | snippet.css("overflow", "scroll"); // sets temp value for measuring 23 | height = snippet.get(0).offsetHeight; 24 | snippet.css("overflow", overflow); // sets styling value 25 | 26 | $(iframes[index]).height(height); 27 | } 28 | }; 29 | 30 | var $preview = $(".js-snippet-preview"), 31 | $previewSource = $preview.find("iframe"), 32 | //viewport 33 | $handleLeft = $(".js-snippet-resize-handle-left"), 34 | $handleRight = $(".js-snippet-resize-handle-right"), 35 | $resizeLength = $(".js-resize-length"), 36 | //data 37 | snippetSource = $(".js-snippet-source"); 38 | 39 | (function () { 40 | var windowWidth = $(".left").width(), 41 | width = 1024; 42 | 43 | if ((width) + 100 > windowWidth) { 44 | width = (windowWidth - 100); 45 | } 46 | $preview.css('width', width); 47 | $resizeLength.css('width', parseInt(width / 2, 10)); 48 | })(); 49 | 50 | interact('.js-resize-length') 51 | .resizable( 52 | { 53 | edges: { 54 | left: ".js-snippet-resize-handle-right", 55 | right: ".js-snippet-resize-handle-left", 56 | bottom: false, 57 | top: false 58 | }, 59 | onmove: function (e) { 60 | 61 | var width = e.rect.width, 62 | windowWidth = $(".left").width(); 63 | 64 | if (width < 160) { 65 | width = 160; 66 | } 67 | else if ((width * 2) + 100 > windowWidth) { 68 | width = (windowWidth - 100) / 2; 69 | } 70 | 71 | $preview 72 | .find(snippetSource) 73 | .addClass('resize-overlay'); 74 | $preview[0].style.width = (width * 2) + 'px'; 75 | $resizeLength[0].style.width = width + 'px'; 76 | handleHeights(); 77 | }, 78 | onend: function () { 79 | $preview 80 | .find(snippetSource) 81 | .removeClass('resize-overlay'); 82 | handleHeights(); 83 | } 84 | } 85 | ); 86 | 87 | var editor_update = function (markup, json) { 88 | $("#display_holder").attr('srcdoc', markup); 89 | $("#json_holder pre").text(JSON.stringify(json, null, 2)); 90 | $("#twig_holder").text(JSON.stringify(json, null, 2)); 91 | updateDirectLink(); 92 | $('#display_holder').load( 93 | function () { 94 | handleHeights(); 95 | } 96 | ); 97 | }; 98 | 99 | var updateDirectLink = function () { 100 | var url = window.location.href.replace(/\?.*/, ''); 101 | var configVal = JSON.stringify(editor.getValue()); 102 | url += '?data=' + encodeURIComponent(btoa(pako.deflate(configVal, {to: 'string'}))); 103 | document.getElementById('direct_link').href = url; 104 | }; 105 | 106 | if (window.location.href.match('[?&]data=([^&]+)')) { 107 | try { 108 | var configVal = window.location.href.match('[?&]data=([^&]+)')[1]; 109 | configVal = atob(decodeURIComponent(configVal)); 110 | data.starting = JSON.parse(pako.inflate(configVal, {to: 'string'})); 111 | } 112 | catch (e) { 113 | console.log('invalid starting data'); 114 | } 115 | } 116 | if (data.starting.name) { 117 | JSONEditor.defaults.options.startval = data.starting; 118 | } 119 | 120 | // Initialize the editor with a JSON schema 121 | var editor = new JSONEditor( 122 | document.getElementById('editor_holder'), { 123 | schema: data.schema, 124 | theme: 'bootstrap3', 125 | iconlib: 'fontawesome4', 126 | keep_oneof_values: false 127 | } 128 | ); 129 | 130 | JSONEditor.plugins.sceditor.emoticonsEnabled = false; 131 | JSONEditor.plugins.ace.theme = 'twilight'; 132 | 133 | // Schema editor ajax debouncer. 134 | // 135 | // Returns a function, that, as long as it continues to be invoked, will not 136 | // be triggered. The function will be called after it stops being called for 137 | // N milliseconds. If `immediate` is passed, trigger the function on the 138 | // leading edge, instead of the trailing. 139 | schemaEditorDebounce = function (func, wait, immediate) { 140 | var timeout; 141 | return function () { 142 | var context = this, args = arguments; 143 | var later = function () { 144 | timeout = null; 145 | if (!immediate) { 146 | func.apply(context, args); 147 | } 148 | }; 149 | var callNow = immediate && !timeout; 150 | clearTimeout(timeout); 151 | timeout = setTimeout(later, wait); 152 | 153 | if (callNow) { 154 | func.apply(context, args); 155 | } 156 | }; 157 | }; 158 | 159 | // On changes to the editor UI, validate the JSON And update the preview render. 160 | editor.on( 161 | 'change', schemaEditorDebounce(function () { 162 | var json = editor.getValue(); 163 | 164 | $.ajax( 165 | { 166 | url: "/api/validate", 167 | method: 'POST', 168 | contentType: 'application/json', 169 | data: JSON.stringify(json, null, 2) 170 | } 171 | ).success( 172 | function (response) { 173 | if (response.trim() === "The supplied JSON validates against the schema.") { 174 | $('.valid').removeClass('alert-danger').addClass('alert-success'); 175 | } 176 | else if (response.includes("The supplied JSON validates against the schema.")) { 177 | $('.valid').removeClass('alert-danger').addClass('alert-warning'); 178 | } 179 | 180 | $('.valid').html(response); 181 | $.ajax( 182 | { 183 | url: "/api/render/page", 184 | method: 'POST', 185 | contentType: 'application/json', 186 | data: JSON.stringify(json, null, 2) 187 | } 188 | ).done( 189 | function (markup) { 190 | editor_update(markup, json); 191 | } 192 | ); 193 | 194 | } 195 | ); 196 | }, 500) 197 | ); 198 | 199 | --------------------------------------------------------------------------------