jekyll-webmention_io 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/jekyll/assets/JekyllWebmentionIO.js +511 -0
- data/lib/jekyll/assets/_utils.js +33 -0
- data/lib/jekyll/assets/liquid.js +134 -0
- data/lib/jekyll/assets/webmention_counters.js +48 -0
- data/lib/jekyll/assets/webmention_loader.js +34 -0
- data/lib/jekyll/assets/webmention_websocket.js +21 -0
- data/lib/jekyll/generators/compile_js.rb +74 -0
- data/lib/jekyll/generators/gather_webmentions.rb +182 -175
- data/lib/jekyll/tags/_.rb +7 -3
- data/lib/jekyll/tags/count.rb +2 -2
- data/lib/jekyll/tags/likes.rb +1 -1
- data/lib/jekyll/tags/links.rb +1 -1
- data/lib/jekyll/tags/posts.rb +1 -1
- data/lib/jekyll/tags/replies.rb +1 -1
- data/lib/jekyll/tags/reposts.rb +1 -1
- data/lib/jekyll/tags/webmentions_head.rb +34 -0
- data/lib/jekyll/tags/webmentions_js.rb +56 -0
- data/lib/jekyll/templates/count.html +2 -1
- data/lib/jekyll/templates/likes.html +15 -15
- data/lib/jekyll/templates/links.html +20 -18
- data/lib/jekyll/templates/posts.html +12 -12
- data/lib/jekyll/templates/replies.html +26 -24
- data/lib/jekyll/templates/reposts.html +15 -15
- data/lib/jekyll/templates/webmentions.html +32 -31
- data/lib/jekyll/webmention_io/version.rb +1 -1
- metadata +25 -3
- data/lib/jekyll/assets/webmention_io.js +0 -549
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 050572d103fbe6372e35ddc50d232de12227baf7
|
4
|
+
data.tar.gz: 8f0d233cf38cd0de07bfa64a74c85adc1fea97e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 241a79370736d77a40337a48e220f333ba8fa9d4ea3b6487910b7065992c6cdf633eed6f3aeca20e5d942a220a3cc8973a322a15cf4b48ec7cab94e72c92ac28
|
7
|
+
data.tar.gz: 5f7df1e176bc298f8538347486f55eeb69b2a66d87371967a2e52eead9eefb4a2de5821f94cce741ed49f50bfd2d3d032a86273f98e9e3a7513ba275e2e12f26
|
@@ -0,0 +1,511 @@
|
|
1
|
+
(function(window, document){
|
2
|
+
|
3
|
+
// prerequisites
|
4
|
+
if ( ! ( 'querySelectorAll' in document ) ||
|
5
|
+
! ( 'filter' in [] ) ||
|
6
|
+
! ( 'content' in document.createElement('template') ) ){ return; }
|
7
|
+
|
8
|
+
if ( ! ( 'JekyllWebmentionIO' in window ) ){ window.JekyllWebmentionIO = {}; }
|
9
|
+
|
10
|
+
//
|
11
|
+
// Public Properties
|
12
|
+
//
|
13
|
+
JekyllWebmentionIO.existing_webmentions = [];
|
14
|
+
|
15
|
+
//
|
16
|
+
// Public Methods
|
17
|
+
//
|
18
|
+
|
19
|
+
JekyllWebmentionIO.processWebmentions = function( data ){
|
20
|
+
// console.log( 'incoming webmentions', data.links );
|
21
|
+
if ( data && ! ( 'error' in data ) )
|
22
|
+
{
|
23
|
+
webmentions = data.links.reverse();
|
24
|
+
|
25
|
+
webmentions = rationalizeIds( webmentions );
|
26
|
+
|
27
|
+
webmentions = removeDuplicates( webmentions );
|
28
|
+
|
29
|
+
// We may not need to proceed if we had them all
|
30
|
+
if ( webmentions.length )
|
31
|
+
{
|
32
|
+
webmentions = addMetadata( webmentions );
|
33
|
+
|
34
|
+
// hande them out
|
35
|
+
doleOutWebmentions( webmentions );
|
36
|
+
|
37
|
+
// reset the counters
|
38
|
+
if ( this.counter_update_event )
|
39
|
+
{
|
40
|
+
document.dispatchEvent( this.counter_update_event );
|
41
|
+
}
|
42
|
+
}
|
43
|
+
else
|
44
|
+
{
|
45
|
+
// console.log( 'no new webmentions to add' );
|
46
|
+
}
|
47
|
+
}
|
48
|
+
};
|
49
|
+
|
50
|
+
//
|
51
|
+
// Private Properties
|
52
|
+
//
|
53
|
+
|
54
|
+
var webmention_receivers = {},
|
55
|
+
templates = {};
|
56
|
+
|
57
|
+
//
|
58
|
+
// Private Methods
|
59
|
+
//
|
60
|
+
|
61
|
+
// Gathers embewdded templates
|
62
|
+
function collectTemplates()
|
63
|
+
{
|
64
|
+
var $templates = document.querySelectorAll( 'template[id^=webmention-]' ),
|
65
|
+
t = $templates.length,
|
66
|
+
$template;
|
67
|
+
|
68
|
+
while ( t-- )
|
69
|
+
{
|
70
|
+
$template = $templates[t];
|
71
|
+
// We only need the list (if one exists)
|
72
|
+
if ( $template.content.querySelector('ol') )
|
73
|
+
{
|
74
|
+
templates[$template.id] = $template.content.querySelector('ol');
|
75
|
+
}
|
76
|
+
else
|
77
|
+
{
|
78
|
+
templates[$template.id] = $template.content;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
$template = null;
|
82
|
+
}
|
83
|
+
|
84
|
+
// Collects webmentions that are already on the page
|
85
|
+
function collectExistingWebmentions()
|
86
|
+
{
|
87
|
+
var $existing_webmentions = document.querySelectorAll( '[id^=webmention-]' ),
|
88
|
+
e = $existing_webmentions.length;
|
89
|
+
|
90
|
+
while ( e-- )
|
91
|
+
{
|
92
|
+
JekyllWebmentionIO.existing_webmentions.push(
|
93
|
+
$existing_webmentions[e]
|
94
|
+
.getAttribute( 'id' )
|
95
|
+
.replace( 'webmention-', '' )
|
96
|
+
);
|
97
|
+
}
|
98
|
+
|
99
|
+
$existing_webmentions = null;
|
100
|
+
}
|
101
|
+
|
102
|
+
function identifyWebmentionCollections()
|
103
|
+
{
|
104
|
+
var $webmention_collections = document.querySelectorAll( '.webmentions' ),
|
105
|
+
w = $webmention_collections.length,
|
106
|
+
$webmention_collection,
|
107
|
+
type,
|
108
|
+
types, t;
|
109
|
+
|
110
|
+
// Assign the type & template if we can determine it
|
111
|
+
while ( w-- )
|
112
|
+
{
|
113
|
+
$webmention_collection = $webmention_collections[w];
|
114
|
+
|
115
|
+
// Assign the type
|
116
|
+
type = 'webmentions'; // Generic
|
117
|
+
if ( $webmention_collection.className.indexOf('webmentions--') > -1 )
|
118
|
+
{
|
119
|
+
type = $webmention_collection.className.match(/webmentions\-\-(.*)/)[1];
|
120
|
+
}
|
121
|
+
$webmention_collection.type = type;
|
122
|
+
|
123
|
+
// Assign the template
|
124
|
+
if ( templates['webmention-' + type] )
|
125
|
+
{
|
126
|
+
$webmention_collection.template = templates['webmention-' + type];
|
127
|
+
}
|
128
|
+
|
129
|
+
// Add to the queues
|
130
|
+
if ( 'dataset' in $webmention_collection &&
|
131
|
+
'webmentionTypes' in $webmention_collection.dataset )
|
132
|
+
{
|
133
|
+
types = $webmention_collection.dataset.webmentionTypes.split(',');
|
134
|
+
}
|
135
|
+
else
|
136
|
+
{
|
137
|
+
types = [ type ];
|
138
|
+
}
|
139
|
+
t = types.length;
|
140
|
+
while (t--)
|
141
|
+
{
|
142
|
+
type = types[t];
|
143
|
+
if ( ! ( type in webmention_receivers ) )
|
144
|
+
{
|
145
|
+
webmention_receivers[type] = [];
|
146
|
+
}
|
147
|
+
webmention_receivers[type].push( $webmention_collection );
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
$webmention_collection = null;
|
152
|
+
}
|
153
|
+
|
154
|
+
// Divvies up the webmentions and populate the lists
|
155
|
+
function doleOutWebmentions( webmentions )
|
156
|
+
{
|
157
|
+
var i = 0, j,
|
158
|
+
webmention,
|
159
|
+
incoming = {},
|
160
|
+
queue_keys = Object.keys( webmention_receivers ),
|
161
|
+
plural_type;
|
162
|
+
|
163
|
+
// set up the queues
|
164
|
+
i = queue_keys.length;
|
165
|
+
while( i--)
|
166
|
+
{
|
167
|
+
incoming[queue_keys[i]] = [];
|
168
|
+
}
|
169
|
+
|
170
|
+
// Assign the webmentions to their respective queues
|
171
|
+
i = webmentions.length;
|
172
|
+
while ( i-- )
|
173
|
+
{
|
174
|
+
webmention = webmentions[i];
|
175
|
+
// reverse lookup to get the plural from the singular
|
176
|
+
plural_type = Object.keys(JekyllWebmentionIO.types)
|
177
|
+
.filter(function(key) {
|
178
|
+
return JekyllWebmentionIO.types[key] === webmention.type;
|
179
|
+
})[0];
|
180
|
+
|
181
|
+
// Is there a specific queue requesting this?
|
182
|
+
if ( queue_keys.indexOf( plural_type ) > -1 )
|
183
|
+
{
|
184
|
+
incoming[plural_type].push( webmention );
|
185
|
+
}
|
186
|
+
|
187
|
+
// If there’s a generic, add it there too
|
188
|
+
if ( incoming.webmentions )
|
189
|
+
{
|
190
|
+
incoming.webmentions.push( webmention );
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
// Now hand them out
|
195
|
+
i = queue_keys.length;
|
196
|
+
while( i-- )
|
197
|
+
{
|
198
|
+
j = webmention_receivers[queue_keys[i]].length;
|
199
|
+
while ( j-- )
|
200
|
+
{
|
201
|
+
// No point passing nothing
|
202
|
+
if ( incoming[queue_keys[i]].length > 0 )
|
203
|
+
{
|
204
|
+
addWebmentionsToCollection( incoming[queue_keys[i]], webmention_receivers[queue_keys[i]][j] );
|
205
|
+
}
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
}
|
210
|
+
|
211
|
+
function addWebmentionsToCollection( mentions, $webmention_collection )
|
212
|
+
{
|
213
|
+
if ( mentions.length < 1 )
|
214
|
+
{
|
215
|
+
console.warn( 'No webmentions to add, check your application code' );
|
216
|
+
return;
|
217
|
+
}
|
218
|
+
|
219
|
+
if ( ! $webmention_collection.template )
|
220
|
+
{
|
221
|
+
console.error( 'No template found for this webmention group', $webmention_collection );
|
222
|
+
return;
|
223
|
+
}
|
224
|
+
|
225
|
+
if ( ! ( 'Liquid' in window ) )
|
226
|
+
{
|
227
|
+
console.error( 'Liquid parsing engine is not available' );
|
228
|
+
return;
|
229
|
+
}
|
230
|
+
|
231
|
+
var $list = $webmention_collection.querySelector('.webmentions__list'),
|
232
|
+
template = $webmention_collection.template,
|
233
|
+
mode = 'append',
|
234
|
+
html;
|
235
|
+
|
236
|
+
// Already working with a list
|
237
|
+
if ( $list )
|
238
|
+
{
|
239
|
+
template = Liquid.parse( template.innerHTML );
|
240
|
+
}
|
241
|
+
// Need a list
|
242
|
+
else
|
243
|
+
{
|
244
|
+
template = Liquid.parse( template.outerHTML );
|
245
|
+
mode = 'replace';
|
246
|
+
}
|
247
|
+
|
248
|
+
// append
|
249
|
+
html = template.render({ 'webmentions': mentions });
|
250
|
+
if ( mode == 'append' )
|
251
|
+
{
|
252
|
+
$list.innerHTML += html;
|
253
|
+
}
|
254
|
+
else
|
255
|
+
{
|
256
|
+
$webmention_collection.innerHTML = html;
|
257
|
+
}
|
258
|
+
|
259
|
+
// console.log( 'Successfully added', mentions.length );
|
260
|
+
}
|
261
|
+
|
262
|
+
// Uses the ID attribute for everything except tweets
|
263
|
+
function rationalizeIds( webmentions )
|
264
|
+
{
|
265
|
+
// console.log( 'rationizing IDs' );
|
266
|
+
var i = webmentions.length,
|
267
|
+
id,
|
268
|
+
url;
|
269
|
+
|
270
|
+
while ( i-- )
|
271
|
+
{
|
272
|
+
id = webmentions[i].id;
|
273
|
+
url = webmentions[i].data.url || webmentions[i].source;
|
274
|
+
if ( url && url.indexOf( 'twitter.com/' ) > -1 )
|
275
|
+
{
|
276
|
+
// Unique tweets gets unique IDs
|
277
|
+
if ( url.indexOf( '#favorited-by' ) < 0 )
|
278
|
+
{
|
279
|
+
id = url.replace( /^.*?status\/(\d+)$/, '$1' );
|
280
|
+
}
|
281
|
+
}
|
282
|
+
// coerce to a string
|
283
|
+
webmentions[i].id = id + '';
|
284
|
+
}
|
285
|
+
|
286
|
+
// console.log( webmentions.length, 'IDs rationalized' );
|
287
|
+
return webmentions;
|
288
|
+
}
|
289
|
+
|
290
|
+
// Removes duplicate webmentions
|
291
|
+
function removeDuplicates( webmentions )
|
292
|
+
{
|
293
|
+
// console.log( 'removing duplicates' );
|
294
|
+
// going backwards, so reverse things to start out
|
295
|
+
webmentions.reverse();
|
296
|
+
|
297
|
+
var unique_webmentions = [],
|
298
|
+
i = webmentions.length,
|
299
|
+
id;
|
300
|
+
|
301
|
+
while ( i-- )
|
302
|
+
{
|
303
|
+
if ( JekyllWebmentionIO.existing_webmentions.indexOf( webmentions[i].id ) < 0 )
|
304
|
+
{
|
305
|
+
unique_webmentions.push(webmentions[i]);
|
306
|
+
}
|
307
|
+
}
|
308
|
+
|
309
|
+
// console.log( 'removed', webmentions.length - unique_webmentions.length, 'duplicates' );
|
310
|
+
return unique_webmentions;
|
311
|
+
}
|
312
|
+
|
313
|
+
// Adds the necessary metadata to each webmention object for the liquid templates
|
314
|
+
function addMetadata( webmentions )
|
315
|
+
{
|
316
|
+
// console.log( 'adding metadata' );
|
317
|
+
// going backwards, so reverse things to start out
|
318
|
+
webmentions.reverse();
|
319
|
+
|
320
|
+
var i = webmentions.length,
|
321
|
+
webmention,
|
322
|
+
webmention_object;
|
323
|
+
|
324
|
+
while ( i-- )
|
325
|
+
{
|
326
|
+
webmention = webmentions[i];
|
327
|
+
|
328
|
+
uri = webmention.data.url || webmention.source;
|
329
|
+
|
330
|
+
source = false;
|
331
|
+
if ( uri.indexOf('twitter.com/') )
|
332
|
+
{
|
333
|
+
source = 'twitter';
|
334
|
+
}
|
335
|
+
else if ( uri.indexOf('/googleplus/') > -1 )
|
336
|
+
{
|
337
|
+
source = 'googleplus';
|
338
|
+
}
|
339
|
+
|
340
|
+
pubdate = webmention.data.published_ts;
|
341
|
+
if ( ! pubdate && webmention.verified_date )
|
342
|
+
{
|
343
|
+
pubdate = webmention.verified_date;
|
344
|
+
}
|
345
|
+
if ( pubdate )
|
346
|
+
{
|
347
|
+
pubdate = (new Date(pubdate)).getTime();
|
348
|
+
}
|
349
|
+
|
350
|
+
webmention_object = {
|
351
|
+
id: webmention.id,
|
352
|
+
url: uri,
|
353
|
+
source: source,
|
354
|
+
pubdate: pubdate,
|
355
|
+
raw: webmentions[i]
|
356
|
+
};
|
357
|
+
|
358
|
+
if ( 'author' in webmention.data )
|
359
|
+
{
|
360
|
+
webmention_object.author = webmentions[i].data.author;
|
361
|
+
}
|
362
|
+
|
363
|
+
type = webmentions[i].activity.type;
|
364
|
+
if ( ! type )
|
365
|
+
{
|
366
|
+
if ( source == 'googleplus' )
|
367
|
+
{
|
368
|
+
if ( uri.indexOf('/like/') > -1 )
|
369
|
+
{
|
370
|
+
type = 'like';
|
371
|
+
}
|
372
|
+
else if ( uri.indexOf( '/repost/' ) > -1 )
|
373
|
+
{
|
374
|
+
type = 'repost';
|
375
|
+
}
|
376
|
+
else if ( uri.indexOf( '/comment/' ) > -1 )
|
377
|
+
{
|
378
|
+
type = 'reply';
|
379
|
+
}
|
380
|
+
else
|
381
|
+
{
|
382
|
+
type = 'link';
|
383
|
+
}
|
384
|
+
}
|
385
|
+
else
|
386
|
+
{
|
387
|
+
type = 'post';
|
388
|
+
}
|
389
|
+
}
|
390
|
+
webmention_object.type = type;
|
391
|
+
|
392
|
+
// Posts
|
393
|
+
title = false;
|
394
|
+
if ( type == 'post' )
|
395
|
+
{
|
396
|
+
readWebPage( uri, function( html_source ){
|
397
|
+
if ( html_source )
|
398
|
+
{
|
399
|
+
updateTitle( webmention_object.id, uri, html_source );
|
400
|
+
}
|
401
|
+
});
|
402
|
+
}
|
403
|
+
|
404
|
+
content = webmention.data.content;
|
405
|
+
if ( type != 'post' && type != 'reply' && type != 'link' )
|
406
|
+
{
|
407
|
+
content = webmention.activity.sentence_html;
|
408
|
+
}
|
409
|
+
webmention_object.content = content;
|
410
|
+
|
411
|
+
// replace the existing webmention
|
412
|
+
webmentions[i] = webmention_object;
|
413
|
+
}
|
414
|
+
|
415
|
+
// console.log( 'added metadata to', webmentions.length, 'webmentions' );
|
416
|
+
return webmentions;
|
417
|
+
}
|
418
|
+
|
419
|
+
// Async update of the title
|
420
|
+
function updateTitle( webmention_id, url, html_source )
|
421
|
+
{
|
422
|
+
var $webmention = document.querySelector( '#webmention-' + webmention_id ),
|
423
|
+
$current_title = $webmention.querySelector( '.webmention__title' ),
|
424
|
+
$page = document.createElement('html'),
|
425
|
+
title = '',
|
426
|
+
$link_title,
|
427
|
+
$title,
|
428
|
+
$h1;
|
429
|
+
|
430
|
+
$page.innerHTML = html_source;
|
431
|
+
$title = $page.querySelector('title');
|
432
|
+
$h1 = $page.querySelector('h1');
|
433
|
+
|
434
|
+
if ( $current_title.length < 0 )
|
435
|
+
{
|
436
|
+
$current_title = $webmention.querySelector( '.webmention__content' );
|
437
|
+
}
|
438
|
+
|
439
|
+
if ( $current_title.length > 0 )
|
440
|
+
{
|
441
|
+
if ( $title.length > 0 )
|
442
|
+
{
|
443
|
+
title = $title.innerText;
|
444
|
+
}
|
445
|
+
else
|
446
|
+
{
|
447
|
+
if ( $h1.length > 0 )
|
448
|
+
{
|
449
|
+
title = $h1.innerHTML;
|
450
|
+
}
|
451
|
+
else
|
452
|
+
{
|
453
|
+
title = 'No title available';
|
454
|
+
}
|
455
|
+
}
|
456
|
+
|
457
|
+
if ( title )
|
458
|
+
{
|
459
|
+
// cleanup
|
460
|
+
title = title.replace( /<\/?[^>]+?>}/, '' );
|
461
|
+
$link_title = document.createElement('a');
|
462
|
+
$link_title.href = uri;
|
463
|
+
$link_title.appendChild( document.createTextNode( title ) );
|
464
|
+
// replace title contents
|
465
|
+
$current_title.innerHTML = $link_title.outerHTML;
|
466
|
+
}
|
467
|
+
}
|
468
|
+
}
|
469
|
+
|
470
|
+
// Synchromous XHR proxied through whateverorigin.org
|
471
|
+
function readWebPage( uri, callback )
|
472
|
+
{
|
473
|
+
if ( 'XMLHttpRequest' in window )
|
474
|
+
{
|
475
|
+
var XHR = new XMLHttpRequest();
|
476
|
+
readWebPage = function( uri, callback ){
|
477
|
+
var done = false;
|
478
|
+
uri = '//whateverorigin.org/get?url=' + encodeURIComponent( uri );
|
479
|
+
XHR.onreadystatechange = function() {
|
480
|
+
if ( this.readyState == 4 && ! done ) {
|
481
|
+
done = true;
|
482
|
+
callback( XHR.responseText );
|
483
|
+
}
|
484
|
+
};
|
485
|
+
xhr.onabort = function() {
|
486
|
+
if ( ! done )
|
487
|
+
{
|
488
|
+
done = true;
|
489
|
+
callback( false );
|
490
|
+
}
|
491
|
+
};
|
492
|
+
XHR.onerror = XHR.onabort;
|
493
|
+
XHR.open( 'GET', uri );
|
494
|
+
XHR.send( null );
|
495
|
+
};
|
496
|
+
}
|
497
|
+
else
|
498
|
+
{
|
499
|
+
readWebPage = function( uri, callback ){
|
500
|
+
callback( false );
|
501
|
+
};
|
502
|
+
}
|
503
|
+
return readWebPage( uri, callback );
|
504
|
+
}
|
505
|
+
|
506
|
+
// init
|
507
|
+
collectTemplates();
|
508
|
+
collectExistingWebmentions();
|
509
|
+
identifyWebmentionCollections();
|
510
|
+
|
511
|
+
}(this, this.document));
|
@@ -0,0 +1,33 @@
|
|
1
|
+
/**
|
2
|
+
* WebMentions.io JS
|
3
|
+
* A re-tooling of Aaron Parecki’s recommended JS for using the WebMention.io API
|
4
|
+
*
|
5
|
+
* Updates Webmentions on a static site immediately when the page is loaded and
|
6
|
+
* in real-time (using WebSockets) as the user engages with the page.
|
7
|
+
*
|
8
|
+
* To inform the JavaScript of additional URLs to check (e.g. when the current page
|
9
|
+
* receives redirects from old URLs), use the following meta element:
|
10
|
+
*
|
11
|
+
* <meta property="webmention:redirected_from" content="URL_1,URL_2">
|
12
|
+
*
|
13
|
+
* The content should be a single URL or multiple, separated by commas.
|
14
|
+
*/
|
15
|
+
|
16
|
+
;(function( window, document ){
|
17
|
+
'use strict';
|
18
|
+
|
19
|
+
if ( ! window.location.origin )
|
20
|
+
{
|
21
|
+
window.location.origin = window.location.protocol + '//' + window.location.host;
|
22
|
+
}
|
23
|
+
|
24
|
+
// http://tokenposts.blogspot.com.au/2012/04/javascript-objectkeys-browser.html
|
25
|
+
if (!Object.keys) Object.keys = function(o) {
|
26
|
+
if (o !== Object(o))
|
27
|
+
throw new TypeError('Object.keys called on a non-object');
|
28
|
+
var k=[],p;
|
29
|
+
for (p in o) if (Object.prototype.hasOwnProperty.call(o,p)) k.push(p);
|
30
|
+
return k;
|
31
|
+
};
|
32
|
+
|
33
|
+
}(this,this.document));
|