2 .object_class_wrapper {
4 grid-template-columns: 1fr 1fr 1fr;
15 .class_grid_wrapper:last-child {
21 grid-template-columns: 1fr 1fr;
25 border:1px solid #cccccc;
30 transition-property: box-shadow, background-color;
31 transition-duration: .2s;
35 box-shadow: 0px 0px 7px 0px rgba(0,0,0,0.45);
36 transition-property: box-shadow;
37 transition-duration: .2s;
42 box-shadow: 0px 0px 4px 0px rgba(0,0,0,0.45);
43 background-color: #fff;
44 transition-property: background-color;
45 transition-duration: .2s;
50 background-color: #EFEFEF;
51 transition-property: box-shadow;
52 transition-duration: .2s;
53 border: 1px solid #ccc;
56 .disabled_node:hover {
60 background-color: #FFFFFF;
70 #dropdown_wrapper > div > h5 {
72 display: inline-block;
73 vertical-align: middle;
76 #dropdown_wrapper > div > button {
82 #dropdown_wrapper > div > input {
87 width: calc(100% - 240px);
90 #dropdown_wrapper > div {
97 box-shadow: 0px 0px 7px 0px rgba(0,0,0,0.75);
98 transition-property: box-shadow, background-color;
99 transition-duration: .2s;
100 display: inline-block;
101 vertical-align: middle;
106 grid-template-columns: 3fr 5fr;
110 <input name="filter_field" id="filter_field" type="hidden"/>
111 <div id="grid_wrapper" class="grid_wrapper">
112 {% for object_class, object_list in filter_objects %}
113 <div class="class_grid_wrapper">
114 <div style="display:inline-block;margin:auto">
115 <h4>{{object_class}}</h4>
117 <div id="{{object_class}}" class="object_class_wrapper">
118 {% for obj in object_list %}
119 <div id="{{ obj.id|default:'not_provided' }}" class="grid-item">
120 <p class="grid-item-header">{{obj.name}}</p>
121 <p class="grid-item-description">{{obj.description}}</p>
122 <button type="button" class="btn btn-success grid-item-select-btn" onclick="processClick(
124 {% if obj.multiple %}true
126 {% endif %});">{% if obj.multiple %}Add{% else %}Select{% endif %}</button>
128 <input type="hidden" name="{{obj.id}}_selected" value="false"/>
135 <div id="dropdown_wrapper">
139 var initialized = false;
140 var mapping = {{ mapping|safe }};
141 var filter_items = {{ filter_items|safe }};
143 var selection = {{selection_data|default_if_none:"null"|safe}};
144 var dropdown_count = 0;
146 {% if selection_data %}
147 make_selection({{selection_data|safe}});
150 function make_selection( selection_data ){
154 for(var k in selection_data) {
155 selected_items = selection_data[k];
156 for( var selected_item in selected_items ){
157 var node = filter_items[selected_item];
158 if(!node['multiple']){
159 var input_value = selected_items[selected_item];
160 if( input_value != 'false' ) {
164 var div = document.getElementById(selected_item)
165 var inputs = div.parentNode.getElementsByTagName("input")
166 var input = div.parentNode.getElementsByTagName("input")[0]
167 input.value = input_value;
168 updateResult(selected_item);
170 make_multiple_selection(selected_items, selected_item);
176 function make_multiple_selection(data, item_class){
177 var node = filter_items[item_class];
180 prepop_data = data[item_class];
181 for(var i=0; i<prepop_data.length; i++){
182 var div = add_item_prepopulate(node, prepop_data[i]);
183 updateObjectResult(div);
187 function markAndSweep(root){
188 for(var nodeId in filter_items) {
189 node = filter_items[nodeId];
190 node['marked'] = true; //mark all nodes
191 //clears grey background of everything
196 while(toCheck.length > 0){
197 node = toCheck.pop();
198 if(!node['marked']) {
199 //already visited, just continue
202 node['marked'] = false; //mark as visited
203 if(node['follow'] || node == root){ //add neighbors if we want to follow this node (labs)
204 var mappingId = node.id
205 var neighbors = mapping[mappingId];
206 for(var neighId in neighbors) {
207 neighId = neighbors[neighId];
208 var neighbor = filter_items[neighId];
209 toCheck.push(neighbor);
214 //now remove all nodes still marked
215 for(var nodeId in filter_items){
216 node = filter_items[nodeId];
223 function process(node) {
224 if(node['selected']) {
229 //remember the currently selected, then reset everything and reselect one at a time
230 for(var nodeId in filter_items) {
231 node = filter_items[nodeId];
232 if(node['selected']) {
238 for(var i=0; i<selected.length; i++) {
241 markAndSweep(selected[i]);
246 function select(node) {
247 elem = document.getElementById(node['id']);
248 node['selected'] = true;
249 elem.classList.remove('cleared_node');
250 elem.classList.remove('disabled_node');
251 elem.classList.add('selected_node');
252 var input = elem.parentNode.getElementsByTagName("input")[0];
253 input.disabled = false;
257 function clear(node) {
258 elem = document.getElementById(node['id']);
259 node['selected'] = false;
260 node['selectable'] = true;
261 elem.classList.add('cleared_node')
262 elem.classList.remove('disabled_node');
263 elem.classList.remove('selected_node');
264 elem.parentNode.getElementsByTagName("input")[0].disabled = true;
267 function disable_node(node) {
268 elem = document.getElementById(node['id']);
269 node['selected'] = false;
270 node['selectable'] = false;
271 elem.classList.remove('cleared_node');
272 elem.classList.add('disabled_node');
273 elem.classList.remove('selected_node');
274 elem.parentNode.getElementsByTagName("input")[0].disabled = true;
277 function processClick(id, multiple){
281 var element = document.getElementById(id);
282 var node = filter_items[id];
283 if(!node['selectable']){
287 return processClickMultipleObject(node);
289 node['selected'] = !node['selected']; //toggle on click
291 if(node['selected']) {
300 function processClickMultipleObject(node){
306 function add_node(node){
307 return add_item_prepopulate(node, {});
312 function restrictchars(input){
313 if( input.validity.patternMismatch ){
314 input.setCustomValidity("Only alphanumeric characters (a-z, A-Z, 0-9), underscore(_), and hyphen (-) are allowed");
315 input.reportValidity();
317 input.value = input.value.replace(/([^A-Za-z0-9-_.])+/g, "");
321 function checkunique(tocheck)
324 for( var i = 0; i < inputs.length; i++ )
326 if( inputs[i].value == val && inputs[i] != tocheck)
328 tocheck.setCustomValidity("All hostnames must be unique");
329 tocheck.reportValidity();
333 tocheck.setCustomValidity("");
336 function add_item_prepopulate(node, prepopulate){
338 var div = document.createElement("DIV");
339 div.class = node['id'];
340 div.id = "dropdown_" + dropdown_count;
342 var label = document.createElement("H5");
343 label.appendChild(document.createTextNode(node['name']));
344 div.appendChild(label);
345 button = document.createElement("BUTTON");
346 button.type = "button";
347 button.appendChild(document.createTextNode("Remove"));
348 button.classList.add("btn-danger");
349 button.classList.add("btn");
350 div.appendChild(button);
351 for(var i=0; i<node['forms'].length; i++){
352 form = node['forms'][i];
353 var input = document.createElement("INPUT");
354 input.type = form['type'];
355 input.name = form['name'];
356 input.pattern = "(?=^.{1,253}$)(^([A-Za-z0-9-_]{1,62}\.)*[A-Za-z0-9-_]{1,63})";
357 input.title = "Only alphanumeric characters (a-z, A-Z, 0-9), underscore(_), and hyphen (-) are allowed"
358 input.placeholder = form['placeholder'];
360 input.onchange = function() { updateObjectResult(div); restrictchars(this); };
361 input.oninput = function() { restrictchars(this); };
362 if(form['name'] in prepopulate){
363 input.value = prepopulate[form['name']];
365 div.appendChild(input);
367 //add class id to dropdown object
368 var hiddenInput = document.createElement("INPUT");
369 hiddenInput.type = "hidden";
370 hiddenInput.name = "class";
371 hiddenInput.value = node['id'];
372 div.appendChild(hiddenInput);
373 button.onclick = function(){
374 remove_dropdown(div.id);
376 document.getElementById("dropdown_wrapper").appendChild(div);
377 var linebreak = document.createElement("BR");
378 document.getElementById("dropdown_wrapper").appendChild(linebreak);
379 updateObjectResult(div);
383 function remove_dropdown(id){
384 var div = document.getElementById(id);
385 var parent = div.parentNode;
386 div.parentNode.removeChild(div);
387 //checks if we have removed last item in class
388 var deselect_class = true;
389 var div_inputs = div.getElementsByTagName("input");
390 var div_class = div_inputs[div_inputs.length-1].value;
391 var result_class = document.getElementById(div_class).parentNode.parentNode.id;
392 delete result[result_class][div.id];
393 for(var i=0; i<parent.children.length; i++){
394 var inputs = parent.children[i].getElementsByTagName("input");
395 var object_class = "";
396 for(var k=0; k<inputs.length; k++){
397 if(inputs[k].name == "class"){
398 object_class = inputs[k].value;
401 if(object_class == div_class){
402 deselect_class = false;
406 clear(filter_items[div_class]);
410 function updateResult(nodeId){
414 if(!filter_items[nodeId]['multiple']){
415 var node = document.getElementById(nodeId);
417 value[nodeId] = node.parentNode.getElementsByTagName("input")[0].value;
418 result[node.parentNode.id] = {};
419 result[node.parentNode.id][nodeId] = value;
423 function updateObjectResult(parentElem){
424 node_type = document.getElementById(parentElem.class).parentNode.id;
426 inputs = parentElem.getElementsByTagName("input");
427 for(var i in inputs){
429 input[e.name] = e.value;
431 result[node_type][parentElem.id] = input;
434 function filter_field_init() {
435 for(nodeId in filter_items) {
436 element = document.getElementById(nodeId);
437 node = filter_items[nodeId];
438 result[element.parentNode.id] = {}