First pass at getting html forms to use textarea widget.
(Input element types text & password, and textarea element.) Can edit and submit forms, but there are loads of issues.
This commit is contained in:
parent
008cdb42d7
commit
762e1aad73
|
@ -11,7 +11,7 @@ S_FETCHERS := curl.c data.c file.c about.c resource.c
|
|||
|
||||
S_CSS := css.c dump.c internal.c select.c utils.c
|
||||
|
||||
S_RENDER := box.c box_construct.c box_normalise.c \
|
||||
S_RENDER := box.c box_construct.c box_normalise.c box_textarea.c \
|
||||
font.c form.c \
|
||||
html.c html_script.c html_interaction.c html_redraw.c \
|
||||
html_forms.c imagemap.c layout.c list.c search.c table.c \
|
||||
|
|
|
@ -57,6 +57,8 @@ typedef enum {
|
|||
DRAGGING_SCR_X,
|
||||
DRAGGING_SCR_Y,
|
||||
DRAGGING_CONTENT_SCROLLBAR,
|
||||
DRAGGING_CONTENT_TEXTAREA_SCROLLBAR,
|
||||
DRAGGING_CONTENT_TEXTAREA_SELECTION,
|
||||
DRAGGING_OTHER
|
||||
} browser_drag_type;
|
||||
|
||||
|
|
|
@ -127,7 +127,13 @@ bool browser_window_key_press(struct browser_window *bw, uint32_t key)
|
|||
|
||||
assert(bw->window != NULL);
|
||||
|
||||
/* safe keys that can be handled whether input claimed or not */
|
||||
if (focus->caret_callback) {
|
||||
/* Pass keypress onto anything that has claimed input focus */
|
||||
return focus->caret_callback(focus, key,
|
||||
focus->caret_p1, focus->caret_p2);
|
||||
}
|
||||
|
||||
/* TODO: pass these to content to deal with */
|
||||
switch (key) {
|
||||
case KEY_COPY_SELECTION:
|
||||
selection_copy_to_clipboard(bw->cur_sel);
|
||||
|
@ -137,6 +143,10 @@ bool browser_window_key_press(struct browser_window *bw, uint32_t key)
|
|||
selection_clear(bw->cur_sel, true);
|
||||
return true;
|
||||
|
||||
case KEY_SELECT_ALL:
|
||||
selection_select_all(bw->cur_sel);
|
||||
return true;
|
||||
|
||||
case KEY_ESCAPE:
|
||||
if (bw->cur_sel && selection_defined(bw->cur_sel)) {
|
||||
selection_clear(bw->cur_sel, true);
|
||||
|
@ -147,19 +157,6 @@ bool browser_window_key_press(struct browser_window *bw, uint32_t key)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (focus->caret_callback) {
|
||||
/* Pass keypress onto anything that has claimed input focus */
|
||||
return focus->caret_callback(focus, key,
|
||||
focus->caret_p1, focus->caret_p2);
|
||||
}
|
||||
|
||||
/* keys we can't handle here if cursor is in form */
|
||||
switch (key) {
|
||||
case KEY_SELECT_ALL:
|
||||
selection_select_all(bw->cur_sel);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "css/select.h"
|
||||
#include "desktop/options.h"
|
||||
#include "render/box.h"
|
||||
#include "render/box_textarea.h"
|
||||
#include "render/form.h"
|
||||
#include "render/html_internal.h"
|
||||
#include "utils/corestrings.h"
|
||||
|
@ -111,7 +112,6 @@ static bool box_image(BOX_SPECIAL_PARAMS);
|
|||
static bool box_textarea(BOX_SPECIAL_PARAMS);
|
||||
static bool box_select(BOX_SPECIAL_PARAMS);
|
||||
static bool box_input(BOX_SPECIAL_PARAMS);
|
||||
static bool box_input_text(BOX_SPECIAL_PARAMS, bool password);
|
||||
static bool box_button(BOX_SPECIAL_PARAMS);
|
||||
static bool box_frameset(BOX_SPECIAL_PARAMS);
|
||||
static bool box_create_frameset(struct content_html_frames *f, dom_node *n,
|
||||
|
@ -2496,6 +2496,38 @@ bool box_iframe(BOX_SPECIAL_PARAMS)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for adding textarea widget to box.
|
||||
*
|
||||
* This is a load of hacks to ensure boxes replaced with textareas
|
||||
* can be handled by the layout code.
|
||||
*/
|
||||
|
||||
static bool box_input_text(html_content *html, struct box *box,
|
||||
struct dom_node *node)
|
||||
{
|
||||
struct box *inline_container, *inline_box;
|
||||
|
||||
box->type = BOX_INLINE_BLOCK;
|
||||
|
||||
inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, html->bctx);
|
||||
if (!inline_container)
|
||||
return false;
|
||||
inline_container->type = BOX_INLINE_CONTAINER;
|
||||
inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
|
||||
html->bctx);
|
||||
if (!inline_box)
|
||||
return false;
|
||||
inline_box->type = BOX_TEXT;
|
||||
inline_box->text = talloc_strdup(html->bctx, "");
|
||||
|
||||
box_add_child(inline_container, inline_box);
|
||||
box_add_child(box, inline_container);
|
||||
|
||||
return box_textarea_create_textarea(html, box, node);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Form control [17.4].
|
||||
*/
|
||||
|
@ -2518,7 +2550,7 @@ bool box_input(BOX_SPECIAL_PARAMS)
|
|||
|
||||
if (type && dom_string_caseless_lwc_isequal(type,
|
||||
corestring_lwc_password)) {
|
||||
if (box_input_text(n, content, box, 0, true) == false)
|
||||
if (box_input_text(content, box, n) == false)
|
||||
goto no_memory;
|
||||
|
||||
} else if (type && dom_string_caseless_lwc_isequal(type,
|
||||
|
@ -2620,7 +2652,7 @@ bool box_input(BOX_SPECIAL_PARAMS)
|
|||
}
|
||||
} else {
|
||||
/* the default type is "text" */
|
||||
if (box_input_text(n, content, box, 0, false) == false)
|
||||
if (box_input_text(content, box, n) == false)
|
||||
goto no_memory;
|
||||
}
|
||||
|
||||
|
@ -2638,52 +2670,6 @@ no_memory:
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for box_input().
|
||||
*/
|
||||
|
||||
bool box_input_text(BOX_SPECIAL_PARAMS, bool password)
|
||||
{
|
||||
struct box *inline_container, *inline_box;
|
||||
|
||||
box->type = BOX_INLINE_BLOCK;
|
||||
|
||||
inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content->bctx);
|
||||
if (!inline_container)
|
||||
return false;
|
||||
inline_container->type = BOX_INLINE_CONTAINER;
|
||||
inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
|
||||
content->bctx);
|
||||
if (!inline_box)
|
||||
return false;
|
||||
inline_box->type = BOX_TEXT;
|
||||
if (password) {
|
||||
inline_box->length = strlen(box->gadget->value);
|
||||
inline_box->text = talloc_array(content->bctx, char,
|
||||
inline_box->length + 1);
|
||||
if (!inline_box->text)
|
||||
return false;
|
||||
memset(inline_box->text, '*', inline_box->length);
|
||||
inline_box->text[inline_box->length] = '\0';
|
||||
} else {
|
||||
/* replace spaces/TABs with hard spaces to prevent line
|
||||
* wrapping */
|
||||
char *text = cnv_space2nbsp(box->gadget->value);
|
||||
if (!text)
|
||||
return false;
|
||||
inline_box->text = talloc_strdup(content->bctx, text);
|
||||
free(text);
|
||||
if (!inline_box->text)
|
||||
return false;
|
||||
inline_box->length = strlen(inline_box->text);
|
||||
}
|
||||
box_add_child(inline_container, inline_box);
|
||||
box_add_child(box, inline_container);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Push button [17.5].
|
||||
*/
|
||||
|
@ -2924,89 +2910,15 @@ no_memory:
|
|||
|
||||
bool box_textarea(BOX_SPECIAL_PARAMS)
|
||||
{
|
||||
/* A textarea is an INLINE_BLOCK containing a single INLINE_CONTAINER,
|
||||
* which contains the text as runs of TEXT separated by BR. There is
|
||||
* at least one TEXT. The first and last boxes are TEXT.
|
||||
* Consecutive BR may not be present. These constraints are satisfied
|
||||
* by using a 0-length TEXT for blank lines. */
|
||||
|
||||
const char *current;
|
||||
dom_string *area_data = NULL;
|
||||
dom_exception err;
|
||||
struct box *inline_container, *inline_box, *br_box;
|
||||
char *s;
|
||||
size_t len;
|
||||
|
||||
box->type = BOX_INLINE_BLOCK;
|
||||
/* Get the form_control for the DOM node */
|
||||
box->gadget = html_forms_get_control_for_node(content->forms, n);
|
||||
if (box->gadget == NULL)
|
||||
return false;
|
||||
|
||||
box->gadget->box = box;
|
||||
|
||||
inline_container = box_create(NULL, 0, false, 0, 0, box->title, 0,
|
||||
content->bctx);
|
||||
if (inline_container == NULL)
|
||||
if (!box_input_text(content, box, n))
|
||||
return false;
|
||||
inline_container->type = BOX_INLINE_CONTAINER;
|
||||
box_add_child(box, inline_container);
|
||||
|
||||
err = dom_node_get_text_content(n, &area_data);
|
||||
if (err != DOM_NO_ERR)
|
||||
return false;
|
||||
|
||||
if (area_data != NULL) {
|
||||
current = dom_string_data(area_data);
|
||||
} else {
|
||||
/* No content, or failed reading it: use a blank string */
|
||||
current = "";
|
||||
}
|
||||
|
||||
while (true) {
|
||||
/* BOX_TEXT */
|
||||
len = strcspn(current, "\r\n");
|
||||
s = talloc_strndup(content->bctx, current, len);
|
||||
if (s == NULL) {
|
||||
if (area_data != NULL)
|
||||
dom_string_unref(area_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
inline_box = box_create(NULL, box->style, false, 0, 0,
|
||||
box->title, 0, content->bctx);
|
||||
if (inline_box == NULL) {
|
||||
if (area_data != NULL)
|
||||
dom_string_unref(area_data);
|
||||
return false;
|
||||
}
|
||||
inline_box->type = BOX_TEXT;
|
||||
inline_box->text = s;
|
||||
inline_box->length = len;
|
||||
box_add_child(inline_container, inline_box);
|
||||
|
||||
current += len;
|
||||
if (current[0] == 0)
|
||||
/* finished */
|
||||
break;
|
||||
|
||||
/* BOX_BR */
|
||||
br_box = box_create(NULL, box->style, false, 0, 0, box->title,
|
||||
0, content->bctx);
|
||||
if (br_box == NULL) {
|
||||
if (area_data != NULL)
|
||||
dom_string_unref(area_data);
|
||||
return false;
|
||||
}
|
||||
br_box->type = BOX_BR;
|
||||
box_add_child(inline_container, br_box);
|
||||
|
||||
if (current[0] == '\r' && current[1] == '\n')
|
||||
current += 2;
|
||||
else
|
||||
current++;
|
||||
}
|
||||
|
||||
if (area_data != NULL)
|
||||
dom_string_unref(area_data);
|
||||
|
||||
*convert_children = false;
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Copyright 2013 Michael Drake <tlsa@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/>.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Box tree treeview box replacement (implementation).
|
||||
*/
|
||||
|
||||
#include <dom/dom.h>
|
||||
|
||||
#include "desktop/browser.h"
|
||||
#include "desktop/textarea.h"
|
||||
#include "desktop/textinput.h"
|
||||
#include "render/box_textarea.h"
|
||||
#include "render/font.h"
|
||||
#include "render/form.h"
|
||||
|
||||
|
||||
static bool box_textarea_browser_caret_callback(struct browser_window *bw,
|
||||
uint32_t key, void *p1, void *p2)
|
||||
{
|
||||
struct box *box = p1;
|
||||
struct form_control *gadget = box->gadget;
|
||||
struct textarea *ta = gadget->data.text.ta;
|
||||
struct form* form = box->gadget->form;
|
||||
html_content *html = p2;
|
||||
struct content *c = (struct content *) html;
|
||||
|
||||
assert(ta != NULL);
|
||||
|
||||
if (gadget->type != GADGET_TEXTAREA) {
|
||||
switch (key) {
|
||||
case KEY_NL:
|
||||
case KEY_CR:
|
||||
if (form)
|
||||
form_submit(content_get_url(c), html->bw,
|
||||
form, 0);
|
||||
return true;
|
||||
|
||||
case KEY_TAB:
|
||||
{
|
||||
struct form_control *next_input;
|
||||
/* Find next text entry field that is actually
|
||||
* displayed (i.e. has an associated box) */
|
||||
for (next_input = gadget->next;
|
||||
next_input &&
|
||||
((next_input->type != GADGET_TEXTBOX &&
|
||||
next_input->type != GADGET_TEXTAREA &&
|
||||
next_input->type != GADGET_PASSWORD) ||
|
||||
!next_input->box);
|
||||
next_input = next_input->next)
|
||||
;
|
||||
if (!next_input)
|
||||
return true;
|
||||
|
||||
textarea_set_caret(ta, -1);
|
||||
textarea_set_caret(next_input->data.text.ta, 0);
|
||||
}
|
||||
return true;
|
||||
|
||||
case KEY_SHIFT_TAB:
|
||||
{
|
||||
struct form_control *prev_input;
|
||||
/* Find previous text entry field that is actually
|
||||
* displayed (i.e. has an associated box) */
|
||||
for (prev_input = gadget->prev;
|
||||
prev_input &&
|
||||
((prev_input->type != GADGET_TEXTBOX &&
|
||||
prev_input->type != GADGET_TEXTAREA &&
|
||||
prev_input->type != GADGET_PASSWORD) ||
|
||||
!prev_input->box);
|
||||
prev_input = prev_input->prev)
|
||||
;
|
||||
if (!prev_input)
|
||||
return true;
|
||||
|
||||
textarea_set_caret(ta, -1);
|
||||
textarea_set_caret(prev_input->data.text.ta, 0);
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
/* Pass to textarea widget */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return textarea_keypress(ta, key);
|
||||
}
|
||||
|
||||
|
||||
static void box_textarea_browser_move_callback(struct browser_window *bw,
|
||||
void *p1, void *p2)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static bool box_textarea_browser_paste_callback(struct browser_window *bw,
|
||||
const char *utf8, unsigned utf8_len, bool last,
|
||||
void *p1, void *p2)
|
||||
{
|
||||
printf("AWWOOOOOGA!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for html form textareas.
|
||||
*/
|
||||
static void box_textarea_callback(void *data, struct textarea_msg *msg)
|
||||
{
|
||||
struct form_textarea_data *d = data;
|
||||
struct content *c = (struct content *)d->html;
|
||||
struct html_content *html = d->html;
|
||||
struct form_control *gadget = d->gadget;
|
||||
struct box *box = gadget->box;
|
||||
union content_msg_data msg_data;
|
||||
|
||||
switch (msg->type) {
|
||||
case TEXTAREA_MSG_DRAG_REPORT:
|
||||
if (msg->data.drag == TEXTAREA_DRAG_NONE) {
|
||||
/* Textarea drag finished */
|
||||
html->textarea = NULL;
|
||||
|
||||
browser_window_set_drag_type(html->bw,
|
||||
DRAGGING_NONE, NULL);
|
||||
|
||||
msg_data.pointer = BROWSER_POINTER_AUTO;
|
||||
content_broadcast(c, CONTENT_MSG_POINTER, msg_data);
|
||||
} else {
|
||||
/* Textarea drag started */
|
||||
struct rect rect = {
|
||||
.x0 = INT_MIN,
|
||||
.y0 = INT_MIN,
|
||||
.x1 = INT_MAX,
|
||||
.y1 = INT_MAX
|
||||
};
|
||||
browser_drag_type bdt;
|
||||
|
||||
if (msg->data.drag == TEXTAREA_DRAG_SCROLLBAR)
|
||||
bdt = DRAGGING_CONTENT_TEXTAREA_SCROLLBAR;
|
||||
else
|
||||
bdt = DRAGGING_CONTENT_TEXTAREA_SELECTION;
|
||||
|
||||
browser_window_set_drag_type(html->bw, bdt, &rect);
|
||||
|
||||
html->textarea = msg->ta;
|
||||
}
|
||||
break;
|
||||
|
||||
case TEXTAREA_MSG_REDRAW_REQUEST:
|
||||
/* Redraw the textarea */
|
||||
/* TODO: don't redraw whole box, just the part asked for */
|
||||
html__redraw_a_box(html, box);
|
||||
break;
|
||||
|
||||
case TEXTAREA_MSG_MOVED_CARET:
|
||||
if (html->bw == NULL)
|
||||
break;
|
||||
|
||||
if (msg->data.caret.hidden) {
|
||||
browser_window_remove_caret(html->bw);
|
||||
} else {
|
||||
browser_window_place_caret(html->bw,
|
||||
msg->data.caret.x, msg->data.caret.y,
|
||||
msg->data.caret.height,
|
||||
box_textarea_browser_caret_callback,
|
||||
box_textarea_browser_paste_callback,
|
||||
box_textarea_browser_move_callback,
|
||||
box, html);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Exported interface, documented in box_textarea.h */
|
||||
bool box_textarea_create_textarea(html_content *html,
|
||||
struct box *box, struct dom_node *node)
|
||||
{
|
||||
dom_string *dom_text = NULL;
|
||||
dom_exception err;
|
||||
textarea_setup ta_setup;
|
||||
textarea_flags ta_flags;
|
||||
plot_font_style_t fstyle;
|
||||
struct form_control *gadget = box->gadget;
|
||||
const char *text;
|
||||
|
||||
/** TODO: Read only textarea */
|
||||
|
||||
assert(gadget != NULL);
|
||||
assert(gadget->type == GADGET_TEXTAREA ||
|
||||
gadget->type == GADGET_TEXTBOX ||
|
||||
gadget->type == GADGET_PASSWORD);
|
||||
|
||||
if (gadget->type == GADGET_TEXTAREA) {
|
||||
ta_flags = TEXTAREA_MULTILINE;
|
||||
|
||||
/* Get the textarea's initial content */
|
||||
err = dom_node_get_text_content(node, &dom_text);
|
||||
if (err != DOM_NO_ERR)
|
||||
return false;
|
||||
|
||||
} else {
|
||||
dom_html_input_element *input = (dom_html_input_element *) node;
|
||||
|
||||
if (gadget->type == GADGET_PASSWORD)
|
||||
ta_flags = TEXTAREA_PASSWORD;
|
||||
else
|
||||
ta_flags = TEXTAREA_DEFAULT;
|
||||
|
||||
/* Get initial text */
|
||||
err = dom_html_input_element_get_value(input, &dom_text);
|
||||
if (err != DOM_NO_ERR)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dom_text != NULL) {
|
||||
text = dom_string_data(dom_text);
|
||||
} else {
|
||||
/* No initial text, or failed reading it;
|
||||
* use a blank string */
|
||||
text = "";
|
||||
}
|
||||
|
||||
gadget->data.text.data.html = html;
|
||||
gadget->data.text.data.gadget = gadget;
|
||||
|
||||
font_plot_style_from_css(gadget->box->style, &fstyle);
|
||||
|
||||
/* Reset to correct values by layout */
|
||||
ta_setup.width = 200;
|
||||
ta_setup.height = 20;
|
||||
ta_setup.pad_top = 4;
|
||||
ta_setup.pad_right = 4;
|
||||
ta_setup.pad_bottom = 4;
|
||||
ta_setup.pad_left = 4;
|
||||
ta_setup.border_width = 0;
|
||||
ta_setup.border_col = 0x000000;
|
||||
ta_setup.selected_text = 0xffffff;
|
||||
ta_setup.selected_bg = 0x000000;
|
||||
ta_setup.text = fstyle;
|
||||
ta_setup.text.foreground = 0x000000;
|
||||
ta_setup.text.background = NS_TRANSPARENT;
|
||||
|
||||
/* Hand reference to dom text over to gadget */
|
||||
gadget->data.text.initial = dom_text;
|
||||
|
||||
gadget->data.text.ta = textarea_create(ta_flags, &ta_setup,
|
||||
box_textarea_callback, &gadget->data.text.data);
|
||||
|
||||
if (gadget->data.text.ta == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!textarea_set_text(gadget->data.text.ta, text))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2013 Michael Drake <tlsa@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/>.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Box tree treeview box replacement (interface).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef _NETSURF_RENDER_BOX_TEXTAREA_H_
|
||||
#define _NETSURF_RENDER_BOX_TEXTAREA_H_
|
||||
|
||||
|
||||
#include "render/box.h"
|
||||
#include "render/html_internal.h"
|
||||
|
||||
struct dom_node;
|
||||
|
||||
/**
|
||||
* Create textarea widget for a form element
|
||||
*
|
||||
* \param html html content object
|
||||
* \param box box with gadget to be given textarea widget
|
||||
* \param node DOM node for form element
|
||||
*/
|
||||
bool box_textarea_create_textarea(html_content *html,
|
||||
struct box *box, struct dom_node *node);
|
||||
|
||||
#endif
|
|
@ -43,6 +43,7 @@
|
|||
#include "desktop/plot_style.h"
|
||||
#include "desktop/plotters.h"
|
||||
#include "desktop/scrollbar.h"
|
||||
#include "desktop/textarea.h"
|
||||
#include "render/box.h"
|
||||
#include "render/font.h"
|
||||
#include "render/form.h"
|
||||
|
@ -85,7 +86,6 @@ static plot_font_style_t plot_fstyle_entry = {
|
|||
.foreground = 0x000000,
|
||||
};
|
||||
|
||||
static char *form_textarea_value(struct form_control *textarea);
|
||||
static char *form_acceptable_charset(struct form *form);
|
||||
static char *form_encode_item(const char *item, const char *charset,
|
||||
const char *fallback);
|
||||
|
@ -252,6 +252,17 @@ void form_free_control(struct form_control *control)
|
|||
form_free_select_menu(control);
|
||||
}
|
||||
|
||||
if (control->type == GADGET_TEXTAREA ||
|
||||
control->type == GADGET_TEXTBOX ||
|
||||
control->type == GADGET_PASSWORD) {
|
||||
|
||||
if (control->data.text.initial != NULL)
|
||||
dom_string_unref(control->data.text.initial);
|
||||
|
||||
if (control->data.text.ta != NULL)
|
||||
textarea_destroy(control->data.text.ta);
|
||||
}
|
||||
|
||||
free(control);
|
||||
}
|
||||
|
||||
|
@ -350,8 +361,6 @@ bool form_successful_controls(struct form *form,
|
|||
|
||||
switch (control->type) {
|
||||
case GADGET_HIDDEN:
|
||||
case GADGET_TEXTBOX:
|
||||
case GADGET_PASSWORD:
|
||||
if (control->value)
|
||||
value = ENCODE_ITEM(control->value);
|
||||
else
|
||||
|
@ -416,17 +425,26 @@ bool form_successful_controls(struct form *form,
|
|||
continue;
|
||||
break;
|
||||
|
||||
case GADGET_TEXTBOX:
|
||||
case GADGET_PASSWORD:
|
||||
case GADGET_TEXTAREA:
|
||||
{
|
||||
{
|
||||
char *v2;
|
||||
int ta_len = textarea_get_text(
|
||||
control->data.text.ta,
|
||||
NULL, 0);
|
||||
|
||||
/* textarea */
|
||||
value = form_textarea_value(control);
|
||||
value = malloc(ta_len);
|
||||
if (!value) {
|
||||
LOG(("failed handling textarea"));
|
||||
goto no_memory;
|
||||
}
|
||||
if (value[0] == 0) {
|
||||
textarea_get_text(control->data.text.ta,
|
||||
value, ta_len);
|
||||
|
||||
if (control->type == GADGET_TEXTAREA &&
|
||||
value[0] == '\0') {
|
||||
/* Textarea not submitted if empty */
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
|
@ -440,7 +458,7 @@ bool form_successful_controls(struct form *form,
|
|||
|
||||
free(value);
|
||||
value = v2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GADGET_IMAGE: {
|
||||
|
@ -616,59 +634,6 @@ no_memory:
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the value for a textarea control.
|
||||
*
|
||||
* \param textarea control of type GADGET_TEXTAREA
|
||||
* \return the value as a UTF-8 string on heap, or 0 on memory exhaustion
|
||||
*/
|
||||
char *form_textarea_value(struct form_control *textarea)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
char *value, *s;
|
||||
struct box *text_box;
|
||||
|
||||
/* Textarea may have no associated box if styled with display: none */
|
||||
if (textarea->box == NULL) {
|
||||
/* Return the empty string: caller treats this as a
|
||||
* non-successful control. */
|
||||
return strdup("");
|
||||
}
|
||||
|
||||
/* find required length */
|
||||
for (text_box = textarea->box->children->children; text_box;
|
||||
text_box = text_box->next) {
|
||||
if (text_box->type == BOX_TEXT)
|
||||
len += text_box->length + 1;
|
||||
else /* BOX_BR */
|
||||
len += 2;
|
||||
}
|
||||
|
||||
/* construct value */
|
||||
s = value = malloc(len + 1);
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
for (text_box = textarea->box->children->children; text_box;
|
||||
text_box = text_box->next) {
|
||||
if (text_box->type == BOX_TEXT) {
|
||||
strncpy(s, text_box->text, text_box->length);
|
||||
s += text_box->length;
|
||||
if (text_box->next && text_box->next->type != BOX_BR)
|
||||
/* only add space if this isn't
|
||||
* the last box on a line (or in the area) */
|
||||
*s++ = ' ';
|
||||
} else { /* BOX_BR */
|
||||
*s++ = '\r';
|
||||
*s++ = '\n';
|
||||
}
|
||||
}
|
||||
*s = 0;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode controls using application/x-www-form-urlencoded.
|
||||
*
|
||||
|
|
|
@ -34,6 +34,7 @@ struct form_control;
|
|||
struct form_option;
|
||||
struct form_select_menu;
|
||||
struct html_content;
|
||||
struct dom_string;
|
||||
|
||||
/** Form submit method. */
|
||||
typedef enum {
|
||||
|
@ -73,6 +74,12 @@ typedef enum {
|
|||
GADGET_BUTTON
|
||||
} form_control_type;
|
||||
|
||||
/** Data for textarea */
|
||||
struct form_textarea_data {
|
||||
struct html_content *html;
|
||||
struct form_control *gadget;
|
||||
};
|
||||
|
||||
/** Form control. */
|
||||
struct form_control {
|
||||
void *node; /**< Corresponding DOM node */
|
||||
|
@ -111,6 +118,11 @@ struct form_control {
|
|||
struct form_option *current;
|
||||
struct form_select_menu *menu;
|
||||
} select;
|
||||
struct {
|
||||
struct textarea *ta;
|
||||
struct dom_string *initial;
|
||||
struct form_textarea_data data;
|
||||
} text; /**< input type=text or textarea */
|
||||
} data;
|
||||
|
||||
struct form_control *prev; /**< Previous control in this form */
|
||||
|
|
|
@ -344,6 +344,7 @@ html_create_html_data(html_content *c, const http_parameter *params)
|
|||
c->page = NULL;
|
||||
c->font_func = &nsfont;
|
||||
c->scrollbar = NULL;
|
||||
c->textarea = NULL;
|
||||
c->scripts_count = 0;
|
||||
c->scripts = NULL;
|
||||
c->jscontext = NULL;
|
||||
|
|
|
@ -46,6 +46,7 @@ struct http_parameter;
|
|||
struct imagemap;
|
||||
struct object_params;
|
||||
struct plotters;
|
||||
struct textarea;
|
||||
struct scrollbar;
|
||||
struct scrollbar_msg_data;
|
||||
struct search_context;
|
||||
|
|
|
@ -523,7 +523,8 @@ invent_fake_gadget(dom_node *node)
|
|||
}
|
||||
|
||||
/* documented in html_internal.h */
|
||||
struct form_control *html_forms_get_control_for_node(struct form *forms, dom_node *node)
|
||||
struct form_control *html_forms_get_control_for_node(struct form *forms,
|
||||
dom_node *node)
|
||||
{
|
||||
struct form *f;
|
||||
struct form_control *ctl = NULL;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "desktop/options.h"
|
||||
#include "desktop/scrollbar.h"
|
||||
#include "desktop/selection.h"
|
||||
#include "desktop/textarea.h"
|
||||
#include "desktop/textinput.h"
|
||||
#include "render/box.h"
|
||||
#include "render/font.h"
|
||||
|
@ -592,94 +593,18 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
|
|||
status = messages_get("FormBadSubmit");
|
||||
}
|
||||
break;
|
||||
case GADGET_TEXTAREA:
|
||||
status = messages_get("FormTextarea");
|
||||
pointer = get_pointer_shape(gadget_box, false);
|
||||
|
||||
if (mouse & (BROWSER_MOUSE_PRESS_1 |
|
||||
BROWSER_MOUSE_PRESS_2)) {
|
||||
if (text_box && selection_root(&html->sel) !=
|
||||
gadget_box)
|
||||
selection_init(&html->sel, gadget_box);
|
||||
|
||||
textinput_textarea_click(c, mouse,
|
||||
gadget_box,
|
||||
gadget_box_x,
|
||||
gadget_box_y,
|
||||
x - gadget_box_x,
|
||||
y - gadget_box_y);
|
||||
}
|
||||
|
||||
if (text_box) {
|
||||
int pixel_offset;
|
||||
size_t idx;
|
||||
|
||||
font_plot_style_from_css(text_box->style,
|
||||
&fstyle);
|
||||
|
||||
nsfont.font_position_in_string(&fstyle,
|
||||
text_box->text,
|
||||
text_box->length,
|
||||
x - gadget_box_x - text_box->x,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
selection_click(&html->sel, mouse,
|
||||
text_box->byte_offset + idx);
|
||||
|
||||
if (selection_dragging(&html->sel)) {
|
||||
browser_window_set_drag_type(bw,
|
||||
DRAGGING_SELECTION,
|
||||
NULL);
|
||||
status = messages_get("Selecting");
|
||||
}
|
||||
}
|
||||
else if (mouse & BROWSER_MOUSE_PRESS_1)
|
||||
selection_clear(&html->sel, true);
|
||||
break;
|
||||
case GADGET_TEXTBOX:
|
||||
case GADGET_PASSWORD:
|
||||
status = messages_get("FormTextbox");
|
||||
case GADGET_TEXTAREA:
|
||||
if (gadget->type == GADGET_TEXTAREA)
|
||||
status = messages_get("FormTextarea");
|
||||
else
|
||||
status = messages_get("FormTextbox");
|
||||
|
||||
pointer = get_pointer_shape(gadget_box, false);
|
||||
|
||||
if ((mouse & BROWSER_MOUSE_PRESS_1) &&
|
||||
!(mouse & (BROWSER_MOUSE_MOD_1 |
|
||||
BROWSER_MOUSE_MOD_2))) {
|
||||
textinput_input_click(c,
|
||||
gadget_box,
|
||||
gadget_box_x,
|
||||
gadget_box_y,
|
||||
x - gadget_box_x,
|
||||
y - gadget_box_y);
|
||||
}
|
||||
if (text_box) {
|
||||
int pixel_offset;
|
||||
size_t idx;
|
||||
|
||||
if (mouse & (BROWSER_MOUSE_DRAG_1 |
|
||||
BROWSER_MOUSE_DRAG_2))
|
||||
selection_init(&html->sel, gadget_box);
|
||||
|
||||
font_plot_style_from_css(text_box->style,
|
||||
&fstyle);
|
||||
|
||||
nsfont.font_position_in_string(&fstyle,
|
||||
text_box->text,
|
||||
text_box->length,
|
||||
x - gadget_box_x - text_box->x,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
selection_click(&html->sel, mouse,
|
||||
text_box->byte_offset + idx);
|
||||
|
||||
if (selection_dragging(&html->sel))
|
||||
browser_window_set_drag_type(bw,
|
||||
DRAGGING_SELECTION,
|
||||
NULL);
|
||||
}
|
||||
else if (mouse & BROWSER_MOUSE_PRESS_1)
|
||||
selection_clear(&html->sel, true);
|
||||
textarea_mouse_action(gadget->data.text.ta, mouse,
|
||||
x - gadget_box_x, y - gadget_box_y);
|
||||
break;
|
||||
case GADGET_HIDDEN:
|
||||
/* not possible: no box generated */
|
||||
|
|
|
@ -102,6 +102,10 @@ typedef struct html_content {
|
|||
* scrollbar, or NULL when no scrollbar drags active */
|
||||
struct scrollbar *scrollbar;
|
||||
|
||||
/** Textarea capturing all mouse events, updated to any active HTML
|
||||
* textarea, or NULL when no textarea drags active */
|
||||
struct textarea *textarea;
|
||||
|
||||
/** Open core-handled form SELECT menu,
|
||||
* or NULL if none currently open. */
|
||||
struct form_control *visible_select_menu;
|
||||
|
@ -162,7 +166,8 @@ bool html_scripts_exec(html_content *c);
|
|||
|
||||
/* in render/html_forms.c */
|
||||
struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc);
|
||||
struct form_control *html_forms_get_control_for_node(struct form *forms, dom_node *node);
|
||||
struct form_control *html_forms_get_control_for_node(struct form *forms,
|
||||
dom_node *node);
|
||||
|
||||
/* Useful dom_string pointers */
|
||||
struct dom_string;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "desktop/options.h"
|
||||
#include "desktop/print.h"
|
||||
#include "desktop/scrollbar.h"
|
||||
#include "desktop/textarea.h"
|
||||
#include "image/bitmap.h"
|
||||
#include "render/box.h"
|
||||
#include "render/font.h"
|
||||
|
@ -2109,7 +2110,11 @@ bool html_redraw_box(const html_content *html, struct box *box,
|
|||
bg_box->type != BOX_TEXT &&
|
||||
bg_box->type != BOX_INLINE_END &&
|
||||
(bg_box->type != BOX_INLINE || bg_box->object ||
|
||||
bg_box->flags & IFRAME || box->flags & REPLACE_DIM)) {
|
||||
bg_box->flags & IFRAME || box->flags & REPLACE_DIM ||
|
||||
(bg_box->gadget != NULL &&
|
||||
(bg_box->gadget->type == GADGET_TEXTAREA ||
|
||||
bg_box->gadget->type == GADGET_TEXTBOX ||
|
||||
bg_box->gadget->type == GADGET_PASSWORD)))) {
|
||||
/* find intersection of clip box and border edge */
|
||||
struct rect p;
|
||||
p.x0 = x - border_left < r.x0 ? r.x0 : x - border_left;
|
||||
|
@ -2154,7 +2159,11 @@ bool html_redraw_box(const html_content *html, struct box *box,
|
|||
if (box->style && box->type != BOX_TEXT &&
|
||||
box->type != BOX_INLINE_END &&
|
||||
(box->type != BOX_INLINE || box->object ||
|
||||
box->flags & IFRAME || box->flags & REPLACE_DIM) &&
|
||||
box->flags & IFRAME || box->flags & REPLACE_DIM ||
|
||||
(box->gadget != NULL &&
|
||||
(box->gadget->type == GADGET_TEXTAREA ||
|
||||
box->gadget->type == GADGET_TEXTBOX ||
|
||||
box->gadget->type == GADGET_PASSWORD))) &&
|
||||
(border_top || border_right ||
|
||||
border_bottom || border_left)) {
|
||||
if (!html_redraw_borders(box, x_parent, y_parent,
|
||||
|
@ -2398,6 +2407,13 @@ bool html_redraw_box(const html_content *html, struct box *box,
|
|||
current_background_color, ctx))
|
||||
return false;
|
||||
|
||||
} else if (box->gadget &&
|
||||
(box->gadget->type == GADGET_TEXTAREA ||
|
||||
box->gadget->type == GADGET_PASSWORD ||
|
||||
box->gadget->type == GADGET_TEXTBOX)) {
|
||||
textarea_redraw(box->gadget->data.text.ta,
|
||||
x, y, current_background_color, &r, ctx);
|
||||
|
||||
} else if (box->text) {
|
||||
if (!html_redraw_text_box(html, box, x, y, &r, scale,
|
||||
current_background_color, ctx))
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "content/content_protected.h"
|
||||
#include "desktop/options.h"
|
||||
#include "desktop/scrollbar.h"
|
||||
#include "desktop/textarea.h"
|
||||
#include "render/box.h"
|
||||
#include "render/font.h"
|
||||
#include "render/form.h"
|
||||
|
@ -650,6 +651,20 @@ bool layout_block_context(struct box *block, int viewport_height,
|
|||
layout_apply_minmax_height(block, NULL);
|
||||
}
|
||||
|
||||
if (block->gadget &&
|
||||
(block->gadget->type == GADGET_TEXTAREA ||
|
||||
block->gadget->type == GADGET_PASSWORD ||
|
||||
block->gadget->type == GADGET_TEXTBOX)) {
|
||||
int ta_width = block->padding[LEFT] + block->width +
|
||||
block->padding[RIGHT];
|
||||
int ta_height = block->padding[TOP] + block->height +
|
||||
block->padding[BOTTOM];
|
||||
textarea_set_layout(block->gadget->data.text.ta,
|
||||
ta_width, ta_height,
|
||||
block->padding[TOP], block->padding[RIGHT],
|
||||
block->padding[BOTTOM], block->padding[LEFT]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue