<commit_before>module.exports = function (window) {
    "use strict";

    require('./css/i-checkbox.css');
    require('itags.core')(window);

    var itagName = 'i-checkbox', // <-- define your own itag-name here
        ITSA = window.ITSA,
        Event = ITSA.Event,
        later = ITSA.later,
        DEFAULT_ON_TEXT = 'I',
        DEFAULT_OFF_TEXT = 'O',
        SUPPRESS_DELAY = 50,
        INTERVAL_FONTCHANGE_CHECK = 350,
        Itag, IFormElement, registeredElements, timer, registerElement, unRegisterElement;

    if (!window.ITAGS[itagName]) {
        ITSA.DD.init();

        registeredElements = [];
        IFormElement = require('i-formelement')(window);

        Event.before(itagName+':manualfocus', function(e) {
            // the i-select itself is unfocussable, but its button is
            // we need to patch `manualfocus`,
            // which is emitted on node.focus()
            // a focus by userinteraction will always appear on the button itself
            // so we don't bother that
            var element = e.target;
            e.preventDefault();
            element.itagReady().then(
                function() {
                    var focusNode = element.getElement('>span');
                    focusNode && focusNode.focus(true, true);
                }
            );
        });

        Event.after('tap', function(e) {
            var element = e.target,
                model = element.model,
                focusNode;
            if (!element.hasData('_suppressTap')) {
                model.checked = !model.checked;
                focusNode = element.getElement('>span');
                focusNode.hasFocus() || focusNode.focus();
            }
        }, 'i-checkbox');

        Event.after('keypress', function(e) {
            var element = e.target,
                model = element.model;
            (e.charCode===32) && (model.checked=!model.checked);
        }, 'i-checkbox');

        Event.after('dd-drag', function(e) {
            var checkbox = e.target.inside('i-checkbox');
            checkbox.setData('_suppressTap', true);
        }, 'i-checkbox');

        Event.after('dd-drop', function(e) {
            var dragNode = e.target,
                checkbox = dragNode.inside('i-checkbox'),
                btnNode = dragNode.getElement('>.i-btn'),
                distance = btnNode.left - checkbox.left - checkbox.getData('_leftBorder') + Math.round(checkbox.getData('_height')/2);
            checkbox.model.checked = (distance>Math.round(checkbox.getData('_width')/2));
            checkbox._setUIState();
            later(function() {
                checkbox.removeData('_suppressTap');
            }, SUPPRESS_DELAY);
        }, 'i-checkbox');

        Event.defineEvent(itagName+':checkedchange').unPreventable();

        Event.after(itagName+':change', function(e) {
            var element = e.target,
                model = element.model;
            /**
            * Emitted when a the i-checkbox changes its `checked`-value
            *
            * @event i-checkbox:checkedchange
            * @param e {Object} eventobject including:
            * @param e.target {HtmlElement} the i-checkbox element
            * @param e.prevValue {Boolean}
            * @param e.newValue {Boolean}
            * @since 0.1
            */
            element.emit('checkedchange', {
                prevValue: !model.checked,
                newValue: model.checked
            });
        });

        // whenever fontsize changes, the calculated height needs to change
        // we have no means of listening to this - even it's unlikely to happen
        // yet we want the i-checkboxes to fit at anytime, so we set up a lazy timer
        // that checks all registered itag-instances

        registerElement = function(element) {
            registeredElements.push(element);
            if (!timer) {
                timer = later(function() {
                    var len = registeredElements.length,
                        i, element;
                    for (i=0; i<len; i++) {
                        element = registeredElements[i];
                        if (!element.hasData('_suppressTap')) {
                            element._fitCheckbox();
                            element._setUIState();
                        }
                    }
                }, INTERVAL_FONTCHANGE_CHECK, true);
            }
        };

        unRegisterElement = function(element) {
            registeredElements.remove(element);
            if ((registeredElements.length===0) && timer) {
                timer.cancel();
                timer = null;
            }
        };

        Itag = IFormElement.subClass(itagName, {
            attrs: {
                checked: 'boolean',
                'reset-value': 'boolean'
            },

            init: function() {
                var element = this,
                    value = element.model.checked,
                    designNode = element.getItagContainer(),
                    options = designNode.getAll('>option');

                // set the reset-value to the inital-value in case `reset-value` was not present
                element.defineWhenUndefined('reset-value', value)
                       .defineWhenUndefined('on-text', options[0] ? options[0].getHTML() : DEFAULT_ON_TEXT)
                       .defineWhenUndefined('off-text', options[1] ? options[1].getHTML() : DEFAULT_OFF_TEXT);
                registerElement(element);
            },

            render: function() {
                var element = this,
                    content, innerDiv, borderLeftWidth;

                content = ''+
                              ''+
                                  ''+
                                      'I'+
                                      'O'+
                                      ''+
                                  ''+
                              ''+
                          '';
                element.setHTML(content);
                innerDiv = element.getElement('>span');
                borderLeftWidth = parseInt(innerDiv.getStyle('border-left-width'), 10);
                element.setData('_leftBorder', borderLeftWidth);
                element.setData('_vertBorders', parseInt(innerDiv.getStyle('border-top-width'), 10) + parseInt(innerDiv.getStyle('border-bottom-width'), 10));
                element.setData('_horBorders', borderLeftWidth + parseInt(innerDiv.getStyle('border-right-width'), 10));
            },

            _fitCheckbox: function() {
                var element = this,
                    // width = parseInt(element.getStyle('width'), 10),
                    // height = parseInt(element.getStyle('height'), 10),
                    width = element.offsetWidth,
                    height = element.offsetHeight,
                    innerDiv, constrainNode, innerNodes, halfHeight, shift;
                if ((width!==element.getData('_width')) || (height!==element.getData('_height'))) {
                    // the height that should be used by the innernodes, schould be decreased by the border-width
                    height -= element.getData('_vertBorders');
                    width -= element.getData('_horBorders');
                    innerDiv = element.getElement('>span');
                    constrainNode = innerDiv.getElement('>span');
                    innerNodes = constrainNode.getAll('>span >span');
                    halfHeight = Math.round(height/2);
                    shift = 3*Math.round(height/4);
                    innerDiv.setInlineStyle('border-radius', height+'px');
                    constrainNode.setInlineStyles([
                        {property: 'left', value: (height-width)+'px'},
                        {property: 'width', value: (3*width-height)+'px'}
                    ]);
                    innerNodes[0].setInlineStyles([
                        {property: 'border-radius', value: height+'px'},
                        {property: 'line-height', value: (height-2)+'px'}, // correct with 2px: the padding-top of i-on
                        {property: 'padding-right', value: shift+'px'},
                        {property: 'width', value: width+'px'}
                    ]);
                    innerNodes[1].setInlineStyles([
                        {property: 'border-radius', value: height+'px'},
                        {property: 'margin-left', value: -height+'px'},
                        {property: 'line-height', value: (height-2)+'px'}, // correct with 2px: the padding-top of i-off
                        {property: 'padding-left', value: shift+'px'},
                        {property: 'width', value: width+'px'}
                    ]);
                    innerNodes[2].setInlineStyles([
                        {property: 'left', value: -width+'px'},
                        {property: 'height', value: height+'px'},
                        {property: 'width', value: height+'px'}
                    ]);
                    element.setData('_width', width);
                    element.setData('_height', height);
                }
            },

            _setUIState: function() {
                var element = this,
                    container = element.getElement('>span >span >span'),
                    newValue = element.model.checked ? (element.getData('_width')-element.getData('_height'))+'px' : '0';
                (container.getInlineStyle('left')===newValue) || container.setInlineStyle('left', newValue);
            },

            sync: function() {
                var element = this,
                    container = element.getElement('>span >span >span'),
                    itemContainers = container.getAll('>span'),
                    model = element.model;
                element._fitCheckbox();
                element._setUIState(model.checked);
                itemContainers[0].setHTML(model['on-text']);
                itemContainers[1].setHTML(model['off-text']);
            },

            getValue: function() {
                return this.model.checked;
            },

            currentToReset: function() {
                var model = this.model;
                model['reset-value'] = model.checked;
            },

            reset: function() {
                var model = this.model;
                model.checked = model['reset-value'];
            },

            destroy: function() {
                unRegisterElement(this);
            }
        });

        window.ITAGS[itagName] = Itag;
    }

    return window.ITAGS[itagName];
};
<commit_msg>intermediate saving<commit_after>module.exports = function (window) {
    "use strict";

    require('./css/i-checkbox.css');
    require('itags.core')(window);

    var itagName = 'i-checkbox', // <-- define your own itag-name here
        ITSA = window.ITSA,
        Event = ITSA.Event,
        later = ITSA.later,
        DEFAULT_ON_TEXT = 'I',
        DEFAULT_OFF_TEXT = 'O',
        SUPPRESS_DELAY = 50,
        INTERVAL_FONTCHANGE_CHECK = 350,
        Itag, IFormElement, registeredElements, timer, registerElement, unRegisterElement;

    if (!window.ITAGS[itagName]) {
        ITSA.DD.init();

        registeredElements = [];
        IFormElement = require('i-formelement')(window);

        Event.before(itagName+':manualfocus', function(e) {
            // the i-select itself is unfocussable, but its button is
            // we need to patch `manualfocus`,
            // which is emitted on node.focus()
            // a focus by userinteraction will always appear on the button itself
            // so we don't bother that
            var element = e.target;
            e.preventDefault();
            element.itagReady().then(
                function() {
                    var focusNode = element.getElement('>span');
                    focusNode && focusNode.focus(true, true);
                }
            );
        });

        Event.after('tap', function(e) {
            var element = e.target,
                model = element.model,
                focusNode;
            if (!element.hasData('_suppressTap')) {
                model.checked = !model.checked;
                focusNode = element.getElement('>span');
                focusNode.hasFocus() || focusNode.focus();
            }
        }, 'i-checkbox');

        Event.after('keypress', function(e) {
            var element = e.target,
                model = element.model;
            (e.charCode===32) && (model.checked=!model.checked);
        }, 'i-checkbox');

        Event.after('dd-drag', function(e) {
            var checkbox = e.target.inside('i-checkbox');
            checkbox.setData('_suppressTap', true);
        }, 'i-checkbox');

        Event.after('dd-drop', function(e) {
            var dragNode = e.target,
                checkbox = dragNode.inside('i-checkbox'),
                btnNode = dragNode.getElement('>.i-btn'),
                distance = btnNode.left - checkbox.left - checkbox.getData('_leftBorder') + Math.round(checkbox.getData('_height')/2);
            checkbox.model.checked = (distance>Math.round(checkbox.getData('_width')/2));
            checkbox._setUIState();
            later(function() {
                checkbox.removeData('_suppressTap');
            }, SUPPRESS_DELAY);
        }, 'i-checkbox');

        Event.defineEvent(itagName+':checkedchange').unPreventable();

        Event.after(itagName+':change', function(e) {
            var element = e.target,
                model = element.model;
            /**
            * Emitted when a the i-checkbox changes its `checked`-value
            *
            * @event i-checkbox:checkedchange
            * @param e {Object} eventobject including:
            * @param e.target {HtmlElement} the i-checkbox element
            * @param e.prevValue {Boolean}
            * @param e.newValue {Boolean}
            * @since 0.1
            */
            element.emit('checkedchange', {
                prevValue: !model.checked,
                newValue: model.checked
            });
        });

        // whenever fontsize changes, the calculated height needs to change
        // we have no means of listening to this - even it's unlikely to happen
        // yet we want the i-checkboxes to fit at anytime, so we set up a lazy timer
        // that checks all registered itag-instances

        registerElement = function(element) {
            registeredElements.push(element);
            if (!timer) {
                timer = later(function() {
                    var len = registeredElements.length,
                        i, element;
                    for (i=0; i<len; i++) {
                        element = registeredElements[i];
                        if (!element.hasData('_suppressTap')) {
                            element._fitCheckbox();
                            element._setUIState();
                        }
                    }
                }, INTERVAL_FONTCHANGE_CHECK, true);
            }
        };

        unRegisterElement = function(element) {
            registeredElements.remove(element);
            if ((registeredElements.length===0) && timer) {
                timer.cancel();
                timer = null;
            }
        };

        Itag = IFormElement.subClass(itagName, {
            attrs: {
                checked: 'boolean',
                'reset-value': 'boolean'
            },

            init: function() {
                var element = this,
                    value = element.model.checked,
                    designNode = element.getItagContainer(),
                    options = designNode.getAll('>option');

                // set the reset-value to the inital-value in case `reset-value` was not present
                element.defineWhenUndefined('reset-value', value)
                       .defineWhenUndefined('on-text', options[0] ? options[0].getHTML() : DEFAULT_ON_TEXT)
                       .defineWhenUndefined('off-text', options[1] ? options[1].getHTML() : DEFAULT_OFF_TEXT);
                registerElement(element);
            },

            render: function() {
                var element = this,
                    content, innerDiv, borderLeftWidth;

                content = ''+
                              ''+
                                  ''+
                                      'I'+
                                      'O'+
                                      ''+
                                  ''+
                              ''+
                          '';
                element.setHTML(content);
                innerDiv = element.getElement('>span');
                borderLeftWidth = parseInt(innerDiv.getStyle('border-left-width'), 10);
                element.setData('_leftBorder', borderLeftWidth);
                element.setData('_vertBorders', parseInt(innerDiv.getStyle('border-top-width'), 10) + parseInt(innerDiv.getStyle('border-bottom-width'), 10));
                element.setData('_horBorders', borderLeftWidth + parseInt(innerDiv.getStyle('border-right-width'), 10));
            },

            _fitCheckbox: function() {
                var element = this,
                    // width = parseInt(element.getStyle('width'), 10),
                    // height = parseInt(element.getStyle('height'), 10),
                    width = element.offsetWidth,
                    height = element.offsetHeight,
                    innerDiv, constrainNode, innerNodes, halfHeight, shift;
                if ((width!==element.getData('_width')) || (height!==element.getData('_height'))) {
                    // the height that should be used by the innernodes, schould be decreased by the border-width
                    height -= element.getData('_vertBorders');
                    width -= element.getData('_horBorders');
                    innerDiv = element.getElement('>span');
                    constrainNode = innerDiv.getElement('>span');
                    innerNodes = constrainNode.getAll('>span >span');
                    halfHeight = Math.round(height/2);
                    shift = 3*Math.round(height/4);
                    innerDiv.setInlineStyle('border-radius', height+'px');
                    constrainNode.setInlineStyles([
                        {property: 'left', value: (height-width)+'px'},
                        {property: 'width', value: (3*width-height)+'px'}
                    ]);
                    innerNodes[0].setInlineStyles([
                        {property: 'border-radius', value: height+'px'},
                        {property: 'line-height', value: (height-2)+'px'}, // correct with 2px: the padding-top of i-on
                        {property: 'padding-right', value: shift+'px'},
                        {property: 'width', value: width+'px'}
                    ]);
                    innerNodes[1].setInlineStyles([
                        {property: 'border-radius', value: height+'px'},
                        {property: 'margin-left', value: -height+'px'},
                        {property: 'line-height', value: (height-2)+'px'}, // correct with 2px: the padding-top of i-off
                        {property: 'padding-left', value: shift+'px'},
                        {property: 'width', value: width+'px'}
                    ]);
                    innerNodes[2].setInlineStyles([
                        {property: 'left', value: -width+'px'},
                        {property: 'height', value: height+'px'},
                        {property: 'width', value: height+'px'}
                    ]);
                    element.setData('_width', width);
                    element.setData('_height', height);
                }
            },

            _setUIState: function() {
                var element = this,
                    container = element.getElement('>span >span >span'),
                    newValue = element.model.checked ? (element.getData('_width')-element.getData('_height'))+'px' : '0';
                (container.getInlineStyle('left')===newValue) || container.setInlineStyle('left', newValue);
            },

            sync: function() {
                var element = this,
                    container = element.getElement('>span >span >span'),
                    itemContainers = container.getAll('>span'),
                    model = element.model;
                element._fitCheckbox();
                element._setUIState(model.checked);
                itemContainers[0].setHTML(model['on-text']);
                itemContainers[1].setHTML(model['off-text']);
            },

            getValue: function() {
                return this.model.checked;
            },

            currentToReset: function() {
                var model = this.model;
                model['reset-value'] = model.checked;
            },

            reset: function() {
                var model = this.model;
                model.checked = model['reset-value'];
            },

            destroy: function() {
                unRegisterElement(this);
            }
        });

        window.ITAGS[itagName] = Itag;
    }

    return window.ITAGS[itagName];
};
<|endoftext|>


