<commit_before>/*
*
*	Chimera abilities
*
*/
abilities[45] =[

// 	First Ability: Cyclic Duality
{
	//	Type : Can be "onQuery","onStartPhase","onDamage"
	trigger : "onStartPhase",

	//	require() :
	require : function(){
		return this.testRequirements();
	},

	//	activate() :
	activate : function() {
		this.tokens = [false,false,false];
	},

	abilityTriggered : function(id){
		if(this.used) return;
		if(this.tokens[id]){
			this.end();
			for (var i = 0; i < this.tokens.length; i++) {
				this.creature.abilities[i+1].used  = this.tokens[i];
			};
			G.UI.checkAbilities();
		}else{
			this.tokens[id] = true;
			this.creature.abilities[id+1].setUsed(false);
		}
	},

	tokens : [false,false,false],
},

//	Second Ability: Tooth Fairy
{
	//	Type : Can be "onQuery","onStartPhase","onDamage"
	trigger : "onQuery",

	damages : {
		crush : 20,
	},

	//	require() :
	require : function(){
		if( !this.testRequirements() ) return false;

		if( !this.atLeastOneTarget( G.grid.getHexMap(this.creature.x-3,this.creature.y-2,0,false,frontnback3hex),"ennemy" ) ){
			this.message = G.msg.abilities.notarget;
			return false;
		}

		//Duality
		if( this.creature.abilities[0].used ){
			//this.message = "Duality has already been used";
			//return false;
		}else{
			this.setUsed(false);
		}

		return true;
	},

	//	query() :
	query : function(){
		var chimera = this.creature;

		G.grid.queryCreature({
			fnOnConfirm : this.activate, //fnOnConfirm
			team : 0, //Team, 0 = ennemies
			id : chimera.id,
			flipped : chimera.flipped,
			hexs : G.grid.getHexMap(chimera.x-3,chimera.y-2,0,false,frontnback3hex),
			args : {ability: this}
		});
	},

	//	activate() :
	activate : function(target,args) {
		var ability = args.ability;
		ability.end();

		ability.creature.abilities[0].abilityTriggered(0);

		var damage = new Damage(
			ability.creature, //Attacker
			"target", //Attack Type
			ability.damages, //Damage Type
			1, //Area
			[]	//Effects
		);
		target.takeDamage(damage);
	},
},

//	Thirt Ability: Power Note
{
	//	Type : Can be "onQuery","onStartPhase","onDamage"
	trigger : "onQuery",

	damages : {
		sonic : 20,
	},

	directions : [0,1,0,0,0,0],

	//	require() :
	require : function(){
		if( !this.testRequirements() ) return false;

		if( !this.testDirection({ team : "ennemy", directions : this.directions }) ){
			this.message = G.msg.abilities.notarget;
			return false;
		}
		//Duality
		if( this.creature.abilities[0].used ){
			//this.message = "Duality has already been used";
			//return false;
		}else{
			this.setUsed(false);
		}
		return true;
	},

	//	query() :
	query : function(){
		var chimera = this.creature;

		G.grid.queryDirection({
			fnOnConfirm : this.activate, //fnOnConfirm
			flipped : chimera.player.flipped,
			team : 0, //enemies
			id : chimera.id,
			requireCreature : false,
			x : chimera.x,
			y : chimera.y,
			directions : this.directions,
			args : {chimera:chimera, ability: this}
		});
	},

	//	activate() :
	activate : function(path,args) {
		var ability = args.ability;
		ability.end();

		ability.creature.abilities[0].abilityTriggered(1);

		crea = path.last().creature;

		var damage = new Damage(
			ability.creature, //Attacker
			"target", //Attack Type
			ability.damages, //Damage Type
			1, //Area
			[]	//Effects
		);
		crea.takeDamage(damage);
	},
},

//	Fourth Ability: Chain Lightning
{
	//	Type : Can be "onQuery","onStartPhase","onDamage"
	trigger : "onQuery",

	damages : {
		shock : 20,
	},

	directions : [0,1,0,0,0,0],

	require : function(){
		if( !this.testRequirements() ) return false;

		if( !this.testDirection({ team : "ennemy", directions : this.directions }) ){
			this.message = G.msg.abilities.notarget;
			return false;
		}
		//Duality
		if( this.creature.abilities[0].used ){
			//this.message = "Duality has already been used";
			//return false;
		}else{
			this.setUsed(false);
		}
		return true;
	},

	//	query() :
	query : function(){
		var chimera = this.creature;

		G.grid.queryDirection({
			fnOnConfirm : this.activate, //fnOnConfirm
			flipped : chimera.player.flipped,
			team : 0, //enemies
			id : chimera.id,
			requireCreature : false,
			x : chimera.x,
			y : chimera.y,
			directions : this.directions,
			args : {chimera:chimera, ability: this}
		});
	},

	//	activate() :
	activate : function(path,args) {
		var ability = args.ability;
		ability.end();

		ability.creature.abilities[0].abilityTriggered(2);

		var targets = [];
		targets.push(path.last().creature);
		var nextdmg = $j.extend({},ability.damages);

		for (var i = 0; i < targets.length; i++) {
			console.log(targets);
			var trg = targets[i];

			var damage = new Damage(
				ability.creature, //Attacker
				"target", //Attack Type
				nextdmg, //Damage Type
				1, //Area
				[] //Effects
			);
			nextdmg = trg.takeDamage(damage);

			if(nextdmg.damages == undefined) break;
			if(nextdmg.damages.total <= 0) break;
			delete nextdmg.damages.total;
			nextdmg = nextdmg.damages;

			nextTargets = ability.getTargets(trg.adjacentHexs(1));

			if(nextTargets.length == 0) break;

			var bestTarget = { stats:{ defense:-99999, shock:-99999 } };
			for (var j = 0; j < nextTargets.length; j++) {
				if (typeof nextTargets[j] == "undefined") continue // Skip empty ids.
				if (targets.indexOf(nextTargets[j].target) != -1) continue
				if (nextTargets[j].target.stats.shock+nextTargets[j].target.stats.defense <= bestTarget.stats.shock+bestTarget.stats.defense) continue
				var bestTarget = nextTargets[j].target;
			};

			if( bestTarget instanceof Creature ){
				targets.push(bestTarget);
			}else{
				break;
			}
		};

	},
}

];
<commit_msg>Fixed #280.<commit_after>/*
*
*	Chimera abilities
*
*/
abilities[45] =[

// 	First Ability: Cyclic Duality
{
	//	Type : Can be "onQuery","onStartPhase","onDamage"
	trigger : "onStartPhase",

	//	require() :
	require : function(){
		return this.testRequirements();
	},

	//	activate() :
	activate : function() {
		this.tokens = [false,false,false];
	},

	abilityTriggered : function(id){
		if(this.used) return;
		if(this.tokens[id]){
			this.end();
			for (var i = 0; i < this.tokens.length; i++) {
				this.creature.abilities[i+1].used  = this.tokens[i];
			};
			G.UI.checkAbilities();
		}else{
			this.tokens[id] = true;
			this.creature.abilities[id+1].setUsed(false);
		}
	},

	tokens : [false,false,false],
},

//	Second Ability: Tooth Fairy
{
	//	Type : Can be "onQuery","onStartPhase","onDamage"
	trigger : "onQuery",

	damages : {
		crush : 20,
	},

	//	require() :
	require : function(){
		if( !this.testRequirements() ) return false;

		if( !this.atLeastOneTarget( G.grid.getHexMap(this.creature.x-3,this.creature.y-2,0,false,frontnback3hex),"ennemy" ) ){
			this.message = G.msg.abilities.notarget;
			return false;
		}

		//Duality
		if( this.creature.abilities[0].used ){
			//this.message = "Duality has already been used";
			//return false;
		}else{
			this.setUsed(false);
		}

		return true;
	},

	//	query() :
	query : function(){
		var chimera = this.creature;

		G.grid.queryCreature({
			fnOnConfirm : this.activate, //fnOnConfirm
			team : 0, //Team, 0 = ennemies
			id : chimera.id,
			flipped : chimera.flipped,
			hexs : G.grid.getHexMap(chimera.x-3,chimera.y-2,0,false,frontnback3hex),
			args : {ability: this}
		});
	},

	//	activate() :
	activate : function(target,args) {
		var ability = args.ability;

		ability.creature.abilities[0].abilityTriggered(0);

		ability.end();

		var damage = new Damage(
			ability.creature, //Attacker
			"target", //Attack Type
			ability.damages, //Damage Type
			1, //Area
			[]	//Effects
		);
		target.takeDamage(damage);
	},
},

//	Thirt Ability: Power Note
{
	//	Type : Can be "onQuery","onStartPhase","onDamage"
	trigger : "onQuery",

	damages : {
		sonic : 20,
	},

	directions : [0,1,0,0,0,0],

	//	require() :
	require : function(){
		if( !this.testRequirements() ) return false;

		if( !this.testDirection({ team : "ennemy", directions : this.directions }) ){
			this.message = G.msg.abilities.notarget;
			return false;
		}
		//Duality
		if( this.creature.abilities[0].used ){
			//this.message = "Duality has already been used";
			//return false;
		}else{
			this.setUsed(false);
		}
		return true;
	},

	//	query() :
	query : function(){
		var chimera = this.creature;

		G.grid.queryDirection({
			fnOnConfirm : this.activate, //fnOnConfirm
			flipped : chimera.player.flipped,
			team : 0, //enemies
			id : chimera.id,
			requireCreature : false,
			x : chimera.x,
			y : chimera.y,
			directions : this.directions,
			args : {chimera:chimera, ability: this}
		});
	},

	//	activate() :
	activate : function(path,args) {
		var ability = args.ability;

		ability.creature.abilities[0].abilityTriggered(1);
		ability.end();

		crea = path.last().creature;

		var damage = new Damage(
			ability.creature, //Attacker
			"target", //Attack Type
			ability.damages, //Damage Type
			1, //Area
			[]	//Effects
		);
		crea.takeDamage(damage);
	},
},

//	Fourth Ability: Chain Lightning
{
	//	Type : Can be "onQuery","onStartPhase","onDamage"
	trigger : "onQuery",

	damages : {
		shock : 20,
	},

	directions : [0,1,0,0,0,0],

	require : function(){
		if( !this.testRequirements() ) return false;

		if( !this.testDirection({ team : "ennemy", directions : this.directions }) ){
			this.message = G.msg.abilities.notarget;
			return false;
		}
		//Duality
		if( this.creature.abilities[0].used ){
			//this.message = "Duality has already been used";
			//return false;
		}else{
			this.setUsed(false);
		}
		return true;
	},

	//	query() :
	query : function(){
		var chimera = this.creature;

		G.grid.queryDirection({
			fnOnConfirm : this.activate, //fnOnConfirm
			flipped : chimera.player.flipped,
			team : 0, //enemies
			id : chimera.id,
			requireCreature : false,
			x : chimera.x,
			y : chimera.y,
			directions : this.directions,
			args : {chimera:chimera, ability: this}
		});
	},

	//	activate() :
	activate : function(path,args) {
		var ability = args.ability;

		ability.creature.abilities[0].abilityTriggered(2);

		ability.end();

		var targets = [];
		targets.push(path.last().creature);
		var nextdmg = $j.extend({},ability.damages);

		for (var i = 0; i < targets.length; i++) {
			console.log(targets);
			var trg = targets[i];

			var damage = new Damage(
				ability.creature, //Attacker
				"target", //Attack Type
				nextdmg, //Damage Type
				1, //Area
				[] //Effects
			);
			nextdmg = trg.takeDamage(damage);

			if(nextdmg.damages == undefined) break;
			if(nextdmg.damages.total <= 0) break;
			delete nextdmg.damages.total;
			nextdmg = nextdmg.damages;

			nextTargets = ability.getTargets(trg.adjacentHexs(1));

			if(nextTargets.length == 0) break;

			var bestTarget = { stats:{ defense:-99999, shock:-99999 } };
			for (var j = 0; j < nextTargets.length; j++) {
				if (typeof nextTargets[j] == "undefined") continue // Skip empty ids.
				if (targets.indexOf(nextTargets[j].target) != -1) continue
				if (nextTargets[j].target.stats.shock+nextTargets[j].target.stats.defense <= bestTarget.stats.shock+bestTarget.stats.defense) continue
				var bestTarget = nextTargets[j].target;
			};

			if( bestTarget instanceof Creature ){
				targets.push(bestTarget);
			}else{
				break;
			}
		};

	},
}

];
<|endoftext|>


