Add a wonderfull css package(pseudom) with custom pseudo selectors

This commit is contained in:
kodjomoustapha 2024-06-15 13:27:44 +01:00
parent 69dd1aab34
commit 59ed4da8de
8 changed files with 174 additions and 4 deletions

View file

@ -141,6 +141,16 @@ class $MDocument implements MDocument, $Instance {
false)
]),
),
'hasAttr': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
},
wrap: true);
@ -194,6 +204,8 @@ class $MDocument implements MDocument, $Instance {
return __xpathFirst;
case 'attr':
return __attr;
case 'hasAttr':
return __hasAttr;
default:
return _superclass.$getProperty(runtime, identifier);
}
@ -276,6 +288,13 @@ class $MDocument implements MDocument, $Instance {
return res == null ? const $null() : $String(res);
}
static const $Function __hasAttr = $Function(_hasAttr);
static $Value? _hasAttr(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MDocument).attr(args[0]?.$value ?? "");
return res == null ? const $null() : $String(res);
}
@override
List<MElement>? select(String selector) => $value.select(selector);
@ -299,6 +318,9 @@ class $MDocument implements MDocument, $Instance {
@override
String? attr(String attr) => $value.attr(attr);
@override
bool hasAttr(String attr) => $value.hasAttr(attr);
@override
MElement? getElementById(String id) => $value.getElementById(id);

View file

@ -162,6 +162,16 @@ class $MElement implements MElement, $Instance {
false)
]),
),
'hasAttr': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
),
},
wrap: true);
@ -245,6 +255,8 @@ class $MElement implements MElement, $Instance {
return __xpath;
case 'xpathFirst':
return __xpathFirst;
case 'hasAttr':
return __hasAttr;
default:
return _superclass.$getProperty(runtime, identifier);
}
@ -322,6 +334,13 @@ class $MElement implements MElement, $Instance {
return res == null ? const $null() : $String(res);
}
static const $Function __hasAttr = $Function(_hasAttr);
static $Value? _hasAttr(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MElement).attr(args[0]?.$value ?? "");
return res == null ? const $null() : $String(res);
}
@override
List<String>? xpath(String xpath) => $value.xpath(xpath);
@ -348,6 +367,9 @@ class $MElement implements MElement, $Instance {
List<MElement>? getElementsByTagName(String localNames) =>
$value.getElementsByTagName(localNames);
@override
bool hasAttr(String attr) => $value.hasAttr(attr);
@override
String? get className => $value.className;

View file

@ -59,4 +59,8 @@ class MDocument {
String? attr(String attr) {
return _document?.attr(attr);
}
bool hasAttr(String attr) {
return _document?.hasAtr(attr) ?? false;
}
}

View file

@ -69,4 +69,8 @@ class MElement {
String? attr(String attribute) {
return _element?.attr(attribute);
}
bool hasAttr(String attr) {
return _element?.hasAtr(attr) ?? false;
}
}

View file

@ -85,6 +85,16 @@ class JsDomSelector {
final attr = args[1];
return parse(input).attr(attr) ?? "";
});
runtime.onMessage('ele_has_attr', (dynamic args) {
final attr = args[0];
final key = args[1];
return _elements[key]?.hasAtr(attr) ?? false;
});
runtime.onMessage('doc_has_attr', (dynamic args) {
final input = args[0];
final attr = args[1];
return parse(input).hasAtr(attr);
});
runtime.onMessage('doc_xpath_first', (dynamic args) {
final input = args[0];
final xpath = args[1];
@ -270,6 +280,12 @@ class Document {
JSON.stringify([this.html, attr])
);
}
hasAttr(attr) {
return sendMessage(
"doc_has_attr",
JSON.stringify([this.html, attr])
);
}
}
class Element {
@ -379,6 +395,12 @@ class Element {
});
return elements;
}
hasAttr(attr) {
return sendMessage(
"ele_has_attr",
JSON.stringify([this.html, attr])
);
}
}
''');
}

View file

@ -1,11 +1,73 @@
import 'package:html/dom.dart';
import 'package:pseudom/pseudom.dart' as pseudom;
import 'package:mangayomi/utils/reg_exp_matcher.dart';
import 'package:xpath_selector_html_parser/xpath_selector_html_parser.dart';
void _initPseudoSelector() {
bool nthChild(Element element, String? args) {
if (int.tryParse(args!) != null) {
final parent = element.parentNode;
return parent != null &&
(int.parse(args) as num) > 0 &&
parent.nodes.indexOf(element) == int.parse(args);
}
return true;
}
bool has(Element element, String? args) {
if (args == null) return false;
final parent = element.parent;
final res = parent == null
? false
: pseudom.parse(args).selectFirst(parent) == element;
return res ? res : pseudom.parse(args).selectFirst(element) != null;
}
bool inot(Element element, String? args) {
if (args == null) return false;
final parent = element.parent;
final res = parent == null
? false
: pseudom.parse(args).selectFirst(parent) != element;
return res ? res : pseudom.parse(args).selectFirst(element) == null;
}
bool contains(Element element, String? args) {
final text = args ?? '';
return element.text.contains(text);
}
bool firstChild(Element element, String? args) {
return element.previousElementSibling == null;
}
bool lastChild(Element element, String? args) {
return element.nextElementSibling == null;
}
bool onlyChild(Element element, String? args) {
return element.nextElementSibling == null;
}
pseudom.PseudoSelector.handlers['nth-child'] = nthChild;
pseudom.PseudoSelector.handlers['has'] = has;
pseudom.PseudoSelector.handlers['inot'] = inot;
pseudom.PseudoSelector.handlers['contains'] = contains;
pseudom.PseudoSelector.handlers['last-child'] = lastChild;
pseudom.PseudoSelector.handlers['first-child'] = firstChild;
pseudom.PseudoSelector.handlers['only-child'] = onlyChild;
}
String _fixSelector(String selector) {
return selector.replaceAll(':not', ':inot');
}
extension DocumentExtension on Document? {
List<Element>? select(String selector) {
try {
return this?.querySelectorAll(selector);
_initPseudoSelector();
final dom = this?.documentElement;
return pseudom.parse(_fixSelector(selector)).select(dom!).toList();
} catch (e) {
return null;
}
@ -13,12 +75,18 @@ extension DocumentExtension on Document? {
Element? selectFirst(String selector) {
try {
return this?.querySelector(selector);
_initPseudoSelector();
final dom = this?.documentElement;
return pseudom.parse(_fixSelector(selector)).selectFirst(dom!);
} catch (e) {
return null;
}
}
bool hasAtr(String attribute) {
return attr(attribute) != null;
}
String? xpathFirst(String xpath) {
final dom = this?.documentElement;
if (dom == null) return null;
@ -50,7 +118,12 @@ extension DocumentExtension on Document? {
extension ElementtExtension on Element {
List<Element>? select(String selector) {
try {
return querySelectorAll(selector);
_initPseudoSelector();
return pseudom
.parse(_fixSelector(selector))
.select(
parent!.nodes.firstWhere((element) => element == this) as Element)
.toList();
} catch (e) {
return null;
}
@ -73,7 +146,9 @@ extension ElementtExtension on Element {
Element? selectFirst(String selector) {
try {
return querySelector(selector);
_initPseudoSelector();
return pseudom.parse(_fixSelector(selector)).selectFirst(
parent!.nodes.firstWhere((element) => element == this) as Element);
} catch (e) {
return null;
}
@ -87,6 +162,10 @@ extension ElementtExtension on Element {
}
}
bool hasAtr(String attribute) {
return attr(attribute) != null;
}
String? get getSrc {
try {
return regSrcMatcher(outerHtml);

View file

@ -25,6 +25,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.11.3"
antlr4:
dependency: transitive
description:
name: antlr4
sha256: "96f576fcb88202a327b28f40485d99ca6987246ff37805488be06bcf05dc227f"
url: "https://pub.dev"
source: hosted
version: "4.13.1"
archive:
dependency: "direct main"
description:
@ -1184,6 +1192,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.0"
pseudom:
dependency: "direct main"
description:
name: pseudom
sha256: "3df7b5aa28adc8e035820db8954e34466aa94353a02e28fd72e54d0ed68b0ecf"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
pub_semver:
dependency: transitive
description:

View file

@ -82,6 +82,7 @@ dependencies:
flutter_rust_bridge: ^2.0.0-dev.39
rust_lib_mangayomi:
path: rust_builder
pseudom: ^1.0.1
dependency_overrides:
http: ^1.2.1