1
0
Fork 0
liza/src/ui/UiStyler.js

290 lines
7.3 KiB
JavaScript

/**
* UiStyler class
*
* Copyright (C) 2017 LoVullo Associates, Inc.
*
* This file is part of the Liza Data Collection Framework.
*
* liza is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Class = require( 'easejs' ).Class,
EventEmitter = require( 'events' ).EventEmitter;
/**
* Handles general styling of the GUI
*
* Supported events:
* questionHover - user hovers mouse over/out of a question
* questionFocus - question is given focus
*/
module.exports = Class( 'UiStyler' )
.extend( EventEmitter,
{
/**
* EventEmitter events
*
* This is a workaround for an issue whereby EventEmitter (which we are
* extending) only has access to the public state, whereas this class
* has access to private; the latter masks the former.
*
* TODO: Remove when this issue is corrected in ease.js.
*
* @var {Array}
*/
'public _events': {},
/**
* Content to be styled
* @type {jQuery}
*/
'private _$content': null,
/**
* Object used to style elements
* @type {ElementStyler}
*/
'private _elementStyler': null,
/**
* Context representing the active step
* @type {Context}
*/
'private _context': null,
/**
* Initializes styler on the given content
*
* The styler will monitor for changes to $content and apply the style to
* any new elements automatically.
*
* @param {jQuery} $content content to initialize
*
* @return {undefined}
*/
'public __construct': function( $content, element_styler )
{
this._$content = $content;
this._elementStyler = element_styler;
},
/**
* Template method that initializes all styles on the content
*
* @return {UiStyler} self
*/
'public init': function()
{
this._initQuestionHover();
this._initQuestionFocus();
this._initErrorBoxHover();
return this;
},
'public register': function( as )
{
var _self = this;
return function()
{
// refuse to raise events if we have no active context
if ( !( _self._context ) )
{
return;
}
_self.emit.apply( _self,
[ as, _self._context ]
.concat( Array.prototype.slice.call( arguments ) )
);
};
return this;
},
'public setContext': function( context )
{
this._context = context;
},
'public attach': function( styler )
{
var hooks = styler.getHooks();
for ( var event in hooks )
{
this.on( event, hooks[ event ] );
}
return this;
},
'public detach': function( styler )
{
var hooks = styler.getHooks();
for ( var event in hooks )
{
this.removeListener( event, hooks[ event ] );
}
return this;
},
/**
* Provides hover effects when mousing over a question row
*
* This is used (a) because CSS cannot be used for certain conditions and
* (b) because IE6 doesn't support :hover for anything other than links.
*
* @return {undefined}
*/
'private _initQuestionHover': function()
{
var _self = this;
this._$content.live( 'mouseover.program mouseout.program',
function( event )
{
var target = event.target || {},
parent = target.parentElement || {};
if ( parent.nodeName === 'DD' )
{
target = parent;
}
var hl = ( event.type == 'mouseover' ) ? true : false;
_self._highlightRow( $( target ), 'hover', hl );
// pass to callback
_self.emit( 'questionHover', target, hl );
}
);
},
/**
* Highlights the question row when it receives focus
*
* @return {undefined}
*/
'private _initQuestionFocus': function()
{
var _self = this;
this._$content.find( 'input' ).live( 'focus.program, blur.program',
function( event )
{
var hl = ( ( event.type == 'focus' )
|| ( event.type == 'focusin' ) )
? true : false;
// select the parent row, be it a normal question list or a
// table
var $element = $( this ).parents( 'dd:first, tr:first' );
_self._highlightRow( $element, 'focus', hl );
// pass to callback
_self.emit( 'questionFocus', this, hl );
}
);
},
/**
* Highlights the associated element when user hovers over error box with
* mouse
*
* @return {undefined}
*/
'private _initErrorBoxHover': function()
{
var _self = this;
this._$content.find( '.error-box li' )
.live( 'mouseover.program mouseout.program',
function( event )
{
var $this = $( this );
var name = $this.data( 'ref' );
var index = $this.data( 'ref_index' );
var $element = _self._$content.find(
'[name="' + name + '[]"]:nth(' + index + ')'
).parents( 'tr, dd' );
var hl = ( event.type == 'mouseover' ) ? true : false;
_self._highlightRow( $element, 'hover', hl );
}
);
},
/**
* Highlights a row
*
* The sibling dd or dt will be located and highlighted automatically.
*
* @param jQuery $element dd or dt to highlight
* @param String style class to apply
* @param Boolean apply whether to apply or remove the style
*
* @return undefined
*/
'private _highlightRow': function( $element, style, apply )
{
if ( $element.length == 0 )
{
return;
}
var node_name = $element.get( 0 ).nodeName,
elements = [ $element ],
element = null;
// locate the sibling element
var $other;
if ( node_name == 'DD' )
{
elements.push( $element.prev( 'dt' ) );
}
else if ( node_name == 'DT' )
{
elements.push( $element.next( 'dd' ) );
}
// apply or remove the style
var len = elements.length;
if ( apply )
{
for ( var i = 0; i < len; i++ )
{
elements[i].addClass( style );
}
}
else
{
for ( var i = 0; i < len; i++ )
{
elements[i].removeClass( style );
}
}
}
} );