Priority: Normal
Current State: Closed
Released In: 1.1.6
Target Release: patch
Applies To: Extension
Component: JQueryPlugin
Branches: Release01x01 trunk
In html5 custom meta tags are no longer allowed. With a custom tag, the validator will give an error like:
Bad value foswiki.WIKIUSERNAME for attribute name on element meta: Keyword foswiki.wikiusername is not registered.
These values could as well be written as a piece of JSON text:
foswiki.data.meta = {
TOPIC: "WebHome",
WEB: "Main",
etc.
}
Affected files:
lib/Foswiki/Plugins/JQueryPlugin/FOSWIKI.pm (writes)
pub/System/JQueryPlugin/plugins/foswiki/jquery.foswiki.js (reads)
pub/System/JavascriptFiles/foswikilib (reads)
As fallback (for the updated plugin working on older Foswiki installations) the javascript code could check for the existence of
foswiki.data.meta
and use the old meta parsing if not found.
--
ArthurClemens - 30 Dec 2011
+1. I did something similar (use JSON instead of <meta> tag) with
TinyMCEPlugin ages ago, actually to cure some
I18N/encoding/unicode issues. Keeping everything as JSON keeps it simple(r).
--
PaulHarvey - 30 Dec 2011
By now jquery.foswiki caches all data to be moved from perl to javascript in the
foswiki.preferences
object. I don't see a need to rename
foswiki.preferences
to
foswiki.data
. We should keep it like this.
The access to this object is guarded by the
foswiki.getPreference()
method. It takes care of reading
foswiki.preferences
properly as well as loading additional data not included in EXPORTEDPREFERENCES using an ajax call to the foswiki server and cache it in
foswiki.preferences
.
That said, I don't see any problem in generating the
foswiki.preferences
right away using a json snipped as part of the html page instead of a set of
meta
tags.
The only problem is extensibility!
For now plugins could just add more meta tags to the head using a normal
ADDTOZONE{"head" text="meta tag"}
. In contrast, writing out a
foswiki.preferences
json object needs more care taking, maybe by defining a
preferences
zone in itself that anybody could write to using an appropriate
ADDTOZONE{"preferences=" text="some json property"}
call. These are all collected and rendered using some
RENDERZONE{"preferences" head="foswiki.preferences = {" separator="," footer="}"}
.
--
MichaelDaum - 30 Dec 2011
So we have a couple of objectives:
- plugins call "add to zone: preference", containing a key/value pair
- all zone preferences are collected in a list
- at
writeCompletePage
the preferences are rendered as JSON: foswiki.preferences = {}
, surrounded by script tags
So instead of the
addToZone
providing the
script
tags, the rendering is delegated to
renderZone
.
Instead of making the rendering of preferences a special case, this principle could be reused by adding a
type
attribute to
addToZone
.
Each type will be rendered specifically. For instance:
-
type="css"
will create surrounding style
tags
-
type="cssfile"
will create style src=""
tags
-
type="json"
will create style src=""
tags
-
type="jsonvalue"
will create a JSON property for each key/value
Likewise
-
type="preference"
will create a JSON property for each key/value, and surrounding foswiki.preferences={...}
code
That also introduces the concept of lists. Currently a zone with a previously used id will overwrite the older zone. It could be useful instead to create a list of zone elements with the same id.
In that case it would be possible to use
id
as the Javascript variable name:
addToZone( 'preference', 'foswiki.preferences', { name='SYSTEMWEB', value='System' } )
- For 'preferences',
type='jsonvalue'
would be assumed
- The
id
foswiki.preferences
could also be assumed, but not for other uses of type="jsonvalue"
- The
data
property for addToZone
is overloaded with a hash
--
ArthurClemens - 02 Jan 2012
I'm wary of doing something like that, because the transition will be painful (
ZonePlugin all over again)...
Something like
%ADDTOZONE{"jsonpreferences", text="key: \"value\""}%
... isn't as elegant, but still workable.
%RENDERZONE{
"jsonpreferences"
header="<script>foswiki.preferences = {$n"
format=" $item"
separator=",$n"
footer="};</script>"
}%
Or, can we use the LIBJS approach, i.e.
%TMPL:P{"foswiki.preferences" name="SYSTEMWEB" value="System"}%
approach again - at least then we could ship the necessary templates with
JQueryPlugin, to ease the upgrade pain.
--
PaulHarvey - 02 Jan 2012
That leaves a lot of specifics open to the programmer or template author. Currently he just has to write %RENDERZONE{"script"}%
.
The preferences are currently used by
JQueryPlugin, so rendering should be done by the plugin as well. But the plugin does not provide any templates to do that.
In all it would be ideal if the preferences are written to head ('script' zone) automatically.
Why would it be an transition problem if Foswiki 2.0 ships with a
type
parameter? We can do a version check in the perl code.
Ok, it
is nasty to get this right.
I am now opting to provide default
%TMPL:DEF{"renderzone"}%
variants:
%TMPL:DEF{"renderzone" zone="head"}%%RENDERZONE{"%zone%"}%%TMPL:END%
%TMPL:DEF{"renderzone:script"}%%RENDERZONE{"script"}%%TMPL:END%
%TMPL:DEF{"renderzone:head"}%%RENDERZONE{"head"}%%TMPL:END%
%TMPL:DEF{"renderzone:jsonpreference"}%%RENDERZONE{
"jsonpreference"
header="<script type='text/javascript'>
foswiki.preferences = {
"
footer="$n};$n</script>"
type="string"
format=" $item"
separator=",$n"
}%%TMPL:END%
This should be included in the lowest level template
foswiki.tmpl
, or provided in new template
zoneformats.tmpl
(and TMPL:INCLUDEd in
foswiki.tmpl
).
Change to
FOSWIKI.pm
:
if ( $Foswiki::Plugins::VERSION < 2.1 ) {
# add exported preferences to head using META tags
my $text = '';
foreach my $pref ( split( /\s*,\s*/, $prefs ) ) {
$text .=
'<meta name="foswiki.'
. $pref
. '" content="%ENCODE{"%'
. $pref
. '%"}%" />'
. " <!-- $pref -->\n";
}
Foswiki::Func::addToZone( "head", "JQUERYPLUGIN::FOSWIKI::META",
$text );
}
else {
# add exported preferences to head using a JSON object
foreach my $pref ( split( /\s*,\s*/, $prefs ) ) {
my $jsonPreference =
'"' . $pref . '": "' . '%ENCODE{"%' . $pref . '%"}%"';
Foswiki::Func::addToZone( "jsonpreference", undef,
$jsonPreference );
}
}
--
ArthurClemens - 03 Jan 2012
Why still produce
meta
tags for older foswikis? Both styles can be mixed freely. There isn't even a hurry to change plugins to make use of the new
preference
zone.
--
MichaelDaum - 04 Jan 2012
Because the jsonpreferences need to get rendered, and that won't be done automatically in older FW.
--
ArthurClemens - 04 Jan 2012
There's no need to render all preferences that are exported from foswiki to javascript using a single json object. Instead, plugins can use
$.extend()
to incrementally add to the
foswiki.preferences
object.
The initial stub is created like this:
<script>
jQuery.extend(foswiki, {
"preferences": {
...
}
});
</script>
Plugins can then add something like this to the script zone:
<script>
jQuery(function($) {
$.extend(foswiki.preferences, {
...
});
});
</script>
A positive sideeffect of moving from meta to JSON is that we don't need to encapsulate preferences into an %ENCODE anymore, which in turn breaks utf8 encoded values ... a bug in its own.
--
MichaelDaum - 10 Apr 2012
But how are the preferences fed to the js foswiki
object if we don't use meta tags?
Oh, I see, it is now done automatically by the plugin.
--
ArthurClemens - 10 Apr 2012