<commit_before>// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt

frappe.ui.form.on('Payment Order', {
	setup: function(frm) {
		frm.set_query("company_bank_account", function() {
			return {
				filters: {
					"is_company_account":1
				}
			}
		});
	},
	refresh: function(frm) {
		if (frm.doc.docstatus == 0) {
			frm.add_custom_button(__('Payment Request'), function() {
				frm.trigger("get_from_payment_request");
			}, __("Get from"));

			frm.add_custom_button(__('Payment Entry'), function() {
				frm.trigger("get_from_payment_entry");
			}, __("Get from"));

			frm.trigger('remove_button');
		}

		// payment Entry
		if (frm.doc.docstatus===1 && frm.doc.payment_order_type==='Payment Request') {
			frm.add_custom_button(__('Create Payment Entries'),
			function() {
				frm.trigger("make_payment_records");
			});
		}
	},

	remove_row_if_empty: function(frm) {
		// remove if first row is empty
		if (frm.doc.references.length > 0 && !frm.doc.references[0].reference_name) {
			frm.doc.references = [];
		}
	},

	remove_button: function(frm) {
		// remove custom button of order type that is not imported

		let label = ["Payment Request", "Payment Entry"]

		if (frm.doc.references.length > 0 && frm.doc.payment_order_type) {
			label = label.reduce(x => {
				x!= frm.doc.payment_order_type;
				return x;
			});
			frm.remove_custom_button(label, "Get from");
		}
	},

	get_from_payment_entry: function(frm) {
		frm.trigger("remove_row_if_empty");
		erpnext.utils.map_current_doc({
			method: "erpnext.accounts.doctype.payment_entry.payment_entry.make_payment_order",
			source_doctype: "Payment Entry",
			target: frm,
			date_field: "posting_date",
			setters: {
				party: frm.doc.supplier || ""
			},
			get_query_filters: {
				bank: frm.doc.bank,
				docstatus: 1,
				bank_account: frm.doc.company_bank_account,
				paid_from: frm.doc.account,
				status: ["=", "Initiated"],
			}
		});
	},

	get_from_payment_request: function(frm) {
		frm.trigger("remove_row_if_empty")
		erpnext.utils.map_current_doc({
			method: "erpnext.accounts.doctype.payment_request.payment_request.make_payment_order",
			source_doctype: "Payment Request",
			target: frm,
			setters: {
				party: frm.doc.supplier || ""
			},
			get_query_filters: {
				bank: frm.doc.bank,
				docstatus: 1,
				status: ["=", "Initiated"],
			}
		});
	},

	make_payment_records: function(frm){
		var dialog = new frappe.ui.Dialog({
			title: __("For Supplier"),
			fields: [
				{"fieldtype": "Link", "label": __("Supplier"), "fieldname": "supplier", "options":"Supplier",
					"get_query": function () {
						return {
							query:"erpnext.accounts.doctype.payment_order.payment_order.get_supplier_query",
							filters: {'parent': frm.doc.name}
						}
					}, "reqd": 1
				},

				{"fieldtype": "Link", "label": __("Mode of Payment"), "fieldname": "mode_of_payment", "options":"Mode of Payment",
					"get_query": function () {
						return {
							query:"erpnext.accounts.doctype.payment_order.payment_order.get_mop_query",
							filters: {'parent': frm.doc.name}
						}
					}
				}
			]
		});

		dialog.set_primary_action(__("Submit"), function() {
			var args = dialog.get_values();
			if(!args) return;

			return frappe.call({
				method: "erpnext.accounts.doctype.payment_order.payment_order.make_payment_records",
				args: {
					"name": me.frm.doc.name,
					"supplier": args.supplier,
					"mode_of_payment": args.mode_of_payment
				},
				freeze: true,
				callback: function(r) {
					dialog.hide();
					frm.refresh();
				}
			})
		})

		dialog.show();
	},
});<commit_msg>style: formatting changes<commit_after>// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt

frappe.ui.form.on('Payment Order', {
	setup: function(frm) {
		frm.set_query("company_bank_account", function() {
			return {
				filters: {
					"is_company_account":1
				}
			}
		});
	},
	refresh: function(frm) {
		if (frm.doc.docstatus == 0) {
			frm.add_custom_button(__('Payment Request'), function() {
				frm.trigger("get_from_payment_request");
			}, __("Get from"));

			frm.add_custom_button(__('Payment Entry'), function() {
				frm.trigger("get_from_payment_entry");
			}, __("Get from"));

			frm.trigger('remove_button');
		}

		// payment Entry
		if (frm.doc.docstatus===1 && frm.doc.payment_order_type==='Payment Request') {
			frm.add_custom_button(__('Create Payment Entries'), function() {
				frm.trigger("make_payment_records");
			});
		}
	},

	remove_row_if_empty: function(frm) {
		// remove if first row is empty
		if (frm.doc.references.length > 0 && !frm.doc.references[0].reference_name) {
			frm.doc.references = [];
		}
	},

	remove_button: function(frm) {
		// remove custom button of order type that is not imported

		let label = ["Payment Request", "Payment Entry"];

		if (frm.doc.references.length > 0 && frm.doc.payment_order_type) {
			label = label.reduce(x => {
				x!= frm.doc.payment_order_type;
				return x;
			});
			frm.remove_custom_button(label, "Get from");
		}
	},

	get_from_payment_entry: function(frm) {
		frm.trigger("remove_row_if_empty");
		erpnext.utils.map_current_doc({
			method: "erpnext.accounts.doctype.payment_entry.payment_entry.make_payment_order",
			source_doctype: "Payment Entry",
			target: frm,
			date_field: "posting_date",
			setters: {
				party: frm.doc.supplier || ""
			},
			get_query_filters: {
				bank: frm.doc.bank,
				docstatus: 1,
				bank_account: frm.doc.company_bank_account,
				paid_from: frm.doc.account,
				status: ["=", "Initiated"],
			}
		});
	},

	get_from_payment_request: function(frm) {
		frm.trigger("remove_row_if_empty");
		erpnext.utils.map_current_doc({
			method: "erpnext.accounts.doctype.payment_request.payment_request.make_payment_order",
			source_doctype: "Payment Request",
			target: frm,
			setters: {
				party: frm.doc.supplier || ""
			},
			get_query_filters: {
				bank: frm.doc.bank,
				docstatus: 1,
				status: ["=", "Initiated"],
			}
		});
	},

	make_payment_records: function(frm){
		var dialog = new frappe.ui.Dialog({
			title: __("For Supplier"),
			fields: [
				{"fieldtype": "Link", "label": __("Supplier"), "fieldname": "supplier", "options":"Supplier",
					"get_query": function () {
						return {
							query:"erpnext.accounts.doctype.payment_order.payment_order.get_supplier_query",
							filters: {'parent': frm.doc.name}
						}
					}, "reqd": 1
				},

				{"fieldtype": "Link", "label": __("Mode of Payment"), "fieldname": "mode_of_payment", "options":"Mode of Payment",
					"get_query": function () {
						return {
							query:"erpnext.accounts.doctype.payment_order.payment_order.get_mop_query",
							filters: {'parent': frm.doc.name}
						}
					}
				}
			]
		});

		dialog.set_primary_action(__("Submit"), function() {
			var args = dialog.get_values();
			if(!args) return;

			return frappe.call({
				method: "erpnext.accounts.doctype.payment_order.payment_order.make_payment_records",
				args: {
					"name": me.frm.doc.name,
					"supplier": args.supplier,
					"mode_of_payment": args.mode_of_payment
				},
				freeze: true,
				callback: function(r) {
					dialog.hide();
					frm.refresh();
				}
			})
		})

		dialog.show();
	},
});<|endoftext|>


<commit_before>import { platform, isArrayEqual, getKeyForPath } from '../util'

const DEBUG = false

export default class SurfaceManager {
  constructor (editorState) {
    this.editorState = editorState
    this.surfaces = new Map()

    editorState.addObserver(['selection', 'document'], this._onSelectionOrDocumentChange, this, { stage: 'pre-position' })
    // editorState.addObserver(['selection', 'document'], this._scrollSelectionIntoView, this, { stage: 'finalize' })
  }

  dispose () {
    this.editorState.off(this)
  }

  getSurface (name) {
    if (name) {
      return this.surfaces.get(name)
    }
  }

  getFocusedSurface () {
    console.error("DEPRECATED: use 'context.editorState.focusedSurface instead")
    return this.editorState.focusedSurface
  }

  registerSurface (surface) {
    const id = surface.getId()
    if (DEBUG) console.log(`Registering surface ${id}.`, surface.__id__)
    if (this.surfaces.has(id)) {
      throw new Error(`A surface with id ${id} has already been registered.`)
    }
    this.surfaces.set(id, surface)
  }

  unregisterSurface (surface) {
    const id = surface.getId()
    if (DEBUG) console.log(`Unregistering surface ${id}.`, surface.__id__)
    const registeredSurface = this.surfaces.get(id)
    if (registeredSurface === surface) {
      this.surfaces.delete(id)
    }
  }

  // TODO: would be good to have an index of surfaces by path
  _getSurfaceForProperty (path) {
    // first try the canonical one
    const canonicalId = getKeyForPath(path)
    if (this.surfaces.has(canonicalId)) {
      return this.surfaces.get(canonicalId)
    }
    for (const surface of this.surfaces.values()) {
      let surfacePath = null
      if (surface._isContainerEditor) {
        surfacePath = surface.getContainerPath()
      } else if (surface.getPath) {
        surfacePath = surface.getPath()
      }
      if (surfacePath && isArrayEqual(path, surfacePath)) {
        return surface
      }
    }
  }

  _onSelectionOrDocumentChange () {
    // console.log('SurfaceManager._onSelectionChange()')

    // Reducing state.focusedSurface (only if selection has changed)
    if (this.editorState.isDirty('selection')) {
      const selection = this.editorState.selection
      if (!selection || selection.isNull()) {
        // blur the focused surface to make sure that it does not remain focused
        // e.g. if DOM selection is not set for some reasons.
        // HACK: not all surfaces implement _blur()
        const focusedSurface = this.editorState.focusedSurface
        if (focusedSurface && focusedSurface._blur) {
          focusedSurface._blur()
        }
      }
      // update state.focusedSurface
      this._reduceFocusedSurface(selection)
      // HACK: removing DOM selection *and* blurring when having a CustomSelection
      // otherwise we will receive events on the wrong surface
      // instead of bubbling up to GlobalEventManager
      if (selection && selection.isCustomSelection() && platform.inBrowser) {
        window.getSelection().removeAllRanges()
        window.document.activeElement.blur()
      }
    }

    // TODO: this still needs to be improved. The DOM selection can be affected by other updates than document changes
    this._recoverDOMSelection()
  }

  _reduceFocusedSurface (sel) {
    const editorState = this.editorState
    let surface = null
    if (sel && sel.surfaceId) {
      surface = this.surfaces.get(sel.surfaceId)
    }
    editorState.focusedSurface = surface
  }