<commit_before>var renderControls = function(node, first, last, parent, level) {

  function render(node, destination, consolidate) {
    var actions = new Data.Hash();

    function computeActions(n, parent) {
      function registerAction(action) {
        if (action.nodeType === '/type/section' && action.level > 3) return;

        if (actions.get(action.nodeType)) {
          if (action.nodeType === '/type/section') {
            actions.get(action.nodeType).push(action);
          } else if (action.level > actions.get(action.nodeType)[0].level) {
            actions.set(action.nodeType, [action]);
          }
        } else {
          actions.set(action.nodeType, [action]);
        }
      }

      var nlevel = parseInt($('#'+n.html_id).attr('level'));

      // Possible children
      if (n.all('children') && n.all('children').length === 0 && destination === 'after') {
        var children = n.properties().get('children').expectedTypes;

        _.each(children, function(type) {
          registerAction({
            node: n._id,
            parentNode: parent ? parent._id : null,
            nodeType: type,
            nodeTypeName: graph.get(type).name,
            insertionType: 'child',
            level: nlevel+1
          });
        });
      }

      // Possible siblings
      if (parent) {
        var siblings = parent.properties().get('children').expectedTypes;
        _.each(siblings, function(type) {
          registerAction({
            node: n._id,
            parentNode: parent ? parent._id : null,
            nodeType: type,
            nodeTypeName: graph.get(type).name,
            insertionType: 'sibling',
            level: nlevel
          });
        });
      }

      // Consolidate actions for child elements
      if (consolidate && n.all('children') && n.all('children').length > 0) {
        computeActions(n.all('children').last(), n);
      }
      return actions;
    }

    return _.tpl('controls', {
      node: node.key,
      destination: destination,
      actions: computeActions(node, parent)
    });
  }

  // Top level
  if (!parent) {
    // Cleanup
    $('#document .controls').remove();
    if (!node.all('children') || node.all('children').length === 0) {
      $(render(node, 'after')).appendTo($('#'+node.html_id));
    }
  } else {
    //  Insert before, but only for starting nodes (first=true)
    if (first) {
      // Insert controls before node
      $(render(node, 'before')).insertBefore($('#'+node.html_id));
    }

    // Consolidate at level 1 (=section level), but only for closing nodes (last=true)
    if (parent.types().get('/type/document')) {
      $(render(node, 'after', true)).insertAfter($('#'+node.html_id));
    } else if (!last) {
      $(render(node,'after')).insertAfter($('#'+node.html_id));
    }
  }

  if (node.all('children')) {
    // Do the same for all children
    node.all('children').each(function(child, key, index) {
      var first = index === 0;
      var last = index === node.all('children').length-1;
      renderControls(child, first, last, node, level + 1);
    });
  }
};

// HTMLRenderer
// ---------------

var HTMLRenderer = function(root, parent, lvl) {

  // Implement node types
  var renderers = {
    "/type/document": function(node, parent, level) {
      var content = '',
          children = node.all('children');

      if (children) {
        children.each(function(child, key, index) {
          content += renderers[child.type._id](child, node, level+1);
        });
      }

      return _.tpl('document', {
        node: node,
        content: content,
        edit: app.document.mode === 'edit',
        title: node.get('title'),
        lead: node.get('lead'),
        empty_lead: app.document.mode === 'edit' && (!node.get('lead') || node.get('lead') === ''),
        empty_title: app.document.mode === 'edit' && (!node.get('title') || node.get('title') === ''),
        level: level
      });
    },

    "/type/story": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/conversation": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/article": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/manual": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/qaa": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/section": function(node, parent, level) {
      var content = '',
          children = node.all('children');

      if (children) {
        node.all('children').each(function(child, key, index) {
          content += renderers[child.type._id](child, node, level+1);
        });
      }

      return Helpers.renderTemplate('section', {
        node: node,
        parent: parent,
        content: content,
        heading_level: level+1,
        level: level,
        edit: app.document.mode === 'edit',
        name: node.get('name'),
        empty: app.document.mode === 'edit' && (!node.get('name') || node.get('name') === ''),
      });
    },

    "/type/text": function(node, parent, level) {
      return Helpers.renderTemplate('text', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        empty: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === '

'),
        level: level
      });
    },

    "/type/quote": function(node, parent, level) {
      return Helpers.renderTemplate('quote', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        author: node.get('author'),
        empty_content: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === ''),
        empty_author: app.document.mode === 'edit' && (!node.get('author') || node.get('author') === ''),
        level: level
      });
    },

    "/type/code": function(node, parent, level) {
      return Helpers.renderTemplate('code', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        empty: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === ''),
        level: level
      });
    },

    "/type/question": function(node, parent, level) {
      return Helpers.renderTemplate('question', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        empty: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === ''),
        level: level
      });
    },

    "/type/answer": function(node, parent, level) {
      return Helpers.renderTemplate('answer', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        empty: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === ''),
        level: level
      });
    },

    "/type/image": function(node, parent, level) {
      return Helpers.renderTemplate('image', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        url: node.get('url'),
        level: level
      });
    },

    "/type/visualization": function(node, parent, level) {
      return Helpers.renderTemplate('visualization', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        visualization_type: node.get('visualization_type'),
        data_source: node.get('data_source'),
        level: level
      });
    }
  };

  return {
    render: function() {
      // Traverse the document
      return renderers[root.type._id](root, parent, parseInt(lvl));
    }
  };
};

var TOCRenderer = function(root) {

  // Known node types
  var renderers = {
    "/type/document": function(node) {
      content = '
Table of contents
';
      content += '
';
      node.all('children').each(function(child) {
        content += '
'+child.get('name')+'
';
      });
      content += '
';
      return content;
    },

    "/type/story": function(node) {
      return renderers["/type/document"](node);
    },

    "/type/conversation": function(node) {
      return "";
    },

    "/type/manual": function(node, parent) {
      return renderers["/type/document"](node, parent);
    },

    "/type/article": function(node, parent) {
      return renderers["/type/document"](node, parent);
    },

    "/type/qaa": function(node, parent) {
      return renderers["/type/document"](node, parent);
    }
  };

  return {
    render: function() {
      // Traverse the document
      return renderers[root.type._id](root);
    }
  };
};<commit_msg>Removed trailing comma.<commit_after>var renderControls = function(node, first, last, parent, level) {

  function render(node, destination, consolidate) {
    var actions = new Data.Hash();

    function computeActions(n, parent) {
      function registerAction(action) {
        if (action.nodeType === '/type/section' && action.level > 3) return;

        if (actions.get(action.nodeType)) {
          if (action.nodeType === '/type/section') {
            actions.get(action.nodeType).push(action);
          } else if (action.level > actions.get(action.nodeType)[0].level) {
            actions.set(action.nodeType, [action]);
          }
        } else {
          actions.set(action.nodeType, [action]);
        }
      }

      var nlevel = parseInt($('#'+n.html_id).attr('level'));

      // Possible children
      if (n.all('children') && n.all('children').length === 0 && destination === 'after') {
        var children = n.properties().get('children').expectedTypes;

        _.each(children, function(type) {
          registerAction({
            node: n._id,
            parentNode: parent ? parent._id : null,
            nodeType: type,
            nodeTypeName: graph.get(type).name,
            insertionType: 'child',
            level: nlevel+1
          });
        });
      }

      // Possible siblings
      if (parent) {
        var siblings = parent.properties().get('children').expectedTypes;
        _.each(siblings, function(type) {
          registerAction({
            node: n._id,
            parentNode: parent ? parent._id : null,
            nodeType: type,
            nodeTypeName: graph.get(type).name,
            insertionType: 'sibling',
            level: nlevel
          });
        });
      }

      // Consolidate actions for child elements
      if (consolidate && n.all('children') && n.all('children').length > 0) {
        computeActions(n.all('children').last(), n);
      }
      return actions;
    }

    return _.tpl('controls', {
      node: node.key,
      destination: destination,
      actions: computeActions(node, parent)
    });
  }

  // Top level
  if (!parent) {
    // Cleanup
    $('#document .controls').remove();
    if (!node.all('children') || node.all('children').length === 0) {
      $(render(node, 'after')).appendTo($('#'+node.html_id));
    }
  } else {
    //  Insert before, but only for starting nodes (first=true)
    if (first) {
      // Insert controls before node
      $(render(node, 'before')).insertBefore($('#'+node.html_id));
    }

    // Consolidate at level 1 (=section level), but only for closing nodes (last=true)
    if (parent.types().get('/type/document')) {
      $(render(node, 'after', true)).insertAfter($('#'+node.html_id));
    } else if (!last) {
      $(render(node,'after')).insertAfter($('#'+node.html_id));
    }
  }

  if (node.all('children')) {
    // Do the same for all children
    node.all('children').each(function(child, key, index) {
      var first = index === 0;
      var last = index === node.all('children').length-1;
      renderControls(child, first, last, node, level + 1);
    });
  }
};

// HTMLRenderer
// ---------------