<commit_before><commit_msg>Delete config - copia.js<commit_after><|endoftext|>


<commit_before>function insertAtCaret(filename, contenttype) {

	// find the active div
    var myDivArray = new Array();
    myDivArray = $('pages').getElementsByClassName('page');
    var i=0;
    while (i < myDivArray.length){
	    if($(myDivArray[i].id).getStyle('display') == 'none'){
		 // do nothing, non-active tab
		} else {
		   var divId = '';
		   divId =  myDivArray[i].id;
		   var myTextAreaArray = new Array();
		   myTextAreaArray = $(divId).getElementsByClassName('textarea');
		   var areaId = '';
		   areaId = myTextAreaArray[0].id;

		}
		i++;
    }

	//     var text = '';
	//     if((contenttype == "image/gif") || (contenttype == "image/jpeg") || (contenttype == "image/png")){
	// 	text = '

';
	// } else if (contenttype == "audio/x-wav"){
	// 	text = '
'+ filename +'
';
	// } else {
	// 	text = filename;
	// }

	var text = '';
	var contentTypeArray = new Array();
	contentTypeArray = contenttype.split("/");

    if(contentTypeArray[0]== 'image'){
		text = '

';
	} else if ((contentTypeArray[0] == 'application') && (contentTypeArray[1] == 'x-shockwave-flash')) {
	 	text = '<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" WIDTH="550" HEIGHT="400" id="myMovieName"><PARAM NAME=movie VALUE="'+filename+'"><PARAM NAME=quality VALUE=high><PARAM NAME=bgcolor VALUE=#FFFFFF><EMBED href="'+filename+'" quality=high bgcolor=#FFFFFF WIDTH="550" HEIGHT="400" NAME="myMovieName" ALIGN="" TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer"></EMBED></OBJECT>';

	} else if (contentTypeArray[0] == "audio"){
		text = '
'+ filename +'
';
	} else {
		text = '
'+ filename +'
';
	}

	var txtarea = document.getElementById(areaId);

	var scrollPos = txtarea.scrollTop;
	var strPos = 0;
	var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ? "ff" : (document.selection ? "ie" : false ) );
	if (br == "ie") {
		txtarea.focus();
		var range = document.selection.createRange();
		range.moveStart ('character', -txtarea.value.length);
		strPos = range.text.length;
	}
	else if (br == "ff") strPos = txtarea.selectionStart;

	var front = (txtarea.value).substring(0,strPos);
	var back = (txtarea.value).substring(strPos,txtarea.value.length);
	txtarea.value=front+text+back;
	strPos = strPos + text.length;
	if (br == "ie") {
		txtarea.focus();
		var range = document.selection.createRange();
		range.moveStart ('character', -txtarea.value.length);
		range.moveStart ('character', strPos);
		range.moveEnd ('character', 0);
		range.select();
	}
	else if (br == "ff") {
		txtarea.selectionStart = strPos;
		txtarea.selectionEnd = strPos; txtarea.focus();
	}
	txtarea.scrollTop = scrollPos;
} <commit_msg>embed<commit_after>function insertAtCaret(filename, contenttype) {

	// find the active div
    var myDivArray = new Array();
    myDivArray = $('pages').getElementsByClassName('page');
    var i=0;
    while (i < myDivArray.length){
	    if($(myDivArray[i].id).getStyle('display') == 'none'){
		 // do nothing, non-active tab
		} else {
		   var divId = '';
		   divId =  myDivArray[i].id;
		   var myTextAreaArray = new Array();
		   myTextAreaArray = $(divId).getElementsByClassName('textarea');
		   var areaId = '';
		   areaId = myTextAreaArray[0].id;

		}
		i++;
    }

	var text = '';
	var contentTypeArray = new Array();
	contentTypeArray = contenttype.split("/");

    if(contentTypeArray[0]== 'image'){
		text = '

';
	} else if ((contentTypeArray[0] == 'application') && (contentTypeArray[1] == 'x-shockwave-flash')) {
	 	text = '<embed src="' + filename + '" width="550" height="400"></embed>';

	} else if (contentTypeArray[0] == "audio"){
		text = '
'+ filename +'
';
	} else {
		text = '
'+ filename +'
';
	}

	var txtarea = document.getElementById(areaId);

	var scrollPos = txtarea.scrollTop;
	var strPos = 0;
	var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ? "ff" : (document.selection ? "ie" : false ) );
	if (br == "ie") {
		txtarea.focus();
		var range = document.selection.createRange();
		range.moveStart ('character', -txtarea.value.length);
		strPos = range.text.length;
	}
	else if (br == "ff") strPos = txtarea.selectionStart;

	var front = (txtarea.value).substring(0,strPos);
	var back = (txtarea.value).substring(strPos,txtarea.value.length);
	txtarea.value=front+text+back;
	strPos = strPos + text.length;
	if (br == "ie") {
		txtarea.focus();
		var range = document.selection.createRange();
		range.moveStart ('character', -txtarea.value.length);
		range.moveStart ('character', strPos);
		range.moveEnd ('character', 0);
		range.select();
	}
	else if (br == "ff") {
		txtarea.selectionStart = strPos;
		txtarea.selectionEnd = strPos; txtarea.focus();
	}
	txtarea.scrollTop = scrollPos;
} <|endoftext|>


