Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor / Upload file or overview from main form #6371

Merged
merged 2 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions schemas/iso19139/src/main/plugin/iso19139/layout/config-editor.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3172,17 +3172,15 @@
<view name="default" class="gn-indent-bluescale gn-label-above-input">-->
<view name="default">
<sidePanel>
<!-- General online source manager
<directive data-gn-onlinesrc-list=""/>
-->
<directive data-gn-validation-report=""/>

<!-- Simple overview manager + online source manger for other types
Limit the max number of overviews with data-number-of-overviews="3" attribute.
In the full view, editor can access and manage the file store and
thumbnail name and description not supported by the overview manager.
-->
<directive data-gn-validation-report=""/>
<directive data-gn-overview-manager=""/>

<directive data-gn-onlinesrc-list=""
data-types="onlinesrc|parent|dataset|service|source|sibling|associated|fcats"/>

Expand All @@ -3192,10 +3190,39 @@
data-lang="lang"/>

<directive data-gn-suggestion-list=""/>

<directive data-gn-need-help="user-guide/describing-information/creating-metadata.html"/>
</sidePanel>

<tab id="default" default="true" mode="flat">

<!--
Example for file upload in the main form
<section>
<field xpath="/gmd:MD_Metadata/gmd:identificationInfo//gmd:title"/>

* Manage uploaded file with a WWW:DOWNLOAD protocol
<directive data-gn-file-uploader=""
data-type="onlines"/>

* Same but with custom titles and icons
<directive data-gn-file-uploader=""
data-title="Resource for download"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this support translation keys?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could put text or a key that you can set in database translation.

data-btn-label="Drop a file here"
data-icon="fa-cloud"
data-type="onlines"/>

* Without the panel
<directive data-gn-file-uploader=""
data-title=""
data-type="onlines"/>

* With a custom protocol
<directive data-gn-file-uploader=""
data-protocol="DIRECTDOWNLOAD"
data-type="onlines"/>
</section>-->

<section xpath="/gmd:MD_Metadata/gmd:identificationInfo"/>
<section xpath="/gmd:MD_Metadata/gmd:referenceSystemInfo"/>
<section xpath="/gmd:MD_Metadata/gmd:spatialRepresentationInfo"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,136 @@
goog.require('gn_urlutils_service');
goog.require('gn_related_directive');


var fileUploader = [
'gnOnlinesrc', 'gnFileStoreService', 'gnCurrentEdit', '$rootScope', '$translate',
function(gnOnlinesrc, gnFileStoreService, gnCurrentEdit, $rootScope, $translate) {
return {
restrict: 'A',
templateUrl: '../../catalog/components/edit/onlinesrc/' +
'partials/file-uploader.html',
scope: {},
link: function (scope, element, attrs) {
scope.relations = {};
scope.uuid = undefined;
scope.lang = scope.$parent.lang;
scope.readonly = false;
scope.numberOfOverviews = parseInt(attrs['numberOfOverviews']) || Infinity;
scope.onlinesrcService = gnOnlinesrc;

scope.defaultType = 'thumbnails';
scope.type = attrs['type'] || scope.defaultType;
scope.title = attrs['title'] || (scope.isOverview ? 'overview' : 'download');
scope.panelMode = angular.isDefined(attrs['title'])
&& attrs['title'] === '' ? false : true;
scope.icon = attrs['icon'] || (scope.isOverview ? 'gn-icon-thumbnail' : 'fa-download');
scope.btnLabel = attrs['btnLabel'] || (scope.isOverview ? 'chooseImage': 'chooseFileToUpload');
scope.protocol = attrs['protocol'] || 'WWW:DOWNLOAD';
scope.isOverview = scope.type === scope.defaultType;
scope.removeBtnConfirm = scope.isOverview ? 'removeThumbnailConfirm' : 'removeOnlinesrcConfirm';
scope.removeBtnTitle = scope.isOverview ? 'removeThumbnail' : 'remove';

var loadRelations = function() {
gnOnlinesrc.getAllResources([scope.type])
.then(function(data) {
var res = gnOnlinesrc.formatResources(
data,
scope.lang,
gnCurrentEdit.mdLanguage);
scope.relations = scope.isOverview
? res.relations[scope.type]
: res.relations[scope.type].filter(function(l) {
return l.protocol === scope.protocol;
});
});
};

var uploadFile = function() {
scope.queue = [];
scope.filestoreUploadOptions = {
autoUpload: true,
url: '../api/records/' + gnCurrentEdit.uuid +
'/attachments?visibility=public',
dropZone: $('#gn-overview-dropzone'),
singleUpload: true,
// TODO: acceptFileTypes: /(\.|\/)(xml|skos|rdf)$/i,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something to improve: for thumbnails, only image formats should be allowed. For files, should be limited to certain types, maybe make both configurable in the settings?

Not in the scope of this pull request, but to create a ticket to track this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done: uploadResourceSuccess,
fail: uploadResourceFailed,
headers: {'X-XSRF-TOKEN': $rootScope.csrf}
};

};

var linkOverviewToRecord = function (link) {
var params = scope.isOverview ? {
thumbnail_url: link.url,
thumbnail_desc: link.name || '',
process: 'thumbnail-add',
id: gnCurrentEdit.id
} : {
url: link.url,
name: link.name || '',
protocol: scope.protocol,
process: 'onlinesrc-add',
id: gnCurrentEdit.id
};
gnOnlinesrc.add(params);
};

var uploadResourceSuccess = function(e, data) {
$rootScope.$broadcast('gnFileStoreUploadDone');
scope.clear(scope.queue);
linkOverviewToRecord(data.response().jqXHR.responseJSON);
};

scope.$on('gnFileStoreUploadDone', scope.loadRelations);

var uploadResourceFailed = function(e, data) {
$rootScope.$broadcast('StatusUpdated', {
title: $translate.instant('resourceUploadError'),
error: {
message: data.errorThrown +
angular.isDefined(
data.response().jqXHR.responseJSON.message) ?
data.response().jqXHR.responseJSON.message : ''
},
timeout: 0,
type: 'danger'});
scope.clear(scope.queue);
};

scope.removeFile = function(file) {
var url = file.url[gnCurrentEdit.mdLanguage];
if (url.match(".*/api/records/" + gnCurrentEdit.uuid + "/attachments/.*") == null) {
// An external URL
gnOnlinesrc[scope.isOverview ? 'removeThumbnail' : 'removeOnlinesrc'](file).then(function() {
loadRelations();
});
} else {
// A thumbnail from the filestore
gnFileStoreService.delete({url: url}).then(function () {
// then remove from record
gnOnlinesrc[scope.isOverview ? 'removeThumbnail' : 'removeOnlinesrc'](file).then(function() {
loadRelations();
});
});
}

};
function init(n, o) {
if (angular.isUndefined(scope.uuid) ||
n != o) {
scope.uuid = n;
loadRelations();
uploadFile();
}
}
scope.$watch('gnCurrentEdit.uuid', init);
scope.$watch('$parent.gnCurrentEdit.uuid', init);
}
}
}];

/**
* @ngdoc overview
* @name gn_onlinesrc
Expand Down Expand Up @@ -206,123 +336,18 @@
}
}])
/**
* Simple interface to add or remove overview.
* Simple interface to add or remove file/overview.
*
* This directive handle in one step the add to filestore
* action and the update metadata record steps. User
* can easily drag & drop thumbnails in here.
* can easily drag & drop file/overview in here.
*
* It does not provide the possibility to set
* overview name and description. See onlineSrcList directive
* name and description. See onlineSrcList directive
* or full editor mode.
*/
.directive('gnOverviewManager', [
'gnOnlinesrc', 'gnFileStoreService', 'gnCurrentEdit', '$rootScope', '$translate',
function(gnOnlinesrc, gnFileStoreService, gnCurrentEdit, $rootScope, $translate) {
return {
restrict: 'A',
templateUrl: '../../catalog/components/edit/onlinesrc/' +
'partials/overview-manager.html',
scope: {},
link: function (scope, element, attrs) {
scope.relations = {};
scope.uuid = undefined;
scope.lang = scope.$parent.lang;
scope.readonly = false;
scope.numberOfOverviews = parseInt(attrs['numberOfOverviews']) || Infinity;
scope.onlinesrcService = gnOnlinesrc;

// Load thumbnail list.
var loadRelations = function() {
gnOnlinesrc.getAllResources(['thumbnails'])
.then(function(data) {
var res = gnOnlinesrc.formatResources(
data,
scope.lang,
gnCurrentEdit.mdLanguage);
scope.relations = res.relations;
});
};

// Upload overview once dropped or selected
var uploadOverview = function() {
scope.queue = [];
scope.filestoreUploadOptions = {
autoUpload: true,
url: '../api/records/' + gnCurrentEdit.uuid +
'/attachments?visibility=public',
dropZone: $('#gn-overview-dropzone'),
singleUpload: true,
// TODO: acceptFileTypes: /(\.|\/)(xml|skos|rdf)$/i,
done: uploadResourceSuccess,
fail: uploadResourceFailed,
headers: {'X-XSRF-TOKEN': $rootScope.csrf}
};
};

var linkOverviewToRecord = function (link) {
var params = {
thumbnail_url: link.url,
thumbnail_desc: link.name || '',
process: 'thumbnail-add',
id: gnCurrentEdit.id
};
gnOnlinesrc.add(params);
};

var uploadResourceSuccess = function(e, data) {
$rootScope.$broadcast('gnFileStoreUploadDone');
scope.clear(scope.queue);
linkOverviewToRecord(data.response().jqXHR.responseJSON);
};

scope.$on('gnFileStoreUploadDone', scope.loadRelations);

var uploadResourceFailed = function(e, data) {
$rootScope.$broadcast('StatusUpdated', {
title: $translate.instant('resourceUploadError'),
error: {
message: data.errorThrown +
angular.isDefined(
data.response().jqXHR.responseJSON.message) ?
data.response().jqXHR.responseJSON.message : ''
},
timeout: 0,
type: 'danger'});
scope.clear(scope.queue);
};

scope.removeOverview = function(thumbnail) {
var url = thumbnail.url[gnCurrentEdit.mdLanguage];
if (url.match(".*/api/records/" + gnCurrentEdit.uuid + "/attachments/.*") == null) {
// An external URL
gnOnlinesrc.removeThumbnail(thumbnail).then(function() {
// and update list.
loadRelations();
});
} else {
// A thumbnail from the filestore
gnFileStoreService.delete({url: url}).then(function () {
// then remove from record
gnOnlinesrc.removeThumbnail(thumbnail).then(function() {
// and update list.
loadRelations();
})
});
}

};
scope.$watch('gnCurrentEdit.uuid', function(n, o) {
if (angular.isUndefined(scope.uuid) ||
n != o) {
scope.uuid = n;
loadRelations();
uploadOverview();
}
});
}
}
}])
.directive('gnFileUploader', fileUploader)
.directive('gnOverviewManager', fileUploader)

/**
* @ngdoc directive
Expand Down Expand Up @@ -369,7 +394,7 @@
scope.lang = scope.$parent.lang;
scope.readonly = attrs['readonly'] || false;
scope.gnCurrentEdit.associatedPanelConfigId = attrs['configId'] || 'default';
scope.relations = {};
scope.relations = [];
scope.gnCurrentEdit.codelistFilter = attrs['codelistFilter'];

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<div data-ng-class="{'panel panel-default': panelMode}"
class="gn-file-uploader">
<div data-ng-if="panelMode" class="panel-heading" data-gn-slide-toggle>
<i class="fa fa-fw {{icon}}"></i>
<span data-translate="">{{title}}</span>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The overview panel with the change displays the header Download instead of Overview

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

</div>
<div data-ng-class="{'panel-body': panelMode}">
<ul class="list-inline">
<li class="gn-list-thumb thumbnail"
data-ng-repeat="f in relations">
<img data-ng-if="isOverview"
class="thumb-small"
title="{{f.title | gnLocalized: lang}}"
data-ng-src="{{onlinesrcService.getApprovedUrl(f.lUrl || f.id)}}"/>

<span data-ng-if="!isOverview">
<i class="fa fa-fw fa-2x fa-download"></i>
<strong>{{f.lUrl.split('/').pop()}}</strong>
</span>

<a href="" class="onlinesrc-remove"
data-ng-if="readonly !== true"
data-gn-confirm-click="{{removeBtnConfirm | translate:{url: f.lUrl} }}"
data-gn-click-and-spin="removeFile(f)"
title="{{removeBtnTitle | translate}}">
<i class="btn fa fa-times text-danger"></i>
</a>
</li>

<!-- The one currently uploaded -->
<li data-ng-repeat="file in queue"
class="gn-list-thumb thumbnail">
<i class="fa gn-icon-thumbnail fa-5x"></i>
{{file.name}}
</li>
</ul>

<div class="form-horizontal"
data-file-upload="filestoreUploadOptions">

<!-- The upload zone -->
<span class="btn btn-primary btn-block fileinput-button"
data-ng-class="{disabled: disabled}"
data-ng-hide="relations.thumbnails.length >= numberOfOverviews">
<i class="fa fa-fw fa-plus-circle"
data-ng-class="{hidden: active()}"/>
<i class="fa fa-fw fa-spinner fa-spin"
data-ng-class="{hidden: !active()}"
data-file-upload-progress="progress()"
data-file-upload-done="loadRelations()"/>
<span>{{btnLabel | translate}}</span>
<input type="file"
name="file"
data-ng-disabled="disabled"/>
</span>
</div>
</div>
</div>
Loading