mirror of https://github.com/MISP/MISP
chg: [tagging] WIP - bulk tagging via generic picker on tag level
parent
b7c1ce79ba
commit
bbdbd3b184
|
@ -2850,11 +2850,33 @@ class AttributesController extends AppController
|
|||
$tag_id_list[] = $tagCollectionTag['tag_id'];
|
||||
}
|
||||
} else {
|
||||
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
|
||||
if (empty($tag)) {
|
||||
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
|
||||
// try to parse json array
|
||||
$tag_ids = json_decode($tag_id);
|
||||
if ($tag_ids !== null) { // can decode json
|
||||
$tag_id_list = array();
|
||||
foreach ($tag_ids as $tag_id) {
|
||||
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
|
||||
$tagChoice = explode('_', $tag_id)[1];
|
||||
$this->loadModel('TagCollection');
|
||||
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
|
||||
if (empty($tagCollection)) {
|
||||
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
|
||||
}
|
||||
$tag_id_list = array();
|
||||
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
|
||||
$tag_id_list[] = $tagCollectionTag['tag_id'];
|
||||
}
|
||||
} else {
|
||||
$tag_id_list[] = $tag_id;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
|
||||
if (empty($tag)) {
|
||||
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
|
||||
}
|
||||
$tag_id = $tag['Tag']['id'];
|
||||
}
|
||||
$tag_id = $tag['Tag']['id'];
|
||||
}
|
||||
}
|
||||
if (!isset($idList)) {
|
||||
|
|
|
@ -3293,16 +3293,17 @@ class EventsController extends AppController
|
|||
}
|
||||
|
||||
public function genericPicker() {
|
||||
$this->set('options', array(
|
||||
'require_choice' => true,
|
||||
'pre_choices' => array(
|
||||
'Tag Collections' => "'4/collections/attribute', 'tags', 'selectTag'",
|
||||
'All Tags' => "4/all/attribute, 'tags', 'selectTag'",
|
||||
)
|
||||
));
|
||||
$this->set('options', array());
|
||||
$this->set('items', array('item1', 'item2', 'item3'));
|
||||
$this->render('/Elements/generic_picker');
|
||||
}
|
||||
public function genericPrePicker() {
|
||||
$this->set('choices', array(
|
||||
'Tag Collections' => "/tags/selectTag/4/collections/attribute",
|
||||
'All Tags' => "/tags/selectTag/4/all/attribute"
|
||||
));
|
||||
$this->render('/Elements/generic_pre_picker');
|
||||
}
|
||||
|
||||
public function addTag($id = false, $tag_id = false)
|
||||
{
|
||||
|
|
|
@ -638,13 +638,6 @@ class TagsController extends AppController
|
|||
$expanded[$tagCollection['TagCollection']['id']] .= sprintf(' (%s)', $tagList);
|
||||
}
|
||||
}
|
||||
$this->set('scope', $scope);
|
||||
$this->set('object_id', $id);
|
||||
$this->set('options', $options);
|
||||
$this->set('expanded', $expanded);
|
||||
$this->set('custom', $taxonomy_id == 0 ? true : false);
|
||||
$this->set('filterData', $filterData);
|
||||
$this->render('ajax/select_tag');
|
||||
} else {
|
||||
if ($taxonomy_id === '0') {
|
||||
$options = $this->Taxonomy->getAllTaxonomyTags(true);
|
||||
|
@ -693,19 +686,40 @@ class TagsController extends AppController
|
|||
unset($options[$hidden_tag]);
|
||||
unset($expanded[$hidden_tag]);
|
||||
}
|
||||
$this->set('scope', $scope);
|
||||
$this->set('object_id', $id);
|
||||
foreach ($options as $k => $v) {
|
||||
if (substr($v, 0, strlen('misp-galaxy:')) === 'misp-galaxy:') {
|
||||
unset($options[$k]);
|
||||
}
|
||||
}
|
||||
$this->set('options', $options);
|
||||
$this->set('expanded', $expanded);
|
||||
$this->set('custom', $taxonomy_id == 0 ? true : false);
|
||||
$this->set('filterData', $filterData);
|
||||
$this->render('ajax/select_tag');
|
||||
}
|
||||
|
||||
$this->set('scope', $scope);
|
||||
$this->set('object_id', $id);
|
||||
$items = array();
|
||||
foreach ($options as $k => $option) {
|
||||
$choice_id = $k;
|
||||
if ($taxonomy_id === 'collections') {
|
||||
$choice_id = 'collection_' . $choice_id;
|
||||
}
|
||||
|
||||
$onClickForm = 'quickSubmitTagForm';
|
||||
if ($scope === 'attribute') {
|
||||
$onClickForm = 'quickSubmitAttributeTagForm';
|
||||
}
|
||||
if ($scope === 'tag_collection') {
|
||||
$onClickForm = 'quickSubmitTagCollectionTagForm';
|
||||
}
|
||||
|
||||
$items[h($option)] = array(
|
||||
'value' => h($choice_id),
|
||||
'additionalData' => array(
|
||||
'id' => h($id)
|
||||
)
|
||||
);
|
||||
}
|
||||
$this->set('items', $items);
|
||||
$this->set('options', array( // set chosen (select picker) options
|
||||
'select_options' => array(
|
||||
'multiple' => true,
|
||||
),
|
||||
'functionName' => $onClickForm,
|
||||
));
|
||||
$this->render('ajax/select_tag');
|
||||
}
|
||||
|
||||
public function tagStatistics($percentage = false, $keysort = false)
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
<?php
|
||||
/**
|
||||
* Generic select picker from JSON
|
||||
* Required: $options, items
|
||||
* Note: setting `require_choice` to true, disable items
|
||||
* Generic select picker
|
||||
*/
|
||||
// prevent exception if not set
|
||||
$options = isset($options) ? $options : array();
|
||||
$items = isset($items) ? $items : array();
|
||||
|
||||
$defaults_options = array(
|
||||
'select_options' => array(
|
||||
// 'multiple' => '', // set to add possibility to pick multiple options in the select
|
||||
//'placeholder' => '' // set to replace the default placeholder text
|
||||
),
|
||||
'chosen_options' => array(
|
||||
'width' => '400px',
|
||||
//'no_results_text' => '', // set to replace the default no result text after filtering
|
||||
//'max_selected_options' => 'Infinity' // set to replace the max selected options
|
||||
'disable_search_threshold' => 10,
|
||||
'allow_single_deselect' => true,
|
||||
),
|
||||
'require_choice' => false,
|
||||
'pre_choices' => array()
|
||||
'functionName' => '', // function to be called on submit
|
||||
);
|
||||
$scope = isset($scope) ? $scope : '';
|
||||
|
||||
// merge options with defaults
|
||||
$defaults = array_replace_recursive($defaults_options, $options);
|
||||
|
@ -34,13 +35,26 @@
|
|||
function add_option($name, $param) {
|
||||
$option_html = '<option';
|
||||
if (is_array($param)) {
|
||||
if (isset($param['value'])) {
|
||||
$option_html .= ' value=' . h($param['value']);
|
||||
} else {
|
||||
$option_html .= ' value=' . h($name);
|
||||
}
|
||||
if (isset($param['additionalData'])) {
|
||||
$additionalData = json_encode($param['additionalData']);
|
||||
} else {
|
||||
$additionalData = json_encode(array());
|
||||
}
|
||||
$option_html .= ' data-additionaldata=' . $additionalData;
|
||||
|
||||
if (in_array('disabled', $param)) {
|
||||
$option_html .= ' disabled';
|
||||
} else if (in_array('selected', $param)) { // nonsense to pre-select if disabled
|
||||
$option_html .= ' selected';
|
||||
}
|
||||
} else {
|
||||
$option_html .= ' value=' . h($param);
|
||||
}
|
||||
$option_html .= ' value=' . (is_array($param)? h($name) : h($param));
|
||||
$option_html .= '>';
|
||||
|
||||
$option_html .= is_array($param)? h($name) : h($param);
|
||||
|
@ -51,19 +65,18 @@
|
|||
?>
|
||||
|
||||
<div class="popover_choice generic_picker">
|
||||
<legend><?php echo __(h($scope));?></legend>
|
||||
|
||||
<select <?php echo h(add_select_params($defaults)); ?>>
|
||||
<?php
|
||||
foreach ($items as $name => $param) {
|
||||
echo add_option($name, $param);
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
|
||||
<div class="overlay_spacing" style="margin: 5px; margin-top: 10px;">
|
||||
<button class="btn btn-primary" onclick="popoverPopup(this, '', 'events', 'genericPicker')">submit</button>
|
||||
<div>
|
||||
<select <?php echo h(add_select_params($defaults)); ?>>
|
||||
<?php
|
||||
foreach ($items as $name => $param) {
|
||||
echo add_option($name, $param);
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<button class="btn btn-primary" onclick="submitFunction(this, <?php echo $defaults['functionName']; ?>)">submit</button>
|
||||
</div>
|
||||
<!-- <div class="overlay_spacing" style="margin: 5px; margin-top: 10px;"> -->
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
@ -75,4 +88,12 @@
|
|||
var chosen_options = <?php echo json_encode($defaults['chosen_options']); ?>;
|
||||
$(".generic_picker select").chosen(chosen_options);
|
||||
})
|
||||
|
||||
function submitFunction(clicked, callback) {
|
||||
var $clicked = $(clicked);
|
||||
var $select = $clicked.parent().find('select');
|
||||
var selected = $select.val();
|
||||
var additionalData = $select.find(":selected").data('additionaldata');
|
||||
callback(selected, additionalData);
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/** Config **/
|
||||
$select_threshold = 3;
|
||||
$select_threshold = 6;
|
||||
|
||||
/** Global **/
|
||||
$use_select = count($choices) > $select_threshold;
|
||||
|
@ -26,13 +26,14 @@ $use_select = count($choices) > $select_threshold;
|
|||
dataType:"html",
|
||||
async: true,
|
||||
cache: false,
|
||||
beforeSend: function() {
|
||||
var loadingHtml = '<div style="height: 40px; width: 40px; left: 50%; position: relative;"><div class="spinner" style="height: 30px; width: 30px;"></div></div>';
|
||||
var $arrow = $clicked.closest('div.popover').find('div.arrow');
|
||||
syncPopoverArrow($arrow, $wrapper, loadingHtml)
|
||||
},
|
||||
success:function (data, textStatus) {
|
||||
var $arrow = $clicked.closest('div.popover').find('div.arrow');
|
||||
var ar_pos = $arrow.position();
|
||||
$wrapper.html(data);
|
||||
// redraw popover
|
||||
$arrow.css('top', ar_pos.top + 'px');
|
||||
$arrow.css('left', ar_pos.left + 'px');
|
||||
syncPopoverArrow($arrow, $wrapper, data)
|
||||
},
|
||||
error:function() {
|
||||
$wrapper.html('<div class="alert alert-error" style="margin-bottom: 0px;">Something went wrong - the queried function returned an exception. Contact your administrator for further details (the exception has been logged).</div>');
|
||||
|
@ -41,6 +42,15 @@ $use_select = count($choices) > $select_threshold;
|
|||
});
|
||||
}
|
||||
|
||||
// Used to keep the popover arrow at the correct place regardless of the popover content
|
||||
function syncPopoverArrow($arrow, $wrapper, content) {
|
||||
var ar_pos = $arrow.position();
|
||||
$wrapper.html(content);
|
||||
// redraw popover
|
||||
$arrow.css('top', ar_pos.top + 'px');
|
||||
$arrow.css('left', ar_pos.left + 'px');
|
||||
}
|
||||
|
||||
<?php if ($use_select): ?>
|
||||
function setupChosen(id) {
|
||||
var $elem = $('#'+id);
|
||||
|
|
|
@ -1,84 +1,16 @@
|
|||
<div class="popover_choice select_tag">
|
||||
<legend><?php echo __('Select Tag');?></legend>
|
||||
|
||||
<div style="display:none;">
|
||||
<?php
|
||||
if ($scope === 'attribute') {
|
||||
echo $this->Form->create('Attribute', array('url' => '/attributes/addTag/' . $object_id, 'style' => 'margin:0px;'));
|
||||
} elseif ($scope === 'event') {
|
||||
echo $this->Form->create('Event', array('url' => '/events/addTag/' . $object_id, 'style' => 'margin:0px;'));
|
||||
} elseif ($scope === 'tag_collection') {
|
||||
echo $this->Form->create('TagCollection', array('url' => '/tag_collections/addTag/' . $object_id, 'style' => 'margin:0px;'));
|
||||
}
|
||||
echo $this->Form->input('attribute_ids', array('style' => 'display:none;', 'label' => false));
|
||||
echo $this->Form->input('tag', array('value' => 0));
|
||||
echo $this->Form->end();
|
||||
?>
|
||||
</div>
|
||||
<div style="text-align:right;width:100%;" class="select_tag_search">
|
||||
<input id="filterField" style="width:100%;border:0px;padding:0px;" value="<?php echo h($filterData); ?>" placeholder="<?php echo __('search tags…');?>"/>
|
||||
</div>
|
||||
<div class="popover_choice_main" id ="popover_choice_main">
|
||||
<table style="width:100%;">
|
||||
<div style="display:none;">
|
||||
<?php
|
||||
foreach ($options as $k => &$option):
|
||||
$choice_id = $k;
|
||||
if ($taxonomy_id === 'collections') {
|
||||
$choice_id = 'collection_' . $choice_id;
|
||||
}
|
||||
if ($scope === 'attribute') {
|
||||
echo $this->Form->create('Attribute', array('url' => '/attributes/addTag/' . $object_id, 'style' => 'margin:0px;'));
|
||||
} elseif ($scope === 'event') {
|
||||
echo $this->Form->create('Event', array('url' => '/events/addTag/' . $object_id, 'style' => 'margin:0px;'));
|
||||
} elseif ($scope === 'tag_collection') {
|
||||
echo $this->Form->create('TagCollection', array('url' => '/tag_collections/addTag/' . $object_id, 'style' => 'margin:0px;'));
|
||||
}
|
||||
echo $this->Form->input('attribute_ids', array('style' => 'display:none;', 'label' => false));
|
||||
echo $this->Form->input('tag', array('value' => 0));
|
||||
echo $this->Form->end();
|
||||
?>
|
||||
|
||||
<tr style="border-top:1px solid black;" class="templateChoiceButton shown" id="field_<?php echo h($choice_id); ?>">
|
||||
<?php
|
||||
$onClickForm = 'quickSubmitTagForm';
|
||||
if ($scope === 'attribute') {
|
||||
$onClickForm = 'quickSubmitAttributeTagForm';
|
||||
}
|
||||
if ($scope === 'tag_collection') {
|
||||
$onClickForm = 'quickSubmitTagCollectionTagForm';
|
||||
}
|
||||
echo '<td style="padding-left:10px;padding-right:10px; text-align:center;width:100%;" onClick="' . $onClickForm .
|
||||
'(\'' . h($object_id) . '\', \'' . h($choice_id) . '\');" title="' . h($expanded[$k]) . '" role="button" tabindex="0" aria-label="' .
|
||||
__('Attach tag') . ' ' . h($option) . '">' . h($option) . '</td>';
|
||||
?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
</div>
|
||||
<div role="button" tabindex="0" aria-label="<?php echo __('Return to taxonomy selection');?>" class="popover-back useCursorPointer" onClick="getPopup('<?php echo h($object_id) . '/' . h($scope); ?>', 'tags', 'selectTaxonomy');" title="<?php echo __('Select Taxonomy');?>"><?php echo __('Back to Taxonomy Selection');?></div>
|
||||
<div role="button" tabindex="0" aria-label="<?php echo __('Cancel');?>" class="templateChoiceButton templateChoiceButtonLast" onClick="cancelPopoverForm();"><?php echo __('Cancel');?></div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var tags = <?php echo json_encode($options); ?>;
|
||||
$(document).ready(function() {
|
||||
resizePopoverBody();
|
||||
// Places the cursor at the end of the input before focusing
|
||||
var filterField = $("#filterField");
|
||||
var tempValue = filterField.val();
|
||||
filterField.val('');
|
||||
filterField.val(tempValue);
|
||||
filter();
|
||||
filterField.focus();
|
||||
});
|
||||
|
||||
function filter() {
|
||||
var filterString = $("#filterField").val().toLowerCase();
|
||||
$.each(tags, function(index, value) {
|
||||
if (value.toLowerCase().indexOf(filterString) == -1) {
|
||||
let element = $('#field_' + index);
|
||||
element.hide();
|
||||
element.removeClass('shown');
|
||||
} else {
|
||||
let element = $('#field_' + index);
|
||||
element.show();
|
||||
element.addClass('shown');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#filterField').keyup(filter);
|
||||
$(window).resize(function() {
|
||||
resizePopoverBody();
|
||||
});
|
||||
</script>
|
||||
<?php echo $this->Html->script('tag-selection-keyboard-navigation.js'); ?>
|
||||
<?php echo $this->element('generic_picker'); ?>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<!-- to delete if unused -->
|
||||
<div class="popover_choice select_tag_source">
|
||||
<legend><?php echo __('Select Tag Source');?></legend>
|
||||
<div style="text-align:right;width:100%;" class="select_tag_search">
|
||||
|
|
|
@ -896,6 +896,12 @@ a.proposal_link_red:hover {
|
|||
|
||||
a.pill-pre-picker {
|
||||
background-color: #0000000f;
|
||||
font-weight: bold;
|
||||
border: solid 1px #00000033;
|
||||
}
|
||||
|
||||
.generic_picker {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.gray_out {
|
||||
|
|
|
@ -586,8 +586,10 @@ function quickSubmitTagForm(event_id, tag_id) {
|
|||
return false;
|
||||
}
|
||||
|
||||
function quickSubmitAttributeTagForm(attribute_id, tag_id) {
|
||||
$('#AttributeTag').val(tag_id);
|
||||
// function quickSubmitAttributeTagForm(attribute_id, tag_id) {
|
||||
function quickSubmitAttributeTagForm(selected_tag_ids, addData) {
|
||||
attribute_id = addData.id;
|
||||
$('#AttributeTag').val(JSON.stringify(selected_tag_ids));
|
||||
if (attribute_id == 'selected') {
|
||||
$('#AttributeAttributeIds').val(getSelected());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue