source: trip-planner-front/node_modules/parse5/lib/parser/formatting-element-list.js@ ceaed42

Last change on this file since ceaed42 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 5.2 KB
Line 
1'use strict';
2
3//Const
4const NOAH_ARK_CAPACITY = 3;
5
6//List of formatting elements
7class FormattingElementList {
8 constructor(treeAdapter) {
9 this.length = 0;
10 this.entries = [];
11 this.treeAdapter = treeAdapter;
12 this.bookmark = null;
13 }
14
15 //Noah Ark's condition
16 //OPTIMIZATION: at first we try to find possible candidates for exclusion using
17 //lightweight heuristics without thorough attributes check.
18 _getNoahArkConditionCandidates(newElement) {
19 const candidates = [];
20
21 if (this.length >= NOAH_ARK_CAPACITY) {
22 const neAttrsLength = this.treeAdapter.getAttrList(newElement).length;
23 const neTagName = this.treeAdapter.getTagName(newElement);
24 const neNamespaceURI = this.treeAdapter.getNamespaceURI(newElement);
25
26 for (let i = this.length - 1; i >= 0; i--) {
27 const entry = this.entries[i];
28
29 if (entry.type === FormattingElementList.MARKER_ENTRY) {
30 break;
31 }
32
33 const element = entry.element;
34 const elementAttrs = this.treeAdapter.getAttrList(element);
35
36 const isCandidate =
37 this.treeAdapter.getTagName(element) === neTagName &&
38 this.treeAdapter.getNamespaceURI(element) === neNamespaceURI &&
39 elementAttrs.length === neAttrsLength;
40
41 if (isCandidate) {
42 candidates.push({ idx: i, attrs: elementAttrs });
43 }
44 }
45 }
46
47 return candidates.length < NOAH_ARK_CAPACITY ? [] : candidates;
48 }
49
50 _ensureNoahArkCondition(newElement) {
51 const candidates = this._getNoahArkConditionCandidates(newElement);
52 let cLength = candidates.length;
53
54 if (cLength) {
55 const neAttrs = this.treeAdapter.getAttrList(newElement);
56 const neAttrsLength = neAttrs.length;
57 const neAttrsMap = Object.create(null);
58
59 //NOTE: build attrs map for the new element so we can perform fast lookups
60 for (let i = 0; i < neAttrsLength; i++) {
61 const neAttr = neAttrs[i];
62
63 neAttrsMap[neAttr.name] = neAttr.value;
64 }
65
66 for (let i = 0; i < neAttrsLength; i++) {
67 for (let j = 0; j < cLength; j++) {
68 const cAttr = candidates[j].attrs[i];
69
70 if (neAttrsMap[cAttr.name] !== cAttr.value) {
71 candidates.splice(j, 1);
72 cLength--;
73 }
74
75 if (candidates.length < NOAH_ARK_CAPACITY) {
76 return;
77 }
78 }
79 }
80
81 //NOTE: remove bottommost candidates until Noah's Ark condition will not be met
82 for (let i = cLength - 1; i >= NOAH_ARK_CAPACITY - 1; i--) {
83 this.entries.splice(candidates[i].idx, 1);
84 this.length--;
85 }
86 }
87 }
88
89 //Mutations
90 insertMarker() {
91 this.entries.push({ type: FormattingElementList.MARKER_ENTRY });
92 this.length++;
93 }
94
95 pushElement(element, token) {
96 this._ensureNoahArkCondition(element);
97
98 this.entries.push({
99 type: FormattingElementList.ELEMENT_ENTRY,
100 element: element,
101 token: token
102 });
103
104 this.length++;
105 }
106
107 insertElementAfterBookmark(element, token) {
108 let bookmarkIdx = this.length - 1;
109
110 for (; bookmarkIdx >= 0; bookmarkIdx--) {
111 if (this.entries[bookmarkIdx] === this.bookmark) {
112 break;
113 }
114 }
115
116 this.entries.splice(bookmarkIdx + 1, 0, {
117 type: FormattingElementList.ELEMENT_ENTRY,
118 element: element,
119 token: token
120 });
121
122 this.length++;
123 }
124
125 removeEntry(entry) {
126 for (let i = this.length - 1; i >= 0; i--) {
127 if (this.entries[i] === entry) {
128 this.entries.splice(i, 1);
129 this.length--;
130 break;
131 }
132 }
133 }
134
135 clearToLastMarker() {
136 while (this.length) {
137 const entry = this.entries.pop();
138
139 this.length--;
140
141 if (entry.type === FormattingElementList.MARKER_ENTRY) {
142 break;
143 }
144 }
145 }
146
147 //Search
148 getElementEntryInScopeWithTagName(tagName) {
149 for (let i = this.length - 1; i >= 0; i--) {
150 const entry = this.entries[i];
151
152 if (entry.type === FormattingElementList.MARKER_ENTRY) {
153 return null;
154 }
155
156 if (this.treeAdapter.getTagName(entry.element) === tagName) {
157 return entry;
158 }
159 }
160
161 return null;
162 }
163
164 getElementEntry(element) {
165 for (let i = this.length - 1; i >= 0; i--) {
166 const entry = this.entries[i];
167
168 if (entry.type === FormattingElementList.ELEMENT_ENTRY && entry.element === element) {
169 return entry;
170 }
171 }
172
173 return null;
174 }
175}
176
177//Entry types
178FormattingElementList.MARKER_ENTRY = 'MARKER_ENTRY';
179FormattingElementList.ELEMENT_ENTRY = 'ELEMENT_ENTRY';
180
181module.exports = FormattingElementList;
Note: See TracBrowser for help on using the repository browser.