DOM initial implementation

This commit is contained in:
Vadim Lopatin 2015-12-23 11:32:14 +03:00
parent 2f4799e140
commit d090f8ad49
5 changed files with 196 additions and 1 deletions

View File

@ -246,6 +246,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="src\dlangui\core\collections.d" />
<Compile Include="src\dlangui\core\dom.d" />
<Compile Include="src\dlangui\core\editable.d" />
<Compile Include="src\dlangui\core\events.d" />
<Compile Include="src\dlangui\core\files.d" />

View File

@ -105,6 +105,7 @@
<ItemGroup>
<Compile Include="src\dlangui\core\collections.d" />
<Compile Include="src\dlangui\core\config.d" />
<Compile Include="src\dlangui\core\dom.d" />
<Compile Include="src\dlangui\core\editable.d" />
<Compile Include="src\dlangui\core\events.d" />
<Compile Include="src\dlangui\core\files.d" />

View File

@ -82,6 +82,7 @@
<ItemGroup>
<Compile Include="src\dlangui\package.d" />
<Compile Include="src\dlangui\core\collections.d" />
<Compile Include="src\dlangui\core\dom.d" />
<Compile Include="src\dlangui\core\editable.d" />
<Compile Include="src\dlangui\core\events.d" />
<Compile Include="src\dlangui\core\files.d" />

View File

@ -33,7 +33,7 @@
<useArrayBounds>0</useArrayBounds>
<noboundscheck>0</noboundscheck>
<useSwitchError>0</useSwitchError>
<useUnitTests>0</useUnitTests>
<useUnitTests>1</useUnitTests>
<useInline>0</useInline>
<release>0</release>
<preservePaths>0</preservePaths>
@ -542,6 +542,7 @@
<Folder name="core">
<File path="src\dlangui\core\collections.d" />
<File path="src\dlangui\core\config.d" />
<File path="src\dlangui\core\dom.d" />
<File path="src\dlangui\core\editable.d" />
<File path="src\dlangui\core\events.d" />
<File path="src\dlangui\core\files.d" />

191
src/dlangui/core/dom.d Normal file
View File

@ -0,0 +1,191 @@
module dlangui.core.dom;
import dlangui.core.collections;
import std.traits;
import std.conv : to;
import std.string;
/// Base class for DOM nodes
class Node {
private:
Node _parent;
Document _document;
public:
/// returns parent node
@property Node parent() { return _parent; }
/// returns document node
@property Document document() { return _document; }
// node properties
/// returns true if node is text
@property bool isText() { return false; }
/// returns true if node is element
@property bool isElement() { return false; }
/// returns true if node has child nodes
@property bool hasChildren() { return false; }
// attributes
/// returns attribute count
@property int attrCount() { return 0; }
// child nodes
/// returns child node count
@property int childCount() { return 0; }
/// returns child node by index
@property Node child(int index) { return null; }
/// returns first child node
@property Node firstChild() { return null; }
/// returns last child node
@property Node lastChild() { return null; }
/// node text
@property dstring text() { return null; }
/// ditto
@property void text(dstring s) { }
}
/// Text node
class Text : Node {
private:
dstring _text;
public:
/// node text
override @property dstring text() { return _text; }
/// ditto
override @property void text(dstring s) { _text = s; }
}
/// Element node
class Element : Node {
private:
Collection!Node _children;
public:
// child nodes
/// returns child node count
override @property int childCount() { return cast(int)_children.length; }
/// returns child node by index
override @property Node child(int index) { return index >= 0 && index < _children.length ? _children[index] : null; }
/// returns first child node
override @property Node firstChild() { return _children.length > 0 ? _children[0] : null; }
/// returns last child node
override @property Node lastChild() { return _children.length > 0 ? _children[_children.length - 1] : null; }
}
/// Document node
class Document : Element {
public:
this() {
_elemIds.init!Tag();
_attrIds.init!Attr();
_nsIds.init!Ns();
}
private:
IdentMap!(elem_id) _elemIds;
IdentMap!(attr_id) _attrIds;
IdentMap!(ns_id) _nsIds;
}
/// id type for interning namespaces
alias ns_id = ushort;
/// id type for interning element names
alias elem_id = uint;
/// id type for interning attribute names
alias attr_id = ushort;
/// remove trailing _ from string, e.g. "body_" -> "body"
private string removeTrailingUnderscore(string s) {
if (s.endsWith("_"))
return s[0..$-1];
return s;
}
/// String identifier to Id map - for interning strings
struct IdentMap(ident_t) {
/// initialize with elements of enum
void init(E)() if (is(E == enum)) {
foreach(member; EnumMembers!E) {
internString(removeTrailingUnderscore(member.to!string), member);
}
}
/// intern string - return ID assigned for it
ident_t internString(string s, ident_t id = 0) {
if (auto p = s in _stringToId)
return *p;
ident_t res;
if (id > 0) {
if (_nextId <= id)
_nextId = cast(ident_t)(id + 1);
res = id;
} else {
res = _nextId++;
}
_idToString[res] = s;
_stringToId[s] = res;
return res;
}
/// lookup id for string, return 0 if string is not found
ident_t opIndex(string s) {
if (auto p = s in _stringToId)
return *p;
return 0;
}
/// lookup name for id, return null if not found
string opIndex(ident_t id) {
if (auto p = id in _idToString)
return *p;
return null;
}
private:
string[ident_t] _idToString;
ident_t[string] _stringToId;
ident_t _nextId = 1;
}
/// standard tags
enum Tag {
NONE,
body_,
pre,
div,
span
}
/// standard attributes
enum Attr {
NONE,
id,
class_,
style
}
/// standard namespaces
enum Ns {
NONE,
xmlns,
xs,
xlink,
l,
xsi
}
unittest {
import std.algorithm : equal;
//import std.stdio;
IdentMap!(elem_id) map;
map.init!Tag();
//writeln("running DOM unit test");
assert(map["pre"] == Tag.pre);
assert(map["body"] == Tag.body_);
assert(map[Tag.div].equal("div"));
Document doc = new Document();
destroy(doc);
}