Added CData operations (append, insert, delete, replace, substring).

Added Element {[sg]et,remove}Attribute
Check for illegal child in Node ops appendChild, insertBefore and replaceChild.
This commit is contained in:
shaver%netscape.com 1998-08-27 05:25:40 +00:00
parent a85eb3e06f
commit 5998e7b720
4 changed files with 351 additions and 7 deletions

View File

@ -76,8 +76,7 @@ struct DOM_NodeOps {
JSBool (*replaceChild)(JSContext *cx, DOM_Node *node, DOM_Node *child,
DOM_Node *old);
JSBool (*removeChild) (JSContext *cx, DOM_Node *node, DOM_Node *old);
JSBool (*appendChild) (JSContext *cx, DOM_Node *node,
DOM_Node *child);
JSBool (*appendChild) (JSContext *cx, DOM_Node *node, DOM_Node *child);
/* free up Node-private data */
void (*destroyNode) (JSContext *cx, DOM_Node *node);
@ -116,7 +115,13 @@ DOM_ReflectNodeStub(JSContext *cx, DOM_Node *node);
struct DOM_ElementOps {
/*
* if this succeeds, pre-existing JS reflections (DOM_Attributes)
* will be updated as well.
* will be updated as well. Removal (removeAttribute, etc.) of an
* attribute is signalled by passing a value of NULL. The
* setAttribute function is responsible for doing
* DOM_SignalException(cx, DOM_INVALID_NAME_ERR) if it's an
* invalid name. (The DOM_NO_MODIFICATION_ALLOWED_ERR case is
* handled in the DOM code itself, and no call will be made to the
* setAttribute handler in that case.)
*/
JSBool (*setAttribute)(JSContext *cx, DOM_Element *element,
const char *name, const char *value);
@ -227,10 +232,21 @@ struct DOM_Document {
DOM_Node node;
};
typedef enum DOM_CDataOperationCode {
CDATA_APPEND,
CDATA_INSERT,
CDATA_DELETE,
CDATA_REPLACE
} DOM_CDataOperationCode;
typedef JSBool (*DOM_CDataOp)(JSContext *cx, DOM_CharacterData *cdata,
DOM_CDataOperationCode op);
struct DOM_CharacterData {
DOM_Node node;
char *data;
uintN len;
DOM_CDataOp notify;
};
struct DOM_Text {
@ -238,7 +254,7 @@ struct DOM_Text {
};
DOM_Text *
DOM_NewText(const char *data, int64 len);
DOM_NewText(const char *data, int64 len, DOM_CDataOp notify);
JSObject *
DOM_NewTextObject(JSContext *cx, DOM_Text *text);

View File

@ -80,6 +80,95 @@ element_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
return JS_TRUE;
}
static JSBool
element_getAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
DOM_Element *element;
JSString *name;
char *value;
JSBool cache;
if (!JS_ConvertArguments(cx, argc, argv, "S", &name))
return JS_FALSE;
element = (DOM_Element *)JS_GetPrivate(cx, obj);
if (!element)
return JS_TRUE;
value = element->ops->getAttribute(cx, element, JS_GetStringBytes(name),
&cache);
if (value) {
*rval = STRING_TO_JSVAL(JS_InternString(cx, value));
if (!JSVAL_TO_STRING(*rval))
return JS_FALSE;
} else {
*rval = STRING_TO_JSVAL(JS_GetEmptyStringValue(cx));
}
return JS_TRUE;
}
static JSBool
element_setAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
DOM_Element *element;
JSString *name, *value;
if (!JS_ConvertArguments(cx, argc, argv, "SS", &name, &value))
return JS_FALSE;
element = (DOM_Element *)JS_GetPrivate(cx, obj);
if (!element)
return JS_TRUE;
return element->ops->setAttribute(cx, element, JS_GetStringBytes(name),
JS_GetStringBytes(value));
}
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;
}
static void
element_finalize(JSContext *cx, JSObject *obj)
{
@ -117,8 +206,7 @@ DOM_ObjectForElement(JSContext *cx, DOM_Element *element)
}
static JSBool
Element(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *vp)
Element(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *vp)
{
return JS_TRUE;
}

View File

