<commit_before>define(['lodash'], function(_) {
    'use strict';

    /**
     * Http endpoint factory
     */
    HttpEndpointFactory.$inject = ['$http', '$q', 'urls'];
    function HttpEndpointFactory($http, $q, urls) {

        /**
         * Get url for given resource
         *
         * @param {Object} resource
         * @returns {Promise}
         */
        function getUrl(resource) {
            return urls.resource(resource.rel);
        }

        /**
         * Get headers for given resource
         *
         * @param {Object} resource
         * @param {Object} item
         * @returns {Object}
         */
        function getHeaders(resource, item) {
            var headers = _.extend({}, resource.config.headers || {});
            if (item && item._etag) {
                headers['If-Match'] = item._etag;
            }
            return headers;
        }

        /**
         * Wrap $http call
         *
         * @param {Object} config
         * @returns {Promise}
         */
        function http(config) {
            return $q.when(config.url)
                .then(function(url) {
                    config.url = url;
                    return $http(config);
                })
                .then(function(response) {
                    if (response.status >= 200 && response.status < 300 &&
                    (!response.data || !response.data._status || response.data._status !== 'ERR')) {
                        return response;
                    } else {
                        return $q.reject(response);
                    }
                });
        }

        /**
         * Remove keys prefixed with '_'
         */
        function clean(data, keepId) {
            var blacklist = {
                    _status: 1,
                    _updated: 1,
                    _created: 1,
                    _etag: 1,
                    _links: 1,
                    _id: keepId ? 0 : 1
                },
                cleanData = {};

            angular.forEach(data, function(val, key) {
                if (!blacklist[key]) {
                    cleanData[key] = val;
                }
            });

            return cleanData;
        }

        /**
         * Http Endpoint
         */
        function HttpEndpoint(name, config) {
            this.name = name;
            this.config = config;
            this.rel = config.rel;
        }

        /**
         * Get entity by url
         *
         * @param {string} url
         * @returns {Promise}
         */
        HttpEndpoint.prototype.getByUrl = function(url, cache) {
            return http({
                method: 'GET',
                url: urls.item(url),
                cache: cache
            }).then(function(response) {
                return response.data;
            });
        };

        /**
         * Get entity by given id
         *
         * @param {string} id
         * @returns {Promise}
         */
        HttpEndpoint.prototype.getById = function(id, cache) {
            return getUrl(this).then(_.bind(function(resourceUrl) {
                var url = resourceUrl.replace(/\/+$/, '') + '/' + id;
                return http({
                    method: 'GET',
                    url: url,
                    cache: cache
                }).then(function(response) {
                    return response.data;
                });
            }, this));
        };

        /**
         * Resource query method
         *
         * @param {Object} params
         */
        HttpEndpoint.prototype.query = function(params, cache) {
            return http({
                method: 'GET',
                params: params,
                url: getUrl(this),
                headers: getHeaders(this),
                cache: cache
            }).then(function(response) {
                return response.data;
            });
        };

        /**
         * Update item
         *
         * @param {Object} item
         * @param {Object} diff
         * @returns {Promise}
         */
        HttpEndpoint.prototype.update = function(item, diff) {
            if (diff && diff._etag) {
                item._etag = diff._etag;
            }

            if (!diff) {
                diff = angular.extend({}, item);
            }

            var url = item._links.self.href;
            return http({
                method: 'PATCH',
                url: urls.item(url),
                data: clean(diff, !item._links),
                headers: getHeaders(this, item)
            }).then(function(response) {
                _.extend(item, response.data);
                return item;
            });
        };

        /**
         * Create new item
         *
         * @param {Object} itemData
         * @returns {Promise}
         */
        HttpEndpoint.prototype.create = function(itemData) {
            return http({
                method: 'POST',
                url: getUrl(this),
                data: itemData,
                headers: getHeaders(this)
            }).then(function(response) {
                delete response.data._status;
                _.extend(itemData, response.data);
                return itemData;
            });
        };

        /**
         * Save item
         *
         * @param {Object} item
         * @param {Object} diff
         * @returns {Promise}
         */
        HttpEndpoint.prototype.save = function(item, diff) {
            return item._id ? this.update(item, diff) : this.create(_.extend(item, diff));
        };

        /**
         * Replace item
         *
         * @param {Object} dest
         * @param {Object} item
         * @returns {Promise}
         */
        HttpEndpoint.prototype.replace = function(dest, item) {
            return http({
                method: 'PUT',
                url: urls.item(dest),
                data: item,
                headers: getHeaders(this, item)
            }).then(function(response) {
                _.extend(item, response.data);
                return item;
            });
        };

        /**
         * Remove item
         *
         * @param {Object} item
         * @returns {Promise}
         */
        HttpEndpoint.prototype.remove = function(item) {
            return http({
                method: 'DELETE',
                url: urls.item(item._links.self.href),
                headers: getHeaders(this, item)
            }).then(null, function(response) {
                return response.status === 404 ? $q.when(response) : $q.reject(response);
            });
        };

        /**
         * Get resource url
         *
         * @returns {Promise}
         */
        HttpEndpoint.prototype.getUrl = function() {
            return getUrl(this);
        };

        /**
         * Get headers
         *
         * @return {Object}
         */
        HttpEndpoint.prototype.getHeaders = function() {
            return getHeaders(this) || {};
        };

        return HttpEndpoint;
    }

    return HttpEndpointFactory;
});
<commit_msg>fix: include params the same as api-service resouce impl.<commit_after>define(['lodash'], function(_) {
    'use strict';

    /**
     * Http endpoint factory
     */
    HttpEndpointFactory.$inject = ['$http', '$q', 'urls'];
    function HttpEndpointFactory($http, $q, urls) {

        /**
         * Get url for given resource
         *
         * @param {Object} resource
         * @returns {Promise}
         */
        function getUrl(resource) {
            return urls.resource(resource.rel);
        }

        /**
         * Get headers for given resource
         *
         * @param {Object} resource
         * @param {Object} item
         * @returns {Object}
         */
        function getHeaders(resource, item) {
            var headers = _.extend({}, resource.config.headers || {});
            if (item && item._etag) {
                headers['If-Match'] = item._etag;
            }
            return headers;
        }

        /**
         * Wrap $http call
         *
         * @param {Object} config
         * @returns {Promise}
         */
        function http(config) {
            return $q.when(config.url)
                .then(function(url) {
                    config.url = url;
                    return $http(config);
                })
                .then(function(response) {
                    if (response.status >= 200 && response.status < 300 &&
                    (!response.data || !response.data._status || response.data._status !== 'ERR')) {
                        return response;
                    } else {
                        return $q.reject(response);
                    }
                });
        }

        /**
         * Remove keys prefixed with '_'
         */
        function clean(data, keepId) {
            var blacklist = {
                    _status: 1,
                    _updated: 1,
                    _created: 1,
                    _etag: 1,
                    _links: 1,
                    _id: keepId ? 0 : 1
                },
                cleanData = {};

            angular.forEach(data, function(val, key) {
                if (!blacklist[key]) {
                    cleanData[key] = val;
                }
            });

            return cleanData;
        }

        /**
         * Http Endpoint
         */
        function HttpEndpoint(name, config) {
            this.name = name;
            this.config = config;
            this.rel = config.rel;
        }

        /**
         * Get entity by url
         *
         * @param {string} url
         * @returns {Promise}
         */
        HttpEndpoint.prototype.getByUrl = function(url, cache) {
            return http({
                method: 'GET',
                url: urls.item(url),
                cache: cache
            }).then(function(response) {
                return response.data;
            });
        };

        /**
         * Get entity by given id
         *
         * @param {string} id
         * @returns {Promise}
         */
        HttpEndpoint.prototype.getById = function(id, params, cache) {
            return getUrl(this).then(_.bind(function(resourceUrl) {
                var url = resourceUrl.replace(/\/+$/, '') + '/' + id;
                return http({
                    method: 'GET',
                    url: url,
                    params: params,
                    cache: cache
                }).then(function(response) {
                    return response.data;
                });
            }, this));
        };

        /**
         * Resource query method
         *
         * @param {Object} params
         */
        HttpEndpoint.prototype.query = function(params, cache) {
            return http({
                method: 'GET',
                params: params,
                url: getUrl(this),
                headers: getHeaders(this),
                cache: cache
            }).then(function(response) {
                return response.data;
            });
        };

        /**
         * Update item
         *
         * @param {Object} item
         * @param {Object} diff
         * @returns {Promise}
         */
        HttpEndpoint.prototype.update = function(item, diff) {
            if (diff && diff._etag) {
                item._etag = diff._etag;
            }

            if (!diff) {
                diff = angular.extend({}, item);
            }

            var url = item._links.self.href;
            return http({
                method: 'PATCH',
                url: urls.item(url),
                data: clean(diff, !item._links),
                headers: getHeaders(this, item)
            }).then(function(response) {
                _.extend(item, response.data);
                return item;
            });
        };

        /**
         * Create new item
         *
         * @param {Object} itemData
         * @returns {Promise}
         */
        HttpEndpoint.prototype.create = function(itemData) {
            return http({
                method: 'POST',
                url: getUrl(this),
                data: itemData,
                headers: getHeaders(this)
            }).then(function(response) {
                delete response.data._status;
                _.extend(itemData, response.data);
                return itemData;
            });
        };

        /**
         * Save item
         *
         * @param {Object} item
         * @param {Object} diff
         * @returns {Promise}
         */
        HttpEndpoint.prototype.save = function(item, diff) {
            return item._id ? this.update(item, diff) : this.create(_.extend(item, diff));
        };

        /**
         * Replace item
         *
         * @param {Object} dest
         * @param {Object} item
         * @returns {Promise}
         */
        HttpEndpoint.prototype.replace = function(dest, item) {
            return http({
                method: 'PUT',
                url: urls.item(dest),
                data: item,
                headers: getHeaders(this, item)
            }).then(function(response) {
                _.extend(item, response.data);
                return item;
            });
        };

        /**
         * Remove item
         *
         * @param {Object} item
         * @returns {Promise}
         */
        HttpEndpoint.prototype.remove = function(item) {
            return http({
                method: 'DELETE',
                url: urls.item(item._links.self.href),
                headers: getHeaders(this, item)
            }).then(null, function(response) {
                return response.status === 404 ? $q.when(response) : $q.reject(response);
            });
        };

        /**
         * Get resource url
         *
         * @returns {Promise}
         */
        HttpEndpoint.prototype.getUrl = function() {
            return getUrl(this);
        };

        /**
         * Get headers
         *
         * @return {Object}
         */
        HttpEndpoint.prototype.getHeaders = function() {
            return getHeaders(this) || {};
        };

        return HttpEndpoint;
    }

    return HttpEndpointFactory;
});
<|endoftext|>


<commit_before>import BABYLON from 'babylonjs';
import {registerBeforeSceneRender} from '../../../mesh-util'
import {getHeightAtCoordinates} from '../powerUtils/mainUtils';

const zeroVector = new BABYLON.Vector3.Zero();

export default class BasePowerObject {
  constructor(game, hero, mesh, vectorStart, vectorEnd, range, lifeSpan, dropHeight=0, dropRange=0,
              collisionCallBack=true, damageMult=10) {
    this.game = game;
    this.hero = hero;
    this.mesh = mesh;

    // setup mesh impostor
    this.collisionActive = false;
    if (collisionCallBack) {
      this.collisionActive = true;
      this.contactVelocity = new BABYLON.Vector3();
      this.damageMult = damageMult;
      this.mesh.physicsImpostor.onCollide = this.onPowerCollide.bind(this);
      mesh.physicsImpostor.forceUpdate();
    }

    this.game.scene.shadowGenerator.getShadowMap().renderList.push(mesh);
    mesh.receiveShadows = true;

    // console.log('vectorstart', vectorStart);
    this.vectorStart = vectorStart;
    this.vectorEnd = vectorEnd;
    this.range = range;
    this.lifeSpan = lifeSpan;
    this.dropHeight = dropHeight;
    this._currentState = 0;
    this.groundMesh = this.game.scene.getMeshesByTags('heightFieldImpostor')[0];
    this.dropRange = dropRange?dropRange:range;

    this.spawn();
    registerBeforeSceneRender(mesh, () => this.update());
  }

  update() {
    if (this._currentState == 0) {
    } else if (this._currentState == 1) {
      // main update loop of power
      this.powerUpdate();
    } else if (this._currentState == 2) {

    }
  }

  powerUpdate() {
    if (this.lifeSpan) {
      this.lifeSpan--;
    } else {
      this._currentState = 2;
      this.destroy();
    }

  }

  spawn() {
    const spawnEndEvent = new BABYLON.AnimationEvent(this.range, () => {
      this.collisionActive = false; // stops the object from colliding with player after moving
      // Switch to powerUpdate state
      this.onPowerSpawn();
      this._currentState = 1;
    });

    this.moveAnimation('spawn', spawnEndEvent);
  }

  destroy() {
    this.range = this.dropRange;
    const destroyEndEvent = new BABYLON.AnimationEvent(this.range, () => {
      //console.log('End animation event!');
      this.mesh.dispose();
    });

    this.vectorStart = this.mesh.position;
    this.vectorEnd = this.mesh.position.clone();
    this.vectorEnd.y = getHeightAtCoordinates(this.groundMesh, this.vectorEnd.x, this.vectorEnd.z) - (this.dropHeight?this.dropHeight:this.mesh.getBoundingInfo().boundingBox.extendSize.y);

    //console.log('what is the range', this.dropRange);

    this.moveAnimation('destroy', destroyEndEvent);
  }

  moveAnimation(animationName, endEvent) {
    //console.log('start pos', this.vectorStart);
    //console.log('end pos', this.vectorEnd);
    var moveAnimation = new BABYLON.Animation(
      animationName, 'position', 60,
      BABYLON.Animation.ANIMATIONTYPE_VECTOR3);

    moveAnimation.addEvent(endEvent);
    var moveAnimationKeys = [
      {
        frame: 0,
        value: this.vectorStart,
      },
      {
        frame: this.range,
        value: this.vectorEnd,
      },
    ];
    // Set the keys
    moveAnimation.setKeys(moveAnimationKeys);
    this.mesh.animations = [];
    this.mesh.animations.push(moveAnimation);

    this.game.scene.beginAnimation(this.mesh, 0, this.range, false);
  }

  onPowerSpawn() {
    // Called when power is spawned
  }

  onPowerCollide(e) {
    // Called when object collides
    // Uses Cannon.js vectors
    if (BABYLON.Tags.HasTags(e.body) && e.body.matchesTagsQuery("hero") && e.body.parent.name != this.hero.name && this.collisionActive) {
        // e.body.parent is the hero that the object is colliding with
        try { // It has thrown an error once, idk why
          this.contactVelocity.copyFrom(this.mesh.physicsImpostor.getLinearVelocity());
        } catch(err) {
          this.contactVelocity.copyFrom(zeroVector);
        }

        // If it does not have a velocity calculate it.
        if ( this.contactVelocity.equals(zeroVector) ) {
          this.contactVelocity = this.vectorEnd.subtract(this.vectorStart);
          let magnitude = this.contactVelocity.length();
          this.contactVelocity.normalize().scaleInPlace(magnitude/this.range);
        }

        this.contactVelocity = this.babylonToCannonVector(this.contactVelocity);
        // apply the damage
        e.body.parent.takeDynamicDamage(this.damageMult, Math.abs(this.contactVelocity.dot(e.contact.ni)));
        this.collisionActive = false;
    }
  }

  babylonToCannonVector(babylonVec) {
      return new CANNON.Vec3(babylonVec.x, babylonVec.y, babylonVec.z);
  }
}
<commit_msg>added more particles<commit_after>import BABYLON from 'babylonjs';
import {registerBeforeSceneRender} from '../../../mesh-util'
import {getHeightAtCoordinates} from '../powerUtils/mainUtils';
import ParticleEmitter from '../../../particle';

const zeroVector = new BABYLON.Vector3.Zero();

export default class BasePowerObject {
  constructor(game, hero, mesh, vectorStart, vectorEnd, range, lifeSpan, dropHeight=0, dropRange=0,
              collisionCallBack=true, damageMult=10) {
    this.game = game;
    this.hero = hero;
    this.mesh = mesh;

    // setup mesh impostor
    this.collisionActive = false;
    if (collisionCallBack) {
      this.collisionActive = true;
      this.contactVelocity = new BABYLON.Vector3();
      this.damageMult = damageMult;
      this.mesh.physicsImpostor.onCollide = this.onPowerCollide.bind(this);
      mesh.physicsImpostor.forceUpdate();
    }

    this.game.scene.shadowGenerator.getShadowMap().renderList.push(mesh);
    mesh.receiveShadows = true;

    // console.log('vectorstart', vectorStart);
    this.vectorStart = vectorStart;
    this.vectorEnd = vectorEnd;
    this.range = range;
    this.lifeSpan = lifeSpan;
    this.dropHeight = dropHeight;
    this._currentState = 0;
    this.groundMesh = this.game.scene.getMeshesByTags('heightFieldImpostor')[0];
    this.dropRange = dropRange?dropRange:range;

    this.dustParticleEmitter = new ParticleEmitter(this.game, 'dustParticle', './textures/effects/circle.png',
      new BABYLON.Vector3(0, 0, 0), //position
      new BABYLON.Vector3(30, 0, -30), //directionwdw
      new BABYLON.Vector3(-30, 0, 30), //direction
      new BABYLON.Vector3(0,-1,0), //gravity
      new BABYLON.Color3(1, 1, 1),
      new BABYLON.Color3(1, 1, 1));
    this.dustParticleEmitter.emitConstant(20, new BABYLON.Vector3(this.vectorEnd.x, getHeightAtCoordinates(this.groundMesh, this.vectorEnd.x, this.vectorEnd.z) + 1, this.vectorEnd.z));

    this.spawn();
    registerBeforeSceneRender(mesh, () => this.update());
  }

  update() {
    if (this._currentState == 0) {
    } else if (this._currentState == 1) {
      // main update loop of power
      this.powerUpdate();
    } else if (this._currentState == 2) {

    }
  }

  powerUpdate() {
    if (this.lifeSpan) {
      this.lifeSpan--;
    } else {
      this._currentState = 2;
      this.destroy();
    }

  }

  spawn() {
    const spawnEndEvent = new BABYLON.AnimationEvent(this.range, () => {
      this.dustParticleEmitter.stop();
      this.collisionActive = false; // stops the object from colliding with player after moving
      // Switch to powerUpdate state
      this.onPowerSpawn();
      this._currentState = 1;
    });

    this.moveAnimation('spawn', spawnEndEvent);
  }

  destroy() {
    this.range = this.dropRange;
    const destroyEndEvent = new BABYLON.AnimationEvent(this.range, () => {
      //console.log('End animation event!');
      this.mesh.dispose();
    });

    this.vectorStart = this.mesh.position;
    this.vectorEnd = this.mesh.position.clone();
    this.vectorEnd.y = getHeightAtCoordinates(this.groundMesh, this.vectorEnd.x, this.vectorEnd.z) - (this.dropHeight?this.dropHeight:this.mesh.getBoundingInfo().boundingBox.extendSize.y);

    //console.log('what is the range', this.dropRange);

    this.moveAnimation('destroy', destroyEndEvent);
  }

  moveAnimation(animationName, endEvent) {
    //console.log('start pos', this.vectorStart);
    //console.log('end pos', this.vectorEnd);
    var moveAnimation = new BABYLON.Animation(
      animationName, 'position', 60,
      BABYLON.Animation.ANIMATIONTYPE_VECTOR3);

    moveAnimation.addEvent(endEvent);
    var moveAnimationKeys = [
      {
        frame: 0,
        value: this.vectorStart,
      },
      {
        frame: this.range,
        value: this.vectorEnd,
      },
    ];
    // Set the keys
    moveAnimation.setKeys(moveAnimationKeys);
    this.mesh.animations = [];
    this.mesh.animations.push(moveAnimation);

    this.game.scene.beginAnimation(this.mesh, 0, this.range, false);
  }