<commit_before>// This JSON describes what type of tags to have.

// {
//   dataType1: [{tagField1forDT1}, {tagField2forDT1}, {tagField3forDT1}],
// },
// {
//   dataType2: [{tagField1forDT2}, {tagField2forDT2}, {tagField3forDT2}],
// },
//
// dataype: video, audio...

// tagField format..
// {
//   name: 'fieldName',      // HTML Label for this field.
//   id: 'fieldIdInDatabase', // Id that will be use to send the data back,
//   type: 'Type of data',    // HTML select, time, number, selectWithOther, Confidence
//   other values needed depending on the type as set above.
// }

var tagsLayout = {
  video: [ // List of tag types for videos.
    {
      name: 'Pest',
      id: 'pestTag',
      fields: [ // Fields for Pest
        {
          name: 'Animal',
          id: 'animal',
          type: 'selectWithOther',
          values: ['Cat', 'Deer', 'Dog', 'Goat', 'Hedgehog', 'Mouse',
            'Stoat', 'Weasel', 'Ferret', 'Pig', 'Possum', 'Rabbit/Hare',
            'Rat', 'Other'
          ],
          required: true,
          description: 'What type of pest do you see? If there is more than' +
            ' one type of animal on at a time, add a tag for each type.'
        },
        {
          name: 'Time range',
          id: 'timeRange',
          type: 'timeRange',
          required: true,
          description: 'When the tag starts and ends.',
        },
        {
          name: 'Number',
          id: 'amount',
          type: 'number',
          required: true,
          description: 'Number of animals of the species selected.',
        },
        {
          name: 'Confidence:',
          id: 'confidence',
          type: 'confidence',
          required: true,
          description: 'How confident are you in the idenfication.'
        },
      ],
    },
    {
      name: 'Bird',
      id: 'birdTag',
      fields: [{
          name: 'Specie',
          id: 'birdSpecie',
          type: 'selectWithOther',
          values: ['Kea', 'Fantail'],
          required: true,
          description: 'What species of bird do you see?',
        },
        {
          name: 'Start',
          id: 'startTime',
          type: 'time',
          required: true,
          description: 'Start time of tag.',
        },
        {
          name: 'End',
          id: 'end',
          type: 'time',
          required: true,
          description: 'End time of tag.',
        },
        {
          name: 'Amount of birds',
          id: 'amountOfAnimals',
          type: 'number',
          required: true,
          description: 'Number of birds of the species selected.'
        },
        {
          name: 'Confidence:',
          id: 'confidence',
          type: 'confidence',
          required: true,
          description: 'How confident are you in the idenfication.'
        },
      ],
    },
  ],
};

var newTag = {};

newTag.hideAllBut = function(type) {
  for (var i in newTag.tagTypeList) {
    var name = newTag.tagTypeList[i];
    var form = document.getElementById(name);
    if (name == type)
      form.hidden = false;
    else
      form.hidden = true;
  }
};

newTag.setup = function() {
  var selectEvent = document.getElementById('event-type');
  var tagsDev = document.getElementById('tags-dev');
  var tagTypes = tagsLayout.video;
  var first = true;
  for (var i in tagTypes) { // For each tag type
    var tagType = tagTypes[i];
    console.log('Adding new tag type: ', tagType.name);
    newTag.tagTypeList.push(tagType.id);
    var tagForm = document.createElement('div');
    tagForm.class = 'form-horizontal';
    tagForm.id = tagType.id;
    // Hide all but the first.
    tagForm.hidden = !first;
    first = false;

    // For each field add append a 'form-row' onto the form for that field.
    // The 'form-row' is generated depending on the 'field.type'.
    for (var j in tagType.fields) {
      var field = tagType.fields[j];
      tagForm.appendChild(newTag.field[field.type](field));
    }

    tagsDev.appendChild(tagForm);
    // Add option to selectEvent.
    var option = document.createElement('option');
    option.innerHTML = tagType.name;
    option.tagId = tagType.id;
    selectEvent.appendChild(option);
  }

  selectEvent.onchange = function(event) {
    newTag.hideAllBut(event.target.options[event.target.selectedIndex].tagId);
  };
};

newTag.tagTypeList = [];

newTag.field = {};

newTag.getNewFieldFormRow = function(field) {
  var formRow = document.createElement('div');
  formRow.class = 'form-group row';
  formRow.type = field.type;
  formRow.id = field.id;
  formRow.required = field.required;
  formRow.disName = field.name;
  var label = document.createElement('label');
  label.innerHTML = field.name;
  formRow.appendChild(label);
  return formRow;
};

// HTML select with 'other' as a optin, when other is selected a text field
// shows where the user can input their value there.
newTag.field.selectWithOther = function(field) {
  var formRow = newTag.getNewFieldFormRow(field); // Makes form row with label.
  var select = document.createElement('select');
  var option = document.createElement('option');
  select.appendChild(option);
  for (var i in field.values) {
    option = document.createElement('option');
    option.innerHTML = field.values[i];
    select.appendChild(option);
  }
  formRow.appendChild(select);
  var otherText = document.createElement('input');
  otherText.setAttribute('type', 'text');
  otherText.hidden = true;
  formRow.appendChild(otherText);
  select.onchange = function() {
    otherText.hidden = select.options[select.selectedIndex].value !==
      'Other';
  };
  return formRow;
};

newTag.field.select = function(field) {
  var formRow = newTag.getNewFieldFormRow(field); // Makes form row with label.
  var select = document.createElement('select');
  var option = document.createElement('option');
  select.appendChild(option);
  for (var i in field.values) {
    option = document.createElement('option');
    option.innerHTML = field.values[i];
    select.appendChild(option);
  }
  formRow.appendChild(select);
  var otherText = document.createElement('input');
  otherText.setAttribute('type', 'text');
  otherText.hidden = true;
  formRow.appendChild(otherText);
  return formRow;
};

newTag.field.time = function(field) {
  var formRow = newTag.getNewFieldFormRow(field);
  var time = document.createElement('input');
  time.setAttribute('type', 'time');
  formRow.appendChild(time);
  return formRow;
};

newTag.field.number = function(field) {
  var formRow = newTag.getNewFieldFormRow(field);
  var number = document.createElement('input');
  number.setAttribute('type', 'number');
  formRow.appendChild(number);
  return formRow;
};

newTag.field.timeRange = function(field) {
  var formRow = newTag.getNewFieldFormRow(field);
  var time1 = document.createElement('input');
  time1.setAttribute('type', 'time');
  var time2 = document.createElement('input');
  time2.setAttribute('type', 'time');
  var label1 = document.createElement('Label');
  label1.innerHTML = 'Start:';
  var label2 = document.createElement('label');
  label2.innerHTML = 'End:';
  formRow.appendChild(label1);
  formRow.appendChild(time1);
  formRow.appendChild(label2);
  formRow.appendChild(time2);
  return formRow;
};

newTag.field.confidence = function(field) {
  var formRow = newTag.getNewFieldFormRow(field);
  // Radio buttons
  var sure = document.createElement('input');
  sure.setAttribute('type', 'radio');
  sure.name = 'confidence';
  var notSure = document.createElement('input');
  notSure.setAttribute('type', 'radio');
  notSure.name = 'confidence';
  var noIdea = document.createElement('input');
  noIdea.setAttribute('type', 'radio');
  noIdea.name = 'confidence';
  // Labels
  var sureL = document.createElement('label');
  sureL.innerHTML = ' Sure:';
  var notSureL = document.createElement('label');
  notSureL.innerHTML = ' Not Sure:';
  var noIdeaL = document.createElement('label');
  noIdeaL.innerHTML = ' No idea:';
  // Append to formRow.
  formRow.appendChild(sureL);
  formRow.appendChild(sure);
  formRow.appendChild(notSureL);
  formRow.appendChild(notSure);
  formRow.appendChild(noIdeaL);
  formRow.appendChild(noIdea);
  return formRow;
};

newTag.addTag = function() {
  var validTag = true;
  var errorMessages = [];
  var result = {};
  var select = document.getElementById('event-type');
  var id = select.options[select.selectedIndex].tagId;
  var form = document.getElementById(id);
  for (var i = 0; i < form.children.length; i++) {
    var childDiv = form.children[i];
    if (childDiv.type) {
      var childResult = newTag.getField[childDiv.type](childDiv);
      for (var key in childResult) {
        if (key == '__error') {
          validTag = false;
          errorMessages.push(childResult[key]);
        }
        if (childDiv.required && childResult[key] === null) {
          validTag = false;
          errorMessages.push("Field '"+childDiv.disName+"' is required.");
        }
        result[key] = childResult[key];
      }
    }
  }
  console.log('Result:', result);
  removeErrorMessages();
  if (validTag)
    addTag(result);
  else
    displayErrorMessages(errorMessages);
};

function removeErrorMessages() {
  var errorBox = document.getElementById('error-box');
  errorBox.innerHTML = '';
}

function displayErrorMessages(errorMessages) {
  var errorBox = document.getElementById('error-box');
  var message = '';
  for (var i in errorMessages) {
    message = message + errorMessages[i]+'<br>';
  }
  errorBox.innerHTML = message;
}

newTag.getField = {};

// Get functions for the fields.
newTag.getField.selectWithOther = function(element) {
  var result = {};
  var id = element.id;
  var select = element.children[1];
  var selectValue = select.options[select.selectedIndex].value;
  if (selectValue === 'Other')
    result[id] = element.children[2].value;
  else
    result[id] = selectValue;
  if (selectValue === '')
    result[id] = null;
  return result;
};

