<commit_before>/**
 * Before updating any "SourceModel" that has a valid "hasOne" association with any other "TargetModel",
 * automatically eager-load the relating model if we haven't been specifically disabled.
 *
 * @param  {Object}   modelData    the data originally provided to SourceModel.update()
 * @param  {Object}   queryOptions the options originally provided to SourceModel.update()
 * @param  {Function} callback     the callback to allow SourceModel.update() to continue execution
 * @return {Promise}               optionally return the promise for use in spread()
 */
module.exports = function findTargetModelBeforeUpdateSourceModel(as, association, targetModel, values, queryOptions, callback) {
  var valueAs     = values[as]
    , entity      = valueAs !== undefined && valueAs !== null ? valueAs.entity : undefined
    , isTargetPk  = valueAs ? !isNaN(valueAs) : false
    , targetPK    = targetModel.primaryKey
    , nestedQuery = !!valueAs && !isTargetPk ? {where:{}} : false;

  if (entity === undefined && valueAs && !isTargetPk && (typeof valueAs !== 'object' || valueAs[targetPK] === undefined)) {
    nestedQuery.where.label = valueAs;

    targetModel
      .find(nestedQuery, queryOptions)
      .then(function(instance) {
        values[as] = instance;
        callback(null);
      })
      .catch(callback);
  } else {
    callback(null);
  }
};<commit_msg>fix(associations): Nested Operation for hasOne now correctly checks for targetPK<commit_after>/**
 * Before updating any "SourceModel" that has a valid "hasOne" association with any other "TargetModel",
 * automatically eager-load the relating model if we haven't been specifically disabled.
 *
 * @param  {Object}   modelData    the data originally provided to SourceModel.update()
 * @param  {Object}   queryOptions the options originally provided to SourceModel.update()
 * @param  {Function} callback     the callback to allow SourceModel.update() to continue execution
 * @return {Promise}               optionally return the promise for use in spread()
 */
module.exports = function findTargetModelBeforeUpdateSourceModel(as, association, targetModel, values, queryOptions, callback) {
  var valueAs     = values[as]
    , entity      = valueAs !== undefined && valueAs !== null ? valueAs.entity : undefined
    , isTargetPk  = valueAs ? !isNaN(valueAs) : false
    , targetPK    = targetModel.primaryKey
    , nestedQuery = !!valueAs && !isTargetPk ? {where:{}} : false;

  if (entity === undefined && valueAs && !isTargetPk && (typeof valueAs !== 'object' || valueAs[targetPK] !== undefined)) {
    nestedQuery.where.label = valueAs;

    targetModel
      .find(nestedQuery, queryOptions)
      .then(function(instance) {
        values[as] = instance;
        callback(null);
      })
      .catch(callback);
  } else {
    callback(null);
  }
};
<|endoftext|>


