<commit_before>// [NOTE] this is a default basic setting for all jQuery UI Draggable objects;
// It should remain as IMMUTABLE
var baseDraggableSettings = {
    cursor:"move",
    scroll: false,
    helper: "clone",
    zIndex: 10000,
    containment: "document",
    appendTo: "body",
};

function newBaseDroppable(acceptableClasses) {
    var weakFocus = "ui-weak-focus", strongFocus = "ui-strong-focus",
    output = {
        over: function(e, ui) {
            var from = ui.draggable;
            var to = $(e.target);
            if (hasAnyClass(from, acceptableClasses)) {
                to.addClass(strongFocus);
                to.removeClass(weakFocus);
            }
        },
        out: function(e, ui) {
            var from = ui.draggable;
            var to = $(e.target);
            if (hasAnyClass(from, acceptableClasses)) {
                to.removeClass(strongFocus);
                to.addClass(weakFocus);
            }
        },
        activate: function(e, ui) {
            var from = ui.draggable;
            var to = $(e.target);
            if (hasAnyClass(from, acceptableClasses)) {
                to.addClass(weakFocus);
            }
        },
        deactivate: function(e, ui) {
            var to = $(e.target);
            to.removeClass(strongFocus);
            to.removeClass(weakFocus);
        },
        greedy: true,
    };
    return output;
}

function relatingFragmentsDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        var fromId = from.attr("_fid");
        var toId = to.find(".fragment-title").attr("_fid") || to.attr("_fid");
        if (fromId != toId) {
            if (!fragmentEditorVisible())
                // [NOTE] block this functionality when the fragment editor is running.
                confirmRelatingFragments(fromId, toId);
        }
    }
}

function fragmentFetchDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (from.hasClass("each-tag")) {
        fetchFragmentsByTag(from, to);
    }
    else if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        fetchFragments(findPanel(to), [from.attr("_fid")]);
    }
}

function bookmarkingDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        var frgId = from.attr("_fid");
        bookmarkFragment([ {name:"fragmentId", value:frgId} ]);
    }
}

function trashingDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        var panelId = findPanel(from);
        var deleting = FRAGMENT_DELETABLE[panelId];
        var frgId = from.attr("_fid");
        confirmTrashingFragments(frgId, deleting);
    }
    else if (from.hasClass("each-tag")) {
        confirmTrashingTag(from.attr("_tid"), Boolean(from.attr("_frgCnt") == 0));
    }
}

function frgEditorDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        var id = from.attr("_fid");
        var title = from.attr("_ft") || from.text();
        title = title ? title.trim() : "";
        var encoded = "{{[frgm] "+id+" "+title+" }}  \n";
        $(this).insertAtCaret(encoded);
    }
    else if (from.hasClass("each-tag")) {
        var id = from.attr("_tid");
        var encoded = "{{[tag] "+id+" }}  \n";
        $(this).insertAtCaret(encoded);
    }
    else if (from.hasClass("fb-file")) {
        var ids = from.attr("id");
        var id = ids.substr(ids.lastIndexOf("-") + 1);
        var encoded = "{{[file] "+id+" }}  \n";
        $(this).insertAtCaret(encoded);
    }
}

function setupDraggableForFragmentTitle() {
    $(".fragment-title, .small-fragment-box").draggable(baseDraggableSettings);
}

function setupDraggableForTags() {
    var tagPalettePanel = $("#tag-palette-panel");
    var overflowOption = tagPalettePanel.css("overflow");
    $("#tag-palette-panel .each-tag, #fragment-group .each-tag").draggable(baseDraggableSettings);
    $("#tag-palette-panel").off(".cvz_tag_dnd")
    .on("dragstart.cvz_tag_dnd", ".each-tag", function(e, ui) {
        // [NOTE] the helper object disappears at the outside of the panel unless doing this
        tagPalettePanel.css({overflow:"initial"});
    })
    .on("dragstop.cvz_tag_dnd", ".each-tag", function(e, ui) {
        tagPalettePanel.css({overflow:overflowOption});
    });
}

function setupDraggableForFiles() {
    var fileBoxPanel = $("#file-box-form\\:file-box-panel");
    var overflowOption = fileBoxPanel.css("overflow");
    $(".fb-file").draggable(baseDraggableSettings);
    $("#file-path-tree").off(".cvz_file_dnd")
    .on("dragstart.cvz_file_dnd", function(e, ui) {
        fileBoxPanel.css({overflow:"initial"});
    })
    .on("dragstop.cvz_file_dnd", function(e, ui) {
        // [NOTE] the overflow style should be identical between the tag palette and file box
        fileBoxPanel.css({overflow:overflowOption});
    });
}

function setupDndForRelatingFragments() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box"]);
    droppable.drop = relatingFragmentsDropHandler;
    $(".fragment-header, .small-fragment-box").droppable(droppable);
}

function setupDndForFragmentFetch() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box", "each-tag"]);
    droppable.drop = fragmentFetchDropHandler;
    $('[id^="fragment-group-form\\:fragment-panel-toolbar-"]').droppable(droppable);
    $("#panel-activation-buttons label").droppable(droppable);
}

function setupDndForBookmarking() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box"]);
    droppable.drop = bookmarkingDropHandler;
    $("#bookmark-form\\:bookmark-panel").droppable(droppable);
}

function setupDndForTrashing() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box", "each-tag"]);
    droppable.drop = trashingDropHandler;
    $("#trashcan").droppable(droppable);
}

function setupDndToDropDataToFrgEditor() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box", "each-tag", "fb-file"]);
    droppable.drop = frgEditorDropHandler;
    $("#fragment-content-editor").droppable(droppable);
}

function setupDragAndDrop() {
    setupDraggableForFragmentTitle();
    setupDraggableForTags();
    setupDraggableForFiles();

    setupDndForRelatingFragments();
    setupDndForFragmentFetch();
    setupDndForBookmarking();
    setupDndForTrashing();
    setupDndToDropDataToFrgEditor();
}

<commit_msg>[update] drag & drop; now elements being dragged (such as fragment title, tag, ...) have a fixed size during D&D; so more easy to drag;<commit_after>// [NOTE] this is a default basic setting for all jQuery UI Draggable objects;
// It should remain as IMMUTABLE
const baseDraggableSettings = {
    cursor:"move",
    cursorAt:{ left:30 },
    scroll: false,
    helper: function() {
        var clone = $(this).clone().removeAttr("id");
        clone.css({ "max-width":60, "overflow":"hidden", "white-space":"nowrap" });
        return clone;
    },
//    helper: "clone",
    zIndex: 10000,
    containment: "document",
    appendTo: "body",
};

function newBaseDroppable(acceptableClasses) {
    var weakFocus = "ui-weak-focus", strongFocus = "ui-strong-focus",
    output = {
        over: function(e, ui) {
            var from = ui.draggable, to = $(e.target);
            if (hasAnyClass(from, acceptableClasses)) {
                to.addClass(strongFocus);
                to.removeClass(weakFocus);
            }
        },
        out: function(e, ui) {
            var from = ui.draggable, to = $(e.target);
            if (hasAnyClass(from, acceptableClasses)) {
                to.removeClass(strongFocus);
                to.addClass(weakFocus);
            }
        },
        activate: function(e, ui) {
            var from = ui.draggable, to = $(e.target);
            if (hasAnyClass(from, acceptableClasses)) {
                to.addClass(weakFocus);
            }
        },
        deactivate: function(e, ui) {
            var to = $(e.target);
            to.removeClass(strongFocus);
            to.removeClass(weakFocus);
        },
        greedy: true,
    };
    return output;
}

function relatingFragmentsDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        var fromId = from.attr("_fid");
        var toId = to.find(".fragment-title").attr("_fid") || to.attr("_fid");
        if (fromId != toId) {
            if (!fragmentEditorVisible())
                // [NOTE] block this functionality when the fragment editor is running.
                confirmRelatingFragments(fromId, toId);
        }
    }
}

function fragmentFetchDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (from.hasClass("each-tag")) {
        fetchFragmentsByTag(from, to);
    }
    else if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        fetchFragments(findPanel(to), [from.attr("_fid")]);
    }
}

function bookmarkingDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        var frgId = from.attr("_fid");
        bookmarkFragment([ {name:"fragmentId", value:frgId} ]);
    }
}

function trashingDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        var panelId = findPanel(from);
        var deleting = FRAGMENT_DELETABLE[panelId];
        var frgId = from.attr("_fid");
        confirmTrashingFragments(frgId, deleting);
    }
    else if (from.hasClass("each-tag")) {
        confirmTrashingTag(from.attr("_tid"), Boolean(from.attr("_frgCnt") == 0));
    }
}

function frgEditorDropHandler(e, ui) {
    var from = ui.draggable;
    var to = $(e.target);
    if (hasAnyClass(from, ["fragment-title", "small-fragment-box"])) {
        var id = from.attr("_fid");
        var title = from.attr("_ft") || from.text();
        title = title ? title.trim() : "";
        var encoded = "{{[frgm] "+id+" "+title+" }}  \n";
        $(this).insertAtCaret(encoded);
    }
    else if (from.hasClass("each-tag")) {
        var id = from.attr("_tid");
        var encoded = "{{[tag] "+id+" }}  \n";
        $(this).insertAtCaret(encoded);
    }
    else if (from.hasClass("fb-file")) {
        var ids = from.attr("id");
        var id = ids.substr(ids.lastIndexOf("-") + 1);
        var encoded = "{{[file] "+id+" }}  \n";
        $(this).insertAtCaret(encoded);
    }
}

function setupDraggableForFragmentTitle() {
    $(".fragment-title, .small-fragment-box").draggable(baseDraggableSettings);
}

function setupDraggableForTags() {
    var tagPalettePanel = $("#tag-palette-panel");
    var overflowOption = tagPalettePanel.css("overflow");
    $("#tag-palette-panel .each-tag, #fragment-group .each-tag").draggable(baseDraggableSettings);
    $("#tag-palette-panel").off(".cvz_tag_dnd")
    .on("dragstart.cvz_tag_dnd", ".each-tag", function(e, ui) {
        // [NOTE] the helper object disappears at the outside of the panel unless doing this
        tagPalettePanel.css({overflow:"initial"});
    })
    .on("dragstop.cvz_tag_dnd", ".each-tag", function(e, ui) {
        tagPalettePanel.css({overflow:overflowOption});
    });
}

function setupDraggableForFiles() {
    var fileBoxPanel = $("#file-box-form\\:file-box-panel");
    var overflowOption = fileBoxPanel.css("overflow");
    $(".fb-file").draggable(baseDraggableSettings);
    $("#file-path-tree").off(".cvz_file_dnd")
    .on("dragstart.cvz_file_dnd", function(e, ui) {
        fileBoxPanel.css({overflow:"initial"});
    })
    .on("dragstop.cvz_file_dnd", function(e, ui) {
        // [NOTE] the overflow style should be identical between the tag palette and file box
        fileBoxPanel.css({overflow:overflowOption});
    });
}

function setupDndForRelatingFragments() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box"]);
    droppable.drop = relatingFragmentsDropHandler;
    $(".fragment-header, .small-fragment-box").droppable(droppable);
}

function setupDndForFragmentFetch() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box", "each-tag"]);
    droppable.drop = fragmentFetchDropHandler;
    $('[id^="fragment-group-form\\:fragment-panel-toolbar-"]').droppable(droppable);
    $("#panel-activation-buttons label").droppable(droppable);
}

function setupDndForBookmarking() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box"]);
    droppable.drop = bookmarkingDropHandler;
    $("#bookmark-form\\:bookmark-panel").droppable(droppable);
}

function setupDndForTrashing() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box", "each-tag"]);
    droppable.drop = trashingDropHandler;
    $("#trashcan").droppable(droppable);
}

