<commit_before>/***
|''Name''|TiddlySpacePublishingCommands|
|''Version''|0.5.3|
|''Status''|@@beta@@|
|''Description''|toolbar commands for drafting and publishing|
|''Author''|Jon Robson|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpacePublishingCommands.js|
|''Requires''|TiddlySpaceConfig ServerSideSavingPlugin|
!Code
***/
//{{{
(function($) {

var tiddlyspace = config.extensions.tiddlyspace;

var cmd = config.commands.publishTiddler = {
	text: "publish",
	tooltip: "Change the public/private state of this tiddler",
	errorMsg: "Error publishing %0: %1",

	isEnabled: function(tiddler) {
		if(readOnly || !store.tiddlerExists(tiddler.title)) {
			return false;
		}
		var space = tiddlyspace.determineSpace(tiddler, true);
		return space && space.name == tiddlyspace.currentSpace.name &&
			space.type == "private";
	},
	handler: function(ev, src, title) {
		var tiddler = store.getTiddler(title);
		if(tiddler) {
			var newWorkspace = tiddler.fields["server.workspace"];
			newWorkspace = cmd.toggleWorkspace(newWorkspace);
			this.moveTiddler(tiddler, {
				title: tiddler.title,
				fields: { "server.workspace": newWorkspace }
			}, true);
		}
	},
	toggleBag: function(bag, to) {
		var newBag;
		if(typeof bag != typeof "") {
			var tiddler = bag;
			bag = tiddler.fields["server.bag"];
		}
		if(bag.indexOf("_private") > -1) { // should make use of endsWith
			to = to ? to : "public";
			newBag = bag.replace("_private", "_" + to);
		} else {
			to = to ? to : "private";
			newBag = bag.replace("_public", "_" + to);
		}
		return newBag;
	},
	toggleWorkspace: function(workspace, to) {
		if(typeof workspace != typeof "") {
			var tiddler = workspace;
			var bag = tiddler.fields["server.bag"];
			workspace = bag ? "bags/%0".format([bag]) : tiddler.fields["server.workspace"];
		}
		var newWorkspace;
		if(workspace.indexOf("_private") > -1) { // should make use of endsWith
			to = to ? to : "public";
			newWorkspace = workspace.replace("_private", "_" + to);
		} else {
			to = to ? to : "private";
			newWorkspace = workspace.replace("_public", "_" + to);
		}
		return newWorkspace;
	},
	copyTiddler: function(title, newWorkspace, callback) {
		var original = store.getTiddler(title);
		var space = tiddlyspace.determineSpace(original);
		var adaptor = original.getAdaptor();
		var publish = function(original, callback) {
			var tiddler = $.extend(new Tiddler(original.title), original);
			tiddler.fields = $.extend({}, original.fields, {
				"server.workspace": newWorkspace || "bags/%0_%1".format([space.name, type]),
				"server.page.revision": "false"
			});
			delete tiddler.fields["server.etag"];
			adaptor.putTiddler(tiddler, null, null, callback);
		};
		publish(original, callback);
	},
	moveTiddler: function(tiddler, newTiddler, withRevisions, callback) {
		if(withRevisions) {
			this.moveTiddlerWithRevisions(tiddler, newTiddler, callback);
		} else {
			var adaptor = tiddler.getAdaptor();
			var newTitle = newTiddler.title;
			var oldTitle = tiddler.title;
			var newWorkspace = newTiddler.fields["server.workspace"];

			cmd.copyTiddler(oldTitle, newWorkspace, function(ctx) {
					var context = {
						tiddler: tiddler,
						workspace: newWorkspace
					};
					tiddler.title = oldTitle; // for cases where a rename occurs
					if(ctx.status) { // only do if a success
						adaptor.deleteTiddler(tiddler, context, {}, function() {
							if(callback) {
								callback();
							} else {
								store.removeTiddler(oldTitle);
								story.closeTiddler(oldTitle);
								store.addTiddler(ctx.tiddler);
								story.refreshTiddler(newTitle, true);
								story.displayTiddler(place, newTitle);
							}
						});
					}
			});
		}
	},
	moveTiddlerWithRevisions: function(tiddler, newTiddler, callback) {
		var adaptor = tiddler.getAdaptor();
		var oldWorkspace = tiddler.fields["server.workspace"];
		var oldTitle = tiddler.title;
		var newTitle = newTiddler.title;
		var newWorkspace = newTiddler.fields["server.workspace"];

		// we first must delete any existing public revisions
		tiddler.title = newTitle;
		tiddler.fields["server.workspace"] = newWorkspace;
		tiddler.fields["server.page.revision"] = "false"; // force this action

		adaptor.deleteTiddler(tiddler, { workspace: newWorkspace }, {},
			function(ctx) {
				tiddler.fields["server.workspace"] = oldWorkspace; // rectify above change to workspace
				adaptor.moveTiddler(
					{ title: oldTitle, workspace: oldWorkspace },
					{ title: newTitle, workspace: newWorkspace },
					{}, {},
					function(context) {
						var newTiddler = context.tiddler;
						// some some reason the old tiddler is not being removed from the store (hence next 3 lines)
						var oldDirty = store.isDirty();
						store.removeTiddler(oldTitle);
						store.setDirty(oldDirty);
						store.addTiddler(newTiddler); // note the tiddler may have changed name
						if(callback) {
							callback();
						}
						var old = story.refreshTiddler(oldTitle, true);
						if(old) {
							story.displayTiddler(old, newTitle);
						}
					}
				);
		});
	}
};

config.commands.changeToPrivate = {
	text: "make private",
	tooltip: "turn this public tiddler into a private tiddler",
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var newWorkspace = cmd.toggleWorkspace(tiddler, "private");
		var newTiddler = { title: title, fields: { "server.workspace": newWorkspace }};
		cmd.moveTiddler(tiddler, newTiddler, true);
	}
};
config.commands.changeToPublic = {
	text: "make public",
	tooltip: "turn this private tiddler into a public tiddler",
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var newWorkspace = cmd.toggleWorkspace(tiddler, "public");
		var newTiddler = { title: title, fields: { "server.workspace": newWorkspace }};
		cmd.moveTiddler(tiddler, newTiddler, true);
	}
};

config.commands.deleteTiddler.deleteResource = function(tiddler, bag) {
	var workspace = "bags/%0".format([bag]);
	var oldDirty = store.isDirty();
	var originalBag = tiddler.fields["server.bag"];
	var originalWorkspace = "bags/%0".format([originalBag]);
	var deleteLocal = originalWorkspace == workspace;
	var context = {
		tiddler: tiddler,
		workspace: workspace
	};
	tiddler.fields["server.bag"] = bag;
	tiddler.fields["server.workspace"] = context.workspace;
	tiddler.fields["server.page.revision"] = "false";
	delete tiddler.fields["server.etag"];
	var callback;
	if(workspace == originalWorkspace) {
		callback = config.extensions.ServerSideSavingPlugin.removeTiddlerCallback;
	} else {
		callback = function(context, userParams) {
			if(context.status) {
				if(deleteLocal) { // remove it locally to trigger getting of public version
					store.removeTiddler(tiddler.title);
				}
				store.setDirty(oldDirty); // will fail to delete locally and throw an error
				tiddler.fields["server.workspace"] = originalWorkspace;
				tiddler.fields["server.bag"] = originalBag;
				story.refreshTiddler(tiddler.title, true);
			}
		};
	}
	tiddler.getAdaptor().deleteTiddler(tiddler, context, {}, callback);
};

config.commands.deletePublicTiddler = {
	text: "delete public",
	tooltip: "Delete any public versions of this tiddler",
	isEnabled: function(tiddler) {
		return tiddler.fields["server.workspace"];
	},
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var bag = cmd.toggleBag(tiddler, "public");
		config.commands.deleteTiddler.deleteResource(tiddler, bag);
	}
};