  onPowerSpawn() {
    // Called when power is spawned
  }

  onPowerCollide(e) {
    // Called when object collides
    // Uses Cannon.js vectors
    if (BABYLON.Tags.HasTags(e.body) && e.body.matchesTagsQuery("hero") && e.body.parent.name != this.hero.name && this.collisionActive) {
        // e.body.parent is the hero that the object is colliding with
        try { // It has thrown an error once, idk why
          this.contactVelocity.copyFrom(this.mesh.physicsImpostor.getLinearVelocity());
        } catch(err) {
          this.contactVelocity.copyFrom(zeroVector);
        }

        // If it does not have a velocity calculate it.
        if ( this.contactVelocity.equals(zeroVector) ) {
          this.contactVelocity = this.vectorEnd.subtract(this.vectorStart);
          let magnitude = this.contactVelocity.length();
          this.contactVelocity.normalize().scaleInPlace(magnitude/this.range);
        }

        this.contactVelocity = this.babylonToCannonVector(this.contactVelocity);
        // apply the damage
        e.body.parent.takeDynamicDamage(this.damageMult, Math.abs(this.contactVelocity.dot(e.contact.ni)));
        this.collisionActive = false;
    }
  }

  babylonToCannonVector(babylonVec) {
      return new CANNON.Vec3(babylonVec.x, babylonVec.y, babylonVec.z);
  }
}
<|endoftext|>


<commit_before>frappe.provide('frappe.ui.form');

frappe.ui.form.quick_entry = function(doctype, success) {
	frappe.model.with_doctype(doctype, function() {
		var mandatory = $.map(frappe.get_meta(doctype).fields,
			function(d) { return (d.reqd || d.bold && !d.read_only) ? d : null });
		var meta = frappe.get_meta(doctype);

		var doc = frappe.model.get_new_doc(doctype, null, null, true);

		if(meta.quick_entry != 1) {
			frappe.set_route('Form', doctype, doc.name);
			return;
		}

		if(mandatory.length > 7) {
			// too many fields, show form
			frappe.set_route('Form', doctype, doc.name);
			return;
		}

		if($.map(mandatory, function(d) { return d.fieldtype==='Table' ? d : null }).length) {
			// has mandatory table, quit!
			frappe.set_route('Form', doctype, doc.name);
			return;
		}

		if(meta.autoname && meta.autoname.toLowerCase()==='prompt') {
			mandatory = [{fieldname:'__name', label:__('{0} Name', [meta.name]),
				reqd: 1, fieldtype:'Data'}].concat(mandatory);
		}

		var dialog = new frappe.ui.Dialog({
			title: __("New {0}", [doctype]),
			fields: mandatory,
		});

		var update_doc = function() {
			var data = dialog.get_values(true);
			$.each(data, function(key, value) {
				if(key==='__name') {
					dialog.doc.name = value;
				} else {
					if(!is_null(value)) {
						dialog.doc[key] = value;
					}
				}
			});
			return dialog.doc;
		}

		var open_doc = function() {
			dialog.hide();
			update_doc();
			frappe.set_route('Form', doctype, doc.name);
		}

		dialog.doc = doc;

		// refresh dependencies etc
		dialog.refresh();

		dialog.set_primary_action(__('Save'), function() {
			if(dialog.working) return;
			var data = dialog.get_values();

			if(data) {
				dialog.working = true;
				values = update_doc();
				frappe.call({
					method: "frappe.client.insert",
					args: {
						doc: values
					},
					callback: function(r) {
						dialog.hide();
						// delete the old doc
						frappe.model.clear_doc(dialog.doc.doctype, dialog.doc.name);
						var doc = r.message;
						if(success) {
							success(doc);
						}
						frappe.ui.form.update_calling_link(doc.name);
					},
					error: function() {
						open_doc();
					},
					always: function() {
						dialog.working = false;
					},
					freeze: true
				});
			}
		});

		var $link = $('
\
			Ctrl+enter to save | Edit in full page
').appendTo(dialog.body);

		$link.find('.edit-full').on('click', function() {
			// edit in form
			open_doc();
		});

		// ctrl+enter to save
		dialog.wrapper.keydown(function(e) {
			if((e.ctrlKey || e.metaKey) && e.which==13) {
				if(!frappe.request.ajax_count) {
					// not already working -- double entry
					dialog.get_primary_btn().trigger("click");
				}
			}
		});

		dialog.show();

		// set defaults
		$.each(dialog.fields_dict, function(fieldname, field) {
			field.doctype = doc.doctype;
			field.docname = doc.name;

			if(!is_null(doc[fieldname])) {
				field.set_input(doc[fieldname]);
			}
		});

	});
}<commit_msg>Translatable "Ctrl+enter to save" and "Edit in full window" in quick entry dialog (#2830)<commit_after>frappe.provide('frappe.ui.form');

frappe.ui.form.quick_entry = function(doctype, success) {
	frappe.model.with_doctype(doctype, function() {
		var mandatory = $.map(frappe.get_meta(doctype).fields,
			function(d) { return (d.reqd || d.bold && !d.read_only) ? d : null });
		var meta = frappe.get_meta(doctype);

		var doc = frappe.model.get_new_doc(doctype, null, null, true);

		if(meta.quick_entry != 1) {
			frappe.set_route('Form', doctype, doc.name);
			return;
		}

		if(mandatory.length > 7) {
			// too many fields, show form
			frappe.set_route('Form', doctype, doc.name);
			return;
		}

		if($.map(mandatory, function(d) { return d.fieldtype==='Table' ? d : null }).length) {
			// has mandatory table, quit!
			frappe.set_route('Form', doctype, doc.name);
			return;
		}

		if(meta.autoname && meta.autoname.toLowerCase()==='prompt') {
			mandatory = [{fieldname:'__name', label:__('{0} Name', [meta.name]),
				reqd: 1, fieldtype:'Data'}].concat(mandatory);
		}

		var dialog = new frappe.ui.Dialog({
			title: __("New {0}", [doctype]),
			fields: mandatory,
		});

		var update_doc = function() {
			var data = dialog.get_values(true);
			$.each(data, function(key, value) {
				if(key==='__name') {
					dialog.doc.name = value;
				} else {
					if(!is_null(value)) {
						dialog.doc[key] = value;
					}
				}
			});
			return dialog.doc;
		}

		var open_doc = function() {
			dialog.hide();
			update_doc();
			frappe.set_route('Form', doctype, doc.name);
		}

		dialog.doc = doc;

		// refresh dependencies etc
		dialog.refresh();

		dialog.set_primary_action(__('Save'), function() {
			if(dialog.working) return;
			var data = dialog.get_values();

			if(data) {
				dialog.working = true;
				values = update_doc();
				frappe.call({
					method: "frappe.client.insert",
					args: {
						doc: values
					},
					callback: function(r) {
						dialog.hide();
						// delete the old doc
						frappe.model.clear_doc(dialog.doc.doctype, dialog.doc.name);
						var doc = r.message;
						if(success) {
							success(doc);
						}
						frappe.ui.form.update_calling_link(doc.name);
					},
					error: function() {
						open_doc();
					},
					always: function() {
						dialog.working = false;
					},
					freeze: true
				});
			}
		});

		var $link = $('
' +
			__("Ctrl+enter to save") + ' | ' + __("Edit in full page") + '
').appendTo(dialog.body);

		$link.find('.edit-full').on('click', function() {
			// edit in form
			open_doc();
		});

		// ctrl+enter to save
		dialog.wrapper.keydown(function(e) {
			if((e.ctrlKey || e.metaKey) && e.which==13) {
				if(!frappe.request.ajax_count) {
					// not already working -- double entry
					dialog.get_primary_btn().trigger("click");
				}
			}
		});

		dialog.show();

		// set defaults
		$.each(dialog.fields_dict, function(fieldname, field) {
			field.doctype = doc.doctype;
			field.docname = doc.name;

			if(!is_null(doc[fieldname])) {
				field.set_input(doc[fieldname]);
			}
		});

	});
}
<|endoftext|>


<commit_before>/*
 * Kuali Coeus, a comprehensive research administration system for higher education.
 *
 * Copyright 2005-2015 Kuali, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
var Kc = Kc || {};
Kc.Inline = Kc.Inline || {};
(function(namespace, $) {
	namespace.determineElementWidth = function(element) {
		var charWidth = 0;
		if ($(element).is("input, textarea")) {
			charWidth = ($(element).val().length + 2) * 8;
		} else if ($(element).is("select")) {
			charWidth = ($(element).find("option:selected").text().length + 2) * 8 + 30;
		}
		if (charWidth < 40) {
			charWidth = 40;
		}
		return charWidth;
	};
	namespace.setWidth = function(element) {
		$(element).css("width", (namespace.determineElementWidth(element) + 'px'));
	};
	namespace.resetValue = function(element) {
		if ($(element).is("input, textarea")) {
			$(element).val(element.defaultValue);
		} else if ($(element).is("select")) {
			$(element).val($(element).find('option[selected]').attr('value'));
		}
	};
	namespace.setNewDefault = function(element) {
		if ($(element).is("input, textarea")) {
			element.defaultValue = $(element).val();
		} else if ($(element).is("select")) {
			$(element).find('option').each(function() {
				if ($(this).attr('value') === $(element).val()) {
					$(this).prop("selected", true);
				} else {
					$(this).prop("selected", false);
				}
			});
		}
	};
	namespace.init = function() {
		$("div.uif-inline input[type='text'], div.uif-inline select, div.uif-inline textarea").each(function () {
		    $(this).addClass("uif-hidden");
		    namespace.setWidth(this);
		    $(this).on("focus.KcInline", function () {
		        $(this).removeClass("uif-hidden");
		        $(this).css("width", "");
		    });
		    $(this).on("blur.KcInline", function () {
		        $(this).addClass("uif-hidden");
		        namespace.setNewDefault(this);
		        namespace.setWidth(this);
		    });
		    $(this).on("keydown.KcInline", function(event) {
				if (event.which == 27) {
					namespace.resetValue(this);
					$(this).blur();

				}
		    });
		});
	};
	$("[data-role='View']").on(kradVariables.EVENTS.UPDATE_CONTENT, namespace.init);

})(Kc.Inline, jQuery);

jQuery(document).ready(function() { Kc.Inline.init(); });
<commit_msg>KRACOEUS-8876:fix text area inline edit fieldwidth<commit_after>/*
 * Kuali Coeus, a comprehensive research administration system for higher education.
 *
 * Copyright 2005-2015 Kuali, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
var Kc = Kc || {};
Kc.Inline = Kc.Inline || {};
(function(namespace, $) {
	namespace.determineElementWidth = function(element) {
		var charWidth = 0;
		if ($(element).is("input")) {
			charWidth = ($(element).val().length + 2) * 8;
		} else if ($(element).is("textarea")) {
            charWidth = $(element).attr("cols") * 8;
        } else if ($(element).is("select")) {
			charWidth = ($(element).find("option:selected").text().length + 2) * 8 + 30;
		}
		if (charWidth < 40) {
			charWidth = 40;
		}
		return charWidth;
	};
	namespace.setWidth = function(element) {
		$(element).css("width", (namespace.determineElementWidth(element) + 'px'));
	};
	namespace.resetValue = function(element) {
		if ($(element).is("input, textarea")) {
			$(element).val(element.defaultValue);
		} else if ($(element).is("select")) {
			$(element).val($(element).find('option[selected]').attr('value'));
		}
	};
	namespace.setNewDefault = function(element) {
		if ($(element).is("input, textarea")) {
			element.defaultValue = $(element).val();
		} else if ($(element).is("select")) {
			$(element).find('option').each(function() {
				if ($(this).attr('value') === $(element).val()) {
					$(this).prop("selected", true);
				} else {
					$(this).prop("selected", false);
				}
			});
		}
	};
	namespace.init = function() {
		$("div.uif-inline input[type='text'], div.uif-inline select, div.uif-inline textarea").each(function () {
		    $(this).addClass("uif-hidden");
		    namespace.setWidth(this);
		    $(this).on("focus.KcInline", function () {
		        $(this).removeClass("uif-hidden");
		        $(this).css("width", "");
		    });
		    $(this).on("blur.KcInline", function () {
		        $(this).addClass("uif-hidden");
		        namespace.setNewDefault(this);
		        namespace.setWidth(this);
		    });
		    $(this).on("keydown.KcInline", function(event) {
				if (event.which == 27) {
					namespace.resetValue(this);
					$(this).blur();

				}
		    });
		});
	};
	$("[data-role='View']").on(kradVariables.EVENTS.UPDATE_CONTENT, namespace.init);

})(Kc.Inline, jQuery);

jQuery(document).ready(function() { Kc.Inline.init(); });
<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Component.extend({

  openConfirmRemove: false,

  actions: {
    cancel () {
      this.cleanErrors();

      this.get('organization').rollbackAttributes();
    },

    save () {
      let organization  = this.get('organization');

      organization.save().then(() => {

        this.cleanErrors();

        this.set('open', false);
      }).catch((error) => {
        this.set('organizationErrors', organization.get('errors'));
        this.set('requestErrors', error.errors);
      });
    },
  },

  cleanErrors () {
    this.set('organizationErrors', null);
    this.set('requestErrors', null);
  }
});
<commit_msg>Add note on error handling<commit_after>import Ember from 'ember';

export default Ember.Component.extend({

  openConfirmRemove: false,

  actions: {
    cancel () {
      this.cleanErrors();

      this.get('organization').rollbackAttributes();
    },

    save () {
      let organization  = this.get('organization');

      organization.save().then(() => {

        this.cleanErrors();

        this.set('open', false);
      }).catch((error) => {
        /* TODO
         * Better handling of errors
         * Currently it is dealing with
         * AdapterError.errors // => ["You need to sign in...."]
         * but also there are:
         * ErrorClass.errors // => [{ detail: 'The adapter ... invalid', title: 'AdapterError'}]
         * but maybe these should be prevented on client
         */
        this.set('organizationErrors', organization.get('errors'));
        this.set('requestErrors', error.errors);
      });
    },
  },

  cleanErrors () {
    this.set('organizationErrors', null);
    this.set('requestErrors', null);
  }
});
<|endoftext|>