function setupDndToDropDataToFrgEditor() {
    var droppable = newBaseDroppable(["fragment-title", "small-fragment-box", "each-tag", "fb-file"]);
    droppable.drop = frgEditorDropHandler;
    $("#fragment-content-editor").droppable(droppable);
}

function setupDragAndDrop() {
    setupDraggableForFragmentTitle();
    setupDraggableForTags();
    setupDraggableForFiles();

    setupDndForRelatingFragments();
    setupDndForFragmentFetch();
    setupDndForBookmarking();
    setupDndForTrashing();
    setupDndToDropDataToFrgEditor();
}

<|endoftext|>


<commit_before>'use strict';

angular.module('metadatamanagementApp', ['LocalStorageModule', 'tmh.dynamicLocale', 'pascalprecht.translate',
               'ui.bootstrap', // for modal dialogs
    'ngResource', 'ui.router', 'ngCookies', 'ngAria', 'ngCacheBuster', 'ngFileUpload', 'infinite-scroll'])

    .run(function ($rootScope, $location, $window, $http, $state, $translate, Language, Auth, Principal, ENV, VERSION) {
        $rootScope.ENV = ENV;
        $rootScope.VERSION = VERSION;
        $rootScope.$on('$stateChangeStart', function (event, toState, toStateParams) {
            $rootScope.toState = toState;
            $rootScope.toStateParams = toStateParams;

            if (Principal.isIdentityResolved()) {
                Auth.authorize();
            }

            // Update the language
            Language.getCurrent().then(function (language) {
                $translate.use(language);
            });

        });

        $rootScope.$on('$stateChangeSuccess',  function(event, toState, toParams, fromState, fromParams) {
            var titleKey = 'global.title' ;

            // Remember previous state unless we've been redirected to login or we've just
            // reset the state memory after logout. If we're redirected to login, our
            // previousState is already set in the authExpiredInterceptor. If we're going
            // to login directly, we don't want to be sent to some previous state anyway
            if (toState.name != 'login' && $rootScope.previousStateName) {
              $rootScope.previousStateName = fromState.name;
              $rootScope.previousStateParams = fromParams;
            }

            // Set the page title key to the one configured in state or use default one
            if (toState.data.pageTitle) {
                titleKey = toState.data.pageTitle;
            }

            $translate(titleKey).then(function (title) {
                // Change window title with translated one
                $window.document.title = title;
            });

        });

        $rootScope.back = function() {
            // If previous state is 'activate' or do not exist go to 'home'
            if ($rootScope.previousStateName === 'activate' || $state.get($rootScope.previousStateName) === null) {
                $state.go('home');
            } else {
                $state.go($rootScope.previousStateName, $rootScope.previousStateParams);
            }
        };
    })
    .config(function ($stateProvider, $urlRouterProvider, $httpProvider, $locationProvider, $translateProvider, tmhDynamicLocaleProvider, httpRequestInterceptorCacheBusterProvider) {

        //Cache everything except rest api requests
        httpRequestInterceptorCacheBusterProvider.setMatchlist([/.*api.*/, /.*protected.*/], true);

        $urlRouterProvider.otherwise('/');
        $stateProvider.state('site', {
            'abstract': true,
            views: {
                'navbar@': {
                    templateUrl: 'scripts/components/navbar/navbar.html',
                    controller: 'NavbarController'
                }
            },
            resolve: {
                authorize: ['Auth',
                    function (Auth) {
                        return Auth.authorize();
                    }
                ],
                translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) {
                    $translatePartialLoader.addPart('global');
                }]
            }
        });

        $httpProvider.interceptors.push('errorHandlerInterceptor');
        $httpProvider.interceptors.push('authExpiredInterceptor');
        $httpProvider.interceptors.push('authInterceptor');
        $httpProvider.interceptors.push('notificationInterceptor');

        // Initialize angular-translate
        $translateProvider.useLoader('$translatePartialLoader', {
            urlTemplate: 'i18n/{lang}/{part}.json'
        });

        $translateProvider.preferredLanguage('en');
        $translateProvider.useCookieStorage();
        $translateProvider.useSanitizeValueStrategy('escaped');
        $translateProvider.addInterpolation('$translateMessageFormatInterpolation');

        tmhDynamicLocaleProvider.localeLocationPattern('bower_components/angular-i18n/angular-locale_{{locale}}.js');
        tmhDynamicLocaleProvider.useCookieStorage();
        tmhDynamicLocaleProvider.storageKey('NG_TRANSLATE_LANG_KEY');

    })
    .config(['$urlMatcherFactoryProvider', function($urlMatcherFactory) {
        $urlMatcherFactory.type('boolean', {
            name : 'boolean',
            decode: function(val) { return val == true ? true : val == "true" ? true : false },
            encode: function(val) { return val ? 1 : 0; },
            equals: function(a, b) { return this.is(a) && a === b; },
            is: function(val) { return [true,false,0,1].indexOf(val) >= 0 },
            pattern: /bool|true|0|1/
        });
    }]);;
<commit_msg>#74 changed display language<commit_after>'use strict';

angular.module('metadatamanagementApp', ['LocalStorageModule', 'tmh.dynamicLocale', 'pascalprecht.translate',
               'ui.bootstrap', // for modal dialogs
    'ngResource', 'ui.router', 'ngCookies', 'ngAria', 'ngCacheBuster', 'ngFileUpload', 'infinite-scroll'])

    .run(function ($rootScope, $location, $window, $http, $state, $translate, Language, Auth, Principal, ENV, VERSION) {
        $rootScope.ENV = ENV;
        $rootScope.VERSION = VERSION;
        $rootScope.$on('$stateChangeStart', function (event, toState, toStateParams) {
            $rootScope.toState = toState;
            $rootScope.toStateParams = toStateParams;

            if (Principal.isIdentityResolved()) {
                Auth.authorize();
            }

            // Update the language
            Language.getCurrent().then(function (language) {
                $translate.use(language);
            });

        });

        $rootScope.$on('$stateChangeSuccess',  function(event, toState, toParams, fromState, fromParams) {
            var titleKey = 'global.title' ;

            // Remember previous state unless we've been redirected to login or we've just
            // reset the state memory after logout. If we're redirected to login, our
            // previousState is already set in the authExpiredInterceptor. If we're going
            // to login directly, we don't want to be sent to some previous state anyway
            if (toState.name != 'login' && $rootScope.previousStateName) {
              $rootScope.previousStateName = fromState.name;
              $rootScope.previousStateParams = fromParams;
            }

            // Set the page title key to the one configured in state or use default one
            if (toState.data.pageTitle) {
                titleKey = toState.data.pageTitle;
            }

            $translate(titleKey).then(function (title) {
                // Change window title with translated one
                $window.document.title = title;
            });

        });

        $rootScope.back = function() {
            // If previous state is 'activate' or do not exist go to 'home'
            if ($rootScope.previousStateName === 'activate' || $state.get($rootScope.previousStateName) === null) {
                $state.go('home');
            } else {
                $state.go($rootScope.previousStateName, $rootScope.previousStateParams);
            }
        };
    })
    .config(function ($stateProvider, $urlRouterProvider, $httpProvider, $locationProvider, $translateProvider, tmhDynamicLocaleProvider, httpRequestInterceptorCacheBusterProvider) {

        //Cache everything except rest api requests
        httpRequestInterceptorCacheBusterProvider.setMatchlist([/.*api.*/, /.*protected.*/], true);

        $urlRouterProvider.otherwise('/');
        $stateProvider.state('site', {
            'abstract': true,
            views: {
                'navbar@': {
                    templateUrl: 'scripts/components/navbar/navbar.html',
                    controller: 'NavbarController'
                }
            },
            resolve: {
                authorize: ['Auth',
                    function (Auth) {
                        return Auth.authorize();
                    }
                ],
                translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) {
                    $translatePartialLoader.addPart('global');
                }]
            }
        });

        $httpProvider.interceptors.push('errorHandlerInterceptor');
        $httpProvider.interceptors.push('authExpiredInterceptor');
        $httpProvider.interceptors.push('authInterceptor');
        $httpProvider.interceptors.push('notificationInterceptor');

        // Initialize angular-translate
        $translateProvider.useLoader('$translatePartialLoader', {
            urlTemplate: 'i18n/{lang}/{part}.json'
        });

        $translateProvider.preferredLanguage('de');
        $translateProvider.useCookieStorage();
        $translateProvider.useSanitizeValueStrategy('escaped');
        $translateProvider.addInterpolation('$translateMessageFormatInterpolation');

        tmhDynamicLocaleProvider.localeLocationPattern('bower_components/angular-i18n/angular-locale_{{locale}}.js');
        tmhDynamicLocaleProvider.useCookieStorage();
        tmhDynamicLocaleProvider.storageKey('NG_TRANSLATE_LANG_KEY');

    })
    .config(['$urlMatcherFactoryProvider', function($urlMatcherFactory) {
        $urlMatcherFactory.type('boolean', {
            name : 'boolean',
            decode: function(val) { return val == true ? true : val == "true" ? true : false },
            encode: function(val) { return val ? 1 : 0; },
            equals: function(a, b) { return this.is(a) && a === b; },
            is: function(val) { return [true,false,0,1].indexOf(val) >= 0 },
            pattern: /bool|true|0|1/
        });
    }]);;
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import styles from 'part:@sanity/components/textinputs/default-style'
import CloseIcon from 'part:@sanity/base/close-icon'
import {omit} from 'lodash'

export default class DefaultTextInput extends React.Component {
  static propTypes = {
    onChange: PropTypes.func,
    onFocus: PropTypes.func,
    onKeyPress: PropTypes.func,
    type: PropTypes.string,
    onBlur: PropTypes.func,
    onClear: PropTypes.func,
    value: PropTypes.string,
    selected: PropTypes.bool,
    error: PropTypes.bool,
    placeholder: PropTypes.string,
    showClearButton: PropTypes.bool,
    id: PropTypes.string.isRequired,
    hasFocus: PropTypes.bool
  }

  static defaultProps = {
    value: '',
    type: 'text',
    onKeyPress() {},
    onChange() {},
    onFocus() {},
    onClear() {},
    onBlur() {}
  }

  handleKeyPress = event => {
    this.props.onKeyPress(event)
  }

  handleFocus = event => {
    this.props.onFocus(event)
  }

  handleBlur = event => {
    this.props.onBlur(event)
  }

  selectInput = event => {
    this._input.select()
  }

  handleClear = event => {
    this.props.onClear(event)
  }

  setInputElement = element => {
    this._input = element
  }

  handleChange = event => {
    this.props.onChange(event)
  }

  componentDidMount() {
    if (this.props.selected) {
      this.selectInput()
    }
  }

  componentDidUpdate() {
    if (this.props.selected) {
      this.selectInput()
    }
  }

  render() {
    const {value, placeholder, error, showClearButton, id, type, hasFocus, level, ...rest} = omit(this.props, 'onClear')

    const rootClass = error ? styles.error : styles.root
    const levelClass = `styles[level_${level}]`

    return (

        <input
          {...rest}
          className={`
            ${error ? styles.inputError : styles.input}
            ${showClearButton && styles.hasClearButton}
            ${hasFocus && styles.hasFocus}
            ${level && levelClass}
          `}
          id={id}
          type={type}
          value={value}
          placeholder={placeholder}
          onChange={this.handleChange}
          onKeyPress={this.handleKeyPress}
          onFocus={this.handleFocus}
          onBlur={this.handleBlur}
          autoComplete="off"
          ref={this.setInputElement}
        />
        {
          showClearButton && (
            <button className={styles.clearButton} onClick={this.handleClear}>
              <CloseIcon color="inherit" />
            </button>
          )
        }

    )
  }
}
<commit_msg>Selected only triggers when isFocused<commit_after>import React, {PropTypes} from 'react'
import styles from 'part:@sanity/components/textinputs/default-style'
import CloseIcon from 'part:@sanity/base/close-icon'
import {omit} from 'lodash'