newTag.getField.select = function(element) {
  var result = {};
  var id = element.id;
  var select = element.children[1];
  var selectValue = select.options[select.selectedIndex].value;
  result[id] = selectValue;
  if (selectValue === '')
    result[id] = null;
  return result;
};

newTag.getField.time = function(element) {
  var result = {};
  var id = element.id;
  var timeInput = element.children[1];
  var time = timeInput.value;
  result[id] = timeToSeconds(time);
  if (isNaN(result[id]))
    result[id] = null;
  return result;
};

newTag.getField.number = function(element) {
  var result = {};
  var id = element.id;
  var numberInput = element.children[1];
  var n = numberInput.value;
  result[id] = n;
  if (n === '')
    result[id] = null;
  return result;
};

newTag.getField.timeRange = function(element) {
  var result = {};
  var start = element.children[2].value;
  var end = element.children[4].value;
  result.start = start;
  result.end = end;
  if (start > end)
    result.__error = "Can't have end time before start time";
  if (start === '' || end === '')
    result.__error = "Invalid time range";
  return result;
};

newTag.getField.confidence = function(element) {
  var result = {};
  var id = element.id;
  if (element.children[2].checked)
    result[id] = 'sure';
  if (element.children[4].checked)
    result[id] = 'notSure';
  if (element.children[6].checked)
    result[id] = 'noIdea';
  if (typeof result[id] !== 'string')
    result[id] = null;
  return result;
};

function timeToSeconds(time) {
  var [minute, seconds] = time.split(':');
  return Number(minute) * 60 + Number(seconds);
}
<commit_msg>Updated minute:second fields to use text instead of time.<commit_after>// This JSON describes what type of tags to have.

// {
//   dataType1: [{tagField1forDT1}, {tagField2forDT1}, {tagField3forDT1}],
// },
// {
//   dataType2: [{tagField1forDT2}, {tagField2forDT2}, {tagField3forDT2}],
// },
//
// dataype: video, audio...

// tagField format..
// {
//   name: 'fieldName',      // HTML Label for this field.
//   id: 'fieldIdInDatabase', // Id that will be use to send the data back,
//   type: 'Type of data',    // HTML select, time, number, selectWithOther, Confidence
//   other values needed depending on the type as set above.
// }

var tagsLayout = {
  video: [ // List of tag types for videos.
    {
      name: 'Pest',
      id: 'pestTag',
      fields: [ // Fields for Pest
        {
          name: 'Animal',
          id: 'animal',
          type: 'selectWithOther',
          values: ['Cat', 'Deer', 'Dog', 'Goat', 'Hedgehog', 'Mouse',
            'Stoat', 'Weasel', 'Ferret', 'Pig', 'Possum', 'Rabbit/Hare',
            'Rat', 'Other'
          ],
          required: true,
          description: 'What type of pest do you see? If there is more than' +
            ' one type of animal on at a time, add a tag for each type.'
        },
        {
          name: 'Time range',
          id: 'timeRange',
          type: 'timeRange',
          required: true,
          description: 'When the tag starts and ends.',
        },
        {
          name: 'Number',
          id: 'amount',
          type: 'number',
          required: true,
          description: 'Number of animals of the species selected.',
        },
        {
          name: 'Confidence:',
          id: 'confidence',
          type: 'confidence',
          required: true,
          description: 'How confident are you in the idenfication.'
        },
      ],
    },
    {
      name: 'Bird',
      id: 'birdTag',
      fields: [{
          name: 'Specie',
          id: 'birdSpecie',
          type: 'selectWithOther',
          values: ['Kea', 'Fantail'],
          required: true,
          description: 'What species of bird do you see?',
        },
        {
          name: 'Start',
          id: 'startTime',
          type: 'time',
          required: true,
          description: 'Start time of tag.',
        },
        {
          name: 'End',
          id: 'end',
          type: 'time',
          required: true,
          description: 'End time of tag.',
        },
        {
          name: 'Amount of birds',
          id: 'amountOfAnimals',
          type: 'number',
          required: true,
          description: 'Number of birds of the species selected.'
        },
        {
          name: 'Confidence:',
          id: 'confidence',
          type: 'confidence',
          required: true,
          description: 'How confident are you in the idenfication.'
        },
      ],
    },
  ],
};

var newTag = {};

newTag.hideAllBut = function(type) {
  for (var i in newTag.tagTypeList) {
    var name = newTag.tagTypeList[i];
    var form = document.getElementById(name);
    if (name == type)
      form.hidden = false;
    else
      form.hidden = true;
  }
};

newTag.setup = function() {
  var selectEvent = document.getElementById('event-type');
  var tagsDev = document.getElementById('tags-dev');
  var tagTypes = tagsLayout.video;
  var first = true;
  for (var i in tagTypes) { // For each tag type
    var tagType = tagTypes[i];
    console.log('Adding new tag type: ', tagType.name);
    newTag.tagTypeList.push(tagType.id);
    var tagForm = document.createElement('div');
    tagForm.class = 'form-horizontal';
    tagForm.id = tagType.id;
    // Hide all but the first.
    tagForm.hidden = !first;
    first = false;

    // For each field add append a 'form-row' onto the form for that field.
    // The 'form-row' is generated depending on the 'field.type'.
    for (var j in tagType.fields) {
      var field = tagType.fields[j];
      tagForm.appendChild(newTag.field[field.type](field));
    }

    tagsDev.appendChild(tagForm);
    // Add option to selectEvent.
    var option = document.createElement('option');
    option.innerHTML = tagType.name;
    option.tagId = tagType.id;
    selectEvent.appendChild(option);
  }

  selectEvent.onchange = function(event) {
    newTag.hideAllBut(event.target.options[event.target.selectedIndex].tagId);
  };
};

newTag.tagTypeList = [];

newTag.field = {};

newTag.getNewFieldFormRow = function(field) {
  var formRow = document.createElement('div');
  formRow.class = 'form-group row';
  formRow.type = field.type;
  formRow.id = field.id;
  formRow.required = field.required;
  formRow.disName = field.name;
  var label = document.createElement('label');
  label.innerHTML = field.name;
  formRow.appendChild(label);
  return formRow;
};

// HTML select with 'other' as a optin, when other is selected a text field
// shows where the user can input their value there.
newTag.field.selectWithOther = function(field) {
  var formRow = newTag.getNewFieldFormRow(field); // Makes form row with label.
  var select = document.createElement('select');
  var option = document.createElement('option');
  select.appendChild(option);
  for (var i in field.values) {
    option = document.createElement('option');
    option.innerHTML = field.values[i];
    select.appendChild(option);
  }
  formRow.appendChild(select);
  var otherText = document.createElement('input');
  otherText.setAttribute('type', 'text');
  otherText.hidden = true;
  formRow.appendChild(otherText);
  select.onchange = function() {
    otherText.hidden = select.options[select.selectedIndex].value !==
      'Other';
  };
  return formRow;
};

newTag.field.select = function(field) {
  var formRow = newTag.getNewFieldFormRow(field); // Makes form row with label.
  var select = document.createElement('select');
  var option = document.createElement('option');
  select.appendChild(option);
  for (var i in field.values) {
    option = document.createElement('option');
    option.innerHTML = field.values[i];
    select.appendChild(option);
  }
  formRow.appendChild(select);
  var otherText = document.createElement('input');
  otherText.setAttribute('type', 'text');
  otherText.hidden = true;
  formRow.appendChild(otherText);
  return formRow;
};

newTag.field.time = function(field) {
  var formRow = newTag.getNewFieldFormRow(field);
  var time = document.createElement('input');
  time.setAttribute('type', 'time');
  formRow.appendChild(time);
  return formRow;
};

newTag.field.number = function(field) {
  var formRow = newTag.getNewFieldFormRow(field);
  var number = document.createElement('input');
  number.setAttribute('type', 'number');
  formRow.appendChild(number);
  return formRow;
};

newTag.field.timeRange = function(field) {
  var formRow = newTag.getNewFieldFormRow(field);
  var time1m = document.createElement('input');
  time1m.setAttribute('type', 'text');
  time1m.value = '00:00';
  var time2m = document.createElement('input');
  time2m.setAttribute('type', 'text');
  time2m.value = '00:00';
  var label1 = document.createElement('Label');
  label1.innerHTML = 'Start:';
  var label2 = document.createElement('label');
  label2.innerHTML = 'End:';
  formRow.appendChild(document.createElement('br'));
  formRow.appendChild(label1);
  formRow.appendChild(time1m);
  formRow.appendChild(document.createElement('br'));
  formRow.appendChild(label2);
  formRow.appendChild(time2m);
  return formRow;
};

newTag.field.confidence = function(field) {
  var formRow = newTag.getNewFieldFormRow(field);
  // Radio buttons
  var sure = document.createElement('input');
  sure.setAttribute('type', 'radio');
  sure.name = 'confidence';
  var notSure = document.createElement('input');
  notSure.setAttribute('type', 'radio');
  notSure.name = 'confidence';
  var noIdea = document.createElement('input');
  noIdea.setAttribute('type', 'radio');
  noIdea.name = 'confidence';
  // Labels
  var sureL = document.createElement('label');
  sureL.innerHTML = ' Sure:';
  var notSureL = document.createElement('label');
  notSureL.innerHTML = ' Not Sure:';
  var noIdeaL = document.createElement('label');
  noIdeaL.innerHTML = ' No idea:';
  // Append to formRow.
  formRow.appendChild(sureL);
  formRow.appendChild(sure);
  formRow.appendChild(notSureL);
  formRow.appendChild(notSure);
  formRow.appendChild(noIdeaL);
  formRow.appendChild(noIdea);
  return formRow;
};

newTag.addTag = function() {
  var validTag = true;
  var errorMessages = [];
  var result = {};
  var select = document.getElementById('event-type');
  var id = select.options[select.selectedIndex].tagId;
  var form = document.getElementById(id);
  for (var i = 0; i < form.children.length; i++) {
    var childDiv = form.children[i];
    if (childDiv.type) {
      var childResult = newTag.getField[childDiv.type](childDiv);
      for (var key in childResult) {
        if (key == '__error') {
          validTag = false;
          errorMessages.push(childResult[key]);
        }
        if (childDiv.required && childResult[key] === null) {
          validTag = false;
          errorMessages.push("Field '" + childDiv.disName + "' is required.");
        }
        result[key] = childResult[key];
      }
    }
  }
  console.log('Result:', result);
  removeErrorMessages();
  if (validTag)
    addTag(result);
  else
    displayErrorMessages(errorMessages);
};