var HTMLRenderer = function(root, parent, lvl) {

  // Implement node types
  var renderers = {
    "/type/document": function(node, parent, level) {
      var content = '',
          children = node.all('children');

      if (children) {
        children.each(function(child, key, index) {
          content += renderers[child.type._id](child, node, level+1);
        });
      }

      return _.tpl('document', {
        node: node,
        content: content,
        edit: app.document.mode === 'edit',
        title: node.get('title'),
        lead: node.get('lead'),
        empty_lead: app.document.mode === 'edit' && (!node.get('lead') || node.get('lead') === ''),
        empty_title: app.document.mode === 'edit' && (!node.get('title') || node.get('title') === ''),
        level: level
      });
    },

    "/type/story": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/conversation": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/article": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/manual": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/qaa": function(node, parent, level) {
      return renderers["/type/document"](node, parent, level)
    },

    "/type/section": function(node, parent, level) {
      var content = '',
          children = node.all('children');

      if (children) {
        node.all('children').each(function(child, key, index) {
          content += renderers[child.type._id](child, node, level+1);
        });
      }

      return Helpers.renderTemplate('section', {
        node: node,
        parent: parent,
        content: content,
        heading_level: level+1,
        level: level,
        edit: app.document.mode === 'edit',
        name: node.get('name'),
        empty: app.document.mode === 'edit' && (!node.get('name') || node.get('name') === '')
      });
    },

    "/type/text": function(node, parent, level) {
      return Helpers.renderTemplate('text', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        empty: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === '

'),
        level: level
      });
    },

    "/type/quote": function(node, parent, level) {
      return Helpers.renderTemplate('quote', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        author: node.get('author'),
        empty_content: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === ''),
        empty_author: app.document.mode === 'edit' && (!node.get('author') || node.get('author') === ''),
        level: level
      });
    },

    "/type/code": function(node, parent, level) {
      return Helpers.renderTemplate('code', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        empty: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === ''),
        level: level
      });
    },

    "/type/question": function(node, parent, level) {
      return Helpers.renderTemplate('question', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        empty: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === ''),
        level: level
      });
    },

    "/type/answer": function(node, parent, level) {
      return Helpers.renderTemplate('answer', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        content: node.get('content'),
        empty: app.document.mode === 'edit' && (!node.get('content') || node.get('content') === ''),
        level: level
      });
    },

    "/type/image": function(node, parent, level) {
      return Helpers.renderTemplate('image', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        url: node.get('url'),
        level: level
      });
    },

    "/type/visualization": function(node, parent, level) {
      return Helpers.renderTemplate('visualization', {
        node: node,
        parent: parent,
        edit: app.document.mode === 'edit',
        visualization_type: node.get('visualization_type'),
        data_source: node.get('data_source'),
        level: level
      });
    }
  };

  return {
    render: function() {
      // Traverse the document
      return renderers[root.type._id](root, parent, parseInt(lvl));
    }
  };
};

var TOCRenderer = function(root) {

  // Known node types
  var renderers = {
    "/type/document": function(node) {
      content = '
Table of contents
';
      content += '
';
      node.all('children').each(function(child) {
        content += '
'+child.get('name')+'
';
      });
      content += '
';
      return content;
    },

    "/type/story": function(node) {
      return renderers["/type/document"](node);
    },

    "/type/conversation": function(node) {
      return "";
    },

    "/type/manual": function(node, parent) {
      return renderers["/type/document"](node, parent);
    },

    "/type/article": function(node, parent) {
      return renderers["/type/document"](node, parent);
    },

    "/type/qaa": function(node, parent) {
      return renderers["/type/document"](node, parent);
    }
  };

  return {
    render: function() {
      // Traverse the document
      return renderers[root.type._id](root);
    }
  };
};<|endoftext|>


<commit_before>/*jshint browser:true */
/*global angular:true */
'use strict';

/*
Angular.js service wrapping the elastic.js API. This module can simply
be injected into your angular controllers.
*/
angular.module('elasticjs.service', [])
  .factory('ejsResource', function ($http) {

  return function (url) {

    var

      // use existing ejs object if it exists
      ejs = window.ejs || {},

      /* results are returned as a promise */
      promiseThen = function (httpPromise, successcb, errorcb) {
        return httpPromise.then(function (response) {
          (successcb || angular.noop)(response.data);
          return response.data;
        }, function (response) {
          (errorcb || angular.noop)(undefined);
          return undefined;
        });
      };

    // set url to empty string if it was not specified
    if (url == null) {
      url = '';
    }

    /* implement the elastic.js client interface for angular */
    ejs.client = {
      server: function (s) {
        if (s == null) {
          return url;
        }

        url = s;
        return this;
      },
      post: function (path, data, successcb, errorcb) {
        path = url + path;
        return promiseThen($http.post(path, data), successcb, errorcb);
      },
      get: function (path, data, successcb, errorcb) {
        path = url + path;
        return promiseThen($http.get(path, data), successcb, errorcb);
      },
      put: function (path, data, successcb, errorcb) {
        path = url + path;
        return promiseThen($http.put(path, data), successcb, errorcb);
      },
      del: function (path, data, successcb, errorcb) {
        path = url + path;
        return promiseThen($http.delee(path, data), successcb, errorcb);
      },
      head: function (path, data, successcb, errorcb) {
        path = url + path;
        return $http.head(path, data)
          .then(function (response) {
          (successcb || angular.noop)(response.headers());
          return response.headers();
        }, function (response) {
          (errorcb || angular.noop)(undefined);
          return undefined;
        });
      }
    };

    return ejs;
  };
});
<commit_msg>make angular client safe for minification<commit_after>/*jshint browser:true */
/*global angular:true */
'use strict';

/*
Angular.js service wrapping the elastic.js API. This module can simply
be injected into your angular controllers.
*/
angular.module('elasticjs.service', [])
  .factory('ejsResource', ['$http', function ($http) {

  return function (url) {

    var

      // use existing ejs object if it exists
      ejs = window.ejs || {},

      /* results are returned as a promise */
      promiseThen = function (httpPromise, successcb, errorcb) {
        return httpPromise.then(function (response) {
          (successcb || angular.noop)(response.data);
          return response.data;
        }, function (response) {
          (errorcb || angular.noop)(undefined);
          return undefined;
        });
      };

    // set url to empty string if it was not specified
    if (url == null) {
      url = '';
    }

    /* implement the elastic.js client interface for angular */
    ejs.client = {
      server: function (s) {
        if (s == null) {
          return url;
        }

        url = s;
        return this;
      },
      post: function (path, data, successcb, errorcb) {
        path = url + path;
        return promiseThen($http.post(path, data), successcb, errorcb);
      },
      get: function (path, data, successcb, errorcb) {
        path = url + path;
        return promiseThen($http.get(path, data), successcb, errorcb);
      },
      put: function (path, data, successcb, errorcb) {
        path = url + path;
        return promiseThen($http.put(path, data), successcb, errorcb);
      },
      del: function (path, data, successcb, errorcb) {
        path = url + path;
        return promiseThen($http.delee(path, data), successcb, errorcb);
      },
      head: function (path, data, successcb, errorcb) {
        path = url + path;
        return $http.head(path, data)
          .then(function (response) {
          (successcb || angular.noop)(response.headers());
          return response.headers();
        }, function (response) {
          (errorcb || angular.noop)(undefined);
          return undefined;
        });
      }
    };

    return ejs;
  };
}]);
<|endoftext|>


<commit_before><commit_msg>Tidying<commit_after><|endoftext|>


<commit_before>import { h, Component } 				from 'preact/preact';

import Notification						from 'com/content-notifications/notification';

import $Node							from '../../shrub/js/node/node';
import $Note							from '../../shrub/js/note/note';

export default class NotificationsBase extends Component {

	constructor( props ) {
		super(props);

		this.state = {
			notifications: [],
			notificationsTotal: -1,
			count: 0,
			status: null,
			feed: [],
		};
	}

	processNotificationFeed(r) {
		const caller_id = r.caller_id;
		let notifications = [];
		r.feed.forEach((notification) => {
			notifications.push(
				[notification.id, <Notification failCallback={ (id) => this.failCallback(id) } caller_id={caller_id} notification={notification} markReadyCallback={(id) => this.markReady(id) } />, false, notification]);
		});

		this.setState({
			feed: r.feed,
			caller_id: caller_id,
			status: r.status,
			count: r.count,
			notifications: notifications,
			notificationsTotal: r.feed.length + this.state.notifications.length,
		});
		this.collectAllNodesAndNodes(r.feed, caller_id);
	}

	collectAllNodesAndNodes(feed, caller_id) {

		let nodeLookup = new Map();
		let nodes = [];
		let notificationLookup = new Map();
		let social = {};

		let soicialPromise = $Node.GetMy().then((response) => {

			social.following = response.star ? response.star : [];
			social.followers = response.refs.star ? response.refs.star : [];
			social.friends = Array.isArray(response.refs.star) ? new Set([...response.star].filter((i) => response.refs.star.indexOf(i) > -1)) : [];
		});

		feed.forEach((notification) => {
			if (nodes.indexOf(notification.node) < 0) {
				nodes.push(notification.node);
			}
			notificationLookup.set(notification.id, notification);
		});

		let node2notes = new Map();
		let notification2nodeAndNote = new Map();
		let noteLookup = new Map();
		let users = [];
		let usersLookup = new Map();

		users.push(caller_id);

		feed.forEach(({id, node, note}) => {
			if (node2notes.has(node)) {
				node2notes.get(node).push(note);
			} else {
				node2notes.set(node, [note]);

			}
			notification2nodeAndNote.set(id, {node: node, note: note});
		});

		let nodesPromise = $Node.Get(nodes)
			.then((response) => {
				console.log('[Notifications:Nodes]', response.node);
				if (response.node) {
					response.node.forEach((node) => {
						nodeLookup.set(node.id, node);
						if (node.author && users.indexOf(node.author) >= 0) {
							users.push(node.author);
						}
						if (node.link && node.link.author) {
							node.link.author.forEach((author) => {
								if (users.indexOf(author) >= 0) {
									users.push(author);
								}
							});
						}
					});
				}

			});

		let notesPromise = $Note.Pick(node2notes).then((response) => {
			console.log('[Notifications:Notes]', response.note);
			if (response.note) {
				response.note.forEach((notes, node) => {
					notes.forEach((note) => {
						noteLookup.set(note.id, note);

						if (note.author && users.indexOf(note.author) >= 0) {
							users.push(note.author);
						}
					});
				});
			}
		});

		Promise.all(nodesPromise, notesPromise, soicialPromise).then(() => { return $Node.Get(users);}).then((response) => {
				console.log('[Notifications:Users]', response.node);
				if (response.node) {
					response.node.forEach((node) => {
						if (node.type == 'user') {
							node.isFriend = social.friends.indexOf(node.id) > -1;
							node.isFollowing = node.isFriend && social.following.indexOf(node.id) > -1;
							node.isFollower = node.isFriend && social.followers.indexOf(node.id) > -1;

							usersLookup.set(node.id, node);
						}
					});
				}

				this.composeNotifications(feed, caller_id, notification2nodeAndNote, node2notes, nodeLookup, noteLookup, usersLookup, notificationLookup);
			});
	}

	composeNotifications(feed, caller_id, notification2nodeAndNote, node2notes, nodeLookup, noteLookup, usersLookup, notificationLookup, social) {

		const myAtName = '@' + usersLookup.get(caller_id).name;
		noteLookup.forEach((note, id) => {
			note.selfauthored = note.author == caller_id;
			note.mention = note.body.indexOf(myAtName) >= 0;
		});

		nodeLookup.forEach((node, id) => {
			node.selfauthored = false;
			if (node.author == caller_id) {
				node.selfauthored = true;
			} else if (node.link && node.link.author) {
				node.link.author.forEach((author) => {
					if (author == caller_id) {
						node.selfauthored = true;
					}
				});
			}
			node.mention = node.body.indexOf(myAtName) >= 0 || node.name.indexOf(myAtName) >= 0;
		});

		let notifications = new Map();
		let processedNotifications = [];

		feed.forEach((notification) => {
			if (processedNotifications.indexOf(notification.id) < 0) {
				let node = nodeLookup.get(notification.node);
				let data = {
					node: node,
					note: undefined,
					notification: [notification],
					multi: false,
					users: new Map(),
				};

				data.users.set(caller_id, usersLookup.get(caller_id));
				data.users.set(node.author, usersLookup.get(node.author));

				if (node.link && node.link.author) {
					node.link.author.forEach((author) => {
						if (!data.users.has(author)) {
							data.users.set(author, usersLookup.get(author));
						}
					});
				}

				if (notification.note) {
					let firstNote = noteLookup.get(notification.note);
					data.note = [firstNote];
					if (!data.users.has(firstNote.author)) {
						data.users.set(firstNote.author, firstNote);
					}

					if (!firstNote.mention && !firstNote.selfauthored) {
						node2notes.get(notification.node).forEach((note) => {
							if (note != notification.note) {
								let noteData = noteLookup.get(note);
								if (!noteData.mention && !noteData.selfauthored) {
									notification2nodeAndNote.forEach((otherData, otherNotification) => {
										if (otherData.note == note) {
											processedNotifications.push(otherNotification);
											data.notification.push(notificationLookup.get(otherNotification));
											data.note.push(noteData);
											if (!data.users.has(noteData.author)) {
												data.users.set(noteData.author, noteData);
											}
											data.multi = true;
										}
									});
								}
							}
						});
					}
				}
				notifications.set(data.notification.sort()[0].id, data);
				processedNotifications.push(notification.id);
			}
		});
		console.log(notifications);
	}

