fixes to events

This commit is contained in:
Peter Schojer 2008-05-19 13:14:14 +00:00
parent 665172eed0
commit ae5b44091f
12 changed files with 199 additions and 46 deletions

View File

@ -104,16 +104,24 @@ public:
/// writes all JS Delegates for a single named JSEvent. /// 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. /// Returns true if data was written, false if no delegates were present and no event handler was written.
static bool writeJSEventPlusServerCallback(std::ostream& out, const std::string& eventName, const std::set<JSDelegate>& delegates, const std::map<std::string, std::string>& addServerParams); static bool writeJSEventPlusServerCallback(std::ostream& out, const std::string& eventName, const std::set<JSDelegate>& delegates, const std::map<std::string, std::string>& addServerParams, bool reloadPage);
/// writes all JS Delegates for a single named JSEvent. adds a callback to the server /// writes all JS Delegates for a single named JSEvent. adds a callback to the server
/// Returns true if data was written, false if no delegates were present and no event handler was written. /// Returns true if data was written, false if no delegates were present and no event handler was written.
/// an addParam that should be treated as a variable must start with the '+' character! /// an addParam that should be treated as a variable must start with the '+' character!
static std::string createURI(const std::map<std::string, std::string>& addParams);
/// Creates the url from the function parameters, writes a js fucntion with method signature function(obj)
static std::string createCallbackFunctionCode(const std::string& signature, const std::map<std::string, std::string>& addParams, bool reloadPage);
/// Creates the url from the function parameters, writes a js fucntion with the given method signature
static bool writeServerCallback(std::ostream& out, const std::string& eventName, const std::string& signature, const std::map<std::string, std::string>& addServerParams, bool reloadPage);
/// Writes a server callback for the given ExtJS eventName and server Params
// signature contaisn the function declaration (i.e.: function(p1,p2))
private: private:
static void writeCodeForDelegate(std::ostream& invoke, std::ostream& jsOut, const std::set<JSDelegate>& jsDels); static void writeCodeForDelegate(std::ostream& invoke, std::ostream& jsOut, const std::set<JSDelegate>& jsDels);
static void writeCodeForDelegate(std::ostream& invoke, std::ostream& jsOut, const JSDelegate& jsDel, int cnt); static void writeCodeForDelegate(std::ostream& invoke, std::ostream& jsOut, const JSDelegate& jsDel, int cnt);
static std::string createFunctionCode(const std::string& eventName, const std::map<std::string, std::string>& addParams);
static void convertPocoDateToPHPDate(char in, std::string& result); static void convertPocoDateToPHPDate(char in, std::string& result);
static void convertPHPDateToPocoDate(char in, std::string& result); static void convertPHPDateToPocoDate(char in, std::string& result);
static void escapeCharForPHP(char in, std::string& result); static void escapeCharForPHP(char in, std::string& result);

View File

@ -57,7 +57,7 @@ void CollapsibleRenderer::writeProperties(const Frame* pFrame, std::ostream& ost
{ {
const Collapsible* pC = static_cast<const Collapsible*>(pFrame); const Collapsible* pC = static_cast<const Collapsible*>(pFrame);
FrameRenderer::writeProperties(pFrame, ostr); FrameRenderer::writeProperties(pFrame, ostr);
ostr << ",collapsible:true,titleCollapse:true, header:true,collapsed:" << (pC->getCollapse()?"true":"false"); ostr << ",collapsible:true,titleCollapse:true, collapsed:" << (pC->getCollapse()?"true":"false");
} }

View File

@ -84,26 +84,40 @@ void TableRenderer::renderProperties(const Table* pTable, const RenderContext& c
WebApplication& app = WebApplication::instance(); WebApplication& app = WebApplication::instance();
Renderable::ID id = app.getCurrentPage()->id(); Renderable::ID id = app.getCurrentPage()->id();
Utility::writeRenderableProperties(pTable, ostr); Utility::writeRenderableProperties(pTable, ostr);
static const std::string afterEdit("afterEdit"); static const std::string afterEdit("afteredit");
static const std::string cellClicked("cellclick");
std::map<std::string, std::string> addParams; std::map<std::string, std::string> addParams;
addParams.insert(std::make_pair(Table::FIELD_COL, "+obj.column")); addParams.insert(std::make_pair(Table::FIELD_COL, "+obj.column"));
addParams.insert(std::make_pair(Table::FIELD_ROW, "+obj.row")); addParams.insert(std::make_pair(Table::FIELD_ROW, "+obj.row"));
addParams.insert(std::make_pair(Table::FIELD_VAL, "+obj.value")); addParams.insert(std::make_pair(Table::FIELD_VAL, "+obj.value"));
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, Table::EV_CELLVALUECHANGED));
JavaScriptEvent<int> ev; JavaScriptEvent<int> ev;
ev.setJSDelegates(pTable->cellValueChanged.jsDelegates());
ev.add(jsDelegate("function(obj){obj.grid.getStore().commitChanges();}")); ev.add(jsDelegate("function(obj){obj.grid.getStore().commitChanges();}"));
ostr << ",listeners:{"; ostr << ",listeners:{";
Utility::writeJSEventPlusServerCallback(ostr, afterEdit, ev.jsDelegates(), addParams); Utility::writeJSEventPlusServerCallback(ostr, afterEdit, ev.jsDelegates(), addParams, pTable->cellValueChanged.hasLocalHandlers());
ostr << "},";
//cellclick : ( Grid this, Number rowIndex, Number columnIndex, Ext.EventObject e )
//hm, more than one param in the eventhanlder of cellclick, writeJSEvent creates a fucntion(obj) wrapper
//FIXME: no support for custom javascript yet
addParams.clear();
addParams.insert(std::make_pair(Table::FIELD_COL, "+columnIndex"));
addParams.insert(std::make_pair(Table::FIELD_ROW, "+rowIndex"));
addParams.insert(std::make_pair(RequestHandler::KEY_EVID, Table::EV_CELLCLICKED));
ostr << ",";
Utility::writeServerCallback(ostr,cellClicked, "function(aGrid, rowIndex,columnIndex,e)",addParams, pTable->cellClicked.hasLocalHandlers());
ostr << "},"; //close listeners
renderColumns(pTable, context, ostr); renderColumns(pTable, context, ostr);
ostr << ",clicksToEdit:1"; ostr << ",clicksToEdit:1,stripeRows:true";
if (pTable->getWidth() > 0) if (pTable->getWidth() > 0)
ostr << ",width:" << pTable->getWidth(); ostr << ",width:" << pTable->getWidth();
if (pTable->getHeight() > 0) if (pTable->getHeight() > 0)
ostr << ",height:" << pTable->getHeight(); ostr << ",height:" << pTable->getHeight();
ostr << ",store:"; ostr << ",store:";
renderStore(pTable, ostr); renderStore(pTable, ostr);
WebApplication::instance().registerAjaxProcessor(Poco::NumberFormatter::format(pTable), const_cast<Table*>(pTable)); WebApplication::instance().registerAjaxProcessor(Poco::NumberFormatter::format(id), const_cast<Table*>(pTable));
} }

View File