function removeErrorMessages() {
  var errorBox = document.getElementById('error-box');
  errorBox.innerHTML = '';
}

function displayErrorMessages(errorMessages) {
  var errorBox = document.getElementById('error-box');
  var message = '';
  for (var i in errorMessages) {
    message = message + errorMessages[i] + '<br>';
  }
  errorBox.innerHTML = message;
}

newTag.getField = {};

// Get functions for the fields.
newTag.getField.selectWithOther = function(element) {
  var result = {};
  var id = element.id;
  var select = element.children[1];
  var selectValue = select.options[select.selectedIndex].value;
  if (selectValue === 'Other')
    result[id] = element.children[2].value;
  else
    result[id] = selectValue;
  if (selectValue === '')
    result[id] = null;
  return result;
};

newTag.getField.select = function(element) {
  var result = {};
  var id = element.id;
  var select = element.children[1];
  var selectValue = select.options[select.selectedIndex].value;
  result[id] = selectValue;
  if (selectValue === '')
    result[id] = null;
  return result;
};

newTag.getField.time = function(element) {
  var result = {};
  var id = element.id;
  var timeInput = element.children[1];
  var time = timeInput.value;
  result[id] = timeToSeconds(time);
  if (isNaN(result[id]))
    result[id] = null;
  return result;
};

newTag.getField.number = function(element) {
  var result = {};
  var id = element.id;
  var numberInput = element.children[1];
  var n = numberInput.value;
  result[id] = n;
  if (n === '')
    result[id] = null;
  return result;
};

newTag.getField.timeRange = function(element) {
  var result = {};
  var start = element.children[3].value;
  var end = element.children[6].value;
  result.start = start;
  result.end = end;
  if (start > end)
    result.__error = "Can't have end time before start time";
  if (start === '' || end === '')
    result.__error = "Invalid time range";
  return result;
};

newTag.getField.confidence = function(element) {
  var result = {};
  var id = element.id;
  if (element.children[2].checked)
    result[id] = 'sure';
  if (element.children[4].checked)
    result[id] = 'notSure';
  if (element.children[6].checked)
    result[id] = 'noIdea';
  if (typeof result[id] !== 'string')
    result[id] = null;
  return result;
};

function timeToSeconds(time) {
  var [minute, seconds] = time.split(':');
  return Number(minute) * 60 + Number(seconds);
}
<|endoftext|>


<commit_before>OpenLayers.Lang.de = {
  'wheelchair_label_yes': 'rollstuhlgerecht',
  'wheelchair_label_limited': 'teilweise rollstuhlgerecht',
  'wheelchair_label_no': 'nicht rollstuhlgerecht',
  'wheelchair_label_unknown': 'unbekannt',
  'wheelchair_update_button': 'Speichern',
  'more_information': 'mehr ...',
  'wheelchair_help': 'Rollstuhlgerecht? (Hilfe)'
};
OpenLayers.Lang.el = {
  'wheelchair_label_yes': 'Κατάλληλο για αναπηρική καρέκλα',
  'wheelchair_label_limited': 'Εν μέρη προσβάσιμο με αναπηρική καρέκλα',
  'wheelchair_label_no': 'ακατάλληλο για αναπηρική καρέκλα',
  'wheelchair_label_unknown': 'Κατάσταση άγνωστη',
  'wheelchair_update_button': 'Ενημέρωση',
  'more_information': 'περισσότερα ...',
  'wheelchair_help': 'Δυνατότητα πρόσβασης με αναπηρική καρέκλα'
};
OpenLayers.Lang.en = {
  'wheelchair_label_yes': 'wheelchair accessible',
  'wheelchair_label_limited': 'partly wheelchair accessible',
  'wheelchair_label_no': 'not wheelchair accessible',
  'wheelchair_label_unknown': 'unknown status',
  'wheelchair_update_button': 'Update',
  'more_information': 'more ...',
  'wheelchair_help': 'Wheelchair accessible? (Help)'
};
OpenLayers.Lang.es = {
  'wheelchair_label_yes': 'accesible en silla de ruedas',
  'wheelchair_label_limited': 'acceso medio en silla de ruedas',
  'wheelchair_label_no': 'sin acceso en silla de ruedas',
  'wheelchair_label_unknown': 'se desconoce el estado',
  'wheelchair_update_button': 'Guardar',
  'more_information': 'más ...',
  'wheelchair_help': '¿Acceso en silla de ruedas? (Ayuda)'
};
OpenLayers.Lang.fr = {
  'wheelchair_label_yes': 'accès pour fauteuil roulant',
  'wheelchair_label_limited': 'accès partiel pour fauteuil roulant',
  'wheelchair_label_no': "pas d'accès pour fauteuil roulant",
  'wheelchair_label_unknown': 'statut inconnu',
  'wheelchair_update_button': 'Sauvegarder',
  'more_information': 'davantage ...',
  'wheelchair_help': 'Accessible pour fauteuil roulant? (Aide)'
};
OpenLayers.Lang.it = {
  'wheelchair_label_yes': 'accessibile in sedia a rotelle',
  'wheelchair_label_limited': 'parzialmente accessibile in sedia a rotelle',
  'wheelchair_label_no': 'non accessibile in sedia a rotelle',
  'wheelchair_label_unknown': 'stato sconosciuto',
  'wheelchair_update_button': 'Salva',
  'more_information': 'più ...',
  'wheelchair_help': 'Accessibile in sedia a rotelle? (Aiuto)'
};
OpenLayers.Lang.is = {
  'wheelchair_label_yes': 'hjólastólaaðgengilegt',
  'wheelchair_label_limited': 'að hluta til hjólastólaaðgengilegt',
  'wheelchair_label_no': 'ekki hjólastólaaðgengilegt',
  'wheelchair_label_unknown': 'óvituð staða',
  'wheelchair_update_button': 'vista',
  'more_information': 'meiri ...',
  'wheelchair_help': 'Hjólastólaaðgengilegt? (Hjálp)'

};
OpenLayers.Lang.jp = {
  'wheelchair_label_yes': '車椅子可',
  'wheelchair_label_limited': '車椅子一部可',
  'wheelchair_label_no': '車椅子不可',
  'wheelchair_label_unknown': '不明',
  'wheelchair_update_button': '保存',
  'more_information': '詳細 ...',
  'wheelchair_help': '車椅子で行けますか？ (ヘルプ)'
};
OpenLayers.Lang.tlh = {
  'wheelchair_label_yes': 'naw\'laH rutlhquS',
  'wheelchair_label_limited': 'loQ naw\'laH rutlhquS',
  'wheelchair_label_no': 'naw\'laHbe\' rutlhquS',
  'wheelchair_label_unknown': 'Suvbe\'bogh Dotlh',
  'wheelchair_update_button': 'qon',
  'more_information': 'latlh ...',
  'wheelchair_help': 'naw\'laH\'a\' rutlhquS? (QaH)'
};
OpenLayers.Lang.tr = {
  'wheelchair_label_yes': 'tekerlekli sandalye ile ulaşılır',
  'wheelchair_label_limited': 'kısmen tekerlekli sandalye ile ulaşılır',
  'wheelchair_label_no': 'tekerlekli sandalye için ulaşılır değil',
  'wheelchair_label_unknown': 'belirsiz statü',
  'wheelchair_update_button': 'Değişiklikeri kaydedin',
  'more_information': 'daha fazla...',
  'wheelchair_help': 'Tekerlekli sandalye için ulaşılırmı? (Yardım)'
};<commit_msg>Update greek translation for popup bubble.<commit_after>OpenLayers.Lang.de = {
  'wheelchair_label_yes': 'rollstuhlgerecht',
  'wheelchair_label_limited': 'teilweise rollstuhlgerecht',
  'wheelchair_label_no': 'nicht rollstuhlgerecht',
  'wheelchair_label_unknown': 'unbekannt',
  'wheelchair_update_button': 'Speichern',
  'more_information': 'mehr ...',
  'wheelchair_help': 'Rollstuhlgerecht? (Hilfe)'
};
OpenLayers.Lang.el = {
  'wheelchair_label_yes': 'Κατάλληλο για αναπηρική καρέκλα',
  'wheelchair_label_limited': 'Εν μέρη προσβάσιμο με αναπηρική καρέκλα',
  'wheelchair_label_no': 'Ακατάλληλο για αναπηρική καρέκλα',
  'wheelchair_label_unknown': 'Κατάσταση άγνωστη',
  'wheelchair_update_button': 'Ενημέρωση',
  'more_information': 'περισσότερα ...',
  'wheelchair_help': 'Δυνατότητα πρόσβασης με αναπηρική καρέκλα'
};
OpenLayers.Lang.en = {
  'wheelchair_label_yes': 'wheelchair accessible',
  'wheelchair_label_limited': 'partly wheelchair accessible',
  'wheelchair_label_no': 'not wheelchair accessible',
  'wheelchair_label_unknown': 'unknown status',
  'wheelchair_update_button': 'Update',
  'more_information': 'more ...',
  'wheelchair_help': 'Wheelchair accessible? (Help)'
};
OpenLayers.Lang.es = {
  'wheelchair_label_yes': 'accesible en silla de ruedas',
  'wheelchair_label_limited': 'acceso medio en silla de ruedas',
  'wheelchair_label_no': 'sin acceso en silla de ruedas',
  'wheelchair_label_unknown': 'se desconoce el estado',
  'wheelchair_update_button': 'Guardar',
  'more_information': 'más ...',
  'wheelchair_help': '¿Acceso en silla de ruedas? (Ayuda)'
};
OpenLayers.Lang.fr = {
  'wheelchair_label_yes': 'accès pour fauteuil roulant',
  'wheelchair_label_limited': 'accès partiel pour fauteuil roulant',
  'wheelchair_label_no': "pas d'accès pour fauteuil roulant",
  'wheelchair_label_unknown': 'statut inconnu',
  'wheelchair_update_button': 'Sauvegarder',
  'more_information': 'davantage ...',
  'wheelchair_help': 'Accessible pour fauteuil roulant? (Aide)'
};
OpenLayers.Lang.it = {
  'wheelchair_label_yes': 'accessibile in sedia a rotelle',
  'wheelchair_label_limited': 'parzialmente accessibile in sedia a rotelle',
  'wheelchair_label_no': 'non accessibile in sedia a rotelle',
  'wheelchair_label_unknown': 'stato sconosciuto',
  'wheelchair_update_button': 'Salva',
  'more_information': 'più ...',
  'wheelchair_help': 'Accessibile in sedia a rotelle? (Aiuto)'
};
OpenLayers.Lang.is = {
  'wheelchair_label_yes': 'hjólastólaaðgengilegt',
  'wheelchair_label_limited': 'að hluta til hjólastólaaðgengilegt',
  'wheelchair_label_no': 'ekki hjólastólaaðgengilegt',
  'wheelchair_label_unknown': 'óvituð staða',
  'wheelchair_update_button': 'vista',
  'more_information': 'meiri ...',
  'wheelchair_help': 'Hjólastólaaðgengilegt? (Hjálp)'

};
OpenLayers.Lang.jp = {
  'wheelchair_label_yes': '車椅子可',
  'wheelchair_label_limited': '車椅子一部可',
  'wheelchair_label_no': '車椅子不可',
  'wheelchair_label_unknown': '不明',
  'wheelchair_update_button': '保存',
  'more_information': '詳細 ...',
  'wheelchair_help': '車椅子で行けますか？ (ヘルプ)'
};
OpenLayers.Lang.tlh = {
  'wheelchair_label_yes': 'naw\'laH rutlhquS',
  'wheelchair_label_limited': 'loQ naw\'laH rutlhquS',
  'wheelchair_label_no': 'naw\'laHbe\' rutlhquS',
  'wheelchair_label_unknown': 'Suvbe\'bogh Dotlh',
  'wheelchair_update_button': 'qon',
  'more_information': 'latlh ...',
  'wheelchair_help': 'naw\'laH\'a\' rutlhquS? (QaH)'
};
OpenLayers.Lang.tr = {
  'wheelchair_label_yes': 'tekerlekli sandalye ile ulaşılır',
  'wheelchair_label_limited': 'kısmen tekerlekli sandalye ile ulaşılır',
  'wheelchair_label_no': 'tekerlekli sandalye için ulaşılır değil',
  'wheelchair_label_unknown': 'belirsiz statü',
  'wheelchair_update_button': 'Değişiklikeri kaydedin',
  'more_information': 'daha fazla...',
  'wheelchair_help': 'Tekerlekli sandalye için ulaşılırmı? (Yardım)'
};<|endoftext|>