config.commands.deletePrivateTiddler = {
	text: "delete private",
	tooltip: "delete any private versions of this tiddler",
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var bag = cmd.toggleBag(tiddler, "private");
		config.commands.deleteTiddler.deleteResource(tiddler, bag);
	}
};
/* Save as draft command */
config.commands.saveDraft = {
	text: "save draft",
	tooltip: "Save as a private draft",
	isEnabled: function(tiddler) {
		if(tiddler) {
			var workspace = tiddler.fields["server.workspace"];
			if(workspace && workspace.indexOf("_public") > -1) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	},
	handler: function(ev, src, title) {
		// TODO: when creating a draft also copy over revisions from the public version
		var tiddler = store.getTiddler(title); // original tiddler
		var tidEl = story.getTiddler(title);
		var fields = {};
		story.gatherSaveFields(tidEl, fields);
		var extendedFields = merge({}, config.defaultCustomFields);
		var currentSpace = tiddlyspace.currentSpace.name;
		var privateWorkspace = "recipes/%0_private".format([currentSpace]);
		var draftTitle;
		var draftNum = "";
		while(!draftTitle) {
			var suggestedTitle = "%0 [draft%1]".format([title, draftNum]);
			if(store.getTiddler(suggestedTitle)) {
				draftNum = !draftNum ? 2 : draftNum + 1;
			} else {
				draftTitle = suggestedTitle;
			}
		}

		extendedFields["server.publish.name"] = title;
		extendedFields["server.workspace"] = privateWorkspace;
		var newDate = new Date();
		for(var n in fields) {
			if(!TiddlyWiki.isStandardField(n)) {
				extendedFields[n] = fields[n];
			}
		}
		tiddler = store.saveTiddler(draftTitle, draftTitle, fields.text, config.options.txtUserName,
			newDate, fields.tags, extendedFields);
		autoSaveChanges(null, [tiddler]);
		story.closeTiddler(title);
		story.displayTiddler(src, draftTitle);
		return draftTitle;
	}
};

})(jQuery);
//}}}
<commit_msg>in a move only delete the old tiddler if not same as the new tiddler<commit_after>/***
|''Name''|TiddlySpacePublishingCommands|
|''Version''|0.5.3|
|''Status''|@@beta@@|
|''Description''|toolbar commands for drafting and publishing|
|''Author''|Jon Robson|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpacePublishingCommands.js|
|''Requires''|TiddlySpaceConfig ServerSideSavingPlugin|
!Code
***/
//{{{
(function($) {

var tiddlyspace = config.extensions.tiddlyspace;

var cmd = config.commands.publishTiddler = {
	text: "publish",
	tooltip: "Change the public/private state of this tiddler",
	errorMsg: "Error publishing %0: %1",

	isEnabled: function(tiddler) {
		if(readOnly || !store.tiddlerExists(tiddler.title)) {
			return false;
		}
		var space = tiddlyspace.determineSpace(tiddler, true);
		return space && space.name == tiddlyspace.currentSpace.name &&
			space.type == "private";
	},
	handler: function(ev, src, title) {
		var tiddler = store.getTiddler(title);
		if(tiddler) {
			var newWorkspace = tiddler.fields["server.workspace"];
			newWorkspace = cmd.toggleWorkspace(newWorkspace);
			this.moveTiddler(tiddler, {
				title: tiddler.title,
				fields: { "server.workspace": newWorkspace }
			}, true);
		}
	},
	toggleBag: function(bag, to) {
		var newBag;
		if(typeof bag != typeof "") {
			var tiddler = bag;
			bag = tiddler.fields["server.bag"];
		}
		if(bag.indexOf("_private") > -1) { // should make use of endsWith
			to = to ? to : "public";
			newBag = bag.replace("_private", "_" + to);
		} else {
			to = to ? to : "private";
			newBag = bag.replace("_public", "_" + to);
		}
		return newBag;
	},
	toggleWorkspace: function(workspace, to) {
		if(typeof workspace != typeof "") {
			var tiddler = workspace;
			var bag = tiddler.fields["server.bag"];
			workspace = bag ? "bags/%0".format([bag]) : tiddler.fields["server.workspace"];
		}
		var newWorkspace;
		if(workspace.indexOf("_private") > -1) { // should make use of endsWith
			to = to ? to : "public";
			newWorkspace = workspace.replace("_private", "_" + to);
		} else {
			to = to ? to : "private";
			newWorkspace = workspace.replace("_public", "_" + to);
		}
		return newWorkspace;
	},
	copyTiddler: function(title, newWorkspace, callback) {
		var original = store.getTiddler(title);
		var space = tiddlyspace.determineSpace(original);
		var adaptor = original.getAdaptor();
		var publish = function(original, callback) {
			var tiddler = $.extend(new Tiddler(original.title), original);
			tiddler.fields = $.extend({}, original.fields, {
				"server.workspace": newWorkspace || "bags/%0_%1".format([space.name, type]),
				"server.page.revision": "false"
			});
			delete tiddler.fields["server.etag"];
			adaptor.putTiddler(tiddler, null, null, callback);
		};
		publish(original, callback);
	},
	moveTiddler: function(tiddler, newTiddler, withRevisions, callback) {
		if(withRevisions) {
			this.moveTiddlerWithRevisions(tiddler, newTiddler, callback);
		} else {
			var adaptor = tiddler.getAdaptor();
			var newTitle = newTiddler.title;
			var oldTitle = tiddler.title;
			var newWorkspace = newTiddler.fields["server.workspace"];

			cmd.copyTiddler(oldTitle, newWorkspace, function(ctx) {
					var context = {
						tiddler: tiddler,
						workspace: newWorkspace
					};
					tiddler.title = oldTitle; // for cases where a rename occurs
					if(ctx.status) { // only do if a success
						if(oldWorkspace != newWorkspace) {
							adaptor.deleteTiddler(tiddler, context, {}, function() {
								if(callback) {
									callback();
								} else {
									store.removeTiddler(oldTitle);
									story.closeTiddler(oldTitle);
									store.addTiddler(ctx.tiddler);
									story.refreshTiddler(newTitle, true);
									story.displayTiddler(place, newTitle);
								}
								store.setDirty(_dirty);
							});
						} else {
							story.refreshTiddler(newTitle, true);
						}
					}
			});
		}
	},
	moveTiddlerWithRevisions: function(tiddler, newTiddler, callback) {
		var adaptor = tiddler.getAdaptor();
		var oldWorkspace = tiddler.fields["server.workspace"];
		var oldTitle = tiddler.title;
		var newTitle = newTiddler.title;
		var newWorkspace = newTiddler.fields["server.workspace"];

		// we first must delete any existing public revisions
		tiddler.title = newTitle;
		tiddler.fields["server.workspace"] = newWorkspace;
		tiddler.fields["server.page.revision"] = "false"; // force this action

		adaptor.deleteTiddler(tiddler, { workspace: newWorkspace }, {},
			function(ctx) {
				tiddler.fields["server.workspace"] = oldWorkspace; // rectify above change to workspace
				adaptor.moveTiddler(
					{ title: oldTitle, workspace: oldWorkspace },
					{ title: newTitle, workspace: newWorkspace },
					{}, {},
					function(context) {
						var newTiddler = context.tiddler;
						// some some reason the old tiddler is not being removed from the store (hence next 3 lines)
						var oldDirty = store.isDirty();
						store.removeTiddler(oldTitle);
						store.setDirty(oldDirty);
						store.addTiddler(newTiddler); // note the tiddler may have changed name
						if(callback) {
							callback();
						}
						var old = story.refreshTiddler(oldTitle, true);
						if(old) {
							story.displayTiddler(old, newTitle);
						}
					}
				);
		});
	}
};

config.commands.changeToPrivate = {
	text: "make private",
	tooltip: "turn this public tiddler into a private tiddler",
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var newWorkspace = cmd.toggleWorkspace(tiddler, "private");
		var newTiddler = { title: title, fields: { "server.workspace": newWorkspace }};
		cmd.moveTiddler(tiddler, newTiddler, true);
	}
};
config.commands.changeToPublic = {
	text: "make public",
	tooltip: "turn this private tiddler into a public tiddler",
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var newWorkspace = cmd.toggleWorkspace(tiddler, "public");
		var newTiddler = { title: title, fields: { "server.workspace": newWorkspace }};
		cmd.moveTiddler(tiddler, newTiddler, true);
	}
};

config.commands.deleteTiddler.deleteResource = function(tiddler, bag) {
	var workspace = "bags/%0".format([bag]);
	var oldDirty = store.isDirty();
	var originalBag = tiddler.fields["server.bag"];
	var originalWorkspace = "bags/%0".format([originalBag]);
	var deleteLocal = originalWorkspace == workspace;
	var context = {
		tiddler: tiddler,
		workspace: workspace
	};
	tiddler.fields["server.bag"] = bag;
	tiddler.fields["server.workspace"] = context.workspace;
	tiddler.fields["server.page.revision"] = "false";
	delete tiddler.fields["server.etag"];
	var callback;
	if(workspace == originalWorkspace) {
		callback = config.extensions.ServerSideSavingPlugin.removeTiddlerCallback;
	} else {
		callback = function(context, userParams) {
			if(context.status) {
				if(deleteLocal) { // remove it locally to trigger getting of public version
					store.removeTiddler(tiddler.title);
				}
				store.setDirty(oldDirty); // will fail to delete locally and throw an error
				tiddler.fields["server.workspace"] = originalWorkspace;
				tiddler.fields["server.bag"] = originalBag;
				story.refreshTiddler(tiddler.title, true);
			}
		};
	}
	tiddler.getAdaptor().deleteTiddler(tiddler, context, {}, callback);
};

config.commands.deletePublicTiddler = {
	text: "delete public",
	tooltip: "Delete any public versions of this tiddler",
	isEnabled: function(tiddler) {
		return tiddler.fields["server.workspace"];
	},
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var bag = cmd.toggleBag(tiddler, "public");
		config.commands.deleteTiddler.deleteResource(tiddler, bag);
	}
};

config.commands.deletePrivateTiddler = {
	text: "delete private",
	tooltip: "delete any private versions of this tiddler",
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var bag = cmd.toggleBag(tiddler, "private");
		config.commands.deleteTiddler.deleteResource(tiddler, bag);
	}
};
/* Save as draft command */
config.commands.saveDraft = {
	text: "save draft",
	tooltip: "Save as a private draft",
	isEnabled: function(tiddler) {
		if(tiddler) {
			var workspace = tiddler.fields["server.workspace"];
			if(workspace && workspace.indexOf("_public") > -1) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	},
	handler: function(ev, src, title) {
		// TODO: when creating a draft also copy over revisions from the public version
		var tiddler = store.getTiddler(title); // original tiddler
		var tidEl = story.getTiddler(title);
		var fields = {};
		story.gatherSaveFields(tidEl, fields);
		var extendedFields = merge({}, config.defaultCustomFields);
		var currentSpace = tiddlyspace.currentSpace.name;
		var privateWorkspace = "recipes/%0_private".format([currentSpace]);
		var draftTitle;
		var draftNum = "";
		while(!draftTitle) {
			var suggestedTitle = "%0 [draft%1]".format([title, draftNum]);
			if(store.getTiddler(suggestedTitle)) {
				draftNum = !draftNum ? 2 : draftNum + 1;
			} else {
				draftTitle = suggestedTitle;
			}
		}

		extendedFields["server.publish.name"] = title;
		extendedFields["server.workspace"] = privateWorkspace;
		var newDate = new Date();
		for(var n in fields) {
			if(!TiddlyWiki.isStandardField(n)) {
				extendedFields[n] = fields[n];
			}
		}
		tiddler = store.saveTiddler(draftTitle, draftTitle, fields.text, config.options.txtUserName,
			newDate, fields.tags, extendedFields);
		autoSaveChanges(null, [tiddler]);
		story.closeTiddler(title);
		story.displayTiddler(src, draftTitle);
		return draftTitle;
	}
};

})(jQuery);
//}}}
<|endoftext|>


<commit_before>import Board from '../../frontend/src/shogi/board';
import Piece from '../../frontend/src/shogi/piece';
import Turn from '../../frontend/src/shogi/turn';
import * as CONST from '../../frontend/src/shogi/constants/boardTypes';
import memo from 'memo-is';
import _ from 'lodash';

describe('isTakenKing', () => {
  context.skip("if take the piece, king is taken", () => {
    const position = memo().is(() => {
      return (
        [
          ['*', 'p+', '*'],
          ['*', 'g', '*'],
          ['*', 'K', '*'],
        ]
      );
    });

    it('returns true', () => {
      const board = new Board(position());
      board.isTakenKing(new Turn).should.eql(true);
    });
  });

  context.skip("if moves the piece, king is taken", () => {
  });
});