<commit_before>'use strict';

describe('Controller for Admin Page...', function() {
    beforeEach(module('umm3601ursamajorApp'));
    beforeEach(module('socketMock'));
    beforeEach(module('authMock'));

    var AdminCtrl, scope;

    beforeEach(inject(function($controller, $rootScope) {
        scope = $rootScope.$new();
        AdminCtrl = $controller('AdminCtrl', {
            $scope: scope
        });
    }));

    beforeEach(function(){
        scope.submissions = [
            {
                _id: "uniqueIdString",
                title: "A Study of the Properties of a Paperclip in the Digestive System of a Sloth",
                format: "Artist Statement",
                abstract: "Many physicists would agree that, had it not been for scatter/gather I/O, the study of link-level acknowledgements might never have occurred. " +
                    "While such a claim might seem unexpected, it usually conflicts with the need to provide thin clients to hackers worldwide. " +
                    "In fact, few security experts would disagree with the construction of kernels. In order to overcome this question, we construct an analysis of the Ethernet (Mollah)," +
                    " which we use to prove that redundancy and replication can interfere to achieve this aim. ",
                presentationType: "Oral Presentation",
                formatChange: false,
                presenterInfo: {first: "Hongya", last: "Zhou", email: "zhoux616@morris.umn.edu"},
                copresenterOneInfo: {first: "Otto", last: "Marckel II", email: "marck018@morris.umn.edu"},
                copresenterTwoInfo: {first: "Dalton", last: "Gusaas", email: "gusaa004@morris.umn.edu"},
                discipline: "Biology",
                sponsors: [], //Might need to worry about if this is static for the DB later.
                adviserInfo: {first: "Maggie", last: "Casale", email: "casal033@morris.umn.edu"},
                featured: false,
                mediaServicesEquipment: "",
                specialRequirements: "a sloth",
                presenterTeeSize: "M",
                otherInfo: "Maybe",
                approval: false,
                status: {strict: "Awaiting Adviser Approval", text: "Your adviser has yet to approve this submission."},
                timestamp: "Mon Oct 20 2014 1:48:54 GMT-0500 (CDT)",
                group: 3,
                resubmissionData: {comment: "Initial Submission", parentSubmission: "testIdForTesting", isPrimary: false, resubmitFlag: false},
                comments: []
            }, {
                _id: "testIdForTesting",
                title: "Blind Construction: Mixed Media",
                format: "Artist Statement",
                abstract: "The basis of this project was to create a garment using mixed media in order to mimic the human body. " +
                    "The materials we used to create this piece include: buckram, copper wire, spray paint, fabric paint, a variety of novelty fabrics, and chains.  " +
                    "The techniques we created in order to manipulate the piece include: fabric branding and burning, grid painting, sewing, draping, molding buckram, and coiling.  " +
                    "Our overall approach was to create a theatrical wearable art piece. " +
                    "Upon completion of the assignment we found the piece aesthetically pleasing because of the way it molds to the human body, but can be a piece all on its own.",
                presentationType: "Performance",
                formatChange: false,
                presenterInfo: {first: "Jacob", last: "Opdahl", email: "opdah023@morris.umn.edu"},
                copresenterOneInfo: {first: "Savannah", last: "Farm", email: "farmx009@morris.umn.edu"},
                copresenterTwoInfo: {first: "Maggie", last: "Casale", email: "casal033@morris.umn.edu"},
                discipline: "Art History",
                sponsors: [],
                adviserInfo: {first: "Mark", last: "Lehet", email: "lehet005@morris.umn.edu"},
                featured: true,
                mediaServicesEquipment: "",
                specialRequirements: "A space to perform with three people.",
                presenterTeeSize: "M",
                otherInfo: "",
                approval: true,
                status: {strict: "Revisions Needed", text: "Your URS submission has been flagged for revisions, and is in need of changes."},
                timestamp: "Tue Oct 21 2014 23:22:54 GMT-0500 (CDT)",
                group: 1,
                resubmissionData: {comment: "Initial Submission", parentSubmission: "", isPrimary: true, resubmitFlag: false},
                comments:[]
            }
        ];

        scope.users = [
            {email: "admin@admin.com", role: "admin", group: 1},
            {email: "user_0@user.com", role: "chair", group: 3},
            {email: "user_1@user.com", role: "user", group: 2}
        ]
    });

    it('1 should equal 1...', function () {
        expect(1).toEqual(1);
    });

//----------------------- Trying to test data in mongo --------------//
/*    describe('Getting Data from Mongo Functions', function(){
      it('getting user data', function() {
        $http.get('/api/users').success(function(users);
        expect(scope.users).toEqual(users);
      });
    });*/

    describe('system info functions...', function() {
        it('Total # of tracked submissions', function() {
          expect(scope.trackedSubmissions()).toEqual(1);
        });

        it('Total # of submissions in system should be accurate', function() {
           expect(scope.totalSubmissions()).toEqual(2);
        });

       it('Total percentage of tracked submissions', function() {
          expect(scope.precentageTracked()).toEqual(50);
        });

        it('Total # of registered users should be accurate', function() {
            expect(scope.totalUsers()).toEqual(3);
        });

        it('Total # of resubmitflags', function() {
          expect(scope.resubmitFlags()).toEqual(0);
        });

        it('Total # of resubmitflags', function() {
          expect(scope.unapprovedResubmits()).toEqual(1);
        });
    });

    describe('functions affecting the view...', function() {
        it('default view should be statistics view', function(){
            expect(scope.toggles.statsToggle).toEqual(true);
        });

        it('resetToggles should reset the view completely', function(){
            scope.resetToggles();
            for(var key in scope.toggles){
                if (scope.toggles.hasOwnProperty(key)){
                    expect(scope.toggles[key]).toEqual(false);
                }
            }
        });

    });

    //TODO: Apparently testing things based on $location is a bit complicated. Someone should look into it.
//    it("should redirect non admins to the home page", inject( function(Auth, $location){
//        Auth.setCurrentUser("user_1@user.com", "user", 1);
//        $location.path('/admin');
//        expect($location.path()).toEqual('/');
//    }));
//
//    it("should allow admins to view the page", inject(function(Auth, $location){
//        Auth.setCurrentUser("admin@admin.com", "admin", 3);
//        $location.path('/admin');
//        expect($location.path()).toEqual('/admin');
//    }));

});
<commit_msg>Added more tests for the admin page<commit_after>'use strict';