@ -447,18 +447,20 @@ void Utility::writeCodeForDelegate(std::ostream& invoke, std::ostream& out, cons
} }
bool Utility::writeJSEventPlusServerCallback(std::ostream& out, const std::string& eventName, const std::set<JSDelegate>& delegates, const std::map<std::string, std::string>& addServerParams) bool Utility::writeJSEventPlusServerCallback(std::ostream& out, const std::string& eventName, const std::set<JSDelegate>& delegates, const std::map<std::string, std::string>& addServerParams, bool reloadPage)
{ {
// rather simple way to support more than one delegate // rather simple way to support more than one delegate
// TODO: there sure is a more efficient way to do this // TODO: there sure is a more efficient way to do this
out << "'" << eventName << "':";
out << eventName << ":";
static const std::string defSignature("function("+JS_EVENTARGNAME+")");
std::ostringstream invoke; std::ostringstream invoke;
invoke << "invoke:function(" << JS_EVENTARGNAME << "){"; invoke << "invoke:function(" << JS_EVENTARGNAME << "){";
out << "{fn:function(" << JS_EVENTARGNAME << "){var all={"; out << "{fn:function(" << JS_EVENTARGNAME << "){var all={";
writeCodeForDelegate(invoke, out, delegates); writeCodeForDelegate(invoke, out, delegates);
//write server callback //write server callback
writeCodeForDelegate(invoke, out, jsDelegate(createFunctionCode(eventName, addServerParams)), static_cast<int>(delegates.size())); writeCodeForDelegate(invoke, out, jsDelegate(createCallbackFunctionCode(defSignature, addServerParams, reloadPage)), static_cast<int>(delegates.size()));
invoke << "}"; invoke << "}";
out << invoke.str() << "};"; //closes all out << invoke.str() << "};"; //closes all
@ -469,15 +471,23 @@ bool Utility::writeJSEventPlusServerCallback(std::ostream& out, const std::strin
} }
std::string Utility::createFunctionCode(const std::string& eventName, const std::map<std::string, std::string>& addParams) bool Utility::writeServerCallback(std::ostream& out, const std::string& eventName, const std::string& signature, const std::map<std::string, std::string>& addServerParams, bool reloadPage)
{
std::string fctCode(createCallbackFunctionCode(signature, addServerParams, reloadPage));
out << eventName << ":";
out << fctCode;
return true;
}
std::string Utility::createURI(const std::map<std::string, std::string>& addParams)
{ {
WebApplication& app = WebApplication::instance(); WebApplication& app = WebApplication::instance();
Renderable::ID id = app.getCurrentPage()->id(); Renderable::ID id = app.getCurrentPage()->id();
std::ostringstream uri; std::ostringstream uri;
uri << "'" << app.getURI().toString(); uri << "'" << app.getURI().toString() << "?";
uri << ";"; //mark as AJAX request uri << RequestHandler::KEY_TYPE << "=" << RequestHandler::VAL_AJAX; //mark as AJAX request
uri << RequestHandler::KEY_ID << "=" << id << "&"; uri << "&" << RequestHandler::KEY_ID << "=" << id;
uri << RequestHandler::KEY_EVID << "=" << eventName;
// add optional params // add optional params
bool commaAtEnd = false; bool commaAtEnd = false;
std::size_t cnt(1); std::size_t cnt(1);
@ -509,10 +519,28 @@ std::string Utility::createFunctionCode(const std::string& eventName, const std:
} }
if (!commaAtEnd) if (!commaAtEnd)
uri << "'"; uri << "'";
return uri.str();
}
std::string Utility::createCallbackFunctionCode(const std::string& signature, const std::map<std::string, std::string>& addParams, bool reloadPage)
{
poco_assert_dbg (!signature.empty());
poco_assert_dbg(signature.find("function") != std::string::npos);
poco_assert_dbg(signature.find("{") == std::string::npos);
std::string uri(createURI(addParams));
// now add the callback code // now add the callback code
std::ostringstream function; std::ostringstream function;
function << "function(" << JS_EVENTARGNAME << "){var uri=" << uri.str() << ";"; function << signature;
function << "{var uri=" << uri << ";";
function << "Ext.Ajax.request({url:uri,"; function << "Ext.Ajax.request({url:uri,";
if (reloadPage)
{
function << "success:function(){window.location.reload();},";
function << "failure:function(){Ext.MessageBox.alert('Status','Failed to write changes back to server.');window.location.reload();}});}";
}
else
function << "failure:function(){Ext.MessageBox.alert('Status','Failed to write changes back to server.');}});}"; function << "failure:function(){Ext.MessageBox.alert('Status','Failed to write changes back to server.');}});}";
return function.str(); return function.str();
} }

View File

@ -108,6 +108,12 @@ public:
return _jsHandlers; return _jsHandlers;
} }
void setJSDelegates(const std::set<JSDelegate>& all)
/// Overwrites all JSDelegates
{
_jsHandlers = all;
}
private: private:
std::set<JSDelegate> _jsHandlers; std::set<JSDelegate> _jsHandlers;
}; };

View File

