1. 使用示例:
<avic-file file-src="{{testFileUrl}}" file-type="file"complete-callback="down">
<div style="text-align:center;background:#eee;margin:5px;padding:25px">点击缓存附件</div>
</avic-file>
2. 参数说明:
① file-src:文件网络地址,缓存后下次无需重新下载,网址即为本地缓存文件名,
a. 浏览器缓存路径为:filesystem:http://{{address:port}}/temporary/avicit_portal/cache/;
b. Android缓存路径为:context.getFilesDir().toString() + "/files/avicit_portal/cache/”(可自行设置AVIC_CACHE_PATH);
② file-type:强制文件类型,该值优先级大于后缀类型。
a. 当传入’file’或不传时,无论网络地址是否为图片都认定为文件附件,用户第一次点击时开始缓存,第二次点击则用file-openner打开;
b. 当传入’image’时,强制认定为图片格式并自动加载,适用于无后缀名的网络图片地址,如 http://dwz.cn/6Jxqci;
③ complete-callback:文件缓存展示完毕回调,此处应传入函数类型(不加括号)。
3. 样式说明:
① 附件样式:可自定义附件样式放于指令标签内,该内容会继续保留(ng-transclude)。
② 下载状态:指令添加单独的标签用于显示下载进度条及下载状态,无需设置。
③ 图片高宽:样式直接设置在avic-file标签上即可,如<avic-file class=”myClass”></avic-file>。
4. 流程图
5. 源码
angular.module('avicfile.directives', [])
.directive('avicFile', function ($cordovaFile, $ionicPlatform, $cordovaFileTransfer, $timeout) {
// const AVIC_CACHE_PATH = cordova.file.externalRootDirectory + 'Download/';
// const AVIC_CACHE_PATH = 'file:///storage/emulated/0/' + 'Download/';
const IMAGE = 'image';
const VIDEO = 'file';
const FILE = 'file';
/**
* 控制下载进度条
* @param element
* @param percentage 当100%时进度条消失
*/
function changeProgress(element, percentage) {
var template = '<div id="avic-file-cache-status" style="float: left;margin-left: 5%;margin-top: 5px;width: 90%; height: 5px; background-color: #ccc;">' +
'<span style="display: block; width: ' + percentage + '%; height: 5px; background-color: #007aff;"></span>' +
'</div>';
if (element.lastChild && element.lastChild.id == 'avic-file-cache-status') {
element.lastChild.outerHTML = template;
} else {
element.innerHTML += template;
}
}
function showTemplate(element, src, type, status) {
if (!fs.isCordova) {
src = rootPath + src;
}
var template;
if (!type) {
type = getFileType(fileName);
}
switch (type) {
case IMAGE:
template = '<img src="' + src + '" width="100%" ></img>';
element.innerHTML = template;
break;
case FILE:
// template = '<div><div style="text-align:center; background: #eee;margin: 5px;padding: 25px">打开' + getPointType(src) + '文件</div></div>';
case VIDEO:
// template = '<video src="' + src + '" width="100%" height="auto" controls="controls">您的浏览器不支持 video 标签。</video>';
default:
template = '<p style="position: absolute;right: 20px;bottom: 6px;color: ' + (status == '已下载' ? '#999' : '#387ef5') + ';" id="avic-file-cache-status">' + status + '</p >';
if (element.lastChild && element.lastChild.id == 'avic-file-cache-status') {
element.lastChild.outerHTML = template;
} else {
element.innerHTML += template;
}
}
}
/**
* 获取后缀名
* @param name
* @returns {*}
*/
function getPointType(name) {
if (!name) {
return 'nothing';
}
var arr = name.split('.');
var type = arr[arr.length - 1];
return type;
}
/**
* 通过后缀名获取文件类型
* @param name
* @returns IMAGE为图片
* @returns VIDEO为视频
* @returns FILE为文件
*/
function getFileType(name) {
var type = getPointType(name);
var res = 'unknown';
switch (type) {
case 'doc':
case 'docx':
case 'xls' :
case 'xlsx':
case 'txt':
case 'ppt':
case 'pptx':
case 'pdf':
res = FILE;
break;
case 'ogg':
;
case 'webm':
;
case 'mp4':
res = VIDEO;
break;
case 'jpg':
;
case 'jpeg':
;
case 'png':
;
case 'gif':
;
case 'bmp':
;
case 'webp':
default:
res = IMAGE;
}
return res;
}
/**
* 缓存文件
* @param url
* @param targetPath
*/
function downFile(url, targetPath, element, fileType, callback) {
var trustHosts = true;
var options = {};
console.log('url : ' + url);
console.log('targetPath : ' + targetPath);
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function (result) {
console.log(JSON.stringify(result));
$timeout(function () {
showTemplate(element, targetPath, fileType, '已下载');
if (typeof callback == 'function') {
callback();
}
}, 500)
}, function (err) {
console.log(JSON.stringify(err));
alert('附件缓存失败');
}, function (progress) {
$timeout(function () {
var percentage = (progress.loaded / progress.total) * 100;
console.log(percentage);
changeProgress(element, percentage);
});
});
// fs.download(url, targetPath, {retry: self._retry}, function (proces) {
// var percentage = proces.loaded / proces.total * 100;
// console.log(percentage + "% - loaded : " + proces.loaded + ": total : " + proces.total);
// changeProgress(element, percentage);
// }).then(function (done) {
// console.log(JSON.stringify(done));
// $timeout(function(){
// showTemplate(element, targetPath, fileType, '已下载');
// },500)
//
// }, function (err) {
// console.log(JSON.stringify(err));
// alert('附件缓存失败');
// });
}
/**
* 通过file-opener2插件打开文件
* @param path
*/
function openFile(path) {
var mime;
var type = getPointType(path);
switch (type) {
case 'html':
case 'htm':
mime = 'text/html';
break;
case 'jpeg':
case 'jpg':
case 'jpe':
mime = 'image/jpeg';
break;
case 'mp4':
case 'mp4v':
case 'mpg4':
mime = 'video/mp4';
break;
case 'png':
mime = 'image/png';
break;
case 'gif':
mime = 'image/gif';
break;
case 'bmp':
mime = 'image/bmp';
break;
case 'wbmp':
mime = 'image/vnd.wap.wbmp';
break;
case 'apk':
mime = 'application/vnd.android.package-archive';
break;
case 'json':
mime = 'application/json';
break;
case 'dot':
case 'doc':
mime = 'application/msword';
break;
case 'docx':
mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
break;
case 'xls' :
mime = 'application/vnd.ms-excel';
break;
case 'xlsx':
mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
break;
case 'txt':
case 'text':
case 'conf':
case 'def':
case 'list':
case 'log':
case 'in':
mime = 'text/plain';
break;
case 'ppt':
case 'pps':
case 'pot':
mime = 'application/vnd.ms-powerpoint';
break;
case 'pptx':
mime = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
break;
case 'pdf':
mime = 'application/pdf';
break;
default:
break;
}
cordova.plugins.fileOpener2.open(
path, // You can also use a Cordova-style file uri: cdvfile://localhost/persistent/Download/starwars.pdf
mime,
{
error: function (e) {
console.log('Error status: ' + e.status + ' - Error message: ' + e.message);
},
success: function () {
console.log('file opened successfully');
}
}
);
}
return {
restrict: 'E',
template: function (elem, attr) {
return '<div ng-click="downOrOpen()" ng-transclude=""></div>';
},
// scope: true, //使用独立scope,防止指令之间的相互干扰
scope: {
completeCallback: '='
},
replace: true,
transclude: true,
link: function ($scope, $element, $attrs, controller) {
var fileName = $attrs.fileSrc.replace(/\/|\\|:|\*|\||\?|%|'|"|<|>/g, '_');
$ionicPlatform.ready(function () {
if (fs.isCordova) {
AVIC_CACHE_PATH = cordova.file.externalRootDirectory + 'Download/';
$cordovaFile.checkFile(AVIC_CACHE_PATH, fileName)
.then(function (success) {
console.log(JSON.stringify(success));
console.log('link - fileEntry:showTemplate');
showTemplate($element[0], AVIC_CACHE_PATH + fileName, $attrs.fileType, '已下载');
if (typeof $scope.completeCallback == 'function') {
$scope.completeCallback();
}
}, function (error) {
console.log(JSON.stringify(error));
if ($attrs.fileType == 'image') {
console.log('link - download');
downFile($attrs.fileSrc, AVIC_CACHE_PATH + fileName, $element[0], $attrs.fileType, $scope.completeCallback);
} else {
console.log('link - fail:showTemplate');
showTemplate($element[0], AVIC_CACHE_PATH + fileName, $attrs.fileType, '未下载');
if (typeof $scope.completeCallback == 'function') {
$scope.completeCallback();
}
}
});
} else {
AVIC_CACHE_PATH = APPNAME + '/cache/'
fs.exists(AVIC_CACHE_PATH + fileName)
.then(function (success) {
console.log(JSON.stringify(success));
console.log('link - fileEntry:showTemplate');
showTemplate($element[0], AVIC_CACHE_PATH + fileName, $attrs.fileType, '已下载');
if (typeof $scope.completeCallback == 'function') {
$scope.completeCallback();
}
}, function (error) {
console.log(JSON.stringify(error));
if ($attrs.fileType == 'image') {
console.log('link - download');
downFile($attrs.fileSrc, AVIC_CACHE_PATH + fileName, $element[0], $attrs.fileType, $scope.completeCallback);
} else {
console.log('link - fail:showTemplate');
showTemplate($element[0], AVIC_CACHE_PATH + fileName, $attrs.fileType, '未下载');
if (typeof $scope.completeCallback == 'function') {
$scope.completeCallback();
}
}
});
}
});
$scope.downOrOpen = function () {
console.log('downOrOpen - fileType: ' + $attrs.fileType);
if ('file' == $attrs.fileType) {
console.log('downOrOpen - ' + AVIC_CACHE_PATH + fileName)
// $cordovaFile.checkFile(AVIC_CACHE_PATH, fileName)
if (fs.isCordova) {
$cordovaFile.checkFile(AVIC_CACHE_PATH, fileName)
.then(function (fileEntry) {
console.log('downOrOpen - openFile');
showTemplate($element[0], AVIC_CACHE_PATH + fileName, $attrs.fileType, '已下载');//防止多个指令同一源情况显示下载状态错误
openFile(AVIC_CACHE_PATH + fileName);
},
function (fail) {
console.log('downOrOpen - download');
downFile($attrs.fileSrc, AVIC_CACHE_PATH + fileName, $element[0], $attrs.fileType, $scope.completeCallback());
});
} else {
fs.exists(AVIC_CACHE_PATH + fileName)
.then(function (fileEntry) {
console.log('downOrOpen - openFile');
showTemplate($element[0], AVIC_CACHE_PATH + fileName, $attrs.fileType, '已下载');
},
function (fail) {
console.log('downOrOpen - download');
downFile($attrs.fileSrc, AVIC_CACHE_PATH + fileName, $element[0], $attrs.fileType, $scope.completeCallback());
});
}
}
}
}
}
});