html5 confirm dialog
diff --git a/web/ons-demo/css/layout.default.css b/web/ons-demo/css/layout.default.css
index 297e31b..f3daf04 100644
--- a/web/ons-demo/css/layout.default.css
+++ b/web/ons-demo/css/layout.default.css
@@ -27,6 +27,38 @@
 	-webkit-box-flex: 1.0;
 }
 
+#confirm {
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	width: 100%;
+	height: 100%;
+	display: -webkit-box;
+	-webkit-box-align: center;
+	-webkit-box-pack: center;
+}
+
+#confirm-background {
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	width: 100%;
+	height: 100%;
+}
+
+#confirm-panel {
+	display: -webkit-box;
+	-webkit-box-orient: vertical;
+	-webkit-box-pack: justify;
+}
+
+#confirm-buttons {
+	display: -webkit-box;
+	-webkit-box-pack: center;
+	-webkit-box-flex: 1.0;
+	-webkit-box-align: center;
+}
+
 .header {
 	width: 100%;
 	display: -webkit-box;
diff --git a/web/ons-demo/css/skin.default.css b/web/ons-demo/css/skin.default.css
index f9aa830..9f1ecf1 100644
--- a/web/ons-demo/css/skin.default.css
+++ b/web/ons-demo/css/skin.default.css
@@ -473,3 +473,58 @@
 	fill: rgba(255, 255, 255, .75);
 }
 
+#confirm {
+	display: none;
+	-webkit-transition: opacity .25s;
+	font-size: 20px;
+}
+
+#confirm-background {
+	background-color: black;
+	opacity: .5;
+}
+
+#confirm-prompt {
+	display: -webkit-box;
+	-webkit-box-pack: center;
+	-webkit-box-align: center;
+	-webkit-box-flex: 1.0;
+	text-align: center;
+}
+
+#confirm-buttons {
+	padding: 1em;
+}
+
+#confirm-prompt {
+	margin-top:1em;
+	line-height: 1.5em;
+}
+
+#confirm-panel {
+	position: relative;
+	background-color: #222;
+	border: 2px solid #aaa;
+	border-radius: 12px;
+	width: 20em;
+	padding: 1em;
+}
+
+.confirm-button {
+	padding: .5em;
+	border: 2px solid #aaa;
+	color: #aaa;
+	border-radius: 6px;
+	margin-left: .5em;
+	margin-right: .5em;
+}
+
+.confirm-button:hover{
+	border: 2px solid white;
+	color: white;
+}
+
+.confirm-button:active{
+	background-color: black;
+}
+
diff --git a/web/ons-demo/index.html b/web/ons-demo/index.html
index 12ac5f9..1b88b4a 100644
--- a/web/ons-demo/index.html
+++ b/web/ons-demo/index.html
@@ -45,28 +45,38 @@
 	<div id='selectedFlows'></div>
 
 	<div id='flowChooser'></div>
-
-	<script src="d3/d3.v3.js" charset="utf-8"></script>
-	<script src="d3/topojson.v0.min.js"></script>
-	<script src="js/async.js"></script>
-	<script src="js/debug.js"></script>
-	<script src="js/constants.js"></script>
-	<script src="js/globals.js"></script>
-	<script src="js/utils.js"></script>
-	<script src="js/model.js"></script>
-	<script src="js/controller.js"></script>
-	<script src="js/controllers.js"></script>
-
-	<!-- choose ring or map layout -->
-	<!--script src="js/rings.js"></script-->
-	<script src="js/map.js"></script>
-
-	<script src="js/topologyactions.js"></script>
-	<script src="js/topology.js"></script>
-	<script src="js/flows.js"></script>
-	<script src="js/init.js"></script>
-	<script src="js/app.js"></script>
 </div>
+<div id='confirm'>
+	<div id='confirm-background'></div>
+	<div id='confirm-panel'>
+		<div id='confirm-prompt'>A PROMPT</div>
+		<div id='confirm-buttons'>
+			<div id='confirm-ok' class='confirm-button'>OK</div>
+			<div id='confirm-cancel' class='confirm-button'>CANCEL</div>
+		</div>
+	</div>
+</div>
+
+<script src="d3/d3.v3.js" charset="utf-8"></script>
+<script src="d3/topojson.v0.min.js"></script>
+<script src="js/async.js"></script>
+<script src="js/debug.js"></script>
+<script src="js/constants.js"></script>
+<script src="js/globals.js"></script>
+<script src="js/utils.js"></script>
+<script src="js/model.js"></script>
+<script src="js/controller.js"></script>
+<script src="js/controllers.js"></script>
+
+<!-- choose ring or map layout -->
+<!--script src="js/rings.js"></script-->
+<script src="js/map.js"></script>
+
+<script src="js/topologyactions.js"></script>
+<script src="js/topology.js"></script>
+<script src="js/flows.js"></script>
+<script src="js/init.js"></script>
+<script src="js/app.js"></script>
 </body>
 
 </html>