	removeFailed(id) {
		let notifications = this.state.notifications.filter(([cur_id, notification, loaded, notificationData]) => cur_id != id);
		this.updateCallback();
		this.setState({notifications: notifications});
	}

	markReady(id) {
		let notifications = [...this.state.notifications];
		for (let i=0; i<notifications.length; i++) {
			if (notifications[i][0] == id) {
				notifications[i][2] = true;
			}
		}
		this.updateCallback();
		this.setState({notifications: notifications});

		if (this.props.getNew && !this.isLoading()) {
			let maxId = -1;

			notifications.forEach(([id, notification, loaded, notificationData]) => {
				if (id > maxId) {
					maxId = id;
				}
			});

			if (id >= 0){
				$Notification.SetMarkRead(maxId);
			}
			if (this.props.countCallback) {
				this.props.countCallback(notifications.length);
			}
		}
	}

	updateCallback() {
		//For subclass to do stuff with
	}

	isLoading() {
		let loading = this.state.notificationsTotal < 0;
		this.state.notifications.forEach(([id, notification, loaded, notificationData]) => {
			if (!loaded) {
				loading = true;
			}
		});
		return loading;
	};

	getNotifications() {
		let Notifications = [];
		const feed = this.state.notifications;
		const caller_id = this.state.caller_id;

		if (feed && feed.length > 0) {

			feed.forEach(([id, notification, loaded, notificationData]) => {
				if (true) {
					Notifications.push([id, notification]);
				}
			});

		}

		return Notifications;
	}

}<commit_msg>Removed the Set<commit_after>import { h, Component } 				from 'preact/preact';

import Notification						from 'com/content-notifications/notification';

import $Node							from '../../shrub/js/node/node';
import $Note							from '../../shrub/js/note/note';

export default class NotificationsBase extends Component {

	constructor( props ) {
		super(props);

		this.state = {
			notifications: [],
			notificationsTotal: -1,
			count: 0,
			status: null,
			feed: [],
		};
	}

	processNotificationFeed(r) {
		const caller_id = r.caller_id;
		let notifications = [];
		r.feed.forEach((notification) => {
			notifications.push(
				[notification.id, <Notification failCallback={ (id) => this.failCallback(id) } caller_id={caller_id} notification={notification} markReadyCallback={(id) => this.markReady(id) } />, false, notification]);
		});

		this.setState({
			feed: r.feed,
			caller_id: caller_id,
			status: r.status,
			count: r.count,
			notifications: notifications,
			notificationsTotal: r.feed.length + this.state.notifications.length,
		});
		this.collectAllNodesAndNodes(r.feed, caller_id);
	}

	collectAllNodesAndNodes(feed, caller_id) {

		let nodeLookup = new Map();
		let nodes = [];
		let notificationLookup = new Map();
		let social = {};

		let soicialPromise = $Node.GetMy().then((response) => {

			social.following = response.star ? response.star : [];
			social.followers = response.refs.star ? response.refs.star : [];
			social.friends = social.followers.filter((i) => social.following.indexOf(i) > -1);
		});

		feed.forEach((notification) => {
			if (nodes.indexOf(notification.node) < 0) {
				nodes.push(notification.node);
			}
			notificationLookup.set(notification.id, notification);
		});

		let node2notes = new Map();
		let notification2nodeAndNote = new Map();
		let noteLookup = new Map();
		let users = [];
		let usersLookup = new Map();

		users.push(caller_id);

		feed.forEach(({id, node, note}) => {
			if (node2notes.has(node)) {
				node2notes.get(node).push(note);
			} else {
				node2notes.set(node, [note]);

			}
			notification2nodeAndNote.set(id, {node: node, note: note});
		});

		let nodesPromise = $Node.Get(nodes)
			.then((response) => {
				console.log('[Notifications:Nodes]', response.node);
				if (response.node) {
					response.node.forEach((node) => {
						nodeLookup.set(node.id, node);
						if (node.author && users.indexOf(node.author) >= 0) {
							users.push(node.author);
						}
						if (node.link && node.link.author) {
							node.link.author.forEach((author) => {
								if (users.indexOf(author) >= 0) {
									users.push(author);
								}
							});
						}
					});
				}

			});

		let notesPromise = $Note.Pick(node2notes).then((response) => {
			console.log('[Notifications:Notes]', response.note);
			if (response.note) {
				response.note.forEach((notes, node) => {
					notes.forEach((note) => {
						noteLookup.set(note.id, note);

						if (note.author && users.indexOf(note.author) >= 0) {
							users.push(note.author);
						}
					});
				});
			}
		});

		Promise.all(nodesPromise, notesPromise, soicialPromise).then(() => { return $Node.Get(users);}).then((response) => {
				console.log('[Notifications:Users]', response.node);
				if (response.node) {
					response.node.forEach((node) => {
						if (node.type == 'user') {
							node.isFriend = social.friends.indexOf(node.id) > -1;
							node.isFollowing = node.isFriend && social.following.indexOf(node.id) > -1;
							node.isFollower = node.isFriend && social.followers.indexOf(node.id) > -1;

							usersLookup.set(node.id, node);
						}
					});
				}

				this.composeNotifications(feed, caller_id, notification2nodeAndNote, node2notes, nodeLookup, noteLookup, usersLookup, notificationLookup);
			});
	}

	composeNotifications(feed, caller_id, notification2nodeAndNote, node2notes, nodeLookup, noteLookup, usersLookup, notificationLookup, social) {

		const myAtName = '@' + usersLookup.get(caller_id).name;
		noteLookup.forEach((note, id) => {
			note.selfauthored = note.author == caller_id;
			note.mention = note.body.indexOf(myAtName) >= 0;
		});

		nodeLookup.forEach((node, id) => {
			node.selfauthored = false;
			if (node.author == caller_id) {
				node.selfauthored = true;
			} else if (node.link && node.link.author) {
				node.link.author.forEach((author) => {
					if (author == caller_id) {
						node.selfauthored = true;
					}
				});
			}
			node.mention = node.body.indexOf(myAtName) >= 0 || node.name.indexOf(myAtName) >= 0;
		});

		let notifications = new Map();
		let processedNotifications = [];

		feed.forEach((notification) => {
			if (processedNotifications.indexOf(notification.id) < 0) {
				let node = nodeLookup.get(notification.node);
				let data = {
					node: node,
					note: undefined,
					notification: [notification],
					multi: false,
					users: new Map(),
				};

				data.users.set(caller_id, usersLookup.get(caller_id));
				data.users.set(node.author, usersLookup.get(node.author));

				if (node.link && node.link.author) {
					node.link.author.forEach((author) => {
						if (!data.users.has(author)) {
							data.users.set(author, usersLookup.get(author));
						}
					});
				}

				if (notification.note) {
					let firstNote = noteLookup.get(notification.note);
					data.note = [firstNote];
					if (!data.users.has(firstNote.author)) {
						data.users.set(firstNote.author, firstNote);
					}

					if (!firstNote.mention && !firstNote.selfauthored) {
						node2notes.get(notification.node).forEach((note) => {
							if (note != notification.note) {
								let noteData = noteLookup.get(note);
								if (!noteData.mention && !noteData.selfauthored) {
									notification2nodeAndNote.forEach((otherData, otherNotification) => {
										if (otherData.note == note) {
											processedNotifications.push(otherNotification);
											data.notification.push(notificationLookup.get(otherNotification));
											data.note.push(noteData);
											if (!data.users.has(noteData.author)) {
												data.users.set(noteData.author, noteData);
											}
											data.multi = true;
										}
									});
								}
							}
						});
					}
				}
				notifications.set(data.notification.sort()[0].id, data);
				processedNotifications.push(notification.id);
			}
		});
		console.log(notifications);
	}

	removeFailed(id) {
		let notifications = this.state.notifications.filter(([cur_id, notification, loaded, notificationData]) => cur_id != id);
		this.updateCallback();
		this.setState({notifications: notifications});
	}

	markReady(id) {
		let notifications = [...this.state.notifications];
		for (let i=0; i<notifications.length; i++) {
			if (notifications[i][0] == id) {
				notifications[i][2] = true;
			}
		}
		this.updateCallback();
		this.setState({notifications: notifications});

		if (this.props.getNew && !this.isLoading()) {
			let maxId = -1;

			notifications.forEach(([id, notification, loaded, notificationData]) => {
				if (id > maxId) {
					maxId = id;
				}
			});

			if (id >= 0){
				$Notification.SetMarkRead(maxId);
			}
			if (this.props.countCallback) {
				this.props.countCallback(notifications.length);
			}
		}
	}

	updateCallback() {
		//For subclass to do stuff with
	}

	isLoading() {
		let loading = this.state.notificationsTotal < 0;
		this.state.notifications.forEach(([id, notification, loaded, notificationData]) => {
			if (!loaded) {
				loading = true;
			}
		});
		return loading;
	};

	getNotifications() {
		let Notifications = [];
		const feed = this.state.notifications;
		const caller_id = this.state.caller_id;

		if (feed && feed.length > 0) {

			feed.forEach(([id, notification, loaded, notificationData]) => {
				if (true) {
					Notifications.push([id, notification]);
				}
			});

		}

		return Notifications;
	}

}<|endoftext|>


<commit_before>/**
 * Fichier : global.js
 * Description : fonctions JS génériques
 * Auteur : Hamza Iqbal - hiqbal[at]actualys.com
 * Copyright: Actualys
 **
 ****************************************/

/* =================================================================================== */
/* VARIABLES GLOBALES */
/* =================================================================================== */

// Ancre
var ancreSite = window.location.hash;

/* Utilisateur */
var utilisateur =
{
	terminal: '',
	largeurEcran: ''
};

var objWindow =
{
	elem: $(window),
	largeur: $(window).width(),
	hauteur: $(window).height()
};

// Fancybox - Config par défaut
var fbConfig =
{
	padding	: 0,
	autoSize : true,
	fitToView : true,
	helpers :
	{
		overlay : { opacity : 1 }
	}
};

/**
 * Initialisation
 ******************************************/
