Skip to content

Commit 7046b9f

Browse files
committed
add "sortable" options with HTML5 drag&drop
1 parent 527fd15 commit 7046b9f

File tree

6 files changed

+310
-39
lines changed

6 files changed

+310
-39
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bower_components
2+
node_modules

bower.json

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
11
{
22
"name": "jQuery-QueryBuilder",
3-
"version": "1.0.0-SNAPSHOT",
4-
"homepage": "https://github.com/mistic100/jQuery-QueryBuilder",
5-
"authors": [
6-
"mistic100"
7-
],
8-
"description": "jQuery-QueryBuilder",
3+
"version": "1.0.0",
4+
"authors": [{
5+
"name": "Damien \"Mistic\" Sorel",
6+
"homepage": "http://www.strangeplanet.fr"
7+
}],
8+
"description": "jQuery plugin for user friendly query/filter creator",
99
"main": [
1010
"./query-builder.js",
1111
"./query-builder.css"
1212
],
1313
"dependencies" : {
1414
"bootstrap": "3.x.x"
1515
},
16-
"license": "MIT"
16+
"keywords": [
17+
"jquery",
18+
"query",
19+
"builder",
20+
"filter"
21+
],
22+
"license": "MIT",
23+
"homepage": "https://github.com/mistic100/jQuery-QueryBuilder",
24+
"repository": {
25+
"type": "git",
26+
"url": "git://github.com/mistic100/jQuery-QueryBuilder.git"
27+
},
28+
"ignore": [
29+
"**/.*",
30+
"node_modules",
31+
"bower_components",
32+
"test",
33+
"tests"
34+
]
1735
}

package.json

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,34 @@
11
{
22
"name": "jQuery-QueryBuilder",
3-
"version": "1.0.0-SNAPSHOT",,
4-
"homepage": "https://github.com/mistic100/jQuery-QueryBuilder",
5-
"author": "mistic100",
3+
"version": "1.0.0",
4+
"author": {
5+
"name": "Damien \"Mistic\" Sorel",
6+
"homepage": "http://www.strangeplanet.fr"
7+
},
8+
"description": "jQuery plugin for user friendly query/filter creator",
69
"main": [
710
"./query-builder.js",
811
"./query-builder.css"
912
],
10-
"scripts": {
11-
"test": "echo \"Error: no test specified\" && exit 1"
13+
"dependencies" : {
14+
"bootstrap": "3.x.x"
1215
},
16+
"keywords": [
17+
"jquery",
18+
"query",
19+
"builder",
20+
"filter"
21+
],
22+
"license": "MIT",
23+
"homepage": "https://github.com/mistic100/jQuery-QueryBuilder",
1324
"repository": {
1425
"type": "git",
1526
"url": "git://github.com/mistic100/jQuery-QueryBuilder.git"
1627
},
17-
"dependencies" : {
18-
"bootstrap": "3.x.x"
19-
},
20-
"license": "MIT",
2128
"bugs": {
2229
"url": "https://github.com/mistic100/jQuery-QueryBuilder/issues"
30+
},
31+
"scripts": {
32+
"test": "echo \"Error: no test specified\" && exit 1"
2333
}
2434
}

query-builder.css

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,23 @@
44
* Licensed under MIT (http://opensource.org/licenses/MIT)
55
*/
66

7+
.rule-container,
8+
.rules-group-container,
9+
.rule-placeholder {
10+
margin:4px 0;
11+
border-radius:5px;
12+
padding:5px;
13+
border:1px solid #eee;
14+
background:#fff;
15+
background:rgba(255, 255, 255, 0.9);
16+
}
17+
718
/* GROUPS */
819
.rules-group-container {
9-
padding:10px;
10-
margin:4px 0;
20+
padding:10px 10px 5px 10px;
1121
border:1px solid #DCC896;
1222
background:#FCF9ED;
1323
background:rgba(250, 240, 210, 0.5);
14-
border-radius:5px;
1524
}
1625
.rules-group-header {
1726
margin-bottom:10px;
@@ -20,25 +29,13 @@
2029
display:none;
2130
}
2231

23-
/* hide first delete button */
24-
.query-builder>.rules-group-container>.rules-group-header [data-delete] {
25-
display:none;
26-
}
27-
2832
/* RULES */
2933
.rules-list {
3034
list-style:none;
3135
padding:0 0 0 20px;
3236
margin:0;
3337
}
34-
.rule-container {
35-
margin:4px 0;
36-
padding:5px;
37-
border:1px solid #eee;
38-
background:#fff;
39-
background:rgba(255, 255, 255, 0.9);
40-
border-radius:5px;
41-
}
38+
.rule-container {}
4239
.rule-container.has-error {
4340
background:#fdd;
4441
border-color:#f99;
@@ -97,4 +94,27 @@
9794
}
9895
.rules-list>*:last-child:after {
9996
display:none;
100-
}
97+
}
98+
99+
/* DRAG & DROP */
100+
.rule-container .drag-handle,
101+
.rules-group-container .drag-handle {
102+
cursor:move;
103+
display:inline-block;
104+
}
105+
106+
.rule-container .dragged,
107+
.rules-group-container .dragged {
108+
opacity:0.5;
109+
}
110+
111+
.rule-placeholder {
112+
border:1px dashed #bbb;
113+
opacity:0.7;
114+
}
115+
116+
/* hide first delete button and drag handle */
117+
.query-builder>.rules-group-container>.rules-group-header [data-delete],
118+
.query-builder>.rules-group-container>.rules-group-header .drag-handle {
119+
display:none;
120+
}

query-builder.js

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@
118118
});
119119

