support more than one form per page

This commit is contained in:
Peter Schojer 2008-09-01 13:49:46 +00:00
parent b741f069ce
commit 64933507ac
3 changed files with 81 additions and 48 deletions

View File

@ -37,6 +37,7 @@
#include "Poco/WebWidgets/ExtJS/FormRenderer.h" #include "Poco/WebWidgets/ExtJS/FormRenderer.h"
#include "Poco/WebWidgets/Form.h" #include "Poco/WebWidgets/Form.h"
#include "Poco/WebWidgets/Button.h" #include "Poco/WebWidgets/Button.h"
#include "Poco/WebWidgets/WebApplication.h"
#include "Poco/NumberFormatter.h" #include "Poco/NumberFormatter.h"
@ -60,7 +61,8 @@ void FormRenderer::renderHead(const Renderable* pRenderable, const RenderContext
poco_assert_dbg (pRenderable != 0); poco_assert_dbg (pRenderable != 0);
poco_assert_dbg (pRenderable->type() == typeid(Poco::WebWidgets::Form)); poco_assert_dbg (pRenderable->type() == typeid(Poco::WebWidgets::Form));
const Form* pForm = static_cast<const Poco::WebWidgets::Form*>(pRenderable); const Form* pForm = static_cast<const Poco::WebWidgets::Form*>(pRenderable);
WebApplication& theApp = WebApplication::instance();
theApp.beginForm(*pForm);
ostr << "new Ext.FormPanel({id:'" << pForm->id() << "',"; ostr << "new Ext.FormPanel({id:'" << pForm->id() << "',";
//ostr << "onSubmit:Ext.emptyFn,submit:function(){this.getEl().dom.submit();},"; //ostr << "onSubmit:Ext.emptyFn,submit:function(){this.getEl().dom.submit();},";
@ -80,7 +82,7 @@ void FormRenderer::renderHead(const Renderable* pRenderable, const RenderContext
} }
ostr << "]})"; ostr << "]})";
//ostr << varName << ".render('p" << pForm->id() << "');"; theApp.endForm(*pForm);
} }

View File

