-
Notifications
You must be signed in to change notification settings - Fork 302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/support querySelector and querySelectorAll #672
Merged
Merged
Changes from all commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
59ece31
feat: add querySelect polyfill.
answershuto 3b9c49d
test: add querySelector test.
answershuto f29bcb0
test: add querySelectorAll test.
answershuto 189692f
fix: delete invalid code.
answershuto 366ef03
chore: remove console.log
answershuto d0e8649
test: modify id of test.
answershuto b8f63e7
chore: modify type.
answershuto 313c39c
Merge branch 'main' into feat/support_querySelector
answershuto 4a6458a
feat: add querySelector.ts.
answershuto f10eb73
chore: modify comments.
answershuto 3730949
chore: delete useless util function.
answershuto 24bbdff
feat: add new file to index .
answershuto 3982398
feat: modify querySelector.
answershuto e968047
feat: add getElementsByClassName.
answershuto 6c1b38b
chore: delete comments.
answershuto fdba750
feat: className property should be save in attributes.
answershuto 0d08b9e
test: add test for getElementsByClassName
answershuto a71c4c0
test: add test for querySelector to find className.
answershuto 3e8b490
fix: getElementsByTagName should work with *.
answershuto 888445c
fix: className shoud be class when set property of element.
answershuto 82c54a2
test: add test for getElementsByTagName of *.
answershuto 0100c1c
chore: add new line.
answershuto afdce2a
test: add querySelectorAll for query attrs.
answershuto f3a52a2
test: add test for query href of querySelectorAll
answershuto a7fc280
test: add test for querySelector when query href.
answershuto d23590b
test: add test for absolute path of querySelector.
answershuto 287d9ba
fix: misjudged the URL to be class.
answershuto eb355a2
fix: modify select class.
answershuto b2c5b8d
feat: modify querySelector.ts to query-selector.ts
answershuto 34522ac
chore: delete semicolon.
answershuto affec47
chore: modify the format.
answershuto a1f9413
chore: modify the format.
answershuto 8ecd064
test: modify query-select to a separate file.
answershuto File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
function fetchSelector(str: string, regex: RegExp) { | ||
return { | ||
selectors: str.match(regex) || [], | ||
ruleStr: str.replace(regex, ' ') | ||
}; | ||
} | ||
|
||
function getElementsBySelector(selector: string): Array<Element | null | HTMLElement> { | ||
let context = document; | ||
let temp, tempElements: Array<Element> = [], elements: Array<Element> = []; | ||
selector = selector.trim(); | ||
|
||
// If selector starts with *, find all elements. | ||
if (selector.charAt(0) === '*') { | ||
let temps: HTMLCollectionOf<Element> = context.getElementsByTagName('*'); | ||
tempElements = Array.from(temps); | ||
} | ||
|
||
// Classes. e.g. .row. | ||
let classes: Array<string> = []; | ||
selector = selector.split(' ').map(item => { | ||
if (item && item.charAt(0) === '.') { | ||
temp = fetchSelector(selector, /\.[\w-_]+/g); | ||
classes = classes.concat(temp.selectors) | ||
return temp.ruleStr; | ||
} | ||
return item; | ||
}).join(' '); | ||
|
||
// Ids. e.g. #mail-title. | ||
temp = fetchSelector(selector, /#[\w-_]+/g); | ||
let id = temp.selectors ? temp.selectors[0] : null; | ||
selector = temp.ruleStr; | ||
|
||
// Attributes. e.g. [rel=external]. | ||
temp = fetchSelector(selector, /\[.+?\]/g); | ||
let attributes = temp.selectors; | ||
selector = temp.ruleStr; | ||
|
||
// Elements. e.g. header, div. | ||
temp = fetchSelector(selector, /\w+/g); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 讨论了下这个正则没问题。 |
||
let els = temp.selectors; | ||
selector = temp.ruleStr; | ||
|
||
// Get by id. | ||
// Id is supposed to be unique. | ||
// More need to attach other selectors. | ||
if (id) { | ||
id = id.substring(1); | ||
return [document.getElementById(id) || null]; | ||
} | ||
|
||
// Get by Elements. | ||
if (els.length !== 0) { | ||
let temps: HTMLCollectionOf<Element> = context.getElementsByTagName(els[0]); | ||
tempElements = tempElements.concat(Array.from(temps)); | ||
} | ||
|
||
// Get by class name. | ||
for (let i = 0, l = classes.length; i !== l; ++i) { | ||
let className = classes[i].substring(1); | ||
let temps: HTMLCollectionOf<Element> = context.getElementsByClassName(className); | ||
let arrTemps: Array<Element> = Array.from(temps); | ||
if (tempElements.length === 0) { | ||
// If no temp elements yet, push into tempElements directly. | ||
tempElements = tempElements.concat(arrTemps); | ||
} | ||
else { | ||
// Otherwise, find intersection. | ||
let prevs: Array<Element> = []; | ||
prevs = prevs.concat(tempElements); | ||
tempElements = []; | ||
|
||
for (let index = 0; index < arrTemps.length; index++) { | ||
let t = arrTemps[index]; | ||
if (prevs.indexOf(t) !== -1) { | ||
tempElements = tempElements.concat([t]); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Get by attributes. | ||
if (attributes.length !== 0) { | ||
let attrs = {}; | ||
for (let i = 0; i < attributes.length; i++) { | ||
let attribute = attributes[i]; | ||
attribute = attribute.substring(1, attribute.length - 1); | ||
let parts: Array<string> = (attribute.split('=')).map(item => item.trim()); | ||
if (parts[1]) { | ||
parts[1] = parts[1].substring(1, parts[1].length - 1); | ||
} | ||
attrs[parts[0]] = parts[1]; | ||
} | ||
let prevs: Array<Element> = []; | ||
prevs = prevs.concat(tempElements); | ||
tempElements = []; | ||
|
||
for (let i = 0, l = prevs.length; i !== l; ++i) { | ||
let t = prevs[i]; | ||
let shouldAdd = true; | ||
for (let key in attrs) { | ||
let lastChar = key.charAt(key.length - 1); | ||
if (/[\^\*\$]$/.test(key)) { | ||
key = key.substring(0, key.length - 1); | ||
} | ||
let tempAttr = t.getAttribute(key) || ''; | ||
// Case: [href*=/en]. | ||
if (lastChar === '*' && tempAttr.indexOf(attrs[key + lastChar]) === -1) { | ||
shouldAdd = false; | ||
break; | ||
} | ||
// Case: [href^=/en]. | ||
else if (lastChar === '^' && tempAttr.indexOf(attrs[key + lastChar]) !== 0) { | ||
shouldAdd = false; | ||
break; | ||
} | ||
// Case: [href$=/en]. | ||
else if (lastChar === '$' && | ||
(tempAttr.lastIndexOf(attrs[key + lastChar]) === -1 | ||
? false | ||
: tempAttr.lastIndexOf(attrs[key + lastChar])) | ||
!== | ||
tempAttr.length - attrs[key + lastChar].length) { | ||
shouldAdd = false; | ||
break; | ||
} | ||
// Case: [href=/en]. | ||
else if (/[\$\*\^]/.test(lastChar) === false && tempAttr !== attrs[key]) { | ||
shouldAdd = false; | ||
break; | ||
} | ||
|
||
} | ||
|
||
if (shouldAdd) { | ||
tempElements = tempElements.concat([t]); | ||
} | ||
} | ||
} | ||
|
||
elements = elements.concat(tempElements); | ||
return elements; | ||
} | ||
|
||
document.querySelectorAll = function <E extends Element = Element>(selector: string): NodeListOf<E> { | ||
if (typeof selector !== 'string') { | ||
throw new TypeError('document.querySelectorAll: Invalid selector type. ' + | ||
'Expect: string. Found: ' + typeof selector + '.'); | ||
} | ||
let elements: Array<E> = []; | ||
|
||
// Split `selector` into rules by `,`. | ||
let rules: Array<string> = selector.split(',').map(item => item.trim()); | ||
|
||
// Iterate through each rule. | ||
// For the sake of performance, use for-loop here rather than forEach. | ||
for (let i = 0, l = rules.length; i !== l; ++i) { | ||
let rule = rules[i]; | ||
|
||
// TODO: support ' ' and '>'. | ||
elements = elements.concat(getElementsBySelector.call(this, rule)); | ||
} | ||
|
||
return (elements as any) as NodeListOf<E>; | ||
}; | ||
|
||
document.querySelector = function (selector: string): Element | null { | ||
if (typeof selector !== 'string') { | ||
throw new TypeError('document.querySelector: Invalid selector type. ' + | ||
'Expect: string. Found: ' + typeof selector + '.'); | ||
} | ||
let elements = this.querySelectorAll(selector); | ||
return elements.length > 0 ? elements[0] : null; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
只支持 equal,正则是不是限定下 /[.+=.+]/g
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
讨论了下这个正则没问题,去掉TODO。