<commit_before>import Ember from 'ember';

var plusId = 0;

var _addBrace = function(element, numberSpaces, hasPlus, braceColor, braceHighlight){
    var jsonLine = {
            elements: [],
            lines: []
        },
        jsonObj = {};

    for(var counter = 0; counter < numberSpaces; counter = counter +1){
        jsonLine.elements.push(_addBlank());
    }

    jsonObj.hasPlus = hasPlus;
    jsonObj.plusId = 'plus_' + plusId;
    jsonObj.isBlank = false;
    jsonObj.element = element;
    if(braceColor || braceHighlight) {
        jsonObj.style = '';
        if(braceColor) { jsonObj.style += 'color:' + braceColor + '; '; }
        if(braceHighlight) { jsonObj.style += 'background-color:' + braceHighlight + '; '; }
    }
    jsonObj.class = 'json-brace';

    jsonLine.elements.push(jsonObj);

    return jsonLine;
};

var _addBlank = function(){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.element = '';
    jsonObj.isBlank = true;
    jsonObj.class = 'json-blank';

    return jsonObj;
};

var _addKey = function(key, numberSpaces, keyColor, keyHighlight){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = key;
    if(keyColor || keyHighlight) {
        jsonObj.style = '';
        if(keyColor) { jsonObj.style += 'color:' + keyColor + '; '; }
        if(keyHighlight) { jsonObj.style += 'background-color:' + keyHighlight + '; '; }
    }
    jsonObj.class = 'json-key';

    return jsonObj;
};

var _addTwoPoints = function(){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = ':';
    jsonObj.style = '';
    jsonObj.class = 'json-two-points';

    return jsonObj;
};

var _addValue = function(value, numberSpaces, hasComma, options){
    var jsonObj = {};

    if(value){
        if(typeof value === 'string'){
            jsonObj = _addStringValue(value, options['stringColor'], options['stringHighlight']);
        }
        else if(Array.isArray(value)){
            if(typeof value[0] === 'object'){

                jsonObj = _createJSONTree(value, numberSpaces, options, hasComma);
            }
            else{
                jsonObj = _createJSONTree(value, numberSpaces, options, hasComma);
            }
        }
        else if(value && typeof value === 'object'){
            jsonObj = _addObjectValue(value, numberSpaces, options);
        }
        else{
            jsonObj = _addStandardValue(value, options['valueColor'], options['valueHighlight']);
        }
    }
    else{
        jsonObj = _addStringValue('null', options['stringColor'], options['stringHighlight']);
    }

    return jsonObj;
};

var _addStringValue = function(value, stringColor, stringHighlight){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = value;
    if(stringColor || stringHighlight) {
        jsonObj.style = '';
        if(stringColor) { jsonObj.style += 'color:' + stringColor + '; '; }
        if(stringHighlight) { jsonObj.style += 'background-color:' + stringHighlight + '; '; }
    }
    jsonObj.class = 'json-string';

    return jsonObj;
};

var _addObjectValue = function(value, numberSpacesInitial, options){
    return _createObject(value, numberSpacesInitial, options);
};

var _addStandardValue = function(value, valueColor, valueHighlight){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = value;
    if(valueColor || valueHighlight) {
        jsonObj.style = '';
        if(valueColor) { jsonObj.style += 'color:' + valueColor + '; '; }
        if(valueHighlight) { jsonObj.style += 'background-color:' + valueHighlight + '; '; }
    }
    jsonObj.class = 'json-value';

    return jsonObj;
};

var _addComma = function(){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = ',';
    jsonObj.class = '';

    return jsonObj;
};

var _createObject = function(obj, numberSpacesInitial, options) {
    var jsonLines = [],
        jsonLine = {
            elements: [],
            lines: []
        },
        numberSpaces = numberSpacesInitial;

    jsonLine = _addBrace('{', numberSpacesInitial, true, options['braceColor'], options['braceHighlight']);

    numberSpaces = numberSpaces + 1;
    Object.keys(obj).forEach(function(key, index){
        var hasComma = false,
            internalJsonLine = {
                elements: [],
                lines: []
            },
            newValue;

        plusId = plusId + 1;

        for(var counter = 0; counter < numberSpaces; counter = counter +1){
            internalJsonLine.elements.push(_addBlank());
        }

        internalJsonLine
            .elements
            .push(_addKey(key, numberSpaces, options['keyColor'], options['keyHighlight']));
        internalJsonLine
            .elements
            .push(_addTwoPoints());

        hasComma = index < (Object.keys(obj).length -1);

        newValue = _addValue(obj[key], numberSpaces, hasComma, options);

        if(Array.isArray(newValue) && newValue[0].elements[newValue[0].elements.length - 1].class === 'json-brace'){
            var openBrace = newValue[0].elements[newValue[0].elements.length - 1];

            internalJsonLine
                .elements
                .push(openBrace);

            internalJsonLine.lines = internalJsonLine
                                        .lines
                                        .concat(newValue[0].lines);

            jsonLine.lines.push(internalJsonLine);

            internalJsonLine = {
                elements: [],
                lines: []
            };

            newValue[1].elements.forEach(function (element) {
                internalJsonLine
                    .elements
                    .push(element);
            });
        }
        else{
            internalJsonLine
                .elements
                .push(newValue);
        }

        jsonLine.lines.push(internalJsonLine);

        if(Array.isArray(internalJsonLine.elements[internalJsonLine.elements.length - 1])){

            var internalArray = internalJsonLine
                                    .elements[internalJsonLine
                                                .elements.length - 1];
            internalJsonLine.elements.pop();

            internalJsonLine.elements.push(internalArray[0].elements[0]);

            internalJsonLine.lines = internalArray[0].lines;

            jsonLine.lines.push(internalArray[internalArray.length - 1]);
        }
        else{
            if(hasComma && internalJsonLine.elements[internalJsonLine.elements.length - 1].element !== ','){
                internalJsonLine.elements.push(_addComma());
            }
        }
    });

    jsonLines.push(jsonLine);
    jsonLines.push(_addBrace('}', numberSpacesInitial, false, options['braceColor'], options['braceHighlight']));

    return jsonLines;
};

var _adjustLinePlusId = function(jsonLines){
    jsonLines.forEach(function(_line){
        var plusId = '';

        if(_line.elements){
            _line.elements.forEach(function(_element){
                if(_element.plusId){
                    plusId = _element.plusId;
                }
            });
        }

        if(_line.lines){
            _line.lines.forEach(function(_internalLine){
                _internalLine.plusId = plusId;
            });

            if(_line.lines.length > 0){
                _line.lines = _adjustLinePlusId(_line.lines);
            }
        }
    });
    return jsonLines;
};

var _createJSONTree = function(obj, numberSpaces, options, hasComma) {
    var jsonLines = [],
        jsonLine = {
            elements: [],
            lines: []
        },
        jsonObj = {
            'hasPlus': false,
            'newLine': false,
            'endLine': false
        },
        numberSpacesInitial = numberSpaces;

    if(Array.isArray(obj)){
        numberSpaces = numberSpaces + 1;

        jsonObj.hasPlus = true;
        jsonObj.plusId = 'plus_' + plusId;
        jsonObj.element = '[';
        jsonObj.isBlank = false;
        if(options['bracketColor'] || options['bracketHighlight']) {
            jsonObj.style = '';
            if(options['bracketColor']) { jsonObj.style += 'color:' + options['bracketColor'] + '; '; }
            if(options['bracketHighlight']) { jsonObj.style += 'background-color:' + options['bracketHighlight'] + '; '; }
        }
        jsonObj.class = 'json-bracket';

        jsonLine.elements.push(jsonObj);

        obj.forEach(function(newObj, index){
            var newObject;

            if(typeof newObj === 'string' || typeof newObj === 'number')
            {
                var internalJsonLine = {
                    elements: [],
                    lines: []
                },
                internaljsonObj = {},
                internalBlanks = numberSpacesInitial + 1;

                internaljsonObj.hasPlus = false;
                internaljsonObj.plusId = '';
                internaljsonObj.element = newObj;
                internaljsonObj.isBlank = false;
                if(typeof newObj === 'string')
                {
                    if(options['stringColor'] || options['stringHighlight']) {
                        internaljsonObj.style = '';
                        if(options['stringColor']) { internaljsonObj.style += 'color:' + options['stringColor'] + '; '; }
                        if(options['stringHighlight']) { internaljsonObj.style += 'background-color:' + options['stringHighlight'] + '; '; }
                    }
                    internaljsonObj.class = 'json-string';
                }
                else {
                    if(options['valueColor'] || options['valueHighlight']) {
                        internaljsonObj.style = '';
                        if(options['valueColor']) { internaljsonObj.style += 'color:' + options['valueColor'] + '; '; }
                        if(options['valueHighlight']) { internaljsonObj.style += 'background-color:' + options['valueHighlight'] + '; '; }
                    }
                    internaljsonObj.class = 'json-value';
                }
                for(var counter = 0; counter < internalBlanks; counter = counter +1){
                    internalJsonLine.elements.push(_addBlank());
                }

                internalJsonLine.elements.push(internaljsonObj);
                if(index < obj.length - 1){
                    internalJsonLine.elements.push(_addComma());
                }

                jsonLine.lines.push(internalJsonLine);
            }
            else{
                plusId = plusId + 1;

                newObject = _createObject(newObj, numberSpaces, options);

                newObject.forEach(function(objectLine){
                    jsonLine.lines.push(objectLine);
                });

                if(index < (obj.length -1)){
                    jsonLine
                        .lines[jsonLine.lines.length - 1]
                            .elements.push(_addComma());
                }

                newObject.forEach(function(line){
                    plusId = plusId + line.lines.length + 1;
                });
            }
        });

        jsonLines.push(jsonLine);

        jsonObj = {
            'hasPlus': false,
            'newLine': false,
            'endLine': false
        };
        jsonLine = {
            elements: [],
            lines: []
        };

        for(var counter = 0; counter < numberSpacesInitial; counter = counter +1){
            jsonLine.elements.push(_addBlank());
        }

        jsonObj.hasPlus = false;
        jsonObj.plusId = null;
        jsonObj.element = ']';
        jsonObj.isBlank = false;
        if(options['bracketColor'] || options['bracketHighlight']) {
            jsonObj.style = '';
            if(options['bracketColor']) { jsonObj.style += 'color:' + options['bracketColor'] + '; '; }
            if(options['bracketHighlight']) { jsonObj.style += 'background-color:' + options['bracketHighlight'] + '; '; }
        }
        jsonObj.class = 'json-bracket';

        jsonLine.elements.push(jsonObj);

        if(hasComma){
            jsonLine.elements.push(_addComma());
        }

        jsonLines.push(jsonLine);
    }
    else{
        jsonLines = _createObject(obj, numberSpaces, options);
    }

    return _adjustLinePlusId(jsonLines);
};

