UNPKG

6.07 kBJavaScriptView Raw
1/**
2@license
3Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4This code may only be used under the BSD style license found at
5http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
6http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
7found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
8part of the polymer project is also subject to an additional IP rights grant
9found at http://polymer.github.io/PATENTS.txt
10*/
11
12import '@polymer/polymer/polymer-legacy.js';
13import '@polymer/marked-element/marked-element.js';
14import '@polymer/prism-element/prism-highlighter.js';
15import '@polymer/prism-element/prism-theme-default.js';
16
17import {Polymer} from '@polymer/polymer/lib/legacy/polymer-fn.js';
18import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
19import {html} from '@polymer/polymer/lib/utils/html-tag.js';
20
21/**
22`demo-snippet` is a helper element that displays the source of a code snippet
23and its rendered demo. It can be used for both native elements and Polymer
24elements.
25
26 Example of a native element demo
27
28 <demo-snippet>
29 <template>
30 <input type="date">
31 </template>
32 </demo-snippet>
33
34 Example of a Polymer <paper-checkbox> demo
35
36 <demo-snippet>
37 <template>
38 <paper-checkbox>Checkbox</paper-checkbox>
39 <paper-checkbox checked>Checkbox</paper-checkbox>
40 </template>
41 </demo-snippet>
42
43### Styling
44
45The following custom properties and mixins are available for styling:
46
47Custom property | Description | Default
48----------------|-------------|----------
49`--demo-snippet` | Mixin applied to the entire element | `{}`
50`--demo-snippet-demo` | Mixin applied to just the demo section | `{}`
51`--demo-snippet-code` | Mixin applied to just the code section | `{}`
52
53@element demo-snippet
54@demo demo/index.html
55*/
56Polymer({
57 _template: html`
58 <style include="prism-theme-default">
59 :host {
60 display: block;
61
62 box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
63 0 1px 5px 0 rgba(0, 0, 0, 0.12),
64 0 3px 1px -2px rgba(0, 0, 0, 0.2);
65 margin-bottom: 40px;
66 @apply --demo-snippet;
67 }
68
69 .demo {
70 display: block;
71 border-bottom: 1px solid #e0e0e0;
72 background-color: white;
73 margin: 0;
74 padding: 20px;
75 @apply --demo-snippet-demo;
76 }
77
78 .code-container {
79 margin: 0;
80 background-color: #f5f5f5;
81 font-size: 13px;
82 overflow: auto;
83 position: relative;
84 padding: 0 20px;
85 @apply --demo-snippet-code;
86 }
87
88 .code {
89 padding: 20px;
90 margin: 0;
91 background-color: var(--google-grey-100);
92 font-size: 13px;
93 overflow: auto;
94 @apply --demo-snippet-code;
95 }
96 .code > pre {
97 margin: 0;
98 padding: 0 0 10px 0;
99 }
100
101 button {
102 position: absolute;
103 top: 0;
104 right: 0px;
105 text-transform: uppercase;
106 border: none;
107 cursor: pointer;
108 background: #e0e0e0;
109 }
110 </style>
111
112 <prism-highlighter></prism-highlighter>
113
114 <div class="demo">
115 <slot id="content"></slot>
116 </div>
117
118 <div class="code-container">
119 <marked-element markdown="[[_markdown]]" id="marked">
120 <div class="code" slot="markdown-html" id="code"></div>
121 </marked-element>
122 <button id="copyButton" title="copy to clipboard" on-tap="_copyToClipboard">Copy</button>
123 </div>
124`,
125
126 is: 'demo-snippet',
127
128 properties: {
129
130 /**
131 * Fired when the demo-snippet is ready, i.e. when it has injected the code to demo
132 * in the DOM and it can be interacted with
133 *
134 * @event dom-ready
135 */
136
137 /** @private */
138 _markdown: {
139 type: String,
140 },
141 },
142
143 attached: function() {
144 this._observer = dom(this.$.content).observeNodes(function(info) {
145 this._updateMarkdown();
146 }.bind(this));
147 },
148
149 detached: function() {
150 if (this._observer) {
151 dom(this.$.content).unobserveNodes(this._observer);
152 this._observer = null;
153 }
154 },
155
156 _updateMarkdown: function() {
157 var template = dom(this).queryDistributedElements('template')[0];
158
159 // If there's no template, render empty code.
160 if (!template) {
161 this._markdown = '';
162 return;
163 }
164
165 var snippet = this.$.marked.unindent(template.innerHTML);
166
167 // Hack: In safari + shady dom, sometime we get an empty 'class' attribute.
168 // if we do, delete it.
169 snippet = snippet.replace(/ class=""/g, '');
170
171 // Boolean properties are displayed as checked="", so remove the ="" bit.
172 snippet = snippet.replace(/=""/g, '');
173
174 this._markdown = '```\n' + snippet + '\n' +
175 '```';
176 // Stamp the template.
177 if (!template.hasAttribute('is')) {
178 // Don't need to listen for more changes (since stamping the template
179 // will trigger an observeNodes)
180 dom(this.$.content).unobserveNodes(this._observer);
181 this._observer = null;
182 dom(this).appendChild(document.importNode(template.content, true));
183 }
184 this.dispatchEvent(new CustomEvent('dom-ready'));
185 },
186
187 _copyToClipboard: function() {
188 // From
189 // https://github.com/google/material-design-lite/blob/master/docs/_assets/snippets.js
190 var snipRange = document.createRange();
191 snipRange.selectNodeContents(this.$.code);
192 var selection = window.getSelection();
193 selection.removeAllRanges();
194 selection.addRange(snipRange);
195 var result = false;
196 try {
197 result = document.execCommand('copy');
198 this.$.copyButton.textContent = 'done';
199 } catch (err) {
200 // Copy command is not available
201 console.error(err);
202 this.$.copyButton.textContent = 'error';
203 }
204
205 // Return to the copy button after a second.
206 setTimeout(this._resetCopyButtonState.bind(this), 1000);
207
208 selection.removeAllRanges();
209 return result;
210 },
211
212 _resetCopyButtonState: function() {
213 this.$.copyButton.textContent = 'copy';
214 }
215});