<commit_before>/**
 * Created by ksinger on 18.02.2016.
 */

import  won from '../won-es6';
import Immutable from 'immutable';
import { actionTypes, actionCreators } from './actions';
import { selectOpenPostUri } from '../selectors';

import {
    accessControl,
    checkAccessToCurrentRoute,
} from '../configRouting';

import {
    stateGoCurrent,
} from './cstm-router-actions';

import {
    checkLoginStatus,
    privateId2Credentials,
    login,
} from '../won-utils';

import config from '../config';

import {
    checkHttpStatus,
    getParameterByName,
} from '../utils';

import {
    fetchOwnedData,
    fetchDataForNonOwnedNeedOnly,
    emptyDataset,
    wellFormedPayload,
} from '../won-message-utils';

export const pageLoadAction = () => (dispatch, getState) => {
    /* TODO the data fetched here should be baked into
    * the send html thus significantly improving the
    * initial page-load-speed.
    * TODO fetch config data here as well
    */

    const privateId = getParameterByName('privateId'); // as this is one of the first action-creators to be executed, we need to get the param directly from the url-bar instead of `state.getIn(['router','currentParams','privateId'])`
    if(privateId) {
        /*
         * we don't have a valid session. however the url might contain `privateId`, which means
         * we're accessing an "accountless"-account and need to sign in with that
         */
        return loadingWithAnonymousAccount(dispatch, getState, privateId)
            .catch(e =>
                loadingWhileSignedOut(dispatch, getState)
        );
    }

    checkLoginStatus()
    /* handle data, dispatch actions */
    .then(data => loadingWhileSignedIn(dispatch, getState, data.username))
    .catch(error => {
        /*
         * ok, we're really not logged in -- thus we need to fetch any publicly visible, required data
         */
        loadingWhileSignedOut(dispatch, getState);
    });
};

function loadingWhileSignedIn(dispatch, getState, username) {
    loginSuccess(username, true, dispatch, getState);
    fetchOwnedData(username, dispatchInitialPageLoad(dispatch));
}

function loadingWithAnonymousAccount(dispatch, getState, privateId) {
    // using an anonymous account. need to log in.
    const {email, password} = privateId2Credentials(privateId);
    return login(email, password)
    /* quickly dispatch log-in status, even before loading data, to
     * allow making correct access-control decisions
     */
    .then(response => {
        loginSuccess(email, true, dispatch, getState);
        return response;
    })
    .then(response =>
        fetchOwnedData(email)
    ).then(allThatData => {
        return dispatch({
            type: actionTypes.initialPageLoad,
            payload: allThatData
        });
    }).catch(e => {
        console.error('failed to sign-in with privateId ', privateId, ' because of: ', e);
        return dispatch({
            type: actionTypes.loginFailed,
            payload: { loginError: 'invalid privateId', credentials: { privateId }}
        });
        throw e;
    });
    //dispatch(actionCreators.login(email, password));
    //return; // the login action should fetch the required data, so we're done here.
}

function loginSuccess(username, loginStatus, dispatch, getState) {

    // reset websocket to make sure it's using the logged-in session
    dispatch(actionCreators.reconnect());

    /* quickly dispatch log-in status, even before loading data, to
     * allow making correct access-control decisions
     */
    dispatchInitialPageLoad(dispatch)({email: username, loggedIn: loginStatus});

    checkAccessToCurrentRoute(dispatch, getState);
}

function loadingWhileSignedOut(dispatch, getState) {
    let dataPromise;
    const state = getState();
    const postUri = selectOpenPostUri(state);
    if(postUri && !state.getIn(["needs", postUri])) { //got an uri but no post loaded yet
        dataPromise = fetchDataForNonOwnedNeedOnly(postUri);
    } else {
        dataPromise = Promise.resolve(Immutable.Map());
    }
    return dataPromise.then(publicData =>
        dispatch({
            type: actionTypes.initialPageLoad,
            payload: publicData
        })
    ).then(() =>
        checkAccessToCurrentRoute(dispatch, getState)
    );

}

function dispatchInitialPageLoad(dispatch) {
    return payload => dispatch({
        type: actionTypes.initialPageLoad,
        payload: wellFormedPayload(payload),
    });
}

/////////// THE ACTIONCREATORS BELOW SHOULD BE PART OF PAGELOAD

/**
 * Anything that is load-once, read-only, global app-config
 * should be initialized in this action. Ideally all of this
 * should be baked-in/prerendered when shipping the code, in
 * future versions => TODO
 */
export function configInit() {
    return (dispatch) =>
        /* this allows the owner-app-server to dynamically switch default nodes. */
        fetch(/*relativePathToConfig=*/'appConfig/getDefaultWonNodeUri')
            .then(checkHttpStatus)
            .then(resp => resp.json())
            .catch(err => {
                const defaultNodeUri = `${location.protocol}://${location.host}/won/resource`;
                console.info(
                    'Failed to fetch default node uri at the relative path `',
                    'appConfig/getDefaultWonNodeUri',
                    '` (is the API endpoint there up and reachable?) -> falling back to the default ',
                    defaultNodeUri
                );
                return defaultNodeUri;
            })
            .then(defaultNodeUri =>
                dispatch(actionCreators.config__update({defaultNodeUri}))
        )
}

<commit_msg>Fixed loading of anon account.<commit_after>/**
 * Created by ksinger on 18.02.2016.
 */

import  won from '../won-es6';
import Immutable from 'immutable';
import { actionTypes, actionCreators } from './actions';
import { selectOpenPostUri } from '../selectors';

import {
    accessControl,
    checkAccessToCurrentRoute,
} from '../configRouting';

import {
    stateGoCurrent,
} from './cstm-router-actions';

import {
    checkLoginStatus,
    privateId2Credentials,
    login,
} from '../won-utils';

import config from '../config';

import {
    checkHttpStatus,
    getParameterByName,
} from '../utils';

import {
    fetchOwnedData,
    fetchDataForNonOwnedNeedOnly,
    emptyDataset,
    wellFormedPayload,
} from '../won-message-utils';

export const pageLoadAction = () => (dispatch, getState) => {
    /* TODO the data fetched here should be baked into
    * the send html thus significantly improving the
    * initial page-load-speed.
    * TODO fetch config data here as well
    */

    const privateId = getParameterByName('privateId'); // as this is one of the first action-creators to be executed, we need to get the param directly from the url-bar instead of `state.getIn(['router','currentParams','privateId'])`
    if(privateId) {
        /*
         * we don't have a valid session. however the url might contain `privateId`, which means
         * we're accessing an "accountless"-account and need to sign in with that
         */
        return loadingWithAnonymousAccount(dispatch, getState, privateId)
            .catch(e =>
                loadingWhileSignedOut(dispatch, getState)
        );
    }

    checkLoginStatus()
    /* handle data, dispatch actions */
    .then(data => loadingWhileSignedIn(dispatch, getState, data.username))
    .catch(error => {
        /*
         * ok, we're really not logged in -- thus we need to fetch any publicly visible, required data
         */
        loadingWhileSignedOut(dispatch, getState);
    });
};

function loadingWhileSignedIn(dispatch, getState, username) {
    loginSuccess(username, true, dispatch, getState);
    fetchOwnedData(username, dispatchInitialPageLoad(dispatch));
}

function loadingWithAnonymousAccount(dispatch, getState, privateId) {
    // using an anonymous account. need to log in.
    const {email, password} = privateId2Credentials(privateId);
    return login({privateId})
    /* quickly dispatch log-in status, even before loading data, to
     * allow making correct access-control decisions
     */
    .then(response => {
        loginSuccess(email, true, dispatch, getState);
        return response;
    })
    .then(response =>
        fetchOwnedData(email)
    ).then(allThatData => {
        return dispatch({
            type: actionTypes.initialPageLoad,
            payload: allThatData
        });
    }).catch(e => {
        console.error('failed to sign-in with privateId ', privateId, ' because of: ', e);
        return dispatch({
            type: actionTypes.loginFailed,
            payload: { loginError: 'invalid privateId', credentials: { privateId }}
        });
        throw e;
    });
    //dispatch(actionCreators.login(email, password));
    //return; // the login action should fetch the required data, so we're done here.
}

function loginSuccess(username, loginStatus, dispatch, getState) {

    // reset websocket to make sure it's using the logged-in session
    dispatch(actionCreators.reconnect());

    /* quickly dispatch log-in status, even before loading data, to
     * allow making correct access-control decisions
     */
    dispatchInitialPageLoad(dispatch)({email: username, loggedIn: loginStatus});

    checkAccessToCurrentRoute(dispatch, getState);
}

function loadingWhileSignedOut(dispatch, getState) {
    let dataPromise;
    const state = getState();
    const postUri = selectOpenPostUri(state);
    if(postUri && !state.getIn(["needs", postUri])) { //got an uri but no post loaded yet
        dataPromise = fetchDataForNonOwnedNeedOnly(postUri);
    } else {
        dataPromise = Promise.resolve(Immutable.Map());
    }
    return dataPromise.then(publicData =>
        dispatch({
            type: actionTypes.initialPageLoad,
            payload: publicData
        })
    ).then(() =>
        checkAccessToCurrentRoute(dispatch, getState)
    );

}

function dispatchInitialPageLoad(dispatch) {
    return payload => dispatch({
        type: actionTypes.initialPageLoad,
        payload: wellFormedPayload(payload),
    });
}