<commit_before>// HTML data binding support.
define(['lib/util', 'lib/modelprop'], function (util, modelprop) {

    // A binding that sets the text content of an element.
    function TextBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-text');
    }
    TextBinding.prototype.update = function (context) {
        var newText = modelprop.get(context, this.model, this.path);
        if (newText === undefined) {
            console.log('Could not bind text: ' + this.path);
            return;
        }
        this.element.text(newText);
    };

    // A two-way binding for the value of an input element.
    function ValueBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-value');

        var self = this;

        // Change handler.
        function onChange() {
            modelprop.set(self.context, self.model, self.path, $(this).val());

            // When the value changes, we need to re-compute bindings,
            // as other stuff may depend on the value.
            updateBindings(self.model);
        }

        // Hook input and change events to support input and select elements.
        element
            .on('input', onChange)
            .on('change', onChange);
    }
    ValueBinding.prototype.update = function (context) {
        // Save context for change handler.
        this.context = context;

        // Only update if actually changed to avoid losing caret position when typing.
        var newVal = modelprop.get(context, this.model, this.path);
        if (this.element.val() !== newVal) {
            this.element.val(newVal);
        }
    };

    // A two-way binding for the checked property of a checkbox input element.
    function CheckedBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-checked');

        var self = this;

        // Change handler.
        element.change(function () {
            modelprop.set(self.context, self.model, self.path, $(this).prop('checked'));

            // When the value changes, we need to re-compute bindings,
            // as other stuff may depend on the value.
            updateBindings(self.model);
        });
    }
    CheckedBinding.prototype.update = function (context) {
        // Save context for change handler.
        this.context = context;

        var newVal = modelprop.get(context, this.model, this.path);
        if (newVal === undefined) {
            console.log('Could not bind value: ' + this.path);
            return;
        }

        if (this.element.prop('checked') !== newVal) {
            this.element.prop('checked', newVal);
        }
    };

    // Binding for the options of a 'select' element.
    function OptionsBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-options');
    }
    OptionsBinding.prototype.update = function (context) {
        // Remember previous value.
        var prevVal = this.element.val();

        // Clear existing options.
        this.element.children('option').remove();

        var options = modelprop.get(context, this.model, this.path);
        if (options === undefined) {
            console.log('Could not bind options: ' + this.path);
            return;
        }

        options.forEach(function (option) {
            $('<option value="' + option + '">')
            .appendTo(this.element)
            .text(option);
        }, this);

        // Reset previous value, if possible.
        if (options.indexOf(prevVal) >= 0) {
            this.element.val(prevVal);
        }
    };

    function ClickBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-click');

        var self = this;

        // Click event handler.
        element.click(util.preventDefaultEvent(function (event) {
            var action = modelprop.getWithParent(self.context, this.model, self.path);
            if (action.value === undefined) {
                console.log('Failed to bind action: ' + self.path);
                return;
            }

            action.value.call(action.parent, event);
        }));
    }
    ClickBinding.prototype.update = function (context) {
        // Save context for change handler.
        this.context = context;
    };

    function VisibilityBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-visibility');
    }
    VisibilityBinding.prototype.update = function (context) {
        var visibility = modelprop.get(context, this.model, this.path);
        this.element.toggle(Boolean(visibility));
    };

    // A binding that sets a property of an element.
    function PropBinding(element, model) {
        this.element = element;
        this.model = model;

        // Parse params, format: 'property;path'
        var params = element.attr('data-bind-prop').split(';');
        if (params.length === 2) {
            this.prop = params[0];
            this.path = params[1];
        } else {
            console.log('Invalid prop bind params: ' + element.attr('data-bind-prop'));
        }
    }
    PropBinding.prototype.update = function (context) {
        if (this.prop && this.path) {
            var value = modelprop.get(context, this.model, this.path);
            this.element.prop(this.prop, value);
        }
    };

    // A binding that adds a class to an element.
    function ClassBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-class');
    }
    ClassBinding.prototype.update = function (context) {
        // Remove any previously-set class.
        if (this.prevClass) {
            this.element.removeClass(this.prevClass);
        }

        var newClass = modelprop.get(context, this.model, this.path);
        if (newClass) {
            this.element.addClass(newClass);
            this.prevClass = newClass;
        }
    };

    // A binding that generates its contents once for each item in an array.
    function EachBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-each');
        this.template = element.children().clone();
        this.currSize = 1;          // Start with a single child.

        // Init bindings for initial single child.
        this.children = [];     // Array of arrays of child bindings.
        this.children[0] = [];
        appendBindings(element.children(), this.model, this.children[0]);
    }
    EachBinding.prototype.update = function (context) {
        var childElements, i;

        // Bound object must be array-like.
        var array = modelprop.get(context, this.model, this.path);
        if (array === undefined) {
            console.log('Could not bind each: ' + this.path);
            return;
        }
        if (util.isUndefined(array.length) || util.isUndefined(array.forEach)) {
            console.log('each binding must be an array');
            return;
        }

        // TODO: Don't completely regenerate from scratch
        if (array.length !== this.currSize) {
            // TODO: Clean up previous bindings.

            // Array has changed, so re-generate contents.
            this.element.empty();
            this.children = [];

            //array.forEach(function (childContext) {
            for (i = 0; i < array.length; i++) {
                // Create a new copy of the template and add it to ourselves.
                childElements = this.template.clone().appendTo(this.element);

                // Init bindings for the new copy.
                this.children[i] = [];
                appendBindings(childElements, this.model, this.children[i]);
            }
            this.currSize = array.length;
        }

        // Update all children.
        for (i = 0; i < array.length; i++) {
            this.children[i].forEach(function (child) { child.update(array[i]); });
        }
    };

    // A binding that generates child items only if the binding expression is true.
    function IfBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-if');
        this.attached = true;

        // Manage our own children.
        this.childBindings = [];
        appendBindings(element.children(), model, this.childBindings);
    }
    IfBinding.prototype.update = function (context) {
        var condition = modelprop.get(context, this.model, this.path);
        if (condition) {
            if (!this.attached) {
                this.element.append(this.childElements);
                this.attached = true;
            }
        } else {
            if (this.attached) {
                this.childElements = this.element.children().detach();
                this.attached = false;
            }
        }

        if (this.attached) {
            // Update all children.
            this.childBindings.forEach(function (child) { child.update(context); });
        }
    };

    // Handy helpers for determining if an element has an attribute/one of a list of attributes.
    $.fn.hasAttr = function (attr) {
        return this.attr(attr) !== undefined;
    };
    $.fn.hasAnyAttr = function (attrs) {
        return attrs.some(function (attr) { return this.hasAttr(attr); }, this);
    };

    function appendBindings(elements, model, bindings) {
        elements.each(function () {
            var element = $(this);
            var prevNumBindings = bindings.length;
            var bRecurseToChildren = true;

            // Mutually exclusive bindings.
            if (element.hasAttr('data-bind-each')) {
                bindings.push(new EachBinding(element, model));

                // Don't recurse to children -- they require special handling.
                bRecurseToChildren = false;
            } else if (element.hasAttr('data-bind-if')) {
                bindings.push(new IfBinding(element, model));

                // Don't recurse to children -- they're handled by the binding.
                bRecurseToChildren = false;
            } else if (element.hasAttr('data-bind-text')) {
                bindings.push(new TextBinding(element, model));

                // Don't recurse to children -- we're going to replace the contents with the bound text.
                bRecurseToChildren = false;
            } else if (element.hasAttr('data-bind-value')) {
                bindings.push(new ValueBinding(element, model));
            } else if (element.hasAttr('data-bind-checked')) {
                bindings.push(new CheckedBinding(element, model));
            }

            // Bindings that any node can have.
            if (element.hasAttr('data-bind-options')) {
                bindings.push(new OptionsBinding(element, model));
            }
            if (element.hasAttr('data-bind-click')) {
                bindings.push(new ClickBinding(element, model));
            }
            if (element.hasAttr('data-bind-visibility')) {
                bindings.push(new VisibilityBinding(element, model));
            }
            if (element.hasAttr('data-bind-prop')) {
                bindings.push(new PropBinding(element, model));
            }
            if (element.hasAttr('data-bind-class')) {
                bindings.push(new ClassBinding(element, model));
            }

            // Only recurse to children if they're not already handled/disallowed by a binding.
            if (bRecurseToChildren) {
                appendBindings(element.children(), model, bindings);
            }
        });
    }

    var allBindings = [];

    function findBindingsIndex(modelOrElement) {
        if (modelOrElement instanceof jQuery) {
            // Look for bindings for this element
            return allBindings.findIndex(function (b) { return b.rootElement === modelOrElement; });
        } else {
            // Look for bindings for this model
            return allBindings.findIndex(function (b) { return b.model === modelOrElement; });
        }
    }

    function findBindings(modelOrElement) {
        var index = findBindingsIndex(modelOrElement);
        return (index >= 0) ? allBindings[index] : undefined;
    }

    function initBinding(rootElement, model) {

        // Check we haven't already got bindings for either this element or model.
        if (findBindings(rootElement)) {
            console.log('Bindings already initialised for element');
            return;
        }
        if (findBindings(model)) {
            console.log('Bindings already initialised for model');
            return;
        }

        // Create new bindings container and create the actual bindings for it.
        var newBindings = {
            rootElement: rootElement,
            model: model,
            bindings: []
        };
        appendBindings(rootElement, model, newBindings.bindings);

        // Add to list of all managed bindings.
        allBindings.push(newBindings);

        // Update bindings now.
        newBindings.bindings.forEach(function (binding) {
            binding.update(model);
        });
    }

    function cleanupBinding(modelOrElement) {
        var index = findBindingsIndex(modelOrElement);
        if (index >= 0) {
            allBindings.splice(index, 1);
        }
    }

    function updateBindings(modelOrElement) {
        var bindings = findBindings(modelOrElement);
        if (bindings) {
            // Update each binding.
            bindings.bindings.forEach(function (binding) {
                binding.update(bindings.model);
            });
        } else {
            console.log('Could not find bindings to update');
        }
    }

    // Module object.
    return {
        initBinding: initBinding,
        cleanupBinding: cleanupBinding,
        updateBindings: updateBindings
    };
});
<commit_msg>Added very simple 'with' binding<commit_after>// HTML data binding support.
define(['lib/util', 'lib/modelprop'], function (util, modelprop) {

    // A binding that sets the text content of an element.
    function TextBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-text');
    }
    TextBinding.prototype.update = function (context) {
        var newText = modelprop.get(context, this.model, this.path);
        if (newText === undefined) {
            console.log('Could not bind text: ' + this.path);
            return;
        }
        this.element.text(newText);
    };

    // A two-way binding for the value of an input element.
    function ValueBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-value');

        var self = this;

        // Change handler.
        function onChange() {
            modelprop.set(self.context, self.model, self.path, $(this).val());

            // When the value changes, we need to re-compute bindings,
            // as other stuff may depend on the value.
            updateBindings(self.model);
        }

        // Hook input and change events to support input and select elements.
        element
            .on('input', onChange)
            .on('change', onChange);
    }
    ValueBinding.prototype.update = function (context) {
        // Save context for change handler.
        this.context = context;

        // Only update if actually changed to avoid losing caret position when typing.
        var newVal = modelprop.get(context, this.model, this.path);
        if (this.element.val() !== newVal) {
            this.element.val(newVal);
        }
    };

    // A two-way binding for the checked property of a checkbox input element.
    function CheckedBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-checked');

        var self = this;

        // Change handler.
        element.change(function () {
            modelprop.set(self.context, self.model, self.path, $(this).prop('checked'));

            // When the value changes, we need to re-compute bindings,
            // as other stuff may depend on the value.
            updateBindings(self.model);
        });
    }
    CheckedBinding.prototype.update = function (context) {
        // Save context for change handler.
        this.context = context;

        var newVal = modelprop.get(context, this.model, this.path);
        if (newVal === undefined) {
            console.log('Could not bind value: ' + this.path);
            return;
        }

        if (this.element.prop('checked') !== newVal) {
            this.element.prop('checked', newVal);
        }
    };

    // Binding for the options of a 'select' element.
    function OptionsBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-options');
    }
    OptionsBinding.prototype.update = function (context) {
        // Remember previous value.
        var prevVal = this.element.val();

        // Clear existing options.
        this.element.children('option').remove();

        var options = modelprop.get(context, this.model, this.path);
        if (options === undefined) {
            console.log('Could not bind options: ' + this.path);
            return;
        }

        options.forEach(function (option) {
            $('<option value="' + option + '">')
            .appendTo(this.element)
            .text(option);
        }, this);

        // Reset previous value, if possible.
        if (options.indexOf(prevVal) >= 0) {
            this.element.val(prevVal);
        }
    };

    function ClickBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-click');

        var self = this;

        // Click event handler.
        element.click(util.preventDefaultEvent(function (event) {
            var action = modelprop.getWithParent(self.context, this.model, self.path);
            if (action.value === undefined) {
                console.log('Failed to bind action: ' + self.path);
                return;
            }

            action.value.call(action.parent, event);
        }));
    }
    ClickBinding.prototype.update = function (context) {
        // Save context for change handler.
        this.context = context;
    };

    function VisibilityBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-visibility');
    }
    VisibilityBinding.prototype.update = function (context) {
        var visibility = modelprop.get(context, this.model, this.path);
        this.element.toggle(Boolean(visibility));
    };

    // A binding that sets a property of an element.
    function PropBinding(element, model) {
        this.element = element;
        this.model = model;

        // Parse params, format: 'property;path'
        var params = element.attr('data-bind-prop').split(';');
        if (params.length === 2) {
            this.prop = params[0];
            this.path = params[1];
        } else {
            console.log('Invalid prop bind params: ' + element.attr('data-bind-prop'));
        }
    }
    PropBinding.prototype.update = function (context) {
        if (this.prop && this.path) {
            var value = modelprop.get(context, this.model, this.path);
            this.element.prop(this.prop, value);
        }
    };

    // A binding that adds a class to an element.
    function ClassBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-class');
    }
    ClassBinding.prototype.update = function (context) {
        // Remove any previously-set class.
        if (this.prevClass) {
            this.element.removeClass(this.prevClass);
        }

        var newClass = modelprop.get(context, this.model, this.path);
        if (newClass) {
            this.element.addClass(newClass);
            this.prevClass = newClass;
        }
    };

    // A binding that generates its contents once for each item in an array.
    function EachBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-each');
        this.template = element.children().clone();
        this.currSize = 1;          // Start with a single child.

        // Init bindings for initial single child.
        this.children = [];     // Array of arrays of child bindings.
        this.children[0] = [];
        appendBindings(element.children(), this.model, this.children[0]);
    }
    EachBinding.prototype.update = function (context) {
        var childElements, i;

        // Bound object must be array-like.
        var array = modelprop.get(context, this.model, this.path);
        if (array === undefined) {
            console.log('Could not bind each: ' + this.path);
            return;
        }
        if (util.isUndefined(array.length) || util.isUndefined(array.forEach)) {
            console.log('each binding must be an array');
            return;
        }

        // TODO: Don't completely regenerate from scratch
        if (array.length !== this.currSize) {
            // TODO: Clean up previous bindings.

            // Array has changed, so re-generate contents.
            this.element.empty();
            this.children = [];

            //array.forEach(function (childContext) {
            for (i = 0; i < array.length; i++) {
                // Create a new copy of the template and add it to ourselves.
                childElements = this.template.clone().appendTo(this.element);

                // Init bindings for the new copy.
                this.children[i] = [];
                appendBindings(childElements, this.model, this.children[i]);
            }
            this.currSize = array.length;
        }

        // Update all children.
        for (i = 0; i < array.length; i++) {
            this.children[i].forEach(function (child) { child.update(array[i]); });
        }
    };

    // A binding that generates child items only if the binding expression is true.
    function IfBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-if');
        this.attached = true;

        // Manage our own children.
        this.childBindings = [];
        appendBindings(element.children(), model, this.childBindings);
    }
    IfBinding.prototype.update = function (context) {
        var condition = modelprop.get(context, this.model, this.path);
        if (condition) {
            if (!this.attached) {
                this.element.append(this.childElements);
                this.attached = true;
            }
        } else {
            if (this.attached) {
                this.childElements = this.element.children().detach();
                this.attached = false;
            }
        }

        if (this.attached) {
            // Update all children.
            this.childBindings.forEach(function (child) { child.update(context); });
        }
    };

    // A binding that changes the context of any sub elements.
    function WithBinding(element, model) {
        this.element = element;
        this.model = model;
        this.path = element.attr('data-bind-with');

        // Manage our own children.
        this.childBindings = [];
        appendBindings(element.children(), model, this.childBindings);
    }
    WithBinding.prototype.update = function (context) {
        var subContext = modelprop.get(context, this.model, this.path);
        this.childBindings.forEach(function (child) { child.update(subContext); });
    };

    // Handy helpers for determining if an element has an attribute/one of a list of attributes.
    $.fn.hasAttr = function (attr) {
        return this.attr(attr) !== undefined;
    };
    $.fn.hasAnyAttr = function (attrs) {
        return attrs.some(function (attr) { return this.hasAttr(attr); }, this);
    };

    function appendBindings(elements, model, bindings) {
        elements.each(function () {
            var element = $(this);
            var prevNumBindings = bindings.length;
            var bRecurseToChildren = true;

            // Mutually exclusive bindings.
            if (element.hasAttr('data-bind-each')) {
                bindings.push(new EachBinding(element, model));

                // Don't recurse to children -- they require special handling.
                bRecurseToChildren = false;
            } else if (element.hasAttr('data-bind-if')) {
                bindings.push(new IfBinding(element, model));

                // Don't recurse to children -- they're handled by the binding.
                bRecurseToChildren = false;
            } else if (element.hasAttr('data-bind-with')) {
                bindings.push(new WithBinding(element, model));

                // Don't recurse to children -- they're handled by the binding.
                bRecurseToChildren = false;
            } else if (element.hasAttr('data-bind-text')) {
                bindings.push(new TextBinding(element, model));

                // Don't recurse to children -- we're going to replace the contents with the bound text.
                bRecurseToChildren = false;
            } else if (element.hasAttr('data-bind-value')) {
                bindings.push(new ValueBinding(element, model));
            } else if (element.hasAttr('data-bind-checked')) {
                bindings.push(new CheckedBinding(element, model));
            }

            // Bindings that any node can have.
            if (element.hasAttr('data-bind-options')) {
                bindings.push(new OptionsBinding(element, model));
            }
            if (element.hasAttr('data-bind-click')) {
                bindings.push(new ClickBinding(element, model));
            }
            if (element.hasAttr('data-bind-visibility')) {
                bindings.push(new VisibilityBinding(element, model));
            }
            if (element.hasAttr('data-bind-prop')) {
                bindings.push(new PropBinding(element, model));
            }
            if (element.hasAttr('data-bind-class')) {
                bindings.push(new ClassBinding(element, model));
            }

            // Only recurse to children if they're not already handled/disallowed by a binding.
            if (bRecurseToChildren) {
                appendBindings(element.children(), model, bindings);
            }
        });
    }

    var allBindings = [];

    function findBindingsIndex(modelOrElement) {
        if (modelOrElement instanceof jQuery) {
            // Look for bindings for this element
            return allBindings.findIndex(function (b) { return b.rootElement === modelOrElement; });
        } else {
            // Look for bindings for this model
            return allBindings.findIndex(function (b) { return b.model === modelOrElement; });
        }
    }

    function findBindings(modelOrElement) {
        var index = findBindingsIndex(modelOrElement);
        return (index >= 0) ? allBindings[index] : undefined;
    }

    function initBinding(rootElement, model) {

        // Check we haven't already got bindings for either this element or model.
        if (findBindings(rootElement)) {
            console.log('Bindings already initialised for element');
            return;
        }
        if (findBindings(model)) {
            console.log('Bindings already initialised for model');
            return;
        }

        // Create new bindings container and create the actual bindings for it.
        var newBindings = {
            rootElement: rootElement,
            model: model,
            bindings: []
        };
        appendBindings(rootElement, model, newBindings.bindings);

        // Add to list of all managed bindings.
        allBindings.push(newBindings);

        // Update bindings now.
        newBindings.bindings.forEach(function (binding) {
            binding.update(model);
        });
    }

    function cleanupBinding(modelOrElement) {
        var index = findBindingsIndex(modelOrElement);
        if (index >= 0) {
            allBindings.splice(index, 1);
        }
    }

    function updateBindings(modelOrElement) {
        var bindings = findBindings(modelOrElement);
        if (bindings) {
            // Update each binding.
            bindings.bindings.forEach(function (binding) {
                binding.update(bindings.model);
            });
        } else {
            console.log('Could not find bindings to update');
        }
    }

    // Module object.
    return {
        initBinding: initBinding,
        cleanupBinding: cleanupBinding,
        updateBindings: updateBindings
    };
});
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import List from 'material-ui/List';
import { withStyles } from 'material-ui/styles';
import axios from 'axios';

axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = 'X-CSRFToken';

class DailyView extends Component {
  constructor(props) {
    super(props);
    this.state = {
      error: null,
      isLoaded: false,
      data: []
    };
    // this.handleDelete = this.handleDelete.bind(this);
    // this.handleCreate = this.handleCreate.bind(this);
    // this.handleUpdate = this.handleUpdate.bind(this);
  }

  componentDidMount() {
    axios.get('/api/entries/')
      .then(
        (response) => {
          this.setState({
            isLoaded: true,
            data: response.data
          });
        },
        (error) => {
          this.setState({
            isLoaded: true,
            error
          });
        }
      );
  }

  render() {
    const { error, isLoaded, data } = this.state;
    if (error) {
      return
Error: {error.message}
;
    } else if (!isLoaded) {
      return
Loading...
;  // TODO loading icon
    } else {
      let entries = data.map(datum =>

        {datum.entry}

      );
      // TODO do I want to just put the CategoryCreator in the List?
      return (
        <List>{entries}</List>
      )
    }
  }
}

export default DailyView;
<commit_msg>DailyView base styling<commit_after>import React, {Component} from 'react';
import List from 'material-ui/List';
import { withStyles } from 'material-ui/styles';
import axios from 'axios';

axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = 'X-CSRFToken';

const styles = theme => ({
  root: {
    margin: '25px auto 0px',
    width: '100%',
    maxWidth: 720,
    backgroundColor: theme.palette.background.paper,
  },
});

class DailyView extends Component {
  constructor(props) {
    super(props);
    this.state = {
      error: null,
      isLoaded: false,
      data: []
    };
    // this.handleDelete = this.handleDelete.bind(this);
    // this.handleCreate = this.handleCreate.bind(this);
    // this.handleUpdate = this.handleUpdate.bind(this);
  }