var _prettyPrint = function(obj, options) {

    var jsonTree = _createJSONTree( obj, 0, options, false);

    return jsonTree;
};

export default Ember.Component.extend({
    tagName: 'code',
    optionsDefault: {
    },
    options: {},
    id: '',
    attributeBindings: ['customId:id'],
    customId: '',
    pretty: function () {
        var jsonObj = this.get('jsonObj'),
            options,
            json_pretty,
            randomId = Math.floor(Math.random() * 60000) + 1;

        this.set('customId', randomId);

        if(typeof jsonObj === 'string'){
            jsonObj = JSON.parse(jsonObj);
        }

        if(this.options){
            if(typeof this.options === 'object'){
                options = Ember.$.extend({}, this.optionsDefault, this.options);
            }
            else{
                options = Ember.$.extend({}, this.optionsDefault, JSON.parse(this.options));
            }
        }
        else{
            options = this.optionsDefault;
        }

        this.set('options', options);

        json_pretty = _prettyPrint( jsonObj,
                                    options);

        return json_pretty;
    }.property('jsonObj'),
    actions: {
        toggleExpand: function(plusId){
            var id = this.get('customId');
            if(Ember.$('#' + id).find('#' + plusId).hasClass('fa-plus-square-o')){
                Ember.$('#' + id).find('#' + plusId).removeClass('fa-plus-square-o');
                Ember.$('#' + id).find('#' + plusId).addClass('fa-minus-square-o');
                Ember.$('#' + id).find('.jsonTreeView').find('[data-id="' + plusId + '"]').show();
            }
            else{
                Ember.$('#' + id).find('#' + plusId).removeClass('fa-minus-square-o');
                Ember.$('#' + id).find('#' + plusId).addClass('fa-plus-square-o');
                Ember.$('#' + id).find('.jsonTreeView').find('[data-id="' + plusId + '"]').hide();
            }
        }
    }
});<commit_msg>supporting printing 'false' boolean and 'null' as value (not string)<commit_after>import Ember from 'ember';

var plusId = 0;

var _addBrace = function(element, numberSpaces, hasPlus, braceColor, braceHighlight){
    var jsonLine = {
            elements: [],
            lines: []
        },
        jsonObj = {};

    for(var counter = 0; counter < numberSpaces; counter = counter +1){
        jsonLine.elements.push(_addBlank());
    }

    jsonObj.hasPlus = hasPlus;
    jsonObj.plusId = 'plus_' + plusId;
    jsonObj.isBlank = false;
    jsonObj.element = element;
    if(braceColor || braceHighlight) {
        jsonObj.style = '';
        if(braceColor) { jsonObj.style += 'color:' + braceColor + '; '; }
        if(braceHighlight) { jsonObj.style += 'background-color:' + braceHighlight + '; '; }
    }
    jsonObj.class = 'json-brace';

    jsonLine.elements.push(jsonObj);

    return jsonLine;
};

var _addBlank = function(){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.element = '';
    jsonObj.isBlank = true;
    jsonObj.class = 'json-blank';

    return jsonObj;
};

var _addKey = function(key, numberSpaces, keyColor, keyHighlight){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = key;
    if(keyColor || keyHighlight) {
        jsonObj.style = '';
        if(keyColor) { jsonObj.style += 'color:' + keyColor + '; '; }
        if(keyHighlight) { jsonObj.style += 'background-color:' + keyHighlight + '; '; }
    }
    jsonObj.class = 'json-key';

    return jsonObj;
};

var _addTwoPoints = function(){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = ':';
    jsonObj.style = '';
    jsonObj.class = 'json-two-points';

    return jsonObj;
};

var _addValue = function(value, numberSpaces, hasComma, options){
    var jsonObj = {};

    if(value || value === false){
        if(typeof value === 'string'){
            jsonObj = _addStringValue(value, options['stringColor'], options['stringHighlight']);
        }
        else if(Array.isArray(value)){
            if(typeof value[0] === 'object'){

                jsonObj = _createJSONTree(value, numberSpaces, options, hasComma);
            }
            else{
                jsonObj = _createJSONTree(value, numberSpaces, options, hasComma);
            }
        }
        else if(value && typeof value === 'object'){
            jsonObj = _addObjectValue(value, numberSpaces, options);
        }
        else{
            jsonObj = _addStandardValue(value, options['valueColor'], options['valueHighlight']);
        }
    }
    else{
        jsonObj = _addStandardValue('null', options['valueColor'], options['valueHighlight']);
    }

    return jsonObj;
};

var _addStringValue = function(value, stringColor, stringHighlight){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = value;
    if(stringColor || stringHighlight) {
        jsonObj.style = '';
        if(stringColor) { jsonObj.style += 'color:' + stringColor + '; '; }
        if(stringHighlight) { jsonObj.style += 'background-color:' + stringHighlight + '; '; }
    }
    jsonObj.class = 'json-string';

    return jsonObj;
};

var _addObjectValue = function(value, numberSpacesInitial, options){
    return _createObject(value, numberSpacesInitial, options);
};

var _addStandardValue = function(value, valueColor, valueHighlight){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = value;
    if(valueColor || valueHighlight) {
        jsonObj.style = '';
        if(valueColor) { jsonObj.style += 'color:' + valueColor + '; '; }
        if(valueHighlight) { jsonObj.style += 'background-color:' + valueHighlight + '; '; }
    }
    jsonObj.class = 'json-value';

    return jsonObj;
};

var _addComma = function(){
    var jsonObj = {};

    jsonObj.hasPlus = false;
    jsonObj.plusId = null;
    jsonObj.isBlank = false;
    jsonObj.element = ',';
    jsonObj.class = '';

    return jsonObj;
};

var _createObject = function(obj, numberSpacesInitial, options) {
    var jsonLines = [],
        jsonLine = {
            elements: [],
            lines: []
        },
        numberSpaces = numberSpacesInitial;

    jsonLine = _addBrace('{', numberSpacesInitial, true, options['braceColor'], options['braceHighlight']);

    numberSpaces = numberSpaces + 1;
    Object.keys(obj).forEach(function(key, index){
        var hasComma = false,
            internalJsonLine = {
                elements: [],
                lines: []
            },
            newValue;

        plusId = plusId + 1;

        for(var counter = 0; counter < numberSpaces; counter = counter +1){
            internalJsonLine.elements.push(_addBlank());
        }

        internalJsonLine
            .elements
            .push(_addKey(key, numberSpaces, options['keyColor'], options['keyHighlight']));
        internalJsonLine
            .elements
            .push(_addTwoPoints());

        hasComma = index < (Object.keys(obj).length -1);

        newValue = _addValue(obj[key], numberSpaces, hasComma, options);

        if(Array.isArray(newValue) && newValue[0].elements[newValue[0].elements.length - 1].class === 'json-brace'){
            var openBrace = newValue[0].elements[newValue[0].elements.length - 1];

            internalJsonLine
                .elements
                .push(openBrace);

            internalJsonLine.lines = internalJsonLine
                                        .lines
                                        .concat(newValue[0].lines);

            jsonLine.lines.push(internalJsonLine);

            internalJsonLine = {
                elements: [],
                lines: []
            };

            newValue[1].elements.forEach(function (element) {
                internalJsonLine
                    .elements
                    .push(element);
            });
        }
        else{
            internalJsonLine
                .elements
                .push(newValue);
        }

        jsonLine.lines.push(internalJsonLine);

        if(Array.isArray(internalJsonLine.elements[internalJsonLine.elements.length - 1])){

            var internalArray = internalJsonLine
                                    .elements[internalJsonLine
                                                .elements.length - 1];
            internalJsonLine.elements.pop();

            internalJsonLine.elements.push(internalArray[0].elements[0]);

            internalJsonLine.lines = internalArray[0].lines;

            jsonLine.lines.push(internalArray[internalArray.length - 1]);
        }
        else{
            if(hasComma && internalJsonLine.elements[internalJsonLine.elements.length - 1].element !== ','){
                internalJsonLine.elements.push(_addComma());
            }
        }
    });

    jsonLines.push(jsonLine);
    jsonLines.push(_addBrace('}', numberSpacesInitial, false, options['braceColor'], options['braceHighlight']));

    return jsonLines;
};

var _adjustLinePlusId = function(jsonLines){
    jsonLines.forEach(function(_line){
        var plusId = '';

        if(_line.elements){
            _line.elements.forEach(function(_element){
                if(_element.plusId){
                    plusId = _element.plusId;
                }
            });
        }

        if(_line.lines){
            _line.lines.forEach(function(_internalLine){
                _internalLine.plusId = plusId;
            });

            if(_line.lines.length > 0){
                _line.lines = _adjustLinePlusId(_line.lines);
            }
        }
    });
    return jsonLines;
};

