Javascript phase 2 finished.
This commit is contained in:
686
js/w3m_dom.c
686
js/w3m_dom.c
@@ -243,14 +243,46 @@ w3m_dom_set_attribute(W3MElement *elem, const char *name, const char *value)
|
||||
elem->attributes.count++;
|
||||
}
|
||||
|
||||
/* JavaScript Binding (Stubs for Phase 1) */
|
||||
void
|
||||
w3m_dom_remove_attribute(W3MElement *elem, const char *name)
|
||||
{
|
||||
if (!elem || !name) return;
|
||||
|
||||
for (int i = 0; i < elem->attributes.count; i++) {
|
||||
if (elem->attributes.names[i] &&
|
||||
strcasecmp(elem->attributes.names[i], name) == 0) {
|
||||
/* Free the attribute */
|
||||
if (elem->attributes.names[i]) GC_free(elem->attributes.names[i]);
|
||||
if (elem->attributes.values[i]) GC_free(elem->attributes.values[i]);
|
||||
|
||||
/* Shift remaining attributes */
|
||||
for (int j = i; j < elem->attributes.count - 1; j++) {
|
||||
elem->attributes.names[j] = elem->attributes.names[j + 1];
|
||||
elem->attributes.values[j] = elem->attributes.values[j + 1];
|
||||
}
|
||||
|
||||
elem->attributes.count--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
w3m_dom_has_attribute(W3MElement *elem, const char *name)
|
||||
{
|
||||
if (!elem || !name) return 0;
|
||||
|
||||
return (w3m_dom_get_attribute(elem, name) != NULL);
|
||||
}
|
||||
|
||||
/* JavaScript Binding - Phase 2 Implementation */
|
||||
|
||||
void
|
||||
w3m_dom_bind_to_js(W3MJSContext *ctx, W3MDocument *doc)
|
||||
{
|
||||
if (!ctx || !doc) return;
|
||||
|
||||
/* Create basic document object */
|
||||
/* Create document object */
|
||||
JSValue document = JS_NewObject(ctx->context);
|
||||
|
||||
/* Set basic properties */
|
||||
@@ -258,6 +290,24 @@ w3m_dom_bind_to_js(W3MJSContext *ctx, W3MDocument *doc)
|
||||
JS_SetPropertyStr(ctx->context, document, "URL",
|
||||
JS_NewString(ctx->context, doc->URL));
|
||||
}
|
||||
if (doc->title) {
|
||||
JS_SetPropertyStr(ctx->context, document, "title",
|
||||
JS_NewString(ctx->context, doc->title));
|
||||
}
|
||||
|
||||
/* Bind DOM methods to document object */
|
||||
JS_SetPropertyStr(ctx->context, document, "getElementById",
|
||||
JS_NewCFunction(ctx->context, js_getElementById, "getElementById", 1));
|
||||
JS_SetPropertyStr(ctx->context, document, "getElementsByTagName",
|
||||
JS_NewCFunction(ctx->context, js_getElementsByTagName, "getElementsByTagName", 1));
|
||||
JS_SetPropertyStr(ctx->context, document, "createElement",
|
||||
JS_NewCFunction(ctx->context, js_createElement, "createElement", 1));
|
||||
JS_SetPropertyStr(ctx->context, document, "write",
|
||||
JS_NewCFunction(ctx->context, js_document_write, "write", 1));
|
||||
|
||||
/* Store document reference in context for function access */
|
||||
JS_SetPropertyStr(ctx->context, ctx->global_obj, "_w3m_document_ptr",
|
||||
JS_NewInt64(ctx->context, (int64_t)(uintptr_t)doc));
|
||||
|
||||
/* Bind to global object */
|
||||
JS_SetPropertyStr(ctx->context, ctx->global_obj, "document", document);
|
||||
@@ -266,27 +316,645 @@ w3m_dom_bind_to_js(W3MJSContext *ctx, W3MDocument *doc)
|
||||
doc->js_document = document;
|
||||
}
|
||||
|
||||
/* JavaScript API Stubs */
|
||||
/* DOM Tree Operations */
|
||||
|
||||
void
|
||||
w3m_dom_append_child(W3MElement *parent, W3MElement *child)
|
||||
{
|
||||
if (!parent || !child) return;
|
||||
|
||||
child->parent = parent;
|
||||
|
||||
if (!parent->firstChild) {
|
||||
parent->firstChild = child;
|
||||
parent->lastChild = child;
|
||||
child->previousSibling = NULL;
|
||||
child->nextSibling = NULL;
|
||||
} else {
|
||||
child->previousSibling = parent->lastChild;
|
||||
child->nextSibling = NULL;
|
||||
parent->lastChild->nextSibling = child;
|
||||
parent->lastChild = child;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
w3m_dom_remove_child(W3MElement *parent, W3MElement *child)
|
||||
{
|
||||
if (!parent || !child || child->parent != parent) return;
|
||||
|
||||
if (child->previousSibling) {
|
||||
child->previousSibling->nextSibling = child->nextSibling;
|
||||
} else {
|
||||
parent->firstChild = child->nextSibling;
|
||||
}
|
||||
|
||||
if (child->nextSibling) {
|
||||
child->nextSibling->previousSibling = child->previousSibling;
|
||||
} else {
|
||||
parent->lastChild = child->previousSibling;
|
||||
}
|
||||
|
||||
child->parent = NULL;
|
||||
child->previousSibling = NULL;
|
||||
child->nextSibling = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
w3m_dom_insert_before(W3MElement *parent, W3MElement *newChild, W3MElement *referenceChild)
|
||||
{
|
||||
if (!parent || !newChild) return;
|
||||
|
||||
if (!referenceChild) {
|
||||
w3m_dom_append_child(parent, newChild);
|
||||
return;
|
||||
}
|
||||
|
||||
if (referenceChild->parent != parent) return;
|
||||
|
||||
newChild->parent = parent;
|
||||
newChild->nextSibling = referenceChild;
|
||||
newChild->previousSibling = referenceChild->previousSibling;
|
||||
|
||||
if (referenceChild->previousSibling) {
|
||||
referenceChild->previousSibling->nextSibling = newChild;
|
||||
} else {
|
||||
parent->firstChild = newChild;
|
||||
}
|
||||
|
||||
referenceChild->previousSibling = newChild;
|
||||
}
|
||||
|
||||
/* Element Search and Access */
|
||||
|
||||
W3MElement *
|
||||
w3m_dom_get_element_by_id(W3MDocument *doc, const char *id)
|
||||
{
|
||||
if (!doc || !id) return NULL;
|
||||
|
||||
for (int i = 0; i < doc->element_count; i++) {
|
||||
W3MElement *elem = doc->all_elements[i];
|
||||
if (elem && elem->id && strcmp(elem->id, id) == 0) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
W3MElement **
|
||||
w3m_dom_get_elements_by_tag_name(W3MDocument *doc, const char *tagName, int *count)
|
||||
{
|
||||
if (!doc || !tagName || !count) {
|
||||
if (count) *count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* First pass: count matching elements */
|
||||
int match_count = 0;
|
||||
for (int i = 0; i < doc->element_count; i++) {
|
||||
W3MElement *elem = doc->all_elements[i];
|
||||
if (elem && elem->tagName &&
|
||||
(strcasecmp(tagName, "*") == 0 || strcasecmp(elem->tagName, tagName) == 0)) {
|
||||
match_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (match_count == 0) {
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Second pass: collect matching elements */
|
||||
W3MElement **result = GC_MALLOC(sizeof(W3MElement*) * match_count);
|
||||
if (!result) {
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int result_index = 0;
|
||||
for (int i = 0; i < doc->element_count; i++) {
|
||||
W3MElement *elem = doc->all_elements[i];
|
||||
if (elem && elem->tagName &&
|
||||
(strcasecmp(tagName, "*") == 0 || strcasecmp(elem->tagName, tagName) == 0)) {
|
||||
result[result_index++] = elem;
|
||||
}
|
||||
}
|
||||
|
||||
*count = match_count;
|
||||
return result;
|
||||
}
|
||||
|
||||
W3MElement **
|
||||
w3m_dom_get_elements_by_class_name(W3MDocument *doc, const char *className, int *count)
|
||||
{
|
||||
if (!doc || !className || !count) {
|
||||
if (count) *count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Simplified implementation - exact class name match only */
|
||||
int match_count = 0;
|
||||
for (int i = 0; i < doc->element_count; i++) {
|
||||
W3MElement *elem = doc->all_elements[i];
|
||||
if (elem && elem->className && strcmp(elem->className, className) == 0) {
|
||||
match_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (match_count == 0) {
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
W3MElement **result = GC_MALLOC(sizeof(W3MElement*) * match_count);
|
||||
if (!result) {
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int result_index = 0;
|
||||
for (int i = 0; i < doc->element_count; i++) {
|
||||
W3MElement *elem = doc->all_elements[i];
|
||||
if (elem && elem->className && strcmp(elem->className, className) == 0) {
|
||||
result[result_index++] = elem;
|
||||
}
|
||||
}
|
||||
|
||||
*count = match_count;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Content Access and Modification */
|
||||
|
||||
char *
|
||||
w3m_dom_get_text_content(W3MElement *elem)
|
||||
{
|
||||
if (!elem) return NULL;
|
||||
|
||||
if (elem->textContent) {
|
||||
int len = strlen(elem->textContent);
|
||||
char *result = GC_MALLOC(len + 1);
|
||||
if (result) {
|
||||
strcpy(result, elem->textContent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
w3m_dom_set_text_content(W3MElement *elem, const char *text)
|
||||
{
|
||||
if (!elem) return;
|
||||
|
||||
if (elem->textContent) {
|
||||
GC_free(elem->textContent);
|
||||
}
|
||||
|
||||
if (text) {
|
||||
int len = strlen(text);
|
||||
elem->textContent = GC_MALLOC(len + 1);
|
||||
if (elem->textContent) {
|
||||
strcpy(elem->textContent, text);
|
||||
}
|
||||
} else {
|
||||
elem->textContent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
w3m_dom_get_inner_html(W3MElement *elem)
|
||||
{
|
||||
if (!elem) return NULL;
|
||||
|
||||
/* Basic implementation - just return innerHTML if set */
|
||||
if (elem->innerHTML) {
|
||||
int len = strlen(elem->innerHTML);
|
||||
char *result = GC_MALLOC(len + 1);
|
||||
if (result) {
|
||||
strcpy(result, elem->innerHTML);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
w3m_dom_set_inner_html(W3MElement *elem, const char *html)
|
||||
{
|
||||
if (!elem) return;
|
||||
|
||||
if (elem->innerHTML) {
|
||||
GC_free(elem->innerHTML);
|
||||
}
|
||||
|
||||
if (html) {
|
||||
int len = strlen(html);
|
||||
elem->innerHTML = GC_MALLOC(len + 1);
|
||||
if (elem->innerHTML) {
|
||||
strcpy(elem->innerHTML, html);
|
||||
}
|
||||
} else {
|
||||
elem->innerHTML = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Buffer Integration - Phase 2 Implementation */
|
||||
|
||||
void
|
||||
set_element_buffer_position(W3MElement *elem, Buffer *buf)
|
||||
{
|
||||
if (!elem || !buf) return;
|
||||
|
||||
/* Set current line reference if buffer has content */
|
||||
if (buf->currentLine) {
|
||||
elem->line = (struct Line *)buf->currentLine;
|
||||
elem->line_pos = 0; /* TODO: implement proper column tracking */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
add_element_to_document(W3MDocument *doc, W3MElement *elem)
|
||||
{
|
||||
if (!doc || !elem) return;
|
||||
|
||||
/* Expand array if needed */
|
||||
if (doc->element_count >= doc->element_capacity) {
|
||||
int new_capacity = doc->element_capacity + 50;
|
||||
W3MElement **new_array = GC_MALLOC(sizeof(W3MElement*) * new_capacity);
|
||||
if (!new_array) return;
|
||||
|
||||
if (doc->all_elements) {
|
||||
memcpy(new_array, doc->all_elements,
|
||||
sizeof(W3MElement*) * doc->element_count);
|
||||
GC_free(doc->all_elements);
|
||||
}
|
||||
|
||||
doc->all_elements = new_array;
|
||||
doc->element_capacity = new_capacity;
|
||||
}
|
||||
|
||||
doc->all_elements[doc->element_count++] = elem;
|
||||
}
|
||||
|
||||
void
|
||||
w3m_dom_build_from_buffer(W3MDocument *doc, Buffer *buf)
|
||||
{
|
||||
if (!doc || !buf) return;
|
||||
|
||||
/* Create basic document structure */
|
||||
W3MElement *html_elem = w3m_dom_create_element("HTML");
|
||||
W3MElement *head_elem = w3m_dom_create_element("HEAD");
|
||||
W3MElement *body_elem = w3m_dom_create_element("BODY");
|
||||
|
||||
if (!html_elem || !head_elem || !body_elem) return;
|
||||
|
||||
doc->documentElement = html_elem;
|
||||
doc->head = head_elem;
|
||||
doc->body = body_elem;
|
||||
|
||||
add_element_to_document(doc, html_elem);
|
||||
add_element_to_document(doc, head_elem);
|
||||
add_element_to_document(doc, body_elem);
|
||||
|
||||
w3m_dom_append_child(html_elem, head_elem);
|
||||
w3m_dom_append_child(html_elem, body_elem);
|
||||
|
||||
/* Set document title from buffer */
|
||||
if (buf->buffername) {
|
||||
int len = strlen(buf->buffername);
|
||||
doc->title = GC_MALLOC(len + 1);
|
||||
if (doc->title) {
|
||||
strcpy(doc->title, buf->buffername);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO Phase 2: Parse buffer lines and create DOM elements
|
||||
* This is a complex process that will require:
|
||||
* 1. Walking through buffer lines
|
||||
* 2. Identifying HTML structure from anchors and form items
|
||||
* 3. Creating appropriate DOM elements
|
||||
* 4. Building proper parent-child relationships
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
w3m_dom_update_buffer(W3MDocument *doc)
|
||||
{
|
||||
if (!doc || !doc->buffer) return;
|
||||
|
||||
/* TODO Phase 2: Update buffer content from DOM changes
|
||||
* This is complex and will require:
|
||||
* 1. Regenerating buffer lines from DOM structure
|
||||
* 2. Updating anchors and form items
|
||||
* 3. Maintaining scroll position and cursor
|
||||
*/
|
||||
}
|
||||
|
||||
W3MElement *
|
||||
w3m_dom_find_element_at_position(W3MDocument *doc, int line_num, int col)
|
||||
{
|
||||
if (!doc) return NULL;
|
||||
|
||||
/* Search for element at specific buffer position */
|
||||
for (int i = 0; i < doc->element_count; i++) {
|
||||
W3MElement *elem = doc->all_elements[i];
|
||||
if (elem && elem->line) {
|
||||
/* TODO: Implement proper position matching */
|
||||
/* This requires understanding buffer line structure */
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Forward declarations */
|
||||
static JSValue create_js_element_object(JSContext *ctx, W3MElement *elem);
|
||||
|
||||
/* Helper function to get document from JavaScript context */
|
||||
static W3MDocument *
|
||||
get_document_from_context(JSContext *ctx)
|
||||
{
|
||||
JSValue doc_ptr = JS_GetPropertyStr(ctx, JS_GetGlobalObject(ctx), "_w3m_document_ptr");
|
||||
if (JS_IsNumber(doc_ptr)) {
|
||||
int64_t ptr_val;
|
||||
if (JS_ToInt64(ctx, &ptr_val, doc_ptr) == 0) {
|
||||
JS_FreeValue(ctx, doc_ptr);
|
||||
return (W3MDocument*)(uintptr_t)ptr_val;
|
||||
}
|
||||
}
|
||||
JS_FreeValue(ctx, doc_ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* JavaScript API Implementation - Phase 2 */
|
||||
|
||||
JSValue
|
||||
js_getElementById(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
/* Phase 1: Return null for now */
|
||||
return JS_NULL;
|
||||
if (argc < 1) return JS_NULL;
|
||||
|
||||
const char *id = JS_ToCString(ctx, argv[0]);
|
||||
if (!id) return JS_NULL;
|
||||
|
||||
/* Get document from context */
|
||||
W3MDocument *doc = get_document_from_context(ctx);
|
||||
if (!doc) {
|
||||
JS_FreeCString(ctx, id);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
/* Find element by ID */
|
||||
W3MElement *elem = w3m_dom_get_element_by_id(doc, id);
|
||||
JS_FreeCString(ctx, id);
|
||||
|
||||
if (!elem) return JS_NULL;
|
||||
|
||||
/* Create complete JavaScript element object */
|
||||
return create_js_element_object(ctx, elem);
|
||||
}
|
||||
|
||||
JSValue
|
||||
js_getElementsByTagName(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
/* Phase 1: Return empty array */
|
||||
return JS_NewArray(ctx);
|
||||
if (argc < 1) return JS_NewArray(ctx);
|
||||
|
||||
const char *tagName = JS_ToCString(ctx, argv[0]);
|
||||
if (!tagName) return JS_NewArray(ctx);
|
||||
|
||||
/* Get document from context */
|
||||
W3MDocument *doc = get_document_from_context(ctx);
|
||||
if (!doc) {
|
||||
JS_FreeCString(ctx, tagName);
|
||||
return JS_NewArray(ctx);
|
||||
}
|
||||
|
||||
/* Find elements by tag name */
|
||||
int count = 0;
|
||||
W3MElement **elements = w3m_dom_get_elements_by_tag_name(doc, tagName, &count);
|
||||
JS_FreeCString(ctx, tagName);
|
||||
|
||||
/* Create JavaScript array */
|
||||
JSValue js_array = JS_NewArray(ctx);
|
||||
|
||||
if (elements && count > 0) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
W3MElement *elem = elements[i];
|
||||
if (elem) {
|
||||
/* Create complete JavaScript element object */
|
||||
JSValue js_elem = create_js_element_object(ctx, elem);
|
||||
|
||||
/* Add to array */
|
||||
JS_SetPropertyUint32(ctx, js_array, i, js_elem);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set array length */
|
||||
JS_SetPropertyStr(ctx, js_array, "length", JS_NewInt32(ctx, count));
|
||||
|
||||
/* Free elements array (elements themselves are managed by GC) */
|
||||
GC_free(elements);
|
||||
}
|
||||
|
||||
return js_array;
|
||||
}
|
||||
|
||||
JSValue
|
||||
js_createElement(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
/* Phase 1: Return empty object */
|
||||
return JS_NewObject(ctx);
|
||||
if (argc < 1) return JS_NewObject(ctx);
|
||||
|
||||
const char *tagName = JS_ToCString(ctx, argv[0]);
|
||||
if (!tagName) return JS_NewObject(ctx);
|
||||
|
||||
/* Create actual DOM element */
|
||||
W3MElement *elem = w3m_dom_create_element(tagName);
|
||||
if (!elem) {
|
||||
JS_FreeCString(ctx, tagName);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
/* Get document to add element to collection */
|
||||
W3MDocument *doc = get_document_from_context(ctx);
|
||||
if (doc) {
|
||||
add_element_to_document(doc, elem);
|
||||
}
|
||||
|
||||
/* Create complete JavaScript element object */
|
||||
JS_FreeCString(ctx, tagName);
|
||||
return create_js_element_object(ctx, elem);
|
||||
}
|
||||
|
||||
/* Helper function to create a complete JavaScript element object */
|
||||
static JSValue
|
||||
create_js_element_object(JSContext *ctx, W3MElement *elem)
|
||||
{
|
||||
if (!elem) return JS_NULL;
|
||||
|
||||
JSValue js_elem = JS_NewObject(ctx);
|
||||
|
||||
/* Set basic properties */
|
||||
if (elem->tagName) {
|
||||
JS_SetPropertyStr(ctx, js_elem, "tagName", JS_NewString(ctx, elem->tagName));
|
||||
}
|
||||
if (elem->id) {
|
||||
JS_SetPropertyStr(ctx, js_elem, "id", JS_NewString(ctx, elem->id));
|
||||
}
|
||||
if (elem->className) {
|
||||
JS_SetPropertyStr(ctx, js_elem, "className", JS_NewString(ctx, elem->className));
|
||||
}
|
||||
|
||||
/* Store element reference for method calls */
|
||||
JS_SetPropertyStr(ctx, js_elem, "_w3m_element_ptr",
|
||||
JS_NewInt64(ctx, (int64_t)(uintptr_t)elem));
|
||||
|
||||
/* Add DOM methods */
|
||||
JS_SetPropertyStr(ctx, js_elem, "getAttribute",
|
||||
JS_NewCFunction(ctx, js_element_getAttribute, "getAttribute", 1));
|
||||
JS_SetPropertyStr(ctx, js_elem, "setAttribute",
|
||||
JS_NewCFunction(ctx, js_element_setAttribute, "setAttribute", 2));
|
||||
|
||||
/* Add property accessors */
|
||||
JSValue textContent = elem->textContent ?
|
||||
JS_NewString(ctx, elem->textContent) : JS_NewString(ctx, "");
|
||||
JS_SetPropertyStr(ctx, js_elem, "textContent", textContent);
|
||||
|
||||
JSValue innerHTML = elem->innerHTML ?
|
||||
JS_NewString(ctx, elem->innerHTML) : JS_NewString(ctx, "");
|
||||
JS_SetPropertyStr(ctx, js_elem, "innerHTML", innerHTML);
|
||||
|
||||
return js_elem;
|
||||
}
|
||||
|
||||
/* Element-level JavaScript API functions */
|
||||
|
||||
static W3MElement *
|
||||
get_element_from_js_value(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
JSValue elem_ptr = JS_GetPropertyStr(ctx, this_val, "_w3m_element_ptr");
|
||||
if (JS_IsNumber(elem_ptr)) {
|
||||
int64_t ptr_val;
|
||||
if (JS_ToInt64(ctx, &ptr_val, elem_ptr) == 0) {
|
||||
JS_FreeValue(ctx, elem_ptr);
|
||||
return (W3MElement*)(uintptr_t)ptr_val;
|
||||
}
|
||||
}
|
||||
JS_FreeValue(ctx, elem_ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSValue
|
||||
js_element_getAttribute(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
if (argc < 1) return JS_NULL;
|
||||
|
||||
W3MElement *elem = get_element_from_js_value(ctx, this_val);
|
||||
if (!elem) return JS_NULL;
|
||||
|
||||
const char *attr_name = JS_ToCString(ctx, argv[0]);
|
||||
if (!attr_name) return JS_NULL;
|
||||
|
||||
const char *attr_value = w3m_dom_get_attribute(elem, attr_name);
|
||||
JS_FreeCString(ctx, attr_name);
|
||||
|
||||
if (attr_value) {
|
||||
return JS_NewString(ctx, attr_value);
|
||||
} else {
|
||||
return JS_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JSValue
|
||||
js_element_setAttribute(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
if (argc < 2) return JS_UNDEFINED;
|
||||
|
||||
W3MElement *elem = get_element_from_js_value(ctx, this_val);
|
||||
if (!elem) return JS_UNDEFINED;
|
||||
|
||||
const char *attr_name = JS_ToCString(ctx, argv[0]);
|
||||
const char *attr_value = JS_ToCString(ctx, argv[1]);
|
||||
|
||||
if (attr_name && attr_value) {
|
||||
w3m_dom_set_attribute(elem, attr_name, attr_value);
|
||||
|
||||
/* Update special attributes */
|
||||
if (strcasecmp(attr_name, "id") == 0) {
|
||||
if (elem->id) GC_free(elem->id);
|
||||
int len = strlen(attr_value);
|
||||
elem->id = GC_MALLOC(len + 1);
|
||||
if (elem->id) strcpy(elem->id, attr_value);
|
||||
} else if (strcasecmp(attr_name, "class") == 0) {
|
||||
if (elem->className) GC_free(elem->className);
|
||||
int len = strlen(attr_value);
|
||||
elem->className = GC_MALLOC(len + 1);
|
||||
if (elem->className) strcpy(elem->className, attr_value);
|
||||
}
|
||||
}
|
||||
|
||||
if (attr_name) JS_FreeCString(ctx, attr_name);
|
||||
if (attr_value) JS_FreeCString(ctx, attr_value);
|
||||
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSValue
|
||||
js_element_get_textContent(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
W3MElement *elem = get_element_from_js_value(ctx, this_val);
|
||||
if (!elem) return JS_NULL;
|
||||
|
||||
char *text = w3m_dom_get_text_content(elem);
|
||||
if (text) {
|
||||
JSValue result = JS_NewString(ctx, text);
|
||||
GC_free(text);
|
||||
return result;
|
||||
}
|
||||
|
||||
return JS_NewString(ctx, "");
|
||||
}
|
||||
|
||||
JSValue
|
||||
js_element_set_textContent(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
if (argc < 1) return JS_UNDEFINED;
|
||||
|
||||
W3MElement *elem = get_element_from_js_value(ctx, this_val);
|
||||
if (!elem) return JS_UNDEFINED;
|
||||
|
||||
const char *text = JS_ToCString(ctx, argv[0]);
|
||||
if (text) {
|
||||
w3m_dom_set_text_content(elem, text);
|
||||
JS_FreeCString(ctx, text);
|
||||
}
|
||||
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
/* Document.write() stub - Phase 2 implementation
|
||||
* This prevents JavaScript errors when pages call document.write()
|
||||
* The actual implementation will be in Phase 3 */
|
||||
JSValue
|
||||
js_document_write(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
if (argc < 1) return JS_UNDEFINED;
|
||||
|
||||
/* For Phase 2, we silently ignore document.write() calls
|
||||
* This prevents JavaScript errors while maintaining compatibility
|
||||
* Phase 3 will implement actual DOM insertion */
|
||||
|
||||
/* Optional: Log what would have been written for debugging */
|
||||
const char *content = JS_ToCString(ctx, argv[0]);
|
||||
if (content) {
|
||||
/* Phase 2: Stub implementation - content is discarded
|
||||
* Phase 3 will insert this content into the DOM */
|
||||
JS_FreeCString(ctx, content);
|
||||
}
|
||||
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
#endif /* USE_JAVASCRIPT */
|
Reference in New Issue
Block a user