(function($)
{

	/**
	 * Initialise les informations de l'utilisateur
	 * $.initUtilisateur();
	 ******************************************/
	$.initUtilisateur = function()
	{
		$.detectTerminal();
	};

	/**
	 * Détecte le nom du terminal utilisé
	 * $.detectTerminal();
	 ******************************************/
	$.detectTerminal = function()
	{
		var terminalAgent = navigator.userAgent.toLowerCase();
		var agentID = terminalAgent.match(/(iphone|ipod|ipad|android)/);
		var version;

		if(agentID)
		{
			if(agentID.indexOf('iphone') >= 0) utilisateur.terminal = 'iphone';
			else if(agentID.indexOf('ipod') >=0 ) utilisateur.terminal = 'ipod';
			else if(agentID.indexOf('ipad') >= 0) utilisateur.terminal = 'ipad';
			else if(agentID.indexOf('android') >= 0) utilisateur.terminal = 'android';
		}
		else
		{
			version = parseInt($.browser.version);

			if($.browser.webkit) utilisateur.terminal = 'webkit';
			else if($.browser.mozilla) utilisateur.terminal = 'mozilla';
			else if($.browser.opera) utilisateur.terminal = 'opera';
			else if($.browser.msie)
			{
				if(version == 6) utilisateur.terminal = 'msie6';
				else if(version == 7) utilisateur.terminal = 'msie7';
				else if(version == 8) utilisateur.terminal = 'msie8';
				else if(version == 9) utilisateur.terminal = 'msie9';
			}
		}

		$('body').addClass(utilisateur.terminal);
		return utilisateur.terminal;
	};

	/**
	 * Sélection de lignes de tableau
	 * $.initTableSelection();
	 ******************************************/
	$.initTableSelection = function()
	{
		var tables = $('.table_selection');

		tables.each(function()
		{
			var table = $(this);
			var selecteurGlobal = table.find('thead .selecteur input');
			var selecteursLignes = table.find('tbody .selecteur input');

			// Selection / Déselection globale
			selecteurGlobal.click(function()
			{
				if(selecteurGlobal.is(':checked'))
				{
					selecteursLignes.attr('checked', 'checked');
				}
				else
				{
					selecteursLignes.removeAttr('checked');
				}
			});

			// Déselection unique
			selecteursLignes.click(function()
			{
				var selecteur = $(this);

				if(!selecteur.is(':checked'))
				{
					selecteurGlobal.removeAttr('checked');
				}
			});
		});
	};

	/* =================================================================================== */
	/* INITIALISATION */
	/* =================================================================================== */
	$(document).ready( function()
	{
		$.initUtilisateur();

		//$.metadata.setType('html5');
		$.inputPlaceholder();

		$.initTableSelection();

	});

})(jQuery);<commit_msg>Chrome ne supporte pas les .contains sur les string / ajout de la fct au global<commit_after>/**
 * Fichier : global.js
 * Description : fonctions JS génériques
 * Auteur : Hamza Iqbal - hiqbal[at]actualys.com
 * Copyright: Actualys
 **
 ****************************************/

/* =================================================================================== */
/* VARIABLES GLOBALES */
/* =================================================================================== */

// Ancre
var ancreSite = window.location.hash;

/* Utilisateur */
var utilisateur =
{
	terminal: '',
	largeurEcran: ''
};

var objWindow =
{
	elem: $(window),
	largeur: $(window).width(),
	hauteur: $(window).height()
};

// Fancybox - Config par défaut
var fbConfig =
{
	padding	: 0,
	autoSize : true,
	fitToView : true,
	helpers :
	{
		overlay : { opacity : 1 }
	}
};

/**
 * Initialisation
 ******************************************/
(function($)
{

	/**
	 * Initialise les informations de l'utilisateur
	 * $.initUtilisateur();
	 ******************************************/
	$.initUtilisateur = function()
	{
		$.detectTerminal();
	};

	/**
	 * Détecte le nom du terminal utilisé
	 * $.detectTerminal();
	 ******************************************/
	$.detectTerminal = function()
	{
		var terminalAgent = navigator.userAgent.toLowerCase();
		var agentID = terminalAgent.match(/(iphone|ipod|ipad|android)/);
		var version;

		if(agentID)
		{
			if(agentID.indexOf('iphone') >= 0) utilisateur.terminal = 'iphone';
			else if(agentID.indexOf('ipod') >=0 ) utilisateur.terminal = 'ipod';
			else if(agentID.indexOf('ipad') >= 0) utilisateur.terminal = 'ipad';
			else if(agentID.indexOf('android') >= 0) utilisateur.terminal = 'android';
		}
		else
		{
			version = parseInt($.browser.version);

			if($.browser.webkit) utilisateur.terminal = 'webkit';
			else if($.browser.mozilla) utilisateur.terminal = 'mozilla';
			else if($.browser.opera) utilisateur.terminal = 'opera';
			else if($.browser.msie)
			{
				if(version == 6) utilisateur.terminal = 'msie6';
				else if(version == 7) utilisateur.terminal = 'msie7';
				else if(version == 8) utilisateur.terminal = 'msie8';
				else if(version == 9) utilisateur.terminal = 'msie9';
			}
		}

		$('body').addClass(utilisateur.terminal);
		return utilisateur.terminal;
	};

	/**
	 * Sélection de lignes de tableau
	 * $.initTableSelection();
	 ******************************************/
	$.initTableSelection = function()
	{
		var tables = $('.table_selection');

		tables.each(function()
		{
			var table = $(this);
			var selecteurGlobal = table.find('thead .selecteur input');
			var selecteursLignes = table.find('tbody .selecteur input');

			// Selection / Déselection globale
			selecteurGlobal.click(function()
			{
				if(selecteurGlobal.is(':checked'))
				{
					selecteursLignes.attr('checked', 'checked');
				}
				else
				{
					selecteursLignes.removeAttr('checked');
				}
			});

			// Déselection unique
			selecteursLignes.click(function()
			{
				var selecteur = $(this);

				if(!selecteur.is(':checked'))
				{
					selecteurGlobal.removeAttr('checked');
				}
			});
		});
	};

	/* =================================================================================== */
	/* INITIALISATION */
	/* =================================================================================== */
	$(document).ready( function()
	{
		$.initUtilisateur();

		//$.metadata.setType('html5');
		$.inputPlaceholder();

		$.initTableSelection();

                if(!('contains' in String.prototype)) {
                   String.prototype.contains = function(str, startIndex) {
                    return -1 !== String.prototype.indexOf.call(this, str, startIndex);
               };
             }

	});

})(jQuery);<|endoftext|>


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

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'LivePaint',
  extends: 'foam.u2.Element',

  implements: [ 'foam.memento.MementoMgr' ],

  requires: [
    'foam.graphics.Circle',
    'foam.dao.EasyDAO',
    'foam.graphics.Box',
    'foam.u2.PopupView',
    'foam.u2.TableView',
  ],

  exports: [ 'as data' ],

  constants: {
    SELECTED_COLOR:   '#ddd',
    UNSELECTED_COLOR: 'white'
  },

  axioms: [
    // TODO: remove '-' after ActionView when CSS naming fixed
    foam.u2.CSS.create({
      code: function() {/*
      ^ { width:600px; margin: 20px; }
      ^ canvas { border: 1px solid black; }
      ^ .foam-u2-ActionView- { margin: 10px; }
      ^ input[type='range'] { width: 400px; }
      */}
    })
  ],

  classes: [
    {
      name: 'DiameterDialog',
      extends: 'foam.u2.View',

      requires: [
        'foam.graphics.Circle',
        'foam.u2.RangeView'
      ],

      methods: [
        function initE() {
          this.nodeName = 'span';
          this.
              cssClass(this.myCls()).
              add('Adjust the diameter of the circle at (', this.data.x$, ', ', this.data.y$, ').').
              tag('br').
              add(this.RangeView.create({data$: this.data.radius$, maxValue: 200, onKey: true}));
        }
      ]
    }
  ],

  properties: [
    'feedback_',
    'currentTool',
    {
      class: 'foam.dao.DAOProperty',
      name: 'tools',
      view: {
        class: 'foam.u2.TableView',
        columns: [ foam.core.Model.NAME ]
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'foam.core.Model',
          daoType: 'MDAO'
        });
        dao.put(foam.graphics.Circle.model_);
        dao.put(foam.graphics.Box.model_);
        return dao;
      }
    },
    {
      name: 'selected',
      postSet: function(o, n) {
        if ( o ) o.color = this.UNSELECTED_COLOR;
        if ( n ) n.color = this.SELECTED_COLOR;
      }
    },
    {
      name: 'canvas',
      factory: function() {
        return this.Box.create({width: 600, height: 500, color: '#f3f3f3'});
      }
    },
  ],

  methods: [

    function initE() {
      this.memento$.sub(function() {
        var m = this.memento;
        if ( this.feedback_ ) return;
        this.canvas.children = [];
        if ( m ) {
          for ( var i = 0 ; i < m.length ; i++ ) {
            var c = m[i];
            this.addCircle(c.x, c.y, c.radius);
          }
        }
        this.selected = null;
      }.bind(this));

      this.
          cssClass(this.myCls()).
          start(this.TOOLS, {selection$: this.currentTool$}).end().
          start('center').
            start(this.BACK,  {label: 'Undo'}).end().
            start(this.FORTH, {label: 'Redo'}).end().
            tag('br').
            start(this.canvas).
              on('click',       this.onClick).
              on('contextmenu', this.onRightClick).
            end().
          end();
    },

    function addCircle(x, y, opt_r) {
      var c = this.Circle.create({
        x: x,
        y: y,
        radius: opt_r || 25,
        color: this.UNSELECTED_COLOR,
        border: 'black'});

      this.canvas.addChildren(c);

      return c;
    },

    function updateMemento() {
      this.feedback_ = true;
      this.memento = this.canvas.children.map(function(c) {
        return {x: c.x, y: c.y, radius: c.radius};
      });
      this.feedback_ = false;
    }
  ],

  listeners: [
    function onClick(evt) {
      var x = evt.offsetX, y = evt.offsetY;
      var c = this.canvas.findFirstChildAt(x, y);

      if ( c ) {
        this.selected = c;
      } else {
        var tool = this.currentTool;
        if ( ! tool ) return;
        var cls = this.lookup(tool.id);
        var o = cls.create({x: x, y: y, width: 25, height: 25, radius: 25});
        this.canvas.addChildren(o);
        this.selected = o;
        this.updateMemento();
      }
    },

    function onRightClick(evt) {
      evt.preventDefault();

      if ( ! this.selected ) return;

      var p = this.PopupView.create({
        width: 450,
        height: 110
      }).add(this.DiameterDialog.create({data: this.selected}));

      this.add(p);

      // If the size is changed with the dialog, then create an updated memento
      var oldRadius = this.selected.radius;
      p.onunload.sub(function() {
        if ( this.selected.radius !== oldRadius ) this.updateMemento();
      }.bind(this));
    }
  ]
});
<commit_msg>Add label support to livepaint.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'LivePaint',
  extends: 'foam.u2.Element',

  implements: [ 'foam.memento.MementoMgr' ],

  requires: [
    'foam.graphics.Circle',
    'foam.dao.EasyDAO',
    'foam.graphics.Box',
    'foam.u2.PopupView',
    'foam.u2.TableView',
  ],

  exports: [ 'as data' ],

  constants: {
    SELECTED_COLOR:   '#ddd',
    UNSELECTED_COLOR: 'white'
  },

  axioms: [
    // TODO: remove '-' after ActionView when CSS naming fixed
    foam.u2.CSS.create({
      code: function() {/*
      ^ { width:600px; margin: 20px; }
      ^ canvas { border: 1px solid black; }
      ^ .foam-u2-ActionView- { margin: 10px; }
      ^ input[type='range'] { width: 400px; }
      */}
    })
  ],

  classes: [
    {
      name: 'DiameterDialog',
      extends: 'foam.u2.View',

      requires: [
        'foam.graphics.Circle',
        'foam.u2.RangeView'
      ],

      methods: [
        function initE() {
          this.nodeName = 'span';
          this.
              cssClass(this.myCls()).
              add('Adjust the diameter of the circle at (', this.data.x$, ', ', this.data.y$, ').').
              tag('br').
              add(this.RangeView.create({data$: this.data.radius$, maxValue: 200, onKey: true}));
        }
      ]
    }
  ],

  properties: [
    'feedback_',
    'currentTool',
    {
      class: 'foam.dao.DAOProperty',
      name: 'tools',
      view: {
        class: 'foam.u2.TableView',
        columns: [ foam.core.Model.NAME ]
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'foam.core.Model',
          daoType: 'MDAO'
        });
        dao.put(foam.graphics.Circle.model_);
        dao.put(foam.graphics.Box.model_);
        dao.put(foam.graphics.Label.model_);
        return dao;
      }
    },
    {
      name: 'selected',
      postSet: function(o, n) {
        if ( o ) o.color = this.UNSELECTED_COLOR;
        if ( n ) n.color = this.SELECTED_COLOR;
      }
    },
    {
      name: 'canvas',
      factory: function() {
        return this.Box.create({width: 600, height: 500, color: '#f3f3f3'});
      }
    },
  ],

  methods: [

    function initE() {
      this.memento$.sub(function() {
        var m = this.memento;
        if ( this.feedback_ ) return;
        this.canvas.children = [];
        if ( m ) {
          for ( var i = 0 ; i < m.length ; i++ ) {
            var c = m[i];
            this.addCircle(c.x, c.y, c.radius);
          }
        }
        this.selected = null;
      }.bind(this));

      this.
          cssClass(this.myCls()).
          start(this.TOOLS, {selection$: this.currentTool$}).end().
          start('center').
            start(this.BACK,  {label: 'Undo'}).end().
            start(this.FORTH, {label: 'Redo'}).end().
            tag('br').
            start(this.canvas).
              on('click',       this.onClick).
              on('contextmenu', this.onRightClick).
            end().
          end();
    },

    function addCircle(x, y, opt_r) {
      var c = this.Circle.create({
        x: x,
        y: y,
        radius: opt_r || 25,
        color: this.UNSELECTED_COLOR,
        border: 'black'});

      this.canvas.addChildren(c);

      return c;
    },

    function updateMemento() {
      this.feedback_ = true;
      this.memento = this.canvas.children.map(function(c) {
        return {x: c.x, y: c.y, radius: c.radius};
      });
      this.feedback_ = false;
    }
  ],

  listeners: [
    function onClick(evt) {
      var x = evt.offsetX, y = evt.offsetY;
      var c = this.canvas.findFirstChildAt(x, y);

      if ( c ) {
        this.selected = c;
      } else {
        var tool = this.currentTool;
        if ( ! tool ) return;
        var cls = this.lookup(tool.id);
        var o = cls.create({
          x: x,
          y: y,
          text: 'Text',
          width: 50,
          height: 50,
          radius: 25
        });
        this.canvas.addChildren(o);
        this.selected = o;
        this.updateMemento();
      }
    },

    function onRightClick(evt) {
      evt.preventDefault();

      if ( ! this.selected ) return;

      var p = this.PopupView.create({
        width: 450,
        height: 110
      }).add(this.DiameterDialog.create({data: this.selected}));

      this.add(p);

      // If the size is changed with the dialog, then create an updated memento
      var oldRadius = this.selected.radius;
      p.onunload.sub(function() {
        if ( this.selected.radius !== oldRadius ) this.updateMemento();
      }.bind(this));
    }
  ]
});
<|endoftext|>