  /*
    At the end of the update flow, make sure the surface is focused
    and displays the right DOM selection
  */
  _recoverDOMSelection () {
    // console.log('SurfaceManager._recoverDOMSelection()')
    const editorState = this.editorState
    // do not rerender the selection if the editorSession has
    // been blurred, e.g., while some component, such as Find-And-Replace
    // dialog has the focus
    if (editorState.isBlurred) return
    const focusedSurface = editorState.focusedSurface
    // console.log('focusedSurface', focusedSurface)
    if (focusedSurface && !focusedSurface.isDisabled()) {
      // console.log('Rendering selection on surface', focusedSurface.getId(), this.editorState.selection.toString())
      focusedSurface._focus()
      focusedSurface.rerenderDOMSelection()
    } else {
      // NOTE: Tried to add an integrity check here
      // for valid sel.surfaceId
      // However this is problematic, when an editor
      // is run headless, i.e. when there are no surfaces rendered
      // On the long run we should separate these to modes
      // more explicitly. For now, any code using surfaces need
      // to be aware of the fact, that this might be not availabls
      // while in the model it is referenced.
    }
  }

  _scrollSelectionIntoView () {
    const editorState = this.editorState
    const focusedSurface = editorState.focusedSurface
    if (focusedSurface && !focusedSurface.isDisabled()) {
      focusedSurface.send('scrollSelectionIntoView', editorState.selection)
    }
  }
}
<commit_msg>Fix in SurfaceManager.<commit_after>import { platform, isArrayEqual, getKeyForPath } from '../util'

const DEBUG = false

export default class SurfaceManager {
  constructor (editorState) {
    this.editorState = editorState
    this.surfaces = new Map()

    editorState.addObserver(['selection', 'document'], this._onSelectionOrDocumentChange, this, { stage: 'pre-position' })
    // editorState.addObserver(['selection', 'document'], this._scrollSelectionIntoView, this, { stage: 'finalize' })
  }

  dispose () {
    this.editorState.off(this)
  }

  getSurface (name) {
    if (name) {
      return this.surfaces.get(name)
    }
  }

  getFocusedSurface () {
    console.error("DEPRECATED: use 'context.editorState.focusedSurface instead")
    return this.editorState.focusedSurface
  }

  registerSurface (surface) {
    const id = surface.getId()
    if (DEBUG) console.log(`Registering surface ${id}.`, surface.__id__)
    if (this.surfaces.has(id)) {
      throw new Error(`A surface with id ${id} has already been registered.`)
    }
    this.surfaces.set(id, surface)
  }

  unregisterSurface (surface) {
    const id = surface.getId()
    if (DEBUG) console.log(`Unregistering surface ${id}.`, surface.__id__)
    const registeredSurface = this.surfaces.get(id)
    if (registeredSurface === surface) {
      this.surfaces.delete(id)
    }
  }

  // TODO: would be good to have an index of surfaces by path
  _getSurfaceForProperty (path) {
    // first try the canonical one
    const canonicalId = getKeyForPath(path)
    if (this.surfaces.has(canonicalId)) {
      return this.surfaces.get(canonicalId)
    }
    for (const surface of this.surfaces.values()) {
      let surfacePath = null
      if (surface._isContainerEditor) {
        surfacePath = surface.getContainerPath()
      } else if (surface.getPath) {
        surfacePath = surface.getPath()
      }
      if (surfacePath && isArrayEqual(path, surfacePath)) {
        return surface
      }
    }
  }

  _onSelectionOrDocumentChange () {
    // console.log('SurfaceManager._onSelectionChange()')

    // Reducing state.focusedSurface (only if selection has changed)
    if (this.editorState.isDirty('selection')) {
      const selection = this.editorState.selection
      if (!selection || selection.isNull()) {
        // blur the focused surface to make sure that it does not remain focused
        // e.g. if DOM selection is not set for some reasons.
        // HACK: not all surfaces implement _blur()
        const focusedSurface = this.editorState.focusedSurface
        if (focusedSurface && focusedSurface._blur) {
          focusedSurface._blur()
        }
      }
      // update state.focusedSurface
      this._reduceFocusedSurface(selection)
      // HACK: removing DOM selection *and* blurring when having a CustomSelection
      // otherwise we will receive events on the wrong surface
      // instead of bubbling up to GlobalEventManager
      if (selection && selection.isCustomSelection() && platform.inBrowser) {
        window.getSelection().removeAllRanges()
        const activeElement = window.document.activeElement
        if (activeElement) {
          activeElement.blur()
        }
      }
    }

    // TODO: this still needs to be improved. The DOM selection can be affected by other updates than document changes
    this._recoverDOMSelection()
  }

  _reduceFocusedSurface (sel) {
    const editorState = this.editorState
    let surface = null
    if (sel && sel.surfaceId) {
      surface = this.surfaces.get(sel.surfaceId)
    }
    editorState.focusedSurface = surface
  }

  /*
    At the end of the update flow, make sure the surface is focused
    and displays the right DOM selection
  */
  _recoverDOMSelection () {
    // console.log('SurfaceManager._recoverDOMSelection()')
    const editorState = this.editorState
    // do not rerender the selection if the editorSession has
    // been blurred, e.g., while some component, such as Find-And-Replace
    // dialog has the focus
    if (editorState.isBlurred) return
    const focusedSurface = editorState.focusedSurface
    // console.log('focusedSurface', focusedSurface)
    if (focusedSurface && !focusedSurface.isDisabled()) {
      // console.log('Rendering selection on surface', focusedSurface.getId(), this.editorState.selection.toString())
      focusedSurface._focus()
      focusedSurface.rerenderDOMSelection()
    } else {
      // NOTE: Tried to add an integrity check here
      // for valid sel.surfaceId
      // However this is problematic, when an editor
      // is run headless, i.e. when there are no surfaces rendered
      // On the long run we should separate these to modes
      // more explicitly. For now, any code using surfaces need
      // to be aware of the fact, that this might be not availabls
      // while in the model it is referenced.
    }
  }

  _scrollSelectionIntoView () {
    const editorState = this.editorState
    const focusedSurface = editorState.focusedSurface
    if (focusedSurface && !focusedSurface.isDisabled()) {
      focusedSurface.send('scrollSelectionIntoView', editorState.selection)
    }
  }
}
<|endoftext|>


<commit_before>import {dom} from './../../../../../utilities/datatables.utilities';

function controller(DTOptionsBuilder,
                         DTColumnBuilder,
                         LinelistService,
                         $scope,
                         $compile) {
  this.dtOptions = DTOptionsBuilder
    .fromFnPromise(() => {
      return LinelistService.getMetadata();
    })
    .withDOM(dom)
    .withScroller()
    .withOption('scrollX', true)
    .withOption('deferRender', true)
    .withOption('scrollY', '50vh')
    .withOption('scrollCollapse', true)
    .withColReorder()
    .withColReorderCallback(() => {
      this.parent.columnReorder(this.fnOrder());
    })
    .withOption('drawCallback', () => {
      // This adds the tools to handle meta data header hiding, template selection and saving.
      // Datatables will add this after the table is created to we need the $compile so that
      // angularjs can grab hold of it.
      const div = document.querySelector('.toolbar');
      // Make sure this only gets added once
      if (div.getElementsByTagName('metadata-component').length === 0) {
        div.innerHTML = `
<metadata-component
    headers="$ctrl.headers"
    on-toggle-field="$ctrl.toggleColumn($event)">
</metadata-component>
`;
        $compile(div)($scope);
      }
    });

  this.dtColumns = this.headers.map(header => {
    return DTColumnBuilder
      .newColumn(header)
      .withTitle(header)
      .renderWith(data => {
        // This is where any custom rendering logic should go.
        // example formatting date columns.
        return data.value;
      });
  });

  this.toggleColumn = $event => {
    const field = $event.field;
    this.dtColumns[field.index].visible = field.selected;
  };
}

controller.$inject = [
  'DTOptionsBuilder',
  'DTColumnBuilder',
  'LinelistService',
  '$scope',
  '$compile'
];

export const TableComponent = {
  template: `

`,
  require: {
    parent: '^^linelist'
  },
  bindings: {
    headers: '<'
  },
  controller
};
<commit_msg>The table now creates the fields map to match the headers, as well as handling saving the template.<commit_after>import {dom} from './../../../../../utilities/datatables.utilities';

function controller(DTOptionsBuilder,
                         DTColumnBuilder,
                         LinelistService,
                         $scope,
                         $compile) {
  // This will be used by the child component to control which columns are visible
  this.fields = this.headers
    .map((header, index) => {
      return ({text: header, index, selected: true});
    });

  this.dtOptions = DTOptionsBuilder
    .fromFnPromise(() => {
      return LinelistService.getMetadata();
    })
    .withDOM(dom)
    .withScroller()
    .withOption('scrollX', true)
    .withOption('deferRender', true)
    .withOption('scrollY', '50vh')
    .withOption('scrollCollapse', true)
    .withColReorder()
    .withColReorderCallback(() => {
      this.parent.columnReorder(this.fnOrder());
    })
    .withOption('drawCallback', () => {
      // This adds the tools to handle meta data header hiding, template selection and saving.
      // Datatables will add this after the table is created to we need the $compile so that
      // angularjs can grab hold of it.
      const div = document.querySelector('.toolbar');
      // Make sure this only gets added once
      if (div.getElementsByTagName('metadata-component').length === 0) {
        div.innerHTML = `
<metadata-component
    fields="$ctrl.fields"
    on-toggle-field="$ctrl.toggleColumn($event)"
    on-save-template="$ctrl.saveTemplate($event)">
</metadata-component>
`;
        $compile(div)($scope);
      }
    });

  this.dtColumns = this.headers.map(header => {
    return DTColumnBuilder
      .newColumn(header)
      .withTitle(header)
      .renderWith(data => {
        // This is where any custom rendering logic should go.
        // example formatting date columns.
        return data.value;
      });
  });

  this.toggleColumn = $event => {
    const field = $event.field;
    this.dtColumns[field.index].visible = field.selected;
  };

  this.saveTemplate = $event => {
    const fields = $event.fields.map(field => field.text);
    console.log(fields);
    LinelistService
      .saveTemplate({url: this.savetemplateurl, fields, name: 'freds'})
      .then(result => console.log(result));
  };
}

controller.$inject = [
  'DTOptionsBuilder',
  'DTColumnBuilder',
  'LinelistService',
  '$scope',
  '$compile'
];

export const TableComponent = {
  template: `

`,
  require: {
    parent: '^^linelist'
  },
  bindings: {
    headers: '<',
    savetemplateurl: '@'
  },
  controller
};
<|endoftext|>