/////////// THE ACTIONCREATORS BELOW SHOULD BE PART OF PAGELOAD

/**
 * Anything that is load-once, read-only, global app-config
 * should be initialized in this action. Ideally all of this
 * should be baked-in/prerendered when shipping the code, in
 * future versions => TODO
 */
export function configInit() {
    return (dispatch) =>
        /* this allows the owner-app-server to dynamically switch default nodes. */
        fetch(/*relativePathToConfig=*/'appConfig/getDefaultWonNodeUri')
            .then(checkHttpStatus)
            .then(resp => resp.json())
            .catch(err => {
                const defaultNodeUri = `${location.protocol}://${location.host}/won/resource`;
                console.info(
                    'Failed to fetch default node uri at the relative path `',
                    'appConfig/getDefaultWonNodeUri',
                    '` (is the API endpoint there up and reachable?) -> falling back to the default ',
                    defaultNodeUri
                );
                return defaultNodeUri;
            })
            .then(defaultNodeUri =>
                dispatch(actionCreators.config__update({defaultNodeUri}))
        )
}

<|endoftext|>


<commit_before>iD.modes.AddLine = function(context) {
    var mode = {
        id: 'add-line',
        button: 'line',
        title: t('modes.add_line.title'),
        description: t('modes.add_line.description'),
        key: '2'
    };

    var behavior = iD.behavior.AddWay(context)
        .tail(t('modes.add_line.tail'))
        .on('start', start)
        .on('startFromWay', startFromWay)
        .on('startFromNode', startFromNode);

    function start(loc) {
        var graph = context.graph(),
            node = iD.Node({loc: loc}),
            way = iD.Way();

        context.perform(
            iD.actions.AddEntity(node),
            iD.actions.AddEntity(way),
            iD.actions.AddVertex(way.id, node.id));

        context.enter(iD.modes.DrawLine(context, way.id, graph));
    }

    function startFromWay(loc, edge) {
        var graph = context.graph(),
            node = iD.Node({loc: loc}),
            way = iD.Way();

        context.perform(
            iD.actions.AddEntity(node),
            iD.actions.AddEntity(way),
            iD.actions.AddVertex(way.id, node.id),
            iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));

        context.enter(iD.modes.DrawLine(context, way.id, graph));
    }

    function startFromNode(node) {
        var way = iD.Way();

        context.perform(
            iD.actions.AddEntity(way),
            iD.actions.AddVertex(way.id, node.id));

        context.enter(iD.modes.DrawLine(context, way.id, context.graph()));
    }

    mode.enter = function() {
        context.install(behavior);
    };

    mode.exit = function() {
        context.uninstall(behavior);
    };

    return mode;
};
<commit_msg>make sure DrawLine mode is called with a clean pre-operation graph<commit_after>iD.modes.AddLine = function(context) {
    var mode = {
        id: 'add-line',
        button: 'line',
        title: t('modes.add_line.title'),
        description: t('modes.add_line.description'),
        key: '2'
    };

    var behavior = iD.behavior.AddWay(context)
        .tail(t('modes.add_line.tail'))
        .on('start', start)
        .on('startFromWay', startFromWay)
        .on('startFromNode', startFromNode);

    function start(loc) {
        var baseGraph = context.graph(),
            node = iD.Node({loc: loc}),
            way = iD.Way();

        context.perform(
            iD.actions.AddEntity(node),
            iD.actions.AddEntity(way),
            iD.actions.AddVertex(way.id, node.id));

        context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
    }

    function startFromWay(loc, edge) {
        var baseGraph = context.graph(),
            node = iD.Node({loc: loc}),
            way = iD.Way();

        context.perform(
            iD.actions.AddEntity(node),
            iD.actions.AddEntity(way),
            iD.actions.AddVertex(way.id, node.id),
            iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));

        context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
    }

    function startFromNode(node) {
        var baseGraph = context.graph(),
            way = iD.Way();

        context.perform(
            iD.actions.AddEntity(way),
            iD.actions.AddVertex(way.id, node.id));

        context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
    }

    mode.enter = function() {
        context.install(behavior);
    };

    mode.exit = function() {
        context.uninstall(behavior);
    };

    return mode;
};
<|endoftext|>


<commit_before>/***********************************************************/
/*                    LiveFilter Plugin                    */
/*                      Version: 1.4                       */
/*                      Mike Merritt                       */
/*        https://github.com/mikemerritt/LiveFilter        */
/***********************************************************/

