refactored JSEvents for easier server callbacks

This commit is contained in:
Peter Schojer 2008-06-09 09:09:02 +00:00
parent db640711d1
commit 515c64faea
15 changed files with 323 additions and 77 deletions

View File

@ -41,6 +41,7 @@
#include "Poco/WebWidgets/ExtJS/CellRenderer.h"
#include "Poco/WebWidgets/JSDelegate.h"
namespace Poco {
@ -75,13 +76,15 @@ public:
static void renderButton(const ButtonCell* pCell, const std::string& content, bool writeId, bool submitButton, std::ostream& ostr, bool showText = true);
/// Renders button properties
static void addClickServerCallback(Button* pCombo, const std::string& onSuccess="", const std::string& onFailure="");
static Poco::WebWidgets::JSDelegate createClickServerCallback(const Button* pCombo);
/// Adds a server callback for the buttonClicked event. The JS method signature for click is
/// click : ( Button this, EventObject e )
protected:
virtual ~ButtonCellRenderer();
/// Destroys the ButtonCellRenderer.
};

View File

@ -42,6 +42,7 @@
#include "Poco/WebWidgets/ExtJS/ExtJS.h"
#include "Poco/WebWidgets/Renderer.h"
#include "Poco/WebWidgets/JSDelegate.h"
#include "Poco/Net/HTTPServerResponse.h"
@ -72,14 +73,14 @@ public:
void renderBody(const Renderable* pRenderable, const RenderContext& context, std::ostream& ostr);
/// Emits code for the page body to the given output stream.
static void addSelectedServerCallback(ComboBox* pCombo, const std::string& onSuccess, const std::string& onFailure);
/// Adds a server callback for the selected event. The method signature for select is
/// select : ( Ext.form.ComboBox combo, Ext.data.Record record, Number index )
private:
static void onLoad(void* pSender, Poco::Net::HTTPServerResponse* &pResponse);
static void serialize(const ComboBoxCell* pCell, std::ostream& out);
static Poco::WebWidgets::JSDelegate createSelectedServerCallback(const ComboBox* pCombo);
/// Adds a server callback for the selected event. The method signature for select is
/// select : ( Ext.form.ComboBox combo, Ext.data.Record record, Number index )
};

View File