export default class DefaultTextInput extends React.Component {
  static propTypes = {
    onChange: PropTypes.func,
    onFocus: PropTypes.func,
    onKeyPress: PropTypes.func,
    type: PropTypes.string,
    onBlur: PropTypes.func,
    onClear: PropTypes.func,
    value: PropTypes.string,
    selected: PropTypes.bool,
    error: PropTypes.bool,
    placeholder: PropTypes.string,
    showClearButton: PropTypes.bool,
    id: PropTypes.string.isRequired,
    hasFocus: PropTypes.bool
  }

  static defaultProps = {
    value: '',
    type: 'text',
    onKeyPress() {},
    onChange() {},
    onFocus() {},
    onClear() {},
    onBlur() {}
  }

  handleKeyPress = event => {
    this.props.onKeyPress(event)
  }

  handleFocus = event => {
    this.props.onFocus(event)
  }

  handleBlur = event => {
    this.props.onBlur(event)
  }

  selectInput = event => {
    // Triggers only when the input is focused
    this._input.setSelectionRange(0, this.props.value.length)
  }

  handleClear = event => {
    this.props.onClear(event)
  }

  setInputElement = element => {
    this._input = element
  }

  handleChange = event => {
    this.props.onChange(event)
  }

  componentDidMount() {
    if (this.props.selected) {
      this.selectInput()
    }
  }

  componentDidUpdate() {
    if (this.props.selected) {
      this.selectInput()
    }
  }

  render() {
    const {value, placeholder, error, showClearButton, id, type, hasFocus, level, ...rest} = omit(this.props, 'onClear')

    const rootClass = error ? styles.error : styles.root
    const levelClass = `styles[level_${level}]`

    return (

        <input
          {...rest}
          className={`
            ${error ? styles.inputError : styles.input}
            ${showClearButton && styles.hasClearButton}
            ${hasFocus && styles.hasFocus}
            ${level && levelClass}
          `}
          id={id}
          type={type}
          value={value}
          placeholder={placeholder}
          onChange={this.handleChange}
          onKeyPress={this.handleKeyPress}
          onFocus={this.handleFocus}
          onBlur={this.handleBlur}
          autoComplete="off"
          ref={this.setInputElement}
        />
        {
          showClearButton && (
            <button className={styles.clearButton} onClick={this.handleClear}>
              <CloseIcon color="inherit" />
            </button>
          )
        }

    )
  }
}
<|endoftext|>


<commit_before>var SendButton = require('../../../../../javascripts/cartodb/organization/organization_notification/send_button_view');
var $ = require('jquery-cdb-v3');

describe('organization/organization_notification/send_button_view', function () {
  beforeEach(function () {
    this.view = new SendButton({
      $form: {}
    });
    spyOn(this.view, '_submit');

    this.view.render();
  });

  it('should render properly', function () {
    expect(this.view.$el.find('.js-button').text()).toContain('Send');
  });

  it('should not have leaks', function () {
    expect(this.view).toHaveNoLeaks();
  });

  afterEach(function () {
    this.view.clean();
  });

  describe('._onUpdate', function () {
    it('should show loader after click', function () {
      expect(this.view.model.get('status')).toBe('idle');
      expect(this.view.$el.find('.js-button').text()).not.toContain('Sending');

      this.view.updateCounter(1);
      this.view.$('.js-button').click();

      expect(this.view.model.get('status')).toBe('loading');
      expect(this.view.$el.find('.js-button').text()).toContain('Sending');
      expect(this.view._submit).toHaveBeenCalled();
    });
  });

  describe('.updateCounter', function () {
    it('should not be disabled if length > 0 and length < 140', function () {
      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(true);

      this.view.updateCounter(1);

      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(false);
    });

    it('should be disabled if length == 0 or length > 140', function () {
      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(true);

      this.view.updateCounter(0);

      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(true);

      this.view.updateCounter(141);

      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(true);
    });

    it('should update counter number', function () {
      expect(this.view.$el.find('.Md-counter').text()).toContain('140');

      this.view.updateCounter(1);

      expect(this.view.$el.find('.Md-counter').text()).toContain('139');
    });

    it('should update counter number color if is disabled', function () {
      expect(this.view.$el.find('.Md-counter').hasClass('Md-counter--negative')).toBe(false);

      this.view.updateCounter(141);

      expect(this.view.$el.find('.Md-counter').hasClass('Md-counter--negative')).toBe(true);
    });
  });
});
<commit_msg>fix tests<commit_after>var SendButton = require('../../../../../javascripts/cartodb/organization/organization_notification/send_button_view');

describe('organization/organization_notification/send_button_view', function () {
  beforeEach(function () {
    this.view = new SendButton({
      $form: {}
    });
    spyOn(this.view, '_submit');

    this.view.render();
  });

  it('should render properly', function () {
    expect(this.view.$el.find('.js-button').text()).toContain('Send');
  });

  it('should not have leaks', function () {
    expect(this.view).toHaveNoLeaks();
  });

  afterEach(function () {
    this.view.clean();
  });

  describe('._onUpdate', function () {
    it('should show loader after click', function () {
      expect(this.view.model.get('status')).toBe('idle');
      expect(this.view.$el.find('.js-button').text()).not.toContain('Sending');

      this.view.updateCounter(1);
      this.view.$('.js-button').click();

      expect(this.view.model.get('status')).toBe('loading');
      expect(this.view.$el.find('.js-button').text()).toContain('Sending');
      expect(this.view._submit).toHaveBeenCalled();
    });
  });

  describe('.updateCounter', function () {
    it('should not be disabled if length > 0 and length < 140', function () {
      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(true);

      this.view.updateCounter(1);

      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(false);
    });

    it('should be disabled if length == 0 or length > 140', function () {
      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(true);

      this.view.updateCounter(0);

      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(true);

      this.view.updateCounter(141);

      expect(this.view.$el.find('.js-button').hasClass('is-disabled')).toBe(true);
    });

    it('should update counter number', function () {
      expect(this.view.$el.find('.Md-counter').text()).toContain('140');

      this.view.updateCounter(1);

      expect(this.view.$el.find('.Md-counter').text()).toContain('139');
    });

    it('should update counter number color if is disabled', function () {
      expect(this.view.$el.find('.Md-counter').hasClass('Md-counter--negative')).toBe(false);

      this.view.updateCounter(141);

      expect(this.view.$el.find('.Md-counter').hasClass('Md-counter--negative')).toBe(true);
    });
  });
});
<|endoftext|>


<commit_before>import React, { useMemo, useCallback } from 'react';
import get from 'lodash/get';
import { GridItem } from '@strapi/design-system/Grid';
import { Select, Option } from '@strapi/design-system/Select';
import { useSelector, shallowEqual } from 'react-redux';
import { useIntl } from 'react-intl';
import { useLayoutDnd } from '../../../hooks';
import { createPossibleMainFieldsForModelsAndComponents, getInputProps } from '../utils';
import { makeSelectModelAndComponentSchemas } from '../../App/selectors';
import getTrad from '../../../utils/getTrad';
import GenericInput from './GenericInput';

const FIELD_SIZES = [
  [4, '33%'],
  [6, '50%'],
  [8, '66%'],
  [12, '100%']
];

const NON_RESIZABLE_FIELD_TYPES = [
  'dynamiczone',
  'component',
  'json',
  'richtext'
];

const ModalForm = ({ onMetaChange, onSizeChange }) => {
  const { formatMessage } = useIntl();
  const { modifiedData, selectedField, attributes, fieldForm } = useLayoutDnd();
  const schemasSelector = useMemo(makeSelectModelAndComponentSchemas, []);
  const { schemas } = useSelector(state => schemasSelector(state), shallowEqual);

  const formToDisplay = useMemo(() => {
    if (!selectedField) {
      return [];
    }

    const associatedMetas = get(modifiedData, ['metadatas', selectedField, 'edit'], {});

    return Object.keys(associatedMetas).filter(meta => meta !== 'visible');
  }, [selectedField, modifiedData]);

  const componentsAndModelsPossibleMainFields = useMemo(() => {
    return createPossibleMainFieldsForModelsAndComponents(schemas);
  }, [schemas]);

  const getSelectedItemSelectOptions = useCallback(
    formType => {
      if (formType !== 'relation' && formType !== 'component') {
        return [];
      }

      const targetKey = formType === 'component' ? 'component' : 'targetModel';
      const key = get(modifiedData, ['attributes', selectedField, targetKey], '');

      return get(componentsAndModelsPossibleMainFields, [key], []);
    },

    [selectedField, componentsAndModelsPossibleMainFields, modifiedData]
  );

  const metaFields = formToDisplay.map(meta => {
    const formType = get(attributes, [selectedField, 'type']);

    if (
      formType === 'dynamiczone' ||
      (formType === 'component' && !['label', 'description'].includes(meta))
    ) {
      return null;
    }

    if (formType === 'component' && meta !== 'label') {
      return null;
    }

    if (['media', 'json', 'boolean'].includes(formType) && meta === 'placeholder') {
      return null;
    }

    return (
      <GridItem col={6} key={meta}>
        <GenericInput
          type={getInputProps(meta).type}
          hint={
            meta === 'mainField'
              ? formatMessage({
                  id: getTrad('containers.SettingPage.editSettings.relation-field.description'),
                })
              : ''
          }
          label={formatMessage({
            id: get(getInputProps(meta), 'label.id', 'app.utils.defaultMessage'),
          })}
          name={meta}
          onChange={onMetaChange}
          value={get(fieldForm, ['metadata', meta], '')}
          options={getSelectedItemSelectOptions(formType)}
        />
      </GridItem>
    );
  });

  const canResize = !NON_RESIZABLE_FIELD_TYPES.includes(attributes[selectedField].type);

  const sizeField = <GridItem col={6} key="size">
    <Select
      value={fieldForm?.size}
      name="size"
      onChange={(value) => {
        onSizeChange({ name: selectedField, value });
      }}
      label={formatMessage({
        id: getTrad('containers.SettingPage.editSettings.size.label'),
        defaultMessage: "Size"
      })}
    >
      {FIELD_SIZES.map(([value, label]) => (
        <Option key={value} value={value}>
          {label}
        </Option>
      ))}
    </Select>
                    </GridItem>;

  return <>
    {metaFields}
    {canResize && sizeField}
  </>
};

export default ModalForm;
<commit_msg>CM: Add missing prop-types<commit_after>import React, { useMemo, useCallback } from 'react';
import PropTypes from 'prop-types';
import get from 'lodash/get';
import { GridItem } from '@strapi/design-system/Grid';
import { Select, Option } from '@strapi/design-system/Select';
import { useSelector, shallowEqual } from 'react-redux';
import { useIntl } from 'react-intl';
import { useLayoutDnd } from '../../../hooks';
import { createPossibleMainFieldsForModelsAndComponents, getInputProps } from '../utils';
import { makeSelectModelAndComponentSchemas } from '../../App/selectors';
import getTrad from '../../../utils/getTrad';
import GenericInput from './GenericInput';

const FIELD_SIZES = [
  [4, '33%'],
  [6, '50%'],
  [8, '66%'],
  [12, '100%']
];

const NON_RESIZABLE_FIELD_TYPES = [
  'dynamiczone',
  'component',
  'json',
  'richtext'
];