@ -185,6 +185,61 @@ if (refNode->parent != node) { \
} \
PR_END_MACRO
static JSBool
IsLegalChild(DOM_Node *node, DOM_Node *child)
{
switch(node->type) {
case NODE_TYPE_ATTRIBUTE:
if (child->type == NODE_TYPE_TEXT ||
child->type == NODE_TYPE_ENTITY_REF)
return JS_TRUE;
return JS_FALSE;
if (child->type == NODE_TYPE_ELEMENT ||
child->type == NODE_TYPE_COMMENT ||
child->type == NODE_TYPE_TEXT ||
child->type == NODE_TYPE_PI ||
child->type == NODE_TYPE_CDATA ||
child->type == NODE_TYPE_ENTITY_REF)
return JS_TRUE;
return JS_FALSE;
case NODE_TYPE_ELEMENT:
case NODE_TYPE_DOCFRAGMENT:
case NODE_TYPE_ENTITY_REF:
if (child->type == NODE_TYPE_ELEMENT ||
child->type == NODE_TYPE_PI ||
child->type == NODE_TYPE_COMMENT ||
child->type == NODE_TYPE_TEXT ||
child->type == NODE_TYPE_CDATA ||
child->type == NODE_TYPE_ENTITY_REF)
return JS_TRUE;
return JS_FALSE;
case NODE_TYPE_DOCUMENT:
if(child->type == NODE_TYPE_PI ||
child->type == NODE_TYPE_COMMENT ||
child->type == NODE_TYPE_DOCTYPE)
return JS_TRUE;
if (child->type == NODE_TYPE_ELEMENT)
/* XXX check to make sure it's the only one */
return JS_TRUE;
return JS_FALSE;
case NODE_TYPE_DOCTYPE:
if (child->type == NODE_TYPE_NOTATION ||
child->type == NODE_TYPE_ENTITY)
return JS_TRUE;
return JS_FALSE;
default: /* PI, COMMENT, TEXT, CDATA, ENTITY, NOTATION */
return JS_FALSE;
}
}
#define CHECK_LEGAL_CHILD(node, child) \
PR_BEGIN_MACRO \
if (!IsLegalChild(node, child)) { \
DOM_SignalException(cx, DOM_HIERARCHY_REQUEST_ERR); \
return JS_FALSE; \
} \
PR_END_MACRO
static JSBool
node_insertBefore(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *vp)
@ -206,6 +261,7 @@ node_insertBefore(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_TRUE;
}
CHECK_LEGAL_CHILD(node, newNode);
FAIL_UNLESS_CHILD(node, refNode);
REMOVE_FROM_TREE(newNode);
@ -240,6 +296,7 @@ node_replaceChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
!newNode || !oldNode)
return JS_TRUE;
CHECK_LEGAL_CHILD(node, newNode);
FAIL_UNLESS_CHILD(node, oldNode);
REMOVE_FROM_TREE(newNode);
@ -290,6 +347,7 @@ node_appendChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
if (!node || !newNode)
return JS_TRUE;
CHECK_LEGAL_CHILD(node, newNode);
REMOVE_FROM_TREE(newNode);
newNode->parent = node;

View File