<commit_before>'use strict';
const LevelUtil = require('../../src/levels').LevelUtil;

exports.listeners = {
	hit: function (l10n) {
		return function (room, attacker, defender, players, hitLocation, damageDealt) {
			checkForCrit(attacker, defender, damageDealt);
		}
	},

	deathblow: function(l10n) {
		return function (room, attacker, defender, players, hitLocation) {
			players.eachIf(
				p => p.getLocation() === defender.getLocation() && p !== attacker,
				p => p.emit('experience', LevelUtils.mobExp(defender.getAttribute('level')) \ 3, 'dying')
			);
		}
	}
};

function checkForCrit(attacker, defender, damageDealt) {
	var defenderHealth    = defender.getAttribute('health');
	var defenderMaxHealth = defender.getAttribute('max_health');

	var massiveDamage = damageDealt > defenderMaxHealth * .5;
	var almostDead  = defenderHealth <= defenderMaxHealth * .2;
	var coupDeGrace = almostDead && damageDealt >= defenderHealth;

	if (massiveDamage || coupDeGrace) {
		attacker.say('<bold><cyan>You have dealt a critical blow!</cyan></bold>');
	}
}
<commit_msg>Fix brokenness<commit_after>'use strict';
const LevelUtil = require('../../../src/levels').LevelUtil;

exports.listeners = {
	hit: function (l10n) {
		return function (room, attacker, defender, players, hitLocation, damageDealt) {
			checkForCrit(attacker, defender, damageDealt);
		}
	},

	deathblow: function(l10n) {
		return function (room, attacker, defender, players, hitLocation) {
			players.eachIf(
				p => p.getLocation() === defender.getLocation() && p !== attacker,
				p => p.emit('experience', LevelUtils.mobExp(defender.getAttribute('level')) * .33, 'dying')
			);
		}
	}
};

function checkForCrit(attacker, defender, damageDealt) {
	var defenderHealth    = defender.getAttribute('health');
	var defenderMaxHealth = defender.getAttribute('max_health');

	var massiveDamage = damageDealt > defenderMaxHealth * .5;
	var almostDead  = defenderHealth <= defenderMaxHealth * .2;
	var coupDeGrace = almostDead && damageDealt >= defenderHealth;

	if (massiveDamage || coupDeGrace) {
		attacker.say('<bold><cyan>You have dealt a critical blow!</cyan></bold>');
	}
}
<|endoftext|>


<commit_before>const fetch = require('node-fetch')
const AbortController = require('abort-controller')
const moment = require('moment')
const fs = require('fs')
const download = require('download')
const XlsxTemplate = require('xlsx-template')
const spsave = require('spsave').spsave
const ENV_VARS = require('./env-vars.json')
const SP_CONFIG = require('./sp-config.json')

const INTERNAL_ERROR = { 'error': 'An error occurred.' }
const INTERNAL_TIMEOUT = 20000
const finalBuildNumber = parseInt(ENV_VARS.buildNumber) + 1000
const buildArtifacts = {}

ENV_VARS.commitHash = ENV_VARS.commitHash.substring(0, 7)

const buildNotify = async () => {
	try {
		const buildTimestamp = moment().format('YYYY-MM-DD h:mm A')
		const fciProjectLink = 'https://codemagic.io/app/' + ENV_VARS.fciProjectId + '/build/' + ENV_VARS.fciBuildId
		let buildSuccess = (ENV_VARS.fciBuildStepStatus === 'success') ? true : false
		let buildApkFile = 'app-release.apk'
		let buildIpaFile = 'UC_San_Diego.ipa'
		let prAuthor = ''
		let saveArtifactApkSuccess = false
		let saveArtifactIpaSuccess = false
		let testPlanFilename = ''
		let testPlanUrl = ''

		console.log('ENV_VARS.fciBuildStepStatus: ' + ENV_VARS.fciBuildStepStatus)
		console.log('buildSuccess: ' + buildSuccess)
		console.log('buildPlatform: ' + ENV_VARS.buildPlatform)
		// Check build success
		if (buildSuccess) {
			// Supplemental GitHub metadata for PRs
			if (ENV_VARS.prNumber) {
				prAuthor = await githubMeta()
			}

			// Save build artifacts
			if (ENV_VARS.buildPlatform === 'IOS') {
				saveArtifactApkSuccess = await saveArtifact(buildApkFile)
			} else if (ENV_VARS.buildPlatform === 'ANDROID') {
				saveArtifactIpaSuccess = await saveArtifact(buildIpaFile)
			}

			// Generate test plan
			;({ testPlanFilename, testPlanUrl } = await generateTestPlan(prAuthor))
		}

		console.log('saveArtifactIpaSuccess: ' + saveArtifactIpaSuccess)
		console.log('saveArtifactApkSuccess: ' + saveArtifactApkSuccess)

		// Construct build notifier message
		let teamsMessage = '#### Campus Mobile Build Notifier\n\n'
		teamsMessage += '
'
		teamsMessage += '
Version:	' + ENV_VARS.appVersion + ' (' + finalBuildNumber + ')
'
		teamsMessage += '
Environment:	' + ENV_VARS.buildEnv + '
'

		// PR or Branch
		if (ENV_VARS.prNumber) {
			teamsMessage += '
PR:	' + ENV_VARS.prNumber + '
'
			teamsMessage += '
Author:	' + prAuthor + '
'
		} else {
			teamsMessage += '
Branch:	' + ENV_VARS.buildBranch + '
'
			teamsMessage += '
Commit:	' + ENV_VARS.commitHash + '
'
		}

		// Build Artifacts
		if (ENV_VARS.buildPlatform === 'IOS') {
			if (saveArtifactIpaSuccess) {
				teamsMessage += '
iOS:	TestFlight ' + ENV_VARS.appVersion + ' (' + finalBuildNumber + ')
'
			} else {
				teamsMessage += '
iOS:	N/A
'
			}
		} else if (ENV_VARS.buildPlatform === 'ANDROID') {
			if (saveArtifactApkSuccess) {
				teamsMessage += '
Android:	' + buildArtifacts.buildApkFinalFilename + '
'
			} else {
				teamsMessage += '
Android:	N/A
'
			}
		}

		// Test plan
		if (testPlanUrl && testPlanFilename) {
			teamsMessage += '
Testing:	' + testPlanFilename + '
'
		}

		const successEmojiList = ['🥇','🏆','🎖','🎉','🎊','🚀','🛫','🏋','💪','👏','💯']
		const failedEmojiList = ['🙀','😱','😵']

		// Build success or failure
		if (buildSuccess &&
			((saveArtifactApkSuccess && ENV_VARS.buildPlatform === 'ANDROID') ||
			(saveArtifactIpaSuccess && ENV_VARS.buildPlatform === 'IOS'))) {
			const successEmoji = successEmojiList[Math.floor(Math.random() * successEmojiList.length)]
			teamsMessage += '
Status:	BUILD SUCCESS ' + successEmoji + ' (detail)
'
		} else {
			const failedEmoji = failedEmojiList[Math.floor(Math.random() * failedEmojiList.length)]
			teamsMessage += '
Status:	BUILD FAILED ' + failedEmoji + ' (detail)
'
		}

		teamsMessage += '
Time:	' + buildTimestamp + '
'
		teamsMessage += '
'

		// Send notification via webhook integration
		console.log('Sending Teams notification for UC San Diego ' + ENV_VARS.appVersion + ' (' + finalBuildNumber + ')\n')
		const notifyController = new AbortController()
		const notifyTimeout = setTimeout(() => { notifyController.abort() }, INTERNAL_TIMEOUT)
		const notifyResp = await fetch(SP_CONFIG.webhookUrl, {
			method: 'POST',
			headers: {
				'Content-Type': 'application/json'
			},
			body: JSON.stringify({
				'text': teamsMessage
			}),
			signal: notifyController.signal,
		})
		clearTimeout(notifyTimeout)

		if (notifyResp.statusText != 'OK') {
			throw 'Error: Unable to POST to webhookUrl (status: ' + notifyResp.statusText + ')'
		}
	} catch (err) {
		console.log(err)
		process.exitCode = 1
	}
}