describe('#invertCor', () => {
  const position = memo().is(() => {
    return (
      [
        ['l', 'n', 's', 'g', 'k', 'g', 's', 'n', 'l'],
        ['*', 'r', '*', '*', '*', '*', '*', 'b', '*'],
        ['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
        ['*', '*', '*', '*', '*', '*', '*', '*', '*'],
        ['*', '*', '*', '*', '*', '*', '*', '*', '*'],
        ['*', '*', '*', '*', '*', '*', '*', '*', '*'],
        ['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
        ['*', 'B', '*', '*', '*', '*', '*', 'R', '*'],
        ['L', 'N', 'S', 'G', 'K', 'G', 'S', 'N', 'L']
      ]
    );
  });

  it('pawn with 2, 7', () => {
    const board = new Board(position());
    const [x, y] = board().invertCor(2, 7);
    board().board[y][x].type.should.eql('P');
    board().board[y][x].x.should.eql(2);
    board().board[y][x].y.should.eql(7);
  });

  it('* with 3, 6', () => {
    const board = new Board(position());
    const [x, y] = board().invertCor(3, 6);
    board().board[y][x].type.should.eql('*');
    board().board[y][x].x.should.eql(3);
    board().board[y][x].y.should.eql(6);
  });
});

describe('#movePiece', () => {
  const position = memo().is(() => { return CONST.USI_INITIAL_BOARD; });

  context('once', () => {
    it('moved piece', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'P', x: 2, y: 7 });
      const toPiece = Piece.create({ type: '*', x: 2, y: 6 });

      const newBoard = board.movePiece(fromPiece, toPiece);
      newBoard.toArray().should.eql(
        [
          [ 'l', 'n', 's', 'g', 'k', 'g', 's', 'n', 'l' ],
          [ '*', 'r', '*', '*', '*', '*', '*', 'b', '*' ],
          [ 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ '*', '*', '*', '*', '*', '*', '*', 'P', '*' ],
          [ 'P', 'P', 'P', 'P', 'P', 'P', 'P', '*', 'P' ],
          [ '*', 'B', '*', '*', '*', '*', '*', 'R', '*' ],
          [ 'L', 'N', 'S', 'G', 'K', 'G', 'S', 'N', 'L' ]
        ]
      );
    });

    // NOTE: if this.board is changed, reducer does not recognize state changing.
    //       Therefore, this.board does not change after #movePiece.
    it('does not change this.board', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'P', x: 2, y: 7 });
      const toPiece = Piece.create({ type: '*', x: 2, y: 6 });

      board.movePiece(fromPiece, toPiece);

      board.toArray().should.eql(
        [
          [ 'l', 'n', 's', 'g', 'k', 'g', 's', 'n', 'l' ],
          [ '*', 'r', '*', '*', '*', '*', '*', 'b', '*' ],
          [ 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P' ],
          [ '*', 'B', '*', '*', '*', '*', '*', 'R', '*' ],
          [ 'L', 'N', 'S', 'G', 'K', 'G', 'S', 'N', 'L' ]
        ]
      );
    });
  });

  context('take the opponent piece', () => {
    const position = memo().is(() => {
      return (
        [
          [ '*', '*', '*' ],
          [ '*', 'p', '*' ],
          [ '*', 'P', '*' ],
        ]
      );
    });

    it('has the property `capturedPiece`', () => {
      const board = new Board(position());
      const fromPiece = new Piece.create({ type: 'P', x: 8, y: 3 });
      const toPiece = new Piece.create({ type: 'p', x: 8, y: 2 });

      board.movePiece(fromPiece, toPiece).capturedPiece.should.eql(toPiece);
    });
  });
});

describe('#checkPieceExistence', () => {
  context('the piece exists in the board', () => {
    const position = memo().is(() => {
      return [
        [ '*', 'k' ],
        [ 'P', 'p' ]
      ];
    });

    it('return true', () => {
      const board = new Board(position());
      const piece = Piece.create({ type: 'P', x: 9, y: 2 });
      board.checkPieceExistence(piece).should.be.true();
    });
  });

  context('the piece does not exist in the board', () => {
    const position = memo().is(() => {
      return [
        [ '*', 'k' ],
        [ 'P', 'p' ]
      ];
    });

    it('throw exception true', () => {
      const board = new Board(position());
      const piece = Piece.create({ type: 'k', x: 9, y: 1 });
      (() => { board.checkPieceExistence(piece); })
        .should
        .throw('Does not match coordinates in board. type = k, xCor = 9, yCor = 1');
    });
  });
});

describe('isTakingPiece', () => {
  context('when destination piece is opponent\'s piece', () => {
    const position = memo().is(() => {
      return [
        ['*', '*', '*'],
        ['*', 'p', '*'],
        ['*', 'P', '*'],
      ];
    });

    it('return true', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'P', x: 8, y: 3 });
      const toPiece = Piece.create({ type: 'p', x: 8, y: 2 });

      board.isTakingPiece(fromPiece, toPiece).should.be.true();
    });
  });

  context('when destination piece is supporter\'s piece', () => {
    const position = memo().is(() => {
      return [
        ['*', '*', '*'],
        ['*', 'l', '*'],
        ['*', 'l', '*'],
      ];
    });

    it('return false', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'l', x: 8, y: 2 });
      const toPiece = Piece.create({ type: 'l', x: 8, y: 3 });

      board.isTakingPiece(fromPiece, toPiece).should.be.false();
    });
  });

  context('when destination piece is empty', () => {
    const position = memo().is(() => {
      return [
        ['*', '*', '*'],
        ['*', '*', '*'],
        ['*', 'P', '*'],
      ];
    });

    it('return false', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'P', x: 8, y: 3 });
      const toPiece = Piece.create({ type: '*', x: 8, y: 2 });

      board.isTakingPiece(fromPiece, toPiece).should.be.false();
    });
  });
});

describe('#promotePiece', () => {
  context('specified piece exists', () => {
    context('black', () => {
      const position = memo().is(() => {
        return [
          ['*', '*', '*'],
          ['*', 'P', '*'],
          ['*', '*', '*'],
        ];
      });

      it('promote piece', () => {
        const board = new Board(position());
        const piece = Piece.create({ type: 'P', x: 8, y: 2 });

        board.promotePiece(piece).toArray().should.eql(
          [
            ['*', '*', '*'],
            ['*', 'P+', '*'],
            ['*', '*', '*'],
          ]
        );
      });
    });

    context('white', () => {
      const position = memo().is(() => {
        return [
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', 'p', '*'],
          ['*', '*', '*'],
        ];
      });

      it('promote piece', () => {
        const board = new Board(position());
        const piece = Piece.create({ type: 'p', x: 8, y: 8});

        board.promotePiece(piece).toArray().should.eql(
          [
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', 'p+', '*'],
            ['*', '*', '*'],
          ]
        );
      });
    });

    context('piece is already promoted', () => {
      const position = memo().is(() => {
        return [
          ['*', '*', '*'],
          ['*', 'G', '*'],
          ['*', '*', '*'],
        ];
      });

      it('does not promote piece', () => {
        const board = new Board(position());
        const piece = Piece.create({ type: 'G', x: 8, y: 2 });

        board.promotePiece(piece).toArray().should.eql(
          [
            ['*', '*', '*'],
            ['*', 'G', '*'],
            ['*', '*', '*'],
          ]
        );
      });
    });
  });

  context('specified piece does not exist', () => {
    const position = memo().is(() => {
      return [
        ['*', '*', '*'],
        ['*', '*', '*'],
        ['*', 'P', '*'],
      ];
    });

    it('throw error', () => {
      const board = new Board(position());
      const piece = Piece.create({ type: 'B', x: 9, y: 2 });
      (() => { board.promotePiece(piece); }).should.throw();
    });
  });
});
<commit_msg>Refactor. Fix functional call because board isn't function.<commit_after>import Board from '../../frontend/src/shogi/board';
import Piece from '../../frontend/src/shogi/piece';
import Turn from '../../frontend/src/shogi/turn';
import * as CONST from '../../frontend/src/shogi/constants/boardTypes';
import memo from 'memo-is';
import _ from 'lodash';

describe('isTakenKing', () => {
  context.skip("if take the piece, king is taken", () => {
    const position = memo().is(() => {
      return (
        [
          ['*', 'p+', '*'],
          ['*', 'g', '*'],
          ['*', 'K', '*'],
        ]
      );
    });

    it('returns true', () => {
      const board = new Board(position());
      board.isTakenKing(new Turn).should.eql(true);
    });
  });

  context.skip("if moves the piece, king is taken", () => {
  });
});

describe('#invertCor', () => {
  const position = memo().is(() => {
    return (
      [
        ['l', 'n', 's', 'g', 'k', 'g', 's', 'n', 'l'],
        ['*', 'r', '*', '*', '*', '*', '*', 'b', '*'],
        ['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
        ['*', '*', '*', '*', '*', '*', '*', '*', '*'],
        ['*', '*', '*', '*', '*', '*', '*', '*', '*'],
        ['*', '*', '*', '*', '*', '*', '*', '*', '*'],
        ['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
        ['*', 'B', '*', '*', '*', '*', '*', 'R', '*'],
        ['L', 'N', 'S', 'G', 'K', 'G', 'S', 'N', 'L']
      ]
    );
  });

  it('pawn with 2, 7', () => {
    const board = new Board(position());
    const [x, y] = board.invertCor(2, 7);
    board.board[y][x].type.should.eql('P');
    board.board[y][x].x.should.eql(2);
    board.board[y][x].y.should.eql(7);
  });

  it('* with 3, 6', () => {
    const board = new Board(position());
    const [x, y] = board.invertCor(3, 6);
    board.board[y][x].type.should.eql('*');
    board.board[y][x].x.should.eql(3);
    board.board[y][x].y.should.eql(6);
  });
});

describe('#movePiece', () => {
  const position = memo().is(() => { return CONST.USI_INITIAL_BOARD; });

  context('once', () => {
    it('moved piece', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'P', x: 2, y: 7 });
      const toPiece = Piece.create({ type: '*', x: 2, y: 6 });

      const newBoard = board.movePiece(fromPiece, toPiece);
      newBoard.toArray().should.eql(
        [
          [ 'l', 'n', 's', 'g', 'k', 'g', 's', 'n', 'l' ],
          [ '*', 'r', '*', '*', '*', '*', '*', 'b', '*' ],
          [ 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ '*', '*', '*', '*', '*', '*', '*', 'P', '*' ],
          [ 'P', 'P', 'P', 'P', 'P', 'P', 'P', '*', 'P' ],
          [ '*', 'B', '*', '*', '*', '*', '*', 'R', '*' ],
          [ 'L', 'N', 'S', 'G', 'K', 'G', 'S', 'N', 'L' ]
        ]
      );
    });

    // NOTE: if this.board is changed, reducer does not recognize state changing.
    //       Therefore, this.board does not change after #movePiece.
    it('does not change this.board', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'P', x: 2, y: 7 });
      const toPiece = Piece.create({ type: '*', x: 2, y: 6 });

      board.movePiece(fromPiece, toPiece);

      board.toArray().should.eql(
        [
          [ 'l', 'n', 's', 'g', 'k', 'g', 's', 'n', 'l' ],
          [ '*', 'r', '*', '*', '*', '*', '*', 'b', '*' ],
          [ 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ '*', '*', '*', '*', '*', '*', '*', '*', '*' ],
          [ 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P' ],
          [ '*', 'B', '*', '*', '*', '*', '*', 'R', '*' ],
          [ 'L', 'N', 'S', 'G', 'K', 'G', 'S', 'N', 'L' ]
        ]
      );
    });
  });

  context('take the opponent piece', () => {
    const position = memo().is(() => {
      return (
        [
          [ '*', '*', '*' ],
          [ '*', 'p', '*' ],
          [ '*', 'P', '*' ],
        ]
      );
    });

    it('has the property `capturedPiece`', () => {
      const board = new Board(position());
      const fromPiece = new Piece.create({ type: 'P', x: 8, y: 3 });
      const toPiece = new Piece.create({ type: 'p', x: 8, y: 2 });

      board.movePiece(fromPiece, toPiece).capturedPiece.should.eql(toPiece);
    });
  });
});