<commit_before>Menubar.Add = function ( editor ) {

	var container = new UI.Panel();
	container.setClass( 'menu' );

	var title = new UI.Panel();
	title.setTextContent( 'Add' );
	title.setMargin( '0px' );
	title.setPadding( '8px' );
	container.add( title );

	//

	var options = new UI.Panel();
	options.setClass( 'options' );
	container.add( options );

	var meshCount = 0;
	var lightCount = 0;

	// add plane

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Plane' );
	option.onClick( function () {

		var width = 200;
		var height = 200;

		var widthSegments = 1;
		var heightSegments = 1;

		var geometry = new THREE.PlaneGeometry( width, height, widthSegments, heightSegments );
		var material = new THREE.MeshPhongMaterial();
		var mesh = new THREE.Mesh( geometry, material );
		mesh.name = 'Plane ' + ( ++ meshCount );

		mesh.rotation.x = - Math.PI/2;

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add cube

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Cube' );
	option.onClick( function () {

		var width = 100;
		var height = 100;
		var depth = 100;

		var widthSegments = 1;
		var heightSegments = 1;
		var depthSegments = 1;

		var geometry = new THREE.CubeGeometry( width, height, depth, widthSegments, heightSegments, depthSegments );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Cube ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add circle

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Circle' );
	option.onClick( function () {

		var radius = 20;
		var segments = 8;

		var geometry = new THREE.CircleGeometry( radius, segments );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Circle ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add cylinder

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Cylinder' );
	option.onClick( function () {

		var radiusTop = 20;
		var radiusBottom = 20;
		var height = 100;
		var radiusSegments = 8;
		var heightSegments = 1;
		var openEnded = false;

		var geometry = new THREE.CylinderGeometry( radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Cylinder ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add sphere

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Sphere' );
	option.onClick( function () {

		var radius = 75;
		var widthSegments = 32;
		var heightSegments = 16;

		var geometry = new THREE.SphereGeometry( radius, widthSegments, heightSegments );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Sphere ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add icosahedron

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Icosahedron' );
	option.onClick( function () {

		var radius = 75;
		var detail = 2;

		var geometry = new THREE.IcosahedronGeometry ( radius, detail );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Icosahedron ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add torus

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Torus' );
	option.onClick( function () {

		var radius = 100;
		var tube = 40;
		var radialSegments = 8;
		var tubularSegments = 6;
		var arc = Math.PI * 2;

		var geometry = new THREE.TorusGeometry( radius, tube, radialSegments, tubularSegments, arc );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Torus ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add torus knot

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'TorusKnot' );
	option.onClick( function () {

		var radius = 100;
		var tube = 40;
		var radialSegments = 64;
		var tubularSegments = 8;
		var p = 2;
		var q = 3;
		var heightScale = 1;

		var geometry = new THREE.TorusKnotGeometry( radius, tube, radialSegments, tubularSegments, p, q, heightScale );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'TorusKnot ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// divider

	options.add( new UI.HorizontalRule() );

	// add sprite

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Sprite' );
	option.onClick( function () {

		var sprite = new THREE.Sprite( new THREE.SpriteMaterial() );
		sprite.name = 'Sprite ' + ( ++ meshCount );

		editor.addObject( sprite );
		editor.select( sprite );

	} );
	options.add( option );

	// divider

	options.add( new UI.HorizontalRule() );

	// add point light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Point light' );
	option.onClick( function () {

		var color = 0xffffff;
		var intensity = 1;
		var distance = 0;

		var light = new THREE.PointLight( color, intensity, distance );
		light.name = 'PointLight ' + ( ++ lightCount );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	// add spot light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Spot light' );
	option.onClick( function () {

		var color = 0xffffff;
		var intensity = 1;
		var distance = 0;
		var angle = Math.PI * 0.1;
		var exponent = 10;

		var light = new THREE.SpotLight( color, intensity, distance, angle, exponent );
		light.name = 'SpotLight ' + ( ++ lightCount );
		light.target.name = 'SpotLight ' + ( lightCount ) + ' Target';

		light.position.set( 0, 1, 0 ).multiplyScalar( 200 );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	// add directional light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Directional light' );
	option.onClick( function () {

		var color = 0xffffff;
		var intensity = 1;

		var light = new THREE.DirectionalLight( color, intensity );
		light.name = 'DirectionalLight ' + ( ++ lightCount );
		light.target.name = 'DirectionalLight ' + ( lightCount ) + ' Target';

		light.position.set( 1, 1, 1 ).multiplyScalar( 200 );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	// add hemisphere light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Hemisphere light' );
	option.onClick( function () {

		var skyColor = 0x00aaff;
		var groundColor = 0xffaa00;
		var intensity = 1;

		var light = new THREE.HemisphereLight( skyColor, groundColor, intensity );
		light.name = 'HemisphereLight ' + ( ++ lightCount );

		light.position.set( 1, 1, 1 ).multiplyScalar( 200 );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	// add ambient light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Ambient light' );
	option.onClick( function () {

		var color = 0x222222;

		var light = new THREE.AmbientLight( color );
		light.name = 'AmbientLight ' + ( ++ lightCount );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	//

	return container;

}
<commit_msg>Editor: Menubar.Add/Object3D<commit_after>Menubar.Add = function ( editor ) {

	var container = new UI.Panel();
	container.setClass( 'menu' );

	var title = new UI.Panel();
	title.setTextContent( 'Add' );
	title.setMargin( '0px' );
	title.setPadding( '8px' );
	container.add( title );

	//

	var options = new UI.Panel();
	options.setClass( 'options' );
	container.add( options );

	var meshCount = 0;
	var lightCount = 0;

	// add object

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Object3D' );
	option.onClick( function () {

		var mesh = new THREE.Object3D();
		mesh.name = 'Object3D ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// divider

	options.add( new UI.HorizontalRule() );

	// add plane

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Plane' );
	option.onClick( function () {

		var width = 200;
		var height = 200;

		var widthSegments = 1;
		var heightSegments = 1;

		var geometry = new THREE.PlaneGeometry( width, height, widthSegments, heightSegments );
		var material = new THREE.MeshPhongMaterial();
		var mesh = new THREE.Mesh( geometry, material );
		mesh.name = 'Plane ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add cube

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Cube' );
	option.onClick( function () {

		var width = 100;
		var height = 100;
		var depth = 100;

		var widthSegments = 1;
		var heightSegments = 1;
		var depthSegments = 1;

		var geometry = new THREE.CubeGeometry( width, height, depth, widthSegments, heightSegments, depthSegments );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Cube ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add circle

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Circle' );
	option.onClick( function () {

		var radius = 20;
		var segments = 8;

		var geometry = new THREE.CircleGeometry( radius, segments );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Circle ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add cylinder

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Cylinder' );
	option.onClick( function () {

		var radiusTop = 20;
		var radiusBottom = 20;
		var height = 100;
		var radiusSegments = 8;
		var heightSegments = 1;
		var openEnded = false;

		var geometry = new THREE.CylinderGeometry( radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Cylinder ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add sphere

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Sphere' );
	option.onClick( function () {

		var radius = 75;
		var widthSegments = 32;
		var heightSegments = 16;

		var geometry = new THREE.SphereGeometry( radius, widthSegments, heightSegments );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Sphere ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add icosahedron

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Icosahedron' );
	option.onClick( function () {

		var radius = 75;
		var detail = 2;

		var geometry = new THREE.IcosahedronGeometry ( radius, detail );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Icosahedron ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add torus

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Torus' );
	option.onClick( function () {

		var radius = 100;
		var tube = 40;
		var radialSegments = 8;
		var tubularSegments = 6;
		var arc = Math.PI * 2;

		var geometry = new THREE.TorusGeometry( radius, tube, radialSegments, tubularSegments, arc );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'Torus ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// add torus knot

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'TorusKnot' );
	option.onClick( function () {

		var radius = 100;
		var tube = 40;
		var radialSegments = 64;
		var tubularSegments = 8;
		var p = 2;
		var q = 3;
		var heightScale = 1;

		var geometry = new THREE.TorusKnotGeometry( radius, tube, radialSegments, tubularSegments, p, q, heightScale );
		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
		mesh.name = 'TorusKnot ' + ( ++ meshCount );

		editor.addObject( mesh );
		editor.select( mesh );

	} );
	options.add( option );

	// divider

	options.add( new UI.HorizontalRule() );

	// add sprite

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Sprite' );
	option.onClick( function () {

		var sprite = new THREE.Sprite( new THREE.SpriteMaterial() );
		sprite.name = 'Sprite ' + ( ++ meshCount );

		editor.addObject( sprite );
		editor.select( sprite );

	} );
	options.add( option );

	// divider

	options.add( new UI.HorizontalRule() );

	// add point light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Point light' );
	option.onClick( function () {

		var color = 0xffffff;
		var intensity = 1;
		var distance = 0;

		var light = new THREE.PointLight( color, intensity, distance );
		light.name = 'PointLight ' + ( ++ lightCount );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	// add spot light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Spot light' );
	option.onClick( function () {

		var color = 0xffffff;
		var intensity = 1;
		var distance = 0;
		var angle = Math.PI * 0.1;
		var exponent = 10;

		var light = new THREE.SpotLight( color, intensity, distance, angle, exponent );
		light.name = 'SpotLight ' + ( ++ lightCount );
		light.target.name = 'SpotLight ' + ( lightCount ) + ' Target';

		light.position.set( 0, 1, 0 ).multiplyScalar( 200 );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	// add directional light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Directional light' );
	option.onClick( function () {

		var color = 0xffffff;
		var intensity = 1;

		var light = new THREE.DirectionalLight( color, intensity );
		light.name = 'DirectionalLight ' + ( ++ lightCount );
		light.target.name = 'DirectionalLight ' + ( lightCount ) + ' Target';

		light.position.set( 1, 1, 1 ).multiplyScalar( 200 );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	// add hemisphere light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Hemisphere light' );
	option.onClick( function () {

		var skyColor = 0x00aaff;
		var groundColor = 0xffaa00;
		var intensity = 1;

		var light = new THREE.HemisphereLight( skyColor, groundColor, intensity );
		light.name = 'HemisphereLight ' + ( ++ lightCount );

		light.position.set( 1, 1, 1 ).multiplyScalar( 200 );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	// add ambient light

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Ambient light' );
	option.onClick( function () {

		var color = 0x222222;

		var light = new THREE.AmbientLight( color );
		light.name = 'AmbientLight ' + ( ++ lightCount );

		editor.addObject( light );
		editor.select( light );

	} );
	options.add( option );

	//

	return container;

}
<|endoftext|>


<commit_before>var map;
var hilites;
var pu_layer;
var markers;
var selectFeatureControl;
var keyboardControl;
var selectGeographyControl;

function getCfFields() {
    // Find the set of conservation features represented in ALL of the selected planning units.
    if (pu_layer.selectedFeatures.length >= 1) {
        var tmpList = pu_layer.selectedFeatures[0].attributes.cf_fields;
        $.each( pu_layer.selectedFeatures, function(idx, feat) {
            fieldList = feat.attributes.cf_fields;
            tmpList = tmpList.intersect(fieldList);
        });
        return tmpList;
    } else {
        return [];
    }
}

function getCostFields() {
    // Find the set of costs represented in ALL of the selected planning units.
    if (pu_layer.selectedFeatures.length >= 1) {
        var tmpList = pu_layer.selectedFeatures[0].attributes.cost_fields;
        $.each( pu_layer.selectedFeatures, function(idx, feat) {
            fieldList = feat.attributes.cost_fields;
            tmpList = tmpList.intersect(fieldList);
        });
        return tmpList;
    } else {
        return [];
    }
}

function init_map() {
    map = new OpenLayers.Map({
        div: "map",
        projection: "EPSG:900913",
        displayProjection: "EPSG:4326",
        controls: [
            new OpenLayers.Control.Navigation(),
            new OpenLayers.Control.Zoom(),
            new OpenLayers.Control.LayerSwitcher({
                'div': OpenLayers.Util.getElement('layerswitcher')
            })
        ],
        minZoomLevel: 3,
        restrictedExtent: new OpenLayers.Bounds(-19140016, 2626698, -10262137, 11307047),
        numZoomLevels: 6
    });

    markers = new OpenLayers.Layer.Markers( "Markers", {displayInLayerSwitcher: false});

    var esri_physical = new OpenLayers.Layer.XYZ( "Mapbox Terrain",
        "http://d.tiles.mapbox.com/v3/examples.map-4l7djmvo/${z}/${x}/${y}.png",
        {sphericalMercator: true}
    );

    var esri_shade = new OpenLayers.Layer.XYZ( "ESRI Shaded Relief Map",
        "http://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/${z}/${y}/${x}",
        {sphericalMercator: true}
    );

    var blue_marble = new OpenLayers.Layer.XYZ( "Blue Marble Satellite",
        //"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/${z}/${y}/${x}",
        "http://c.tiles.mapbox.com/v3/mapbox.blue-marble-topo-bathy-jul/${z}/${x}/${y}.png",
        {sphericalMercator: true, opacity: 0.75}
    );

    var pu_utfgrid = new OpenLayers.Layer.UTFGrid({
         url: "/tiles/utfgrid/${z}/${x}/${y}.json", //dynamic, use once mapnik is figured out
         //url: "/media/tiles/planning_units/${z}/${x}/${y}.json",
         utfgridResolution: 4,
         sphericalMercator: true,
         displayInLayerSwitcher: false
        }
    );

    var pu_tiles = new OpenLayers.Layer.OSM( "Planning Units",
        "/tiles/planning_units/${z}/${x}/${y}.png",
        {
         sphericalMercator: true,
         isBaseLayer: false
        }
    );

    var myStyles = new OpenLayers.StyleMap({
        "default": new OpenLayers.Style({
            display: "none",  /* needs to be set temporarily to true for selection to work */
            strokeWidth: 0,
            fillOpacity: 0
        }),
        "select": new OpenLayers.Style({
            display: true,
            strokeWidth: 0,
            fillColor: "#ffff00",
            fillOpacity: 0.5,
            graphicZIndex: 2
        }),
        "select_geography": new OpenLayers.Style({
            display: true,
            fillColor: "#777777",
            fillOpacity: 0.5
        })
    });

    // allow testing of specific renderers via "?renderer=Canvas", etc
    var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
    renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;
    pu_layer = new OpenLayers.Layer.Vector("Planning Unit Highlight", {
        styleMap: myStyles,
        renderers: renderer,
        displayInLayerSwitcher: false
    });

    var url = "/seak/planning_units.geojson";
    var jqxhr = $.ajax({
        url: url,
        cache: true,
        dataType: 'json',
        success: function(data) {
            var gformat = new OpenLayers.Format.GeoJSON();
            try {
                var feats = gformat.read(data);
                pu_layer.addFeatures(feats);
            } catch(err) {
                console.log(err.message);
                app.scenarios.viewModel.planningUnitsLoadError(true);
            }
        }
    })
    .error(function() { app.scenarios.viewModel.planningUnitsLoadError(true); })
    .complete(function() { app.scenarios.viewModel.planningUnitsLoadComplete(true); });

    map.isValidZoomLevel = function(zoomLevel) {
        // Why is this even necessary OpenLayers?.. grrr
        // http://stackoverflow.com/questions/4240610/min-max-zoom-level-in-openlayers
        return ( (zoomLevel !== null) &&
            (zoomLevel >= this.minZoomLevel) &&
            (zoomLevel < this.minZoomLevel + this.numZoomLevels));
    };

    selectFeatureControl = new OpenLayers.Control.SelectFeature(
        pu_layer,
        {
            multiple: true
        }
    );

    var geographySelectCallback = function(){
        $('#geographySelectionCount').html(pu_layer.selectedFeatures.length);
    };

    selectGeographyControl = new OpenLayers.Control.SelectFeature(
        pu_layer,
        {
            clickout: true,
            toggle: false,
            multiple: true,
            hover: false,
            toggleKey: "ctrlKey", // ctrl key removes from selection
            multipleKey: "shiftKey", // shift key adds to selection
            renderIntent: "select_geography",
            box: true,
            onSelect: geographySelectCallback,
            onUnselect: geographySelectCallback
        }
    );

    keyboardControl = new OpenLayers.Control.KeyboardDefaults();

    selectFeatureControl.deactivate();
    keyboardControl.deactivate();
    selectGeographyControl.deactivate();
    map.addControls([selectFeatureControl, selectGeographyControl, keyboardControl]);

    map.addLayers([esri_shade, blue_marble, esri_physical, pu_layer, pu_tiles, pu_utfgrid, markers]);
    map.getLayersByName("Markers")[0].setZIndex(9999);

    var lookup_url = "/seak/field_lookup.json";
    var fieldLookup;
    $('
<input type="checkbox" id="layer-select-toggle"></input>
')
        .appendTo('#layerswitcher')
        .attr("id", "layer-select-div");
    var sel = $('<select>').appendTo('#layer-select-div').attr("id","layer-select");
    sel.append($("<option>").attr('value','').text('.. Select attribute to map ..'));
    var xhr = $.ajax({
        url: lookup_url,
        cache: true,
        dataType: 'json',
        success: function(data) {
            fieldLookup = data;
            $.each(data, function(dbf_fieldname, realname) {
                map.addLayer(
                    new OpenLayers.Layer.OSM( realname,
                        "/tiles/" + dbf_fieldname + "/${z}/${x}/${y}.png",
                        { visibility: false,
                          sphericalMercator: true,
                          displayInLayerSwitcher: false,
                          isBaseLayer: false }
                    )
                );
                sel.append($("<option>").attr('value',realname).text(realname));
            });
            // sort 'em
            var my_options = $("select#layer-select option");
            my_options.sort(function(a,b) {
                if (a.text > b.text) return 1;
                else if (a.text < b.text) return -1;
                else return 0;
            });
            sel.empty().append( my_options );
        }
    })
    .error( function() {
        fieldLookup = null;
    });

    // when the dropdown changes, tell openlayers
    var switchLayer = function() {
        var lyrname;
        $.each($("select#layer-select option"), function(k,v) {
            lyrname = $(v).val();
            if (lyrname !== '')
                map.getLayersByName(lyrname)[0].setVisibility(false);
        });
        lyrname = $("select#layer-select option:selected").val();
        if (lyrname !== '' && $('#layer-select-toggle').prop('checked')) {
            map.getLayersByName(lyrname)[0].setVisibility(true);
            map.getLayersByName('Planning Unit Highlight')[0].setVisibility(false);
            $('.map-legend-group').hide();
            $('#map-legend-attr').show();
        } else {
            map.getLayersByName('Planning Unit Highlight')[0].setVisibility(true);
            $('.map-legend-group').hide();
            $('#map-legend-scenario').show();
        }
    }

    $('#layer-select-toggle').bind('change', switchLayer);
    sel.bind('change', switchLayer);

    var sortByKeys = function(obj) {
        var tmpObj = {};
        var fullName;
        var keys = [];
        var i, k, len;
        var outObj = {};

        for(var key in obj) {
            fullName = fieldLookup[key];

            if (!fullName)
                fullName = key;

            if (fullName !== 'NAME')
                tmpObj[fullName] = obj[key];
        }

        for(var key in tmpObj) {
            if(tmpObj.hasOwnProperty(key)) {
                keys.push(key);
            }
        }

        keys.sort();
        len = keys.length;
        for (i=0; i < len; i++) {
            k = keys[i];
            outObj[k] = tmpObj[k];
        }
        return outObj;
    };

    var utfgridCallback = function(infoLookup) {
        var msg = "";
        var puname = "Watershed Info";
        $("#info").hide();
        var fnc = function(idx, val) {
            if (val >= 0) { // Assume negative is null
                try {
                    msg += "
"+ idx + "	" + val.toPrecision(6) + "
";
                } catch (err) {
                    msg += "
"+ idx + "	" + val + "
";
                }
            } else if(idx.toLowerCase() == "name") { // assume "name"
                puname = val;
            }
        };

        $.each(infoLookup, function(k, info) {
            if (info.data) {
                msg = "
";
                $.each(sortByKeys(info.data), fnc);
                msg += "
";
                $("#info").show();
            }
        });
        $("#info-title").html("
" + puname + "
");
        $("#info-content").html(msg);
    };

    var ctl = new OpenLayers.Control.UTFGrid({
        callback: utfgridCallback,
        handlerMode: "click"
    });

    map.addControl(ctl);

    map.setCenter(new OpenLayers.LonLat(-15400000, 6700000), 4);
}
<commit_msg>Get watershed name working again in utfgrid callbacks<commit_after>var map;
var hilites;
var pu_layer;
var markers;
var selectFeatureControl;
var keyboardControl;
var selectGeographyControl;

function getCfFields() {
    // Find the set of conservation features represented in ALL of the selected planning units.
    if (pu_layer.selectedFeatures.length >= 1) {
        var tmpList = pu_layer.selectedFeatures[0].attributes.cf_fields;
        $.each( pu_layer.selectedFeatures, function(idx, feat) {
            fieldList = feat.attributes.cf_fields;
            tmpList = tmpList.intersect(fieldList);
        });
        return tmpList;
    } else {
        return [];
    }
}

function getCostFields() {
    // Find the set of costs represented in ALL of the selected planning units.
    if (pu_layer.selectedFeatures.length >= 1) {
        var tmpList = pu_layer.selectedFeatures[0].attributes.cost_fields;
        $.each( pu_layer.selectedFeatures, function(idx, feat) {
            fieldList = feat.attributes.cost_fields;
            tmpList = tmpList.intersect(fieldList);
        });
        return tmpList;
    } else {
        return [];
    }
}

function init_map() {
    map = new OpenLayers.Map({
        div: "map",
        projection: "EPSG:900913",
        displayProjection: "EPSG:4326",
        controls: [
            new OpenLayers.Control.Navigation(),
            new OpenLayers.Control.Zoom(),
            new OpenLayers.Control.LayerSwitcher({
                'div': OpenLayers.Util.getElement('layerswitcher')
            })
        ],
        minZoomLevel: 3,
        restrictedExtent: new OpenLayers.Bounds(-19140016, 2626698, -10262137, 11307047),
        numZoomLevels: 6
    });

    markers = new OpenLayers.Layer.Markers( "Markers", {displayInLayerSwitcher: false});

    var esri_physical = new OpenLayers.Layer.XYZ( "Mapbox Terrain",
        "http://d.tiles.mapbox.com/v3/examples.map-4l7djmvo/${z}/${x}/${y}.png",
        {sphericalMercator: true}
    );

    var esri_shade = new OpenLayers.Layer.XYZ( "ESRI Shaded Relief Map",
        "http://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/${z}/${y}/${x}",
        {sphericalMercator: true}
    );

    var blue_marble = new OpenLayers.Layer.XYZ( "Blue Marble Satellite",
        //"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/${z}/${y}/${x}",
        "http://c.tiles.mapbox.com/v3/mapbox.blue-marble-topo-bathy-jul/${z}/${x}/${y}.png",
        {sphericalMercator: true, opacity: 0.75}
    );

    var pu_utfgrid = new OpenLayers.Layer.UTFGrid({
         url: "/tiles/utfgrid/${z}/${x}/${y}.json", //dynamic, use once mapnik is figured out
         //url: "/media/tiles/planning_units/${z}/${x}/${y}.json",
         utfgridResolution: 4,
         sphericalMercator: true,
         displayInLayerSwitcher: false
        }
    );

    var pu_tiles = new OpenLayers.Layer.OSM( "Planning Units",
        "/tiles/planning_units/${z}/${x}/${y}.png",
        {
         sphericalMercator: true,
         isBaseLayer: false
        }
    );

    var myStyles = new OpenLayers.StyleMap({
        "default": new OpenLayers.Style({
            display: "none",  /* needs to be set temporarily to true for selection to work */
            strokeWidth: 0,
            fillOpacity: 0
        }),
        "select": new OpenLayers.Style({
            display: true,
            strokeWidth: 0,
            fillColor: "#ffff00",
            fillOpacity: 0.5,
            graphicZIndex: 2
        }),
        "select_geography": new OpenLayers.Style({
            display: true,
            fillColor: "#777777",
            fillOpacity: 0.5
        })
    });

    // allow testing of specific renderers via "?renderer=Canvas", etc
    var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
    renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;
    pu_layer = new OpenLayers.Layer.Vector("Planning Unit Highlight", {
        styleMap: myStyles,
        renderers: renderer,
        displayInLayerSwitcher: false
    });

    var url = "/seak/planning_units.geojson";
    var jqxhr = $.ajax({
        url: url,
        cache: true,
        dataType: 'json',
        success: function(data) {
            var gformat = new OpenLayers.Format.GeoJSON();
            try {
                var feats = gformat.read(data);
                pu_layer.addFeatures(feats);
            } catch(err) {
                console.log(err.message);
                app.scenarios.viewModel.planningUnitsLoadError(true);
            }
        }
    })
    .error(function() { app.scenarios.viewModel.planningUnitsLoadError(true); })
    .complete(function() { app.scenarios.viewModel.planningUnitsLoadComplete(true); });

    map.isValidZoomLevel = function(zoomLevel) {
        // Why is this even necessary OpenLayers?.. grrr
        // http://stackoverflow.com/questions/4240610/min-max-zoom-level-in-openlayers
        return ( (zoomLevel !== null) &&
            (zoomLevel >= this.minZoomLevel) &&
            (zoomLevel < this.minZoomLevel + this.numZoomLevels));
    };

    selectFeatureControl = new OpenLayers.Control.SelectFeature(
        pu_layer,
        {
            multiple: true
        }
    );

    var geographySelectCallback = function(){
        $('#geographySelectionCount').html(pu_layer.selectedFeatures.length);
    };

    selectGeographyControl = new OpenLayers.Control.SelectFeature(
        pu_layer,
        {
            clickout: true,
            toggle: false,
            multiple: true,
            hover: false,
            toggleKey: "ctrlKey", // ctrl key removes from selection
            multipleKey: "shiftKey", // shift key adds to selection
            renderIntent: "select_geography",
            box: true,
            onSelect: geographySelectCallback,
            onUnselect: geographySelectCallback
        }
    );

    keyboardControl = new OpenLayers.Control.KeyboardDefaults();

    selectFeatureControl.deactivate();
    keyboardControl.deactivate();
    selectGeographyControl.deactivate();
    map.addControls([selectFeatureControl, selectGeographyControl, keyboardControl]);

    map.addLayers([esri_shade, blue_marble, esri_physical, pu_layer, pu_tiles, pu_utfgrid, markers]);
    map.getLayersByName("Markers")[0].setZIndex(9999);

    var lookup_url = "/seak/field_lookup.json";
    var fieldLookup;
    $('
<input type="checkbox" id="layer-select-toggle"></input>
')
        .appendTo('#layerswitcher')
        .attr("id", "layer-select-div");
    var sel = $('<select>').appendTo('#layer-select-div').attr("id","layer-select");
    sel.append($("<option>").attr('value','').text('.. Select attribute to map ..'));
    var xhr = $.ajax({
        url: lookup_url,
        cache: true,
        dataType: 'json',
        success: function(data) {
            fieldLookup = data;
            $.each(data, function(dbf_fieldname, realname) {
                map.addLayer(
                    new OpenLayers.Layer.OSM( realname,
                        "/tiles/" + dbf_fieldname + "/${z}/${x}/${y}.png",
                        { visibility: false,
                          sphericalMercator: true,
                          displayInLayerSwitcher: false,
                          isBaseLayer: false }
                    )
                );
                sel.append($("<option>").attr('value',realname).text(realname));
            });
            // sort 'em
            var my_options = $("select#layer-select option");
            my_options.sort(function(a,b) {
                if (a.text > b.text) return 1;
                else if (a.text < b.text) return -1;
                else return 0;
            });
            sel.empty().append( my_options );
        }
    })
    .error( function() {
        fieldLookup = null;
    });

    // when the dropdown changes, tell openlayers
    var switchLayer = function() {
        var lyrname;
        $.each($("select#layer-select option"), function(k,v) {
            lyrname = $(v).val();
            if (lyrname !== '')
                map.getLayersByName(lyrname)[0].setVisibility(false);
        });
        lyrname = $("select#layer-select option:selected").val();
        if (lyrname !== '' && $('#layer-select-toggle').prop('checked')) {
            map.getLayersByName(lyrname)[0].setVisibility(true);
            map.getLayersByName('Planning Unit Highlight')[0].setVisibility(false);
            $('.map-legend-group').hide();
            $('#map-legend-attr').show();
        } else {
            map.getLayersByName('Planning Unit Highlight')[0].setVisibility(true);
            $('.map-legend-group').hide();
            $('#map-legend-scenario').show();
        }
    }

    $('#layer-select-toggle').bind('change', switchLayer);
    sel.bind('change', switchLayer);

    var sortByKeys = function(obj) {
        var tmpObj = {};
        var fullName;
        var keys = [];
        var i, k, len;
        var outObj = {};

        for(var key in obj) {
            fullName = fieldLookup[key];
            if (!fullName)
                fullName = key;
            tmpObj[fullName] = obj[key];
        }

        for(var key in tmpObj) {
            if(tmpObj.hasOwnProperty(key)) {
                keys.push(key);
            }
        }

        keys.sort();
        len = keys.length;
        for (i=0; i < len; i++) {
            k = keys[i];
            outObj[k] = tmpObj[k];
        }
        return outObj;
    };

    var utfgridCallback = function(infoLookup) {
        var msg = "";
        var puname = "Watershed Info";
        $("#info").hide();
        var fnc = function(idx, val) {
            if (val >= 0) { // Assume negative is null
                try {
                    msg += "
"+ idx + "	" + val.toPrecision(6) + "
";
                } catch (err) {
                    msg += "
"+ idx + "	" + val + "
";
                }
            }
            if(idx.toLowerCase() == "name") { // assume "name"
                puname = val;
            }
        };

        $.each(infoLookup, function(k, info) {
            if (info.data) {
                msg = "
";
                $.each(sortByKeys(info.data), fnc);
                msg += "
";
                $("#info").show();
            }
        });
        $("#info-title").html("
" + puname + "
");
        $("#info-content").html(msg);
    };

    var ctl = new OpenLayers.Control.UTFGrid({
        callback: utfgridCallback,
        handlerMode: "click"
    });

    map.addControl(ctl);

    map.setCenter(new OpenLayers.LonLat(-15400000, 6700000), 4);
}
<|endoftext|>


<commit_before>$(function () {
    window.register_dmmd_preview = function ($preview) {
        var $update = $preview.find('.dmmd-preview-update');
        var $content = $preview.find('.dmmd-preview-content');
        var preview_url = $preview.attr('data-preview-url');
        var $textarea = $('#' + $preview.attr('data-textarea-id'));

        $update.click(function () {
            var text = $textarea.val();
            if (text) {
                $.post(preview_url, {
                    preview: text,
                    csrfmiddlewaretoken: $.cookie('csrftoken')
                }, function (result) {
                    $content.html(result);
                    $preview.addClass('dmmd-preview-has-content');

                    var $jax = $content.find('.require-mathjax-support');
                    if ($jax.length) {
                        if (!('MathJax' in window)) {
                            $.ajax({
                                type: 'GET',
                                url: $jax.attr('data-config'),
                                dataType: 'script',
                                cache: true,
                                success: function () {
                                    $.ajax({
                                        type: 'GET',
                                        url: '//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML',
                                        dataType: 'script',
                                        cache: true,
                                        success: function () {
                                            MathJax.Hub.Queue(function () {
                                                $content.find('.tex-image').hide();
                                                $content.find('.tex-text').show();
                                            });
                                        }
                                    });
                                }
                            });
                        } else {
                            MathJax.Hub.Queue(['Typeset', MathJax.Hub, $content[0]], function () {
                                $content.find('.tex-image').hide();
                                $content.find('.tex-text').show();
                            });
                        }
                    }
                });
            } else {
                $content.empty();
                $preview.removeClass('dmmd-preview-has-content');
            }
        }).click();

        var timeout = $preview.attr('data-timeout');
        var last_event = null;
        if (timeout) {
            $textarea.on('keyup', function () {
                if (last_event)
                    clearTimeout(last_event);
                last_event = setTimeout(function () {
                    $update.click();
                    last_event = null;
                }, timeout);
            });
        }
    };

    $('.dmmd-preview').each(function () {
        register_dmmd_preview($(this));
    });

    if ('django' in window && 'jQuery' in window.django)
        django.jQuery(document).on('formset:added', function(event, $row) {
            var $preview = $row.find('.dmmd-preview');
            if ($preview.length) {
                var id = $row.attr('id');
                id = id.substr(id.lastIndexOf('-') + 1);
                $preview.attr('data-textarea-id', $preview.attr('data-textarea-id').replace('__prefix__', id));
                register_dmmd_preview($preview);
            }
        });
});
<commit_msg>Add a dmmd-preview-stale css class when preview is stale; #444<commit_after>$(function () {
    window.register_dmmd_preview = function ($preview) {
        var $update = $preview.find('.dmmd-preview-update');
        var $content = $preview.find('.dmmd-preview-content');
        var preview_url = $preview.attr('data-preview-url');
        var $textarea = $('#' + $preview.attr('data-textarea-id'));

        $update.click(function () {
            var text = $textarea.val();
            if (text) {
                $.post(preview_url, {
                    preview: text,
                    csrfmiddlewaretoken: $.cookie('csrftoken')
                }, function (result) {
                    $content.html(result);
                    $preview.addClass('dmmd-preview-has-content').removeClass('dmmd-preview-stale');

                    var $jax = $content.find('.require-mathjax-support');
                    if ($jax.length) {
                        if (!('MathJax' in window)) {
                            $.ajax({
                                type: 'GET',
                                url: $jax.attr('data-config'),
                                dataType: 'script',
                                cache: true,
                                success: function () {
                                    $.ajax({
                                        type: 'GET',
                                        url: '//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML',
                                        dataType: 'script',
                                        cache: true,
                                        success: function () {
                                            MathJax.Hub.Queue(function () {
                                                $content.find('.tex-image').hide();
                                                $content.find('.tex-text').show();
                                            });
                                        }
                                    });
                                }
                            });
                        } else {
                            MathJax.Hub.Queue(['Typeset', MathJax.Hub, $content[0]], function () {
                                $content.find('.tex-image').hide();
                                $content.find('.tex-text').show();
                            });
                        }
                    }
                });
            } else {
                $content.empty();
                $preview.removeClass('dmmd-preview-has-content');
            }
        }).click();

        var timeout = $preview.attr('data-timeout');
        var last_event = null;
        if (timeout) {
            $textarea.on('keyup', function () {
                $preview.addClass('dmmd-preview-stale');
                if (last_event)
                    clearTimeout(last_event);
                last_event = setTimeout(function () {
                    $update.click();
                    last_event = null;
                }, timeout);
            });
        }
    };

    $('.dmmd-preview').each(function () {
        register_dmmd_preview($(this));
    });

    if ('django' in window && 'jQuery' in window.django)
        django.jQuery(document).on('formset:added', function(event, $row) {
            var $preview = $row.find('.dmmd-preview');
            if ($preview.length) {
                var id = $row.attr('id');
                id = id.substr(id.lastIndexOf('-') + 1);
                $preview.attr('data-textarea-id', $preview.attr('data-textarea-id').replace('__prefix__', id));
                register_dmmd_preview($preview);
            }
        });
});
<|endoftext|>


<commit_before>/*
 * Copyright © 2015 Cask Data, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

class ConfigActionsFactory {
  constructor(ConfigDispatcher, myPipelineApi, $state, ConfigStore, mySettings, ConsoleActionsFactory, EventPipe, myAppsApi, GLOBALS, myHelpers, $stateParams) {
    this.ConfigStore = ConfigStore;
    this.mySettings = mySettings;
    this.$state = $state;
    this.myPipelineApi = myPipelineApi;
    this.ConsoleActionsFactory = ConsoleActionsFactory;
    this.EventPipe = EventPipe;
    this.myAppsApi = myAppsApi;
    this.GLOBALS = GLOBALS;
    this.myHelpers = myHelpers;
    this.$stateParams = $stateParams;

    this.dispatcher = ConfigDispatcher.getDispatcher();
  }
  initializeConfigStore(config) {
    this.dispatcher.dispatch('onInitialize', config);
  }
  setMetadataInfo(name, description) {
    this.dispatcher.dispatch('onMetadataInfoSave', name, description);
  }
  setDescription(description) {
    this.dispatcher.dispatch('onDescriptionSave', description);
  }
  setConfig(config) {
    this.dispatcher.dispatch('onConfigSave', config);
  }
  savePlugin(plugin, type) {
    this.dispatcher.dispatch('onPluginSave', {plugin: plugin, type: type});
  }
  saveAsDraft(config) {
    this.dispatcher.dispatch('onSaveAsDraft', config);
  }
  setArtifact(artifact) {
    this.dispatcher.dispatch('onArtifactSave', artifact);
  }
  addPlugin (plugin, type) {
    this.dispatcher.dispatch('onPluginAdd', plugin, type);
  }
  editPlugin(pluginId, pluginProperties) {
    this.dispatcher.dispatch('onPluginEdit', pluginId, pluginProperties);
  }
  propagateSchemaDownStream(pluginId) {
    this.dispatcher.dispatch('onSchemaPropagationDownStream', pluginId);
  }
  setSchedule(schedule) {
    this.dispatcher.dispatch('onSetSchedule', schedule);
  }
  setInstance(instance) {
    this.dispatcher.dispatch('onSetInstance', instance);
  }
  publishPipeline() {
    this.ConsoleActionsFactory.resetMessages();
    let error = this.ConfigStore.validateState(true);

    if (!error) { return; }
    this.EventPipe.emit('showLoadingIcon', 'Publishing Pipeline to CDAP');

    let removeFromUserDrafts = (adapterName) => {
      let draftId = this.ConfigStore.getState().__ui__.draftId;
      this.mySettings
        .get('hydratorDrafts', true)
        .then(
          (res) => {
            var savedDraft = this.myHelpers.objectQuery(res, this.$stateParams.namespace, draftId);
            if (savedDraft) {
              delete res[this.$stateParams.namespace][draftId];
              return this.mySettings.set('hydratorDrafts', res);
            }
          },
          (err) => {
            this.ConsoleActionsFactory.addMessage({
              type: 'error',
              content: err
            });
            return this.$q.reject(false);
          }
        )
        .then(
          () => {
            this.EventPipe.emit('hideLoadingIcon.immediate');
            this.$state.go('hydrator.detail', { pipelineId: adapterName });
          }
        );
    };

    let publish = (pipelineName) => {
      this.myPipelineApi.save(
        {
          namespace: this.$state.params.namespace,
          pipeline: pipelineName
        },
        config
      )
      .$promise
      .then(
        removeFromUserDrafts.bind(this, pipelineName),
        (err) => {
          this.EventPipe.emit('hideLoadingIcon.immediate');
          this.ConsoleActionsFactory.addMessage({
            type: 'error',
            content: angular.isObject(err) ? err.data : err
          });
        }
      );
    };

    var config = this.ConfigStore.getConfigForExport();

    // Checking if Pipeline name already exist
    this.myAppsApi
      .list({ namespace: this.$state.params.namespace })
      .$promise
      .then( (apps) => {
        var appNames = apps.map( (app) => { return app.name; } );

        if (appNames.indexOf(config.name) !== -1) {
          this.ConsoleActionsFactory.addMessage({
            type: 'error',
            content: this.GLOBALS.en.hydrator.studio.error['NAME-ALREADY-EXISTS']
          });
          this.EventPipe.emit('hideLoadingIcon.immediate');
        } else {
          publish(config.name);
        }
      });

  }
}

ConfigActionsFactory.$inject = ['ConfigDispatcher', 'myPipelineApi', '$state', 'ConfigStore', 'mySettings', 'ConsoleActionsFactory', 'EventPipe', 'myAppsApi', 'GLOBALS', 'myHelpers', '$stateParams'];
angular.module(`${PKG.name}.feature.hydrator`)
  .service('ConfigActionsFactory', ConfigActionsFactory);
<commit_msg>modify view state of hydrator detail to hydrator++ detail view<commit_after>/*
 * Copyright © 2015 Cask Data, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

class ConfigActionsFactory {
  constructor(ConfigDispatcher, myPipelineApi, $state, ConfigStore, mySettings, ConsoleActionsFactory, EventPipe, myAppsApi, GLOBALS, myHelpers, $stateParams) {
    this.ConfigStore = ConfigStore;
    this.mySettings = mySettings;
    this.$state = $state;
    this.myPipelineApi = myPipelineApi;
    this.ConsoleActionsFactory = ConsoleActionsFactory;
    this.EventPipe = EventPipe;
    this.myAppsApi = myAppsApi;
    this.GLOBALS = GLOBALS;
    this.myHelpers = myHelpers;
    this.$stateParams = $stateParams;

    this.dispatcher = ConfigDispatcher.getDispatcher();
  }
  initializeConfigStore(config) {
    this.dispatcher.dispatch('onInitialize', config);
  }
  setMetadataInfo(name, description) {
    this.dispatcher.dispatch('onMetadataInfoSave', name, description);
  }
  setDescription(description) {
    this.dispatcher.dispatch('onDescriptionSave', description);
  }
  setConfig(config) {
    this.dispatcher.dispatch('onConfigSave', config);
  }
  savePlugin(plugin, type) {
    this.dispatcher.dispatch('onPluginSave', {plugin: plugin, type: type});
  }
  saveAsDraft(config) {
    this.dispatcher.dispatch('onSaveAsDraft', config);
  }
  setArtifact(artifact) {
    this.dispatcher.dispatch('onArtifactSave', artifact);
  }
  addPlugin (plugin, type) {
    this.dispatcher.dispatch('onPluginAdd', plugin, type);
  }
  editPlugin(pluginId, pluginProperties) {
    this.dispatcher.dispatch('onPluginEdit', pluginId, pluginProperties);
  }
  propagateSchemaDownStream(pluginId) {
    this.dispatcher.dispatch('onSchemaPropagationDownStream', pluginId);
  }
  setSchedule(schedule) {
    this.dispatcher.dispatch('onSetSchedule', schedule);
  }
  setInstance(instance) {
    this.dispatcher.dispatch('onSetInstance', instance);
  }
  publishPipeline() {
    this.ConsoleActionsFactory.resetMessages();
    let error = this.ConfigStore.validateState(true);

    if (!error) { return; }
    this.EventPipe.emit('showLoadingIcon', 'Publishing Pipeline to CDAP');

    let removeFromUserDrafts = (adapterName) => {
      let draftId = this.ConfigStore.getState().__ui__.draftId;
      this.mySettings
        .get('hydratorDrafts', true)
        .then(
          (res) => {
            var savedDraft = this.myHelpers.objectQuery(res, this.$stateParams.namespace, draftId);
            if (savedDraft) {
              delete res[this.$stateParams.namespace][draftId];
              return this.mySettings.set('hydratorDrafts', res);
            }
          },
          (err) => {
            this.ConsoleActionsFactory.addMessage({
              type: 'error',
              content: err
            });
            return this.$q.reject(false);
          }
        )
        .then(
          () => {
            this.EventPipe.emit('hideLoadingIcon.immediate');
            this.$state.go('hydratorplusplus.detail', { pipelineId: adapterName });
          }
        );
    };

    let publish = (pipelineName) => {
      this.myPipelineApi.save(
        {
          namespace: this.$state.params.namespace,
          pipeline: pipelineName
        },
        config
      )
      .$promise
      .then(
        removeFromUserDrafts.bind(this, pipelineName),
        (err) => {
          this.EventPipe.emit('hideLoadingIcon.immediate');
          this.ConsoleActionsFactory.addMessage({
            type: 'error',
            content: angular.isObject(err) ? err.data : err
          });
        }
      );
    };

    var config = this.ConfigStore.getConfigForExport();

    // Checking if Pipeline name already exist
    this.myAppsApi
      .list({ namespace: this.$state.params.namespace })
      .$promise
      .then( (apps) => {
        var appNames = apps.map( (app) => { return app.name; } );

        if (appNames.indexOf(config.name) !== -1) {
          this.ConsoleActionsFactory.addMessage({
            type: 'error',
            content: this.GLOBALS.en.hydrator.studio.error['NAME-ALREADY-EXISTS']
          });
          this.EventPipe.emit('hideLoadingIcon.immediate');
        } else {
          publish(config.name);
        }
      });

  }
}

ConfigActionsFactory.$inject = ['ConfigDispatcher', 'myPipelineApi', '$state', 'ConfigStore', 'mySettings', 'ConsoleActionsFactory', 'EventPipe', 'myAppsApi', 'GLOBALS', 'myHelpers', '$stateParams'];
angular.module(`${PKG.name}.feature.hydrator`)
  .service('ConfigActionsFactory', ConfigActionsFactory);
<|endoftext|>


<commit_before>const _ = require('lodash')
const { MOVE, ROTATE, ORIENTATION } = require('../../lib/utils/types')
const pathfinder = require('./../../lib/pathfinder')
const {
  getGameState,
  getEntity,
  getAllEntities,
  isFieldEmpty,
  findFieldNearPosition,
  findEmptyFieldNearPosition
} = require('@robotopia/choo-game')

const SAVE_ZONE_SIZE = 4 // how far enemy towers have to build from base

module.exports = {
  namespace: 'robot',
  globals: {
    getRandomNumber: (min, max) => {
      return Math.floor(Math.random() * (max - min + 1) + min)
    }
  },
  actionsPerRound: 1,
  actions: {
    move: (direction) => ({
      action: ['game:movable.move', { direction: MOVE[direction] }],
      cost: 1
    }),

    rotate: (direction) => ({
      action: ['game:movable.rotate', { direction: ROTATE[direction] }],
      cost: 0
    }),

    setRotation: (direction) => ({
      action: ['game:movable.setRotation', { direction: ORIENTATION[direction] }],
      cost: 0
    }),

    placeMarker: (type, requiredWorkers) => ({
      action: ['game:markerSpawner.spawn', { type, requiredWorkers }],
      cost: 1
    }),

    buildTower: () => ({
      action: ['game:towerSpawner.spawn'],
      cost: 1
    }),

    collectResource: () => ({
      action: ['game:collector.collectResource'],
      cost: 1
    }),

    depositResource: () => ({
      action: ['game:collector.depositResource'],
      cost: 1
    })
  },

  // Be careful here, the methods are converted to strings and interpreted by esper
  // that's because we need to execute them step by step
  // inside the scope of the methods only the specified actions and sensors are available
  // es6 is also not fully supported by esper.js yet. Don't use things like: let, const or arrow functions
  //
  // Examples:
  //   robot.rotate(1)
  //   robot.getPosition()

  methods: {
    moveTo: function (x, y) {
      var nextPosition
      var currentPosition = this.getPosition()

      var target = this.findEmptyFieldNearPosition(x, y)

      if (target === null) {
        return
      }

      var path = this.getPathTo(target.x, target.y)
      for (var i = 1; i < path.length; i++) {
        nextPosition = path[i]

        if (currentPosition.y < nextPosition.y) {
          this.setRotation('FRONT')
        } else if (currentPosition.y > nextPosition.y) {
          this.setRotation('BACK')
        } else if (currentPosition.x < nextPosition.x) {
          this.setRotation('RIGHT')
        } else {
          this.setRotation('LEFT')
        }

        this.move('FORWARD')

        currentPosition = nextPosition
      }
    },

    buildTowerNearPosition: function () { // don't use arrow shorthand here because it messes with toString
      var botPosition = this.getPosition()
      var towerPosition = this.findFieldForTowerNearPosition(botPosition.x, botPosition.y)

      this.moveTo(towerPosition.x, towerPosition.y)
      this.buildTower()
    },

    onMode: function (name, handler) {
      if (this.__modeHandlers === undefined) {
        this.__modeHandlers = {}
      }

      this.__modeHandlers[name] = handler
    },

    onEvent: function (name, handler) {
      if (this.__eventHandlers === undefined) {
        this.__eventHandlers = {}
      }

      this.__eventHandlers[name] = handler
    }
  },

  sensors: {
    getPosition: (state, id) => {
      const game = getGameState(state)
      const entity = getEntity(id, game)

      return entity.position
    },

    isFieldEmpty: (state, id, x, y) => {
      const game = getGameState(state)

      return isFieldEmpty(game, x, y)
    },

    findFieldForTowerNearPosition: (state, id, x, y) => {
      const game = getGameState(state)
      const bot = getEntity(id, game)
      const bases = getEnemyBases(game, bot)

      // find a field which is empty and not inside the save zone of another base
      return findFieldNearPosition(game, x, y, (game, x, y) => {
        if (!isFieldEmpty(game, x, y)) {
          return false
        }

        return _.every(bases, ({ position }) => {
          const distance = Math.sqrt(Math.pow(position.x - x, 2) + Math.pow(position.y - y, 2))
          return distance > SAVE_ZONE_SIZE
        })
      })
    },

    findEmptyFieldNearPosition: (state, id, x, y) => {
      const game = getGameState(state)

      return findEmptyFieldNearPosition(game, x, y)
    },

    getPathTo: (state, id, x, y) => {
      const game = getGameState(state)
      const entity = getEntity(id, game)

      return pathfinder.getPath(game, entity.position, { x, y })
    },

    getBasePosition: (state, id, x, y) => {
      const game = getGameState(state)
      const entity = getEntity(id, game)

      return getBaseOfTeam(game, entity.team.id).position
    },

    getCollectedResources: (state, id, x, y) => {
      const game = getGameState(state)
      const entity = getEntity(id, game)

      return game.teams[entity.team.id].resources
    }
  }
}

function getBaseOfTeam (game, teamId) {
  const bases = getAllEntities('robotSpawner', game)

  return _.find(bases, ({ team }) => team.id === teamId)
}

function getEnemyBases (game, entity) {
  const bases = getAllEntities('robotSpawner', game)

  return _.filter(bases, ({ team }) => team.id !== entity.team.id)
}
<commit_msg>Recalculate path if moveTo was interrupted<commit_after>const _ = require('lodash')
const { MOVE, ROTATE, ORIENTATION } = require('../../lib/utils/types')
const pathfinder = require('./../../lib/pathfinder')
const {
  getGameState,
  getEntity,
  getAllEntities,
  isFieldEmpty,
  findFieldNearPosition,
  findEmptyFieldNearPosition
} = require('@robotopia/choo-game')

const SAVE_ZONE_SIZE = 4 // how far enemy towers have to build from base

module.exports = {
  namespace: 'robot',
  globals: {
    getRandomNumber: (min, max) => {
      return Math.floor(Math.random() * (max - min + 1) + min)
    }
  },
  actionsPerRound: 1,
  actions: {
    move: (direction) => ({
      action: ['game:movable.move', { direction: MOVE[direction] }],
      cost: 1
    }),

    rotate: (direction) => ({
      action: ['game:movable.rotate', { direction: ROTATE[direction] }],
      cost: 0
    }),

    setRotation: (direction) => ({
      action: ['game:movable.setRotation', { direction: ORIENTATION[direction] }],
      cost: 0
    }),

    placeMarker: (type, requiredWorkers) => ({
      action: ['game:markerSpawner.spawn', { type, requiredWorkers }],
      cost: 1
    }),

    buildTower: () => ({
      action: ['game:towerSpawner.spawn'],
      cost: 1
    }),

    collectResource: () => ({
      action: ['game:collector.collectResource'],
      cost: 1
    }),

    depositResource: () => ({
      action: ['game:collector.depositResource'],
      cost: 1
    })
  },

  // Be careful here, the methods are converted to strings and interpreted by esper
  // that's because we need to execute them step by step
  // inside the scope of the methods only the specified actions and sensors are available
  // es6 is also not fully supported by esper.js yet. Don't use things like: let, const or arrow functions
  //
  // Examples:
  //   robot.rotate(1)
  //   robot.getPosition()

  methods: {
    moveTo: function (x, y) {
      var comparePosition, i, path
      var nextPosition
      var currentPosition = this.getPosition()

      var target = this.findEmptyFieldNearPosition(x, y)

      if (target === null) {
        return
      }

      // repeat trying to find a path until target is reached
      while (currentPosition.x !== target.x || currentPosition.y !== target.y) {

        // recalculate target if it is no longer empty
        if (!this.isFieldEmpty(target.x, target.y)) {
          target = this.findEmptyFieldNearPosition(x, y)
          break;
        }

        // calculate route
        path = this.getPathTo(target.x, target.y)

        // traverse route
        for (i = 1; i < path.length; i++) {
          // check if method has been interrupted by mode change or event in this case break and recalculate route
          comparePosition = this.getPosition();
          if (currentPosition.x !== comparePosition.x || currentPosition.y !== comparePosition.y) {
            currentPosition = comparePosition
            break
          }

          nextPosition = path[i]

          // recalculate route if next position isn't empty
          if (!this.isFieldEmpty(nextPosition.x, nextPosition.y)) {
            break;
          }

          if (currentPosition.y < nextPosition.y) {
            this.setRotation('FRONT')
          } else if (currentPosition.y > nextPosition.y) {
            this.setRotation('BACK')
          } else if (currentPosition.x < nextPosition.x) {
            this.setRotation('RIGHT')
          } else {
            this.setRotation('LEFT')
          }

          this.move('FORWARD')

          currentPosition = nextPosition
        }
      }
    },

    buildTowerNearPosition: function () { // don't use arrow shorthand here because it messes with toString
      var botPosition = this.getPosition()
      var towerPosition = this.findFieldForTowerNearPosition(botPosition.x, botPosition.y)

      this.moveTo(towerPosition.x, towerPosition.y)
      this.buildTower()
    },

    onMode: function (name, handler) {
      if (this.__modeHandlers === undefined) {
        this.__modeHandlers = {}
      }

      this.__modeHandlers[name] = handler
    },

    onEvent: function (name, handler) {
      if (this.__eventHandlers === undefined) {
        this.__eventHandlers = {}
      }

      this.__eventHandlers[name] = handler
    }
  },

  sensors: {
    getPosition: (state, id) => {
      const game = getGameState(state)
      const entity = getEntity(id, game)

      return entity.position
    },

    isFieldEmpty: (state, id, x, y) => {
      const game = getGameState(state)

      return isFieldEmpty(game, x, y)
    },

    findFieldForTowerNearPosition: (state, id, x, y) => {
      const game = getGameState(state)
      const bot = getEntity(id, game)
      const bases = getEnemyBases(game, bot)

      // find a field which is empty and not inside the save zone of another base
      return findFieldNearPosition(game, x, y, (game, x, y) => {
        if (!isFieldEmpty(game, x, y)) {
          return false
        }

        return _.every(bases, ({ position }) => {
          const distance = Math.sqrt(Math.pow(position.x - x, 2) + Math.pow(position.y - y, 2))
          return distance > SAVE_ZONE_SIZE
        })
      })
    },

    findEmptyFieldNearPosition: (state, id, x, y) => {
      const game = getGameState(state)

      return findEmptyFieldNearPosition(game, x, y)
    },

    getPathTo: (state, id, x, y) => {
      const game = getGameState(state)
      const entity = getEntity(id, game)

      return pathfinder.getPath(game, entity.position, { x, y })
    },

    getBasePosition: (state, id, x, y) => {
      const game = getGameState(state)
      const entity = getEntity(id, game)

      return getBaseOfTeam(game, entity.team.id).position
    },

    getCollectedResources: (state, id, x, y) => {
      const game = getGameState(state)
      const entity = getEntity(id, game)

      return game.teams[entity.team.id].resources
    }
  }
}

function getBaseOfTeam (game, teamId) {
  const bases = getAllEntities('robotSpawner', game)

  return _.find(bases, ({ team }) => team.id === teamId)
}

function getEnemyBases (game, entity) {
  const bases = getAllEntities('robotSpawner', game)

  return _.filter(bases, ({ team }) => team.id !== entity.team.id)
}
<|endoftext|>


<commit_before>const async = require('async');
const vm = require('vm');

const DataModel = require('../models/data');
const DeviceModel = require('../models/device');
const RuleModel = require('../models/rule');

function evaluateRule(previous, input, rule) {
  const sandbox = {
    previous: previous ? previous.data : null,
    input: input ? input.data : null,
    output: null,
  };

  try {
    vm.runInNewContext(rule.rule, sandbox);
    return sandbox.output;
  } catch (err) {
    return null;
  }
}

function triggerRules(socket, data) {
  async.parallel({
    previous: function getPreviousDatapoint(cb) {
      DataModel.findOne({
        device: data.device._id.toString(),
      })
        .sort('-createdAt')
        .skip(1)
        .exec(cb);
    },
    rules: function getActiveRules(cb) {
      RuleModel.find({
        input: data.device._id.toString(),
        enabled: true,
      }, cb);
    },
  }, (err, results) => {
    if (results.rules) {
      results.rules.forEach(rule => {
        const output = evaluateRule(rule);
        if (output) {
          socket.room(`output:stream:${data.device._id.toString()}`).write({
            address: data.device.address,
            data: output,
          });
        }
      });
    }
  });
}

function addData(socket, data, done) {
  const { payload } = data;

  if (!socket.jwt) {
    return done({
      status: 'fail',
      meta: {
        room: data.room,
        action: data.action,
        message: 'You are not authorised.',
      },
      data: null,
    });
  }

  DeviceModel
  .findOne({
    address: payload.address,
  })
  .populate('deviceType')
  .exec((err, device) => {
    if (err || device === null) {
      return done({
        status: 'fail',
        meta: {
          room: data.room,
          action: data.action,
          message: 'The data could not be stored - the associated device could not be found.',
        },
        data: null,
      });
    }

    if (device.owner.toString() !== socket.jwt.id) {
      return done({
        status: 'fail',
        meta: {
          room: data.room,
          action: data.action,
          message: 'You are not authorised.',
        },
        data: null,
      });
    }

    if (device.deviceType.deviceClass !== 'input') {
      return done({
        status: 'fail',
        meta: {
          room: data.room,
          action: data.action,
          message: 'The specified device cannot generate data.',
        },
        data: null,
      });
    }

    DataModel.create({
      device,
      data: payload.data,
    }, (saveErr, doc) => {
      if (saveErr) {
        return done({
          status: 'fail',
          meta: {
            room: data.room,
            action: data.action,
            message: 'The data could not be stored. Check validation.',
            validation: saveErr.errors,
          },
          data: null,
        });
      }

      const docObj = doc.toObject();

      socket
        .room(`input:stream:${docObj._id.toString()}`)
        .write({
          data: docObj,
        });

      triggerRules(socket, doc);

      done({
        status: 'success',
        meta: {
          room: data.room,
          action: data.action,
          message: 'The data was saved.',
        },
        data: docObj,
      });
    });
  });
}

function joinStream(socket, data, done) {
  const { room } = data;
  const pattern = /^(input):(stream):([a-fA-F0-9]{24})$/;
  const segments = pattern.exec(room);
  const deviceId = Array.isArray(segments) && segments[3] ? segments[3] : null;

  DeviceModel
  .findOne({
    _id: deviceId,
  })
  .populate('deviceType')
  .exec((err, device) => {
    if (err || device === null) {
      return done({
        status: 'fail',
        meta: {
          message: 'The stream could not be joined - the device was not found.',
        },
        data: null,
      });
    }

    if (device.deviceType.deviceClass !== 'input') {
      return done({
        status: 'fail',
        meta: {
          message: 'The specified device cannot generate data.',
        },
        data: null,
      });
    }

    const isPrivate = device.visibility === 'private';
    const isAnonymous = !socket.jwt;
    const notOwner = socket.jwt && socket.jwt.id !== device.owner.toString();

    if (isPrivate && (isAnonymous || notOwner)) {
      return done({
        status: 'fail',
        meta: {
          message: 'You are not authorised.',
        },
        data: null,
      });
    }

    socket.join(room, () => {
      done({
        status: 'success',
        meta: {
          message: `You have been added to the room ${room}`,
        },
        data: null,
      });
    });
  });
}

function leaveStream(socket, data, done) {
  const { room } = data;
  const pattern = /^(input):(stream):([a-fA-F0-9]{24})$/;
  const segments = pattern.exec(room);
  const deviceId = Array.isArray(segments) && segments[3] ? segments[3] : null;

  if (!deviceId) {
    return done({
      status: 'fail',
      meta: {
        message: 'You have not provided a valid room ID.',
      },
      data: null,
    });
  }

  const ids = socket.room(room).clients();

  if (!ids || ids.indexOf(socket.id) === -1) {
    return done({
      status: 'fail',
      meta: {
        message: 'You are not in the specified room.',
      },
      data: null,
    });
  }

  socket.leave(room, () => {
    done({
      status: 'success',
      meta: {
        message: 'You have left the room.',
      },
      data: null,
    });
  });
}

const handlers = {
  stream: {
    listen: joinStream,
    leave: leaveStream,
  },
  data: {
    talk: addData,
  },
};

module.exports = handlers;
<commit_msg>realtime input: renaming handlers<commit_after>const async = require('async');
const vm = require('vm');

const DataModel = require('../models/data');
const DeviceModel = require('../models/device');
const RuleModel = require('../models/rule');

function evaluateRule(previous, input, rule) {
  const sandbox = {
    previous: previous ? previous.data : null,
    input: input ? input.data : null,
    output: null,
  };

  try {
    vm.runInNewContext(rule.rule, sandbox);
    return sandbox.output;
  } catch (err) {
    return null;
  }
}

function triggerRules(socket, data) {
  async.parallel({
    previous: function getPreviousDatapoint(cb) {
      DataModel.findOne({
        device: data.device._id.toString(),
      })
        .sort('-createdAt')
        .skip(1)
        .exec(cb);
    },
    rules: function getActiveRules(cb) {
      RuleModel.find({
        input: data.device._id.toString(),
        enabled: true,
      }, cb);
    },
  }, (err, results) => {
    if (results.rules) {
      results.rules.forEach(rule => {
        const output = evaluateRule(rule);
        if (output) {
          socket.room(`output:stream:${data.device._id.toString()}`).write({
            address: data.device.address,
            data: output,
          });
        }
      });
    }
  });
}

function publish(socket, data, done) {
  const { payload } = data;

  if (!socket.jwt) {
    return done({
      status: 'fail',
      meta: {
        room: data.room,
        action: data.action,
        message: 'You are not authorised.',
      },
      data: null,
    });
  }

  DeviceModel
  .findOne({
    address: payload.address,
  })
  .populate('deviceType')
  .exec((err, device) => {
    if (err || device === null) {
      return done({
        status: 'fail',
        meta: {
          room: data.room,
          action: data.action,
          message: 'The data could not be stored - the associated device could not be found.',
        },
        data: null,
      });
    }

    if (device.owner.toString() !== socket.jwt.id) {
      return done({
        status: 'fail',
        meta: {
          room: data.room,
          action: data.action,
          message: 'You are not authorised.',
        },
        data: null,
      });
    }

    if (device.deviceType.deviceClass !== 'input') {
      return done({
        status: 'fail',
        meta: {
          room: data.room,
          action: data.action,
          message: 'The specified device cannot generate data.',
        },
        data: null,
      });
    }

    DataModel.create({
      device,
      data: payload.data,
    }, (saveErr, doc) => {
      if (saveErr) {
        return done({
          status: 'fail',
          meta: {
            room: data.room,
            action: data.action,
            message: 'The data could not be stored. Check validation.',
            validation: saveErr.errors,
          },
          data: null,
        });
      }

      const docObj = doc.toObject();

      socket
        .room(`input:stream:${docObj._id.toString()}`)
        .write({
          data: docObj,
        });

      triggerRules(socket, doc);

      done({
        status: 'success',
        meta: {
          room: data.room,
          action: data.action,
          message: 'The data was saved.',
        },
        data: docObj,
      });
    });
  });
}

function subscribe(socket, data, done) {
  const { room } = data;
  const pattern = /^(input):(stream):([a-fA-F0-9]{24})$/;
  const segments = pattern.exec(room);
  const deviceId = Array.isArray(segments) && segments[3] ? segments[3] : null;

  DeviceModel
  .findOne({
    _id: deviceId,
  })
  .populate('deviceType')
  .exec((err, device) => {
    if (err || device === null) {
      return done({
        status: 'fail',
        meta: {
          message: 'The stream could not be joined - the device was not found.',
        },
        data: null,
      });
    }

    if (device.deviceType.deviceClass !== 'input') {
      return done({
        status: 'fail',
        meta: {
          message: 'The specified device cannot generate data.',
        },
        data: null,
      });
    }

    const isPrivate = device.visibility === 'private';
    const isAnonymous = !socket.jwt;
    const notOwner = socket.jwt && socket.jwt.id !== device.owner.toString();

    if (isPrivate && (isAnonymous || notOwner)) {
      return done({
        status: 'fail',
        meta: {
          message: 'You are not authorised.',
        },
        data: null,
      });
    }

    socket.join(room, () => {
      done({
        status: 'success',
        meta: {
          message: `You have been added to the room ${room}`,
        },
        data: null,
      });
    });
  });
}

function unsubscribe(socket, data, done) {
  const { room } = data;
  const pattern = /^(input):(stream):([a-fA-F0-9]{24})$/;
  const segments = pattern.exec(room);
  const deviceId = Array.isArray(segments) && segments[3] ? segments[3] : null;

  if (!deviceId) {
    return done({
      status: 'fail',
      meta: {
        message: 'You have not provided a valid room ID.',
      },
      data: null,
    });
  }

  const ids = socket.room(room).clients();

  if (!ids || ids.indexOf(socket.id) === -1) {
    return done({
      status: 'fail',
      meta: {
        message: 'You are not in the specified room.',
      },
      data: null,
    });
  }

  socket.leave(room, () => {
    done({
      status: 'success',
      meta: {
        message: 'You have left the room.',
      },
      data: null,
    });
  });
}

const handlers = {
  subscribe,
  unsubscribe,
  publish,
};

module.exports = handlers;
<|endoftext|>