120120
// INIT
121+
if (this.settings.sortable) {
122+
this.initSortable();
123+
}
124+
121125
this.$el.addClass('query-builder');
122126
this.addGroup(this.$el);
123127
};
@@ -127,6 +131,7 @@
127131
onAfterAddGroup: null,
128132
onAfterAddRule: null,
129133

134+
sortable: false,
130135
filters: [],
131136

132137
lang: {
@@ -725,6 +730,92 @@
725730
this.$el.trigger(e);
726731
};
727732

733+
/**
734+
* Init HTML5 drag and drop
735+
*/
736+
QueryBuilder.prototype.initSortable = function() {
737+
$.event.props.push('dataTransfer');
738+
739+
var placeholder, isHandle = false;
740+
741+
this.$el.on('mousedown', '.drag-handle', function(e) {
742+
isHandle = true;
743+
});
744+
this.$el.on('mouseup', '.drag-handle', function(e) {
745+
isHandle = false;
746+
});
747+
748+
this.$el.on('dragstart', '[draggable]', function(e) {
749+
e.stopPropagation();
750+
751+
if (isHandle) {
752+
e.dataTransfer.setData('id', e.target.id);
753+
754+
placeholder = $('<div class="rule-placeholder">&nbsp;</div>');
755+
placeholder.height($(e.target).height());
756+
placeholder.insertAfter(e.target);
757+
758+
$(e.target).hide();
759+
760+
isHandle = false;
761+
}
762+
else {
763+
e.preventDefault();
764+
}
765+
});
766+
767+
this.$el.on('dragenter', '[draggable]', function(e) {
768+
e.stopPropagation();
769+
770+
var target = $(e.target), parent;
771+
772+
parent = target.closest('.rule-container');
773+
if (parent.length) {
774+
placeholder.detach().insertAfter(parent);
775+
return;
776+
}
777+
778+
parent = target.closest('.rules-group-container');
779+
if (parent.length) {
780+
placeholder.detach().appendTo(parent.find('.rules-list').eq(0));
781+
return;
782+
}
783+
});
784+
785+
this.$el.on('dragover', '[draggable]', function(e) {
786+
e.preventDefault();
787+
e.stopPropagation();
788+
});
789+
790+
this.$el.on('drop', function(e) {
791+
e.stopPropagation();
792+
793+
var src = $('#'+ e.dataTransfer.getData('id')),
794+
target = $(e.target), parent;
795+
796+
parent = target.closest('.rule-container');
797+
if (parent.length) {
798+
src.detach().insertAfter(parent);
799+
return;
800+
}
801+
802+
parent = target.closest('.rules-group-container');
803+
if (parent.length) {
804+
src.detach().appendTo(parent.find('.rules-list').eq(0));
805+
return;
806+
}
807+
});
808+
809+
this.$el.on('dragend', '[draggable]', function(e) {
810+
e.stopPropagation();
811+
812+
var src = $('#'+ e.dataTransfer.getData('id'));
813+
814+
src.show();
815+
placeholder.remove();
816+
});
817+
};
818+
728819

