mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-11-28 17:23:09 +03:00
extend javascript object hierarchy
This commit is contained in:
parent
126141a52c
commit
0ace9f5e0b
@ -155,7 +155,7 @@ JSObject *jsapi_new_window(JSContext *cx, JSObject *parent, void *win_priv);
|
|||||||
* @param doc_priv The private context to set on the object
|
* @param doc_priv The private context to set on the object
|
||||||
* @return new javascript object or NULL on error
|
* @return new javascript object or NULL on error
|
||||||
*/
|
*/
|
||||||
JSObject *jsapi_new_document(JSContext *cx, JSObject *parent, void *doc_priv);
|
JSObject *jsapi_new_document(JSContext *cx, JSObject *parent, struct html_content *htmlc);
|
||||||
|
|
||||||
/** Create a new javascript console object
|
/** Create a new javascript console object
|
||||||
*
|
*
|
||||||
|
@ -24,79 +24,58 @@
|
|||||||
#include "render/html_internal.h"
|
#include "render/html_internal.h"
|
||||||
#include "utils/log.h"
|
#include "utils/log.h"
|
||||||
|
|
||||||
/* IDL from http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html
|
/* IDL http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-document
|
||||||
|
|
||||||
|
CAUTION - write, writeln are not part of the DOM they come from:
|
||||||
|
http://www.w3.org/TR/html5/apis-in-html-documents.html#document.write
|
||||||
|
|
||||||
interface Document : Node {
|
interface Document : Node {
|
||||||
// Modified in DOM Level 3:
|
|
||||||
readonly attribute DocumentType doctype;
|
|
||||||
readonly attribute DOMImplementation implementation;
|
readonly attribute DOMImplementation implementation;
|
||||||
readonly attribute Element documentElement;
|
readonly attribute DOMString URL;
|
||||||
Element createElement(in DOMString tagName)
|
readonly attribute DOMString documentURI;
|
||||||
raises(DOMException);
|
readonly attribute DOMString compatMode;
|
||||||
DocumentFragment createDocumentFragment();
|
readonly attribute DOMString characterSet;
|
||||||
Text createTextNode(in DOMString data);
|
readonly attribute DOMString contentType;
|
||||||
Comment createComment(in DOMString data);
|
|
||||||
CDATASection createCDATASection(in DOMString data)
|
|
||||||
raises(DOMException);
|
|
||||||
ProcessingInstruction createProcessingInstruction(in DOMString target,
|
|
||||||
in DOMString data)
|
|
||||||
raises(DOMException);
|
|
||||||
Attr createAttribute(in DOMString name)
|
|
||||||
raises(DOMException);
|
|
||||||
EntityReference createEntityReference(in DOMString name)
|
|
||||||
raises(DOMException);
|
|
||||||
NodeList getElementsByTagName(in DOMString tagname);
|
|
||||||
// Introduced in DOM Level 2:
|
|
||||||
Node importNode(in Node importedNode,
|
|
||||||
in boolean deep)
|
|
||||||
raises(DOMException);
|
|
||||||
// Introduced in DOM Level 2:
|
|
||||||
Element createElementNS(in DOMString namespaceURI,
|
|
||||||
in DOMString qualifiedName)
|
|
||||||
raises(DOMException);
|
|
||||||
// Introduced in DOM Level 2:
|
|
||||||
Attr createAttributeNS(in DOMString namespaceURI,
|
|
||||||
in DOMString qualifiedName)
|
|
||||||
raises(DOMException);
|
|
||||||
// Introduced in DOM Level 2:
|
|
||||||
NodeList getElementsByTagNameNS(in DOMString namespaceURI,
|
|
||||||
in DOMString localName);
|
|
||||||
// Introduced in DOM Level 2:
|
|
||||||
Element getElementById(in DOMString elementId);
|
|
||||||
// Introduced in DOM Level 3:
|
|
||||||
readonly attribute DOMString inputEncoding;
|
|
||||||
// Introduced in DOM Level 3:
|
|
||||||
readonly attribute DOMString xmlEncoding;
|
|
||||||
// Introduced in DOM Level 3:
|
|
||||||
attribute boolean xmlStandalone;
|
|
||||||
// raises(DOMException) on setting
|
|
||||||
|
|
||||||
// Introduced in DOM Level 3:
|
readonly attribute DocumentType? doctype;
|
||||||
attribute DOMString xmlVersion;
|
readonly attribute Element? documentElement;
|
||||||
// raises(DOMException) on setting
|
HTMLCollection getElementsByTagName(DOMString localName);
|
||||||
|
HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
|
||||||
|
HTMLCollection getElementsByClassName(DOMString classNames);
|
||||||
|
Element? getElementById(DOMString elementId);
|
||||||
|
|
||||||
// Introduced in DOM Level 3:
|
Element createElement(DOMString localName);
|
||||||
attribute boolean strictErrorChecking;
|
Element createElementNS(DOMString? namespace, DOMString qualifiedName);
|
||||||
// Introduced in DOM Level 3:
|
DocumentFragment createDocumentFragment();
|
||||||
attribute DOMString documentURI;
|
Text createTextNode(DOMString data);
|
||||||
// Introduced in DOM Level 3:
|
Comment createComment(DOMString data);
|
||||||
Node adoptNode(in Node source)
|
ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);
|
||||||
raises(DOMException);
|
|
||||||
// Introduced in DOM Level 3:
|
Node importNode(Node node, optional boolean deep = true);
|
||||||
readonly attribute DOMConfiguration domConfig;
|
Node adoptNode(Node node);
|
||||||
// Introduced in DOM Level 3:
|
|
||||||
void normalizeDocument();
|
Event createEvent(DOMString interface);
|
||||||
// Introduced in DOM Level 3:
|
|
||||||
Node renameNode(in Node n,
|
Range createRange();
|
||||||
in DOMString namespaceURI,
|
|
||||||
in DOMString qualifiedName)
|
// NodeFilter.SHOW_ALL = 0xFFFFFFFF
|
||||||
raises(DOMException);
|
NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
|
||||||
|
TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
|
||||||
|
|
||||||
|
// NEW
|
||||||
|
void prepend((Node or DOMString)... nodes);
|
||||||
|
void append((Node or DOMString)... nodes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static void jsfinalize_document(JSContext *cx, JSObject *obj);
|
||||||
|
|
||||||
|
struct jsclass_document_priv {
|
||||||
|
struct html_content *htmlc;
|
||||||
|
dom_document *node;
|
||||||
|
};
|
||||||
|
|
||||||
static JSClass jsclass_document =
|
static JSClass jsclass_document =
|
||||||
{
|
{
|
||||||
@ -109,24 +88,29 @@ static JSClass jsclass_document =
|
|||||||
JS_EnumerateStub,
|
JS_EnumerateStub,
|
||||||
JS_ResolveStub,
|
JS_ResolveStub,
|
||||||
JS_ConvertStub,
|
JS_ConvertStub,
|
||||||
JS_FinalizeStub,
|
jsfinalize_document,
|
||||||
JSCLASS_NO_OPTIONAL_MEMBERS
|
JSCLASS_NO_OPTIONAL_MEMBERS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define JSCLASS_NAME document
|
||||||
|
|
||||||
|
#include "node.c"
|
||||||
|
|
||||||
static JSBool JSAPI_NATIVE(getElementById, JSContext *cx, uintN argc, jsval *vp)
|
static JSBool JSAPI_NATIVE(getElementById, JSContext *cx, uintN argc, jsval *vp)
|
||||||
{
|
{
|
||||||
JSString* u16_txt;
|
JSString* u16_txt;
|
||||||
char *txt;
|
char *txt;
|
||||||
unsigned long txtlen;
|
unsigned long txtlen;
|
||||||
struct html_content *htmlc;
|
|
||||||
dom_string *idstr;
|
dom_string *idstr;
|
||||||
dom_element *idelement;
|
dom_element *idelement;
|
||||||
|
struct jsclass_document_priv *document;
|
||||||
|
|
||||||
htmlc = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &jsclass_document, NULL);
|
document = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &jsclass_document, NULL);
|
||||||
if (htmlc == NULL)
|
if (document == NULL) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (htmlc->document == NULL) {
|
if (document->node == NULL) {
|
||||||
/* no document available, this is obviously a problem
|
/* no document available, this is obviously a problem
|
||||||
* for finding elements
|
* for finding elements
|
||||||
*/
|
*/
|
||||||
@ -142,9 +126,9 @@ static JSBool JSAPI_NATIVE(getElementById, JSContext *cx, uintN argc, jsval *vp)
|
|||||||
|
|
||||||
dom_string_create((unsigned char*)txt, txtlen, &idstr);
|
dom_string_create((unsigned char*)txt, txtlen, &idstr);
|
||||||
|
|
||||||
dom_document_get_element_by_id(htmlc->document, idstr, &idelement);
|
dom_document_get_element_by_id(document->node, idstr, &idelement);
|
||||||
|
|
||||||
JSAPI_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(jsapi_new_element(cx, JS_GetGlobalObject(cx), htmlc, idelement)));
|
JSAPI_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(jsapi_new_element(cx, JS_GetGlobalObject(cx), document->htmlc, idelement)));
|
||||||
|
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
@ -154,20 +138,23 @@ static JSBool JSAPI_NATIVE(write, JSContext *cx, uintN argc, jsval *vp)
|
|||||||
JSString* u16_txt;
|
JSString* u16_txt;
|
||||||
char *txt;
|
char *txt;
|
||||||
unsigned long length;
|
unsigned long length;
|
||||||
struct html_content *htmlc;
|
struct jsclass_document_priv *document;
|
||||||
|
|
||||||
htmlc = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &jsclass_document, NULL);
|
document = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &jsclass_document, NULL);
|
||||||
if (htmlc == NULL)
|
if (document == NULL) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!JS_ConvertArguments(cx, argc, JSAPI_ARGV(cx, vp), "S", &u16_txt))
|
if (!JS_ConvertArguments(cx, argc, JSAPI_ARGV(cx, vp), "S", &u16_txt)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
JSString_to_char(u16_txt, txt, length);
|
JSString_to_char(u16_txt, txt, length);
|
||||||
|
|
||||||
LOG(("content %p parser %p writing %s",htmlc, htmlc->parser, txt));
|
LOG(("content %p parser %p writing %s",
|
||||||
if (htmlc->parser != NULL) {
|
document->htmlc, document->htmlc->parser, txt));
|
||||||
dom_hubbub_parser_insert_chunk(htmlc->parser, (uint8_t *)txt, length);
|
if (document->htmlc->parser != NULL) {
|
||||||
|
dom_hubbub_parser_insert_chunk(document->htmlc->parser, (uint8_t *)txt, length);
|
||||||
}
|
}
|
||||||
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
@ -175,6 +162,7 @@ static JSBool JSAPI_NATIVE(write, JSContext *cx, uintN argc, jsval *vp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static JSFunctionSpec jsfunctions_document[] = {
|
static JSFunctionSpec jsfunctions_document[] = {
|
||||||
|
JSAPI_FS_NODE,
|
||||||
JSAPI_FS(write, 1, 0),
|
JSAPI_FS(write, 1, 0),
|
||||||
JSAPI_FS(getElementById, 1, 0),
|
JSAPI_FS(getElementById, 1, 0),
|
||||||
JSAPI_FS_END
|
JSAPI_FS_END
|
||||||
@ -182,11 +170,30 @@ static JSFunctionSpec jsfunctions_document[] = {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void jsfinalize_document(JSContext *cx, JSObject *obj)
|
||||||
JSObject *jsapi_new_document(JSContext *cx, JSObject *parent, void *doc_priv)
|
|
||||||
{
|
{
|
||||||
JSObject *doc;
|
struct jsclass_document_priv *document;
|
||||||
doc = JS_InitClass(cx,
|
|
||||||
|
document = JS_GetInstancePrivate(cx, obj, &jsclass_document, NULL);
|
||||||
|
if (document != NULL) {
|
||||||
|
free(document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject *jsapi_new_document(JSContext *cx, JSObject *parent, struct html_content *htmlc)
|
||||||
|
{
|
||||||
|
/* create document object and return it */
|
||||||
|
JSObject *jsdocument;
|
||||||
|
struct jsclass_document_priv *document;
|
||||||
|
|
||||||
|
document = malloc(sizeof(document));
|
||||||
|
if (document == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
document->htmlc = htmlc;
|
||||||
|
document->node = htmlc->document;
|
||||||
|
|
||||||
|
jsdocument = JS_InitClass(cx,
|
||||||
parent,
|
parent,
|
||||||
NULL,
|
NULL,
|
||||||
&jsclass_document,
|
&jsclass_document,
|
||||||
@ -196,16 +203,18 @@ JSObject *jsapi_new_document(JSContext *cx, JSObject *parent, void *doc_priv)
|
|||||||
jsfunctions_document,
|
jsfunctions_document,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
if (doc == NULL) {
|
if (jsdocument == NULL) {
|
||||||
|
free(document);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(("setting content to %p",doc_priv));
|
LOG(("setting document private to %p", document));
|
||||||
/* private pointer to browsing context */
|
/* private pointer to browsing context */
|
||||||
if (JS_SetPrivate(cx, doc, doc_priv) != JS_TRUE) {
|
if (JS_SetPrivate(cx, jsdocument, document) != JS_TRUE) {
|
||||||
LOG(("failed to set content"));
|
LOG(("failed to set document private"));
|
||||||
|
free(document);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return doc;
|
return jsdocument;
|
||||||
}
|
}
|
||||||
|
106
javascript/jsapi/domexception.c
Normal file
106
javascript/jsapi/domexception.c
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
|
||||||
|
*
|
||||||
|
* This file is part of NetSurf, http://www.netsurf-browser.org/
|
||||||
|
*
|
||||||
|
* NetSurf is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* NetSurf is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dom/dom.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "javascript/jsapi.h"
|
||||||
|
#include "utils/config.h"
|
||||||
|
#include "render/html_internal.h"
|
||||||
|
#include "utils/log.h"
|
||||||
|
|
||||||
|
/* IDL http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#exception-domexception
|
||||||
|
exception DOMException {
|
||||||
|
const unsigned short INDEX_SIZE_ERR = 1;
|
||||||
|
const unsigned short DOMSTRING_SIZE_ERR = 2; // historical
|
||||||
|
const unsigned short HIERARCHY_REQUEST_ERR = 3;
|
||||||
|
const unsigned short WRONG_DOCUMENT_ERR = 4;
|
||||||
|
const unsigned short INVALID_CHARACTER_ERR = 5;
|
||||||
|
const unsigned short NO_DATA_ALLOWED_ERR = 6; // historical
|
||||||
|
const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7;
|
||||||
|
const unsigned short NOT_FOUND_ERR = 8;
|
||||||
|
const unsigned short NOT_SUPPORTED_ERR = 9;
|
||||||
|
const unsigned short INUSE_ATTRIBUTE_ERR = 10; // historical
|
||||||
|
const unsigned short INVALID_STATE_ERR = 11;
|
||||||
|
const unsigned short SYNTAX_ERR = 12;
|
||||||
|
const unsigned short INVALID_MODIFICATION_ERR = 13;
|
||||||
|
const unsigned short NAMESPACE_ERR = 14;
|
||||||
|
const unsigned short INVALID_ACCESS_ERR = 15;
|
||||||
|
const unsigned short VALIDATION_ERR = 16; // historical
|
||||||
|
const unsigned short TYPE_MISMATCH_ERR = 17;
|
||||||
|
const unsigned short SECURITY_ERR = 18;
|
||||||
|
const unsigned short NETWORK_ERR = 19;
|
||||||
|
const unsigned short ABORT_ERR = 20;
|
||||||
|
const unsigned short URL_MISMATCH_ERR = 21;
|
||||||
|
const unsigned short QUOTA_EXCEEDED_ERR = 22;
|
||||||
|
const unsigned short TIMEOUT_ERR = 23;
|
||||||
|
const unsigned short INVALID_NODE_TYPE_ERR = 24;
|
||||||
|
const unsigned short DATA_CLONE_ERR = 25;
|
||||||
|
unsigned short code;
|
||||||
|
};
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
static JSClass jsclass_domexception =
|
||||||
|
{
|
||||||
|
"DOMException",
|
||||||
|
JSCLASS_HAS_PRIVATE,
|
||||||
|
JS_PropertyStub,
|
||||||
|
JS_PropertyStub,
|
||||||
|
JS_PropertyStub,
|
||||||
|
JS_StrictPropertyStub,
|
||||||
|
JS_EnumerateStub,
|
||||||
|
JS_ResolveStub,
|
||||||
|
JS_ConvertStub,
|
||||||
|
JS_FinalizeStub,
|
||||||
|
JSCLASS_NO_OPTIONAL_MEMBERS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
JSObject *
|
||||||
|
jsapi_new_domexception(JSContext *cx,
|
||||||
|
JSObject *parent,
|
||||||
|
int code)
|
||||||
|
{
|
||||||
|
/* create element object and return it*/
|
||||||
|
JSObject *jsdomexception;
|
||||||
|
|
||||||
|
jssomexception = JS_InitClass(cx,
|
||||||
|
parent,
|
||||||
|
NULL,
|
||||||
|
&jsclass_domexception,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
if (jsdomexecption == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(("setting element private to %d", code));
|
||||||
|
/* private pointer to browsing context */
|
||||||
|
if (JS_SetPrivate(cx, jsdomexception, code) != JS_TRUE) {
|
||||||
|
LOG(("failed to set content"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsdomexception;
|
||||||
|
}
|
@ -24,16 +24,62 @@
|
|||||||
#include "render/html_internal.h"
|
#include "render/html_internal.h"
|
||||||
#include "utils/log.h"
|
#include "utils/log.h"
|
||||||
|
|
||||||
|
/* IDL http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-element
|
||||||
|
|
||||||
|
CAUTION - innerHTML etc. are not part of the DOM they come from:
|
||||||
|
http://html5.org/specs/dom-parsing.html#extensions-to-the-element-interface
|
||||||
|
|
||||||
|
interface Element : Node {
|
||||||
|
readonly attribute DOMString? namespaceURI;
|
||||||
|
readonly attribute DOMString? prefix;
|
||||||
|
readonly attribute DOMString localName;
|
||||||
|
readonly attribute DOMString tagName;
|
||||||
|
|
||||||
|
attribute DOMString id;
|
||||||
|
attribute DOMString className;
|
||||||
|
readonly attribute DOMTokenList classList;
|
||||||
|
|
||||||
|
readonly attribute Attr[] attributes;
|
||||||
|
DOMString? getAttribute(DOMString name);
|
||||||
|
DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
|
||||||
|
void setAttribute(DOMString name, DOMString value);
|
||||||
|
void setAttributeNS(DOMString? namespace, DOMString name, DOMString value);
|
||||||
|
void removeAttribute(DOMString name);
|
||||||
|
void removeAttributeNS(DOMString? namespace, DOMString localName);
|
||||||
|
boolean hasAttribute(DOMString name);
|
||||||
|
boolean hasAttributeNS(DOMString? namespace, DOMString localName);
|
||||||
|
|
||||||
|
HTMLCollection getElementsByTagName(DOMString localName);
|
||||||
|
HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
|
||||||
|
HTMLCollection getElementsByClassName(DOMString classNames);
|
||||||
|
|
||||||
|
readonly attribute HTMLCollection children;
|
||||||
|
readonly attribute Element? firstElementChild;
|
||||||
|
readonly attribute Element? lastElementChild;
|
||||||
|
readonly attribute Element? previousElementSibling;
|
||||||
|
readonly attribute Element? nextElementSibling;
|
||||||
|
readonly attribute unsigned long childElementCount;
|
||||||
|
|
||||||
|
// NEW
|
||||||
|
void prepend((Node or DOMString)... nodes);
|
||||||
|
void append((Node or DOMString)... nodes);
|
||||||
|
void before((Node or DOMString)... nodes);
|
||||||
|
void after((Node or DOMString)... nodes);
|
||||||
|
void replace((Node or DOMString)... nodes);
|
||||||
|
void remove();
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
static void jsfinalize_element(JSContext *cx, JSObject *obj);
|
static void jsfinalize_element(JSContext *cx, JSObject *obj);
|
||||||
|
|
||||||
typedef struct {
|
struct jsclass_document_priv {
|
||||||
struct html_content *htmlc;
|
struct html_content *htmlc;
|
||||||
struct dom_element *dom_element;
|
dom_element *node;
|
||||||
} elementp;
|
};
|
||||||
|
|
||||||
static JSClass jsclass_element =
|
static JSClass jsclass_element =
|
||||||
{
|
{
|
||||||
"element",
|
"Element",
|
||||||
JSCLASS_HAS_PRIVATE,
|
JSCLASS_HAS_PRIVATE,
|
||||||
JS_PropertyStub,
|
JS_PropertyStub,
|
||||||
JS_PropertyStub,
|
JS_PropertyStub,
|
||||||
@ -46,9 +92,13 @@ static JSClass jsclass_element =
|
|||||||
JSCLASS_NO_OPTIONAL_MEMBERS
|
JSCLASS_NO_OPTIONAL_MEMBERS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define JSCLASS_NAME element
|
||||||
|
|
||||||
|
#include "node.c"
|
||||||
|
|
||||||
static void jsfinalize_element(JSContext *cx, JSObject *obj)
|
static void jsfinalize_element(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
elementp *element;
|
struct jsclass_document_priv *element;
|
||||||
element = JS_GetInstancePrivate(cx, obj, &jsclass_element, NULL);
|
element = JS_GetInstancePrivate(cx, obj, &jsclass_element, NULL);
|
||||||
if (element != NULL) {
|
if (element != NULL) {
|
||||||
free(element);
|
free(element);
|
||||||
@ -58,6 +108,7 @@ static void jsfinalize_element(JSContext *cx, JSObject *obj)
|
|||||||
|
|
||||||
|
|
||||||
static JSFunctionSpec jsfunctions_element[] = {
|
static JSFunctionSpec jsfunctions_element[] = {
|
||||||
|
JSAPI_FS_NODE,
|
||||||
JSAPI_FS_END
|
JSAPI_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,18 +117,18 @@ JSObject *
|
|||||||
jsapi_new_element(JSContext *cx,
|
jsapi_new_element(JSContext *cx,
|
||||||
JSObject *parent,
|
JSObject *parent,
|
||||||
struct html_content *htmlc,
|
struct html_content *htmlc,
|
||||||
struct dom_element *domelement)
|
dom_element *domelement)
|
||||||
{
|
{
|
||||||
/* create element object and return it*/
|
/* create element object and return it */
|
||||||
JSObject *jselement;
|
JSObject *jselement;
|
||||||
elementp *element;
|
struct jsclass_document_priv *element;
|
||||||
|
|
||||||
element = malloc(sizeof(element));
|
element = malloc(sizeof(element));
|
||||||
if (element == NULL) {
|
if (element == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
element->htmlc = htmlc;
|
element->htmlc = htmlc;
|
||||||
element->dom_element = domelement;
|
element->node = domelement;
|
||||||
|
|
||||||
jselement = JS_InitClass(cx,
|
jselement = JS_InitClass(cx,
|
||||||
parent,
|
parent,
|
||||||
@ -94,10 +145,10 @@ jsapi_new_element(JSContext *cx,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(("setting element private to %p", element));
|
LOG(("setting private to %p", element));
|
||||||
/* private pointer to browsing context */
|
/* private pointer to browsing context */
|
||||||
if (JS_SetPrivate(cx, jselement, element) != JS_TRUE) {
|
if (JS_SetPrivate(cx, jselement, element) != JS_TRUE) {
|
||||||
LOG(("failed to set content"));
|
LOG(("failed to set private"));
|
||||||
free(element);
|
free(element);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
88
javascript/jsapi/eventtarget.c
Normal file
88
javascript/jsapi/eventtarget.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
|
||||||
|
*
|
||||||
|
* This file is part of NetSurf, http://www.netsurf-browser.org/
|
||||||
|
*
|
||||||
|
* NetSurf is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* NetSurf is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* IDL http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#eventtarget
|
||||||
|
|
||||||
|
interface EventTarget {
|
||||||
|
void addEventListener(DOMString type, EventListener? callback, optional boolean capture = false);
|
||||||
|
void removeEventListener(DOMString type, EventListener? callback, optional boolean capture = false);
|
||||||
|
boolean dispatchEvent(Event event);
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef JSCLASS_NAME
|
||||||
|
#error "The class name must be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSCLASS_TYPE
|
||||||
|
#define CLASS jsclass
|
||||||
|
#define PRIVATE priv
|
||||||
|
#define EXPAND(a,b) PASTE(a,b)
|
||||||
|
#define PASTE(x,y) x##_##y
|
||||||
|
#define JSCLASS_OBJECT EXPAND(CLASS,JSCLASS_NAME)
|
||||||
|
#define JSCLASS_TYPE EXPAND(JSCLASS_OBJECT,PRIVATE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(addEventListener, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(removeEventListener, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(dispatchEvent, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define JSAPI_FS_EVENTTARGET \
|
||||||
|
JSAPI_FS(addEventListener, 0, 0), \
|
||||||
|
JSAPI_FS(removeEventListener, 0, 0), \
|
||||||
|
JSAPI_FS(dispatchEvent, 0, 0)
|
288
javascript/jsapi/node.c
Normal file
288
javascript/jsapi/node.c
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
|
||||||
|
*
|
||||||
|
* This file is part of NetSurf, http://www.netsurf-browser.org/
|
||||||
|
*
|
||||||
|
* NetSurf is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* NetSurf is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* IDL http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-node
|
||||||
|
interface Node : EventTarget {
|
||||||
|
const unsigned short ELEMENT_NODE = 1;
|
||||||
|
const unsigned short ATTRIBUTE_NODE = 2; // historical
|
||||||
|
const unsigned short TEXT_NODE = 3;
|
||||||
|
const unsigned short CDATA_SECTION_NODE = 4; // historical
|
||||||
|
const unsigned short ENTITY_REFERENCE_NODE = 5; // historical
|
||||||
|
const unsigned short ENTITY_NODE = 6; // historical
|
||||||
|
const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
|
||||||
|
const unsigned short COMMENT_NODE = 8;
|
||||||
|
const unsigned short DOCUMENT_NODE = 9;
|
||||||
|
const unsigned short DOCUMENT_TYPE_NODE = 10;
|
||||||
|
const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
|
||||||
|
const unsigned short NOTATION_NODE = 12; // historical
|
||||||
|
readonly attribute unsigned short nodeType;
|
||||||
|
readonly attribute DOMString nodeName;
|
||||||
|
|
||||||
|
readonly attribute DOMString? baseURI;
|
||||||
|
|
||||||
|
readonly attribute Document? ownerDocument;
|
||||||
|
readonly attribute Node? parentNode;
|
||||||
|
readonly attribute Element? parentElement;
|
||||||
|
boolean hasChildNodes();
|
||||||
|
readonly attribute NodeList childNodes;
|
||||||
|
readonly attribute Node? firstChild;
|
||||||
|
readonly attribute Node? lastChild;
|
||||||
|
readonly attribute Node? previousSibling;
|
||||||
|
readonly attribute Node? nextSibling;
|
||||||
|
|
||||||
|
const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
|
||||||
|
const unsigned short DOCUMENT_POSITION_PRECEDING = 0x02;
|
||||||
|
const unsigned short DOCUMENT_POSITION_FOLLOWING = 0x04;
|
||||||
|
const unsigned short DOCUMENT_POSITION_CONTAINS = 0x08;
|
||||||
|
const unsigned short DOCUMENT_POSITION_CONTAINED_BY = 0x10;
|
||||||
|
const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20; // historical
|
||||||
|
unsigned short compareDocumentPosition(Node other);
|
||||||
|
boolean contains(Node? other);
|
||||||
|
|
||||||
|
attribute DOMString? nodeValue;
|
||||||
|
attribute DOMString? textContent;
|
||||||
|
Node insertBefore(Node node, Node? child);
|
||||||
|
Node appendChild(Node node);
|
||||||
|
Node replaceChild(Node node, Node child);
|
||||||
|
Node removeChild(Node child);
|
||||||
|
void normalize();
|
||||||
|
|
||||||
|
|
||||||
|
Node cloneNode(optional boolean deep = true);
|
||||||
|
boolean isEqualNode(Node? node);
|
||||||
|
|
||||||
|
DOMString lookupPrefix(DOMString? namespace);
|
||||||
|
DOMString lookupNamespaceURI(DOMString? prefix);
|
||||||
|
boolean isDefaultNamespace(DOMString? namespace);
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "eventtarget.c"
|
||||||
|
|
||||||
|
#ifndef JSCLASS_NAME
|
||||||
|
#error "The class name must be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSCLASS_TYPE
|
||||||
|
#define CLASS jsclass
|
||||||
|
#define PRIVATE priv
|
||||||
|
#define EXPAND(a,b) PASTE(a,b)
|
||||||
|
#define PASTE(x,y) x##_##y
|
||||||
|
#define JSCLASS_OBJECT EXPAND(CLASS,JSCLASS_NAME)
|
||||||
|
#define JSCLASS_TYPE EXPAND(JSCLASS_OBJECT,PRIVATE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(hasChildNodes, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(compareDocumentPosition, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(contains, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(insertBefore, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(appendChild, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(replaceChild, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(removeChild, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(normalize, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(cloneNode, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(isEqualNode, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(lookupPrefix, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(lookupNamespaceURI, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSBool JSAPI_NATIVE(isDefaultNamespace, JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
{
|
||||||
|
struct JSCLASS_TYPE *priv;
|
||||||
|
|
||||||
|
priv = JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx,vp), &JSCLASS_OBJECT, NULL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
JSAPI_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define JSAPI_FS_NODE \
|
||||||
|
JSAPI_FS_EVENTTARGET, \
|
||||||
|
JSAPI_FS(hasChildNodes, 0, 0), \
|
||||||
|
JSAPI_FS(compareDocumentPosition, 0, 0), \
|
||||||
|
JSAPI_FS(contains, 0, 0), \
|
||||||
|
JSAPI_FS(insertBefore, 0, 0), \
|
||||||
|
JSAPI_FS(appendChild, 0, 0), \
|
||||||
|
JSAPI_FS(replaceChild, 0, 0), \
|
||||||
|
JSAPI_FS(removeChild, 0, 0), \
|
||||||
|
JSAPI_FS(normalize, 0, 0), \
|
||||||
|
JSAPI_FS(cloneNode, 0, 0), \
|
||||||
|
JSAPI_FS(isEqualNode, 0, 0), \
|
||||||
|
JSAPI_FS(lookupPrefix, 0, 0), \
|
||||||
|
JSAPI_FS(lookupNamespaceURI, 0, 0), \
|
||||||
|
JSAPI_FS(isDefaultNamespace, 0, 0)
|
Loading…
Reference in New Issue
Block a user