\ No newline at end of file
diff --git a/web/ons-demo/js/controllers.js b/web/ons-demo/js/controllers.js
index abe966b..513799b 100644
--- a/web/ons-demo/js/controllers.js
+++ b/web/ons-demo/js/controllers.js
@@ -26,16 +26,20 @@
 	controllers.on('dblclick', function (c) {
 		if (model.activeControllers.indexOf(c) != -1) {
 			var prompt = 'Dectivate ' + c + '?';
-			if (confirm(prompt)) {
-				controllerDown(c);
-				setPending(d3.select(this));
-			};
+			doConfirm(prompt, function (result) {
+				if (result) {
+					controllerDown(c);
+					setPending(d3.select(this));
+				};
+			})
 		} else {
 			var prompt = 'Activate ' + c + '?';
-			if (confirm(prompt)) {
-				controllerUp(c);
-				setPending(d3.select(this));
-			};
+			doConfirm(prompt, function (result) {
+				if (result) {
+					controllerUp(c);
+					setPending(d3.select(this));
+				};
+			});
 		}
 	});
 
diff --git a/web/ons-demo/js/flows.js b/web/ons-demo/js/flows.js
index fa0ccf2..bc30d11 100644
--- a/web/ons-demo/js/flows.js
+++ b/web/ons-demo/js/flows.js
@@ -142,16 +142,18 @@
 		row.on('dblclick', function () {
 			if (d) {
 				var prompt = 'Delete flow ' + d.flowId + '?';
-				if (confirm(prompt)) {
-					deleteFlow(d);
-					d.deletePending = true;
-					updateSelectedFlows();
-
-					setTimeout(function () {
-						d.deletePending = false;
+				doConfirm(prompt, function (result) {
+					if (result) {
+						deleteFlow(d);
+						d.deletePending = true;
 						updateSelectedFlows();
-					}, pendingTimeout)
-				};
+
+						setTimeout(function () {
+							d.deletePending = false;
+							updateSelectedFlows();
+						}, pendingTimeout)
+					};
+				});
 			}
 		});
 