var _createJSONTree = function(obj, numberSpaces, options, hasComma) {
    var jsonLines = [],
        jsonLine = {
            elements: [],
            lines: []
        },
        jsonObj = {
            'hasPlus': false,
            'newLine': false,
            'endLine': false
        },
        numberSpacesInitial = numberSpaces;

    if(Array.isArray(obj)){
        numberSpaces = numberSpaces + 1;

        jsonObj.hasPlus = true;
        jsonObj.plusId = 'plus_' + plusId;
        jsonObj.element = '[';
        jsonObj.isBlank = false;
        if(options['bracketColor'] || options['bracketHighlight']) {
            jsonObj.style = '';
            if(options['bracketColor']) { jsonObj.style += 'color:' + options['bracketColor'] + '; '; }
            if(options['bracketHighlight']) { jsonObj.style += 'background-color:' + options['bracketHighlight'] + '; '; }
        }
        jsonObj.class = 'json-bracket';

        jsonLine.elements.push(jsonObj);

        obj.forEach(function(newObj, index){
            var newObject;

            if(typeof newObj === 'string' || typeof newObj === 'number' || typeof newObj === 'boolean')
            {
                var internalJsonLine = {
                    elements: [],
                    lines: []
                },
                internaljsonObj = {},
                internalBlanks = numberSpacesInitial + 1;

                internaljsonObj.hasPlus = false;
                internaljsonObj.plusId = '';
                internaljsonObj.element = newObj;
                internaljsonObj.isBlank = false;
                if(typeof newObj === 'string')
                {
                    if(options['stringColor'] || options['stringHighlight']) {
                        internaljsonObj.style = '';
                        if(options['stringColor']) { internaljsonObj.style += 'color:' + options['stringColor'] + '; '; }
                        if(options['stringHighlight']) { internaljsonObj.style += 'background-color:' + options['stringHighlight'] + '; '; }
                    }
                    internaljsonObj.class = 'json-string';
                }
                else {
                    if(options['valueColor'] || options['valueHighlight']) {
                        internaljsonObj.style = '';
                        if(options['valueColor']) { internaljsonObj.style += 'color:' + options['valueColor'] + '; '; }
                        if(options['valueHighlight']) { internaljsonObj.style += 'background-color:' + options['valueHighlight'] + '; '; }
                    }
                    internaljsonObj.class = 'json-value';
                }
                for(var counter = 0; counter < internalBlanks; counter = counter +1){
                    internalJsonLine.elements.push(_addBlank());
                }

                internalJsonLine.elements.push(internaljsonObj);
                if(index < obj.length - 1){
                    internalJsonLine.elements.push(_addComma());
                }

                jsonLine.lines.push(internalJsonLine);
            }
            else{
                plusId = plusId + 1;

                newObject = _createObject(newObj, numberSpaces, options);

                newObject.forEach(function(objectLine){
                    jsonLine.lines.push(objectLine);
                });

                if(index < (obj.length -1)){
                    jsonLine
                        .lines[jsonLine.lines.length - 1]
                            .elements.push(_addComma());
                }

                newObject.forEach(function(line){
                    plusId = plusId + line.lines.length + 1;
                });
            }
        });

        jsonLines.push(jsonLine);

        jsonObj = {
            'hasPlus': false,
            'newLine': false,
            'endLine': false
        };
        jsonLine = {
            elements: [],
            lines: []
        };

        for(var counter = 0; counter < numberSpacesInitial; counter = counter +1){
            jsonLine.elements.push(_addBlank());
        }

        jsonObj.hasPlus = false;
        jsonObj.plusId = null;
        jsonObj.element = ']';
        jsonObj.isBlank = false;
        if(options['bracketColor'] || options['bracketHighlight']) {
            jsonObj.style = '';
            if(options['bracketColor']) { jsonObj.style += 'color:' + options['bracketColor'] + '; '; }
            if(options['bracketHighlight']) { jsonObj.style += 'background-color:' + options['bracketHighlight'] + '; '; }
        }
        jsonObj.class = 'json-bracket';

        jsonLine.elements.push(jsonObj);

        if(hasComma){
            jsonLine.elements.push(_addComma());
        }

        jsonLines.push(jsonLine);
    }
    else{
        jsonLines = _createObject(obj, numberSpaces, options);
    }

    return _adjustLinePlusId(jsonLines);
};

var _prettyPrint = function(obj, options) {

    var jsonTree = _createJSONTree( obj, 0, options, false);

    return jsonTree;
};

export default Ember.Component.extend({
    tagName: 'code',
    optionsDefault: {
    },
    options: {},
    id: '',
    attributeBindings: ['customId:id'],
    customId: '',
    pretty: function () {
        var jsonObj = this.get('jsonObj'),
            options,
            json_pretty,
            randomId = Math.floor(Math.random() * 60000) + 1;

        this.set('customId', randomId);

        if(typeof jsonObj === 'string'){
            jsonObj = JSON.parse(jsonObj);
        }

        if(this.options){
            if(typeof this.options === 'object'){
                options = Ember.$.extend({}, this.optionsDefault, this.options);
            }
            else{
                options = Ember.$.extend({}, this.optionsDefault, JSON.parse(this.options));
            }
        }
        else{
            options = this.optionsDefault;
        }

        this.set('options', options);

        json_pretty = _prettyPrint( jsonObj,
                                    options);

        return json_pretty;
    }.property('jsonObj'),
    actions: {
        toggleExpand: function(plusId){
            var id = this.get('customId');
            if(Ember.$('#' + id).find('#' + plusId).hasClass('fa-plus-square-o')){
                Ember.$('#' + id).find('#' + plusId).removeClass('fa-plus-square-o');
                Ember.$('#' + id).find('#' + plusId).addClass('fa-minus-square-o');
                Ember.$('#' + id).find('.jsonTreeView').find('[data-id="' + plusId + '"]').show();
            }
            else{
                Ember.$('#' + id).find('#' + plusId).removeClass('fa-minus-square-o');
                Ember.$('#' + id).find('#' + plusId).addClass('fa-plus-square-o');
                Ember.$('#' + id).find('.jsonTreeView').find('[data-id="' + plusId + '"]').hide();
            }
        }
    }
});<|endoftext|>


<commit_before>'use strict';

// changing for changings sake

// var userName;
//
// if(localStorage.userName){
//   console.log(localStorage.userName);
//   userName = JSON.parse(localStorage.userName);
// }else{
//   userName = prompt('Hmmmm looks like we forgot your name. What was it again?');
//   localStorage.userName = userName;
// };
var incorrectNumber = 0;

var answerEl = document.getElementById('possibleAnswers'); //correct answer for event listener

// Question One Variables
var questionOne = 'What is a "for" loop?';
var answerOne = 'to count things';
var answerOneIncorrectOne = 'testing321';
var answerOneIncorrectTwo = 'testing123';

// Question Two Variables
var questionTwo = 'What is the meaning of life?';
var answerTwo = 'answer two';
var answerTwoIncorrectOne = '22222incorrect answer one22222';
var answerTwoIncorrectTwo = '222222incorrect answer two22222';

// Question Three Variable
var questionThree = 'Question Three';
var answerThree = 'your mom';
var answerThreeIncorrectOne = '333333 incorrect answer one33333';
var answerThreeIncorrectTwo = '333333 incorrect answer two33333';

// total questions wrong and messages

var questionsWrong = function () {
  if (incorrectNumber < 2) {
    confirm('you passed');
  } else if (incorrectNumber > 2 && incorrectNumber < 4) {
    confirm('you passed. BARELY!');
  } else {
    confirm('You got ' + incorrectNumber + ' wrong.  YOU FAIL!!');
  }
};

// Handle correct answer click
function handleClick(event) {
  event.preventDefault();
  event.stopPropagation();

  console.log(event.target);

  if (event.target.id === 'correctAnswerOne') {
    questionTwoEl();
  } else if (event.target.id === 'correctAnswerTwo') {
    questionThreeEl();
  } else if (event.target.id === 'correctAnswerThree') {
    questionsWrong();
    location.href = 'index.html';
  } else {
    incorrectNumber++;
    console.log(incorrectNumber);
    confirm('You got it wrong fool. Pick again');
  }
};

// Question One
var questionOneEl = function() {
  var questionEl = document.getElementById('question');
  question.textContent = questionOne;

  var questionOneAnswerOneEl = document.createElement('li');
  questionOneAnswerOneEl.setAttribute('id', 'correctAnswerOne');
  answerEl.appendChild(questionOneAnswerOneEl);
  questionOneAnswerOneEl.textContent = answerOne;
  questionOneAnswerOneEl.addEventListener('click', handleClick);

  var questionOneAnswerTwoEl = document.createElement('li');
  questionOneAnswerTwoEl.setAttribute('id', 'incorrectAnswerOne');
  answerEl.appendChild(questionOneAnswerTwoEl);
  questionOneAnswerTwoEl.textContent = answerOneIncorrectOne;
  questionOneAnswerTwoEl.addEventListener('click', handleClick);

  var questionOneAnswerThreeEl = document.createElement('li');
  questionOneAnswerThreeEl.setAttribute('id', 'incorrectAnswerTwo');
  answerEl.appendChild(questionOneAnswerThreeEl);
  questionOneAnswerThreeEl.textContent = answerOneIncorrectTwo;
  questionOneAnswerThreeEl.addEventListener('click', handleClick);

};

// Question Two

var questionTwoEl = function() {
  var questionEl = document.getElementById('question');
  question.textContent = questionTwo;

  var questionTwoAnswerOneEl = document.getElementById('correctAnswerOne');
  questionTwoAnswerOneEl.setAttribute('id', 'incorrectAnswerOne');
  answerEl.appendChild(questionTwoAnswerOneEl);
  questionTwoAnswerOneEl.textContent = answerTwoIncorrectOne;
  questionTwoAnswerOneEl.addEventListener('click', handleClick);

  var questionTwoAnswerTwoEl = document.getElementById('incorrectAnswerOne');
  questionTwoAnswerTwoEl.setAttribute('id', 'correctAnswerTwo');
  answerEl.appendChild(questionTwoAnswerTwoEl);
  questionTwoAnswerTwoEl.textContent = answerTwo;
  questionTwoAnswerTwoEl.addEventListener('click', handleClick);

  var questionTwoAnswerThreeEl = document.getElementById('incorrectAnswerTwo');
  questionTwoAnswerThreeEl.setAttribute('id', 'incorrectAnswerTwo');
  answerEl.appendChild(questionTwoAnswerThreeEl);
  questionTwoAnswerThreeEl.textContent = answerTwoIncorrectTwo;
  questionTwoAnswerThreeEl.addEventListener('click', handleClick);

};

// Question Three

