├── .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 |
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 |
6 | {{attribution_name}} {% if attribution_title %}, {{attribution_title}}{% endif %}
7 |
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 |
39 | {% block secondary_nav %}{% endblock %}
40 |
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 |
5 |
6 |
9 |
10 |
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 |
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 |
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 |
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 |
84 |
Save and share this prototype
85 |
A unique URL will be generated that contains all your content and settings within this pattern, which you can then share with anyone who has access to this tool.
86 |
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 |
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 |
2 |
3 |
12 |
13 |
29 | {% if sg_active %}
30 |
33 | {% endif %}
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/resources/templates/secondary-nav.twig:
--------------------------------------------------------------------------------
1 |
2 | {# This logic renders the secondary nav items in the order specified #}
3 | {# Otherwise they are randomly ordered in the list #}
4 | {% set secondary_nav_ordered, secondary_nav_random = [], [] %}
5 | {% for i in 0..secondary_nav|length %}
6 | {% for item in secondary_nav %}
7 | {% if loop.index == 1 and i == 0 %}
8 | {% endif %}
9 | {% if item.order %}
10 | {% if item.order == (i + 1) %}
11 | {% set secondary_nav_ordered = secondary_nav_ordered|merge([ item ]) %}
12 | {% endif %}
13 | {% else %}
14 | {# Only add random items during the first loop #}
15 | {% if i == 0 %}
16 | {% set secondary_nav_random = secondary_nav_random|merge([ item ]) %}
17 | {% endif %}
18 | {% endif %}
19 | {% endfor %}
20 | {% endfor %}
21 | {# Add the nav items without specified order to the end of the list #}
22 | {% set secondary_nav_ordered = secondary_nav_ordered|merge(secondary_nav_random) %}
23 |
24 | {% for item in secondary_nav_ordered %}
25 |
26 |
27 | {{ item.title }}
28 |
29 |
30 | {% endfor %}
31 |
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 |
12 |
13 | {% for css in app_config.assets.custom.css.shared %}
14 |
15 | {% endfor %}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {% include template ?: name ~ '.twig' %}
24 |
25 |
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 |
--------------------------------------------------------------------------------