这是一个使用 jquery ui 拖放的代码示例:http: //jsfiddle.net/kwMpH/7/
“显示批准级别”按钮试图显示哪些用户气泡落入哪些框。它似乎有效,但有一种情况我可以打破它:
- 将一个元素拖到第一个审批级别。
- 点击“添加审批级别”
- 取一个不同的元素并将其添加到新创建的审批级别
- 将气泡从 2 级移动到 1 级,然后快速单击“显示批准级别”
值得注意的是,我使用 detach 和 appendTo 的原因与这篇旧帖子的“表单提交”要求相同:
这是代码:
<div class="container">
<div class="topInstructions">Drag and Drop a one or more categories of users to one or more approval levels.</div>
<div class="workFlowNameArea">
<div class="workFlowNameSubArea">
<div style="font-weight:bold;">Work Flow Name</div>
<div>
<input type="text" name="workFlowName" id="workFlowName" maxlength="100" width="50" />
</div>
</div>
<div class="workFlowNameSubArea" style="margin-left: 20px; margin-top: 17px;">
<input id="saveButton" type="button" value="Save" />
</div>
<div class="workFlowNameSubArea" style="margin-left: 20px; margin-top: 17px;">
<input id="addApprovalLevel" type="button" value="Add Approval Level" />
</div>
<div class="workFlowNameSubArea" style="margin-left: 20px; margin-top: 17px;">
<input id="showState" type="button" value="Show State" />
</div>
<div class="workFlowNameSubArea" style="margin-left: 20px; margin-top: 17px;">
<input id="appLevel" type="button" value="Show approval Levels" />
</div>
</div>
<div class="dropGroup">
<div id="approval1" class="approvalText">Approval Level 1
<div id="deleteApproval1" class="deleteApproval" style="visibility: hidden;">
<img src="/images/redX.gif" />
</div>
<div id="droppable1" class="droppable"></div>
</div>
<div id="arrow1" class="arrow">
<img src="/images/arrow_in_circle_down.png" />
</div>
<div id="ellipsis1" class="ellipsis">
<img src="/images/ellipsis.png" />
</div>
</div>
<div class="choices">
<div class="approvalText">Categories</div>
<div class="draggable" title="click and drag to an approval level" style="background: #CC0000; color: #fff;">System Administrators</div>
<div class="draggable" title="click and drag to an approval level" style="background: #FF9933; color: #000;">Administrators</div>
<div class="draggable" title="click and drag to an approval level" style="background: #FFFF00; color: #000;">Managers</div>
<div class="draggable" title="click and drag to an approval level" style="background: #99FF66; color: #000;">Instructors</div>
<div class="draggable" title="click and drag to an approval level" style="background: #66CCFF; color: #000;">School Administrators</div>
<div class="draggable" title="click and drag to an approval level" style="background: #6600FF; color: #fff;">Users</div>
<div class="clonable" title="click to create a custom group" style="background: #999; color: #fff;">Custom</div>
</div>
</div>
.draggable {
width: 100px;
height: 35px;
display: inline-block;
margin-top: 10px;
margin-bottom: 10px;
border: 2px solid #000;
border-radius: 15px;
-webkit-border-radius: 15px;
-khtml-border-radius: 15px;
-moz-border-radius: 15px;
text-align: center;
line-height: normal;
vertical-align: middle;
font-weight: bold;
font-family: arial;
font-size: 12px;
cursor: pointer;
}
.clonable {
width: 100px;
height: 35px;
display: inline-block;
margin-top: 10px;
margin-bottom: 10px;
border: 2px solid #000;
border-radius: 15px;
-webkit-border-radius: 15px;
-khtml-border-radius: 15px;
-moz-border-radius: 15px;
text-align: center;
line-height: normal;
vertical-align: middle;
font-weight: bold;
font-family: arial;
font-size: 12px;
cursor: pointer;
}
.droppable {
width: 150px;
height: 75px;
margin: 10px;
border-color: #999;
color: #999;
border-style: dashed;
margin-left: auto;
margin-right: auto;
}
.topInstructions {
position: relative;
float: top;
margin-top: 5px;
margin-bottom: 10px;
text-align: center;
font-family: arial;
font-size: 16px;
}
.dropGroup {
position: relative;
float: right;
margin-right: 100px;
color: #999;
text-align: center;
width: 300px;
height: 450px;
margin-top: 5px;
}
.choices {
position: relative;
text-align: center;
float: left;
width: 150px;
height: 430px;
margin-left: 75px;
margin-top: 5px;
}
.approvalText {
color: #999;
font-family: arial;
font-size: 12px;
}
.deleteApproval {
color: red;
display: inline-block;
cursor: hand;
cursor: pointer;
}
.workFlowNameArea {
position: relative;
float: top;
width: 680px;
margin-left: 75px;
margin-bottom: 15px;
}
.workFlowNameSubArea {
display: inline-block;
float: left;
}
.container {
width: 680px;
position: relative;
}
var globalElement;
$(document).ready(function () {
$(".draggable").draggable({
helper: "clone",
revert: true,
containment: "document",
start: function (event, ui) {
globalElement = $(this);
},
stop: function (event, ui) {
globalElement = null;
}
});
$(".droppable").droppable({
accepts: ".draggable",
tolerance: "intersect",
drop: function (event, ui) {
dropFunction($(this), event, ui);
}
}).hover(function () {
if ($(this).find(".draggable").length < 1) {
}
});
$(".choices").droppable({
accepts: ".draggable",
tolerance: "intersect",
drop: function (event, ui) {
dropFunction($(this), event, ui);
}
});
$(".clonable").click(function () {
//TODO pop up for user list
});
$(".startOverButton").click(function () {
// is this possible?
});
$("#addApprovalLevel").click(function () {
addNextApprovalLevel();
});
$("#saveButton").click(function () {
saveWorkflow();
console.log("approval levels\n");
$(".droppable").each(function (index) {
console.log((index + 1) + ":" + $(this).find(".draggable").length + ":" + $(this).find(".draggable").text());
});
});
$("#showState").click(function () {
alert(state);
});
$("#appLevel").click(function () {
// this does not work in drop function but does work here... maybe because drop is not completely done?
//console.log("approval levels");
for (i = 0; i < 1000; i++){}
var str = "approval levels";
$(".droppable").each(function (index) {
str += "" + (index + 1) + ":" + $(this).find(".draggable").length + ":" + $(this).find(".draggable").text() + "\n";
});
alert(str);
});
});
var state = new Array();
function dropFunction(jObj, event, ui) {
if (globalElement != null) {
ui.helper.fadeOut();
globalElement.detach().appendTo(jObj);
$(jObj).css("border-color", "#999");
drpGroup = $(".dropGroup").height();
net = 0;
$.each($(".droppable"), function (i, drp) {
oldHeight = $(drp).height();
newHeight = ($(drp).find(".draggable").length * 45) + 75;
$(drp).css("height", newHeight);
net += newHeight - oldHeight;
//console.log("old = " + oldHeight + ", new = " + newHeight + ", net = " + net);
});
drpGroup += net;
$(".dropGroup").css("height", drpGroup);
//console.log("new drop group height = " + $(".dropGroup").height());
} else {
//console.log("too fast!");
}
}
function addNextApprovalLevel() {
var curHighest = $(".droppable").length;
$("#ellipsis" + curHighest).remove();
var nextLevelNum = curHighest + 1;
var newApprovalText = "<div id='approval" + nextLevelNum + "'>Approval Level " + nextLevelNum + " <div id='deleteApproval" + nextLevelNum + "' class='deleteApproval'><img src='/images/redX.gif' /></div>" + "</div>";
var newApprovalBox = $("<div id='droppable" + nextLevelNum + "' class='droppable'>" + "</div>");
//$("#droppable" + curHighest).clone().attr("id", "droppable" + nextLevelNum);
$(newApprovalBox).droppable({
accepts: ".draggable",
tolerance: "intersect",
drop: function (event, ui) {
dropFunction($(this), event, ui);
//$("#droppable1").css("height", $("#droppable1").find(".draggable").length * 75);
//console.log($("#droppable1").find(".draggable").length + "\n" +
// $("#droppable1").find(".draggable").text() );
}
});
$("#arrow" + curHighest).css("margin-bottom", "5px");
$(".dropGroup").append(newApprovalText);
$(".dropGroup").append(newApprovalBox);
var newArrow = "<div id='arrow" + nextLevelNum + "' class='arrow'><img src='/images/arrow_in_circle_down.png' /></div>";
var newEllipsis = "<div id='ellipsis" + nextLevelNum + "' class='ellipsis'><img src='/images/ellipsis.png' /></div>";
$(".dropGroup").append(newArrow);
$(".dropGroup").append(newEllipsis);
$(".dropGroup").css("height", $(".dropGroup").height() + 170);
$("#deleteApproval" + nextLevelNum).click(function () {
if ($("#droppable" + nextLevelNum).parent().find(".draggable").length >= 1) {
alert("A user category must first be removed before an approval level can be deleted.");
} else {
deleteApprovalBox($(this));
}
});
}
function deleteApprovalBox(jqAppBox) {
level = parseInt($(jqAppBox).attr("id").substring("deleteApproval".length));
$("#approval" + level).remove();
$("#droppable" + level).remove();
$("#arrow" + level).remove();
level++;
while ($("#approval" + level).length) {
$("#approval" + level).html("Approval Level " + (level - 1) + " <div id='deleteApproval" + (level - 1) + "' class='deleteApproval'><img src='/images/redX.gif' /></div>");
$("#approval" + level).attr("id", "approval" + (level - 1));
$("#droppable" + level).attr("id", "droppable" + (level - 1));
$("#arrow" + level).attr("id", "arrow" + (level - 1));
$("#deleteApproval" + (level - 1)).click(function () {
if ($("#droppable" + (level - 1)).parent().find(".draggable").length >= 1) {
alert("A user category must first be removed before an approval level can be deleted.");
} else {
deleteApprovalBox($(this));
}
});
level++;
}
level--;
if ($("#ellipsis" + level).length == 1) {
$("#ellipsis" + level).attr("id", "ellipsis" + (level - 1));
}
}
function saveWorkflow() {
// validate the name
var alphaNum = new RegExp(/^([\sa-zA-Z0-9_-]+)$/);
if ($("#workFlowName").val().length < 1) {
alert("Work flow name must be between 1 and 100 characters.");
return false;
}
if (!alphaNum.test($("#workFlowName").val())) {
alert("Invalid Work flow name. Must have numbers or letters.");
return false;
}
// check if there are no empty
// check if any approval levels are empty
if ($(".droppable").length > 1) {
$.each($(".droppable"), function (i, drp) {
//console.log(i + ":" + $(drp).find(".draggable").length);
if ($(drp).find(".draggable").length < 1) {
$(drp).css("border-color", "red");
alert("Approval Level " + (i + 1) + " is empty. Delete?");
// TODO, implement an approval level delete method hooked into the NO of the YES/NO
return;
}
});
}
//var findResult = $("#droppable1").find(".draggable");
// remove ellipis... do we need to do this?
//var curHighest = $(".droppable").length;
//$("#ellipsis" + curHighest).remove();
}