@ -41,11 +41,15 @@
#include "Poco/WebWidgets/ExtJS/ExtJS.h"
#include "Poco/WebWidgets/JSDelegate.h"
#include "Poco/WebWidgets/Renderer.h"
namespace Poco {
namespace WebWidgets {
class Page;
namespace ExtJS {
@ -67,6 +71,14 @@ public:
void renderBody(const Renderable* pRenderable, const RenderContext& context, std::ostream& ostr);
/// Emits code for the page body to the given output stream.
protected:
static Poco::WebWidgets::JSDelegate createBeforeRenderCallback(const Page* pPage);
/// JS signature: beforerender : ( Ext.Component this )
static Poco::WebWidgets::JSDelegate createAfterRenderCallback(const Page* pPage);
/// JS signature: show : ( Ext.Component this )
};

View File

@ -79,24 +79,6 @@ public:
void renderBody(const Renderable* pRenderable, const RenderContext& context, std::ostream& ostr);
/// Emits code for the page body to the given output stream.
static void addCellValueChangedServerCallback(Table* pTable, const std::string& onSuccess=std::string(), const std::string& onFailure=std::string());
/// Adds a javascript callback to inform the WebServer that the client has changed a value in the Table
/// The Extjs handler offers a method signature of "function(obj)" where obj is a complex element containing members (column, row, value)
static void addCellClickedServerCallback(Table* pTable, const std::string& onSuccess=std::string(), const std::string& onFailure=std::string());
/// Adds a javascript callback to inform the WebServer that the client has clicked on a cell in the Table
/// Method signature is cellclick : ( Grid this, Number rowIndex, Number columnIndex, Ext.EventObject e )
static void addRowClickedServerCallback(Table* pTable, const std::string& onSuccess=std::string(), const std::string& onFailure=std::string());
/// Adds a javascript callback to inform the WebServer that the client has clicke don a row
/// This event will only be added if the Table uses a Row selection model!
/// Single cell selection will trigger an exception!
/// Method signature is rowselect : ( SelectionModel this, Number rowIndex, Ext.Data.Record r )
static void addAfterLoadServerCallback(Table* pTable, const std::string& onSuccess=std::string(), const std::string& onFailure=std::string());
/// Adds a javascript callback to inform the WebServer that the client has finished loading data
/// Method signature is ( Store this, Ext.data.Record[] records, Object options )
protected:
static void renderProperties(const Table* pTable, const RenderContext& context, std::ostream& ostr);
@ -112,6 +94,24 @@ protected:
/// Renders the data store of the table
static void onBeforeLoad(void* pSender, Table::LoadData& ld);
static Poco::WebWidgets::JSDelegate createCellValueChangedServerCallback(const Table* pTable);
/// Adds a javascript callback to inform the WebServer that the client has changed a value in the Table
/// The Extjs handler offers a method signature of "function(obj)" where obj is a complex element containing members (column, row, value)
static Poco::WebWidgets::JSDelegate createCellClickedServerCallback(const Table* pTable);
/// Adds a javascript callback to inform the WebServer that the client has clicked on a cell in the Table
/// Method signature is cellclick : ( Grid this, Number rowIndex, Number columnIndex, Ext.EventObject e )
static Poco::WebWidgets::JSDelegate createRowClickedServerCallback(const Table* pTable);
/// Adds a javascript callback to inform the WebServer that the client has clicke don a row
/// This event will only be added if the Table uses a Row selection model!
/// Single cell selection will trigger an exception!
/// Method signature is rowselect : ( SelectionModel this, Number rowIndex, Ext.Data.Record r )
static Poco::WebWidgets::JSDelegate createAfterLoadServerCallback(const Table* pTable);
/// Adds a javascript callback to inform the WebServer that the client has finished loading data
/// Method signature is ( Store this, Ext.data.Record[] records, Object options )
};

View File

@ -109,6 +109,8 @@ public:
/// writes all JS Delegates for a single named JSEvent.
/// Returns true if data was written, false if no delegates were present and no event handler was written.
static bool writeJSEvent(std::ostream& out, const std::string& eventName, const std::list<JSDelegate>& delegates, const Poco::WebWidgets::JSDelegate& serverCallback, std::size_t serverCallPos);
/// writes all JS Delegates for a single named JSEvent. plus the server callbacb, Always returns true.
static std::string createURI(const std::map<std::string, std::string>& addParams, Renderable::ID id);
/// Creates the url from the function parameters, adds the id parameter automatically
@ -141,6 +143,13 @@ public:
ev.add(jsDelegate(code));
}
static Poco::WebWidgets::JSDelegate createServerCallback(
const std::string& signature,
const std::map<std::string, std::string>& addServerParams,
Renderable::ID id,
const std::string& onSuccessJS,
const std::string& onFailureJS);
private:
static void convertPocoDateToPHPDate(char in, std::string& result);

View File