@ -41,6 +41,7 @@
#include "Poco/WebWidgets/TextFieldCell.h" #include "Poco/WebWidgets/TextFieldCell.h"
#include "Poco/WebWidgets/IntFormatter.h"
namespace Poco { namespace Poco {
@ -53,7 +54,7 @@ class WebWidgets_API NumberFieldCell: public TextFieldCell
public: public:
typedef Poco::AutoPtr<NumberFieldCell> Ptr; typedef Poco::AutoPtr<NumberFieldCell> Ptr;
NumberFieldCell(View* pOwner); NumberFieldCell(View* pOwner, Formatter::Ptr pF = new IntFormatter());
/// Creates the NumberFieldCell. /// Creates the NumberFieldCell.
virtual ~NumberFieldCell(); virtual ~NumberFieldCell();

View File

@ -59,6 +59,8 @@ class WebWidgets_API RequestHandler: public Poco::Net::HTTPRequestHandler
public: public:
static const std::string KEY_ID; /// key for form param contains id static const std::string KEY_ID; /// key for form param contains id
static const std::string KEY_EVID; /// form param containing the event name static const std::string KEY_EVID; /// form param containing the event name
static const std::string VAL_AJAX; /// value to detect an AJAX request
static const std::string KEY_TYPE; /// key identifying the type of request
RequestHandler(WebApplication& app); RequestHandler(WebApplication& app);
/// Creates the RequestHandler, using the given WebApplication. /// Creates the RequestHandler, using the given WebApplication.

View File

@ -45,6 +45,7 @@
#include "Poco/WebWidgets/TableModel.h" #include "Poco/WebWidgets/TableModel.h"
#include "Poco/WebWidgets/TableColumn.h" #include "Poco/WebWidgets/TableColumn.h"
#include "Poco/WebWidgets/RequestProcessor.h" #include "Poco/WebWidgets/RequestProcessor.h"
#include "Poco/WebWidgets/JavaScriptEvent.h"
#include <vector> #include <vector>
@ -62,6 +63,30 @@ public:
static const std::string FIELD_COL; static const std::string FIELD_COL;
static const std::string FIELD_ROW; static const std::string FIELD_ROW;
static const std::string FIELD_VAL; static const std::string FIELD_VAL;
static const std::string EV_CELLCLICKED;
static const std::string EV_CELLVALUECHANGED;
struct CellClick
{
std::size_t row;
std::size_t col;
CellClick(std::size_t row, std::size_t col);
};
struct CellValueChange
{
std::size_t row;
std::size_t col;
const Poco::Any oldValue;
const Poco::Any newValue;
CellValueChange(std::size_t row, std::size_t col, const Poco::Any& oldValue, const Poco::Any& newValue);
};
JavaScriptEvent<Table::CellClick> cellClicked;
JavaScriptEvent<Table::CellValueChange> cellValueChanged;
Table(const TableColumns& tc, TableModel::Ptr pModel); Table(const TableColumns& tc, TableModel::Ptr pModel);
/// Creates an anonymous Table. /// Creates an anonymous Table.
@ -94,9 +119,12 @@ public:
/// Handles a complete HTTP request submitted by the client. /// Handles a complete HTTP request submitted by the client.
private: private:
void apply(); void handleValueChanged();
///Applies the update to the table ///Applies the update to the table
void handleCellClicked();
///handles cell clicked
void handleCol(const std::string& val); void handleCol(const std::string& val);
void handleRow(const std::string& val); void handleRow(const std::string& val);
void handleVal(const std::string& val); void handleVal(const std::string& val);
@ -119,6 +147,7 @@ private:
int _col; int _col;
int _row; int _row;
std::string _val; std::string _val;
std::string _ev;
}; };
@ -143,12 +172,6 @@ inline std::size_t Table::getRowCount() const
} }
inline void Table::setValue(const Poco::Any& val, std::size_t row, std::size_t col)
{
_pModel->setValue(val, row, col);
}
inline const Table::TableColumns& Table::getColumns() const inline const Table::TableColumns& Table::getColumns() const
{ {
return _columns; return _columns;

View File

@ -92,6 +92,7 @@ void ContainerView::remove(View::Ptr pView)
View::Ptr ContainerView::findChild(const std::string& name) const View::Ptr ContainerView::findChild(const std::string& name) const
{
{ {
for (ConstIterator it = begin(); it != end(); ++it) for (ConstIterator it = begin(); it != end(); ++it)
{ {
@ -100,9 +101,23 @@ View::Ptr ContainerView::findChild(const std::string& name) const
return *it; return *it;
} }
} }
}
{
View::Ptr result;
for (ConstIterator it = begin(); it != end(); ++it)
{
if (*it)
{
result = (*it)->findChild(name);
}
if (result)
return result;
}
return View::findChild(name); return View::findChild(name);
} }
}
} } // namespace Poco::WebWidgets } } // namespace Poco::WebWidgets

View File

