==================== Advanced Usage Notes ==================== Build Information ================= Every time a build is performed, the building process stores information about the build into a file which at run time is available as a module at the ``lib/wed/build-info`` location relative to the root of the build directory. This module contains two fields: * ``desc`` is a description of the build. This string is created by running ``git describe`` and adding to the result the string ``-unclean`` if the build was done with an unclean working tree. * ``date`` is the date of the build. (To be precise, it is the date at which the build ``build-info`` module was generated.) This information was added to wed as of version 0.11.0. If you happen to use wed's development code that was produced after version 0.10.0 was released but before version 0.11.0 was released, then the version number you'll get in the ``desc`` field will start with "v0.10.0-x". The additional "-x" is a special case to work around a bug in gitflow. .. _tech_notes_deployment_considerations: Deployment Considerations ========================= It is possible to deploy wed using the ``build/standalone/`` file tree but you will pay in execution time and bandwidth because the files in this tree are not optimized. The ``build/packed/`` file tree is optimized with Webpack. This optimization is designed to provide a balance between performance and flexibility. Greater performance could have been achieved by incorporating into one file all of the external libraries. However, such bundle would be unlikely to be trivially deployable on a full-fledged web site in which wed would be embedded. Such site might already be using jQuery and Bootstrap, perhaps different versions from those used to build wed, etc. The optimization described above could conceivably be used on this hypothetical server, provided that the configuration is updated to look for the external libraries at the right places. Schema and Structure Considerations =================================== The following discussion covers schema design considerations if you wish to use wed to enforce editing constraints. It is possible to rely instead on user discipline to enforce constraints, just like one would do if using a plain text editor to edit XML. If this is your case, then you do not need to concern yourself with the following. If you want constraints to be enforced **by wed**, then prioritize using a data structure that accurately reflects your **editing** concerns rather than your interchange concerns or your standard conformance concerns. Here's an example. Suppose that you use a schema based on the TEI markup, and that for interchange purposes with another system it makes sense to encode something like::

Étranger is a foreign term.

However, you do not want to allow your users to insert text inside the ```` element but outside ```` because that encoding is meaningless in your project. Wed is not designed to easily enforce this restriction. Wed will allow your users to create something like::

The term étranger is a foreign term.

