pip-webui
Version:
HTML5 UI for LOB applications
466 lines (391 loc) • 17.5 kB
JavaScript
/**
* @file Picture list edit control
* @copyright Digital Living Software Corp. 2014-2015
* @todo
* - Improve samples in sampler app
* - Add animations to add/remove pictures
* - ?? Replace placeholder with default image generated on server?
*/
/* global angular */
(function () {
'use strict';
var thisModule = angular.module("pipPictureListEdit",
['ui.event', 'angularFileUpload', 'pipCore', 'pipFocused', 'pipRest', 'pipPicturePaste']);
thisModule.config(function(pipTranslateProvider) {
pipTranslateProvider.translations('en', {
'PICTURE_LIST_EDIT_TEXT': 'Click here to add a picture',
'ERROR_TRANSACTION_IN_PROGRESS': 'Transaction is in progress. Please, wait until it is finished or abort',
'ERROR_IMAGE_PRELOADING': 'Image loading error. The picture can not be saved'
});
pipTranslateProvider.translations('ru', {
'PICTURE_LIST_EDIT_TEXT': 'Нажмите сюда чтобы добавить картинку',
'ERROR_TRANSACTION_IN_PROGRESS': 'Транзакция еще не завершена. Подождите окончания или прервите её',
'ERROR_IMAGE_PRELOADING': 'Ошибка при загрузки картинки. Картинка не сохранена.'
});
});
thisModule.directive('pipPictureListEdit',
function() {
return {
restrict: 'EA',
scope: {
pipPictureIds: '=',
pipAddedPicture: '=',
ngDisabled: '&',
pipCreated: '&',
pipChanged: '&'
},
templateUrl: 'picture_list_edit/picture_list_edit.html',
controller: 'pipPictureListEditController'
};
}
);
thisModule.controller('pipPictureListEditController',
function($scope, $rootScope, $element, $attrs, $parse, $http, $upload, $timeout, pipUtils,
pipRest, pipPicturePaste, pipImageUtils) {
var
$control = $element.children('.pip-picture-drop'),
itemPin = 0;
$scope.text = $attrs.pipDefaultText || 'PICTURE_LIST_EDIT_TEXT';
$scope.icon = $attrs.pipDefaultIcon || 'picture-no-border';
$scope.pipRebind = pipUtils.toBoolean($attrs.pipRebind);
$scope.pictureStartState = pipUtils.toBoolean($scope.pipAddedPicture) ? 'copied' : 'original';
$scope.control = {
uploading: 0,
items: []
};
$scope.control.reset = reset;
$scope.control.save = save;
$scope.control.abort = abort;
$scope.filterItem = function(item) {
return item.state != 'deleted';
};
$scope.readItemLocally = readItemLocally;
$scope.onSelectClick = onSelectClick;
$scope.onDeleteClick = onDeleteClick;
$scope.onKeyDown = onKeyDown;
$scope.onImageError = onImageError;
$scope.onImageLoad = onImageLoad;
$scope.onChange = onChange;
$scope.onBlur = onBlur;
$scope.onFocus = onFocus;
// Watch for changes
if ($scope.pipRebind) {
$scope.$watch(
function () {
// Todo: Optimize change tracking
return $scope.pipPictureIds;
},
function (newValue) {
$scope.control.reset();
}
);
}
// // Add paste listeners
// $element.find('.pip-picture-upload').focus(function () {
// pipPicturePaste.addPasteListener(function (item) {
// $scope.readItemLocally(item.url, item.file);
// });
// });
// $element.find('.pip-picture-upload').blur(function () {
// pipPicturePaste.removePasteListener();
// });
// Add class
$element.addClass('pip-picture-list-edit');
// Initialize control
$scope.control.reset();
// Execute callback
if ($scope.pipCreated) {
$scope.pipCreated({
$event: { sender: $scope.control },
$control: $scope.control
});
}
return;
function contentUrl(id) {
var
serverUrl = pipRest.serverUrl(),
partyId = $scope.$party ? $scope.$party.id : pipRest.userId();
return serverUrl + '/api/parties/' + partyId + '/files/' + id + '/content';
}
function onImageError($event, item) {
item.error = true;
};
function onFocus(a) {
pipPicturePaste.addPasteListener(function (item) {
$scope.readItemLocally(item.url, item.file);
});
};
function onBlur () {
pipPicturePaste.removePasteListener();
};
function getItems() {
var
pictureIds = $scope.pipPictureIds,
items = [];
if (pictureIds == null || pictureIds.length == 0)
return items;
for (var i = 0; i < pictureIds.length; i++) {
items.push({
pin: itemPin++,
id: pictureIds[i],
uploading: false,
uploaded: false,
progress: 0,
file: null,
url: contentUrl(pictureIds[i]),
state: $scope.pictureStartState //'original'
});
}
return items;
}
function setItems() {
// Clean the array
if ($scope.pipPictureIds && $scope.pipPictureIds.length > 0)
$scope.pipPictureIds.splice(0, $scope.pipPictureIds.length);
for (var i = 0; i < $scope.control.items.length; i++) {
var item = $scope.control.items[i];
if (item.id)
$scope.pipPictureIds.push(item.id);
}
}
function reset() {
$scope.control.uploading = 0;
$scope.control.items = getItems();
}
function addItemUrl(item) {
var name = item.url.slice(item.url.lastIndexOf('/') + 1, item.url.length).split('?')[0];
var
serverUrl = pipRest.serverUrl(),
partyId = $scope.$party ? $scope.$party.id : pipRest.userId();
return serverUrl + '/api/parties/' + partyId + '/files?name=' + name + '&url=' + item.url
}
function addItemUrlWithFile(item) {
var
serverUrl = pipRest.serverUrl(),
partyId = $scope.$party ? $scope.$party.id : pipRest.userId();
return serverUrl + '/api/parties/' + partyId + '/files?name=' + item.file.name
}
function addItem(item, callback) {
if (item.file !== null) {
var file = item.file;
var fileReader = new FileReader();
fileReader.onload = function (e) {
if (item.uploading) return;
item.uploading = true;
item.upload = $upload.http({
url: addItemUrlWithFile(item),
headers: {'Content-Type': file.type},
data: e.target.result
})
.then(
function (response) {
item.id = response.data ? response.data.id : null;
item.uploaded = true;
item.uploading = false;
item.progress = 0;
item.upload = null;
item.file = null;
item.url = contentUrl(item.id);
item.state = 'original';
callback();
},
function (error) {
item.uploaded = false;
item.uploading = false;
item.progress = 0;
item.upload = null;
//$scope.$apply();
//
callback(error);
},
function (e) {
// Math.min is to fix IE which reports 200% sometimes
item.progress = Math.min(100, parseInt(100.0 * e.loaded / e.total));
}
);
};
fileReader.readAsArrayBuffer(file);
} else {
var url = addItemUrl(item);
item.uploading = true;
$http['post'](url)
.success(function (response) {
item.id = response.data ? response.data.id : response.id || null;
item.uploaded = true;
item.uploading = false;
item.progress = 0;
item.upload = null;
item.file = null;
item.url = contentUrl(item.id);
item.state = 'original';
callback();
})
.error(function (error) {
item.uploaded = false;
item.uploading = false;
item.progress = 0;
item.upload = null;
callback();
});
}
}
function deleteItemUrl(item) {
var
serverUrl = pipRest.serverUrl(),
partyId = $scope.$party ? $scope.$party.id : pipRest.userId();
return serverUrl + '/api/parties/' + partyId + '/files/' + item.id;
}
function deleteItem(item, callback) {
var control = $scope.control;
// Avoid double transactions
if (item.upload) {
item.upload.abort();
item.upload = null;
}
if (item.state != 'deleted')
return;
//pipImageUtils.addHttpHeaders();
$http['delete'](deleteItemUrl(item))
.success(function (data) {
_.remove(control.items, {pin: item.pin});
callback();
})
.error(function (data, status) {
// Todo: perform a better processing
if (data == null) {
_.remove(control.items, {pin: item.pin});
} else {
item.uploaded = false;
item.uploading = false;
item.progress = 0;
item.upload = null;
}
callback(data);
});
}
function save(successCallback, errorCallback) {
var control = $scope.control;
if (control.uploading) {
if (errorCallback) errorCallback('ERROR_TRANSACTION_IN_PROGRESS');
return;
}
control.error = null;
control.uploading = 0;
var onItemCallback = function(error) {
// Storing only the first error
if (error && !control.error) {
control.error = error;
}
control.uploading--;
// Finished uploading
if (control.uploading == 0) {
if (control.error) {
if (errorCallback) errorCallback(control.error);
else console.error(control.error);
} else {
setItems();
if (successCallback) successCallback();
}
}
};
for (var i = 0; i < control.items.length; i++) {
var item = control.items[i];
if (item.state == 'added' && !item.error) {
control.uploading++;
addItem(item, onItemCallback);
} else if (item.state == 'deleted') {
control.uploading++;
deleteItem(item, onItemCallback);
}
}
// Nothing was uploaded
if (control.uploading == 0) {
if (successCallback) successCallback();
}
}
function abort() {
var control = $scope.control;
for (var i = 0; i < control.items.length; i++) {
var item = control.items[i];
if (item.uploading) {
if (item.upload) item.upload.abort();
item.uploaded = false;
item.uploading = false;
item.progress = 0;
item.upload = null;
}
}
// Abort transaction
control.uploading = 0;
}
function readItemLocally(url, file) {
$scope.control.items.push({
pin: itemPin++,
id: null,
uploading: false,
uploaded: false,
progress: 0,
file: file,
url: url,
state: 'added'
});
$scope.onChange();
}
function onSelectClick($files) {
$control.focus();
if ($files == null || $files.length == 0)
return;
for (var i = 0; i < $files.length; i++) {
var file = $files[i];
if (file.type.indexOf('image') > -1) {
readItemLocally(file);
}
}
}
function onDeleteClick(item) {
if (item.state == 'added' || item.state == 'copied') {
_.remove($scope.control.items, {pin: item.pin});
} else {
item.state = 'deleted';
}
$scope.onChange();
}
function onKeyDown($event, item) {
if (item) {
if ($event.keyCode == 46 || $event.keyCode == 8) {
if (item.state == 'added') {
_.remove($scope.control.items, {pin: item.pin});
} else {
item.state = 'deleted';
}
$scope.onChange();
}
} else {
if ($event.keyCode == 13 || $event.keyCode == 32) {
// !! Avoid clash with $apply()
setTimeout(function() {
$control.trigger('click');
}, 0);
}
}
}
function onImageLoad($event, item) {
item.error = false;
setTimeout(function () {
var image = $($event.target);
pipImageUtils.setImageMarginCSS({clientWidth: 80, clientHeight: 80}, image);
}, 250);
item.loaded = true;
}
// On change event
function onChange() {
if ($scope.pipChanged) {
$scope.pipChanged({
$event: { sender: $scope.control },
$control: $scope.control
});
}
}
}
);
})();