@ -42,10 +42,10 @@ namespace Poco {
namespace WebWidgets { namespace WebWidgets {
NumberFieldCell::NumberFieldCell(View* pOwner): NumberFieldCell::NumberFieldCell(View* pOwner, Formatter::Ptr pF):
TextFieldCell(pOwner, typeid(NumberFieldCell)) TextFieldCell(pOwner, typeid(NumberFieldCell))
{ {
this->setFormatter(new IntFormatter()); this->setFormatter(pF);
} }

View File

@ -56,6 +56,8 @@ namespace WebWidgets {
const std::string RequestHandler::KEY_ID("id"); const std::string RequestHandler::KEY_ID("id");
const std::string RequestHandler::KEY_EVID("evId"); const std::string RequestHandler::KEY_EVID("evId");
const std::string RequestHandler::VAL_AJAX("ajax");
const std::string RequestHandler::KEY_TYPE("appinf");
RequestHandler::RequestHandler(WebApplication& app): RequestHandler::RequestHandler(WebApplication& app):
@ -72,22 +74,29 @@ RequestHandler::~RequestHandler()
void RequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) void RequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{ {
_app.attachToThread(); _app.attachToThread();
Poco::Net::NameValueCollection args;
parseRequest(request, args);
if (args.empty())
{
Poco::Net::HTMLForm form(request, request.stream()); Poco::Net::HTMLForm form(request, request.stream());
if (!form.empty()) if (!form.empty())
{ {
handleForm(form); Poco::Net::NameValueCollection::ConstIterator it = form.find(KEY_TYPE);
} if (it != form.end())
handlePageRequest(request, response); {
if (it->second == VAL_AJAX)
{
form.erase(KEY_TYPE);
handleAjaxRequest(request, response, form);
} }
else else
{ {
handleAjaxRequest(request, response, args); form.erase(KEY_TYPE);
handleForm(form);
} }
} }
else
handleForm(form);
}
else
handlePageRequest(request, response);
}
void RequestHandler::handlePageRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) void RequestHandler::handlePageRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)

View File

@ -35,6 +35,7 @@
#include "Poco/WebWidgets/Table.h" #include "Poco/WebWidgets/Table.h"
#include "Poco/WebWidgets/RequestHandler.h"
#include "Poco/NumberParser.h" #include "Poco/NumberParser.h"
@ -45,6 +46,8 @@ namespace WebWidgets {
const std::string Table::FIELD_COL("col"); const std::string Table::FIELD_COL("col");
const std::string Table::FIELD_ROW("row"); const std::string Table::FIELD_ROW("row");
const std::string Table::FIELD_VAL("val"); const std::string Table::FIELD_VAL("val");
const std::string Table::EV_CELLCLICKED("click");
const std::string Table::EV_CELLVALUECHANGED("edit");
Table::Table(const TableColumns& tc, TableModel::Ptr pModel): Table::Table(const TableColumns& tc, TableModel::Ptr pModel):
@ -126,19 +129,25 @@ void Table::handleForm(const std::string& field, const std::string& value)
handleRow(value); handleRow(value);
else if (field == FIELD_VAL) else if (field == FIELD_VAL)
handleVal(value); handleVal(value);
else if (field == RequestHandler::KEY_EVID)
_ev = value;
} }
void Table::handleRequest(const Poco::Net::HTTPServerRequest& req) void Table::handleRequest(const Poco::Net::HTTPServerRequest& req)
{ {
apply(); if (_ev == EV_CELLVALUECHANGED)
handleValueChanged();
else if (_ev == EV_CELLCLICKED)
handleCellClicked();
_col = -1; _col = -1;
_row = -1; _row = -1;
_val.clear();; _val.clear();
_ev.clear();
} }
void Table::apply() void Table::handleValueChanged()
{ {
if (_col < 0 || _row < 0 || _col >= getColumnCount()) if (_col < 0 || _row < 0 || _col >= getColumnCount())
throw InvalidArgumentException("col/row out of range"); throw InvalidArgumentException("col/row out of range");
@ -156,6 +165,16 @@ void Table::apply()
} }
void Table::handleCellClicked()
{
if (_col < 0 || _row < 0 || _col >= getColumnCount())
throw InvalidArgumentException("col/row out of range");
CellClick ev(_row, _col);
cellClicked(this, ev);
}
void Table::handleCol(const std::string& val) void Table::handleCol(const std::string& val)
{ {
_col = Poco::NumberParser::parse(val); _col = Poco::NumberParser::parse(val);
@ -176,4 +195,32 @@ void Table::handleVal(const std::string& val)
_val = val; _val = val;
} }
void Table::setValue(const Poco::Any& val, std::size_t row, std::size_t col)
{
Poco::Any oldValue;
if (getRowCount() > row)
oldValue = getValue(row, col);
CellValueChange ev(row, col, oldValue, val);
_pModel->setValue(val, row, col);
cellValueChanged(this, ev);
}
Table::CellClick::CellClick(std::size_t r, std::size_t c):
row(r),
col(c)
{
}
Table::CellValueChange::CellValueChange(std::size_t r, std::size_t c, const Poco::Any& old, const Poco::Any& n):
row(r),
col(c),
oldValue(old),
newValue(n)
{
}
} } // namespace Poco::WebWidgets } } // namespace Poco::WebWidgets