var questionThreeEl = function() {
  var questionEl = document.getElementById('question');
  question.textContent = questionThree;

  var questionThreeAnswerOneEl = document.getElementById('incorrectAnswerTwo');
  questionThreeAnswerOneEl.setAttribute('id', 'incorrectAnswerOne');
  answerEl.appendChild(questionThreeAnswerOneEl);
  questionThreeAnswerOneEl.textContent = answerThreeIncorrectOne;
  questionThreeAnswerOneEl.addEventListener('click', handleClick);

  console.log(incorrectNumber);

  var questionThreeAnswerTwoEl = document.getElementById('incorrectAnswerOne');
  questionThreeAnswerTwoEl.setAttribute('id', 'incorrectAnswerTwo');
  answerEl.appendChild(questionThreeAnswerTwoEl);
  questionThreeAnswerTwoEl.textContent = answerThreeIncorrectTwo;
  questionThreeAnswerTwoEl.addEventListener('click', handleClick);

  console.log(incorrectNumber);

  var questionThreeAnswerThreeEl = document.getElementById('correctAnswerTwo');
  questionThreeAnswerThreeEl.setAttribute('id', 'correctAnswerThree');
  answerEl.appendChild(questionThreeAnswerThreeEl);
  questionThreeAnswerThreeEl.textContent = answerThree;
  questionThreeAnswerThreeEl.addEventListener('click', handleClick);

  console.log(incorrectNumber);

};

questionOneEl();
<commit_msg>3 questions done, working on 4th.<commit_after>'use strict';

// changing for changings sake

// var userName;
//
// if(localStorage.userName){
//   console.log(localStorage.userName);
//   userName = JSON.parse(localStorage.userName);
// }else{
//   userName = prompt('Hmmmm looks like we forgot your name. What was it again?');
//   localStorage.userName = userName;
// };

var pageLink = 'casino.html'; //insert link for quiz completion

var incorrectNumber = 0; //number of incorrect answers

var answerEl = document.getElementById('possibleAnswers'); //correct answer for event listener

// Question One Variables
var questionOne = 'What is a "for" loop?';
var answerOne = 'to count things';
var answerOneIncorrectOne = 'testing321';
var answerOneIncorrectTwo = 'testing123';

// Question Two Variables
var questionTwo = 'What is the meaning of life?';
var answerTwo = 'answer two';
var answerTwoIncorrectOne = '22222incorrect answer one22222';
var answerTwoIncorrectTwo = '222222incorrect answer two22222';

// Question Three Variable
var questionThree = 'Question Three';
var answerThree = 'your mom';
var answerThreeIncorrectOne = '333333 incorrect answer one33333';
var answerThreeIncorrectTwo = '333333 incorrect answer two33333';

// Question Four Variable
var questionFour = 'Question Four';
var answerFourPicOne = 'image2.jpg';
var answerFourPicTwo = 'image3.jpg';
var answerFourPicThree = 'image4.jpg';

// total questions wrong and messages

var questionsWrong = function () {
  if (incorrectNumber < 2) {
    confirm('you passed');
  } else if (incorrectNumber > 2 && incorrectNumber < 4) {
    confirm('you passed. BARELY!');
  } else {
    confirm('You got ' + incorrectNumber + ' wrong.  YOU FAIL!!');
  }
};

// Handle correct answer click
function handleClick(event) {
  event.preventDefault();
  event.stopPropagation();

  console.log(event.target);

  if (event.target.id === 'correctAnswerOne') {
    questionTwoEl();
  } else if (event.target.id === 'correctAnswerTwo') {
    questionThreeEl();
  } else if (event.target.id === 'correctAnswerThree') {
    questionsWrong();
    location.href = pageLink;
  } else {
    incorrectNumber++;
    console.log(incorrectNumber);
    confirm('You got it wrong fool. Pick again');
  }
};

// Question One
var questionOneEl = function() {
  var questionEl = document.getElementById('question');
  question.textContent = questionOne;

  var questionOneAnswerOneEl = document.createElement('li');
  questionOneAnswerOneEl.setAttribute('id', 'correctAnswerOne');
  answerEl.appendChild(questionOneAnswerOneEl);
  questionOneAnswerOneEl.textContent = answerOne;
  questionOneAnswerOneEl.addEventListener('click', handleClick);

  var questionOneAnswerTwoEl = document.createElement('li');
  questionOneAnswerTwoEl.setAttribute('id', 'incorrectAnswerOne');
  answerEl.appendChild(questionOneAnswerTwoEl);
  questionOneAnswerTwoEl.textContent = answerOneIncorrectOne;
  questionOneAnswerTwoEl.addEventListener('click', handleClick);

  var questionOneAnswerThreeEl = document.createElement('li');
  questionOneAnswerThreeEl.setAttribute('id', 'incorrectAnswerTwo');
  answerEl.appendChild(questionOneAnswerThreeEl);
  questionOneAnswerThreeEl.textContent = answerOneIncorrectTwo;
  questionOneAnswerThreeEl.addEventListener('click', handleClick);

};

// Question Two

var questionTwoEl = function() {
  var questionEl = document.getElementById('question');
  question.textContent = questionTwo;

  var questionTwoAnswerOneEl = document.getElementById('correctAnswerOne');
  questionTwoAnswerOneEl.setAttribute('id', 'incorrectAnswerOne');
  answerEl.appendChild(questionTwoAnswerOneEl);
  questionTwoAnswerOneEl.textContent = answerTwoIncorrectOne;
  questionTwoAnswerOneEl.addEventListener('click', handleClick);

  var questionTwoAnswerTwoEl = document.getElementById('incorrectAnswerOne');
  questionTwoAnswerTwoEl.setAttribute('id', 'correctAnswerTwo');
  answerEl.appendChild(questionTwoAnswerTwoEl);
  questionTwoAnswerTwoEl.textContent = answerTwo;
  questionTwoAnswerTwoEl.addEventListener('click', handleClick);

  var questionTwoAnswerThreeEl = document.getElementById('incorrectAnswerTwo');
  questionTwoAnswerThreeEl.setAttribute('id', 'incorrectAnswerTwo');
  answerEl.appendChild(questionTwoAnswerThreeEl);
  questionTwoAnswerThreeEl.textContent = answerTwoIncorrectTwo;
  questionTwoAnswerThreeEl.addEventListener('click', handleClick);

};

// Question Three

var questionThreeEl = function() {
  var questionEl = document.getElementById('question');
  question.textContent = questionThree;

  var questionThreeAnswerOneEl = document.getElementById('incorrectAnswerTwo');
  questionThreeAnswerOneEl.setAttribute('id', 'incorrectAnswerOne');
  answerEl.appendChild(questionThreeAnswerOneEl);
  questionThreeAnswerOneEl.textContent = answerThreeIncorrectOne;
  questionThreeAnswerOneEl.addEventListener('click', handleClick);

  console.log(incorrectNumber);

  var questionThreeAnswerTwoEl = document.getElementById('incorrectAnswerOne');
  questionThreeAnswerTwoEl.setAttribute('id', 'incorrectAnswerTwo');
  answerEl.appendChild(questionThreeAnswerTwoEl);
  questionThreeAnswerTwoEl.textContent = answerThreeIncorrectTwo;
  questionThreeAnswerTwoEl.addEventListener('click', handleClick);

  console.log(incorrectNumber);

  var questionThreeAnswerThreeEl = document.getElementById('correctAnswerTwo');
  questionThreeAnswerThreeEl.setAttribute('id', 'correctAnswerThree');
  answerEl.appendChild(questionThreeAnswerThreeEl);
  questionThreeAnswerThreeEl.textContent = answerThree;
  questionThreeAnswerThreeEl.addEventListener('click', handleClick);

  console.log(incorrectNumber);

};

//  Question Four
//
// var questionFourEl = function() {
//   var questionEl = document.getElementById('question');
//   question.textContent = questionThree;
//
//   var questionFourAnswerOneEl = document.getElementById('incorrectAnswerTwo');
//   questionFourAnswerOneEl.setAttribute('src', 'image1.image');
//   answerEl.appendChild(questionFourAnswerOneEl);
//   questionFourAnswerOneEl.textContent = answerThreeIncorrectOne;
//   questionFourAnswerOneEl.addEventListener('click', handleClick);
//
//   console.log(incorrectNumber);
//
//   var questionFourAnswerTwoEl = document.getElementById('incorrectAnswerOne');
//   questionFourAnswerTwoEl.setAttribute('src', 'image2.jpg');
//   answerEl.appendChild(questionFourAnswerTwoEl);
//   questionFourAnswerTwoEl.textContent = answerThreeIncorrectTwo;
//   questionFourAnswerTwoEl.addEventListener('click', handleClick);
//
//   console.log(incorrectNumber);
//
//   var questionFourAnswerThreeEl = document.getElementById('correctAnswerTwo');
//   questionFourAnswerThreeEl.setAttribute('id', 'correctAnswerThree');
//   answerEl.appendChild(questionFourAnswerThreeEl);
//   questionFourAnswerThreeEl.textContent = answerThree;
//   questionFourAnswerThreeEl.addEventListener('click', handleClick);
//
//   console.log(incorrectNumber);
//
// };

questionOneEl();
<|endoftext|>


<commit_before>import { LightningElement, api, track, wire } from 'lwc';
import GeFormService from 'c/geFormService';
import { NavigationMixin } from 'lightning/navigation';
import messageLoading from '@salesforce/label/c.labelMessageLoading';
import geSave from '@salesforce/label/c.labelGeSave';
import geCancel from '@salesforce/label/c.labelGeCancel';
import { showToast, handleError, getRecordFieldNames, setRecordValuesOnTemplate } from 'c/utilTemplateBuilder';
import { getQueryParameters } from 'c/utilCommon';
import { getRecord } from 'lightning/uiRecordApi';
import FORM_TEMPLATE_FIELD from '@salesforce/schema/DataImportBatch__c.Form_Template__c';
import TEMPLATE_JSON_FIELD from '@salesforce/schema/Form_Template__c.Template_JSON__c';

export default class GeFormRenderer extends NavigationMixin(LightningElement) {
    @api recordId = '';
    @api record;
    fieldNames = [];
    @api sections = [];
    @track ready = false;
    @track name = '';
    @track description = '';
    @track mappingSet = '';
    @track version = '';
    @api showSpinner = false;
    @api batchId;
    @api submissions = [];
    @api hasPageLevelError = false;
    label = { messageLoading, geSave, geCancel };
    @track formTemplateId;
    erroredFields = [];
    @api pageLevelErrorMessageList = [];