const ModalForm = ({ onMetaChange, onSizeChange }) => {
  const { formatMessage } = useIntl();
  const { modifiedData, selectedField, attributes, fieldForm } = useLayoutDnd();
  const schemasSelector = useMemo(makeSelectModelAndComponentSchemas, []);
  const { schemas } = useSelector(state => schemasSelector(state), shallowEqual);

  const formToDisplay = useMemo(() => {
    if (!selectedField) {
      return [];
    }

    const associatedMetas = get(modifiedData, ['metadatas', selectedField, 'edit'], {});

    return Object.keys(associatedMetas).filter(meta => meta !== 'visible');
  }, [selectedField, modifiedData]);

  const componentsAndModelsPossibleMainFields = useMemo(() => {
    return createPossibleMainFieldsForModelsAndComponents(schemas);
  }, [schemas]);

  const getSelectedItemSelectOptions = useCallback(
    formType => {
      if (formType !== 'relation' && formType !== 'component') {
        return [];
      }

      const targetKey = formType === 'component' ? 'component' : 'targetModel';
      const key = get(modifiedData, ['attributes', selectedField, targetKey], '');

      return get(componentsAndModelsPossibleMainFields, [key], []);
    },

    [selectedField, componentsAndModelsPossibleMainFields, modifiedData]
  );

  const metaFields = formToDisplay.map(meta => {
    const formType = get(attributes, [selectedField, 'type']);

    if (
      formType === 'dynamiczone' ||
      (formType === 'component' && !['label', 'description'].includes(meta))
    ) {
      return null;
    }

    if (formType === 'component' && meta !== 'label') {
      return null;
    }

    if (['media', 'json', 'boolean'].includes(formType) && meta === 'placeholder') {
      return null;
    }

    return (
      <GridItem col={6} key={meta}>
        <GenericInput
          type={getInputProps(meta).type}
          hint={
            meta === 'mainField'
              ? formatMessage({
                  id: getTrad('containers.SettingPage.editSettings.relation-field.description'),
                })
              : ''
          }
          label={formatMessage({
            id: get(getInputProps(meta), 'label.id', 'app.utils.defaultMessage'),
          })}
          name={meta}
          onChange={onMetaChange}
          value={get(fieldForm, ['metadata', meta], '')}
          options={getSelectedItemSelectOptions(formType)}
        />
      </GridItem>
    );
  });

  const canResize = !NON_RESIZABLE_FIELD_TYPES.includes(attributes[selectedField].type);

  const sizeField = <GridItem col={6} key="size">
    <Select
      value={fieldForm?.size}
      name="size"
      onChange={(value) => {
        onSizeChange({ name: selectedField, value });
      }}
      label={formatMessage({
        id: getTrad('containers.SettingPage.editSettings.size.label'),
        defaultMessage: "Size"
      })}
    >
      {FIELD_SIZES.map(([value, label]) => (
        <Option key={value} value={value}>
          {label}
        </Option>
      ))}
    </Select>
  </GridItem>;

  return <>
    {metaFields}
    {canResize && sizeField}
  </>
};

ModalForm.propTypes = {
  onMetaChange: PropTypes.func.isRequired,
  onSizeChange: PropTypes.func.isRequired,
};

export default ModalForm;
<|endoftext|>


<commit_before>angular.module('app').factory('keypressService', [
    '$window',
    '$rootScope',
    '$log',
    function($window, $rootScope, $log) {

      function KeypressService() {
        this.registeredCombos = [];
        this.listener = new $window.keypress.Listener();
      }

      KeypressService.prototype.isRegistered = function isRegistered(combo) {
        var registration = this.registeredCombos[combo];
        return registration ? true : false;
      };

      KeypressService.prototype.registerCombo = function registerCombo(combo, callback) {
        if (this.isRegistered(combo)) {
          $log.error(combo + ' is already registered, unregistering previous combo');
          this.unregisterCombo(combo);
        }

        $log.debug('Registering keypress combo : ' + combo);

        this.listener.counting_combo(combo, function() { // jshint ignore:line
          callback.call(arguments);
          $rootScope.$apply();
        }, true);
      };

      KeypressService.prototype.unregisterCombo = function unregisterCombo(combo) {
        this.listener.unregister_combo(combo); // jshint ignore:line
      };

      KeypressService.prototype.EVENTS = {
        CLOSE_WINDOW: 'meta w',
        NEW_TAB: 'meta t',
        MOVE_LEFT: 'meta shift {',
        MOVE_RIGHT: 'meta shift }',
        OPEN_CONNECTION_MANAGER: 'meta shift n'
      };

      return new KeypressService();
    }
  ])
  .run([
    '$rootScope',
    'keypressService',
    'tabCache',
    function($rootScope, keypressService, tabCache) {
      $rootScope.$on('$destroy', function() {
        keypressService.unregisterCombo(keypressService.EVENTS.CLOSE_WINDOW);
        keypressService.unregisterCombo(keypressService.EVENTS.MOVE_LEFT);
        keypressService.unregisterCombo(keypressService.EVENTS.MOVE_RIGHT);
        keypressService.unregisterCombo(keypressService.EVENTS.OPEN_CONNECTION_MANAGER);
      });

      keypressService.registerCombo(keypressService.EVENTS.CLOSE_WINDOW, function() {
        console.log(keypressService.EVENTS.CLOSE_WINDOW);
        tabCache.removeActive();
      });

      keypressService.registerCombo(keypressService.EVENTS.MOVE_LEFT, function() {
        console.log(keypressService.EVENTS.MOVE_LEFT);
        tabCache.activatePrevious();
      });

      keypressService.registerCombo(keypressService.EVENTS.MOVE_RIGHT, function() {
        console.log(keypressService.EVENTS.MOVE_RIGHT);
        tabCache.activateNext();
      });

      keypressService.registerCombo(keypressService.EVENTS.OPEN_CONNECTION_MANAGER, function() {
        console.log(keypressService.EVENTS.OPEN_CONNECTION_MANAGER);
        $rootScope.showConnections();
      });
    }
  ]);
<commit_msg>cleanup unregistering keypress events<commit_after>angular.module('app').factory('keypressService', [
  '$window',
  '$rootScope',
  '$log',
  function($window, $rootScope, $log) {

    function KeypressService() {
      this.registeredCombos = [];
      this.listener = new $window.keypress.Listener();
    }

    KeypressService.prototype.isRegistered = function isRegistered(combo) {
      var registration = this.registeredCombos[combo];
      return registration ? true : false;
    };

    KeypressService.prototype.registerCombo = function registerCombo(combo, callback) {
      if (this.isRegistered(combo)) {
        $log.error(combo + ' is already registered, unregistering previous combo');
        this.unregisterCombo(combo);
      }

      $log.debug('Registering keypress combo : ' + combo);

      this.listener.counting_combo(combo, function() { // jshint ignore:line
        callback.call(arguments);
        $rootScope.$apply();
      }, true);
    };

    KeypressService.prototype.unregisterCombo = function unregisterCombo(combo) {
      this.listener.unregister_combo(combo); // jshint ignore:line
    };

    KeypressService.prototype.unregisterAllCombos = function unregisterAllCombos() {
      var _this = this;

      _.each(_this.registeredCombos, function(combo) {
        _this.listener.unregister_combo(combo); // jshint ignore:line
      });
    };

    KeypressService.prototype.EVENTS = {
      CLOSE_WINDOW: 'meta w',
      NEW_TAB: 'meta t',
      MOVE_LEFT: 'meta shift {',
      MOVE_RIGHT: 'meta shift }',
      OPEN_CONNECTION_MANAGER: 'meta shift n',
      OPEN_SETTINGS: 'meta ,'
    };

    return new KeypressService();
  }
]);

// run block for registering keypress events
angular.module('app').run([
  '$rootScope',
  'keypressService',
  'tabCache',
  function($rootScope, keypressService, tabCache) {
    $rootScope.$on('$destroy', function() {
      keypressService.unregisterAllCombos();
    });

    keypressService.registerCombo(keypressService.EVENTS.CLOSE_WINDOW, function() {
      console.log(keypressService.EVENTS.CLOSE_WINDOW);
      tabCache.removeActive();
    });

    keypressService.registerCombo(keypressService.EVENTS.MOVE_LEFT, function() {
      console.log(keypressService.EVENTS.MOVE_LEFT);
      tabCache.activatePrevious();
    });

    keypressService.registerCombo(keypressService.EVENTS.MOVE_RIGHT, function() {
      console.log(keypressService.EVENTS.MOVE_RIGHT);
      tabCache.activateNext();
    });

    keypressService.registerCombo(keypressService.EVENTS.OPEN_CONNECTION_MANAGER, function() {
      console.log(keypressService.EVENTS.OPEN_CONNECTION_MANAGER);
      $rootScope.showConnections();
    });

    keypressService.registerCombo(keypressService.EVENTS.OPEN_SETTINGS, function() {
      console.log(keypressService.EVENTS.OPEN_SETTINGS);
      $rootScope.showSettings();
    });
  }
]);
<|endoftext|>


