Commit 359743f1 authored by Xiaowu Zhang's avatar Xiaowu Zhang

Reimplement formulator GadgetField for compatibility with the RelationStringField

1. Use form submit instead of ajax in erp5_gadgetfield.js file
2. Data decode is realized in GadgetFieldValidator
3. Move jio files in erp5_core for activity watcher gadget
4. Update gadgetfield test
   Add test with RelationStringField
   Remove DataURL test which is not necessary
parent be7079a9
......@@ -91,41 +91,167 @@
\n
\n
<!-- Initialize -->\n
\n
<tr>\n
<td>waitForElementPresent</td>\n
<td>//input[@title=\'field_my_subject\']</td>\n
<td>//input[@name=\'field_my_successor_title\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>type</td>\n
<td>//input[@name=\'field_my_successor_title\']</td>\n
<td>test</td>\n
</tr>\n
\n
<tr>\n
<td>clickAndWait</td>\n
<td>//button[@title=\'Save\']</td>\n
<td></td>\n
</tr>\n
<tr>\n
<td>verifyText</td>\n
<td>//div[@id=\'information_area\']</td>\n
<td>Input data has errors. Please look at the error messages below.</td>\n
</tr>\n
\n
<tr>\n
<td>type</td>\n
<td>//input[@title=\'field_my_subject\']</td>\n
<td>couscous</td>\n
<td>//input[@name=\'field_my_successor_title\']</td>\n
<td></td>\n
</tr>\n
\n
\n
<tr>\n
<td>clickAndWait</td>\n
<td>//input[@name=\'portal_selections/viewSearchRelatedDocumentDialog0:method\']</td>\n
<td></td>\n
</tr>\n
\n
\n
<tr>\n
<td>click</td>\n
<td>//input[@type=\'checkbox\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>clickAndWait</td>\n
<td>//button[@id=\'dialog_submit_button\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>verifyPortalStatusMessage</td>\n
<td>Data updated.</td>\n
<td></td>\n
</tr>\n
\n
\n
<tr>\n
<td>verifyValue</td>\n
<td>//input[@name=\'field_my_successor_title\']</td>\n
<td>Title 0</td>\n
</tr>\n
\n
<tr>\n
<td>waitForElementPresent</td>\n
<td>//input[@title=\'field_my_description\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>type</td>\n
<td>//input[@name=\'field_my_successor_title\']</td>\n
<td>Titl%</td>\n
</tr>\n
\n
<tr>\n
<td>type</td>\n
<td>//input[@title=\'field_my_description\']</td>\n
<td>relationFieldTest</td>\n
</tr>\n
\n
\n
<tr>\n
<td>clickAndWait</td>\n
<td>//button[@title=\'Save\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>verifyPortalStatusMessage</td>\n
<td>Data updated.</td>\n
<td></td>\n
</tr>\n
\n
\n
<tr>\n
<td>pause</td>\n
<td>2000</td>\n
<td>waitForElementPresent</td>\n
<td>//input[@title=\'field_my_description\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>verifyValue</td>\n
<td>//input[@name=\'field_my_successor_title\']</td>\n
<td>Title 0</td>\n
</tr>\n
\n
<tr>\n
<td>verifyValue</td>\n
<td>//input[@title=\'field_my_description\']</td>\n
<td>relationFieldTest</td>\n
</tr>\n
\n
\n
<tr>\n
<td>verifyBodyText</td>\n
<td>"Error: URL is not a dataURL"</td>\n
<td>type</td>\n
<td>//input[@title=\'field_my_description\']</td>\n
<td>relationFieldTestSuite</td>\n
</tr>\n
\n
<tr>\n
<td>clickAndWait</td>\n
<td>//input[@name=\'portal_selections/viewSearchRelatedDocumentDialog0:method\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>click</td>\n
<td>//input[@name=\'uids:list\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>clickAndWait</td>\n
<td>//button[@name=\'Base_callDialogMethod:method\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>verifyPortalStatusMessage</td>\n
<td>Data updated.</td>\n
<td></td>\n
</tr>\n
\n
\n
<tr>\n
<td>waitForElementPresent</td>\n
<td>//input[@title=\'field_my_description\']</td>\n
<td></td>\n
</tr>\n
\n
<tr>\n
<td>verifyValue</td>\n
<td>//input[@name=\'field_my_successor_title\']</td>\n
<td>Title 0</td>\n
</tr>\n
\n
<tr>\n
<td>verifyValue</td>\n
<td>//input[@title=\'field_my_description\']</td>\n
<td>relationFieldTestSuite</td>\n
</tr>\n
\n
\n
</tbody></table>\n
......@@ -144,7 +270,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testNotDataURLException</string> </value>
<value> <string>testSaveAndLoadWithRelationField</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
......
......@@ -78,6 +78,7 @@
<string>my_title</string>
<string>my_description</string>
<string>my_language</string>
<string>my_successor_title</string>
</list>
</value>
</item>
......@@ -86,7 +87,6 @@
<value>
<list>
<string>my_file</string>
<string>my_subject</string>
</list>
</value>
</item>
......
......@@ -136,6 +136,10 @@
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>data_url</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
......@@ -160,6 +164,10 @@
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
......
......@@ -136,6 +136,10 @@
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>data_url</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
......@@ -160,6 +164,10 @@
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
......@@ -176,6 +184,10 @@
<key> <string>js_sandbox</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Language</string> </value>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="GadgetField" module="Products.ERP5Form.GadgetField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_subject</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>gadget_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>js_sandbox</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>gadget_url</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>js_sandbox</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>20</int> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>gadget_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>js_sandbox</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Subject</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: field.restrictedTraverse(\'gadget_create_manual_generalurl.html\').absolute_url()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -8,7 +8,7 @@
<dictionary>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts16394141.44</string> </value>
<value> <string>ts20545224.7</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
......@@ -47,10 +47,8 @@
form_gadget = this,\n
result = {};\n
if (input.value) {\n
result[form_gadget.props.key] = {\'url\': "data:text/plain;base64,"\n
+ btoa(input.value),\n
\'type\': \'text/plain\',\n
\'file_name\': \'test.txt\'};\n
result[form_gadget.props.key] = "data:text/plain;base64,"\n
+ btoa(input.value);\n
}\n
return result;\n
});\n
......@@ -63,7 +61,7 @@
</item>
<item>
<key> <string>size</string> </key>
<value> <int>1093</int> </value>
<value> <int>955</int> </value>
</item>
<item>
<key> <string>title</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts16492973.44</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>gadget_create_manual_generalurl.html</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>data</string> </key>
<value> <string encoding="cdata"><![CDATA[
<!DOCTYPE html>\n
<html>\n
<head>\n
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />\n
<meta name="viewport" content="width=device-width, user-scalable=no" />\n
\n
\n
<!-- renderjs -->\n
<script src="rsvp.js" type="text/javascript"></script>\n
<script src="renderjs.js" type="text/javascript"></script>\n
<!-- custom script -->\n
<script src="gadget_create_manual_generalurl.js" type="text/javascript"></script>\n
\n
</head>\n
<body>\n
<input type=\'text\'/>\n
</body>\n
</html>
]]></string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>505</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts16394133.05</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>gadget_create_manual_generalurl.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>data</string> </key>
<value> <string>/*global window, rJS, console, RSVP */\n
/*jslint nomen: true, maxlen:80, indent:2*/\n
(function (rJS) {\n
"use strict";\n
\n
rJS(window)\n
.ready(function (g) {\n
g.props = {};\n
})\n
.ready(function (g) {\n
return g.getElement()\n
.push(function (element) {\n
g.props.element = element;\n
});\n
})\n
.declareMethod(\'render\', function (options) {\n
var gadget = this;\n
gadget.props.key = options.key || "";\n
gadget.props.element.querySelector(\'input\').value = options.value || "";\n
gadget.props.element.querySelector(\'input\').title = options.key;\n
})\n
\n
.declareMethod(\'getContent\', function () {\n
var input = this.props.element.querySelector(\'input\'),\n
form_gadget = this,\n
result = {};\n
if (input.value) {\n
result[form_gadget.props.key] = {\'url\': input.value,\n
\'type\': \'text/html\',\n
\'file_name\': \'test.txt\'};\n
}\n
return result;\n
});\n
\n
}(rJS));</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>1028</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -8,7 +8,7 @@
<dictionary>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts17097929.83</string> </value>
<value> <string>ts20545059.65</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
......@@ -22,25 +22,10 @@
<key> <string>data</string> </key>
<value> <string encoding="cdata"><![CDATA[
/*global window, rJS, RSVP, Blob, Uint8Array, document, FormData, jIO */\n
/*global window, rJS, RSVP, document*/\n
/*jslint nomen: true, maxlen:80, indent:2*/\n
(function (window, rJS, RSVP) {\n
(function (window, document, rJS, RSVP) {\n
"use strict";\n
function convertDataURL2Blob(url, type) {\n
var binary,\n
array = [],\n
i;\n
url = url.split(\',\')[1];\n
if (url !== undefined) {\n
binary = window.atob(url);\n
for (i = 0; i < binary.length; i += 1) {\n
array.push(binary.charCodeAt(i));\n
}\n
return new Blob([new Uint8Array(array)], {type: type});\n
}\n
throw "Error: URL is not a dataURL";\n
}\n
\n
function promiseEventListener(target, type, useCapture) {\n
//////////////////////////\n
// Resolve the promise as soon as the event is triggered\n
......@@ -65,6 +50,7 @@
}\n
return new RSVP.Promise(resolver, canceller);\n
}\n
\n
rJS(window)\n
/////////////////////////////////////////////////////////////////\n
// ready\n
......@@ -87,22 +73,29 @@
.declareService(function () {\n
var g = this,\n
i,\n
formdata,\n
list_gadget = document.getElementsByClassName("gadget"),\n
all_gadget,\n
list = [],\n
gadget_attributes = [],\n
url,\n
form = g.props.element.querySelector("form"),\n
scope,\n
value,\n
key,\n
tmp;\n
for (i = 0; i < list_gadget.length; i += 1) {\n
scope = list_gadget[i].getAttribute("data-gadget-scope");\n
if (scope !== undefined) {\n
url = list_gadget[i].getAttribute("data-gadget-url");\n
key = list_gadget[i].getAttribute("data-gadget-editable");\n
value = list_gadget[i].getAttribute("data-gadget-value");\n
//renderable \n
if (url !== undefined && url !== null) {\n
tmp = {};\n
scope = list_gadget[i].getAttribute("data-gadget-scope");\n
list.push(g.getDeclaredGadget(scope));\n
tmp.sandbox = list_gadget[i].getAttribute("data-gadget-sandbox");\n
tmp.editable = list_gadget[i].getAttribute("data-gadget-editable");\n
tmp.key = tmp.editable;\n
tmp.value = list_gadget[i].getAttribute("data-gadget-value");\n
tmp.editable = key;\n
tmp.key = key;\n
tmp.value = value;\n
gadget_attributes.push(tmp);\n
}\n
}\n
......@@ -122,15 +115,19 @@
})\n
.push(function (elements) {\n
var iframe,\n
j;\n
j,\n
sub_value,\n
sub_key;\n
list = [];\n
for (i = 0, j = 0; i < gadget_attributes.length; i += 1) {\n
if (all_gadget[i].render !== undefined) {\n
sub_value = gadget_attributes[i].value;\n
sub_key = gadget_attributes[i].key;\n
list.push(\n
all_gadget[i].render(\n
{\n
"key": gadget_attributes[i].key,\n
"value": gadget_attributes[i].value\n
"key": sub_key,\n
"value": sub_value\n
}\n
)\n
);\n
......@@ -151,12 +148,50 @@
return RSVP.all(list);\n
})\n
.push(function () {\n
return promiseEventListener(g.props.element,\n
\'submit\', false);\n
/*Do not use ajax call but submit an hidden form.\n
So in this way, we can use form submit mecanisme\n
provided by browser.\n
if use ajax, we should get the return page manually\n
which is difficult.\n
The new hidden fields have been added with the \n
gadget values and the submit button which \n
has been activated (relation field image, save button, etc).\n
This is done by listening the "click" event on the \n
submit/image button.\n
After all, submit the form manually again.\n
*/\n
var input_images =\n
g.props.element.querySelectorAll("input[type=\'image\']"),\n
input_submits =\n
g.props.element.querySelectorAll("button[type=\'submit\']");\n
list = [];\n
if (input_images.length || input_submits.length) {\n
list.push(promiseEventListener(g.props.element, "submit", false));\n
for (i = 0; i < input_images.length; i += 1) {\n
list.push(promiseEventListener(input_images[i], "click", false));\n
}\n
for (i = 0; i < input_submits.length; i += 1) {\n
list.push(promiseEventListener(input_submits[i], "click", false));\n
}\n
return RSVP.any(list);\n
}\n
return promiseEventListener(g.props.element, "submit", false);\n
})\n
.push(function (evt) {\n
var input,\n
hidden_button,\n
target;\n
list = [];\n
formdata = new FormData(evt.target);\n
if (evt.type === "click") {\n
input = document.createElement("input");\n
input.setAttribute("type", "hidden");\n
target = evt.currentTarget || evt.target;\n
input.setAttribute("name", target.getAttribute("name"));\n
form.appendChild(input);\n
} else {\n
hidden_button = g.props.element.querySelector(".hidden_button");\n
hidden_button.setAttribute("type", "hidden");\n
}\n
for (i = 0; i < all_gadget.length; i += 1) {\n
if (all_gadget[i].getContent !== undefined &&\n
gadget_attributes[i].editable !== null) {\n
......@@ -166,47 +201,25 @@
return RSVP.all(list);\n
})\n
.push(function (all_content) {\n
var key,\n
form,\n
arg,\n
result;\n
var input,\n
name;\n
for (i = 0; i < all_content.length; i += 1) {\n
for (key in all_content[i]) {\n
if (all_content[i].hasOwnProperty(key)) {\n
if (typeof all_content[i][key] === "object") {\n
arg = all_content[i][key];\n
result = convertDataURL2Blob(arg.url, arg.type);\n
formdata.append(key, result, arg.file_name);\n
} else {\n
formdata.append(key, all_content[i][key]);\n
}\n
for (name in all_content[i]) {\n
if (all_content[i].hasOwnProperty(name)) {\n
input = document.createElement("input");\n
input.setAttribute("type", "hidden");\n
input.setAttribute("name", name);\n
input.setAttribute("value", all_content[i][name]);\n
form.appendChild(input);\n
}\n
}\n
}\n
form = g.props.element.querySelector(\'form\');\n
return jIO.util.ajax(\n
{\n
"type": form.getAttribute("method"),\n
"url": form.getAttribute("action"),\n
"data": formdata,\n
"xhrFields":\n
{\n
withCredentials: true\n
}\n
}\n
);\n
})\n
.push(function (evt) {\n
//XXX WORK ONLY IN ERP5!!!!!\n
//In erp5, after form submit, a new page is redirected automatically\n
//so get the new url, it should use getResponseHeader(\'Location\')\n
//But since the response code is 302, we have no way to get new url\n
//with getResponseHeader, that\'s why in this cas, we use responseURL \n
//It only works in erp5. \n
return window.location.replace(evt.target.responseURL);\n
.push(function () {\n
form.submit();\n
});\n
});\n
}(window, rJS, RSVP));
}(window, document, rJS, RSVP));
]]></string> </value>
</item>
......@@ -216,7 +229,7 @@
</item>
<item>
<key> <string>size</string> </key>
<value> <int>6264</int> </value>
<value> <int>7063</int> </value>
</item>
<item>
<key> <string>title</string> </key>
......
......@@ -3,6 +3,7 @@ from Products.Formulator import Widget
from Products.Formulator.DummyField import fields
from Products.Formulator import Validator
from zLOG import LOG, ERROR
from cStringIO import StringIO
class GadgetWidget(Widget.TextWidget):
"""
......@@ -40,26 +41,43 @@ class GadgetWidget(Widget.TextWidget):
**kw)
def get_javascript_list(self, field, REQUEST=None):
"""
Returns list of javascript needed by the widget
"""
js_list = ['rsvp.js', 'renderjs.js', 'erp5_gadgetfield.js',
'jio_sha256.amd.js', 'jio.js']
result = []
try:
for js_file in js_list:
result.append(field.restrictedTraverse(js_file).absolute_url())
except KeyError:
LOG('keyError:', ERROR, 'Error Value: %s' % js_file)
return []
"""
Returns list of javascript needed by the widget
"""
js_list = ['rsvp.js', 'renderjs.js', 'erp5_gadgetfield.js']
result = []
try:
for js_file in js_list:
result.append(field.restrictedTraverse(js_file).absolute_url())
except KeyError:
LOG('keyError:', ERROR, 'Error Value: %s' % js_file)
return []
return result
return result
class GadgetFieldValidator(Validator.Validator):
property_names = Validator.Validator.property_names + ['data_url']
data_url = fields.CheckBoxField('data_url',
title='Data Url',
description=(
"Checked if gadget return data url."),
default=0)
def validate(self, field, key, REQUEST):
value = REQUEST.get(key, None)
if value is not None:
if field.get_value('data_url'):
value=value.split(",")[1]
return StringIO(value.decode('base64'))
return value
GadgetWidgetInstance = GadgetWidget()
GadgetFieldValidatorInstance = GadgetFieldValidator()
class GadgetField(ZMIField):
meta_type = "GadgetField"
widget = GadgetWidgetInstance
validator = Validator.FileValidatorInstance
validator = GadgetFieldValidatorInstance
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment