<commit_before>class TableController extends DocumentController {

    constructor(model, parent) {
        super(model, parent);
        this.columns = [];
        this.items = [
            {
                getTitle: () => 'Columns',
                items: this.columns
            }
        ];
    }

    init() {
        this.model.columns.forEach(column => this.createColumn(column));
    }
    createColumn(model) {
        const column = new ColumnController(model, this);
        column.init();
        this.columns.push(column);
        return column;
    }
    removeColumn(columnController) {
        console.log('TableController.removeColumn', columnController.getTitle());
        const i = this.columns.indexOf(columnController);
        if (i === -1) throw new Error('no such columnController');
        this.columns.splice(i, 1);
    }

    getActions() {
        return [
            {'action':'newColumn','caption':'New Column'},
            {'action':'','caption':'-'},
            {'action': 'delete', 'caption': 'Delete'},
        ];
    }

    async doAction(name) {
        switch (name) {
            case 'delete':
                this.delete();
                break;
            case 'newColumn':
                this.actionNewColumn();
                break;
            default:
                throw new Error(`unknown action: ${name}`);
        }
    }

    static async getView(view) {
        return await QForms.doHttpRequest({
            controller: 'Table',
            action    : 'getView',
            params    : Helper.encodeObject({
                view: view
            })
        });
    }

    async actionNewColumn() {
        const self = this;
        const result = await ColumnController.getView('new.html');
        if (!result.view) throw new Error('actionNewColumn: no view');
        $(document.body).append(result.view);
        $('#myModal').on('hidden.bs.modal', function(e){$(this).remove();});
        $("#myModal button[name='create']").click(function() {
            const columnName = $("#myModal input[id='columnName']").val();
            self.model.newColumn(columnName).then((data) => {
                self.addColumnItem(data).select();
            });
            $('#myModal').modal('hide');
        });
        $('#myModal').modal('show');
        $("#myModal input[id='columnName']").focus();
    }

    async createTab(docs) {
        console.log('TableController.createTab');
        const result = await TableController.getView('TableView/TableView.ejs');
        const html = QForms.render(result.view, {model: this.model});
        const $div = $(html);
        $div.find('.btnCreateForm').click(() => {
            this.createFormAction();
        });
        super.createTab(docs, $div.get(0));
    }
    onCreateFormButtonClick = async e => {
        console.log('TableController.onCreateFormButtonClick');
        await this.createFormAction();
    }
    static async getView(view) {
        console.log('TableController.getView', view);
        return QForms.doHttpRequest({
            controller: 'Table',
            action    : 'getView',
            params    : Helper.encodeObject({view : view})
        });
    }

    async createFormAction() {
        console.log('TableController.createFormAction');
        const result = await TableController.getView('newForm.ejs');
        const databaseController = this.parent;
        const applicationController = databaseController.parent;
        const application = this.model.parent.parent;
        const html = QForms.render(result.view, {
            tableName: this.model.getName(),
            pages    : application.pageLinks.map(pageLink => pageLink.getName())
        });
        $(document.body).append(html);
        $('#modal').on('hidden.bs.modal', function(e) {
            $(this).remove();
        });
        $("#modal button[name='create']").click(async () => {
            const formPage    = $("#modal select[id='formPage']").val();
            const formClass   = $("#modal select[id='formClass']").val();
            const formName    = $("#modal input[id='formName']").val();
            const formCaption = $("#modal input[id='formCaption']").val();
            const formWizard = FormWizard.create({
                model       : this.model,
                pageName    : formPage,
                className   : formClass,
                formName    : formName,
                formCaption : formCaption,
            });
            const params = formWizard.getFormParams();
            // console.log('params:', params);

            const pageLinkController = applicationController.findPageLink(formPage);
            if (!pageLinkController.pageController) {
                await pageLinkController.loadPage();
            }
            const pageController = pageLinkController.pageController;
            // console.log('pageController:', pageController);
            const form = await pageController.model.newForm(params);
            // console.log('form:', form);

            const formController = pageController.createForm(form);
            await EditorController.editorController.treeWidget2.select(formController);
            formController.view.parent.open();
            pageLinkController.view.rerender();
            EditorController.editorController.treeWidget2.scrollToSelected();

            $('#modal').modal('hide');
        });
        $('#modal').modal('show');
        $("#modal input[id='formPage']").focus();
    }
    async delete() {
        console.log('TableController.delete', this.getTitle());
        await this.model.delete();
        this.parent.removeTable2(this);
        EditorController.editorController.treeWidget2.select(null);
        EditorController.editorController.treeWidget2.rerender();
    }
    getDocumentViewClass() {
        return TableView;
    }

}
<commit_msg>TableView done<commit_after>class TableController extends DocumentController {

    constructor(model, parent) {
        super(model, parent);
        this.columns = [];
        this.items = [
            {
                getTitle: () => 'Columns',
                items: this.columns
            }
        ];
    }

    init() {
        this.model.columns.forEach(column => this.createColumn(column));
    }
    createColumn(model) {
        const column = new ColumnController(model, this);
        column.init();
        this.columns.push(column);
        return column;
    }
    removeColumn(columnController) {
        console.log('TableController.removeColumn', columnController.getTitle());
        const i = this.columns.indexOf(columnController);
        if (i === -1) throw new Error('no such columnController');
        this.columns.splice(i, 1);
    }

    getActions() {
        return [
            {
                'action': 'newColumn',
                'caption': 'New Column'
            },
            {
                'action': '',
                'caption': '-'
            },
            {
                'action': 'delete',
                'caption': 'Delete'
            },
        ];
    }

    async doAction(name) {
        switch (name) {
            case 'delete':
                this.delete();
                break;
            case 'newColumn':
                this.actionNewColumn();
                break;
            default:
                throw new Error(`unknown action: ${name}`);
        }
    }

    static async getView(view) {
        return await QForms.doHttpRequest({
            controller: 'Table',
            action    : 'getView',
            params    : Helper.encodeObject({
                view: view
            })
        });
    }

    async actionNewColumn() {
        const self = this;
        const result = await ColumnController.getView('new.html');
        if (!result.view) throw new Error('actionNewColumn: no view');
        $(document.body).append(result.view);
        $('#myModal').on('hidden.bs.modal', function(e){$(this).remove();});
        $("#myModal button[name='create']").click(function() {
            const columnName = $("#myModal input[id='columnName']").val();
            self.model.newColumn(columnName).then((data) => {
                self.addColumnItem(data).select();
            });
            $('#myModal').modal('hide');
        });
        $('#myModal').modal('show');
        $("#myModal input[id='columnName']").focus();
    }

    async createTab(docs) {
        /*console.log('TableController.createTab');
        const result = await TableController.getView('TableView/TableView.ejs');
        const html = QForms.render(result.view, {model: this.model});
        const $div = $(html);
        $div.find('.btnCreateForm').click(() => {
            this.createFormAction();
        });
        super.createTab(docs, $div.get(0));*/
    }
    onCreateFormButtonClick = async e => {
        console.log('TableController.onCreateFormButtonClick');
        await this.createFormAction();
    }
    static async getView(view) {
        console.log('TableController.getView', view);
        return QForms.doHttpRequest({
            controller: 'Table',
            action    : 'getView',
            params    : Helper.encodeObject({view : view})
        });
    }

    async createFormAction() {
        console.log('TableController.createFormAction');
        const result = await TableController.getView('newForm.ejs');
        const databaseController = this.parent;
        const applicationController = databaseController.parent;
        const application = this.model.parent.parent;
        const html = QForms.render(result.view, {
            tableName: this.model.getName(),
            pages    : application.pageLinks.map(pageLink => pageLink.getName())
        });
        $(document.body).append(html);
        $('#modal').on('hidden.bs.modal', function(e) {
            $(this).remove();
        });
        $("#modal button[name='create']").click(async () => {
            const formPage    = $("#modal select[id='formPage']").val();
            const formClass   = $("#modal select[id='formClass']").val();
            const formName    = $("#modal input[id='formName']").val();
            const formCaption = $("#modal input[id='formCaption']").val();
            const formWizard = FormWizard.create({
                model       : this.model,
                pageName    : formPage,
                className   : formClass,
                formName    : formName,
                formCaption : formCaption,
            });
            const params = formWizard.getFormParams();
            // console.log('params:', params);

            const pageLinkController = applicationController.findPageLink(formPage);
            if (!pageLinkController.pageController) {
                await pageLinkController.loadPage();
            }
            const pageController = pageLinkController.pageController;
            // console.log('pageController:', pageController);
            const form = await pageController.model.newForm(params);
            // console.log('form:', form);

            const formController = pageController.createForm(form);
            await EditorController.editorController.treeWidget2.select(formController);
            formController.view.parent.open();
            pageLinkController.view.rerender();
            EditorController.editorController.treeWidget2.scrollToSelected();

            $('#modal').modal('hide');
        });
        $('#modal').modal('show');
        $("#modal input[id='formPage']").focus();
    }
    async delete() {
        console.log('TableController.delete', this.getTitle());
        await this.model.delete();
        this.parent.removeTable2(this);
        EditorController.editorController.treeWidget2.select(null);
        EditorController.editorController.treeWidget2.rerender();
    }
    getDocumentViewClass() {
        return TableView;
    }

}
<|endoftext|>


<commit_before>"use strict";

class MQ {
  constructor(breakpoints){
    this.bp = breakpoints;
  }

  checkBP(size){
    return checkBP(size, this.bp);
  }

  min(size, callback) {
    return result(
      screenWidth() > this.checkBP(size),
      callback
    );
  }
  //alias for "min"
  minWidth(size, callback){
    return this.min(size, callback);
  }

  max(size, callback){
    return result(
      screenWidth() <= this.checkBP(size),
      callback
    );
  }
  //alias for "max"
  maxWidth(size, callback){
    return this.max(size, callback);
  }

  minHeight(size, callback){
    return result(
      screenHeight() > this.checkBP(size),
      callback
    );
  }

  maxHeight(size, callback){
    return result(
      screenHeight() <= this.checkBP(size),
      callback
    );
  }

  ratio(ratio, callback){
    return result(
      checkRatio(ratio, 'exact'),
      callback
    );
  }

  minRatio(ratio, callback){
    return result(
      checkRatio(ratio, 'min'),
      callback
    );
  }

  maxRatio(ratio, callback){
    return result(
      checkRatio(ratio, 'max'),
      callback
    );
  }

  orientation(orientation, callback){
    return result(
      checkOrientation(orientation),
      callback
    );
  }

  inside(wideSize, thinSize, callback){
    return result(
      inside(wideSize, thinSize, 'width', this.bp),
      callback
    );
  }

  outside(wideSize, thinSize, callback){
    return result(
      !inside(wideSize, thinSize, 'width', this.bp),
      callback
    );
  }

  insideHeight(tallSize, shortSize, callback){
    return result(
      inside(tallSize, shortSize, 'height', this.bp),
      callback
    );
  }

  outsideHeight(tallSize, shortSize, callback){
    return result(
      !inside(tallSize, shortSize, 'height', this.bp),
      callback
    );
  }

}

function result (isAllowed, callback = ()=>{}) {
  if (isAllowed) callback.call(window, screenSize());
  return isAllowed;
}

function screenWidth () {
  return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
}

function screenHeight () {
  return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
}

function screenSize(){
  return { width: screenWidth(), height: screenHeight() };
}

//Checks if the size is a valid breakpoint value
function checkBP(size, breakpoints){
  if (typeof size === 'string'){
    if (typeof breakpoints[size] !== 'undefined'){
      return breakpoints[size];
    } else {
      console.log('Available Breakpoints:', breakpoints);
      throw new Error(`"${size}" breakpoint does not exist`);
    }
  } else if (typeof size === 'number') {
    return size;
  } else {
    console.log('Available Breakpoints:', breakpoints);
    throw new Error(`"${size}" is not a valid breakpoint. It must be a string or a number`);
  }
}

// Test if current screen size is between 2 values
function inside (largeSize, smallSize, dimension, breakpoints) {

  const dimensions = screenSize();

  const screen_dimension = dimensions[dimension];

  if (!screen_dimension){
    throw new Error(`invalid direction: "${direction}"; valid directions are: ${Object.keys(dimensions)}`);
  }

  let largeSize = checkBP(largeSize, breakpoints);
  let smallSize = checkBP(smallSize, breakpoints);

  //If smallest is first, it swaps the values around
  if (largeSize < smallSize){
    const tmp = largeSize;
    largeSize = smallSize;
    smallSize = tmp;
  }

  return smallSize < screen_dimension && screen_dimension <= largeSize;
}

function checkRatio(ratio, style) {
  const ratios = getRatios(ratio);
  return {
    exact: ()=> ratios.converted === ratios.screen,
    min: ()=> ratios.converted > ratios.screen,
    max: ()=> ratios.converted <= ratios.screen,
  }[style];
}

function exactRatioCheck (ratio) {
  const ratios = getRatios(ratio);
  return ratios.converted === ratios.screen;
}

function minRatio () {
  return ratios.converted === ratios.screen;

}

function getRatios (ratio) {
  const { width, height } = screenSize();

  return {
    converted: convertRatio(ratio),
    screen: width / height,
  }
}

function convertRatio (ratio) {
  if (typeof ratio !== 'number' || typeof ratio !== 'string' || !ratio.match(/[0-9\.]+\s*?\/\s*?[0-9\.]+/)) {
    throw new Error(`"${ratio}" must be either a number or a string in the format "[width] / [height]"`);
  }

  if (typeof ratio === 'number') {
    return ratio;
  } else {
    return eval(ratio);
  }
}

function checkOrientation (orientation) {
  const { width, height } = screenSize();

  const orientations = {
    portrait: ()=> width < height,
    landscape: ()=> width > height,
    square: ()=> width === height,
  }

  if (!orientations[orientation]) throw new Error(`"${orientation}" not supported, valid orientations: ${Object.keys(orientations)}`);

  return orientations[orientation]();
}

export default MQ;
<commit_msg>Made all the inside/outside things have consistent naming<commit_after>"use strict";

class MQ {
  constructor(breakpoints){
    this.bp = breakpoints;
  }

  checkBP(size){
    return checkBP(size, this.bp);
  }

  min(size, callback) {
    return result(
      screenWidth() > this.checkBP(size),
      callback
    );
  }
  //alias for "min"
  minWidth(size, callback){
    return this.min(size, callback);
  }

  max(size, callback){
    return result(
      screenWidth() <= this.checkBP(size),
      callback
    );
  }
  //alias for "max"
  maxWidth(size, callback){
    return this.max(size, callback);
  }

  minHeight(size, callback){
    return result(
      screenHeight() > this.checkBP(size),
      callback
    );
  }

  maxHeight(size, callback){
    return result(
      screenHeight() <= this.checkBP(size),
      callback
    );
  }

  ratio(ratio, callback){
    return result(
      checkRatio(ratio, 'exact'),
      callback
    );
  }

  minRatio(ratio, callback){
    return result(
      checkRatio(ratio, 'min'),
      callback
    );
  }

  maxRatio(ratio, callback){
    return result(
      checkRatio(ratio, 'max'),
      callback
    );
  }

  orientation(orientation, callback){
    return result(
      checkOrientation(orientation),
      callback
    );
  }

  inside(large, small, callback){
    return result(
      inside(large, small, 'width', this.bp),
      callback
    );
  }
  //inside alias
  insideWidth(large, small, callback){
    return this.inside(large, small, callback);
  }

  outside(large, small, callback){
    return result(
      !inside(large, small, 'width', this.bp),
      callback
    );
  }
  //outside alias
  outsideWidth(large, small, callback){
    return this.outside(large, small, callback);
  }

  insideHeight(large, small, callback){
    return result(
      inside(large, small, 'height', this.bp),
      callback
    );
  }

  outsideHeight(large, small, callback){
    return result(
      !inside(large, small, 'height', this.bp),
      callback
    );
  }

}

function result (isAllowed, callback = ()=>{}) {
  if (isAllowed) callback.call(window, screenSize());
  return isAllowed;
}

function screenWidth () {
  return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
}

function screenHeight () {
  return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
}

function screenSize(){
  return { width: screenWidth(), height: screenHeight() };
}

//Checks if the size is a valid breakpoint value
function checkBP(size, breakpoints){
  if (typeof size === 'string'){
    if (typeof breakpoints[size] !== 'undefined'){
      return breakpoints[size];
    } else {
      console.log('Available Breakpoints:', breakpoints);
      throw new Error(`"${size}" breakpoint does not exist`);
    }
  } else if (typeof size === 'number') {
    return size;
  } else {
    console.log('Available Breakpoints:', breakpoints);
    throw new Error(`"${size}" is not a valid breakpoint. It must be a string or a number`);
  }
}

// Test if current screen size is between 2 values
function inside (largeSize, smallSize, dimension, breakpoints) {

  const dimensions = screenSize();

  const screen_dimension = dimensions[dimension];

  if (!screen_dimension){
    throw new Error(`invalid direction: "${direction}"; valid directions are: ${Object.keys(dimensions)}`);
  }

  let largeSize = checkBP(largeSize, breakpoints);
  let smallSize = checkBP(smallSize, breakpoints);

  //If smallest is first, it swaps the values around
  if (largeSize < smallSize){
    const tmp = largeSize;
    largeSize = smallSize;
    smallSize = tmp;
  }

  return smallSize < screen_dimension && screen_dimension <= largeSize;
}

function checkRatio(ratio, style) {
  const ratios = getRatios(ratio);
  return {
    exact: ()=> ratios.converted === ratios.screen,
    min: ()=> ratios.converted > ratios.screen,
    max: ()=> ratios.converted <= ratios.screen,
  }[style];
}

function exactRatioCheck (ratio) {
  const ratios = getRatios(ratio);
  return ratios.converted === ratios.screen;
}

function minRatio () {
  return ratios.converted === ratios.screen;

}

function getRatios (ratio) {
  const { width, height } = screenSize();

  return {
    converted: convertRatio(ratio),
    screen: width / height,
  }
}

function convertRatio (ratio) {
  if (typeof ratio !== 'number' || typeof ratio !== 'string' || !ratio.match(/[0-9\.]+\s*?\/\s*?[0-9\.]+/)) {
    throw new Error(`"${ratio}" must be either a number or a string in the format "[width] / [height]"`);
  }

  if (typeof ratio === 'number') {
    return ratio;
  } else {
    return eval(ratio);
  }
}

function checkOrientation (orientation) {
  const { width, height } = screenSize();

  const orientations = {
    portrait: ()=> width < height,
    landscape: ()=> width > height,
    square: ()=> width === height,
  }

  if (!orientations[orientation]) throw new Error(`"${orientation}" not supported, valid orientations: ${Object.keys(orientations)}`);

  return orientations[orientation]();
}

export default MQ;
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

sap.ui.define(['jquery.sap.global', 'sap/ui/core/ValueStateSupport'],
	function(jQuery, ValueStateSupport) {
	"use strict";

	/**
	 * RadioButton renderer.
	 * @namespace
	 */
	var RadioButtonRenderer = {};

	/**
	 * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the Render-Output-Buffer
	 * @param {sap.ui.core.Control} oRadioButton an object representation of the control that should be rendered
	 */
	RadioButtonRenderer.render = function(oRm, oRadioButton) {
		// get control properties
		var sId = oRadioButton.getId();
		var bEnabled = oRadioButton.getEnabled();
		var bEditable = oRadioButton.getEditable();
		var bReadOnly = !bEnabled || !bEditable;
		var bInErrorState = sap.ui.core.ValueState.Error == oRadioButton.getValueState();
		var bInWarningState = sap.ui.core.ValueState.Warning == oRadioButton.getValueState();

		// Radio Button style class
		oRm.addClass("sapMRb");

		if (!bReadOnly) {
			oRm.addClass("sapMPointer");
		}

		// write the HTML into the render manager
		oRm.write("<div"); // Control - DIV
		oRm.writeControlData(oRadioButton);

		var sTooltipWithStateMessage = ValueStateSupport.enrichTooltip(oRadioButton, oRadioButton.getTooltip_AsString());
		if (sTooltipWithStateMessage) {
			oRm.writeAttributeEscaped("title", sTooltipWithStateMessage);
		}

		// ARIA
		oRm.writeAccessibilityState(oRadioButton, {
			role: "radio",
			selected: null, // Avoid output aria-selected
			checked: oRadioButton.getSelected() === true,
			disabled: !oRadioButton.getEditable() ? true : undefined, // Avoid output aria-disabled=false when the button is editable
			labelledby: sId + "-label",
			describedby: sTooltipWithStateMessage ? sId + "-Descr" : undefined
		});

		// Add classes and properties depending on the state
		if (oRadioButton.getSelected()) {
			oRm.addClass("sapMRbSel");
		}

		if (!bEnabled) {
			oRm.addClass("sapMRbDis");
		}

		if (!bEditable) {
			oRm.addClass("sapMRbRo");
		}

		if (bInErrorState) {
			oRm.addClass("sapMRbErr");
		}

		if (bInWarningState) {
			oRm.addClass("sapMRbWarn");
		}

		oRm.writeClasses();

		if (bEnabled) {
			oRm.writeAttribute("tabindex", oRadioButton.hasOwnProperty("_iTabIndex") ? oRadioButton._iTabIndex : 0);
		}

		oRm.write(">"); // DIV element

		oRm.write("
");

		oRm.write("
"); // DIV element
		oRm.write("
"); // DIV element

		// Write the real - potentially hidden - HTML RadioButton element
		oRm.write("<input type='radio' tabindex='-1'");
		oRm.writeAttribute("id", sId + "-RB");
		oRm.writeAttributeEscaped("name", oRadioButton.getGroupName());
		if (oRadioButton.getSelected()) {
			oRm.writeAttribute("checked", "checked");
		}

		if (bReadOnly) {
			oRm.writeAttribute("readonly", "readonly");
			oRm.writeAttribute("disabled", "disabled");
		}

		oRm.write(" />"); // Close RadioButton-input-element

		oRm.write("

"); // Control - DIVs close

		oRm.write("
");
		oRm.renderControl(oRadioButton._oLabel);

		if (sTooltipWithStateMessage) {
			// for ARIA, the tooltip must be in a separate SPAN and assigned via aria-describedby.
			// otherwise, JAWS does not read it.
			oRm.write("");
			oRm.writeEscaped(sTooltipWithStateMessage);
			oRm.write("");
		}
		oRm.write("
"); // Control - DIVs close
	};

	return RadioButtonRenderer;

}, /* bExport= */ true);
<commit_msg>[INTERNAL][FIX] sap.m.RadioButton:  ARIA attribute "aria-checked" output fixed<commit_after>/*!
 * ${copyright}
 */

sap.ui.define(['jquery.sap.global', 'sap/ui/core/ValueStateSupport'],
	function(jQuery, ValueStateSupport) {
	"use strict";

	/**
	 * RadioButton renderer.
	 * @namespace
	 */
	var RadioButtonRenderer = {};

	/**
	 * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the Render-Output-Buffer
	 * @param {sap.ui.core.Control} oRadioButton an object representation of the control that should be rendered
	 */
	RadioButtonRenderer.render = function(oRm, oRadioButton) {
		// get control properties
		var sId = oRadioButton.getId();
		var bEnabled = oRadioButton.getEnabled();
		var bEditable = oRadioButton.getEditable();
		var bReadOnly = !bEnabled || !bEditable;
		var bInErrorState = sap.ui.core.ValueState.Error == oRadioButton.getValueState();
		var bInWarningState = sap.ui.core.ValueState.Warning == oRadioButton.getValueState();

		// Radio Button style class
		oRm.addClass("sapMRb");

		if (!bReadOnly) {
			oRm.addClass("sapMPointer");
		}

		// write the HTML into the render manager
		oRm.write("<div"); // Control - DIV
		oRm.writeControlData(oRadioButton);

		var sTooltipWithStateMessage = ValueStateSupport.enrichTooltip(oRadioButton, oRadioButton.getTooltip_AsString());
		if (sTooltipWithStateMessage) {
			oRm.writeAttributeEscaped("title", sTooltipWithStateMessage);
		}

		// ARIA
		oRm.writeAccessibilityState(oRadioButton, {
			role: "radio",
			selected: null, // Avoid output aria-selected
			checked: oRadioButton.getSelected() === true ? true : undefined, // aria-checked=false is default value and must not be set explicitly
			disabled: !oRadioButton.getEditable() ? true : undefined, // Avoid output aria-disabled=false when the button is editable
			labelledby: sId + "-label",
			describedby: sTooltipWithStateMessage ? sId + "-Descr" : undefined
		});

		// Add classes and properties depending on the state
		if (oRadioButton.getSelected()) {
			oRm.addClass("sapMRbSel");
		}

		if (!bEnabled) {
			oRm.addClass("sapMRbDis");
		}

		if (!bEditable) {
			oRm.addClass("sapMRbRo");
		}

		if (bInErrorState) {
			oRm.addClass("sapMRbErr");
		}

		if (bInWarningState) {
			oRm.addClass("sapMRbWarn");
		}

		oRm.writeClasses();

		if (bEnabled) {
			oRm.writeAttribute("tabindex", oRadioButton.hasOwnProperty("_iTabIndex") ? oRadioButton._iTabIndex : 0);
		}

		oRm.write(">"); // DIV element

		oRm.write("
");

		oRm.write("
"); // DIV element
		oRm.write("
"); // DIV element

		// Write the real - potentially hidden - HTML RadioButton element
		oRm.write("<input type='radio' tabindex='-1'");
		oRm.writeAttribute("id", sId + "-RB");
		oRm.writeAttributeEscaped("name", oRadioButton.getGroupName());
		if (oRadioButton.getSelected()) {
			oRm.writeAttribute("checked", "checked");
		}

		if (bReadOnly) {
			oRm.writeAttribute("readonly", "readonly");
			oRm.writeAttribute("disabled", "disabled");
		}

		oRm.write(" />"); // Close RadioButton-input-element

		oRm.write("

"); // Control - DIVs close

		oRm.write("
");
		oRm.renderControl(oRadioButton._oLabel);

		if (sTooltipWithStateMessage) {
			// for ARIA, the tooltip must be in a separate SPAN and assigned via aria-describedby.
			// otherwise, JAWS does not read it.
			oRm.write("");
			oRm.writeEscaped(sTooltipWithStateMessage);
			oRm.write("");
		}
		oRm.write("
"); // Control - DIVs close
	};

	return RadioButtonRenderer;

}, /* bExport= */ true);
<|endoftext|>


<commit_before>import {assertThrows} from './helpers.js';

contract('Exchange', function(accounts) {
  async function createTradingAccounts() {
    const custodian = SimpleCustodian.deployed();
    const seller= accounts[1];
    const buyer= accounts[2];
    const exchange = Exchange.at(await custodian.exchange());
    await custodian.give(seller, 10);
    for (let side = 0; side < 2; side++) {
      while ((await exchange.getNumberOfOffers.call(side)) > 0) {
        const [price, shares] = await exchange.getTopOffer.call(side);
        const sender = side == 0 ? buyer : seller;
        await exchange.cancelOffer(side, price, shares, {from: sender});
      }
    }
    return {custodian, exchange, buyer, seller};
  }

  function getGasCost(tx) {
    const transaction = web3.eth.getTransaction(tx);
    const receipt = web3.eth.getTransactionReceipt(tx);
    return transaction.gasPrice.mul(receipt.gasUsed);
  }

  it("should not allow offers priced at zero", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    await assertThrows(async () => await exchange.postOffer(0, 0, 100));
  });

  it("should not allow offers for zero shares", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    await assertThrows(async () => await exchange.postOffer(0, 100, 0));
  });

  it("should not allow bids without enough value", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    await assertThrows(async () => await exchange.postOffer(0, 100, 1, {value: 50}));
  });

  it("should reserve shares for accepted asks", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialAskCount = await exchange.getNumberOfOffers.call(1);
    const initialReservedShares = await custodian.getReservedBalance.call(seller);
    const initialAvailableShares = await custodian.getAvailableBalance.call(seller);
    await exchange.postOffer(1, 100, 1, {from: seller});
    const newReservedShares = await custodian.getReservedBalance.call(seller);
    const newAvailableShares = await custodian.getAvailableBalance.call(seller);
    const availableDifference = newAvailableShares.sub(initialAvailableShares);
    const reservedDifference = newReservedShares.sub(initialReservedShares);
    assert.equal(-1, availableDifference.toNumber());
    assert.equal(1, reservedDifference.toNumber());
  });

  it("should allow bids to an empty book", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialBalance = web3.eth.getBalance(buyer);
    const initialExchangeBalance = web3.eth.getBalance(exchange.address);
    const initialBidCount = await exchange.getNumberOfOffers.call(0);
    const tx = await exchange.postOffer(0, 100, 1, {from: buyer, value: 100});
    const exchangeBalance = web3.eth.getBalance(exchange.address);
    const expectedExchangeBalance = initialExchangeBalance.add(100).toString();
    assert.equal(expectedExchangeBalance.toString(), exchangeBalance.toString())
    const gasCost = getGasCost(tx);
    const balance = web3.eth.getBalance(buyer);
    const expectedBiddingBalance = initialBalance.sub(100).sub(gasCost);
    assert.equal(expectedBiddingBalance.toString(), balance.toString())
    assert.equal(initialBidCount.add(1).toString(), (await exchange.getNumberOfOffers.call(0)).toNumber());
  });

  it("should allow bids to be cancelled, returning funds", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialBidCount = await exchange.getNumberOfOffers.call(0);
    const initialExchangeBalance = await exchange.getBalance.call({from: buyer});
    await exchange.postOffer(0, 100, 1, {from: buyer, value: 100});
    await exchange.cancelOffer(0, 100, 1, {from: buyer});
    const newBidCount = await exchange.getNumberOfOffers.call(0);
    assert.equal(initialBidCount.toNumber(), newBidCount.toNumber());
    const newExchangeBalance = await exchange.getBalance.call({from: buyer});
    const returned = newExchangeBalance.sub(initialExchangeBalance).toNumber();
    assert.equal(100, returned);
  });

  it("should allow sells to be cancelled, returning funds", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialAskCount = await exchange.getNumberOfOffers.call(1);
    const initialShares = await custodian.getAvailableBalance.call(seller);
    await exchange.postOffer(1, 100, 1, {from: seller});
    await exchange.cancelOffer(1, 100, 1, {from: seller});
    const newAskCount = await exchange.getNumberOfOffers.call(1);
    assert.equal(initialAskCount.toNumber(), newAskCount.toNumber());
    const newShares = await custodian.getAvailableBalance.call(seller);
    assert.equal(initialShares.toString(), newShares.toString());
  });

  it("should allow cancelled funds to be withdrawn", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialExchangeBalance = await exchange.getBalance.call({from: buyer});
    const initialBalance = web3.eth.getBalance(buyer).add(initialExchangeBalance);
    const tx1 = await exchange.postOffer(0, 100, 1, {from: buyer, value: 100});
    let gasCost = getGasCost(tx1);
    const tx2 = await exchange.cancelOffer(0, 100, 1, {from: buyer});
    gasCost = gasCost.add(getGasCost(tx2));
    const tx3 = await exchange.withdrawal({from: buyer});
    gasCost = gasCost.add(getGasCost(tx3));
    const balance = web3.eth.getBalance(buyer);
    const expected = initialBalance.sub(gasCost);
    assert.equal(expected.toString(), balance.toString());
  })

  it("should reserve offered shares with custodian", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const startingAvailableBalance = await custodian.getAvailableBalance.call(seller);
    const startingReservedBalance = await custodian.getReservedBalance.call(seller);
    await exchange.postOffer(1, 101, 1, {from: seller});
    const newAvailableBalance = await custodian.getAvailableBalance.call(seller);
    const expectedAvailable = startingAvailableBalance.sub(1);
    assert.equal(expectedAvailable.toString(), newAvailableBalance.toString());
    const newReservedBalance = await custodian.getReservedBalance.call(seller);
    const expectedReserved = startingReservedBalance.add(1);
    assert.equal(expectedReserved.toString(), newReservedBalance.toString());
  });

  it("should match buyer with seller for exact amounts, clearing exchange", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const sellerStartingShares = await custodian.getAvailableBalance.call(seller);
    const buyerStartingShares = await custodian.getAvailableBalance.call(buyer);
    const sellerStartingBalance = await exchange.getBalance.call({from: seller});
    const buyerStartingBalance = await exchange.getBalance.call({from: buyer});
    const sellTx = await exchange.postOffer(1, 101, 1, {from: seller});
    const buyTx = await exchange.postOffer(0, 101, 1, {from: buyer, value: 101});
    const sellerEndingShares = await custodian.getAvailableBalance.call(seller);
    const buyerEndingShares = await custodian.getAvailableBalance.call(buyer);
    const sellerEndingBalance = await exchange.getBalance.call({from: seller});
    const buyerEndingBalance = await exchange.getBalance.call({from: buyer});
    const newAskCount = await exchange.getNumberOfOffers.call(1);
    const newBidCount = await exchange.getNumberOfOffers.call(0);
    assert.equal(0, newAskCount.toNumber());
    assert.equal(0, newBidCount.toNumber());
    assert.equal(buyerStartingBalance.toString(), buyerEndingBalance.toString());
    assert.equal(sellerStartingBalance.add(101).toString(), sellerEndingBalance.toString());
    assert.equal(buyerStartingShares.add(1).toString(), buyerEndingShares.toString());
    assert.equal(sellerStartingShares.sub(1).toString(), sellerEndingShares.toString());
  });

  it("should match large buyer with small seller, leaving excess on the exchange", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const sellerStartingShares = await custodian.getAvailableBalance.call(seller);
    const buyerStartingShares = await custodian.getAvailableBalance.call(buyer);
    const sellerStartingBalance = await exchange.getBalance.call({from: seller});
    const buyerStartingBalance = await exchange.getBalance.call({from: buyer});
    const sellTx = await exchange.postOffer(1, 101, 1, {from: seller});
    const buyTx = await exchange.postOffer(0, 101, 2, {from: buyer, value: 202});
    const sellerEndingShares = await custodian.getAvailableBalance.call(seller);
    const buyerEndingShares = await custodian.getAvailableBalance.call(buyer);
    const sellerEndingBalance = await exchange.getBalance.call({from: seller});
    const buyerEndingBalance = await exchange.getBalance.call({from: buyer});
    const newAskCount = await exchange.getNumberOfOffers.call(1);
    const newBidCount = await exchange.getNumberOfOffers.call(0);
    const [topBidPrice, topBidShares] = await exchange.getTopOffer.call(0);
    assert.equal(101, topBidPrice);
    assert.equal(1, topBidShares);
    assert.equal(0, newAskCount.toNumber());
    assert.equal(1, newBidCount.toNumber());
    assert.equal(buyerStartingBalance.toString(), buyerEndingBalance.toString());
    assert.equal(sellerStartingBalance.add(101).toString(), sellerEndingBalance.toString());
    assert.equal(buyerStartingShares.add(1).toString(), buyerEndingShares.toString());
    assert.equal(sellerStartingShares.sub(1).toString(), sellerEndingShares.toString());
  });
})
<commit_msg>Test for non-fill.<commit_after>import {assertThrows} from './helpers.js';

contract('Exchange', function(accounts) {
  async function createTradingAccounts() {
    const custodian = SimpleCustodian.deployed();
    const seller= accounts[1];
    const buyer= accounts[2];
    const exchange = Exchange.at(await custodian.exchange());
    await custodian.give(seller, 10);
    for (let side = 0; side < 2; side++) {
      while ((await exchange.getNumberOfOffers.call(side)) > 0) {
        const [price, shares] = await exchange.getTopOffer.call(side);
        const sender = side == 0 ? buyer : seller;
        await exchange.cancelOffer(side, price, shares, {from: sender});
      }
    }
    return {custodian, exchange, buyer, seller};
  }

  function getGasCost(tx) {
    const transaction = web3.eth.getTransaction(tx);
    const receipt = web3.eth.getTransactionReceipt(tx);
    return transaction.gasPrice.mul(receipt.gasUsed);
  }

  it("should not allow offers priced at zero", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    await assertThrows(async () => await exchange.postOffer(0, 0, 100));
  });

  it("should not allow offers for zero shares", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    await assertThrows(async () => await exchange.postOffer(0, 100, 0));
  });

  it("should not allow bids without enough value", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    await assertThrows(async () => await exchange.postOffer(0, 100, 1, {value: 50}));
  });

  it("should reserve shares for accepted asks", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialAskCount = await exchange.getNumberOfOffers.call(1);
    const initialReservedShares = await custodian.getReservedBalance.call(seller);
    const initialAvailableShares = await custodian.getAvailableBalance.call(seller);
    await exchange.postOffer(1, 100, 1, {from: seller});
    const newReservedShares = await custodian.getReservedBalance.call(seller);
    const newAvailableShares = await custodian.getAvailableBalance.call(seller);
    const availableDifference = newAvailableShares.sub(initialAvailableShares);
    const reservedDifference = newReservedShares.sub(initialReservedShares);
    assert.equal(-1, availableDifference.toNumber());
    assert.equal(1, reservedDifference.toNumber());
  });

  it("should allow bids to an empty book", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialBalance = web3.eth.getBalance(buyer);
    const initialExchangeBalance = web3.eth.getBalance(exchange.address);
    const initialBidCount = await exchange.getNumberOfOffers.call(0);
    const tx = await exchange.postOffer(0, 100, 1, {from: buyer, value: 100});
    const exchangeBalance = web3.eth.getBalance(exchange.address);
    const expectedExchangeBalance = initialExchangeBalance.add(100).toString();
    assert.equal(expectedExchangeBalance.toString(), exchangeBalance.toString())
    const gasCost = getGasCost(tx);
    const balance = web3.eth.getBalance(buyer);
    const expectedBiddingBalance = initialBalance.sub(100).sub(gasCost);
    assert.equal(expectedBiddingBalance.toString(), balance.toString())
    assert.equal(initialBidCount.add(1).toString(), (await exchange.getNumberOfOffers.call(0)).toNumber());
  });

  it("should allow bids to be cancelled, returning funds", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialBidCount = await exchange.getNumberOfOffers.call(0);
    const initialExchangeBalance = await exchange.getBalance.call({from: buyer});
    await exchange.postOffer(0, 100, 1, {from: buyer, value: 100});
    await exchange.cancelOffer(0, 100, 1, {from: buyer});
    const newBidCount = await exchange.getNumberOfOffers.call(0);
    assert.equal(initialBidCount.toNumber(), newBidCount.toNumber());
    const newExchangeBalance = await exchange.getBalance.call({from: buyer});
    const returned = newExchangeBalance.sub(initialExchangeBalance).toNumber();
    assert.equal(100, returned);
  });

  it("should allow sells to be cancelled, returning funds", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialAskCount = await exchange.getNumberOfOffers.call(1);
    const initialShares = await custodian.getAvailableBalance.call(seller);
    await exchange.postOffer(1, 100, 1, {from: seller});
    await exchange.cancelOffer(1, 100, 1, {from: seller});
    const newAskCount = await exchange.getNumberOfOffers.call(1);
    assert.equal(initialAskCount.toNumber(), newAskCount.toNumber());
    const newShares = await custodian.getAvailableBalance.call(seller);
    assert.equal(initialShares.toString(), newShares.toString());
  });

  it("should allow cancelled funds to be withdrawn", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const initialExchangeBalance = await exchange.getBalance.call({from: buyer});
    const initialBalance = web3.eth.getBalance(buyer).add(initialExchangeBalance);
    const tx1 = await exchange.postOffer(0, 100, 1, {from: buyer, value: 100});
    let gasCost = getGasCost(tx1);
    const tx2 = await exchange.cancelOffer(0, 100, 1, {from: buyer});
    gasCost = gasCost.add(getGasCost(tx2));
    const tx3 = await exchange.withdrawal({from: buyer});
    gasCost = gasCost.add(getGasCost(tx3));
    const balance = web3.eth.getBalance(buyer);
    const expected = initialBalance.sub(gasCost);
    assert.equal(expected.toString(), balance.toString());
  })

  it("should reserve offered shares with custodian", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const startingAvailableBalance = await custodian.getAvailableBalance.call(seller);
    const startingReservedBalance = await custodian.getReservedBalance.call(seller);
    await exchange.postOffer(1, 101, 1, {from: seller});
    const newAvailableBalance = await custodian.getAvailableBalance.call(seller);
    const expectedAvailable = startingAvailableBalance.sub(1);
    assert.equal(expectedAvailable.toString(), newAvailableBalance.toString());
    const newReservedBalance = await custodian.getReservedBalance.call(seller);
    const expectedReserved = startingReservedBalance.add(1);
    assert.equal(expectedReserved.toString(), newReservedBalance.toString());
  });

  it("should not match a low buyer with high seller", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const sellTx = await exchange.postOffer(1, 101, 1, {from: seller});
    const buyTx = await exchange.postOffer(0, 100, 1, {from: buyer, value: 100});
    const newAskCount = await exchange.getNumberOfOffers.call(1);
    const newBidCount = await exchange.getNumberOfOffers.call(0);
    assert.equal(1, newAskCount.toNumber());
    assert.equal(1, newBidCount.toNumber());
  });

  it("should match buyer with seller for exact amounts, clearing exchange", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const sellerStartingShares = await custodian.getAvailableBalance.call(seller);
    const buyerStartingShares = await custodian.getAvailableBalance.call(buyer);
    const sellerStartingBalance = await exchange.getBalance.call({from: seller});
    const buyerStartingBalance = await exchange.getBalance.call({from: buyer});
    const sellTx = await exchange.postOffer(1, 101, 1, {from: seller});
    const buyTx = await exchange.postOffer(0, 101, 1, {from: buyer, value: 101});
    const sellerEndingShares = await custodian.getAvailableBalance.call(seller);
    const buyerEndingShares = await custodian.getAvailableBalance.call(buyer);
    const sellerEndingBalance = await exchange.getBalance.call({from: seller});
    const buyerEndingBalance = await exchange.getBalance.call({from: buyer});
    const newAskCount = await exchange.getNumberOfOffers.call(1);
    const newBidCount = await exchange.getNumberOfOffers.call(0);
    assert.equal(0, newAskCount.toNumber());
    assert.equal(0, newBidCount.toNumber());
    assert.equal(buyerStartingBalance.toString(), buyerEndingBalance.toString());
    assert.equal(sellerStartingBalance.add(101).toString(), sellerEndingBalance.toString());
    assert.equal(buyerStartingShares.add(1).toString(), buyerEndingShares.toString());
    assert.equal(sellerStartingShares.sub(1).toString(), sellerEndingShares.toString());
  });

  it("should match large buyer with small seller, leaving excess on the exchange", async function() {
    const {custodian, exchange, buyer, seller} = await createTradingAccounts();
    const sellerStartingShares = await custodian.getAvailableBalance.call(seller);
    const buyerStartingShares = await custodian.getAvailableBalance.call(buyer);
    const sellerStartingBalance = await exchange.getBalance.call({from: seller});
    const buyerStartingBalance = await exchange.getBalance.call({from: buyer});
    const sellTx = await exchange.postOffer(1, 101, 1, {from: seller});
    const buyTx = await exchange.postOffer(0, 101, 2, {from: buyer, value: 202});
    const sellerEndingShares = await custodian.getAvailableBalance.call(seller);
    const buyerEndingShares = await custodian.getAvailableBalance.call(buyer);
    const sellerEndingBalance = await exchange.getBalance.call({from: seller});
    const buyerEndingBalance = await exchange.getBalance.call({from: buyer});
    const newAskCount = await exchange.getNumberOfOffers.call(1);
    const newBidCount = await exchange.getNumberOfOffers.call(0);
    const [topBidPrice, topBidShares] = await exchange.getTopOffer.call(0);
    assert.equal(101, topBidPrice);
    assert.equal(1, topBidShares);
    assert.equal(0, newAskCount.toNumber());
    assert.equal(1, newBidCount.toNumber());
    assert.equal(buyerStartingBalance.toString(), buyerEndingBalance.toString());
    assert.equal(sellerStartingBalance.add(101).toString(), sellerEndingBalance.toString());
    assert.equal(buyerStartingShares.add(1).toString(), buyerEndingShares.toString());
    assert.equal(sellerStartingShares.sub(1).toString(), sellerEndingShares.toString());
  });
})
<|endoftext|>


<commit_before>export const notes = state => state.notes;
export const targetNoteHash = state => state.targetNoteHash;

export const getNotesData = state => state.notesData;
export const getNotesDataByProp = state => prop => state.notesData[prop];

export const getIssueData = state => state.issueData;
export const getIssueDataByProp = state => prop => state.issueData[prop];

export const getUserData = state => state.userData;
export const getUserDataByProp = state => prop => state.userData && state.userData[prop];

export const notesById = state => state.notes.reduce((acc, note) => {
  note.notes.every(n => Object.assign(acc, { [n.id]: n }));
  return acc;
}, {});

const reverseNotes = array => array.slice(0).reverse();
const isLastNote = (note, userId) => !note.system && note.author.id === userId;

export const getCurrentUserLastNote = state => userId => reverseNotes(state.notes)
  .reduce((acc, note) => {
    acc.push(reverseNotes(note.notes).find(el => isLastNote(el, userId)));
    return acc;
  }, []).filter(el => el !== undefined)[0];

// eslint-disable-next-line no-unused-vars
export const getDiscussionLastNote = state => (discussion, userId) => reverseNotes(discussion.notes)
  .find(el => isLastNote(el, userId));

<commit_msg>[ci skip] Improve performance of getting last note<commit_after>import _ from 'underscore';

export const notes = state => state.notes;
export const targetNoteHash = state => state.targetNoteHash;

export const getNotesData = state => state.notesData;
export const getNotesDataByProp = state => prop => state.notesData[prop];

export const getIssueData = state => state.issueData;
export const getIssueDataByProp = state => prop => state.issueData[prop];

export const getUserData = state => state.userData;
export const getUserDataByProp = state => prop => state.userData && state.userData[prop];

export const notesById = state => state.notes.reduce((acc, note) => {
  note.notes.every(n => Object.assign(acc, { [n.id]: n }));
  return acc;
}, {});

const reverseNotes = array => array.slice(0).reverse();
const isLastNote = (note, state) => !note.system && note.author.id === state.userData.id;

export const getCurrentUserLastNote = state => _.flatten(reverseNotes(state.notes)
  .map(note => note.notes))
  .find(el => isLastNote(el, state));

export const getDiscussionLastNote = state => discussion => reverseNotes(discussion.notes)
  .find(el => isLastNote(el, state));
<|endoftext|>


<commit_before>function draw(){
    if(game_running){
        frames += 1;

        /*if new obstacle should be added this frame, add one*/
        if(frames%frames_per_obstacle === 0){
            i = random_number(30) + 40;
            obstacles.splice(
                0,
                0,
                [
                    width + i,
                    y + (random_number(500) - 250),
                    i,
                    random_number(30) + 40
                ]
            )
        }

        /*if obstacle frequency increase should happen this frame, do it*/
        if(settings[4] > 0 && frames_per_obstacle > 1 && frames%settings[4] === 0){
            /*obstacle frequency increase*/
            frames_per_obstacle -= 1
        }

        /*if the player has activated jetpack, increase y speed and add smoke*/
        if(key_jetpack){
            player_speed += settings[2];/*jetpack power*/
            smoke.splice(
                0,
                0,
                [-20,player_y - 10]
            )

        /*else apply gravity*/
        }else{
            player_speed -= settings[1]/*gravity*/
        }

        player_y += player_speed
    }

    if(settings[8]){/*clear?*/
        buffer.clearRect(
            0,
            0,
            width,
            height
        )
    }

    /*draw corridor over grey background*/
    buffer.fillStyle = '#000';
    buffer.fillRect(
        0,
        y - 250,
        width,
        500
    );

    /*draw player body*/
    buffer.fillStyle = '#fff';
    buffer.fillRect(
        x,
        y - player_y - 25,
        25,
        50
    );

    /*draw jetpack*/
    buffer.fillStyle = '#aaa';
    buffer.fillRect(
        x - 25,
        y - player_y - 15,
        25,
        20
    );

    /*draw activated jetpack fire*/
    if(game_running && key_jetpack){
        buffer.fillStyle = '#f00';
        buffer.fillRect(
            x - 22,
            y - player_y + 5,
            18,
            10
        )
    }

    /*check if player is outside of game boundaries*/
    if(player_y + 25 > 250 || player_y - 25 < -250){
        game_running = 0;
        update_best()
    }

    i = obstacles.length - 1;
    if(i >= 0){
        j = y - player_y;

        do{
            /*delete obstacles that are past left side of screen*/
            if(obstacles[i][0] < 0){
                obstacles.splice(i,1)
            }else if(game_running){
                /*move obstacles left*/
                obstacles[i][0] -= 10;

                /*check for player collision with obstacle*/
                if(obstacles[i][0] >= x - 25 - obstacles[i][2] / 2 &&
                   obstacles[i][0] <= x + 25 + obstacles[i][2] / 2 &&
                   obstacles[i][1] >= j - 25 - obstacles[i][3] / 2 &&
                   obstacles[i][1] <= j + 25 + obstacles[i][3] / 2){
                    game_running = 0;
                    update_best()
                }
            }
        }while(i--);

        /*draw obstacles*/
        i = obstacles.length - 1;
        if(i >= 0){
            buffer.fillStyle = '#555';
            do{
                buffer.fillRect(
                    obstacles[i][0] - obstacles[i][2] / 2,
                    obstacles[i][1] - obstacles[i][3] / 2,
                    obstacles[i][2],
                    obstacles[i][3]
                )
            }while(i--)
        }
    }

    i = smoke.length-1;
    if(i >= 0){
        /*delete smoke trails past left side of screen, else move left*/
        do{
            if(smoke[i][0] < -x){
                smoke.splice(i,1)
            }else if(game_running){
                smoke[i][0] -= 10
            }
        }while(i--);

        /*draw smoke trails behind the player*/
        i = smoke.length - 1;
        if(i >= 0){
            buffer.fillStyle = '#777';
            do{
                buffer.fillRect(
                    x + smoke[i][0],
                    y - smoke[i][1],
                    10,
                    10
                )
            }while(i--)
        }
    }

    /*setup text display*/
    buffer.font = '23pt sans-serif';
    buffer.textAlign = 'center';
    buffer.textBaseline = 'top';
    buffer.fillStyle = '#afa';

    /*if game is over, display game over messages*/
    if(!game_running){
        if(!played_explosion_sound){
            if(settings[5] > 0){/*audio volume*/
                /*play explode sound*/
            }
            played_explosion_sound = 1
        }
        i = y / 2;
        if(frames > best_display){
            buffer.fillText(
                'NEW BEST SCORE!',
                x,
                i - 60
            )
        }
        buffer.fillText(
            'You crashed... ☹',
            x,
            i
        );
        buffer.fillText(
            settings[7] + '=Restart',/*restart key*/
            x,
            i + 60
        );
        buffer.fillText(
            'ESC=Main Menu',
            x,
            i+120
        )
    }

    /*top left text displays*/
    buffer.textAlign = 'left';
    buffer.fillText(
        frames,
        5,
        0
    );
    buffer.fillText(
        best_display,
        5,
        32
    );

    if(settings[8]){/*clear?*/
        canvas.clearRect(
            0,
            0,
            width,
            height
        )
    }
    canvas.drawImage(
        get('buffer'),
        0,
        0
    )
}

function get(i){
    return document.getElementById(i)
}

function random_number(i){
    return Math.floor(Math.random() * i)
}

function resize(){
    if(mode > 0){
        width = get('buffer').width = get('canvas').width = window.innerWidth;
        height = get('buffer').height = get('canvas').height = window.innerHeight;

        x = width / 2;
        y = height / 2
    }
}

function save(){
    i = 3;
    do{
        if(isNaN(get(['ms-per-frame','obstacle-frequency','obstacle-increase','audio-volume'][i]).value) || get(['ms-per-frame','obstacle-frequency','obstacle-increase','audio-volume'][i]).value < [1,1,0,0][i]){
            get('si').value = [30,23,115,1][i]
        }
    }while(i--);

    i = 5;
    do{
        j = [
            'ms-per-frame',
            'gravity',
            'jetpack-power',
            'obstacle-frequency',
            'obstacle-increase',
            'audio-volume'
        ][i];
        if(isNaN(get(j).value) || get(j).value === [30,1,2,23,115,1][i]){
            ls.removeItem('jetpack' + i);
            settings[i] = [30,1,2,23,115,1][i];
            get(j).value = settings[i]
        }else{
            settings[i] = parseFloat(get(j).value);
            ls.setItem('jetpack' + i,settings[i])
        }
    }while(i--);

    if(get('jetpack-key').value === 'W'){
        ls.removeItem('jetpack6');
        settings[6] = 'W'
    }else{
        settings[6] = get('jetpack-key').value;
        ls.setItem('jetpack6',settings[6])
    }

    if(get('restart-key').value === 'H'){
        ls.removeItem('jetpack7');
        settings[7] = 'H'
    }else{
        settings[7] = get('restart-key').value;
        ls.setItem('jetpack7',settings[7])
    }

    settings[8] = get('clear').checked;
    if(settings[8]){
        ls.removeItem('jetpack8')
    }else{
        ls.setItem('jetpack8',0)
    }
}

function setmode(newmode){
    clearInterval(interval);

    obstacles = [];
    smoke = [];
    best_display = best;
    mode = newmode;

    /*play game mode*/
    if(mode > 0){
        save();

        frames = 0;
        frames_per_obstacle = settings[3];/*obstacle frequency*/
        game_running = 1;
        played_explosion_sound = 0;
        player_speed = 0;
        player_y = 0;

        get('page').innerHTML='<canvas id=canvas></canvas>';
        buffer = get('buffer').getContext('2d');
        canvas = get('canvas').getContext('2d');

        resize();

        interval = setInterval('draw()',settings[0])/*ms/frame*/

    /*main menu mode*/
    }else{
        buffer = 0;
        canvas = 0;

        get('page').innerHTML='

Jetpack

Cave Corridor (Best: ' + best + ')

Reset Best

<input disabled size=9 style=border:0 type=text value="Mouse Click">Activate Jetpack
<input id=jetpack-key maxlength=1 size=9 type=text value=' + settings[6] + '>Activate Jetpack
<input disabled size=9 style=border:0 type=text value=ESC>Main Menu
<input id=restart-key maxlength=1 size=9 type=text value=' + settings[7] + '>Restart

<input id=audio-volume max=1 min=0 step=.01 type=range value=' + settings[5] + '>Audio
<input ' + (settings[8] ? 'checked ' : '')+'id=clear type=checkbox>Clear
Reset Settings
Hack

<input id=gravity size=1 type=text value=' + settings[1] + '>Gravity
<input id=jetpack-power size=1 type=text value=' + settings[2] + '>Jetpack Power
<input id=ms-per-frame size=1 type=text value=' + settings[0] + '>ms/Frame
<input id=obstacle-frequency size=1 type=text value=' + settings[3] + '>Obstacle Frequency
<input id=obstacle-increase size=1 type=text value=' + settings[4] + '>Obstacle Increase

'
    }
}