<commit_before>/*
THIS SOFTWARE IS PROVIDED BY ANDREW M. TRICE ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANDREW M. TRICE OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

var ViewNavigator = function( target, backLinkCSS, bindToWindow ) {

	this.supportsBackKey = true; //phonegap on android only
	this.animating = false;
	this.animationX = 150;
	this.animationDuration = 400;
	this.history = [];
	this.scroller = null;
	this.headerPadding = 5;

	this.uniqueId = this.guid();

	var regexp = new RegExp("Windows Phone OS 7");
	this.winPhone = (navigator.userAgent.search(regexp) >= 0);

	this.rootElement = $('

');
	this.header = $('

');
	this.content = $('

');
	this.rootElement.append( this.header );
	this.rootElement.append( this.content );

	this.parent = $( target );

	this.backLinkCSS = backLinkCSS ? backLinkCSS : "viewNavigator_backButton";

	var self = this;
	//$(window).resize( function(event){ self.resizeContent() } );
	//alert( this.parent.toString() );
	//this.parent.resize( function(event){ self.resizeContent() } );

	if ( bindToWindow != false ) {
		$(window).resize( function(event){ self.resizeContent() } );
	}
	else {
		this.parent.resize( function(event){ self.resizeContent() } );
	}

	this.parent.append( this.rootElement );

	if ( window.viewNavigators == null || window.viewNavigators == undefined ) {
		window.viewNavigators = {};
	}
	window.viewNavigators[ this.uniqueId ] = this;

}

ViewNavigator.prototype.replaceView = function( viewDescriptor ) {
	if (this.animating)
		return;
	viewDescriptor.animation = "pushEffect"

	//this is a hack to mimic behavior of pushView, then pop off the "current" from the history
	this.history.push( viewDescriptor );
	this.updateView( viewDescriptor );
	this.history.pop();
	this.history.pop();
	this.history.push( viewDescriptor );
}

ViewNavigator.prototype.pushView = function( viewDescriptor ) {
	if (this.animating)
		return;
	viewDescriptor.animation = "pushEffect"
	this.history.push( viewDescriptor );
	this.updateView( viewDescriptor );
}

ViewNavigator.prototype.popView = function() {

	if (this.animating || this.history.length <= 1 )
		return;

	var currentViewDescriptor = this.history[ this.history.length-1];
	if ( currentViewDescriptor.backCallback ) {
		currentViewDescriptor.backCallback();
	}

	this.history.pop();
	var viewDescriptor = this.history[ this.history.length-1 ];
	viewDescriptor.animation = "popEffect"
	this.updateView( viewDescriptor );
}

ViewNavigator.prototype.setHeaderPadding = function( amount ) {
	this.headerPadding = amount;
	if ( this.headerBacklink ) {
		this.headerBacklink.css("left", amount);
	}
}

ViewNavigator.prototype.updateView = function( viewDescriptor ) {

	this.animating = true;

	this.contentPendingRemove = this.contentViewHolder;
	this.headerContentPendingRemove = this.headerContent;

	this.headerContent = $('

');

	this.headerTitle = $("
" + viewDescriptor.title + "
");
	this.headerContent.append( this.headerTitle );

	var linkGuid = this.guid();
	if ( viewDescriptor.backLabel ) {
		this.headerBacklink = $('
'+ viewDescriptor.backLabel + '
');
		this.headerContent.append( this.headerBacklink );

		//this is for proper handling in splitviewnavigator
		this.setHeaderPadding( this.headerPadding );
	}

	var id = this.guid();
	this.contentViewHolder = $('

');
	this.contentViewHolder.append( viewDescriptor.view );
	this.resizeContent();

	if ( this.contentPendingRemove ){
        this.contentPendingRemove.stop()
	}
	if ( this.headerContentPendingRemove ) {
        this.headerContentPendingRemove.stop()
	}
	this.headerContent.stop()
	this.contentViewHolder.stop()

	if ( this.scroller != null ) {
	    var scrollY = this.scroller.y;
        this.scroller.destroy();
        this.scroller = null;

        if (this.contentPendingRemove) {
            //console.log( scrollY );

            //use this to mantain scroll position when scroller is destroyed
            var children = $( this.contentPendingRemove.children()[0] );
            children.attr( "scrollY", scrollY );
            var originalTopMargin = children.css( "margin-top" );
            children.attr( "originalTopMargin", originalTopMargin );

            var cssString = "translate3d(0px, "+(parseInt( scrollY ) + parseInt( originalTopMargin )).toString()+"px, 0px)";
            children.css( "-webkit-transform", cssString );

           // children.css( "margin-top", (parseInt( scrollY ) + parseInt( originalTopMargin )).toString() + "px" );
        }
    }

	$(this.contentPendingRemove).click(function(){ return false; });

	if ( viewDescriptor.animation == "popEffect" ) {

		this.contentViewHolder.css( "left", -this.contentViewHolder.width() );
		this.contentViewHolder.css( "opacity", 1 );
    	this.content.prepend( this.contentViewHolder );

		this.headerContent.css( "left", -this.animationX );
		this.headerContent.css( "opacity", 0 );
		this.header.append( this.headerContent );

    	var func = this.animationCompleteHandler(this.contentPendingRemove, this.headerContentPendingRemove, this.headerContent, this.contentViewHolder );

 	   	this.contentPendingRemove.animate({
   	 			left:this.contentViewHolder.width(),
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration*0.8);

    	//remove this to change back
 	   	this.contentViewHolder.animate({
   	 			left:0,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration/2);

    	this.headerContentPendingRemove.animate({
   	 			left:this.animationX,
    			opacity:0,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration, func );

    	this.headerContent.animate({
   	 			left:0,
    			opacity:1,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration/2 );

    	//using a timeout to get around inconsistent response times for webkittransitionend event
        //var func = this.animationCompleteHandler(this.contentPendingRemove, this.headerContentPendingRemove, this.headerContent, this.contentViewHolder );
    	//setTimeout( func, this.animationDuration+90 );
	}
	else if ( this.history.length > 1 ) {

		this.contentViewHolder.css( "left", this.contentViewHolder.width() );
		this.contentViewHolder.css( "opacity", 1 );

    	this.content.append( this.contentViewHolder );

		this.headerContent.css( "left", this.animationX );
		this.headerContent.css( "opacity", 0 );
		this.header.append( this.headerContent );

        var func = this.animationCompleteHandler(this.contentPendingRemove, this.headerContentPendingRemove, this.headerContent, this.contentViewHolder );

 	   	this.contentViewHolder.animate({
   	 			left:0,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration*0.75);

 	   	this.contentPendingRemove.animate({
   	 			left:-this.contentViewHolder.width()/2,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration, func);

    	this.headerContent.animate({
   	 			left:0,
    			opacity:1,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration*0.75);

    	this.headerContentPendingRemove.animate({
   	 			left:-this.animationX,
    			opacity:0,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration );

    	//using a timeout to get around inconsistent response times for webkittransitionend event
    	//var func = this.animationCompleteHandler(this.contentPendingRemove, this.headerContentPendingRemove, this.headerContent, this.contentViewHolder );
    	//setTimeout( func, this.animationDuration+90 );
	}
	else {
		this.contentViewHolder.css( "left", 0 );
		this.contentViewHolder.css( "opacity", 1 );
    	this.content.append( this.contentViewHolder );

		this.headerContent.css( "left", 0 );
		this.headerContent.css( "opacity", 1 );
		this.header.append( this.headerContent );
		this.animating = false;
		this.resetScroller();
	}

    if ( viewDescriptor.backLabel ) {
    	new NoClickDelay( this.headerBacklink.get()[0] );
	}

	if ( viewDescriptor.showCallback ) {
	    viewDescriptor.showCallback();
	}
}

ViewNavigator.prototype.destroyScroller = function() {

	if ( !this.winPhone ) {
		if ( this.scroller != null ) {
			this.scroller.destroy();
			this.scroller = null;
		}
    }
}

ViewNavigator.prototype.resetScroller = function() {

    var id = this.contentViewHolder.attr( "id" );
    var currentViewDescriptor = this.history[ this.history.length-1];
    this.destroyScroller();

	if ( !this.winPhone ) {
		if ( id && !(currentViewDescriptor && currentViewDescriptor.scroll == false)) {
			var self = this;
			if ( this.touchEnabled ){
                setTimeout( function() {

                    //use this to mantain scroll position when scroller is destroyed
                    var targetDiv = $( $("#"+id ).children()[0] );
                    var scrollY= targetDiv.attr( "scrollY" );
                    var originalTopMargin = targetDiv.attr( "originalTopMargin" );
                    if ( currentViewDescriptor.maintainScrollPosition !== false && scrollY != undefined && scrollY != "" ){
                      //  console.log( "resetScroller scrollY: " + scrollY)
                      //  targetDiv.css( "margin-top", originalTopMargin );
                        var cssString = "translate3d(0px, "+(originalTopMargin).toString()+"px, 0px)";
                        targetDiv.css( "-webkit-transform", cssString );
                    }
                    self.scroller = new iScroll( id );
                    if ( currentViewDescriptor.maintainScrollPosition !== false && scrollY != undefined && scrollY != "" ) {
                        self.scroller.scrollTo( 0, parseInt( scrollY ) );
                    }
                }, 10 );
                //this.scroller = new iScroll( id );
			}
			else {
			    var target = $("#"+id );
			    target.css( "overflow", "auto" );
			}
		}
    }
}

ViewNavigator.prototype.refreshScroller = function() {

	if ( !this.winPhone ) {
		if ( this.scroller != null ) {
			this.scroller.refresh();
		}
    }
}

ViewNavigator.prototype.animationCompleteHandler = function(removalTarget, headerRemovalTarget, headerView, contentView) {
	var self = this;
	return function() {
		self.animating = false;
        self.resetScroller();
		if ( removalTarget ) {
			removalTarget.unbind( "click" );
			removalTarget.detach();
		}
		if ( headerRemovalTarget ) {
			headerRemovalTarget.unbind( "click" );
			headerRemovalTarget.detach();
		}
	}
}

ViewNavigator.prototype.resizeContent = function(event) {

	var targetWidth = this.parent.width();
	if ( this.headerContent )
		this.headerContent.width( targetWidth );
	if ( this.contentViewHolder )
		this.contentViewHolder.width( targetWidth );
}

//GUID logic from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript

ViewNavigator.prototype.S4 = function() {
    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}

ViewNavigator.prototype.guid = function() {
	return (this.S4() + this.S4() + "-" + this.S4() + "-4" + this.S4().substr(0,3) + "-" + this.S4() + "-" + this.S4() + this.S4() + this.S4()).toLowerCase();
}

/*  PHONEGAP INTEGRATION */
/*
//android+phonegap specific back button support - will only work if phonegap is used on android (www.phonegap.com)
if ( typeof PhoneGap != 'undefined' ) {
	document.addEventListener("deviceready", onDeviceReady, false);
}

function onDeviceReady() {
   document.addEventListener("backbutton", onBackKey, false);
}

function onBackKey( event ) {
	event.preventDefault();
	window.viewNavigator.popView();
	for ( var x=0; x<window.backKeyViewNavigators.length; x++ ) {
		window.backKeyViewNavigators[x].popView();
	}
}
*/
<commit_msg>re-added code to block "normal" page scrolling on touch<commit_after>/*
THIS SOFTWARE IS PROVIDED BY ANDREW M. TRICE ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANDREW M. TRICE OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

var ViewNavigator = function( target, backLinkCSS, bindToWindow ) {

	this.supportsBackKey = true; //phonegap on android only
	this.animating = false;
	this.animationX = 150;
	this.animationDuration = 400;
	this.history = [];
	this.scroller = null;
	this.headerPadding = 5;

	this.uniqueId = this.guid();

	var regexp = new RegExp("Windows Phone OS 7");
	this.winPhone = (navigator.userAgent.search(regexp) >= 0);

	this.rootElement = $('

');
	this.header = $('

');
	this.content = $('

');
	this.rootElement.append( this.header );
	this.rootElement.append( this.content );

	this.parent = $( target );

	this.backLinkCSS = backLinkCSS ? backLinkCSS : "viewNavigator_backButton";

	var self = this;
	//$(window).resize( function(event){ self.resizeContent() } );
	//alert( this.parent.toString() );
	//this.parent.resize( function(event){ self.resizeContent() } );

	if ( bindToWindow != false ) {
		$(window).resize( function(event){ self.resizeContent() } );
	}
	else {
		this.parent.resize( function(event){ self.resizeContent() } );
	}

	this.parent.append( this.rootElement );

	if ( window.viewNavigators == null || window.viewNavigators == undefined ) {
		window.viewNavigators = {};
	}
	window.viewNavigators[ this.uniqueId ] = this;

}

ViewNavigator.prototype.replaceView = function( viewDescriptor ) {
	if (this.animating)
		return;
	viewDescriptor.animation = "pushEffect"

	//this is a hack to mimic behavior of pushView, then pop off the "current" from the history
	this.history.push( viewDescriptor );
	this.updateView( viewDescriptor );
	this.history.pop();
	this.history.pop();
	this.history.push( viewDescriptor );
}

ViewNavigator.prototype.pushView = function( viewDescriptor ) {
	if (this.animating)
		return;
	viewDescriptor.animation = "pushEffect"
	this.history.push( viewDescriptor );
	this.updateView( viewDescriptor );
}

ViewNavigator.prototype.popView = function() {

	if (this.animating || this.history.length <= 1 )
		return;

	var currentViewDescriptor = this.history[ this.history.length-1];
	if ( currentViewDescriptor.backCallback ) {
		currentViewDescriptor.backCallback();
	}

	this.history.pop();
	var viewDescriptor = this.history[ this.history.length-1 ];
	viewDescriptor.animation = "popEffect"
	this.updateView( viewDescriptor );
}

ViewNavigator.prototype.setHeaderPadding = function( amount ) {
	this.headerPadding = amount;
	if ( this.headerBacklink ) {
		this.headerBacklink.css("left", amount);
	}
}

ViewNavigator.prototype.updateView = function( viewDescriptor ) {

	this.animating = true;

	this.contentPendingRemove = this.contentViewHolder;
	this.headerContentPendingRemove = this.headerContent;

	this.headerContent = $('

');

	this.headerTitle = $("
" + viewDescriptor.title + "
");
	this.headerContent.append( this.headerTitle );

	var linkGuid = this.guid();
	if ( viewDescriptor.backLabel ) {
		this.headerBacklink = $('
'+ viewDescriptor.backLabel + '
');
		this.headerContent.append( this.headerBacklink );

		//this is for proper handling in splitviewnavigator
		this.setHeaderPadding( this.headerPadding );
	}

	var id = this.guid();
	this.contentViewHolder = $('

');
	this.contentViewHolder.append( viewDescriptor.view );
	this.resizeContent();

	if ( this.contentPendingRemove ){
        this.contentPendingRemove.stop()
	}
	if ( this.headerContentPendingRemove ) {
        this.headerContentPendingRemove.stop()
	}
	this.headerContent.stop()
	this.contentViewHolder.stop()

	if ( this.scroller != null ) {
	    var scrollY = this.scroller.y;
        this.scroller.destroy();
        this.scroller = null;

        if (this.contentPendingRemove) {
            //console.log( scrollY );

            //use this to mantain scroll position when scroller is destroyed
            var children = $( this.contentPendingRemove.children()[0] );
            children.attr( "scrollY", scrollY );
            var originalTopMargin = children.css( "margin-top" );
            children.attr( "originalTopMargin", originalTopMargin );

            var cssString = "translate3d(0px, "+(parseInt( scrollY ) + parseInt( originalTopMargin )).toString()+"px, 0px)";
            children.css( "-webkit-transform", cssString );

           // children.css( "margin-top", (parseInt( scrollY ) + parseInt( originalTopMargin )).toString() + "px" );
        }
    }

	$(this.contentPendingRemove).click(function(){ return false; });

	if ( viewDescriptor.animation == "popEffect" ) {

		this.contentViewHolder.css( "left", -this.contentViewHolder.width() );
		this.contentViewHolder.css( "opacity", 1 );
    	this.content.prepend( this.contentViewHolder );

		this.headerContent.css( "left", -this.animationX );
		this.headerContent.css( "opacity", 0 );
		this.header.append( this.headerContent );

    	var func = this.animationCompleteHandler(this.contentPendingRemove, this.headerContentPendingRemove, this.headerContent, this.contentViewHolder );

 	   	this.contentPendingRemove.animate({
   	 			left:this.contentViewHolder.width(),
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration*0.8);

    	//remove this to change back
 	   	this.contentViewHolder.animate({
   	 			left:0,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration/2);

    	this.headerContentPendingRemove.animate({
   	 			left:this.animationX,
    			opacity:0,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration, func );

    	this.headerContent.animate({
   	 			left:0,
    			opacity:1,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration/2 );

    	//using a timeout to get around inconsistent response times for webkittransitionend event
        //var func = this.animationCompleteHandler(this.contentPendingRemove, this.headerContentPendingRemove, this.headerContent, this.contentViewHolder );
    	//setTimeout( func, this.animationDuration+90 );
	}
	else if ( this.history.length > 1 ) {

		this.contentViewHolder.css( "left", this.contentViewHolder.width() );
		this.contentViewHolder.css( "opacity", 1 );

    	this.content.append( this.contentViewHolder );

		this.headerContent.css( "left", this.animationX );
		this.headerContent.css( "opacity", 0 );
		this.header.append( this.headerContent );

        var func = this.animationCompleteHandler(this.contentPendingRemove, this.headerContentPendingRemove, this.headerContent, this.contentViewHolder );

 	   	this.contentViewHolder.animate({
   	 			left:0,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration*0.75);

 	   	this.contentPendingRemove.animate({
   	 			left:-this.contentViewHolder.width()/2,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration, func);

    	this.headerContent.animate({
   	 			left:0,
    			opacity:1,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration*0.75);

    	this.headerContentPendingRemove.animate({
   	 			left:-this.animationX,
    			opacity:0,
    			avoidTransforms:false,
    			useTranslate3d: true
    		}, this.animationDuration );

    	//using a timeout to get around inconsistent response times for webkittransitionend event
    	//var func = this.animationCompleteHandler(this.contentPendingRemove, this.headerContentPendingRemove, this.headerContent, this.contentViewHolder );
    	//setTimeout( func, this.animationDuration+90 );
	}
	else {
		this.contentViewHolder.css( "left", 0 );
		this.contentViewHolder.css( "opacity", 1 );
    	this.content.append( this.contentViewHolder );

		this.headerContent.css( "left", 0 );
		this.headerContent.css( "opacity", 1 );
		this.header.append( this.headerContent );
		this.animating = false;
		this.resetScroller();
	}

    if ( viewDescriptor.backLabel ) {
    	new NoClickDelay( this.headerBacklink.get()[0] );
	}

	if ( viewDescriptor.showCallback ) {
	    viewDescriptor.showCallback();
	}
}

ViewNavigator.prototype.destroyScroller = function() {

	if ( !this.winPhone ) {
		if ( this.scroller != null ) {
			this.scroller.destroy();
			this.scroller = null;
		}
    }
}

ViewNavigator.prototype.resetScroller = function() {

    var id = this.contentViewHolder.attr( "id" );
    var currentViewDescriptor = this.history[ this.history.length-1];
    this.destroyScroller();

	if ( !this.winPhone ) {
		if ( id && !(currentViewDescriptor && currentViewDescriptor.scroll == false)) {
			var self = this;
			if ( this.touchEnabled ){
                setTimeout( function() {

                    //use this to mantain scroll position when scroller is destroyed
                    var targetDiv = $( $("#"+id ).children()[0] );
                    var scrollY= targetDiv.attr( "scrollY" );
                    var originalTopMargin = targetDiv.attr( "originalTopMargin" );
                    if ( currentViewDescriptor.maintainScrollPosition !== false && scrollY != undefined && scrollY != "" ){
                      //  console.log( "resetScroller scrollY: " + scrollY)
                      //  targetDiv.css( "margin-top", originalTopMargin );
                        var cssString = "translate3d(0px, "+(originalTopMargin).toString()+"px, 0px)";
                        targetDiv.css( "-webkit-transform", cssString );
                    }
                    self.scroller = new iScroll( id );
                    if ( currentViewDescriptor.maintainScrollPosition !== false && scrollY != undefined && scrollY != "" ) {
                        self.scroller.scrollTo( 0, parseInt( scrollY ) );
                    }
                }, 10 );
                //this.scroller = new iScroll( id );
			}
			else {
			    var target = $("#"+id );
			    target.css( "overflow", "auto" );
			}
		}
    }
}

ViewNavigator.prototype.refreshScroller = function() {

	if ( !this.winPhone ) {
		if ( this.scroller != null ) {
			this.scroller.refresh();
		}
    }
}

ViewNavigator.prototype.animationCompleteHandler = function(removalTarget, headerRemovalTarget, headerView, contentView) {
	var self = this;
	return function() {
		self.animating = false;
        self.resetScroller();
		if ( removalTarget ) {
			removalTarget.unbind( "click" );
			removalTarget.detach();
		}
		if ( headerRemovalTarget ) {
			headerRemovalTarget.unbind( "click" );
			headerRemovalTarget.detach();
		}
	}
}

ViewNavigator.prototype.resizeContent = function(event) {

	var targetWidth = this.parent.width();
	if ( this.headerContent )
		this.headerContent.width( targetWidth );
	if ( this.contentViewHolder )
		this.contentViewHolder.width( targetWidth );
}

//GUID logic from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript

ViewNavigator.prototype.S4 = function() {
    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}

ViewNavigator.prototype.guid = function() {
	return (this.S4() + this.S4() + "-" + this.S4() + "-4" + this.S4().substr(0,3) + "-" + this.S4() + "-" + this.S4() + this.S4() + this.S4()).toLowerCase();
}

/*  PHONEGAP INTEGRATION */
/*
//android+phonegap specific back button support - will only work if phonegap is used on android (www.phonegap.com)
if ( typeof PhoneGap != 'undefined' ) {
	document.addEventListener("deviceready", onDeviceReady, false);
}

function onDeviceReady() {
   document.addEventListener("backbutton", onBackKey, false);
}

function onBackKey( event ) {
	event.preventDefault();
	window.viewNavigator.popView();
	for ( var x=0; x<window.backKeyViewNavigators.length; x++ ) {
		window.backKeyViewNavigators[x].popView();
	}
}
*/