The solution here is to represent the ```` structure as one element, for editing purposes. If it so happens that all instances of ```` are always to be interpreted as ```` for interchange purposes, then you might as well make your editing structure ```` and convert it to the interchange structure when you actually need to interchange. In other cases, you might want to create your own element for editing, like ````, which is then created in the right context by the mode you create for your project. .. _remote_logging: Remote Logging ============== Wed uses log4javascript to log anything worth logging. By default, wed does not log anything to a remote server; however, if the ``ajaxlog`` option is passed to wed, it will add an ``AjaxAppender`` to the logger and log messages using ``XmlLayout``. The ``ajaxlog`` option is of the form:: ajaxlog: { url: "...", headers: { ... } } The ``url`` parameter is the URL where log4javascript will send the log messages. The ``headers`` parameter specifies additional headers to send. In particular this is useful when the receiver is an installation requiring that some anti-CSRF token be set on HTTP headers. .. _saving: Saving ====== Wed saves documents using Ajax queries to a server. Where wed saves is determined by the ``save`` option. It is of the form:: save: { path: "...", options: { } } The ``path`` parameter is the path to the module that implements the ``Saver`` abstract class. The two choices for now are ``wed/savers/ajax`` and ``wed/savers/localforage``. Ajax Saver ---------- The Ajax saver requires a server that understands the wire protocol used by this saver. The configuration for it is as follows:: save: { path: "wed/savers/ajax", options: { url: "...", headers: { ... } autosave: ..., initial_etag: ..., } } The ``url`` option is required. It is the URL where wed will send the Ajax queries for saving. The ``headers`` option is as described above for logging. It is optional. The ``autosave`` option is a number of seconds between autosaves. It is optional. Setting it to 0 will turn off autosaving. Wed will autosave only if it detects that the document has been changed since the last save. The ``initial_etag`` option is the ``ETag`` of the document being loaded. It is required. Queries are sent as POST requests with the following parameters: * ``command``: the command wed is issuing. * ``version``: the version of wed issuing the command. * ``data``: The data associated with the command. This is always a string serialization of the data tree. The possible commands are: * ``check``: This is a mere version check. * ``save``: Sent when the user manually requests a save. * ``autosave``: Sent when an autosave occurs. * ``recover``: Sent when wed detects a fatal condition requiring reloading the editor from scratch. The server must save the data received and note that it was a recovery. The replies are sent as JSON-encoded data. Each reply is a single object with a single field named ``messages`` which is a list of messages. Each message has a ``type`` field which determines its meaning and what other fields may be present in the message. The possible message types are: * ``version_too_old_error`` indicates that the version of wed trying to access the server is too old. * ``save_transient_error`` indicates that the save operation cannot happen for some transient reason. The ``msg`` parameter on the message should give a user-friendly message indicating what the problem is and, to the extent possible, how to resolve it. * ``save_fatal_error`` indicates that the save operation failed fatally. This is used for cases where the user cannot reasonably do anything to resolve the problem. * ``locked_error`` indicates that the document the user wants to save is locked. * ``save_successful`` indicates that the save was successful. The protocol uses ``If-Match`` to check that the document being saved has not been edited by some other user. Therefore, it needs an ``ETag`` to be generated. It acquires its initial ``ETag`` from the ``save`` option described above. Subsequent successful save operations must provide an ``ETag`` value representing the saved document. The meaning of the ``ETag`` value is generally ambiguous. See the following documents for some discussions of the issue: - https://datatracker.ietf.org/doc/draft-whitehead-http-etag/ - https://datatracker.ietf.org/doc/draft-reschke-http-etag-on-write/ The current code handles the lack of precision such that ``ETag`` values returned on error conditions are ignored. Otherwise, the following could happen: 1. Alice loads document, grabs initial ``ETag``. 2. Bob loads same document, grabs initial ``ETag``. 3. Bob saves new version, creates new ``ETag``. 4. Alice tries to save with an ``If-Match`` that has the old ``ETag``. This fails and returns an ``ETag`` with the response. This last ``ETag`` would have to be the one that matches what is *currently* stored in the server. Alice's wed instance **must not** use this ``ETag`` to update the ``ETag`` it associates with its document, otherwise a subsequent save will (erroneously) go through. This may not correspond to how other systems use ``ETag``. Localforage Saver ----------------- .. warning:: The localForage saver is deprecated. It is no longer used by wed's development team, and comes with serious caveats. This saver uses `localForage `_ to store the data in the browser. It is configured as follows:: save: { path: "wed/savers/localforage", options: { name: "..." } } The ``name`` parameter is the name to use for saving the document in localForage. It is the "file name" of sorts of the document. Testing ======= Note that due to the asynchronous nature of the JavaScript environments used to run the tests, if the test suites are run on a system experiencing heavy load or if the OS has to swap a lot of memory from the hard disk, they may fail some or all tests. We've witnessed this happen, for instance, due to RequireJS timing out on a ``require()`` call because the OS was busy loading things into memory from swap. The solution is to run the test suites again. Another issue with running the tests is that wed uses ``setTimeout`` to do the validation work in a parallel fashion. (This actually simulates parallelism.) Now, browsers clamp timeouts to at most once a second for tests that are in background tabs (i.e. tabs whose content is not currently visible). Some tests want the first validation to be finished before starting. The upshot is that if the test tab is pushed to the background some tests will fail due to timeouts. The solution for now is don't push the tab in which tests are run to the background. Web workers would solve this problem but would create other complications so it is unclear whether they are a viable solution. Tests are of two types: * Karma-based tests. * Selenium-based tests which run *outside* the browser but use selenium to control a browser. Karma-Based Tests ----------------- To run the Karma-based tests do:: $ gulp test-karma These tests are located in the ``lib/tests/``. You can also run ``karma`` directly from the command line but having ``gulp`` build the ``test`` target will trigger a build to ensure that the tests are run against the latest code. .. warning:: Keep in mind that tests are **always** run against the code present in ``build/standalone/``. If you modify your source and fail to rebuild before running the test suite, the suite will run against **old code! In September 2017 we started implementing some of the tests in Karma and moving the tests that used to run in plain Node (i.e. Mocha running tests straight in the Node VM) to Karma. We evaluated the relative advantages of running the tests in jsdom, Chrome and ChromeHeadless. At some point in the implementation of the tests, we had 231 tests running in Karma, exercising multiple aspects of the DOM. Overall the speed results were: jsdom: 10.5s Chrome: 9.5s Chrome Headless: 8s There's no speed advantage to using jsdom relative to using Chrome, especially Chrome in headless mode. Also, the old Node+Mocha tests used to take 14s to run. Compare to the numbers above. There were many reasons for this. Some of it had to do with the fact that the TypeScript tests were compiled on the fly so the test run also included compilation time. The Karma tests, in contrast, run the pre-compiled code. Selenium-Based Tests -------------------- Everything that follows is specific to wed. You need to have `selenic `_ installed and available on your ``PYTHONPATH``. Read its documentation. You also need to have `wedutil `_ installed and available on your ``PYTHONPATH``. It is very likely that you'll want to override some of the values in :github:`config/selenium_config.py` by creating ``local_config/selenium_config.py`` that loads the default file but override or adds some values. For instance:: # If used, must appear before the default file is loaded. The # default is to not log anything. LOGS = True # Load the default file execfile("config/selenium_config.py") # Add some local values... SAUCELABS_CREDENTIALS = "foo:bar" CHROMEDRIVER_PATH = ".../selenium/chromedriver" Finally, to run the suite issue:: $ gulp selenium-test --behave-params="-D browser=,," Behind the scenes, this will launch Behave. An instance of ``./server.js`` will be launched automatically to respond to the requests of the browser that the test suite launches. See the gulpfile :github:`gulpfile.babel.js` for information about how behave is run. The ``browser`` variable determines which browser will run the test. You may omit any of ``platform``, ``browser`` or ``versions`` so long as the parts that are specified are enough to match a **single** configuration defined in :github:`config/selenium_config.py`. See the list of configurations there to see what has been configured. If you want something different from the list there, you'll have to configure it in the copy you made into ``local_config``. The environment variable ``BEHAVE_WAIT_BETWEEN_STEPS`` can be set to a numerical value in seconds to get behave to stop between steps. It makes the Selenium test unfold more slowly. The environment variable ``SELENIUM_QUIT`` can be set to ``never`` to prevent Selenium from quitting the browser after the suite is run. It can be set to ``on-success`` so that the Selenium quits only if the suite is successful. Q. Why is Python required to run the Selenium-based tests? You've introduced a dependency on an additional language! A. We've found that JavaScript is poorly supported by the various agents on which we depend for running Selenium the way we want. We've tried to avoid adding a dependency on Python to software which is JavaScript through and through, but that fight proved fruitless. Do we want to spend our time chasing bugs, badly documented code, and obscure or unsupported packages, or do we want to focus on wed? We chose the latter. Troubleshooting the Selenium Tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Symptom: All tests fail! ```````````````````````` Make sure that SauceConnect is running. Symptom: Some Firefox tests fail and I am at a loss to know why. ```````````````````````````````````````````````````````````````` Firefox is picky. Make sure you have a windows manager that manages FF's window. (This would come into play if you use Xephyr or Xnest for instance. You'd have to start a window manager running on the server they create.) Some tests that failed in Xephyr have also stopped failing once leftover windows from previous tests were closed. Internals ========= The Tag v0.10.0-x ----------------- The git repository contains tags v0.10.0 and v0.10.0-x. What's the deal? Both tags represent the same state of development. The first points into the master branch, the second into the develop branch. The second tag was created to work around a bug that prevents using ``git describe`` when using the `nvie edition `__ of gitflow. If you use gitflow with wed, use the `AVH edition `__. JavaScript Event Handling ------------------------- Modes are free to bind whatever handlers they want to those GUI elements they themselves are responsible for creating, managing and destroying. However, modes **must not** bind their own event handlers for the standard JavaScript type of events onto any GUI element that wed is responsible for managing. They must use the appropriate custom wed events. This ensures proper ordering of processing. Here is the list of JavaScript events for which custom events have been defined; the order the events are listed corresponds to the order they are processed * keydown: + wed-input-trigger-keydown + wed-global-keydown * keypress: + wed-input-trigger-keypress + wed-global-keypress * paste: + wed-post-paste * contextmenu: + wed-context-menu Those handlers that are bound to these custom events should have the following signature: ``handler(wed_event, javascript_event)`` Where ``wed_event`` is the jQuery ``Event`` object created for dispatching custom events and ``javascript_event`` is the original JavaScript event that caused the custom event to be triggered. .. warning:: Returning ``false`` from handlers bound to custom events won't stop the propagation of the original JavaScript event. Handlers for custom events that wish to stop propagation of the JavaScript event **must** call the appropriate method on the ``javascript_event`` object. They must additionally return ``false`` or call the appropriate methods on the ``wed_event`` object. * wed-input-trigger-* events are meant to be handled by ``InputTrigger`` objects. * wed-global-* events are meant to be handled by the default event handlers for wed, or those event handlers meaning to alter default processing. * The paste event has no wed-global-* event associated with it. Wed also uses the custom events ``wed-click`` and ``wed-unclick`` to inform element labels that they should change their status to clicked or unclicked. These events are used (``wed-click`` specifically) so that if the status must change due to an event not caused by a mouse operation, then wed won't cause a mouse event to happen. A ``click`` event would trickle up the handler chain, etc. Modes that define elements in the GUI tree that want to have their own custom context menu handler must listen for ``wed-context-menu`` **and** define a data field named ``data-wed-custom--context-menu`` set to a truthy value. This field must be set **in the DOM** as an attribute (and not merely using jQuery's ``data()`` method. Selections ---------- Wed works with multiple types of selections: DOM selection The selection as understood by DOM. Methods working with this selection have ``DOM`` in their name. GUI selection The selection in the GUI tree. The GUI selection is just called "selection", without any further qualifier. This is the range selected by the user in the document being edited. The methods operating on this selection do not use a special qualifier. Data selection The selection that corresponds to the GUI selection in the data tree. Methods working with this selection have ``data`` in their name. Mode will typically want to work with this selection. Carets ------ Wed works with multiple types of carets: Caret mark A caret that exists only for wed. It has no existence as a caret as far as DOM is concerned. GUI caret The caret in the GUI tree. It may or may not correspond to a DOM caret. Data caret The caret in the data tree that corresponds to the GUI caret. It may or may not correspond to a DOM caret. Support for GUI Controls Outside Wed ------------------------------------ By default, wed does not provide any kind of drop down menus or toolbar to perform actions like undo/redo, etc. The application that embeds wed into it, however, might need such tools. Now, the problem is that as far as wed is concerned, these items are not part of the editing pane and thus, manipulating them should cause a blurring of the editor. This is undesirable because: - It means that a GUI control that fires a transformation would fire it when the caret is not defined (because of the blur). This causes wed to raise an exception. - Even if the previous point could somehow be worked around because wed keeps enough state to know where the caret was before the blur happened, the user would still **see** the focus leave the editor pane. Consequently, such elements must be made known to wed so that it does not consider clicks in them to cause a loss of focus. ``Editor.excludeFromBlur`` is the method to use to register these elements with wed. .. warning:: These elements must also have ``mousedown`` and ``click`` handlers that do not cause the **browser** to change the focus. This typically means that handlers for these two events should prevent the default browser behavior. IM Support ---------- As usual, the browsers and various web standards make a mess of what ought to be simple. On both Firefox 23 and Chrome 29, entering text using IBus does not generate ``keypress`` events. The only events available are ``keydown`` and ``keyup``. Firefox 23 generates a single ``keyup`` event at the end of composition, Chrome 29 generates a bunch of ``keyup`` and ``keydown`` events while the character is being composed. These events are mostly useless because their parameters are set to values that do not indicate what the user is actually typing. The browsers also fire ``input`` and ``composition{start,update,end}`` events, which are also nearly useless. The ``input`` event does not state what was done to the data. The ``composition{start,update,end}`` events indicate that composition happened. In theory the ``data`` parameter should hold the data being changed, but on Chrome 29 the ``compositionend`` event has a blank ``data`` field when entering the Chinese character for wo3 ("I"). There's an additional complication in that these events can happen when the user wants to **edit** a composed character rather than delete or add text. Suppose that we are editing the string "livré" to read "livre". The way to do it without composition is in two operations: delete the "é" and insert "e" (or in the reverse order). However, with composition a character can be transformed into another character by one atomic change on the data. A composition method could make the change by replacing "é" with "e" as one operation, without there being a deletion followed by an insertion. The character itself is transformed. What wed currently does is capture all keydown and keypress events that are capturable to edit the data tree and **cancel** the default behavior. (Then the GUI tree is updated from the data tree and it looks like text input happened.) So these won't generate input events. When an input event **is** detected, compare all text nodes of the element on which the event triggered (a GUI node) with those of its corresponding data element. Update data nodes as needed. .. warning:: With this system, composed characters cannot serve as hot keys for the input triggers. GUI Tree and Data Tree ---------------------- Wed maintains two trees of DOM nodes: * A data tree which is not attached to the browser's document. (It is not visible. It does not receive events.) It is a mere representation in DOM format of the document being edited. You can think of this tree as being a part of the model aspect of the MVC pattern. (A ``TreeUpdater`` together with a data tree correspond to a model.) Note that this is an XML document. **It is currently not possible to perform searches in the data tree using ``querySelector`` and its friends if tags are prefixed**. So ``querySelector("foo:bar")`` won't find an element whose local name is ``foo:bar``. You can perform the search in the GUI tree to find the GUI node and convert to the data node. Or you can use ``getElementsByTagNameNS`` if you want to search in the data tree for specific tags. Or you can use ``domutil.dataFind/dataFindAll``. * A GUI tree which is derived from the data tree. This GUI tree is attached to the browser's document. It receives events and is what the user sees. You can think of this tree as being a part of the view and controler aspects of the MVC pattern. The ``GUIUpdater`` object stored in ``Editor._gui_updater`` is responsible for inserting and deleting the nodes of the GUI tree that corresponds to those of the data tree whenever the latter is modified. Elements of the GUI Tree ------------------------ Wed operates on an HTML structure constructed as follows: * All elements from the XML document become HTML ``div`` elements. * The original element's qualified name is stored as the first class in ``@class``. * All other classes that wed reserved to wed's own purposes have an underscore prepended to them. * All elements that correspond to an actual element in the XML document are of the ``_real`` class. * All elements that are added for decorative purposes are either in the ``_phantom`` or ``_phantom_wrap`` class. * A ``_phantom`` element is not editable, period. * A ``_phantom_wrap`` element is not itself editable but contains editable (``_real``) children. * The XML element's attributes are stored in attributes of the form: * ``data-wed-[name]-[diff]="..."`` when the attribute name is without namespace prefix * ``data-wed-[prefix]---[name]-[diff]="..."`` when the attribute name has a namespace prefix The ``[name]`` part is converted so that three dashes become four, four become five, etc. The ``[diff]`` part records differences between the origninal XML name and the name in HTML. Here are examples of XML attributes and what they become in HTML: * ``foo`` -> ``data-wed-foo-`` * ``xml:lang`` -> ``data-wed-xml---lang-`` * ``xml:a-b`` -> ``data-wed-xml---a-b-`` * ``xml:a---b`` -> ``data-wed-xml---a----b-`` * ``Foo`` -> ``data-wed-foo-u1``. This one encodes the fact that the original name had an uppercase first letter. * Wed may add attributes for its internal purposes. These do not correspond to any XML attributes. They are encoded as ``data-wed--[name]``. An XML attribute name or prefix may not begin with a dash, so there cannot be a clash. Classes Used by Wed ------------------- ``_phantom``: All elements added by wed for representing the data to the user are of this class. ``_phantom _gui``: All elements that are more that just uneditable text. ``_phantom _text``: All elements that are text added to represent some XML data. That is, there is some node in the data tree that corresponds specifically to this element. ``_phantom_wrap``: An element which is not itself editable but contains editable (``_real``) children. This cannot be used to wrap nodes that are text nodes in the data tree. ``_phantom _decoration_text``: All elements that are text added for purely decorative purposes. The difference between these elements and those which are ``_phantom _text`` is that the latter represents some contents whereas the former is purely decorating the data. For instance if an ```` element which points to the image of a cow is represented on screen by the word "cow" then this text should be ``_phantom _text``. On the other hand if a period is added after numbers in a list so that they look nice on screen, these periods should be ``_phantom _decoration_text`` elements. ``__start_label``: In combination with ``_gui``, indicates a label that marks the start of an element. ``__end_label``: In combination with ``_gui``, indicates a label that marks the end of an element. ``__label``: The ```` part is the name of an element. This class marks a label as belonging to an ```` element. For instance, a label for a ``p`` element will have the class ``_p_label``. The full set of classes for such a label which happens to mark the start of ``p`` will be ``_gui _phantom __start_label _p_label``. ``_start_wrapper``: Marks an element which wraps the editable content of an element. There may be many such elements at the start of an element. For instance a ``ref`` could contain an element label and then the phantom text ``(``. Both would be marked with this class. ``_end_wrapper``: Like ``_start_wrapper`` but marks the end. ``_readonly``: Marks an element or attribute that cannot be edited. Possible Due to Wildcard ------------------------ As explained in :ref:`complex_name_patterns`, wed *can* handle the name patterns ``NsName`` and ``AnyName`` for the purpose of validating a document but will not allow editing such elements. In order to limit this editing, during validation wed must set a flag on every element and attribute to indicate whether the element's or attribute's existence is only possible due to a wildcard. Then, the GUI rendering part of wed listens to changes to this flag and adds or remove the CSS class ``_readonly`` to the GUI elements that render the original XML element. This is specifically designed to avoid having the decorator refresh elements because this can get pretty expensive. Note that it is not possible to set the flag once and for all on an element and never change it. Suppose the following Relax NG:: start = element a { element q { empty }, any+ } any = element * { any* } The file ````. The first ``q`` validates because of ``element q`` in the schema. The second one because of ``any+``. If the first ``q`` is removed, then the 2nd ``q`` will become first and will validate because of ``element q``. In other words, the deletion of the first ``q`` *changes the reason* the second ``q`` is deemed valid. So the second ``q`` would be first flagged to be valid due to a wildcard, and then after the edit, the flag could be made false. Starting with a document that has ony one ``q`` and adding another ``q`` in front of it would also cause the flag to change, but the other way around. .. warning:: There may be ways to optimize the whole process so as to allow more substantial functionality than a CSS change but any such change should be considered very carefully. For instance, one may think that we could just have rendering code call the validator to perform a check on each element. Calling the validator from rendering code *is possible* but has a significant impact on performance. And it is tricky. If one is not careful, it is possible to create an infinite loop: rendering causes validation, which emits validation events, which cause rendering, which casues validation, which emits events... Browser Issues ============== The sad fact is that browsers are limited in functionality, buggy, or incompatible with each other. This section documents such issues. Cut, Paste, Copy ---------------- Copying and pasting don't present any special difficulties. However, cutting is problematic, because: 1. Browsers don't allow JavaScript to initiate cuts. So it is not possible to intercept a ``cut`` event and then cause the browser to cut by using a *different* event. 2. A cut modifies the DOM directly. This is a problem because wed wants modifications to go through ``TreeUpdater`` objects. An earlier version of wed was letting ``cut`` events go through and updated the data tree but this caused the GUI tree to become stale. (An additional complication is that there is no undoing.) It is possible to listen to ``cut`` events and let them go through or veto them, but this is about the maximum level of control that can be achieved cross-browser. ``contenteditable`` ------------------- Wed no longer uses ``contenteditable ``*generally* so the following section is mostly kept as a historical note. Incompatibilities ~~~~~~~~~~~~~~~~~ One area of incompatibility is the implementation of ``contenteditable`` across browsers. Even a single browser can behave inconsistently depending on how the DOM tree is structured. (In Firefox 20, the presence or absence of white-space text nodes sometimes changes the way BACKSPACE is handled when the caret is at the start of a ``contenteditable`` element.) Successive Elements and the Caret ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Suppose the structure::