function update_best(){
    if(frames > best){
        best = frames
    }
    if(best > 0){
        ls.setItem('jetpack_best',best)
    }else{
        ls.removeItem('jetpack_best')
    }
}

var ls = window.localStorage;

var best = ls.getItem('jetpack_best') === null ? 0 : parseInt(ls.getItem('jetpack_best'));
var best_display = 0;
var buffer = 0;
var canvas = 0;
var frames = 0;
var game_running = 0;
var height = 0;
var i = 0;
var interval = 0;
var j = 0;
var key_jetpack = 0;
var mode = 0;
var obstacles = [];
var played_explosion_sound = 0;
var player_speed = 0;
var player_y = 0;
var frames_per_obstacle = 0;
var settings = [
    ls.getItem('jetpack0') === null ? 30 : parseInt(ls.getItem('jetpack0')),/*ms/frame*/
    ls.getItem('jetpack1') === null ? 1 : parseFloat(ls.getItem('jetpack1')),/*gravity*/
    ls.getItem('jetpack2') === null ? 2 : parseFloat(ls.getItem('jetpack2')),/*jetpack power*/
    ls.getItem('jetpack3') === null ? 23 : parseInt(ls.getItem('jetpack3')),/*obstacle frequency*/
    ls.getItem('jetpack4') === null ? 115 : parseInt(ls.getItem('jetpack4')),/*obstacle increase*/
    ls.getItem('jetpack5') === null ? 1 : parseFloat(ls.getItem('jetpack5')),/*audio volume*/
    ls.getItem('jetpack6') === null ? 'W' : ls.getItem('jetpack6'),/*activate jetpack key*/
    ls.getItem('jetpack7') === null ? 'H' : ls.getItem('jetpack7'),/*restart key*/
    ls.getItem('jetpack8') === null/*clear?*/
];
var smoke = [];
var width = 0;
var x = 0;
var y = 0;

setmode(0);

window.onkeydown = function(e){
    if(mode > 0){
        i = window.event ? event : e;
        i = i.charCode ? i.charCode : i.keyCode;
        if(String.fromCharCode(i) === settings[6]){/*activate jetpack key*/
            key_jetpack = 1
        }else if(String.fromCharCode(i) === settings[7]){/*restart key*/
            obstacles = [];
            smoke = [];
            best_display = best;
            frames = 0;
            frames_per_obstacle = settings[3];/*obstacle frequency*/
            game_running = 1;
            played_explosion_sound = 0;
            player_speed = 0;
            player_y = 0
        }else if(i === 27){/*ESC*/
            setmode(0)
        }
    }
};

window.onkeyup = function(e){
    i = window.event ? event : e;
    i = i.charCode ? i.charCode : i.keyCode;
    if(String.fromCharCode(i) === settings[6]){/*activate jetpack key*/
        key_jetpack = 0
    }
};

window.onmousedown = function(e){
    if(mode > 0){
        e.preventDefault();
        key_jetpack = 1
    }
};

window.onmouseup = function(e){
    key_jetpack = 0
};

window.onresize = resize
<commit_msg>improved obstacle/smoke handling<commit_after>function draw(){
    if(game_running){
        frames += 1;

        /*if new obstacle should be added this frame, add one*/
        if(frames % frames_per_obstacle === 0){
            i = random_number(30) + 40;
            obstacles.splice(
                0,
                0,
                [
                    x + i,
                    random_number(500) - 250,
                    i,
                    random_number(30) + 40
                ]
            )
        }

        /*if obstacle frequency increase should happen this frame, do it*/
        if(settings[4] > 0 && frames_per_obstacle > 1 && frames % settings[4] === 0){
            /*obstacle frequency increase*/
            frames_per_obstacle -= 1
        }

        /*if the player has activated jetpack, increase y speed and add smoke*/
        if(key_jetpack){
            player_speed += settings[2];/*jetpack power*/
            smoke.splice(
                0,
                0,
                [
                    -20,
                    player_y - 10
                ]
            )

        /*else apply gravity*/
        }else{
            player_speed -= settings[1]/*gravity*/
        }

        player_y += player_speed
    }

    if(settings[8]){/*clear?*/
        buffer.clearRect(
            0,
            0,
            width,
            height
        )
    }

    /*draw corridor over grey background*/
    buffer.fillStyle = '#000';
    buffer.fillRect(
        0,
        y - 250,
        width,
        500
    );

    /*draw player body*/
    buffer.fillStyle = '#fff';
    buffer.fillRect(
        x,
        y - player_y - 25,
        25,
        50
    );

    /*draw jetpack*/
    buffer.fillStyle = '#aaa';
    buffer.fillRect(
        x - 25,
        y - player_y - 15,
        25,
        20
    );

    /*draw activated jetpack fire*/
    if(game_running && key_jetpack){
        buffer.fillStyle = '#f00';
        buffer.fillRect(
            x - 22,
            y - player_y + 5,
            18,
            10
        )
    }

    /*check if player is outside of game boundaries*/
    if(player_y + 25 > 250 || player_y - 25 < -250){
        game_running = 0;
        update_best()
    }

    i = obstacles.length - 1;
    if(i >= 0){
        if(game_running){
            do{
                /*delete obstacles that are past left side of screen*/
                if(obstacles[i][0] < -x){
                    obstacles.splice(i,1)
                }else{
                    /*move obstacles left*/
                    obstacles[i][0] -= 10;

                    /*check for player collision with obstacle*/
                    if(obstacles[i][0] >= -25 - obstacles[i][2] / 2 &&
                       obstacles[i][0] <=  25 + obstacles[i][2] / 2 &&
                       obstacles[i][1] >= -player_y - 25 - obstacles[i][3] / 2 &&
                       obstacles[i][1] <= -player_y + 25 + obstacles[i][3] / 2){
                        game_running = 0;
                        update_best()
                    }
                }
            }while(i--);

            /*get new amount of obstacles, some may have been spliced*/
            i = obstacles.length - 1
        }

        /*draw obstacles*/
        if(i >= 0){
            buffer.fillStyle = '#555';
            do{
                buffer.fillRect(
                    x + obstacles[i][0] - obstacles[i][2] / 2,
                    y + obstacles[i][1] - obstacles[i][3] / 2,
                    obstacles[i][2],
                    obstacles[i][3]
                )
            }while(i--)
        }
    }

    i = smoke.length-1;
    if(i >= 0){
        if(game_running){
            /*delete smoke trails past left side of screen, else move left*/
            do{
                if(smoke[i][0] < -x){
                    smoke.splice(i,1)
                }else if(game_running){
                    smoke[i][0] -= 10
                }
            }while(i--);

            /*get new amount of smoke, some may have been spliced*/
            i = smoke.length - 1
        }

        /*draw smoke trails behind the player*/
        if(i >= 0){
            buffer.fillStyle = '#777';
            do{
                buffer.fillRect(
                    x + smoke[i][0],
                    y - smoke[i][1],
                    10,
                    10
                )
            }while(i--)
        }
    }

    /*setup text display*/
    buffer.font = '23pt sans-serif';
    buffer.textAlign = 'center';
    buffer.textBaseline = 'top';
    buffer.fillStyle = '#afa';

    /*if game is over, display game over messages*/
    if(!game_running){
        if(!played_explosion_sound){
            if(settings[5] > 0){/*audio volume*/
                /*play explode sound*/
            }
            played_explosion_sound = 1
        }

        i = y / 2;
        if(frames > best_display){
            buffer.fillText(
                'NEW BEST SCORE!',
                x,
                i - 60
            )
        }
        buffer.fillText(
            'You crashed... ☹',
            x,
            i
        );
        buffer.fillText(
            settings[7] + '=Restart',/*restart key*/
            x,
            i + 60
        );
        buffer.fillText(
            'ESC=Main Menu',
            x,
            i+120
        )
    }

    /*top left text displays*/
    buffer.textAlign = 'left';
    buffer.fillText(
        frames,
        5,
        0
    );
    buffer.fillText(
        best_display,
        5,
        32
    );

    if(settings[8]){/*clear?*/
        canvas.clearRect(
            0,
            0,
            width,
            height
        )
    }
    canvas.drawImage(
        get('buffer'),
        0,
        0
    )
}

function get(i){
    return document.getElementById(i)
}

function random_number(i){
    return Math.floor(Math.random() * i)
}

function resize(){
    if(mode > 0){
        width = get('buffer').width = get('canvas').width = window.innerWidth;
        height = get('buffer').height = get('canvas').height = window.innerHeight;

        x = width / 2;
        y = height / 2
    }
}

function save(){
    i = 3;
    do{
        if(isNaN(get(['ms-per-frame','obstacle-frequency','obstacle-increase','audio-volume'][i]).value) || get(['ms-per-frame','obstacle-frequency','obstacle-increase','audio-volume'][i]).value < [1,1,0,0][i]){
            get('si').value = [30,23,115,1][i]
        }
    }while(i--);

    i = 5;
    do{
        j = [
            'ms-per-frame',
            'gravity',
            'jetpack-power',
            'obstacle-frequency',
            'obstacle-increase',
            'audio-volume'
        ][i];
        if(isNaN(get(j).value) || get(j).value === [30,1,2,23,115,1][i]){
            ls.removeItem('jetpack' + i);
            settings[i] = [30,1,2,23,115,1][i];
            get(j).value = settings[i]
        }else{
            settings[i] = parseFloat(get(j).value);
            ls.setItem('jetpack' + i,settings[i])
        }
    }while(i--);

    if(get('jetpack-key').value === 'W'){
        ls.removeItem('jetpack6');
        settings[6] = 'W'
    }else{
        settings[6] = get('jetpack-key').value;
        ls.setItem('jetpack6',settings[6])
    }

    if(get('restart-key').value === 'H'){
        ls.removeItem('jetpack7');
        settings[7] = 'H'
    }else{
        settings[7] = get('restart-key').value;
        ls.setItem('jetpack7',settings[7])
    }

    settings[8] = get('clear').checked;
    if(settings[8]){
        ls.removeItem('jetpack8')
    }else{
        ls.setItem('jetpack8',0)
    }
}

function setmode(newmode){
    clearInterval(interval);

    obstacles = [];
    smoke = [];
    best_display = best;
    mode = newmode;

    /*play game mode*/
    if(mode > 0){
        save();

        frames = 0;
        frames_per_obstacle = settings[3];/*obstacle frequency*/
        game_running = 1;
        played_explosion_sound = 0;
        player_speed = 0;
        player_y = 0;

        get('page').innerHTML='<canvas id=canvas></canvas>';
        buffer = get('buffer').getContext('2d');
        canvas = get('canvas').getContext('2d');

        resize();

        interval = setInterval('draw()',settings[0])/*ms/frame*/

    /*main menu mode*/
    }else{
        buffer = 0;
        canvas = 0;

        get('page').innerHTML='

Jetpack

Cave Corridor (Best: ' + best + ')

Reset Best

<input disabled size=9 style=border:0 type=text value="Mouse Click">Activate Jetpack
<input id=jetpack-key maxlength=1 size=9 type=text value=' + settings[6] + '>Activate Jetpack
<input disabled size=9 style=border:0 type=text value=ESC>Main Menu
<input id=restart-key maxlength=1 size=9 type=text value=' + settings[7] + '>Restart

<input id=audio-volume max=1 min=0 step=.01 type=range value=' + settings[5] + '>Audio
<input ' + (settings[8] ? 'checked ' : '')+'id=clear type=checkbox>Clear
Reset Settings
Hack

<input id=gravity size=1 type=text value=' + settings[1] + '>Gravity
<input id=jetpack-power size=1 type=text value=' + settings[2] + '>Jetpack Power
<input id=ms-per-frame size=1 type=text value=' + settings[0] + '>ms/Frame
<input id=obstacle-frequency size=1 type=text value=' + settings[3] + '>Obstacle Frequency
<input id=obstacle-increase size=1 type=text value=' + settings[4] + '>Obstacle Increase

'
    }
}

function update_best(){
    if(frames > best){
        best = frames
    }
    if(best > 0){
        ls.setItem('jetpack_best',best)
    }else{
        ls.removeItem('jetpack_best')
    }
}

var ls = window.localStorage;

var best = ls.getItem('jetpack_best') === null ? 0 : parseInt(ls.getItem('jetpack_best'));
var best_display = 0;
var buffer = 0;
var canvas = 0;
var frames = 0;
var game_running = 0;
var height = 0;
var i = 0;
var interval = 0;
var j = 0;
var key_jetpack = 0;
var mode = 0;
var obstacles = [];
var played_explosion_sound = 0;
var player_speed = 0;
var player_y = 0;
var frames_per_obstacle = 0;
var settings = [
    ls.getItem('jetpack0') === null ? 30 : parseInt(ls.getItem('jetpack0')),/*ms/frame*/
    ls.getItem('jetpack1') === null ? 1 : parseFloat(ls.getItem('jetpack1')),/*gravity*/
    ls.getItem('jetpack2') === null ? 2 : parseFloat(ls.getItem('jetpack2')),/*jetpack power*/
    ls.getItem('jetpack3') === null ? 23 : parseInt(ls.getItem('jetpack3')),/*obstacle frequency*/
    ls.getItem('jetpack4') === null ? 115 : parseInt(ls.getItem('jetpack4')),/*obstacle increase*/
    ls.getItem('jetpack5') === null ? 1 : parseFloat(ls.getItem('jetpack5')),/*audio volume*/
    ls.getItem('jetpack6') === null ? 'W' : ls.getItem('jetpack6'),/*activate jetpack key*/
    ls.getItem('jetpack7') === null ? 'H' : ls.getItem('jetpack7'),/*restart key*/
    ls.getItem('jetpack8') === null/*clear?*/
];
var smoke = [];
var width = 0;
var x = 0;
var y = 0;

setmode(0);

window.onkeydown = function(e){
    if(mode > 0){
        i = window.event ? event : e;
        i = i.charCode ? i.charCode : i.keyCode;
        if(String.fromCharCode(i) === settings[6]){/*activate jetpack key*/
            key_jetpack = 1
        }else if(String.fromCharCode(i) === settings[7]){/*restart key*/
            obstacles = [];
            smoke = [];
            best_display = best;
            frames = 0;
            frames_per_obstacle = settings[3];/*obstacle frequency*/
            game_running = 1;
            played_explosion_sound = 0;
            player_speed = 0;
            player_y = 0
        }else if(i === 27){/*ESC*/
            setmode(0)
        }
    }
};

window.onkeyup = function(e){
    i = window.event ? event : e;
    i = i.charCode ? i.charCode : i.keyCode;
    if(String.fromCharCode(i) === settings[6]){/*activate jetpack key*/
        key_jetpack = 0
    }
};

window.onmousedown = function(e){
    if(mode > 0){
        e.preventDefault();
        key_jetpack = 1
    }
};

window.onmouseup = function(e){
    key_jetpack = 0
};

window.onresize = resize
<|endoftext|>


<commit_before>$(document).ready(function() {

  var app = {}; // namespace

  _.templateSettings = {
      interpolate: /<@=(.+?)@>/g,
      escape: /<@-(.+?)@>/g,
      evaluate: /<@(.+?)@>/g
  };

  app.Entity = Backbone.Model.extend({
    name: 'entities',
    defaults: {
      name: '',
      id: null
    },
    toJSON: function() {
      return { entities: [ _.clone( this.attributes ) ] }
    },
    urlRoot: $( "body" ).data("api-url" ) + "/entities"
  });

  app.EntityCollection = Backbone.Collection.extend({
    model: app.Entity,
    comparator: 'name',
    url: $( "body" ).data("api-url" ) + "/entities"
  });

  app.Contact = Backbone.Model.extend({
    name: 'contacts',
    defaults: {
      first_name: '',
      last_name: '',
      email: '',
      id: null
    },
    toJSON: function() {
      return { contacts: [ _.clone( this.attributes ) ] }
    },
    // required for all linked data types received
    // TODO how will we handle circular references? make it a string and eval it?
    linkages: {
      entity: app.Entity,
      entities: app.EntityCollection
    },
    urlRoot : $( "body" ).data("api-url" ) + "/contacts"
  });

  app.ContactCollection = Backbone.Collection.extend({
    model: app.Contact,
    url: $( "body" ).data("api-url" ) + "/contacts",
    linkages: {
      entity: app.Entity,
      entities: app.EntityCollection
    },
  });

  app.ActionsView = Backbone.View.extend({
    tagName: 'div',
    className: 'actions',
    template: _.template($('#contact-actions-template').html()),
    events: {
      "click .contact_add" : "add",
    },
    add: function() {
      var contact = new app.Contact();
      contact.set('links', {entities: new app.EntityCollection()});
      this.collection.add(contact);
    },
    render: function() {
      this.$el.html(this.template({}));
      return this;
    }
  });

  // this.model      == current contact
  // this.collection == duplicate of entities with
  //     entities enabled for this contact removed
  app.EntityChooser = Backbone.View.extend({
    tagName: 'input',
    attributes: {type: 'hidden'},
    className: 'entityChooser',
    initialize: function() {
      var contact_entity_ids = this.model.get('links')['entities'].pluck('id');

      var someEntities = allEntities.reject(function(item, context) {
        return _.contains(contact_entity_ids, item.get('id'));
      });

      this.collection = new app.EntityCollection(someEntities);
    },
   render: function() {
      var jqel = $(this.el);

      var results = this.collection.map( function(item) {
        return item.attributes;
      });

      var format = function(item) { return item.name; }

      jqel.select2({
        placeholder: "Select an Entity",
        data: { results: results, text: 'name'},
        formatSelection: format,
        formatResult: format
      });

      return this;
    },

  });

  app.EntitiesEnabled = Backbone.View.extend({
    tagName: 'select',
    className: 'entityList',
    attributes: {
      size: "12",
      multiple: "multiple"
    },
    initialize: function() {
      this.collection.on('add', this.render, this);
    },
    render: function() {
      var jqel = $(this.el);

      jqel.find('option').remove();

      this.collection.each(function(entity) {
         var item = new app.EntityListItem({ model: entity });
         jqel.append(item.render().el);
      });

      return this;
    },
  });

  app.ContactList = Backbone.View.extend({
    tagName: 'ul',
    className: 'contactList',
    initialize: function() {
      this.collection.on('add', this.render, this);
    },
    render: function() {
      var jqel = $(this.el);

      jqel.find('li').remove();

      this.collection.each(function(contact) {
        var item = new app.ContactListItem({ model: contact });
        jqel.append(item.render().el);
      });

      return this;
    },
  });

  app.EntityListItem = Backbone.View.extend({
    tagName: 'option',
    render: function() {

      // TODO piggyback data from model record
      this.$el.html('<option>' + this.model.escape('name')  + '</option>');

      return this;
    }
  });

  app.ContactListItem = Backbone.View.extend({
    tagName: 'li',
    template: _.template($('#contact-list-item-template').html()),
    events: {
      "click button.contact_entities" : "toggleEntities",
      "click button.contact_edit"     : "toggleEdit",
      "click button.contact_save"     : "save",
      "click button.contact_reset"    : "reset",
      "click button.contact_remove"   : "remove",
    },

    render: function() {
      var template_values = _.clone(this.model.attributes);
      var el = this.$el;
      _.each(['entities', 'edit'], function(item) {
        var display = el.children('div.contact_' + item + '_view').css('display');

        if ( _.isUndefined(display) || (display == 'none') ) {
          display = 'none';
        } else {
          display = 'block';
        }
        template_values[item + '_display'] = display;
      });

      this.$el.html(this.template(template_values));

      var entities = this.model.get('links')['entities'];

      if ( _.isUndefined(entities) ) {
        entities = new app.EntityCollection();
      }

      var entitiesEnabled = new app.EntitiesEnabled({collection: entities});
      entitiesEnabled.render();

      var entityChooser = new app.EntityChooser({model: this.model});

      this.$el.find('div.contact_entities_view').empty()
        .append( entitiesEnabled.$el )
        .append( entityChooser.$el );

      // after the element is attached to the DOM
      entityChooser.render();

      return this;
    },
    toggleEntities: function() {
      this.$el.children('div.contact_entities_view').toggle();
    },
    toggleEdit: function() {
      this.$el.children('div.contact_edit_view').toggle();
    },
    save: function() {
      this.model.save({
        first_name: this.$el.find('input.contact_first_name').val(),
        last_name:  this.$el.find('input.contact_last_name').val(),
        email:      this.$el.find('input.contact_email').val()
      });
      this.$el.children('.contact').hide();
      this.render();
    },
    reset: function() {
      this.render();
    },
    remove: function() {
      this.model.destroy();
      this.$el.remove();
    }

  });

  var allEntities = new app.EntityCollection();
  var contacts = new app.ContactCollection();

  allEntities.fetch({success: function(coll, response, options) {
    contacts.fetch({success: function(coll, response, options) {
      var actionsView = new app.ActionsView({collection: coll});
      var contactList = new app.ContactList({collection: coll});
      $('#container').append(actionsView.render().el);
      $('#container').append(contactList.render().el);
    }});
  }});

});
<commit_msg>Refactor data url out into a single variable<commit_after>$(document).ready(function() {

  var app = {
    api_url: $('div#data-api-url').data('api-url')
  };

  _.templateSettings = {
      interpolate: /<@=(.+?)@>/g,
      escape: /<@-(.+?)@>/g,
      evaluate: /<@(.+?)@>/g
  };

  app.Entity = Backbone.Model.extend({
    name: 'entities',
    defaults: {
      name: '',
      id: null
    },
    toJSON: function() {
      return { entities: [ _.clone( this.attributes ) ] }
    },
    urlRoot: app.api_url + "/entities"
  });

  app.EntityCollection = Backbone.Collection.extend({
    model: app.Entity,
    comparator: 'name',
    url: app.api_url + "/entities"
  });

  app.Contact = Backbone.Model.extend({
    name: 'contacts',
    defaults: {
      first_name: '',
      last_name: '',
      email: '',
      id: null
    },
    toJSON: function() {
      return { contacts: [ _.clone( this.attributes ) ] }
    },
    // required for all linked data types received
    // TODO how will we handle circular references? make it a string and eval it?
    linkages: {
      entity: app.Entity,
      entities: app.EntityCollection
    },
    urlRoot : app.api_url + "/contacts"
  });

  app.ContactCollection = Backbone.Collection.extend({
    model: app.Contact,
    url: app.api_url + "/contacts",
    linkages: {
      entity: app.Entity,
      entities: app.EntityCollection
    },
  });

  app.ActionsView = Backbone.View.extend({
    tagName: 'div',
    className: 'actions',
    template: _.template($('#contact-actions-template').html()),
    events: {
      "click .contact_add" : "add",
    },
    add: function() {
      var contact = new app.Contact();
      contact.set('links', {entities: new app.EntityCollection()});
      this.collection.add(contact);
    },
    render: function() {
      this.$el.html(this.template({}));
      return this;
    }
  });

  // this.model      == current contact
  // this.collection == duplicate of entities with
  //     entities enabled for this contact removed
  app.EntityChooser = Backbone.View.extend({
    tagName: 'input',
    attributes: {type: 'hidden'},
    className: 'entityChooser',
    initialize: function() {
      var contact_entity_ids = this.model.get('links')['entities'].pluck('id');

      var someEntities = allEntities.reject(function(item, context) {
        return _.contains(contact_entity_ids, item.get('id'));
      });

      this.collection = new app.EntityCollection(someEntities);
    },
   render: function() {
      var jqel = $(this.el);

      var results = this.collection.map( function(item) {
        return item.attributes;
      });

      var format = function(item) { return item.name; }

      jqel.select2({
        placeholder: "Select an Entity",
        data: { results: results, text: 'name'},
        formatSelection: format,
        formatResult: format
      });

      return this;
    },

  });

  app.EntitiesEnabled = Backbone.View.extend({
    tagName: 'select',
    className: 'entityList',
    attributes: {
      size: "12",
      multiple: "multiple"
    },
    initialize: function() {
      this.collection.on('add', this.render, this);
    },
    render: function() {
      var jqel = $(this.el);

      jqel.find('option').remove();

      this.collection.each(function(entity) {
         var item = new app.EntityListItem({ model: entity });
         jqel.append(item.render().el);
      });

      return this;
    },
  });

  app.ContactList = Backbone.View.extend({
    tagName: 'ul',
    className: 'contactList',
    initialize: function() {
      this.collection.on('add', this.render, this);
    },
    render: function() {
      var jqel = $(this.el);

      jqel.find('li').remove();

      this.collection.each(function(contact) {
        var item = new app.ContactListItem({ model: contact });
        jqel.append(item.render().el);
      });

      return this;
    },
  });

  app.EntityListItem = Backbone.View.extend({
    tagName: 'option',
    render: function() {

      // TODO piggyback data from model record
      this.$el.html('<option>' + this.model.escape('name')  + '</option>');

      return this;
    }
  });

  app.ContactListItem = Backbone.View.extend({
    tagName: 'li',
    template: _.template($('#contact-list-item-template').html()),
    events: {
      "click button.contact_entities" : "toggleEntities",
      "click button.contact_edit"     : "toggleEdit",
      "click button.contact_save"     : "save",
      "click button.contact_reset"    : "reset",
      "click button.contact_remove"   : "remove",
    },

    render: function() {
      var template_values = _.clone(this.model.attributes);
      var el = this.$el;
      _.each(['entities', 'edit'], function(item) {
        var display = el.children('div.contact_' + item + '_view').css('display');

        if ( _.isUndefined(display) || (display == 'none') ) {
          display = 'none';
        } else {
          display = 'block';
        }
        template_values[item + '_display'] = display;
      });

      this.$el.html(this.template(template_values));

      var entities = this.model.get('links')['entities'];

      if ( _.isUndefined(entities) ) {
        entities = new app.EntityCollection();
      }

      var entitiesEnabled = new app.EntitiesEnabled({collection: entities});
      entitiesEnabled.render();

      var entityChooser = new app.EntityChooser({model: this.model});

      this.$el.find('div.contact_entities_view').empty()
        .append( entitiesEnabled.$el )
        .append( entityChooser.$el );

      // after the element is attached to the DOM
      entityChooser.render();

      return this;
    },
    toggleEntities: function() {
      this.$el.children('div.contact_entities_view').toggle();
    },
    toggleEdit: function() {
      this.$el.children('div.contact_edit_view').toggle();
    },
    save: function() {
      this.model.save({
        first_name: this.$el.find('input.contact_first_name').val(),
        last_name:  this.$el.find('input.contact_last_name').val(),
        email:      this.$el.find('input.contact_email').val()
      });
      this.$el.children('.contact').hide();
      this.render();
    },
    reset: function() {
      this.render();
    },
    remove: function() {
      this.model.destroy();
      this.$el.remove();
    }
  });

  var allEntities = new app.EntityCollection();
  var contacts = new app.ContactCollection();

  allEntities.fetch({success: function(coll, response, options) {
    contacts.fetch({
      success: function(collection, response, options) {
        var actionsView = new app.ActionsView({collection: collection});
        var contactList = new app.ContactList({collection: collection});
          $('#container').append(actionsView.render().el);
          $('#container').append(contactList.render().el);
        }
    });
  }});

});
<|endoftext|>


<commit_before>describe( 'weatherWidget', function() {

	var controller ;

	// Make the AngularJS app available to each test
	beforeEach( module( 'weatherWidget' ) ) ;

	// Make the widget controller available to each test
	// In a normal app we wouldn't do this, but because we only have one controller it's OK
	beforeEach( inject( function( _$controller_ ) {
		controller = _$controller_( 'weatherController' ) ;
	} ) ) ;

	describe( 'array functions in weather widget controller', function() {

		var mockLocation = { name: 'Paradise', data: { temperature: 40, summary: 'Bloody hot', icon: '' } } ;

		it( 'locations array should initially be empty', function() {
			expect( controller.locations.length ).toBe( 0 ) ;
		} ) ;

		it( 'addLocation should extend the locations array', function() {
			controller.addLocation( mockLocation.name, mockLocation.data )
			.then( function( result ) {
				expect( controller.locations.length ).toBe( 1 ) ;
			} )
			.catch( function( error ) {
				fail( 'Error adding location ' + error ) ;
			} ) ;
		} ) ;

	} ) ;

} ) ;
<commit_msg>Bit more testing added<commit_after>describe( 'weatherWidget', function() {

	var controller ;

	// Make the AngularJS app available to each test
	beforeEach( module( 'weatherWidget' ) ) ;

	// Make the widget controller available to each test
	// In a normal app we wouldn't do this, but because we only have one controller it's OK
	beforeEach( inject( function( _$controller_ ) {
		controller = _$controller_( 'weatherController' ) ;
	} ) ) ;

	describe( 'array functions in weather widget controller', function() {

		var mockLocation = { name: 'Paradise', data: { temperature: 40, summary: 'Bloody hot', icon: '' } } ;

		it( 'locations array should initially be empty', function() {
			expect( controller.locations.length ).toBe( 0 ) ;
		} ) ;

		it( 'addLocation should lengthen the locations array', function() {
			controller.addLocation( mockLocation.name, mockLocation.data )
			.then( function( result ) {
				expect( controller.locations.length ).toBe( 1 ) ;
			} )
			.catch( function( error ) {
				fail( 'Error adding location ' + error ) ;
			} ) ;
		} ) ;

		it( 'removeLocation should shorten the locations array', function() {
			controller.removeLocation( 0 ) ;
			expect( controller.locations.length ).toBe( 0 ) ;
		} ) ;

	} ) ;

} ) ;
<|endoftext|>


<commit_before>import Mixin from '@ember/object/mixin';
import Errors from 'ui/utils/errors';
import { get, set, setProperties, computed } from '@ember/object';

export default Mixin.create({

  isEnabled: computed('authConfig.enabled', 'testing', function() {
    const testing = get(this, 'testing');
    const enabled = get(this, 'authConfig.enabled');

    return enabled && !testing;
  }),

  editing:    false,
  authConfig: null,

  actions: {

    cancel() {
      if (this.transitionToRoute) {
        this.transitionToRoute('security.authentication');
      }
    },

    edit() {
      set(this, 'editing', true);
    },

    waitAndRefresh(url) {
      $('#loading-underlay, #loading-overlay').removeClass('hide').show();  // eslint-disable-line

      setTimeout(() => {
        window.location.href = url || window.location.href;
      }, 1000);
    },

    gotError(err) {
      if ( err.message ) {
        this.send('showError', err.message + (err.detail ? `(${ err.detail })` : ''));
      } else {
        this.send('showError', `Error (${ err.status  } - ${  err.code })`);
      }

      setProperties(this, {
        testing: false,
        saving:  false,
      });
    },

    showError(err) {
      set(this, 'errors', [Errors.stringify(err)]);

      window.scrollY = 0;
    },

    clearError() {
      set(this, 'errors', null);
    },

    disable() {
      this.send('clearError');

      const model = get(this, 'authConfig');
      const accessMode = get(model, 'id') === 'github' || 'googleoauth' ? 'restricted' : 'unrestricted';

      setProperties(model, {
        enabled:             false,
        accessMode,
        allowedPrincipalIds: []
      });

      model.doAction('disable').then(() => {
        model.save().then( () => {
          this.send('waitAndRefresh');
        });
      }).catch((err) => {
        this.send('gotError', err);
      }).finally(() => {
        set(this, 'confirmDisable', false);
      });
    },

  }
});
<commit_msg>Remove PUT request on disabling auth<commit_after>import Mixin from '@ember/object/mixin';
import Errors from 'ui/utils/errors';
import { get, set, setProperties, computed } from '@ember/object';

export default Mixin.create({

  isEnabled: computed('authConfig.enabled', 'testing', function() {
    const testing = get(this, 'testing');
    const enabled = get(this, 'authConfig.enabled');

    return enabled && !testing;
  }),

  editing:    false,
  authConfig: null,

  actions: {

    cancel() {
      if (this.transitionToRoute) {
        this.transitionToRoute('security.authentication');
      }
    },

    edit() {
      set(this, 'editing', true);
    },

    waitAndRefresh(url) {
      $('#loading-underlay, #loading-overlay').removeClass('hide').show();  // eslint-disable-line

      setTimeout(() => {
        window.location.href = url || window.location.href;
      }, 1000);
    },

    gotError(err) {
      if ( err.message ) {
        this.send('showError', err.message + (err.detail ? `(${ err.detail })` : ''));
      } else {
        this.send('showError', `Error (${ err.status  } - ${  err.code })`);
      }

      setProperties(this, {
        testing: false,
        saving:  false,
      });
    },

    showError(err) {
      set(this, 'errors', [Errors.stringify(err)]);

      window.scrollY = 0;
    },

    clearError() {
      set(this, 'errors', null);
    },

    disable() {
      this.send('clearError');

      const model = get(this, 'authConfig');
      const accessMode = get(model, 'id') === 'github' || 'googleoauth' ? 'restricted' : 'unrestricted';

      setProperties(model, {
        enabled:             false,
        accessMode,
        allowedPrincipalIds: []
      });

      model.doAction('disable').then(() => {
        this.send('waitAndRefresh');
      }).catch((err) => {
        this.send('gotError', err);
      }).finally(() => {
        set(this, 'confirmDisable', false);
      });
    },

  }
});
<|endoftext|>