[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