describe('#checkPieceExistence', () => {
  context('the piece exists in the board', () => {
    const position = memo().is(() => {
      return [
        [ '*', 'k' ],
        [ 'P', 'p' ]
      ];
    });

    it('return true', () => {
      const board = new Board(position());
      const piece = Piece.create({ type: 'P', x: 9, y: 2 });
      board.checkPieceExistence(piece).should.be.true();
    });
  });

  context('the piece does not exist in the board', () => {
    const position = memo().is(() => {
      return [
        [ '*', 'k' ],
        [ 'P', 'p' ]
      ];
    });

    it('throw exception true', () => {
      const board = new Board(position());
      const piece = Piece.create({ type: 'k', x: 9, y: 1 });
      (() => { board.checkPieceExistence(piece); })
        .should
        .throw('Does not match coordinates in board. type = k, xCor = 9, yCor = 1');
    });
  });
});

describe('isTakingPiece', () => {
  context('when destination piece is opponent\'s piece', () => {
    const position = memo().is(() => {
      return [
        ['*', '*', '*'],
        ['*', 'p', '*'],
        ['*', 'P', '*'],
      ];
    });

    it('return true', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'P', x: 8, y: 3 });
      const toPiece = Piece.create({ type: 'p', x: 8, y: 2 });

      board.isTakingPiece(fromPiece, toPiece).should.be.true();
    });
  });

  context('when destination piece is supporter\'s piece', () => {
    const position = memo().is(() => {
      return [
        ['*', '*', '*'],
        ['*', 'l', '*'],
        ['*', 'l', '*'],
      ];
    });

    it('return false', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'l', x: 8, y: 2 });
      const toPiece = Piece.create({ type: 'l', x: 8, y: 3 });

      board.isTakingPiece(fromPiece, toPiece).should.be.false();
    });
  });

  context('when destination piece is empty', () => {
    const position = memo().is(() => {
      return [
        ['*', '*', '*'],
        ['*', '*', '*'],
        ['*', 'P', '*'],
      ];
    });

    it('return false', () => {
      const board = new Board(position());
      const fromPiece = Piece.create({ type: 'P', x: 8, y: 3 });
      const toPiece = Piece.create({ type: '*', x: 8, y: 2 });

      board.isTakingPiece(fromPiece, toPiece).should.be.false();
    });
  });
});

describe('#promotePiece', () => {
  context('specified piece exists', () => {
    context('black', () => {
      const position = memo().is(() => {
        return [
          ['*', '*', '*'],
          ['*', 'P', '*'],
          ['*', '*', '*'],
        ];
      });

      it('promote piece', () => {
        const board = new Board(position());
        const piece = Piece.create({ type: 'P', x: 8, y: 2 });

        board.promotePiece(piece).toArray().should.eql(
          [
            ['*', '*', '*'],
            ['*', 'P+', '*'],
            ['*', '*', '*'],
          ]
        );
      });
    });

    context('white', () => {
      const position = memo().is(() => {
        return [
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', '*', '*'],
          ['*', 'p', '*'],
          ['*', '*', '*'],
        ];
      });

      it('promote piece', () => {
        const board = new Board(position());
        const piece = Piece.create({ type: 'p', x: 8, y: 8});

        board.promotePiece(piece).toArray().should.eql(
          [
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', '*', '*'],
            ['*', 'p+', '*'],
            ['*', '*', '*'],
          ]
        );
      });
    });

    context('piece is already promoted', () => {
      const position = memo().is(() => {
        return [
          ['*', '*', '*'],
          ['*', 'G', '*'],
          ['*', '*', '*'],
        ];
      });

      it('does not promote piece', () => {
        const board = new Board(position());
        const piece = Piece.create({ type: 'G', x: 8, y: 2 });

        board.promotePiece(piece).toArray().should.eql(
          [
            ['*', '*', '*'],
            ['*', 'G', '*'],
            ['*', '*', '*'],
          ]
        );
      });
    });
  });

  context('specified piece does not exist', () => {
    const position = memo().is(() => {
      return [
        ['*', '*', '*'],
        ['*', '*', '*'],
        ['*', 'P', '*'],
      ];
    });

    it('throw error', () => {
      const board = new Board(position());
      const piece = Piece.create({ type: 'B', x: 9, y: 2 });
      (() => { board.promotePiece(piece); }).should.throw();
    });
  });
});
<|endoftext|>