diff --git a/web/ons-demo/js/init.js b/web/ons-demo/js/init.js
index a412440..f7bd55b 100644
--- a/web/ons-demo/js/init.js
+++ b/web/ons-demo/js/init.js
@@ -9,16 +9,20 @@
 
 	d3.select('#action-all').on('click', function () {
 		var prompt = "Switch controllers to all?"
-		if (confirm(prompt)) {
-			switchAll();
-		}
+		doConfirm(prompt, function (result) {
+			if (result) {
+				switchAll();
+			}
+		});
 	});
 
 	d3.select('#action-local').on('click', function () {
 		var prompt = "Switch controllers to local?"
-		if (confirm(prompt)) {
-			switchLocal();
-		}
+		doConfirm(prompt, function (result) {
+			if (result) {
+				switchLocal();
+			}
+		});
 	});
 
 	d3.select('#action-scale').on('click', function () {
diff --git a/web/ons-demo/js/topologyactions.js b/web/ons-demo/js/topologyactions.js
index 6501e5b..28d418b 100644
--- a/web/ons-demo/js/topologyactions.js
+++ b/web/ons-demo/js/topologyactions.js
@@ -101,16 +101,20 @@
 	var circle = d3.select(document.getElementById(data.dpid)).select('circle');
 	if (data.state == 'ACTIVE') {
 		var prompt = 'Deactivate ' + data.dpid + '?';
-		if (confirm(prompt)) {
-			switchDown(data);
-			setPending(circle);
-		}
+		doConfirm(prompt, function(result) {
+			if (result) {
+				switchDown(data);
+				setPending(circle);
+			}
+		});
 	} else {
 		var prompt = 'Activate ' + data.dpid + '?';
-		if (confirm(prompt)) {
-			switchUp(data);
-			setPending(circle);
-		}
+		doConfirm(prompt, function (result) {
+			if (result) {
+				switchUp(data);
+				setPending(circle);
+			}
+		});
 	}
 }
 
@@ -148,78 +152,87 @@
 
 		if (s1Data.className == 'edge' && s2Data.className == 'edge') {
 			var prompt = 'Create flow from ' + srcData.dpid + ' to ' + dstData.dpid + '?';
-			if (confirm(prompt)) {
-				addFlow(srcData, dstData);
+			doConfirm(prompt, function (result) {
+				if (result) {
+					addFlow(srcData, dstData);
 
-				var flow = {
-					dataPath: {
-						srcPort: {
-							dpid: {
-								value: srcData.dpid
+					var flow = {
+						dataPath: {
+							srcPort: {
+								dpid: {
+									value: srcData.dpid
+								}
+							},
+							dstPort: {
+								dpid: {
+									value: dstData.dpid
+								}
 							}
 						},
-						dstPort: {
-							dpid: {
-								value: dstData.dpid
-							}
-						}
-					},
-				        srcDpid: srcData.dpid,
-				        dstDpid: dstData.dpid,
-					createPending: true
-				};
+					        srcDpid: srcData.dpid,
+					        dstDpid: dstData.dpid,
+						createPending: true
+					};
 
-				selectFlow(flow);
+					selectFlow(flow);
 
-				setTimeout(function () {
-					deselectFlowIfCreatePending(flow);
-				}, pendingTimeout);
-			}
+					setTimeout(function () {
+						deselectFlowIfCreatePending(flow);
+					}, pendingTimeout);
+				}
+			});
+
 		} else {
 			var map = linkMap[srcData.dpid];
 			if (map && map[dstData.dpid]) {
 				var prompt = 'Remove link between ' + srcData.dpid + ' and ' + dstData.dpid + '?';
-				if (confirm(prompt)) {
-					removeLink(map[dstData.dpid]);
-				}
+				doConfirm(prompt, function (result) {
+					if (result) {
+						removeLink(map[dstData.dpid]);
+					}
+				});
 			} else {
 				map = linkMap[dstData.dpid];
 				if (map && map[srcData.dpid]) {
 					var prompt = 'Remove link between ' + dstData.dpid + ' and ' + srcData.dpid + '?';
-					if (confirm(prompt)) {
-						removeLink(map[srcData.dpid]);
-					}
+					doConfirm(prompt, function (result) {
+						if (result) {
+							removeLink(map[srcData.dpid]);
+						}
+					});
 				} else {
 					var prompt = 'Create link between ' + srcData.dpid + ' and ' + dstData.dpid + '?';
-					if (confirm(prompt)) {
-						var link1 = {
-							'src-switch': srcData.dpid,
-							'src-port': 1,
-							'dst-switch': dstData.dpid,
-							'dst-port': 1,
-							pending: true
-						};
-						pendingLinks[makeLinkKey(link1)] = link1;
-						var link2 = {
-							'src-switch': dstData.dpid,
-							'src-port': 1,
-							'dst-switch': srcData.dpid,
-							'dst-port': 1,
-							pending: true
-						};
-						pendingLinks[makeLinkKey(link2)] = link2;
-						updateTopology();
-
-						linkUp(link1);
-
-						// remove the pending links after 10s
-						setTimeout(function () {
-							delete pendingLinks[makeLinkKey(link1)];
-							delete pendingLinks[makeLinkKey(link2)];
-
+					doConfirm(prompt, function (result) {
+						if (result) {
+							var link1 = {
+								'src-switch': srcData.dpid,
+								'src-port': 1,
+								'dst-switch': dstData.dpid,
+								'dst-port': 1,
+								pending: true
+							};
+							pendingLinks[makeLinkKey(link1)] = link1;
+							var link2 = {
+								'src-switch': dstData.dpid,
+								'src-port': 1,
+								'dst-switch': srcData.dpid,
+								'dst-port': 1,
+								pending: true
+							};
+							pendingLinks[makeLinkKey(link2)] = link2;
 							updateTopology();
-						}, pendingTimeout);
-					}
+
+							linkUp(link1);
+
+							// remove the pending links after 10s
+							setTimeout(function () {
+								delete pendingLinks[makeLinkKey(link1)];
+								delete pendingLinks[makeLinkKey(link2)];
+
+								updateTopology();
+							}, pendingTimeout);
+						}
+					});
 				}
 			}
 		}
diff --git a/web/ons-demo/js/utils.js b/web/ons-demo/js/utils.js
index 65117f5..265c661 100644
--- a/web/ons-demo/js/utils.js
+++ b/web/ons-demo/js/utils.js
@@ -201,6 +201,45 @@
 }
 
 
+/***************************************************************************************************
+
+***************************************************************************************************/
+function doConfirm(prompt, cb) {
+	var confirm = d3.select('#confirm');
+	confirm.select('#confirm-prompt').text(prompt);
+
+	function show() {
+		confirm.style('display', '-webkit-box');
+		confirm.style('opacity', 0);
+		setTimeout(function () {
+			confirm.style('opacity', 1);
+		}, 0);
+	}
+
+	function dismiss() {
+		confirm.style('opacity', 0);
+		confirm.on('webkitTransitionEnd', function () {
+			confirm.style('display', 'none');
+			confirm.on('webkitTransitionEnd', null);
+		});
+	}
+
+	confirm.select('#confirm-ok').on('click', function () {
+		d3.select(this).on('click', null);
+		dismiss();
+		cb(true);
+	});
+
+	confirm.select('#confirm-cancel').on('click', function () {
+		d3.select(this).on('click', null);
+		dismiss();
+		cb(false);
+	});
+
+	show();
+}
+
+