//block page scrolling
$(document).ready(function() {

	$(document).bind( "touchmove", function (e) { e.preventDefault(); return false; } );

}

<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { List } from 'immutable';
import classnames from 'classnames';

import ReactDataGrid from 'react-data-grid/addons';
import TextField from 'material-ui/lib/text-field';

import {
  SORT_ASCENDING, SORT_DESCENDING, SORT_NONE,
  getFilter, getFilteredSortedRows,
  searchSetFilter, searchSetSortColumn, searchSetSortDirection
} from '../../redux/modules/search';

import classes from './SearchView.css';

// map ReactDataGrid's internal direction to our constants
const DIRECTION = {
  ASC: SORT_ASCENDING,
  DESC: SORT_DESCENDING,
  NONE: SORT_NONE
};

export class SearchView extends React.Component {
  static propTypes = {
    filter: PropTypes.string,
    rows: PropTypes.instanceOf(List),
    searchSetFilter: PropTypes.func.isRequired,
    searchSetSortColumn: PropTypes.func.isRequired,
    searchSetSortDirection: PropTypes.func.isRequired
  };

  constructor () {
    super();
    this.handleFilterChange = this.handleFilterChange.bind(this);
    this.handleGridSort = this.handleGridSort.bind(this);
  }

  handleFilterChange () {}

  handleGridSort (column, direction) {
    this.props.searchSetSortColumn(column);
    this.props.searchSetSortDirection(DIRECTION[direction]);
  }

  render () {
    const { filter, rows, searchSetFilter } = this.props;

    const columnProps = {
      filterable: true,
      sortable: true
    };

    const gridProps = {
      columns: [
        Object.assign({ key: 'firstname', name: 'First Name' }, columnProps),
        Object.assign({ key: 'lastname', name: 'Surname' }, columnProps),
        Object.assign({ key: 'location', name: 'Location' }, columnProps)
      ],
      enableCellSelect: true,
      minHeight: document.documentElement.clientHeight - 220,
      onGridSort: this.handleGridSort,
      rowGetter: (index) => rows.get(index),
      rowsCount: rows.size
    };

    const filterProps = {
      className: classes.filter,
      floatingLabelText: 'Filter',
      type: 'search',
      onChange: () => searchSetFilter(this.refs.search.getValue()),
      ref: 'search',
      value: filter
    };

    return (

        <TextField {...filterProps} />
        <ReactDataGrid {...gridProps} />

    );
  }
}

const mapStateToProps = (state) => ({
  getFilter: getFilter(state),
  rows: getFilteredSortedRows(state)
});
export default connect((mapStateToProps), {
  searchSetFilter,
  searchSetSortColumn,
  searchSetSortDirection
})(SearchView);
<commit_msg>/search refreshes data every 30 seconds<commit_after>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { List } from 'immutable';
import classnames from 'classnames';

import ReactDataGrid from 'react-data-grid/addons';
import TextField from 'material-ui/lib/text-field';

import {
  SORT_ASCENDING, SORT_DESCENDING, SORT_NONE,
  getFilter, getFilteredSortedRows,
  searchSetFilter, searchSetSortColumn, searchSetSortDirection
} from '../../redux/modules/search';
import { readersRequest } from '../../redux/modules/readers';
import { tagsRequest } from '../../redux/modules/tags';
import { usersRequest } from '../../redux/modules/users';

import classes from './SearchView.css';

// map ReactDataGrid's internal direction to our constants
const DIRECTION = {
  ASC: SORT_ASCENDING,
  DESC: SORT_DESCENDING,
  NONE: SORT_NONE
};

export class SearchView extends React.Component {
  static propTypes = {
    filter: PropTypes.string,
    readersRequest: PropTypes.func.isRequired,
    rows: PropTypes.instanceOf(List),
    searchSetFilter: PropTypes.func.isRequired,
    searchSetSortColumn: PropTypes.func.isRequired,
    searchSetSortDirection: PropTypes.func.isRequired,
    tagsRequest: PropTypes.func.isRequired,
    usersRequest: PropTypes.func.isRequired
  };

  constructor () {
    super();
    this.handleFilterChange = this.handleFilterChange.bind(this);
    this.handleGridSort = this.handleGridSort.bind(this);
  }

  componentDidMount () {
    // automatically refresh user listing
    this.props.readersRequest();
    this.props.tagsRequest();
    this.props.usersRequest();
    // automatically refresh user listing every 30 seconds
    this.setState({
      timer: setInterval(() => {
        this.props.readersRequest();
        this.props.tagsRequest();
        this.props.usersRequest();
      }, 30e3)
    });
  }

  componentWillUnmount () {
    clearTimeout(this.state.timer);
  }

  handleFilterChange () {}

  handleGridSort (column, direction) {
    this.props.searchSetSortColumn(column);
    this.props.searchSetSortDirection(DIRECTION[direction]);
  }

  render () {
    const { filter, rows, searchSetFilter } = this.props;

    const columnProps = {
      filterable: true,
      sortable: true
    };

    const gridProps = {
      columns: [
        Object.assign({ key: 'firstname', name: 'First Name' }, columnProps),
        Object.assign({ key: 'lastname', name: 'Surname' }, columnProps),
        Object.assign({ key: 'location', name: 'Location' }, columnProps)
      ],
      enableCellSelect: true,
      minHeight: document.documentElement.clientHeight - 220,
      onGridSort: this.handleGridSort,
      rowGetter: (index) => rows.get(index),
      rowsCount: rows.size
    };

    const filterProps = {
      className: classes.filter,
      floatingLabelText: 'Filter',
      type: 'search',
      onChange: () => searchSetFilter(this.refs.search.getValue()),
      ref: 'search',
      value: filter
    };

    return (

        <TextField {...filterProps} />
        <ReactDataGrid {...gridProps} />

    );
  }
}

const mapStateToProps = (state) => ({
  getFilter: getFilter(state),
  rows: getFilteredSortedRows(state)
});
export default connect((mapStateToProps), {
  readersRequest,
  searchSetFilter,
  searchSetSortColumn,
  searchSetSortDirection,
  tagsRequest,
  usersRequest
})(SearchView);
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var restify = require('restify')
var bufferize = require('./lib/bufferize')
var version = require('../package.json').version
var errors = require('./lib/error')
const safeJsonFormatter = require('./lib/safeJsonFormatter')

function createServer(db) {

  var implementation = db.constructor.name || '__anonymousconstructor__'

  function reply(fn) {
    return function (req, res, next) {
      fn(req.params, req.body, req.query)
        .then(
          handleSuccess.bind(null, req, res),
          handleError.bind(null, req, res)
        )
        .then(next, next)
    }
  }

  function withIdAndBody(fn) {
    return reply(function (params, body, query) {
      return fn.call(db, params.id, body)
    })
  }

  function withBodyAndQuery(fn) {
    return reply(function (params, body, query) {
      return fn.call(db, body, query)
    })
  }

  function withParams(fn) {
    return reply(function (params, body, query) {
      return fn.call(db, params)
    })
  }

  function withParamsAndBody(fn) {
    return reply(function (params, body, query) {
      return fn.call(db, params, body)
    })
  }

  const api = restify.createServer({
    formatters: {
      'application/json; q=0.9': safeJsonFormatter
    },
    maxParamLength: 256
  })

  api.use(restify.plugins.bodyParser())
  api.use(restify.plugins.queryParser())
  api.use(bufferize.bufferizeRequest.bind(null, new Set([
    // These are all the different params that we handle as binary Buffers,
    // but are passed into the API as hex strings.
    'authKey',
    'authSalt',
    'data',
    'deviceId',
    'emailCode',
    'flowId',
    'id',
    'kA',
    'keyBundle',
    'passCode',
    'sessionTokenId',
    'tokenId',
    'tokenVerificationId',
    'uid',
    'verifyHash',
    'wrapWrapKb'
  ])))

  api.get('/account/:id', withIdAndBody(db.account))
  api.del('/account/:id', withIdAndBody(db.deleteAccount))
  api.put('/account/:id', withIdAndBody(db.createAccount))
  api.get('/account/:id/devices', withIdAndBody(db.accountDevices))
  api.post('/account/:id/checkPassword', withIdAndBody(db.checkPassword))
  api.post('/account/:id/reset', withIdAndBody(db.resetAccount))
  api.post('/account/:id/resetTokens', withIdAndBody(db.resetAccountTokens))
  api.post('/account/:id/verifyEmail/:emailCode',
    op(function (req) {
      return db.verifyEmail(req.params.id, req.params.emailCode)
    })
  )
  api.post('/account/:id/locale', withIdAndBody(db.updateLocale))
  api.get('/account/:id/sessions', withIdAndBody(db.sessions))

  api.get('/account/:id/emails', withIdAndBody(db.accountEmails))
  api.post('/account/:id/emails', withIdAndBody(db.createEmail))
  api.del('/account/:id/emails/:email',
    op(function (req) {
      return db.deleteEmail(req.params.id, bufferize.hexToUtf8(req.params.email))
    })
  )

  api.get('/email/:email',
    op(function (req) {
      return db.getSecondaryEmail(bufferize.hexToUtf8(req.params.email))
    })
  )
  api.get('/email/:email/account',
    op(function (req) {
      return db.accountRecord(bufferize.hexToUtf8(req.params.email))
    })
  )
  api.post('/email/:email/account/:id',
    op(function (req) {
      return db.setPrimaryEmail(req.params.id, bufferize.hexToUtf8(req.params.email))
    })
  )

  api.get('/sessionToken/:id', withIdAndBody(db.sessionToken))
  api.del('/sessionToken/:id', withIdAndBody(db.deleteSessionToken))
  api.put('/sessionToken/:id', withIdAndBody(db.createSessionToken))
  api.post('/sessionToken/:id/update', withIdAndBody(db.updateSessionToken))
  api.get('/sessionToken/:id/device', withIdAndBody(db.sessionToken))

  api.get('/keyFetchToken/:id', withIdAndBody(db.keyFetchToken))
  api.del('/keyFetchToken/:id', withIdAndBody(db.deleteKeyFetchToken))
  api.put('/keyFetchToken/:id', withIdAndBody(db.createKeyFetchToken))

  api.get('/keyFetchToken/:id/verified', withIdAndBody(db.keyFetchTokenWithVerificationStatus))
  api.post('/tokens/:id/verify', withIdAndBody(db.verifyTokens))
  api.post('/tokens/:id/verifyWithMethod', withIdAndBody(db.verifyTokensWithMethod))
  api.post('/tokens/:code/verifyCode', withParamsAndBody(db.verifyTokenCode))

  api.get('/accountResetToken/:id', withIdAndBody(db.accountResetToken))
  api.del('/accountResetToken/:id', withIdAndBody(db.deleteAccountResetToken))

  api.get('/passwordChangeToken/:id', withIdAndBody(db.passwordChangeToken))
  api.del('/passwordChangeToken/:id', withIdAndBody(db.deletePasswordChangeToken))
  api.put('/passwordChangeToken/:id', withIdAndBody(db.createPasswordChangeToken))

  api.get('/passwordForgotToken/:id', withIdAndBody(db.passwordForgotToken))
  api.del('/passwordForgotToken/:id', withIdAndBody(db.deletePasswordForgotToken))
  api.put('/passwordForgotToken/:id', withIdAndBody(db.createPasswordForgotToken))
  api.post('/passwordForgotToken/:id/update', withIdAndBody(db.updatePasswordForgotToken))
  api.post('/passwordForgotToken/:id/verified', withIdAndBody(db.forgotPasswordVerified))

  api.get('/verificationReminders', withBodyAndQuery(db.fetchReminders))
  api.post('/verificationReminders', withBodyAndQuery(db.createVerificationReminder))
  api.del('/verificationReminders', withBodyAndQuery(db.deleteReminder))

  api.get('/securityEvents/:id/ip/:ipAddr', withParams(db.securityEvents))
  api.post('/securityEvents', withBodyAndQuery(db.createSecurityEvent))

  api.get('/emailBounces/:id', withIdAndBody(db.fetchEmailBounces))
  api.post('/emailBounces', withBodyAndQuery(db.createEmailBounce))

  api.get('/emailRecord/:id', withIdAndBody(db.emailRecord))
  api.head('/emailRecord/:id', withIdAndBody(db.accountExists))

  api.get('/totp/:id', withIdAndBody(db.totpToken))
  api.del('/totp/:id', withIdAndBody(db.deleteTotpToken))
  api.put('/totp/:id', withIdAndBody(db.createTotpToken))
  api.post('/totp/:id/update', withIdAndBody(db.updateTotpToken))

  api.get('/__heartbeat__', withIdAndBody(db.ping))

  function op(fn) {
    return function (req, res, next) {
      fn.call(null, req)
        .then(
          handleSuccess.bind(null, req, res),
          handleError.bind(null, req, res)
        )
        .then(next, next)
    }
  }

  api.put(
    '/account/:uid/device/:deviceId',
    op(function (req) {
      return db.createDevice(req.params.uid, req.params.deviceId, req.body)
    })
  )
  api.post(
    '/account/:uid/device/:deviceId/update',
    op(function (req) {
      return db.updateDevice(req.params.uid, req.params.deviceId, req.body)
    })
  )
  api.del(
    '/account/:uid/device/:deviceId',
    op(function (req) {
      return db.deleteDevice(req.params.uid, req.params.deviceId)
    })
  )

  api.get(
    '/account/:uid/tokens/:tokenVerificationId/device',
    op(function (req) {
      return db.deviceFromTokenVerificationId(req.params.uid, req.params.tokenVerificationId)
    })
  )

  api.put(
    '/account/:uid/unblock/:code',
    op(function (req) {
      return db.createUnblockCode(req.params.uid, req.params.code)
    })
  )

  api.del(
    '/account/:uid/unblock/:code',
    op(function (req) {
      return db.consumeUnblockCode(req.params.uid, req.params.code)
    })
  )

  api.put(
    '/signinCodes/:code',
    op(req => db.createSigninCode(req.params.code, req.body.uid, req.body.createdAt, req.body.flowId))
  )

  api.post(
    '/signinCodes/:code/consume',
    op(req => db.consumeSigninCode(req.params.code))
  )

  api.post('/account/:id/recoveryCodes',
    op((req) => {
      return db.replaceRecoveryCodes(req.params.id, req.body.count)
    })
  )

  api.post('/account/:id/recoveryCodes/:code',
    op((req) => db.consumeRecoveryCode(req.params.id, req.params.code))
  )

  api.get(
    '/',
    function (req, res, next) {
      res.send({ version: version, implementation: implementation })
      next()
    }
  )

  api.get(
    '/__version__',
    function (req, res, next) {
      res.send({ version: version, implementation: implementation })
      next()
    }
  )

  function handleSuccess(req, res, result) {
    api.emit(
      'success',
      {
        code: 200,
        route: req.route.name,
        method: req.method,
        path: req.url,
        t: Date.now() - req.time()
      }
    )
    if (Array.isArray(result)) {
      res.send(result.map(bufferize.unbuffer))
    }
    else {

      // When performing a `HEAD` request, the content type is not
      // set, manually set to application/json
      if (req.method === 'HEAD') {
        res.setHeader('Content-Type', 'application/json')
      }

      res.send(bufferize.unbuffer(result || {}))
    }
  }

  function handleError (req, res, err) {
    if (typeof err !== 'object') {
      err = { message: err || 'none' }
    }

    var statusCode = err.code || 500

    api.emit(
      'failure',
      {
        code: statusCode,
        route: req.route ? req.route.name : 'unknown',
        method: req.method,
        path: req.url,
        err: err,
        t: Date.now() - req.time(),
      }
    )

    res.send(statusCode, {
      message: err.message,
      errno: err.errno,
      error: err.error,
      code: err.code
    })
  }

  var memInterval = setInterval(function() {
    api.emit('mem', process.memoryUsage())
  }, 15000)
  memInterval.unref()

  api.on('NotFound', function (req, res) {
    handleError(req, res, errors.notFound())
  })

  return api
}

module.exports = {
  createServer: createServer,
  errors: errors
}
<commit_msg>fix(restify): update param size<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var restify = require('restify')
var bufferize = require('./lib/bufferize')
var version = require('../package.json').version
var errors = require('./lib/error')
const safeJsonFormatter = require('./lib/safeJsonFormatter')

function createServer(db) {

  var implementation = db.constructor.name || '__anonymousconstructor__'

  function reply(fn) {
    return function (req, res, next) {
      fn(req.params, req.body, req.query)
        .then(
          handleSuccess.bind(null, req, res),
          handleError.bind(null, req, res)
        )
        .then(next, next)
    }
  }

  function withIdAndBody(fn) {
    return reply(function (params, body, query) {
      return fn.call(db, params.id, body)
    })
  }

  function withBodyAndQuery(fn) {
    return reply(function (params, body, query) {
      return fn.call(db, body, query)
    })
  }

  function withParams(fn) {
    return reply(function (params, body, query) {
      return fn.call(db, params)
    })
  }

  function withParamsAndBody(fn) {
    return reply(function (params, body, query) {
      return fn.call(db, params, body)
    })
  }

  const api = restify.createServer({
    formatters: {
      'application/json; q=0.9': safeJsonFormatter
    },
    // Auth-server accepts 255 unicode email address and sends them over has hex encoded values.
    // These values could be as large as 1530 characters.
    maxParamLength: 1530
  })

  api.use(restify.plugins.bodyParser())
  api.use(restify.plugins.queryParser())
  api.use(bufferize.bufferizeRequest.bind(null, new Set([
    // These are all the different params that we handle as binary Buffers,
    // but are passed into the API as hex strings.
    'authKey',
    'authSalt',
    'data',
    'deviceId',
    'emailCode',
    'flowId',
    'id',
    'kA',
    'keyBundle',
    'passCode',
    'sessionTokenId',
    'tokenId',
    'tokenVerificationId',
    'uid',
    'verifyHash',
    'wrapWrapKb'
  ])))

  api.get('/account/:id', withIdAndBody(db.account))
  api.del('/account/:id', withIdAndBody(db.deleteAccount))
  api.put('/account/:id', withIdAndBody(db.createAccount))
  api.get('/account/:id/devices', withIdAndBody(db.accountDevices))
  api.post('/account/:id/checkPassword', withIdAndBody(db.checkPassword))
  api.post('/account/:id/reset', withIdAndBody(db.resetAccount))
  api.post('/account/:id/resetTokens', withIdAndBody(db.resetAccountTokens))
  api.post('/account/:id/verifyEmail/:emailCode',
    op(function (req) {
      return db.verifyEmail(req.params.id, req.params.emailCode)
    })
  )
  api.post('/account/:id/locale', withIdAndBody(db.updateLocale))
  api.get('/account/:id/sessions', withIdAndBody(db.sessions))

  api.get('/account/:id/emails', withIdAndBody(db.accountEmails))
  api.post('/account/:id/emails', withIdAndBody(db.createEmail))
  api.del('/account/:id/emails/:email',
    op(function (req) {
      return db.deleteEmail(req.params.id, bufferize.hexToUtf8(req.params.email))
    })
  )

  api.get('/email/:email',
    op(function (req) {
      return db.getSecondaryEmail(bufferize.hexToUtf8(req.params.email))
    })
  )
  api.get('/email/:email/account',
    op(function (req) {
      return db.accountRecord(bufferize.hexToUtf8(req.params.email))
    })
  )
  api.post('/email/:email/account/:id',
    op(function (req) {
      return db.setPrimaryEmail(req.params.id, bufferize.hexToUtf8(req.params.email))
    })
  )

  api.get('/sessionToken/:id', withIdAndBody(db.sessionToken))
  api.del('/sessionToken/:id', withIdAndBody(db.deleteSessionToken))
  api.put('/sessionToken/:id', withIdAndBody(db.createSessionToken))
  api.post('/sessionToken/:id/update', withIdAndBody(db.updateSessionToken))
  api.get('/sessionToken/:id/device', withIdAndBody(db.sessionToken))

  api.get('/keyFetchToken/:id', withIdAndBody(db.keyFetchToken))
  api.del('/keyFetchToken/:id', withIdAndBody(db.deleteKeyFetchToken))
  api.put('/keyFetchToken/:id', withIdAndBody(db.createKeyFetchToken))

  api.get('/keyFetchToken/:id/verified', withIdAndBody(db.keyFetchTokenWithVerificationStatus))
  api.post('/tokens/:id/verify', withIdAndBody(db.verifyTokens))
  api.post('/tokens/:id/verifyWithMethod', withIdAndBody(db.verifyTokensWithMethod))
  api.post('/tokens/:code/verifyCode', withParamsAndBody(db.verifyTokenCode))

  api.get('/accountResetToken/:id', withIdAndBody(db.accountResetToken))
  api.del('/accountResetToken/:id', withIdAndBody(db.deleteAccountResetToken))

  api.get('/passwordChangeToken/:id', withIdAndBody(db.passwordChangeToken))
  api.del('/passwordChangeToken/:id', withIdAndBody(db.deletePasswordChangeToken))
  api.put('/passwordChangeToken/:id', withIdAndBody(db.createPasswordChangeToken))

  api.get('/passwordForgotToken/:id', withIdAndBody(db.passwordForgotToken))
  api.del('/passwordForgotToken/:id', withIdAndBody(db.deletePasswordForgotToken))
  api.put('/passwordForgotToken/:id', withIdAndBody(db.createPasswordForgotToken))
  api.post('/passwordForgotToken/:id/update', withIdAndBody(db.updatePasswordForgotToken))
  api.post('/passwordForgotToken/:id/verified', withIdAndBody(db.forgotPasswordVerified))

  api.get('/verificationReminders', withBodyAndQuery(db.fetchReminders))
  api.post('/verificationReminders', withBodyAndQuery(db.createVerificationReminder))
  api.del('/verificationReminders', withBodyAndQuery(db.deleteReminder))

  api.get('/securityEvents/:id/ip/:ipAddr', withParams(db.securityEvents))
  api.post('/securityEvents', withBodyAndQuery(db.createSecurityEvent))

  api.get('/emailBounces/:id', withIdAndBody(db.fetchEmailBounces))
  api.post('/emailBounces', withBodyAndQuery(db.createEmailBounce))

  api.get('/emailRecord/:id', withIdAndBody(db.emailRecord))
  api.head('/emailRecord/:id', withIdAndBody(db.accountExists))

  api.get('/totp/:id', withIdAndBody(db.totpToken))
  api.del('/totp/:id', withIdAndBody(db.deleteTotpToken))
  api.put('/totp/:id', withIdAndBody(db.createTotpToken))
  api.post('/totp/:id/update', withIdAndBody(db.updateTotpToken))

  api.get('/__heartbeat__', withIdAndBody(db.ping))

  function op(fn) {
    return function (req, res, next) {
      fn.call(null, req)
        .then(
          handleSuccess.bind(null, req, res),
          handleError.bind(null, req, res)
        )
        .then(next, next)
    }
  }

  api.put(
    '/account/:uid/device/:deviceId',
    op(function (req) {
      return db.createDevice(req.params.uid, req.params.deviceId, req.body)
    })
  )
  api.post(
    '/account/:uid/device/:deviceId/update',
    op(function (req) {
      return db.updateDevice(req.params.uid, req.params.deviceId, req.body)
    })
  )
  api.del(
    '/account/:uid/device/:deviceId',
    op(function (req) {
      return db.deleteDevice(req.params.uid, req.params.deviceId)
    })
  )

  api.get(
    '/account/:uid/tokens/:tokenVerificationId/device',
    op(function (req) {
      return db.deviceFromTokenVerificationId(req.params.uid, req.params.tokenVerificationId)
    })
  )

  api.put(
    '/account/:uid/unblock/:code',
    op(function (req) {
      return db.createUnblockCode(req.params.uid, req.params.code)
    })
  )

  api.del(
    '/account/:uid/unblock/:code',
    op(function (req) {
      return db.consumeUnblockCode(req.params.uid, req.params.code)
    })
  )

  api.put(
    '/signinCodes/:code',
    op(req => db.createSigninCode(req.params.code, req.body.uid, req.body.createdAt, req.body.flowId))
  )

  api.post(
    '/signinCodes/:code/consume',
    op(req => db.consumeSigninCode(req.params.code))
  )

  api.post('/account/:id/recoveryCodes',
    op((req) => {
      return db.replaceRecoveryCodes(req.params.id, req.body.count)
    })
  )

  api.post('/account/:id/recoveryCodes/:code',
    op((req) => db.consumeRecoveryCode(req.params.id, req.params.code))
  )

  api.get(
    '/',
    function (req, res, next) {
      res.send({ version: version, implementation: implementation })
      next()
    }
  )

  api.get(
    '/__version__',
    function (req, res, next) {
      res.send({ version: version, implementation: implementation })
      next()
    }
  )

  function handleSuccess(req, res, result) {
    api.emit(
      'success',
      {
        code: 200,
        route: req.route.name,
        method: req.method,
        path: req.url,
        t: Date.now() - req.time()
      }
    )
    if (Array.isArray(result)) {
      res.send(result.map(bufferize.unbuffer))
    }
    else {

      // When performing a `HEAD` request, the content type is not
      // set, manually set to application/json
      if (req.method === 'HEAD') {
        res.setHeader('Content-Type', 'application/json')
      }

      res.send(bufferize.unbuffer(result || {}))
    }
  }

  function handleError (req, res, err) {
    if (typeof err !== 'object') {
      err = { message: err || 'none' }
    }

    var statusCode = err.code || 500

    api.emit(
      'failure',
      {
        code: statusCode,
        route: req.route ? req.route.name : 'unknown',
        method: req.method,
        path: req.url,
        err: err,
        t: Date.now() - req.time(),
      }
    )

    res.send(statusCode, {
      message: err.message,
      errno: err.errno,
      error: err.error,
      code: err.code
    })
  }

  var memInterval = setInterval(function() {
    api.emit('mem', process.memoryUsage())
  }, 15000)
  memInterval.unref()

  api.on('NotFound', function (req, res) {
    handleError(req, res, errors.notFound())
  })

  return api
}

module.exports = {
  createServer: createServer,
  errors: errors
}
<|endoftext|>


<commit_before>'use strict'

const {STRING} = require('sequelize')

module.exports = db => db.define('things', {
  name: STRING,
})

module.exports.associations = (Thing, {User, Favorite}) => {
  Thing.belongsToMany(User, {as: 'lovers', through: Favorite})
}
<commit_msg>Removed thing model (#17)<commit_after><|endoftext|>


<commit_before>'use strict'

const Sequelize = require('sequelize');
const db = require('APP/db');
const Product = require('./product');

const Category = db.define('categories', {
    category_name: {
        type: Sequelize.STRING,
        allowNull: false,
        notEmpty: true,
    }
}, {})<commit_msg>one redundant line removed<commit_after>'use strict'

const Sequelize = require('sequelize');
const db = require('APP/db');

const Category = db.define('categories', {
    category_name: {
        type: Sequelize.STRING,
        allowNull: false,
        notEmpty: true,
    }
}, {})<|endoftext|>