Further work on the taxonomies

- colour coding
- filters on the index
- mass tag creation
pull/762/head
Iglocska 2015-11-26 04:31:24 +01:00
parent 1328d83fe5
commit 0572b2030e
9 changed files with 336 additions and 79 deletions

View File

@ -23,12 +23,19 @@ class TaxonomiesController extends AppController {
}
public function view($id) {
if (isset($this->passedArgs['pages'])) $currentPage = $this->passedArgs['pages'];
else $currentPage = 1;
if (isset($this->passedArgs['pages'])) {
$currentPage = $this->passedArgs['pages'];
} else {
$currentPage = 1;
}
$this->set('page', $currentPage);
$urlparams = '';
$passedArgs = array();
App::uses('CustomPaginationTool', 'Tools');
$taxonomy = $this->Taxonomy->getTaxonomy($id, array('full' => true));
$filter = isset($this->passedArgs['filter']) ? $this->passedArgs['filter'] : false;
$taxonomy = $this->Taxonomy->getTaxonomy($id, array('full' => true, 'filter' => $filter));
$this->set('filter', $filter);
if (empty($taxonomy)) throw new NotFoundException('Taxonomy not found.');
$pageCount = count($taxonomy['entries']);
$customPagination = new CustomPaginationTool();
$params = $customPagination->createPaginationRules($taxonomy['entries'], $this->passedArgs, 'TaxonomyEntry');
@ -153,4 +160,27 @@ class TaxonomiesController extends AppController {
}
$this->redirect(array('controller' => 'taxonomies', 'action' => 'index'));
}
public function addTag() {
if ((!$this->_isSiteAdmin() && !$this->userRole['perm_tagger']) || !$this->request->is('post')) throw new NotFoundException('You don\'t have permission to do that.');
if (isset($this->request->data['Taxonomy'])) {
$this->request->data['Tag'] = $this->request->data['Taxonomy'];
unset($this->request->data['Taxonomy']);
}
if (isset($this->request->data['Tag']['request'])) $this->request->data['Tag'] = $this->request->data['Tag']['request'];
if (!isset($this->request->data['Tag']['nameList'])) $this->request->data['Tag']['nameList'] = array($this->request->data['Tag']['name']);
else $this->request->data['Tag']['nameList'] = json_decode($this->request->data['Tag']['nameList'], true);
if ($this->Taxonomy->addTags($this->request->data['Tag']['taxonomy_id'], $this->request->data['Tag']['nameList'])) {
$this->Session->setFlash('The tag has been saved.');
} else {
$this->Session->setFlash('The tag could not be saved. Please, try again.');
}
$this->redirect($this->referer());
}
public function taxonomyMassConfirmation($id) {
if (!$this->_isSiteAdmin() && !$this->userRole['perm_tagger']) throw new NotFoundException('You don\'t have permission to do that.');
$this->set('id', $id);
$this->render('ajax/taxonomy_mass_confirmation');
}
}

View File

@ -56,4 +56,31 @@ class ColourPaletteTool {
}
return $colour;
}
// pass the element's id from the list along to get a colour for a single item
function generatePaletteFromString($string, $items, $onlySpecific = false) {
$hue = $this->__stringToNumber($string);
$saturation = 1;
$steps = 80 / $items;
$results = array();
if ($onlySpecific !== false && is_numeric($onlySpecific)) {
$value = (20 + ($steps * ($onlySpecific + 1))) / 100;
return $this->HSVtoRGB(array($hue, $saturation, $value));
}
for ($i = 0; $i < $items; $i++) {
$value = (20 + ($steps * ($i + 1))) / 100;
$rgb = $this->HSVtoRGB(array($hue, $saturation, $value));
$results[] = $rgb;
}
return $results;
}
private function __stringToNumber($string) {
$string = mb_convert_encoding($string, 'ASCII');
$number = 0;
for ($i = 0; $i < strlen($string); $i++) {
$number += ord($string[$i]);
}
return $number % 100 / 100;
}
}

View File

@ -59,8 +59,4 @@ class CustomPaginationTool {
if ($this->direction == 'desc') $multiplier = -1;
return strcmp(strtolower($a[$this->filterField]), strtolower($b[$this->filterField])) * $multiplier;
}
function truncateByRules($items, $rules, $passedArgs) {
}
}

View File