    @wire(getRecord, { recordId: '$recordId', optionalFields: '$fieldNames'})
    wiredGetRecordMethod({ error, data }) {
        if (data) {
            this.record = data;
            this.handleGetTemplate();
        } else if (error) {
            console.error(JSON.stringify(error));
        }
    }

    connectedCallback() {

        if (this.batchId) {
            // When the form is being used for Batch Gift Entry, the Form Template JSON
            // uses the @wire service below to retrieve the Template using the Template Id
            // stored on the Batch.
            return;
        }

        // check if there is a record id in the url
        this.recordId = getQueryParameters().c__recordId;

        GeFormService.getFormTemplate().then(response => {
            // read the template header info
            if(response !== null && typeof response !== 'undefined') {
                const { formTemplate } = response;
                const fieldMappings = response.fieldMappingSetWrapper.fieldMappingByDevName;

                // get the target field names to be used by getRecord
                this.fieldNames = getRecordFieldNames(formTemplate, fieldMappings);
            }
        });
    }

    handleGetTemplate = async () => {
        let response = await GeFormService.getFormTemplate();

        if (response !== null && typeof response !== 'undefined') {
            this.initializeForm(response);
        }
    }

    initializeForm(response) {
        const { formTemplate } = response;
        const fieldMappings = response.fieldMappingSetWrapper.fieldMappingByDevName;

        // read the template header info
        this.ready = true;
        this.name = formTemplate.name;
        this.description = formTemplate.description;
        this.version = formTemplate.layout.version;
        if (typeof formTemplate.layout !== 'undefined'
            && Array.isArray(formTemplate.layout.sections)) {

            // add record data to the template fields
            let sectionsWithValues = setRecordValuesOnTemplate(formTemplate.layout.sections, fieldMappings, this.record);
            this.sections = sectionsWithValues;
            this.dispatchEvent(new CustomEvent('sectionsretrieved'));
        }
    }

    @wire(getRecord, {
        recordId: '$batchId',
        fields: FORM_TEMPLATE_FIELD
    })
    wiredBatch({data, error}) {
        if (data) {
            this.formTemplateId = data.fields[FORM_TEMPLATE_FIELD.fieldApiName].value;
        } else if (error) {
            handleError(error);
        }
    }

    @wire(getRecord, {
        recordId: '$formTemplateId',
        fields: TEMPLATE_JSON_FIELD
    })
    wiredTemplate({data, error}) {
        if (data) {
            this.loadTemplate(
                JSON.parse(data.fields[TEMPLATE_JSON_FIELD.fieldApiName].value));
        } else if (error) {
            handleError(error);
        }
    }

    async loadTemplate(formTemplate){
        // With the change to using a Lookup field to connect a Batch to a Template,
        // we can use getRecord to get the Template JSON.  But the GeFormService
        // component still needs to be initialized with the field mappings, and the
        // call to getFormTemplate() does that.
        // TODO: Maybe initialize GeFormService with the field mappings in its connected
        //       callback instead?
        await GeFormService.getFormTemplate();
        this.initializeForm(formTemplate);
    }

    handleCancel() {
        console.log('Form Cancel button clicked');
    }

    handleSave(event) {
        event.target.disabled = true;
        const enableSaveButton = function() {
            this.disabled = false;
        }.bind(event.target);

        this.clearErrors();

        // TODO: Pass the actual Data Import record, and navigate to the new Opportunity
        // const OpportunityId = GeFormService.createOpportunityFromDataImport(dataImport);
        const sectionsList = this.template.querySelectorAll('c-ge-form-section');

        if(!this.isFormValid(sectionsList)){
            return;
        }

        // show the spinner
        this.toggleSpinner();

        // callback used to toggle spinner after save
        const toggleSpinner = () => this.toggleSpinner();

        if (this.batchId) {
            const submission = {
                sectionsList: sectionsList
            };
            this.submissions.push(submission);
            this.dispatchEvent(new CustomEvent('submit', {
                detail: {
                    success: function () {
                        enableSaveButton();
                        toggleSpinner();
                    },
                    error: function() {
                        enableSaveButton();
                        toggleSpinner();
                    }
                }
            }));
        } else {
            GeFormService.handleSave(sectionsList, this.record).then(opportunityId => {
                this.navigateToRecordPage(opportunityId);
            })
                .catch(error => {

                    this.toggleSpinner();

                    // Show on top if it is a page level
                    this.hasPageLevelError = true;
                    const exceptionWrapper = JSON.parse(error.body.message);
                    const allDisplayedFields = this.getDisplayedFieldsMappedByAPIName(sectionsList);

                    if (exceptionWrapper.exceptionType !== null && exceptionWrapper.exceptionType !== '') {

                        // Check to see if there are any field level errors
                        if (Object.entries(exceptionWrapper.DMLErrorFieldNameMapping).length === undefined || Object.entries(exceptionWrapper.DMLErrorFieldNameMapping).length === 0) {

                            // If there are no specific fields the error has to go to, put it on the page level error message.
                            for (const dmlIndex in exceptionWrapper.DMLErrorMessageMapping) {
                                this.pageLevelErrorMessageList = [...this.pageLevelErrorMessageList, {index: dmlIndex, errorMessage: exceptionWrapper.DMLErrorMessageMapping[dmlIndex]}];
                            }
                        } else {
                            // If there is a specific field that each error is supposed to go to, show it on the field on the page.
                            // If it is not on the page to show, display it on the page level.
                            for (const key in exceptionWrapper.DMLErrorFieldNameMapping) {

                                // List of fields with this error
                                let fieldList = exceptionWrapper.DMLErrorFieldNameMapping[key];

                                // Error message for the field.
                                let errorMessage = exceptionWrapper.DMLErrorMessageMapping[key];

                                // Errored fields that are not displayed
                                let hiddenFieldList = [];

                                fieldList.forEach(fieldWithError => {
                                    // Go to the field and set the error message using setCustomValidity
                                    if (fieldWithError in allDisplayedFields) {
                                        let fieldInput = allDisplayedFields[fieldWithError];
                                        this.erroredFields.push(fieldInput);

                                        fieldInput.setCustomValidity(errorMessage);
                                    } else {

                                        // Keep track of errored fields that are not displayed.
                                        hiddenFieldList.push(fieldWithError);
                                    }
                                });

                                // If there are hidden fields, display the error message at the page level.
                                // With the fields noted.
                                if (hiddenFieldList.length > 0) {
                                    let combinedFields = hiddenFieldList.join(', ');

                                    this.pageLevelErrorMessageList = [...this.pageLevelErrorMessageList, {index: key, errorMessage: errorMessage + ' [' + combinedFields + ']'}];
                                }
                            }
                        }
                    } else {
                        pageLevelErrorMessageList = [...pageLevelErrorMessageList, {index: 0, errorMessage: exceptionWrapper.errorMessage}];
                    }

                    // focus either the page level or field level error messsage somehow
                    window.scrollTo(0,0);
                }) ;
        }
    }

    isFormValid(sectionsList){
        let invalidFields = [];
        sectionsList.forEach(section => {
            const fields = section.getInvalidFields();
            invalidFields.push(...fields);
        });

        if(invalidFields.length > 0){
            let fieldListAsString = invalidFields.join(', ');
            showToast('Invalid Form', 'The following fields are required: ' + fieldListAsString, 'error');
        }

        return invalidFields.length === 0;
    }

    navigateToRecordPage(recordId) {
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: recordId,
                actionName: 'view'
            }
        });
    }

    // change showSpinner to the opposite of its current value
    toggleSpinner() {
        this.showSpinner = !this.showSpinner;
    }

    getDisplayedFieldsMappedByAPIName(sectionsList) {
        let allFields = {};
        sectionsList.forEach(section => {
            const fields = section.getAllFieldsByAPIName();

            allFields = Object.assign(allFields, fields);
        });

        return allFields;
    }

    clearErrors() {

        // Clear the page level error
        this.pageLevelErrorMessageList = [];

        // Clear the field level errors
        if (this.erroredFields.length > 0) {
            this.erroredFields.forEach(fieldToReset => {
                fieldToReset.setCustomValidity('');
            });
        }

        this.erroredFields = [];
    }
}<commit_msg>updated var names with donor record<commit_after>import { LightningElement, api, track, wire } from 'lwc';
import GeFormService from 'c/geFormService';
import { NavigationMixin } from 'lightning/navigation';
import messageLoading from '@salesforce/label/c.labelMessageLoading';
import geSave from '@salesforce/label/c.labelGeSave';
import geCancel from '@salesforce/label/c.labelGeCancel';
import { showToast, handleError, getRecordFieldNames, setRecordValuesOnTemplate } from 'c/utilTemplateBuilder';
import { getQueryParameters } from 'c/utilCommon';
import { getRecord } from 'lightning/uiRecordApi';
import FORM_TEMPLATE_FIELD from '@salesforce/schema/DataImportBatch__c.Form_Template__c';
import TEMPLATE_JSON_FIELD from '@salesforce/schema/Form_Template__c.Template_JSON__c';

export default class GeFormRenderer extends NavigationMixin(LightningElement) {
    @api donorRecordId = '';
    @api donorRecord;
    fieldNames = [];
    @api sections = [];
    @track ready = false;
    @track name = '';
    @track description = '';
    @track mappingSet = '';
    @track version = '';
    @api showSpinner = false;
    @api batchId;
    @api submissions = [];
    @api hasPageLevelError = false;
    label = { messageLoading, geSave, geCancel };
    @track formTemplateId;
    erroredFields = [];
    @api pageLevelErrorMessageList = [];

    @wire(getRecord, { recordId: '$donorRecordId', optionalFields: '$fieldNames'})
    wiredGetRecordMethod({ error, data }) {
        if (data) {
            this.donorRecord = data;
            this.handleGetTemplate();
        } else if (error) {
            console.error(JSON.stringify(error));
        }
    }

    connectedCallback() {

        if (this.batchId) {
            // When the form is being used for Batch Gift Entry, the Form Template JSON
            // uses the @wire service below to retrieve the Template using the Template Id
            // stored on the Batch.
            return;
        }

        // check if there is a record id in the url
        this.donorRecordId = getQueryParameters().c__recordId;

        GeFormService.getFormTemplate().then(response => {
            // read the template header info
            if(response !== null && typeof response !== 'undefined') {
                const { formTemplate } = response;
                const fieldMappings = response.fieldMappingSetWrapper.fieldMappingByDevName;

                // get the target field names to be used by getRecord
                this.fieldNames = getRecordFieldNames(formTemplate, fieldMappings);
            }
        });
    }