(function($){
  $.fn.liveFilter = function (options) {

    // Default settings
    var defaults = {
      delay: 0,
      defaultText: 'Type to Filter:',
      noMatches: 'No Matches',
      hideDefault: false,
      addInputs: false,
      zebra: {
        enabled: false,
        baseColor: false,
        altColor: false
      }
    };

    // Overwrite default settings with user provided ones. Declare some vars.
    var options = $.extend(defaults, options);
    var keyDelay, filter, child;

    // Cache our wrapper element and find our target list.
    var wrap = $(this);
    var filterTarget = wrap.find('ul, ol, table');

    // Add no matches text.
    wrap.append('
'+options.noMatches+'
');
    var nomatches = $('.nomatches');
    nomatches.hide();

    // Determine our child element type.
    if (filterTarget.is('ul') || filterTarget.is('ol')) {
      child = 'li';
    } else if (filterTarget.is('table')) {
      child = 'tbody tr';
    }

    // Hide the list/table by default. If not being hidden apply zebra striping if needed.
    if (options.hideDefault === true) {
      filterTarget.find(child).hide();
    } else if (options.hideDefault === false && options.zebra.enabled != false) {
      zebraStriping();
    }

    // Add inputs if required
    if (options.addInputs === true) {
      var markup = '<input class="filter" type="text" value="" /><input class="reset" type="reset" value="Reset!" />';
      wrap.prepend(markup);
    }

    // Used to reset our text input and show all items in the filtered list
    wrap.find('input[type="reset"]').on("click", function() {

      if (options.defaultText === false) {

        wrap.find('input[type="text"]').attr('value', '');

        if (options.hideDefault === false) {
          list.each(function(i) {
            $(this).show();
          });
        } else if (options.hideDefault === true) {
          list.each(function(i) {
            $(this).hide();
          });
        }

      } else {

        wrap.find('input[type="text"]').attr('value', options.defaultText);

        if (options.hideDefault === false) {
          list.each(function(i) {
            $(this).show();
          });
        } else if (options.hideDefault === true) {
          list.each(function(i) {
            $(this).hide();
          });
        }

      }
      return false;
    });

    // Used to set the default text of the text input if there is any
    if (options.defaultText != false) {

      var input = wrap.find('input[type="text"]');
      input.attr('value', options.defaultText);

      input.focus(function() {
        var curVal = $(this).attr('value');
        if (curVal === options.defaultText) {
          $(this).attr('value', '');
        }
      });

      input.blur(function() {
        var curVal = $(this).attr('value');
        if (curVal === '') {
          $(this).attr('value', options.defaultText);
        }
      });

    }

    // Cache list/table elements so we don't have to keep traversing the DOM.
    var list = filterTarget.find(child);

    // Keyup event - where the magic happens.
    wrap.find('input[type="text"]').on("keyup", function() {

      var input = $(this);
      clearTimeout(keyDelay);

      // Setting timeout for performance reasons.
      keyDelay = setTimeout(function () {

        filter = input.val().toLowerCase();
        var visible = 0;
        var words = filter.split(' ');

        if (filter === '' && options.hideDefault === true) {
          list.each(function(i) {
            $(this).hide();
          })
        } else {
          // Iterate through list and show/hide the proper elements.
          list.each(function(i) {
            text = $(this).text().toLowerCase();

            // Non consecutive filtering
            for (var t = 0; t < words.length; t++) {
              if (text.indexOf(words[t]) < 0) {
                var match = false;
                break;
              } else {
                var match = true;
              }
            }

            if (match === true) {
              visible ++;
              $(this).show();
            } else if (match === false) {
              $(this).hide();
            }
          });

          if (visible === 0) {
            nomatches.show();
          } else if (visible > 0) {
            nomatches.hide();
          }

          if(options.zebra.enabled != false) {
            zebraStriping();
          }
        }

        clearTimeout(keyDelay);
      }, options.delay);

    });

    // Used for zebra striping list/table.
    function zebraStriping() {
      filterTarget.find(child + ':visible:odd').css({ background: options.zebra.baseColor });
      filterTarget.find(child + ':visible:even').css({ background: options.zebra.altColor });
    }

  }
})(jQuery);<commit_msg>Hiding 'No Matches' text on reset button click.<commit_after>/***********************************************************/
/*                    LiveFilter Plugin                    */
/*                      Version: 1.4                       */
/*                      Mike Merritt                       */
/*        https://github.com/mikemerritt/LiveFilter        */
/***********************************************************/

(function($){
  $.fn.liveFilter = function (options) {

    // Default settings
    var defaults = {
      delay: 0,
      defaultText: 'Type to Filter:',
      noMatches: 'No Matches',
      hideDefault: false,
      addInputs: false,
      zebra: {
        enabled: false,
        baseColor: false,
        altColor: false
      }
    };

    // Overwrite default settings with user provided ones. Declare some vars.
    var options = $.extend(defaults, options);
    var keyDelay, filter, child;

    // Cache our wrapper element and find our target list.
    var wrap = $(this);
    var filterTarget = wrap.find('ul, ol, table');

    // Add no matches text.
    wrap.append('
'+options.noMatches+'
');
    var nomatches = $('.nomatches');
    nomatches.hide();

    // Determine our child element type.
    if (filterTarget.is('ul') || filterTarget.is('ol')) {
      child = 'li';
    } else if (filterTarget.is('table')) {
      child = 'tbody tr';
    }

    // Hide the list/table by default. If not being hidden apply zebra striping if needed.
    if (options.hideDefault === true) {
      filterTarget.find(child).hide();
    } else if (options.hideDefault === false && options.zebra.enabled != false) {
      zebraStriping();
    }

    // Add inputs if required
    if (options.addInputs === true) {
      var markup = '<input class="filter" type="text" value="" /><input class="reset" type="reset" value="Reset!" />';
      wrap.prepend(markup);
    }

    // Used to reset our text input and show all items in the filtered list
    wrap.find('input[type="reset"]').on("click", function() {
      nomatches.hide();

      if (options.defaultText === false) {

        wrap.find('input[type="text"]').attr('value', '');

        if (options.hideDefault === false) {
          list.each(function(i) {
            $(this).show();
          });
        } else if (options.hideDefault === true) {
          list.each(function(i) {
            $(this).hide();
          });
        }

      } else {

        wrap.find('input[type="text"]').attr('value', options.defaultText);

        if (options.hideDefault === false) {
          list.each(function(i) {
            $(this).show();
          });
        } else if (options.hideDefault === true) {
          list.each(function(i) {
            $(this).hide();
          });
        }

      }
      return false;
    });

    // Used to set the default text of the text input if there is any
    if (options.defaultText != false) {

      var input = wrap.find('input[type="text"]');
      input.attr('value', options.defaultText);

      input.focus(function() {
        var curVal = $(this).attr('value');
        if (curVal === options.defaultText) {
          $(this).attr('value', '');
        }
      });

      input.blur(function() {
        var curVal = $(this).attr('value');
        if (curVal === '') {
          $(this).attr('value', options.defaultText);
        }
      });

    }

    // Cache list/table elements so we don't have to keep traversing the DOM.
    var list = filterTarget.find(child);

    // Keyup event - where the magic happens.
    wrap.find('input[type="text"]').on("keyup", function() {

      var input = $(this);
      clearTimeout(keyDelay);

      // Setting timeout for performance reasons.
      keyDelay = setTimeout(function () {

        filter = input.val().toLowerCase();
        var visible = 0;
        var words = filter.split(' ');

        if (filter === '' && options.hideDefault === true) {
          list.each(function(i) {
            $(this).hide();
          })
        } else {
          // Iterate through list and show/hide the proper elements.
          list.each(function(i) {
            text = $(this).text().toLowerCase();

            // Non consecutive filtering
            for (var t = 0; t < words.length; t++) {
              if (text.indexOf(words[t]) < 0) {
                var match = false;
                break;
              } else {
                var match = true;
              }
            }

            if (match === true) {
              visible ++;
              $(this).show();
            } else if (match === false) {
              $(this).hide();
            }
          });

          if (visible === 0) {
            nomatches.show();
          } else if (visible > 0) {
            nomatches.hide();
          }

          if(options.zebra.enabled != false) {
            zebraStriping();
          }
        }

        clearTimeout(keyDelay);
      }, options.delay);

    });

    // Used for zebra striping list/table.
    function zebraStriping() {
      filterTarget.find(child + ':visible:odd').css({ background: options.zebra.baseColor });
      filterTarget.find(child + ':visible:even').css({ background: options.zebra.altColor });
    }

  }
})(jQuery);
<|endoftext|>


<commit_before>;(function($, undefined) {
    // ======================================================================
    // Transition jQuery function to animate Height/Width changes
    // ======================================================================
    $.fn.transition = function(options) {
        // options.property (required) eg. 'height' or 'width'
        // options.endValue (required) eg. 'auto', '' (initial value) or '100px' (absolute value)
        // options.duration (optional) eg. '0.3s', '300ms' etc.
        // options.timingFunction (optional) eg 'linear', 'ease' etc.

        // Default option values
        options.duration = options.duration || '0.3s';
        options.timingFunction = options.timingFunction || 'ease';

        $(this).each(function() {
            var autoValue;
            var $element = $(this);

            // remove any esiting transitionend.transition events bound to this element.
            $element.off('transitionend.transition');

            if ( ! $element.data('transition-in-progress') ) {
                // If not currently transitioning...
                $element.data('transition-in-progress', true);

                // Turn off transitions so javascript width/height changes are not animated
                $element.css('transition', 'none');

                var initialValue = $element[options.property]();

                // calculate auto width/height value and store in data-attribute
                $element.css(options.property, 'auto');
                autoValue = $element[options.property]();
                $element.data('transition-auto-value', autoValue);

                if (initialValue === options.endValue || options.endValue === 'auto' && initialValue === autoValue) {
                    // Element width/height already equals endValue, nothing to do
                    $element.data('transition-in-progress', false);
                    return;
                }

                // Reset element width/height to initialValue and force browser repaint by querying offsetWidth
                $element.css(options.property, initialValue);
                $element.get(0).offsetWidth;

                // Add inline css transition property to element
                $element.css('transition', options.property + ' ' + options.duration + ' ' + options.timingFunction);
            } else {
                // If currently transitioning...
                autoValue = $element.data('transition-auto-value');
            }

            // Set element width/height with inline css, specifying absolute pixel value
            if (options.endValue === 'auto') {
                $element.css(options.property, autoValue);
            } else {
                $element.css(options.property, options.endValue);
            }

            $element.one('transitionend.transition', function(event) {
                // when transition completes, clean up data attributes and inline CSS
                $element.removeData('transition-in-progress');
                $element.removeData('transition-auto-value');
                $element.css('transition', '');
                if (options.endValue === 'auto') {
                    // Set height to 'auto' to instead of autoHeight to accomodate responsive layouts
                    $element.css(options.property, 'auto');
                }
            });
        });

        return this;
    }
})(jQuery);<commit_msg>typos<commit_after>;(function($, undefined) {
    // ======================================================================
    // Transition jQuery function to animate Height/Width changes
    // ======================================================================
    $.fn.transition = function(options) {
        // options.property (required) eg. 'height' or 'width'
        // options.endValue (required) eg. 'auto', '' (initial value) or '100px' (absolute value)
        // options.duration (optional) eg. '0.3s', '300ms' etc.
        // options.timingFunction (optional) eg 'linear', 'ease' etc.

        // Default option values
        options.duration = options.duration || '0.3s';
        options.timingFunction = options.timingFunction || 'ease';

        $(this).each(function() {
            var autoValue;
            var $element = $(this);

            // remove any existing transitionend.transition events bound to this element.
            $element.off('transitionend.transition');

            if ( ! $element.data('transition-in-progress') ) {
                // If not currently transitioning...
                $element.data('transition-in-progress', true);

                // Turn off transitions so JavaScript width/height changes are not animated
                $element.css('transition', 'none');

                var initialValue = $element[options.property]();

                // calculate auto width/height value and store in data-attribute
                $element.css(options.property, 'auto');
                autoValue = $element[options.property]();
                $element.data('transition-auto-value', autoValue);

                if (initialValue === options.endValue || options.endValue === 'auto' && initialValue === autoValue) {
                    // Element width/height already equals endValue, nothing to do
                    $element.data('transition-in-progress', false);
                    return;
                }

                // Reset element width/height to initialValue and force browser repaint by querying offsetWidth
                $element.css(options.property, initialValue);
                $element.get(0).offsetWidth;

                // Add inline css transition property to element
                $element.css('transition', options.property + ' ' + options.duration + ' ' + options.timingFunction);
            } else {
                // If currently transitioning...
                autoValue = $element.data('transition-auto-value');
            }

            // Set element width/height with inline css, specifying absolute pixel value
            if (options.endValue === 'auto') {
                $element.css(options.property, autoValue);
            } else {
                $element.css(options.property, options.endValue);
            }

            $element.one('transitionend.transition', function(event) {
                // when transition completes, clean up data attributes and inline CSS
                $element.removeData('transition-in-progress');
                $element.removeData('transition-auto-value');
                $element.css('transition', '');
                if (options.endValue === 'auto') {
                    // Set height to 'auto' to instead of autoHeight to accommodate responsive layouts
                    $element.css(options.property, 'auto');
                }
            });
        });

        return this;
    }
})(jQuery);<|endoftext|>


<commit_before>// Server-side validation plugin
;(function($, window, document) {

    $.widget('qcode.validation', {

        options: {
            qtip: {
                position: {
                    my: 'bottom center',
                    at: 'bottom center',
                    viewport: $(window)
                },
                show: {
                    event: false,
                    ready: true
                },
                hide: {
                    event: 'click focus blurs reset keydown paste cut',
                    delay: 0
                },
                style: {
                    classes: 'qtip-qcode'
                },
                events: {
		    render: function(event, api) {
                        // Clicking on the tooltip causes the target element to gain focus and hides the tooltip.
			api.elements.tooltip.on('click', function(event) {
                            api.elements.target.focus();
                            // Call the hide method in case the default hide events were overwritten
                            api.hide();
                        });
		    }
                }
            },
            hints: {},
            messages: {
                error: {
                    classes: 'message-area error'
                },
                notify: {
                    classes: 'message-area notify'
                },
                alert: {
                    classes: 'message-area alert'
                }
            },
	    submit: true,
            timeout: 20000
        },

        _create: function() {
            var widget = this;
            var $form = $(this.element);
            this.message = [];

            // Logic for default http method to be used for validation service.
            if ( typeof this.options.method === 'undefined' ) {
                if ( typeof $form.attr('method') === 'undefined' || $form.attr('method') === 'GET' ) {
                    var method = 'VALIDATE';
                } else {
                    var method = 'POST';
                }
            } else {
                method = this.options.method;
            }

            // Default url used for validation service.
            if ( typeof this.options.url === 'undefined' ) {
                var url = $form.attr('action');
            }

            // Click handlers for submit buttons on the form.
            // Used to add hidden input elements with the button's name and value because jQuery form.serialize() function does not
            // include submit button data since it has no way of knowing which button was used to submit the form.
            $form.find('button:not([type]), button[type="submit"], input[type="submit"]').click(function(event) {
                var name = $(this).attr('name');
                var value = $(this).attr('value');

                if ($form.find('input[type="hidden"][name="' + name + '"]').length === 0) {
                    $(this).before('<input type="hidden" name="' + name  + '" value="' + value  + '">');
                }
            });

            // Handler function for submit event.
            function validate (event) {
                // Stop the form submission.
                event.preventDefault();
                var $form = $(this);

                // Do not allow concurrent validation requests
                if ( ! $form.is('.validating') ) {
                    $form.addClass('validating');

                    // blur() then focus() any text inputs in the form that currently have focus
                    // hack to fix bug where autocomplete popup can become detached from input when page layout changes (when error messages displayed/hidden)
                    $('input:focus', '#register').filter('[type=text],[type=email],[type=tel],[type=password]').blur().focus();

                    // Hide any existing validation messages
                    $('[data-hasqtip]:visible').qtip('hide');
                    $form.validation('hideMessage', 'alert');
                    $form.validation('hideMessage', 'notify');
                    $form.validation('hideMessage', 'error');

                    // Set up form data
                    var data = $form.serializeArray();
                    var ajax_method;
                    if ( method === 'POST' || method === 'GET' ) {
                        ajax_method = method;
                    } else {
                        // Emulate HTTP method
                        ajax_method = 'POST';
                        var found = false;
                        $.each(data, function(index, item) {
                            if ( item.name === '_method' ) {
                                item.value = method;
                                found = true;
                                return;
                            }
                        });

                        if ( !found ) {
                            data.push({
                                name: '_method',
                                value: method
                            });
                        }
                    }

                    // Send the form data
                    $.ajax({
                        url: url,
                        data: data,
                        method: ajax_method,
                        dataType: 'JSON',
                        headers: {
                            'X-Authenticity-Token': Cookies.get('authenticity_token')
                        },
                        timeout: widget.options.timeout,
                        success: function(response, success, request) {
                            $form.validation('parseResponse', response);

                            // Trigger validationComplete event
                            $form.trigger({
                                type: 'validationComplete',
                                response: response
                            });
                        },
                        error: function(jqXHR, textStatus, errorThrown) {
                            var returnType = jqXHR.getResponseHeader('content-type');

                            if ( returnType == "application/json; charset=utf-8" && jqXHR.status != 200 && jqXHR.status != 0 ) {
                                // HTTP Error with JSON response
                                var response = $.parseJSON(jqXHR.responseText)
                                $form.validation('parseResponse', response);

                                // Trigger validationComplete event
                                $form.trigger({
                                    type: 'validationComplete',
                                    response: response
                                });

                            } else {
                                if ( textStatus == "parsererror" ) {
                                    // Parse error
                                    var errorMessage = "Sorry, we were unable to parse the server's response. Please try again.";
                                } else if ( textStatus == "timeout" ) {
                                    // Timeout
                                    var errorMessage = "Sorry, your request timed out. Please try again.";
                                } else {
                                    // Generic error message
                                    var errorMessage = "Sorry, something went wrong. Please try again.";
                                }

                                // Show error message
                                $form.validation('showMessage', 'error', errorMessage);
                                scrollToElement($form.validation('getMessage', 'error'), 200);

                                // Trigger validationError event
                                $form.trigger({
                                    type: 'validationError',
                                    errorMessage: errorMessage
                                });
                            }
                        },
                        complete: function(jqXHR, textStatus) {
                            $form.removeClass('validating');
                        }
                    });
                }
            }

            $form.on('submit.validate', validate);
        },

        parseResponse: function(response) {
            // Parses the response to show qtips and messages where necessary.
            var $form = $(this.element);
            var $scrollElement = undefined;
            // Check each record item is valid.
            $.each(response.record, function (name, object) {
                var $element = $form.find('[name=' + name + ']');
                if ( ! object.valid ) {
                    // Record item not valid - mark invalid and display message to user.
                    if ( $element.length !== 0 ) {
                        $form.validation('showValidationMessage', $element, object.message);
                        $element.addClass('invalid');

                        // Compare to highest element on page so far
                        if ( typeof $scrollElement === 'undefined' || $element.offset().top < $scrollElement.offset().top ) {
                            $scrollElement = $element;
                        }
                    }
                } else {
                    $element.removeClass('invalid');
                }
            });

            // Show messages if action redirect is not given
            var showMessages = true;
            if ( response.action && response.action.redirect ) {
                // don't show messages if redirect action was given
                showMessages = false;
            }
            if ( response.action && response.action.resubmit && $form.data('resubmit-disabled')!==true ) {
                // don't show messages if resubmit action was given and resubmission has not been disabled
                showMessages = false;
            }
            if ( showMessages && response.message ) {
                $.each(response.message, function(type, object) {
                    $form.validation('showMessage', type, object.value);
                    // Compare message to highest element on page
                    var $message = $form.validation('getMessage', type);
                    if ( typeof $scrollElement === 'undefined' ||
                         ($message.is(':visible') && $message.offset().top < $scrollElement.offset().top) ) {
                        $scrollElement = $message;
                    }
                });
            }

            if ( response.status === 'valid' ) {
                // submission was valid

                // re-enable future resubmit actions
                $form.data('resubmit-disabled',false);

                // redirect action
                if ( response.action && response.action.redirect ) {
                    // Redirect if record was valid and the redirect action was given
                    window.location.href = response.action.redirect.value;
                    return;
                } else if ( this.options.submit ) {
                    // default action
                    // resubmit form without validation
                    $form.off('submit.validate').submit();
                    return;
                }
            } else {
                // submission was invalid

                // resubmit action - used for authenticity token errors
                if ( response.action && response.action.resubmit && $form.data('resubmit-disabled')!==true ) {
                    // resubmit the form
                    $form.submit();
                    // disable future resubmit actions to prevent inifite loop
                    $form.data('resubmit-disabled',true);
                    return;
                } else {
                    // re-enable future resubmit actions
                    $form.data('resubmit-disabled',false);
                }
            }

            // Scroll to the element if there is one to scroll to
            if ( typeof $scrollElement !== 'undefined' && typeof $scrollElement.qtip('api') !== 'undefined' ) {
                // $scrollElement exists and has has a qtip

                var scrollToHighest = function(api) {
                    // Scrolls to the highest element on the page out of three possible elements:
                    // the qtip, the element the qtip is bound to, and the label for the element if it has one.

                    // Check if element has a label
                    var $label = $form.find('label[for=' + $scrollElement.attr('id') + ']');
                    if ( $label.length === 0 ) {
                        $label = $scrollElement.closest('label');
                    }

                    // If a label was found then check if the label is higher than the element on the page
                    if ( $label.length > 0 && $label.offset().top < $scrollElement.offset().top ) {
                        $scrollElement = $label
                    }

                    // Compare the top offset of highest elements to the qtip tooltip
                    if ( api.tooltip.offset().top < $scrollElement.offset().top ) {
                        $scrollElement = api.tooltip;
                    }

                    scrollToElement($scrollElement, 200);
                }

                if ( $scrollElement.qtip('api').rendered ) {
                    // Qtip for element has been rendered so can scroll to it
                    scrollToHighest($scrollElement.qtip('api'));
                } else {
                    // Qtip hasn't been rendered yet - listen for render event then scroll to element
                    $scrollElement.qtip('api').set('events.render', function(event, api) {
                        // Clicking on the tooltip causes the target element to gain focus and hides the tooltip.
			api.elements.tooltip.on('click', function(event) {
                            api.elements.target.focus();
                            // Call the hide method in case the default hide events were overwritten
                            api.hide();
                        });
                        scrollToHighest(api);
		    });
                }
            } else if ( typeof $scrollElement !== 'undefined' ) {
                // $scrollElement exists but has no qtip - scroll to the $scrollElement
                scrollToElement($scrollElement, 200);
            }
        },

        showValidationMessage: function($element, message) {
            // Show the validation message with the message as the content for the given element.
            var api = $element.qtip('api');
            if ( api === undefined ) {
                var qtipOptions = {
                    content: message,
                    position: {
                        target: $element
                    }
                };
                $.extend(true, qtipOptions, this.options.qtip);
                $.each(this.options.hints, function(selector, hintOptions) {
                    if ( $element.is(selector) ) {
                        $.extend(true, qtipOptions, hintOptions);
                    }
                });
                // initialise qtip
                $element.qtip(qtipOptions);
            } else {
                // Update existing qtip and show
                api.set('content.text', message);
                api.reposition();
                api.show();
            }
            return $element;
        },

        hideValidationMessage: function($element) {
            // Hide the validation message for the given element.
            $element.qtip('hide');
            return $element;
        },

        showMessage: function(type, message) {
            // Show the message of the type given with message as the content.
            if (! this.message[type]) {
                // Message area doesn't exist so create it.
                var messageDiv = $('

').addClass(this.options.messages[type].classes)
                var messageContent = $('

').html(message).addClass('message-content');

                messageDiv.append(messageContent).hide();
                var validationElement = $(this.element);
                messageDiv.click(function(event){
                    validationElement.validation('hideMessage', type);
                    validationElement.validation('reposition');
                });

                if (this.options.messages[type].before) {
                    $(this.options.messages[type].before).before(messageDiv);
                } else if (this.options.messages[type].after) {
                    $(this.options.messages[type].after).after(messageDiv);
                } else {
                    $('body').append(messageDiv);
                }

                this.message[type] = messageDiv;
                messageDiv.show(200, $.proxy(function() {
                    this.reposition();
                }, this));
            } else {
                // Update the message
                this.message[type].find('.message-content').html(message);
                this.message[type].show(200, $.proxy(function() {
                    this.reposition();
                }, this));
            }
        },

        hideMessage: function(type) {
            // Hide the message with the given type.
            if (this.message[type]) {
                this.message[type].hide(100, $.proxy(function() {
                    this.reposition();
                }, this));
            }
        },

        getMessage: function(type) {
            // Returns the jquery object for the message of the given type
            return this.message[type];
        },

        reposition: function() {
            // Reposition or hide all validation messages.
            $('[data-hasqtip]').each(function() {
                if ( ! $(this).is(':visible') ) {
                    $(this).qtip('hide');
                } else {
                    $(this).qtip('reposition');
                }
            });
        },

        _destroy: function() {
            // Remove the elements created by this plugin.
            this.element.unbind('submit.validate');
            $(this.element).removeClass('validating');
            this._validationMessagesDestroy();
            this._messagesDestroy();
        },

        _validationMessagesDestroy: function() {
            // Destroy any tooltips associated with this element or it's descendants.
            $(this.element).find('[data-hasqtip]').qtip('destroy');
        },

        _messagesDestroy: function() {
            // Remove all messages added by this plugin.
            this.message['alert'].remove();
            this.message['error'].remove();
            this.message['notify'].remove();
        }

    });

})(jQuery, window, document);
<commit_msg>Update jquery.validation.js<commit_after>// Server-side validation plugin
;(function($, window, document) {

    $.widget('qcode.validation', {

        options: {
            qtip: {
                position: {
                    my: 'bottom center',
                    at: 'bottom center',
                    viewport: $(window)
                },
                show: {
                    event: false,
                    ready: true
                },
                hide: {
                    event: 'click focus blurs reset keydown paste cut',
                    delay: 0
                },
                style: {
                    classes: 'qtip-qcode'
                },
                events: {
		    render: function(event, api) {
                        // Clicking on the tooltip causes the target element to gain focus and hides the tooltip.
			api.elements.tooltip.on('click', function(event) {
                            api.elements.target.focus();
                            // Call the hide method in case the default hide events were overwritten
                            api.hide();
                        });
		    }
                }
            },
            hints: {},
            messages: {
                error: {
                    classes: 'message-area error'
                },
                notify: {
                    classes: 'message-area notify'
                },
                alert: {
                    classes: 'message-area alert'
                }
            },
	    submit: true,
            timeout: 20000
        },

        _create: function() {
            var widget = this;
            var $form = $(this.element);
            this.message = [];

            // Logic for default http method to be used for validation service.
            if ( typeof this.options.method === 'undefined' ) {
                if ( typeof $form.attr('method') === 'undefined' || $form.attr('method') === 'GET' ) {
                    var method = 'VALIDATE';
                } else {
                    var method = 'POST';
                }
            } else {
                method = this.options.method;
            }

            // Default url used for validation service.
            if ( typeof this.options.url === 'undefined' ) {
                var url = $form.attr('action');
            }

            // Click handlers for submit buttons on the form.
            // Used to add hidden input elements with the button's name and value because jQuery form.serialize() function does not
            // include submit button data since it has no way of knowing which button was used to submit the form.
            $form.find('button:not([type]), button[type="submit"], input[type="submit"]').click(function(event) {
                var name = $(this).attr('name');
                var value = $(this).attr('value');

                if ($form.find('input[type="hidden"][name="' + name + '"]').length === 0) {
                    $(this).before('<input type="hidden" name="' + name  + '" value="' + value  + '">');
                }
            });

            // Handler function for submit event.
            function validate (event) {
                // Stop the form submission.
                event.preventDefault();
                var $form = $(this);

                // Do not allow concurrent validation requests
                if ( ! $form.is('.validating') ) {
                    $form.addClass('validating');

                    // blur() then focus() any text inputs in the form that currently have focus
                    // hack to fix bug where autocomplete popup can become detached from input when page layout changes (when error messages displayed/hidden)
                    $('input:focus', $form).filter('[type=text],[type=email],[type=tel],[type=password]').blur().focus();

                    // Hide any existing validation messages
                    $('[data-hasqtip]:visible').qtip('hide');
                    $form.validation('hideMessage', 'alert');
                    $form.validation('hideMessage', 'notify');
                    $form.validation('hideMessage', 'error');

                    // Set up form data
                    var data = $form.serializeArray();
                    var ajax_method;
                    if ( method === 'POST' || method === 'GET' ) {
                        ajax_method = method;
                    } else {
                        // Emulate HTTP method
                        ajax_method = 'POST';
                        var found = false;
                        $.each(data, function(index, item) {
                            if ( item.name === '_method' ) {
                                item.value = method;
                                found = true;
                                return;
                            }
                        });

                        if ( !found ) {
                            data.push({
                                name: '_method',
                                value: method
                            });
                        }
                    }

                    // Send the form data
                    $.ajax({
                        url: url,
                        data: data,
                        method: ajax_method,
                        dataType: 'JSON',
                        headers: {
                            'X-Authenticity-Token': Cookies.get('authenticity_token')
                        },
                        timeout: widget.options.timeout,
                        success: function(response, success, request) {
                            $form.validation('parseResponse', response);

                            // Trigger validationComplete event
                            $form.trigger({
                                type: 'validationComplete',
                                response: response
                            });
                        },
                        error: function(jqXHR, textStatus, errorThrown) {
                            var returnType = jqXHR.getResponseHeader('content-type');

                            if ( returnType == "application/json; charset=utf-8" && jqXHR.status != 200 && jqXHR.status != 0 ) {
                                // HTTP Error with JSON response
                                var response = $.parseJSON(jqXHR.responseText)
                                $form.validation('parseResponse', response);

                                // Trigger validationComplete event
                                $form.trigger({
                                    type: 'validationComplete',
                                    response: response
                                });

                            } else {
                                if ( textStatus == "parsererror" ) {
                                    // Parse error
                                    var errorMessage = "Sorry, we were unable to parse the server's response. Please try again.";
                                } else if ( textStatus == "timeout" ) {
                                    // Timeout
                                    var errorMessage = "Sorry, your request timed out. Please try again.";
                                } else {
                                    // Generic error message
                                    var errorMessage = "Sorry, something went wrong. Please try again.";
                                }

                                // Show error message
                                $form.validation('showMessage', 'error', errorMessage);
                                scrollToElement($form.validation('getMessage', 'error'), 200);

                                // Trigger validationError event
                                $form.trigger({
                                    type: 'validationError',
                                    errorMessage: errorMessage
                                });
                            }
                        },
                        complete: function(jqXHR, textStatus) {
                            $form.removeClass('validating');
                        }
                    });
                }
            }

            $form.on('submit.validate', validate);
        },

        parseResponse: function(response) {
            // Parses the response to show qtips and messages where necessary.
            var $form = $(this.element);
            var $scrollElement = undefined;
            // Check each record item is valid.
            $.each(response.record, function (name, object) {
                var $element = $form.find('[name=' + name + ']');
                if ( ! object.valid ) {
                    // Record item not valid - mark invalid and display message to user.
                    if ( $element.length !== 0 ) {
                        $form.validation('showValidationMessage', $element, object.message);
                        $element.addClass('invalid');

                        // Compare to highest element on page so far
                        if ( typeof $scrollElement === 'undefined' || $element.offset().top < $scrollElement.offset().top ) {
                            $scrollElement = $element;
                        }
                    }
                } else {
                    $element.removeClass('invalid');
                }
            });

            // Show messages if action redirect is not given
            var showMessages = true;
            if ( response.action && response.action.redirect ) {
                // don't show messages if redirect action was given
                showMessages = false;
            }
            if ( response.action && response.action.resubmit && $form.data('resubmit-disabled')!==true ) {
                // don't show messages if resubmit action was given and resubmission has not been disabled
                showMessages = false;
            }
            if ( showMessages && response.message ) {
                $.each(response.message, function(type, object) {
                    $form.validation('showMessage', type, object.value);
                    // Compare message to highest element on page
                    var $message = $form.validation('getMessage', type);
                    if ( typeof $scrollElement === 'undefined' ||
                         ($message.is(':visible') && $message.offset().top < $scrollElement.offset().top) ) {
                        $scrollElement = $message;
                    }
                });
            }

            if ( response.status === 'valid' ) {
                // submission was valid

                // re-enable future resubmit actions
                $form.data('resubmit-disabled',false);

                // redirect action
                if ( response.action && response.action.redirect ) {
                    // Redirect if record was valid and the redirect action was given
                    window.location.href = response.action.redirect.value;
                    return;
                } else if ( this.options.submit ) {
                    // default action
                    // resubmit form without validation
                    $form.off('submit.validate').submit();
                    return;
                }
            } else {
                // submission was invalid

                // resubmit action - used for authenticity token errors
                if ( response.action && response.action.resubmit && $form.data('resubmit-disabled')!==true ) {
                    // resubmit the form
                    $form.submit();
                    // disable future resubmit actions to prevent inifite loop
                    $form.data('resubmit-disabled',true);
                    return;
                } else {
                    // re-enable future resubmit actions
                    $form.data('resubmit-disabled',false);
                }
            }

            // Scroll to the element if there is one to scroll to
            if ( typeof $scrollElement !== 'undefined' && typeof $scrollElement.qtip('api') !== 'undefined' ) {
                // $scrollElement exists and has has a qtip

                var scrollToHighest = function(api) {
                    // Scrolls to the highest element on the page out of three possible elements:
                    // the qtip, the element the qtip is bound to, and the label for the element if it has one.

                    // Check if element has a label
                    var $label = $form.find('label[for=' + $scrollElement.attr('id') + ']');
                    if ( $label.length === 0 ) {
                        $label = $scrollElement.closest('label');
                    }

                    // If a label was found then check if the label is higher than the element on the page
                    if ( $label.length > 0 && $label.offset().top < $scrollElement.offset().top ) {
                        $scrollElement = $label
                    }

                    // Compare the top offset of highest elements to the qtip tooltip
                    if ( api.tooltip.offset().top < $scrollElement.offset().top ) {
                        $scrollElement = api.tooltip;
                    }

                    scrollToElement($scrollElement, 200);
                }

                if ( $scrollElement.qtip('api').rendered ) {
                    // Qtip for element has been rendered so can scroll to it
                    scrollToHighest($scrollElement.qtip('api'));
                } else {
                    // Qtip hasn't been rendered yet - listen for render event then scroll to element
                    $scrollElement.qtip('api').set('events.render', function(event, api) {
                        // Clicking on the tooltip causes the target element to gain focus and hides the tooltip.
			api.elements.tooltip.on('click', function(event) {
                            api.elements.target.focus();
                            // Call the hide method in case the default hide events were overwritten
                            api.hide();
                        });
                        scrollToHighest(api);
		    });
                }
            } else if ( typeof $scrollElement !== 'undefined' ) {
                // $scrollElement exists but has no qtip - scroll to the $scrollElement
                scrollToElement($scrollElement, 200);
            }
        },

        showValidationMessage: function($element, message) {
            // Show the validation message with the message as the content for the given element.
            var api = $element.qtip('api');
            if ( api === undefined ) {
                var qtipOptions = {
                    content: message,
                    position: {
                        target: $element
                    }
                };
                $.extend(true, qtipOptions, this.options.qtip);
                $.each(this.options.hints, function(selector, hintOptions) {
                    if ( $element.is(selector) ) {
                        $.extend(true, qtipOptions, hintOptions);
                    }
                });
                // initialise qtip
                $element.qtip(qtipOptions);
            } else {
                // Update existing qtip and show
                api.set('content.text', message);
                api.reposition();
                api.show();
            }
            return $element;
        },

        hideValidationMessage: function($element) {
            // Hide the validation message for the given element.
            $element.qtip('hide');
            return $element;
        },

        showMessage: function(type, message) {
            // Show the message of the type given with message as the content.
            if (! this.message[type]) {
                // Message area doesn't exist so create it.
                var messageDiv = $('

').addClass(this.options.messages[type].classes)
                var messageContent = $('

').html(message).addClass('message-content');

                messageDiv.append(messageContent).hide();
                var validationElement = $(this.element);
                messageDiv.click(function(event){
                    validationElement.validation('hideMessage', type);
                    validationElement.validation('reposition');
                });

                if (this.options.messages[type].before) {
                    $(this.options.messages[type].before).before(messageDiv);
                } else if (this.options.messages[type].after) {
                    $(this.options.messages[type].after).after(messageDiv);
                } else {
                    $('body').append(messageDiv);
                }

                this.message[type] = messageDiv;
                messageDiv.show(200, $.proxy(function() {
                    this.reposition();
                }, this));
            } else {
                // Update the message
                this.message[type].find('.message-content').html(message);
                this.message[type].show(200, $.proxy(function() {
                    this.reposition();
                }, this));
            }
        },

        hideMessage: function(type) {
            // Hide the message with the given type.
            if (this.message[type]) {
                this.message[type].hide(100, $.proxy(function() {
                    this.reposition();
                }, this));
            }
        },

        getMessage: function(type) {
            // Returns the jquery object for the message of the given type
            return this.message[type];
        },

        reposition: function() {
            // Reposition or hide all validation messages.
            $('[data-hasqtip]').each(function() {
                if ( ! $(this).is(':visible') ) {
                    $(this).qtip('hide');
                } else {
                    $(this).qtip('reposition');
                }
            });
        },

        _destroy: function() {
            // Remove the elements created by this plugin.
            this.element.unbind('submit.validate');
            $(this.element).removeClass('validating');
            this._validationMessagesDestroy();
            this._messagesDestroy();
        },

        _validationMessagesDestroy: function() {
            // Destroy any tooltips associated with this element or it's descendants.
            $(this.element).find('[data-hasqtip]').qtip('destroy');
        },

        _messagesDestroy: function() {
            // Remove all messages added by this plugin.
            this.message['alert'].remove();
            this.message['error'].remove();
            this.message['notify'].remove();
        }

    });

})(jQuery, window, document);
<|endoftext|>


<commit_before>export default {
  "republican small area": "#E60008",
  "republican large area": "#FF4C55",
  democrat: "#0F5499",
  "social republican": "#FF5760",
  "social democrat small area": "#177EE6",
  "social democrat large area": "#579DD5",
};
<commit_msg>oops. swap social dems small and large areas<commit_after>export default {
  "republican small area": "#E60008",
  "republican large area": "#FF4C55",
  democrat: "#0F5499",
  "social republican": "#FF5760",
  "social democrat small area": "#579DD5",
  "social democrat large area": "#177EE6",
};
<|endoftext|>


<commit_before>(function() {
  'use strict';

  angular
    .module('blocks.exception')
    .factory('exception', exception);

  /* @ngInject */
  function exception($q, logger) {
    var service = {
      catcher: catcher
    };
    return service;

    function catcher(e) {
        var newMessage;
        console.info(e.data)
        if (e.data.message) {
            newMessage = e.data.message;
        } else if (e.data.errors[0]) {
            newMessage = e.data.errors[0].validationMessage;
        }
        logger.error(newMessage);
        return $q.reject(e);
    }
  }
})();
<commit_msg>exception reworked (#16)<commit_after>(function () {
    'use strict';

    angular
        .module('blocks.exception')
        .factory('exception', exception);

    /* @ngInject */
    function exception($q, logger) {
        var service = {
            catcher: catcher
        };
        return service;

        function catcher(e) {
            var newMessage;
            console.info(e.data)
            if (e.data.message) {
                newMessage = e.data.message;
                logger.error(newMessage);
            } else if (e.data.errors) {
                e.data.errors.forEach(function (item) {
                    logger.error(item.validationMessage)
                })
            }
            return $q.reject(e);
        }
    }
})();
<|endoftext|>


<commit_before>'use strict';

import React              from 'react';
import ReduxUtil          from '../../util/ReduxUtil';

import autoBindAllMethods from '../../../shared/util/autoBindAllMethods';
import assert             from 'assert';
import {AC}               from '../../state/actions';

import AddCircleOutlineIcon    from 'material-ui/lib/svg-icons/content/add-circle-outline';
import RemoveCircleOutlineIcon from 'material-ui/lib/svg-icons/content/remove-circle-outline'; // replaced with standard 'x'
import IconButton              from 'material-ui/lib/icon-button';
import IconMenu                from 'material-ui/lib/menus/icon-menu';
import MenuItem                from 'material-ui/lib/menus/menu-item';
import Select                  from 'react-select'
import SelectField             from 'material-ui/lib/select-field';
import Table                   from 'material-ui/lib/table/table';
import TableBody               from 'material-ui/lib/table/table-body';
import TableRow                from 'material-ui/lib/table/table-row';
import TableRowColumn          from 'material-ui/lib/table/table-row-column';
import TextField               from 'material-ui/lib/text-field';

import colors                  from 'material-ui/lib/styles/colors';

/**
 * The SelCritDetail component provides an interactive editor for the
 * selCrit.filter data content.
 *
 * The editSelCrit.extra.filter contains an optimized structure for
 * the UI, that syncs to the persistent state
 * editSelCrit.selCrit.filter.  For example:
 *
 *   appState.editSelCrit.selCrit.filter: { // the master
 *     "gender": {
 *       "$eq": "F"
 *     },
 *     "addr.state": {
 *       "$in": [
 *         "Missouri",
 *         "Indiana"
 *       ]
 *     },
 *     "gpa": {
 *       "$gte": "3.6"
 *     }
 *   }
 *
 *   appState.editSelCrit.extra.filter: [  // temporal structure streamlining our UI components
 *     {
 *       "fieldName": "gender",
 *       "operator": "$eq",
 *       "value": "F"
 *     },
 *     {
 *       "fieldName": "addr.state",
 *       "operator": "$in",
 *       "value": [
 *         "Missouri",
 *         "Indiana"
 *       ]
 *     },
 *     {
 *       "fieldName": "gpa",
 *       "operator": "$gte",
 *       "value": "3.6"
 *     }
 *   ]
 */
const SelCritDetail = ReduxUtil.wrapCompWithInjectedProps(

  class SelCritDetail extends React.Component { // component definition

    constructor(props, context) {
      super(props, context);

      const p = this.props;

      assert(p.meta, "<SelCritDetail> meta property is required.");

      autoBindAllMethods(this);
    }

    /**
     * handleFilterChange()
     */
    handleFilterChange(extraFilter) {
      const p = this.props;
      p.dispatch( AC.selCrit.edit.filterChange(extraFilter) );
    }

    /**
     * handleOperatorChange()
     */
    handleOperatorChange(fieldName, opValue) {
      const p = this.props;
      const newExtraFilter = p.extraFilter.map( (extraFilterObj) => {
        if (extraFilterObj.fieldName === fieldName) {
          return {...extraFilterObj, operator: opValue};
        }
        else {
          return extraFilterObj;
        }
      });
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleTextValueChange()
     */
    handleTextValueChange(fieldName, txtValue) {
      const p = this.props;
      const newExtraFilter = p.extraFilter.map( (extraFilterObj) => {
        if (extraFilterObj.fieldName === fieldName) {
          return {...extraFilterObj, value: txtValue}; // prune options down to strictly the value strings
        }
        else {
          return extraFilterObj;
        }
      });
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleSingleSelectValueChange()
     */
    handleSingleSelectValueChange(fieldName, value) {
      const p = this.props;
      const newExtraFilter = p.extraFilter.map( (extraFilterObj) => {
        if (extraFilterObj.fieldName === fieldName) {
          return {...extraFilterObj, value: value}; // prune option down to strictly the value string
        }
        else {
          return extraFilterObj;
        }
      });
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleMultiSelectValueChange()
     */
    handleMultiSelectValueChange(fieldName, options) {
      const p = this.props;
      const newExtraFilter = p.extraFilter.map( (extraFilterObj) => {
        if (extraFilterObj.fieldName === fieldName) {
          return {...extraFilterObj, value: options.map( (option) => option.value)}; // prune options down to strictly the value strings
        }
        else {
          return extraFilterObj;
        }
      });
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleAddFilter()
     */
    handleAddFilter(fieldName) {
      const p = this.props;

      const metaSelCritField = p.meta.selCritFields[fieldName];

      const initialOperator = {
        singleSelect: '$eq',
        multiSelect:  '$in',
        comparison:   null, // require user selection (vs. '$eq')
      };

      const initialValue = {
        singleSelect: '',
        multiSelect:  [],
        comparison:   '',
      };

      const newExtraFilterObj = { fieldName, operator: initialOperator[metaSelCritField.type], value: initialValue[metaSelCritField.type]};

      const newExtraFilter    = [...p.extraFilter, newExtraFilterObj];

      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleDeleteFilter()
     */
    handleDeleteFilter(fieldName) {
      const p = this.props;

      const indx           = p.extraFilter.findIndex( (filter) => filter.fieldName === fieldName );
      const newExtraFilter = [...p.extraFilter.slice(0,indx), ...p.extraFilter.slice(indx+1)];
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * genFilterOperatorElm()
     */
    genFilterOperatorElm(extraFilterObj) {
      const p = this.props;

      const metaSelCritField = p.meta.selCritFields[extraFilterObj.fieldName];

      switch (metaSelCritField.type) {

        case 'singleSelect':
          return 'matches';

        case 'multiSelect':
          return 'any of';

        case 'comparison':
          return (
            <SelectField value={extraFilterObj.operator}
                         onChange={ (e, key, value) => this.handleOperatorChange(extraFilterObj.fieldName, value) }
                         errorText={extraFilterObj.operator ? null : 'operator is required'}
                         style={{width: '4em'}}
                         iconStyle={{fill: '#666'}}
                         hintText="operator">
              <MenuItem value="$eq"  primaryText="="/>
              <MenuItem value="$gt"  primaryText=">"/>
              <MenuItem value="$gte" primaryText=">="/>
              <MenuItem value="$lt"  primaryText="<"/>
              <MenuItem value="$lte" primaryText="<="/>
              <MenuItem value="$ne"  primaryText="!="/>
            </SelectField>
          );

        default:
          return `UNSUPPORTED meta.selCritFields.type: '${metaSelCritField.type}' with value: ${extraFilterObj.value}`;
      }
    }

    /**
     * genFilterValueElm()
     */
    genFilterValueElm(extraFilterObj) {
      const p = this.props;

      const metaSelCritField = p.meta.selCritFields[extraFilterObj.fieldName];

      switch (metaSelCritField.type) {

        case 'singleSelect':
          return (
            <SelectField value={extraFilterObj.value}
                         onChange={ (e, key, value) => this.handleSingleSelectValueChange(extraFilterObj.fieldName, value) }
                         errorText={extraFilterObj.value ? null : 'value is required'}
                         autoWidth={true}
                         iconStyle={{fill: '#666'}}>
              { metaSelCritField.options.map( (option) => {
                  return <MenuItem key={option.value} value={option.value} primaryText={option.label}/>
                })}
            </SelectField>
          );

        case 'multiSelect':
          return <Select multi={true}
                         style={{width: '10em'}}
                         options={metaSelCritField.options}
                         value={extraFilterObj.value}
                         onChange={ (options) => this.handleMultiSelectValueChange(extraFilterObj.fieldName, options) }
                         placeholder={value is required}
                         resetValue={[]}/>;

        case 'comparison':
          return <TextField style={{ width: '20em' }}
                            value={extraFilterObj.value}
                            onChange={ (e) => this.handleTextValueChange(extraFilterObj.fieldName, e.target.value) }
                            errorText={extraFilterObj.value ? null : 'value is required'}/>;

        default:
          return `UNSUPPORTED meta.selCritFields.type: '${metaSelCritField.type}' with value: ${extraFilterObj.value}`;
      }
    }

    /**
     * render()
     */
    render() {
      const p = this.props;

      const metaSelCritFieldNames = Object.keys(p.meta.selCritFields);

      return (

          Selection Criteria:
          <IconMenu iconButtonElement={ <IconButton title="Add new field to Selection Criteria">
                                          <AddCircleOutlineIcon color={colors.red900}/>
                                        </IconButton> }
                    targetOrigin={{vertical: 'top', horizontal: 'right', }}
                    anchorOrigin={{vertical: 'top', horizontal: 'right'}}>
            { metaSelCritFieldNames.map( (fieldName) => { // add MenuItem's for fields that are NOT already part of the filter
                return (p.extraFilter.find( (filter) => filter.fieldName === fieldName))
                       ? null
                       : <MenuItem key={fieldName}
                                   primaryText={p.meta.validFields[fieldName]}
                                   onTouchTap={()=> this.handleAddFilter(fieldName)}/>;
            })}
          </IconMenu>

            <TableBody deselectOnClickaway={false}
                       displayRowCheckbox={false}
                       showRowHover={true}
                       stripedRows={false}>
              { p.extraFilter.map( (extraFilterObj) => {
                  return (
                    <TableRow key={extraFilterObj.fieldName}>
                      <TableRowColumn>{p.meta.validFields[extraFilterObj.fieldName]}</TableRowColumn>
                      <TableRowColumn>{this.genFilterOperatorElm(extraFilterObj)}</TableRowColumn>
                      <TableRowColumn>{this.genFilterValueElm(extraFilterObj)}</TableRowColumn>
                      <TableRowColumn>
                        <IconButton title="Remove field from Selection Criteria"
                                    onTouchTap={()=> this.handleDeleteFilter(extraFilterObj.fieldName)}>
                          <RemoveCircleOutlineIcon color={colors.red900}/>
                        </IconButton>
                      </TableRowColumn>
                    </TableRow>
                  );
                })}
            </TableBody>

      );
    }
  }, // end of ... component definition

  { // component property injection
    mapStateToProps(appState, ownProps) {
      return {
        extraFilter: appState.editSelCrit.extra.filter,
      };
    }
  }); // end of ... component property injection

// define expected props
SelCritDetail.propTypes = {
  meta: React.PropTypes.any.isRequired,
}

export default SelCritDetail;
<commit_msg>change add/remove button color<commit_after>'use strict';

import React              from 'react';
import ReduxUtil          from '../../util/ReduxUtil';

import autoBindAllMethods from '../../../shared/util/autoBindAllMethods';
import assert             from 'assert';
import {AC}               from '../../state/actions';

import AddCircleOutlineIcon    from 'material-ui/lib/svg-icons/content/add-circle-outline';
import RemoveCircleOutlineIcon from 'material-ui/lib/svg-icons/content/remove-circle-outline'; // replaced with standard 'x'
import IconButton              from 'material-ui/lib/icon-button';
import IconMenu                from 'material-ui/lib/menus/icon-menu';
import MenuItem                from 'material-ui/lib/menus/menu-item';
import Select                  from 'react-select'
import SelectField             from 'material-ui/lib/select-field';
import Table                   from 'material-ui/lib/table/table';
import TableBody               from 'material-ui/lib/table/table-body';
import TableRow                from 'material-ui/lib/table/table-row';
import TableRowColumn          from 'material-ui/lib/table/table-row-column';
import TextField               from 'material-ui/lib/text-field';

import colors                  from 'material-ui/lib/styles/colors';

/**
 * The SelCritDetail component provides an interactive editor for the
 * selCrit.filter data content.
 *
 * The editSelCrit.extra.filter contains an optimized structure for
 * the UI, that syncs to the persistent state
 * editSelCrit.selCrit.filter.  For example:
 *
 *   appState.editSelCrit.selCrit.filter: { // the master
 *     "gender": {
 *       "$eq": "F"
 *     },
 *     "addr.state": {
 *       "$in": [
 *         "Missouri",
 *         "Indiana"
 *       ]
 *     },
 *     "gpa": {
 *       "$gte": "3.6"
 *     }
 *   }
 *
 *   appState.editSelCrit.extra.filter: [  // temporal structure streamlining our UI components
 *     {
 *       "fieldName": "gender",
 *       "operator": "$eq",
 *       "value": "F"
 *     },
 *     {
 *       "fieldName": "addr.state",
 *       "operator": "$in",
 *       "value": [
 *         "Missouri",
 *         "Indiana"
 *       ]
 *     },
 *     {
 *       "fieldName": "gpa",
 *       "operator": "$gte",
 *       "value": "3.6"
 *     }
 *   ]
 */
const SelCritDetail = ReduxUtil.wrapCompWithInjectedProps(

  class SelCritDetail extends React.Component { // component definition

    constructor(props, context) {
      super(props, context);

      const p = this.props;

      assert(p.meta, "<SelCritDetail> meta property is required.");

      autoBindAllMethods(this);
    }

    /**
     * handleFilterChange()
     */
    handleFilterChange(extraFilter) {
      const p = this.props;
      p.dispatch( AC.selCrit.edit.filterChange(extraFilter) );
    }

    /**
     * handleOperatorChange()
     */
    handleOperatorChange(fieldName, opValue) {
      const p = this.props;
      const newExtraFilter = p.extraFilter.map( (extraFilterObj) => {
        if (extraFilterObj.fieldName === fieldName) {
          return {...extraFilterObj, operator: opValue};
        }
        else {
          return extraFilterObj;
        }
      });
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleTextValueChange()
     */
    handleTextValueChange(fieldName, txtValue) {
      const p = this.props;
      const newExtraFilter = p.extraFilter.map( (extraFilterObj) => {
        if (extraFilterObj.fieldName === fieldName) {
          return {...extraFilterObj, value: txtValue}; // prune options down to strictly the value strings
        }
        else {
          return extraFilterObj;
        }
      });
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleSingleSelectValueChange()
     */
    handleSingleSelectValueChange(fieldName, value) {
      const p = this.props;
      const newExtraFilter = p.extraFilter.map( (extraFilterObj) => {
        if (extraFilterObj.fieldName === fieldName) {
          return {...extraFilterObj, value: value}; // prune option down to strictly the value string
        }
        else {
          return extraFilterObj;
        }
      });
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleMultiSelectValueChange()
     */
    handleMultiSelectValueChange(fieldName, options) {
      const p = this.props;
      const newExtraFilter = p.extraFilter.map( (extraFilterObj) => {
        if (extraFilterObj.fieldName === fieldName) {
          return {...extraFilterObj, value: options.map( (option) => option.value)}; // prune options down to strictly the value strings
        }
        else {
          return extraFilterObj;
        }
      });
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleAddFilter()
     */
    handleAddFilter(fieldName) {
      const p = this.props;

      const metaSelCritField = p.meta.selCritFields[fieldName];

      const initialOperator = {
        singleSelect: '$eq',
        multiSelect:  '$in',
        comparison:   null, // require user selection (vs. '$eq')
      };

      const initialValue = {
        singleSelect: '',
        multiSelect:  [],
        comparison:   '',
      };

      const newExtraFilterObj = { fieldName, operator: initialOperator[metaSelCritField.type], value: initialValue[metaSelCritField.type]};

      const newExtraFilter    = [...p.extraFilter, newExtraFilterObj];

      this.handleFilterChange(newExtraFilter);
    }

    /**
     * handleDeleteFilter()
     */
    handleDeleteFilter(fieldName) {
      const p = this.props;

      const indx           = p.extraFilter.findIndex( (filter) => filter.fieldName === fieldName );
      const newExtraFilter = [...p.extraFilter.slice(0,indx), ...p.extraFilter.slice(indx+1)];
      this.handleFilterChange(newExtraFilter);
    }

    /**
     * genFilterOperatorElm()
     */
    genFilterOperatorElm(extraFilterObj) {
      const p = this.props;

      const metaSelCritField = p.meta.selCritFields[extraFilterObj.fieldName];

      switch (metaSelCritField.type) {

        case 'singleSelect':
          return 'matches';

        case 'multiSelect':
          return 'any of';

        case 'comparison':
          return (
            <SelectField value={extraFilterObj.operator}
                         onChange={ (e, key, value) => this.handleOperatorChange(extraFilterObj.fieldName, value) }
                         errorText={extraFilterObj.operator ? null : 'operator is required'}
                         style={{width: '4em'}}
                         iconStyle={{fill: '#666'}}
                         hintText="operator">
              <MenuItem value="$eq"  primaryText="="/>
              <MenuItem value="$gt"  primaryText=">"/>
              <MenuItem value="$gte" primaryText=">="/>
              <MenuItem value="$lt"  primaryText="<"/>
              <MenuItem value="$lte" primaryText="<="/>
              <MenuItem value="$ne"  primaryText="!="/>
            </SelectField>
          );

        default:
          return `UNSUPPORTED meta.selCritFields.type: '${metaSelCritField.type}' with value: ${extraFilterObj.value}`;
      }
    }

    /**
     * genFilterValueElm()
     */
    genFilterValueElm(extraFilterObj) {
      const p = this.props;

      const metaSelCritField = p.meta.selCritFields[extraFilterObj.fieldName];

      switch (metaSelCritField.type) {

        case 'singleSelect':
          return (
            <SelectField value={extraFilterObj.value}
                         onChange={ (e, key, value) => this.handleSingleSelectValueChange(extraFilterObj.fieldName, value) }
                         errorText={extraFilterObj.value ? null : 'value is required'}
                         autoWidth={true}
                         iconStyle={{fill: '#666'}}>
              { metaSelCritField.options.map( (option) => {
                  return <MenuItem key={option.value} value={option.value} primaryText={option.label}/>
                })}
            </SelectField>
          );

        case 'multiSelect':
          return <Select multi={true}
                         style={{width: '10em'}}
                         options={metaSelCritField.options}
                         value={extraFilterObj.value}
                         onChange={ (options) => this.handleMultiSelectValueChange(extraFilterObj.fieldName, options) }
                         placeholder={value is required}
                         resetValue={[]}/>;

        case 'comparison':
          return <TextField style={{ width: '20em' }}
                            value={extraFilterObj.value}
                            onChange={ (e) => this.handleTextValueChange(extraFilterObj.fieldName, e.target.value) }
                            errorText={extraFilterObj.value ? null : 'value is required'}/>;

        default:
          return `UNSUPPORTED meta.selCritFields.type: '${metaSelCritField.type}' with value: ${extraFilterObj.value}`;
      }
    }

    /**
     * render()
     */
    render() {
      const p = this.props;

      const metaSelCritFieldNames = Object.keys(p.meta.selCritFields);

      return (

          Selection Criteria:
          <IconMenu iconButtonElement={ <IconButton title="Add new field to Selection Criteria">
                                          <AddCircleOutlineIcon color={colors.deepOrangeA200}/>
                                        </IconButton> }
                    targetOrigin={{vertical: 'top', horizontal: 'right', }}
                    anchorOrigin={{vertical: 'top', horizontal: 'right'}}>
            { metaSelCritFieldNames.map( (fieldName) => { // add MenuItem's for fields that are NOT already part of the filter
                return (p.extraFilter.find( (filter) => filter.fieldName === fieldName))
                       ? null
                       : <MenuItem key={fieldName}
                                   primaryText={p.meta.validFields[fieldName]}
                                   onTouchTap={()=> this.handleAddFilter(fieldName)}/>;
            })}
          </IconMenu>

            <TableBody deselectOnClickaway={false}
                       displayRowCheckbox={false}
                       showRowHover={true}
                       stripedRows={false}>
              { p.extraFilter.map( (extraFilterObj) => {
                  return (
                    <TableRow key={extraFilterObj.fieldName}>
                      <TableRowColumn>{p.meta.validFields[extraFilterObj.fieldName]}</TableRowColumn>
                      <TableRowColumn>{this.genFilterOperatorElm(extraFilterObj)}</TableRowColumn>
                      <TableRowColumn>{this.genFilterValueElm(extraFilterObj)}</TableRowColumn>
                      <TableRowColumn>
                        <IconButton title="Remove field from Selection Criteria"
                                    onTouchTap={()=> this.handleDeleteFilter(extraFilterObj.fieldName)}>
                          <RemoveCircleOutlineIcon color={colors.deepOrangeA200}/>
                        </IconButton>
                      </TableRowColumn>
                    </TableRow>
                  );
                })}
            </TableBody>

      );
    }
  }, // end of ... component definition

  { // component property injection
    mapStateToProps(appState, ownProps) {
      return {
        extraFilter: appState.editSelCrit.extra.filter,
      };
    }
  }); // end of ... component property injection

// define expected props
SelCritDetail.propTypes = {
  meta: React.PropTypes.any.isRequired,
}

export default SelCritDetail;
<|endoftext|>