@ -91,25 +91,33 @@ void ButtonCellRenderer::renderProperties(const ButtonCell* pButtonCell, const s
Form::Ptr pForm = Utility::insideForm(pButtonCell);
ostr << "handler: function(){Ext.getCmp('" << pForm->id() << "').getForm().submit();},";
}
Button* pOwner = dynamic_cast<Button*>(pButtonCell->getOwner());
poco_check_ptr (pOwner);
View* pView = pButtonCell->getOwner();
poco_check_ptr (pView);
Button* pOwner = dynamic_cast<Button*>(pView);
// a buttoncell inside a table will have no parent of type button!
if (writeId)
Utility::writeRenderableProperties(pOwner, ostr);
Utility::writeRenderableProperties(pView, ostr);
if (!pButtonCell->isEnabled())
ostr << ",disabled:true";
if (!pView->getName().empty())
ostr << ",name:'" << pOwner->getName() << "'";
if (pView->getWidth() != 0)
ostr << ",minWidth:" << pOwner->getWidth();
if (!pView->isVisible())
ostr << ",hidden:true";
if (pOwner)
{
if (!pOwner->getName().empty())
ostr << ",name:'" << pOwner->getName() << "'";
if (pOwner->getWidth() != 0)
ostr << ",minWidth:" << pOwner->getWidth();
if (!pOwner->isVisible())
ostr << ",hidden:true";
if (!pOwner->buttonClicked.jsDelegates().empty())
if (pOwner->buttonClicked.hasJavaScriptCode())
{
ostr << ",listeners:{";
Utility::writeJSEvent(ostr, EV_CLICK, pOwner->buttonClicked.jsDelegates());
if (pOwner->buttonClicked.willDoServerCallback())
Utility::writeJSEvent(ostr, EV_CLICK, pOwner->buttonClicked.jsDelegates(),
createClickServerCallback(pOwner), pOwner->buttonClicked.getServerCallbackPos());
else
Utility::writeJSEvent(ostr, EV_CLICK, pOwner->buttonClicked.jsDelegates());
ostr << "}";
}
}
@ -120,7 +128,7 @@ void ButtonCellRenderer::renderProperties(const ButtonCell* pButtonCell, const s
if (!toolTip.empty())
ostr << ",tooltip:'" << Utility::safe(toolTip) << "'";
WebApplication::instance().registerAjaxProcessor(Poco::NumberFormatter::format(pButtonCell->id()), const_cast<ButtonCell*>(pButtonCell));
WebApplication::instance().registerAjaxProcessor(Poco::NumberFormatter::format(pView->id()), const_cast<ButtonCell*>(pButtonCell));
}
@ -139,13 +147,13 @@ void ButtonCellRenderer::writeConfigData(const Cell* pCell, const RenderContext&
void ButtonCellRenderer::addClickServerCallback(Button* pButton, const std::string& onSuccess, const std::string& onFailure)
JSDelegate ButtonCellRenderer::createClickServerCallback(const Button* pButton)
{
//click : ( Button this, EventObject e )
static const std::string signature("function(but,e)");
std::map<std::string, std::string> addParams;
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, ButtonCell::EV_BUTTONCLICKED));
Utility::addServerCallback(pButton->buttonClicked, signature, addParams, pButton->getCell()->id(), onSuccess, onFailure);
return Utility::createServerCallback(signature, addParams, pButton->id(), pButton->buttonClicked.getOnSuccess(), pButton->buttonClicked.getOnFailure());
}

View File