<commit_before>/***
|''Name''|TiddlySpaceTiddlerIconsPlugin|
|''Version''|0.21|
|''Status''|beta|
|''Description''|Provides ability to render SiteIcons and icons that correspond to the home location of given tiddlers|
|''Requires''|TiddlySpaceConfig ImageMacroPlugin|
|''Source''||
!Notes
Provides an additional SiteIcon view for use with view macro
{{{<<view modifier SiteIcon>>}}}
will show the SiteIcon located in the space with the same name as modifier.
It also works if the attribute given ends with _private or _public (so {{{<<view server.bag SiteIcon>>}}} is usable).

{{{<<tiddlerOrigin>>}}} shows the origin of the tiddler it is being run on.
In TiddlySpace terms this means it will determine whether the tiddler is external, public or private.
Where private it will analyse whether a public version exists and distinguish between the different scenarios.
If a tiddler is external, the SiteIcon of that external space will be shown

When a ViewTemplate contains an element with class concertina, clicking on the icon outputted by the tiddlerOrigin macro
will reveal more detailed information on what the icon means.
!Parameters
both take the same parameters
width / height : define a width or height of the outputted icon
label: if label parameter is set to yes, a label will accompany the icon.

!!additional view parameters
labelPrefix / labelSuffix : prefix or suffix the label with additional text. eg. labelPrefix:'modified by '
!Code
***/
//{{{
(function($) {

if(!config.macros.image) {
	throw "Missing dependency: ImageMacroPlugin";
}

var imageMacro = config.macros.image;
var tweb = config.extensions.tiddlyweb;
var tiddlyspace = config.extensions.tiddlyspace;

config.macros.view.views.SiteIcon = function(value, place, params, wikifier,
		paramString, tiddler) {
	var publicSuffix = value.indexOf("_public");
	var privateSuffix = value.indexOf("_private");
	if(publicSuffix == value.length - 7) {
		value = value.substr(0, publicSuffix);
	} else if(privateSuffix == value.length - 8) {
		value = value.substr(0, privateSuffix);
	}
	if(value == "None") { // the default modifier might be None meaning no-one.
		value = false;
	}
	var args = paramString.parseParams("name", null, true, false, true)[0];
	var labelPrefix = args.labelPrefix ? args.labelPrefix[0] : "";
	var labelSuffix = args.labelSuffix ? args.labelSuffix[0] : "";
	var imageOptions = imageMacro.getArguments(paramString, []);
	tweb.getStatus(function(status) {
		var container = $('
');
		var uri = tiddlyspace.getAvatar(status.server_host, {name: value});
		var extraArgs = params.splice(2, params.length - 2).join(" ");
		var imageOptions = imageMacro.getArguments(extraArgs, []);
		imageMacro.renderImage(container, uri, imageOptions);
		if(!value) {
			value = "tiddlyspace";
		}
		$('
').
			text("%0%1%2".format([labelPrefix, value, labelSuffix])).
			appendTo(container);
		$(container).prependTo(place);
		$(container).attr("title", value).attr("alt", value);
	});
};

var originMacro = config.macros.tiddlerOrigin = {
	locale: {
		"private": "private",
		"public": "public",
		"privateAndPublic": "public and private tiddler",
		"privateNotPublic": "new draft of public",
		"external": "from %0",
		"external_info": "This tiddler was written by %0 in the %1 space. \n It is visible to all at:\n%2",
		"private_info": "This tiddler is currently private.\n It is visible to only members of this space at:\n%2",
		"public_info": "This tiddler is currently public with no private revision.\nIt is visible to all at:\n%2",
		"privateAndPublic_info": "This tiddler is currently public without any later private revisions.\nIt is visible to all at:\n%2",
		"privateNotPublic_info": "This tiddler is currently public, with a later private revision.\nIt is visible to all at:\n%2\nbut the content will differ depending on permissions.",
		"unknownUser": "an unknown user"
	},

	handler: function(place, macroName, params,wikifier, paramString, tiddler){
		var adaptor = tiddler.getAdaptor();
		var imageOptions = imageMacro.getArguments(paramString, []);
		var locale = originMacro.locale;
		var type = "private";
		var parsedParams = paramString.parseParams("name")[0];
		var includeLabel = parsedParams.label && parsedParams.label[0] == "yes";
		if(store.tiddlerExists(tiddler.title) || store.isShadowTiddler(tiddler.title)) {
			var space = tiddlyspace.determineSpace(tiddler, true);
			type = space && space.name == tiddlyspace.currentSpace.name ? space.type : "external";

			var tidEl = story.findContainingTiddler(place);
			var concertina = $(".concertina", tidEl)[0];
			var concertinaButton = $('').
				click(function() {
					if($(tidEl).hasClass("concertinaOn")) {
						$(tidEl).removeClass("concertinaOn");
						$(concertina).hide(500);
					} else {
						$(tidEl).addClass("concertinaOn");
						$(concertina).show(500, function() {
							$(concertina).attr("style", "display:block;"); // jQuery uses the filter for opacity
						});
					}
				}).appendTo(place)[0];

			var label;
			var showLabel = function(type) {
				$(tidEl).
					removeClass("private public external privateAndPublic privateNotPublic").
					addClass(type);
				if(includeLabel) {
					$('
').text(label).appendTo(concertinaButton);
				}
				$(concertinaButton).prependTo(place).attr("title", label);
			};

			if(type != "external") {
				var showPrivacyRoundel = function(context) {
					if(context && context.status) { // there is a public tiddler as well as the current tiddler!
						// to do: not this is not enough.. we also need to check if the public tiddler is the same as..
						// .. the private tiddler to determine whether this is a draft
						// use of hashes would be useful here.
						if(context.tiddler.modified < tiddler.modified) { // public is older so therefore this is a draft
							label = locale.privateNotPublic;
							type = "privateNotPublic";
						} else {
							label = locale.privateAndPublic;
							type = "privateAndPublic";
						}
					}
					imageMacro.renderImage(concertinaButton, "%0Icon".format([type]), imageOptions);
					showLabel(type);
					originMacro.fillConcertina(concertina, type, tiddler);
				};
				if(type == "private") { //check for a public version
					var context = {
						workspace: "bags/%0_public".format([space.name])
					};
					label = locale["private"];
					adaptor.getTiddler(tiddler.title, context, null, showPrivacyRoundel);
				} else {
					label = locale["public"];
					showPrivacyRoundel();
				}
			} else {
				label = locale.external.format([space.name || "tiddlyspace"]);
				tweb.getStatus(function(status) {
					var uri = tiddlyspace.getAvatar(status.server_host, space);
					imageMacro.renderImage(concertinaButton, uri, imageOptions);
					showLabel(type);
					originMacro.fillConcertina(concertina, type, tiddler);
				});
			}
		}
	},
	fillConcertina: function(place, privacyType, tiddler) {
		if(!place) {
			return;
		} else {
			var locale = originMacro.locale;
			var space = tiddlyspace.determineSpace(tiddler);
			space = space.name ? space.name : false;
			tweb.getStatus(function(status) {
				var modifier = tiddler.modifier;
				if(modifier == "None") {
					modifier = locale.unknownUser;
				}
				var spaceLink, link;
				if(!space) {
					space = "core";
					link = "[[/%0|/%0]]".format([tiddler.title]);
				} else {
					spaceLink = tiddlyspace.getHost(status.server_host, space);
					space = "[[%0|%1]]".format([space, spaceLink]);
					link = "[[%0/%1]]".format([spaceLink, tiddler.title]);
				}

				var localeString = locale["%0_info".format([privacyType])];
				if(localeString){
					wikify(localeString.format([modifier, space, link]), place);
				}
			});
		}
	}
};

})(jQuery);
//}}}
<commit_msg>fixed handling of shadow tiddlers in SiteIcon view<commit_after>/***
|''Name''|TiddlySpaceTiddlerIconsPlugin|
|''Version''|0.21|
|''Status''|beta|
|''Description''|Provides ability to render SiteIcons and icons that correspond to the home location of given tiddlers|
|''Requires''|TiddlySpaceConfig ImageMacroPlugin|
|''Source''||
!Notes
Provides an additional SiteIcon view for use with view macro
{{{<<view modifier SiteIcon>>}}}
will show the SiteIcon located in the space with the same name as modifier.
It also works if the attribute given ends with _private or _public (so {{{<<view server.bag SiteIcon>>}}} is usable).

{{{<<tiddlerOrigin>>}}} shows the origin of the tiddler it is being run on.
In TiddlySpace terms this means it will determine whether the tiddler is external, public or private.
Where private it will analyse whether a public version exists and distinguish between the different scenarios.
If a tiddler is external, the SiteIcon of that external space will be shown

When a ViewTemplate contains an element with class concertina, clicking on the icon outputted by the tiddlerOrigin macro
will reveal more detailed information on what the icon means.
!Parameters
both take the same parameters
width / height : define a width or height of the outputted icon
label: if label parameter is set to yes, a label will accompany the icon.

!!additional view parameters
labelPrefix / labelSuffix : prefix or suffix the label with additional text. eg. labelPrefix:'modified by '
!Code
***/
//{{{
(function($) {

if(!config.macros.image) {
	throw "Missing dependency: ImageMacroPlugin";
}

var imageMacro = config.macros.image;
var tweb = config.extensions.tiddlyweb;
var tiddlyspace = config.extensions.tiddlyspace;

config.macros.view.views.SiteIcon = function(value, place, params, wikifier,
		paramString, tiddler) {
	var publicSuffix = value.indexOf("_public");
	var privateSuffix = value.indexOf("_private");
	if(publicSuffix == value.length - 7) {
		value = value.substr(0, publicSuffix);
	} else if(privateSuffix == value.length - 8) {
		value = value.substr(0, privateSuffix);
	}
	if(!store.tiddlerExists(tiddler.title) || value == "None") { // some core tiddlers lack modifier
		value = false;
	}
	var args = paramString.parseParams("name", null, true, false, true)[0];
	var labelPrefix = args.labelPrefix ? args.labelPrefix[0] : "";
	var labelSuffix = args.labelSuffix ? args.labelSuffix[0] : "";
	var imageOptions = imageMacro.getArguments(paramString, []);
	tweb.getStatus(function(status) {
		var container = $('
');
		var uri = tiddlyspace.getAvatar(status.server_host, {name: value});
		var extraArgs = params.splice(2, params.length - 2).join(" ");
		var imageOptions = imageMacro.getArguments(extraArgs, []);
		imageMacro.renderImage(container, uri, imageOptions);
		if(!value) {
			value = "tiddlyspace";
		}
		$('
').
			text("%0%1%2".format([labelPrefix, value, labelSuffix])).
			appendTo(container);
		$(container).prependTo(place);
		$(container).attr("title", value).attr("alt", value);
	});
};

var originMacro = config.macros.tiddlerOrigin = {
	locale: {
		"private": "private",
		"public": "public",
		"privateAndPublic": "public and private tiddler",
		"privateNotPublic": "new draft of public",
		"external": "from %0",
		"external_info": "This tiddler was written by %0 in the %1 space. \n It is visible to all at:\n%2",
		"private_info": "This tiddler is currently private.\n It is visible to only members of this space at:\n%2",
		"public_info": "This tiddler is currently public with no private revision.\nIt is visible to all at:\n%2",
		"privateAndPublic_info": "This tiddler is currently public without any later private revisions.\nIt is visible to all at:\n%2",
		"privateNotPublic_info": "This tiddler is currently public, with a later private revision.\nIt is visible to all at:\n%2\nbut the content will differ depending on permissions.",
		"unknownUser": "an unknown user"
	},

	handler: function(place, macroName, params,wikifier, paramString, tiddler){
		var adaptor = tiddler.getAdaptor();
		var imageOptions = imageMacro.getArguments(paramString, []);
		var locale = originMacro.locale;
		var type = "private";
		var parsedParams = paramString.parseParams("name")[0];
		var includeLabel = parsedParams.label && parsedParams.label[0] == "yes";
		if(store.tiddlerExists(tiddler.title) || store.isShadowTiddler(tiddler.title)) {
			var space = tiddlyspace.determineSpace(tiddler, true);
			type = space && space.name == tiddlyspace.currentSpace.name ? space.type : "external";

			var tidEl = story.findContainingTiddler(place);
			var concertina = $(".concertina", tidEl)[0];
			var concertinaButton = $('').
				click(function() {
					if($(tidEl).hasClass("concertinaOn")) {
						$(tidEl).removeClass("concertinaOn");
						$(concertina).hide(500);
					} else {
						$(tidEl).addClass("concertinaOn");
						$(concertina).show(500, function() {
							$(concertina).attr("style", "display:block;"); // jQuery uses the filter for opacity
						});
					}
				}).appendTo(place)[0];

			var label;
			var showLabel = function(type) {
				$(tidEl).
					removeClass("private public external privateAndPublic privateNotPublic").
					addClass(type);
				if(includeLabel) {
					$('
').text(label).appendTo(concertinaButton);
				}
				$(concertinaButton).prependTo(place).attr("title", label);
			};

			if(type != "external") {
				var showPrivacyRoundel = function(context) {
					if(context && context.status) { // there is a public tiddler as well as the current tiddler!
						// to do: not this is not enough.. we also need to check if the public tiddler is the same as..
						// .. the private tiddler to determine whether this is a draft
						// use of hashes would be useful here.
						if(context.tiddler.modified < tiddler.modified) { // public is older so therefore this is a draft
							label = locale.privateNotPublic;
							type = "privateNotPublic";
						} else {
							label = locale.privateAndPublic;
							type = "privateAndPublic";
						}
					}
					imageMacro.renderImage(concertinaButton, "%0Icon".format([type]), imageOptions);
					showLabel(type);
					originMacro.fillConcertina(concertina, type, tiddler);
				};
				if(type == "private") { //check for a public version
					var context = {
						workspace: "bags/%0_public".format([space.name])
					};
					label = locale["private"];
					adaptor.getTiddler(tiddler.title, context, null, showPrivacyRoundel);
				} else {
					label = locale["public"];
					showPrivacyRoundel();
				}
			} else {
				label = locale.external.format([space.name || "tiddlyspace"]);
				tweb.getStatus(function(status) {
					var uri = tiddlyspace.getAvatar(status.server_host, space);
					imageMacro.renderImage(concertinaButton, uri, imageOptions);
					showLabel(type);
					originMacro.fillConcertina(concertina, type, tiddler);
				});
			}
		}
	},
	fillConcertina: function(place, privacyType, tiddler) {
		if(!place) {
			return;
		} else {
			var locale = originMacro.locale;
			var space = tiddlyspace.determineSpace(tiddler);
			space = space.name ? space.name : false;
			tweb.getStatus(function(status) {
				var modifier = tiddler.modifier;
				if(modifier == "None") {
					modifier = locale.unknownUser;
				}
				var spaceLink, link;
				if(!space) {
					space = "core";
					link = "[[/%0|/%0]]".format([tiddler.title]);
				} else {
					spaceLink = tiddlyspace.getHost(status.server_host, space);
					space = "[[%0|%1]]".format([space, spaceLink]);
					link = "[[%0/%1]]".format([spaceLink, tiddler.title]);
				}

				var localeString = locale["%0_info".format([privacyType])];
				if(localeString){
					wikify(localeString.format([modifier, space, link]), place);
				}
			});
		}
	}
};

})(jQuery);
//}}}
<|endoftext|>


<commit_before>//Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var ContainerPlugin = require('container_plugin')
var Events = require('events')

class ClickToPausePlugin extends ContainerPlugin {
  get name() { return 'click_to_pause' }

  constructor(options) {
    if (!options.chromeless) {
      super(options)
    }
  }

  bindEvents() {
    this.listenTo(this.container, Events.CONTAINER_CLICK, this.click)
    this.listenTo(this.container, Events.CONTAINER_SETTINGSUPDATE, this.settingsUpdate)
  }

  click() {
    if (this.container.getPlaybackType() !== 'live' || this.container.isDvrEnabled()) {
      if (this.container.isPlaying()) {
        this.container.pause()
      } else {
        this.container.play()
      }
    }
  }

  settingsUpdate() {
    this.container.$el.removeClass('pointer-enabled')
    if (this.container.getPlaybackType() !== 'live' || this.container.isDvrEnabled()) {
      this.container.$el.addClass('pointer-enabled')
    }
  }
}

module.exports = ClickToPausePlugin
<commit_msg>click_to_pause: add stopListening() method<commit_after>//Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var ContainerPlugin = require('container_plugin')
var Events = require('events')

class ClickToPausePlugin extends ContainerPlugin {
  get name() { return 'click_to_pause' }

  constructor(options) {
    if (!options.chromeless) {
      super(options)
    }
  }

  bindEvents() {
    this.listenTo(this.container, Events.CONTAINER_CLICK, this.click)
    this.listenTo(this.container, Events.CONTAINER_SETTINGSUPDATE, this.settingsUpdate)
  }

  stopListening() {
    this.stopListening(this.container, Events.CONTAINER_CLICK)
    this.stopListening(this.container, Events.CONTAINER_SETTINGSUPDATE)
  }

  click() {
    if (this.container.getPlaybackType() !== 'live' || this.container.isDvrEnabled()) {
      if (this.container.isPlaying()) {
        this.container.pause()
      } else {
        this.container.play()
      }
    }
  }

  settingsUpdate() {
    this.container.$el.removeClass('pointer-enabled')
    if (this.container.getPlaybackType() !== 'live' || this.container.isDvrEnabled()) {
      this.container.$el.addClass('pointer-enabled')
    }
  }
}

module.exports = ClickToPausePlugin
<|endoftext|>


<commit_before>const path = require('path')
const instance = require('src/index')
const args = require('src/args')
const fixtures = require('test/fixtures/instance')
const output = require('src/output')
const proc = require('src/proc')
const services = require('src/services')

const configPath = path.resolve(__dirname, '../fixtures/devlab.yml')

describe('index', () => {
  global.instanceId = 'test'
  let processCwdStub
  let outputSuccessStub
  let outputSpinnerStub
  let outputErrorStub
  let outputLineStub
  before(() => {
    processCwdStub = sinon.stub(process, 'cwd', () => '/tmp')
    outputSpinnerStub = sinon.stub(output, 'spinner', () => {
      return { succeed: () => null, fail: () => null }
    })
    outputLineStub = sinon.stub(output, 'line')
    outputSuccessStub = sinon.stub(output, 'success')
    outputErrorStub = sinon.stub(output, 'error')
  })
  after(() => {
    processCwdStub.restore()
    outputSpinnerStub.restore()
    outputSuccessStub.restore()
    outputErrorStub.restore()
    outputLineStub.restore()
  })
  describe('startServices', () => {
    let servicesRunStub
    afterEach(() => {
      if (servicesRunStub) servicesRunStub.restore()
    })
    it('imediately resolves if there are no services', () => {
      const cfg = { services: [] }
      return expect(instance.startServices(cfg)).to.be.fulfilled()
    })
    it('resolves after services are successfully started', () => {
      const cfg = { services: [ 'foo', 'bar' ] }
      servicesRunStub = sinon.stub(services, 'run', () => Promise.resolve())
      return expect(instance.startServices(cfg)).to.be.fulfilled()
    })
    it('rejects after services fail to start', () => {
      const cfg = { services: [ 'foo' ] }
      servicesRunStub = sinon.stub(services, 'run', () => Promise.reject())
      return expect(instance.startServices(cfg)).to.be.rejected()
    })
  })
  describe('runCommand', () => {
    let procRunStub
    afterEach(() => {
      procRunStub.restore()
    })
    it('starts command, succeeds, and resolves with stopServices', () => {
      procRunStub = sinon.stub(proc, 'run', () => Promise.resolve())
      return instance.runCommand({ primary: [ 'foo' ] })
        .then(() => {
          expect(outputLineStub).to.be.called()
          expect(outputSuccessStub).to.be.called()
        })
    })
    it('starts command, fails, and throws', () => {
      procRunStub = sinon.stub(proc, 'run', () => Promise.reject(1))
      return expect(instance.runCommand({ primary: [ 'foo' ] })).to.be.rejectedWith('Command failed')
    })
  })
  describe('getConfig', () => {
    it('loads config and args and returns exec run command objects', () => {
      args.raw = { f: 'node:6', e: 'echo "foo"', _: [], c: configPath }
      expect(instance.getConfig()).to.deep.equal(fixtures.exec)
    })
    it('loads config and args and returns task run command objects', () => {
      args.raw = { f: 'node:6', _: [ 'env' ], c: configPath }
      expect(instance.getConfig()).to.deep.equal(fixtures.task)
    })
  })
  describe('start', () => {
    afterEach(() => {
      if (instance.startServices.restore) instance.startServices.restore()
      if (instance.runCommand.restore) instance.runCommand.restore()
      if (instance.getConfig.restore) instance.getConfig.restore()
    })
    it('outputs default failure message if rejected without error message', () => {
      sinon.stub(instance, 'getConfig', () => {
        const err = new Error()
        err.message = undefined
        throw err
      })
      return expect(instance.start()).to.be.rejectedWith('Process failed')
    })
    it('throws and outputs error when config throws', () => {
      args.raw = { 'not-a-flag': true, _: [ 'env' ], c: configPath }
      return instance.start().then(() => new Error('Should have failed'))
        .catch(() => {
          expect(outputErrorStub).to.be.calledWith('Invalid argument \'not-a-flag\', please see documentation')
        })
    })
    it('throws when unable to start services', () => {
      sinon.stub(instance, 'startServices', () => Promise.reject())
      args.raw = { _: [ 'env' ], c: configPath }
      return expect(instance.start()).to.be.rejected()
    })
    it('throws when unable to start primary container', () => {
      sinon.stub(instance, 'runCommand', () => Promise.reject())
      args.raw = { 'f': 'notactuallyanimage', _: [ 'env' ], c: configPath }
      return expect(instance.start()).to.be.rejected()
    })
    it('resolves when config, services and primary container run successfully', () => {
      sinon.stub(instance, 'startServices', () => Promise.resolve())
      sinon.stub(instance, 'runCommand', () => Promise.resolve())
      args.raw = { _: [ 'env' ], c: configPath }
      return expect(instance.start()).to.be.fulfilled()
    })
  })
})
<commit_msg>test(instance): stub service start so CI doesn't timeout<commit_after>const path = require('path')
const instance = require('src/index')
const args = require('src/args')
const fixtures = require('test/fixtures/instance')
const output = require('src/output')
const proc = require('src/proc')
const services = require('src/services')

const configPath = path.resolve(__dirname, '../fixtures/devlab.yml')

describe('index', () => {
  global.instanceId = 'test'
  let processCwdStub
  let outputSuccessStub
  let outputSpinnerStub
  let outputErrorStub
  let outputLineStub
  before(() => {
    processCwdStub = sinon.stub(process, 'cwd', () => '/tmp')
    outputSpinnerStub = sinon.stub(output, 'spinner', () => {
      return { succeed: () => null, fail: () => null }
    })
    outputLineStub = sinon.stub(output, 'line')
    outputSuccessStub = sinon.stub(output, 'success')
    outputErrorStub = sinon.stub(output, 'error')
  })
  after(() => {
    processCwdStub.restore()
    outputSpinnerStub.restore()
    outputSuccessStub.restore()
    outputErrorStub.restore()
    outputLineStub.restore()
  })
  describe('startServices', () => {
    let servicesRunStub
    afterEach(() => {
      if (servicesRunStub) servicesRunStub.restore()
    })
    it('imediately resolves if there are no services', () => {
      const cfg = { services: [] }
      return expect(instance.startServices(cfg)).to.be.fulfilled()
    })
    it('resolves after services are successfully started', () => {
      const cfg = { services: [ 'foo', 'bar' ] }
      servicesRunStub = sinon.stub(services, 'run', () => Promise.resolve())
      return expect(instance.startServices(cfg)).to.be.fulfilled()
    })
    it('rejects after services fail to start', () => {
      const cfg = { services: [ 'foo' ] }
      servicesRunStub = sinon.stub(services, 'run', () => Promise.reject())
      return expect(instance.startServices(cfg)).to.be.rejected()
    })
  })
  describe('runCommand', () => {
    let procRunStub
    afterEach(() => {
      procRunStub.restore()
    })
    it('starts command, succeeds, and resolves with stopServices', () => {
      procRunStub = sinon.stub(proc, 'run', () => Promise.resolve())
      return instance.runCommand({ primary: [ 'foo' ] })
        .then(() => {
          expect(outputLineStub).to.be.called()
          expect(outputSuccessStub).to.be.called()
        })
    })
    it('starts command, fails, and throws', () => {
      procRunStub = sinon.stub(proc, 'run', () => Promise.reject(1))
      return expect(instance.runCommand({ primary: [ 'foo' ] })).to.be.rejectedWith('Command failed')
    })
  })
  describe('getConfig', () => {
    it('loads config and args and returns exec run command objects', () => {
      args.raw = { f: 'node:6', e: 'echo "foo"', _: [], c: configPath }
      expect(instance.getConfig()).to.deep.equal(fixtures.exec)
    })
    it('loads config and args and returns task run command objects', () => {
      args.raw = { f: 'node:6', _: [ 'env' ], c: configPath }
      expect(instance.getConfig()).to.deep.equal(fixtures.task)
    })
  })
  describe('start', () => {
    afterEach(() => {
      if (instance.startServices.restore) instance.startServices.restore()
      if (instance.runCommand.restore) instance.runCommand.restore()
      if (instance.getConfig.restore) instance.getConfig.restore()
    })
    it('outputs default failure message if rejected without error message', () => {
      sinon.stub(instance, 'getConfig', () => {
        const err = new Error()
        err.message = undefined
        throw err
      })
      return expect(instance.start()).to.be.rejectedWith('Process failed')
    })
    it('throws and outputs error when config throws', () => {
      args.raw = { 'not-a-flag': true, _: [ 'env' ], c: configPath }
      return instance.start().then(() => new Error('Should have failed'))
        .catch(() => {
          expect(outputErrorStub).to.be.calledWith('Invalid argument \'not-a-flag\', please see documentation')
        })
    })
    it('throws when unable to start services', () => {
      sinon.stub(instance, 'startServices', () => Promise.reject())
      args.raw = { _: [ 'env' ], c: configPath }
      return expect(instance.start()).to.be.rejected()
    })
    it('throws when unable to start primary container', () => {
      sinon.stub(instance, 'startServices', () => Promise.resolve())
      sinon.stub(instance, 'runCommand', () => Promise.reject())
      args.raw = { 'f': 'notactuallyanimage', _: [ 'env' ], c: configPath }
      return expect(instance.start()).to.be.rejected()
    })
    it('resolves when config, services and primary container run successfully', () => {
      sinon.stub(instance, 'startServices', () => Promise.resolve())
      sinon.stub(instance, 'runCommand', () => Promise.resolve())
      args.raw = { _: [ 'env' ], c: configPath }
      return expect(instance.start()).to.be.fulfilled()
    })
  })
})
<|endoftext|>


<commit_before>const assert = require('assert');
const path = require('path');
const moduleWatcher = require('../../src/index');

describe('#index', () => {

    it('moduleWatcher.send()', () => {
        let name = 'script';
        let options = {
            modules: [name],
            assets: path.join(__dirname, '..', 'dist', 'assets.json'),
            program: {
                command: 'node ${modulePath}/send.js'
            }
        };
        let context = path.join(__dirname, '..', 'file');

        return moduleWatcher(options, context).then(assets => {

            let mod = assets.modules[name];

            assert.deepEqual({
                index: 'index.js'
            }, mod.chunks);

            assert.deepEqual([
                'index.js',
                'index.js.map',
                'index.css'
            ], mod.assets);

        });
    });

});
<commit_msg>添加测试用例<commit_after>const assert = require('assert');
const path = require('path');
const moduleWatcher = require('../../src/index');

describe('#index', () => {

    it('moduleWatcher.send()', () => {
        let name = 'script';
        let options = {
            modules: [name],
            assets: path.join(__dirname, '..', 'dist', 'assets.json'),
            program: {
                command: 'node ${modulePath}/send.js'
            }
        };
        let context = path.join(__dirname, '..', 'file');

        return moduleWatcher(options, context).then(assets => {

            let mod = assets.modules[name];

            assert.deepEqual([name], assets.latest);
            assert.deepEqual('string', typeof assets.revision['../file/script']);

            assert.deepEqual({
                index: 'index.js'
            }, mod.chunks);

            assert.deepEqual([
                'index.js',
                'index.js.map',
                'index.css'
            ], mod.assets);

        });
    });

});
<|endoftext|>


<commit_before>/**
 * Plugin.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

define(
  'tinymce.plugins.imagetools.Plugin',
  [
    'ephox.imagetools.api.BlobConversions',
    'ephox.imagetools.api.ImageTransformations',
    'tinymce.core.Env',
    'tinymce.core.PluginManager',
    'tinymce.core.util.Delay',
    'tinymce.core.util.Promise',
    'tinymce.core.util.Tools',
    'tinymce.core.util.URI',
    'tinymce.plugins.imagetools.core.ImageSize',
    'tinymce.plugins.imagetools.core.Proxy',
    'tinymce.plugins.imagetools.ui.Dialog'
  ],
  function (
    BlobConversions, ImageTransformations, Env, PluginManager, Delay, Promise, Tools,
    URI, ImageSize, Proxy, Dialog
  ) {
    var plugin = function (editor) {
      var count = 0, imageUploadTimer, lastSelectedImage;

      if (!Env.fileApi) {
        return;
      }

      function displayError(error) {
        editor.notificationManager.open({
          text: error,
          type: 'error'
        });
      }

      function getSelectedImage() {
        return editor.selection.getNode();
      }

      function extractFilename(url) {
        var m = url.match(/\/([^\/\?]+)?\.(?:jpeg|jpg|png|gif)(?:\?|$)/i);
        if (m) {
          return editor.dom.encode(m[1]);
        }
        return null;
      }

      function createId() {
        return 'imagetools' + count++;
      }

      function isLocalImage(img) {
        var url = img.src;

        return url.indexOf('data:') === 0 || url.indexOf('blob:') === 0 || new URI(url).host === editor.documentBaseURI.host;
      }

      function isCorsImage(img) {
        return Tools.inArray(editor.settings.imagetools_cors_hosts, new URI(img.src).host) !== -1;
      }

      function getApiKey() {
        return editor.settings.api_key || editor.settings.imagetools_api_key;
      }

      function imageToBlob(img) {
        var src = img.src, apiKey;

        if (isCorsImage(img)) {
          return Proxy.getUrl(img.src, null);
        }

        if (!isLocalImage(img)) {
          src = editor.settings.imagetools_proxy;
          src += (src.indexOf('?') === -1 ? '?' : '&') + 'url=' + encodeURIComponent(img.src);
          apiKey = getApiKey();
          return Proxy.getUrl(src, apiKey);
        }

        return BlobConversions.imageToBlob(img);
      }

      function findSelectedBlob() {
        var blobInfo;

        blobInfo = editor.editorUpload.blobCache.getByUri(getSelectedImage().src);
        if (blobInfo) {
          return blobInfo.blob();
        }

        return imageToBlob(getSelectedImage());
      }

      function startTimedUpload() {
        imageUploadTimer = Delay.setEditorTimeout(editor, function () {
          editor.editorUpload.uploadImagesAuto();
        }, editor.settings.images_upload_timeout || 30000);
      }

      function cancelTimedUpload() {
        clearTimeout(imageUploadTimer);
      }

      function updateSelectedImage(ir, uploadImmediately) {
        return ir.toBlob().then(function (blob) {
          var uri, name, blobCache, blobInfo, selectedImage;

          blobCache = editor.editorUpload.blobCache;
          selectedImage = getSelectedImage();
          uri = selectedImage.src;

          if (editor.settings.images_reuse_filename) {
            blobInfo = blobCache.getByUri(uri);
            if (blobInfo) {
              uri = blobInfo.uri();
              name = blobInfo.name();
            } else {
              name = extractFilename(uri);
            }
          }

          blobInfo = blobCache.create({
            id: createId(),
            blob: blob,
            base64: ir.toBase64(),
            uri: uri,
            name: name
          });

          blobCache.add(blobInfo);

          editor.undoManager.transact(function () {
            function imageLoadedHandler() {
              editor.$(selectedImage).off('load', imageLoadedHandler);
              editor.nodeChanged();

              if (uploadImmediately) {
                editor.editorUpload.uploadImagesAuto();
              } else {
                cancelTimedUpload();
                startTimedUpload();
              }
            }

            editor.$(selectedImage).on('load', imageLoadedHandler);

            editor.$(selectedImage).attr({
              src: blobInfo.blobUri()
            }).removeAttr('data-mce-src');
          });

          return blobInfo;
        });
      }

      function selectedImageOperation(fn) {
        return function () {
          return editor._scanForImages().
            then(findSelectedBlob).
            then(BlobConversions.blobToImageResult).
            then(fn).
            then(updateSelectedImage, displayError);
        };
      }

      function rotate(angle) {
        return function () {
          return selectedImageOperation(function (imageResult) {
            var size = ImageSize.getImageSize(getSelectedImage());

            if (size) {
              ImageSize.setImageSize(getSelectedImage(), {
                w: size.h,
                h: size.w
              });
            }

            return ImageTransformations.rotate(imageResult, angle);
          })();
        };
      }

      function flip(axis) {
        return function () {
          return selectedImageOperation(function (imageResult) {
            return ImageTransformations.flip(imageResult, axis);
          })();
        };
      }

      function editImageDialog() {
        var img = getSelectedImage(), originalSize = ImageSize.getNaturalImageSize(img);

        var handleDialogBlob = function (blob) {
          return new Promise(function (resolve) {
            BlobConversions.blobToImage(blob).
              then(function (newImage) {
                var newSize = ImageSize.getNaturalImageSize(newImage);

                if (originalSize.w != newSize.w || originalSize.h != newSize.h) {
                  if (ImageSize.getImageSize(img)) {
                    ImageSize.setImageSize(img, newSize);
                  }
                }

                URL.revokeObjectURL(newImage.src);
                resolve(blob);
              });
          });
        };

        var openDialog = function (imageResult) {
          return Dialog.edit(imageResult).then(handleDialogBlob).
            then(BlobConversions.blobToImageResult).
            then(function (imageResult) {
              return updateSelectedImage(imageResult, true);
            }, function () {
              // Close dialog
            });
        };

        findSelectedBlob().
          then(BlobConversions.blobToImageResult).
          then(openDialog, displayError);
      }

      function addButtons() {
        editor.addButton('rotateleft', {
          title: 'Rotate counterclockwise',
          cmd: 'mceImageRotateLeft'
        });

        editor.addButton('rotateright', {
          title: 'Rotate clockwise',
          cmd: 'mceImageRotateRight'
        });

        editor.addButton('flipv', {
          title: 'Flip vertically',
          cmd: 'mceImageFlipVertical'
        });

        editor.addButton('fliph', {
          title: 'Flip horizontally',
          cmd: 'mceImageFlipHorizontal'
        });

        editor.addButton('editimage', {
          title: 'Edit image',
          cmd: 'mceEditImage'
        });

        editor.addButton('imageoptions', {
          title: 'Image options',
          icon: 'options',
          cmd: 'mceImage'
        });

        /*
        editor.addButton('crop', {
          title: 'Crop',
          onclick: startCrop
        });
        */
      }

      function addEvents() {
        editor.on('NodeChange', function (e) {
          // If the last node we selected was an image
          // And had a source that doesn't match the current blob url
          // We need to attempt to upload it
          if (lastSelectedImage && lastSelectedImage.src != e.element.src) {
            cancelTimedUpload();
            editor.editorUpload.uploadImagesAuto();
            lastSelectedImage = undefined;
          }

          // Set up the lastSelectedImage
          if (isEditableImage(e.element)) {
            lastSelectedImage = e.element;
          }
        });
      }

      function isEditableImage(img) {
        var selectorMatched = editor.dom.is(img, 'img:not([data-mce-object],[data-mce-placeholder])');

        return selectorMatched && (isLocalImage(img) || isCorsImage(img) || editor.settings.imagetools_proxy);
      }

      function addToolbars() {
        var toolbarItems = editor.settings.imagetools_toolbar;

        if (!toolbarItems) {
          toolbarItems = 'rotateleft rotateright | flipv fliph | crop editimage imageoptions';
        }

        editor.addContextToolbar(
          isEditableImage,
          toolbarItems
        );
      }

      Tools.each({
        mceImageRotateLeft: rotate(-90),
        mceImageRotateRight: rotate(90),
        mceImageFlipVertical: flip('v'),
        mceImageFlipHorizontal: flip('h'),
        mceEditImage: editImageDialog
      }, function (fn, cmd) {
        editor.addCommand(cmd, fn);
      });

      addButtons();
      addToolbars();
      addEvents();
    };

    PluginManager.add('imagetools', plugin);

    return function () { };
  }
);
<commit_msg>TINY-1081, imagetools: findSelectedBlob() has to be promise-compliant in all logic paths<commit_after>/**
 * Plugin.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

define(
  'tinymce.plugins.imagetools.Plugin',
  [
    'ephox.imagetools.api.BlobConversions',
    'ephox.imagetools.api.ImageTransformations',
    'tinymce.core.Env',
    'tinymce.core.PluginManager',
    'tinymce.core.util.Delay',
    'tinymce.core.util.Promise',
    'tinymce.core.util.Tools',
    'tinymce.core.util.URI',
    'tinymce.plugins.imagetools.core.ImageSize',
    'tinymce.plugins.imagetools.core.Proxy',
    'tinymce.plugins.imagetools.ui.Dialog'
  ],
  function (
    BlobConversions, ImageTransformations, Env, PluginManager, Delay, Promise, Tools,
    URI, ImageSize, Proxy, Dialog
  ) {
    var plugin = function (editor) {
      var count = 0, imageUploadTimer, lastSelectedImage;

      if (!Env.fileApi) {
        return;
      }

      function displayError(error) {
        editor.notificationManager.open({
          text: error,
          type: 'error'
        });
      }

      function getSelectedImage() {
        return editor.selection.getNode();
      }

      function extractFilename(url) {
        var m = url.match(/\/([^\/\?]+)?\.(?:jpeg|jpg|png|gif)(?:\?|$)/i);
        if (m) {
          return editor.dom.encode(m[1]);
        }
        return null;
      }

      function createId() {
        return 'imagetools' + count++;
      }

      function isLocalImage(img) {
        var url = img.src;

        return url.indexOf('data:') === 0 || url.indexOf('blob:') === 0 || new URI(url).host === editor.documentBaseURI.host;
      }

      function isCorsImage(img) {
        return Tools.inArray(editor.settings.imagetools_cors_hosts, new URI(img.src).host) !== -1;
      }

      function getApiKey() {
        return editor.settings.api_key || editor.settings.imagetools_api_key;
      }

      function imageToBlob(img) {
        var src = img.src, apiKey;

        if (isCorsImage(img)) {
          return Proxy.getUrl(img.src, null);
        }

        if (!isLocalImage(img)) {
          src = editor.settings.imagetools_proxy;
          src += (src.indexOf('?') === -1 ? '?' : '&') + 'url=' + encodeURIComponent(img.src);
          apiKey = getApiKey();
          return Proxy.getUrl(src, apiKey);
        }

        return BlobConversions.imageToBlob(img);
      }

      function findSelectedBlob() {
        var blobInfo;
        blobInfo = editor.editorUpload.blobCache.getByUri(getSelectedImage().src);
        if (blobInfo) {
          return new Promise(function (resolve) {
            resolve(blobInfo.blob());
          });
        }

        return imageToBlob(getSelectedImage());
      }

      function startTimedUpload() {
        imageUploadTimer = Delay.setEditorTimeout(editor, function () {
          editor.editorUpload.uploadImagesAuto();
        }, editor.settings.images_upload_timeout || 30000);
      }

      function cancelTimedUpload() {
        clearTimeout(imageUploadTimer);
      }

      function updateSelectedImage(ir, uploadImmediately) {
        return ir.toBlob().then(function (blob) {
          var uri, name, blobCache, blobInfo, selectedImage;

          blobCache = editor.editorUpload.blobCache;
          selectedImage = getSelectedImage();
          uri = selectedImage.src;

          if (editor.settings.images_reuse_filename) {
            blobInfo = blobCache.getByUri(uri);
            if (blobInfo) {
              uri = blobInfo.uri();
              name = blobInfo.name();
            } else {
              name = extractFilename(uri);
            }
          }

          blobInfo = blobCache.create({
            id: createId(),
            blob: blob,
            base64: ir.toBase64(),
            uri: uri,
            name: name
          });

          blobCache.add(blobInfo);

          editor.undoManager.transact(function () {
            function imageLoadedHandler() {
              editor.$(selectedImage).off('load', imageLoadedHandler);
              editor.nodeChanged();

              if (uploadImmediately) {
                editor.editorUpload.uploadImagesAuto();
              } else {
                cancelTimedUpload();
                startTimedUpload();
              }
            }

            editor.$(selectedImage).on('load', imageLoadedHandler);

            editor.$(selectedImage).attr({
              src: blobInfo.blobUri()
            }).removeAttr('data-mce-src');
          });

          return blobInfo;
        });
      }

      function selectedImageOperation(fn) {
        return function () {
          return editor._scanForImages().
            then(findSelectedBlob).
            then(BlobConversions.blobToImageResult).
            then(fn).
            then(updateSelectedImage, displayError);
        };
      }

      function rotate(angle) {
        return function () {
          return selectedImageOperation(function (imageResult) {
            var size = ImageSize.getImageSize(getSelectedImage());

            if (size) {
              ImageSize.setImageSize(getSelectedImage(), {
                w: size.h,
                h: size.w
              });
            }

            return ImageTransformations.rotate(imageResult, angle);
          })();
        };
      }

      function flip(axis) {
        return function () {
          return selectedImageOperation(function (imageResult) {
            return ImageTransformations.flip(imageResult, axis);
          })();
        };
      }

      function editImageDialog() {
        var img = getSelectedImage(), originalSize = ImageSize.getNaturalImageSize(img);

        var handleDialogBlob = function (blob) {
          return new Promise(function (resolve) {
            BlobConversions.blobToImage(blob).
              then(function (newImage) {
                var newSize = ImageSize.getNaturalImageSize(newImage);

                if (originalSize.w != newSize.w || originalSize.h != newSize.h) {
                  if (ImageSize.getImageSize(img)) {
                    ImageSize.setImageSize(img, newSize);
                  }
                }

                URL.revokeObjectURL(newImage.src);
                resolve(blob);
              });
          });
        };

        var openDialog = function (imageResult) {
          return Dialog.edit(imageResult).then(handleDialogBlob).
            then(BlobConversions.blobToImageResult).
            then(function (imageResult) {
              return updateSelectedImage(imageResult, true);
            }, function () {
              // Close dialog
            });
        };

        findSelectedBlob().
          then(BlobConversions.blobToImageResult).
          then(openDialog, displayError);
      }

      function addButtons() {
        editor.addButton('rotateleft', {
          title: 'Rotate counterclockwise',
          cmd: 'mceImageRotateLeft'
        });

        editor.addButton('rotateright', {
          title: 'Rotate clockwise',
          cmd: 'mceImageRotateRight'
        });

        editor.addButton('flipv', {
          title: 'Flip vertically',
          cmd: 'mceImageFlipVertical'
        });

        editor.addButton('fliph', {
          title: 'Flip horizontally',
          cmd: 'mceImageFlipHorizontal'
        });

        editor.addButton('editimage', {
          title: 'Edit image',
          cmd: 'mceEditImage'
        });

        editor.addButton('imageoptions', {
          title: 'Image options',
          icon: 'options',
          cmd: 'mceImage'
        });

        /*
        editor.addButton('crop', {
          title: 'Crop',
          onclick: startCrop
        });
        */
      }

      function addEvents() {
        editor.on('NodeChange', function (e) {
          // If the last node we selected was an image
          // And had a source that doesn't match the current blob url
          // We need to attempt to upload it
          if (lastSelectedImage && lastSelectedImage.src != e.element.src) {
            cancelTimedUpload();
            editor.editorUpload.uploadImagesAuto();
            lastSelectedImage = undefined;
          }

          // Set up the lastSelectedImage
          if (isEditableImage(e.element)) {
            lastSelectedImage = e.element;
          }
        });
      }

      function isEditableImage(img) {
        var selectorMatched = editor.dom.is(img, 'img:not([data-mce-object],[data-mce-placeholder])');

        return selectorMatched && (isLocalImage(img) || isCorsImage(img) || editor.settings.imagetools_proxy);
      }

      function addToolbars() {
        var toolbarItems = editor.settings.imagetools_toolbar;

        if (!toolbarItems) {
          toolbarItems = 'rotateleft rotateright | flipv fliph | crop editimage imageoptions';
        }

        editor.addContextToolbar(
          isEditableImage,
          toolbarItems
        );
      }

      Tools.each({
        mceImageRotateLeft: rotate(-90),
        mceImageRotateRight: rotate(90),
        mceImageFlipVertical: flip('v'),
        mceImageFlipHorizontal: flip('h'),
        mceEditImage: editImageDialog
      }, function (fn, cmd) {
        editor.addCommand(cmd, fn);
      });

      addButtons();
      addToolbars();
      addEvents();
    };

    PluginManager.add('imagetools', plugin);

    return function () { };
  }
);
<|endoftext|>