<commit_before>const gulp = require('gulp');
const tsc = require('gulp-typescript');
const Server = require('karma').Server;
const tsProject = tsc.createProject('src/tsconfig.json');

gulp.task('default', ['build']);
gulp.task('build', () => {
  return tsProject.src()
    .pipe(tsc(tsProject))
    .pipe(gulp.dest('.'));
});
gulp.task('build:commonjs', () => {
  const tsProjectCommonJS = tsc.createProject('src/tsconfig.json', {
    module: 'commonjs'
  });

  return tsProjectCommonJS.src()
    .pipe(tsc(tsProjectCommonJS))
    .pipe(gulp.dest('.'));
});
gulp.task('build:umd', () => {
  const tsProjectUMD = tsc.createProject('src/tsconfig.json', {
    module: 'umd'
  });

  return tsProjectUMD.src()
    .pipe(tsc(tsProjectUMD))
    .pipe(gulp.dest('.'));
});
gulp.task('test', ['test-build:spec', 'test-build:src'], () => {
  new Server({
    configFile: __dirname + '/karma.conf.js',
    singleRun: true,
    plugins: [
      'karma-jasmine',
      'karma-requirejs',
      'karma-spec-reporter',
      'karma-coverage',
      'karma-coveralls',
      'karma-phantomjs-launcher',
      'karma-chrome-launcher'
    ]
  }).start();
});
gulp.task('test:umd', ['test-build:spec', 'test-build:src:umd'], () => {
  new Server({
    configFile: __dirname + '/karma.conf.js',
    singleRun: true,
    plugins: [
      'karma-jasmine',
      'karma-requirejs',
      'karma-spec-reporter',
      'karma-coverage',
      'karma-coveralls',
      'karma-phantomjs-launcher',
      'karma-chrome-launcher'
    ]
  }).start();
});
gulp.task('test-build:spec', (done) => {
  const tsProjectSpec = tsc.createProject('spec/tsconfig.json');

  tsProjectSpec.src()
    .pipe(tsc(tsProjectSpec))
    .pipe(gulp.dest('test-build'))
    .on('end', done);
});
gulp.task('test-build:src', (done) => {
  tsProject.src()
    .pipe(tsc(tsProject))
    .pipe(gulp.dest('test-build/src'))
    .on('end', done);
});

gulp.task('test-build:src:umd', (done) => {
  const tsProjectUMD = tsc.createProject('src/tsconfig.json', {
    module: 'umd'
  });

  tsProjectUMD.src()
    .pipe(tsc(tsProjectUMD))
    .pipe(gulp.dest('test-build/src'))
    .on('end', done);
});
<commit_msg>Require gulp-mocha in gulpfile<commit_after>const gulp = require('gulp');
const tsc = require('gulp-typescript');
const Server = require('karma').Server;
const tsProject = tsc.createProject('src/tsconfig.json');
const mocha = require('gulp-mocha');

gulp.task('default', ['build']);
gulp.task('build', () => {
  return tsProject.src()
    .pipe(tsc(tsProject))
    .pipe(gulp.dest('.'));
});
gulp.task('build:commonjs', () => {
  const tsProjectCommonJS = tsc.createProject('src/tsconfig.json', {
    module: 'commonjs'
  });

  return tsProjectCommonJS.src()
    .pipe(tsc(tsProjectCommonJS))
    .pipe(gulp.dest('.'));
});
gulp.task('build:umd', () => {
  const tsProjectUMD = tsc.createProject('src/tsconfig.json', {
    module: 'umd'
  });

  return tsProjectUMD.src()
    .pipe(tsc(tsProjectUMD))
    .pipe(gulp.dest('.'));
});
gulp.task('test', ['test-build:spec', 'test-build:src'], () => {
  new Server({
    configFile: __dirname + '/karma.conf.js',
    singleRun: true,
    plugins: [
      'karma-jasmine',
      'karma-requirejs',
      'karma-spec-reporter',
      'karma-coverage',
      'karma-coveralls',
      'karma-phantomjs-launcher',
      'karma-chrome-launcher'
    ]
  }).start();
});
gulp.task('test:umd', ['test-build:spec', 'test-build:src:umd'], () => {
  new Server({
    configFile: __dirname + '/karma.conf.js',
    singleRun: true,
    plugins: [
      'karma-jasmine',
      'karma-requirejs',
      'karma-spec-reporter',
      'karma-coverage',
      'karma-coveralls',
      'karma-phantomjs-launcher',
      'karma-chrome-launcher'
    ]
  }).start();
});
gulp.task('test-build:spec', (done) => {
  const tsProjectSpec = tsc.createProject('spec/tsconfig.json');

  tsProjectSpec.src()
    .pipe(tsc(tsProjectSpec))
    .pipe(gulp.dest('test-build'))
    .on('end', done);
});
gulp.task('test-build:src', (done) => {
  tsProject.src()
    .pipe(tsc(tsProject))
    .pipe(gulp.dest('test-build/src'))
    .on('end', done);
});