const saveArtifact = async (artifactFilename) => {
	try {
		// Exit if artifact filename unavailable (build failed)
		if (!artifactFilename) {
			console.log('Error1: saveArtifact: artifact filename unavailable (build failed)')
			return false
		}

		const buildFilenamePrEnvStr = ENV_VARS.prNumber ? '-PR-' + ENV_VARS.prNumber : '-' + ENV_VARS.buildEnv
		const buildFolder = ENV_VARS.prNumber ? SP_CONFIG.spPullRequestBuildFolder : SP_CONFIG.spRegressionBuildFolder
		const coreOptions = { siteUrl: SP_CONFIG.spSiteUrl }
		const fileOptions = { folder: ENV_VARS.prNumber ? SP_CONFIG.spPullRequestBuildFolder : SP_CONFIG.spRegressionBuildFolder }

		// Save build artifacts to SP
		if (ENV_VARS.buildPlatform === 'ANDROID') {
			buildArtifacts.buildApkFilepath = '../../build/app/outputs/apk/release/app-release.apk'
			buildArtifacts.buildApkFinalFilename = ENV_VARS.appVersion + '-' + finalBuildNumber + buildFilenamePrEnvStr + '.apk'
			buildArtifacts.buildApkFinalUrl = (SP_CONFIG.spSiteUrl + buildFolder + buildArtifacts.buildApkFinalFilename).replace(/ /g, '%20')
			fs.copyFileSync(buildArtifacts.buildApkFilepath, './' + buildArtifacts.buildApkFinalFilename)
			fileOptions.fileName = buildArtifacts.buildApkFinalFilename
			fileOptions.fileContent = fs.readFileSync(buildArtifacts.buildApkFinalFilename)
			console.log('Saving artifact `' + fileOptions.fileName + ' to SP...')
			await spsave(coreOptions, SP_CONFIG.credentials, fileOptions)
			return true
		} else if (ENV_VARS.buildPlatform === 'IOS') {
			buildArtifacts.buildIpaFilepath = '../../build/ios/ipa/UC San Diego.ipa'
			buildArtifacts.buildIpaFinalFilename = ENV_VARS.appVersion + '-' + finalBuildNumber + buildFilenamePrEnvStr + '.ipa'
			buildArtifacts.buildIpaFinalUrl = (SP_CONFIG.spSiteUrl + buildFolder + buildArtifacts.buildIpaFinalFilename).replace(/ /g, '%20')
			fs.copyFileSync(buildArtifacts.buildIpaFilepath, './' + buildArtifacts.buildIpaFinalFilename)
			fileOptions.fileName = buildArtifacts.buildIpaFinalFilename
			fileOptions.fileContent = fs.readFileSync(buildArtifacts.buildIpaFinalFilename)
			console.log('Saving artifact `' + fileOptions.fileName + ' to SP...')
			await spsave(coreOptions, SP_CONFIG.credentials, fileOptions)
			return true
		}
		return false
	} catch(err) {
		console.log(err)
		return false
	}
}

const generateTestPlan = async (prAuthor) => {
	try {
		let testPlanFilename
		let testPlanUrl
		if (ENV_VARS.prNumber) {
			console.log('Generating test plan for PR ' + ENV_VARS.prNumber)
			testPlanFilename = 'PR-' + ENV_VARS.prNumber + '-Test-Plan-' + ENV_VARS.appVersion + '-' + ENV_VARS.buildEnv + '-' + finalBuildNumber + '.xlsx'
			testPlanUrl = (SP_CONFIG.spSiteUrl + SP_CONFIG.spPullRequestTestFolder + testPlanFilename + '?web=1').replace(/ /g, '%20')
			console.log('  (1/3) Downloading PR test plan template ...')
			if (ENV_VARS.buildPlatform === 'IOS') {
				fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prTestPlanTemplateUrlIos))
			} else if (ENV_VARS.buildPlatform === 'ANDROID') {
				fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prTestPlanTemplateUrlAndroid))
			}
		} else {
			console.log('Generating regression test plan for branch ' + ENV_VARS.buildBranch)
			testPlanFilename = 'Regression-Test-Plan-' + ENV_VARS.appVersion + '-' + ENV_VARS.buildEnv + '-' + finalBuildNumber + '.xlsx'
			testPlanUrl = (SP_CONFIG.spSiteUrl + SP_CONFIG.spRegressionTestFolder + testPlanFilename + '?web=1').replace(/ /g, '%20')
			switch(ENV_VARS.buildEnv) {
				case 'PROD':
					console.log('  (1/3) Downloading PROD regression test plan template ...')
					if (ENV_VARS.buildPlatform === 'IOS') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prodRegressionTestPlanTemplateUrlIos))
					} else if (ENV_VARS.buildPlatform === 'ANDROID') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prodRegressionTestPlanTemplateUrlAndroid))
					}
					break
				case 'PROD-TEST':
					console.log('  (1/3) Downloading PROD-TEST regression test plan template ...')
					if (ENV_VARS.buildPlatform === 'IOS') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prodtestRegressionTestPlanTemplateUrlIos))
					} else if (ENV_VARS.buildPlatform === 'ANDROID') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prodtestRegressionTestPlanTemplateUrlAndroid))
					}
					break
				default:
					console.log('  (1/3) Downloading QA regression test plan template ...')
					if (ENV_VARS.buildPlatform === 'IOS') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.qaRegressionTestPlanTemplateUrlIos))
					} else if (ENV_VARS.buildPlatform === 'ANDROID') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.qaRegressionTestPlanTemplateUrlAndroid))
					}
			}
		}

		console.log('  (2/4) Making replacements ...')
		const data = fs.readFileSync(testPlanFilename)
		const template = new XlsxTemplate(data)
		const sheetNumber = 1
		const values = {
			APP_VERSION: ENV_VARS.appVersion,
			BUILD_ENV: ENV_VARS.buildEnv,
			BUILD_NUMBER: finalBuildNumber,
			BUILD_BRANCH: ENV_VARS.buildBranch,
		}
		if (ENV_VARS.prNumber) {
			values.PR_AUTHOR = prAuthor
			values.PR_NUMBER = ENV_VARS.prNumber
		}

		template.substitute(sheetNumber, values)

		console.log('  (3/4) Writing ' + testPlanFilename)
		fs.writeFileSync(testPlanFilename, Buffer.from(
			template.generate({type: 'base64'}),
			'base64'
		))

		console.log('  (4/4) Uploading test plan for build ' + finalBuildNumber)
		const coreOptions = { siteUrl: SP_CONFIG.spSiteUrl }
		const fileOptions = {
			folder: ENV_VARS.prNumber ? SP_CONFIG.spPullRequestTestFolder : SP_CONFIG.spRegressionTestFolder,
			fileName: testPlanFilename,
			fileContent: fs.readFileSync(testPlanFilename)
		}
		await spsave(coreOptions, SP_CONFIG.credentials, fileOptions)
		return {
			testPlanFilename: testPlanFilename,
			testPlanUrl: testPlanUrl,
		}
	} catch(err) {
		console.log(err)
		return null
	}
}

const githubMeta = async () => {
	try {
		console.log('Fetching GitHub metadata for PR ' + ENV_VARS.prNumber)
		const ghController = new AbortController()
		const ghTimeout = setTimeout(() => { ghController.abort() }, INTERNAL_TIMEOUT)
		const ghResp = await fetch('https://api.github.com/repos/UCSD/campus-mobile/pulls/' + ENV_VARS.prNumber, { signal: ghController.signal })
		const ghRespJson = await ghResp.json()
		clearTimeout(ghTimeout)
		return ghRespJson.user.login
	} catch (err) {
		console.log(err)
		return 'n/a'
	}
}

buildNotify()
<commit_msg>Update codemagic ci build notifier<commit_after>const fetch = require('node-fetch')
const AbortController = require('abort-controller')
const moment = require('moment')
const fs = require('fs')
const download = require('download')
const XlsxTemplate = require('xlsx-template')
const spsave = require('spsave').spsave
const ENV_VARS = require('./env-vars.json')
const SP_CONFIG = require('./sp-config.json')

const INTERNAL_ERROR = { 'error': 'An error occurred.' }
const INTERNAL_TIMEOUT = 20000
const finalBuildNumber = parseInt(ENV_VARS.buildNumber) + 1000
const buildArtifacts = {}

ENV_VARS.commitHash = ENV_VARS.commitHash.substring(0, 7)