describe('Controller for Admin Page...', function() {
    beforeEach(module('umm3601ursamajorApp'));
    beforeEach(module('socketMock'));
    beforeEach(module('authMock'));

    var AdminCtrl, scope;

    beforeEach(inject(function($controller, $rootScope) {
        scope = $rootScope.$new();
        AdminCtrl = $controller('AdminCtrl', {
            $scope: scope
        });
    }));

    beforeEach(function(){
        scope.submissions = [
            {
                _id: "uniqueIdString",
                title: "A Study of the Properties of a Paperclip in the Digestive System of a Sloth",
                format: "Artist Statement",
                abstract: "Many physicists would agree that, had it not been for scatter/gather I/O, the study of link-level acknowledgements might never have occurred. " +
                    "While such a claim might seem unexpected, it usually conflicts with the need to provide thin clients to hackers worldwide. " +
                    "In fact, few security experts would disagree with the construction of kernels. In order to overcome this question, we construct an analysis of the Ethernet (Mollah)," +
                    " which we use to prove that redundancy and replication can interfere to achieve this aim. ",
                presentationType: "Oral Presentation",
                formatChange: false,
                presenterInfo: {first: "Hongya", last: "Zhou", email: "zhoux616@morris.umn.edu"},
                copresenterOneInfo: {first: "Otto", last: "Marckel II", email: "marck018@morris.umn.edu"},
                copresenterTwoInfo: {first: "Dalton", last: "Gusaas", email: "gusaa004@morris.umn.edu"},
                discipline: "Biology",
                sponsors: [], //Might need to worry about if this is static for the DB later.
                adviserInfo: {first: "Maggie", last: "Casale", email: "casal033@morris.umn.edu"},
                featured: false,
                mediaServicesEquipment: "",
                specialRequirements: "a sloth",
                presenterTeeSize: "M",
                otherInfo: "Maybe",
                approval: false,
                status: {strict: "Awaiting Adviser Approval", text: "Your adviser has yet to approve this submission."},
                timestamp: "Mon Oct 20 2014 1:48:54 GMT-0500 (CDT)",
                group: 3,
                resubmissionData: {comment: "Initial Submission", parentSubmission: "testIdForTesting", isPrimary: false, resubmitFlag: false},
                comments: []
            }, {
                _id: "testIdForTesting",
                title: "Blind Construction: Mixed Media",
                format: "Artist Statement",
                abstract: "The basis of this project was to create a garment using mixed media in order to mimic the human body. " +
                    "The materials we used to create this piece include: buckram, copper wire, spray paint, fabric paint, a variety of novelty fabrics, and chains.  " +
                    "The techniques we created in order to manipulate the piece include: fabric branding and burning, grid painting, sewing, draping, molding buckram, and coiling.  " +
                    "Our overall approach was to create a theatrical wearable art piece. " +
                    "Upon completion of the assignment we found the piece aesthetically pleasing because of the way it molds to the human body, but can be a piece all on its own.",
                presentationType: "Performance",
                formatChange: false,
                presenterInfo: {first: "Jacob", last: "Opdahl", email: "opdah023@morris.umn.edu"},
                copresenterOneInfo: {first: "Savannah", last: "Farm", email: "farmx009@morris.umn.edu"},
                copresenterTwoInfo: {first: "Maggie", last: "Casale", email: "casal033@morris.umn.edu"},
                discipline: "Art History",
                sponsors: [],
                adviserInfo: {first: "Mark", last: "Lehet", email: "lehet005@morris.umn.edu"},
                featured: true,
                mediaServicesEquipment: "",
                specialRequirements: "A space to perform with three people.",
                presenterTeeSize: "M",
                otherInfo: "",
                approval: true,
                status: {strict: "Revisions Needed", text: "Your URS submission has been flagged for revisions, and is in need of changes."},
                timestamp: "Tue Oct 21 2014 23:22:54 GMT-0500 (CDT)",
                group: 1,
                resubmissionData: {comment: "Initial Submission", parentSubmission: "", isPrimary: true, resubmitFlag: false},
                comments:[]
            }
        ];

        scope.users = [
            {email: "admin@admin.com", role: "admin", group: 1},
            {email: "user_0@user.com", role: "chair", group: 3},
            {email: "user_1@user.com", role: "user", group: 2}
        ]
    });

    it('1 should equal 1...', function () {
        expect(1).toEqual(1);
    });

//----------------------- Trying to test data in mongo --------------//

    describe('system info functions...', function() {
        it('Total # of tracked submissions', function() {
          expect(scope.trackedSubmissions()).toEqual(1);
        });

        it('Total # of submissions in system should be accurate', function() {
           expect(scope.totalSubmissions()).toEqual(2);
        });

       it('Total percentage of tracked submissions', function() {
          expect(scope.precentageTracked()).toEqual(50);
        });

        it('Total # of registered users should be accurate', function() {
            expect(scope.totalUsers()).toEqual(3);
        });

        it('Total # of resubmitflags', function() {
          expect(scope.resubmitFlags()).toEqual(0);
        });

        it('Total # of resubmitflags', function() {
          expect(scope.unapprovedResubmits()).toEqual(1);
        });
    });

  //----------------------------- Nav Control ---------------------------//

  describe('functions affecting the view...', function() {
        it('default view should be statistics view', function(){
          expect(scope.toggles.statsToggle).toEqual(true);
          expect(scope.toggles.subFormEditorToggle).toEqual(false);
          expect(scope.toggles.userEditToggle).toEqual(false);
          expect(scope.toggles.statusEditToggle).toEqual(false);
          expect(scope.toggles.abstractBookToggle).toEqual(false);
          expect(scope.toggles.subListToggle).toEqual(false);

        });

        it('resetToggles should reset the view completely', function(){
            scope.resetToggles();
            for(var key in scope.toggles){
                if (scope.toggles.hasOwnProperty(key)){
                    expect(scope.toggles[key]).toEqual(false);
                }
            }
        });

        it('toggling sublist', function() {
            scope.toggles.subListToggle();
            scope.resetToggles();
            expect(scope.toggles.subListToggle).toEqual(true);
        });

    });

    //TODO: Apparently testing things based on $location is a bit complicated. Someone should look into it.
//    it("should redirect non admins to the home page", inject( function(Auth, $location){
//        Auth.setCurrentUser("user_1@user.com", "user", 1);
//        $location.path('/admin');
//        expect($location.path()).toEqual('/');
//    }));
//
//    it("should allow admins to view the page", inject(function(Auth, $location){
//        Auth.setCurrentUser("admin@admin.com", "admin", 3);
//        $location.path('/admin');
//        expect($location.path()).toEqual('/admin');
//    }));

});
<|endoftext|>


<commit_before>/*
 test-driven-008
 Test drive the javascript as well
 Since all of the require.js modules expose constructors rather than implementations
 I have an opportunity to override the collaborators with stubs/fakes/mocks
 I also rely on a "helper" class to make the tests easier to understand at a high level
 by delegating low level details to the helper

 Notice that the implementation gets its html from design showcase rather than templates
 This ensures that the appearance matches what the customer agreed to

 Although it is not complete yet, the sample http requests/responses will eventually come from a separate "specification" project
 This ensures that when the contract between the application and the persistence service changes, there are tests that catch the mismatch
 */

define(['qunit', 'tasks', 'fake-http', 'marshalling', 'node-util', 'text!todo-list-style-showcase.html'],
    (qunit, createTasks, createHttp, createMarshalling, createNodeUtil, template) => {
        'use strict';
        qunit.module('task');

        var marshalling = createMarshalling();
        var httpGetNoTasks = {
            request: {
                url: 'database/task',
                method: 'GET'
            },
            response: {
                status: 200,
                body: ''
            }
        };
        var selectExactlyOne = (dom, selector) => {
            var nodes = dom.querySelectorAll(selector);
            if (nodes.length === 1) {
                return nodes[0];
            } else {
                throw 'Expected exactly one match for ' + selector + ' got ' + nodes.length;
            }
        };

        var howManyExist = (dom, selector) => {
            var nodes = dom.querySelectorAll(selector);
            return nodes.length;
        };

        var isChecked = (dom, selector) => {
            return dom.querySelectorAll(selector + ':checked').length === 1
        };

        var toggleCheckbox = checkbox => {
            checkbox.checked = !checkbox.checked;
            var event = document.createEvent("HTMLEvents");
            event.initEvent("change", false, true);
            return checkbox.dispatchEvent(event);
        };

        var sendKeyUp = (target, key) => {
            var event = document.createEvent("HTMLEvents");
            event.initEvent("keyup", false, true);
            event.which = key;
            return target.dispatchEvent(event);
        };

        var createHelper = () => {
            var http = createHttp();
            var tasks = createTasks({
                http: http,
                marshalling: marshalling,
                nodeUtil: createNodeUtil(),
                template: template
            });
            var dom;
            var render = () => {
                return tasks.render().then(renderedDom => dom = renderedDom)
            };
            var userPressesAddTaskButton = () => {
                return tasks.addButtonClick();
            };
            var userPressesClearDoneButton = () => {
                return tasks.clearButtonClick();
            };
            var userTogglesDoneCheckboxForId = id => {
                var element = selectExactlyOne(dom, '[data-id="' + id + '"] .checkbox-task-done');
                return toggleCheckbox(element);
            };
            var userTypesTaskName = taskName => {
                selectExactlyOne(dom, '.input-task-name').value = taskName;
            };
            var userPressesKey = whichKey => {
                var element = selectExactlyOne(dom, '.input-task-name');
                return sendKeyUp(element, whichKey);
            };
            var taskElementToTask = taskElement => {
                var name = selectExactlyOne(taskElement, '.label-task-name').textContent;
                var done = isChecked(taskElement, '.checkbox-task-done');
                var id = marshalling.stringToInt(taskElement.dataset.id);
                return {
                    id: id,
                    name: name,
                    done: done
                };
            };
            var tasksDisplayedToUser = () => {
                var taskElements = dom.querySelectorAll('.list-item-task');
                var tasks = Array.prototype.map.call(taskElements, taskElementToTask);
                return tasks;
            };
            var contract = {
                render: render,
                userTypesTaskName: userTypesTaskName,
                addRequestResponsePair: http.addRequestResponsePair,
                userPressesAddTaskButton: userPressesAddTaskButton,
                userPressesClearDoneButton: userPressesClearDoneButton,
                userTogglesDoneCheckboxForId: userTogglesDoneCheckboxForId,
                userPressesKey: userPressesKey,
                tasksDisplayedToUser: tasksDisplayedToUser,
                unconsumedRequestResponsePairs: http.unconsumedRequestResponsePairs
            };
            return contract;
        };

        qunit.test("render empty", assert => {
            var helper = createHelper();
            helper.addRequestResponsePair(httpGetNoTasks);
            assert.expect(8);
            var done = assert.async();
            var verify = dom => {
                assert.equal(dom.querySelectorAll('.list-item-task').length, 0, 'No tasks');
                assert.equal(helper.unconsumedRequestResponsePairs().length, 0, 'No unconsumed http requests');
                assert.equal(selectExactlyOne(dom, 'h1').textContent, 'Todo List', 'title');
                assert.equal(selectExactlyOne(dom, '.input-task-name').value, '', 'task name starts out empty');
                assert.equal(selectExactlyOne(dom, '.button-add-task').innerText, 'Add Task', 'add task button exists');
                assert.equal(howManyExist(dom, '.list-tasks'), 1, 'task list exists');
                assert.equal(selectExactlyOne(dom, '.button-clear-done').innerText, 'Clear Done', 'clear done button exists');
                assert.deepEqual(helper.tasksDisplayedToUser(), [], 'Added task');
                done();
            };
            helper.render().then(verify);
        });

        qunit.test("render tasks", assert => {
            var helper = createHelper();
            var httpGetThreeSampleTasks = {
                request: {
                    url: 'database/task',
                    method: 'GET'
                },
                response: {
                    status: 200,
                    body: '1 false Task A\n2 true Task B\n3 false Task C'
                }
            };
            helper.addRequestResponsePair(httpGetThreeSampleTasks);
            assert.expect(2);
            var done = assert.async();
            var verify = dom => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'Task A',
                    done: false
                }, {
                    id: 2,
                    name: 'Task B',
                    done: true
                }, {
                    id: 3,
                    name: 'Task C',
                    done: false
                }], 'All three sample tasks found');
                assert.equal(helper.unconsumedRequestResponsePairs().length, 0, 'No unconsumed http requests');
                done();
            };
            helper.render().then(verify);
        });

        qunit.test("add item using button", assert => {
            var helper = createHelper();
            helper.addRequestResponsePair(httpGetNoTasks);
            var addUser = () => {
                helper.userTypesTaskName('Some Task');
                helper.addRequestResponsePair({
                    request: {
                        url: 'database/task-event',
                        method: 'POST',
                        body: 'add Some Task'
                    },
                    response: {
                        status: 201,
                        body: '1 false Some Task'
                    }
                });
                return helper.userPressesAddTaskButton();
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'Some Task',
                    done: false
                }], 'Added task');
                assert.equal(helper.unconsumedRequestResponsePairs().length, 0, 'No unconsumed http requests');
                done();
            };
            helper.render().then(addUser).then(verify);
        });

        qunit.test("add item using enter key", assert => {
            var helper = createHelper();
            helper.addRequestResponsePair(httpGetNoTasks);
            var enterKey = 13;
            var addUser = () => {
                helper.userTypesTaskName('Some Task');
                helper.addRequestResponsePair({
                    request: {
                        url: 'database/task-event',
                        method: 'POST',
                        body: 'add Some Task'
                    },
                    response: {
                        status: 201,
                        body: '1 false Some Task'
                    }
                });
                return helper.userPressesKey(enterKey);
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'Some Task',
                    done: false
                }], 'Added task');
                assert.equal(helper.unconsumedRequestResponsePairs().length, 0, 'No unconsumed http requests');
                done();
            };
            helper.render().then(addUser).then(verify);
        });

        qunit.test("clear done", assert => {
            var helper = createHelper();
            var taskDoneAndTaskNotDone = {
                request: {
                    url: 'database/task',
                    method: 'GET'
                },
                response: {
                    status: 200,
                    body: '1 false This is not done\n2 true This is done'
                }
            };
            helper.addRequestResponsePair(taskDoneAndTaskNotDone);
            var clearDone = () => {
                helper.addRequestResponsePair({
                    request: {
                        url: 'database/task-event',
                        method: 'POST',
                        body: 'clear'
                    },
                    response: {
                        status: 200
                    }
                });
                helper.addRequestResponsePair({
                    request: {
                        url: 'database/task',
                        method: 'GET'
                    },
                    response: {
                        status: 200,
                        body: '1 false This is not done'
                    }
                });
                return helper.userPressesClearDoneButton();
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'This is not done',
                    done: false
                }], 'Done task cleared');
                assert.equal(helper.unconsumedRequestResponsePairs().length, 0, 'No unconsumed http requests');
                done();
            };
            helper.render().then(clearDone).then(verify);
        });

        qunit.test("set done", assert => {
            var helper = createHelper();
            var taskDoneAndTaskNotDone = {
                request: {
                    url: 'database/task',
                    method: 'GET'
                },
                response: {
                    status: 200,
                    body: '1 false This started out not done'
                }
            };
            helper.addRequestResponsePair(taskDoneAndTaskNotDone);
            var setDone = () => {
                helper.addRequestResponsePair({
                    request: {
                        url: 'database/task-event',
                        method: 'POST',
                        body: 'done 1'
                    },
                    response: {
                        status: 200
                    }
                });
                return helper.userTogglesDoneCheckboxForId(1);
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'This started out not done',
                    done: true
                }], 'Done toggled to true');
                assert.equal(helper.unconsumedRequestResponsePairs().length, 0, 'No unconsumed http requests');
                done();
            };
            helper.render().then(setDone).then(verify);
        });

        qunit.test("unset done", assert => {
            var helper = createHelper();
            var taskDoneAndTaskNotDone = {
                request: {
                    url: 'database/task',
                    method: 'GET'
                },
                response: {
                    status: 200,
                    body: '1 true This started out done'
                }
            };
            helper.addRequestResponsePair(taskDoneAndTaskNotDone);
            var setDone = () => {
                helper.addRequestResponsePair({
                    request: {
                        url: 'database/task-event',
                        method: 'POST',
                        body: 'undone 1'
                    },
                    response: {
                        status: 200
                    }
                });
                return helper.userTogglesDoneCheckboxForId(1);
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'This started out done',
                    done: false
                }], 'Done toggled to false');
                assert.equal(helper.unconsumedRequestResponsePairs().length, 0, 'No unconsumed http requests');
                done();
            };
            helper.render().then(setDone).then(verify);
        });
    }
);
<commit_msg>Reworked test-task to account for using tasks-persistence-api instead of direct http calls<commit_after>/*
 test-driven-008
 Test drive the javascript as well
 Since all of the require.js modules expose constructors rather than implementations
 I have an opportunity to override the collaborators with stubs/fakes/mocks
 I also rely on a "helper" class to make the tests easier to understand at a high level
 by delegating low level details to the helper

 Notice that the implementation gets its html from design showcase rather than templates
 This ensures that the appearance matches what the customer agreed to

 Using a fake persistence api for the tasks allows us to decouple http concerns from gui concerns.
 */

