2 .object_class_wrapper {
4 grid-template-columns: 1fr 1fr 1fr;
15 .class_grid_wrapper:last-child {
21 grid-template-columns: 1fr 1fr;
32 box-shadow: 0px 0px 7px 0px rgba(0,0,0,0.75);
33 transition-property: box-shadow, background-color;
34 transition-duration: .2s;
38 box-shadow: 0px 0px 14px 0px rgba(0,0,0,0.75);
39 transition-property: box-shadow;
40 transition-duration: .2s;
45 box-shadow: 0px 0px 14px 0px rgba(0,0,0,0.75);
46 background-color: #CCECD7;
47 transition-property: background-color;
48 transition-duration: .2s;
53 background-color: #EFEFEF;
54 box-shadow: 0px 0px 1px 0px rgba(0,0,0,0.75);
55 transition-property: box-shadow;
56 transition-duration: .2s;
59 .disabled_node:hover {
60 box-shadow: 0px 0px 1px 0px rgba(0,0,0,0.75);
64 background-color: #FFFFFF;
74 #dropdown_wrapper > div > h5 {
76 display: inline-block;
77 vertical-align: middle;
80 #dropdown_wrapper > div > button {
86 #dropdown_wrapper > div > input {
91 width: calc(100% - 240px);
94 #dropdown_wrapper > div {
101 box-shadow: 0px 0px 7px 0px rgba(0,0,0,0.75);
102 transition-property: box-shadow, background-color;
103 transition-duration: .2s;
104 display: inline-block;
105 vertical-align: middle;
110 grid-template-columns: 3fr 5fr;
114 <input name="filter_field" id="filter_field" type="hidden"/>
115 <div id="grid_wrapper" class="grid_wrapper">
116 {% for object_class, object_list in filter_objects %}
117 <div class="class_grid_wrapper">
118 <div style="display:inline-block;margin:auto">
119 <h4>{{object_class}}</h4>
121 <div id="{{object_class}}" class="object_class_wrapper">
122 {% for obj in object_list %}
123 <div id="object_parent">
124 <div id="{{ obj.id|default:'not_provided' }}" class="grid-item">
125 <p class="grid-item-header">{{obj.name}}</p>
126 <p class="grid-item-description">{{obj.description}}</p>
127 <button type="button" class="btn btn-success grid-item-select-btn" onclick="processClick('{{obj.id}}', {% if obj.multiple %}true{% else %}false{% endif %});">{% if obj.multiple %}Add{% else %}Select{% endif %}</button>
129 <input type="hidden" name="{{obj.id}}_selected" value="false"/>
137 <div id="dropdown_wrapper">
141 var initialized = false;
142 var mapping = {{ mapping|safe }};
143 var filter_items = {{ filter_items|safe }};
145 var selection = {{selection_data|default_if_none:"null"|safe}};
146 var dropdown_count = 0;
148 {% if selection_data %}
149 make_selection({{selection_data|safe}});
152 function make_selection( selection_data ){
156 for(var k in selection_data) {
157 selected_items = selection_data[k];
158 for( var selected_item in selected_items ){
159 var node = filter_items[selected_item];
160 if(!node['multiple']){
161 var input_value = selected_items[selected_item];
162 if( input_value != 'false' ) {
166 var div = document.getElementById(selected_item)
167 var inputs = div.parentNode.getElementsByTagName("input")
168 var input = div.parentNode.getElementsByTagName("input")[0]
169 input.value = input_value;
170 updateResult(selected_item);
172 make_multiple_selection(selected_items, selected_item);
178 function make_multiple_selection(data, item_class){
179 var node = filter_items[item_class];
182 prepop_data = data[item_class];
183 for(var i=0; i<prepop_data.length; i++){
184 var div = add_item_prepopulate(node, prepop_data[i]);
185 updateObjectResult(div);
189 function markAndSweep(root){
190 for(var nodeId in filter_items) {
191 node = filter_items[nodeId];
192 node['marked'] = true; //mark all nodes
193 //clears grey background of everything
199 while(toCheck.length > 0){
200 node = toCheck.pop();
201 if(!node['marked']) {
202 //already visited, just continue
205 node['marked'] = false; //mark as visited
206 if(node['follow'] || node == root){ //add neighbors if we want to follow this node (labs)
207 var mappingId = node.id
208 var neighbors = mapping[mappingId];
209 for(var neighId in neighbors) {
210 neighId = neighbors[neighId];
211 var neighbor = filter_items[neighId];
212 toCheck.push(neighbor);
217 //now remove all nodes still marked
218 for(var nodeId in filter_items){
219 node = filter_items[nodeId];
226 function process(node) {
227 if(node['selected']) {
232 //remember the currently selected, then reset everything and reselect one at a time
233 for(var nodeId in filter_items) {
234 node = filter_items[nodeId];
235 if(node['selected']) {
241 for(var i=0; i<selected.length; i++) {
244 markAndSweep(selected[i]);
249 function select(node) {
250 elem = document.getElementById(node['id']);
251 node['selected'] = true;
252 elem.classList.remove('cleared_node');
253 elem.classList.remove('disabled_node');
254 elem.classList.add('selected_node');
255 var input = elem.parentNode.getElementsByTagName("input")[0];
256 input.disabled = false;
260 function clear(node) {
261 elem = document.getElementById(node['id']);
262 node['selected'] = false;
263 node['selectable'] = true;
264 elem.classList.add('cleared_node')
265 elem.classList.remove('disabled_node');
266 elem.classList.remove('selected_node');
267 elem.parentNode.getElementsByTagName("input")[0].disabled = true;
270 function disable_node(node) {
271 elem = document.getElementById(node['id']);
272 node['selected'] = false;
273 node['selectable'] = false;
274 elem.classList.remove('cleared_node');
275 elem.classList.add('disabled_node');
276 elem.classList.remove('selected_node');
277 elem.parentNode.getElementsByTagName("input")[0].disabled = true;
280 function processClick(id, multiple){
284 var element = document.getElementById(id);
285 var node = filter_items[id];
286 if(!node['selectable']){
290 return processClickMultipleObject(node);
292 node['selected'] = !node['selected']; //toggle on click
294 if(node['selected']) {
304 function processClickMultipleObject(node){
310 function add_node(node){
311 return add_item_prepopulate(node, {});
316 function restrictchars(input)
318 if( input.validity.patternMismatch )
320 input.setCustomValidity("Only alphanumeric characters (a-z, A-Z, 0-9), underscore(_), and hyphen (-) are allowed");
321 input.reportValidity();
324 input.value = input.value.replace(/([^A-Za-z0-9-_.])+/g, "");
329 function checkunique(tocheck)
332 for( var i = 0; i < inputs.length; i++ )
334 if( inputs[i].value == val && inputs[i] != tocheck)
336 tocheck.setCustomValidity("All hostnames must be unique");
337 tocheck.reportValidity();
341 tocheck.setCustomValidity("");
344 function add_item_prepopulate(node, prepopulate){
346 var div = document.createElement("DIV");
347 div.class = node['id'];
348 div.id = "dropdown_" + dropdown_count;
350 var label = document.createElement("H5");
351 label.appendChild(document.createTextNode(node['name']));
352 div.appendChild(label);
353 button = document.createElement("BUTTON");
354 button.type = "button";
355 button.appendChild(document.createTextNode("Remove"));
356 button.classList.add("btn-danger");
357 button.classList.add("btn");
358 div.appendChild(button);
359 for(var i=0; i<node['forms'].length; i++){
360 form = node['forms'][i];
361 var input = document.createElement("INPUT");
362 input.type = form['type'];
363 input.name = form['name'];
364 input.pattern = "(?=^.{1,253}$)(^([A-Za-z0-9-_]{1,62}\.)*[A-Za-z0-9-_]{1,63})";
365 input.title = "Only alphanumeric characters (a-z, A-Z, 0-9), underscore(_), and hyphen (-) are allowed"
366 input.placeholder = form['placeholder'];
368 input.onchange = function() { updateObjectResult(div); restrictchars(this); };
369 input.oninput = function() { restrictchars(this); };
370 if(form['name'] in prepopulate){
371 input.value = prepopulate[form['name']];
373 div.appendChild(input);
375 //add class id to dropdown object
376 var hiddenInput = document.createElement("INPUT");
377 hiddenInput.type = "hidden";
378 hiddenInput.name = "class";
379 hiddenInput.value = node['id'];
380 div.appendChild(hiddenInput);
381 button.onclick = function(){
382 remove_dropdown(div.id);
384 document.getElementById("dropdown_wrapper").appendChild(div);
385 var linebreak = document.createElement("BR");
386 document.getElementById("dropdown_wrapper").appendChild(linebreak);
387 updateObjectResult(div);
391 function remove_dropdown(id){
392 var div = document.getElementById(id);
393 var parent = div.parentNode;
394 div.parentNode.removeChild(div);
395 //checks if we have removed last item in class
396 var deselect_class = true;
397 var div_inputs = div.getElementsByTagName("input");
398 var div_class = div_inputs[div_inputs.length-1].value;
399 var result_class = document.getElementById(div_class).parentNode.parentNode.id;
400 delete result[result_class][div.id];
401 for(var i=0; i<parent.children.length; i++){
402 var inputs = parent.children[i].getElementsByTagName("input");
403 var object_class = "";
404 for(var k=0; k<inputs.length; k++){
405 if(inputs[k].name == "class"){
406 object_class = inputs[k].value;
409 if(object_class == div_class){
410 deselect_class = false;
414 clear(filter_items[div_class]);
418 function updateResult(nodeId){
422 if(!filter_items[nodeId]['multiple']){
423 var node = document.getElementById(nodeId);
425 value[nodeId] = node.parentNode.getElementsByTagName("input")[0].value;
426 result[node.parentNode.parentNode.id] = {};
427 result[node.parentNode.parentNode.id][nodeId] = value;
431 function updateObjectResult(parentElem){
432 node_type = document.getElementById(parentElem.class).parentNode.parentNode.id;
434 inputs = parentElem.getElementsByTagName("input");
435 for(var i in inputs){
437 input[e.name] = e.value;
439 result[node_type][parentElem.id] = input;
442 function filter_field_init() {
443 for(nodeId in filter_items) {
444 element = document.getElementById(nodeId);
445 node = filter_items[nodeId];
446 result[element.parentNode.parentNode.id] = {}