<commit_before>/* global describe, it, xit */
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai'),
  assert = chai.assert,
  expect = chai.expect,
  should = chai.should();

const flow = require('kronos-flow'),
  kronos = require('../lib/manager.js'),
  someStepFactory = require('./fixtures/steps1/someStep');

const flowDecl = {
  "name": "flow1",
  "type": "kronos-flow",
  "steps": {
    "s1": {
      "type": "some-step"
    }
  }
};

describe('service manager', () => {
  describe('std attributes', () => {
    it('should have a name', done => {
      kronos.manager({
        name: 'myName',
        logLevel: 'trace'
      }).then(manager => {
        try {
          assert.equal(manager.name, 'myName');
          assert.equal(manager.toString(), 'myName');

          // test if there is a log level entry point
          manager.info(level => 'level ');
          assert.equal(manager.logLevel, 'trace');
          done();
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });
  });

  describe('stop', () => {
    it('empty', done => {
      kronos.manager().then(manager => {
        try {
          manager.stop().then(
            () => done(), done
          );
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });

    it('with flows', done => {
      kronos.manager().then(manager => {
        try {
          Promise.all([
            manager.registerStep(someStepFactory),
            flow.registerWithManager(manager)
          ]).then(() => {
            const aFlow = manager.createStepInstanceFromConfig(flowDecl);
            manager.registerFlow(aFlow);
            aFlow.start().then(() => manager.stop().then(r => done(), done));
          });
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });
  });

  describe('step registration', () => {
    it('registers steps present', done => {
      kronos.manager().then(manager => {
        try {
          let stepFromEvent;
          manager.addListener('stepRegistered', step => stepFromEvent = step);

          manager.registerStep(someStepFactory).then(() => {
            const myStep = manager.steps['some-step'];
            assert.equal(myStep.name, 'some-step');
            assert.equal(stepFromEvent, myStep);

            // do not fire a 2nd. time stepRegistered
            stepFromEvent = undefined;
            manager.registerStep(someStepFactory);
            assert.equal(stepFromEvent, undefined);

            done();
          });
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });

    describe('getStepInstance', () => {
      it('not registerd should throw', done => {
        kronos.manager().then(manager => {
          try {
            assert.throws(function () {
              manager.getStepInstance({
                type: "not-already-registered"
              });
            });
            done();
          } catch (e) {
            done(e);
          }
        }, () => done("Manager not created"));
      });
    });
  });

  describe('interceptors', () => {
    it('has interceptors', done => {
      kronos.manager().then(myManager => {
        assert.isDefined(myManager.interceptors);
        done();
      });
    });
  });

  describe('flows', () => {
    const flowName = 'flow1';

    it('registered should be present', done => {
      kronos.manager().then(myManager => {
        try {
          let flowFromEvent;
          myManager.addListener('flowRegistered', flow => flowFromEvent = flow);

          Promise.all([
            flow.registerWithManager(myManager),
            myManager.registerStep(someStepFactory),
            myManager.registerFlow(myManager.createStepInstanceFromConfig(flowDecl))
          ]).then(() => {
            const aFlow = myManager.flows[flowName];
            should.exist(aFlow);
            expect(aFlow.name).to.equal(flowName);
            expect(aFlow.state).to.equal("stopped");

            assert.equal(flowFromEvent, aFlow);
            done();
          });
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });

    it('can be removed again', done => {
      kronos.manager().then(myManager => {
        try {
          let removedStepFromEventDone = false;

          myManager.addListener('stepStateChanged', (step, oldState, newState) => {
            if (newState === 'removed' && step.name === 'flow1') {
              removedStepFromEventDone = true;
            }
          });

          Promise.all([
            flow.registerWithManager(myManager),
            myManager.registerStep(someStepFactory),
            myManager.registerFlow(myManager.createStepInstanceFromConfig(flowDecl))
          ]).then(() => {
            myManager.unregisterFlow(flowName).then(() => {
              try {
                assert.equal(myManager.flows.flow1, undefined);

                // stepStateChanged may get fired late ??
                setTimeout(() => {
                  assert.isTrue(removedStepFromEventDone);
                  done();
                }, 10);
              } catch (e) {
                done(e);
              }
            }, done);
          });
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });

    it('deleting unknown flow rejects', done => {
      kronos.manager().then(myManager => {
        try {
          myManager.unregisterFlow("unknownFlow").then(() =>
            done(new Error("should not fullfill: deletion of an unknown flow")), reject => done());
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });
  });
});
<commit_msg>test: wip<commit_after>/* global describe, it, xit */
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai'),
  assert = chai.assert,
  expect = chai.expect,
  should = chai.should();

const flow = require('kronos-flow'),
  kronos = require('../lib/manager.js'),
  someStepFactory = require('./fixtures/steps1/someStep');

const flowDecl = {
  "name": "flow1",
  "type": "kronos-flow",
  "steps": {
    "s1": {
      "type": "some-step"
    }
  }
};

describe('service manager', () => {
  describe('std attributes', () => {
    it('should have a name', done => {
      kronos.manager({
        name: 'myName',
        logLevel: 'trace'
      }).then(manager => {
        try {
          assert.equal(manager.name, 'myName');
          assert.equal(manager.toString(), 'myName');

          // test if there is a log level entry point
          manager.info(level => 'level ');
          assert.equal(manager.logLevel, 'trace');
          done();
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });
  });

  describe('stop', () => {
    it('empty', done => {
      kronos.manager().then(manager => {
        try {
          manager.stop().then(
            () => done(), done
          );
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });

    it('with flows', done => {
      kronos.manager({
        logLevel: 'info'
      }).then(manager => {
        try {
          Promise.all([
            manager.registerStep(someStepFactory),
            flow.registerWithManager(manager)
          ]).then(() => {
            const aFlow = manager.createStepInstanceFromConfig(flowDecl);
            manager.registerFlow(aFlow);
            aFlow.start().then(() => manager.stop().then(r => done(), done));
          }).catch(done);
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });
  });

  describe('step registration', () => {
    it('registers steps present', done => {
      kronos.manager().then(manager => {
        try {
          let stepFromEvent;
          manager.addListener('stepRegistered', step => stepFromEvent = step);

          manager.registerStep(someStepFactory).then(() => {
            const myStep = manager.steps['some-step'];
            assert.equal(myStep.name, 'some-step');
            assert.equal(stepFromEvent, myStep);

            // do not fire a 2nd. time stepRegistered
            stepFromEvent = undefined;
            manager.registerStep(someStepFactory).then(() => {
              assert.equal(stepFromEvent, undefined);
              done();
            });
          }).catch(done);
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });

    describe('createStepInstanceFromConfig', () => {
      it('not registerd should throw', done => {
        kronos.manager().then(manager => {
          try {
            assert.throws(function () {
              manager.createStepInstanceFromConfig({
                type: "not-already-registered"
              });
            });
            done();
          } catch (e) {
            done(e);
          }
        }, () => done("Manager not created"));
      });
    });
  });

  describe('interceptors', () => {
    it('has interceptors', done => {
      kronos.manager().then(myManager => {
        assert.isDefined(myManager.interceptors);
        done();
      });
    });
  });

  describe('flows', () => {
    const flowName = 'flow1';

    it('registered should be present', done => {
      kronos.manager().then(myManager => {
        try {
          let flowFromEvent;
          myManager.addListener('flowRegistered', flow => flowFromEvent = flow);

          Promise.all([
            flow.registerWithManager(myManager),
            myManager.registerStep(someStepFactory)
          ]).then(() => myManager.registerFlow(myManager.createStepInstanceFromConfig(flowDecl))).then(
            () => {
              const aFlow = myManager.flows[flowName];
              should.exist(aFlow);
              expect(aFlow.name).to.equal(flowName);
              expect(aFlow.state).to.equal("stopped");

              assert.equal(flowFromEvent, aFlow);
              done();
            }).catch(done);
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });

    it('can be removed again', done => {
      kronos.manager().then(myManager => {
        try {
          let removedStepFromEventDone = false;

          myManager.addListener('stepStateChanged', (step, oldState, newState) => {
            if (newState === 'removed' && step.name === 'flow1') {
              removedStepFromEventDone = true;
            }
          });

          Promise.all([
            flow.registerWithManager(myManager),
            myManager.registerStep(someStepFactory),
            myManager.registerFlow(myManager.createStepInstanceFromConfig(flowDecl))
          ]).then(() => {
            myManager.unregisterFlow(flowName).then(() => {
              try {
                assert.equal(myManager.flows.flow1, undefined);

                // stepStateChanged may get fired late ??
                setTimeout(() => {
                  assert.isTrue(removedStepFromEventDone);
                  done();
                }, 10);
              } catch (e) {
                done(e);
              }
            }, done);
          });
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });

    it('deleting unknown flow rejects', done => {
      kronos.manager().then(myManager => {
        try {
          myManager.unregisterFlow("unknownFlow").then(() =>
            done(new Error("should not fullfill: deletion of an unknown flow")), reject => done());
        } catch (e) {
          done(e);
        }
      }, () => done("Manager not created"));
    });
  });
});
<|endoftext|>


<commit_before>/*!
 * jQuery Confirm Action
 * https://github.com/sdelements/jquery-confirm-action
 *
 * Copyright 2015, Houssam Haidar
 * Released under the MIT license
 */

'use strict';

(function($) {

    //
    // Helpers
    //

    var each = function(iterable, callback, context) {
        $.each(iterable, context ? $.proxy(callback, context) : callback);
    };

    var map = function(iterable, callback, context) {
        return $.map(iterable, context ? $.proxy(callback, context) : callback);
    };

    //
    // Modal
    //

    var ConfirmActionModal = function(options) {

        this.options = options;

        this.init();

    };

    ConfirmActionModal.prototype = {

        constructor: ConfirmActionModal,

        styles: {
            overlay: {
                position: 'fixed',
                top: 0,
                right: 0,
                bottom: 0,
                left: 0,
                zIndex: 1000,
                backgroundColor: '#000000'
            },
            base: {
                width: '100%',
                height: '100%',
                position: 'fixed',
                top: 0,
                left: 0,
                bottom: 0,
                right: 0,
                zIndex: 1001,
                overflow: 'auto'
            },
            dialog: {
                backgroundColor: '#ffffff',
                width: '100%',
                maxWidth: '600px',
                margin: '40px auto',
                textAlign: 'center',
                fontSize: '14px',
                borderRadius: '3px',
                position: 'relative',
                zIndex: 1001
            },
            header: {
                padding: '30px'
            },
            title: {
                fontWeight: '300',
                fontSize: '20px',
                color: '#555555',
                lineHeight: '40px',
                marginBottom: '0'
            },
            close: {
                position: 'absolute',
                top: '-25px',
                right: '-25px',
                fontSize: '30px',
                color: '#f2f2f2',
                cursor: 'pointer'
            },
            content: {
                padding: '10px 40px 60px 40px',
                color: '#888888',
                fontSize: '16px',
                fontWeight: '300',
                lineHeight: '20px'
            },
            actions: {
                backgroundColor: '#f5f5f5',
                padding: '30px',
                borderRadius: '0 0 3px 3px'
            },
            button: {
                background: 'none',
                fontSize: '14px',
                color: '#aaaaaa',
                padding: '10px 40px',
                margin: '3px 6px',
                border: '1px #cccccc solid',
                borderRadius: '4px'
            },
            titles: {
                danger: {
                    color: '#e56657'
                },
                warning: {
                    color: '#ffb347'
                },
                success: {
                    color: '#77dd77'
                }
            },
            buttons: {
                danger: {
                    backgroundColor: '#e56657',
                    borderColor: '#e56657',
                    color: '#ffffff'
                },
                warning: {
                    backgroundColor: '#ffb347',
                    borderColor: '#ffb347',
                    color: '#ffffff'
                },
                success: {
                    backgroundColor: '#77dd77',
                    borderColor: '#77dd77',
                    color: '#ffffff'
                }
            },
            conditions: {
                width: '60%',
                textAlign: 'left',
                margin: '0 auto',
                marginTop: '20px'
            },
            label: {
                fontSize: '14px',
                color: '#aaaaaa',
                marginTop: '10px',
                display: 'block'
            },
            checkbox: {
                margin: '0 5px 0 0',
                verticalAlign: 'baseline'
            }
        },

        html: {
            overlay: '
',
            base: '
',
            dialog: '
',
            header: '
',
            title: '
Confirm
',
            close: '×',
            content: '
',
            message: '
',
            conditions: '
',
            actions: '
',
            button: '<button class="confirm-action-modal-button">Confirm</button>',
            label: '',
            checkbox: '<input type="checkbox" />',
            conditionText: ''
        },

        init: function() {

            this.components = {};

            each(this.html, function(key, html) {

                this.components['$' + key] = $(html).css(this.styles[key] || {});

            }, this);

            this.$overlay = this.components.$overlay.fadeTo(0, 0.5);

            this.components.$title
                .css(this.styles.titles[this.options.title.style || 'danger']);

            var $conditions = map(this.options.conditions, function(condition, key) {

                if (condition.type === 'checkbox') {
                    return this.components.$label.clone()
                        .append([
                            this.components.$checkbox.clone().attr('data-confirm-condition-id', key),
                            this.components.$conditionText.clone().text(condition.text || 'Are you sure?')
                        ]);
                }

            }, this);

            var $buttons = [
                this.components.$button.clone()
                    .text('Cancel')
                    .attr('data-confirm-action-close', true)
            ];

            each(this.options.actions, function(key, action) {

                $buttons.push(
                    this.components.$button.clone()
                        .attr('data-confirm-action-id', key)
                        .text(action.text)
                        .css(this.styles.buttons[action.style || 'danger'])
                );

            }, this);

            this.$element = this.components.$base.append([
                this.$overlay,
                this.components.$dialog.append([
                    this.components.$header.append([
                        this.components.$title,
                        this.components.$close
                    ]),
                    this.components.$content.append([
                        this.components.$message,
                        this.components.$conditions.append($conditions)
                    ]),
                    this.components.$actions.append($buttons)
                ])
            ]);

            this.update();

        },

        setTitleAndMessage: function() {
            this.setContent(this.options.title, this.components.$title);
            this.setContent(this.options.message, this.components.$message);
        },

        setContent: function(options, container) {
            if (options.html) {
                var html = typeof options.html === 'function' ? options.html() : options.html;
                if ($.isArray(html)) {
                    html = html.join('\n');
                }
                container.html(html);
            }

            if (options.text) {
                var text = typeof options.text === 'function' ? options.text() : options.text;
                container.text(text);
            }
        },

        listen: function(sourceEvent) {

            var that = this;

            this.$element.delegate('[data-confirm-action-close]', 'click', $.proxy(this.close, this));

            this.$overlay.on('click', $.proxy(this.close, this));

            var confirm = function() {

                $(sourceEvent.target).trigger('click', true);

                that.close();

            };

            this.$element.find('[data-confirm-condition-id]').each(function() {

                $(this).on('change.confirm.condition', function() {

                    that.update();

                });

            });

            this.$element.find('[data-confirm-action-id]').each(function() {

                $(this).on('click.confirm.action', function(e) {

                    e.preventDefault();

                    var callback = that.options.actions[$(this).data('confirm-action-id')].callback;

                    if (typeof callback !== 'function') {

                        callback = $.fn.confirmAction.defaults.actions.confirm.callback;

                    }

                    callback(confirm, $.proxy(that.close, that));

                });

            });

        },

        update: function() {

            var that = this;

            each(this.options.actions, function(actionKey, action) {

                var disabled = false;

                each(action.conditions || [], function(key, condition) {

                    if (disabled) {

                        return;

                    }

                    if (!that.options.conditions[condition]) {

                        disabled = true;
                    }

                    if (that.options.conditions[condition].type === 'checkbox') {

                        if (!that.$element.find('[data-confirm-condition-id=' + condition + ']').is(':checked')) {

                            disabled = true;

                        }

                    }

                });

                that.$element.find('[data-confirm-action-id=' + actionKey + ']')
                    .prop('disabled', disabled)
                    .css('cursor', disabled ? 'not-allowed' : 'pointer')
                    .fadeTo(50, disabled ? .5 : 1);

            });

        },

        show: function(sourceEvent) {

            this.setTitleAndMessage();

            this.$element.appendTo('body');

            this.listen(sourceEvent || $.Event('click'));

        },

        close: function() {

            this.resetConditions();
            this.update();
            this.$element.remove();

        },

        resetConditions: function() {
            this.components.$conditions.find('input[type=checkbox]').prop('checked', false);
        }

    };

    //
    // Core
    //

    var ConfirmAction = function(element, options) {

        this.init(element, options);

    };

    ConfirmAction.prototype = {

        constructor: ConfirmAction,

        init: function(element, options) {

            this.options = options;

            this.$element = $(element);

            this.$element.on('click.confirm', $.proxy(this.intercept, this));

            this.modal = new ConfirmActionModal(this.options);

        },

        intercept: function(e, confirmed) {

            var that = this;

            var execute = function(run) {

                if (!run) {
                    return;
                }

                that.modal.show(e);

                if (confirmed !== true) {

                    e.preventDefault();
                    e.stopImmediatePropagation();

                }

            };

            if (typeof this.options.conditional === 'function') {

                this.options.conditional(execute);

                return;

            }

            execute(true);

        }

    };

    //
    // jQuery Plugin
    //

    $.fn.confirmAction = function(options) {

        return this.each(function() {
            var title;
            var message;

            if (typeof options.title === 'string' || typeof options.message === 'function') {
                title = options.title;
                delete options.title;
            }

            if (typeof options === 'string') {
                message = options;
            }

            if (typeof options.message === 'string' || typeof options.message === 'function') {
                message = options.message;
                delete options.message;
            }

            options = $.extend({}, $.fn.confirmAction.defaults, typeof options === 'object' && options);

            if (title) {
                options.title.text = message;
            }

            if (message) {
                options.message.text = message;
            }

            new ConfirmAction(this, options);
        });

    };

    $.fn.confirmAction.defaults = {
        title: {
            text: 'Warning',
            style: 'danger'
        },
        message: {
            text: 'Are you sure?'
        },
        actions: {
            confirm: {
                text: 'Confirm',
                style: 'danger',
                callback: function(confirm) {
                    confirm();
                }
            }
        },
        conditions: {}
    };

})(jQuery);
<commit_msg>Add cypress support to action buttons<commit_after>/*!
 * jQuery Confirm Action
 * https://github.com/sdelements/jquery-confirm-action
 *
 * Copyright 2015, Houssam Haidar
 * Released under the MIT license
 */

'use strict';

(function($) {

    //
    // Helpers
    //

    var each = function(iterable, callback, context) {
        $.each(iterable, context ? $.proxy(callback, context) : callback);
    };

    var map = function(iterable, callback, context) {
        return $.map(iterable, context ? $.proxy(callback, context) : callback);
    };

    //
    // Modal
    //

    var ConfirmActionModal = function(options) {

        this.options = options;

        this.init();

    };

    ConfirmActionModal.prototype = {

        constructor: ConfirmActionModal,

        styles: {
            overlay: {
                position: 'fixed',
                top: 0,
                right: 0,
                bottom: 0,
                left: 0,
                zIndex: 1000,
                backgroundColor: '#000000'
            },
            base: {
                width: '100%',
                height: '100%',
                position: 'fixed',
                top: 0,
                left: 0,
                bottom: 0,
                right: 0,
                zIndex: 1001,
                overflow: 'auto'
            },
            dialog: {
                backgroundColor: '#ffffff',
                width: '100%',
                maxWidth: '600px',
                margin: '40px auto',
                textAlign: 'center',
                fontSize: '14px',
                borderRadius: '3px',
                position: 'relative',
                zIndex: 1001
            },
            header: {
                padding: '30px'
            },
            title: {
                fontWeight: '300',
                fontSize: '20px',
                color: '#555555',
                lineHeight: '40px',
                marginBottom: '0'
            },
            close: {
                position: 'absolute',
                top: '-25px',
                right: '-25px',
                fontSize: '30px',
                color: '#f2f2f2',
                cursor: 'pointer'
            },
            content: {
                padding: '10px 40px 60px 40px',
                color: '#888888',
                fontSize: '16px',
                fontWeight: '300',
                lineHeight: '20px'
            },
            actions: {
                backgroundColor: '#f5f5f5',
                padding: '30px',
                borderRadius: '0 0 3px 3px'
            },
            button: {
                background: 'none',
                fontSize: '14px',
                color: '#aaaaaa',
                padding: '10px 40px',
                margin: '3px 6px',
                border: '1px #cccccc solid',
                borderRadius: '4px'
            },
            titles: {
                danger: {
                    color: '#e56657'
                },
                warning: {
                    color: '#ffb347'
                },
                success: {
                    color: '#77dd77'
                }
            },
            buttons: {
                danger: {
                    backgroundColor: '#e56657',
                    borderColor: '#e56657',
                    color: '#ffffff'
                },
                warning: {
                    backgroundColor: '#ffb347',
                    borderColor: '#ffb347',
                    color: '#ffffff'
                },
                success: {
                    backgroundColor: '#77dd77',
                    borderColor: '#77dd77',
                    color: '#ffffff'
                }
            },
            conditions: {
                width: '60%',
                textAlign: 'left',
                margin: '0 auto',
                marginTop: '20px'
            },
            label: {
                fontSize: '14px',
                color: '#aaaaaa',
                marginTop: '10px',
                display: 'block'
            },
            checkbox: {
                margin: '0 5px 0 0',
                verticalAlign: 'baseline'
            }
        },

        html: {
            overlay: '
',
            base: '
',
            dialog: '
',
            header: '
',
            title: '
Confirm
',
            close: '×',
            content: '
',
            message: '
',
            conditions: '
',
            actions: '
',
            button: '<button class="confirm-action-modal-button">Confirm</button>',
            label: '',
            checkbox: '<input type="checkbox" />',
            conditionText: ''
        },

        init: function() {

            this.components = {};

            each(this.html, function(key, html) {

                this.components['$' + key] = $(html).css(this.styles[key] || {});

            }, this);

            this.$overlay = this.components.$overlay.fadeTo(0, 0.5);

            this.components.$title
                .css(this.styles.titles[this.options.title.style || 'danger']);

            var $conditions = map(this.options.conditions, function(condition, key) {

                if (condition.type === 'checkbox') {
                    return this.components.$label.clone()
                        .append([
                            this.components.$checkbox.clone().attr('data-confirm-condition-id', key),
                            this.components.$conditionText.clone().text(condition.text || 'Are you sure?')
                        ]);
                }

            }, this);

            var $buttons = [
                this.components.$button.clone()
                    .text('Cancel')
                    .attr('data-confirm-action-close', true)
            ];

            each(this.options.actions, function(key, action) {

                $buttons.push(
                    this.components.$button.clone()
                        .attr('data-confirm-action-id', key)
                        .attr('data-cy', action['data-cy'])
                        .text(action.text)
                        .css(this.styles.buttons[action.style || 'danger'])
                );

            }, this);

            this.$element = this.components.$base.append([
                this.$overlay,
                this.components.$dialog.append([
                    this.components.$header.append([
                        this.components.$title,
                        this.components.$close
                    ]),
                    this.components.$content.append([
                        this.components.$message,
                        this.components.$conditions.append($conditions)
                    ]),
                    this.components.$actions.append($buttons)
                ])
            ]);

            this.update();

        },

        setTitleAndMessage: function() {
            this.setContent(this.options.title, this.components.$title);
            this.setContent(this.options.message, this.components.$message);
        },

        setContent: function(options, container) {
            if (options.html) {
                var html = typeof options.html === 'function' ? options.html() : options.html;
                if ($.isArray(html)) {
                    html = html.join('\n');
                }
                container.html(html);
            }

            if (options.text) {
                var text = typeof options.text === 'function' ? options.text() : options.text;
                container.text(text);
            }
        },

        listen: function(sourceEvent) {

            var that = this;

            this.$element.delegate('[data-confirm-action-close]', 'click', $.proxy(this.close, this));

            this.$overlay.on('click', $.proxy(this.close, this));

            var confirm = function() {

                $(sourceEvent.target).trigger('click', true);

                that.close();

            };

            this.$element.find('[data-confirm-condition-id]').each(function() {

                $(this).on('change.confirm.condition', function() {

                    that.update();

                });

            });

            this.$element.find('[data-confirm-action-id]').each(function() {

                $(this).on('click.confirm.action', function(e) {

                    e.preventDefault();

                    var callback = that.options.actions[$(this).data('confirm-action-id')].callback;

                    if (typeof callback !== 'function') {

                        callback = $.fn.confirmAction.defaults.actions.confirm.callback;

                    }

                    callback(confirm, $.proxy(that.close, that));

                });

            });

        },

        update: function() {

            var that = this;

            each(this.options.actions, function(actionKey, action) {

                var disabled = false;

                each(action.conditions || [], function(key, condition) {

                    if (disabled) {

                        return;

                    }

                    if (!that.options.conditions[condition]) {

                        disabled = true;
                    }

                    if (that.options.conditions[condition].type === 'checkbox') {

                        if (!that.$element.find('[data-confirm-condition-id=' + condition + ']').is(':checked')) {

                            disabled = true;

                        }

                    }

                });

                that.$element.find('[data-confirm-action-id=' + actionKey + ']')
                    .prop('disabled', disabled)
                    .css('cursor', disabled ? 'not-allowed' : 'pointer')
                    .fadeTo(50, disabled ? .5 : 1);

            });

        },

        show: function(sourceEvent) {

            this.setTitleAndMessage();

            this.$element.appendTo('body');

            this.listen(sourceEvent || $.Event('click'));

        },

        close: function() {

            this.resetConditions();
            this.update();
            this.$element.remove();

        },

        resetConditions: function() {
            this.components.$conditions.find('input[type=checkbox]').prop('checked', false);
        }

    };

    //
    // Core
    //

    var ConfirmAction = function(element, options) {

        this.init(element, options);

    };

    ConfirmAction.prototype = {

        constructor: ConfirmAction,

        init: function(element, options) {

            this.options = options;

            this.$element = $(element);

            this.$element.on('click.confirm', $.proxy(this.intercept, this));

            this.modal = new ConfirmActionModal(this.options);

        },

        intercept: function(e, confirmed) {

            var that = this;

            var execute = function(run) {

                if (!run) {
                    return;
                }

                that.modal.show(e);

                if (confirmed !== true) {

                    e.preventDefault();
                    e.stopImmediatePropagation();

                }

            };

            if (typeof this.options.conditional === 'function') {

                this.options.conditional(execute);

                return;

            }

            execute(true);

        }

    };

    //
    // jQuery Plugin
    //

    $.fn.confirmAction = function(options) {

        return this.each(function() {
            var title;
            var message;

            if (typeof options.title === 'string' || typeof options.message === 'function') {
                title = options.title;
                delete options.title;
            }

            if (typeof options === 'string') {
                message = options;
            }

            if (typeof options.message === 'string' || typeof options.message === 'function') {
                message = options.message;
                delete options.message;
            }

            options = $.extend({}, $.fn.confirmAction.defaults, typeof options === 'object' && options);

            if (title) {
                options.title.text = message;
            }

            if (message) {
                options.message.text = message;
            }

            new ConfirmAction(this, options);
        });

    };

    $.fn.confirmAction.defaults = {
        title: {
            text: 'Warning',
            style: 'danger'
        },
        message: {
            text: 'Are you sure?'
        },
        actions: {
            confirm: {
                text: 'Confirm',
                style: 'danger',
                callback: function(confirm) {
                    confirm();
                }
            }
        },
        conditions: {}
    };

})(jQuery);
<|endoftext|>


<commit_before>var debug = require('debug')('rms:eventstore'),
	_ = require('lodash');

var AggRoot = function(when) {
	var eventhandlers = when;

	this.handle = function(events) {
		debug('', 'Handling Events: ' + JSON.stringify(events));
		var self = this;
		if (events.length > 0) {
			_.each(events, function(ev) {
				if (eventhandlers[ev.eventType] !== undefined) {
					eventhandlers[ev.eventType].call(self, ev);
					if (ev.eventNumber) {
						self._version = ev.eventNumber;
					}
				}
			});
		}
	};
};

module.exports = AggRoot;<commit_msg>[Fix] version of aggregrate not setting on event 0<commit_after>var debug = require('debug')('geteventstore:aggRoot'),
	_ = require('lodash');

var AggRoot = function(when) {
	var eventhandlers = when;

	this.handle = function(events) {
		debug('', 'Handling Events: ' + JSON.stringify(events));
		var self = this;
		if (events.length > 0) {
			_.each(events, function(ev) {
				if (eventhandlers[ev.eventType] !== undefined) {
					eventhandlers[ev.eventType].call(self, ev);
					if (ev.eventNumber !== undefined) {
						self._version = ev.eventNumber;
					}
				}
			});
		}
	};
};

module.exports = AggRoot;<|endoftext|>


<commit_before>/**
 * fastLiveFilter jQuery plugin 1.0.2
 *
 * Copyright (c) 2011, Anthony Bush
 * License: <http://www.opensource.org/licenses/bsd-license.php>
 * Project Website: http://anthonybush.com/projects/jquery_fast_live_filter/
 **/

jQuery.fn.fastLiveFilter = function(list, options) {
	// Options: input, list, timeout, callback
	list = jQuery(list);
	var input = this;
	var timeout = options.timeout || 0;
	var callback = options.callback || function() {};

	var keyTimeout;

	// NOTE: because we cache lis & len here, users would need to re-init the plugin
	// if they modify the list in the DOM later.  This doesn't give us that much speed
	// boost, so perhaps it's not worth putting it here.
	var lis = list.children();
	var len = lis.length;
	var oldDisplay = len > 0 ? lis[0].style.display : "block";
	callback(len); // do a one-time callback on initialization to make sure everything's in sync

	input.change(function() {
		// var startTime = new Date().getTime();
		var filter = input.val().toLowerCase();
		var li;
		var numShown = 0;
		for (i = 0; i < len; i++) {
			li = lis[i];
			if ((li.textContent || li.innerText || "").toLowerCase().indexOf(filter) >= 0) {
				if (li.style.display == "none") {
					li.style.display = oldDisplay;
				}
				numShown++;
			} else {
				if (li.style.display != "none") {
					li.style.display = "none";
				}
			}
		}
		callback(numShown);
		// var endTime = new Date().getTime();
		// console.log('Search for ' + filter + ' took: ' + (endTime - startTime) + ' (' + numShown + ' results)');
		return false;
	}).keydown(function() {
		// TODO: one point of improvement could be in here: currently the change event is
		// invoked even if a change does not occur (e.g. by pressing a modifier key or
		// something)
		clearTimeout(keyTimeout);
		keyTimeout = setTimeout(function() { input.change(); }, timeout);
	});
	return this; // maintain jQuery chainability
}
<commit_msg>Fix issue #4 (options arg isn't optional)<commit_after>/**
 * fastLiveFilter jQuery plugin 1.0.2
 *
 * Copyright (c) 2011, Anthony Bush
 * License: <http://www.opensource.org/licenses/bsd-license.php>
 * Project Website: http://anthonybush.com/projects/jquery_fast_live_filter/
 **/

jQuery.fn.fastLiveFilter = function(list, options) {
	// Options: input, list, timeout, callback
	options = options || {};
	list = jQuery(list);
	var input = this;
	var timeout = options.timeout || 0;
	var callback = options.callback || function() {};

	var keyTimeout;

	// NOTE: because we cache lis & len here, users would need to re-init the plugin
	// if they modify the list in the DOM later.  This doesn't give us that much speed
	// boost, so perhaps it's not worth putting it here.
	var lis = list.children();
	var len = lis.length;
	var oldDisplay = len > 0 ? lis[0].style.display : "block";
	callback(len); // do a one-time callback on initialization to make sure everything's in sync

	input.change(function() {
		// var startTime = new Date().getTime();
		var filter = input.val().toLowerCase();
		var li;
		var numShown = 0;
		for (i = 0; i < len; i++) {
			li = lis[i];
			if ((li.textContent || li.innerText || "").toLowerCase().indexOf(filter) >= 0) {
				if (li.style.display == "none") {
					li.style.display = oldDisplay;
				}
				numShown++;
			} else {
				if (li.style.display != "none") {
					li.style.display = "none";
				}
			}
		}
		callback(numShown);
		// var endTime = new Date().getTime();
		// console.log('Search for ' + filter + ' took: ' + (endTime - startTime) + ' (' + numShown + ' results)');
		return false;
	}).keydown(function() {
		// TODO: one point of improvement could be in here: currently the change event is
		// invoked even if a change does not occur (e.g. by pressing a modifier key or
		// something)
		clearTimeout(keyTimeout);
		keyTimeout = setTimeout(function() { input.change(); }, timeout);
	});
	return this; // maintain jQuery chainability
}
<|endoftext|>


<commit_before>/*!
 * jquery.responcy. The jQuery source resizing plugin
 *
 * Copyright (c) 2014 Barış Güler
 * http://hwclass.github.io
 *
 * Licensed under MIT
 * http://www.opensource.org/licenses/mit-license.php
 *
 * http://docs.jquery.com/Plugins/Authoring
 * jQuery authoring guidelines
 *
 * Launch  : April 2014
 * Version : 1.0
 * Released: April 1st, 2014
 *
 *
 * A jQuery plugin for responsive source calls for a selected HTML element like for image or html
 */

(function ($) {
  $.fn.responcy = function (options) {
    /*config object with default source sizes*/
    var config = {
      tags: { img: 'IMG'},
      sizes: { small: 1024, medium: 1600, large: 2000 }
    }
    /*get needed data from the element with responcy attribute*/
    var responcyObj = JSON.stringify($(this).data('responcy'));
    /*initialize a responcy object to control itself*/
    responcyObj = JSON.parse(responcyObj, function (key, value) {
      var type;
      if (value && typeof value === 'object') {
        type = value.type;
        if (typeof type === 'string' && typeof window[type] === 'function') {
          return new(window[type])(value);
        }
      }
      return value;
    });
    var tagName = $(this).get(0).tagName,
    		currentSrc = new String();
    /*get all sizes*/
    if (typeof options !== 'undefined') {
      config.sizes.small = options.small;
      config.sizes.medium = options.medium;
      config.sizes.large = options.large;
    }
    /*calculate the screen resolutions*/
    if (getWindowWidth() <= config.sizes.small && getDocWidth() <= config.sizes.small) {
      currentSrc = responcyObj.small;
    } else if (getWindowWidth() > config.sizes.small && getDocWidth() > config.sizes.small && getWindowWidth() <= config.sizes.medium && getDocWidth() <= config.sizes.medium) {
      currentSrc = responcyObj.medium;
    } else if (getWindowWidth() > config.sizes.medium && getDocWidth() > config.sizes.medium && getWindowWidth() <= config.sizes.large && getDocWidth() <= config.sizes.large) {
      currentSrc = responcyObj.large;
    } else if (getWindowWidth() >= config.sizes.large && getDocWidth() >= config.sizes.large) {
      currentSrc = responcyObj.large;
    }
    /*magic is here!*/
    if (tagName === config.tags.img) {
      $(this).attr('src', currentSrc);
    } else {
      $($(this)).load(currentSrc, function (response, status, xhr) {
        if (status == "error") {
          var msg = "Responcy Error: " + xhr.status + " " + xhr.statusText;
          console.log(msg);
        }
      });
    };
    // returns height of browser viewport
    function getWindowHeight() { return $(window).height(); };
    // returns height of HTML document
    function getDocHeight() { return $(document).height(); };
    // returns width of browser viewport
    function getWindowWidth() { return $(window).width(); };
    // returns width of HTML document
    function getDocWidth() { return $(document).width(); };
  }
})(jQuery);<commit_msg>Update jquery.responcy.1.0.0.js<commit_after>/*!
 * jquery.responcy. The jQuery source resizing plugin
 *
 * Copyright (c) 2014 Barış Güler
 * http://hwclass.github.io
 *
 * Licensed under MIT
 * http://www.opensource.org/licenses/mit-license.php
 *
 * http://docs.jquery.com/Plugins/Authoring
 * jQuery authoring guidelines
 *
 * Launch  : April 2014
 * Version : 1.0
 * Released: April 1st, 2014
 *
 *
 * A jQuery plugin for responsive source calls for a selected HTML element like for image or html
 */

(function ($) {
  $.fn.responcy = function (options) {
    /*config object with default source sizes*/
    var config = {
      tags: { img: 'IMG'},
      sizes: { small: 1024, medium: 1600, large: 2000 }
    }
    /*get needed data from the element with responcy attribute*/
    var responcyObj = JSON.stringify($(this).data('responcy'));
    /*initialize a responcy object to control itself*/
    responcyObj = JSON.parse(responcyObj, function (key, value) {
      var type;
      if (value && typeof value === 'object') {
        type = value.type;
        if (typeof type === 'string' && typeof window[type] === 'function') {
          return new(window[type])(value);
        }
      }
      return value;
    });
    var tagName = $(this).get(0).tagName,
    		currentSrc = new String();
    /*get all sizes*/
    if (isUndefined(options)) {
      config.sizes.small = options.small;
      config.sizes.medium = options.medium;
      config.sizes.large = options.large;
    }
    /*calculate the screen resolutions*/
    if (getWindowWidth() <= config.sizes.small && getDocWidth() <= config.sizes.small) {
      currentSrc = responcyObj.small;
    } else if (getWindowWidth() > config.sizes.small && getDocWidth() > config.sizes.small && getWindowWidth() <= config.sizes.medium && getDocWidth() <= config.sizes.medium) {
      currentSrc = responcyObj.medium;
    } else if (getWindowWidth() > config.sizes.medium && getDocWidth() > config.sizes.medium && getWindowWidth() <= config.sizes.large && getDocWidth() <= config.sizes.large) {
      currentSrc = responcyObj.large;
    } else if (getWindowWidth() >= config.sizes.large && getDocWidth() >= config.sizes.large) {
      currentSrc = responcyObj.large;
    }
    /*magic is here!*/
    if (tagName === config.tags.img) {
      $(this).attr('src', currentSrc);
    } else {
      $($(this)).load(currentSrc, function (response, status, xhr) {
        if (status == "error") {
          var msg = "Responcy Error: " + xhr.status + " " + xhr.statusText;
          console.log(msg);
        }
      });
    };
    // returns height of browser viewport
    function getWindowHeight() { return $(window).height(); };
    // returns height of HTML document
    function getDocHeight() { return $(document).height(); };
    // returns width of browser viewport
    function getWindowWidth() { return $(window).width(); };
    // returns width of HTML document
    function getDocWidth() { return $(document).width(); };
    //checks if the arg parameter is undefined or not
    function isUndefined(arg) { return (typeof arg === 'undefined' ? true : false);  }
  }
})(jQuery);
<|endoftext|>


<commit_before>/*!
 * $.fn.scrollIntoView - similar to the default browser scrollIntoView
 * The default browser behavior always places the element at the top or bottom of its container.
 * This override is smart enough to not scroll if the element is already visible.
 *
 * Copyright 2011 Arwid Bancewicz
 * Licensed under the MIT license
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @date 9 May 2011
 * @author Arwid Bancewicz http://arwid.ca
 * @version 0.2
 */
 (function($) {
    $.fn.scrollIntoView = function(duration, easing, complete) {
        // The arguments are optional.
        // The first argment can be false for no animation or a duration.
        // The first argment could also be a map of options.
        // Refer to http://api.jquery.com/animate/.
        var opts = $.extend({},
        $.fn.scrollIntoView.defaults);

        // Get options
        if ($.type(duration) == "object") {
            $.extend(opts, duration);
        } else if ($.type(duration) == "number") {
            $.extend(opts, { duration: duration, easing: easing, complete: complete });
        } else if (duration == false) {
            opts.smooth = false;
        }

        // get enclosing offsets
        var elY = Infinity, elH = 0;
				if (this.size()==1)((elY=this.get(0).offsetTop)==null||(elH=elY+this.get(0).offsetHeight));
				else this.each(function(n){(n.offsetTop<elY?elY=n.offsetTop:n.offsetTop+n.offsetHeight>elH?elH=n.offsetTop+n.offsetHeight:null);});
        elH -= elY;

        // start from the common ancester
        var pEl = this.commonAncestor().get(0);

        // go up parents until we find one that scrolls
        while (pEl) {
            var pY = pEl.scrollTop, pH = pEl.clientHeight;

            if (
            // it wiggles?
            (pEl.scrollTop != ((pEl.scrollTop += 1) == null || pEl.scrollTop) && (pEl.scrollTop -= 1) != null) ||
            (pEl.scrollTop != ((pEl.scrollTop -= 1) == null || pEl.scrollTop) && (pEl.scrollTop += 1) != null)) {
                if (elY < pY) scrollTo(pEl, elY); // scroll up
                else if ((elY + elH) > (pY + pH)) scrollTo(pEl, elY + elH - pH); // scroll down
                return;
            }

            // try next parent
            pEl = pEl.parentNode;
        }

        function scrollTo(el, scrollTo) {
            if (opts.smooth) $(el).stop().animate({ scrollTop: scrollTo }, opts);
            else el.scrollTop = elY;
        }
        return this;
    };

    $.fn.scrollIntoView.defaults = {
        smooth: true,
        duration: null,
        easing: $.easing && $.easing.easeOutExpo ? 'easeOutExpo': null,
        // Note: easeOutExpo requires jquery.effects.core.js
        // 			 otherwise jQuery will default to use 'swing'
        complete: $.noop(),
        step: null,
        specialEasing: null
    };

    $.fn.isOutOfView = function(completely) {
        // completely? whether element is out of view completely
        var outOfView = true;
        this.each(function() {
            var pEl = this.parentNode, pY = pEl.scrollTop, pH = pEl.clientHeight, elY = this.offsetTop, elH = this.offsetHeight;
            if (completely ? (elY) > (pY + pH) : (elY + elH) > (pY + pH)) {}
            else if (completely ? (elY + elH) < pY: elY < pY) {}
            else outOfView = false;
        });
        return outOfView;
    };

    $.fn.commonAncestor = function() {
        var parents = [];
        var minlen = Infinity;

        $(this).each(function() {
            var curparents = $(this).parents();
            parents.push(curparents);
            minlen = Math.min(minlen, curparents.length);
        });

        for (var i in parents) {
            parents[i] = parents[i].slice(parents[i].length - minlen);
        }

        // Iterate until equality is found
        for (var i in parents[0]) {
            var equal = true;
            for (var j in parents) {
                if (parents[j][i] != parents[0][i]) {
                    equal = false;
                    break;
                }
            }
            if (equal) return $(parents[0][i]);
        }
        return $([]);
    }

})(jQuery);<commit_msg>fixed text indents<commit_after>/*!
 * $.fn.scrollIntoView - similar to the default browser scrollIntoView
 * The default browser behavior always places the element at the top or bottom of its container.
 * This override is smart enough to not scroll if the element is already visible.
 *
 * Copyright 2011 Arwid Bancewicz
 * Licensed under the MIT license
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @date 9 May 2011
 * @author Arwid Bancewicz http://arwid.ca
 * @version 0.2
 */
 (function($) {
    $.fn.scrollIntoView = function(duration, easing, complete) {
        // The arguments are optional.
        // The first argment can be false for no animation or a duration.
        // The first argment could also be a map of options.
        // Refer to http://api.jquery.com/animate/.
        var opts = $.extend({},
        $.fn.scrollIntoView.defaults);

        // Get options
        if ($.type(duration) == "object") {
            $.extend(opts, duration);
        } else if ($.type(duration) == "number") {
            $.extend(opts, { duration: duration, easing: easing, complete: complete });
        } else if (duration == false) {
            opts.smooth = false;
        }

        // get enclosing offsets
        var elY = Infinity, elH = 0;
        if (this.size()==1)((elY=this.get(0).offsetTop)==null||(elH=elY+this.get(0).offsetHeight));
        else this.each(function(n){(n.offsetTop<elY?elY=n.offsetTop:n.offsetTop+n.offsetHeight>elH?elH=n.offsetTop+n.offsetHeight:null);});
        elH -= elY;

        // start from the common ancester
        var pEl = this.commonAncestor().get(0);

        // go up parents until we find one that scrolls
        while (pEl) {
            var pY = pEl.scrollTop, pH = pEl.clientHeight;

            if (
            // it wiggles?
            (pEl.scrollTop != ((pEl.scrollTop += 1) == null || pEl.scrollTop) && (pEl.scrollTop -= 1) != null) ||
            (pEl.scrollTop != ((pEl.scrollTop -= 1) == null || pEl.scrollTop) && (pEl.scrollTop += 1) != null)) {
                if (elY < pY) scrollTo(pEl, elY); // scroll up
                else if ((elY + elH) > (pY + pH)) scrollTo(pEl, elY + elH - pH); // scroll down
                return;
            }

            // try next parent
            pEl = pEl.parentNode;
        }

        function scrollTo(el, scrollTo) {
            if (opts.smooth) $(el).stop().animate({ scrollTop: scrollTo }, opts);
            else el.scrollTop = elY;
        }
        return this;
    };

    $.fn.scrollIntoView.defaults = {
        smooth: true,
        duration: null,
        easing: $.easing && $.easing.easeOutExpo ? 'easeOutExpo': null,
        // Note: easeOutExpo requires jquery.effects.core.js
        //       otherwise jQuery will default to use 'swing'
        complete: $.noop(),
        step: null,
        specialEasing: null
    };

    $.fn.isOutOfView = function(completely) {
        // completely? whether element is out of view completely
        var outOfView = true;
        this.each(function() {
            var pEl = this.parentNode, pY = pEl.scrollTop, pH = pEl.clientHeight, elY = this.offsetTop, elH = this.offsetHeight;
            if (completely ? (elY) > (pY + pH) : (elY + elH) > (pY + pH)) {}
            else if (completely ? (elY + elH) < pY: elY < pY) {}
            else outOfView = false;
        });
        return outOfView;
    };

    $.fn.commonAncestor = function() {
        var parents = [];
        var minlen = Infinity;

        $(this).each(function() {
            var curparents = $(this).parents();
            parents.push(curparents);
            minlen = Math.min(minlen, curparents.length);
        });

        for (var i in parents) {
            parents[i] = parents[i].slice(parents[i].length - minlen);
        }

        // Iterate until equality is found
        for (var i in parents[0]) {
            var equal = true;
            for (var j in parents) {
                if (parents[j][i] != parents[0][i]) {
                    equal = false;
                    break;
                }
            }
            if (equal) return $(parents[0][i]);
        }
        return $([]);
    }

})(jQuery);<|endoftext|>


<commit_before>$(function () {

  // Allow user configuration?
  const allowRegex = true;
  const minInputForFullText = 1;

  function constructRegex(searchTerm, makeRe, allowRegex) {
    try {
      if (allowRegex) {
        return makeRe(searchTerm);
      }
    } catch (e) {
    }
    // In case of invalid regexp fall back to non-regexp, but still allow . to match /
    return makeRe(searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\./g, '[./]'));
  }

  function getWeightFunction(searchTerm, allowRegex) {
    function makeRe(searchTerm) {
      return {
        begin: new RegExp('\\b' + searchTerm), // Begin matches word boundary
        baseName: new RegExp('\\b' + searchTerm + '[^/]*$'), // Begin matches word boundary of class / module name
        fullName: new RegExp('\\b' + searchTerm + '(?:[~.]|$)'), // Complete word(s) of class / module matches
        completeName: new RegExp('^' + searchTerm + '$') // Match from start to finish
      }
    }
    const re = constructRegex(searchTerm, makeRe, allowRegex);
    return function (matchedItem, beginOnly) {
      // We could get smarter on the weight here
      const name = matchedItem.data('name');
      if (beginOnly) {
        return re.baseName.test(name) ? 10000 : 0;
      }
      let weight = 0;
      if (name.match(re.begin)) {
        weight += 10000;
        if (re.baseName.test(name)) {
          weight += 1000000;
          if (re.fullName.test(name)) {
            // Full match of the last part of the path is weighted even higher
            weight += 10000000;
            if (re.completeName.test(name)) {
              // Complete match is weighted highest.
              weight += 100000000;
            }
          }
        }
      }
      // If everything else is equal, prefer shorter names.
      weight -= name.length;
      return weight;
    }
  }

  // sort function callback
  var weightSorter = function (a, b) {
    var aW = $(a).data('weight') || 0;
    var bW = $(b).data('weight') || 0;
    return bW - aW;
  };

  // Show an item related a current documentation automatically
  const longname = $('.page-title').data('filename')
    .replace(/\.[a-z]+$/, '')
    .replace('module-', 'module:')
    .replace(/_/g, '/')
    .replace(/-/g, '~');
  var $currentItem = $('.navigation .item[data-longname="' + longname + '"]:eq(0)');

  if ($currentItem.length) {
    $currentItem
      .prependTo('.navigation .list')
      .show()
      .find('.member-list')
      .show();
  }

  function doSearch(searchTerm) {
    var $el = $('.navigation');

    if (searchTerm.length > 1) {
      searchTerm = searchTerm.toLowerCase();
      const getSearchWeight = getWeightFunction(searchTerm, allowRegex);
      const beginOnly = searchTerm.length < minInputForFullText;
      const regexp = constructRegex(searchTerm, function (searchTerm) {
        return new RegExp(searchTerm);
      }, allowRegex);
      $el.find('li, .member-list').hide();

      $el.find('li').each(function (i, v) {
        const $item = $(v);
        const name = $item.data('name');

        if (regexp.test(name)) {
          const $classEntry = $item.closest('.item');
          const $members = $item.closest('.member-list');

          // Do the weight thing
          const weight = getSearchWeight($classEntry, beginOnly);
          $classEntry.data('weight', weight);

          $item.show();
          $members.show();
          $classEntry.show();
        }
      });

      $(".navigation ul.list li.item:visible")
        .sort(weightSorter) // sort elements
        .appendTo(".navigation ul.list"); // append again to the list

    } else {
      $currentItem.prependTo('.navigation .list');
      $currentItem.find('.member-list, li').show();
      $el.find('.item').show();
    }

    $el.find('.list').scrollTop(0);
  }

  const searchInput = $('#search').get(0);
  // Skip searches when typing fast.
  let key;
  let start;
  const brandNode = document.querySelector('.brand');
  function queueSearch() {
    if (!key) {
      start = Date.now();
      key = setTimeout(function () {
        key = undefined;

        const searchTerm = searchInput.value;
        doSearch(searchTerm);

        const time = Date.now() - start
        brandNode.innerHTML = time + ' ms';
        console.log(searchTerm + ':', time, 'ms');
        start = undefined;
      }, 0);
    }
  }

  // Search Items
  searchInput.addEventListener('input', queueSearch);
  if (searchInput.value) {
    doSearch(searchInput.value);
  }

  // Toggle when click an item element
  $('.navigation').on('click', '.toggle', function (e) {
    $(this).parent().parent().find('.member-list').toggle();
  });

  // Auto resizing on navigation
  var _onResize = function () {
    var height = $(window).height();
    var $el = $('.navigation');

    $el.height(height).find('.list').height(height - 133);
  };

  $(window).on('resize', _onResize);
  _onResize();

  var currentVersion = document.getElementById('package-version').innerHTML;

  // warn about outdated version
  var packageUrl = 'https://raw.githubusercontent.com/openlayers/openlayers.github.io/build/package.json';
  fetch(packageUrl).then(function(response) {
    return response.json();
  }).then(function(json) {
    var latestVersion = json.version;
    document.getElementById('latest-version').innerHTML = latestVersion;
    var url = window.location.href;
    var branchSearch = url.match(/\/([^\/]*)\/apidoc\//);
    var cookieText = 'dismissed=-' + latestVersion + '-';
    var dismissed = document.cookie.indexOf(cookieText) != -1;
    if (branchSearch && !dismissed && /^v[0-9\.]*$/.test(branchSearch[1]) && currentVersion != latestVersion) {
      var link = url.replace(branchSearch[0], '/latest/apidoc/');
      fetch(link, {method: 'head'}).then(function(response) {
        var a = document.getElementById('latest-link');
        a.href = response.status == 200 ? link : '../../latest/apidoc/';
      });
      var latestCheck = document.getElementById('latest-check');
      latestCheck.style.display = '';
      document.getElementById('latest-dismiss').onclick = function() {
        latestCheck.style.display = 'none';
        document.cookie = cookieText;
      }
    }
  });

  // create source code links to github
  var srcLinks = $('div.tag-source');
  srcLinks.each(function(i, el) {
    var textParts = el.innerHTML.trim().split(', ');
    var link = 'https://github.com/openlayers/openlayers/blob/v' + currentVersion + '/src/ol/' +
      textParts[0];
    el.innerHTML = '' + textParts[0] + ', ' +
      '' +
      textParts[1] + '';
  });
});
<commit_msg>Use strict mode<commit_after>$(function () {
  'use strict';

  // Allow user configuration?
  const allowRegex = true;
  const minInputForFullText = 1;

  function constructRegex(searchTerm, makeRe, allowRegex) {
    try {
      if (allowRegex) {
        return makeRe(searchTerm);
      }
    } catch (e) {
    }
    // In case of invalid regexp fall back to non-regexp, but still allow . to match /
    return makeRe(searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\./g, '[./]'));
  }

  function getWeightFunction(searchTerm, allowRegex) {
    function makeRe(searchTerm) {
      return {
        begin: new RegExp('\\b' + searchTerm), // Begin matches word boundary
        baseName: new RegExp('\\b' + searchTerm + '[^/]*$'), // Begin matches word boundary of class / module name
        fullName: new RegExp('\\b' + searchTerm + '(?:[~.]|$)'), // Complete word(s) of class / module matches
        completeName: new RegExp('^' + searchTerm + '$') // Match from start to finish
      }
    }
    const re = constructRegex(searchTerm, makeRe, allowRegex);
    return function (matchedItem, beginOnly) {
      // We could get smarter on the weight here
      const name = matchedItem.data('name');
      if (beginOnly) {
        return re.baseName.test(name) ? 10000 : 0;
      }
      let weight = 0;
      if (name.match(re.begin)) {
        weight += 10000;
        if (re.baseName.test(name)) {
          weight += 1000000;
          if (re.fullName.test(name)) {
            // Full match of the last part of the path is weighted even higher
            weight += 10000000;
            if (re.completeName.test(name)) {
              // Complete match is weighted highest.
              weight += 100000000;
            }
          }
        }
      }
      // If everything else is equal, prefer shorter names.
      weight -= name.length;
      return weight;
    }
  }

  // sort function callback
  var weightSorter = function (a, b) {
    var aW = $(a).data('weight') || 0;
    var bW = $(b).data('weight') || 0;
    return bW - aW;
  };

  // Show an item related a current documentation automatically
  const longname = $('.page-title').data('filename')
    .replace(/\.[a-z]+$/, '')
    .replace('module-', 'module:')
    .replace(/_/g, '/')
    .replace(/-/g, '~');
  var $currentItem = $('.navigation .item[data-longname="' + longname + '"]:eq(0)');

  if ($currentItem.length) {
    $currentItem
      .prependTo('.navigation .list')
      .show()
      .find('.member-list')
      .show();
  }

  function doSearch(searchTerm) {
    var $el = $('.navigation');

    if (searchTerm.length > 1) {
      searchTerm = searchTerm.toLowerCase();
      const getSearchWeight = getWeightFunction(searchTerm, allowRegex);
      const beginOnly = searchTerm.length < minInputForFullText;
      const regexp = constructRegex(searchTerm, function (searchTerm) {
        return new RegExp(searchTerm);
      }, allowRegex);
      $el.find('li, .member-list').hide();

      $el.find('li').each(function (i, v) {
        const $item = $(v);
        const name = $item.data('name');

        if (regexp.test(name)) {
          const $classEntry = $item.closest('.item');
          const $members = $item.closest('.member-list');

          // Do the weight thing
          const weight = getSearchWeight($classEntry, beginOnly);
          $classEntry.data('weight', weight);

          $item.show();
          $members.show();
          $classEntry.show();
        }
      });

      $(".navigation ul.list li.item:visible")
        .sort(weightSorter) // sort elements
        .appendTo(".navigation ul.list"); // append again to the list

    } else {
      $currentItem.prependTo('.navigation .list');
      $currentItem.find('.member-list, li').show();
      $el.find('.item').show();
    }

    $el.find('.list').scrollTop(0);
  }

  const searchInput = $('#search').get(0);
  // Skip searches when typing fast.
  let key;
  let start;
  const brandNode = document.querySelector('.brand');
  function queueSearch() {
    if (!key) {
      start = Date.now();
      key = setTimeout(function () {
        key = undefined;

        const searchTerm = searchInput.value;
        doSearch(searchTerm);

        const time = Date.now() - start
        brandNode.innerHTML = time + ' ms';
        console.log(searchTerm + ':', time, 'ms');
        start = undefined;
      }, 0);
    }
  }

  // Search Items
  searchInput.addEventListener('input', queueSearch);
  if (searchInput.value) {
    doSearch(searchInput.value);
  }

  // Toggle when click an item element
  $('.navigation').on('click', '.toggle', function (e) {
    $(this).parent().parent().find('.member-list').toggle();
  });

  // Auto resizing on navigation
  var _onResize = function () {
    var height = $(window).height();
    var $el = $('.navigation');

    $el.height(height).find('.list').height(height - 133);
  };

  $(window).on('resize', _onResize);
  _onResize();

  var currentVersion = document.getElementById('package-version').innerHTML;

  // warn about outdated version
  var packageUrl = 'https://raw.githubusercontent.com/openlayers/openlayers.github.io/build/package.json';
  fetch(packageUrl).then(function(response) {
    return response.json();
  }).then(function(json) {
    var latestVersion = json.version;
    document.getElementById('latest-version').innerHTML = latestVersion;
    var url = window.location.href;
    var branchSearch = url.match(/\/([^\/]*)\/apidoc\//);
    var cookieText = 'dismissed=-' + latestVersion + '-';
    var dismissed = document.cookie.indexOf(cookieText) != -1;
    if (branchSearch && !dismissed && /^v[0-9\.]*$/.test(branchSearch[1]) && currentVersion != latestVersion) {
      var link = url.replace(branchSearch[0], '/latest/apidoc/');
      fetch(link, {method: 'head'}).then(function(response) {
        var a = document.getElementById('latest-link');
        a.href = response.status == 200 ? link : '../../latest/apidoc/';
      });
      var latestCheck = document.getElementById('latest-check');
      latestCheck.style.display = '';
      document.getElementById('latest-dismiss').onclick = function() {
        latestCheck.style.display = 'none';
        document.cookie = cookieText;
      }
    }
  });

  // create source code links to github
  var srcLinks = $('div.tag-source');
  srcLinks.each(function(i, el) {
    var textParts = el.innerHTML.trim().split(', ');
    var link = 'https://github.com/openlayers/openlayers/blob/v' + currentVersion + '/src/ol/' +
      textParts[0];
    el.innerHTML = '' + textParts[0] + ', ' +
      '' +
      textParts[1] + '';
  });
});
<|endoftext|>


<commit_before>'use strict';

var $ = require('jquery');

function FilterBarComponent(html) {
    this.$html = html;
    this.$container = this.$html.find('.filter-bar');
};

FilterBarComponent.prototype.init = function () {
    var component = this;

    // Create the filter add button
    createFilterListButton(component);

    // Hide the form elements
    hideFormControls(component);

    // Move save button
    moveFormActions(component);

    // Handlers
    showFilterBar(component);
    showAddFilterPopover(component);
    addFilter(component);
    removeFilter(component);
    clearAllFilters(component);
}

function showFilterBar (component) {
    component.$html.on('click', '[data-ui="show-filter-bar"]', function(e) {
        var $addFilterButton = component.$container.find('[data-ui="show-filter-list"]');

        e.preventDefault();

        // Show add button if hidden by clear
        $addFilterButton.removeClass('display--none');

        // Show filter bar
        component.$container.removeClass('display--none');
    });
}

function createFilterListButton (component) {
    var $formGroups = component.$container.find('.form__group'),
        $addFilterButton,
        $filterList = $('

'),
        $filterLabelsWrapper = $('

'),
        $target;

    // Loop through form groups
    $formGroups.each(function() {
        $filterList.append('
'+ $(this).find('.control__label').text() +'
')
    });

    // Build up list and mark up for Add filter button
    $addFilterButton = $('<button class="btn filter-bar__add" role="button" data-ui="show-filter-list" data-toggle="popover" data-trigger="click" title="Filter by" data-html="true" data-container="body" data-placement="bottom" data-content=""></button>');
    $addFilterButton.attr('data-content', $filterList[0].outerHTML);

    // Append button and label wrapper
    $filterLabelsWrapper.appendTo(component.$container.find('fieldset'));
    $addFilterButton.appendTo($filterLabelsWrapper);

    // Initialize popover
    $addFilterButton.popover();

    // Prevent default on button
    component.$html.on('click', '[data-ui="show-filter-list"]', function(e) {
        e.preventDefault();
    });
}

function hideFormControls (component) {
    component.$container
        .find('.form__group')
        .addClass('display--none');
    component.$container
        .find('.form__actions')
        .addClass('display--none');
}

function moveFormActions (component) {
    var $formActions = component.$container.find('.form__actions'),
        $fieldset = component.$container.find('fieldset');

    $formActions.appendTo($fieldset);
    $formActions.addClass('display--none');
}

function showAddFilterPopover (component) {
    var filterTitle,
        filterId,
        select2Placeholder,
        $clickedFilterListItem,
        $formGroup,
        $filterLabel,
        $popoverControls,
        $popoverContent,
        $field,
        $select2,
        $addFilterButton = component.$container.find('[data-ui="show-filter-list"]');

    component.$html.on('click', '[data-ui="filter-item"]', function(e) {
        e.preventDefault();

        filterTitle = $(this).attr('data-filter-title');
        filterId = $(this).attr('data-filter-id');
        $field = component.$container.find('#' + filterId);

        // Hide the filter item in the list
        updateFilterList($addFilterButton, filterId, 'hide');

        // Add new filter label
        $filterLabel = $('' + filterTitle + ' ');
        $filterLabel.insertBefore($addFilterButton);

        // If checkbox, check it but no need to display it or move to popover
        if ($field[0].type == 'checkbox') {

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Check the checkbox
            $field.prop('checked', true);

            // Add the remove button to the label
            filterId = $filterLabel.attr('data-filter-id');
            $filterLabel.append('');

            // Add the label
            $filterLabel
                .removeClass('label--primary')
                .addClass('label--inverse');

            // Hide the filter list button if no links remaining
            filterListButtonVisibility(component);

            // Check if save button should be visible
            formActionsVisibility(component);

        } else {

            // Create content for the popover
            $popoverContent = $('

');

            // Move the field into the popover content
            $formGroup = component.$container.find('#' + filterId).closest('.form__group');
            $formGroup.appendTo($popoverContent);
            $formGroup.addClass('form__group--flush');

            // Hide the control label
            $formGroup
                .removeClass('display--none')
                .find('.control__label')
                    .addClass('hide');

            // Add popover controls
            $popoverControls = $('
<button type="submit" class="btn btn--primary is-disabled" data-ui="add-filter" disabled="disabled">Add</button>Cancel
');
            $popoverControls.insertAfter($formGroup);

            // Refresh the select2
            $select2 = $popoverContent.find('.js-select2');
            select2Placeholder = $select2.attr('placeholder');
            $select2.select2({placeholder: select2Placeholder});

            // Trigger popover with form field on added label
            /* istanbul ignore next: difficult to test generated popover content */
            $filterLabel.popover({
                html: true,
                title: function () {
                    return filterTitle
                },
                content: function () {
                    return $popoverContent;
                },
                placement: 'bottom',
                trigger: 'manual'
            });

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Show the popover
            $filterLabel.popover('show');

            // Disable the add filter button
            $addFilterButton
                .addClass('is-disabled')
                .attr('disabled', true)
                .attr('aria-disabled', true);

            // Hide the filter list button if no links remaining
            filterListButtonVisibility(component);

            // Focus on field to avoid unnecessary extra click
            if ($field.hasClass('js-select2')) {
                $field.select2('open');
            } else {
                /* istanbul ignore next: difficult to test due to generated popover content */
                $field.focus();
            }

            // Enable button when field has value
            /* istanbul ignore next: difficult to test due to field being inside generated popover content */
            $field.on('change keyup', function(e) {
                if ($field.val()) {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .removeClass('is-disabled')
                        .attr('disabled', false)
                        .attr('aria-disabled', false);
                } else {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .addClass('is-disabled')
                        .attr('disabled', true)
                        .attr('aria-disabled', true);
                }
            });
        }
    });
}

/* istanbul ignore next: difficult to test due to field and form controls being inside generated popover content */
function addFilter (component) {
    component.$html.on('click', '[data-ui="add-filter"]', function(e) {
        var $field = $(this).closest('.added-popover-content').find('.form__control'),
            $popover = $(this).closest('.popover'),
            $formGroup = $popover.find('.form__group'),
            $label = $popover.prev('.label'),
            $addFilterButton = component.$container.find('[data-ui="show-filter-list"]'),
            $legend = component.$container.find('form fieldset legend'),
            values,
            valueForLabel = null,
            filterId;

        e.preventDefault();

        // Check if field is a select2
        if ($field.hasClass('js-select2')) {

            values = $field.select2('data');

            $.each(values, function( index, value ) {
                if (valueForLabel == null) {
                    valueForLabel = value.text;
                } else {
                    valueForLabel = valueForLabel + ', ' + value.text;
                }
            });

        } else {
            valueForLabel = $field.val();
        }

        // Add it to the label
        $label
            .find('.chosen-filter')
            .text(': ' + valueForLabel);

        // Add the remove button to the label
        filterId = $label.attr('data-filter-id');
        $label.append('');

        // Swap classes
        $label
            .removeClass('label--primary')
            .addClass('label--inverse');

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the filterbar form
        $formGroup.insertAfter($legend);

        // Close popover and destroy to prevent an empty popover showing on label click
        $label.popover('destroy');

        // Enable add filter button
        $addFilterButton.removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Check if save button should be visible
        formActionsVisibility(component);
    });
}

function removeFilter (component) {
    var $addFilterButton = component.$container.find('[data-ui="show-filter-list"]');

    component.$html.on('click', '[data-ui="filter-cancel"]', function(e) {
        var filterId = $(this).attr('data-filter-id'),
            $legend = component.$container.find('form fieldset legend'),
            $field = component.$container.find('#' + filterId),
            $formGroup = $field.closest('.form__group'),
            $filterLabel,
            $hiddenFilterListItem,
            $label;

        e.preventDefault();

        if ($(this).parents('.popover').length) {
            $label = $(this).closest('.popover').prev('.label');
        } else {
            $label = $(this).closest('.label');
        }

        // Add option back to list
        updateFilterList($addFilterButton, filterId, 'show');

        // Empty values from field
        if ($field[0].type == 'select-one' || $field[0].type == 'select-multiple') {
            $field.find('option:selected').prop('selected', false);
        } else if ($field[0].type == 'checkbox') {
            $field.prop('checked', false);
        } else {
            $field.val('');
        }

        // Destroy select2
        if ($field.hasClass('js-select2')) {
            $field.select2('destroy');
        }

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the form
        $formGroup.insertAfter($legend);

        // Remove the popover and label
        $label.popover('hide');
        $label.remove();

        // Enable add filter button
        $addFilterButton
            .removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Find any open add filter button popover
        $addFilterButton.popover('hide');

        // Check if button should be visible
        filterListButtonVisibility(component);

        // Check if save button should be visible
        formActionsVisibility(component);
    });
}

function filterListButtonVisibility (component) {
    var $addFilterButton = component.$container.find('[data-ui="show-filter-list"]'),
        addFilterList,
        $addFilterList;

    addFilterList = $addFilterButton.attr('data-content');
    $addFilterList = $(addFilterList);

    if ($addFilterList.find('li:not(.display--none)').length) {
        $addFilterButton.removeClass('display--none');
    } else {
        $addFilterButton.addClass('display--none');
    }
}

function formActionsVisibility (component) {
    var $formActions = component.$container.find('.form__actions');

    if (component.$container.find('.label').length) {
        $formActions.removeClass('display--none');
    } else {
        $formActions.addClass('display--none');
    }
}

function clearAllFilters (component) {
    var $addFilterButton = component.$container.find('[data-ui="show-filter-list"]');

    component.$html.on('click', '[data-ui="clear-all-filters"]', function(e) {

        e.preventDefault();

        // Close filter bar
        component.$container.addClass('display--none');

        // Remove all labels
        component.$container.find('.label').remove();

        // Reset filter list
        updateFilterList($addFilterButton, null, 'reset');

        // Hide form actions
        formActionsVisibility(component);

        // Reset form
        component.$container.find('form').trigger('reset');
    });
}

function updateFilterList ($addFilterButton, filterId, visibility) {
    var addFilterList = $addFilterButton.attr('data-content'),
        $addFilterList = $(addFilterList),
        $filterItem,
        $filterItemParent;

    if (filterId !== null) {
        $filterItem = $addFilterList.find('[data-filter-id="' + filterId + '"]');
        $filterItemParent = $filterItem.parent();
    }

    if (visibility === 'show') {
        $filterItemParent.removeClass('display--none');
    } else if (visibility === 'hide') {
        $filterItemParent.addClass('display--none');
    } else if (visibility === 'reset') {
        $addFilterList.find('li.display--none').removeClass('display--none');
    }

    $addFilterButton.attr('data-content', $addFilterList[0].outerHTML);
}

module.exports = FilterBarComponent;
<commit_msg>Fixed hound issues<commit_after>'use strict';

var $ = require('jquery');

function FilterBarComponent(html) {
    this.$html = html;
    this.$container = this.$html.find('.filter-bar');
}

FilterBarComponent.prototype.init = function () {
    var component = this;

    // Create the filter add button
    createFilterListButton(component);

    // Hide the form elements
    hideFormControls(component);

    // Move save button
    moveFormActions(component);

    // Handlers
    showFilterBar(component);
    showAddFilterPopover(component);
    addFilter(component);
    removeFilter(component);
    clearAllFilters(component);
};

function showFilterBar (component) {
    component.$html.on('click', '[data-ui="show-filter-bar"]', function(e) {
        var $addFilterButton = component.$container.find('[data-ui="show-filter-list"]');

        e.preventDefault();

        // Show add button if hidden by clear
        $addFilterButton.removeClass('display--none');

        // Show filter bar
        component.$container.removeClass('display--none');
    });
}

function createFilterListButton (component) {
    var $formGroups = component.$container.find('.form__group'),
        $addFilterButton,
        $filterList = $('

'),
        $filterLabelsWrapper = $('

');

    // Loop through form groups
    $formGroups.each(function() {
        $filterList.append('
'+ $(this).find('.control__label').text() +'
');
    });

    // Build up list and mark up for Add filter button
    $addFilterButton = $('<button class="btn filter-bar__add" role="button" data-ui="show-filter-list" data-toggle="popover" data-trigger="click" title="Filter by" data-html="true" data-container="body" data-placement="bottom" data-content=""></button>');
    $addFilterButton.attr('data-content', $filterList[0].outerHTML);

    // Append button and label wrapper
    $filterLabelsWrapper.appendTo(component.$container.find('fieldset'));
    $addFilterButton.appendTo($filterLabelsWrapper);

    // Initialize popover
    $addFilterButton.popover();

    // Prevent default on button
    component.$html.on('click', '[data-ui="show-filter-list"]', function(e) {
        e.preventDefault();
    });
}

function hideFormControls (component) {
    component.$container
        .find('.form__group')
        .addClass('display--none');
    component.$container
        .find('.form__actions')
        .addClass('display--none');
}

function moveFormActions (component) {
    var $formActions = component.$container.find('.form__actions'),
        $fieldset = component.$container.find('fieldset');

    $formActions.appendTo($fieldset);
    $formActions.addClass('display--none');
}

function showAddFilterPopover (component) {
    var filterTitle,
        filterId,
        select2Placeholder,
        $formGroup,
        $filterLabel,
        $popoverControls,
        $popoverContent,
        $field,
        $select2,
        $addFilterButton = component.$container.find('[data-ui="show-filter-list"]');

    component.$html.on('click', '[data-ui="filter-item"]', function(e) {
        e.preventDefault();

        filterTitle = $(this).attr('data-filter-title');
        filterId = $(this).attr('data-filter-id');
        $field = component.$container.find('#' + filterId);

        // Hide the filter item in the list
        updateFilterList($addFilterButton, filterId, 'hide');

        // Add new filter label
        $filterLabel = $('' + filterTitle + ' ');
        $filterLabel.insertBefore($addFilterButton);

        // If checkbox, check it but no need to display it or move to popover
        if ($field[0].type === 'checkbox') {

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Check the checkbox
            $field.prop('checked', true);

            // Add the remove button to the label
            filterId = $filterLabel.attr('data-filter-id');
            $filterLabel.append('');

            // Add the label
            $filterLabel
                .removeClass('label--primary')
                .addClass('label--inverse');

            // Hide the filter list button if no links remaining
            filterListButtonVisibility(component);

            // Check if save button should be visible
            formActionsVisibility(component);

        } else {

            // Create content for the popover
            $popoverContent = $('

');

            // Move the field into the popover content
            $formGroup = component.$container.find('#' + filterId).closest('.form__group');
            $formGroup.appendTo($popoverContent);
            $formGroup.addClass('form__group--flush');

            // Hide the control label
            $formGroup
                .removeClass('display--none')
                .find('.control__label')
                    .addClass('hide');

            // Add popover controls
            $popoverControls = $('
<button type="submit" class="btn btn--primary is-disabled" data-ui="add-filter" disabled="disabled">Add</button>Cancel
');
            $popoverControls.insertAfter($formGroup);

            // Refresh the select2
            $select2 = $popoverContent.find('.js-select2');
            select2Placeholder = $select2.attr('placeholder');
            $select2.select2({placeholder: select2Placeholder});

            // Trigger popover with form field on added label
            /* istanbul ignore next: difficult to test generated popover content */
            $filterLabel.popover({
                html: true,
                title: function () {
                    return filterTitle;
                },
                content: function () {
                    return $popoverContent;
                },
                placement: 'bottom',
                trigger: 'manual'
            });

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Show the popover
            $filterLabel.popover('show');

            // Disable the add filter button
            $addFilterButton
                .addClass('is-disabled')
                .attr('disabled', true)
                .attr('aria-disabled', true);

            // Hide the filter list button if no links remaining
            filterListButtonVisibility(component);

            // Focus on field to avoid unnecessary extra click
            if ($field.hasClass('js-select2')) {
                $field.select2('open');
            } else {
                /* istanbul ignore next: difficult to test due to generated popover content */
                $field.focus();
            }

            // Enable button when field has value
            /* istanbul ignore next: difficult to test due to field being inside generated popover content */
            $field.on('change keyup', function() {
                if ($field.val()) {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .removeClass('is-disabled')
                        .attr('disabled', false)
                        .attr('aria-disabled', false);
                } else {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .addClass('is-disabled')
                        .attr('disabled', true)
                        .attr('aria-disabled', true);
                }
            });
        }
    });
}

/* istanbul ignore next: difficult to test due to field and form controls being inside generated popover content */
function addFilter (component) {
    component.$html.on('click', '[data-ui="add-filter"]', function(e) {
        var $field = $(this).closest('.added-popover-content').find('.form__control'),
            $popover = $(this).closest('.popover'),
            $formGroup = $popover.find('.form__group'),
            $label = $popover.prev('.label'),
            $addFilterButton = component.$container.find('[data-ui="show-filter-list"]'),
            $legend = component.$container.find('form fieldset legend'),
            values,
            valueForLabel = null,
            filterId;

        e.preventDefault();

        // Check if field is a select2
        if ($field.hasClass('js-select2')) {

            values = $field.select2('data');

            $.each(values, function( index, value ) {
                if (valueForLabel === null) {
                    valueForLabel = value.text;
                } else {
                    valueForLabel = valueForLabel + ', ' + value.text;
                }
            });

        } else {
            valueForLabel = $field.val();
        }

        // Add it to the label
        $label
            .find('.chosen-filter')
            .text(': ' + valueForLabel);

        // Add the remove button to the label
        filterId = $label.attr('data-filter-id');
        $label.append('');

        // Swap classes
        $label
            .removeClass('label--primary')
            .addClass('label--inverse');

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the filterbar form
        $formGroup.insertAfter($legend);

        // Close popover and destroy to prevent an empty popover showing on label click
        $label.popover('destroy');

        // Enable add filter button
        $addFilterButton.removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Check if save button should be visible
        formActionsVisibility(component);
    });
}

function removeFilter (component) {
    var $addFilterButton = component.$container.find('[data-ui="show-filter-list"]');

    component.$html.on('click', '[data-ui="filter-cancel"]', function(e) {
        var filterId = $(this).attr('data-filter-id'),
            $legend = component.$container.find('form fieldset legend'),
            $field = component.$container.find('#' + filterId),
            $formGroup = $field.closest('.form__group'),
            $hiddenFilterListItem,
            $label;

        e.preventDefault();

        if ($(this).parents('.popover').length) {
            $label = $(this).closest('.popover').prev('.label');
        } else {
            $label = $(this).closest('.label');
        }

        // Add option back to list
        updateFilterList($addFilterButton, filterId, 'show');

        // Empty values from field
        if ($field[0].type === 'select-one' || $field[0].type === 'select-multiple') {
            $field.find('option:selected').prop('selected', false);
        } else if ($field[0].type === 'checkbox') {
            $field.prop('checked', false);
        } else {
            $field.val('');
        }

        // Destroy select2
        if ($field.hasClass('js-select2')) {
            $field.select2('destroy');
        }

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the form
        $formGroup.insertAfter($legend);

        // Remove the popover and label
        $label.popover('hide');
        $label.remove();

        // Enable add filter button
        $addFilterButton
            .removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Find any open add filter button popover
        $addFilterButton.popover('hide');

        // Check if button should be visible
        filterListButtonVisibility(component);

        // Check if save button should be visible
        formActionsVisibility(component);
    });
}

function filterListButtonVisibility (component) {
    var $addFilterButton = component.$container.find('[data-ui="show-filter-list"]'),
        addFilterList,
        $addFilterList;

    addFilterList = $addFilterButton.attr('data-content');
    $addFilterList = $(addFilterList);

    if ($addFilterList.find('li:not(.display--none)').length) {
        $addFilterButton.removeClass('display--none');
    } else {
        $addFilterButton.addClass('display--none');
    }
}

function formActionsVisibility (component) {
    var $formActions = component.$container.find('.form__actions');

    if (component.$container.find('.label').length) {
        $formActions.removeClass('display--none');
    } else {
        $formActions.addClass('display--none');
    }
}

function clearAllFilters (component) {
    var $addFilterButton = component.$container.find('[data-ui="show-filter-list"]');

    component.$html.on('click', '[data-ui="clear-all-filters"]', function(e) {

        e.preventDefault();

        // Close filter bar
        component.$container.addClass('display--none');

        // Remove all labels
        component.$container.find('.label').remove();

        // Reset filter list
        updateFilterList($addFilterButton, null, 'reset');

        // Hide form actions
        formActionsVisibility(component);

        // Reset form
        component.$container.find('form').trigger('reset');
    });
}

function updateFilterList ($addFilterButton, filterId, visibility) {
    var addFilterList = $addFilterButton.attr('data-content'),
        $addFilterList = $(addFilterList),
        $filterItem,
        $filterItemParent;

    if (filterId !== null) {
        $filterItem = $addFilterList.find('[data-filter-id="' + filterId + '"]');
        $filterItemParent = $filterItem.parent();
    }

    if (visibility === 'show') {
        $filterItemParent.removeClass('display--none');
    } else if (visibility === 'hide') {
        $filterItemParent.addClass('display--none');
    } else if (visibility === 'reset') {
        $addFilterList.find('li.display--none').removeClass('display--none');
    }

    $addFilterButton.attr('data-content', $addFilterList[0].outerHTML);
}

module.exports = FilterBarComponent;
<|endoftext|>