gulp.task('test-build:src:umd', (done) => {
  const tsProjectUMD = tsc.createProject('src/tsconfig.json', {
    module: 'umd'
  });

  tsProjectUMD.src()
    .pipe(tsc(tsProjectUMD))
    .pipe(gulp.dest('test-build/src'))
    .on('end', done);
});
<|endoftext|>


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

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Property',
  ids: [ 'name' ],
  properties: [
    {
      class: 'String',
      name: 'name'
    },
    [ 'value',  0 ]
  ],
  actions: [
    {
      name: 'deleteRow',
      label: 'X',
      code: function deleteRow(X) {
        X.properties.remove(X.data);
      }
    }
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Clock',
  extends: 'com.google.foam.demos.clock.Clock',
  implements: [ 'foam.physics.Physical' ],
  properties: [
    [ 'gravity', 1 ],
    [ 'radius', 45 ],
    [ 'width', 90 ],
    [ 'height', 90 ]
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Text',
  extends: 'foam.graphics.Label',
  implements: [ 'foam.physics.Physical' ],
  properties: [
    [ 'gravity', 1 ],
    [ 'width',  100 ],
    [ 'height', 50 ],
    [ 'text', 'Text' ],
    [ 'color', '#000000' ],
    [ 'font', '50px Arial' ]
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Circle',
  extends: 'foam.graphics.Circle',
  implements: [ 'foam.physics.Physical' ],
  properties: [
    [ 'gravity', 1 ],
    [ 'radius',  25 ]
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Box',
  extends: 'foam.graphics.Box',
  implements: [ 'foam.physics.Physical' ],
  properties: [
    // [ 'mass',  0 ],
    [ 'width',  50 ],
    [ 'height', 50 ]
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'LivePaint',
  extends: 'foam.u2.Element',

  implements: [
    'foam.mlang.Expressions',
    'foam.memento.MementoMgr'
  ],

  requires: [
    'com.google.livepaint.Property',
    'foam.dao.EasyDAO',
    'foam.graphics.Box',
    'foam.graphics.CView',
    'foam.graphics.Circle',
    'foam.physics.Physical',
    'foam.physics.PhysicsEngine',
    'foam.u2.PopupView',
    'foam.u2.TableView'
  ],

  exports: [
    'as data',
    'properties'
  ],

  constants: {
    SELECTED_COLOR:   '#dddddd',
    UNSELECTED_COLOR: '#ffffff'
  },

  axioms: [
    foam.u2.CSS.create({
      code: function() {/*
      body { overflow: hidden }
      ^ { display: flex; }
      ^ > * { padding-left: 16px; padding-right: 16px; }
      ^tools, ^properties, ^sheet { box-shadow: 3px 3px 6px 0 gray; height: 100%; }
      ^sheet { width: 100%; overflow-y: scroll; }
      ^tools thead, ^properties thead { display: none }
      .foam-u2-TableView-selected { background: lightgray; }
      ^ canvas { border: 1px solid black; box-shadow: 3px 3px 6px 0 gray; }
      ^ .foam-u2-ActionView { margin: 10px; }
      ^properties .foam-u2-ActionView { background: white; padding: 0; margin: 2px; border: none; }
      */}
    })
  ],

  properties: [
    {
      name: 'physics',
      factory: function() {
        return this.PhysicsEngine.create({
          enableGravity: false,
          bounceOnWalls: true,
          bounds: this.canvas
        });
      }
    },
    'feedback_',
    'currentTool',
    {
      class: 'foam.dao.DAOProperty',
      name: 'tools',
      view: {
        class: 'foam.u2.TableView',
        columns: [ foam.core.Model.NAME ]
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'foam.core.Model',
          daoType: 'ARRAY'
        });
        dao.put(com.google.livepaint.Box.model_);
        dao.put(com.google.livepaint.Circle.model_);
        dao.put(com.google.livepaint.Text.model_);
        dao.put(com.google.livepaint.Clock.model_);
        dao.put(com.google.livepaint.Mushroom.model_);
        dao.put(com.google.foam.demos.robot.Robot.model_);
        dao.put(foam.audio.Speak.model_);
        dao.put(foam.audio.Beep.model_);
        return dao;
      }
    },
    {
      name: 'value',
      view: { class: 'foam.u2.DetailView', showActions: true }
    },
    {
      name: 'selected',
      postSet: function(o, n) {
        this.value = n && n.value;
        // TODO: check and only set if a CView
        if ( o ) { o.value.shadowBlur = 0; }
        if ( n ) { n.value.shadowBlur = 10; n.value.shadowColor = '#ff0000'; }
      }
    },
    {
      name: 'properties',
      view: {
        class: 'foam.u2.TableView',
        columns: [
          com.google.livepaint.Property.NAME,
          com.google.livepaint.Property.DELETE_ROW
        ]
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'com.google.livepaint.Property',
          guid: true,
          seqProperty: this.Property.NAME,
//          daoType: 'MDAO'
          daoType: 'ARRAY'
        });

        var p = this.Property.create({name: 'canvas', value: this.canvas});
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        p = this.Property.create({name: 'physics', value: this.physics});
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        return dao;
      }
    },
    {
      name: 'canvas',
      factory: function() {
        return this.Box.create({autoRepaint: true, width: 600, height: 600, color: '#f3f3f3'});
      }
    },
  ],

  methods: [

    function initE() {
      this.properties.on.put.sub(this.onPropertyPut);
      this.properties.on.remove.sub(this.onPropertyRemove);

      this.memento$.sub(function() {
        var m = this.memento;
        if ( this.feedback_ ) return;
        this.properties.removeAll();
        if ( m ) {
          for ( var i = 0 ; i < m.length ; i++ ) {
            var c = m[i];
            this.properties.put(c);
          }
        }
        this.selected = null;
      }.bind(this));

      this.
          cssClass(this.myCls()).
          start(this.TOOLS, {selection$: this.currentTool$}).cssClass(this.myCls('tools')).end().
          start('center').
            style({'padding-top': 0}).
            start(this.canvas).
              on('click',       this.onClick).
              on('contextmenu', this.onRightClick).
            end().
            tag('br').
            start(this.BACK,  {label: 'Undo'}).end().
            start(this.FORTH, {label: 'Redo'}).end().
          end().
          start('div').
            cssClass(this.myCls('properties')).
            start(this.PROPERTIES, {selection$: this.selected$}).end().
          end().
          start(this.VALUE).cssClass(this.myCls('sheet')).end();

      // this.physics.start();
    },

    function addProperty(value, opt_name, opt_i) {
      var self = this;
      if ( ! opt_name ) {
        var i = opt_i || 1;
        var prefix = value.cls_.name.toLowerCase();
        this.properties.find(prefix + i).then(function (o) {
          self.addProperty(value, null, i+1);
        }).catch(function(x) {
          self.addProperty(value, prefix+i);
        });
      } else {
        var p = this.Property.create({
          name: opt_name,
          value: value
        });
//        value.gravity = 1;
        value.setPrivate_('lpp_', p);
        this.properties.put(p);
        this.selected = p;
      }
    },

    function updateMemento() {
      this.feedback_ = true;
      this.memento = this.canvas.children.map(function(c) {
        return {x: c.x, y: c.y, radius: c.radius};
      });
      this.feedback_ = false;
    }
  ],

  actions: [
    {
      name: 'deleteProperty',
      label: 'X',
      code: function(X) {
        debugger;
      }
    }
  ],

  listeners: [
    function onPropertyPut(_, _, _, p) {
      var o = p.value;
      if ( this.CView.isInstance(o) ) {
        this.canvas.add(o);

        if ( this.Physical.isInstance(o) ) {
          this.physics.add(o);
        }
      }
    },

    function onPropertyRemove(_, _, _, p) {
      var o = p.value;
      if ( this.CView.isInstance(o) ) {
        this.canvas.remove(o);

        if ( this.Physical.isInstance(o) ) {
          this.physics.remove(o);
        }
      }
    },

    function onClick(evt) {
      var x = evt.offsetX, y = evt.offsetY;
      var c = this.canvas.findFirstChildAt(x, y);

      if ( c ) {
        var p = c.getPrivate_('lpp_');
        this.selected = p;
      } else {
        var tool = this.currentTool;
        if ( ! tool ) return;
        var cls = this.lookup(tool.id);
        var o = cls.create({x: x, y: y});
        var p = this.addProperty(o);
        this.updateMemento();
      }
    },

    function onRightClick(evt) {
      evt.preventDefault();

      if ( ! this.selected ) return;
    }
  ]
});
<commit_msg>Improved Livepaint CSS.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Property',
  ids: [ 'name' ],
  properties: [
    {
      class: 'String',
      name: 'name'
    },
    [ 'value',  0 ]
  ],
  actions: [
    {
      name: 'deleteRow',
      label: 'X',
      code: function deleteRow(X) {
        X.properties.remove(X.data);
      }
    }
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Clock',
  extends: 'com.google.foam.demos.clock.Clock',
  implements: [ 'foam.physics.Physical' ],
  properties: [
    [ 'gravity', 1 ],
    [ 'radius', 45 ],
    [ 'width', 90 ],
    [ 'height', 90 ]
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Text',
  extends: 'foam.graphics.Label',
  implements: [ 'foam.physics.Physical' ],
  properties: [
    [ 'gravity', 1 ],
    [ 'width',  100 ],
    [ 'height', 50 ],
    [ 'text', 'Text' ],
    [ 'color', '#000000' ],
    [ 'font', '50px Arial' ]
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Circle',
  extends: 'foam.graphics.Circle',
  implements: [ 'foam.physics.Physical' ],
  properties: [
    [ 'gravity', 1 ],
    [ 'radius',  25 ]
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'Box',
  extends: 'foam.graphics.Box',
  implements: [ 'foam.physics.Physical' ],
  properties: [
    // [ 'mass',  0 ],
    [ 'width',  50 ],
    [ 'height', 50 ]
  ]
});

foam.CLASS({
  package: 'com.google.livepaint',
  name: 'LivePaint',
  extends: 'foam.u2.Element',

  implements: [
    'foam.mlang.Expressions',
    'foam.memento.MementoMgr'
  ],

  requires: [
    'com.google.livepaint.Property',
    'foam.dao.EasyDAO',
    'foam.graphics.Box',
    'foam.graphics.CView',
    'foam.graphics.Circle',
    'foam.physics.Physical',
    'foam.physics.PhysicsEngine',
    'foam.u2.PopupView',
    'foam.u2.TableView'
  ],

  exports: [
    'as data',
    'properties'
  ],

  constants: {
    SELECTED_COLOR:   '#dddddd',
    UNSELECTED_COLOR: '#ffffff'
  },

  axioms: [
    foam.u2.CSS.create({
      code: function() {/*
      body { overflow: hidden }
      ^ { display: flex; }
      ^ > * { padding-left: 16px; padding-right: 16px; }
      ^tools, ^properties, ^sheet { box-shadow: 3px 3px 6px 0 gray; height: 100%; }
      ^sheet { width: 100%; overflow-y: scroll; }
      ^tools thead, ^properties thead { display: none }
      ^tools tr { height: 30px }
      .foam-u2-TableView { border-collapse: collapse; }
      .foam-u2-TableView-selected { border: 1px solid red; }
      ^ canvas { border: 1px solid black; box-shadow: 3px 3px 6px 0 gray; }
      ^ .foam-u2-ActionView { margin: 10px; }
      ^properties .foam-u2-ActionView { background: white; padding: 0; margin: 2px; border: none; }
      */}
    })
  ],

  properties: [
    {
      name: 'physics',
      factory: function() {
        return this.PhysicsEngine.create({
          enableGravity: false,
          bounceOnWalls: true,
          bounds: this.canvas
        });
      }
    },
    'feedback_',
    'currentTool',
    {
      class: 'foam.dao.DAOProperty',
      name: 'tools',
      view: {
        class: 'foam.u2.TableView',
        columns: [ foam.core.Model.NAME ]
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'foam.core.Model',
          daoType: 'ARRAY'
        });
        dao.put(com.google.livepaint.Box.model_);
        dao.put(com.google.livepaint.Circle.model_);
        dao.put(com.google.livepaint.Text.model_);
        dao.put(com.google.livepaint.Clock.model_);
        dao.put(com.google.livepaint.Mushroom.model_);
        dao.put(com.google.foam.demos.robot.Robot.model_);
        dao.put(foam.audio.Speak.model_);
        dao.put(foam.audio.Beep.model_);
        return dao;
      }
    },
    {
      name: 'value',
      view: { class: 'foam.u2.DetailView', showActions: true }
    },
    {
      name: 'selected',
      postSet: function(o, n) {
        this.value = n && n.value;
        // TODO: check and only set if a CView
        if ( o ) { o.value.shadowBlur = 0; }
        if ( n ) { n.value.shadowBlur = 10; n.value.shadowColor = '#ff0000'; }
      }
    },
    {
      name: 'properties',
      view: {
        class: 'foam.u2.TableView',
        columns: [
          com.google.livepaint.Property.NAME,
          com.google.livepaint.Property.DELETE_ROW
        ]
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'com.google.livepaint.Property',
          guid: true,
          seqProperty: this.Property.NAME,
//          daoType: 'MDAO'
          daoType: 'ARRAY'
        });

        var p = this.Property.create({name: 'canvas', value: this.canvas});
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        p = this.Property.create({name: 'physics', value: this.physics});
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        return dao;
      }
    },
    {
      name: 'canvas',
      factory: function() {
        return this.Box.create({autoRepaint: true, width: 600, height: 600, color: '#f3f3f3'});
      }
    },
  ],

  methods: [

    function initE() {
      this.properties.on.put.sub(this.onPropertyPut);
      this.properties.on.remove.sub(this.onPropertyRemove);

      this.memento$.sub(function() {
        var m = this.memento;
        if ( this.feedback_ ) return;
        this.properties.removeAll();
        if ( m ) {
          for ( var i = 0 ; i < m.length ; i++ ) {
            var c = m[i];
            this.properties.put(c);
          }
        }
        this.selected = null;
      }.bind(this));

      this.
          cssClass(this.myCls()).
          start('div').
            cssClass(this.myCls('tools')).
            start(this.TOOLS, {selection$: this.currentTool$}).end().
          end().
          start('center').
            style({'padding-top': 0}).
            start(this.canvas).
              on('click',       this.onClick).
              on('contextmenu', this.onRightClick).
            end().
            tag('br').
            start(this.BACK,  {label: 'Undo'}).end().
            start(this.FORTH, {label: 'Redo'}).end().
          end().
          start('div').
            cssClass(this.myCls('properties')).
            start(this.PROPERTIES, {selection$: this.selected$}).end().
          end().
          start(this.VALUE).cssClass(this.myCls('sheet')).end();

      // this.physics.start();
    },

    function addProperty(value, opt_name, opt_i) {
      var self = this;
      if ( ! opt_name ) {
        var i = opt_i || 1;
        var prefix = value.cls_.name.toLowerCase();
        this.properties.find(prefix + i).then(function (o) {
          self.addProperty(value, null, i+1);
        }).catch(function(x) {
          self.addProperty(value, prefix+i);
        });
      } else {
        var p = this.Property.create({
          name: opt_name,
          value: value
        });
//        value.gravity = 1;
        value.setPrivate_('lpp_', p);
        this.properties.put(p);
        this.selected = p;
      }
    },

    function updateMemento() {
      this.feedback_ = true;
      this.memento = this.canvas.children.map(function(c) {
        return {x: c.x, y: c.y, radius: c.radius};
      });
      this.feedback_ = false;
    }
  ],

  actions: [
    {
      name: 'deleteProperty',
      label: 'X',
      code: function(X) {
        debugger;
      }
    }
  ],

  listeners: [
    function onPropertyPut(_, _, _, p) {
      var o = p.value;
      if ( this.CView.isInstance(o) ) {
        this.canvas.add(o);

        if ( this.Physical.isInstance(o) ) {
          this.physics.add(o);
        }
      }
    },

    function onPropertyRemove(_, _, _, p) {
      var o = p.value;
      if ( this.CView.isInstance(o) ) {
        this.canvas.remove(o);

        if ( this.Physical.isInstance(o) ) {
          this.physics.remove(o);
        }
      }
    },

    function onClick(evt) {
      var x = evt.offsetX, y = evt.offsetY;
      var c = this.canvas.findFirstChildAt(x, y);

      if ( c ) {
        var p = c.getPrivate_('lpp_');
        this.selected = p;
      } else {
        var tool = this.currentTool;
        if ( ! tool ) return;
        var cls = this.lookup(tool.id);
        var o = cls.create({x: x, y: y});
        var p = this.addProperty(o);
        this.updateMemento();
      }
    },

    function onRightClick(evt) {
      evt.preventDefault();

      if ( ! this.selected ) return;
    }
  ]
});
<|endoftext|>