    handleGetTemplate = async () => {
        let response = await GeFormService.getFormTemplate();

        if (response !== null && typeof response !== 'undefined') {
            this.initializeForm(response);
        }
    }

    initializeForm(response) {
        const { formTemplate } = response;
        const fieldMappings = response.fieldMappingSetWrapper.fieldMappingByDevName;

        // read the template header info
        this.ready = true;
        this.name = formTemplate.name;
        this.description = formTemplate.description;
        this.version = formTemplate.layout.version;
        if (typeof formTemplate.layout !== 'undefined'
            && Array.isArray(formTemplate.layout.sections)) {

            // add record data to the template fields
            let sectionsWithValues = setRecordValuesOnTemplate(formTemplate.layout.sections, fieldMappings, this.donorRecord);
            this.sections = sectionsWithValues;
            this.dispatchEvent(new CustomEvent('sectionsretrieved'));
        }
    }

    @wire(getRecord, {
        recordId: '$batchId',
        fields: FORM_TEMPLATE_FIELD
    })
    wiredBatch({data, error}) {
        if (data) {
            this.formTemplateId = data.fields[FORM_TEMPLATE_FIELD.fieldApiName].value;
        } else if (error) {
            handleError(error);
        }
    }

    @wire(getRecord, {
        recordId: '$formTemplateId',
        fields: TEMPLATE_JSON_FIELD
    })
    wiredTemplate({data, error}) {
        if (data) {
            this.loadTemplate(
                JSON.parse(data.fields[TEMPLATE_JSON_FIELD.fieldApiName].value));
        } else if (error) {
            handleError(error);
        }
    }

    async loadTemplate(formTemplate){
        // With the change to using a Lookup field to connect a Batch to a Template,
        // we can use getRecord to get the Template JSON.  But the GeFormService
        // component still needs to be initialized with the field mappings, and the
        // call to getFormTemplate() does that.
        // TODO: Maybe initialize GeFormService with the field mappings in its connected
        //       callback instead?
        await GeFormService.getFormTemplate();
        this.initializeForm(formTemplate);
    }

    handleCancel() {
        console.log('Form Cancel button clicked');
    }

    handleSave(event) {
        event.target.disabled = true;
        const enableSaveButton = function() {
            this.disabled = false;
        }.bind(event.target);

        this.clearErrors();

        // TODO: Pass the actual Data Import record, and navigate to the new Opportunity
        // const OpportunityId = GeFormService.createOpportunityFromDataImport(dataImport);
        const sectionsList = this.template.querySelectorAll('c-ge-form-section');

        if(!this.isFormValid(sectionsList)){
            return;
        }

        // show the spinner
        this.toggleSpinner();

        // callback used to toggle spinner after save
        const toggleSpinner = () => this.toggleSpinner();

        if (this.batchId) {
            const submission = {
                sectionsList: sectionsList
            };
            this.submissions.push(submission);
            this.dispatchEvent(new CustomEvent('submit', {
                detail: {
                    success: function () {
                        enableSaveButton();
                        toggleSpinner();
                    },
                    error: function() {
                        enableSaveButton();
                        toggleSpinner();
                    }
                }
            }));
        } else {
            GeFormService.handleSave(sectionsList, this.record).then(opportunityId => {
                this.navigateToRecordPage(opportunityId);
            })
                .catch(error => {

                    this.toggleSpinner();

                    // Show on top if it is a page level
                    this.hasPageLevelError = true;
                    const exceptionWrapper = JSON.parse(error.body.message);
                    const allDisplayedFields = this.getDisplayedFieldsMappedByAPIName(sectionsList);

                    if (exceptionWrapper.exceptionType !== null && exceptionWrapper.exceptionType !== '') {

                        // Check to see if there are any field level errors
                        if (Object.entries(exceptionWrapper.DMLErrorFieldNameMapping).length === undefined || Object.entries(exceptionWrapper.DMLErrorFieldNameMapping).length === 0) {

                            // If there are no specific fields the error has to go to, put it on the page level error message.
                            for (const dmlIndex in exceptionWrapper.DMLErrorMessageMapping) {
                                this.pageLevelErrorMessageList = [...this.pageLevelErrorMessageList, {index: dmlIndex, errorMessage: exceptionWrapper.DMLErrorMessageMapping[dmlIndex]}];
                            }
                        } else {
                            // If there is a specific field that each error is supposed to go to, show it on the field on the page.
                            // If it is not on the page to show, display it on the page level.
                            for (const key in exceptionWrapper.DMLErrorFieldNameMapping) {

                                // List of fields with this error
                                let fieldList = exceptionWrapper.DMLErrorFieldNameMapping[key];

                                // Error message for the field.
                                let errorMessage = exceptionWrapper.DMLErrorMessageMapping[key];

                                // Errored fields that are not displayed
                                let hiddenFieldList = [];

                                fieldList.forEach(fieldWithError => {
                                    // Go to the field and set the error message using setCustomValidity
                                    if (fieldWithError in allDisplayedFields) {
                                        let fieldInput = allDisplayedFields[fieldWithError];
                                        this.erroredFields.push(fieldInput);

                                        fieldInput.setCustomValidity(errorMessage);
                                    } else {

                                        // Keep track of errored fields that are not displayed.
                                        hiddenFieldList.push(fieldWithError);
                                    }
                                });

                                // If there are hidden fields, display the error message at the page level.
                                // With the fields noted.
                                if (hiddenFieldList.length > 0) {
                                    let combinedFields = hiddenFieldList.join(', ');

                                    this.pageLevelErrorMessageList = [...this.pageLevelErrorMessageList, {index: key, errorMessage: errorMessage + ' [' + combinedFields + ']'}];
                                }
                            }
                        }
                    } else {
                        pageLevelErrorMessageList = [...pageLevelErrorMessageList, {index: 0, errorMessage: exceptionWrapper.errorMessage}];
                    }

                    // focus either the page level or field level error messsage somehow
                    window.scrollTo(0,0);
                }) ;
        }
    }

    isFormValid(sectionsList){
        let invalidFields = [];
        sectionsList.forEach(section => {
            const fields = section.getInvalidFields();
            invalidFields.push(...fields);
        });

        if(invalidFields.length > 0){
            let fieldListAsString = invalidFields.join(', ');
            showToast('Invalid Form', 'The following fields are required: ' + fieldListAsString, 'error');
        }

        return invalidFields.length === 0;
    }

    navigateToRecordPage(recordId) {
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: recordId,
                actionName: 'view'
            }
        });
    }

    // change showSpinner to the opposite of its current value
    toggleSpinner() {
        this.showSpinner = !this.showSpinner;
    }

    getDisplayedFieldsMappedByAPIName(sectionsList) {
        let allFields = {};
        sectionsList.forEach(section => {
            const fields = section.getAllFieldsByAPIName();

            allFields = Object.assign(allFields, fields);
        });

        return allFields;
    }

    clearErrors() {

        // Clear the page level error
        this.pageLevelErrorMessageList = [];

        // Clear the field level errors
        if (this.erroredFields.length > 0) {
            this.erroredFields.forEach(fieldToReset => {
                fieldToReset.setCustomValidity('');
            });
        }

        this.erroredFields = [];
    }
}<|endoftext|>


<commit_before>import { inject as service } from '@ember/service';
import { get, set, computed } from '@ember/object';
import Component from '@ember/component';
import layout from '../templates/components/tour-start-button';
import { typeOf as getTypeOf } from '@ember/utils';
import { task, timeout } from 'ember-concurrency';
import Ember from 'ember';