const buildNotify = async () => {
	try {
		const buildTimestamp = moment().format('YYYY-MM-DD h:mm A')
		const fciProjectLink = 'https://codemagic.io/app/' + ENV_VARS.fciProjectId + '/build/' + ENV_VARS.fciBuildId
		let buildSuccess = (ENV_VARS.fciBuildStepStatus === 'success') ? true : false
		let buildApkFile = 'app-release.apk'
		let buildIpaFile = 'UC_San_Diego.ipa'
		let prAuthor = ''
		let saveArtifactApkSuccess = false
		let saveArtifactIpaSuccess = false
		let testPlanFilename = ''
		let testPlanUrl = ''

		console.log('ENV_VARS.fciBuildStepStatus: ' + ENV_VARS.fciBuildStepStatus)
		console.log('buildSuccess: ' + buildSuccess)
		console.log('buildPlatform: ' + ENV_VARS.buildPlatform)
		// Check build success
		if (buildSuccess) {
			// Supplemental GitHub metadata for PRs
			if (ENV_VARS.prNumber) {
				prAuthor = await githubMeta()
			}

			// Save build artifacts
			if (ENV_VARS.buildPlatform === 'IOS') {
				saveArtifactIpaSuccess = await saveArtifact(buildIpaFile)
			} else if (ENV_VARS.buildPlatform === 'ANDROID') {
				saveArtifactApkSuccess = await saveArtifact(buildApkFile)
			}

			// Generate test plan
			;({ testPlanFilename, testPlanUrl } = await generateTestPlan(prAuthor))
		}

		console.log('saveArtifactIpaSuccess: ' + saveArtifactIpaSuccess)
		console.log('saveArtifactApkSuccess: ' + saveArtifactApkSuccess)

		// Construct build notifier message
		let teamsMessage = '#### Campus Mobile Build Notifier\n\n'
		teamsMessage += '
'
		teamsMessage += '
Version:	' + ENV_VARS.appVersion + ' (' + finalBuildNumber + ')
'
		teamsMessage += '
Environment:	' + ENV_VARS.buildEnv + '
'

		// PR or Branch
		if (ENV_VARS.prNumber) {
			teamsMessage += '
PR:	' + ENV_VARS.prNumber + '
'
			teamsMessage += '
Author:	' + prAuthor + '
'
		} else {
			teamsMessage += '
Branch:	' + ENV_VARS.buildBranch + '
'
			teamsMessage += '
Commit:	' + ENV_VARS.commitHash + '
'
		}

		// Build Artifacts
		if (ENV_VARS.buildPlatform === 'IOS') {
			if (saveArtifactIpaSuccess) {
				teamsMessage += '
iOS:	TestFlight ' + ENV_VARS.appVersion + ' (' + finalBuildNumber + ')
'
			} else {
				teamsMessage += '
iOS:	N/A
'
			}
		} else if (ENV_VARS.buildPlatform === 'ANDROID') {
			if (saveArtifactApkSuccess) {
				teamsMessage += '
Android:	' + buildArtifacts.buildApkFinalFilename + '
'
			} else {
				teamsMessage += '
Android:	N/A
'
			}
		}

		// Test plan
		if (testPlanUrl && testPlanFilename) {
			teamsMessage += '
Testing:	' + testPlanFilename + '
'
		}

		const successEmojiList = ['🥇','🏆','🎖','🎉','🎊','🚀','🛫','🏋','💪','👏','💯']
		const failedEmojiList = ['🙀','😱','😵']

		// Build success or failure
		if (buildSuccess &&
			((saveArtifactApkSuccess && ENV_VARS.buildPlatform === 'ANDROID') ||
			(saveArtifactIpaSuccess && ENV_VARS.buildPlatform === 'IOS'))) {
			const successEmoji = successEmojiList[Math.floor(Math.random() * successEmojiList.length)]
			teamsMessage += '
Status:	BUILD SUCCESS ' + successEmoji + ' (detail)
'
		} else {
			const failedEmoji = failedEmojiList[Math.floor(Math.random() * failedEmojiList.length)]
			teamsMessage += '
Status:	BUILD FAILED ' + failedEmoji + ' (detail)
'
		}

		teamsMessage += '
Time:	' + buildTimestamp + '
'
		teamsMessage += '
'

		// Send notification via webhook integration
		console.log('Sending Teams notification for UC San Diego ' + ENV_VARS.appVersion + ' (' + finalBuildNumber + ')\n')
		const notifyController = new AbortController()
		const notifyTimeout = setTimeout(() => { notifyController.abort() }, INTERNAL_TIMEOUT)
		const notifyResp = await fetch(SP_CONFIG.webhookUrl, {
			method: 'POST',
			headers: {
				'Content-Type': 'application/json'
			},
			body: JSON.stringify({
				'text': teamsMessage
			}),
			signal: notifyController.signal,
		})
		clearTimeout(notifyTimeout)

		if (notifyResp.statusText != 'OK') {
			throw 'Error: Unable to POST to webhookUrl (status: ' + notifyResp.statusText + ')'
		}
	} catch (err) {
		console.log(err)
		process.exitCode = 1
	}
}

const saveArtifact = async (artifactFilename) => {
	try {
		// Exit if artifact filename unavailable (build failed)
		if (!artifactFilename) {
			console.log('Error1: saveArtifact: artifact filename unavailable (build failed)')
			return false
		}

		const buildFilenamePrEnvStr = ENV_VARS.prNumber ? '-PR-' + ENV_VARS.prNumber : '-' + ENV_VARS.buildEnv
		const buildFolder = ENV_VARS.prNumber ? SP_CONFIG.spPullRequestBuildFolder : SP_CONFIG.spRegressionBuildFolder
		const coreOptions = { siteUrl: SP_CONFIG.spSiteUrl }
		const fileOptions = { folder: ENV_VARS.prNumber ? SP_CONFIG.spPullRequestBuildFolder : SP_CONFIG.spRegressionBuildFolder }

		// Save build artifacts to SP
		if (ENV_VARS.buildPlatform === 'ANDROID') {
			buildArtifacts.buildApkFilepath = '../../build/app/outputs/apk/release/app-release.apk'
			buildArtifacts.buildApkFinalFilename = ENV_VARS.appVersion + '-' + finalBuildNumber + buildFilenamePrEnvStr + '.apk'
			buildArtifacts.buildApkFinalUrl = (SP_CONFIG.spSiteUrl + buildFolder + buildArtifacts.buildApkFinalFilename).replace(/ /g, '%20')
			fs.copyFileSync(buildArtifacts.buildApkFilepath, './' + buildArtifacts.buildApkFinalFilename)
			fileOptions.fileName = buildArtifacts.buildApkFinalFilename
			fileOptions.fileContent = fs.readFileSync(buildArtifacts.buildApkFinalFilename)
			console.log('Saving artifact `' + fileOptions.fileName + ' to SP...')
			await spsave(coreOptions, SP_CONFIG.credentials, fileOptions)
			return true
		} else if (ENV_VARS.buildPlatform === 'IOS') {
			buildArtifacts.buildIpaFilepath = '../../build/ios/ipa/UC San Diego.ipa'
			buildArtifacts.buildIpaFinalFilename = ENV_VARS.appVersion + '-' + finalBuildNumber + buildFilenamePrEnvStr + '.ipa'
			buildArtifacts.buildIpaFinalUrl = (SP_CONFIG.spSiteUrl + buildFolder + buildArtifacts.buildIpaFinalFilename).replace(/ /g, '%20')
			fs.copyFileSync(buildArtifacts.buildIpaFilepath, './' + buildArtifacts.buildIpaFinalFilename)
			fileOptions.fileName = buildArtifacts.buildIpaFinalFilename
			fileOptions.fileContent = fs.readFileSync(buildArtifacts.buildIpaFinalFilename)
			console.log('Saving artifact `' + fileOptions.fileName + ' to SP...')
			await spsave(coreOptions, SP_CONFIG.credentials, fileOptions)
			return true
		}
		return false
	} catch(err) {
		console.log(err)
		return false
	}
}

const generateTestPlan = async (prAuthor) => {
	try {
		let testPlanFilename
		let testPlanUrl
		if (ENV_VARS.prNumber) {
			console.log('Generating test plan for PR ' + ENV_VARS.prNumber)
			testPlanFilename = 'PR-' + ENV_VARS.prNumber + '-Test-Plan-' + ENV_VARS.appVersion + '-' + ENV_VARS.buildEnv + '-' + finalBuildNumber + '.xlsx'
			testPlanUrl = (SP_CONFIG.spSiteUrl + SP_CONFIG.spPullRequestTestFolder + testPlanFilename + '?web=1').replace(/ /g, '%20')
			console.log('  (1/3) Downloading PR test plan template ...')
			if (ENV_VARS.buildPlatform === 'IOS') {
				fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prTestPlanTemplateUrlIos))
			} else if (ENV_VARS.buildPlatform === 'ANDROID') {
				fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prTestPlanTemplateUrlAndroid))
			}
		} else {
			console.log('Generating regression test plan for branch ' + ENV_VARS.buildBranch)
			testPlanFilename = 'Regression-Test-Plan-' + ENV_VARS.appVersion + '-' + ENV_VARS.buildEnv + '-' + finalBuildNumber + '.xlsx'
			testPlanUrl = (SP_CONFIG.spSiteUrl + SP_CONFIG.spRegressionTestFolder + testPlanFilename + '?web=1').replace(/ /g, '%20')
			switch(ENV_VARS.buildEnv) {
				case 'PROD':
					console.log('  (1/3) Downloading PROD regression test plan template ...')
					if (ENV_VARS.buildPlatform === 'IOS') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prodRegressionTestPlanTemplateUrlIos))
					} else if (ENV_VARS.buildPlatform === 'ANDROID') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prodRegressionTestPlanTemplateUrlAndroid))
					}
					break
				case 'PROD-TEST':
					console.log('  (1/3) Downloading PROD-TEST regression test plan template ...')
					if (ENV_VARS.buildPlatform === 'IOS') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prodtestRegressionTestPlanTemplateUrlIos))
					} else if (ENV_VARS.buildPlatform === 'ANDROID') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.prodtestRegressionTestPlanTemplateUrlAndroid))
					}
					break
				default:
					console.log('  (1/3) Downloading QA regression test plan template ...')
					if (ENV_VARS.buildPlatform === 'IOS') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.qaRegressionTestPlanTemplateUrlIos))
					} else if (ENV_VARS.buildPlatform === 'ANDROID') {
						fs.writeFileSync(testPlanFilename, await download(SP_CONFIG.qaRegressionTestPlanTemplateUrlAndroid))
					}
			}
		}

		console.log('  (2/4) Making replacements ...')
		const data = fs.readFileSync(testPlanFilename)
		const template = new XlsxTemplate(data)
		const sheetNumber = 1
		const values = {
			APP_VERSION: ENV_VARS.appVersion,
			BUILD_ENV: ENV_VARS.buildEnv,
			BUILD_NUMBER: finalBuildNumber,
			BUILD_BRANCH: ENV_VARS.buildBranch,
		}
		if (ENV_VARS.prNumber) {
			values.PR_AUTHOR = prAuthor
			values.PR_NUMBER = ENV_VARS.prNumber
		}

		template.substitute(sheetNumber, values)

		console.log('  (3/4) Writing ' + testPlanFilename)
		fs.writeFileSync(testPlanFilename, Buffer.from(
			template.generate({type: 'base64'}),
			'base64'
		))

		console.log('  (4/4) Uploading test plan for build ' + finalBuildNumber)
		const coreOptions = { siteUrl: SP_CONFIG.spSiteUrl }
		const fileOptions = {
			folder: ENV_VARS.prNumber ? SP_CONFIG.spPullRequestTestFolder : SP_CONFIG.spRegressionTestFolder,
			fileName: testPlanFilename,
			fileContent: fs.readFileSync(testPlanFilename)
		}
		await spsave(coreOptions, SP_CONFIG.credentials, fileOptions)
		return {
			testPlanFilename: testPlanFilename,
			testPlanUrl: testPlanUrl,
		}
	} catch(err) {
		console.log(err)
		return null
	}
}

const githubMeta = async () => {
	try {
		console.log('Fetching GitHub metadata for PR ' + ENV_VARS.prNumber)
		const ghController = new AbortController()
		const ghTimeout = setTimeout(() => { ghController.abort() }, INTERNAL_TIMEOUT)
		const ghResp = await fetch('https://api.github.com/repos/UCSD/campus-mobile/pulls/' + ENV_VARS.prNumber, { signal: ghController.signal })
		const ghRespJson = await ghResp.json()
		clearTimeout(ghTimeout)
		return ghRespJson.user.login
	} catch (err) {
		console.log(err)
		return 'n/a'
	}
}

buildNotify()
<|endoftext|>