  componentDidMount() {
    axios.get('/api/entries/')
      .then(
        (response) => {
          this.setState({
            isLoaded: true,
            data: response.data
          });
        },
        (error) => {
          this.setState({
            isLoaded: true,
            error
          });
        }
      );
  }

  render() {
    const { error, isLoaded, data } = this.state;
    if (error) {
      return
Error: {error.message}
;
    } else if (!isLoaded) {
      return
Loading...
;  // TODO loading icon
    } else {
      let entries = data.map(datum =>

        {datum.entry}

      );
      // TODO do I want to just put the CategoryCreator in the List?
      return (

          <List>{entries}</List>

      )
    }
  }
}

export default withStyles(styles)(DailyView);
<|endoftext|>


<commit_before>var validateCreateForm = function (formObject) {
	var error = false;
	var therapyNameString = formObject["name"];
	var therapyDuration = formObject["default-duration"];
	var therapyTracerDose = formObject["tracer-dose"];

	// Check range to be [1,64]
	if (therapyNameString.trim().length < 1) {
		toastr.error("Please enter a valid name for the therapy.");
		error = true;
	}
	if (therapyNameString.length > 64) {
		toastr.error("Therapy name should not exceed 64 characters.");
		error = true;
	}

	// Check if the duration represents a number and is in integer range
	if ($.isNumeric(therapyDuration) == false) {
		toastr.error("Please enter a valid value for the duration of the therapy. Expecting a number.");
		error = true;
	} else {
		if (therapyDuration > 2147483647 || therapyDuration < 0) {
			toastr.error("Therapy duration should be a positive number smaller than 2,147,483,647");
			error = true;
		}
	}

	// dose
	if (therapyTracerDose.trim().length < 1) {
		toastr.error("Please enter a valid value for the tracer dose.");
		error = true;
	}
	if (therapyTracerDose.length > 32) {
		toastr.error("Tracer dose should not exceed 32 characters.");
		error = true;
	}

	//loop through patient questions
	for (var fieldName in formObject) {
		if (fieldName.indexOf('patient-question') > -1) {
			var patientQuestion = formObject[fieldName];

			//check range [<256]
			if (patientQuestion.length > 256) {
				toastr.error("Patient questions should not exceed 256 characters.");
				error = true;
			}

		}
	}

	return !error;
};

var validateEditForm = function (formObject) {
	var error = false;

	var therapyNameString = formObject["name"];
	var therapyDuration = formObject["default-duration"];
	var therapyTracerDose = formObject["tracer-dose"];

	// Check range to be [1,64]
	if (therapyNameString.trim().length < 1) {
		toastr.error("Please enter a valid name for the therapy.");
		error = true;
	}
	if (therapyNameString.trim().length > 64) {
		toastr.error("Therapy name should not exceed 64 characters.");
		error = true;
	}

	// Check if the duration represents a number and is in integer range
	if ($.isNumeric(therapyDuration) == false) {
		toastr.error("Please enter a valid value for the duration of the therapy. Expecting a number.");
		error = true;
	} else {
		if (therapyDuration > 2147483647 || therapyDuration < 0) {
			toastr.error("Therapy duration should be a positive number smaller than 2,147,483,647");
			error = true;
		}
	}

	//TODO therapyTracerRequired. Ask the client;

	if (therapyTracerDose.trim().length < 1) {
		toastr.error("Please enter a valid value for the tracer dose.");
		error = true;
	}
	if (therapyTracerDose.trim().length > 32) {
		toastr.error("Tracer dose should not exceed 32 characters.");
		error = true;
	}

	//loop through patient questions
	for (var fieldName in formObject) {
		if (fieldName.indexOf('patient-question') > -1) {
			var patientQuestion = formObject[fieldName];

			//check range [<256]
			if (patientQuestion.length > 256) {
				toastr.error("Patient questions should not exceed 256 characters.");
				error = true;
			}
		}
	}

	return !error;
};