@ -145,13 +145,34 @@ class Tag extends AppModel {
return $colour;
}
public function quickAdd($name) {
public function quickAdd($name, $colour = false) {
$this->create();
if ($colour === false) $colour = $this->random_color();
$data = array(
'name' => $name,
'colour' => $this->random_color(),
'colour' => $colour,
'exportable' => 1
);
return ($this->save($data));
}
public function quickEdit($tag, $name, $colour) {
if ($tag['Tag']['colour'] !== $colour || $tag['Tag']['name'] !== $name) {
$tag['Tag']['name'] = $name;
$tag['Tag']['colour'] = $colour;
return ($this->save($tag['Tag']));
}
return true;
}
public function getTagsForNamespace($namespace) {
$tags_temp = $this->find('all', array(
'recursive' => -1,
'contain' => 'EventTag',
'conditions' => array('UPPER(name) LIKE' => strtoupper($namespace) . '%'),
));
$tags = array();
foreach ($tags_temp as &$temp) $tags[strtoupper($temp['Tag']['name'])] = $temp;
return $tags;
}
}

View File

@ -81,28 +81,22 @@ class Taxonomy extends AppModel{
}
}
$result = $this->saveAssociated($taxonomy, array('deep' => true));
if ($result) return $this->id;
if ($result) {
$this->__updateTags($this->id);
return $this->id;
}
return $this->validationErrors;
}
public function getTaxonomy($id, $options = array('full' => false)) {
$this->Tag = ClassRegistry::init('Tag');
private function __getTaxonomy($id, $options = array('full' => false, 'filter' => false)) {
$recursive = -1;
if ($options['full']) $recursive = 2;
$filter = false;
if (isset($options['filter'])) $filter = $options['filter'];
$taxonomy = $this->find('first', array(
'recursive' => $recursive,
'conditions' => array('Taxonomy.id' => $id)
));
$tags_temp = $this->Tag->find('all', array(
'recursive' => -1,
'contain' => 'EventTag',
'conditions' => array('name LIKE' => $taxonomy['Taxonomy']['namespace'] . '%'),
));
$tags = array();
foreach ($tags_temp as &$temp) {
$tags[$temp['Tag']['name']] = $temp;
}
unset($tags_temp);
if (empty($taxonomy)) return false;
$entries = array();
foreach ($taxonomy['TaxonomyPredicate'] as &$predicate) {
@ -110,21 +104,81 @@ class Taxonomy extends AppModel{
foreach ($predicate['TaxonomyEntry'] as &$entry) {
$temp = array('tag' => $taxonomy['Taxonomy']['namespace'] . ':' . $predicate['value'] . '="' . $entry['value'] . '"');
$temp['expanded'] = (!empty($predicate['expanded']) ? $predicate['expanded'] : $predicate['value']) . ': ' . (!empty($entry['expanded']) ? $entry['expanded'] : $entry['value']);
$temp['existing_tag'] = isset($tags[$temp['tag']]) ? $tags[$temp['tag']] : false;
$entries[] = $temp;
}
} else {
$temp = array('tag' => $taxonomy['Taxonomy']['namespace'] . ':' . $predicate['value']);
$temp['existing_tag'] = isset($tags[$temp['tag']]) ? $tags[$temp['tag']] : false;
$temp['expanded'] = !empty($predicate['expanded']) ? $predicate['expanded'] : $predicate['value'];
$entries[] = $temp;
}
}
$taxonomy = array('Taxonomy' => $taxonomy['Taxonomy']);
if ($filter) {
$namespaceLength = strlen($taxonomy['Taxonomy']['namespace']);
foreach ($entries as $k => &$entry) {
if (strpos(substr(strtoupper($entry['tag']), $namespaceLength), strtoupper($filter)) === false) unset($entries[$k]);
}
}
$taxonomy['entries'] = $entries;
return $taxonomy;
}
public function getTaxonomy($id, $options = array('full' => false)) {
$this->Tag = ClassRegistry::init('Tag');
$taxonomy = $this->__getTaxonomy($id, $options);
if (empty($taxonomy)) return false;
$tags = $this->Tag->getTagsForNamespace($taxonomy['Taxonomy']['namespace']);
if (isset($taxonomy['entries'])) {
foreach ($taxonomy['entries'] as &$temp) {
$temp['existing_tag'] = isset($tags[strtoupper($temp['tag'])]) ? $tags[strtoupper($temp['tag'])] : false;
}
}
return $taxonomy;
}
private function __updateTags($id) {
$this->Tag = ClassRegistry::init('Tag');
App::uses('ColourPaletteTool', 'Tools');
$paletteTool = new ColourPaletteTool();
$taxonomy = $this->__getTaxonomy($id, array('full' => true));
$colours = $paletteTool->generatePaletteFromString($taxonomy['Taxonomy']['namespace'], count($taxonomy['entries']));
$this->Tag = ClassRegistry::init('Tag');
$tags = $this->Tag->getTagsForNamespace($taxonomy['Taxonomy']['namespace']);
foreach ($taxonomy['entries'] as $k => &$entry) {
if (isset($tags[strtoupper($entry['tag'])])) {
$temp = $tags[strtoupper($entry['tag'])];
if ($temp['Tag']['colour'] != $colours[$k] || $temp['Tag']['name'] !== $entry['tag']) {
$temp['Tag']['colour'] = $colours[$k];
$temp['Tag']['name'] = $entry['tag'];
$this->Tag->save($temp['Tag']);
}
}
}
}
public function addTags($id, $tagList) {
if (!is_array($tagList)) $tagList = array($tagList);
$this->Tag = ClassRegistry::init('Tag');
App::uses('ColourPaletteTool', 'Tools');
$paletteTool = new ColourPaletteTool();
App::uses('ColourPaletteTool', 'Tools');
$taxonomy = $this->__getTaxonomy($id, array('full' => true));
$tags = $this->Tag->getTagsForNamespace($taxonomy['Taxonomy']['namespace']);
$colours = $paletteTool->generatePaletteFromString($taxonomy['Taxonomy']['namespace'], count($taxonomy['entries']));
foreach ($taxonomy['entries'] as $k => &$entry) {
foreach ($tagList as $tagName) {
if ($tagName === $entry['tag']) {
if (isset($tags[strtoupper($entry['tag'])])) {
$this->Tag->quickEdit($tags[strtoupper($entry['tag'])], $tagName, $colours[$k]);
} else {
$this->Tag->quickAdd($tagName, $colours[$k]);
}
}
}
}
return true;
}
public function listTaxonomies($options = array('full' => false, 'enabled' => false)) {
$recursive = -1;
if ($options['full']) $recursive = 2;

View File

@ -0,0 +1,37 @@
<div class="confirmation">
<?php
echo $this->Form->create('Taxonomy', array('style' => 'margin:0px;', 'id' => 'PromptForm', 'url' => '/taxonomies/addTag'));
?>
<div class="hidden">
<?php
echo $this->Form->input('nameList', array('value' => '{}'));
?>
</div>
<?php
echo $this->Form->input('taxonomy_id', array('type' => 'hidden', 'value' => $id));
?>
<legend>Create Tags</legend>
<div style="padding-left:5px;padding-right:5px;padding-bottom:5px;">
<p>Are you sure you want to create / update all selected tags?</p>
<table>
<tr>
<td style="vertical-align:top">
<span id="PromptYesButton" class="btn btn-primary" onClick="submitMassTaxonomyTag()">Yes</span>
</td>
<td style="width:540px;">
</td>
<td style="vertical-align:top;">
<span class="btn btn-inverse" id="PromptNoButton" onClick="cancelPrompt();">No</span>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
$(document).ready(function(){
getSelectedTaxonomyNames();
});
</script>
<?php
echo $this->Form->end();
?>
</div>

View File

@ -36,6 +36,7 @@
&nbsp;
</dd>
</dl>
<br />
<div class="pagination">
<ul>
<?php
@ -53,70 +54,102 @@
?>
</ul>
</div>
<table class="table table-striped table-hover table-condensed">
<tr>
<th><?php echo $this->Paginator->sort('tag');?></th>
<th><?php echo $this->Paginator->sort('expanded');?></th>
<th><?php echo $this->Paginator->sort('events');?></th>
<th><?php echo $this->Paginator->sort('tag');?></th>
</tr><?php
foreach ($entries as $k => $item): ?>
<tr>
<td class="short"><?php echo h($item['tag']); ?>&nbsp;</td>
<td><?php echo h($item['expanded']); ?>&nbsp;</td>
<td class="short">
<?php
if ($item['existing_tag']) {
?>
<a href='<?php echo $baseurl."/events/index/searchtag:". h($item['existing_tag']['Tag']['id']);?>'><?php echo count($item['existing_tag']['EventTag']);?></a>
<?php
} else {
echo 'N/A';
}
?>
</td>
<td class="short">
<?php
if ($item['existing_tag']):
$url = $baseurl . '/events/index/searchtag:' . h($item['existing_tag']['Tag']['id']);
if ($isAclTagger) $url = $baseurl . '/tags/edit/' . h($item['existing_tag']['Tag']['id']);
?>
<a href="<?php echo $url;?>" class="<?php echo $isAclTagger ? 'tagFirstHalf' : 'tag' ?>" style="background-color:<?php echo h($item['existing_tag']['Tag']['colour']);?>;color:<?php echo $this->TextColour->getTextColour($item['existing_tag']['Tag']['colour']);?>"><?php echo h($item['existing_tag']['Tag']['name']); ?></a>
<?php
else:
<div id="attributeList" class="attributeListContainer">
<div class="tabMenuFixedContainer">
<div class="tabMenu tabMenuEditBlock noPrint mass-select" style="float:left;top:-1px;">
<span id="multi-edit-button" title="Create / update selected tags" class="icon-plus useCursorPointer" onClick="addSelectedTaxonomies(<?php echo $taxonomy['id']; ?>);"></span>
</div>
<div style="float:right !important;overflow:hidden;border:0px;padding:0px;padding-right:200px;">
<input type="text" id="quickFilterField" class="tabMenuFilterField taxFilter" value="<?php echo h($filter);?>"></input><span id="quickFilterButton" class="useCursorPointer taxFilterButton" onClick='quickFilterTaxonomy("<?php echo h($taxonomy['id']);?>");'>Filter</span>
</div>
</div>
<table class="table table-striped table-hover table-condensed">
<tr>
<?php if ($isAclTagger && !empty($entries)): ?>
<th><input class="select_all" type="checkbox" onClick="toggleAllTaxonomyCheckboxes();" /></th>
<?php endif;?>
<th><?php echo $this->Paginator->sort('tag');?></th>
<th><?php echo $this->Paginator->sort('expanded');?></th>
<th><?php echo $this->Paginator->sort('events');?></th>
<th><?php echo $this->Paginator->sort('tag');?></th>
<th>Action</th>
</tr><?php
foreach ($entries as $k => $item): ?>
<tr>
<?php if ($isAclTagger): ?>
<td style="width:10px;">
<input id = "select_<?php echo h($k); ?>" class="select_taxonomy" type="checkbox" data-id="<?php echo h($k);?>" />
</td>
<?php endif; ?>
<td id="tag_<?php echo h($k); ?>" class="short"><?php echo h($item['tag']); ?></td>
<td><?php echo h($item['expanded']); ?>&nbsp;</td>
<td class="short">
<?php
if ($item['existing_tag']) {
?>
<a href='<?php echo $baseurl."/events/index/searchtag:". h($item['existing_tag']['Tag']['id']);?>'><?php echo count($item['existing_tag']['EventTag']);?></a>
<?php
} else {
echo 'N/A';
}
?>
</td>
<td class="short">
<?php
if ($item['existing_tag']):
$url = $baseurl . '/events/index/searchtag:' . h($item['existing_tag']['Tag']['id']);
if ($isAclTagger) $url = $baseurl . '/tags/edit/' . h($item['existing_tag']['Tag']['id']);
?>
<a href="<?php echo $url;?>" class="<?php echo $isAclTagger ? 'tagFirstHalf' : 'tag' ?>" style="background-color:<?php echo h($item['existing_tag']['Tag']['colour']);?>;color:<?php echo $this->TextColour->getTextColour($item['existing_tag']['Tag']['colour']);?>"><?php echo h($item['existing_tag']['Tag']['name']); ?></a>
<?php
endif;
?>
</td>
<td class="action">
<?php
if ($isAclTagger && $taxonomy['enabled']) {
echo $this->Form->create('Tag', array('id' => 'quick_' . h($k), 'url' => '/tags/quickAdd/', 'style' => 'margin:0px;'));
echo $this->Form->create('Tag', array('id' => 'quick_' . h($k), 'url' => '/taxonomies/addTag/', 'style' => 'margin:0px;'));
echo $this->Form->input('name', array('type' => 'hidden', 'value' => $item['tag']));
echo $this->Form->input('taxonomy_id', array('type' => 'hidden', 'value' => $taxonomy['id']));
?>
<span class="icon-plus useCursorPointer" onClick="submitQuickTag('<?php echo 'quick_' . h($k); ?>');"></span>
<span class="<?php echo $item['existing_tag'] ? 'icon-refresh' : 'icon-plus'; ?> useCursorPointer" onClick="submitQuickTag('<?php echo 'quick_' . h($k); ?>');"></span>
<?php
echo $this->Form->end();
} else {
echo 'N/A';
}
endif;
?>
</td>
</tr>
<?php endforeach; ?>
</table>
<p>
<?php
echo $this->Paginator->counter(array(
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
));
?>
</p>
<div class="pagination">
<ul>
<?php
echo $this->Paginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
echo $this->Paginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
?>
</ul>
</div>
?>
</td>
</tr>
<?php endforeach; ?>
</table>
<p>
<?php
echo $this->Paginator->counter(array(
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
));
?>
</p>
<div class="pagination">
<ul>
<?php
echo $this->Paginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
echo $this->Paginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
?>
</ul>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('input:checkbox').removeAttr('checked');
$('.mass-select').hide();
$('.select_taxonomy, .select_all').click(function(){
taxonomyListAnyCheckBoxesChecked();
});
});
</script>
<?php
echo $this->element('side_menu', array('menuList' => 'taxonomies', 'menuItem' => 'view'));
?>

View File

@ -1032,6 +1032,22 @@ a.proposal_link_red:hover {
margin-left:200px;
}
.taxFilter {
float:none !important;
margin-bottom:0px !important;
}
.taxFilterButton {
border-radius: 0px 10px 0 0 !important;
border: 1px solid #ddd !important;
border-bottom: 0px !important;
padding-left: 3px;
padding-top: 2px;
padding-bottom: 5px;
padding-right: 4px;
background-color: #f9f9f9 !important;
}
.tabMenu [class^="icon-"] {
vertical-align:baseline;
margin-top:3px;

View File

@ -349,6 +349,14 @@ function toggleAllAttributeCheckboxes() {
}
}
function toggleAllTaxonomyCheckboxes() {
if ($(".select_all").is(":checked")) {
$(".select_taxonomy").prop("checked", true);
} else {
$(".select_taxonomy").prop("checked", false);
}
}
function attributeListAnyAttributeCheckBoxesChecked() {
if ($('.select_attribute:checked').length > 0) $('.mass-select').show();
else $('.mass-select').hide();
@ -359,6 +367,11 @@ function attributeListAnyProposalCheckBoxesChecked() {
else $('.mass-proposal-select').hide();
}
function taxonomyListAnyCheckBoxesChecked() {
if ($('.select_taxonomy:checked').length > 0) $('.mass-select').show();
else $('.mass-select').hide();
}
function multiSelectAction(event, context) {
var settings = {
deleteAttributes: {
@ -417,6 +430,19 @@ function editSelectedAttributes(event) {
});
}
function addSelectedTaxonomies(taxonomy) {
$.get("/taxonomies/taxonomyMassConfirmation/"+taxonomy, function(data) {
$("#confirmation_box").fadeIn();
$("#gray_out").fadeIn();
$("#confirmation_box").html(data);
});
}
function submitMassTaxonomyTag() {
$('#PromptForm').submit();
}
function getSelected() {
var selected = [];
$(".select_attribute").each(function() {
@ -428,6 +454,18 @@ function getSelected() {
return JSON.stringify(selected);
}
function getSelectedTaxonomyNames() {
var selected = [];
$(".select_taxonomy").each(function() {
if ($(this).is(":checked")) {
var row = $(this).data("id");
var temp = $('#tag_' + row).html();
selected.push(temp);
}
});
$('#TaxonomyNameList').val(JSON.stringify(selected));
}
function loadEventTags(id) {
$.ajax({
dataType:"html",
@ -1027,6 +1065,11 @@ function quickFilterEvents(passedArgs) {
window.location.href=url;
}
function quickFilterTaxonomy(taxonomy_id, passedArgs) {
var url = "/taxonomies/view/" + taxonomy_id + "/filter:" + $('#quickFilterField').val();
window.location.href=url;
}
function quickFilterRemoteEvents(passedArgs, id) {
passedArgs["searchall"] = $('#quickFilterField').val();
var url = "/servers/previewIndex/" + id;