define(['qunit', 'tasks', 'marshalling', 'node-util', 'text!todo-list-style-showcase.html'],
    (qunit, createTasks, createMarshalling, createNodeUtil, template) => {
        'use strict';
        qunit.module('task');

        var createTasksPersistenceApi = () => {
            var tasks = [];
            var addResult;
            var undoneInvocations = [];
            var clearInvocationCount = 0;
            var doneInvocations = [];
            var addInvocations = [];
            return {
                list: () => {
                    return Promise.resolve(tasks);
                },
                add: name => {
                    addInvocations.push(name);
                    return Promise.resolve(addResult);
                },
                undone: id => {
                    undoneInvocations.push(id);
                },
                done: id => {
                    doneInvocations.push(id);
                },
                clear: () => {
                    clearInvocationCount++;
                    return Promise.resolve();
                },
                addSampleTask: task => tasks.push(task),
                setSampleAddResult: result => {
                    addResult = result
                },
                clearInvocationCount: () => {
                    return clearInvocationCount
                },
                doneInvocations: () => {
                    return doneInvocations
                },
                undoneInvocations: () => {
                    return undoneInvocations
                },
                addInvocations: () => {
                    return addInvocations
                }
            };
        };
        var marshalling = createMarshalling();
        var selectExactlyOne = (dom, selector) => {
            var nodes = dom.querySelectorAll(selector);
            if (nodes.length === 1) {
                return nodes[0];
            } else {
                throw 'Expected exactly one match for ' + selector + ' got ' + nodes.length;
            }
        };

        var howManyExist = (dom, selector) => {
            var nodes = dom.querySelectorAll(selector);
            return nodes.length;
        };

        var isChecked = (dom, selector) => {
            return dom.querySelectorAll(selector + ':checked').length === 1
        };

        var toggleCheckbox = checkbox => {
            checkbox.checked = !checkbox.checked;
            var event = document.createEvent("HTMLEvents");
            event.initEvent("change", false, true);
            return checkbox.dispatchEvent(event);
        };

        var sendKeyUp = (target, key) => {
            var event = document.createEvent("HTMLEvents");
            event.initEvent("keyup", false, true);
            event.which = key;
            return target.dispatchEvent(event);
        };

        var createHelper = () => {
            var tasksPersistenceApi = createTasksPersistenceApi();
            var nodeUtil = createNodeUtil();
            var tasks = createTasks({
                tasksPersistenceApi: tasksPersistenceApi,
                nodeUtil: nodeUtil,
                template: template
            });
            var dom;
            var render = () => {
                return tasks.render().then(renderedDom => dom = renderedDom)
            };
            var userPressesAddTaskButton = () => {
                return tasks.addButtonClick();
            };
            var userPressesClearDoneButton = () => {
                return tasks.clearButtonClick();
            };
            var userTogglesDoneCheckboxForId = id => {
                var element = selectExactlyOne(dom, '[data-id="' + id + '"] .checkbox-task-done');
                return toggleCheckbox(element);
            };
            var userTypesTaskName = taskName => {
                selectExactlyOne(dom, '.input-task-name').value = taskName;
            };
            var userPressesKey = whichKey => {
                var element = selectExactlyOne(dom, '.input-task-name');
                return sendKeyUp(element, whichKey);
            };
            var taskElementToTask = taskElement => {
                var name = selectExactlyOne(taskElement, '.label-task-name').textContent;
                var done = isChecked(taskElement, '.checkbox-task-done');
                var id = marshalling.stringToInt(taskElement.dataset.id);
                return {
                    id: id,
                    name: name,
                    done: done
                };
            };
            var tasksDisplayedToUser = () => {
                var taskElements = dom.querySelectorAll('.list-item-task');
                var tasks = Array.prototype.map.call(taskElements, taskElementToTask);
                return tasks;
            };
            var contract = {
                render: render,
                userTypesTaskName: userTypesTaskName,
                userPressesAddTaskButton: userPressesAddTaskButton,
                userPressesClearDoneButton: userPressesClearDoneButton,
                userTogglesDoneCheckboxForId: userTogglesDoneCheckboxForId,
                userPressesKey: userPressesKey,
                tasksDisplayedToUser: tasksDisplayedToUser,
                tasksPersistenceApi: tasksPersistenceApi
            };
            return contract;
        };

        qunit.test("render empty", assert => {
            var helper = createHelper();
            assert.expect(7);
            var done = assert.async();
            var verify = dom => {
                assert.equal(dom.querySelectorAll('.list-item-task').length, 0, 'No tasks');
                assert.equal(selectExactlyOne(dom, 'h1').textContent, 'Todo List', 'title');
                assert.equal(selectExactlyOne(dom, '.input-task-name').value, '', 'task name starts out empty');
                assert.equal(selectExactlyOne(dom, '.button-add-task').innerText, 'Add Task', 'add task button exists');
                assert.equal(howManyExist(dom, '.list-tasks'), 1, 'task list exists');
                assert.equal(selectExactlyOne(dom, '.button-clear-done').innerText, 'Clear Done', 'clear done button exists');
                assert.deepEqual(helper.tasksDisplayedToUser(), [], 'Added task');
                done();
            };
            helper.render().then(verify);
        });

        qunit.test("render tasks", assert => {
            var helper = createHelper();
            helper.tasksPersistenceApi.addSampleTask({
                "done": false,
                "id": 1,
                "name": "Task A"
            });
            helper.tasksPersistenceApi.addSampleTask({
                "done": true,
                "id": 2,
                "name": "Task B"
            });
            helper.tasksPersistenceApi.addSampleTask({
                "done": false,
                "id": 3,
                "name": "Task C"
            });
            assert.expect(1);
            var done = assert.async();
            var verify = dom => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'Task A',
                    done: false
                }, {
                    id: 2,
                    name: 'Task B',
                    done: true
                }, {
                    id: 3,
                    name: 'Task C',
                    done: false
                }], 'All three sample tasks found');
                done();
            };
            helper.render().then(verify);
        });

        qunit.test("add item using button", assert => {
            var helper = createHelper();
            helper.tasksPersistenceApi.setSampleAddResult({
                id: 1,
                name: 'Some Task',
                done: false
            });
            var addUser = () => {
                helper.userTypesTaskName('Some Task');
                return helper.userPressesAddTaskButton();
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'Some Task',
                    done: false
                }], 'Added task');
                assert.deepEqual(helper.tasksPersistenceApi.addInvocations(), ['Some Task'], 'add invoked');
                done();
            };
            helper.render().then(addUser).then(verify);
        });

        qunit.test("add item using enter key", assert => {
            var helper = createHelper();
            helper.tasksPersistenceApi.setSampleAddResult({
                id: 1,
                name: 'Some Task',
                done: false
            });
            var enterKey = 13;
            var addUser = () => {
                helper.userTypesTaskName('Some Task');
                return helper.userPressesKey(enterKey);
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'Some Task',
                    done: false
                }], 'Added task');
                assert.deepEqual(helper.tasksPersistenceApi.addInvocations(), ['Some Task'], 'add invoked');
                done();
            };
            helper.render().then(addUser).then(verify);
        });

        qunit.test("clear all tasks that are done", assert => {
            var helper = createHelper();
            helper.tasksPersistenceApi.addSampleTask({
                "done": false,
                "id": 1,
                "name": "This is not done"
            });
            var clearDone = () => {
                return helper.userPressesClearDoneButton();
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'This is not done',
                    done: false
                }], 'Done task cleared');
                assert.equal(helper.tasksPersistenceApi.clearInvocationCount(), 1, 'clear invoked')
                done();
            };
            helper.render().then(clearDone).then(verify);
        });

        qunit.test("set done", assert => {
            var helper = createHelper();
            helper.tasksPersistenceApi.addSampleTask({
                id: 1,
                name: 'This started out not done',
                done: false
            });
            var setDone = () => {
                return helper.userTogglesDoneCheckboxForId(1);
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'This started out not done',
                    done: true
                }], 'Done toggled to true');
                assert.deepEqual(helper.tasksPersistenceApi.doneInvocations(), [1], 'done invoked')
                done();
            };
            helper.render().then(setDone).then(verify);
        });

        qunit.test("unset done", assert => {
            var helper = createHelper();
            helper.tasksPersistenceApi.addSampleTask({
                id: 1,
                name: 'This started out done',
                done: true
            });
            var setDone = () => {
                return helper.userTogglesDoneCheckboxForId(1);
            };
            assert.expect(2);
            var done = assert.async();
            var verify = () => {
                assert.deepEqual(helper.tasksDisplayedToUser(), [{
                    id: 1,
                    name: 'This started out done',
                    done: false
                }], 'Done toggled to false');
                assert.deepEqual(helper.tasksPersistenceApi.undoneInvocations(), [1], 'undone invoked')
                done();
            };
            helper.render().then(setDone).then(verify);
        });
    }
);
<|endoftext|>


<commit_before>'use strict';

angular.module('hrr10MjbeApp')
  .config(function ($stateProvider) {
    $stateProvider
      .state('classprogress', {
        url: '/classprogress/',
        templateUrl: 'app/classprogress/classprogress.html',
        controller: 'ClassprogressCtrl'
      });
  });
<commit_msg>fix routing bug<commit_after>'use strict';

angular.module('hrr10MjbeApp')
  .config(function ($stateProvider) {
    $stateProvider
      .state('classprogress', {
        url: '/classprogress/:id',
        templateUrl: 'app/classprogress/classprogress.html',
        controller: 'ClassprogressCtrl'
      });
  });
<|endoftext|>


<commit_before>'use strict';

/**
 * After applying this directive element.board will be chess board (chessboard.js)
 * and element.game will be chess game (chess.js)
 * Also drag and drop functions will be defined.
 * This small library is useful for separating drag&drop logic and application logic
 */
playzoneControllers.directive('chessBoardLegal', function (SettingService) {
    function isMyTurn(scope, element) {
        return element.game.turn() === scope.game.color;
    }

    function doMoveOnTheBoard(scope, element, to) {
        scope.current_move.to = to; // move by click&click
        scope.current_move.promotion = 'q'; // NOTE: always promote to a queen for example simplicity

        if (!element.game.move(scope.current_move)) {
            scope.current_move.to = false;
            scope.pre_move = false;
            return;
        }

        scope.game.pgn = element.game.pgn();

        if (!element.board) {
            return;
        }

        element.board.position(element.game.fen());
        element.updateStatus();
        element.onMove(scope.current_move);
    }

    function moveByOneClick(element, square, scope) {
        if (!isMyTurn(scope, element)) {
            return;
        }

        var legalMoves = element.game.moves({verbose: true});

        var isSingleOptionToMoveHere = false;

        $.each(
            legalMoves,
            function (index, value) {
                if (value.to === square) {
                    if (isSingleOptionToMoveHere) {
                        isSingleOptionToMoveHere = false;
                        scope.current_move = false;
                        return false;
                    } else {
                        isSingleOptionToMoveHere = true;
                        scope.current_move = {
                            from: value.from
                        };
                        console.log('test');
                    }
                }
            }
        );

        if (isSingleOptionToMoveHere) {
            doMoveOnTheBoard(scope, element, square);
            return true;
        } else {
            return false;
        }
    }

    return {
        restrict: 'C',
        link: function(scope, element) {
            element.game = new Chess();

            var statusEl = $(element).find('.status'),
                fenEl = $(element).find('.fen'),
                pgnEl = $(element).find('.pgn');

            var highlightSquare = function (square) {
                $(element).find('[class*="square"]').removeClass(scope.boardConfig.highlightClass);
                $(element).find('.square-' + square).addClass(scope.boardConfig.highlightClass);
            };

            // do not pick up pieces if the game is over
            // only pick up pieces for the side to move
            var onDragStart = function(source, piece, position, orientation) {
                if (scope.game.status !== 'play' || !scope.game.mine || !element.isMyMove(piece)) {
                    return false;
                }

                if (!scope.current_move) {
                    scope.current_move = { from: source }; // for move click&click
                } else {
                    doMoveOnTheBoard(scope, element, source);
                    return true;
                }

                return !scope.pre_move;
            };

            var onDrop = function(source, target) {
                if (element.game.turn() !== scope.game.color) {
                    // pre-move functionality for draggable
                    scope.pre_move = {from: source, to: target};
                }
                // see if the move is legal
                var moveObject = {
                    from: source,
                    to: target,
                    promotion: 'q' // NOTE: always promote to a queen for example simplicity
                };
                var move = element.game.move(moveObject);

                // illegal move
                if (move === null) return 'snapback';

                element.updateStatus();

                if (element.onMove) {
                    element.onMove(moveObject);
                }
            };

            $(element).on('click', '[class*="square"]', function () {
                if (!scope.game.mine) {
                    return false;
                }

                var square = $(this).data('square');

                var piece = $(this).find('img');

                var isMyPiece = piece.length && piece.data('piece').indexOf(scope.game.color) === 0;

                if (!isMyPiece &&
                    !scope.current_move &&
                    SettingService.getSetting('One-click move')) { // move by one click
                    if (moveByOneClick(element, square, scope)) {
                        return;
                    }
                }

                if (isMyTurn(scope, element)) {
                    if (!scope.current_move || isMyPiece) {
                        scope.current_move = {
                            from: square
                        };
                        highlightSquare(square);
                    } else {
                        doMoveOnTheBoard(scope, element, square);
                    }
                } else {
                    if (!scope.pre_move || !!scope.pre_move.to) {
                        scope.pre_move = {
                            from: square
                        };
                        highlightSquare(square);
                    } else {
                        scope.pre_move.to = square;
                        scope.highlightLastMove(scope, element, scope.pre_move);
                    }

                }
            });

            // update the board position after the piece snap
            // for castling, en passant, pawn promotion
            var onSnapEnd = function() {
                element.board.position(element.game.fen());
            };

            element.updateStatus = function() {
                var status = '';

                var moveColor = 'White';
                if (element.game.turn() === 'b') {
                    moveColor = 'Black';
                }

                // checkmate?
                if (element.game.in_checkmate() === true) {
                    status = 'Game over, ' + moveColor + ' is in checkmate.';
                }

                // draw?
                else if (element.game.in_draw() === true) {
                    status = 'Game over, drawn position';
                }

                // game still on
                else {
                    status = moveColor + ' to move';

                    // check?
                    if (element.game.in_check() === true) {
                        status += ', ' + moveColor + ' is in check';
                    }
                }

                statusEl.html(status);
                fenEl.html(element.game.fen());
                pgnEl.html(element.game.pgn());
            };

            element.loadBoard = function (userConfig) {
                element.board = ChessBoard(element.data('board'), {
                    draggable: scope.boardConfig.draggable,
                    moveSpeed: 1,
                    position: 'start',
                    onDragStart: onDragStart,
                    onDrop: onDrop,
                    onSnapEnd: onSnapEnd,
                    pieceTheme: 'img/chesspieces/' + userConfig.pieceType + '/{piece}.png'
                });
                element.updateStatus();
            };

            element.loadPgn = function (pgn) {
                element.game.load_pgn(pgn);
                element.board.position(element.game.fen());
                element.updateStatus();
            };
        }
    }
});<commit_msg>fix(frontend): Highlight pre-move for draggable.<commit_after>'use strict';

/**
 * After applying this directive element.board will be chess board (chessboard.js)
 * and element.game will be chess game (chess.js)
 * Also drag and drop functions will be defined.
 * This small library is useful for separating drag&drop logic and application logic
 */
playzoneControllers.directive('chessBoardLegal', function (SettingService, $timeout) {
    function isMyTurn(scope, element) {
        return element.game.turn() === scope.game.color;
    }

    function doMoveOnTheBoard(scope, element, to) {
        scope.current_move.to = to; // move by click&click
        scope.current_move.promotion = 'q'; // NOTE: always promote to a queen for example simplicity

        if (!element.game.move(scope.current_move)) {
            scope.current_move.to = false;
            scope.pre_move = false;
            return;
        }

        scope.game.pgn = element.game.pgn();

        if (!element.board) {
            return;
        }

        element.board.position(element.game.fen());
        element.updateStatus();
        element.onMove(scope.current_move);
    }

    function moveByOneClick(element, square, scope) {
        if (!isMyTurn(scope, element)) {
            return;
        }

        var legalMoves = element.game.moves({verbose: true});

        var isSingleOptionToMoveHere = false;

        $.each(
            legalMoves,
            function (index, value) {
                if (value.to === square) {
                    if (isSingleOptionToMoveHere) {
                        isSingleOptionToMoveHere = false;
                        scope.current_move = false;
                        return false;
                    } else {
                        isSingleOptionToMoveHere = true;
                        scope.current_move = {
                            from: value.from
                        };
                        console.log('test');
                    }
                }
            }
        );

        if (isSingleOptionToMoveHere) {
            doMoveOnTheBoard(scope, element, square);
            return true;
        } else {
            return false;
        }
    }

    return {
        restrict: 'C',
        link: function(scope, element) {
            element.game = new Chess();

            var statusEl = $(element).find('.status'),
                fenEl = $(element).find('.fen'),
                pgnEl = $(element).find('.pgn');

            var highlightSquare = function (square) {
                $(element).find('[class*="square"]').removeClass(scope.boardConfig.highlightClass);
                $(element).find('.square-' + square).addClass(scope.boardConfig.highlightClass);
            };

            // do not pick up pieces if the game is over
            // only pick up pieces for the side to move
            var onDragStart = function(source, piece, position, orientation) {
                if (scope.game.status !== 'play' || !scope.game.mine || !element.isMyMove(piece)) {
                    return false;
                }

                if (!scope.current_move) {
                    scope.current_move = { from: source }; // for move click&click
                } else {
                    doMoveOnTheBoard(scope, element, source);
                    return true;
                }

                return !scope.pre_move;
            };

            var onDrop = function(source, target) {
                if (!isMyTurn(scope, element)) {
                    // pre-move functionality for draggable
                    scope.pre_move = {from: source, to: target};

                    $timeout(
                        function () {
                            scope.highlightLastMove(scope, element, scope.pre_move);
                        },
                        150
                    );

                    return;
                }
                // see if the move is legal
                var moveObject = {
                    from: source,
                    to: target,
                    promotion: 'q' // NOTE: always promote to a queen for example simplicity
                };
                var move = element.game.move(moveObject);

                // illegal move
                if (move === null) return 'snapback';

                element.updateStatus();

                if (element.onMove) {
                    element.onMove(moveObject);
                }
            };

            $(element).on('click', '[class*="square"]', function () {
                if (!scope.game.mine) {
                    return false;
                }

                var square = $(this).data('square');

                var piece = $(this).find('img');

                var isMyPiece = piece.length && piece.data('piece').indexOf(scope.game.color) === 0;

                if (!isMyPiece &&
                    !scope.current_move &&
                    SettingService.getSetting('One-click move')) { // move by one click
                    if (moveByOneClick(element, square, scope)) {
                        return;
                    }
                }

                if (isMyTurn(scope, element)) {
                    if (!scope.current_move || isMyPiece) {
                        scope.current_move = {
                            from: square
                        };
                        highlightSquare(square);
                    } else {
                        doMoveOnTheBoard(scope, element, square);
                    }
                } else {
                    if (!scope.pre_move || !!scope.pre_move.to) {
                        scope.pre_move = {
                            from: square
                        };
                        highlightSquare(square);
                    } else {
                        scope.pre_move.to = square;
                        scope.highlightLastMove(scope, element, scope.pre_move);
                    }

                }
            });

            // update the board position after the piece snap
            // for castling, en passant, pawn promotion
            var onSnapEnd = function() {
                element.board.position(element.game.fen());
            };

            element.updateStatus = function() {
                var status = '';

                var moveColor = 'White';
                if (element.game.turn() === 'b') {
                    moveColor = 'Black';
                }

                // checkmate?
                if (element.game.in_checkmate() === true) {
                    status = 'Game over, ' + moveColor + ' is in checkmate.';
                }

                // draw?
                else if (element.game.in_draw() === true) {
                    status = 'Game over, drawn position';
                }

                // game still on
                else {
                    status = moveColor + ' to move';

                    // check?
                    if (element.game.in_check() === true) {
                        status += ', ' + moveColor + ' is in check';
                    }
                }

                statusEl.html(status);
                fenEl.html(element.game.fen());
                pgnEl.html(element.game.pgn());
            };

            element.loadBoard = function (userConfig) {
                element.board = ChessBoard(element.data('board'), {
                    draggable: scope.boardConfig.draggable,
                    moveSpeed: 1,
                    position: 'start',
                    onDragStart: onDragStart,
                    onDrop: onDrop,
                    onSnapEnd: onSnapEnd,
                    pieceTheme: 'img/chesspieces/' + userConfig.pieceType + '/{piece}.png'
                });
                element.updateStatus();
            };

            element.loadPgn = function (pgn) {
                element.game.load_pgn(pgn);
                element.board.position(element.game.fen());
                element.updateStatus();
            };
        }
    }
});<|endoftext|>