export default Component.extend({

  // ---------------------------------------------------------------------------------------------------------
  // Properties

  layout,

  tourManager: service('tourManager'),
  attributeBindings: ['data-test-start-tour'],

  // ---------------------------------------------------------------------------------------------------------
  // Attributes

  'data-test-start-tour': true,

  /**
   * The tour object for this button.
   *
   * @attribute tour
   * @type {EmberTour.Object.Tour}
   * @required
   * @public
   */
  tour: null,

  /**
   * An optional model.
   * This is passed to the steps and can be used to only show steps if certain criteria pass.
   *
   * @attribute model
   * @type {Mixed}
   * @optional
   * @public
   */
  model: null,

  /**
   * A text for a callout.
   * If this is not set, not callout will be displayed.
   *
   * @attribute callout
   * @type {String}
   * @optional
   * @public
   */
  callout: null,

  /**
   * The placement for the callout.
   *
   * @attribute calloutPlacement
   * @type {'top'|'right'|'bottom'|'left'}
   * @default 'top'
   * @optional
   * @public
   */
  calloutPlacement: 'top',

  /**
   * The title for the callout.
   *
   * @attribute calloutTitle
   * @type {String}
   * @default 'Start a tour!',
   * @optional
   * @public
   */
  calloutTitle: 'Start a tour!',

  /**
   * This action is called when the tour starts.
   *
   * @event tourStarted
   * @param {Object} The tour object
   * @public
   */
  tourStarted: null,

  /**
   * This action is called when the tour ends after the last step.
   *
   * @event tourEnded
   * @param {Object} The tour object
   * @public
   */
  tourEnded: null,

  /**
   * This action is called when the tour is closed before the last step.
   *
   * @event tourClosed
   * @param {Object} The tour object
   * @public
   */
  tourClosed: null,

  /**
   * This action is called when the callout is displayed.
   *
   * @event calloutShown
   * @param {Object} The tour object
   * @public
   */
  calloutShown: null,

  /**
   * This action is called when the callout is closed manually.
   *
   * @event calloutClosed
   * @param {Object} The tour object
   * @public
   */
  calloutClosed: null,

  // Properties

  calloutTimeoutTime: computed(function() {
    return Ember.testing ? 1 : 2000;
  }),

  // ---------------------------------------------------------------------------------------------------------
  // Methods

  /**
   * Setup the tour & event listeners.
   * Also show the callout if it is available.
   *
   * @method didInsertElement
   * @protected
   * @override
   */
  didInsertElement() {
    this._super(...arguments);

    get(this, '_setupCalloutTask').perform();
    this._setupEventListeners();
  },

  /**
   * When the element is destroyed, tear down the event listeners & timers.
   *
   * @method willDestroyElement
   * @protected
   * @override
   */
  willDestroyElement() {
    this._tearDownEventListeners();

    let tour = get(this, 'tour');
    if (tour) {
      tour.hideCallout({ markAsRead: false });
    }

    this._super(...arguments);
  },

  /**
   * On click, start the tour.
   *
   * @event click
   * @protected
   */
  click() {
    let tour = get(this, 'tour');
    tour.start();
  },

  _sendAction(actionName, ...args) {
    let action = get(this, actionName);
    if (action && getTypeOf(action) === 'function') {
      return action(...args);
    }
  },

  _eventListeners: null,

  /**
   * Setup the tour event listeners.
   *
   * @method _setupEventListeners
   * @private
   */
  _setupEventListeners() {
    let tour = get(this, 'tour');
    if (!tour) {
      return;
    }

    let eventListeners = {
      'tour-start': (e) => {
        this._sendAction('tourStarted', e);
      },
      'tour.end': (e) => {
        this._sendAction('tourEnded', e);
      },
      'tour.close': (e) => {
        this._sendAction('tourClosed', e);
      },
      'callout.show': (e) => {
        this._sendAction('calloutShown', e);
      },
      'callout.close': (e) => {
        this._sendAction('calloutClosed', e);
      }
    };

    tour.on('tour.start', eventListeners['tour.start']);
    tour.on('tour.end', eventListeners['tour.end']);
    tour.on('tour.close', eventListeners['tour.close']);
    tour.on('callout.show', eventListeners['callout.show']);
    tour.on('callout.close', eventListeners['callout.close']);

    set(this, '_eventListeners', eventListeners);
  },

  /**
   * Tear down the tour's event listeners.
   *
   * @method _tearDownEventListeners
   * @private
   */
  _tearDownEventListeners() {
    let tour = get(this, 'tour');
    let eventListeners = get(this, '_eventListeners');

    if (!tour) {
      return;
    }

    tour.off('tour.start', eventListeners['tour.start']);
    tour.off('tour.end', eventListeners['tour.end']);
    tour.off('tour.close', eventListeners['tour.close']);
    tour.off('callout.show', eventListeners['callout.show']);
    tour.off('callout.close', eventListeners['callout.close']);
  },

  _setupCalloutTask: task(function* () {
    let tourManager = get(this, 'tourManager');
    let tour = get(this, 'tour');
    let calloutTimeoutTime = get(this, 'calloutTimeoutTime');
    let callout = get(this, 'callout');
    let placement = get(this, 'calloutPlacement') || 'top';

    let { element } = this;
    let [target] = element.children;

    if (!tour || !callout || !target) {
      return;
    }

    tourManager.addCallout(tour, {
      calloutMessage: callout,
      placement,
      target
    });

    yield timeout(calloutTimeoutTime);

    tour.showCallout();
  })
});
<commit_msg>Fix typo in tour event listener<commit_after>import { inject as service } from '@ember/service';
import { get, set, computed } from '@ember/object';
import Component from '@ember/component';
import layout from '../templates/components/tour-start-button';
import { typeOf as getTypeOf } from '@ember/utils';
import { task, timeout } from 'ember-concurrency';
import Ember from 'ember';

