Using Wed in an Application¶
Wed is a schema-aware editor for XML documents. It runs in a web browser. The software is at the beta stage. It is currently used in a project for editing scholarly articles. We aim to make it extensible by means of a stable API, but the API is likely to change quickly for now.
Make sure to read Browser Requirements to learn which browsers are supported by wed.
Known limitations:
- Wed does not load documents containing XML comments (
<!-- ... -->
) or CDATA sections.
- Wed does not load documents containing XML comments (
Wed does not load documents that include processing instructions other than the
<?xml ...>
declaration at the very top of documents. (Some hold that the XML declaration is not a processing instruction. The distinction is irrelevant to the point being made here.)Wed supports most of Relax NG, with a few limitations. See the salve package for details.
Wed does not currently support ordering attributes according to some preference. (The order is alphabetic.)
Wed does not currently support multiline values in attributes.
Empty elements appear in the editor as if they had an opening and closing tag, irrespective of how they are encoded in the original document. So
<foo/>
and<foo></foo>
are treated the same. Part of this problem is due to the fact that wed sees the document as a DOM tree, not as a serialization. In a DOM tree,<foo/>
and<foo></foo>
are the same.Elements that must be empty appear in the editor as if they could contain contents. Note that the validator raises an error if these elements are filled with any contents but it would be nicer if they were displayed in a way that distinguished them from the elements that can be filled with contents. We worked on a prototype that would check whether an element can contain anything and display it differently if it could not. However, this required that the rendering engine query the validating engine during rendering, which made rendering extremely slow. Since the editor will raise an error if an element that should be empty is filled erroneously, we’ve decided that a solution to this problem can wait.
Eventually the plan is to handle XML namespace changes completely, and there is incipient code to deal with this; for now the safe thing to do if you have a file using multiple namespaces is to declare them once and for all on the top element, and never change them throughout the document. Otherwise, problems are likely.
[A significant issue here is that the various browsers do not handle namespaces in the same way. For instance FF and Chrome are absolutely fine if you specify
xmlns
with DOM’ssetAttribute
on an element that is on the same namespace as the namespace specified with the newxmlns
attribute and they will produce a correct serialization. IE, on the other hand, will produce a node with twoxmlns
attributes.]We’ve not tested a setup in which more than one wed instance appears on the same page. So using more than one wed editor on the same page could be problematic.
Keyboard navigation in contextual menus works. However, if the mouse is hovering over menu items, two items will be highlighted at once, which may be confusing. This seems to be a limitation of CSS which Bootstrap does nothing to deal with. (One element may be in the focused state (keyboard) while another is in the hover state.)
Wed does not work with RTL scripts. There no inherent reason wed could not support them but the project for which it is developed currently does not need support for RTL scripts. So no resources have been expended towards supporting this.
Wed is not internationalized. Although the contents of a document could be in any language, wed’s UI is in English. Again, there is no inherent reason wed could not support other languages for the UI. The project for which it is developed currently does not need support for other languages, hence this state of affairs.
See also Browser Requirements.
See also Round-Tripping, as some limitations there may affect whether you can use wed for your project.
Wed does not use XPath nor is it currently recommended to use XPath. See The XPath Problem.
Dependencies¶
Wed is packaged as an AMD module. To use it in a browser environment, you need to first load RequireJS and pass to it a configuration that will allow it to find wed’s code. An example of such configuration, which allows running the browser-dependent test suite, is located in config/requirejs-config-dev.js.
Warning
If you want to change this configuration for experimentation or to
match your local setup, please copy it to the local_config
directory and edit it there. This directory is not tracked by
git. This is true of all files that are stored in
config/.
Please see the package.json, config/requirejs-config-dev.js, Makefile and build.mk files for details regarding run-time and development dependencies. Running the test suite also requires that saxon be installed.
Wed works with jQuery 3.x and 2.x. We strongly recommend using jQuery 3.x. jQuery 2.x is no longer maintained by its development team and thus no longer receives security patches. There is no formal support for running wed with jQuery 1.x or earlier versions.
The optimized builds of wed include jQuery 3.x.
Building wed’s documentation additionally requires the following packages:
- rst2html
Running wed’s selenium-based tests additionally requires Python 2.7 and the
Python packages listed in dev_requirements.txt
.
If you want to contribute to wed, your code will have to pass the checks listed in .glerbl/repo_conf.py. So you either have to install glerbl to get those checks done for you or run the checks through other means. See Contributing.
Building¶
Everything generated during a build is output to the build/
subdirectory,
except for some documentation files like README.html
and CHANGELOG.html
,
which are in the root directory.
Wed uses gulp to build itself. You may want to create a gulp.local.js
file
to record settings specific to your own build environment. Run gulp --help
to see what variables you can set. Note that the variable names when use on the
command line have dashes where they would have underscore in
gulp.local.js
. For instance, on the command line you’d use
--behave-params
to set the parameters passed to behave
but in
gulp.local.js
it would be behave_params
. Also note that your
gulp.local.js
file should return a single anonymous object whose fields are
the values you want to set. For instance:
module.export = {
behave_params: "foo"
};
When everything is set, install gulp locally (npm install gulp
) and run:
$ gulp
Gulp will install locally some packages with npm
and download some external
packages that cannot be installed with npm
for whatever reason and place
them in downloads/
. It will then create a tree of files that could be served
by a web server. The files will be in build/standalone/
. As the name
“standalone” implies, this build includes everything needed to run wed on
your own server, except the configuration for RequireJS.
Gulp will additionally create an optimized version of wed in
build/packed/
. This is a version that has been optimized using Webpack. This
optimization exists for illustration purposes, for testing wed, and as a
possible candidate for deploying wed. See the
Deployment Considerations section in Advanced Usage Notes to
determine whether this is the optimization you want to use to deploy wed.
Testing¶
See Advanced Usage Notes.
Local Demos¶
The demos, you must have a minimal server running. To run a server suitable for the demos, you can do:
$ ./misc/server.js localhost:8888 &
The address and port localhost:8888
is just a suggestion, but the link in
the documentation below assume that’s the address used.
Demos Saving to a Server¶
Once the server is started, point your browser to either:
- http://localhost:8888/build/standalone/kitchen-sink.html to view the demo with the unoptimized file tree.
- or http://localhost:8888/build/packed/kitchen-sink.html to view the demo with an optimized file tree.
The demo currently starts with an empty document using a vanilla TEI schema. See Wed’s Help to learn what wed can do, in general.
When you save with this demo, the data is currently dumped into a file located
at build/ajax/save.txt
. You won’t be able to reload data from that file. For
full functionality wed needs to be used with a server able to save the data and
serve it intelligently.
Ctrl-` allows to go into development mode. Since this is meant only for
developers, you should read the source code of wed to know what this allows.
(In particular, search for this._development_mode
in the
_globalKeydownHandler
method.)
It is possible to run the kitchen sink with a different mode than the default
one (generic) by passing a mode
parameter in the URL, for instance the URL
http://localhost:8888/web/kitchen-sink.html?mode=tei would tell the kitchen
sink to load the tei mode.
Label Visibility¶
Wed allows the user to reduce or increase the number of element labeled on the screen. How this works is dependent in part on the specific mode that the user has selected. For instance, the default mode that comes with wed (the “generic” mode) knows only two levels of visibility: 0 and 1. At level 0, no elements are labeled. At level 1, all elements are labeled. A mode with levels 0, 1, and 2 would label all elements at level 2, no elements at level 0 and some elements at level 1. Which elements are labeled depends on how the mode designer designed the mode.
Using¶
Starting with version 0.31, wed is much stricter as to what it exposes to
libraries. The only parts of the code base that are safe to access are those
exported by the facade exposed as wed
. wed
exports EditorInstance
for the sake of allowing the creation of editors. However, modes must access
the editor through the interface defined in wed/mode-api
(which is
reexported by wed
). It is not legal for a mode to cast an EditorAPI
variable to anything that exposes members that are not exposed through
wed/mode-api
. Any access that bypasses the public API is liable to break
without notice, no complaints, no recourse.
Also note that under the new regime the only module that is generally legitimate
to load is wed
, and nothing else. You can probably still load individual
modules from the standalone
subdirectory as you used to, but this way of
operating is deprecated and will most likely be gone by version 1.0. There are a
few exceptions to the rule just given:
- You may load
wed/onerror
by itself to set an error handler. - You may load
wed/log
by itself if you need to mess with logging. - The files in
wed/glue
,wed/patches
andwed/polyfills
can (and sometimes must) be used indepdently of the mainwed
module. - You may load any module from the bundled editing modes. This may be useful to build your own modes.
To include wed in a web page you must:
Require
wed
Instantiate an
Editor
object of that module as follows:var editor = wed.makeEditor(widget, options); [...] editor.init(data);
Between the creation of the
Editor
object and the call toinit
, there conceivably could be some calls to add event handlers or condition handlers. Thewidget
parameter must be an element (preferably adiv
) that wed will take over to install its GUI. Theoptions
parameter is either an anonymous JavaScript object that contains the options to pass to the editor, or it can be aRuntime
object. If the latter, the options are passed to theRuntime
and the runtime is passed to theEditor
instance. Thedata
parameter is a string containing the document to edit, in XML format.
Options¶
The options
parameter is a dictionary which at present understands the
following keys:
schema
: the path to the schema to use for interpreting the document. This file must contain the result of doing the schema conversion required by salve since wed uses salve. See salve’s documentation.mode
: a simple object recording mode parameters. This object must have apath
field set to the RequireJS path of the mode. An optionaloptions
field may contain options to be passed to the mode. Wed comes bundled with a generic mode located at lib/wed/modes/generic/generic.js.ajaxlog
: See the documentation about remote logging.save
: See the documentation about saving.bluejaxOptions
: This is passed directly to Bluejax when the editor uses Bluejax. So you can use this to configure how many times wed would retry a failing connection, and whether it would provide error checking. The default value is:{ tries: 3, delay: 100, diagnose: { on: true, knownServers: [ "http://www.google.com/", "http://www.cloudfront.com/", ], }, };
There is no
serverURL
set because there’s no good default value for it.
Here is an example of an options
object:
{
schema: 'test/tei-simplified-rng.js',
mode: {
path: 'wed/modes/generic/generic',
options: {
metadata: '.../path/to/metadata'
}
}
}
The mode.options
will be passed to the generic mode when it is created. What
options are accepted and what they mean is determined by each mode.
Errors¶
The lib/wed/onerror.js module provides an error handler that could be
used with last-resort or with any
other error handler that can call a handler that takes a single argument which
is an error
DOM event. This handler tries to save the data in all editors
that exist in the window. Here is an example that uses last-resort
:
define(function (require) {
var lr = require("last-resort");
var onerror = require("wed/onerror");
var onError = lr.install(window);
onError.register(onerror.handler);
//...
Warning
IF YOU DO NOT SET THE HANDLER TO BE CALLED ON UNCAUGHT EXCEPTIONS, WED CANNOT DO ERROR RECOVERY. Previous versions of wed would automatically install a handler but the problem with this is that it makes wed a bad player when it is used on pages that already have their handlers.
Round-Tripping¶
At this stage wed does not guarantee that saving an unmodified document will sent the exact same string as what it was originally given to edit. This is due to the fact that the same document can be represented in XML in multiple ways. Notably:
- The XML declaration is not preserved.
- The order of the attributes could differ.
- The order and location of namespaces declarations could differ.
- The encoding of empty elements could differ. That is,
<foo></foo>
could become<foo/>
or vice-versa. - Whitespace before the start tag of the top element or after the end tag of the top element may not be preserved.
The Generic Mode¶
Wed is bundled with a single mode, the “generic” mode. We recommend to developers who wish to create modes to use the generic mode as their basis. Therefore, the explanations here should apply to those modes that follow our recommendations.
The generic mode is a mode that provides almost no customization of wed’s capabilities. For instance, a custom mode could represent elements that are paragraphs purely through indentation changes and line breaks rather than start and end labels. (Such a mode does exist for the BTW project.) The generic mode does not do this: it represents paragraphs as any other element, with a start label and end label.
Nonetheless, the generic mode requires a minimum amount of customization in order to be able to do its work. In particular, it needs to use a “metadata” file that provides information on the schema being used. This is necessary because Relax NG schemas often lack information that wed needs. For instance, while it is possible to include documentation about the elements that are part of a schema into a Relax NG schema, this is not the most convenient place for it. For one thing, salve (which is what wed uses for validation) right now does not save this information when it convert a Relax NG schema to use for validation. Even if it did, it would not solve all problems. The TEI documentation, for instance, is multilingual. Having it all stored in the schema would increase its size considerably, even if the user needs using only one language. It would be possible to produce schemas that include documentation only in one language but then you’d need one schema per language. By having the metadata be responsible for providing this documentation, wed can load only the language the user needs. Another issue that the metadata addresses is the fact that Relax NG schemas do not specify what prefix to use for namespaces. One of the jobs of the metadata is to provide defaults for namespace prefixes. These are used internally by the mode, rather than require mode developers to spell out namespace URIs every time they need to refer to a namespace. The XML file being edited can use whatever prefix desired, but the mode must have a standardized mapping of prefix to URI.
The information provided by the metadata is not made part of the mode itself because the information it provides may be orthogonal to the concerns of the mode. The generic mode is a case in point: it can work just as well (or as “generically”) for editing TEI documents as DocBook documents, or documents using any other schema. Or to take another example, TEI allows for quite a bit of customization: elements can be redefined, added, or removed. Entire modules can be added if a project calls for it. A mode specialized for editing TEI documents could have its metadata load only the documentation that pertains to the specific customization of TEI being used.
Therefore, the generic mode takes a metadata
option which is a simple string
which is a path to metadata that will be loaded by the mode.
Here is an example of what the mode
option passed to wed could contain:
path: 'wed/modes/generic/generic',
options: {
metadata: '../../../../../schemas/tei-math-metadata.json'
}
This tells wed to load the generic mode, and have it load the metadata file
../../../../../schemas/tei-math-metadata.json
.
The way the generic mode operates entails that three elements must cooperate for a file to be usable by wed:
- the correct schema must be passed to wed,
- the correct mode must be selected,
- this mode must load the correct metadata file.
Contributing¶
Contributions must pass the commit checks turned on in
.glerbl/repo_conf.py. Use glerbl install
to install the
hooks. Glerbl itself can be found at https://github.com/lddubeau/glerbl. It
will eventually make its way to the Python package repository so that pip
install glerbl
will work.