1
0
Fork 0

Prepare for DOM optimizations

Didn't get any actual work done.
master
Mike Gerwitz 2018-02-06 13:21:39 -05:00
commit 54e01628bb
4 changed files with 133 additions and 28 deletions

View File

@ -125,9 +125,7 @@ but don't sacrifice space on small screens.
border-color: #d33682;
}
.doc-notice.devnotice p::before,
.doc-notice.devnote p::before,
.doc-notice.tip p::before
.doc-notice p::before
{
display: block;
float: left;
@ -151,9 +149,12 @@ but don't sacrifice space on small screens.
content: '\261E';
}
.doc-notice.devnotice p,
.doc-notice.devnote p,
.doc-notice.tip p
.doc-notice.trivia p::before
{
content: '\1F914';
}
.doc-notice p
{
padding-left: 1.75em;
}

View File

@ -150,6 +150,18 @@ This system has maintenance concerns.
@end macro
@c Conveying the historical details of the project is important to
@c understand why the system exists in the state that it does
@c today. Use of this macro will hopefully help mitigate some of the
@c problems noted by Peter Naur in his paper Programming as Theory Building:
@c http://pages.cs.wisc.edu/~remzi/Naur.pdf
@macro trivia{text}
@noticestart{trivia}
\text\
@noticeend
@end macro
@c link to source file if URI is known, otherwise display
@c the path to the file
@ifset SRCURI

View File

@ -45,6 +45,7 @@ Programs are ideally compiled from a @ref{Program XML,,Program@tie{}XML}
@end menu
@node Program UI
@section Program UI
@maintenance{
@ -101,11 +102,13 @@ It also displays question help text (also configured through the XML)
and any error messages (@pxref{Error Handling}).
@menu
* Group Styles:: Different ways of displaying groups of questions to
the user.
* Group Styles:: Different ways of displaying groups of questions
to the user.
* DOM Abstraction :: Representing and efficiently manipulating the DOM.
@end menu
@node Group Styles
@subsection Group Styles
@refactor{
@ -187,6 +190,104 @@ A list of available styles is detailed in @ref{t:group-styles}.
@node DOM Abstraction
@subsection DOM Abstraction
@cindex DOM
@cindex Dojo, History
@cindex jQuery
@devnotice{jQuery is still used throughout parts of the framework and
is a performance bottleneck@mdash{
}it needs to be fully removed and replaced with this
DOM@tie{}abstraction.@footnote{
See @srcrefraw{src/ui/ElementStyler}.}}
@trivia{Liza was conceived long before frameworks like React existed.
The implementation originally used Dojo because of its
broad widget set,
but it was later dropped because of extreme performance issues,
especially on the browsers of the day
(Liza had to support Internet Explorer@tie{}6!);
at one point,
certain steps took over a minute to load for the
most unfortunate of users.
jQuery was then used for various parts of the UI and for ease of
DOM manipulation,
because of the lack of good and universal DOM APIs back then.
It too became a bottleneck.
Using DOM@tie{}APIs is now easy with modern browsers.}
Liza's DOM abstraction contains a couple of components:
@cindex DOM, Context
@cindex DOM, Field
@itemize
@item @dfn{DOM Fields} represent a field on the DOM.
Each field has a name and an index associated with the
DOM@tie{}node.
Nodes are cached in memory after first access and queue requests
during lookups to prevent stampeding.
Provides basic DOM operations,
including styling, containing row, and parent/sibling selecting.
See @srcref{src/ui/field}.
@item @dfn{DOM Context} is a slice of the DOM used for restricting queries.
It can attach and detach sections of the DOM,
and be further split into a context hierarchy.
The @srcrefjs{src/ui/context,DomContext} provides field querying
(see @srcrefjs{src/ui/field,DomField}) and caching.
See @srcrefraw{src/ui/context}.
@end itemize
@tip{It is important to always use these abstractions for any portions
of the DOM under control of this abstraction;
otherwise, assumptions used for caching may result in
unintended behavior.}
Using DOM contexts,
DOM operations can be restricted to small windows (for example,
groups or tabs),
further reducing the impact of DOM queries.
The @dfn{root context} is represented by
@srcrefjs{src/ui/context,RootDomContext}@mdash{
}sub-contexts can be obtained by invoking @jsmethod{slice} on any
context,
which creates a new context from a subset of the parent.
Detaching a parent will detach all child contexts.
Contexts can be manipulated in memory before being re-attached.
Detach a context from the DOM with @jsmethod{detach},
and attach with@tie{}@jsmethod{attach}.
A context is aware of its parent and will re-attach itself to the DOM
in the correct place.
A child context always attaches to the parent,
and so will not be rendered until the parent attaches.
@tip{Always detach from the DOM before performing extensive manipulations;
this prevents the need for expensive re-painting until
manipulation is done,
at which point the context can be re-attached.}
@menu
* Field Styling:: Styling @srcrefjs{src/ui/field,DomField}.
@end menu
@node Field Styling
@subsubsection Field Styling
@cindex Field, Styling
@helpwanted
@srcrefjs{src/ui/field,DomField} is styled using field stylers
(see @srcrefraw{src/ui/styler}).
The two most notable stylers are
@srcrefjs{src/ui/field/ErrorFieldStyler} and
@srcrefjs{src/ui/field/NaFieldStyler},
which style fields in error and hide fields that are no applicable
respectively.
@node Program XML
@section Program XML
@helpwanted
@ -301,6 +402,7 @@ There is no limit to the number of groups that can share the same link.
fields in the link.}
@node Specifying Predicates
@subsection Specifying Predicates

View File

@ -452,7 +452,13 @@ module.exports = Class( 'ElementStyler',
{
change_event = ( change_event === undefined ) ? true : change_event;
var $element;
// just to be sure before we fully remove this
if ( change_event !== false )
{
throw Error(
"ElementStyler#setValueByName change_event is being removed"
);
}
// set value
switch ( this._getElementType( name ) )
@ -486,35 +492,19 @@ module.exports = Class( 'ElementStyler',
var i = elements.length;
while ( i-- )
{
var $question = $( elements[ i ] );
if ( $question.attr( 'value' ) == value )
{
$question.attr( 'checked', true );
$element = $question;
}
else
{
$question.attr( 'checked', false );
}
const question = elements[ i ];
question.checked = ( question.value === ''+value );
}
break;
default:
$element = this.getElementByName(
const $element = this.getElementByName(
name, index, null, $context
);
$element.val( ''+( value ) );
}
// the autochange propery signifies that we should trigger the
// change event
if ( $element !== undefined && ( change_event || ( $element.data( 'autochange' ) === true ) ) )
{
$element.trigger( 'change' );
}
return this;
},