foo bar

If you place the caret just before the space before "bar" and hit the left arrow to move it back between buttons A and B, various browsers will handle it differently. At any rate, in both Chrome 26 and Firefox 20, there will **not** be a caret **between** A and B. The caret may disappear or be moved somewhere else. The same result occurs if you place the caret after the space after ``foo`` and hit the right arrow. Setting the caret programmatically does not work either but in general results in the caret disappearing. Browsers differ a little bit. In Chrome 26, it seems that even though the caret becomes invisible, it still exists between the two elements. (It is possible to delete either button.) In Firefox 20, the caret becomes non-existent (editing is not possible). So to allow editing between successive elements, wed has to create a placeholder to allow the user to put their caret between elements. IE11 and line breaks ~~~~~~~~~~~~~~~~~~~~ We've discovered late that IE11 has a rendering issue with elements that are ``contenteditable``. Take the following::

This is a paragraph with highlighting and more

Read it as an abstract representation of the GUI tree. The start and end tags have corresponding labels in the GUI tree. More importantly, there is a line break between ``with`` and ``highlighting``. This is as we want it. This it how it works in Chrome and FF. In IE11, however, the ``hi`` element will be kept on one line, no matter what. The only way to have IE break it is to remove the ``contenteditable`` attribute from the element created for the GUI tree! Synthetic Keyboard Events ------------------------- In Firefox 20, it seems impossible to get the browser to handle a synthetic keyboard event exactly as if the user had typed it. The event can be created and dispatched, and it will trigger event handlers. However, sending a series of "keydown", "keypress", "keyup" events for the letter "a" while the caret is in a ``contenteditable`` region won't result in the letter "a" being added to the element being edited. It is possible to use plugins like sendkeys_ to simulate key presses that actually modify the contents of editable elements. However, when it comes to simulating key presses in ``contenteditable`` elements, the simulation is very imperfect. Cursory testing sending BACKSPACE using sendkeys and BACKSPACE using the keyboard shows inconsistent behavior. .. _sendkeys: http://bililite.com/blog/2011/01/23/improved-sendkeys/ Vetoing Mutations ----------------- It might seem that using MutationObserver to check on a DOM tree, one would be able to veto a user-initiated change inside ``contenteditable`` elements. In practice, a single keyboard key (like BACKSPACE) hit might result in 5-6 mutations of the DOM tree, and there is no simple way to know that these 5-6 mutations were all initiated by a single key. .. _tech_notes_xpath: The XPath Problem ----------------- Wed does not use XPath internally. A mode that you develop for wed **could** require the use of XPath but please read on before making that choice. The issues: 1. Browsers only natively support XPath 1. 2. On some browsers (any version of Internet Explorer, for instance), the way to perform XPath queries is radically different from other browsers. Most browsers will allow performing queries on a document produced with ``DOMParser``. Moreover the document produced by ``DOMParser`` is a DOM document with support for all the DOM methods normally found on a document. The machinery for XPath queries on IE browsers on the other hand produce an "document" which is not an actual DOM document. It is an entirely different beast. (Just to name one simple difference: you can use ``querySelector`` on documents created using ``DOMParser``. You cannot do the same on the document created through IE's ActiveXObject nonsense.) So using the browser machinery would require (at least) two significantly different methods of working with XML documents. 3. There are non-native solutions that *should* work on various browsers. However, + `Wicked Good XPath `__ has a `basic flaw `_ in how it handles case-sensitivity. It works inconsistently across platforms. + `This library `__ seems a better choice but it is currently in flux and has no clear releases. + The version of Saxon that loads in browsers has support for XPath but this means loading a huge library. There's no trivial way to support XPath right now. We're keeping an eye on development of XPath libraries to determine a moment when adding such support is reasonable. Historical Notes ================ Initially wed was designed with the idea that ``contenteditable`` would take care of caret management, selection management, text entry, etc. Consequently, wed would let the browser drive the management of these things and query the browser to know where the caret was, whether there was a selection, etc. However, experience soon proved that the browsers did not handle these functions in a way that was appropriate for wed. So wed had to take over the management of some of these functions. Since there was always some hope that at least *some* of these functions could *still* be delegated to the browser, these changes happened incrementally, changing only as much as needed to get the desired result. Some of these changes made earlier code obsolete but this was not discovered immediately. So wed evolved form this approach: * The browser is the authority on the caret position, the selection, and related things. Wed queries the browser as needed. To this approach: * Wed is the authority on the caret position, the selection, and related things. Wed updates the browser's idea of such things as needed. The incremental nature of the changes made it so that overtime code that operated under the first approach was found right next to code that operated under the second approach. Version 0.17.0 cleaned up a good deal of the old code (first approach) that was made obsolete by the incremental changes, but some obsolete code may still remain. Prior to version 3.x, wed made the GUI tree use ``contenteditable="true"`` As of version 3.x, wed no longer uses ``contenteditable`` *generally*. It is used for a few very specific functions. .. LocalWords: truthy unclicked unclick github gui requirejs py deployable js .. LocalWords: AVH nvie SauceLabs wedutil gitflow CSS programmatically desc .. LocalWords: namespace DOM PYTHONPATH config selenic setTimeout RequireJS .. LocalWords: Github msg JSON CSRF url ajaxlog IM XmlLayout AjaxAppender TEI .. LocalWords: IBus étranger Étranger GUIUpdater capturable livre livré keyup .. LocalWords: compositionend sendkeys lang xml prepended wed's InputTrigger .. LocalWords: contextmenu jQuery javascript keypress keydown contenteditable .. LocalWords: MutationObserver