<commit_before>var Strategy = require('../lib/index').OAuth2Strategy;

describe.only('LinkedIn Stratgey', function () {

  it('init with basic profile', function (done) {

    var options = {
        clientID: "clientId",
        clientSecret: "clientSecret"
      };

    var st = new Strategy(options, function(){});
    st.name.should.eql("linkedin");
    st.profileUrl.should.eql('https://api.linkedin.com/v1/people/~:(id,first-name,last-name,picture-url)');
    done();
    });

  it('init with email scope', function (done) {

    var options = {
        clientID: "clientId",
        clientSecret: "clientSecret",
        scope: ['r_emailaddress']
      };

    var st = new Strategy(options, function(){});
    st.name.should.eql("linkedin");
    st.profileUrl.should.eql('https://api.linkedin.com/v1/people/~:(id,first-name,last-name,picture-url,email-address)');
    done();
    });

  it('init with profile and email scope', function (done) {

    var options = {
        clientID: "clientId",
        clientSecret: "clientSecret",
        scope: ['r_basicprofile', 'r_emailaddress']
      };

    var st = new Strategy(options, function(){});
    st.name.should.eql("linkedin");
    st.profileUrl.should.eql('https://api.linkedin.com/v1/people/~:(id,first-name,last-name,picture-url,email-address)');
    done();
    });
});<commit_msg>Fixed tests. Typos<commit_after>var Strategy = require('../lib/index').OAuth2Strategy;