@ -48,13 +48,16 @@
#include "Poco/ThreadLocal.h" #include "Poco/ThreadLocal.h"
#include "Poco/URI.h" #include "Poco/URI.h"
#include <map> #include <map>
#include <stack>
namespace Poco { namespace Poco {
namespace Net { namespace Net {
class HTMLForm; class HTMLForm;
class HTTPServerRequest; class HTTPServerRequest;
} }
namespace WebWidgets { namespace WebWidgets {
@ -90,13 +93,20 @@ public:
ResourceManager::Ptr getResourceManager() const; ResourceManager::Ptr getResourceManager() const;
/// Gets the ResourceManager /// Gets the ResourceManager
void beginForm(const Form& form);
// Notifies the WebApplication that a form starts
void registerFormProcessor(const std::string& fieldName, RequestProcessor* pProc); void registerFormProcessor(const std::string& fieldName, RequestProcessor* pProc);
/// Registers a RequestProcessor for a given form field. /// Registers a RequestProcessor for a given form field.
/// beginForm should have been called soemtimes earlier
void endForm(const Form& form);
/// Closes the form
void handleForm(const Poco::Net::HTMLForm& form); void handleForm(const Poco::Net::HTMLForm& form);
///Handles a form ///Handles a form. beginForm must be called earlier
RequestProcessor* getFormProcessor(const std::string& fieldName); RequestProcessor* getFormProcessor(Renderable::ID formId, const std::string& fieldName);
/// Returns the requestprocessor or null /// Returns the requestprocessor or null
void registerAjaxProcessor(const std::string& id, RequestProcessor* pProc); void registerAjaxProcessor(const std::string& id, RequestProcessor* pProc);
@ -123,8 +133,6 @@ public:
/// triggers the click event of the submitbutton /// triggers the click event of the submitbutton
/// required because click event and POST happens in parallel /// required because click event and POST happens in parallel
/// and we want click to be triggered after POST /// and we want click to be triggered after POST
private:
static Form::Ptr insideForm(const View* pChild);
private: private:
WebApplication(const WebApplication&); WebApplication(const WebApplication&);
@ -132,12 +140,15 @@ private:
typedef std::map<std::string, RequestProcessor* > RequestProcessorMap; typedef std::map<std::string, RequestProcessor* > RequestProcessorMap;
typedef std::map<Renderable::ID, SubmitButtonCell*> SubmitButtons; typedef std::map<Renderable::ID, SubmitButtonCell*> SubmitButtons;
typedef std::map<Renderable::ID, RequestProcessorMap> FormMap;
typedef std::stack<Renderable::ID> OpenForms;
ResourceManager::Ptr _pResource; ResourceManager::Ptr _pResource;
LookAndFeel::Ptr _pLookAndFeel; LookAndFeel::Ptr _pLookAndFeel;
Page::Ptr _pCurrentPage; Page::Ptr _pCurrentPage;
Poco::URI _uri; Poco::URI _uri;
RequestProcessorMap _requestProcessorMap; FormMap _formMap;
OpenForms _forms;
RequestProcessorMap _ajaxProcessorMap; RequestProcessorMap _ajaxProcessorMap;
SubmitButtons _submitButtons; SubmitButtons _submitButtons;
static Poco::ThreadLocal<WebApplication*> _pInstance; static Poco::ThreadLocal<WebApplication*> _pInstance;

View File

@ -41,6 +41,7 @@
#include "Poco/Net/HTMLForm.h" #include "Poco/Net/HTMLForm.h"
#include "Poco/Net/HTTPServerRequest.h" #include "Poco/Net/HTTPServerRequest.h"
#include "Poco/NumberFormatter.h" #include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
namespace Poco { namespace Poco {
@ -77,8 +78,11 @@ void WebApplication::setLookAndFeel(LookAndFeel::Ptr pLookAndFeel)
void WebApplication::setCurrentPage(Page::Ptr pPage) void WebApplication::setCurrentPage(Page::Ptr pPage)
{ {
_pCurrentPage = pPage; _pCurrentPage = pPage;
_requestProcessorMap.clear(); _formMap.clear();
_ajaxProcessorMap.clear(); _ajaxProcessorMap.clear();
_submitButtons.clear();
while (!_forms.empty())
_forms.pop();
} }
@ -103,32 +107,58 @@ std::string WebApplication::clientHostName()
} }
void WebApplication::registerFormProcessor(const std::string& fieldName, RequestProcessor* pProc) void WebApplication::beginForm(const Form& form)
{ {
std::pair<RequestProcessorMap::iterator, bool> res = _requestProcessorMap.insert(std::make_pair(fieldName, pProc)); if (!_forms.empty())
if (!res.second) throw WebWidgetsException("nested forms not allowed");
res.first->second = pProc; _forms.push(form.id());
_formMap.insert(std::make_pair(form.id(), RequestProcessorMap()));
} }
RequestProcessor* WebApplication::getFormProcessor(const std::string& fieldName) void WebApplication::registerFormProcessor(const std::string& fieldName, RequestProcessor* pProc)
{ {
RequestProcessorMap::iterator it = _requestProcessorMap.find(fieldName); // per default we register everyting that has a name as form processor
if (it == _requestProcessorMap.end()) if (!_forms.empty())
{
FormMap::iterator itForm = _formMap.find(_forms.top());
poco_assert (itForm != _formMap.end());
std::pair<RequestProcessorMap::iterator, bool> res = itForm->second.insert(std::make_pair(fieldName, pProc));
if (!res.second)
res.first->second = pProc;
}
}
RequestProcessor* WebApplication::getFormProcessor(Renderable::ID formId, const std::string& fieldName)
{
FormMap::iterator itForm = _formMap.find(formId);
if (itForm == _formMap.end())
return 0;
RequestProcessorMap::iterator it = itForm->second.find(fieldName);
if (it == itForm->second.end())
return 0; return 0;
return it->second; return it->second;
} }
void WebApplication::endForm(const Form& form)
{
poco_assert_dbg (_forms.size() == 1);
poco_assert_dbg (_forms.top() == form.id());
_forms.pop();
}
void WebApplication::registerAjaxProcessor(const std::string& id, RequestProcessor* pProc) void WebApplication::registerAjaxProcessor(const std::string& id, RequestProcessor* pProc)
{ {
SubmitButtonCell* pCell = dynamic_cast<SubmitButtonCell*>(pProc); SubmitButtonCell* pCell = dynamic_cast<SubmitButtonCell*>(pProc);
if (pCell) if (pCell)
{ {
Form::Ptr pForm = insideForm(pCell->getOwner()); if (_forms.empty())
if (!pForm)
throw Poco::WebWidgets::WebWidgetsException("submitButton without outer Form detected"); throw Poco::WebWidgets::WebWidgetsException("submitButton without outer Form detected");
std::pair<SubmitButtons::iterator, bool> res = _submitButtons.insert(std::make_pair(pForm->id(), pCell)); std::pair<SubmitButtons::iterator, bool> res = _submitButtons.insert(std::make_pair(_forms.top(), pCell));
if (!res.second) if (!res.second)
res.first->second = pCell; res.first->second = pCell;
} }
@ -149,25 +179,31 @@ RequestProcessor* WebApplication::getAjaxProcessor(const std::string& id)
void WebApplication::handleForm(const Poco::Net::HTMLForm& form) void WebApplication::handleForm(const Poco::Net::HTMLForm& form)
{ {
Renderable::ID formID = Poco::NumberParser::parse(form.get(Form::FORM_ID));
FormMap::iterator itForm = _formMap.find(formID);
if (itForm == _formMap.end())
throw Poco::NotFoundException("unknown form id");
Poco::Net::NameValueCollection::ConstIterator it = form.begin(); Poco::Net::NameValueCollection::ConstIterator it = form.begin();
RequestProcessorMap& processors = itForm->second;
for (;it != form.end(); ++it) for (;it != form.end(); ++it)
{ {
const std::string& key = it->first; const std::string& key = it->first;
RequestProcessorMap::iterator itR = _requestProcessorMap.find(key); RequestProcessorMap::iterator itR = processors.find(key);
if (itR != _requestProcessorMap.end()) if (itR != processors.end())
{ {
itR->second->handleForm(key, it->second); itR->second->handleForm(key, it->second);
_requestProcessorMap.erase(itR); processors.erase(itR);
} }
} }
//those that are not included are either deselected or empty //those that are not included are either deselected or empty
RequestProcessorMap::iterator itR = _requestProcessorMap.begin(); RequestProcessorMap::iterator itR = processors.begin();
std::string empty; std::string empty;
for (; itR != _requestProcessorMap.end(); ++itR) for (; itR != processors.end(); ++itR)
{ {
itR->second->handleForm(itR->first, empty); itR->second->handleForm(itR->first, empty);
} }
_requestProcessorMap.clear(); processors.clear();
} }
@ -182,20 +218,4 @@ void WebApplication::notifySubmitButton(Renderable::ID id)
} }
Form::Ptr WebApplication::insideForm(const View* pChild)
{
Form::Ptr ptr;
while (pChild && !ptr)
{
View::Ptr ptrView = pChild->parent();
ptr = ptrView.cast<Form>();
pChild = ptrView;
}
return ptr;
}
} } // namespace Poco::WebWidgets } } // namespace Poco::WebWidgets