@ -65,14 +65,14 @@ ComboBoxCellRenderer::~ComboBoxCellRenderer()
}
void ComboBoxCellRenderer::addSelectedServerCallback(ComboBox* pCombo, const std::string& onSuccess, const std::string& onFailure)
JSDelegate ComboBoxCellRenderer::createSelectedServerCallback(const ComboBox* pCombo)
{
//select : ( Ext.form.ComboBox combo, Ext.data.Record record, Number index )
static const std::string signature("function(combo,rec,idx)");
std::map<std::string, std::string> addParams;
addParams.insert(std::make_pair(ComboBoxCell::FIELD_VAL, "+rec.get('d')"));
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, ComboBoxCell::EV_SELECTED));
Utility::addServerCallback(pCombo->selected, signature, addParams, pCombo->id(), onSuccess, onFailure);
return Utility::createServerCallback(signature, addParams, pCombo->id(), pCombo->selected.getOnSuccess(), pCombo->selected.getOnFailure());
}
@ -100,10 +100,13 @@ void ComboBoxCellRenderer::renderHead(const Renderable* pRenderable, const Rende
std::string tooltip (pCell->getToolTip());
if (pComboOwner && !pComboOwner->selected.jsDelegates().empty())
if (pComboOwner && pComboOwner->selected.hasJavaScriptCode())
{
ostr << ",listeners:{";
Utility::writeJSEvent(ostr, EV_SELECTED, pComboOwner->selected.jsDelegates());
if (pComboOwner->selected.willDoServerCallback())
Utility::writeJSEvent(ostr, EV_SELECTED, pComboOwner->selected.jsDelegates(), createSelectedServerCallback(pComboOwner), pComboOwner->selected.getServerCallbackPos());
else
Utility::writeJSEvent(ostr, EV_SELECTED, pComboOwner->selected.jsDelegates());
if (!tooltip.empty())
ostr << ",render:function(c){Ext.QuickTips.register({target:c.getEl(),text:'" << Utility::safe(tooltip) << "'});}";
ostr << "}";

View File

@ -40,6 +40,7 @@
#include "Poco/WebWidgets/RenderContext.h"
#include "Poco/WebWidgets/LookAndFeel.h"
#include "Poco/WebWidgets/WebApplication.h"
#include "Poco/WebWidgets/RequestHandler.h"
namespace Poco {
@ -125,14 +126,20 @@ void PageRenderer::renderHead(const Renderable* pRenderable, const RenderContext
// always nest a panel around, so we can get rid of dynamic casts to check for parent type
ostr << "new Ext.Panel({renderTo:'p" << pPage->id() << "',border:false,bodyBorder:false";
if (!pPage->beforeRender.jsDelegates().empty() || !pPage->afterRender.jsDelegates().empty())
if (pPage->beforeRender.hasJavaScriptCode() || pPage->afterRender.hasJavaScriptCode())
{
ostr << ",listeners:{";
bool written = Utility::writeJSEvent(ostr, EV_BEFORERENDER, pPage->beforeRender.jsDelegates());
bool written = false;
if (pPage->beforeRender.willDoServerCallback())
written = Utility::writeJSEvent(ostr, EV_BEFORERENDER, pPage->beforeRender.jsDelegates(), createBeforeRenderCallback(pPage), pPage->beforeRender.getServerCallbackPos());
else
written = Utility::writeJSEvent(ostr, EV_BEFORERENDER, pPage->beforeRender.jsDelegates());
if (written)
ostr << ",";
Utility::writeJSEvent(ostr, EV_AFTERRENDER, pPage->afterRender.jsDelegates());
if (pPage->afterRender.willDoServerCallback())
Utility::writeJSEvent(ostr, EV_AFTERRENDER, pPage->afterRender.jsDelegates(), createAfterRenderCallback(pPage), pPage->afterRender.getServerCallbackPos());
else
Utility::writeJSEvent(ostr, EV_AFTERRENDER, pPage->afterRender.jsDelegates());
ostr << "}";
}
if (pPage->getHeight() > 0)
@ -190,4 +197,24 @@ void PageRenderer::renderBody(const Renderable* pRenderable, const RenderContext
}
Poco::WebWidgets::JSDelegate PageRenderer::createBeforeRenderCallback(const Page* pPage)
{
// JS signature: beforerender : ( Ext.Component this )
static const std::string signature("function(p)");
std::map<std::string, std::string> addParams;
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, Page::EV_BEFORERENDER));
return Utility::createServerCallback(signature, addParams, pPage->id(), pPage->beforeRender.getOnSuccess(), pPage->beforeRender.getOnFailure());
}
Poco::WebWidgets::JSDelegate PageRenderer::createAfterRenderCallback(const Page* pPage)
{
// JS signature: show : ( Ext.Component this )
static const std::string signature("function(p)");
std::map<std::string, std::string> addParams;
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, Page::EV_AFTERRENDER));
return Utility::createServerCallback(signature, addParams, pPage->id(), pPage->afterRender.getOnSuccess(), pPage->afterRender.getOnFailure());
}
} } } // namespace Poco::WebWidgets::ExtJS

View File