describe.only('LinkedIn Strategy', function () {

  it('init with basic profile', function (done) {

    var options = {
        clientID: "clientId",
        clientSecret: "clientSecret"
      };

    var st = new Strategy(options, function(){});
    st.name.should.eql("linkedin");
    st.profileUrl.should.eql('https://api.linkedin.com/v1/people/~:(id,first-name,last-name,picture-url,formatted-name)');
    done();
    });

  it('init with email scope', function (done) {

    var options = {
        clientID: "clientId",
        clientSecret: "clientSecret",
        scope: ['r_emailaddress']
      };

    var st = new Strategy(options, function(){});
    st.name.should.eql("linkedin");
    st.profileUrl.should.eql('https://api.linkedin.com/v1/people/~:(id,first-name,last-name,picture-url,formatted-name,email-address)');
    done();
    });

  it('init with profile and email scope', function (done) {

    var options = {
        clientID: "clientId",
        clientSecret: "clientSecret",
        scope: ['r_basicprofile', 'r_emailaddress']
      };

    var st = new Strategy(options, function(){});
    st.name.should.eql("linkedin");
    st.profileUrl.should.eql('https://api.linkedin.com/v1/people/~:(id,first-name,last-name,picture-url,formatted-name,email-address)');
    done();
    });
});<|endoftext|>