1998-09-11 23:46:23 +04:00
|
|
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
1998-08-27 04:02:31 +04:00
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* NPL.
|
|
|
|
*
|
|
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* DOM Element implementation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "dom_priv.h"
|
|
|
|
|
|
|
|
static JSPropertySpec element_props[] = {
|
1998-09-11 23:46:23 +04:00
|
|
|
{"tagName", DOM_ELEMENT_TAGNAME, JSPROP_READONLY, 0, 0},
|
1998-08-27 04:02:31 +04:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
element_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
|
|
{
|
|
|
|
intN slot;
|
|
|
|
DOM_Element *element;
|
|
|
|
|
|
|
|
if (!JSVAL_IS_INT(id))
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
slot = JSVAL_TO_INT(id);
|
|
|
|
|
1998-09-11 23:46:23 +04:00
|
|
|
/*
|
1998-08-27 04:02:31 +04:00
|
|
|
* Look, ma! Inheritance!
|
|
|
|
* We handle .attributes ourselves because we return something other
|
|
|
|
* than null, unlike every other Node subclass.
|
|
|
|
*/
|
|
|
|
if (slot != DOM_NODE_ATTRIBUTES &&
|
|
|
|
slot <= DOM_NODE_NODENAME &&
|
|
|
|
slot >= DOM_NODE_HASCHILDNODES) {
|
|
|
|
return dom_node_getter(cx, obj, id, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
element = (DOM_Element *)JS_GetPrivate(cx, obj);
|
|
|
|
if (!element)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
if (slot == DOM_ELEMENT_TAGNAME) {
|
1998-09-07 22:50:13 +04:00
|
|
|
JSString *tagName;
|
|
|
|
#ifdef DEBUG_shaver_0
|
1998-09-11 23:46:23 +04:00
|
|
|
fprintf(stderr, "getting tagName %s",
|
|
|
|
element->tagName ? element->tagName : "#tag");
|
|
|
|
tagName = JS_InternString(cx, element->tagName ?
|
|
|
|
element->tagName : "#tag");
|
|
|
|
fprintf(stderr, ": %x\n", tagName);
|
1998-09-01 02:31:44 +04:00
|
|
|
#else
|
1998-09-11 23:46:23 +04:00
|
|
|
tagName = JS_NewStringCopyZ(cx, element->tagName
|
|
|
|
? element->tagName
|
|
|
|
: "#tag");
|
1998-09-01 02:31:44 +04:00
|
|
|
#endif
|
1998-08-27 04:02:31 +04:00
|
|
|
if (!tagName)
|
|
|
|
return JS_FALSE;
|
|
|
|
*vp = STRING_TO_JSVAL(tagName);
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
element_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
|
|
{
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
1998-09-04 03:51:58 +04:00
|
|
|
static JSClass DOM_ElementClass = {
|
|
|
|
"Element", JSCLASS_HAS_PRIVATE,
|
|
|
|
JS_PropertyStub, JS_PropertyStub, element_getter, element_setter,
|
|
|
|
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, dom_node_finalize
|
|
|
|
};
|
|
|
|
|
1998-08-27 09:25:40 +04:00
|
|
|
static JSBool
|
|
|
|
element_getAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval)
|
|
|
|
{
|
|
|
|
DOM_Element *element;
|
|
|
|
JSString *name;
|
1998-09-10 18:21:43 +04:00
|
|
|
DOM_AttributeEntry *entry;
|
1998-08-27 09:25:40 +04:00
|
|
|
|
|
|
|
if (!JS_ConvertArguments(cx, argc, argv, "S", &name))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
element = (DOM_Element *)JS_GetPrivate(cx, obj);
|
|
|
|
if (!element)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
1998-09-10 18:21:43 +04:00
|
|
|
if (!DOM_GetElementAttribute(cx, element, JS_GetStringBytes(name),
|
|
|
|
&entry))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
if (entry && entry->value) {
|
1998-09-11 23:46:23 +04:00
|
|
|
JSString *valstr = JS_NewStringCopyZ(cx, entry->value);
|
|
|
|
if (!valstr)
|
1998-08-27 09:25:40 +04:00
|
|
|
return JS_FALSE;
|
1998-09-11 23:46:23 +04:00
|
|
|
*rval = STRING_TO_JSVAL(valstr);
|
1998-08-27 09:25:40 +04:00
|
|
|
} else {
|
1998-09-11 23:46:23 +04:00
|
|
|
*rval = JS_GetEmptyStringValue(cx);
|
1998-08-27 09:25:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
element_setAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval)
|
|
|
|
{
|
|
|
|
DOM_Element *element;
|
1998-09-10 18:21:43 +04:00
|
|
|
char *name, *value;
|
1998-08-27 09:25:40 +04:00
|
|
|
|
1998-09-10 18:21:43 +04:00
|
|
|
if (!JS_ConvertArguments(cx, argc, argv, "ss", &name, &value))
|
1998-08-27 09:25:40 +04:00
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
element = (DOM_Element *)JS_GetPrivate(cx, obj);
|
|
|
|
if (!element)
|
|
|
|
return JS_TRUE;
|
1998-09-10 18:21:43 +04:00
|
|
|
|
|
|
|
return DOM_SetElementAttribute(cx, element, name, value);
|
1998-08-27 09:25:40 +04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
element_removeAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval)
|
|
|
|
{
|
|
|
|
DOM_Element *element;
|
|
|
|
JSString *name;
|
|
|
|
|
|
|
|
if (!JS_ConvertArguments(cx, argc, argv, "S", &name))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
element = (DOM_Element *)JS_GetPrivate(cx, obj);
|
|
|
|
if (!element)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
/* NULL setAttribute call indicates removal */
|
|
|
|
return element->ops->setAttribute(cx, element, JS_GetStringBytes(name),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
element_getAttributeNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval)
|
|
|
|
{
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
element_setAttributeNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval)
|
|
|
|
{
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
element_removeAttributeNode(JSContext *cx, JSObject *obj, uintN argc,
|
|
|
|
jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
1998-09-04 03:51:58 +04:00
|
|
|
static JSFunctionSpec element_methods[] = {
|
1998-09-11 23:46:23 +04:00
|
|
|
{"setAttribute", element_setAttribute, 2},
|
|
|
|
{"getAttribute", element_getAttribute, 1},
|
|
|
|
{"removeAttribute", element_removeAttribute, 1},
|
|
|
|
{"setAttributeNode", element_setAttributeNode, 1},
|
|
|
|
{"getAttributeNode", element_getAttributeNode, 1},
|
1998-09-04 03:51:58 +04:00
|
|
|
{"removeAttributeNode", element_removeAttributeNode, 1},
|
|
|
|
{0}
|
1998-08-27 04:02:31 +04:00
|
|
|
};
|
|
|
|
|
1998-09-05 08:36:38 +04:00
|
|
|
DOM_Element *
|
|
|
|
DOM_NewElement(const char *tagName, DOM_ElementOps *eleops, char *name,
|
1998-09-29 02:51:50 +04:00
|
|
|
char *styleClass, char *styleID, DOM_NodeOps *nodeops)
|
1998-09-05 08:36:38 +04:00
|
|
|
{
|
|
|
|
DOM_Node *node;
|
|
|
|
DOM_Element *element = XP_NEW_ZAP(DOM_Element);
|
|
|
|
if (!element)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
node = (DOM_Node *)element;
|
|
|
|
node->type = NODE_TYPE_ELEMENT;
|
|
|
|
node->name = name;
|
|
|
|
node->ops = nodeops;
|
|
|
|
|
|
|
|
element->tagName = tagName;
|
1998-09-29 02:51:50 +04:00
|
|
|
element->styleClass = styleClass;
|
|
|
|
element->styleID = styleID;
|
1998-09-05 08:36:38 +04:00
|
|
|
element->ops = eleops;
|
1998-09-29 02:51:50 +04:00
|
|
|
|
1998-09-05 08:36:38 +04:00
|
|
|
return element;
|
|
|
|
}
|
|
|
|
|
1998-08-27 04:02:31 +04:00
|
|
|
JSObject *
|
|
|
|
DOM_NewElementObject(JSContext *cx, DOM_Element *element)
|
|
|
|
{
|
|
|
|
JSObject *obj;
|
1998-09-11 23:46:23 +04:00
|
|
|
|
1998-08-27 04:02:31 +04:00
|
|
|
obj = JS_ConstructObject(cx, &DOM_ElementClass, NULL, NULL);
|
|
|
|
if (!obj)
|
|
|
|
return NULL;
|
|
|
|
if (!JS_SetPrivate(cx, obj, element))
|
|
|
|
return NULL;
|
|
|
|
element->node.mocha_object = obj;
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject *
|
|
|
|
DOM_ObjectForElement(JSContext *cx, DOM_Element *element)
|
|
|
|
{
|
|
|
|
if (!element)
|
|
|
|
return NULL;
|
|
|
|
if (element->node.mocha_object)
|
|
|
|
return element->node.mocha_object;
|
|
|
|
return DOM_NewElementObject(cx, element);
|
|
|
|
}
|
|
|
|
|
1998-09-10 18:21:43 +04:00
|
|
|
static void
|
|
|
|
DestroyAttrs(JSContext *cx, DOM_Element *element)
|
|
|
|
{
|
|
|
|
uintN i;
|
|
|
|
DOM_AttributeEntry *entry;
|
|
|
|
for (i = 0; i < element->nattrs; i++) {
|
|
|
|
entry = element->attrs + i;
|
1998-10-17 00:51:20 +04:00
|
|
|
if (!entry->dtor || entry->dtor(entry)) {
|
|
|
|
JS_free(cx, (char *)entry->name);
|
|
|
|
JS_free(cx, (char *)entry->value);
|
|
|
|
JS_free(cx, entry);
|
|
|
|
}
|
1998-09-10 18:21:43 +04:00
|
|
|
}
|
|
|
|
JS_free(cx, element->attrs);
|
|
|
|
element->attrs = NULL;
|
|
|
|
element->nattrs = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
|
|
|
DOM_SetElementAttributes(JSContext *cx, DOM_Element *element,
|
|
|
|
const char **names, const char **values, uintN count)
|
|
|
|
{
|
|
|
|
DOM_AttributeEntry *entry;
|
|
|
|
uintN i;
|
|
|
|
|
|
|
|
if (element->attrs)
|
|
|
|
DestroyAttrs(cx, element);
|
|
|
|
if (!(count && names && values))
|
|
|
|
return JS_TRUE;
|
|
|
|
element->attrs =
|
|
|
|
(DOM_AttributeEntry *)JS_malloc(cx,count * sizeof(DOM_AttributeEntry));
|
|
|
|
if (!element->attrs)
|
|
|
|
return JS_FALSE;
|
|
|
|
element->nattrs = count;
|
|
|
|
|
1998-10-15 21:45:03 +04:00
|
|
|
#ifdef DEBUG_shaver_attributes
|
|
|
|
fprintf(stderr, "ELEMENT %p has %d attrs\n", element,
|
|
|
|
element->nattrs);
|
|
|
|
#endif
|
|
|
|
|
1998-09-10 18:21:43 +04:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
entry = element->attrs + i;
|
|
|
|
entry->name = names[i];
|
|
|
|
entry->value = values[i];
|
|
|
|
entry->dirty = entry->data = 0;
|
|
|
|
}
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
|
|
|
DOM_GetElementAttribute(JSContext *cx, DOM_Element *element, const char *name,
|
|
|
|
DOM_AttributeEntry **entryp)
|
|
|
|
{
|
|
|
|
DOM_AttributeEntry *entry;
|
|
|
|
uintN i;
|
|
|
|
|
|
|
|
for (i = 0, entry = element->attrs;
|
|
|
|
i < element->nattrs && entry->name;
|
|
|
|
i++, entry++) {
|
|
|
|
if (!strcmp(name, entry->name)) {
|
|
|
|
*entryp = entry;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*entryp = NULL;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
1998-09-29 02:51:50 +04:00
|
|
|
JSBool
|
|
|
|
DOM_GetCleanEntryData(JSContext *cx, DOM_AttributeEntry *entry,
|
1998-10-17 00:51:20 +04:00
|
|
|
DOM_DataParser parser, DOM_DataDestructor dtor,
|
|
|
|
uint32 *data, void *closure)
|
1998-09-29 02:51:50 +04:00
|
|
|
{
|
|
|
|
if (entry->dirty) {
|
|
|
|
uint32 newdata;
|
|
|
|
if (!parser(entry->value, &newdata, closure))
|
|
|
|
return JS_FALSE;
|
1998-10-17 00:51:20 +04:00
|
|
|
entry->dtor = dtor;
|
1998-09-29 02:51:50 +04:00
|
|
|
entry->data = newdata;
|
|
|
|
entry->dirty = JS_FALSE;
|
|
|
|
}
|
|
|
|
*data = entry->data;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DOM_AttributeEntry *
|
1998-09-10 18:21:43 +04:00
|
|
|
AddAttribute(JSContext *cx, DOM_Element *element, const char *name,
|
|
|
|
const char *value)
|
|
|
|
{
|
|
|
|
DOM_AttributeEntry *entry;
|
|
|
|
|
|
|
|
if (!element->attrs) {
|
|
|
|
element->attrs = JS_malloc(cx, sizeof(DOM_AttributeEntry));
|
|
|
|
if (!element->attrs)
|
1998-09-29 02:51:50 +04:00
|
|
|
return NULL;
|
1998-09-10 18:21:43 +04:00
|
|
|
element->nattrs = 1;
|
|
|
|
} else {
|
|
|
|
element->attrs = XP_REALLOC(element->attrs,
|
|
|
|
(element->nattrs++) * sizeof(DOM_AttributeEntry));
|
|
|
|
if (!element->attrs)
|
1998-09-29 02:51:50 +04:00
|
|
|
return NULL;
|
1998-09-10 18:21:43 +04:00
|
|
|
}
|
|
|
|
entry = element->attrs + element->nattrs - 1;
|
|
|
|
entry->name = name;
|
|
|
|
entry->value = value;
|
1998-10-15 21:45:03 +04:00
|
|
|
#ifdef DEBUG_shaver_attributes
|
|
|
|
fprintf(stderr,
|
|
|
|
"ELEMENT %p has %d attrs after adding #%d %p/%s=%p/%s @ %p\n",
|
|
|
|
element, element->nattrs, entry - element->attrs, entry->name,
|
|
|
|
entry->name, entry->value, entry->value, entry);
|
|
|
|
#endif
|
1998-09-29 02:51:50 +04:00
|
|
|
return entry;
|
1998-09-10 18:21:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
1998-09-29 02:51:50 +04:00
|
|
|
dom_SetElementAttribute(JSContext *cx, DOM_Element *element, const char *name,
|
|
|
|
const char *value, JSBool runCallback)
|
1998-09-10 18:21:43 +04:00
|
|
|
{
|
|
|
|
DOM_AttributeEntry *entry;
|
|
|
|
if (!DOM_GetElementAttribute(cx, element, name, &entry))
|
|
|
|
return JS_FALSE;
|
|
|
|
if (!entry) {
|
1998-09-29 02:51:50 +04:00
|
|
|
entry = AddAttribute(cx, element, name, value);
|
|
|
|
if (!entry)
|
1998-09-10 18:21:43 +04:00
|
|
|
return JS_FALSE;
|
|
|
|
} else {
|
|
|
|
if (entry->value)
|
|
|
|
JS_free(cx, (char *)entry->value);
|
|
|
|
entry->value = value;
|
|
|
|
}
|
|
|
|
entry->dirty = JS_TRUE;
|
|
|
|
|
1998-09-29 02:51:50 +04:00
|
|
|
if (!runCallback)
|
|
|
|
return JS_TRUE;
|
1998-09-10 18:21:43 +04:00
|
|
|
return element->ops->setAttribute(cx, element, name, value);
|
|
|
|
}
|
|
|
|
|
1998-09-29 02:51:50 +04:00
|
|
|
JSBool
|
|
|
|
DOM_SetElementAttribute(JSContext *cx, DOM_Element *element, const char *name,
|
|
|
|
const char *value)
|
|
|
|
{
|
|
|
|
return dom_SetElementAttribute(cx, element, name, value, JS_TRUE);
|
|
|
|
}
|
|
|
|
|
1998-08-27 04:02:31 +04:00
|
|
|
static JSBool
|
1998-08-27 09:25:40 +04:00
|
|
|
Element(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *vp)
|
1998-08-27 04:02:31 +04:00
|
|
|
{
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject *
|
|
|
|
dom_ElementInit(JSContext *cx, JSObject *scope, JSObject *node_proto)
|
|
|
|
{
|
|
|
|
JSObject *proto = JS_InitClass(cx, scope, node_proto, &DOM_ElementClass,
|
1998-09-11 23:46:23 +04:00
|
|
|
Element, 0,
|
|
|
|
element_props, element_methods,
|
|
|
|
NULL, NULL);
|
1998-08-27 04:02:31 +04:00
|
|
|
if (!JS_DefineProperties(cx, proto, dom_node_props))
|
|
|
|
return NULL;
|
|
|
|
return proto;
|
|
|
|
}
|