729820
// DATA ACCESS
730821
// ===============================
@@ -881,17 +972,18 @@
881972
*/
882973
QueryBuilder.prototype.getGroupTemplate = function(group_id) {
883974
return '\
884-
<dl id='+ group_id +' class="rules-group-container"> \
975+
<dl id='+ group_id +' class="rules-group-container" '+ (this.settings.sortable ? 'draggable="true"' : '') +'> \
885976
<dt class="rules-group-header"> \
886-
<div class="btn-group"> \
887-
<label class="btn btn-xs btn-primary active"><input type="radio" name="'+ group_id +'_cond" value="AND" checked> '+ this.lang.and_condition +'</label> \
888-
<label class="btn btn-xs btn-primary"><input type="radio" name="'+ group_id +'_cond" value="OR"> '+ this.lang.or_condition +'</label> \
889-
</div> \
890977
<div class="btn-group pull-right"> \
891978
<button type="button" class="btn btn-xs btn-success" data-add="rule"><i class="glyphicon glyphicon-plus"></i> '+ this.lang.add_rule +'</button> \
892979
<button type="button" class="btn btn-xs btn-success" data-add="group"><i class="glyphicon glyphicon-plus-sign"></i> '+ this.lang.add_group +'</button> \
893980
<button type="button" class="btn btn-xs btn-danger" data-delete="group"><i class="glyphicon glyphicon-remove"></i> '+ this.lang.delete_group +'</button> \
894981
</div> \
982+
<div class="btn-group"> \
983+
<label class="btn btn-xs btn-primary active"><input type="radio" name="'+ group_id +'_cond" value="AND" checked> '+ this.lang.and_condition +'</label> \
984+
<label class="btn btn-xs btn-primary"><input type="radio" name="'+ group_id +'_cond" value="OR"> '+ this.lang.or_condition +'</label> \
985+
</div> \
986+
'+ (this.settings.sortable ? '<div class="drag-handle"><i class="glyphicon glyphicon-sort"></i></div>' : '') +' \
895987
</dt> \
896988
<dd class=rules-group-body> \
897989
<ul class=rules-list></ul> \
@@ -906,12 +998,13 @@
906998
*/
907999
QueryBuilder.prototype.getRuleTemplate = function(rule_id) {
9081000
return '\
909-
<li id='+ rule_id +' class="rule-container"> \
1001+
<li id='+ rule_id +' class="rule-container" '+ (this.settings.sortable ? 'draggable="true"' : '') +'> \
9101002
<div class="rule-header"> \
9111003
<div class="btn-group pull-right"> \
9121004
<button type="button" class="btn btn-xs btn-danger" data-delete="rule"><i class="glyphicon glyphicon-remove"></i> '+ this.lang.delete_rule +'</button> \
9131005
</div> \
9141006
</div> \
1007+
'+ (this.settings.sortable ? '<div class="drag-handle"><i class="glyphicon glyphicon-sort"></i></div>' : '') +' \
9151008
<div class="rule-filter-container">'+ this.getRuleFilterSelect(rule_id) +'</div> \
9161009
<div class="rule-operator-container"></div> \
9171010
<div class="rule-value-container"></div> \

0 commit comments

Comments
 (0)