<commit_before>var del       = require('del'),
    sequence  = require('run-sequence'),
    highlight = require('highlight.js'),
    gulp      = require('gulp'),
    connect   = require('gulp-connect'),
    file      = require('gulp-file'),
    ghPages   = require('gulp-gh-pages'),
    markdown  = require('gulp-markdown'),
    rename    = require('gulp-rename'),
    sass      = require('gulp-sass'),
    util      = require('gulp-util');

var paths = {
      sass: ['docs/template/scss/*.scss', 'scss/*.scss', 'hocus-pocus.scss'],
  markdown: ['README.md', 'docs/*.md'],
  template: ['docs/template/index.html', 'docs/template/tag/*.tag']
};

gulp.task('sass', function() {
  return gulp.src('docs/template/scss/docs.scss')
    .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
    .pipe(gulp.dest('build/css'))
    .pipe(connect.reload());
});

gulp.task('markdown', function() {
  return gulp.src(['README.md', 'docs/*.md'])
    .pipe(rename(function(path) {
      if (path.basename === 'README') path.basename = 'home';
    }))
    .pipe(markdown({
      highlight: function (code, lang) {
        return highlight.highlightAuto(code, [lang]).value;
      }
    }))
    .pipe(gulp.dest('build/html'))
    .pipe(connect.reload());
});

gulp.task('img', function() {
  return gulp.src('docs/template/img/*.png')
    .pipe(gulp.dest('build/img'));
});

gulp.task('tag', function() {
  return gulp.src('docs/template/tag/*.tag')
    .pipe(gulp.dest('build/tag'))
    .pipe(connect.reload());
});

gulp.task('html', function() {
  return gulp.src('docs/template/index.html')
    .pipe(gulp.dest('build'))
    .pipe(connect.reload());
});

gulp.task('clean', function() {
  return del(['build']);
});

gulp.task('watch', function() {
  gulp.watch(paths.sass, ['sass']);
  gulp.watch(paths.markdown, ['markdown']);
  gulp.watch(paths.template, ['template']);
});

gulp.task('connect', function() {
  connect.server({
    root: 'build',
    livereload: true
  });
});

gulp.task('cname', function() {
  return file('CNAME', 'hocus-pocus.io', { src: true })
    .pipe(gulp.dest('build'));
});

gulp.task('deploy', function() {
  return gulp.src('build/**/*')
    .pipe(ghPages());
});

gulp.task('template', ['img', 'tag', 'html']);
gulp.task('build', ['sass', 'markdown', 'template', 'cname']);
gulp.task('default', ['serve']);

gulp.task('serve', function(callback) {
  sequence('clean', 'build', ['watch', 'connect'], callback);
});

gulp.task('publish', function(callback) {
  sequence('clean', 'build', 'deploy', callback);
});
<commit_msg>Remove CNAME<commit_after>var del       = require('del'),
    sequence  = require('run-sequence'),
    highlight = require('highlight.js'),
    gulp      = require('gulp'),
    connect   = require('gulp-connect'),
    file      = require('gulp-file'),
    ghPages   = require('gulp-gh-pages'),
    markdown  = require('gulp-markdown'),
    rename    = require('gulp-rename'),
    sass      = require('gulp-sass'),
    util      = require('gulp-util');

var paths = {
      sass: ['docs/template/scss/*.scss', 'scss/*.scss', 'hocus-pocus.scss'],
  markdown: ['README.md', 'docs/*.md'],
  template: ['docs/template/index.html', 'docs/template/tag/*.tag']
};

gulp.task('sass', function() {
  return gulp.src('docs/template/scss/docs.scss')
    .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
    .pipe(gulp.dest('build/css'))
    .pipe(connect.reload());
});

gulp.task('markdown', function() {
  return gulp.src(['README.md', 'docs/*.md'])
    .pipe(rename(function(path) {
      if (path.basename === 'README') path.basename = 'home';
    }))
    .pipe(markdown({
      highlight: function (code, lang) {
        return highlight.highlightAuto(code, [lang]).value;
      }
    }))
    .pipe(gulp.dest('build/html'))
    .pipe(connect.reload());
});

gulp.task('img', function() {
  return gulp.src('docs/template/img/*.png')
    .pipe(gulp.dest('build/img'));
});

gulp.task('tag', function() {
  return gulp.src('docs/template/tag/*.tag')
    .pipe(gulp.dest('build/tag'))
    .pipe(connect.reload());
});

gulp.task('html', function() {
  return gulp.src('docs/template/index.html')
    .pipe(gulp.dest('build'))
    .pipe(connect.reload());
});

gulp.task('clean', function() {
  return del(['build']);
});

gulp.task('watch', function() {
  gulp.watch(paths.sass, ['sass']);
  gulp.watch(paths.markdown, ['markdown']);
  gulp.watch(paths.template, ['template']);
});

gulp.task('connect', function() {
  connect.server({
    root: 'build',
    livereload: true
  });
});

gulp.task('deploy', function() {
  return gulp.src('build/**/*')
    .pipe(ghPages());
});

gulp.task('template', ['img', 'tag', 'html']);
gulp.task('build', ['sass', 'markdown', 'template']);
gulp.task('default', ['serve']);

gulp.task('serve', function(callback) {
  sequence('clean', 'build', ['watch', 'connect'], callback);
});

gulp.task('publish', function(callback) {
  sequence('clean', 'build', 'deploy', callback);
});
<|endoftext|>


<commit_before>const { init } = require('../src')

describe('plugins:', () => {
  xtest('should add onModel subscriptions', () => {
    const { modelHooks } = require('../src/core')
    const fns = [() => 1, () => 2]
    init({
      plugins: [
        { init: () => ({ onModel: fns[0] }) },
        { init: () => ({ onModel: fns[1] }) },
      ]
    })
    expect(modelHooks.slice(-2)).toEqual(fns)
  })

  xtest('should add multiple middleware', () => {
    const { pluginMiddlewares } = require('../src/core')
    const m1 = () => next => action => next(action)
    const m2 = () => next => action => next(action)
    init({
      plugins: [
        { init: () => ({ middleware: m1 }) },
        { init: () => ({ middleware: m2 }) },
      ]
    })
    expect(pluginMiddlewares.slice(-2)).toEqual([m1, m2])
  })

  test('should add a model', () => {
    const a = {
      state: 0,
    }
    const plugin = {
      config: {
        models: { a }
      }
    }
    const store = init({
      plugins: [plugin]
    })
    expect(store.getState()).toEqual({ a: 0 })
  })

  test('should add multiple models', () => {
    const a = {
      state: 0,
    }
    const b = {
      state: 0,
    }
    const plugin = {
      config: {
        models: { a, b }
      }
    }
    const store = init({
      plugins: [plugin]
    })
    expect(store.getState()).toEqual({ a: 0, b: 0 })
  })

  test('should merge plugin configs into configs', () => {
    const plugin1 = {
      config: {
        redux: {
          initialState: {
            app: 1
          }
        }
      },
    }
    const store = init({
      plugins: [plugin1],
    })
    expect(store.getState()).toEqual({ app: 1 })
  })
})
<commit_msg>Got these tests passing.<commit_after>const { init } = require('../src')

describe('plugins:', () => {
  test('should add onModel subscription', () => {
    let messageFromOnModel = null
    init({
      models: {
        count: { state: 0 }
      },
      plugins: [{
        onModel: () => {
          messageFromOnModel = 'Hello, Rematch!'
        }
      }]
    })
    expect(messageFromOnModel).toEqual('Hello, Rematch!')
  })

  test('should add middleware', () => {
    const payloadIsAlways100Middleware = () => next => action => {
      return next({ ...action, payload: 100 })
    }
    const store = init({
      models: {
        a: {
          state: 0,
          reducers: { set: (state, payload) => payload }
        }
      },
      plugins: [
        { middleware: payloadIsAlways100Middleware },
      ]
    })
    store.dispatch.a.set(1)
    expect(store.getState()).toEqual({ a: 100 })

  })

  test('should add a model', () => {
    const a = {
      state: 0,
    }
    const plugin = {
      config: {
        models: { a }
      }
    }
    const store = init({
      plugins: [plugin]
    })
    expect(store.getState()).toEqual({ a: 0 })
  })

  test('should add multiple models', () => {
    const a = {
      state: 0,
    }
    const b = {
      state: 0,
    }
    const plugin = {
      config: {
        models: { a, b }
      }
    }
    const store = init({
      plugins: [plugin]
    })
    expect(store.getState()).toEqual({ a: 0, b: 0 })
  })

  test('should merge plugin configs into configs', () => {
    const plugin1 = {
      config: {
        redux: {
          initialState: {
            app: 1
          }
        }
      },
    }
    const store = init({
      plugins: [plugin1],
    })
    expect(store.getState()).toEqual({ app: 1 })
  })
})
<|endoftext|>