@ -73,6 +73,183 @@ cdata_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
return JS_TRUE;
}
static JSBool
cdata_substringData(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *vp)
{
JSString *substr;
uint32 offset, count;
DOM_CharacterData *cdata;
if (!JS_ConvertArguments(cx, argc, argv, "uu", &offset, &count))
return JS_FALSE;
cdata = (DOM_CharacterData *)JS_GetPrivate(cx, obj);
if (!cdata) {
*vp = STRING_TO_JSVAL(JS_GetEmptyStringValue(cx));
return JS_TRUE;
}
if (offset > cdata->len || offset < 0 || count < 0) {
DOM_SignalException(cx, DOM_INDEX_SIZE_ERR);
return JS_FALSE;
}
if (offset + count > cdata->len)
count = cdata->len - offset;
substr = JS_NewStringCopyN(cx, cdata->data + offset, count);
if (!substr)
return JS_FALSE;
*vp = STRING_TO_JSVAL(substr);
return JS_TRUE;
}
static JSBool
cdata_appendData(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *vp)
{
JSString *newData;
uint32 newlen;
DOM_CharacterData *cdata;
if (!JS_ConvertArguments(cx, argc, argv, "S", &newData))
return JS_FALSE;
cdata = (DOM_CharacterData *)JS_GetPrivate(cx, obj);
if (!cdata)
return JS_TRUE;
newlen = JS_GetStringLength(newData);
cdata->data = XP_REALLOC(cdata->data, cdata->len + newlen);
if (!cdata->data)
return JS_FALSE;
XP_MEMCPY(cdata->data + cdata->len, JS_GetStringBytes(newData),
newlen);
cdata->len += newlen;
return cdata->notify(cx, cdata, CDATA_APPEND);
}
static JSBool
cdata_insertData(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *vp)
{
uint32 offset, newlen;
JSString *newData;
char *data2;
DOM_CharacterData *cdata;
if (!JS_ConvertArguments(cx, argc, argv, "uS", &offset, &newData))
return JS_FALSE;
cdata = (DOM_CharacterData *)JS_GetPrivate(cx, obj);
if (!cdata)
return JS_TRUE;
if (offset < 0 || offset > cdata->len) {
DOM_SignalException(cx, DOM_INDEX_SIZE_ERR);
return JS_FALSE;
}
newlen = JS_GetStringLength(newData);
data2 = XP_ALLOC(cdata->len + newlen);
if (!data2)
return JS_FALSE;
XP_MEMCPY(data2, cdata->data, offset);
XP_MEMCPY(data2 + offset, JS_GetStringBytes(newData), newlen);
XP_MEMCPY(data2 + offset + newlen, cdata->data + offset,
cdata->len - offset);
XP_FREE(cdata->data);
cdata->data = data2;
cdata->len += newlen;
return cdata->notify(cx, cdata, CDATA_INSERT);
}
static JSBool
cdata_deleteData(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *vp)
{
uint32 offset, count;
DOM_CharacterData *cdata;
char *data2;
if (!JS_ConvertArguments(cx, argc, argv, "uu", &offset, &count))
return JS_FALSE;
cdata = (DOM_CharacterData *)JS_GetPrivate(cx, obj);
if (!cdata)
return JS_TRUE;
if (offset < 0 || offset > cdata->len || count < 0) {
DOM_SignalException(cx, DOM_INDEX_SIZE_ERR);
return JS_FALSE;
}
if (offset + count > cdata->len)
count = cdata->len - offset;
data2 = XP_ALLOC(cdata->len - count);
if (!data2)
return JS_FALSE;
XP_MEMCPY(data2, cdata->data, offset);
XP_MEMCPY(data2 + offset, cdata->data + offset + count,
cdata->len - offset - count);
XP_FREE(cdata->data);
cdata->data = data2;
cdata->len -= count;
return cdata->notify(cx, cdata, CDATA_DELETE);
}
static JSBool
cdata_replaceData(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *vp)
{
uint32 offset, count, newlen;
JSString *newData;
DOM_CharacterData *cdata;
char *data2;
if (!JS_ConvertArguments(cx, argc, argv, "uuS", &offset, &count,
&newData))
return JS_FALSE;
cdata = (DOM_CharacterData *)JS_GetPrivate(cx, obj);
if (!cdata)
return JS_TRUE;
if (offset < 0 || offset > cdata->len || count < 0) {
DOM_SignalException(cx, DOM_INDEX_SIZE_ERR);
return JS_FALSE;
}
if (offset + count > cdata->len)
count = cdata->len - offset;
newlen = JS_GetStringLength(newData);
data2 = XP_ALLOC(cdata->len - count + newlen);
if (!data2)
return JS_FALSE;
XP_MEMCPY(data2, cdata->data, offset);
XP_MEMCPY(data2 + offset, JS_GetStringBytes(newData), newlen);
XP_MEMCPY(data2 + offset + newlen, cdata->data + offset + count,
cdata->len - offset - count);
XP_FREE(cdata->data);
cdata->data = data2;
cdata->len += newlen - count;
return cdata->notify(cx, cdata, CDATA_REPLACE);
}
static JSClass DOM_CDataClass = {
"CharacterData", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, cdata_getter, cdata_setter,
@ -88,6 +265,11 @@ static JSPropertySpec cdata_props[] = {
};
static JSFunctionSpec cdata_methods[] = {
{"substringData", cdata_substringData, 2},
{"appendData", cdata_appendData, 1},
{"insertData", cdata_insertData, 2},
{"deleteData", cdata_deleteData, 2},
{"replaceData", cdata_replaceData, 3},
{0}
};
@ -142,7 +324,7 @@ DOM_NewTextObject(JSContext *cx, DOM_Text *text)
}
DOM_Text *
DOM_NewText(const char *data, int64 length)
DOM_NewText(const char *data, int64 length, DOM_CDataOp notify)
{
XP_ASSERT((0 && "DOM_NewText NYI"));
return NULL;