1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-06-27 01:25:34 +00:00

[spidermonkey] element.style (getter)

This commit is contained in:
Witold Filipczyk 2023-09-19 17:29:08 +02:00
parent b34d1b6b60
commit 0b7caf4e82
5 changed files with 471 additions and 2 deletions

View File

@ -3,6 +3,6 @@ include $(top_builddir)/Makefile.config
INCLUDES += $(SPIDERMONKEY_CFLAGS)
OBJS = attr.obj attributes.obj collection.obj console.obj document.obj element.obj form.obj forms.obj heartbeat.obj history.obj implementation.obj input.obj \
keyboard.obj localstorage.obj location.obj message.obj navigator.obj nodelist.obj screen.obj unibar.obj window.obj xhr.obj
keyboard.obj localstorage.obj location.obj message.obj navigator.obj nodelist.obj screen.obj style.obj unibar.obj window.obj xhr.obj
include $(top_srcdir)/Makefile.lib

View File

@ -34,6 +34,7 @@
#include "ecmascript/spidermonkey/heartbeat.h"
#include "ecmascript/spidermonkey/keyboard.h"
#include "ecmascript/spidermonkey/nodelist.h"
#include "ecmascript/spidermonkey/style.h"
#include "ecmascript/spidermonkey/window.h"
#include "intl/libintl.h"
#include "main/select.h"
@ -91,6 +92,7 @@ static bool element_get_property_parentElement(JSContext *ctx, unsigned int argc
static bool element_get_property_parentNode(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool element_get_property_previousElementSibling(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool element_get_property_previousSibling(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool element_get_property_style(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool element_get_property_tagName(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool element_get_property_textContent(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool element_set_property_textContent(JSContext *ctx, unsigned int argc, JS::Value *vp);
@ -158,6 +160,7 @@ JSPropertySpec element_props[] = {
JS_PSG("parentNode", element_get_property_parentNode, JSPROP_ENUMERATE),
JS_PSG("previousElementSibling", element_get_property_previousElementSibling, JSPROP_ENUMERATE),
JS_PSG("previousSibling", element_get_property_previousSibling, JSPROP_ENUMERATE),
JS_PSG("style", element_get_property_style, JSPROP_ENUMERATE),
JS_PSG("tagName", element_get_property_tagName, JSPROP_ENUMERATE),
JS_PSGS("textContent", element_get_property_textContent, element_set_property_textContent, JSPROP_ENUMERATE),
JS_PSGS("title", element_get_property_title, element_set_property_title, JSPROP_ENUMERATE),
@ -1589,6 +1592,48 @@ element_get_property_previousSibling(JSContext *ctx, unsigned int argc, JS::Valu
return true;
}
static bool
element_get_property_style(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
JS::CallArgs args = CallArgsFromVp(argc, vp);
JS::RootedObject hobj(ctx, &args.thisv().toObject());
struct view_state *vs;
JS::Realm *comp = js::GetContextRealm(ctx);
if (!comp) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return false;
}
/* This can be called if @obj if not itself an instance of the
* appropriate class but has one in its prototype chain. Fail
* such calls. */
if (!JS_InstanceOf(ctx, hobj, &element_class, NULL)) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return false;
}
dom_node *el = (dom_node *)JS::GetMaybePtrFromReservedSlot<dom_node>(hobj, 0);
if (!el) {
args.rval().setNull();
return true;
}
JSObject *style = getStyle(ctx, el);
args.rval().setObject(*style);
return true;
}
static bool
element_get_property_tagName(JSContext *ctx, unsigned int argc, JS::Value *vp)
{

View File

@ -1,2 +1,2 @@
srcs += files('attr.cpp', 'attributes.cpp', 'collection.cpp', 'console.cpp', 'document.cpp', 'element.cpp', 'form.cpp', 'forms.cpp', 'heartbeat.cpp', 'history.cpp', 'implementation.cpp', 'input.cpp', 'keyboard.cpp',
'localstorage.cpp', 'location.cpp', 'message.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'unibar.cpp', 'window.cpp', 'xhr.cpp')
'localstorage.cpp', 'location.cpp', 'message.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'style.cpp', 'unibar.cpp', 'window.cpp', 'xhr.cpp')

View File

@ -0,0 +1,416 @@
/* The SpiderMonkey style object implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include "ecmascript/libdom/dom.h"
#include "ecmascript/spidermonkey/util.h"
#include <jsfriendapi.h>
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/libdom/corestrings.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/libdom/dom.h"
#include "ecmascript/spidermonkey/style.h"
#include "intl/libintl.h"
#include "main/select.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
static bool style_style(JSContext *ctx, unsigned int argc, JS::Value *vp, const char *property);
static bool style_get_property_background(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_backgroundColor(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_color(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_display(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_fontStyle(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_fontWeight(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_lineStyle(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_lineStyleType(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_textAlign(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_textDecoration(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool style_get_property_whiteSpace(JSContext *ctx, unsigned int argc, JS::Value *vp);
static void style_finalize(JS::GCContext *op, JSObject *obj)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
}
JSClassOps style_ops = {
nullptr, // addProperty
nullptr, // deleteProperty
nullptr, // enumerate
nullptr, // newEnumerate
nullptr, // resolve
nullptr, // mayResolve
style_finalize, // finalize
nullptr, // call
nullptr, // construct
JS_GlobalObjectTraceHook
};
JSClass style_class = {
"style",
JSCLASS_HAS_RESERVED_SLOTS(1),
&style_ops
};
static JSPropertySpec style_props[] = {
JS_PSG("background", style_get_property_background, JSPROP_ENUMERATE),
JS_PSG("backgroundColor", style_get_property_backgroundColor, JSPROP_ENUMERATE),
JS_PSG("color", style_get_property_color, JSPROP_ENUMERATE),
JS_PSG("display", style_get_property_display, JSPROP_ENUMERATE),
JS_PSG("fontStyle", style_get_property_fontStyle, JSPROP_ENUMERATE),
JS_PSG("fontWeight", style_get_property_fontWeight, JSPROP_ENUMERATE),
JS_PSG("lineStyle", style_get_property_lineStyle, JSPROP_ENUMERATE),
JS_PSG("lineStyleType", style_get_property_lineStyleType, JSPROP_ENUMERATE),
JS_PSG("textAlign", style_get_property_textAlign, JSPROP_ENUMERATE),
JS_PSG("textDecoration",style_get_property_textDecoration, JSPROP_ENUMERATE),
JS_PSG("whiteSpace", style_get_property_whiteSpace, JSPROP_ENUMERATE),
JS_PS_END
};
static bool
style_get_property_background(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "background");
}
static bool
style_get_property_backgroundColor(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "background-color");
}
static bool
style_get_property_color(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "color");
}
static bool
style_get_property_display(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "display");
}
static bool
style_get_property_fontStyle(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "font-style");
}
static bool
style_get_property_fontWeight(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "font-weight");
}
static bool
style_get_property_lineStyle(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "line-style");
}
static bool
style_get_property_lineStyleType(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "line-style-type");
}
static bool
style_get_property_textAlign(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "text-align");
}
static bool
style_get_property_textDecoration(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "text-decoration");
}
static bool
style_get_property_whiteSpace(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
return style_style(ctx, argc, vp, "white-space");
}
const std::map<std::string, bool> good = {
{ "background", true },
{ "background-color", true },
{ "color", true },
{ "display", true },
{ "font-style", true },
{ "font-weight", true },
{ "list-style", true },
{ "list-style-type", true },
{ "text-align", true },
{ "text-decoration", true },
{ "white-space", true }
};
static std::string
trimString(std::string str)
{
const std::string whiteSpaces = " \t\n\r\f\v";
// Remove leading whitespace
size_t first_non_space = str.find_first_not_of(whiteSpaces);
str.erase(0, first_non_space);
// Remove trailing whitespace
size_t last_non_space = str.find_last_not_of(whiteSpaces);
str.erase(last_non_space + 1);
return str;
}
void *
set_elstyle(const char *text)
{
if (!text || !*text) {
return NULL;
}
std::stringstream str(text);
std::string word;
std::string param, value;
std::map<std::string, std::string> *css = NULL;
while (!str.eof()) {
getline(str, word, ';');
std::stringstream params(word);
getline(params, param, ':');
getline(params, value, ':');
param = trimString(param);
value = trimString(value);
if (good.find(param) != good.end()) {
if (!css) {
css = new std::map<std::string, std::string>;
}
if (css) {
(*css)[param] = value;
}
}
}
return (void *)css;
}
const char *
get_elstyle(void *m)
{
std::map<std::string, std::string> *css = static_cast<std::map<std::string, std::string> *>(m);
std::string delimiter("");
std::stringstream output("");
std::map<std::string, std::string>::iterator it;
for (it = css->begin(); it != css->end(); it++) {
output << delimiter << it->first << ":" << it->second;
delimiter = ";";
}
return stracpy(output.str().c_str());
}
const char *
get_css_value(const char *text, const char *param)
{
void *m = set_elstyle(text);
char *res = NULL;
if (!m) {
return stracpy("");
}
std::map<std::string, std::string> *css = static_cast<std::map<std::string, std::string> *>(m);
if (css->find(param) != css->end()) {
res = stracpy((*css)[param].c_str());
} else {
res = stracpy("");
}
css->clear();
delete css;
return res;
}
const char *
set_css_value(const char *text, const char *param, const char *value)
{
void *m = set_elstyle(text);
std::map<std::string, std::string> *css = NULL;
if (m) {
css = static_cast<std::map<std::string, std::string> *>(m);
if (good.find(param) != good.end()) {
(*css)[param] = value;
}
return get_elstyle(m);
}
if (good.find(param) != good.end()) {
css = new std::map<std::string, std::string>;
if (!css) {
return stracpy("");
}
(*css)[param] = value;
return get_elstyle((void *)css);
}
return stracpy("");
}
static bool
style_style(JSContext *ctx, unsigned int argc, JS::Value *vp, const char *property)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
JS::CallArgs args = CallArgsFromVp(argc, vp);
JS::RootedObject hobj(ctx, &args.thisv().toObject());
JS::Realm *comp = js::GetContextRealm(ctx);
if (!comp) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return false;
}
/* This can be called if @obj if not itself an instance of the
* appropriate class but has one in its prototype chain. Fail
* such calls. */
if (!JS_InstanceOf(ctx, hobj, &style_class, NULL)) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return false;
}
dom_node *el = (dom_node *)JS::GetMaybePtrFromReservedSlot<dom_node>(hobj, 0);
dom_exception exc;
dom_string *style = NULL;
const char *res = NULL;
if (!el) {
args.rval().setNull();
return true;
}
exc = dom_element_get_attribute(el, corestring_dom_style, &style);
if (exc != DOM_NO_ERR) {
args.rval().setString(JS_NewStringCopyZ(ctx, ""));
return true;
}
if (!style || !dom_string_length(style)) {
args.rval().setString(JS_NewStringCopyZ(ctx, ""));
if (style) {
dom_string_unref(style);
}
return true;
}
res = get_css_value(dom_string_data(style), property);
dom_string_unref(style);
if (!res) {
args.rval().setString(JS_NewStringCopyZ(ctx, ""));
return true;
}
args.rval().setString(JS_NewStringCopyZ(ctx, res));
mem_free(res);
return true;
}
JSObject *
getStyle(JSContext *ctx, void *node)
{
JSObject *el = JS_NewObject(ctx, &style_class);
if (!el) {
return NULL;
}
JS::RootedObject r_el(ctx, el);
JS_DefineProperties(ctx, r_el, (JSPropertySpec *) style_props);
// spidermonkey_DefineFunctions(ctx, el, attributes_funcs);
JS::SetReservedSlot(el, 0, JS::PrivateValue(node));
return el;
}

View File

@ -0,0 +1,8 @@
#ifndef EL__ECMASCRIPT_SPIDERMONKEY_STYLE_H
#define EL__ECMASCRIPT_SPIDERMONKEY_STYLE_H
#include "ecmascript/spidermonkey/util.h"
JSObject *getStyle(JSContext *ctx, void *node);
#endif