export default Component.extend({

  // ---------------------------------------------------------------------------------------------------------
  // Properties

  layout,

  tourManager: service('tourManager'),
  attributeBindings: ['data-test-start-tour'],

  // ---------------------------------------------------------------------------------------------------------
  // Attributes

  'data-test-start-tour': true,

  /**
   * The tour object for this button.
   *
   * @attribute tour
   * @type {EmberTour.Object.Tour}
   * @required
   * @public
   */
  tour: null,

  /**
   * An optional model.
   * This is passed to the steps and can be used to only show steps if certain criteria pass.
   *
   * @attribute model
   * @type {Mixed}
   * @optional
   * @public
   */
  model: null,

  /**
   * A text for a callout.
   * If this is not set, not callout will be displayed.
   *
   * @attribute callout
   * @type {String}
   * @optional
   * @public
   */
  callout: null,

  /**
   * The placement for the callout.
   *
   * @attribute calloutPlacement
   * @type {'top'|'right'|'bottom'|'left'}
   * @default 'top'
   * @optional
   * @public
   */
  calloutPlacement: 'top',

  /**
   * The title for the callout.
   *
   * @attribute calloutTitle
   * @type {String}
   * @default 'Start a tour!',
   * @optional
   * @public
   */
  calloutTitle: 'Start a tour!',

  /**
   * This action is called when the tour starts.
   *
   * @event tourStarted
   * @param {Object} The tour object
   * @public
   */
  tourStarted: null,

  /**
   * This action is called when the tour ends after the last step.
   *
   * @event tourEnded
   * @param {Object} The tour object
   * @public
   */
  tourEnded: null,

  /**
   * This action is called when the tour is closed before the last step.
   *
   * @event tourClosed
   * @param {Object} The tour object
   * @public
   */
  tourClosed: null,

  /**
   * This action is called when the callout is displayed.
   *
   * @event calloutShown
   * @param {Object} The tour object
   * @public
   */
  calloutShown: null,

  /**
   * This action is called when the callout is closed manually.
   *
   * @event calloutClosed
   * @param {Object} The tour object
   * @public
   */
  calloutClosed: null,

  // Properties

  calloutTimeoutTime: computed(function() {
    return Ember.testing ? 1 : 2000;
  }),

  // ---------------------------------------------------------------------------------------------------------
  // Methods

  /**
   * Setup the tour & event listeners.
   * Also show the callout if it is available.
   *
   * @method didInsertElement
   * @protected
   * @override
   */
  didInsertElement() {
    this._super(...arguments);

    get(this, '_setupCalloutTask').perform();
    this._setupEventListeners();
  },

  /**
   * When the element is destroyed, tear down the event listeners & timers.
   *
   * @method willDestroyElement
   * @protected
   * @override
   */
  willDestroyElement() {
    this._tearDownEventListeners();

    let tour = get(this, 'tour');
    if (tour) {
      tour.hideCallout({ markAsRead: false });
    }

    this._super(...arguments);
  },

  /**
   * On click, start the tour.
   *
   * @event click
   * @protected
   */
  click() {
    let tour = get(this, 'tour');
    tour.start();
  },

  _sendAction(actionName, ...args) {
    let action = get(this, actionName);
    if (action && getTypeOf(action) === 'function') {
      return action(...args);
    }
  },

  _eventListeners: null,

  /**
   * Setup the tour event listeners.
   *
   * @method _setupEventListeners
   * @private
   */
  _setupEventListeners() {
    let tour = get(this, 'tour');
    if (!tour) {
      return;
    }

    let eventListeners = {
      'tour.start': (e) => {
        this._sendAction('tourStarted', e);
      },
      'tour.end': (e) => {
        this._sendAction('tourEnded', e);
      },
      'tour.close': (e) => {
        this._sendAction('tourClosed', e);
      },
      'callout.show': (e) => {
        this._sendAction('calloutShown', e);
      },
      'callout.close': (e) => {
        this._sendAction('calloutClosed', e);
      }
    };

    tour.on('tour.start', eventListeners['tour.start']);
    tour.on('tour.end', eventListeners['tour.end']);
    tour.on('tour.close', eventListeners['tour.close']);
    tour.on('callout.show', eventListeners['callout.show']);
    tour.on('callout.close', eventListeners['callout.close']);

    set(this, '_eventListeners', eventListeners);
  },

  /**
   * Tear down the tour's event listeners.
   *
   * @method _tearDownEventListeners
   * @private
   */
  _tearDownEventListeners() {
    let tour = get(this, 'tour');
    let eventListeners = get(this, '_eventListeners');

    if (!tour) {
      return;
    }

    tour.off('tour.start', eventListeners['tour.start']);
    tour.off('tour.end', eventListeners['tour.end']);
    tour.off('tour.close', eventListeners['tour.close']);
    tour.off('callout.show', eventListeners['callout.show']);
    tour.off('callout.close', eventListeners['callout.close']);
  },

  _setupCalloutTask: task(function* () {
    let tourManager = get(this, 'tourManager');
    let tour = get(this, 'tour');
    let calloutTimeoutTime = get(this, 'calloutTimeoutTime');
    let callout = get(this, 'callout');
    let placement = get(this, 'calloutPlacement') || 'top';

    let { element } = this;
    let [target] = element.children;

    if (!tour || !callout || !target) {
      return;
    }

    tourManager.addCallout(tour, {
      calloutMessage: callout,
      placement,
      target
    });

    yield timeout(calloutTimeoutTime);

    tour.showCallout();
  })
});
<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Mixin.create({
  init: function (...args) {
    this._super.apply(this, args);

    this.set('boundClickoutHandler', Ember.run.bind(this, this.clickoutHandler));
    this.set('boundEscapeHandler', Ember.run.bind(this, this.escapeHandler));
  },

  onOpen: Ember.K,
  onClose: Ember.K,

  dropdownExpanded: false,

  dropdownToggleSelector: '.rl-dropdown-toggle',

  dropdownSelector: '.rl-dropdown',

  closingEventNamespace: 'rl-dropdown',

  closeOnEscape: true,

  actions: {
    toggleDropdown: function () {
      this.toggleProperty('dropdownExpanded');

      if (this.get('dropdownExpanded')) {
        this.get('onOpen')();
      } else {
        this.get('onClose')();
      }
    },

    openDropdown: function () {
      this.set('dropdownExpanded', true);
      this.get('onOpen')();
    },

    closeDropdown: function () {
      this.set('dropdownExpanded', false);
      this.get('onClose')();
    }
  },

  manageClosingEvents: Ember.on('didInsertElement', Ember.observer('dropdownExpanded', function () {
    let namespace = this.get('closingEventNamespace');
    let clickEventName = 'click.'+ namespace;
    let touchEventName = 'touchstart.'+ namespace;
    let escapeEventName = 'keydown.'+ namespace;
    let component = this;
    let $document = Ember.$(document);

    if (this.get('dropdownExpanded')) {

      /* Add clickout handler with 1ms delay, to allow opening the dropdown
       * by clicking e.g. a checkbox and binding to dropdownExpanded, without
       * having the handler close the dropdown immediately. */
      Ember.run.later(() => {
        $document.bind(clickEventName, {component: component}, component.boundClickoutHandler);
        $document.bind(touchEventName, {component: component}, component.boundClickoutHandler);
      }, 1);

      if (this.get('closeOnEscape')) {
        $document.bind(escapeEventName, {component: component}, component.boundEscapeHandler);
      }
    } else {
      $document.unbind(clickEventName, component.boundClickoutHandler);
      $document.unbind(touchEventName, component.boundClickoutHandler);
      $document.unbind(escapeEventName, component.boundEscapeHandler);
    }
  })),

  unbindClosingEvents: Ember.on('willDestroyElement', function () {
    let namespace = this.get('closingEventNamespace');
    let $document = Ember.$(document);

    $document.unbind('click.'+ namespace, this.boundClickoutHandler);
    $document.unbind('touchstart.'+ namespace, this.boundClickoutHandler);
    $document.unbind('keydown.'+ namespace, this.boundEscapeHandler);
  }),

  clickoutHandler(event) {
    let component = event.data.component;
    let $c = component.$();
    let $target = Ember.$(event.target);

    /* There is an issue when the click triggered a dom change in the
     * dropdown that unloaded the target element. The ancestry of the target
     * can no longer be determined. We can check if html is still an ancestor
     * to determine if this has happened. The safe option then seems to be to
     * not close the dropdown, as occasionaly not closing the dropdown when it
     * should have closed, seems to be less bad for usability than occasionaly
     * closing the dropdown when it should not have closed.
     */
    if(component.get('dropdownExpanded') && $target.closest('html').length &&
      !($target.closest($c.find(component.get('dropdownToggleSelector'))).length ||
      $target.closest($c.find(component.get('dropdownSelector'))).length)
    ) {
      component.send('closeDropdown');
    }
  },

  escapeHandler(event) {
    if (event.keyCode === 27) {
      event.data.component.send('closeDropdown');
    }
  }
});
<commit_msg>Close dropdowns on 'focusin' event (#18)<commit_after>import Ember from 'ember';

export default Ember.Mixin.create({
  init: function (...args) {
    this._super.apply(this, args);

    this.set('boundClickoutHandler', Ember.run.bind(this, this.clickoutHandler));
    this.set('boundEscapeHandler', Ember.run.bind(this, this.escapeHandler));
  },

  onOpen: Ember.K,
  onClose: Ember.K,

  dropdownExpanded: false,

  dropdownToggleSelector: '.rl-dropdown-toggle',

  dropdownSelector: '.rl-dropdown',

  closingEventNamespace: 'rl-dropdown',

  closeOnEscape: true,

  actions: {
    toggleDropdown: function () {
      this.toggleProperty('dropdownExpanded');

      if (this.get('dropdownExpanded')) {
        this.get('onOpen')();
      } else {
        this.get('onClose')();
      }
    },

    openDropdown: function () {
      this.set('dropdownExpanded', true);
      this.get('onOpen')();
    },

    closeDropdown: function () {
      this.set('dropdownExpanded', false);
      this.get('onClose')();
    }
  },

  manageClosingEvents: Ember.on('didInsertElement', Ember.observer('dropdownExpanded', function () {
    let namespace = this.get('closingEventNamespace');
    let clickEventName = 'click.'+ namespace;
    let focusEventName = 'focusin.'+ namespace;
    let touchEventName = 'touchstart.'+ namespace;
    let escapeEventName = 'keydown.'+ namespace;
    let component = this;
    let $document = Ember.$(document);

    if (this.get('dropdownExpanded')) {

      /* Add clickout handler with 1ms delay, to allow opening the dropdown
       * by clicking e.g. a checkbox and binding to dropdownExpanded, without
       * having the handler close the dropdown immediately. */
      Ember.run.later(() => {
        $document.bind(clickEventName, {component: component}, component.boundClickoutHandler);
        $document.bind(focusEventName, {component: component}, component.boundClickoutHandler);
        $document.bind(touchEventName, {component: component}, component.boundClickoutHandler);
      }, 1);

      if (this.get('closeOnEscape')) {
        $document.bind(escapeEventName, {component: component}, component.boundEscapeHandler);
      }
    } else {
      $document.unbind(clickEventName, component.boundClickoutHandler);
      $document.unbind(focusEventName, component.boundClickoutHandler);
      $document.unbind(touchEventName, component.boundClickoutHandler);
      $document.unbind(escapeEventName, component.boundEscapeHandler);
    }
  })),

  unbindClosingEvents: Ember.on('willDestroyElement', function () {
    let namespace = this.get('closingEventNamespace');
    let $document = Ember.$(document);

    $document.unbind('click.'+ namespace, this.boundClickoutHandler);
    $document.unbind('focusin.'+ namespace, this.boundClickoutHandler);
    $document.unbind('touchstart.'+ namespace, this.boundClickoutHandler);
    $document.unbind('keydown.'+ namespace, this.boundEscapeHandler);
  }),

  clickoutHandler(event) {
    let component = event.data.component;
    let $c = component.$();
    let $target = Ember.$(event.target);

    /* There is an issue when the click triggered a dom change in the
     * dropdown that unloaded the target element. The ancestry of the target
     * can no longer be determined. We can check if html is still an ancestor
     * to determine if this has happened. The safe option then seems to be to
     * not close the dropdown, as occasionaly not closing the dropdown when it
     * should have closed, seems to be less bad for usability than occasionaly
     * closing the dropdown when it should not have closed.
     */
    if(component.get('dropdownExpanded') && $target.closest('html').length &&
      !($target.closest($c.find(component.get('dropdownToggleSelector'))).length ||
      $target.closest($c.find(component.get('dropdownSelector'))).length)
    ) {
      component.send('closeDropdown');
    }
  },

  escapeHandler(event) {
    if (event.keyCode === 27) {
      event.data.component.send('closeDropdown');
    }
  }
});
<|endoftext|>


<commit_before>'use strict';

var keypress 	  = require('keypress');
var RollingSpider = require('rolling-spider');
var colors 		  = require('colors');

var uuid = 'ff5af834737b41e6afd3a66260315f86';

// Hello World! :D
console.log('***** PARROT PILOT *****'.yellow);

// Make `process.stdin` begin emitting "keypress" events
keypress(process.stdin);

// Connecting to drone...
var rs = new RollingSpider({'uuid': uuid});

// NEW CODE BELOW HERE

rs.connect(function() {

	console.log('[INFO] Connecting to: '.green + uuid.green);

  	rs.setup(function() {
  			console.log('[INFO] Connected to: '.green + uuid.green);
  	});
});

// Listening for the "keypress" event
process.stdin.on('keypress', function (ch, key) {

	// Takeoff...
	if (key && key.name == 't') {
		try {
		  rs.calibrate(function() {
		  	rs.takeOff(function() {
	          	console.log('[INFO] Rolling Spider take-off completed'.green);
		  	});
		  });
   		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}
	};

	// Process flightplan
	if(key && key.name == 'f') {
		console.log('[INFO] We have a plan... Let\'s fly!'.green);

		try {

		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}
	}

	// Emergency landing...
	if (key && key.name == 'e') {
		console.log('[INFO] Emergency landing!'.red);

		try {
			rs.calibrate(function() {
				rs.emergency();
			});
		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}

		process.exit();
	};

	if (key && key.name == 'l') {
		// A normal landing...
		console.log('[INFO] Landing...'.green);

		try {
			rs.calibrate(function() {
				rs.land();
			});
		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}
	}

	if (key && key.name == 'x') {
		try {
			rs.calibrate(function() {
				rs.land(function() {
					rs.disconnect();
				});
			});
		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}

		console.log('***** GOODBYE! *****'.rainbow);
		process.exit();
	}
});

process.stdin.setRawMode(true);
process.stdin.resume();<commit_msg>Rotating<commit_after>'use strict';

var keypress 	  = require('keypress');
var RollingSpider = require('rolling-spider');
var colors 		  = require('colors');

var uuid = 'ff5af834737b41e6afd3a66260315f86';

// Hello World! :D
console.log('***** PARROT PILOT *****'.yellow);

// Make `process.stdin` begin emitting "keypress" events
keypress(process.stdin);

// Connecting to drone...
var rs = new RollingSpider({'uuid': uuid});

// NEW CODE BELOW HERE

rs.connect(function() {

	console.log('[INFO] Connecting to: '.green + uuid.green);

  	rs.setup(function() {
  			console.log('[INFO] Connected to: '.green + uuid.green);
  	});
});

// Listening for the "keypress" event
process.stdin.on('keypress', function (ch, key) {

	// Takeoff...
	if (key && key.name == 't') {
		try {
		  rs.calibrate(function() {
		  	rs.takeOff(function() {
	          	console.log('[INFO] Rolling Spider take-off completed'.green);
		  	});
		  });
   		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}
	};

	// Process flightplan
	if(key && key.name == 'f') {
		console.log('[INFO] We have a plan... Let\'s fly!'.green);

		try {

		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}
	}

	// Emergency landing...
	if (key && key.name == 'e') {
		console.log('[INFO] Emergency landing!'.red);

		try {
			rs.calibrate(function() {
				rs.emergency(function() {
					rs.disconnect();
				});
			});
		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}

		process.exit();
	};

	if (key && key.name == 'l') {
		// A normal landing...
		console.log('[INFO] Landing...'.green);

		try {
			rs.calibrate(function() {
				rs.land();
			});
		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}
	}

	if (key && key.name == 'r') {
		// A normal landing...
		console.log('[INFO] Rotating clockwise...'.green);

		try {
			rs.calibrate(function() {
				rs.clockwise({
					'speed': 50,
					'steps': 50
				});
			});
		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}
	}

	if (key && key.name == 'x') {
		try {
			rs.calibrate(function() {
				rs.land(function() {
					rs.disconnect();
				});
			});
		} catch(err) {
			console.log('[ERROR] '.red + err.red);
		}

		console.log('***** GOODBYE! *****'.rainbow);
		process.exit();
	}
});

process.stdin.setRawMode(true);
process.stdin.resume();<|endoftext|>