$(document).ready(function () {
	setUpDataTable('#therapies-table', 0, [[1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [0, 0]]);

	$('.add-question').click(function () {
		var targetDiv = $('.patient-questions');
		var children = targetDiv.children('input').length;
		targetDiv.append('
<input class="form-control" type="text" name="patient-question-' + children + '" placeholder="Leave blank if not required."/>');
	});
});

customFieldPrefill = function (key, data) {
	var output = '';
	if (key.substr(7) == 'patient-questions') {
		for (var i in data) {
			output += (output == '' ? '' : '
') + '<input class="form-control patient-question-input" type="text" name="patient-question-' + i + '" placeholder="Leave blank if not required." value="' + data[i] + '"/>'
		}
	}
	return output;
};<commit_msg>empty patient question box when none are set<commit_after>var validateCreateForm = function (formObject) {
	var error = false;
	var therapyNameString = formObject["name"];
	var therapyDuration = formObject["default-duration"];
	var therapyTracerDose = formObject["tracer-dose"];

	// Check range to be [1,64]
	if (therapyNameString.trim().length < 1) {
		toastr.error("Please enter a valid name for the therapy.");
		error = true;
	}
	if (therapyNameString.length > 64) {
		toastr.error("Therapy name should not exceed 64 characters.");
		error = true;
	}

	// Check if the duration represents a number and is in integer range
	if ($.isNumeric(therapyDuration) == false) {
		toastr.error("Please enter a valid value for the duration of the therapy. Expecting a number.");
		error = true;
	} else {
		if (therapyDuration > 2147483647 || therapyDuration < 0) {
			toastr.error("Therapy duration should be a positive number smaller than 2,147,483,647");
			error = true;
		}
	}

	// dose
	if (therapyTracerDose.trim().length < 1) {
		toastr.error("Please enter a valid value for the tracer dose.");
		error = true;
	}
	if (therapyTracerDose.length > 32) {
		toastr.error("Tracer dose should not exceed 32 characters.");
		error = true;
	}

	//loop through patient questions
	for (var fieldName in formObject) {
		if (fieldName.indexOf('patient-question') > -1) {
			var patientQuestion = formObject[fieldName];

			//check range [<256]
			if (patientQuestion.length > 256) {
				toastr.error("Patient questions should not exceed 256 characters.");
				error = true;
			}

		}
	}

	return !error;
};

var validateEditForm = function (formObject) {
	var error = false;

	var therapyNameString = formObject["name"];
	var therapyDuration = formObject["default-duration"];
	var therapyTracerDose = formObject["tracer-dose"];

	// Check range to be [1,64]
	if (therapyNameString.trim().length < 1) {
		toastr.error("Please enter a valid name for the therapy.");
		error = true;
	}
	if (therapyNameString.trim().length > 64) {
		toastr.error("Therapy name should not exceed 64 characters.");
		error = true;
	}

	// Check if the duration represents a number and is in integer range
	if ($.isNumeric(therapyDuration) == false) {
		toastr.error("Please enter a valid value for the duration of the therapy. Expecting a number.");
		error = true;
	} else {
		if (therapyDuration > 2147483647 || therapyDuration < 0) {
			toastr.error("Therapy duration should be a positive number smaller than 2,147,483,647");
			error = true;
		}
	}

	//TODO therapyTracerRequired. Ask the client;

	if (therapyTracerDose.trim().length < 1) {
		toastr.error("Please enter a valid value for the tracer dose.");
		error = true;
	}
	if (therapyTracerDose.trim().length > 32) {
		toastr.error("Tracer dose should not exceed 32 characters.");
		error = true;
	}

	//loop through patient questions
	for (var fieldName in formObject) {
		if (fieldName.indexOf('patient-question') > -1) {
			var patientQuestion = formObject[fieldName];

			//check range [<256]
			if (patientQuestion.length > 256) {
				toastr.error("Patient questions should not exceed 256 characters.");
				error = true;
			}
		}
	}

	return !error;
};

$(document).ready(function () {
	setUpDataTable('#therapies-table', 0, [[1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [0, 0]]);

	$('.add-question').click(function () {
		var targetDiv = $('.patient-questions');
		var children = targetDiv.children('input').length;
		targetDiv.append('
<input class="form-control" type="text" name="patient-question-' + children + '" placeholder="Leave blank if not required."/>');
	});
});

customFieldPrefill = function (key, data) {
	if (data == null || data.length == 0) {
		return '<input class="form-control patient-question-input" type="text" name="patient-question-0" placeholder="Leave blank if not required."/>';
	}

	var output = '';
	if (key.substr(7) == 'patient-questions') {
		for (var i in data) {
			output += (output == '' ? '' : '
') + '<input class="form-control patient-question-input" type="text" name="patient-question-' + i + '" placeholder="Leave blank if not required." value="' + data[i] + '"/>'
		}
	}
	return output;
};<|endoftext|>


<commit_before>/**
 * Created by edgilmore on 11/5/2015.
 */
'use strict';
function truncate(str, num) {
    // Clear out that junk in your trunk
    var elipse = '...';
    var oStringLen = str.length;
    if(str.length > num){
        if(num > 3){
            str = str.slice(str, num -3);
            str += elipse;
        }
        else{
            str = str.slice(str, num);
            str += elipse;
        }
    }
    console.log(str, oStringLen, num);
    return str;
}

truncate("Absolutely Longer", 2);<commit_msg>Added a comment.<commit_after>/**
 * Created by edgilmore on 11/5/2015.
 */
'use strict';
function truncate(str, num) {
    // Clear out that junk in your trunk
    var elipse = '...';
    var oStringLen = str.length;
    if(str.length > num){
        if(num > 3){
            str = str.slice(str, num -3);
            str += elipse;
        }
        else{
            str = str.slice(str, num);
            str += elipse;
        }
    }
    console.log(str, oStringLen, num);
    return str;
}

truncate("Absolutely Longer", 2);

//added a string to get credit for my commit.<|endoftext|>


<commit_before>import { React, PropTypes, styled, observer } from 'vendor';
import Router from '../../../helpers/router';
import { Modal, Button } from 'react-bootstrap';
import { Formik } from 'formik';
import UX from '../ux';
import CloneModal from 'components/course-modal';
import { colors, breakpoints } from 'theme';

const StyledTemplateModal = styled(CloneModal)`
  .modal-dialog {
    margin-top: 3rem;
    max-width: 90%;
  }

  .modal-body {
    background: ${colors.white};
    padding: 0 1rem;
  }

  &&& {
    .modal-footer {
      border-top: 2px solid ${colors.neutral.pale};
      background-color: ${colors.neutral.bright};
      padding: 1rem 2rem;
      display: flex;
      justify-content: space-between;

      /* Cancel buttons */
      & div:first-child {
        .btn {
          background: white;
        }
      }
      /* Save as Draft, Publish, and Edit other details buttons */
      & div:last-child {
        .btn:not(:last-child) {
          background: ${colors.neutral.lite};
          border: 1px solid ${colors.neutral.lite};
        }
      }
    }
  }

  @media ${breakpoints.xlUp} {
  .modal-dialog {
    max-width: 65%;
  }
}
`;

const WrqNote = styled.div`
  padding: 0 1rem;
  ul {
    padding: 0 1.5rem;
    color: ${colors.neutral.dark};
  }
`;

@observer
class Editor extends React.Component {

  static propTypes = {
    ux: PropTypes.instanceOf(UX).isRequired,
    showModal: PropTypes.bool.isRequired,
    onHide: PropTypes.func.isRequired,
  }

  async saveDraft() {
    const { ux: { saveAsDraft }, onHide } = this.props;
    await saveAsDraft();
    onHide();
  }

  async publish() {
    const { ux: { savePlan }, onHide } = this.props;
    await savePlan();
    onHide();
  }

  async editDetails() {
    const { ux: { saveAsDraft, navigateToStep } } = this.props;
    await saveAsDraft();
    navigateToStep('details');
  }

  onCancel() {
    this.props.onHide();
  }

  render() {
    const { ux, showModal, onHide } = this.props;
    return (

    );
  }
}
export default Editor;
<commit_msg>deleting unused code<commit_after>import { React, PropTypes, styled, observer } from 'vendor';
import { Modal, Button } from 'react-bootstrap';
import { Formik } from 'formik';
import UX from '../ux';
import CloneModal from 'components/course-modal';
import { colors, breakpoints } from 'theme';

const StyledTemplateModal = styled(CloneModal)`
  .modal-dialog {
    margin-top: 3rem;
    max-width: 90%;
  }

  .modal-body {
    background: ${colors.white};
    padding: 0 1rem;
  }

  &&& {
    .modal-footer {
      border-top: 2px solid ${colors.neutral.pale};
      background-color: ${colors.neutral.bright};
      padding: 1rem 2rem;
      display: flex;
      justify-content: space-between;

      /* Cancel buttons */
      & div:first-child {
        .btn {
          background: white;
        }
      }
      /* Save as Draft, Publish, and Edit other details buttons */
      & div:last-child {
        .btn:not(:last-child) {
          background: ${colors.neutral.lite};
          border: 1px solid ${colors.neutral.lite};
        }
      }
    }
  }

  @media ${breakpoints.xlUp} {
  .modal-dialog {
    max-width: 65%;
  }
}
`;

const WrqNote = styled.div`
  padding: 0 1rem;
  ul {
    padding: 0 1.5rem;
    color: ${colors.neutral.dark};
  }
`;

@observer
class Editor extends React.Component {

  static propTypes = {
    ux: PropTypes.instanceOf(UX).isRequired,
    showModal: PropTypes.bool.isRequired,
    onHide: PropTypes.func.isRequired,
  }

  async saveDraft() {
    const { ux: { saveAsDraft }, onHide } = this.props;
    await saveAsDraft();
    onHide();
  }

  async publish() {
    const { ux: { savePlan }, onHide } = this.props;
    await savePlan();
    onHide();
  }

  async editDetails() {
    const { ux: { saveAsDraft, navigateToStep } } = this.props;
    await saveAsDraft();
    navigateToStep('details');
  }

  onCancel() {
    this.props.onHide();
  }

  render() {
    const { ux, showModal, onHide } = this.props;
    return (

    );
  }
}
export default Editor;
<|endoftext|>


<commit_before>import React, {PropTypes, Component} from 'react'
import _ from 'lodash'
import classNames from 'classnames'

import Dropdown from 'src/shared/components/Dropdown'
import LoadingDots from 'src/shared/components/LoadingDots'
import TemplateDrawer from 'src/shared/components/TemplateDrawer'
import {QUERY_TEMPLATES} from 'src/data_explorer/constants'
import {TEMPLATE_MATCHER} from 'src/dashboards/constants'

class RawQueryEditor extends Component {
  constructor(props) {
    super(props)
    this.state = {
      value: this.props.query,
      isTemplating: false,
      selectedTempVar: {
        tempVar: '',
      },
    }

    this.handleKeyDown = ::this.handleKeyDown
    this.handleChange = ::this.handleChange
    this.handleUpdate = ::this.handleUpdate
    this.handleChooseTemplate = ::this.handleChooseTemplate
    this.handleCloseDrawer = ::this.handleCloseDrawer
    this.findTempVar = ::this.findTempVar
    this.handleTemplateReplace = ::this.handleTemplateReplace
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.query !== nextProps.query) {
      this.setState({value: nextProps.query})
    }
  }

  handleCloseDrawer() {
    this.setState({isTemplating: false})
  }

  handleKeyDown(e) {
    const {isTemplating, value} = this.state

    if (isTemplating) {
      if (e.key === ('ArrowRight' || 'ArrowDown')) {
        e.preventDefault()

        this.handleTemplateReplace('next')
      }

      if (e.key === ('ArrowLeft' || 'ArrowUp')) {
        e.preventDefault()
        this.handleTemplateReplace('previous')
      }

      if (e.key === 'Enter') {
        e.preventDefault()
        const start = this.editor.selectionStart
        const end = this.editor.selectionEnd
        this.editor.setSelectionRange(start, end)
      }
    } else if (e.key === 'Escape') {
      e.preventDefault()
      this.setState({value, isTemplating: false})
    } else if (e.key === 'Enter') {
      this.handleUpdate()
    }
  }

  handleTemplateReplace(direction) {
    const {selectionStart, value} = this.editor
    const selectedTempVar = this.findTempVar(direction)

    let templatedValue
    const matched = value.match(TEMPLATE_MATCHER)
    if (matched) {
      templatedValue = value.replace(
        TEMPLATE_MATCHER,
        `:${selectedTempVar.tempVar}`
      )
    }

    // debugger
    const diffInLength = selectedTempVar.tempVar.length - matched[0].length
    // console.log(diffInLength)

    this.setState({value: templatedValue, selectedTempVar}, () =>
      this.editor.setSelectionRange(
        selectionStart + diffInLength + 1,
        selectionStart + diffInLength + 1
      )
    )
  }

  findTempVar(direction) {
    const {templates} = this.props
    const {selectedTempVar} = this.state

    const i = _.findIndex(templates, selectedTempVar)
    const lastIndex = templates.length - 1

    if (i >= 0) {
      if (direction === 'next') {
        if (i === lastIndex) {
          return templates[0]
        }
        return templates[i + 1]
      }

      if (direction === 'previous') {
        if (i === 0) {
          return templates[lastIndex]
        }
        return templates[i - 1]
      }
    }

    return templates[0]
  }

  handleChange() {
    const value = this.editor.value

    if (value.match(TEMPLATE_MATCHER)) {
      // maintain cursor poition
      const start = this.editor.selectionStart
      const end = this.editor.selectionEnd
      this.setState({isTemplating: true, value})
      this.editor.setSelectionRange(start, end)
    } else {
      this.setState({isTemplating: false, value})
    }
  }

  handleUpdate() {
    this.props.onUpdate(this.state.value)
  }

  handleChooseTemplate(template) {
    this.setState({value: template.query})
  }

  handleSelectTempVar(tempVar) {
    this.setState({selectedTempVar: tempVar})
  }

  render() {
    const {config: {status}, templates} = this.props
    const {value, isTemplating, selectedTempVar} = this.state

    return (

        {isTemplating
          ? <TemplateDrawer
              templates={templates}
              selected={selectedTempVar}
              handleClickOutside={this.handleCloseDrawer}
            />
          : null}
        <textarea
          className="raw-text--field"
          onChange={this.handleChange}
          onKeyDown={this.handleKeyDown}
          onBlur={this.handleUpdate}
          ref={editor => (this.editor = editor)}
          value={value}
          placeholder="Enter a query or select database, measurement, and field below and have us build one for you..."
          autoComplete="off"
          spellCheck="false"
        />
        {this.renderStatus(status)}
        <Dropdown
          items={QUERY_TEMPLATES}
          selected={'Query Templates'}
          onChoose={this.handleChooseTemplate}
          className="query-template"
        />

    )
  }

  renderStatus(status) {
    if (!status) {
      return

    }

    if (status.loading) {
      return (

          <LoadingDots />

      )
    }

    return (

        {status.error || status.warn || status.success}

    )
  }
}

const {arrayOf, func, shape, string} = PropTypes

RawQueryEditor.propTypes = {
  query: string.isRequired,
  onUpdate: func.isRequired,
  config: shape().isRequired,
  templates: arrayOf(
    shape({
      tempVar: string.isRequired,
    })
  ).isRequired,
}

export default RawQueryEditor
<commit_msg>Make selecting tempVar func better<commit_after>import React, {PropTypes, Component} from 'react'
import _ from 'lodash'
import classNames from 'classnames'

import Dropdown from 'src/shared/components/Dropdown'
import LoadingDots from 'src/shared/components/LoadingDots'
import TemplateDrawer from 'src/shared/components/TemplateDrawer'
import {QUERY_TEMPLATES} from 'src/data_explorer/constants'
import {TEMPLATE_MATCHER} from 'src/dashboards/constants'

class RawQueryEditor extends Component {
  constructor(props) {
    super(props)
    this.state = {
      value: this.props.query,
      isTemplating: false,
      selectedTempVar: {
        tempVar: '',
      },
    }

    this.handleKeyDown = ::this.handleKeyDown
    this.handleChange = ::this.handleChange
    this.handleUpdate = ::this.handleUpdate
    this.handleChooseTemplate = ::this.handleChooseTemplate
    this.handleCloseDrawer = ::this.handleCloseDrawer
    this.findTempVar = ::this.findTempVar
    this.handleTemplateReplace = ::this.handleTemplateReplace
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.query !== nextProps.query) {
      this.setState({value: nextProps.query})
    }
  }

  handleCloseDrawer() {
    this.setState({isTemplating: false})
  }

  handleKeyDown(e) {
    const {isTemplating, value} = this.state

    if (isTemplating) {
      if (e.key === ('ArrowRight' || 'ArrowDown')) {
        e.preventDefault()

        this.handleTemplateReplace('next')
      }

      if (e.key === ('ArrowLeft' || 'ArrowUp')) {
        e.preventDefault()
        this.handleTemplateReplace('previous')
      }

      if (e.key === 'Enter') {
        e.preventDefault()
        const start = this.editor.selectionStart
        const end = this.editor.selectionEnd
        this.editor.setSelectionRange(start, end)
      }
    } else if (e.key === 'Escape') {
      e.preventDefault()
      this.setState({value, isTemplating: false})
    } else if (e.key === 'Enter') {
      this.handleUpdate()
    }
  }

  handleTemplateReplace(direction) {
    const {selectionStart, value} = this.editor
    const selectedTempVar = this.findTempVar(direction)

    let templatedValue
    const matched = value.match(TEMPLATE_MATCHER)
    if (matched) {
      templatedValue = value.replace(
        TEMPLATE_MATCHER,
        `:${selectedTempVar.tempVar}`
      )
    }

    // debugger
    const diffInLength = selectedTempVar.tempVar.length - matched[0].length
    // console.log(diffInLength)

    this.setState({value: templatedValue, selectedTempVar}, () =>
      this.editor.setSelectionRange(
        selectionStart + diffInLength + 1,
        selectionStart + diffInLength + 1
      )
    )
  }

  findTempVar(direction) {
    const {templates} = this.props
    const {selectedTempVar} = this.state

    const i = _.findIndex(templates, selectedTempVar)
    const lastIndex = templates.length - 1

    if (i >= 0) {
      if (direction === 'next') {
        return templates[(i + 1) % templates.length]
      }

      if (direction === 'previous') {
        if (i === 0) {
          return templates[lastIndex]
        }

        return templates[i - 1]
      }
    }

    return templates[0]
  }

  handleChange() {
    const value = this.editor.value

    if (value.match(TEMPLATE_MATCHER)) {
      // maintain cursor poition
      const start = this.editor.selectionStart
      const end = this.editor.selectionEnd
      this.setState({isTemplating: true, value})
      this.editor.setSelectionRange(start, end)
    } else {
      this.setState({isTemplating: false, value})
    }
  }

  handleUpdate() {
    this.props.onUpdate(this.state.value)
  }

  handleChooseTemplate(template) {
    this.setState({value: template.query})
  }

  handleSelectTempVar(tempVar) {
    this.setState({selectedTempVar: tempVar})
  }

  render() {
    const {config: {status}, templates} = this.props
    const {value, isTemplating, selectedTempVar} = this.state

    return (

        {isTemplating
          ? <TemplateDrawer
              templates={templates}
              selected={selectedTempVar}
              handleClickOutside={this.handleCloseDrawer}
            />
          : null}
        <textarea
          className="raw-text--field"
          onChange={this.handleChange}
          onKeyDown={this.handleKeyDown}
          onBlur={this.handleUpdate}
          ref={editor => (this.editor = editor)}
          value={value}
          placeholder="Enter a query or select database, measurement, and field below and have us build one for you..."
          autoComplete="off"
          spellCheck="false"
        />
        {this.renderStatus(status)}
        <Dropdown
          items={QUERY_TEMPLATES}
          selected={'Query Templates'}
          onChoose={this.handleChooseTemplate}
          className="query-template"
        />

    )
  }

  renderStatus(status) {
    if (!status) {
      return

    }

    if (status.loading) {
      return (

          <LoadingDots />

      )
    }

    return (

        {status.error || status.warn || status.success}

    )
  }
}

const {arrayOf, func, shape, string} = PropTypes

RawQueryEditor.propTypes = {
  query: string.isRequired,
  onUpdate: func.isRequired,
  config: shape().isRequired,
  templates: arrayOf(
    shape({
      tempVar: string.isRequired,
    })
  ).isRequired,
}

export default RawQueryEditor
<|endoftext|>


<commit_before>import React, {Component} from 'react';

import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';
import Crumbs from 'src/Crumbs';

import PropTypeDescTable from '../PropTypeDescTable';
import CrumbsDoc from 'assets/propTypes/Crumbs.json';

import 'sass/containers/app/modules/layout/CrumbsExamples.scss';

export default class CrumbsExamples extends Component {

    constructor(props) {

        super(props);

        this.items = [{
            text: 'Root',
            route: '/'
        }, {
            text: 'Components',
            route: '/components'
        }, {
            text: 'Crumbs',
            route: '/components/Crumbs'
        }];

    }

    render() {
        return (

Crumbs

                    A Crumbs element.

Examples

                <Widget>

                    <WidgetHeader className="example-header" title="Crumbs Example"/>

                                <Crumbs items={this.items}/>

                </Widget>

Properties

                <PropTypeDescTable data={CrumbsDoc}/>

        );
    }
};<commit_msg>update Crumbs examples<commit_after>import React, {Component} from 'react';

import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';
import Crumbs from 'src/Crumbs';

import PropTypeDescTable from '../PropTypeDescTable';
import CrumbsDoc from 'assets/propTypes/Crumbs.json';

import 'sass/containers/app/modules/layout/CrumbsExamples.scss';

export default class CrumbsExamples extends Component {

    constructor(props) {

        super(props);

        this.items = [{
            text: 'Root',
            route: '/#/'
        }, {
            text: 'Landing',
            route: '/#/landing'
        }, {
            text: 'Crumbs',
            route: '/#/components/Crumbs'
        }];

    }

    render() {
        return (

Crumbs

                    A Crumbs element.

Examples

                <Widget>

                    <WidgetHeader className="example-header" title="Crumbs Example"/>

                                <Crumbs items={this.items}/>

                </Widget>

Properties

                <PropTypeDescTable data={CrumbsDoc}/>

        );
    }
};<|endoftext|>


<commit_before>// Ensure that jsinterop @defines are included.
/** @suppress {extraRequire} */
let jsinterop = goog.require('jsinterop');
<commit_msg>Module import should be constant.<commit_after>// Ensure that jsinterop @defines are included.
/** @suppress {extraRequire} */
const jsinterop = goog.require('jsinterop');
<|endoftext|>


<commit_before>'use strict';

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Alan Plum
////////////////////////////////////////////////////////////////////////////////

const _ = require('lodash');
const fs = require('fs');
const vary = require('vary');
const httperr = require('http-errors');
const statuses = require('statuses');
const mediaTyper = require('media-typer');
const mimeTypes = require('mime-types');
const typeIs = require('type-is');
const contentDisposition = require('content-disposition');
const actions = require('@arangodb/actions');
const crypto = require('@arangodb/crypto');

const MIME_BINARY = 'application/octet-stream';
const MIME_JSON = 'application/json; charset=utf-8';

module.exports = class SyntheticResponse {
  constructor(res, context) {
    this._raw = res;
    this._responses = new Map();
    this.context = context;
  }

  // Node compat

  get headers() {
    if (!this._raw.headers) {
      this._raw.headers = {};
    }
    return this._raw.headers;
  }

  get statusCode() {
    return this._raw.responseCode;
  }

  set statusCode(value) {
    this._raw.responseCode = value;
  }

  get body() {
    return this._raw.body;
  }

  set body(data) {
    if (data === null || data === undefined) {
      delete this._raw.body;
      return;
    }
    if (typeof data === 'string' || data instanceof Buffer) {
      this._raw.body = data;
    } else if (typeof data === 'object') {
      this._raw.body = JSON.stringify(data);
    } else {
      this._raw.body = String(data);
    }
  }

  getHeader(name) {
    name = name.toLowerCase();
    if (name === 'content-type') {
      return this._raw.contentType;
    }
    return this.headers[name];
  }

  removeHeader(name) {
    name = name.toLowerCase();
    if (name === 'content-type') {
      delete this._raw.contentType;
    }
    delete this.headers[name];
    return this;
  }

  setHeader(name, value) {
    if (!name) {
      return this;
    }
    name = name.toLowerCase();
    if (name === 'content-type') {
      this._raw.contentType = value;
    } else {
      this.headers[name] = value;
    }
    return this;
  }

  write(data) {
    const bodyIsBuffer = this._raw.body instanceof Buffer;
    const dataIsBuffer = data instanceof Buffer;
    if (data === null || data === undefined) {
      return this;
    }
    if (!dataIsBuffer) {
      if (typeof data === 'object') {
        data = JSON.stringify(data);
      } else {
        data = String(data);
      }
    }
    if (!this._raw.body) {
      this._raw.body = data;
    } else if (bodyIsBuffer || dataIsBuffer) {
      this._raw.body = Buffer.concat([
        bodyIsBuffer ? this._raw.body : new Buffer(this._raw.body),
        dataIsBuffer ? data : new Buffer(data)
      ]);
    } else {
      this._raw.body += data;
    }
    return this;
  }

  // Express compat

  attachment(filename) {
    this.headers['content-disposition'] = contentDisposition(filename);
    if (filename && !this._raw.contentType) {
      this._raw.contentType = mimeTypes.lookup(filename) || MIME_BINARY;
    }
    return this;
  }

  download(path, filename) {
    this.attachment(filename || path);
    this.sendFile(path);
    return this;
  }

  json(value) {
    if (!this._raw.contentType) {
      this._raw.contentType = MIME_JSON;
    }
    if (this.context.isDevelopment) {
      this._raw.body = JSON.stringify(value, null, 2);
    } else {
      this._raw.body = JSON.stringify(value);
    }
    return this;
  }

  redirect(status, path) {
    if (!path) {
      path = status;
      status = undefined;
    }
    if (status === 'permanent') {
      status = 301;
    }
    if (status || !this.statusCode) {
      this.statusCode = status || 302;
    }
    this.setHeader('location', path);
    return this;
  }

  sendFile(filename, opts) {
    if (typeof opts === 'boolean') {
      opts = {lastModified: opts};
    }
    if (!opts) {
      opts = {};
    }
    this._raw.body = fs.readBuffer(filename);
    if (opts.lastModified || (
      opts.lastModified !== false && !this.headers['last-modified']
    )) {
      const lastModified = new Date(fs.mtime(filename) * 1000);
      this.headers['last-modified'] = lastModified.toUTCString();
    }
    if (!this._raw.contentType) {
      this._raw.contentType = mimeTypes.lookup(filename) || MIME_BINARY;
    }
    return this;
  }

  sendStatus(status) {
    if (typeof status === 'string') {
      status = statuses(status);
    }
    const message = String(statuses[status] || status);
    this.statusCode = status;
    this.body = message;
    return this;
  }

  set(name, value) {
    if (name && typeof name === 'object') {
      _.each(name, function (v, k) {
        this.set(k, v);
      }, this);
    } else {
      this.setHeader(name, value);
    }
    return this;
  }

  status(statusCode) {
    if (typeof statusCode === 'string') {
      statusCode = statuses(statusCode);
    }
    this.statusCode = statusCode;
    return this;
  }

  vary(value) {
    const header = this.getHeader('vary');
    if (header) {
      value = vary.append(header, value);
    }
    this.setHeader('vary', value);
    return this;
  }

  // idiosyncratic

  cookie(name, value, opts) {
    if (!opts) {
      opts = {};
    } else if (typeof opts === 'string') {
      opts = {secret: opts};
    } else if (typeof opts === 'number') {
      opts = {ttl: opts};
    }
    const ttl = (
      (typeof opts.ttl === 'number' && opts.ttl !== Infinity)
      ? opts.ttl
      : undefined
    );
    actions.addCookie(
      this._raw,
      name,
      value,
      ttl,
      opts.path,
      opts.domain,
      opts.secure,
      opts.httpOnly
    );
    if (opts.secret) {
      const signature = crypto.hmac(opts.secret, value, opts.algorithm);
      actions.addCookie(
        this._raw,
        `${name}.sig`,
        signature,
        ttl,
        opts.path,
        opts.domain,
        opts.secure,
        opts.httpOnly
      );
    }
    return this;
  }

  throw(status, reason, args) {
    if (typeof status === 'string') {
      status = statuses(status);
    }
    if (reason && typeof reason === 'object') {
      args = reason;
      reason = undefined;
    }
    throw Object.assign(
      httperr(status, reason),
      {statusCode: status, status},
      args
    );
  }

  send(body, type) {
    if (body && body.isArangoResultSet) {
      body = body.toArray();
    }

    if (!type) {
      type = 'auto';
    }

    let contentType;
    const status = this.statusCode || 200;
    const response = this._responses.get(status);

    if (response) {
      if (response.model && response.model.forClient) {
        if (response.multiple && Array.isArray(body)) {
          body = body.map(function (item) {
            return response.model.forClient(item);
          });
        } else {
          body = response.model.forClient(body);
        }
      }
      if (type === 'auto' && response.contentTypes) {
        type = response.contentTypes[0];
        contentType = type;
      }
    }

    if (type === 'auto') {
      if (body instanceof Buffer) {
        type = MIME_BINARY;
      } else if (body && typeof body === 'object') {
        type = 'json';
      } else {
        type = 'html';
      }
    }

    type = mimeTypes.lookup(type) || type;

    let handler;
    for (const entry of this.context.service.types.entries()) {
      const key = entry[0];
      const value = entry[1];
      let match;
      if (key instanceof RegExp) {
        match = type.test(key);
      } else if (typeof key === 'function') {
        match = key(type);
      } else {
        match = typeIs.is(key, type);
      }
      if (match && value.forClient) {
        contentType = key;
        handler = value;
        break;
      }
    }

    if (handler) {
      const result = handler.forClient(body, this, mediaTyper.parse(contentType));
      if (result.headers || result.data) {
        contentType = result.headers['content-type'] || contentType;
        this.set(result.headers);
        body = result.data;
      } else {
        body = result;
      }
    }

    this._raw.body = body;
    this._raw.contentType = contentType || this._raw.contentType;

    return this;
  }
};
<commit_msg>Allow passing an error to res.throw as reason<commit_after>'use strict';

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Alan Plum
////////////////////////////////////////////////////////////////////////////////

const _ = require('lodash');
const fs = require('fs');
const vary = require('vary');
const httperr = require('http-errors');
const statuses = require('statuses');
const mediaTyper = require('media-typer');
const mimeTypes = require('mime-types');
const typeIs = require('type-is');
const contentDisposition = require('content-disposition');
const actions = require('@arangodb/actions');
const crypto = require('@arangodb/crypto');

const MIME_BINARY = 'application/octet-stream';
const MIME_JSON = 'application/json; charset=utf-8';

module.exports = class SyntheticResponse {
  constructor(res, context) {
    this._raw = res;
    this._responses = new Map();
    this.context = context;
  }

  // Node compat

  get headers() {
    if (!this._raw.headers) {
      this._raw.headers = {};
    }
    return this._raw.headers;
  }

  get statusCode() {
    return this._raw.responseCode;
  }

  set statusCode(value) {
    this._raw.responseCode = value;
  }

  get body() {
    return this._raw.body;
  }

  set body(data) {
    if (data === null || data === undefined) {
      delete this._raw.body;
      return;
    }
    if (typeof data === 'string' || data instanceof Buffer) {
      this._raw.body = data;
    } else if (typeof data === 'object') {
      this._raw.body = JSON.stringify(data);
    } else {
      this._raw.body = String(data);
    }
  }

  getHeader(name) {
    name = name.toLowerCase();
    if (name === 'content-type') {
      return this._raw.contentType;
    }
    return this.headers[name];
  }

  removeHeader(name) {
    name = name.toLowerCase();
    if (name === 'content-type') {
      delete this._raw.contentType;
    }
    delete this.headers[name];
    return this;
  }

  setHeader(name, value) {
    if (!name) {
      return this;
    }
    name = name.toLowerCase();
    if (name === 'content-type') {
      this._raw.contentType = value;
    } else {
      this.headers[name] = value;
    }
    return this;
  }

  write(data) {
    const bodyIsBuffer = this._raw.body instanceof Buffer;
    const dataIsBuffer = data instanceof Buffer;
    if (data === null || data === undefined) {
      return this;
    }
    if (!dataIsBuffer) {
      if (typeof data === 'object') {
        data = JSON.stringify(data);
      } else {
        data = String(data);
      }
    }
    if (!this._raw.body) {
      this._raw.body = data;
    } else if (bodyIsBuffer || dataIsBuffer) {
      this._raw.body = Buffer.concat([
        bodyIsBuffer ? this._raw.body : new Buffer(this._raw.body),
        dataIsBuffer ? data : new Buffer(data)
      ]);
    } else {
      this._raw.body += data;
    }
    return this;
  }

  // Express compat

  attachment(filename) {
    this.headers['content-disposition'] = contentDisposition(filename);
    if (filename && !this._raw.contentType) {
      this._raw.contentType = mimeTypes.lookup(filename) || MIME_BINARY;
    }
    return this;
  }

  download(path, filename) {
    this.attachment(filename || path);
    this.sendFile(path);
    return this;
  }

  json(value) {
    if (!this._raw.contentType) {
      this._raw.contentType = MIME_JSON;
    }
    if (this.context.isDevelopment) {
      this._raw.body = JSON.stringify(value, null, 2);
    } else {
      this._raw.body = JSON.stringify(value);
    }
    return this;
  }

  redirect(status, path) {
    if (!path) {
      path = status;
      status = undefined;
    }
    if (status === 'permanent') {
      status = 301;
    }
    if (status || !this.statusCode) {
      this.statusCode = status || 302;
    }
    this.setHeader('location', path);
    return this;
  }

  sendFile(filename, opts) {
    if (typeof opts === 'boolean') {
      opts = {lastModified: opts};
    }
    if (!opts) {
      opts = {};
    }
    this._raw.body = fs.readBuffer(filename);
    if (opts.lastModified || (
      opts.lastModified !== false && !this.headers['last-modified']
    )) {
      const lastModified = new Date(fs.mtime(filename) * 1000);
      this.headers['last-modified'] = lastModified.toUTCString();
    }
    if (!this._raw.contentType) {
      this._raw.contentType = mimeTypes.lookup(filename) || MIME_BINARY;
    }
    return this;
  }

  sendStatus(status) {
    if (typeof status === 'string') {
      status = statuses(status);
    }
    const message = String(statuses[status] || status);
    this.statusCode = status;
    this.body = message;
    return this;
  }

  set(name, value) {
    if (name && typeof name === 'object') {
      _.each(name, function (v, k) {
        this.set(k, v);
      }, this);
    } else {
      this.setHeader(name, value);
    }
    return this;
  }

  status(statusCode) {
    if (typeof statusCode === 'string') {
      statusCode = statuses(statusCode);
    }
    this.statusCode = statusCode;
    return this;
  }

  vary(value) {
    const header = this.getHeader('vary');
    if (header) {
      value = vary.append(header, value);
    }
    this.setHeader('vary', value);
    return this;
  }

  // idiosyncratic

  cookie(name, value, opts) {
    if (!opts) {
      opts = {};
    } else if (typeof opts === 'string') {
      opts = {secret: opts};
    } else if (typeof opts === 'number') {
      opts = {ttl: opts};
    }
    const ttl = (
      (typeof opts.ttl === 'number' && opts.ttl !== Infinity)
      ? opts.ttl
      : undefined
    );
    actions.addCookie(
      this._raw,
      name,
      value,
      ttl,
      opts.path,
      opts.domain,
      opts.secure,
      opts.httpOnly
    );
    if (opts.secret) {
      const signature = crypto.hmac(opts.secret, value, opts.algorithm);
      actions.addCookie(
        this._raw,
        `${name}.sig`,
        signature,
        ttl,
        opts.path,
        opts.domain,
        opts.secure,
        opts.httpOnly
      );
    }
    return this;
  }

  throw(status, reason, args) {
    if (typeof status === 'string') {
      status = statuses(status);
    }
    if (reason instanceof Error) {
      const err = reason;
      reason = err.message;
      args = Object.extend({
        cause: err,
        errorNum: err.errorNum
      }, args);
    }
    if (reason && typeof reason === 'object') {
      args = reason;
      reason = undefined;
    }
    throw Object.assign(
      httperr(status, reason),
      {statusCode: status, status},
      args
    );
  }

  send(body, type) {
    if (body && body.isArangoResultSet) {
      body = body.toArray();
    }

    if (!type) {
      type = 'auto';
    }

    let contentType;
    const status = this.statusCode || 200;
    const response = this._responses.get(status);

    if (response) {
      if (response.model && response.model.forClient) {
        if (response.multiple && Array.isArray(body)) {
          body = body.map(function (item) {
            return response.model.forClient(item);
          });
        } else {
          body = response.model.forClient(body);
        }
      }
      if (type === 'auto' && response.contentTypes) {
        type = response.contentTypes[0];
        contentType = type;
      }
    }

    if (type === 'auto') {
      if (body instanceof Buffer) {
        type = MIME_BINARY;
      } else if (body && typeof body === 'object') {
        type = 'json';
      } else {
        type = 'html';
      }
    }

    type = mimeTypes.lookup(type) || type;

    let handler;
    for (const entry of this.context.service.types.entries()) {
      const key = entry[0];
      const value = entry[1];
      let match;
      if (key instanceof RegExp) {
        match = type.test(key);
      } else if (typeof key === 'function') {
        match = key(type);
      } else {
        match = typeIs.is(key, type);
      }
      if (match && value.forClient) {
        contentType = key;
        handler = value;
        break;
      }
    }

    if (handler) {
      const result = handler.forClient(body, this, mediaTyper.parse(contentType));
      if (result.headers || result.data) {
        contentType = result.headers['content-type'] || contentType;
        this.set(result.headers);
        body = result.data;
      } else {
        body = result;
      }
    }

    this._raw.body = body;
    this._raw.contentType = contentType || this._raw.contentType;

    return this;
  }
};
<|endoftext|>