From: Matěj Cepl on
Hi,

I wrote a jetpack (http://bit.ly/rhbzjetpack) for working at the Red Hat
Bugzilla. I am playing with the idea, whether it wouldn't be possible to
add offline capability to my bugzilla processing (there is no Internet
connection in the Prague metro ;)). Would it be possible to catch
"submit" event with addEventListener, and if we are offline, store the
request (somehow) to the local storage (jetpack.simple.storage or DOM
Storage or ???), and when switching online (or restarting Firefox when
online) pushing these requests (somehow) to the bugzilla.

Of course the foundation of this would be something like this:

------------------------------------------------------------------------

var win = jetpack.tabs.focused.contentWindow;

function newsubmit(event) {
var target = event ? event.target : this;

// do anything you like here
console.log('Submitting form to ' + target.action);

// call real submit function
if ( navigator.online ) {
this._submit();
} else {
reqQueue.push( <something> ); // HOW?
}
}

function submitQueue() {
reqQueue.forEach( submitItem ); // HOW?
}

// in the initialization part of the jetpack

win.addEventListener( "submit", newsubmit, false);
// If a script calls someForm.submit(), the onsubmit event does not
// fire, so we need to redefine the submit method of the
// HTMLFormElement class.
HTMLFormElement.prototype._submit =
HTMLFormElement.prototype.submit;
HTMLFormElement.prototype.submit = newsubmit;

win.addEventListener("online", submitQueue, false);

------------------------------------------------------------------------

Now the question is how to store the request in some form somewhere, and
when it is restored, how to submit it.

Any ideas? URLs for some related articles?

Thanks a lot for any suggestions,

Mat�j

--
http://www.ceplovi.cz/matej/, Jabber: mcepl<at>ceplovi.cz
GPG Finger: 89EF 4BC6 288A BF43 1BAB 25C3 E09F EF25 D964 84AC

I didn't attend the funeral, but I sent a nice letter saying
I approved of it.
-- Mark Twain
From: Thomas 'PointedEars' Lahn on
Matěj Cepl wrote:

> I wrote a jetpack (http://bit.ly/rhbzjetpack) for working at the Red Hat
> Bugzilla. I am playing with the idea, whether it wouldn't be possible to
> add offline capability to my bugzilla processing (there is no Internet
> connection in the Prague metro ;)). Would it be possible to catch
> "submit" event with addEventListener,

Yes, but unnecessary. Use the `onsubmit' attribute.

> and if we are offline, store the
> request (somehow) to the local storage (jetpack.simple.storage or DOM
> Storage or ???),

Yes.

> and when switching online (or restarting Firefox when
> online) pushing these requests (somehow) to the bugzilla.

Yes.

> [...]
> Now the question is how to store the request in some form somewhere, and
> when it is restored, how to submit it.
>
> Any ideas? URLs for some related articles?

You can store the form data in a cookie or Storage, and restore the form
data from it when applicable. You could make an non-modifying XHR request
to your server and handle it synchronously to see if you are online. You
need to assume you are online if XHR is not supported.


PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)
From: Matěj Cepl on
Dne 16.12.2009 22:55, Thomas 'PointedEars' Lahn napsal(a):
> Yes, but unnecessary. Use the `onsubmit' attribute.

According to
http://www.oreillynet.com/pub/a/network/2005/11/01/avoid-common-greasemonkey-pitfalls.html?page=3
XPCNativeWrappers (which is what jetpack gives me) have problems with
..on<event> attributes. Maybe it is not true about FF3.5 anymore (Jetpack
is FF3.5+ only)? However, anyway, this is immaterial to my issue, isn't it?

>> Now the question is how to store the request in some form somewhere, and
>> when it is restored, how to submit it.
>>
>> Any ideas? URLs for some related articles?
>
> You can store the form data in a cookie or Storage, and restore the form
> data from it when applicable. You could make an non-modifying XHR request
> to your server and handle it synchronously to see if you are online. You
> need to assume you are online if XHR is not supported.

