[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-core-devel
Subject: Re: I was kinda bored
From: Rolf Eike Beer <kde () opensource ! sf-tec ! de>
Date: 2010-10-07 18:53:15
Message-ID: 201010072053.15659.kde () opensource ! sf-tec ! de
[Download RAW message or body]
[Attachment #2 (multipart/mixed)]
Maksim Orlovich wrote:
> On 10/6/10, Rolf Eike Beer <kde@opensource.sf-tec.de> wrote:
> > I was hacking for something like 3 or 4 hours and came up with this
> > implementation of the "new" HTML5 <input type="number"> field. I have no
> > idea
> > if that is the right way to do it, I must also confess that most of the
> > code is copy&paste from the normal input fields. The only real testing I
> > did was using
> > http://diveintohtml5.org/examples/input-type-number-min-max-step.html
> > which seems to work as expected.
> >
> > If someone with any insight in KHTML could take a look if this is
> > anything close to a sane implementation I would be happy to see
> > something like this going into KHTML for KDE 4.6. If it covers only half
> > of the cases it still makes the users life easier than the pure text
> > field ;)
> Thanks. Looks cool, and the diff looks pretty good (though I can't
> check the visual stuff in my head)... A couple things I noticed from
> reading it, though:
>
> 1) Don't change misc/htmlnames.{h/cpp} directly. Rather edit
> misc/htmlattrs.in and re-run
> misc/gennames.py. Then "enjoy" a full recompile...
Whatever works ;) This should definitely go into khtml/doc/ something then.
> 2)
> + if ((int)m_numberMin == m_numberMin)
> + ok = ((int)tmp == tmp);
>
> Probably need to check the original ok here, too.
> It's probably also worth checking whether something like
> setAttribute("min", "monkeys!") is supposed to reset the value to default
> or not.
That's probably somehow related to JavaScript and stuff, no? There are some JS
accessor functions (input.stepUp(n), input.stepDown(n) and
input.valueAsNumber() that are missing). I have no idea about JavaScript at
all, even less about how to implement this in KHTML.
> 3) RenderNumberEdit::upateFromElement:() needs to update min/max/step as
> well
Yeah, probably. Also W3C says an empty string as input must be allowed. And of
course there are no unit-tests.
> Also, it'd probably be better to e-mail kfm-devel with stuff like
> this, especially if you use a vague title ;-).
Yeah, you are right. Full quote and CC, once again the attachment (sorry kde-
core-devel).
Eike
["html5-number.patch" (text/x-patch)]
Index: misc/htmlnames.h
===================================================================
--- misc/htmlnames.h (Revision 1183252)
+++ misc/htmlnames.h (Arbeitskopie)
@@ -620,6 +620,7 @@
#define ID_CLOSE_TAG 16384
#define ATTR_LAST_ATTR 254
#define ATTR_LAST_CI_ATTR 210
+#define ATTR_STEP ((DOM::xmlNamespace << 16) | 556)
#define caseSensitiveAttr(id) (((localNamePart(id)) > ATTR_LAST_CI_ATTR || (id) == \
ATTR_ABBR || (id) == ATTR_CITE || (id) == ATTR_CODE || (id) == ATTR_LABEL || (id) == \
ATTR_OBJECT || (id) == ATTR_TITLE))
Index: misc/htmlnames.cpp
===================================================================
--- misc/htmlnames.cpp (Revision 1183252)
+++ misc/htmlnames.cpp (Arbeitskopie)
@@ -518,6 +518,7 @@
s_idTable->addStaticMapping(localNamePart(ATTR_STDDEVIATION), "stdDeviation");
s_idTable->addStaticMapping(localNamePart(ATTR_STEMH), "stemh");
s_idTable->addStaticMapping(localNamePart(ATTR_STEMV), "stemv");
+ s_idTable->addStaticMapping(localNamePart(ATTR_STEP), "step");
s_idTable->addStaticMapping(localNamePart(ATTR_STITCHTILES), "stitchTiles");
s_idTable->addStaticMapping(localNamePart(ATTR_STOP_COLOR), "stop-color");
s_idTable->addStaticMapping(localNamePart(ATTR_STOP_OPACITY), "stop-opacity");
Index: html/html_formimpl.cpp
===================================================================
--- html/html_formimpl.cpp (Revision 1183252)
+++ html/html_formimpl.cpp (Arbeitskopie)
@@ -66,8 +66,8 @@
#include <ksslkeygen.h>
#include <assert.h>
+#include <float.h>
-
using namespace DOM;
using namespace khtml;
using namespace WTF;
@@ -1289,6 +1289,10 @@
m_inited = false;
m_unsubmittedFormChange = false;
+ m_numberMin = FLT_MIN;
+ m_numberMax = FLT_MAX;
+ m_numberStep = 1.0;
+
xPos = 0;
yPos = 0;
@@ -1337,6 +1341,8 @@
newType = BUTTON;
else if ( strcasecmp( t, "khtml_isindex" ) == 0 )
newType = ISINDEX;
+ else if ( strcasecmp( t, "number" ) == 0 )
+ newType = NUMBER;
else
newType = TEXT;
@@ -1375,6 +1381,7 @@
case HIDDEN: return "hidden";
case IMAGE: return "image";
case BUTTON: return "button";
+ case NUMBER: return "number";
default: return "";
}
}
@@ -1503,6 +1510,34 @@
setHTMLEventListener(EventImpl::CHANGE_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onchange", \
this)); break;
+ case ATTR_MIN:
+ {
+ bool ok;
+ float tmp = attr->value().toFloat(&ok);
+ if (ok)
+ m_numberMin = tmp;
+ break;
+ }
+ case ATTR_MAX:
+ {
+ bool ok;
+ float tmp = attr->value().toFloat(&ok);
+ if (ok)
+ m_numberMax = tmp;
+ break;
+ }
+ case ATTR_STEP:
+ {
+ bool ok;
+ float tmp = attr->value().toFloat(&ok);
+ // W3C HTML5 says: "The step scale factor is 1. The default step is 1
+ // (allowing only integers, unless the min attribute has a non-integer \
value)." + if ((int)m_numberMin == m_numberMin)
+ ok = ((int)tmp == tmp);
+ if (ok)
+ m_numberStep = tmp;
+ break;
+ }
default:
HTMLGenericFormElementImpl::parseAttribute(attr);
}
@@ -1576,6 +1611,7 @@
case FILE: m_render = new (document()->renderArena()) \
RenderFileButton(this); break;
case BUTTON: m_render = new (document()->renderArena()) \
RenderPushButton(this); case HIDDEN: break;
+ case NUMBER: m_render = new (document()->renderArena()) \
RenderNumberEdit(this); break; }
}
@@ -1716,6 +1752,7 @@
case HIDDEN:
case TEXT:
case PASSWORD:
+ case NUMBER:
// always successful
encoding += fixUpfromUnicode(codec, value().string());
return true;
@@ -1832,6 +1869,7 @@
case SEARCH:
#endif
case TEXT:
+ case NUMBER:
break;
}
}
Index: html/html_formimpl.h
===================================================================
--- html/html_formimpl.h (Revision 1183252)
+++ html/html_formimpl.h (Arbeitskopie)
@@ -41,6 +41,7 @@
class RenderLineEdit;
class RenderRadioButton;
class RenderFileButton;
+ class RenderNumberEdit;
typedef QList<QByteArray> encodingList;
}
@@ -252,6 +253,7 @@
friend class khtml::RenderLineEdit;
friend class khtml::RenderRadioButton;
friend class khtml::RenderFileButton;
+ friend class khtml::RenderNumberEdit;
public:
// do not change the order!
@@ -266,7 +268,8 @@
FILE,
HIDDEN,
IMAGE,
- BUTTON
+ BUTTON,
+ NUMBER
};
HTMLInputElementImpl(DocumentImpl *doc, HTMLFormElementImpl *f = 0);
@@ -289,6 +292,9 @@
int size() const { return m_size; }
DOMString type() const;
void setType(const DOMString& t);
+ float minValue() const { return m_numberMin; }
+ float maxValue() const { return m_numberMax; }
+ float step() const { return m_numberStep; }
DOMString value() const;
void setValue(DOMString val);
@@ -351,6 +357,9 @@
bool m_autocomplete : 1;
bool m_inited : 1;
bool m_unsubmittedFormChange : 1;
+ float m_numberMin;
+ float m_numberMax;
+ float m_numberStep;
};
// -------------------------------------------------------------------------
Index: rendering/render_form.h
===================================================================
--- rendering/render_form.h (Revision 1183252)
+++ rendering/render_form.h (Arbeitskopie)
@@ -39,6 +39,7 @@
#include <QtGui/QCheckBox>
#include <QtGui/QRadioButton>
#include <QtGui/QPushButton>
+#include <QtGui/QDoubleSpinBox>
#include <klistwidget.h>
#include <kcombobox.h>
#include "dom/dom_misc.h"
@@ -327,6 +328,58 @@
// -------------------------------------------------------------------------
+class RenderNumberEdit : public RenderFormElement
+{
+ Q_OBJECT
+public:
+ RenderNumberEdit(DOM::HTMLInputElementImpl *element);
+ virtual ~RenderNumberEdit();
+
+ virtual void calcMinMaxWidth();
+
+ virtual const char *renderName() const { return "RenderNumberEdit"; }
+ virtual void updateFromElement();
+ virtual void setStyle(RenderStyle *style);
+ virtual short baselinePosition( bool ) const;
+ virtual void handleFocusOut();
+
+ void select();
+
+ QDoubleSpinBox *widget() const { return static_cast<QDoubleSpinBox*>(m_widget); \
} + DOM::HTMLInputElementImpl* element() const
+ { return static_cast<DOM::HTMLInputElementImpl*>(RenderObject::element()); }
+
+public Q_SLOTS:
+ void slotReturnPressed();
+ void slotValueChanged(double d);
+protected:
+
+private:
+ virtual bool isEditable() const { return true; }
+ virtual bool canHaveBorder() const { return true; }
+};
+
+// -------------------------------------------------------------------------
+
+class NumberEditWidget : public QDoubleSpinBox, public KHTMLWidget
+{
+ Q_OBJECT
+public:
+ NumberEditWidget(DOM::HTMLInputElementImpl* input,
+ KHTMLView* view, QWidget* parent);
+ ~NumberEditWidget();
+ void setFocus();
+
+protected:
+ virtual void paintEvent( QPaintEvent *pe );
+
+private:
+ DOM::HTMLInputElementImpl* m_input;
+ KHTMLView* m_view;
+};
+
+// -------------------------------------------------------------------------
+
class RenderFieldset : public RenderBlock
{
public:
Index: rendering/render_form.cpp
===================================================================
--- rendering/render_form.cpp (Revision 1183252)
+++ rendering/render_form.cpp (Arbeitskopie)
@@ -766,6 +766,22 @@
setText( s );
}
+NumberEditWidget::NumberEditWidget(DOM::HTMLInputElementImpl* input, KHTMLView* \
view, QWidget* parent) + : QDoubleSpinBox(parent), m_input(input), m_view(view)
+{
+ m_kwp->setIsRedirected( true );
+ setMouseTracking(true);
+}
+
+NumberEditWidget::~NumberEditWidget()
+{
+}
+
+void NumberEditWidget::setFocus()
+{
+ QDoubleSpinBox::setFocus();
+}
+
namespace khtml {
/**
@@ -1008,6 +1024,15 @@
setDragEnabled(true);
}
+void NumberEditWidget::paintEvent( QPaintEvent *pe )
+{
+ if (!hasFrame()) {
+ QPainter p(this);
+ p.fillRect(pe->rect(), palette().brush(QPalette::Base));
+ p.end();
+ }
+ QDoubleSpinBox::paintEvent( pe );
+}
// -----------------------------------------------------------------------------
@@ -1210,6 +1235,100 @@
w->setSelection(start, end - start);
}
+// -----------------------------------------------------------------------------
+
+RenderNumberEdit::RenderNumberEdit(HTMLInputElementImpl *element)
+ : RenderFormElement(element)
+{
+ NumberEditWidget *edit = new NumberEditWidget(element, view(), \
view()->widget()); + connect(edit,SIGNAL(returnPressed()), this, \
SLOT(slotReturnPressed())); + \
connect(edit,SIGNAL(valueChanged(double)),this,SLOT(slotValueChanged(double))); +
+ edit->setRange( element->minValue(), element->maxValue() );
+ edit->setSingleStep( element->step() );
+
+ // we need only to check the minimum value here
+ // if the minimum is an int, step is only allowed to be int, too
+ if ( (int)element->minValue() == element->minValue() )
+ edit->setDecimals(0);
+
+ setQWidget(edit);
+}
+
+RenderNumberEdit::~RenderNumberEdit()
+{
+}
+
+short RenderNumberEdit::baselinePosition( bool f ) const
+{
+ bool hasFrame = static_cast<NumberEditWidget*>(widget())->hasFrame();
+ int bTop = hasFrame ? 0 : borderTop();
+ int bBottom = hasFrame ? 0 : borderBottom();
+ int ret = (height()-RenderWidget::paddingTop()-RenderWidget::paddingBottom()-bTop-bBottom+1)/2;
+ ret += marginTop() + RenderWidget::paddingTop() + bTop;
+ ret += ((fontMetrics( f ).ascent())/2)-2;
+ return ret;
+}
+
+void RenderNumberEdit::setStyle(RenderStyle* _style)
+{
+ RenderFormElement::setStyle( _style );
+
+ widget()->setAlignment(textAlignment());
+}
+
+void RenderNumberEdit::slotReturnPressed()
+{
+}
+
+void RenderNumberEdit::handleFocusOut()
+{
+}
+
+void RenderNumberEdit::calcMinMaxWidth()
+{
+ KHTMLAssert( !minMaxKnown() );
+
+ const QFontMetrics &fm = style()->fontMetrics();
+ QSize s;
+
+ int size = element()->size();
+
+ int h = fm.lineSpacing();
+ int w = fm.width( 'x' ) * (size > 0 ? size+1 : 17); // "some"
+
+ QStyleOptionFrame opt;
+ opt.initFrom(widget());
+ if (static_cast<NumberEditWidget*>(widget())->hasFrame())
+ opt.lineWidth = widget()->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, \
&opt, widget()); +
+ s = QSize(w, qMax(h, 14));
+ s = widget()->style()->sizeFromContents(QStyle::CT_LineEdit, &opt, s, widget());
+ s = s.expandedTo(QApplication::globalStrut());
+
+ setIntrinsicWidth( s.width() );
+ setIntrinsicHeight( s.height() );
+
+ RenderFormElement::calcMinMaxWidth();
+}
+
+void RenderNumberEdit::updateFromElement()
+{
+ if (element()->value().toInt() != widget()->value()) {
+ widget()->setValue(element()->value().toInt());
+ }
+ widget()->setReadOnly(element()->readOnly());
+
+ RenderFormElement::updateFromElement();
+}
+
+void RenderNumberEdit::slotValueChanged(double d)
+{
+ // don't use setValue here!
+ element()->m_value = QString::number(d);
+ element()->m_unsubmittedFormChange = true;
+}
+
// ---------------------------------------------------------------------------
RenderFieldset::RenderFieldset(HTMLGenericFormElementImpl *element)
["signature.asc" (application/pgp-signature)]
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic