Commit 353e4105 authored by Robert Lyon's avatar Robert Lyon

Bug 1272122: Add image rotator to the filebrowser edit item form

behatnotneeded

Change-Id: I7fb2fa618719dd12d6b77177a9e1ad127ea175d2
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent 95aada8c
......@@ -43,13 +43,13 @@ class PluginBlocktypeImage extends MaharaCoreBlocktype {
$image = $instance->get_artefact_instance($id);
$wwwroot = get_config('wwwroot');
$viewid = $instance->get('view');
$edittime = '&time=' . time();
if ($image instanceof ArtefactTypeProfileIcon) {
$src = $wwwroot . 'thumb.php?type=profileiconbyid&id=' . $id . '&view=' . $viewid;
$src = $wwwroot . 'thumb.php?type=profileiconbyid&id=' . $id . '&view=' . $viewid . $edittime;
$description = $image->get('title');
}
else {
$src = $wwwroot . 'artefact/file/download.php?file=' . $id . '&view=' . $viewid;
$src = $wwwroot . 'artefact/file/download.php?file=' . $id . '&view=' . $viewid . $edittime;
$description = $image->get('description');
$description = empty($description) ? $image->get('title') : $description;
}
......@@ -112,6 +112,19 @@ class PluginBlocktypeImage extends MaharaCoreBlocktype {
);
}
public static function instance_config_save($values, $instance) {
if (isset($values['artefactid'])) {
// Pass back a list of any other blocks that need to be rendered
// due to this change.
$values['_redrawblocks'] = array_unique(get_column(
'view_artefact', 'block',
'artefact', $values['artefactid'],
'view', $instance->get('view')
));
}
return $values;
}
public static function filebrowser_element(&$instance, $default=array()) {
$element = ArtefactTypeFileBase::blockconfig_filebrowser_element($instance, $default);
$element['title'] = get_string('image');
......
......@@ -26,6 +26,7 @@
<FIELD NAME="artefact" TYPE="int" LENGTH="10" NOTNULL="true" />
<FIELD NAME="width" TYPE="int" LENGTH="10" NOTNULL="false" />
<FIELD NAME="height" TYPE="int" LENGTH="10" NOTNULL="false" />
<FIELD NAME="orientation" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" ENUM="true" ENUMVALUES="'0','90','180','270'" />
</FIELDS>
<KEYS>
<KEY NAME="artefactpk" TYPE="primary" FIELDS="artefact" />
......
......@@ -498,5 +498,17 @@ function xmldb_artefact_file_upgrade($oldversion=0) {
add_index($table, $index);
}
if ($oldversion < 2017101300) {
log_debug("Add 'orientation' column to the 'artefact_file_image' table for image rotator");
$table = new XMLDBTable('artefact_file_image');
$field = new XMLDBField('orientation');
$field->setAttributes(XMLDB_TYPE_CHAR, 10, null, null, null, XMLDB_ENUM, array('0', '90', '180', '270'), '0');
if (!field_exists($table, $field)) {
add_field($table, $field);
}
// clear the cached resized images to all recreation with new naming scheme
clear_resized_images_cache();
}
return $status;
}
......@@ -282,6 +282,29 @@ var FileBrowser = (function($) {
else {
descriptionrow.removeClass('hidden');
}
if (self.filedata[id].artefacttype == 'image' || self.filedata[id].artefacttype == 'profileicon') {
var rotator = $('#' + self.id + '_rotator');
rotator.removeClass('hidden');
var rotatorimg = rotator.find('img');
// set up initial info
var origangle = parseInt(self.filedata[id].orientation, 10);
var jstimestamp = Math.round(new Date().getTime()/1000);
rotatorimg.prop('src', config.wwwroot + '/artefact/file/download.php?file=' + id + '&maxheight=100&maxwidth=100&ts=' + jstimestamp);
rotatorimg.data('angle', origangle);
rotatorimg.prop('style', '');
rotator.find('span').off();
$('#' + self.id + '_edit_orientation').val(origangle);
// Do transformation
rotator.find('span').on('click', function() {
var angle = (rotatorimg.data('angle') + 90) || 90;
rotatorimg.css({'transform': 'rotate(' + (angle - origangle) + 'deg)', 'transition': 'all 1s ease'});
rotatorimg.data('angle', angle);
$('#' + self.id + '_edit_orientation').val(angle % 360);
});
}
else {
$('#' + self.id + '_rotator').addClass('hidden');
}
$('#' + self.id + '_edit_title').val(self.filedata[id].title);
$('#' + self.id + '_edit_description').val(self.filedata[id].description == null ? '' : self.filedata[id].description);
if ($('#' + self.id + '_edit_license').length) {
......
......@@ -537,12 +537,13 @@ abstract class ArtefactTypeFileBase extends ArtefactType {
global $USER;
$select = '
SELECT
a.id, a.artefacttype, a.mtime, f.size, a.title, a.description, a.license, a.licensor, a.licensorurl, a.locked, a.allowcomments, u.profileicon AS defaultprofileicon,
a.id, a.artefacttype, a.mtime, f.size, fi.orientation, a.title, a.description, a.license, a.licensor, a.licensorurl, a.locked, a.allowcomments, u.profileicon AS defaultprofileicon,
COUNT(DISTINCT c.id) AS childcount, COUNT (DISTINCT aa.artefact) AS attachcount, COUNT(DISTINCT va.view) AS viewcount, COUNT(DISTINCT s.id) AS skincount,
COUNT(DISTINCT api.id) AS profileiconcount';
$from = '
FROM {artefact} a
LEFT OUTER JOIN {artefact_file_files} f ON f.artefact = a.id
LEFT OUTER JOIN {artefact_file_image} fi ON fi.artefact = a.id
LEFT OUTER JOIN {artefact} c ON c.parent = a.id
LEFT OUTER JOIN {artefact} api ON api.parent = a.id AND api.artefacttype = \'profileicon\'
LEFT OUTER JOIN {view_artefact} va ON va.artefact = a.id
......@@ -567,7 +568,7 @@ abstract class ArtefactTypeFileBase extends ArtefactType {
$groupby = '
GROUP BY
a.id, a.artefacttype, a.mtime, f.size, a.title, a.description, a.license, a.licensor, a.licensorurl, a.locked, a.allowcomments,
u.profileicon';
u.profileicon, fi.orientation';
$phvals = array();
......@@ -2308,6 +2309,7 @@ class ArtefactTypeImage extends ArtefactTypeFile {
protected $width;
protected $height;
protected $orientation;
public function __construct($id = 0, $data = null) {
parent::__construct($id, $data);
......@@ -2345,7 +2347,8 @@ class ArtefactTypeImage extends ArtefactTypeFile {
$data = (object)array(
'artefact' => $this->get('id'),
'width' => $this->get('width'),
'height' => $this->get('height')
'height' => $this->get('height'),
'orientation' => $this->get('orientation')
);
if ($new) {
......@@ -2380,7 +2383,9 @@ class ArtefactTypeImage extends ArtefactTypeFile {
}
public function get_local_path($data=array()) {
return get_dataroot_image_path('artefact/file/', $this->fileid, $data);
require_once('file.php');
$result = get_dataroot_image_path('artefact/file/', $this->fileid, $data, $this->orientation);
return $result;
}
public function delete() {
......@@ -2480,7 +2485,9 @@ class ArtefactTypeProfileIcon extends ArtefactTypeImage {
}
public function get_local_path($data=array()) {
return get_dataroot_image_path('artefact/file/profileicons/', $this->fileid, $data);
require_once('file.php');
$result = get_dataroot_image_path('artefact/file/profileicons/', $this->fileid, $data, $this->orientation);
return $result;
}
public function in_view_list() {
......@@ -2586,6 +2593,7 @@ class ArtefactTypeProfileIcon extends ArtefactTypeImage {
$mimetype = get_field('artefact_file_files', 'filetype', 'artefact', $id);
if ($id && $fileid = get_field('artefact_file_files', 'fileid', 'artefact', $id)) {
$orientation = get_field('artefact_file_image', 'orientation', 'artefact', $id);
// Check that the profile icon is allowed to be seen
// Any profileiconbyid file that has been set as a user's default icon is ok
// But icons that are not should only be seen by their owner
......@@ -2605,7 +2613,7 @@ class ArtefactTypeProfileIcon extends ArtefactTypeImage {
}
}
}
if ($path = get_dataroot_image_path('artefact/file/profileicons', $fileid, $size)) {
if ($path = get_dataroot_image_path('artefact/file/profileicons', $fileid, $size, $orientation)) {
if ($mimetype) {
header('Content-type: ' . $mimetype);
......
......@@ -12,6 +12,6 @@
defined('INTERNAL') || die();
$config = new StdClass;
$config->version = 2017100901;
$config->release = '1.2.9';
$config->version = 2017101300;
$config->release = '1.3.0';
......@@ -48,6 +48,7 @@ $string['loading'] = 'Loading ...';
$string['showtags'] = 'Show my tags';
$string['errorprocessingform'] = 'There was an error with submitting this form. Please check the marked fields and try again.';
$string['description'] = 'Description';
$string['orientation'] = 'Orientation';
$string['remove'] = 'Remove';
$string['Close'] = 'Close';
$string['Help'] = 'Help';
......
......@@ -5790,5 +5790,12 @@ function xmldb_core_upgrade($oldversion=0) {
add_index($table, $index);
}
if ($oldversion < 2018022500) {
log_debug('Upgrade artefact/file plugin');
if ($data = check_upgrades('artefact.file')) {
upgrade_plugin($data);
}
}
return $status;
}
......@@ -511,10 +511,15 @@ function is_image_file($path) {
*
* As a number, the path returned will have the largest side being
* the length specified.
* @param int $orientation The orinetation of the returned image
* - valid options 0 (original),
* 90 (90 deg clockwise),
* 180 (inverted),
* 270 (90 deg anti-clockwise)
* @return string The path on disk where the appropriate file resides, or false
* if an appropriate file could not be located or generated
*/
function get_dataroot_image_path($path, $id, $size=null) {
function get_dataroot_image_path($path, $id, $size=null, $orientation = 0) {
global $THEME;
$dataroot = get_config('dataroot');
$imagepath = $dataroot . $path;
......@@ -544,11 +549,21 @@ function get_dataroot_image_path($path, $id, $size=null) {
return false;
}
if (!$size) {
// No size has been asked for. Return the original
if (!$size && $orientation == 0) {
// No size has been asked for nor any rotation. Return the original
return $originalimage;
}
else {
// If we are rorating an image and do not have the $size supplied we need to get size of original
if (!$size && $orientation != 0 && is_readable($originalimage) && filesize($originalimage)) {
list($owidth, $oheight) = getimagesize($originalimage);
$size['w'] = $owidth;
$size['h'] = $oheight;
if ($orientation == 90 || $orientation == 270) {
$size['h'] = $owidth;
$size['w'] = $oheight;
}
}
// Check if the image is available in the size requested
$sizestr = serialize($size);
$md5 = md5("{$id}.{$sizestr}");
......@@ -559,7 +574,7 @@ function get_dataroot_image_path($path, $id, $size=null) {
$resizedimagedir .= substr($md5, $i, 1) . '/';
check_dir_exists($resizedimagedir);
}
$resizedimagefile = "{$resizedimagedir}{$md5}.$id";//.$sizestr";
$resizedimagefile = "{$resizedimagedir}{$md5}.{$orientation}.$id";//.$sizestr";
if (is_readable($resizedimagefile)) {
return $resizedimagefile;
......@@ -635,6 +650,11 @@ function get_dataroot_image_path($path, $id, $size=null) {
return false;
}
if ($orientation != 0) {
// We minus orientation from 360 as imagerotate() does rotation anticlockwise and we do it clockwise
$oldih = imagerotate($oldih, 360 - $orientation, 0);
}
$oldx = imagesx($oldih);
$oldy = imagesy($oldih);
......
......@@ -87,6 +87,7 @@ function pieform_element_filebrowser(Pieform $form, $element) {
}
if ($config['select']) {
$selected = array();
if (function_exists($element['selectlistcallback'])) {
if ($form->is_submitted() && $form->has_errors() && param_exists($prefix . '_selected') && is_array(param_array($prefix . '_selected'))) {
$value = array_keys(param_array($prefix . '_selected'));
......@@ -110,6 +111,9 @@ function pieform_element_filebrowser(Pieform $form, $element) {
}
$selected = $element['selectlistcallback']($value);
}
foreach ($selected as $k => $v) {
$v->time = '&time=' . time();
}
$smarty->assign('selectedlist', $selected);
$selectedliststr = json_encode($selected);
}
......@@ -157,14 +161,17 @@ function pieform_element_filebrowser(Pieform $form, $element) {
$filters = isset($element['filters']) ? $element['filters'] : null;
$filedata = ArtefactTypeFileBase::get_my_files_data($folder, $userid, $group, $institution, $filters);
$smarty->assign('filelist', $filedata);
// Only allow 'Download folder content as zip' link if theres some kind of content (file or subfolder with content)
$addzipdownloadlink = false;
foreach ($filedata as $k => $v) {
if (empty($v->isparent) && ($v->artefacttype != 'folder' || ($v->artefacttype == 'folder' && !empty($v->childcount)))) {
$addzipdownloadlink = true;
}
if ($v->artefacttype == 'image' || $v->artefacttype == 'profileicon') {
$v->icon .= '&time=' . time();
}
}
$smarty->assign('filelist', $filedata);
$smarty->assign('downloadfolderaszip', $addzipdownloadlink);
$configstr = json_encode($config);
$fileliststr = json_encode($filedata);
......@@ -339,9 +346,12 @@ function pieform_element_filebrowser_build_filelist($form, $element, $folder, $h
if (empty($v->isparent) && ($v->artefacttype != 'folder' || ($v->artefacttype == 'folder' && !empty($v->childcount)))) {
$addzipdownloadlink = true;
}
if ($v->artefacttype == 'image' || $v->artefacttype == 'profileicon') {
$v->icon .= '&time=' . time();
}
}
$smarty->assign('downloadfolderaszip', $addzipdownloadlink);
$smarty->assign('downloadfolderaszip', $addzipdownloadlink);
$smarty->assign('edit', -1);
$smarty->assign('highlight', $highlight);
$smarty->assign('editable', $editable);
......@@ -597,6 +607,7 @@ function pieform_element_filebrowser_doupdate(Pieform $form, $element) {
'tags' => param_variable($prefix . '_edit_tags', ''),
'folder' => $element['folder'],
'allowcomments' => param_boolean($prefix . '_edit_allowcomments'),
'orientation' => param_variable($prefix . '_edit_orientation'),
);
if (get_config('licensemetadata')) {
$data = array_merge($data, array(
......@@ -1203,6 +1214,10 @@ function pieform_element_filebrowser_update(Pieform $form, $element, $data) {
$artefact->set('title', trim($data['title']));
$artefact->set('description', $data['description']);
$artefact->set('allowcomments', (int) $data['allowcomments']);
if (property_exists($artefact, 'orientation')) {
$orientation = is_mysql() ? (string) $data['orientation'] : (int) $data['orientation'];
$artefact->set('orientation', $orientation);
}
$oldtags = $artefact->get('tags');
$newtags = $data['tags'];
......
......@@ -5150,7 +5150,7 @@ function is_valid_serialized_skin_attribute($sobj) {
}
/*
* Crear all Mahara chaches.
* Clear all Mahara caches.
* @param bool $clearsessiondirs Optional to clear sessions. Useful during upgrade when session structure changes
*
* @return bool True if success, false otherwise.
......@@ -5162,6 +5162,7 @@ function clear_all_caches($clearsessiondirs = false) {
clear_menu_cache();
update_safe_iframe_regex();
bump_cache_version();
clear_resized_images_cache();
$dwoo_dir = get_config('dataroot') . 'dwoo';
if (check_dir_exists($dwoo_dir) && !rmdirr($dwoo_dir)) {
......@@ -5188,6 +5189,30 @@ function clear_all_caches($clearsessiondirs = false) {
return $result;
}
/**
* Clear the generated resized images
* @param bool $profileonly Optional clear only the profile image resized files
*
* @return bool True if success, false otherwise
*/
function clear_resized_images_cache($profileonly=false) {
require_once(get_config('libroot') . 'file.php');
$filedir = get_config('dataroot') . 'artefact/file/';
$profiledir = $filedir . 'profileicons/resized';
if (check_dir_exists($profiledir) && !rmdirr($profiledir)) {
log_debug('Can not remove profile image resized directory ' . $profiledir);
return false;
}
if (!$profileonly) {
$imagedir = $filedir . 'resized';
if (check_dir_exists($imagedir) && !rmdirr($imagedir)) {
log_debug('Can not remove image resized directory ' . $imagedir);
return false;
}
}
}
/*
* Replaces all accented characters with un-accented counterparts.
*
......
......@@ -16,7 +16,7 @@ $config = new stdClass();
// See https://wiki.mahara.org/wiki/Developer_Area/Version_Numbering_Policy
// For upgrades on stable branches, increment the version by one. On master, use the date.
$config->version = 2018022400;
$config->version = 2018022500;
$config->series = '18.04';
$config->release = '18.04dev';
$config->minupgradefrom = 2015030409;
......
......@@ -5,10 +5,18 @@
{if $fileinfo}{if $fileinfo->artefacttype == 'folder'}{str tag=editfolder section=artefact.file}{else}{str tag=editfile section=artefact.file}{/if}{/if}
</h4>
<div class="form-group requiredmarkerdesc">{str tag='requiredfields' section='pieforms' arg1='*'}</div>
<div id="{$prefix}_rotator" class="form-group image-rotator">
<label for="{$prefix}_edit_orientation">{str tag=orientation}</label>
<span class="image-rotator-inner">
<img role="presentation" aria-hidden="true" src="" title="" alt="">
</span>
<span class="icon icon-rotate-right btn btn-default"></span>
<input type="hidden" id="{$prefix}_edit_orientation" name="{$prefix}_edit_orientation" value="0">
</div>
<div class="required form-group">
<label for="{$prefix}_edit_title">{str tag=name}<span class="requiredmarker"> *</span>
</label>
<input type="text" class="text" name="{$prefix}_edit_title" id="{$prefix}_edit_title" value="{$fileinfo->title}"/>
<input type="text" class="text" name="{$prefix}_edit_title" id="{$prefix}_edit_title" value="{$fileinfo->title}" size="40" />
</div>
{if $fileinfo->artefacttype != 'profileicon'}
<div class="form-group">
......
......@@ -12,7 +12,7 @@
{if $file->artefacttype !== 'image'}
<span class="icon icon-{$file->artefacttype} icon-lg" role="presentation" aria-hidden="true"></span>
{else}
<img src="{if $file->artefacttype == 'image' || $file->artefacttype == 'profileicon'}{$WWWROOT}artefact/file/download.php?file={$file->id}&size=24x24{else}{theme_url filename=images/`$file->artefacttype`.png}{/if}">
<img src="{if $file->artefacttype == 'image' || $file->artefacttype == 'profileicon'}{$WWWROOT}artefact/file/download.php?file={$file->id}&size=24x24{else}{theme_url filename=images/`$file->artefacttype`.png}{/if}{$file->time}">
{/if}
</td>
<td class="filename">
......
......@@ -559,3 +559,14 @@
#agreetoprivacy .panel {
border: 0;
}
.image-rotator {
height: 110px;
line-height: 75px;
.image-rotator-inner {
display: inline-block;
text-align: center;
width: 110px;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment