<commit_before>function modelAccessor(scope, element) {
  var expr = element.attr('name');
  if (!expr) throw "Required field 'name' not found.";
  return {
    get: function() {
      return scope.$eval(expr);
    },
    set: function(value) {
      if (value !== undefined) {
        scope.$tryEval(expr + '=' + toJson(value), element);
      }
    }
  };
}

function compileValidator(expr) {
  return new Parser(expr).validator()();
}

function valueAccessor(scope, element) {
  var validatorName = element.attr('ng-validate') || NOOP,
      validator = compileValidator(validatorName),
      required = element.attr('ng-required'),
      farmatterName = element.attr('ng-format') || NOOP,
      formatter = angularFormatter(farmatterName),
      format, parse, lastError;
      invalidWidgets = scope.$invalidWidgets || {markValid:noop, markInvalid:noop};
  if (!validator) throw "Validator named '" + validatorName + "' not found.";
  if (!formatter) throw "Formatter named '" + farmatterName + "' not found.";
  format = formatter.format;
  parse = formatter.parse;
  required = required || required === '';

  element.data('$validate', validate);
  return {
    get: function(){
      if (lastError)
        elementError(element, NG_VALIDATION_ERROR, null);
      try {
        return parse(element.val());
      } catch (e) {
        lastError = e;
        elementError(element, NG_VALIDATION_ERROR, e);
      }
    },
    set: function(value) {
      var oldValue = element[0].value,
          newValue = format(value);
      if (oldValue != newValue) {
        element[0].value = newValue;
      }
      validate();
    }
  };

  function validate() {
    var value = trim(element[0].value);
    if (element[0].disabled || element[0].readOnly) {
      elementError(element, NG_VALIDATION_ERROR, null);
      invalidWidgets.markValid(element);
    } else {
      var error,
          validateScope = extend(new (extend(function(){}, {prototype:scope}))(), {$element:element});
      error = required && !value ?
            "Required" :
            (value ? validator({state:validateScope, scope:{get:validateScope.$get, set:validateScope.$set}}, value) : null);
      elementError(element, NG_VALIDATION_ERROR, error);
      lastError = error;
      if (error) {
        invalidWidgets.markInvalid(element);
      } else {
        invalidWidgets.markValid(element);
      }
    }
  }
}

function checkedAccessor(scope, element) {
  var domElement = element[0], elementValue = domElement.value;
  return {
    get: function(){
      return !!domElement.checked;
    },
    set: function(value){
      domElement.checked = toBoolean(value);
    }
  };
}

function radioAccessor(scope, element) {
  var domElement = element[0];
  return {
    get: function(){
      return domElement.checked ? domElement.value : null;
    },
    set: function(value){
      domElement.checked = value == domElement.value;
    }
  };
}

function optionsAccessor(scope, element) {
  var options = element[0].options;
  return {
    get: function(){
      var values = [];
      foreach(options, function(option){
        if (option.selected) values.push(option.value);
      });
      return values;
    },
    set: function(values){
      var keys = {};
      foreach(values, function(value){ keys[value] = true; });
      foreach(options, function(option){
        option.selected = keys[option.value];
      });
    }
  };
}

function noopAccessor() { return { get: noop, set: noop }; }

var textWidget = inputWidget('keyup change', modelAccessor, valueAccessor, initWidgetValue()),
    buttonWidget = inputWidget('click', noopAccessor, noopAccessor, noop),
    INPUT_TYPE = {
      'text':            textWidget,
      'textarea':        textWidget,
      'hidden':          textWidget,
      'password':        textWidget,
      'button':          buttonWidget,
      'submit':          buttonWidget,
      'reset':           buttonWidget,
      'image':           buttonWidget,
      'checkbox':        inputWidget('click', modelAccessor, checkedAccessor, initWidgetValue(false)),
      'radio':           inputWidget('click', modelAccessor, radioAccessor, radioInit),
      'select-one':      inputWidget('change', modelAccessor, valueAccessor, initWidgetValue(null)),
      'select-multiple': inputWidget('change', modelAccessor, optionsAccessor, initWidgetValue([]))
//      'file':            fileWidget???
    };

function initWidgetValue(initValue) {
  return function (model, view) {
    var value = view.get();
    if (!value && isDefined(initValue))
      value = copy(initValue);
    if (isUndefined(model.get()) && isDefined(value)) {
      model.set(value);
    }
  };
}

function radioInit(model, view, element) {
 var modelValue = model.get(), viewValue = view.get(), input = element[0];
 input.name = this.$id + '@' + input.name;
 if (isUndefined(modelValue)) model.set(null);
 if (viewValue !== null) model.set(viewValue);
}

function inputWidget(events, modelAccessor, viewAccessor, initFn) {
  return function(element) {
    var scope = this,
        model = modelAccessor(scope, element),
        view = viewAccessor(scope, element),
        action = element.attr('ng-change') || '';
    initFn.call(scope, model, view, element);
    this.$eval(element.attr('ng-init')||'');
    // Don't register a handler if we are a button (noopAccessor) and there is no action
    if (action || modelAccessor !== noopAccessor) {
      element.bind(events, function(){
        model.set(view.get());
        scope.$tryEval(action, element);
        scope.$root.$eval();
        // if we have noop initFn than we are just a button,
        // therefore we want to prevent default action
        return initFn != noop;
      });
    }
    view.set(model.get());
    scope.$watch(model.get, view.set);
  };
}

function inputWidgetSelector(element){
  this.directives(true);
  return INPUT_TYPE[lowercase(element[0].type)] || noop;
}

angularWidget('INPUT', inputWidgetSelector);
angularWidget('TEXTAREA', inputWidgetSelector);
angularWidget('BUTTON', inputWidgetSelector);
angularWidget('SELECT', function(element){
  this.descend(true);
  return inputWidgetSelector.call(this, element);
});

angularWidget('NG:INCLUDE', function(element){
  var compiler = this,
      srcExp = element.attr("src"),
      scopeExp = element.attr("scope") || '';
  if (element[0]['ng-compiled']) {
    this.descend(true);
    this.directives(true);
  } else {
    element[0]['ng-compiled'] = true;
    return function(element){
      var scope = this, childScope;
      var changeCounter = 0;
      function incrementChange(){ changeCounter++;}
      this.$watch(srcExp, incrementChange);
      this.$watch(scopeExp, incrementChange);
      scope.$onEval(function(){
        if (childScope) childScope.$eval();
      });
      this.$watch(function(){return changeCounter;}, function(){
        var src = this.$eval(srcExp),
        useScope = this.$eval(scopeExp);
        if (src) {
          scope.$xhr.cache('GET', src, function(code, response){
            element.html(response);
            childScope = useScope || createScope(scope);
            compiler.compile(element)(element, childScope);
            childScope.$init();
          });
        }
      });
    };
  }
});

var ngSwitch = angularWidget('NG:SWITCH', function (element){
  var compiler = this,
      watchExpr = element.attr("on"),
      usingExpr = (element.attr("using") || 'equals'),
      usingExprParams = usingExpr.split(":"),
      usingFn = ngSwitch[usingExprParams.shift()],
      changeExpr = element.attr('change') || '',
      cases = [];
  if (!usingFn) throw "Using expression '" + usingExpr + "' unknown.";
  eachNode(element, function(caseElement){
    var when = caseElement.attr('ng-switch-when');
    if (when) {
      cases.push({
        when: function(scope, value){
          var args = [value, when];
          foreach(usingExprParams, function(arg){
            args.push(arg);
          });
          return usingFn.apply(scope, args);
        },
        change: changeExpr,
        element: caseElement,
        template: compiler.compile(caseElement)
      });
    }
  });

  // this needs to be here for IE
  foreach(cases, function(_case){
    _case.element.remove();
  });

  element.html('');
  return function(element){
    var scope = this, childScope;
    this.$watch(watchExpr, function(value){
      element.html('');
      childScope = createScope(scope);
      foreach(cases, function(switchCase){
        if (switchCase.when(childScope, value)) {
          var caseElement = switchCase.element.clone();
          element.append(caseElement);
          childScope.$tryEval(switchCase.change, element);
          switchCase.template(caseElement, childScope);
          if (scope.$invalidWidgets)
            scope.$invalidWidgets.clearOrphans();
          childScope.$init();
        }
      });
    });
    scope.$onEval(function(){
      if (childScope) childScope.$eval();
    });
  };
}, {
  equals: function(on, when) {
    return on == when;
  },
  route: function(on, when, dstName) {
    var regex = '^' + when.replace(/[\.\\\(\)\^\$]/g, "\$1") + '$',
        params = [],
        dst = {};
    foreach(when.split(/\W/), function(param){
      if (param) {
        var paramRegExp = new RegExp(":" + param + "([\\W])");
        if (regex.match(paramRegExp)) {
          regex = regex.replace(paramRegExp, "([^\/]*)$1");
          params.push(param);
        }
      }
    });
    var match = on.match(new RegExp(regex));
    if (match) {
      foreach(params, function(name, index){
        dst[name] = match[index + 1];
      });
      if (dstName) this.$set(dstName, dst);
    }
    return match ? dst : null;
  }
});
<commit_msg>fix handling of null on ie<commit_after>function modelAccessor(scope, element) {
  var expr = element.attr('name');
  if (!expr) throw "Required field 'name' not found.";
  return {
    get: function() {
      return scope.$eval(expr);
    },
    set: function(value) {
      if (value !== undefined) {
        scope.$tryEval(expr + '=' + toJson(value), element);
      }
    }
  };
}

function compileValidator(expr) {
  return new Parser(expr).validator()();
}

function valueAccessor(scope, element) {
  var validatorName = element.attr('ng-validate') || NOOP,
      validator = compileValidator(validatorName),
      required = element.attr('ng-required'),
      farmatterName = element.attr('ng-format') || NOOP,
      formatter = angularFormatter(farmatterName),
      format, parse, lastError;
      invalidWidgets = scope.$invalidWidgets || {markValid:noop, markInvalid:noop};
  if (!validator) throw "Validator named '" + validatorName + "' not found.";
  if (!formatter) throw "Formatter named '" + farmatterName + "' not found.";
  format = formatter.format;
  parse = formatter.parse;
  required = required || required === '';

  element.data('$validate', validate);
  return {
    get: function(){
      if (lastError)
        elementError(element, NG_VALIDATION_ERROR, null);
      try {
        return parse(element.val());
      } catch (e) {
        lastError = e;
        elementError(element, NG_VALIDATION_ERROR, e);
      }
    },
    set: function(value) {
      var oldValue = element.val(),
          newValue = format(value);
      if (oldValue != newValue) {
        element.val(newValue || ''); // needed for ie
      }
      validate();
    }
  };

  function validate() {
    var value = trim(element.val());
    if (element[0].disabled || element[0].readOnly) {
      elementError(element, NG_VALIDATION_ERROR, null);
      invalidWidgets.markValid(element);
    } else {
      var error,
          validateScope = extend(new (extend(function(){}, {prototype:scope}))(), {$element:element});
      error = required && !value ?
            "Required" :
            (value ? validator({state:validateScope, scope:{get:validateScope.$get, set:validateScope.$set}}, value) : null);
      elementError(element, NG_VALIDATION_ERROR, error);
      lastError = error;
      if (error) {
        invalidWidgets.markInvalid(element);
      } else {
        invalidWidgets.markValid(element);
      }
    }
  }
}

function checkedAccessor(scope, element) {
  var domElement = element[0], elementValue = domElement.value;
  return {
    get: function(){
      return !!domElement.checked;
    },
    set: function(value){
      domElement.checked = toBoolean(value);
    }
  };
}

function radioAccessor(scope, element) {
  var domElement = element[0];
  return {
    get: function(){
      return domElement.checked ? domElement.value : null;
    },
    set: function(value){
      domElement.checked = value == domElement.value;
    }
  };
}

function optionsAccessor(scope, element) {
  var options = element[0].options;
  return {
    get: function(){
      var values = [];
      foreach(options, function(option){
        if (option.selected) values.push(option.value);
      });
      return values;
    },
    set: function(values){
      var keys = {};
      foreach(values, function(value){ keys[value] = true; });
      foreach(options, function(option){
        option.selected = keys[option.value];
      });
    }
  };
}

function noopAccessor() { return { get: noop, set: noop }; }

var textWidget = inputWidget('keyup change', modelAccessor, valueAccessor, initWidgetValue()),
    buttonWidget = inputWidget('click', noopAccessor, noopAccessor, noop),
    INPUT_TYPE = {
      'text':            textWidget,
      'textarea':        textWidget,
      'hidden':          textWidget,
      'password':        textWidget,
      'button':          buttonWidget,
      'submit':          buttonWidget,
      'reset':           buttonWidget,
      'image':           buttonWidget,
      'checkbox':        inputWidget('click', modelAccessor, checkedAccessor, initWidgetValue(false)),
      'radio':           inputWidget('click', modelAccessor, radioAccessor, radioInit),
      'select-one':      inputWidget('change', modelAccessor, valueAccessor, initWidgetValue(null)),
      'select-multiple': inputWidget('change', modelAccessor, optionsAccessor, initWidgetValue([]))
//      'file':            fileWidget???
    };

function initWidgetValue(initValue) {
  return function (model, view) {
    var value = view.get();
    if (!value && isDefined(initValue)) {
      value = copy(initValue);
    }
    if (isUndefined(model.get()) && isDefined(value)) {
      model.set(value);
    }
  };
}

function radioInit(model, view, element) {
 var modelValue = model.get(), viewValue = view.get(), input = element[0];
 input.name = this.$id + '@' + input.name;
 if (isUndefined(modelValue)) model.set(null);
 if (viewValue !== null) model.set(viewValue);
}

function inputWidget(events, modelAccessor, viewAccessor, initFn) {
  return function(element) {
    var scope = this,
        model = modelAccessor(scope, element),
        view = viewAccessor(scope, element),
        action = element.attr('ng-change') || '';
    initFn.call(scope, model, view, element);
    this.$eval(element.attr('ng-init')||'');
    // Don't register a handler if we are a button (noopAccessor) and there is no action
    if (action || modelAccessor !== noopAccessor) {
      element.bind(events, function(){
        model.set(view.get());
        scope.$tryEval(action, element);
        scope.$root.$eval();
        // if we have noop initFn than we are just a button,
        // therefore we want to prevent default action
        return initFn != noop;
      });
    }
    view.set(model.get());
    scope.$watch(model.get, view.set);
  };
}

function inputWidgetSelector(element){
  this.directives(true);
  return INPUT_TYPE[lowercase(element[0].type)] || noop;
}

angularWidget('INPUT', inputWidgetSelector);
angularWidget('TEXTAREA', inputWidgetSelector);
angularWidget('BUTTON', inputWidgetSelector);
angularWidget('SELECT', function(element){
  this.descend(true);
  return inputWidgetSelector.call(this, element);
});

angularWidget('NG:INCLUDE', function(element){
  var compiler = this,
      srcExp = element.attr("src"),
      scopeExp = element.attr("scope") || '';
  if (element[0]['ng-compiled']) {
    this.descend(true);
    this.directives(true);
  } else {
    element[0]['ng-compiled'] = true;
    return function(element){
      var scope = this, childScope;
      var changeCounter = 0;
      function incrementChange(){ changeCounter++;}
      this.$watch(srcExp, incrementChange);
      this.$watch(scopeExp, incrementChange);
      scope.$onEval(function(){
        if (childScope) childScope.$eval();
      });
      this.$watch(function(){return changeCounter;}, function(){
        var src = this.$eval(srcExp),
        useScope = this.$eval(scopeExp);
        if (src) {
          scope.$xhr.cache('GET', src, function(code, response){
            element.html(response);
            childScope = useScope || createScope(scope);
            compiler.compile(element)(element, childScope);
            childScope.$init();
          });
        }
      });
    };
  }
});

var ngSwitch = angularWidget('NG:SWITCH', function (element){
  var compiler = this,
      watchExpr = element.attr("on"),
      usingExpr = (element.attr("using") || 'equals'),
      usingExprParams = usingExpr.split(":"),
      usingFn = ngSwitch[usingExprParams.shift()],
      changeExpr = element.attr('change') || '',
      cases = [];
  if (!usingFn) throw "Using expression '" + usingExpr + "' unknown.";
  eachNode(element, function(caseElement){
    var when = caseElement.attr('ng-switch-when');
    if (when) {
      cases.push({
        when: function(scope, value){
          var args = [value, when];
          foreach(usingExprParams, function(arg){
            args.push(arg);
          });
          return usingFn.apply(scope, args);
        },
        change: changeExpr,
        element: caseElement,
        template: compiler.compile(caseElement)
      });
    }
  });

  // this needs to be here for IE
  foreach(cases, function(_case){
    _case.element.remove();
  });

  element.html('');
  return function(element){
    var scope = this, childScope;
    this.$watch(watchExpr, function(value){
      element.html('');
      childScope = createScope(scope);
      foreach(cases, function(switchCase){
        if (switchCase.when(childScope, value)) {
          var caseElement = switchCase.element.clone();
          element.append(caseElement);
          childScope.$tryEval(switchCase.change, element);
          switchCase.template(caseElement, childScope);
          if (scope.$invalidWidgets)
            scope.$invalidWidgets.clearOrphans();
          childScope.$init();
        }
      });
    });
    scope.$onEval(function(){
      if (childScope) childScope.$eval();
    });
  };
}, {
  equals: function(on, when) {
    return on == when;
  },
  route: function(on, when, dstName) {
    var regex = '^' + when.replace(/[\.\\\(\)\^\$]/g, "\$1") + '$',
        params = [],
        dst = {};
    foreach(when.split(/\W/), function(param){
      if (param) {
        var paramRegExp = new RegExp(":" + param + "([\\W])");
        if (regex.match(paramRegExp)) {
          regex = regex.replace(paramRegExp, "([^\/]*)$1");
          params.push(param);
        }
      }
    });
    var match = on.match(new RegExp(regex));
    if (match) {
      foreach(params, function(name, index){
        dst[name] = match[index + 1];
      });
      if (dstName) this.$set(dstName, dst);
    }
    return match ? dst : null;
  }
});
<|endoftext|>


<commit_before>export function changeDepartmentAmount(departmentId, percentChange) {
  return {
    type: 'CHANGE_DEPARTMENT_AMOUNT',
    departmentId,
    percentChange,
  };
}

export function updateExplainResponse(departmentId, text) {
  return {
    type: 'UPDATE_EXPLAIN_RESPONSE',
    departmentId,
    text
  }
}
<commit_msg>eslint<commit_after>export function changeDepartmentAmount(departmentId, percentChange) {
  return {
    type: 'CHANGE_DEPARTMENT_AMOUNT',
    departmentId,
    percentChange,
  };
}

export function updateExplainResponse(departmentId, text) {
  return {
    type: 'UPDATE_EXPLAIN_RESPONSE',
    departmentId,
    text,
  }
}
<|endoftext|>


