-
Notifications
You must be signed in to change notification settings - Fork 16
/
iron-doc-viewer-behavior.js
184 lines (167 loc) · 5.14 KB
/
iron-doc-viewer-behavior.js
1
2
3
4
5
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {afterNextRender} from '@polymer/polymer/lib/utils/render-status.js';
/**
* @polymerBehavior
*/
export const IronDocViewerBehavior = {
properties: {
/**
* The [Polymer
* Analyzer](https://github.com/Polymer/polymer-analyzer)-generated element
* descriptor to display details for.
*/
descriptor: {
type: Object,
},
/**
* The base href where this doc viewer is located.
*/
baseHref: {type: String, value: ''},
/**
* Prefix for fragment identifiers used in anchors.
* For static routing `iron-component-page` can
* set this to a string identifying the current component.
*/
fragmentPrefix: {type: String, value: ''},
/**
* Whether protected members should be hidden or shown.
*/
_showProtected: {
type: Boolean,
value: false,
},
/**
* Whether inherited members should be hidden or shown.
*/
_showInherited: {
type: Boolean,
value: true,
},
},
_filterMembers: function(items, showProtected, showInherited) {
return (items || []).filter(function(i) {
// If privacy not specified, better to err on the side of showing
// something instead of nothing. Also some things like namespaces
// don't have privacy anyway.
var privacy = i.privacy || 'public';
var privacyOk = privacy === 'public';
if (showProtected) {
privacyOk = privacyOk || privacy === 'protected';
}
var inheritedOk = showInherited || (i.inheritedFrom == null);
return privacyOk && inheritedOk;
});
},
_noneToShow: function(showProtected, showInherited, descriptor, name) {
if (!descriptor) {
return true;
}
var items =
(name === 'behaviors' ? this._getPolymerBehaviors(descriptor) :
descriptor[name]);
if (!items) {
return true;
}
var filteredItems =
this._filterMembers(items, showProtected, showInherited);
return filteredItems.length === 0;
},
/**
* Scroll to the descriptor (element, function, etc.) with an `anchor-id`
* matching the given URL hash (`#` optional). If no hash is specified,
* uses `window.location.hash`.
*
* Whichever element or script is in charge of routing should call this
* method on initial page load and on `hashchange` events.
*/
scrollToAnchor: function(hash) {
hash = hash || window.location.hash;
if (!hash || hash.length === 0) {
return;
}
if (hash.indexOf('#') === 0) {
hash = hash.substring(1);
}
// Ensure dom-repeats have stamped.
flush();
var anchor = this.fragmentPrefix + hash;
var element = this.$$('[anchor-id="' + anchor + '"]');
if (element) {
// Don't scroll until we've drawn the next frame, otherwise our
// element might not know it's final screen position yet.
afterNextRender(this, function() {
element.scrollIntoView({behavior: 'smooth'});
// Highlight the section for a moment so we can tell where
// exactly we were deep-linked.
element.classList.add('scrolled');
this.async(function() {
element.classList.remove('scrolled');
}, 1000);
});
return;
}
// Maybe our API section has this anchor.
var api = this.$$('iron-doc-api');
if (api) {
api.scrollToAnchor(hash);
return;
}
// Maybe some other subsection has the anchor.
var subElements = this.root.querySelectorAll('*');
for (var i = 0; i < subElements.length; i++) {
var element = subElements[i];
if (element.fragmentPrefix && element.scrollToAnchor &&
hash.indexOf(element.fragmentPrefix) === 0) {
element.scrollToAnchor(hash.slice(element.fragmentPrefix.length));
return;
}
}
},
_getElementName: function(element) {
var name = '';
if (element.tagname) {
name += '<' + element.tagname + '>';
if (element.name) {
name += ' (' + element.name + ')';
}
} else if (element.name) {
name += element.name;
}
return name;
},
_getElementId: function(element) {
return element.name || element.tagname;
},
_getPolymerBehaviors: function(descriptor) {
return (((descriptor || {}).metadata || {}).polymer || {}).behaviors || [];
},
/**
* Compare two analysis descriptors (elements, functions, etc.) by
* display name.
*/
_compareDescriptors: function(a, b) {
// Elements display as "<tagname> (name)" or "name", while
// everything else displays as "name".
if (a.name != b.name) {
return compareUnderscoresLast(a.name || '', b.name || '');
}
if (a.tagname != b.tagname) {
return compareUnderscoresLast(a.tagname || '', b.tagname || '');
}
return 0;
},
};
/**
* Compare two strings such that more leading underscores sort later.
*/
function compareUnderscoresLast(a, b) {
var numA = numLeadingUnderscores(a);
var numB = numLeadingUnderscores(b);
if (numA !== numB) {
return numA - numB;
}
return a.localeCompare(b);
}
function numLeadingUnderscores(str) {
return str.match(/^_*/)[0].length;
}