public void set(string name, ReadOnlyMemory <byte> blobValue, string filename = null) {/* Docs: https://xhr.spec.whatwg.org/#dom-formdata-set */ FormDataEntryValue entry = null; if (string.IsNullOrEmpty(filename)) { /* 3) If value is a Blob object and not a File object, then set value to a new File object, representing the same bytes, whose name attribute value is "blob". */ entry = new FormDataEntryValue(EFormDataValueType.Blob, name, new FileBlob(blobValue, "blob")); } else { entry = new FormDataEntryValue(EFormDataValueType.File, name, new FileBlob(blobValue, filename)); } int index = Entries.FindIndex(e => StringCommon.StrEq(name, e.Item1)); Entries.RemoveAll(e => StringCommon.StrEq(name, e.Item1)); if (index < 0) { Entries.Add(new Tuple <string, FormDataEntryValue>(name, entry)); } else { Entries.Insert(index, new Tuple <string, FormDataEntryValue>(name, entry)); } }
public static bool Is_Valid_Custom_Element_Name(ReadOnlyMemory <char> data) {/* Docs: https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name */ /* FORMAT: [a-z] (PCENChar)* '-' (PCENChar)* */ if (data.IsEmpty || data.Length < 2) { return(false); } DataConsumer <char> Stream = new DataConsumer <char>(data, EOF); /* Must start with a lowercased alpha character */ if (!Is_ASCII_Lower_Alpha(Stream.Next)) { return(false); } /* Consume the first char */ Stream.Consume(); /* Consume any chars that are valid PCEN but NOT the first hypen */ Stream.Consume_While(c => Is_PCEN_Char(c) && c != CHAR_HYPHEN_MINUS); /* The name must contain atleast one hypen */ if (Stream.Next != CHAR_HYPHEN_MINUS) { return(false); } /* Consume all remaining PCEN chars */ Stream.Consume_While(c => Is_PCEN_Char(c)); /* All PCEN chars have been consumed, if this isnt EOF then its an invalid char */ if (Stream.Next != EOF) { return(false); } /* name must not be any of the following: * annotation-xml * color-profile * font-face * font-face-src * font-face-uri * font-face-format * font-face-name * missing-glyph */ for (int i = 0; i < FORBIDDEN_CUSTOM_ELEMENT_NAMES.Length; i++) { if (StringCommon.StrEq(data.Span, FORBIDDEN_CUSTOM_ELEMENT_NAMES[i])) { return(false); } } return(true); }
public override bool Equals(object obj) { if (!(obj is AttributeValue other)) { return(false); } if (Type == other.Type) { switch (Type) { case EAttributeType.Boolean: { // A boolean attributes value is based on it's mere existance. So if the other object exists then they are both true and equal! return(other.Value is object); } case EAttributeType.Integer: { // cast to large type just incase return((Int64)Value == (Int64)other.Value); } case EAttributeType.NonNegative_Integer: { // cast to large type just incase return((UInt64)Value == (UInt64)other.Value); } case EAttributeType.Enumerated: { return((int)Value == (int)other.Value); } case EAttributeType.NonZero_Length: case EAttributeType.NonZero_Percentage: case EAttributeType.FloatingPoint: { return((double)Value == (double)other.Value); } default: { if (other.Type == EAttributeType.String) { return(((AtomicString)Value).Equals((AtomicString)other.Value)); } else { return(StringCommon.StrEq(Data, other.Data)); } } } } else {/* Its possible these values are compatible but have different types */ return(StringCommon.StrEq(Data, other.Data)); } }
public override ENodeFilterResult acceptNode(Node node) { if (!(node is Element)) { return(ENodeFilterResult.FILTER_SKIP); } // We test reference of string just incase the one being used is like a const or static decleration, or maybe an interned string. it's faster to match an address ptr than to check all chars in an array. if (ReferenceEquals((node as Element).localName, Name) || StringCommon.StrEq((node as Element).localName.AsSpan(), Name.AsSpan())) { return(ENodeFilterResult.FILTER_ACCEPT); } return(ENodeFilterResult.FILTER_SKIP); }
public void set(string name, string value) {/* Docs: https://xhr.spec.whatwg.org/#dom-formdata-set */ var entry = new FormDataEntryValue(EFormDataValueType.String, name, value); int index = Entries.FindIndex(e => StringCommon.StrEq(name, e.Item1)); Entries.RemoveAll(e => StringCommon.StrEq(name, e.Item1)); if (index < 0) { Entries.Add(new Tuple <string, FormDataEntryValue>(name, entry)); } else { Entries.Insert(index, new Tuple <string, FormDataEntryValue>(name, entry)); } }
public static void Validate_And_Extract(string Namespace, string qualifiedName, out string outPrefix, out string outLocalName) {/* Docs: https://dom.spec.whatwg.org/#validate-and-extract */ /* 1) If namespace is the empty string, set it to null. */ if (Namespace.Length <= 0) { Namespace = null; } /* 2) Validate qualifiedName. */ Validate(qualifiedName); string prefix = null; string localName = qualifiedName; /* 5) If qualifiedName contains a ":" (U+003E), then split the string on it and set prefix to the part before and localName to the part after. */ if (qualifiedName.Contains(':')) { string[] tok = qualifiedName.Split(':'); prefix = tok[0]; localName = tok[1]; } if (prefix != null && Namespace == null) { throw new NamespaceError($"The qualified name contains a prefix but no namespace was specified"); } /* 7) If prefix is "xml" and namespace is not the XML namespace, then throw a "NamespaceError" DOMException. */ if (StringCommon.StrEq("xml".AsSpan(), prefix.AsSpan()) && !StringCommon.StrEq(Namespace.AsSpan(), DOMCommon.XMLNamespace.AsSpan())) { throw new NamespaceError($"The qualified names' prefix \"{qualifiedName}\" does not match the namespace specified \"{Namespace}\""); } /* 8) If either qualifiedName or prefix is "xmlns" and namespace is not the XMLNS namespace, then throw a "NamespaceError" DOMException. */ if ((StringCommon.StrEq("xmlns".AsSpan(), qualifiedName.AsSpan()) || StringCommon.StrEq("xmlns".AsSpan(), prefix.AsSpan())) && !StringCommon.StrEq(Namespace.AsSpan(), DOMCommon.XMLNSNamespace.AsSpan())) { throw new NamespaceError($"The qualified names' prefix \"{qualifiedName}\" does not match the namespace specified \"{Namespace}\""); } /* 9) If namespace is the XMLNS namespace and neither qualifiedName nor prefix is "xmlns", then throw a "NamespaceError" DOMException. */ if ((!StringCommon.StrEq("xmlns".AsSpan(), qualifiedName.AsSpan()) || !StringCommon.StrEq("xmlns".AsSpan(), prefix.AsSpan())) && StringCommon.StrEq(Namespace.AsSpan(), DOMCommon.XMLNSNamespace.AsSpan())) { throw new NamespaceError($"The qualified names' prefix \"{qualifiedName}\" does not match the namespace specified \"{Namespace}\""); } outPrefix = prefix; outLocalName = localName; }
public override ENodeFilterResult acceptNode(Node node) {/* Docs: https://html.spec.whatwg.org/multipage/input.html#radio-button-state-(type=radio):radio-button-group */ if (!Subject_Is_Valid) { return(ENodeFilterResult.FILTER_REJECT); } if (node.nodeType != ENodeType.ELEMENT_NODE) { return(ENodeFilterResult.FILTER_REJECT); } /* Dont accept our own subject or else theyll end up in their own grouplist which doesnt make sense and will also screw up the logic of input element functions */ if (ReferenceEquals(Subject, node)) { return(ENodeFilterResult.FILTER_SKIP); } /* The input element b's type attribute is in the Radio Button state. */ if (node is HTMLInputElement inputElement && inputElement.type == EInputType.Radio) { /* Either a and b have the same form owner, or they both have no form owner. */ if (ReferenceEquals(subjectForm, inputElement.form)) { /* Both a and b are in the same tree. */ if (ReferenceEquals(Subject.ownerDocument, inputElement.ownerDocument)) { /* They both have a name attribute, their name attributes are not empty, and the value of a's name attribute equals the value of b's name attribute. */ string nameStr = inputElement.name; if (!ReferenceEquals(null, nameStr) && nameStr.Length > 0) { if (StringCommon.StrEq(subjectName, nameStr)) { return(ENodeFilterResult.FILTER_ACCEPT); } } } } } return(ENodeFilterResult.FILTER_SKIP); }
public override ENodeFilterResult acceptNode(Node node) { if (!(node is Element element)) { return(ENodeFilterResult.FILTER_SKIP); } // We test reference of string just incase the one being used is like a const or static decleration, or maybe an interned string. it's faster to match an address ptr than to check all chars in an array. if (ReferenceEquals(element.id, Name) || StringCommon.StrEq(element.id.AsSpan(), Name.AsSpan())) { return(ENodeFilterResult.FILTER_ACCEPT); } if (ReferenceEquals(element.NamespaceURI, DOMCommon.HTMLNamespace) || StringCommon.StrEq(element.NamespaceURI.AsSpan(), DOMCommon.HTMLNamespace.AsSpan())) { var nameAttrValue = element.getAttribute(EAttributeName.Name)?.AsString(); if (ReferenceEquals(nameAttrValue, Name) || StringCommon.StrEq(nameAttrValue.AsSpan(), Name.AsSpan())) { return(ENodeFilterResult.FILTER_ACCEPT); } } return(ENodeFilterResult.FILTER_SKIP); }
public void StrEqTest(string Left, string Right, bool Expected) { Assert.Equal(Expected, StringCommon.StrEq(Left, Right)); }
override public bool Matches(Element E, params Node[] scopeElements) { switch (Operator) { // CSS 2.0 operators case ECssAttributeOperator.Isset: // isset { return(E.hasAttribute(AttributeName)); } case ECssAttributeOperator.Equals: // equals { if (string.IsNullOrEmpty(Value)) { return(false); } return(StringCommon.StrEq(Value, E.getAttribute(AttributeName).AsString())); } case ECssAttributeOperator.PrefixedWith: // equals or prefixed-with { if (!E.hasAttribute(AttributeName)) { return(false); } string val = E.getAttribute(AttributeName).AsString(); if (StringCommon.StrEq(Value, val)) { return(true); } if (val.StartsWith(string.Concat(Value, '-'))) { return(true); } return(false); } case ECssAttributeOperator.Includes: // list-contains { if (string.IsNullOrEmpty(Value)) { return(false); } /* First lets check the elements token-list map */ if (E.tokenListMap.TryGetValue(AttributeName, out IAttributeTokenList listMap)) { var TokenList = (AttributeTokenList <string>)listMap; return(TokenList.Contains(Value)); } if (!E.hasAttribute(AttributeName)) { return(false); } var attr = E.getAttribute(AttributeName); var set = DOMCommon.Parse_Ordered_Set(attr.AsAtomic().AsMemory()); return(set.Contains(Value.AsMemory())); } // Sub-string operators case ECssAttributeOperator.StartsWith: // starts-with { if (string.IsNullOrEmpty(Value)) { return(false); } if (!E.hasAttribute(AttributeName)) { return(false); } var attr = E.getAttribute(AttributeName); return(attr.AsString().StartsWith(Value)); } case ECssAttributeOperator.EndsWith: // ends-with { if (string.IsNullOrEmpty(Value)) { return(false); } if (!E.hasAttribute(AttributeName)) { return(false); } var attr = E.getAttribute(AttributeName); return(attr.AsString().EndsWith(Value)); } case ECssAttributeOperator.Contains: // contains { if (string.IsNullOrEmpty(Value)) { return(false); } if (!E.hasAttribute(AttributeName)) { return(false); } var attr = E.getAttribute(AttributeName); return(StringCommon.Contains(attr.AsAtomic().AsMemory().Span, Value.AsMemory().Span)); } default: throw new CssSelectorException($"Attribute selector operator ({Enum.GetName(typeof(ECssAttributeOperator), Operator)}) logic not implemented!"); } }
public bool has(string name) {/* Docs: https://xhr.spec.whatwg.org/#dom-formdata-has */ return(Entries.Any(e => StringCommon.StrEq(name, e.Item1))); }
public IReadOnlyCollection <FormDataEntryValue> getAll(string name) {/* Docs: https://xhr.spec.whatwg.org/#dom-formdata-getall */ return(Entries.Where(e => StringCommon.StrEq(name, e.Item1)).Select(e => e.Item2).ToArray()); }
public FormDataEntryValue get(string name) {/* Docs: https://xhr.spec.whatwg.org/#dom-formdata-get */ return(Entries.First(e => StringCommon.StrEq(name, e.Item1)).Item2); }
public void delete(string name) {/* Docs: https://xhr.spec.whatwg.org/#dom-formdata-delete */ Entries.RemoveAll(e => StringCommon.StrEq(name, e.Item1)); }