@ -99,9 +99,8 @@ void TableRenderer::renderBody(const Renderable* pRenderable, const RenderContex
}
void TableRenderer::addCellValueChangedServerCallback(Table* pTable, const std::string& onSuccess, const std::string& onFailure)
Poco::WebWidgets::JSDelegate TableRenderer::createCellValueChangedServerCallback(const Table* pTable)
{
poco_check_ptr (pTable);
static const std::string signature("function(obj)");
//extract the true row index from the last column!
std::string origRow("+obj.record.get('");
@ -112,28 +111,27 @@ void TableRenderer::addCellValueChangedServerCallback(Table* pTable, const std::
addParams.insert(std::make_pair(Table::FIELD_ROW, origRow));
//problem: I need the displayed string from teh renderer, not the value!
// date fields cause problems here, and I only habe one cellclick event per table not per column!
// from the tabel get the TableCOlumn, from thsi get the renderer for the given col and render obj.value
// from the table get the TableColumn, from this get the renderer for the given col and render obj.value
// {(var r=obj.grid.getColumnModel().getRenderer(obj.column))?r(obj.value);:obj.value;}, hm renderer exists for everthing
addParams.insert(std::make_pair(Table::FIELD_VAL, "+obj.grid.getColumnModel().getRenderer(obj.column)(obj.value)"));
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, Table::EV_CELLVALUECHANGED));
Utility::addServerCallback(pTable->cellValueChanged, signature, addParams, pTable->id(), onSuccess, onFailure);
pTable->cellValueChanged.add(jsDelegate("function(obj){obj.grid.getStore().commitChanges();}"));
const std::string& success = pTable->cellValueChanged.getOnSuccess();
return Utility::createServerCallback(signature, addParams, pTable->id(), pTable->cellValueChanged.getOnSuccess(), pTable->cellValueChanged.getOnFailure());
}
void TableRenderer::addAfterLoadServerCallback(Table* pTable, const std::string& onSuccess, const std::string& onFailure)
Poco::WebWidgets::JSDelegate TableRenderer::createAfterLoadServerCallback(const Table* pTable)
{
poco_check_ptr (pTable);
static const std::string signature("function(aStore, recs, op)");
std::map<std::string, std::string> addParams;
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, Table::EV_AFTERLOAD));
Utility::addServerCallback(pTable->afterLoad, signature, addParams, pTable->id(), onSuccess, onFailure);
return Utility::createServerCallback(signature, addParams, pTable->id(), pTable->afterLoad.getOnSuccess(), pTable->afterLoad.getOnFailure());
}
void TableRenderer::addCellClickedServerCallback(Table* pTable, const std::string& onSuccess, const std::string& onFailure)
Poco::WebWidgets::JSDelegate TableRenderer::createCellClickedServerCallback(const Table* pTable)
{
poco_check_ptr (pTable);
static const std::string signature("function(theGrid,row,col,e)");
@ -145,12 +143,11 @@ void TableRenderer::addCellClickedServerCallback(Table* pTable, const std::strin
addParams.insert(std::make_pair(Table::FIELD_COL, "+col"));
addParams.insert(std::make_pair(Table::FIELD_ROW, origRow));
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, Table::EV_CELLCLICKED));
Utility::addServerCallback(pTable->cellClicked, signature, addParams, pTable->id(), onSuccess, onFailure);
return Utility::createServerCallback(signature, addParams, pTable->id(), pTable->cellClicked.getOnSuccess(), pTable->cellClicked.getOnFailure());
}
void TableRenderer::addRowClickedServerCallback(Table* pTable, const std::string& onSuccess, const std::string& onFailure)
Poco::WebWidgets::JSDelegate TableRenderer::createRowClickedServerCallback(const Table* pTable)
{
poco_check_ptr (pTable);
poco_assert (pTable->getSelectionModel() != Table::SM_CELL);
@ -164,7 +161,7 @@ void TableRenderer::addRowClickedServerCallback(Table* pTable, const std::string
std::map<std::string, std::string> addParams;
addParams.insert(std::make_pair(Table::FIELD_ROW, origRow));
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, Table::EV_ROWCLICKED));
Utility::addServerCallback(pTable->rowClicked, signature, addParams, pTable->id(), onSuccess, onFailure);
return Utility::createServerCallback(signature, addParams, pTable->id(), pTable->rowClicked.getOnSuccess(), pTable->rowClicked.getOnFailure());
}
@ -183,11 +180,26 @@ void TableRenderer::renderProperties(const Table* pTable, const RenderContext& c
ostr << ",listeners:{";
bool written = false;
if (editable)
written = Utility::writeJSEvent(ostr, EV_AFTEREDIT, pTable->cellValueChanged.jsDelegates());
{
JSDelegate jsDel("function(obj){obj.grid.getStore().commitChanges();}");
std::list<JSDelegate> modList(pTable->cellValueChanged.jsDelegates());
modList.push_back(jsDel);
if (pTable->cellValueChanged.willDoServerCallback())
written = Utility::writeJSEvent(ostr, EV_AFTEREDIT, modList,
TableRenderer::createCellValueChangedServerCallback(pTable),
pTable->cellValueChanged.getServerCallbackPos());
else
written = Utility::writeJSEvent(ostr, EV_AFTEREDIT, modList);
}
if (written)
ostr << ",";
written = Utility::writeJSEvent(ostr, EV_CELLCLICKED, pTable->cellClicked.jsDelegates());
if (pTable->cellClicked.willDoServerCallback())
written = Utility::writeJSEvent(ostr, EV_CELLCLICKED, pTable->cellClicked.jsDelegates(),
TableRenderer::createCellClickedServerCallback(pTable),
pTable->cellClicked.getServerCallbackPos());
else
written = Utility::writeJSEvent(ostr, EV_CELLCLICKED, pTable->cellClicked.jsDelegates());
@ -203,10 +215,15 @@ void TableRenderer::renderProperties(const Table* pTable, const RenderContext& c
ostr << ",selModel:new Ext.grid.RowSelectionModel({singleSelect:true";
else if (pTable->getSelectionModel() == Table::SM_MULTIROW)
ostr << ",selModel:new Ext.grid.RowSelectionModel({singleSelect:false";
if (!pTable->rowClicked.jsDelegates().empty())
if (pTable->rowClicked.hasJavaScriptCode())
{
ostr << ",listeners:{";
Utility::writeJSEvent(ostr, EV_ROWCLICKED, pTable->rowClicked.jsDelegates());
if (pTable->rowClicked.willDoServerCallback())
Utility::writeJSEvent(ostr, EV_ROWCLICKED, pTable->rowClicked.jsDelegates(),
TableRenderer::createRowClickedServerCallback(pTable),
pTable->rowClicked.getServerCallbackPos());
else
Utility::writeJSEvent(ostr, EV_ROWCLICKED, pTable->rowClicked.jsDelegates());
ostr << "}";
}
ostr << "})"; //close selModel
@ -334,9 +351,16 @@ void TableRenderer::renderStore(const Table* pTable, std::ostream& ostr)
std::string url(Utility::createURI(addParams, pTable->id()));
ostr << url << "}),";
ostr << "reader:new Ext.data.ArrayReader()";
ostr << ",listeners:{";
Utility::writeJSEvent(ostr, EV_AFTERLOAD, pTable->afterLoad.jsDelegates());
ostr << "}";
if (pTable->afterLoad.hasJavaScriptCode())
{
ostr << ",listeners:{";
if (pTable->afterLoad.willDoServerCallback())
Utility::writeJSEvent(ostr, EV_AFTERLOAD, pTable->afterLoad.jsDelegates(), createAfterLoadServerCallback(pTable), pTable->afterLoad.getServerCallbackPos());
else
Utility::writeJSEvent(ostr, EV_AFTERLOAD, pTable->afterLoad.jsDelegates());
ostr << "}";
}
ostr << "})";
}

View File

@ -479,6 +479,27 @@ bool Utility::writeJSEvent(std::ostream& out, const std::string& eventName, cons
}
bool Utility::writeJSEvent(std::ostream& out, const std::string& eventName, const std::list<JSDelegate>& delegates, const Poco::WebWidgets::JSDelegate& serverCallback, std::size_t serverCallPos)
{
// TODO: we can optimize here a bit by avoiding the copy
std::list<JSDelegate> dels;
std::list<JSDelegate>::const_iterator it = dels.begin();
bool written = false;
for (; it != dels.end(); ++it, --serverCallPos)
{
if (serverCallPos == 0)
{
dels.push_back(serverCallback);
written = true;
}
dels.push_back(*it);
}
if (!written)
dels.push_back(serverCallback);
return writeJSEvent(out, eventName, dels);
}
void Utility::writeFunction(std::ostream& out, const std::string& fctName, const std::vector<std::string> &params, const std::string& code)
{
out << fctName << "(";
@ -583,6 +604,18 @@ std::string Utility::createCallbackFunctionCode(const std::string& signature, co
}
Poco::WebWidgets::JSDelegate Utility::createServerCallback(
const std::string& signature,
const std::map<std::string, std::string>& addServerParams,
Renderable::ID id,
const std::string& onSuccessJS,
const std::string& onFailureJS)
{
std::string code(createCallbackFunctionCode(signature, addServerParams, id, onSuccessJS, onFailureJS));
return (jsDelegate(code));
}
int Utility::detectMaxParamCount(const std::list<JSDelegate>& delegates)
{
int cnt = 0;

View File

@ -63,6 +63,9 @@ public:
bool operator<(const JSDelegate& del) const;
bool operator ==(const JSDelegate& del) const;
bool operator !=(const JSDelegate& del) const;
private:
std::string _jsCode;
@ -75,12 +78,24 @@ inline const std::string& JSDelegate::jsCode() const
}
inline bool JSDelegate::operator<(const JSDelegate& del) const
{
return (_jsCode < del._jsCode);
}
inline bool JSDelegate::operator ==(const JSDelegate& del) const
{
return jsCode() == del.jsCode();
}
inline bool JSDelegate::operator !=(const JSDelegate& del) const
{
return jsCode() != del.jsCode();
}
static JSDelegate jsDelegate(const std::string& jsCode);

View File

@ -53,6 +53,14 @@ namespace Poco {
namespace WebWidgets {
enum ServerCallback
{
SC_NO = 0,
SC_YES,
SC_ONLOCALHANDLERS
};
template <class TArgs>
class JavaScriptEvent: public Poco::AbstractEvent <
TArgs, Poco::DefaultStrategy<TArgs, Poco::AbstractDelegate<TArgs>, Poco::p_less<Poco::AbstractDelegate<TArgs> > >,
@ -61,11 +69,17 @@ class JavaScriptEvent: public Poco::AbstractEvent <
/// Event class used to handle JavaScriptEvents. Allows to register two different types
/// of delegates. The standard delegates, as known from Poco::BasicEvent and JSDelegates
/// which will be embedded into the WebPage when the Parser generates the site.
/// Per default a server callback happens only when local listeners are registered.
{
public:
typedef typename std::list<JSDelegate> JSDelegates;
JavaScriptEvent()
JavaScriptEvent():
_jsHandlers(),
_serverCallback(SC_ONLOCALHANDLERS),
_callbackPos(0),
_onSuccess(),
_onFailure()
/// Creates the JavaScriptEvent.
{
}
@ -113,9 +127,73 @@ public:
{
_jsHandlers = all;
}
void setServerCallback(ServerCallback sc, const std::string& onSuccess = "", const std::string& onFailure = "")
/// Sets the server callback. onSuccess and onFailure must either be a JavaScript function pointer or a complete
/// anonymous function. The server callback position will be set after the currently defined jsHandlers.
/// If you want to set the server callback as the very first jsHandler, call setServerCallback before
/// any event->add.
/// Note that with most renderers you should not worry about the position of the server callback due to its
/// asynchronous nature! If you require to execute JS code after the server callback, you must use onSuccess or
/// onFailure!
{
FastMutex::ScopedLock lock(this->_mutex);
_serverCallback = sc;
_callbackPos = _jsHandlers.size();
_onSuccess = onSuccess;
_onFailure = onFailure;
}
bool willDoServerCallback() const
/// Checks if servercallback is set to true or to DEPENDS and if localHandlers exist
{
return (_serverCallback == SC_YES || (_serverCallback == SC_ONLOCALHANDLERS && hasLocalHandlers()));
}
ServerCallback getServerCallback() const
/// Returns the server callback value
{
return _serverCallback;
}
std::size_t getServerCallbackPos() const
/// Returns how many jsHandlers are executed before the serverCallback
{
return _callbackPos;
}
void setServerCallbackPos(std::size_t pos) const
/// Sets how many jsHandlers are executed before the serverCallback. Set to 0 to guarantee that the server callback is the first
{
_callbackPos = pos;
}
const std::string& getOnSuccess() const
/// Returns the onSuccess value
{
return _onSuccess;
}
const std::string& getOnFailure() const
/// Returns the onFailure value
{
return _onFailure;
}
bool hasJavaScriptCode() const
/// Returns true if any JSCode (incl, the server callback) is attached to this event
{
return (willDoServerCallback() || !_jsHandlers.empty());
}
private:
JSDelegates _jsHandlers;
JSDelegates _jsHandlers;
ServerCallback _serverCallback; /// Set to SC_YES if a server callback should be done always
std::size_t _callbackPos; /// Sets when the server callback should happen (the number defines how many jsHandlers are executed before the server callback)
std::string _onSuccess; /// code to execute when the server callback succeeds
std::string _onFailure; /// code to execute when the server callback fails
};

View File

@ -43,18 +43,23 @@
#include "Poco/WebWidgets/ContainerView.h"
#include "Poco/WebWidgets/JavaScriptEvent.h"
#include "Poco/WebWidgets/ResourceManager.h"
#include "Poco/WebWidgets/RequestProcessor.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Net/HTTPServerResponse.h"
namespace Poco {
namespace WebWidgets {
class WebWidgets_API Page: public ContainerView
class WebWidgets_API Page: public ContainerView, public RequestProcessor
/// A Page displays a HTML Page
{
public:
typedef Poco::AutoPtr<Page> Ptr;
static const std::string EV_BEFORERENDER;
static const std::string EV_AFTERRENDER;
JavaScriptEvent<Page*> beforeRender;
/// event thrown before GUI rendering.
@ -77,6 +82,12 @@ public:
const ResourceManager& resourceManager() const;
/// Returns the ResourceManager
void handleAjaxRequest(const Poco::Net::NameValueCollection& args, Poco::Net::HTTPServerResponse& response);
/// Handles a complete AJAX request submitted by the client.
void handleForm(const std::string& field, const std::string& value);
/// Dummy implementation
protected:
Page(const std::string& name, const std::type_info& type);
@ -110,6 +121,11 @@ inline const ResourceManager& Page::resourceManager() const
}
inline void Page::handleForm(const std::string& , const std::string& )
{
}
} } // namespace Poco::WebWidgets

View File

@ -52,10 +52,4 @@ JSDelegate::~JSDelegate()
}
bool JSDelegate::operator<(const JSDelegate& del) const
{
return (_jsCode < del._jsCode);
}
} } // namespace Poco::WebWidgets

View File

@ -35,12 +35,17 @@
#include "Poco/WebWidgets/Page.h"
#include "Poco/WebWidgets/RequestHandler.h"
namespace Poco {
namespace WebWidgets {
const std::string Page::EV_BEFORERENDER("beforeRender");
const std::string Page::EV_AFTERRENDER("afterRender");
Page::Page():
ContainerView(typeid(Page)),
_text(),
@ -90,4 +95,22 @@ std::string Page::getText() const
}
void Page::handleAjaxRequest(const Poco::Net::NameValueCollection& args, Poco::Net::HTTPServerResponse& response)
{
const std::string& ev = args[RequestHandler::KEY_EVID];
Page* pPage = this;
if (ev == EV_BEFORERENDER)
{
beforeRender.notify(this, pPage);
}
else if (ev == EV_AFTERRENDER)
{
afterRender.notify(this, pPage);
}
response.send();
}
} } // namespace Poco::WebWidgets