Liberated StepUiBuilder
parent
9a1dd337eb
commit
44323a0b59
|
@ -0,0 +1,269 @@
|
|||
/**
|
||||
* Builds UI from template
|
||||
*
|
||||
* Copyright (C) 2015 LoVullo Associates, Inc.
|
||||
*
|
||||
* This file is part of liza.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* @needsLove
|
||||
* - Global references to jQuery must be removed.
|
||||
* - Dependencies need to be liberated:
|
||||
* - ElementStyler;
|
||||
* - UI.
|
||||
* - This may not be needed, may be able to be handled differently, and
|
||||
* really should load from data rather than a pre-generated template (?)
|
||||
* @end needsLove
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
EventEmitter = require( 'events' ).EventEmitter;
|
||||
|
||||
|
||||
module.exports = Class( 'StepUiBuilder' )
|
||||
.extend( EventEmitter,
|
||||
{
|
||||
/**
|
||||
* Used to style elements
|
||||
* @type {ElementStyler}
|
||||
*/
|
||||
'private _elementStyler': null,
|
||||
|
||||
/**
|
||||
* Used for building groups
|
||||
* @type {function()}
|
||||
*/
|
||||
'private _groupBuilder': null,
|
||||
|
||||
/**
|
||||
* Retrieves step data
|
||||
* @type {function( step_id: number )}
|
||||
*/
|
||||
'private _dataGet': null,
|
||||
|
||||
/**
|
||||
* Step that the StepUi is being modeled after
|
||||
* @type {Step}
|
||||
*/
|
||||
'private _step': null,
|
||||
|
||||
/**
|
||||
* Format bucket data for display
|
||||
* @type {BucketDataValidator}
|
||||
*/
|
||||
'private _formatter': null,
|
||||
|
||||
|
||||
'public __construct': function(
|
||||
element_styler,
|
||||
formatter,
|
||||
groupBuilder,
|
||||
dataGet
|
||||
)
|
||||
{
|
||||
this._elementStyler = element_styler;
|
||||
this._formatter = formatter;
|
||||
this._groupBuilder = groupBuilder;
|
||||
this._dataGet = dataGet;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Sets the underlying step
|
||||
*
|
||||
* @param {Step} step
|
||||
*
|
||||
* @return {StepUiBuilder} self
|
||||
*/
|
||||
'public setStep': function( step )
|
||||
{
|
||||
this._step = step;
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
'public build': function( StepUi, callback )
|
||||
{
|
||||
var _self = this;
|
||||
|
||||
if ( !( this._step ) )
|
||||
{
|
||||
throw Error( 'No step provided' );
|
||||
}
|
||||
|
||||
// create a new StepUi
|
||||
var ui = StepUi(
|
||||
this._step,
|
||||
this._elementStyler,
|
||||
this._formatter
|
||||
);
|
||||
|
||||
// retrieve and process the step data (this kick-starts the entire
|
||||
// process)
|
||||
this._getData( function( data )
|
||||
{
|
||||
_self._processData( data, ui );
|
||||
|
||||
// build is complete
|
||||
callback.call( null, ui );
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves step data using the previously provided function
|
||||
*
|
||||
* This process may be asynchronous.
|
||||
*
|
||||
* @param {function( data: Object )} callback function to call with data
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
'private _getData': function( callback )
|
||||
{
|
||||
this._dataGet.call( this, this._step.getId(), function( data )
|
||||
{
|
||||
callback( data );
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Processes the step data after it has been retrieved
|
||||
*
|
||||
* @param Object data step data (source should return as JSON)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
'private _processData': function( data, ui )
|
||||
{
|
||||
// sanity check
|
||||
if ( !( data.content.html ) )
|
||||
{
|
||||
// todo: show more information and give user option to retry
|
||||
data.content.html = '<h1>Error</h1><p>A problem was encountered ' +
|
||||
'while attempting to view this step.</p>';
|
||||
}
|
||||
|
||||
// enclose it in a div so that we have a single element we can query,
|
||||
// making our lives much easier
|
||||
ui.setContent(
|
||||
$( '<div class="raterStepDiv" />' )
|
||||
.attr( 'id', '__step' + ui.getStep().getId() )
|
||||
.html( data.content.html )
|
||||
);
|
||||
|
||||
// free the content from memory, as it's no longer needed (we don't need
|
||||
// both the DOM representation and the string representation in memory
|
||||
// for the life of the script - it's a waste)
|
||||
delete data.content;
|
||||
|
||||
// create the group objects
|
||||
this._createGroups( ui );
|
||||
|
||||
// track changes so we know when to validate and post
|
||||
ui.setDirtyTrigger();
|
||||
|
||||
// let others do any final processing before we consider ourselves
|
||||
// ready
|
||||
ui.emit( ui.__self.$( 'EVENT_POST_PROCESS' ) );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates Group objects for each group in the step content, then
|
||||
* styles them
|
||||
*
|
||||
* TODO: refactor into own builder
|
||||
*
|
||||
* @param {StepUi} ui new ui instance
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
'private _createGroups': function( ui )
|
||||
{
|
||||
// reference to self for use in closure
|
||||
var _self = this,
|
||||
groups = {},
|
||||
group = null,
|
||||
group_id = 0,
|
||||
|
||||
step = ui.getStep();
|
||||
|
||||
// instantiate a group object for each of the groups within this step
|
||||
var $groups = ( ui.getContent().find( '.stepGroup' ) ).each( function()
|
||||
{
|
||||
group = _self._groupBuilder( $( this ), _self._elementStyler );
|
||||
group_id = group.getGroupId();
|
||||
|
||||
groups[ group_id ] = group;
|
||||
|
||||
// let the step know what fields it contains
|
||||
step.addExclusiveFieldNames(
|
||||
group.getGroup().getExclusiveFieldNames()
|
||||
);
|
||||
|
||||
_self._hookGroup( group, ui );
|
||||
} );
|
||||
|
||||
// XXX: remove public property assignment
|
||||
ui.groups = groups;
|
||||
ui.initGroupFieldData();
|
||||
|
||||
// we can style all the groups, since the elements that cannot be styled
|
||||
// (e.g. table groups) have been removed already
|
||||
_self._elementStyler.apply( $groups, false );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Hook various group events for processing
|
||||
*
|
||||
* @param {GroupUi} group group to hook
|
||||
* @param {StepUi} ui new ui instance
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
'private _hookGroup': function( group, ui )
|
||||
{
|
||||
group
|
||||
.invalidate( function()
|
||||
{
|
||||
ui.invalidate();
|
||||
} )
|
||||
.on( 'indexAdd', function( index )
|
||||
{
|
||||
ui.emit( ui.__self.$( 'EVENT_INDEX_ADD' ), index, this );
|
||||
} )
|
||||
.on( 'indexRemove', function( index )
|
||||
{
|
||||
ui.emit( ui.__self.$( 'EVENT_INDEX_REMOVE' ), index, this );
|
||||
} ).on( 'indexReset', function( index )
|
||||
{
|
||||
ui.emit( ui.__self.$( 'EVENT_INDEX_RESET' ), index, this );
|
||||
} )
|
||||
.on( 'action', function( type, ref, index )
|
||||
{
|
||||
// simply forward
|
||||
ui.emit( ui.__self.$( 'EVENT_ACTION' ), type, ref, index );
|
||||
} )
|
||||
.on( 'postAddRow', function( index )
|
||||
{
|
||||
ui.emit( 'postAddRow', index );
|
||||
} );
|
||||
}
|
||||
} );
|
Loading…
Reference in New Issue