<commit_before>define([
    'tpl!vellum/templates/widget_control_keyvalue',
    'underscore',
    'jquery',
    'vellum/util'
], function (
    widget_control_keyvalue,
    _,
    $,
    util
) {
    var base = function(mug, options) {
        // set properties shared by all widgets
        var widget = {};
        widget.options = options;
        widget.mug = mug;
        widget.id = options.id;
        util.eventuality(widget);

        widget.isDisabled = function () {
            // requires widget.path to be set.  This only happens in
            // normal.  Need to change widgets that inherit directly from
            // base to use the path/property system.
            if (!widget.path) {
                return false;
            }

            return mug.form.vellum.isPropertyLocked(mug.absolutePath,
                                                    widget.path);
        };

        widget.getDisplayName = function () {
            // use the display text, or the property name if none found
            return this.definition.lstring ? this.definition.lstring : this.path;
        };

        widget.getControl = function () {
            throw ("must be overridden");
        };

        widget.setValue = function (val) {
            // noop
        };

        widget.getValue = function () {
            // noop
        };

        widget.getHelp = function () {
            if (this.definition && this.definition.help) {
                return {
                    text: this.definition.help,
                    url: this.definition.helpURL
                };
            }
            return null;
        };

        widget.handleChange = function () {
            widget.updateValue();
            options.afterChange();
            widget.fire("change");
        };

        widget.updateValue = function () {
            // When a widget's value changes, do whatever work you need to in
            // the model/UI to make sure we are in a consistent state.

            var isID = (['nodeID', 'defaultValue'].indexOf(widget.path) !== -1),
                val = widget.getValue();

            if (isID && val.indexOf(' ') !== -1) {
                // attempt to sanitize nodeID and choice values
                // TODO, still may allow some bad values
                widget.setValue(val.replace(/\s/g, '_'));
            }

            //short circuit the mug property changing process for when the
            //nodeID is changed to empty-string (i.e. when the user backspaces
            //the whole value).  This allows us to keep a reference to everything
            //and rename smoothly to the new value the user will ultimately enter.
            if (isID && val === "") {
                return;
            }

            widget.save();
        };

        widget.save = function () {
            throw 'Not Implemented';
        };

        widget.getUIElement = function () {
            return getUIElement(widget.getControl(), widget.getDisplayName(),
                                !!widget.isDisabled(), widget.getHelp());
        };

        return widget;
    };

    var normal = function(mug, options) {
        var path = options.widgetValuePath || options.path,
            inputID = 'property-' + path,
            disabled = options.disabled || false,
            widget = base(mug, options);

        widget.path = path;
        widget.definition = mug.p.getDefinition(options.path);
        widget.currentValue = mug.p[path];
        widget.id = inputID;

        widget.input = $("<input />")
            .attr("name", inputID)
            .prop('disabled', disabled);

        widget.getControl = function () {
            return widget.input;
        };

        widget.save = function () {
            this.mug.p[this.path] = this.getValue();
        };
        return widget;
    };

    var text = function (mug, options) {
        var widget = normal(mug, options),
            input = widget.input;
        input.attr("type", "text").addClass('input-block-level');

        widget.setValue = function (value) {
            if (value) {
                // <input> converts newlines to spaces; this preserves them
                value = value.replace(/\n/g, '
');
            }

            var position = util.getCaretPosition(input[0]);
            var oldvalue = input.val();
            input.val(value);

            // If this input has focus and value hasn't changed much,
            // keep the cursor in the same position
            if (input.is(":focus") && oldvalue.length === value.length) {
                util.setCaretPosition(input[0], position, position);
            }
        };

        widget.getValue = function() {
            return input.val().replace(/
/g, '\n');
        };

        input.bind("change input", function () {
            widget.handleChange();
        });
        return widget;
    };

    var droppableText = function (mug, options) {
        var widget = text(mug, options);
        widget.input.addClass('jstree-drop')
            .attr('placeholder', 'Hint: drag a question here.')
            .change(function () {
                widget.handleChange();
            });

        return widget;
    };

    var checkbox = function (mug, options) {
        var widget = normal(mug, options),
            input = widget.input;
        input.attr("type", "checkbox");

        widget.setValue = function (value) {
            input.prop("checked", value);
        };

        widget.getValue = function() {
            return input.prop("checked");
        };

        input.change(function () {
            widget.handleChange();
        });
        return widget;
    };

    var xPath = function (mug, options) {
        var widget = text(mug, options);

        var super_getValue = widget.getValue,
            super_setValue = widget.setValue;
        widget.getValue = function() {
            var val = super_getValue();
            if ($.trim(val) === "") {
                return "";
            }
            return val;
        };

        widget.getUIElement = function () {
            var elem = getUIElement(
                widget.getControl(),
                widget.getDisplayName(),
                !!widget.isDisabled(),
                widget.getHelp()
            );
            return getUIElementWithEditButton(elem, function () {
                widget.options.displayXPathEditor({
                    value: super_getValue(),
                    xpathType: widget.definition.xpathType,
                    done: function (val) {
                        if (val !== false) {
                            super_setValue(val);
                            widget.handleChange();
                        }
                    }
                });
                if (typeof window.ga !== "undefined") {
                    window.ga('send', 'event', 'Form Builder', 'Logic', options.lstring);
                }
            }, !!widget.isDisabled());
        };

        return widget;
    };

    var baseKeyValue = function (mug, options) {
        var widget = base(mug, options),
            id = options.id;
        widget.definition = {};

        // todo make a style for this when vellum gets a facelift
        widget.kvInput = $('
').attr('name', id);

        widget.getControl = function () {
            if (widget.isDisabled()) {
                // todo
            }
            return widget.kvInput;
        };

        widget.setValue = function (value) {
            widget.kvInput.html(widget_control_keyvalue({
                pairs: value
            }));
            widget.kvInput.find('input').bind('change keyup', function () {
                widget.handleChange();
            });
            widget.kvInput.find('.fd-kv-add-pair').click(function (e) {
                widget.refreshControl();
                e.preventDefault();
            });
            widget.kvInput.find('.fd-kv-remove-pair').click(function (e) {
                $(this).parent().parent().remove();
                widget.refreshControl();
                widget.save();
                e.preventDefault();
            });
        };

        widget.getValue = function () {
            var currentValues = {};
            _.each(widget.kvInput.find('.fd-kv-pair'), function (kvPair) {
                var $pair = $(kvPair);
                currentValues[$pair.find('.fd-kv-key').val()] = $pair.find('.fd-kv-val').val();
            });
            return currentValues;
        };

        widget.getValidValues = function () {
            var values = _.clone(widget.getValue());
            if (values[""]) {
                delete values[""];
            }
            return values;
        };

        widget.updateValue = function () {
            var currentValues = widget.getValue();
            if (!("" in currentValues)) {
                widget.kvInput.find('.btn').removeClass('hide');
                widget.kvInput.find('.fd-kv-remove-pair').removeClass('hide');
            }
            widget.save();
        };

        widget.refreshControl = function () {
            widget.setValue(widget.getValue());
        };

        return widget;
    };

    var dropdown = function (mug, options) {
        var widget = normal(mug, options);
        widget.input = $("<select />")
            .attr("name", widget.id);
        widget.isDropdown = true;

        var input = widget.input;

        widget.setValue = function (value) {
            var val = equivilentOption(value);
            if (val) {
                input.val(val.value);
            }
        };

        widget.getValue = function () {
            return input.val();
        };

        widget.updateValue = function () {
            widget.save();
        };

        input.change(function () {
            widget.handleChange();
        });

        widget.addOption = function (value, text) {
            var option = $('<option />')
                .attr('value', value)
                .text(text);
            this.input.append(option);
        };

        widget.addOptions = function (options) {
            var _this = this;
            _.forEach(options, function(option) {
                _this.addOption(option.value, option.text);
            });
        };

        widget.getOptions = function () {
            return _.map(widget.input.find('option'), function(option) {
                return {
                    value: option.value,
                    text: option.text
                };
            });
        };

        function equivilentOption(val) {
            val = val ? JSON.parse(val) : '';
            return _.find(widget.getOptions(), function (option) {
                return _.isEqual(option.value ? JSON.parse(option.value) : '', val);
            });
        }

        widget.equivilentOption = equivilentOption;

        return widget;
    };

    var readOnlyControl = function (mug, options) {
        options.id = "readonly-control";
        var widget = base(mug, options);
        widget.definition = {};
        widget.currentValue = $('
').append(mug.p.rawControlXML).clone().html();

        widget.getControl = function () {
            var control = $("
").text(this.currentValue);
            return control;
        };

        return widget;
    };

    var textOrDropDown = function (mug, options, dropDownOptions, val,
                                   emptyDropDownOption) {
        var widget, useDropDown = false,
            super_setValue;
        emptyDropDownOption = emptyDropDownOption || {value: "", text: "Empty"};

        if (val) {
            useDropDown = _.some(dropDownOptions, function(option){
                return _.isEqual(_.isString(option.value) ? JSON.parse(option.value) : {},
                                 _.isString(val.value) ? JSON.parse(val.value) : {});
            });
        } else {
            useDropDown = true;
            dropDownOptions.push(emptyDropDownOption);
        }

        if (useDropDown) {
            widget = dropdown(mug, options);
            widget.addOptions(dropDownOptions);
            widget.setValue(val ? val.value : '');
        } else {
            widget = text(mug, options);
        }

        super_setValue = widget.setValue;

        widget.setValue = function(value) {
            if (widget.isDropdown && !widget.equivilentOption(value)) {
                widget.addOption(value, 'Temp Value -- Should not be displayed');
            }
            super_setValue(value);
        };

        return widget;
    };

    var getUIElementWithEditButton = function($uiElem, editFn, isDisabled) {
        var input = $uiElem.find('input');
        if (_.isUndefined(isDisabled)) {
            isDisabled = input ? input.prop('disabled') : false;
        }

        var button = $('<button />')
            .addClass("fd-edit-button pull-right")
            .text("Edit")
            .stopLink()
            .addClass('btn')
            .attr('type', 'button')
            .prop('disabled', isDisabled)
            .click(editFn);

        $uiElem.find('label').after(button);
        $uiElem.find('.controls').css('margin-right', '60px');
        return $uiElem;
    };

    var getUIElement = function($input, labelText, isDisabled, help) {
        var uiElem = $("
").addClass("widget control-group"),
            $controls = $('
'),
            $label = $("").text(labelText);
        $label.addClass('control-label');
        if (help) {
            var $help = $("").attr({
                "href": (help.url || "#"),
                "class": "fd-help",
                "target": "_blank",
                "data-title": labelText,
                "data-content": help.text
            });
            if (!help.url) {
                $help.click(function (e) { e.preventDefault(); });
            }
            $label.append($help);
        }
        uiElem.append($label);

        $input.prop('disabled', !!isDisabled);
        $controls.append($input);
        uiElem.append($controls);
        return uiElem;
    };

    return {
        base: base,
        normal: normal,
        text: text,
        droppableText: droppableText,
        checkbox: checkbox,
        dropdown: dropdown,
        xPath: xPath,
        textOrDropDown: textOrDropDown,
        baseKeyValue: baseKeyValue,
        readOnlyControl: readOnlyControl,
        util: {
            getUIElementWithEditButton: getUIElementWithEditButton,
            getUIElement: getUIElement
        }
    };
});

<commit_msg>Fix dropdown css<commit_after>define([
    'tpl!vellum/templates/widget_control_keyvalue',
    'underscore',
    'jquery',
    'vellum/util'
], function (
    widget_control_keyvalue,
    _,
    $,
    util
) {
    var base = function(mug, options) {
        // set properties shared by all widgets
        var widget = {};
        widget.options = options;
        widget.mug = mug;
        widget.id = options.id;
        util.eventuality(widget);

        widget.isDisabled = function () {
            // requires widget.path to be set.  This only happens in
            // normal.  Need to change widgets that inherit directly from
            // base to use the path/property system.
            if (!widget.path) {
                return false;
            }

            return mug.form.vellum.isPropertyLocked(mug.absolutePath,
                                                    widget.path);
        };

        widget.getDisplayName = function () {
            // use the display text, or the property name if none found
            return this.definition.lstring ? this.definition.lstring : this.path;
        };

        widget.getControl = function () {
            throw ("must be overridden");
        };

        widget.setValue = function (val) {
            // noop
        };

        widget.getValue = function () {
            // noop
        };

        widget.getHelp = function () {
            if (this.definition && this.definition.help) {
                return {
                    text: this.definition.help,
                    url: this.definition.helpURL
                };
            }
            return null;
        };

        widget.handleChange = function () {
            widget.updateValue();
            options.afterChange();
            widget.fire("change");
        };

        widget.updateValue = function () {
            // When a widget's value changes, do whatever work you need to in
            // the model/UI to make sure we are in a consistent state.

            var isID = (['nodeID', 'defaultValue'].indexOf(widget.path) !== -1),
                val = widget.getValue();

            if (isID && val.indexOf(' ') !== -1) {
                // attempt to sanitize nodeID and choice values
                // TODO, still may allow some bad values
                widget.setValue(val.replace(/\s/g, '_'));
            }

            //short circuit the mug property changing process for when the
            //nodeID is changed to empty-string (i.e. when the user backspaces
            //the whole value).  This allows us to keep a reference to everything
            //and rename smoothly to the new value the user will ultimately enter.
            if (isID && val === "") {
                return;
            }

            widget.save();
        };

        widget.save = function () {
            throw 'Not Implemented';
        };

        widget.getUIElement = function () {
            return getUIElement(widget.getControl(), widget.getDisplayName(),
                                !!widget.isDisabled(), widget.getHelp());
        };

        return widget;
    };

    var normal = function(mug, options) {
        var path = options.widgetValuePath || options.path,
            inputID = 'property-' + path,
            disabled = options.disabled || false,
            widget = base(mug, options);

        widget.path = path;
        widget.definition = mug.p.getDefinition(options.path);
        widget.currentValue = mug.p[path];
        widget.id = inputID;

        widget.input = $("<input />")
            .attr("name", inputID)
            .prop('disabled', disabled);

        widget.getControl = function () {
            return widget.input;
        };

        widget.save = function () {
            this.mug.p[this.path] = this.getValue();
        };
        return widget;
    };

    var text = function (mug, options) {
        var widget = normal(mug, options),
            input = widget.input;
        input.attr("type", "text").addClass('input-block-level');

        widget.setValue = function (value) {
            if (value) {
                // <input> converts newlines to spaces; this preserves them
                value = value.replace(/\n/g, '
');
            }

            var position = util.getCaretPosition(input[0]);
            var oldvalue = input.val();
            input.val(value);

            // If this input has focus and value hasn't changed much,
            // keep the cursor in the same position
            if (input.is(":focus") && oldvalue.length === value.length) {
                util.setCaretPosition(input[0], position, position);
            }
        };

        widget.getValue = function() {
            return input.val().replace(/
/g, '\n');
        };

        input.bind("change input", function () {
            widget.handleChange();
        });
        return widget;
    };

    var droppableText = function (mug, options) {
        var widget = text(mug, options);
        widget.input.addClass('jstree-drop')
            .attr('placeholder', 'Hint: drag a question here.')
            .change(function () {
                widget.handleChange();
            });

        return widget;
    };

    var checkbox = function (mug, options) {
        var widget = normal(mug, options),
            input = widget.input;
        input.attr("type", "checkbox");

        widget.setValue = function (value) {
            input.prop("checked", value);
        };

        widget.getValue = function() {
            return input.prop("checked");
        };

        input.change(function () {
            widget.handleChange();
        });
        return widget;
    };

    var xPath = function (mug, options) {
        var widget = text(mug, options);

        var super_getValue = widget.getValue,
            super_setValue = widget.setValue;
        widget.getValue = function() {
            var val = super_getValue();
            if ($.trim(val) === "") {
                return "";
            }
            return val;
        };

        widget.getUIElement = function () {
            var elem = getUIElement(
                widget.getControl(),
                widget.getDisplayName(),
                !!widget.isDisabled(),
                widget.getHelp()
            );
            return getUIElementWithEditButton(elem, function () {
                widget.options.displayXPathEditor({
                    value: super_getValue(),
                    xpathType: widget.definition.xpathType,
                    done: function (val) {
                        if (val !== false) {
                            super_setValue(val);
                            widget.handleChange();
                        }
                    }
                });
                if (typeof window.ga !== "undefined") {
                    window.ga('send', 'event', 'Form Builder', 'Logic', options.lstring);
                }
            }, !!widget.isDisabled());
        };

        return widget;
    };

    var baseKeyValue = function (mug, options) {
        var widget = base(mug, options),
            id = options.id;
        widget.definition = {};

        // todo make a style for this when vellum gets a facelift
        widget.kvInput = $('
').attr('name', id);

        widget.getControl = function () {
            if (widget.isDisabled()) {
                // todo
            }
            return widget.kvInput;
        };

        widget.setValue = function (value) {
            widget.kvInput.html(widget_control_keyvalue({
                pairs: value
            }));
            widget.kvInput.find('input').bind('change keyup', function () {
                widget.handleChange();
            });
            widget.kvInput.find('.fd-kv-add-pair').click(function (e) {
                widget.refreshControl();
                e.preventDefault();
            });
            widget.kvInput.find('.fd-kv-remove-pair').click(function (e) {
                $(this).parent().parent().remove();
                widget.refreshControl();
                widget.save();
                e.preventDefault();
            });
        };

        widget.getValue = function () {
            var currentValues = {};
            _.each(widget.kvInput.find('.fd-kv-pair'), function (kvPair) {
                var $pair = $(kvPair);
                currentValues[$pair.find('.fd-kv-key').val()] = $pair.find('.fd-kv-val').val();
            });
            return currentValues;
        };

        widget.getValidValues = function () {
            var values = _.clone(widget.getValue());
            if (values[""]) {
                delete values[""];
            }
            return values;
        };

        widget.updateValue = function () {
            var currentValues = widget.getValue();
            if (!("" in currentValues)) {
                widget.kvInput.find('.btn').removeClass('hide');
                widget.kvInput.find('.fd-kv-remove-pair').removeClass('hide');
            }
            widget.save();
        };

        widget.refreshControl = function () {
            widget.setValue(widget.getValue());
        };

        return widget;
    };

    var dropdown = function (mug, options) {
        var widget = normal(mug, options);
        widget.input = $("<select />")
            .attr("name", widget.id)
            .addClass('input-block-level');
        widget.isDropdown = true;

        var input = widget.input;

        widget.setValue = function (value) {
            var val = equivilentOption(value);
            if (val) {
                input.val(val.value);
            }
        };

        widget.getValue = function () {
            return input.val();
        };

        widget.updateValue = function () {
            widget.save();
        };

        input.change(function () {
            widget.handleChange();
        });

        widget.addOption = function (value, text) {
            var option = $('<option />')
                .attr('value', value)
                .text(text);
            this.input.append(option);
        };

        widget.addOptions = function (options) {
            var _this = this;
            _.forEach(options, function(option) {
                _this.addOption(option.value, option.text);
            });
        };

        widget.getOptions = function () {
            return _.map(widget.input.find('option'), function(option) {
                return {
                    value: option.value,
                    text: option.text
                };
            });
        };

        function equivilentOption(val) {
            val = val ? JSON.parse(val) : '';
            return _.find(widget.getOptions(), function (option) {
                return _.isEqual(option.value ? JSON.parse(option.value) : '', val);
            });
        }

        widget.equivilentOption = equivilentOption;

        return widget;
    };

    var readOnlyControl = function (mug, options) {
        options.id = "readonly-control";
        var widget = base(mug, options);
        widget.definition = {};
        widget.currentValue = $('
').append(mug.p.rawControlXML).clone().html();

        widget.getControl = function () {
            var control = $("
").text(this.currentValue);
            return control;
        };

        return widget;
    };

    var textOrDropDown = function (mug, options, dropDownOptions, val,
                                   emptyDropDownOption) {
        var widget, useDropDown = false,
            super_setValue;
        emptyDropDownOption = emptyDropDownOption || {value: "", text: "Empty"};

        if (val) {
            useDropDown = _.some(dropDownOptions, function(option){
                return _.isEqual(_.isString(option.value) ? JSON.parse(option.value) : {},
                                 _.isString(val.value) ? JSON.parse(val.value) : {});
            });
        } else {
            useDropDown = true;
            dropDownOptions.push(emptyDropDownOption);
        }

        if (useDropDown) {
            widget = dropdown(mug, options);
            widget.addOptions(dropDownOptions);
            widget.setValue(val ? val.value : '');
        } else {
            widget = text(mug, options);
        }

        super_setValue = widget.setValue;

        widget.setValue = function(value) {
            if (widget.isDropdown && !widget.equivilentOption(value)) {
                widget.addOption(value, 'Temp Value -- Should not be displayed');
            }
            super_setValue(value);
        };

        return widget;
    };

    var getUIElementWithEditButton = function($uiElem, editFn, isDisabled) {
        var input = $uiElem.find('input');
        if (_.isUndefined(isDisabled)) {
            isDisabled = input ? input.prop('disabled') : false;
        }

        var button = $('<button />')
            .addClass("fd-edit-button pull-right")
            .text("Edit")
            .stopLink()
            .addClass('btn')
            .attr('type', 'button')
            .prop('disabled', isDisabled)
            .click(editFn);

        $uiElem.find('label').after(button);
        $uiElem.find('.controls').css('margin-right', '60px');
        return $uiElem;
    };

    var getUIElement = function($input, labelText, isDisabled, help) {
        var uiElem = $("
").addClass("widget control-group"),
            $controls = $('
'),
            $label = $("").text(labelText);
        $label.addClass('control-label');
        if (help) {
            var $help = $("").attr({
                "href": (help.url || "#"),
                "class": "fd-help",
                "target": "_blank",
                "data-title": labelText,
                "data-content": help.text
            });
            if (!help.url) {
                $help.click(function (e) { e.preventDefault(); });
            }
            $label.append($help);
        }
        uiElem.append($label);

        $input.prop('disabled', !!isDisabled);
        $controls.append($input);
        uiElem.append($controls);
        return uiElem;
    };

    return {
        base: base,
        normal: normal,
        text: text,
        droppableText: droppableText,
        checkbox: checkbox,
        dropdown: dropdown,
        xPath: xPath,
        textOrDropDown: textOrDropDown,
        baseKeyValue: baseKeyValue,
        readOnlyControl: readOnlyControl,
        util: {
            getUIElementWithEditButton: getUIElementWithEditButton,
            getUIElement: getUIElement
        }
    };
});

<|endoftext|>


<commit_before>app.directive('orgChart', function () {
    return {
        restrict: 'AE',
        scope: {
            orgOptions: '=',
            onChange : '&'
        },

        link: function (scope, element, attrs, ngModelCtrl) {
            var option = {};

            for(key in scope.orgOptions) {
                option[key] = scope.orgOptions[key];
            }

            if(scope.orgOptions.draggable) {
                option.dropCriteria = scope.orgOptions.dropCriteria ? scope.orgOptions.dropCriteria : dragbble;
            }

            function dragbble($draggedNode, $dragZone, $dropZone) {
                if ($draggedNode.find('.content').text().indexOf('manager') > -1 && $dropZone.find('.content').text().indexOf('engineer') > -1) {
                    return false;
                }
                return true;
            }
                (element).orgchart(option)
                 .children('.orgchart').on('nodedropped.orgchart', function (event) {
                    console.log('draggedNode:' + event.draggedNode.children('.title').text(), event.draggedNode.attr('id')
                    + ', dragZone:' + event.dragZone.children('.title').text(), event.dragZone.attr('id')
                    + ', dropZone:' + event.dropZone.children('.title').text(), event.dropZone.attr('id'));
                    var tree = $(element).orgchart('getHierarchy');
                    scope.onChange({hierarchy : tree});
                })
                .on('click', '.node', function() {
                    var $this = $(this);
                    $('#selected-node').val($this.find('.title').text()).data('node', $this);
                })
                .on('click', '.orgchart', function(event) {
                    if (!$(event.target).closest('.node').length) {
                        $('#selected-node').val('');
                    }
                });
        },
        controller : function() {
            $('input[name="chart-state"]').on('click', function() {
                $('.orgchart').toggleClass('view-state', this.value !== 'view');
                $('#edit-panel').toggleClass('view-state', this.value === 'view');
                if ($(this).val() === 'edit') {
                    $('.orgchart').find('tr').removeClass('hidden')
                        .find('td').removeClass('hidden')
                        .find('.node').removeClass('slide-up slide-down slide-right slide-left');
                } else {
                    $('#btn-reset').trigger('click');
                }
            });

            $('input[name="node-type"]').on('click', function() {
                var $this = $(this);
                if ($this.val() === 'parent') {
                    $('#edit-panel').addClass('edit-parent-node');
                    $('#new-nodelist').children(':gt(0)').remove();
                } else {
                    $('#edit-panel').removeClass('edit-parent-node');
                }
            });

            $('#btn-add-input').on('click', function() {
                $('#new-nodelist').append('
<input type="text" class="new-node">
');
            });

            $('#btn-remove-input').on('click', function() {
                var inputs = $('#new-nodelist').children('li');
                if (inputs.length > 1) {
                    inputs.last().remove();
                }
            });

            $('#btn-add-nodes').on('click', function() {
                var $chartContainer = $('#chart-container');
                var nodeVals = [];
                $('#new-nodelist').find('.new-node').each(function(index, item) {
                    var validVal = item.value.trim();
                    if (validVal.length) {
                        nodeVals.push(validVal);
                    }
                });
                var $node = $('#selected-node').data('node');
                if (!nodeVals.length) {
                    alert('Please input value for new node');
                    return;
                }
                var nodeType = $('input[name="node-type"]:checked');
                if (!nodeType.length) {
                    alert('Please select a node type');
                    return;
                }
                if (nodeType.val() !== 'parent' && !$('.orgchart').length) {
                    alert('Please creat the root node firstly when you want to build up the orgchart from the scratch');
                    return;
                }
                if (nodeType.val() !== 'parent' && !$node) {
                    alert('Please select one node in orgchart');
                    return;
                }
                if (nodeType.val() === 'parent') {
                    if (!$chartContainer.children().length) {// if the original chart has been deleted
                        $chartContainer.orgchart({
                            'data' : { 'name': nodeVals[0] },
                            'exportButton': true,
                            'exportFilename': 'SportsChart',
                            'parentNodeSymbol': 'fa-th-large',
                            'createNode': function($node, data) {
                                $node[0].id = getId();
                            }
                        })
                            .find('.orgchart').addClass('view-state');
                    } else {
                        $chartContainer.orgchart('addParent', $chartContainer.find('.node:first'), { 'name': nodeVals[0], 'Id': getId() });
                    }
                } else if (nodeType.val() === 'siblings') {
                    $chartContainer.orgchart('addSiblings', $node,
                        { 'siblings': nodeVals.map(function(item) { return { 'name': item, 'relationship': '110', 'Id': getId() }; })
                        });
                } else {
                    var hasChild = $node.parent().attr('colspan') > 0 ? true : false;
                    if (!hasChild) {
                        var rel = nodeVals.length > 1 ? '110' : '100';
                        $chartContainer.orgchart('addChildren', $node, {
                            'children': nodeVals.map(function(item) {
                                return { 'name': item, 'relationship': rel, 'Id': getId() };
                            })
                        }, $.extend({}, $chartContainer.find('.orgchart').data('options'), { depth: 0 }));
                    } else {
                        $chartContainer.orgchart('addSiblings', $node.closest('tr').siblings('.nodes').find('.node:first'),
                            { 'siblings': nodeVals.map(function(item) { return { 'name': item, 'relationship': '110', 'Id': getId() }; })
                            });
                    }
                }
            });

            $('#btn-delete-nodes').on('click', function() {
                var $node = $('#selected-node').data('node');
                if (!$node) {
                    alert('Please select one node in orgchart');
                    return;
                } else if ($node[0] === $('.orgchart').find('.node:first')[0]) {
                    if (!window.confirm('Are you sure you want to delete the whole chart?')) {
                        return;
                    }
                }
                $('#chart-container').orgchart('removeNodes', $node);
                $('#selected-node').val('').data('node', null);
            });

            $('#btn-reset').on('click', function() {
                $('.orgchart').find('.focused').removeClass('focused');
                $('#selected-node').val('');
                $('#new-nodelist').find('input:first').val('').parent().siblings().remove();
                $('#node-type-panel').find('input').prop('checked', false);
            });
        }
    };
});<commit_msg>added default option in org chart<commit_after>app.directive('orgChart', function () {
    return {
        restrict: 'AE',
        scope: {
            orgOptions: '=',
            onChange : '&'
        },

        link: function (scope, element, attrs, ngModelCtrl) {
            var option = {};

            for(key in scope.orgOptions) {
                option[key] = scope.orgOptions[key];
            }

            if(scope.orgOptions.draggable) {
                option.dropCriteria = scope.orgOptions.dropCriteria ? scope.orgOptions.dropCriteria : dragbble;
            }

            function dragbble($draggedNode, $dragZone, $dropZone) {
                if ($draggedNode.find('.content').text().indexOf('manager') > -1 && $dropZone.find('.content').text().indexOf('engineer') > -1) {
                    return false;
                }
                return true;
            }
            $(element).orgchart(option)
                .children('.orgchart').on('nodedropped.orgchart', function (event) {
                    console.log('draggedNode:' + event.draggedNode.children('.title').text(), event.draggedNode.attr('id')
                    + ', dragZone:' + event.dragZone.children('.title').text(), event.dragZone.attr('id')
                    + ', dropZone:' + event.dropZone.children('.title').text(), event.dropZone.attr('id'));
                    var tree = $(element).orgchart('getHierarchy');
                    scope.onChange({hierarchy : tree});
                })
                .on('click', '.node', function() {
                    var $this = $(this);
                    $('#selected-node').val($this.find('.title').text()).data('node', $this);
                })
                .on('click', '.orgchart', function(event) {
                    if (!$(event.target).closest('.node').length) {
                        $('#selected-node').val('');
                    }
                });
        },
        controller : function() {
            $('input[name="chart-state"]').on('click', function() {
                $('.orgchart').toggleClass('view-state', this.value !== 'view');
                $('#edit-panel').toggleClass('view-state', this.value === 'view');
                if ($(this).val() === 'edit') {
                    $('.orgchart').find('tr').removeClass('hidden')
                        .find('td').removeClass('hidden')
                        .find('.node').removeClass('slide-up slide-down slide-right slide-left');
                } else {
                    $('#btn-reset').trigger('click');
                }
            });

            $('input[name="node-type"]').on('click', function() {
                var $this = $(this);
                if ($this.val() === 'parent') {
                    $('#edit-panel').addClass('edit-parent-node');
                    $('#new-nodelist').children(':gt(0)').remove();
                } else {
                    $('#edit-panel').removeClass('edit-parent-node');
                }
            });

            $('#btn-add-input').on('click', function() {
                $('#new-nodelist').append('
<input type="text" class="new-node">
');
            });

            $('#btn-remove-input').on('click', function() {
                var inputs = $('#new-nodelist').children('li');
                if (inputs.length > 1) {
                    inputs.last().remove();
                }
            });

            $('#btn-add-nodes').on('click', function() {
                var $chartContainer = $('#chart-container');
                var nodeVals = [];
                $('#new-nodelist').find('.new-node').each(function(index, item) {
                    var validVal = item.value.trim();
                    if (validVal.length) {
                        nodeVals.push(validVal);
                    }
                });
                var $node = $('#selected-node').data('node');
                if (!nodeVals.length) {
                    alert('Please input value for new node');
                    return;
                }
                var nodeType = $('input[name="node-type"]:checked');
                if (!nodeType.length) {
                    alert('Please select a node type');
                    return;
                }
                if (nodeType.val() !== 'parent' && !$('.orgchart').length) {
                    alert('Please creat the root node firstly when you want to build up the orgchart from the scratch');
                    return;
                }
                if (nodeType.val() !== 'parent' && !$node) {
                    alert('Please select one node in orgchart');
                    return;
                }
                if (nodeType.val() === 'parent') {
                    if (!$chartContainer.children().length) {// if the original chart has been deleted
                        $chartContainer.orgchart({
                            'data' : { 'name': nodeVals[0] },
                            'exportButton': true,
                            'exportFilename': 'SportsChart',
                            'parentNodeSymbol': 'fa-th-large',
                            'createNode': function($node, data) {
                                $node[0].id = getId();
                            }
                        })
                            .find('.orgchart').addClass('view-state');
                    } else {
                        $chartContainer.orgchart('addParent', $chartContainer.find('.node:first'), { 'name': nodeVals[0], 'Id': getId() });
                    }
                } else if (nodeType.val() === 'siblings') {
                    $chartContainer.orgchart('addSiblings', $node,
                        { 'siblings': nodeVals.map(function(item) { return { 'name': item, 'relationship': '110', 'Id': getId() }; })
                        });
                } else {
                    var hasChild = $node.parent().attr('colspan') > 0 ? true : false;
                    if (!hasChild) {
                        var rel = nodeVals.length > 1 ? '110' : '100';
                        $chartContainer.orgchart('addChildren', $node, {
                            'children': nodeVals.map(function(item) {
                                return { 'name': item, 'relationship': rel, 'Id': getId() };
                            })
                        }, $.extend({}, $chartContainer.find('.orgchart').data('options'), { depth: 0 }));
                    } else {
                        $chartContainer.orgchart('addSiblings', $node.closest('tr').siblings('.nodes').find('.node:first'),
                            { 'siblings': nodeVals.map(function(item) { return { 'name': item, 'relationship': '110', 'Id': getId() }; })
                            });
                    }
                }
            });

            $('#btn-delete-nodes').on('click', function() {
                var $node = $('#selected-node').data('node');
                if (!$node) {
                    alert('Please select one node in orgchart');
                    return;
                } else if ($node[0] === $('.orgchart').find('.node:first')[0]) {
                    if (!window.confirm('Are you sure you want to delete the whole chart?')) {
                        return;
                    }
                }
                $('#chart-container').orgchart('removeNodes', $node);
                $('#selected-node').val('').data('node', null);
            });

            $('#btn-reset').on('click', function() {
                $('.orgchart').find('.focused').removeClass('focused');
                $('#selected-node').val('');
                $('#new-nodelist').find('input:first').val('').parent().siblings().remove();
                $('#node-type-panel').find('input').prop('checked', false);
            });
        }
    };
});<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { Image, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import AreaChart from './area-chart'
import XAxis from './x-axis'
import YAxis from './y-axis'
import LineChart from './line-chart'
import PieChart from './pie-chart'
import BarChart from './bar-chart'
import * as dateFns from 'date-fns'
import ProgressCircle from './progress-circle'
import Label from './assets/d3.png'

const _data = [
    [
        { 'value': 80, 'key': 'Fun activities', color: 'blue', date: new Date(2016, 7) },
        { 'value': 15, 'key': 'Dog', color: 'green', date: new Date(2016, 8) },
        { 'value': 150, 'key': 'Food', color: 'purple', date: new Date(2016, 9) },
        { 'value': 10, 'key': 'YouFood', color: 'purple', date: new Date(2016, 10) },
        { 'value': 100, 'key': 'barfoo', color: 'purple', date: new Date(2016, 11) },
        { 'value': -23, 'key': 'Car', color: 'gray', date: new Date(2016, 12) },
        { 'value': 220, 'key': 'Rent', color: 'red', date: new Date(2017, 1) },
        { 'value': 20, 'key': 'Rent2', color: 'red', date: new Date(2017, 2) },
        { 'value': 30, 'key': 'bar', color: 'red', date: new Date(2017, 3) },
        { 'value': -40, 'key': 'baz', color: 'orange', date: new Date(2017, 4) },
        { 'value': -100, 'key': 'foobar', color: 'orange', date: new Date(2017, 5) },
    ],
    [
        { 'value': 60, 'key': 'Fun activities', color: 'blue', date: new Date(2016, 7) },
        { 'value': 150, 'key': 'Dog', color: 'green', date: new Date(2016, 8) },
        { 'value': 15, 'key': 'Food', color: 'purple', date: new Date(2016, 9) },
        { 'value': undefined, 'key': 'YouFood', color: 'purple', date: new Date(2016, 10) },
        { 'value': 10, 'key': 'barfoo', color: 'purple', date: new Date(2016, 11) },
        { 'value': -23, 'key': 'Car', color: 'gray', date: new Date(2016, 12) },
        { 'value': 220, 'key': 'Rent', color: 'red', date: new Date(2017, 1) },
        { 'value': undefined, 'key': 'Rent2', color: 'red', date: new Date(2017, 2) },
        { 'value': 0, 'key': 'bar', color: 'red', date: new Date(2017, 3) },
        { 'value': -40, 'key': 'baz', color: 'orange', date: new Date(2017, 4) },
        { 'value': -100, 'key': 'foobar', color: 'orange', date: new Date(2017, 5) },
    ],
    [
        { 'value': 30, 'key': 'Fun activities', color: 'blue', date: new Date(2017, 10) },
        { 'value': 65, 'key': 'Dog', color: 'green', date: new Date(2017, 11) },
        { 'value': -20, 'key': 'Foo', color: 'green', date: new Date(2017, 12) },
        { 'value': 10, 'key': 'Food', color: 'purple', date: new Date(2018, 1) },
        { 'value': 230, 'key': 'Car', color: 'gray', date: new Date(2018, 2) },
        { 'value': 20, 'key': 'Rent', color: 'red', date: new Date(2018, 3) },
        { 'value': 410, 'key': 'Misc', color: 'orange', date: new Date(2018, 4) },
    ],
    [
        { 'value': 30, 'key': 'Fun activities', color: 'blue', date: new Date(2017, 10) },
        { 'value': 65, 'key': 'Dog', color: 'green', date: new Date(2017, 11) },
    ],
    [
        { 'value': 30, 'key': 'Fun activities', color: 'blue', date: new Date(2017, 10) },
    ],
]

const _progressData = [
    0.4,
    0.8,
    0.2,
    1,
    0,
]

const _multipleBarData = [
    {
        fillColor: 'green',
        strokeColor: 'green',
        strokeColorNegative: 'red',
        fillColorNegative: 'red',
        values: _data[ 0 ].map(obj => obj.value),
    },
    {
        fillColor: 'blue',
        strokeColor: 'blue',
        strokeColorNegative: 'orange',
        fillColorNegative: 'orange',
        values: _data[ 1 ].map(obj => obj.value),
    },
]

class App extends Component {

    state = {
        index: 0,
        data: _data[ 0 ],
        progress: _progressData[ 0 ],
    }

    _toggleData() {
        const { index } = this.state

        const newIndex = index < _data.length - 1 ? index + 1 : 0

        this.setState({
            data: _data[ newIndex ],
            progress: _progressData[ newIndex ],
            index: newIndex,
        })
    }

    render() {
        const { data, progress } = this.state
        return (
            <View style={{ flex: 1 }}>
                <ScrollView contentContainerStyle={styles.container}>
                    <View style={styles.card}>
                        <View style={{ flexDirection: 'row', height: 200 }}>
                            <YAxis
                                style={{ paddingRight: 5 }}
                                contentInset={{ bottom: 20 }}
                                dataPoints={_multipleBarData[ 0 ].values}
                                labelStyle={{ color: 'grey' }}
                            />
                            <View style={{ flex: 1 }}>
                                <BarChart
                                    style={{ flex: 1 }}
                                    dataPoints={_multipleBarData}
                                    spacing={0.3}
                                />
                                <XAxis
                                    chartType={XAxis.Type.BAR}
                                    spacing={0.3}
                                    style={{ height: 20, justifyContent: 'center' }}
                                    values={_data[ 0 ].map(data => data.date)}
                                    formatLabel={date => dateFns.format(date, 'MMM')}
                                    labelStyle={{ color: 'grey', fontSize: 8 }}
                                />
                            </View>
                        </View>
                    </View>
                    <View style={[ styles.card, { height: 120 } ]}>
                        <ProgressCircle
                            style={{ flex: 1 }}
                            progress={progress}
                        />
                    </View>
                    <View style={styles.card}>
                        <View style={{ flexDirection: 'row', height: 200 }}>
                            <YAxis
                                style={{ width: 30 }}
                                contentInset={{ bottom: 20 }}
                                dataPoints={data.map(data => data.value)}
                                labelStyle={{ color: 'grey' }}
                            />
                            <View style={{ flex: 1 }}>
                                <BarChart
                                    style={{ flex: 1 }}
                                    dataPoints={[ { values: data.map(data => data.value) } ]}
                                    spacing={0.05}
                                />
                                <XAxis
                                    chartType={XAxis.Type.BAR}
                                    spacing={0.05}
                                    style={{ height: 20, justifyContent: 'center' }}
                                    values={data.map(data => data.date)}
                                    formatLabel={date => dateFns.format(date, 'MMM')}
                                    labelStyle={{ color: 'grey' }}
                                />
                            </View>
                        </View>
                    </View>
                    <View style={styles.card}>
                        <View style={{ height: 200, flexDirection: 'row' }}>
                            <YAxis
                                dataPoints={data.map(data => data.value)}
                                style={{ marginTop: 10, marginRight: 5 }}
                                contentInset={{ bottom: 30 }}
                            />
                            <View style={{ flex: 1 }}>
                                <LineChart
                                    style={{ flex: 1 }}
                                    dataPoints={data.map(data => data.value)}
                                    dashSize={5}
                                    showPoints={true}
                                    shadowColor={'rgba(34, 182, 176, 0.2)'}
                                    contentInset={{ bottom: 10, left: 15, right: 15, top: 10 }}
                                />
                                <XAxis
                                    chartType={XAxis.Type.LINE}
                                    spacing={0.05}
                                    style={{ height: 20, justifyContent: 'center' }}
                                    contentInset={{ left: 15, right: 15 }}
                                    values={data.map(data => data.date)}
                                    formatLabel={date => dateFns.format(date, 'MMM')}
                                />
                            </View>
                        </View>
                    </View>
                    <View style={[ styles.card, { height: 250 } ]}>
                        <PieChart
                            style={{ flex: 1 }}
                            dataPoints={data.filter(data => data.value >= 0)}
                            labelDistance={5}
                            innerRadius={0.7}
                            labelSpacing={40}
                            renderLabel={item => (
                                <TouchableOpacity
                                    style={[ styles.pieLabelContainer, { borderColor: item.color } ]}
                                    onPress={() => console.log('clicked!', item)}
                                >
                                    <Image source={Label} style={styles.pieLabelImage}/>
                                </TouchableOpacity>
                            )}
                        />
                    </View>
                    <View style={styles.card}>
                        <View style={{ flexDirection: 'row', height: 200 }}>
                            <YAxis
                                dataPoints={data.map(data => data.value)}
                                style={{ width: 40 }}
                                contentInset={{ bottom: 30, top: 10 }}
                            />
                            <View style={{ flex: 1 }}>
                                <AreaChart
                                    style={{ flex: 1 }}
                                    dataPoints={data.map(data => data.value)}
                                    showPoints={true}
                                    contentInset={{ bottom: 10, left: 15, top: 10, right: 15 }}
                                />
                                <XAxis
                                    style={{ height: 20 }}
                                    values={data.map(data => data.date)}
                                    contentInset={{ left: 15, right: 15 }}
                                    formatLabel={date => dateFns.format(date, 'MMM')}
                                    spacing={0}
                                />
                            </View>
                        </View>
                    </View>
                </ScrollView>
                <TouchableOpacity
                    onPress={() => this._toggleData()}
                >
                    <View style={styles.button}>
                        <Text style={{ color: 'white' }}>{'Switch data'}</Text>
                    </View>
                </TouchableOpacity>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        backgroundColor: '#F5FCFF',
    },
    card: {
        backgroundColor: 'white',
        shadowOffset: {
            height: 2,
            width: 2,
        },
        elevation: 4,
        shadowColor: 'black',
        shadowOpacity: 0.5,
        margin: 16,
        padding: 16,
    },
    button: {
        padding: 16,
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: 'blue',
    },
    pieLabelContainer: {
        padding: 5,
        borderWidth: 2,
        borderRadius: 30,
        backgroundColor: 'white',
    },
    pieLabelImage: {
        height: 15,
        width: 15,
    },
})

export default App
<commit_msg>apparently using inline styles always triggers a re-render<commit_after>import React, { Component } from 'react'
import { AppState, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import AreaChart from './area-chart'
import XAxis from './x-axis'
import YAxis from './y-axis'
import LineChart from './line-chart'
import PieChart from './pie-chart'
import BarChart from './bar-chart'
import * as dateFns from 'date-fns'
import ProgressCircle from './progress-circle'
import Label from './assets/d3.png'

const _data = [
    [
        { 'value': 80, 'key': 'Fun activities', color: 'blue', date: new Date(2016, 7) },
        { 'value': 15, 'key': 'Dog', color: 'green', date: new Date(2016, 8) },
        { 'value': 150, 'key': 'Food', color: 'purple', date: new Date(2016, 9) },
        { 'value': 10, 'key': 'YouFood', color: 'purple', date: new Date(2016, 10) },
        { 'value': 100, 'key': 'barfoo', color: 'purple', date: new Date(2016, 11) },
        { 'value': -23, 'key': 'Car', color: 'gray', date: new Date(2016, 12) },
        { 'value': 220, 'key': 'Rent', color: 'red', date: new Date(2017, 1) },
        { 'value': 20, 'key': 'Rent2', color: 'red', date: new Date(2017, 2) },
        { 'value': 30, 'key': 'bar', color: 'red', date: new Date(2017, 3) },
        { 'value': -40, 'key': 'baz', color: 'orange', date: new Date(2017, 4) },
        { 'value': -100, 'key': 'foobar', color: 'orange', date: new Date(2017, 5) },
    ],
    [
        { 'value': 60, 'key': 'Fun activities', color: 'blue', date: new Date(2016, 7) },
        { 'value': 150, 'key': 'Dog', color: 'green', date: new Date(2016, 8) },
        { 'value': 15, 'key': 'Food', color: 'purple', date: new Date(2016, 9) },
        { 'value': undefined, 'key': 'YouFood', color: 'purple', date: new Date(2016, 10) },
        { 'value': 10, 'key': 'barfoo', color: 'purple', date: new Date(2016, 11) },
        { 'value': -23, 'key': 'Car', color: 'gray', date: new Date(2016, 12) },
        { 'value': 220, 'key': 'Rent', color: 'red', date: new Date(2017, 1) },
        { 'value': undefined, 'key': 'Rent2', color: 'red', date: new Date(2017, 2) },
        { 'value': 0, 'key': 'bar', color: 'red', date: new Date(2017, 3) },
        { 'value': -40, 'key': 'baz', color: 'orange', date: new Date(2017, 4) },
        { 'value': -100, 'key': 'foobar', color: 'orange', date: new Date(2017, 5) },
    ],
    [
        { 'value': 30, 'key': 'Fun activities', color: 'blue', date: new Date(2017, 10) },
        { 'value': 65, 'key': 'Dog', color: 'green', date: new Date(2017, 11) },
        { 'value': -20, 'key': 'Foo', color: 'green', date: new Date(2017, 12) },
        { 'value': 10, 'key': 'Food', color: 'purple', date: new Date(2018, 1) },
        { 'value': 230, 'key': 'Car', color: 'gray', date: new Date(2018, 2) },
        { 'value': 20, 'key': 'Rent', color: 'red', date: new Date(2018, 3) },
        { 'value': 410, 'key': 'Misc', color: 'orange', date: new Date(2018, 4) },
    ],
    [
        { 'value': 30, 'key': 'Fun activities', color: 'blue', date: new Date(2017, 10) },
        { 'value': 65, 'key': 'Dog', color: 'green', date: new Date(2017, 11) },
    ],
    [
        { 'value': 30, 'key': 'Fun activities', color: 'blue', date: new Date(2017, 10) },
    ],
]

const _progressData = [
    0.4,
    0.8,
    0.2,
    1,
    0,
]

const _multipleBarData = [
    {
        fillColor: 'green',
        strokeColor: 'green',
        strokeColorNegative: 'red',
        fillColorNegative: 'red',
        values: _data[ 0 ].map(obj => obj.value),
    },
    {
        fillColor: 'blue',
        strokeColor: 'blue',
        strokeColorNegative: 'orange',
        fillColorNegative: 'orange',
        values: _data[ 1 ].map(obj => obj.value),
    },
]

const FLEX_1 = { flex: 1 }
class App extends Component {

    state = {
        index: 0,
        data: _data[ 0 ],
        progress: _progressData[ 0 ],
    }

    _toggleData() {
        const { index } = this.state

        const newIndex = index < _data.length - 1 ? index + 1 : 0

        this.setState({
            data: _data[ newIndex ],
            progress: _progressData[ newIndex ],
            index: newIndex,
        })
    }

    render() {
        const { data, progress } = this.state
        return (
            <View style={styles.flex1}>
                <ScrollView contentContainerStyle={styles.container}>
                    <View style={styles.card}>
                        <View style={{ flexDirection: 'row', height: 200 }}>
                            <YAxis
                                style={{ paddingRight: 5 }}
                                contentInset={{ bottom: 20 }}
                                dataPoints={_multipleBarData[ 0 ].values}
                                labelStyle={{ color: 'grey' }}
                            />
                            <View style={styles.flex1}>
                                <BarChart
                                    style={FLEX_1}
                                    dataPoints={_multipleBarData}
                                    spacing={0.3}
                                />
                                <XAxis
                                    chartType={XAxis.Type.BAR}
                                    spacing={0.3}
                                    style={{ height: 20, justifyContent: 'center' }}
                                    values={_data[ 0 ].map(data => data.date)}
                                    formatLabel={date => dateFns.format(date, 'MMM')}
                                    labelStyle={{ color: 'grey', fontSize: 8 }}
                                />
                            </View>
                        </View>
                    </View>
                    <View style={[ styles.card, { height: 120 } ]}>
                        <ProgressCircle
                            style={styles.flex1}
                            progress={progress}
                        />
                    </View>
                    <View style={styles.card}>
                        <View style={{ flexDirection: 'row', height: 200 }}>
                            <YAxis
                                style={{ width: 30 }}
                                contentInset={{ bottom: 20 }}
                                dataPoints={data.map(data => data.value)}
                                labelStyle={{ color: 'grey' }}
                            />
                            <View style={styles.flex1}>
                                <BarChart
                                    style={FLEX_1}
                                    dataPoints={[ { values: data.map(data => data.value) } ]}
                                    spacing={0.05}
                                />
                                <XAxis
                                    chartType={XAxis.Type.BAR}
                                    spacing={0.05}
                                    style={{ height: 20, justifyContent: 'center' }}
                                    values={data.map(data => data.date)}
                                    formatLabel={date => dateFns.format(date, 'MMM')}
                                    labelStyle={{ color: 'grey' }}
                                />
                            </View>
                        </View>
                    </View>
                    <View style={styles.card}>
                        <View style={{ height: 200, flexDirection: 'row' }}>
                            <YAxis
                                dataPoints={data.map(data => data.value)}
                                style={{ marginTop: 10, marginRight: 5 }}
                                contentInset={{ bottom: 30 }}
                            />
                            <View style={styles.flex1}>
                                <LineChart
                                    style={styles.flex1}
                                    dataPoints={data.map(data => data.value)}
                                    dashSize={5}
                                    showPoints={true}
                                    shadowColor={'rgba(34, 182, 176, 0.2)'}
                                    contentInset={{ bottom: 10, left: 15, right: 15, top: 10 }}
                                />
                                <XAxis
                                    chartType={XAxis.Type.LINE}
                                    spacing={0.05}
                                    style={{ height: 20, justifyContent: 'center' }}
                                    contentInset={{ left: 15, right: 15 }}
                                    values={data.map(data => data.date)}
                                    formatLabel={date => dateFns.format(date, 'MMM')}
                                />
                            </View>
                        </View>
                    </View>
                    <View style={[ styles.card, { height: 250 } ]}>
                        <PieChart
                            style={styles.flex1}
                            dataPoints={data.filter(data => data.value >= 0)}
                            labelDistance={5}
                            innerRadius={0.7}
                            labelSpacing={40}
                            renderLabel={item => (
                                <TouchableOpacity
                                    style={[ styles.pieLabelContainer, { borderColor: item.color } ]}
                                    onPress={() => console.log('clicked!', item)}
                                >
                                    <Image source={Label} style={styles.pieLabelImage}/>
                                </TouchableOpacity>
                            )}
                        />
                    </View>
                    <View style={styles.card}>
                        <View style={{ flexDirection: 'row', height: 200 }}>
                            <YAxis
                                dataPoints={data.map(data => data.value)}
                                style={{ width: 40 }}
                                contentInset={{ bottom: 30, top: 10 }}
                            />
                            <View style={styles.flex1}>
                                <AreaChart
                                    style={styles.flex1}
                                    dataPoints={data.map(data => data.value)}
                                    showPoints={true}
                                    contentInset={{ bottom: 10, left: 15, top: 10, right: 15 }}
                                />
                                <XAxis
                                    style={{ height: 20 }}
                                    values={data.map(data => data.date)}
                                    contentInset={{ left: 15, right: 15 }}
                                    formatLabel={date => dateFns.format(date, 'MMM')}
                                    spacing={0}
                                />
                            </View>
                        </View>
                    </View>
                </ScrollView>
                <TouchableOpacity
                    onPress={() => this._toggleData()}
                >
                    <View style={styles.button}>
                        <Text style={{ color: 'white' }}>{'Switch data'}</Text>
                    </View>
                </TouchableOpacity>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        backgroundColor: '#F5FCFF',
    },
    flex1: {
        flex: 1,
    },
    card: {
        backgroundColor: 'white',
        shadowOffset: {
            height: 2,
            width: 2,
        },
        elevation: 4,
        shadowColor: 'black',
        shadowOpacity: 0.5,
        margin: 16,
        padding: 16,
    },
    button: {
        padding: 16,
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: 'blue',
    },
    pieLabelContainer: {
        padding: 5,
        borderWidth: 2,
        borderRadius: 30,
        backgroundColor: 'white',
    },
    pieLabelImage: {
        height: 15,
        width: 15,
    },
})

export default App
<|endoftext|>


<commit_before>/*!
 * Copyright 2016 PREGIOTEK
 * http://pregiotek.com/
 *
 * ion-floating-menu
 * Material UI-like Floating Action Button and Menu for Ionic applications.
 *
 * By @ennedigi
 *
 * Licensed under the MIT license. Please see LICENSE for more information.
 *
 */

(function () {
    'use strict';

    angular.module('ion-floating-menu', [])

            .directive('ionFloatingButton', ionFloatingButton)
            .directive('ionFloatingMenu', ionFloatingMenu)
            .directive('ionFloatingItem', ionFloatingItem);

    function ionFloatingButton() {
        return {
            restrict: 'E',
            scope: {
                click: '&?',
                buttonColor: '@?',
                buttonClass: '@?',
                icon: '@?',
                iconColor: '@?',
                hasFooter: '=?',
                isCentered: '=?'},
            template: '
' +
                    '
' +
                    '' +
                    '
' +
                    '
',
            replace: true,
            transclude: true,
            controller: ionFloatingButtonCtrl
        };
    }

    ionFloatingButtonCtrl.$inject = ['$scope'];
    function ionFloatingButtonCtrl($scope) {
        $scope.buttonColor = $scope.buttonColor || '#2AC9AA';
        $scope.icon = $scope.icon || 'ion-plus';
        $scope.iconColor = $scope.iconColor || '#fff';
        $scope.hasFooter = $scope.hasFooter || false;
        $scope.isCentered = $scope.isCentered || false;

        if ($scope.hasFooter) {
            $scope.bottomValue = '60px';
        } else {
            $scope.bottomValue = '20px';
        }
    }

    function ionFloatingMenu() {
        return {
            restrict: 'E',
            scope: {
                menuOpenColor: '@?',
                menuOpenIcon: '@?',
                menuOpenIconColor: '@?',
                menuColor: '@?',
                menuIcon: '@?',
                menuIconColor: '@?',
                hasFooter: '=?',
                backdrop: '=?'
            },
            template: '
' +
                    '

' +
                    '

' +
                    '
',
            replace: false,
            transclude: true,
            link: function (scope, element, attrs, ctrl, transclude)
            {
                element.find('div').replaceWith(transclude());
            },
            controller: ionFloatingMenuCtrl
        };
    }

    function ionFloatingItem() {
        return {
            restrict: 'E',
            require: ['^ionFloatingMenu'],
            scope: {
                click: '&?',
                icon: '@',
                buttonColor: '@?',
                buttonClass: '@?',
                iconColor: '@?',
                text: '@?',
                textClass: '@?'},
            template:
                    '
' +
                    '' +
                    '
',
            replace: false,
            controller: ionFloatingItemCtrl
        };
    }

    ionFloatingMenuCtrl.$inject = ['$scope', '$rootScope','$ionicBackdrop'];
    function ionFloatingMenuCtrl($scope, $rootScope, $ionicBackdrop) {
        $scope.isOpen = false;
        $scope.open = function () {
            $scope.isOpen = !$scope.isOpen;
            if ($scope.isOpen) {
                $scope.setOpen();
            } else {
                $scope.setClose();
            }
        };
        $scope.setOpen = function () {
            $scope.buttonColor = menuOpenColor;
            $scope.icon = menuOpenIcon;
            $scope.iconColor = menuOpenIconColor;

            if (backdrop){
                $ionicBackdrop.retain();
             }
             $rootScope.$broadcast('floating-menu:open');
        };
        $scope.setClose = function () {
            $scope.buttonColor = menuColor;
            $scope.icon = menuIcon;
            $scope.iconColor = menuIconColor;
            if (backdrop){
                $ionicBackdrop.release();
             }
             $rootScope.$broadcast('floating-menu:close');
        };
        var menuColor = $scope.menuColor || '#2AC9AA';
        var menuIcon = $scope.menuIcon || 'ion-plus';
        var menuIconColor = $scope.menuIconColor || '#fff';
        var menuOpenColor = $scope.menuOpenColor || '#2AC9AA';
        var menuOpenIcon = $scope.menuOpenIcon || 'ion-minus';
        var menuOpenIconColor = $scope.menuOpenIconColor || '#fff';
        var backdrop = $scope.backdrop || false;
        $scope.setClose();
        $scope.hasFooter = $scope.hasFooter || false;
        if ($scope.hasFooter) {
            $scope.bottomValue = '60px';
        } else {
            $scope.bottomValue = '20px';
        }

    }

    ionFloatingItemCtrl.$inject = ['$scope'];
    function ionFloatingItemCtrl($scope) {
        $scope.buttonColor = $scope.buttonColor || '#2AC9AA';
        $scope.iconColor = $scope.iconColor || '#fff';
    }

})();
<commit_msg>Restore replace = false<commit_after>/*!
 * Copyright 2016 PREGIOTEK
 * http://pregiotek.com/
 *
 * ion-floating-menu
 * Material UI-like Floating Action Button and Menu for Ionic applications.
 *
 * By @ennedigi
 *
 * Licensed under the MIT license. Please see LICENSE for more information.
 *
 */

(function () {
    'use strict';

    angular.module('ion-floating-menu', [])

            .directive('ionFloatingButton', ionFloatingButton)
            .directive('ionFloatingMenu', ionFloatingMenu)
            .directive('ionFloatingItem', ionFloatingItem);

    function ionFloatingButton() {
        return {
            restrict: 'E',
            scope: {
                click: '&?',
                buttonColor: '@?',
                buttonClass: '@?',
                icon: '@?',
                iconColor: '@?',
                hasFooter: '=?',
                isCentered: '=?'},
            template: '
' +
                    '
' +
                    '' +
                    '
' +
                    '
',
            replace: false,
            transclude: true,
            controller: ionFloatingButtonCtrl
        };
    }

    ionFloatingButtonCtrl.$inject = ['$scope'];
    function ionFloatingButtonCtrl($scope) {
        $scope.buttonColor = $scope.buttonColor || '#2AC9AA';
        $scope.icon = $scope.icon || 'ion-plus';
        $scope.iconColor = $scope.iconColor || '#fff';
        $scope.hasFooter = $scope.hasFooter || false;
        $scope.isCentered = $scope.isCentered || false;

        if ($scope.hasFooter) {
            $scope.bottomValue = '60px';
        } else {
            $scope.bottomValue = '20px';
        }
    }

    function ionFloatingMenu() {
        return {
            restrict: 'E',
            scope: {
                menuOpenColor: '@?',
                menuOpenIcon: '@?',
                menuOpenIconColor: '@?',
                menuColor: '@?',
                menuIcon: '@?',
                menuIconColor: '@?',
                hasFooter: '=?',
                backdrop: '=?'
            },
            template: '
' +
                    '

' +
                    '

' +
                    '
',
            replace: false,
            transclude: true,
            link: function (scope, element, attrs, ctrl, transclude)
            {
                element.find('div').replaceWith(transclude());
            },
            controller: ionFloatingMenuCtrl
        };
    }

    function ionFloatingItem() {
        return {
            restrict: 'E',
            require: ['^ionFloatingMenu'],
            scope: {
                click: '&?',
                icon: '@',
                buttonColor: '@?',
                buttonClass: '@?',
                iconColor: '@?',
                text: '@?',
                textClass: '@?'},
            template:
                    '
' +
                    '' +
                    '
',
            replace: false,
            controller: ionFloatingItemCtrl
        };
    }

    ionFloatingMenuCtrl.$inject = ['$scope', '$rootScope','$ionicBackdrop'];
    function ionFloatingMenuCtrl($scope, $rootScope, $ionicBackdrop) {
        $scope.isOpen = false;
        $scope.open = function () {
            $scope.isOpen = !$scope.isOpen;
            if ($scope.isOpen) {
                $scope.setOpen();
            } else {
                $scope.setClose();
            }
        };
        $scope.setOpen = function () {
            $scope.buttonColor = menuOpenColor;
            $scope.icon = menuOpenIcon;
            $scope.iconColor = menuOpenIconColor;

            if (backdrop){
                $ionicBackdrop.retain();
             }
             $rootScope.$broadcast('floating-menu:open');
        };
        $scope.setClose = function () {
            $scope.buttonColor = menuColor;
            $scope.icon = menuIcon;
            $scope.iconColor = menuIconColor;
            if (backdrop){
                $ionicBackdrop.release();
             }
             $rootScope.$broadcast('floating-menu:close');
        };
        var menuColor = $scope.menuColor || '#2AC9AA';
        var menuIcon = $scope.menuIcon || 'ion-plus';
        var menuIconColor = $scope.menuIconColor || '#fff';
        var menuOpenColor = $scope.menuOpenColor || '#2AC9AA';
        var menuOpenIcon = $scope.menuOpenIcon || 'ion-minus';
        var menuOpenIconColor = $scope.menuOpenIconColor || '#fff';
        var backdrop = $scope.backdrop || false;
        $scope.setClose();
        $scope.hasFooter = $scope.hasFooter || false;
        if ($scope.hasFooter) {
            $scope.bottomValue = '60px';
        } else {
            $scope.bottomValue = '20px';
        }

    }

    ionFloatingItemCtrl.$inject = ['$scope'];
    function ionFloatingItemCtrl($scope) {
        $scope.buttonColor = $scope.buttonColor || '#2AC9AA';
        $scope.iconColor = $scope.iconColor || '#fff';
    }

})();
<|endoftext|>