mirror of
https://github.com/pocoproject/poco.git
synced 2025-04-26 18:11:29 +02:00
Extensions for JSEvents
This commit is contained in:
parent
0d3e23167a
commit
fba8e67818
@ -43,7 +43,10 @@
|
||||
#include "Poco/WebWidgets/ExtJS/ExtJS.h"
|
||||
#include "Poco/WebWidgets/Form.h"
|
||||
#include "Poco/WebWidgets/LookAndFeel.h"
|
||||
#include "Poco/WebWidgets/JavaScriptEvent.h"
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -97,7 +100,20 @@ public:
|
||||
static std::string convertPocoDateToPHPDate(const std::string& dateTimeFmt);
|
||||
/// Converts a poco date time format string to its PHP/extjs equivalent
|
||||
|
||||
static bool writeJSEvent(std::ostream& out, const std::string& eventName, const std::set<JSDelegate>& delegates);
|
||||
/// 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 writeJSEventPlusServerCallback(std::ostream& out, const std::string& eventName, const std::set<JSDelegate>& delegates, const std::map<std::string, std::string>& addServerParams);
|
||||
/// 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.
|
||||
/// an addParam that should be treated as a variable must start with the '+' character!
|
||||
|
||||
|
||||
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 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 convertPHPDateToPocoDate(char in, std::string& result);
|
||||
static void escapeCharForPHP(char in, std::string& result);
|
||||
|
@ -80,31 +80,24 @@ void TableRenderer::renderBody(const Renderable* pRenderable, const RenderContex
|
||||
|
||||
void TableRenderer::renderProperties(const Table* pTable, const RenderContext& context, std::ostream& ostr)
|
||||
{
|
||||
Utility::writeRenderableProperties(pTable, ostr);
|
||||
WebApplication& app = WebApplication::instance();
|
||||
Renderable::ID id = app.getCurrentPage()->id();
|
||||
// add an afterEdit handler
|
||||
// event handlers can be defined in the constructor after the listeners member
|
||||
//{
|
||||
// 'afterEdit' : {
|
||||
// fn: function(obj){obj.row, obj.column, obj.value, tableId}
|
||||
//},
|
||||
|
||||
std::ostringstream uri;
|
||||
uri << "'" <<app.getURI().toString();
|
||||
uri << ";"; //mark as AJAX request
|
||||
uri << RequestHandler::KEY_ID << "=" << id << "&";
|
||||
uri << Table::FIELD_COL << "='+obj.column+'&";
|
||||
uri << Table::FIELD_ROW << "='+obj.row+'&" << Table::FIELD_VAL << "='+obj.value";
|
||||
//obj.commitChanges... hides the red triangle
|
||||
ostr << ", listeners: {'afteredit':{fn:function(obj){var uri=" << uri.str() << ";obj.grid.getStore().commitChanges();";
|
||||
ostr << "Ext.Ajax.request({url:uri,";
|
||||
ostr << "failure:function(){Ext.MessageBox.alert('Status','Failed to write changes back to server.');}});}}},";
|
||||
Utility::writeRenderableProperties(pTable, ostr);
|
||||
static const std::string afterEdit("afterEdit");
|
||||
std::map<std::string, std::string> addParams;
|
||||
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_VAL, "+obj.value"));
|
||||
JavaScriptEvent<int> ev;
|
||||
ev.add(jsDelegate("function(obj){obj.grid.getStore().commitChanges();}"));
|
||||
ostr << ",listeners:{";
|
||||
Utility::writeJSEventPlusServerCallback(ostr, afterEdit, ev.jsDelegates(), addParams);
|
||||
ostr << "},";
|
||||
|
||||
renderColumns(pTable, context, ostr);
|
||||
ostr << ",clicksToEdit:1,store:";
|
||||
renderStore(pTable, ostr);
|
||||
app.registerAjaxProcessor(Poco::NumberFormatter::format(id), const_cast<Table*>(pTable));
|
||||
WebApplication::instance().registerAjaxProcessor(Poco::NumberFormatter::format(pTable), const_cast<Table*>(pTable));
|
||||
}
|
||||
|
||||
|
||||
|
@ -88,10 +88,12 @@
|
||||
#include "Poco/WebWidgets/TabView.h"
|
||||
#include "Poco/WebWidgets/ListBoxCell.h"
|
||||
#include "Poco/WebWidgets/Table.h"
|
||||
|
||||
#include "Poco/WebWidgets/WebApplication.h"
|
||||
#include "Poco/WebWidgets/RequestHandler.h"
|
||||
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/DateTimeFormat.h"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -379,4 +381,129 @@ Form::Ptr Utility::insideForm(const Cell* pChild)
|
||||
}
|
||||
|
||||
|
||||
bool Utility::writeJSEvent(std::ostream& out, const std::string& eventName, const std::set<JSDelegate>& delegates)
|
||||
{
|
||||
//'click' : {
|
||||
// fn: this.onClick,
|
||||
// scope: this,
|
||||
// delay: 100
|
||||
//}
|
||||
if (delegates.empty())
|
||||
return false;
|
||||
|
||||
out << "'" << eventName << "':";
|
||||
|
||||
if (delegates.size() == 1)
|
||||
out << "{fn:" << delegates.begin()->jsCode() << "}";
|
||||
else
|
||||
{
|
||||
// rather simple way to support more than one delegate
|
||||
// TODO: there sure is a more efficient way to do this
|
||||
std::ostringstream invoke;
|
||||
invoke << "invoke:function(" << JS_EVENTARGNAME << "){";
|
||||
out << "{fn:function(" << JS_EVENTARGNAME << "){var all={";
|
||||
writeCodeForDelegate(invoke, out, delegates);
|
||||
invoke << "}";
|
||||
out << invoke.str() << "};"; //closes all
|
||||
|
||||
out << "all.invoke(" << JS_EVENTARGNAME << ");";
|
||||
out << "}"; //closes fn
|
||||
out << "}"; //closes function
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Utility::writeCodeForDelegate(std::ostream& invoke, std::ostream& out, const std::set<JSDelegate>& jsDels)
|
||||
{
|
||||
int cnt(0);
|
||||
std::set<JSDelegate>::const_iterator it = jsDels.begin();
|
||||
for (; it != jsDels.end(); ++it)
|
||||
{
|
||||
writeCodeForDelegate(invoke, out, *it, cnt);
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Utility::writeCodeForDelegate(std::ostream& invoke, std::ostream& out, const JSDelegate& jsDel, int cnt)
|
||||
{
|
||||
std::string code(Poco::trim(jsDel.jsCode()));
|
||||
if (code.find("function") == 0)
|
||||
{
|
||||
// inline function definition
|
||||
out << "d" << cnt << ":" << code << ",";
|
||||
invoke << "this.d" << cnt << "(" << JS_EVENTARGNAME << ");";
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "d" << cnt << ":function(" << JS_EVENTARGNAME << "){" << code;
|
||||
if (!code.empty() && code[code.size()-1] != ';')
|
||||
out << ";";
|
||||
out << "},";
|
||||
invoke << "this.d" << cnt << "(" << JS_EVENTARGNAME << ");";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Utility::writeJSEventPlusServerCallback(std::ostream& out, const std::string& eventName, const std::set<JSDelegate>& delegates, const std::map<std::string, std::string>& addServerParams)
|
||||
{
|
||||
// rather simple way to support more than one delegate
|
||||
// TODO: there sure is a more efficient way to do this
|
||||
std::ostringstream invoke;
|
||||
invoke << "invoke:function(" << JS_EVENTARGNAME << "){";
|
||||
out << "{fn:function(" << JS_EVENTARGNAME << "){var all={";
|
||||
writeCodeForDelegate(invoke, out, delegates);
|
||||
//write server callback
|
||||
writeCodeForDelegate(invoke, out, jsDelegate(createFunctionCode(eventName, addServerParams)), static_cast<int>(delegates.size()));
|
||||
invoke << "}";
|
||||
out << invoke.str() << "};"; //closes all
|
||||
|
||||
out << "all.invoke(" << JS_EVENTARGNAME << ");";
|
||||
out << "}"; //closes fn
|
||||
out << "}"; //closes function
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::string Utility::createFunctionCode(const std::string& eventName, const std::map<std::string, std::string>& addParams)
|
||||
{
|
||||
WebApplication& app = WebApplication::instance();
|
||||
Renderable::ID id = app.getCurrentPage()->id();
|
||||
std::ostringstream uri;
|
||||
uri << "'" << app.getURI().toString();
|
||||
uri << ";"; //mark as AJAX request
|
||||
uri << RequestHandler::KEY_ID << "=" << id << "&";
|
||||
uri << RequestHandler::KEY_EVID << "=" << eventName;
|
||||
// add optional params
|
||||
std::map<std::string, std::string>::const_iterator it = addParams.begin();
|
||||
for (; it != addParams.end(); ++it)
|
||||
{
|
||||
uri << "&" << it->first;
|
||||
if (it->second.empty())
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (it->second[0] == '+')
|
||||
{
|
||||
// a variable was added
|
||||
uri << "='" << it->second << "+'";
|
||||
}
|
||||
else
|
||||
uri << "=" << it->second;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// now add the callback code
|
||||
std::ostringstream function;
|
||||
function << "function(" << JS_EVENTARGNAME << "){var uri=" << uri.str() << ";";
|
||||
function << "Ext.Ajax.request({url:uri,";
|
||||
function << "failure:function(){Ext.MessageBox.alert('Status','Failed to write changes back to server.');}});}";
|
||||
return function.str();
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::WebWidgets::ExtJS
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "Poco/WebWidgets/ImageButtonCell.h"
|
||||
#include "Poco/WebWidgets/TextEditCell.h"
|
||||
#include "Poco/WebWidgets/SimpleTableModel.h"
|
||||
#include "Poco/WebWidgets/JSDelegate.h"
|
||||
#include "Poco/TeeStream.h"
|
||||
#include "Poco/DateTimeFormat.h"
|
||||
#include "Poco/DateTime.h"
|
||||
@ -1315,6 +1316,36 @@ void ExtJSTest::testTableImageButton()
|
||||
}
|
||||
|
||||
|
||||
void ExtJSTest::testJSEvent()
|
||||
{
|
||||
Button::Ptr pBut(new Button());
|
||||
pBut->buttonClicked.add(jsDelegate("someFunction(obj)"));
|
||||
pBut->buttonClicked.add(jsDelegate("function(obj){alert('Click');}"));
|
||||
std::ostringstream out;
|
||||
Utility::writeJSEvent(out, "clicked", pBut->buttonClicked.jsDelegates());
|
||||
std::string result(out.str());
|
||||
static const std::string expected("'clicked':"
|
||||
"{"
|
||||
"fn:function(obj){"
|
||||
"var all={"
|
||||
"d0:function(obj){"
|
||||
"alert('Click');"
|
||||
"},"
|
||||
"d1:function(obj){"
|
||||
"someFunction(obj);"
|
||||
"},"
|
||||
"invoke:function(obj){"
|
||||
"this.d0(obj);"
|
||||
"this.d1(obj);"
|
||||
"}"
|
||||
"};"
|
||||
"all.invoke(obj);"
|
||||
"}"
|
||||
"}");
|
||||
assert (result == expected);
|
||||
}
|
||||
|
||||
|
||||
void ExtJSTest::setUp()
|
||||
{
|
||||
}
|
||||
@ -1365,6 +1396,7 @@ CppUnit::Test* ExtJSTest::suite()
|
||||
CppUnit_addTest(pSuite, ExtJSTest, testTableComboBox);
|
||||
CppUnit_addTest(pSuite, ExtJSTest, testTableButton);
|
||||
CppUnit_addTest(pSuite, ExtJSTest, testTableImageButton);
|
||||
CppUnit_addTest(pSuite, ExtJSTest, testJSEvent);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
void testTableComboBox();
|
||||
void testTableButton();
|
||||
void testTableImageButton();
|
||||
|
||||
void testJSEvent();
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
#include "Poco/WebWidgets/Control.h"
|
||||
#include "Poco/WebWidgets/Event.h"
|
||||
#include "Poco/BasicEvent.h"
|
||||
#include "Poco/WebWidgets/JavaScriptEvent.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -59,7 +59,7 @@ public:
|
||||
typedef Poco::AutoPtr<Button> Ptr;
|
||||
typedef Event<Button> ButtonEvent;
|
||||
|
||||
Poco::BasicEvent<ButtonEvent> buttonClicked;
|
||||
JavaScriptEvent<ButtonEvent> buttonClicked;
|
||||
|
||||
Button(const std::string& name);
|
||||
/// Creates a Button with the given name.
|
||||
|
@ -51,46 +51,34 @@ class WebWidgets_API JSDelegate
|
||||
/// A JSDelegate adds a javascript method call to a JavaScriptEvent
|
||||
{
|
||||
public:
|
||||
JSDelegate(const std::string& fct, const std::string& file);
|
||||
JSDelegate(const std::string& jsCode);
|
||||
/// Creates the JSDelegate.
|
||||
|
||||
virtual ~JSDelegate();
|
||||
/// Destroys the JSDelegate.
|
||||
|
||||
const std::string& functionName() const;
|
||||
/// The JavaScript function to call. It is assumed that the
|
||||
/// function takes one parameter, which is of type JavaScript EventArgs
|
||||
|
||||
const std::string& jsFile() const;
|
||||
/// The javascript file we need to import so that
|
||||
/// the function is available
|
||||
const std::string& jsCode() const;
|
||||
/// The javascript code that should be executed
|
||||
|
||||
bool operator<(const JSDelegate& del) const;
|
||||
|
||||
private:
|
||||
std::string _functionName;
|
||||
std::string _jsFile;
|
||||
std::string _jsCode;
|
||||
};
|
||||
|
||||
|
||||
inline const std::string& JSDelegate::functionName() const
|
||||
inline const std::string& JSDelegate::jsCode() const
|
||||
{
|
||||
return _functionName;
|
||||
return _jsCode;
|
||||
}
|
||||
|
||||
|
||||
inline const std::string& JSDelegate::jsFile() const
|
||||
static JSDelegate jsDelegate(const std::string& jsCode);
|
||||
|
||||
|
||||
inline JSDelegate jsDelegate(const std::string& jsCode)
|
||||
{
|
||||
return _jsFile;
|
||||
}
|
||||
|
||||
|
||||
static JSDelegate jsDelegate(const std::string& fct, const std::string& file);
|
||||
|
||||
|
||||
inline JSDelegate jsDelegate(const std::string& fct, const std::string& file)
|
||||
{
|
||||
return JSDelegate(fct, file);
|
||||
return JSDelegate(jsCode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,8 +51,11 @@ namespace Poco {
|
||||
namespace WebWidgets {
|
||||
|
||||
|
||||
static const std::string JS_EVENTARGNAME("obj"); /// each javascript method receives one single param which is named JS_EVENTARGNAME
|
||||
|
||||
|
||||
template <class TArgs>
|
||||
class WebWidgets_API JavaScriptEvent: public Poco::AbstractEvent <
|
||||
class JavaScriptEvent: public Poco::AbstractEvent <
|
||||
TArgs, Poco::DefaultStrategy<TArgs, Poco::AbstractDelegate<TArgs>, Poco::p_less<Poco::AbstractDelegate<TArgs> > >,
|
||||
Poco::AbstractDelegate<TArgs>
|
||||
>
|
||||
|
@ -57,7 +57,8 @@ class WebWidgets_API RequestHandler: public Poco::Net::HTTPRequestHandler
|
||||
/// The HTTP request handler for WebWidgets.
|
||||
{
|
||||
public:
|
||||
static const std::string KEY_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
|
||||
|
||||
RequestHandler(WebApplication& app);
|
||||
/// Creates the RequestHandler, using the given WebApplication.
|
||||
|
@ -41,9 +41,8 @@ namespace Poco {
|
||||
namespace WebWidgets {
|
||||
|
||||
|
||||
JSDelegate::JSDelegate(const std::string& fct, const std::string& file):
|
||||
_functionName(fct),
|
||||
_jsFile(file)
|
||||
JSDelegate::JSDelegate(const std::string& code):
|
||||
_jsCode(code)
|
||||
{
|
||||
}
|
||||
|
||||
@ -55,13 +54,7 @@ JSDelegate::~JSDelegate()
|
||||
|
||||
bool JSDelegate::operator<(const JSDelegate& del) const
|
||||
{
|
||||
if (_functionName < del._functionName)
|
||||
return true;
|
||||
|
||||
if (_functionName > del._functionName)
|
||||
return false;
|
||||
|
||||
return _jsFile < del._jsFile;
|
||||
return (_jsCode < del._jsCode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -55,6 +55,7 @@ namespace WebWidgets {
|
||||
|
||||
|
||||
const std::string RequestHandler::KEY_ID("id");
|
||||
const std::string RequestHandler::KEY_EVID("evId");
|
||||
|
||||
|
||||
RequestHandler::RequestHandler(WebApplication& app):
|
||||
|
Loading…
x
Reference in New Issue
Block a user