Hmm, sounds interesting. I have in meantime dived a little bit more into
forms submission technology and I think I am getting some ideas now. It
will be fun to put it all together but it sounds doable. If I have
enough time, that is :(.

Best,

Matěj

--
http://www.ceplovi.cz/matej/, Jabber: mcepl<at>ceplovi.cz
GPG Finger: 89EF 4BC6 288A BF43 1BAB 25C3 E09F EF25 D964 84AC

Q: Is vi an easy editor to learn, is it intuitive?
A: Yes, some of us think so. But most people think that we are
crazy.
-- vi FAQ
From: Thomas 'PointedEars' Lahn on
Matěj Cepl wrote:

> Dne 16.12.2009 22:55, Thomas 'PointedEars' Lahn napsal(a):
>> Yes, but unnecessary. Use the `onsubmit' attribute.
>
> According to
> http://www.oreillynet.com/pub/a/network/2005/11/01/avoid-common-
greasemonkey-pitfalls.html?page=3
> XPCNativeWrappers (which is what jetpack gives me) have problems with
> .on<event> attributes.

Those are event-handler *properties*; I was talking about the `onsubmit'
*attribute* instead:

<form ... onsubmit="...">
...
</form>

Anyhow, if you are writing a GreaseMonkey script, you need to use
addEventListener('submit', ...), indeed. You may also need to remove
already added listeners beforehand.

>>> Now the question is how to store the request in some form somewhere, and
>>> when it is restored, how to submit it.
>>>
>>> Any ideas? URLs for some related articles?
>>
>> You can store the form data in a cookie or Storage, and restore the form
>> data from it when applicable. You could make an non-modifying XHR
>> request to your server and handle it synchronously to see if you are
>> online. You need to assume you are online if XHR is not supported.
>
> Hmm, sounds interesting. I have in meantime dived a little bit more into
> forms submission technology and I think I am getting some ideas now. It
> will be fun to put it all together but it sounds doable. If I have
> enough time, that is :(.

Following the beta of a form serialization method that I am going to
distribute as free software (under the GNU GPL v3) as part of
httprequest.js, which should be enough to get you started:

/**
* Retrieves the data to send in the request, and optionally the request
* method, from an (X)HTML form. TODO: select[multiple] elements
*
* @param f : HTMLFormElement
* @param bUseFormMethod: optional boolean
* If <code>true</code>, the form's request method becomes the
* <code>HTTPRequest</code> object's request method. The default
* is <code>false</code>.
* @return boolean
*/
getDataFromForm: function(f, bUseFormMethod) {
var result = false, es, len;

if (f && (es = f.elements) && (len = es.length))
{
if (bUseFormMethod) this.method = f.method;

var aData = [];

for (var i = 0; i < len; i++)
{
var o = es[i];
if (o.name)
{
aData.push(esc(o.name) + "=" + esc(o.value != "" ? o.value : ""));
}
}

this.data = aData.join("&");
result = true;
}

return result;
},


HTH

PointedEars
--
Prototype.js was written by people who don't know javascript for people
who don't know javascript. People who don't know javascript are not
the best source of advice on designing systems that use javascript.
-- Richard Cornford, cljs, <f806at$ail$1$8300dec7(a)news.demon.co.uk>
From: Thomas 'PointedEars' Lahn on
Thomas 'PointedEars' Lahn wrote:

> Matěj Cepl wrote:
>> Dne 16.12.2009 22:55, Thomas 'PointedEars' Lahn napsal(a):
>>> You can store the form data in a cookie or Storage, and restore the form
>>> data from it when applicable. You could make an non-modifying XHR
>>> request to your server and handle it synchronously to see if you are
>>> online. You need to assume you are online if XHR is not supported.
>>
>> Hmm, sounds interesting. I have in meantime dived a little bit more into
>> forms submission technology and I think I am getting some ideas now. It
>> will be fun to put it all together but it sounds doable. If I have
>> enough time, that is :(.
>
> Following the beta of a form serialization method that I am going to
> distribute as free software (under the GNU GPL v3) as part of
> httprequest.js, which should be enough to get you started:
>
> [...]

And here is a better (but still improvable), production code from another
project that I have not backported yet:

/* ------------------------------------------------------------------ */

/**
* @param f : Form|HTMLFormElement
* @return string
*/
function serializeForm(f)
{
var gotSubmit = false;

/**
* @param o
*/
function serializeControl(o)
{
/* HTML 4.01: Controls that are disabled cannot be successful. */
if (!o.disabled)
{
/*
* If a form contains more than one submit button,
* only the activated submit button is successful.
* (here: the first one)
*/
var isSubmit = /(^|\s)(submit|image)(\s|$)/i.test(o.type);
if (!gotSubmit || !isSubmit)
{
if (isSubmit) gotSubmit = true;

/*
* For menus, the control name is provided by a SELECT element
* and values are provided by OPTION elements. Only selected
* options may be successful. When no options are selected,
* the control is not successful and neither the name nor any
* values are submitted to the server when the form is submitted.
*/
var m = /(^|\s)(select(-one)?|undefined)(\s|$)/i.exec(o.type);
if (m)
{
/* select-one */
if (m[3])
{
if (o.selectedIndex > -1)
{
items.add(o.name, o.options[o.selectedIndex].value);
}
}

/* select */
else if (m[2])
{
for (var i = 0, opts = o.options, len = opts && opts.length;
i < len; i++)
{
var opt = opts[i];
if (opt.selected)
{
items.add(o.name, opt.value);
}
}
}
}

/*
* All "on" checkboxes may be successful.
* For radio buttons that share the same value of the
* name attribute, only the "on" radio button may be successful.
*/
else if (!/(^|\s)file|reset(\s|$)/i.test(o.type)
&& !(/(^|\s)object(\s|$)/i.test(o.tagName) && o.declare)
&& !/(^|\s)(checkbox|radio)(\s|$)/i.test(o.type)
|| o.checked)
{
items.add(o.name, o.value);
}
}
}
}

var es = getFeature(f, "elements");
if (es)
{
var items = [];

items.add = function(sName, sValue) {
var s = esc(sName) + "=" + esc(sValue);
this.push(s);
};

if (!isMethod(items, "push"))
{
items.push = function() {
for (var i = 0, len = arguments.length; i < len; i++)
{
items[items.length] = arguments[i];
}
};
}

for (var i = 0, len = es.length; i < len; i++)
{
var e = es[i];

/*
* Elements with the same name create a NodeList object,
* however options of select objects are also indexable in Gecko.
*/
if (typeof e[0] != "undefined" && typeof e.options == "undefined")
{
for (var j = 0, len2 = e.length; j < len2; j++)
{
serializeControl(e[j]);
}
}
else
{
serializeControl(e);
}
}

return items.join("&");
}

return "";
}

/* ------------------------------------------------------------------ */

esc(), getFeature() and isMethod() are user-defined, of course, but you
probably get the idea..


PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16