mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-05-06 23:57:20 +02:00
Initial Commit
This commit is contained in:
163
static/filemanager_app/src/css/animations.css
Normal file
163
static/filemanager_app/src/css/animations.css
Normal file
@@ -0,0 +1,163 @@
|
||||
@-webkit-keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
};
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
};
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeInDown {
|
||||
0% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, -100%, 0);
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
};
|
||||
}
|
||||
|
||||
@keyframes fadeInDown {
|
||||
0% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, -100%, 0);
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
};
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
};
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotate {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
};
|
||||
}
|
||||
|
||||
@keyframes colors {
|
||||
0% {
|
||||
stroke: #4285F4;
|
||||
}
|
||||
|
||||
25% {
|
||||
stroke: #DE3E35;
|
||||
}
|
||||
|
||||
50% {
|
||||
stroke: #F7C223;
|
||||
}
|
||||
|
||||
75% {
|
||||
stroke: #1B9A59;
|
||||
}
|
||||
|
||||
100% {
|
||||
stroke: #4285F4;
|
||||
};
|
||||
}
|
||||
|
||||
@keyframes dash {
|
||||
0% {
|
||||
stroke-dasharray: 1,150;
|
||||
stroke-dashoffset: 0;
|
||||
stroke: red;
|
||||
}
|
||||
|
||||
50% {
|
||||
stroke-dasharray: 90,150;
|
||||
stroke-dashoffset: -35;
|
||||
stroke: yellow;
|
||||
}
|
||||
|
||||
100% {
|
||||
stroke-dasharray: 90,150;
|
||||
stroke-dashoffset: -124;
|
||||
stroke: green;
|
||||
};
|
||||
}
|
||||
|
||||
@-webkit-keyframes dash {
|
||||
0% {
|
||||
stroke-dasharray: 1,150;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
stroke-dasharray: 90,150;
|
||||
stroke-dashoffset: -35;
|
||||
}
|
||||
|
||||
100% {
|
||||
stroke-dasharray: 90,150;
|
||||
stroke-dashoffset: -124;
|
||||
};
|
||||
}
|
||||
|
||||
.animated {
|
||||
-webkit-animation-duration: .7s;
|
||||
animation-duration: .7s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.modal.animated,
|
||||
.animated.fast {
|
||||
-webkit-animation-duration: .2s;
|
||||
animation-duration: .2s;
|
||||
}
|
||||
|
||||
.animated.slow {
|
||||
-webkit-animation-duration: 1.1s;
|
||||
animation-duration: 1.1s;
|
||||
}
|
||||
|
||||
.animated.fadeInDown {
|
||||
-webkit-animation-name: fadeInDown;
|
||||
animation-name: fadeInDown;
|
||||
}
|
||||
|
||||
.animated.fadeIn {
|
||||
-webkit-animation-name: fadeIn;
|
||||
animation-name: fadeIn;
|
||||
}
|
||||
|
||||
.spinner-container {
|
||||
-webkit-animation: rotate 2s linear infinite;
|
||||
animation: rotate 2s linear infinite;
|
||||
z-index: 2;
|
||||
width: 65px;
|
||||
height: 65px;
|
||||
}
|
||||
|
||||
.spinner-container .path {
|
||||
stroke-dasharray: 1,150;
|
||||
stroke-dashoffset: 0;
|
||||
stroke: #2196F3;
|
||||
stroke-linecap: round;
|
||||
-webkit-animation: dash 1.5s ease-in-out infinite, colors 5.6s ease-in-out infinite;
|
||||
animation: dash 1.5s ease-in-out infinite, colors 5.6s ease-in-out infinite;
|
||||
}
|
||||
96
static/filemanager_app/src/css/dialogs.css
Normal file
96
static/filemanager_app/src/css/dialogs.css
Normal file
@@ -0,0 +1,96 @@
|
||||
.modal {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.modal .label.error-msg {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
padding: 0;
|
||||
padding: 5px;
|
||||
margin-top: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.modal .label.error-msg > span {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.modal .breadcrumb {
|
||||
margin: 0;
|
||||
background: #00bcd4;
|
||||
font-size: 16px;
|
||||
max-height: inherit;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.modal-fullscreen .modal-dialog,
|
||||
.modal-fullscreen .modal-content {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.modal-fullscreen .modal-dialog {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modal-fullscreen .modal-content {
|
||||
border: none;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
-webkit-box-shadow: inherit;
|
||||
-moz-box-shadow: inherit;
|
||||
-o-box-shadow: inherit;
|
||||
box-shadow: inherit;
|
||||
}
|
||||
|
||||
.modal-fullscreen textarea.code {
|
||||
min-height: 450px;
|
||||
}
|
||||
|
||||
.modal img.preview {
|
||||
max-width: 100%;
|
||||
max-height: 640px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.modal img.preview.loading {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
.modal .modal-content {
|
||||
border-radius: 10px 10px 4px 4px;
|
||||
}
|
||||
|
||||
.modal .modal-header {
|
||||
border-radius: 4px 4px 0 0;
|
||||
background: #2196F3;
|
||||
padding: 1.3em;
|
||||
}
|
||||
|
||||
.modal .modal-header .modal-title {
|
||||
font-size: 20px;
|
||||
line-height: 100%;
|
||||
color: #D4E5F5;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal .modal-header .close {
|
||||
opacity: 1;
|
||||
color: #D4E5F5;
|
||||
}
|
||||
|
||||
.modal .modal-header .close.fullscreen {
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
margin-right: .8em;
|
||||
}
|
||||
446
static/filemanager_app/src/css/main.css
Normal file
446
static/filemanager_app/src/css/main.css
Normal file
@@ -0,0 +1,446 @@
|
||||
body {
|
||||
font-size: 14px;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
*,
|
||||
*:focus {
|
||||
outline: 0!important;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
min-height: 32px;
|
||||
margin-bottom: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.navbar .navbar-collapse {
|
||||
overflow: visible;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.navbar .navbar-toggle {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.navbar .navbar-brand {
|
||||
font-size: inherit;
|
||||
height: 55px;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.btn.btn-default {
|
||||
color: #444;
|
||||
background-color: #FAFAFA;
|
||||
}
|
||||
|
||||
.btn {
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .26);
|
||||
font-weight: 500;
|
||||
letter-spacing: .01em;
|
||||
border: none;
|
||||
}
|
||||
|
||||
textarea.code {
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
font-size: 13px;
|
||||
min-height: 250px;
|
||||
resize: vertical;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.sub-header {
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: none;
|
||||
background: #fafafa;
|
||||
margin-top: 2px;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
|
||||
.btn-go-back {
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.nav-sidebar {
|
||||
margin-right: -21px;
|
||||
margin-bottom: 20px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
|
||||
.nav-sidebar > li > a {
|
||||
color: #7a7a7a;
|
||||
padding: 7px 0 7px 16px;
|
||||
}
|
||||
|
||||
|
||||
.nav-sidebar> li > a:hover,
|
||||
.nav-sidebar> li > a:focus {
|
||||
background: none;
|
||||
color: #1378b9;
|
||||
}
|
||||
|
||||
.nav-sidebar > li.active > a {
|
||||
color: #2196F3;
|
||||
}
|
||||
|
||||
|
||||
.main {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.main .page-header {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.file-tree ul.nav.nav-sidebar {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.file-tree ul.nav.nav-sidebar:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.file-tree ul.nav.nav-sidebar.file-tree-root > li {
|
||||
border-left: none;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.table td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#context-menu {
|
||||
position: absolute;
|
||||
display: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.iconset {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.col-120 {
|
||||
width: 100px;
|
||||
max-height: 100px;
|
||||
float: left;
|
||||
margin-bottom: 9px;
|
||||
margin-right: 9px;
|
||||
}
|
||||
|
||||
.col-120:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.noselect {
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-khtml-user-select: none; /* Konqueror */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE/Edge */
|
||||
user-select: none; /* non-prefixed version, currently */
|
||||
}
|
||||
|
||||
.iconset .thumbnail {
|
||||
border-radius: 0;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding: 10px 0;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.table-files .selected,
|
||||
.iconset .thumbnail.selected {
|
||||
background: #2196F3;
|
||||
}
|
||||
|
||||
.iconset .thumbnail.selected,
|
||||
.table-files .selected td,
|
||||
.table-files .selected td a {
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.iconset .thumbnail .item-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.detail-sources {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1), inset -1px -1px 0 rgba(0, 0, 0, .07);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
min-height: 0.8em;
|
||||
min-width: 0.8em;
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1), inset -1px -1px 0 rgba(0, 0, 0, .07);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #bbb;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
background-color: #888;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a {
|
||||
padding: 6px 20px;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a > i {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.dropdown-menu.dropdown-right-click {
|
||||
display: block;
|
||||
position: static;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.dropdown-menu.dropdown-right-click .divider {
|
||||
margin: 3px 0;
|
||||
}
|
||||
|
||||
.upload-dragover .main {
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
.upload-dragover:before {
|
||||
content: "\e198";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 100;
|
||||
color: #2196F3;
|
||||
font-size: 8em;
|
||||
font-family: 'Glyphicons Halflings';
|
||||
}
|
||||
|
||||
.upload-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.spinner-wrapper {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
margin-top: 8%;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:active,
|
||||
a:focus,
|
||||
table th > a:hover,
|
||||
table th > a:active,
|
||||
table th > a:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sortorder:after {
|
||||
color: #2196f3;
|
||||
content: '\25bc';
|
||||
}
|
||||
|
||||
.sortorder.reverse:after {
|
||||
color: #2196f3;
|
||||
content: '\25b2';
|
||||
}
|
||||
|
||||
[ng\:cloak], [ng-cloak],
|
||||
[data-ng-cloak], [x-ng-cloak],
|
||||
.ng-cloak, .x-ng-cloak {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mr2 {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.mr5 {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.mt10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mb0 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.main {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.main {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
/* The view should fill all available vertical space */
|
||||
angular-filemanager > div,.row,.main,.sidebar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
height: -webkit-calc(100% - 58px);
|
||||
height: -moz-calc(100% - 58px);
|
||||
height: calc(100% - 58px);
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.selected-file-details {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.item-extension::after {
|
||||
font-family: "Roboto","Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||
content: attr(data-ext);
|
||||
left: 4px;
|
||||
position: absolute;
|
||||
color: #fff;
|
||||
font-size: 9px;
|
||||
text-transform: uppercase;
|
||||
top: 21px;
|
||||
}
|
||||
|
||||
.selected .item-extension::after {
|
||||
color: #2196F3;
|
||||
}
|
||||
|
||||
.form-control.search-input {
|
||||
max-width: 20em;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.like-code {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.point {
|
||||
margin-right: 8px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.navbar .btn.btn-flat {
|
||||
padding: 2px;
|
||||
width: 32px;
|
||||
height: 30px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-toggle .icon-bar {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-form input[type="text"] {
|
||||
color: #7a7a7a;
|
||||
box-shadow: none;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.navbar .navbar-form {
|
||||
border-bottom: none;
|
||||
border-top: none;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
font-size: 17px;
|
||||
margin: 12px 0;
|
||||
overflow: hidden;
|
||||
max-height: 30px
|
||||
}
|
||||
|
||||
.breadcrumb>.active,
|
||||
.breadcrumb a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.breadcrumb>li+li:before {
|
||||
font-family: 'Glyphicons Halflings';
|
||||
content: "\e080";
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.scrollable-menu {
|
||||
height: auto;
|
||||
max-height: 200px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.btn.btn-flat {
|
||||
background: none;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-group.open > .btn-flat,
|
||||
.btn.btn-flat,
|
||||
.btn.btn-flat:active {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.btn.btn-flat > i {
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
line-height: 100%;
|
||||
}
|
||||
58
static/filemanager_app/src/js/app.js
Normal file
58
static/filemanager_app/src/js/app.js
Normal file
@@ -0,0 +1,58 @@
|
||||
(function(window, angular, $) {
|
||||
'use strict';
|
||||
angular.module('FileManagerApp', ['pascalprecht.translate', 'ngFileUpload']);
|
||||
|
||||
/**
|
||||
* jQuery inits
|
||||
*/
|
||||
$(window.document).on('shown.bs.modal', '.modal', function() {
|
||||
window.setTimeout(function() {
|
||||
$('[autofocus]', this).focus();
|
||||
}.bind(this), 100);
|
||||
});
|
||||
|
||||
$(window.document).on('click', function() {
|
||||
$('#context-menu').hide();
|
||||
});
|
||||
|
||||
$(window.document).on('contextmenu', '.main-navigation .table-files tr.item-list:has("td"), .item-list', function(e) {
|
||||
var menu = $('#context-menu');
|
||||
|
||||
if (e.pageX >= window.innerWidth - menu.width()) {
|
||||
e.pageX -= menu.width();
|
||||
}
|
||||
if (e.pageY >= window.innerHeight - menu.height()) {
|
||||
e.pageY -= menu.height();
|
||||
}
|
||||
|
||||
menu.hide().css({
|
||||
left: e.pageX,
|
||||
top: e.pageY
|
||||
}).appendTo('body').show();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
if (! Array.prototype.find) {
|
||||
Array.prototype.find = function(predicate) {
|
||||
if (this == null) {
|
||||
throw new TypeError('Array.prototype.find called on null or undefined');
|
||||
}
|
||||
if (typeof predicate !== 'function') {
|
||||
throw new TypeError('predicate must be a function');
|
||||
}
|
||||
var list = Object(this);
|
||||
var length = list.length >>> 0;
|
||||
var thisArg = arguments[1];
|
||||
var value;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
value = list[i];
|
||||
if (predicate.call(thisArg, value, i, list)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
|
||||
})(window, angular, jQuery);
|
||||
361
static/filemanager_app/src/js/controllers/main.js
Normal file
361
static/filemanager_app/src/js/controllers/main.js
Normal file
@@ -0,0 +1,361 @@
|
||||
(function(angular, $) {
|
||||
'use strict';
|
||||
angular.module('FileManagerApp').controller('FileManagerCtrl', [
|
||||
'$scope', '$rootScope', '$window', '$translate', 'fileManagerConfig', 'item', 'fileNavigator', 'apiMiddleware',
|
||||
function($scope, $rootScope, $window, $translate, fileManagerConfig, Item, FileNavigator, ApiMiddleware) {
|
||||
|
||||
var $storage = $window.localStorage;
|
||||
$scope.config = fileManagerConfig;
|
||||
$scope.reverse = false;
|
||||
$scope.predicate = ['model.type', 'model.name'];
|
||||
$scope.order = function(predicate) {
|
||||
$scope.reverse = ($scope.predicate[1] === predicate) ? !$scope.reverse : false;
|
||||
$scope.predicate[1] = predicate;
|
||||
};
|
||||
$scope.query = '';
|
||||
$scope.fileNavigator = new FileNavigator();
|
||||
$scope.apiMiddleware = new ApiMiddleware();
|
||||
$scope.uploadFileList = [];
|
||||
$scope.viewTemplate = $storage.getItem('viewTemplate') || 'main-icons.html';
|
||||
$scope.fileList = [];
|
||||
$scope.temps = [];
|
||||
|
||||
$scope.$watch('temps', function() {
|
||||
if ($scope.singleSelection()) {
|
||||
$scope.temp = $scope.singleSelection();
|
||||
} else {
|
||||
$scope.temp = new Item({rights: 644});
|
||||
$scope.temp.multiple = true;
|
||||
}
|
||||
$scope.temp.revert();
|
||||
});
|
||||
|
||||
$scope.fileNavigator.onRefresh = function() {
|
||||
$scope.temps = [];
|
||||
$scope.query = '';
|
||||
$rootScope.selectedModalPath = $scope.fileNavigator.currentPath;
|
||||
};
|
||||
|
||||
$scope.setTemplate = function(name) {
|
||||
$storage.setItem('viewTemplate', name);
|
||||
$scope.viewTemplate = name;
|
||||
};
|
||||
|
||||
$scope.changeLanguage = function (locale) {
|
||||
if (locale) {
|
||||
$storage.setItem('language', locale);
|
||||
return $translate.use(locale);
|
||||
}
|
||||
$translate.use($storage.getItem('language') || fileManagerConfig.defaultLang);
|
||||
};
|
||||
|
||||
$scope.isSelected = function(item) {
|
||||
return $scope.temps.indexOf(item) !== -1;
|
||||
};
|
||||
|
||||
$scope.selectOrUnselect = function(item, $event) {
|
||||
var indexInTemp = $scope.temps.indexOf(item);
|
||||
var isRightClick = $event && $event.which == 3;
|
||||
|
||||
if ($event && $event.target.hasAttribute('prevent')) {
|
||||
$scope.temps = [];
|
||||
return;
|
||||
}
|
||||
if (! item || (isRightClick && $scope.isSelected(item))) {
|
||||
return;
|
||||
}
|
||||
if ($event && $event.shiftKey && !isRightClick) {
|
||||
var list = $scope.fileList;
|
||||
var indexInList = list.indexOf(item);
|
||||
var lastSelected = $scope.temps[0];
|
||||
var i = list.indexOf(lastSelected);
|
||||
var current = undefined;
|
||||
if (lastSelected && list.indexOf(lastSelected) < indexInList) {
|
||||
$scope.temps = [];
|
||||
while (i <= indexInList) {
|
||||
current = list[i];
|
||||
!$scope.isSelected(current) && $scope.temps.push(current);
|
||||
i++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (lastSelected && list.indexOf(lastSelected) > indexInList) {
|
||||
$scope.temps = [];
|
||||
while (i >= indexInList) {
|
||||
current = list[i];
|
||||
!$scope.isSelected(current) && $scope.temps.push(current);
|
||||
i--;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ($event && !isRightClick && ($event.ctrlKey || $event.metaKey)) {
|
||||
$scope.isSelected(item) ? $scope.temps.splice(indexInTemp, 1) : $scope.temps.push(item);
|
||||
return;
|
||||
}
|
||||
$scope.temps = [item];
|
||||
};
|
||||
|
||||
$scope.singleSelection = function() {
|
||||
return $scope.temps.length === 1 && $scope.temps[0];
|
||||
};
|
||||
|
||||
$scope.totalSelecteds = function() {
|
||||
return {
|
||||
total: $scope.temps.length
|
||||
};
|
||||
};
|
||||
|
||||
$scope.selectionHas = function(type) {
|
||||
return $scope.temps.find(function(item) {
|
||||
return item && item.model.type === type;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.prepareNewFolder = function() {
|
||||
var item = new Item(null, $scope.fileNavigator.currentPath);
|
||||
$scope.temps = [item];
|
||||
return item;
|
||||
};
|
||||
|
||||
$scope.smartClick = function(item) {
|
||||
var pick = $scope.config.allowedActions.pickFiles;
|
||||
if (item.isFolder()) {
|
||||
return $scope.fileNavigator.folderClick(item);
|
||||
}
|
||||
|
||||
if (typeof $scope.config.pickCallback === 'function' && pick) {
|
||||
var callbackSuccess = $scope.config.pickCallback(item.model);
|
||||
if (callbackSuccess === true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.isImage()) {
|
||||
if ($scope.config.previewImagesInModal) {
|
||||
return $scope.openImagePreview(item);
|
||||
}
|
||||
return $scope.apiMiddleware.download(item, true);
|
||||
}
|
||||
|
||||
if (item.isEditable()) {
|
||||
return $scope.openEditItem(item);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.openImagePreview = function() {
|
||||
var item = $scope.singleSelection();
|
||||
$scope.apiMiddleware.apiHandler.inprocess = true;
|
||||
$scope.modal('imagepreview', null, true)
|
||||
.find('#imagepreview-target')
|
||||
.attr('src', $scope.apiMiddleware.getUrl(item))
|
||||
.unbind('load error')
|
||||
.on('load error', function() {
|
||||
$scope.apiMiddleware.apiHandler.inprocess = false;
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openEditItem = function() {
|
||||
var item = $scope.singleSelection();
|
||||
$scope.apiMiddleware.getContent(item).then(function(data) {
|
||||
item.tempModel.content = item.model.content = data.result;
|
||||
});
|
||||
$scope.modal('edit');
|
||||
};
|
||||
|
||||
$scope.modal = function(id, hide, returnElement) {
|
||||
var element = $('#' + id);
|
||||
element.modal(hide ? 'hide' : 'show');
|
||||
$scope.apiMiddleware.apiHandler.error = '';
|
||||
$scope.apiMiddleware.apiHandler.asyncSuccess = false;
|
||||
return returnElement ? element : true;
|
||||
};
|
||||
|
||||
$scope.modalWithPathSelector = function(id) {
|
||||
$rootScope.selectedModalPath = $scope.fileNavigator.currentPath;
|
||||
return $scope.modal(id);
|
||||
};
|
||||
|
||||
$scope.isInThisPath = function(path) {
|
||||
var currentPath = $scope.fileNavigator.currentPath.join('/') + '/';
|
||||
return currentPath.indexOf(path + '/') !== -1;
|
||||
};
|
||||
|
||||
$scope.edit = function() {
|
||||
$scope.apiMiddleware.edit($scope.singleSelection()).then(function() {
|
||||
$scope.modal('edit', true);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.changePermissions = function() {
|
||||
$scope.apiMiddleware.changePermissions($scope.temps, $scope.temp).then(function() {
|
||||
$scope.fileNavigator.refresh();
|
||||
$scope.modal('changepermissions', true);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.download = function() {
|
||||
var item = $scope.singleSelection();
|
||||
if ($scope.selectionHas('dir')) {
|
||||
return;
|
||||
}
|
||||
if (item) {
|
||||
return $scope.apiMiddleware.download(item);
|
||||
}
|
||||
return $scope.apiMiddleware.downloadMultiple($scope.temps);
|
||||
};
|
||||
|
||||
$scope.copy = function() {
|
||||
var item = $scope.singleSelection();
|
||||
if (item) {
|
||||
var name = item.tempModel.name.trim();
|
||||
var nameExists = $scope.fileNavigator.fileNameExists(name);
|
||||
if (nameExists && validateSamePath(item)) {
|
||||
$scope.apiMiddleware.apiHandler.error = $translate.instant('error_invalid_filename');
|
||||
return false;
|
||||
}
|
||||
if (!name) {
|
||||
$scope.apiMiddleware.apiHandler.error = $translate.instant('error_invalid_filename');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$scope.apiMiddleware.copy($scope.temps, $rootScope.selectedModalPath).then(function() {
|
||||
$scope.fileNavigator.refresh();
|
||||
$scope.modal('copy', true);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.compress = function() {
|
||||
var name = $scope.temp.tempModel.name.trim();
|
||||
var nameExists = $scope.fileNavigator.fileNameExists(name);
|
||||
|
||||
if (nameExists && validateSamePath($scope.temp)) {
|
||||
$scope.apiMiddleware.apiHandler.error = $translate.instant('error_invalid_filename');
|
||||
return false;
|
||||
}
|
||||
if (!name) {
|
||||
$scope.apiMiddleware.apiHandler.error = $translate.instant('error_invalid_filename');
|
||||
return false;
|
||||
}
|
||||
|
||||
$scope.apiMiddleware.compress($scope.temps, name, $rootScope.selectedModalPath).then(function() {
|
||||
$scope.fileNavigator.refresh();
|
||||
if (! $scope.config.compressAsync) {
|
||||
return $scope.modal('compress', true);
|
||||
}
|
||||
$scope.apiMiddleware.apiHandler.asyncSuccess = true;
|
||||
}, function() {
|
||||
$scope.apiMiddleware.apiHandler.asyncSuccess = false;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.extract = function() {
|
||||
var item = $scope.temp;
|
||||
var name = $scope.temp.tempModel.name.trim();
|
||||
var nameExists = $scope.fileNavigator.fileNameExists(name);
|
||||
|
||||
if (nameExists && validateSamePath($scope.temp)) {
|
||||
$scope.apiMiddleware.apiHandler.error = $translate.instant('error_invalid_filename');
|
||||
return false;
|
||||
}
|
||||
if (!name) {
|
||||
$scope.apiMiddleware.apiHandler.error = $translate.instant('error_invalid_filename');
|
||||
return false;
|
||||
}
|
||||
|
||||
$scope.apiMiddleware.extract(item, name, $rootScope.selectedModalPath).then(function() {
|
||||
$scope.fileNavigator.refresh();
|
||||
if (! $scope.config.extractAsync) {
|
||||
return $scope.modal('extract', true);
|
||||
}
|
||||
$scope.apiMiddleware.apiHandler.asyncSuccess = true;
|
||||
}, function() {
|
||||
$scope.apiMiddleware.apiHandler.asyncSuccess = false;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.remove = function() {
|
||||
$scope.apiMiddleware.remove($scope.temps).then(function() {
|
||||
$scope.fileNavigator.refresh();
|
||||
$scope.modal('remove', true);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.move = function() {
|
||||
var anyItem = $scope.singleSelection() || $scope.temps[0];
|
||||
if (anyItem && validateSamePath(anyItem)) {
|
||||
$scope.apiMiddleware.apiHandler.error = $translate.instant('error_cannot_move_same_path');
|
||||
return false;
|
||||
}
|
||||
$scope.apiMiddleware.move($scope.temps, $rootScope.selectedModalPath).then(function() {
|
||||
$scope.fileNavigator.refresh();
|
||||
$scope.modal('move', true);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.rename = function() {
|
||||
var item = $scope.singleSelection();
|
||||
var name = item.tempModel.name;
|
||||
var samePath = item.tempModel.path.join('') === item.model.path.join('');
|
||||
if (!name || (samePath && $scope.fileNavigator.fileNameExists(name))) {
|
||||
$scope.apiMiddleware.apiHandler.error = $translate.instant('error_invalid_filename');
|
||||
return false;
|
||||
}
|
||||
$scope.apiMiddleware.rename(item).then(function() {
|
||||
$scope.fileNavigator.refresh();
|
||||
$scope.modal('rename', true);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.createFolder = function() {
|
||||
var item = $scope.singleSelection();
|
||||
var name = item.tempModel.name;
|
||||
if (!name || $scope.fileNavigator.fileNameExists(name)) {
|
||||
return $scope.apiMiddleware.apiHandler.error = $translate.instant('error_invalid_filename');
|
||||
}
|
||||
$scope.apiMiddleware.createFolder(item).then(function() {
|
||||
$scope.fileNavigator.refresh();
|
||||
$scope.modal('newfolder', true);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addForUpload = function($files) {
|
||||
$scope.uploadFileList = $scope.uploadFileList.concat($files);
|
||||
$scope.modal('uploadfile');
|
||||
};
|
||||
|
||||
$scope.removeFromUpload = function(index) {
|
||||
$scope.uploadFileList.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.uploadFiles = function() {
|
||||
$scope.apiMiddleware.upload($scope.uploadFileList, $scope.fileNavigator.currentPath).then(function() {
|
||||
$scope.fileNavigator.refresh();
|
||||
$scope.uploadFileList = [];
|
||||
$scope.modal('uploadfile', true);
|
||||
}, function(data) {
|
||||
var errorMsg = data.result && data.result.error || $translate.instant('error_uploading_files');
|
||||
$scope.apiMiddleware.apiHandler.error = errorMsg;
|
||||
});
|
||||
};
|
||||
|
||||
var validateSamePath = function(item) {
|
||||
var selectedPath = $rootScope.selectedModalPath.join('');
|
||||
var selectedItemsPath = item && item.model.path.join('');
|
||||
return selectedItemsPath === selectedPath;
|
||||
};
|
||||
|
||||
var getQueryParam = function(param) {
|
||||
var found = $window.location.search.substr(1).split('&').filter(function(item) {
|
||||
return param === item.split('=')[0];
|
||||
});
|
||||
return found[0] && found[0].split('=')[1] || undefined;
|
||||
};
|
||||
|
||||
$scope.changeLanguage(getQueryParam('lang'));
|
||||
$scope.isWindows = getQueryParam('server') === 'Windows';
|
||||
$scope.fileNavigator.refresh();
|
||||
|
||||
}]);
|
||||
})(angular, jQuery);
|
||||
@@ -0,0 +1,58 @@
|
||||
(function(angular) {
|
||||
'use strict';
|
||||
angular.module('FileManagerApp').controller('ModalFileManagerCtrl',
|
||||
['$scope', '$rootScope', 'fileNavigator', function($scope, $rootScope, FileNavigator) {
|
||||
|
||||
$scope.reverse = false;
|
||||
$scope.predicate = ['model.type', 'model.name'];
|
||||
$scope.fileNavigator = new FileNavigator();
|
||||
$rootScope.selectedModalPath = [];
|
||||
|
||||
$scope.order = function(predicate) {
|
||||
$scope.reverse = ($scope.predicate[1] === predicate) ? !$scope.reverse : false;
|
||||
$scope.predicate[1] = predicate;
|
||||
};
|
||||
|
||||
$scope.select = function(item) {
|
||||
$rootScope.selectedModalPath = item.model.fullPath().split('/').filter(Boolean);
|
||||
$scope.modal('selector', true);
|
||||
};
|
||||
|
||||
$scope.selectCurrent = function() {
|
||||
$rootScope.selectedModalPath = $scope.fileNavigator.currentPath;
|
||||
$scope.modal('selector', true);
|
||||
};
|
||||
|
||||
$scope.selectedFilesAreChildOfPath = function(item) {
|
||||
var path = item.model.fullPath();
|
||||
return $scope.temps.find(function(item) {
|
||||
var itemPath = item.model.fullPath();
|
||||
if (path == itemPath) {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
if (path.startsWith(itemPath)) {
|
||||
fixme names in same folder like folder-one and folder-one-two
|
||||
at the moment fixed hidding affected folders
|
||||
}
|
||||
*/
|
||||
});
|
||||
};
|
||||
|
||||
$rootScope.openNavigator = function(path) {
|
||||
$scope.fileNavigator.currentPath = path;
|
||||
$scope.fileNavigator.refresh();
|
||||
$scope.modal('selector');
|
||||
};
|
||||
|
||||
$rootScope.getSelectedPath = function() {
|
||||
var path = $rootScope.selectedModalPath.filter(Boolean);
|
||||
var result = '/' + path.join('/');
|
||||
if ($scope.singleSelection() && !$scope.singleSelection().isFolder()) {
|
||||
result += '/' + $scope.singleSelection().tempModel.name;
|
||||
}
|
||||
return result.replace(/\/\//, '/');
|
||||
};
|
||||
|
||||
}]);
|
||||
})(angular);
|
||||
40
static/filemanager_app/src/js/directives/directives.js
Normal file
40
static/filemanager_app/src/js/directives/directives.js
Normal file
@@ -0,0 +1,40 @@
|
||||
(function(angular) {
|
||||
'use strict';
|
||||
var app = angular.module('FileManagerApp');
|
||||
|
||||
app.directive('angularFilemanager', ['$parse', 'fileManagerConfig', function($parse, fileManagerConfig) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
templateUrl: fileManagerConfig.tplPath + '/main.html'
|
||||
};
|
||||
}]);
|
||||
|
||||
app.directive('ngFile', ['$parse', function($parse) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attrs) {
|
||||
var model = $parse(attrs.ngFile);
|
||||
var modelSetter = model.assign;
|
||||
|
||||
element.bind('change', function() {
|
||||
scope.$apply(function() {
|
||||
modelSetter(scope, element[0].files);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
app.directive('ngRightClick', ['$parse', function($parse) {
|
||||
return function(scope, element, attrs) {
|
||||
var fn = $parse(attrs.ngRightClick);
|
||||
element.bind('contextmenu', function(event) {
|
||||
scope.$apply(function() {
|
||||
event.preventDefault();
|
||||
fn(scope, {$event: event});
|
||||
});
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
})(angular);
|
||||
109
static/filemanager_app/src/js/entities/chmod.js
Normal file
109
static/filemanager_app/src/js/entities/chmod.js
Normal file
@@ -0,0 +1,109 @@
|
||||
(function(angular) {
|
||||
'use strict';
|
||||
angular.module('FileManagerApp').service('chmod', function () {
|
||||
|
||||
var Chmod = function(initValue) {
|
||||
this.owner = this.getRwxObj();
|
||||
this.group = this.getRwxObj();
|
||||
this.others = this.getRwxObj();
|
||||
|
||||
if (initValue) {
|
||||
var codes = isNaN(initValue) ?
|
||||
this.convertfromCode(initValue):
|
||||
this.convertfromOctal(initValue);
|
||||
|
||||
if (! codes) {
|
||||
throw new Error('Invalid chmod input data (%s)'.replace('%s', initValue));
|
||||
}
|
||||
|
||||
this.owner = codes.owner;
|
||||
this.group = codes.group;
|
||||
this.others = codes.others;
|
||||
}
|
||||
};
|
||||
|
||||
Chmod.prototype.toOctal = function(prepend, append) {
|
||||
var result = [];
|
||||
['owner', 'group', 'others'].forEach(function(key, i) {
|
||||
result[i] = this[key].read && this.octalValues.read || 0;
|
||||
result[i] += this[key].write && this.octalValues.write || 0;
|
||||
result[i] += this[key].exec && this.octalValues.exec || 0;
|
||||
}.bind(this));
|
||||
return (prepend||'') + result.join('') + (append||'');
|
||||
};
|
||||
|
||||
Chmod.prototype.toCode = function(prepend, append) {
|
||||
var result = [];
|
||||
['owner', 'group', 'others'].forEach(function(key, i) {
|
||||
result[i] = this[key].read && this.codeValues.read || '-';
|
||||
result[i] += this[key].write && this.codeValues.write || '-';
|
||||
result[i] += this[key].exec && this.codeValues.exec || '-';
|
||||
}.bind(this));
|
||||
return (prepend||'') + result.join('') + (append||'');
|
||||
};
|
||||
|
||||
Chmod.prototype.getRwxObj = function() {
|
||||
return {
|
||||
read: false,
|
||||
write: false,
|
||||
exec: false
|
||||
};
|
||||
};
|
||||
|
||||
Chmod.prototype.octalValues = {
|
||||
read: 4, write: 2, exec: 1
|
||||
};
|
||||
|
||||
Chmod.prototype.codeValues = {
|
||||
read: 'r', write: 'w', exec: 'x'
|
||||
};
|
||||
|
||||
Chmod.prototype.convertfromCode = function (str) {
|
||||
str = ('' + str).replace(/\s/g, '');
|
||||
str = str.length === 10 ? str.substr(1) : str;
|
||||
if (! /^[-rwxts]{9}$/.test(str)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var result = [], vals = str.match(/.{1,3}/g);
|
||||
for (var i in vals) {
|
||||
var rwxObj = this.getRwxObj();
|
||||
rwxObj.read = /r/.test(vals[i]);
|
||||
rwxObj.write = /w/.test(vals[i]);
|
||||
rwxObj.exec = /x|t/.test(vals[i]);
|
||||
result.push(rwxObj);
|
||||
}
|
||||
|
||||
return {
|
||||
owner : result[0],
|
||||
group : result[1],
|
||||
others: result[2]
|
||||
};
|
||||
};
|
||||
|
||||
Chmod.prototype.convertfromOctal = function (str) {
|
||||
str = ('' + str).replace(/\s/g, '');
|
||||
str = str.length === 4 ? str.substr(1) : str;
|
||||
if (! /^[0-7]{3}$/.test(str)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var result = [], vals = str.match(/.{1}/g);
|
||||
for (var i in vals) {
|
||||
var rwxObj = this.getRwxObj();
|
||||
rwxObj.read = /[4567]/.test(vals[i]);
|
||||
rwxObj.write = /[2367]/.test(vals[i]);
|
||||
rwxObj.exec = /[1357]/.test(vals[i]);
|
||||
result.push(rwxObj);
|
||||
}
|
||||
|
||||
return {
|
||||
owner : result[0],
|
||||
group : result[1],
|
||||
others: result[2]
|
||||
};
|
||||
};
|
||||
|
||||
return Chmod;
|
||||
});
|
||||
})(angular);
|
||||
68
static/filemanager_app/src/js/entities/item.js
Normal file
68
static/filemanager_app/src/js/entities/item.js
Normal file
@@ -0,0 +1,68 @@
|
||||
(function(angular) {
|
||||
'use strict';
|
||||
angular.module('FileManagerApp').factory('item', ['fileManagerConfig', 'chmod', function(fileManagerConfig, Chmod) {
|
||||
|
||||
var Item = function(model, path) {
|
||||
var rawModel = {
|
||||
name: model && model.name || '',
|
||||
path: path || [],
|
||||
type: model && model.type || 'file',
|
||||
size: model && parseInt(model.size || 0),
|
||||
date: parseMySQLDate(model && model.date),
|
||||
perms: new Chmod(model && model.rights),
|
||||
content: model && model.content || '',
|
||||
recursive: false,
|
||||
fullPath: function() {
|
||||
var path = this.path.filter(Boolean);
|
||||
return ('/' + path.join('/') + '/' + this.name).replace(/\/\//, '/');
|
||||
}
|
||||
};
|
||||
|
||||
this.error = '';
|
||||
this.processing = false;
|
||||
|
||||
this.model = angular.copy(rawModel);
|
||||
this.tempModel = angular.copy(rawModel);
|
||||
|
||||
function parseMySQLDate(mysqlDate) {
|
||||
var d = (mysqlDate || '').toString().split(/[- :]/);
|
||||
return new Date(d[0], d[1] - 1, d[2], d[3], d[4], d[5]);
|
||||
}
|
||||
};
|
||||
|
||||
Item.prototype.update = function() {
|
||||
angular.extend(this.model, angular.copy(this.tempModel));
|
||||
};
|
||||
|
||||
Item.prototype.revert = function() {
|
||||
angular.extend(this.tempModel, angular.copy(this.model));
|
||||
this.error = '';
|
||||
};
|
||||
|
||||
Item.prototype.isFolder = function() {
|
||||
return this.model.type === 'dir';
|
||||
};
|
||||
|
||||
Item.prototype.isEditable = function() {
|
||||
return !this.isFolder() && fileManagerConfig.isEditableFilePattern.test(this.model.name);
|
||||
};
|
||||
|
||||
Item.prototype.isImage = function() {
|
||||
return fileManagerConfig.isImageFilePattern.test(this.model.name);
|
||||
};
|
||||
|
||||
Item.prototype.isCompressible = function() {
|
||||
return this.isFolder();
|
||||
};
|
||||
|
||||
Item.prototype.isExtractable = function() {
|
||||
return !this.isFolder() && fileManagerConfig.isExtractableFilePattern.test(this.model.name);
|
||||
};
|
||||
|
||||
Item.prototype.isSelectable = function() {
|
||||
return (this.isFolder() && fileManagerConfig.allowedActions.pickFolders) || (!this.isFolder() && fileManagerConfig.allowedActions.pickFiles);
|
||||
};
|
||||
|
||||
return Item;
|
||||
}]);
|
||||
})(angular);
|
||||
46
static/filemanager_app/src/js/filters/filters.js
Normal file
46
static/filemanager_app/src/js/filters/filters.js
Normal file
@@ -0,0 +1,46 @@
|
||||
(function(angular) {
|
||||
'use strict';
|
||||
var app = angular.module('FileManagerApp');
|
||||
|
||||
app.filter('strLimit', ['$filter', function($filter) {
|
||||
return function(input, limit, more) {
|
||||
if (input.length <= limit) {
|
||||
return input;
|
||||
}
|
||||
return $filter('limitTo')(input, limit) + (more || '...');
|
||||
};
|
||||
}]);
|
||||
|
||||
app.filter('fileExtension', ['$filter', function($filter) {
|
||||
return function(input) {
|
||||
return /\./.test(input) && $filter('strLimit')(input.split('.').pop(), 3, '..') || '';
|
||||
};
|
||||
}]);
|
||||
|
||||
app.filter('formatDate', ['$filter', function() {
|
||||
return function(input) {
|
||||
return input instanceof Date ?
|
||||
input.toISOString().substring(0, 19).replace('T', ' ') :
|
||||
(input.toLocaleString || input.toString).apply(input);
|
||||
};
|
||||
}]);
|
||||
|
||||
app.filter('humanReadableFileSize', ['$filter', 'fileManagerConfig', function($filter, fileManagerConfig) {
|
||||
// See https://en.wikipedia.org/wiki/Binary_prefix
|
||||
var decimalByteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
var binaryByteUnits = ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
||||
|
||||
return function(input) {
|
||||
var i = -1;
|
||||
var fileSizeInBytes = input;
|
||||
|
||||
do {
|
||||
fileSizeInBytes = fileSizeInBytes / 1024;
|
||||
i++;
|
||||
} while (fileSizeInBytes > 1024);
|
||||
|
||||
var result = fileManagerConfig.useBinarySizePrefixes ? binaryByteUnits[i] : decimalByteUnits[i];
|
||||
return Math.max(fileSizeInBytes, 0.1).toFixed(1) + ' ' + result;
|
||||
};
|
||||
}]);
|
||||
})(angular);
|
||||
75
static/filemanager_app/src/js/providers/config.js
Normal file
75
static/filemanager_app/src/js/providers/config.js
Normal file
@@ -0,0 +1,75 @@
|
||||
(function(angular) {
|
||||
'use strict';
|
||||
angular.module('FileManagerApp').provider('fileManagerConfig', function() {
|
||||
|
||||
var values = {
|
||||
appName: 'angular-filemanager v1.5',
|
||||
defaultLang: 'en',
|
||||
|
||||
listUrl: 'bridges/php/handler.php',
|
||||
uploadUrl: 'bridges/php/handler.php',
|
||||
renameUrl: 'bridges/php/handler.php',
|
||||
copyUrl: 'bridges/php/handler.php',
|
||||
moveUrl: 'bridges/php/handler.php',
|
||||
removeUrl: 'bridges/php/handler.php',
|
||||
editUrl: 'bridges/php/handler.php',
|
||||
getContentUrl: 'bridges/php/handler.php',
|
||||
createFolderUrl: 'bridges/php/handler.php',
|
||||
downloadFileUrl: 'bridges/php/handler.php',
|
||||
downloadMultipleUrl: 'bridges/php/handler.php',
|
||||
compressUrl: 'bridges/php/handler.php',
|
||||
extractUrl: 'bridges/php/handler.php',
|
||||
permissionsUrl: 'bridges/php/handler.php',
|
||||
basePath: '/',
|
||||
|
||||
searchForm: true,
|
||||
sidebar: true,
|
||||
breadcrumb: true,
|
||||
allowedActions: {
|
||||
upload: true,
|
||||
rename: true,
|
||||
move: true,
|
||||
copy: true,
|
||||
edit: true,
|
||||
changePermissions: true,
|
||||
compress: true,
|
||||
compressChooseName: true,
|
||||
extract: true,
|
||||
download: true,
|
||||
downloadMultiple: true,
|
||||
preview: true,
|
||||
remove: true,
|
||||
createFolder: true,
|
||||
pickFiles: false,
|
||||
pickFolders: false
|
||||
},
|
||||
|
||||
multipleDownloadFileName: 'angular-filemanager.zip',
|
||||
filterFileExtensions: [],
|
||||
showExtensionIcons: true,
|
||||
showSizeForDirectories: false,
|
||||
useBinarySizePrefixes: false,
|
||||
downloadFilesByAjax: true,
|
||||
previewImagesInModal: true,
|
||||
enablePermissionsRecursive: true,
|
||||
compressAsync: false,
|
||||
extractAsync: false,
|
||||
pickCallback: null,
|
||||
|
||||
isEditableFilePattern: /\.(txt|diff?|patch|svg|asc|cnf|cfg|conf|html?|.html|cfm|cgi|aspx?|ini|pl|py|md|css|cs|js|jsp|log|htaccess|htpasswd|gitignore|gitattributes|env|json|atom|eml|rss|markdown|sql|xml|xslt?|sh|rb|as|bat|cmd|cob|for|ftn|frm|frx|inc|lisp|scm|coffee|php[3-6]?|java|c|cbl|go|h|scala|vb|tmpl|lock|go|yml|yaml|tsv|lst)$/i,
|
||||
isImageFilePattern: /\.(jpe?g|gif|bmp|png|svg|tiff?)$/i,
|
||||
isExtractableFilePattern: /\.(gz|tar|rar|g?zip)$/i,
|
||||
tplPath: 'src/templates'
|
||||
};
|
||||
|
||||
return {
|
||||
$get: function() {
|
||||
return values;
|
||||
},
|
||||
set: function (constants) {
|
||||
angular.extend(values, constants);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
})(angular);
|
||||
1490
static/filemanager_app/src/js/providers/translations.js
Normal file
1490
static/filemanager_app/src/js/providers/translations.js
Normal file
File diff suppressed because it is too large
Load Diff
370
static/filemanager_app/src/js/services/apihandler.js
Normal file
370
static/filemanager_app/src/js/services/apihandler.js
Normal file
@@ -0,0 +1,370 @@
|
||||
(function(angular, $) {
|
||||
'use strict';
|
||||
angular.module('FileManagerApp').service('apiHandler', ['$http', '$q', '$window', '$translate', 'Upload',
|
||||
function ($http, $q, $window, $translate, Upload) {
|
||||
|
||||
$http.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
var ApiHandler = function() {
|
||||
this.inprocess = false;
|
||||
this.asyncSuccess = false;
|
||||
this.error = '';
|
||||
};
|
||||
|
||||
ApiHandler.prototype.deferredHandler = function(data, deferred, code, defaultMsg) {
|
||||
if (!data || typeof data !== 'object') {
|
||||
this.error = 'Error %s - Bridge response error, please check the API docs or this ajax response.'.replace('%s', code);
|
||||
}
|
||||
if (code == 404) {
|
||||
this.error = 'Error 404 - Backend bridge is not working, please check the ajax response.';
|
||||
}
|
||||
if (data.result && data.result.error) {
|
||||
this.error = data.result.error;
|
||||
}
|
||||
if (!this.error && data.error) {
|
||||
this.error = data.error.message;
|
||||
}
|
||||
if (!this.error && defaultMsg) {
|
||||
this.error = defaultMsg;
|
||||
}
|
||||
if (this.error) {
|
||||
return deferred.reject(data);
|
||||
}
|
||||
return deferred.resolve(data);
|
||||
};
|
||||
|
||||
ApiHandler.prototype.list = function(apiUrl, path, customDeferredHandler, exts) {
|
||||
var self = this;
|
||||
var dfHandler = customDeferredHandler || self.deferredHandler;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'list',
|
||||
path: path,
|
||||
fileExtensions: exts && exts.length ? exts : undefined
|
||||
};
|
||||
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
dfHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
dfHandler(data, deferred, code, 'Unknown error listing, check the response');
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.copy = function(apiUrl, items, path, singleFilename) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'copy',
|
||||
items: items,
|
||||
newPath: path
|
||||
};
|
||||
|
||||
if (singleFilename && items.length === 1) {
|
||||
data.singleFilename = singleFilename;
|
||||
}
|
||||
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_copying'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.move = function(apiUrl, items, path) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'move',
|
||||
items: items,
|
||||
newPath: path
|
||||
};
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_moving'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.remove = function(apiUrl, items) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'remove',
|
||||
items: items
|
||||
};
|
||||
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_deleting'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.upload = function(apiUrl, destination, files) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
self.inprocess = true;
|
||||
self.progress = 0;
|
||||
self.error = '';
|
||||
|
||||
var data = {
|
||||
destination: destination
|
||||
};
|
||||
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
data['file-' + i] = files[i];
|
||||
}
|
||||
|
||||
if (files && files.length) {
|
||||
Upload.upload({
|
||||
url: apiUrl,
|
||||
data: data
|
||||
}).then(function (data) {
|
||||
self.deferredHandler(data.data, deferred, data.status);
|
||||
}, function (data) {
|
||||
self.deferredHandler(data.data, deferred, data.status, 'Unknown error uploading files');
|
||||
}, function (evt) {
|
||||
self.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total)) - 1;
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
self.progress = 0;
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.getContent = function(apiUrl, itemPath) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'getContent',
|
||||
item: itemPath
|
||||
};
|
||||
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_getting_content'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.edit = function(apiUrl, itemPath, content) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'edit',
|
||||
item: itemPath,
|
||||
content: content
|
||||
};
|
||||
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_modifying'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.rename = function(apiUrl, itemPath, newPath) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'rename',
|
||||
item: itemPath,
|
||||
newItemPath: newPath
|
||||
};
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_renaming'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.getUrl = function(apiUrl, path) {
|
||||
var data = {
|
||||
action: 'download',
|
||||
path: path
|
||||
};
|
||||
return path && [apiUrl, $.param(data)].join('?');
|
||||
};
|
||||
|
||||
ApiHandler.prototype.download = function(apiUrl, itemPath, toFilename, downloadByAjax, forceNewWindow) {
|
||||
var self = this;
|
||||
var url = this.getUrl(apiUrl, itemPath);
|
||||
|
||||
if (!downloadByAjax || forceNewWindow || !$window.saveAs) {
|
||||
!$window.saveAs && $window.console.log('Your browser dont support ajax download, downloading by default');
|
||||
return !!$window.open(url, '_blank', '');
|
||||
}
|
||||
|
||||
var deferred = $q.defer();
|
||||
self.inprocess = true;
|
||||
$http.get(url).success(function(data) {
|
||||
var bin = new $window.Blob([data]);
|
||||
deferred.resolve(data);
|
||||
$window.saveAs(bin, toFilename);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_downloading'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.downloadMultiple = function(apiUrl, items, toFilename, downloadByAjax, forceNewWindow) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'downloadMultiple',
|
||||
items: items,
|
||||
toFilename: toFilename
|
||||
};
|
||||
var url = [apiUrl, $.param(data)].join('?');
|
||||
|
||||
if (!downloadByAjax || forceNewWindow || !$window.saveAs) {
|
||||
!$window.saveAs && $window.console.log('Your browser dont support ajax download, downloading by default');
|
||||
return !!$window.open(url, '_blank', '');
|
||||
}
|
||||
|
||||
self.inprocess = true;
|
||||
$http.get(apiUrl).success(function(data) {
|
||||
var bin = new $window.Blob([data]);
|
||||
deferred.resolve(data);
|
||||
$window.saveAs(bin, toFilename);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_downloading'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.compress = function(apiUrl, items, compressedFilename, path) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'compress',
|
||||
items: items,
|
||||
destination: path,
|
||||
compressedFilename: compressedFilename
|
||||
};
|
||||
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_compressing'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.extract = function(apiUrl, item, folderName, path) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'extract',
|
||||
item: item,
|
||||
destination: path,
|
||||
folderName: folderName
|
||||
};
|
||||
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_extracting'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.changePermissions = function(apiUrl, items, permsOctal, permsCode, recursive) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'changePermissions',
|
||||
items: items,
|
||||
perms: permsOctal,
|
||||
permsCode: permsCode,
|
||||
recursive: !!recursive
|
||||
};
|
||||
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_changing_perms'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ApiHandler.prototype.createFolder = function(apiUrl, path) {
|
||||
var self = this;
|
||||
var deferred = $q.defer();
|
||||
var data = {
|
||||
action: 'createFolder',
|
||||
newPath: path
|
||||
};
|
||||
|
||||
self.inprocess = true;
|
||||
self.error = '';
|
||||
$http.post(apiUrl, data).success(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code);
|
||||
}).error(function(data, code) {
|
||||
self.deferredHandler(data, deferred, code, $translate.instant('error_creating_folder'));
|
||||
})['finally'](function() {
|
||||
self.inprocess = false;
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return ApiHandler;
|
||||
|
||||
}]);
|
||||
})(angular, jQuery);
|
||||
135
static/filemanager_app/src/js/services/apimiddleware.js
Normal file
135
static/filemanager_app/src/js/services/apimiddleware.js
Normal file
@@ -0,0 +1,135 @@
|
||||
(function(angular) {
|
||||
'use strict';
|
||||
angular.module('FileManagerApp').service('apiMiddleware', ['$window', 'fileManagerConfig', 'apiHandler',
|
||||
function ($window, fileManagerConfig, ApiHandler) {
|
||||
|
||||
var ApiMiddleware = function() {
|
||||
this.apiHandler = new ApiHandler();
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.getPath = function(arrayPath) {
|
||||
return '/' + arrayPath.join('/');
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.getFileList = function(files) {
|
||||
return (files || []).map(function(file) {
|
||||
return file && file.model.fullPath();
|
||||
});
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.getFilePath = function(item) {
|
||||
return item && item.model.fullPath();
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.list = function(path, customDeferredHandler) {
|
||||
return this.apiHandler.list(fileManagerConfig.listUrl, this.getPath(path), customDeferredHandler);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.copy = function(files, path) {
|
||||
var items = this.getFileList(files);
|
||||
var singleFilename = items.length === 1 ? files[0].tempModel.name : undefined;
|
||||
return this.apiHandler.copy(fileManagerConfig.copyUrl, items, this.getPath(path), singleFilename);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.move = function(files, path) {
|
||||
var items = this.getFileList(files);
|
||||
return this.apiHandler.move(fileManagerConfig.moveUrl, items, this.getPath(path));
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.remove = function(files) {
|
||||
var items = this.getFileList(files);
|
||||
return this.apiHandler.remove(fileManagerConfig.removeUrl, items);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.upload = function(files, path) {
|
||||
if (! $window.FormData) {
|
||||
throw new Error('Unsupported browser version');
|
||||
}
|
||||
|
||||
var destination = this.getPath(path);
|
||||
|
||||
return this.apiHandler.upload(fileManagerConfig.uploadUrl, destination, files);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.getContent = function(item) {
|
||||
var itemPath = this.getFilePath(item);
|
||||
return this.apiHandler.getContent(fileManagerConfig.getContentUrl, itemPath);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.edit = function(item) {
|
||||
var itemPath = this.getFilePath(item);
|
||||
return this.apiHandler.edit(fileManagerConfig.editUrl, itemPath, item.tempModel.content);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.rename = function(item) {
|
||||
var itemPath = this.getFilePath(item);
|
||||
var newPath = item.tempModel.fullPath();
|
||||
|
||||
return this.apiHandler.rename(fileManagerConfig.renameUrl, itemPath, newPath);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.getUrl = function(item) {
|
||||
var itemPath = this.getFilePath(item);
|
||||
return this.apiHandler.getUrl(fileManagerConfig.downloadFileUrl, itemPath);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.download = function(item, forceNewWindow) {
|
||||
//TODO: add spinner to indicate file is downloading
|
||||
var itemPath = this.getFilePath(item);
|
||||
var toFilename = item.model.name;
|
||||
|
||||
if (item.isFolder()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.apiHandler.download(
|
||||
fileManagerConfig.downloadFileUrl,
|
||||
itemPath,
|
||||
toFilename,
|
||||
fileManagerConfig.downloadFilesByAjax,
|
||||
forceNewWindow
|
||||
);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.downloadMultiple = function(files, forceNewWindow) {
|
||||
var items = this.getFileList(files);
|
||||
var timestamp = new Date().getTime().toString().substr(8, 13);
|
||||
var toFilename = timestamp + '-' + fileManagerConfig.multipleDownloadFileName;
|
||||
|
||||
return this.apiHandler.downloadMultiple(
|
||||
fileManagerConfig.downloadMultipleUrl,
|
||||
items,
|
||||
toFilename,
|
||||
fileManagerConfig.downloadFilesByAjax,
|
||||
forceNewWindow
|
||||
);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.compress = function(files, compressedFilename, path) {
|
||||
var items = this.getFileList(files);
|
||||
return this.apiHandler.compress(fileManagerConfig.compressUrl, items, compressedFilename, this.getPath(path));
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.extract = function(item, folderName, path) {
|
||||
var itemPath = this.getFilePath(item);
|
||||
return this.apiHandler.extract(fileManagerConfig.extractUrl, itemPath, folderName, this.getPath(path));
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.changePermissions = function(files, dataItem) {
|
||||
var items = this.getFileList(files);
|
||||
var code = dataItem.tempModel.perms.toCode();
|
||||
var octal = dataItem.tempModel.perms.toOctal();
|
||||
var recursive = !!dataItem.tempModel.recursive;
|
||||
|
||||
return this.apiHandler.changePermissions(fileManagerConfig.permissionsUrl, items, code, octal, recursive);
|
||||
};
|
||||
|
||||
ApiMiddleware.prototype.createFolder = function(item) {
|
||||
var path = item.tempModel.fullPath();
|
||||
return this.apiHandler.createFolder(fileManagerConfig.createFolderUrl, path);
|
||||
};
|
||||
|
||||
return ApiMiddleware;
|
||||
|
||||
}]);
|
||||
})(angular);
|
||||
159
static/filemanager_app/src/js/services/filenavigator.js
Normal file
159
static/filemanager_app/src/js/services/filenavigator.js
Normal file
@@ -0,0 +1,159 @@
|
||||
(function(angular) {
|
||||
'use strict';
|
||||
angular.module('FileManagerApp').service('fileNavigator', [
|
||||
'apiMiddleware', 'fileManagerConfig', 'item', function (ApiMiddleware, fileManagerConfig, Item) {
|
||||
|
||||
var FileNavigator = function() {
|
||||
this.apiMiddleware = new ApiMiddleware();
|
||||
this.requesting = false;
|
||||
this.fileList = [];
|
||||
this.currentPath = this.getBasePath();
|
||||
this.history = [];
|
||||
this.error = '';
|
||||
|
||||
this.onRefresh = function() {};
|
||||
};
|
||||
|
||||
FileNavigator.prototype.getBasePath = function() {
|
||||
var path = (fileManagerConfig.basePath || '').replace(/^\//, '');
|
||||
return path.trim() ? path.split('/') : [];
|
||||
};
|
||||
|
||||
FileNavigator.prototype.deferredHandler = function(data, deferred, code, defaultMsg) {
|
||||
if (!data || typeof data !== 'object') {
|
||||
this.error = 'Error %s - Bridge response error, please check the API docs or this ajax response.'.replace('%s', code);
|
||||
}
|
||||
if (code == 404) {
|
||||
this.error = 'Error 404 - Backend bridge is not working, please check the ajax response.';
|
||||
}
|
||||
if (code == 200) {
|
||||
this.error = null;
|
||||
}
|
||||
if (!this.error && data.result && data.result.error) {
|
||||
this.error = data.result.error;
|
||||
}
|
||||
if (!this.error && data.error) {
|
||||
this.error = data.error.message;
|
||||
}
|
||||
if (!this.error && defaultMsg) {
|
||||
this.error = defaultMsg;
|
||||
}
|
||||
if (this.error) {
|
||||
return deferred.reject(data);
|
||||
}
|
||||
return deferred.resolve(data);
|
||||
};
|
||||
|
||||
FileNavigator.prototype.list = function() {
|
||||
return this.apiMiddleware.list(this.currentPath, this.deferredHandler.bind(this));
|
||||
};
|
||||
|
||||
FileNavigator.prototype.refresh = function() {
|
||||
var self = this;
|
||||
if (! self.currentPath.length) {
|
||||
self.currentPath = this.getBasePath();
|
||||
}
|
||||
var path = self.currentPath.join('/');
|
||||
self.requesting = true;
|
||||
self.fileList = [];
|
||||
return self.list().then(function(data) {
|
||||
self.fileList = (data.result || []).map(function(file) {
|
||||
return new Item(file, self.currentPath);
|
||||
});
|
||||
self.buildTree(path);
|
||||
self.onRefresh();
|
||||
}).finally(function() {
|
||||
self.requesting = false;
|
||||
});
|
||||
};
|
||||
|
||||
FileNavigator.prototype.buildTree = function(path) {
|
||||
var flatNodes = [], selectedNode = {};
|
||||
|
||||
function recursive(parent, item, path) {
|
||||
var absName = path ? (path + '/' + item.model.name) : item.model.name;
|
||||
if (parent.name && parent.name.trim() && path.trim().indexOf(parent.name) !== 0) {
|
||||
parent.nodes = [];
|
||||
}
|
||||
if (parent.name !== path) {
|
||||
parent.nodes.forEach(function(nd) {
|
||||
recursive(nd, item, path);
|
||||
});
|
||||
} else {
|
||||
for (var e in parent.nodes) {
|
||||
if (parent.nodes[e].name === absName) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
parent.nodes.push({item: item, name: absName, nodes: []});
|
||||
}
|
||||
|
||||
parent.nodes = parent.nodes.sort(function(a, b) {
|
||||
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : a.name.toLowerCase() === b.name.toLowerCase() ? 0 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
function flatten(node, array) {
|
||||
array.push(node);
|
||||
for (var n in node.nodes) {
|
||||
flatten(node.nodes[n], array);
|
||||
}
|
||||
}
|
||||
|
||||
function findNode(data, path) {
|
||||
return data.filter(function (n) {
|
||||
return n.name === path;
|
||||
})[0];
|
||||
}
|
||||
|
||||
//!this.history.length && this.history.push({name: '', nodes: []});
|
||||
!this.history.length && this.history.push({ name: this.getBasePath()[0] || '', nodes: [] });
|
||||
flatten(this.history[0], flatNodes);
|
||||
selectedNode = findNode(flatNodes, path);
|
||||
selectedNode && (selectedNode.nodes = []);
|
||||
|
||||
for (var o in this.fileList) {
|
||||
var item = this.fileList[o];
|
||||
item instanceof Item && item.isFolder() && recursive(this.history[0], item, path);
|
||||
}
|
||||
};
|
||||
|
||||
FileNavigator.prototype.folderClick = function(item) {
|
||||
this.currentPath = [];
|
||||
if (item && item.isFolder()) {
|
||||
this.currentPath = item.model.fullPath().split('/').splice(1);
|
||||
}
|
||||
this.refresh();
|
||||
};
|
||||
|
||||
FileNavigator.prototype.upDir = function() {
|
||||
if (this.currentPath[0]) {
|
||||
this.currentPath = this.currentPath.slice(0, -1);
|
||||
this.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
FileNavigator.prototype.goTo = function(index) {
|
||||
this.currentPath = this.currentPath.slice(0, index + 1);
|
||||
this.refresh();
|
||||
};
|
||||
|
||||
FileNavigator.prototype.fileNameExists = function(fileName) {
|
||||
return this.fileList.find(function(item) {
|
||||
return fileName && item.model.name.trim() === fileName.trim();
|
||||
});
|
||||
};
|
||||
|
||||
FileNavigator.prototype.listHasFolders = function() {
|
||||
return this.fileList.find(function(item) {
|
||||
return item.model.type === 'dir';
|
||||
});
|
||||
};
|
||||
|
||||
FileNavigator.prototype.getCurrentFolderName = function() {
|
||||
return this.currentPath.slice(-1)[0] || '/';
|
||||
};
|
||||
|
||||
return FileNavigator;
|
||||
}]);
|
||||
})(angular);
|
||||
@@ -0,0 +1,15 @@
|
||||
<ol class="breadcrumb">
|
||||
<li>
|
||||
<a href="" ng-click="fileNavigator.goTo(-1)">
|
||||
{{"filemanager" | translate}}
|
||||
</a>
|
||||
</li>
|
||||
<li ng-repeat="(key, dir) in fileNavigator.currentPath track by key" ng-class="{'active':$last}" class="animated fast fadeIn">
|
||||
<a href="" ng-show="!$last" ng-click="fileNavigator.goTo(key)">
|
||||
{{dir | strLimit : 8}}
|
||||
</a>
|
||||
<span ng-show="$last">
|
||||
{{dir | strLimit : 12}}
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
98
static/filemanager_app/src/templates/item-context-menu.html
Normal file
98
static/filemanager_app/src/templates/item-context-menu.html
Normal file
@@ -0,0 +1,98 @@
|
||||
<div id="context-menu" class="dropdown clearfix animated fast fadeIn">
|
||||
<ul class="dropdown-menu dropdown-right-click" role="menu" aria-labelledby="dropdownMenu" ng-show="temps.length">
|
||||
|
||||
<li ng-show="singleSelection() && singleSelection().isFolder()">
|
||||
<a href="" tabindex="-1" ng-click="smartClick(singleSelection())">
|
||||
<i class="glyphicon glyphicon-folder-open"></i> {{'open' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.pickCallback && singleSelection() && singleSelection().isSelectable()">
|
||||
<a href="" tabindex="-1" ng-click="config.pickCallback(singleSelection().model)">
|
||||
<i class="glyphicon glyphicon-hand-up"></i> {{'select_this' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.download && !selectionHas('dir') && singleSelection()">
|
||||
<a href="" tabindex="-1" ng-click="download()">
|
||||
<i class="glyphicon glyphicon-cloud-download"></i> {{'download' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.downloadMultiple && !selectionHas('dir') && !singleSelection()">
|
||||
<a href="" tabindex="-1" ng-click="download()">
|
||||
<i class="glyphicon glyphicon-cloud-download"></i> {{'download_as_zip' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.preview && singleSelection().isImage() && singleSelection()">
|
||||
<a href="" tabindex="-1" ng-click="openImagePreview()">
|
||||
<i class="glyphicon glyphicon-picture"></i> {{'view_item' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.rename && singleSelection()">
|
||||
<a href="" tabindex="-1" ng-click="modal('rename')">
|
||||
<i class="glyphicon glyphicon-edit"></i> {{'rename' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.move">
|
||||
<a href="" tabindex="-1" ng-click="modalWithPathSelector('move')">
|
||||
<i class="glyphicon glyphicon-arrow-right"></i> {{'move' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.copy && !selectionHas('dir')">
|
||||
<a href="" tabindex="-1" ng-click="modalWithPathSelector('copy')">
|
||||
<i class="glyphicon glyphicon-log-out"></i> {{'copy' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.edit && singleSelection() && singleSelection().isEditable()">
|
||||
<a href="" tabindex="-1" ng-click="openEditItem()">
|
||||
<i class="glyphicon glyphicon-pencil"></i> {{'edit' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.changePermissions">
|
||||
<a href="" tabindex="-1" ng-click="modal('changepermissions')">
|
||||
<i class="glyphicon glyphicon-lock"></i> {{'permissions' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.compress && (!singleSelection() || selectionHas('dir'))">
|
||||
<a href="" tabindex="-1" ng-click="modal('compress')">
|
||||
<i class="glyphicon glyphicon-compressed"></i> {{'compress' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="config.allowedActions.extract && singleSelection() && singleSelection().isExtractable()">
|
||||
<a href="" tabindex="-1" ng-click="modal('extract')">
|
||||
<i class="glyphicon glyphicon-export"></i> {{'extract' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="divider" ng-show="config.allowedActions.remove"></li>
|
||||
|
||||
<li ng-show="config.allowedActions.remove">
|
||||
<a href="" tabindex="-1" ng-click="modal('remove')">
|
||||
<i class="glyphicon glyphicon-trash"></i> {{'remove' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<ul class="dropdown-menu dropdown-right-click" role="menu" aria-labelledby="dropdownMenu" ng-show="!temps.length">
|
||||
<li ng-show="config.allowedActions.createFolder">
|
||||
<a href="" tabindex="-1" ng-click="modal('newfolder') && prepareNewFolder()">
|
||||
<i class="glyphicon glyphicon-plus"></i> {{'new_folder' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="config.allowedActions.upload">
|
||||
<a href="" tabindex="-1" ng-click="modal('uploadfile')">
|
||||
<i class="glyphicon glyphicon-cloud-upload"></i> {{'upload_files' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
25
static/filemanager_app/src/templates/main-icons.html
Normal file
25
static/filemanager_app/src/templates/main-icons.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<div class="iconset noselect">
|
||||
<div class="item-list clearfix" ng-click="selectOrUnselect(null, $event)" ng-right-click="selectOrUnselect(null, $event)" prevent="true">
|
||||
<div class="col-120" ng-repeat="item in $parent.fileList = (fileNavigator.fileList | filter: {model:{name: query}})" ng-show="!fileNavigator.requesting && !fileNavigator.error">
|
||||
<a href="" class="thumbnail text-center" ng-click="selectOrUnselect(item, $event)" ng-dblclick="smartClick(item)" ng-right-click="selectOrUnselect(item, $event)" title="{{item.model.name}} ({{item.model.size | humanReadableFileSize}})" ng-class="{selected: isSelected(item)}">
|
||||
<div class="item-icon">
|
||||
<i class="glyphicon glyphicon-folder-open" ng-show="item.model.type === 'dir'"></i>
|
||||
<i class="glyphicon glyphicon-file" data-ext="{{ item.model.name | fileExtension }}" ng-show="item.model.type === 'file'" ng-class="{'item-extension': config.showExtensionIcons}"></i>
|
||||
</div>
|
||||
{{item.model.name | strLimit : 11 }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="fileNavigator.requesting">
|
||||
<div ng-include="config.tplPath + '/spinner.html'"></div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning" ng-show="!fileNavigator.requesting && fileNavigator.fileList.length < 1 && !fileNavigator.error">
|
||||
{{"no_files_in_folder" | translate}}...
|
||||
</div>
|
||||
|
||||
<div class="alert alert-danger" ng-show="!fileNavigator.requesting && fileNavigator.error">
|
||||
{{ fileNavigator.error }}
|
||||
</div>
|
||||
</div>
|
||||
46
static/filemanager_app/src/templates/main-table-modal.html
Normal file
46
static/filemanager_app/src/templates/main-table-modal.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<table class="table table-condensed table-modal-condensed mb0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<a href="" ng-click="order('model.name')">
|
||||
{{"name" | translate}}
|
||||
<span class="sortorder" ng-show="predicate[1] === 'model.name'" ng-class="{reverse:reverse}"></span>
|
||||
</a>
|
||||
</th>
|
||||
<th class="text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="file-item">
|
||||
<tr ng-show="fileNavigator.requesting">
|
||||
<td colspan="2">
|
||||
<div ng-include="config.tplPath + '/spinner.html'"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-show="!fileNavigator.requesting && !fileNavigator.listHasFolders() && !fileNavigator.error">
|
||||
<td>
|
||||
{{"no_folders_in_folder" | translate}}...
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<button class="btn btn-sm btn-default" ng-click="fileNavigator.upDir()">{{"go_back" | translate}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-show="!fileNavigator.requesting && fileNavigator.error">
|
||||
<td colspan="2">
|
||||
{{ fileNavigator.error }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-repeat="item in fileNavigator.fileList | orderBy:predicate:reverse" ng-show="!fileNavigator.requesting && item.model.type === 'dir'" ng-if="!selectedFilesAreChildOfPath(item)">
|
||||
<td>
|
||||
<a href="" ng-click="fileNavigator.folderClick(item)" title="{{item.model.name}} ({{item.model.size | humanReadableFileSize}})">
|
||||
<i class="glyphicon glyphicon-folder-close"></i>
|
||||
{{item.model.name | strLimit : 32}}
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<button class="btn btn-sm btn-default" ng-click="select(item)">
|
||||
<i class="glyphicon glyphicon-hand-up"></i> {{"select_this" | translate}}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
67
static/filemanager_app/src/templates/main-table.html
Normal file
67
static/filemanager_app/src/templates/main-table.html
Normal file
@@ -0,0 +1,67 @@
|
||||
<table class="table mb0 table-files noselect">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<a href="" ng-click="order('model.name')">
|
||||
{{"name" | translate}}
|
||||
<span class="sortorder" ng-show="predicate[1] === 'model.name'" ng-class="{reverse:reverse}"></span>
|
||||
</a>
|
||||
</th>
|
||||
<th class="hidden-xs" ng-hide="config.hideSize">
|
||||
<a href="" ng-click="order('model.size')">
|
||||
{{"size" | translate}}
|
||||
<span class="sortorder" ng-show="predicate[1] === 'model.size'" ng-class="{reverse:reverse}"></span>
|
||||
</a>
|
||||
</th>
|
||||
<th class="hidden-sm hidden-xs" ng-hide="config.hideDate">
|
||||
<a href="" ng-click="order('model.date')">
|
||||
{{"date" | translate}}
|
||||
<span class="sortorder" ng-show="predicate[1] === 'model.date'" ng-class="{reverse:reverse}"></span>
|
||||
</a>
|
||||
</th>
|
||||
<th class="hidden-sm hidden-xs" ng-hide="config.hidePermissions">
|
||||
<a href="" ng-click="order('model.permissions')">
|
||||
{{"permissions" | translate}}
|
||||
<span class="sortorder" ng-show="predicate[1] === 'model.permissions'" ng-class="{reverse:reverse}"></span>
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="file-item">
|
||||
<tr ng-show="fileNavigator.requesting">
|
||||
<td colspan="5">
|
||||
<div ng-include="config.tplPath + '/spinner.html'"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-show="!fileNavigator.requesting && fileNavigator.fileList.length < 1 && !fileNavigator.error">
|
||||
<td colspan="5">
|
||||
{{"no_files_in_folder" | translate}}...
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-show="!fileNavigator.requesting && fileNavigator.error">
|
||||
<td colspan="5">
|
||||
{{ fileNavigator.error }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="item-list" ng-repeat="item in $parent.fileList = (fileNavigator.fileList | filter: {model:{name: query}} | orderBy:predicate:reverse)" ng-show="!fileNavigator.requesting" ng-click="selectOrUnselect(item, $event)" ng-dblclick="smartClick(item)" ng-right-click="selectOrUnselect(item, $event)" ng-class="{selected: isSelected(item)}">
|
||||
<td>
|
||||
<a href="" title="{{item.model.name}} ({{item.model.size | humanReadableFileSize}})">
|
||||
<i class="glyphicon glyphicon-folder-close" ng-show="item.model.type === 'dir'"></i>
|
||||
<i class="glyphicon glyphicon-file" ng-show="item.model.type === 'file'"></i>
|
||||
{{item.model.name | strLimit : 64}}
|
||||
</a>
|
||||
</td>
|
||||
<td class="hidden-xs">
|
||||
<span ng-show="item.model.type !== 'dir' || config.showSizeForDirectories">
|
||||
{{item.model.size | humanReadableFileSize}}
|
||||
</span>
|
||||
</td>
|
||||
<td class="hidden-sm hidden-xs" ng-hide="config.hideDate">
|
||||
{{item.model.date | formatDate }}
|
||||
</td>
|
||||
<td class="hidden-sm hidden-xs" ng-hide="config.hidePermissions">
|
||||
{{item.model.perms.toCode(item.model.type === 'dir'?'d':'-')}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
18
static/filemanager_app/src/templates/main.html
Normal file
18
static/filemanager_app/src/templates/main.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<div ng-controller="FileManagerCtrl" ngf-drop="addForUpload($files)" ngf-drag-over-class="'upload-dragover'" ngf-multiple="true">
|
||||
<div ng-include="config.tplPath + '/navbar.html'"></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-4 col-md-3 sidebar file-tree animated slow fadeIn" ng-include="config.tplPath + '/sidebar.html'" ng-show="config.sidebar && fileNavigator.history[0]">
|
||||
</div>
|
||||
|
||||
<div class="main" ng-class="config.sidebar && fileNavigator.history[0] && 'col-sm-8 col-md-9'">
|
||||
<div ng-include="config.tplPath + '/' + viewTemplate" class="main-navigation clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-include="config.tplPath + '/modals.html'"></div>
|
||||
<div ng-include="config.tplPath + '/item-context-menu.html'"></div>
|
||||
</div>
|
||||
445
static/filemanager_app/src/templates/modals.html
Normal file
445
static/filemanager_app/src/templates/modals.html
Normal file
@@ -0,0 +1,445 @@
|
||||
<div class="modal animated fadeIn" id="imagepreview">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{"preview" | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="text-center">
|
||||
<img id="imagepreview-target" class="preview" alt="{{singleSelection().model.name}}" ng-class="{'loading': apiMiddleware.apiHandler.inprocess}">
|
||||
<span class="label label-warning" ng-show="apiMiddleware.apiHandler.inprocess">{{'loading' | translate}} ...</span>
|
||||
</div>
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"close" | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="remove">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form ng-submit="remove()">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{"confirm" | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{'sure_to_delete' | translate}} <span ng-include data-src="'selected-files-msg'"></span>
|
||||
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"cancel" | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-disabled="apiMiddleware.apiHandler.inprocess" autofocus="autofocus">{{"remove" | translate}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="move">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form ng-submit="move()">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{'move' | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div ng-include data-src="'path-selector'" class="clearfix"></div>
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"cancel" | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-disabled="apiMiddleware.apiHandler.inprocess">{{'move' | translate}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal animated fadeIn" id="rename">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form ng-submit="rename()">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{'rename' | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label class="radio">{{'enter_new_name_for' | translate}} <b>{{singleSelection() && singleSelection().model.name}}</b></label>
|
||||
<input class="form-control" ng-model="singleSelection().tempModel.name" autofocus="autofocus">
|
||||
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"cancel" | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-disabled="apiMiddleware.apiHandler.inprocess">{{'rename' | translate}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="copy">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form ng-submit="copy()">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{'copy_file' | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div ng-show="singleSelection()">
|
||||
<label class="radio">{{'enter_new_name_for' | translate}} <b>{{singleSelection().model.name}}</b></label>
|
||||
<input class="form-control" ng-model="singleSelection().tempModel.name" autofocus="autofocus">
|
||||
</div>
|
||||
|
||||
<div ng-include data-src="'path-selector'" class="clearfix"></div>
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"cancel" | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"copy" | translate}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="compress">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form ng-submit="compress()">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{'compress' | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div ng-show="apiMiddleware.apiHandler.asyncSuccess">
|
||||
<div class="label label-success error-msg">{{'compression_started' | translate}}</div>
|
||||
</div>
|
||||
<div ng-hide="apiMiddleware.apiHandler.asyncSuccess">
|
||||
<div ng-hide="config.allowedActions.compressChooseName">
|
||||
{{'sure_to_start_compression_with' | translate}} <b>{{singleSelection().model.name}}</b> ?
|
||||
</div>
|
||||
<div ng-show="config.allowedActions.compressChooseName">
|
||||
<label class="radio">
|
||||
{{'enter_file_name_for_compression' | translate}}
|
||||
<span ng-include data-src="'selected-files-msg'"></span>
|
||||
</label>
|
||||
<input class="form-control" ng-model="temp.tempModel.name" autofocus="autofocus">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div ng-show="apiMiddleware.apiHandler.asyncSuccess">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"close" | translate}}</button>
|
||||
</div>
|
||||
<div ng-hide="apiMiddleware.apiHandler.asyncSuccess">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"cancel" | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-disabled="apiMiddleware.apiHandler.inprocess">{{'compress' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="extract" ng-init="singleSelection().emptyName()">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form ng-submit="extract()">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{'extract_item' | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div ng-show="apiMiddleware.apiHandler.asyncSuccess">
|
||||
<div class="label label-success error-msg">{{'extraction_started' | translate}}</div>
|
||||
</div>
|
||||
<div ng-hide="apiMiddleware.apiHandler.asyncSuccess">
|
||||
<label class="radio">{{'enter_folder_name_for_extraction' | translate}} <b>{{singleSelection().model.name}}</b></label>
|
||||
<input class="form-control" ng-model="singleSelection().tempModel.name" autofocus="autofocus">
|
||||
</div>
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div ng-show="apiMiddleware.apiHandler.asyncSuccess">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"close" | translate}}</button>
|
||||
</div>
|
||||
<div ng-hide="apiMiddleware.apiHandler.asyncSuccess">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"cancel" | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-disabled="apiMiddleware.apiHandler.inprocess">{{'extract' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="edit" ng-class="{'modal-fullscreen': fullscreen}">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<form ng-submit="edit()">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<button type="button" class="close fullscreen" ng-click="fullscreen=!fullscreen">
|
||||
<i class="glyphicon glyphicon-fullscreen"></i>
|
||||
<span class="sr-only">{{'toggle_fullscreen' | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{'edit_file' | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label class="radio bold">{{ singleSelection().model.fullPath() }}</label>
|
||||
<span class="label label-warning" ng-show="apiMiddleware.apiHandler.inprocess">{{'loading' | translate}} ...</span>
|
||||
<textarea class="form-control code" ng-model="singleSelection().tempModel.content" ng-show="!apiMiddleware.apiHandler.inprocess" autofocus="autofocus"></textarea>
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{'close' | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-show="config.allowedActions.edit" ng-disabled="apiMiddleware.apiHandler.inprocess">{{'edit' | translate}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="newfolder">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form ng-submit="createFolder()">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{'new_folder' | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label class="radio">{{'folder_name' | translate}}</label>
|
||||
<input class="form-control" ng-model="singleSelection().tempModel.name" autofocus="autofocus">
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"cancel" | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-disabled="apiMiddleware.apiHandler.inprocess">{{'create' | translate}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="uploadfile">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form>
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{"upload_files" | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label class="radio">
|
||||
{{"files_will_uploaded_to" | translate}}
|
||||
<b>/{{fileNavigator.currentPath.join('/')}}</b>
|
||||
</label>
|
||||
<button class="btn btn-default btn-block" ngf-select="$parent.addForUpload($files)" ngf-multiple="true">
|
||||
{{"select_files" | translate}}
|
||||
</button>
|
||||
|
||||
<div class="upload-list">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item" ng-repeat="(index, uploadFile) in $parent.uploadFileList">
|
||||
<button class="btn btn-sm btn-danger pull-right" ng-click="$parent.removeFromUpload(index)">
|
||||
×
|
||||
</button>
|
||||
<h5 class="list-group-item-heading">{{uploadFile.name}}</h5>
|
||||
<p class="list-group-item-text">{{uploadFile.size | humanReadableFileSize}}</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-show="apiMiddleware.apiHandler.inprocess">
|
||||
<em>{{"uploading" | translate}}... {{apiMiddleware.apiHandler.progress}}%</em>
|
||||
<div class="progress mb0">
|
||||
<div class="progress-bar active" role="progressbar" aria-valuenow="{{apiMiddleware.apiHandler.progress}}" aria-valuemin="0" aria-valuemax="100" style="width: {{apiMiddleware.apiHandler.progress}}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{"cancel" | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-disabled="!$parent.uploadFileList.length || apiMiddleware.apiHandler.inprocess" ng-click="uploadFiles()">{{'upload' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="changepermissions">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form ng-submit="changePermissions()">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{'change_permissions' | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table class="table mb0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{'permissions' | translate}}</th>
|
||||
<th class="col-xs-1 text-center">{{'read' | translate}}</th>
|
||||
<th class="col-xs-1 text-center">{{'write' | translate}}</th>
|
||||
<th class="col-xs-1 text-center">{{'exec' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="(permTypeKey, permTypeValue) in temp.tempModel.perms">
|
||||
<td>{{permTypeKey | translate}}</td>
|
||||
<td ng-repeat="(permKey, permValue) in permTypeValue" class="col-xs-1 text-center" ng-click="main()">
|
||||
<label class="col-xs-12">
|
||||
<input type="checkbox" ng-model="temp.tempModel.perms[permTypeKey][permKey]">
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="checkbox" ng-show="config.enablePermissionsRecursive && selectionHas('dir')">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="temp.tempModel.recursive"> {{'recursive' | translate}}
|
||||
</label>
|
||||
</div>
|
||||
<div class="clearfix mt10">
|
||||
<span class="label label-primary pull-left" ng-hide="temp.multiple">
|
||||
{{'original' | translate}}:
|
||||
{{temp.model.perms.toCode(selectionHas('dir') ? 'd':'-')}}
|
||||
({{temp.model.perms.toOctal()}})
|
||||
</span>
|
||||
<span class="label label-primary pull-right">
|
||||
{{'changes' | translate}}:
|
||||
{{temp.tempModel.perms.toCode(selectionHas('dir') ? 'd':'-')}}
|
||||
({{temp.tempModel.perms.toOctal()}})
|
||||
</span>
|
||||
</div>
|
||||
<div ng-include data-src="'error-bar'" class="clearfix"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{"cancel" | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" ng-disabled="">{{'change' | translate}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal animated fadeIn" id="selector" ng-controller="ModalFileManagerCtrl">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">{{"close" | translate}}</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{"select_destination_folder" | translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div>
|
||||
<div ng-include="config.tplPath + '/current-folder-breadcrumb.html'"></div>
|
||||
<div ng-include="config.tplPath + '/main-table-modal.html'"></div>
|
||||
<hr />
|
||||
<button class="btn btn-sm btn-default" ng-click="selectCurrent()">
|
||||
<i class="glyphicon"></i> {{"select_this" | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="apiMiddleware.apiHandler.inprocess">{{"close" | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/ng-template" id="path-selector">
|
||||
<div class="panel panel-primary mt10 mb0">
|
||||
<div class="panel-body">
|
||||
<div class="detail-sources">
|
||||
<div class="like-code mr5"><b>{{"selection" | translate}}:</b>
|
||||
<span ng-include="'selected-files-msg'"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-sources">
|
||||
<div class="like-code mr5">
|
||||
<b>{{"destination" | translate}}:</b> {{ getSelectedPath() }}
|
||||
</div>
|
||||
<a href="" class="label label-primary" ng-click="openNavigator(fileNavigator.currentPath)">
|
||||
{{'change' | translate}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="error-bar">
|
||||
<div class="label label-danger error-msg pull-left animated fadeIn" ng-show="apiMiddleware.apiHandler.error">
|
||||
<i class="glyphicon glyphicon-remove-circle"></i>
|
||||
<span>{{apiMiddleware.apiHandler.error}}</span>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="selected-files-msg">
|
||||
<span ng-show="temps.length == 1">
|
||||
{{singleSelection().model.name}}
|
||||
</span>
|
||||
<span ng-show="temps.length > 1">
|
||||
{{'these_elements' | translate:totalSelecteds()}}
|
||||
<a href="" class="label label-primary" ng-click="showDetails = !showDetails">
|
||||
{{showDetails ? '-' : '+'}} {{'details' | translate}}
|
||||
</a>
|
||||
</span>
|
||||
<div ng-show="temps.length > 1 && showDetails">
|
||||
<ul class="selected-file-details">
|
||||
<li ng-repeat="tempItem in temps">
|
||||
<b>{{tempItem.model.name}}</b>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</script>
|
||||
84
static/filemanager_app/src/templates/navbar.html
Normal file
84
static/filemanager_app/src/templates/navbar.html
Normal file
@@ -0,0 +1,84 @@
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-9 col-md-10 hidden-xs">
|
||||
<div ng-show="!config.breadcrumb">
|
||||
<a class="navbar-brand hidden-xs ng-binding" href="">angular-{{"filemanager" | translate}}</a>
|
||||
</div>
|
||||
<div ng-include="config.tplPath + '/current-folder-breadcrumb.html'" ng-show="config.breadcrumb">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3 col-md-2">
|
||||
<div class="navbar-collapse">
|
||||
<div class="navbar-form navbar-right text-right">
|
||||
<div class="pull-left visible-xs" ng-if="fileNavigator.currentPath.length">
|
||||
<button class="btn btn-primary btn-flat" ng-click="fileNavigator.upDir()">
|
||||
<i class="glyphicon glyphicon-chevron-left"></i>
|
||||
</button>
|
||||
{{fileNavigator.getCurrentFolderName() | strLimit : 12}}
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-flat btn-sm dropdown-toggle" type="button" id="dropDownMenuSearch" data-toggle="dropdown" aria-expanded="true">
|
||||
<i class="glyphicon glyphicon-search mr2"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu animated fast fadeIn pull-right" role="menu" aria-labelledby="dropDownMenuLang">
|
||||
<input type="text" class="form-control" ng-show="config.searchForm" placeholder="{{'search' | translate}}..." ng-model="$parent.query">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-flat btn-sm" ng-click="$parent.setTemplate('main-icons.html')" ng-show="$parent.viewTemplate !=='main-icons.html'" title="{{'icons' | translate}}">
|
||||
<i class="glyphicon glyphicon-th-large"></i>
|
||||
</button>
|
||||
|
||||
<button class="btn btn-flat btn-sm" ng-click="$parent.setTemplate('main-table.html')" ng-show="$parent.viewTemplate !=='main-table.html'" title="{{'list' | translate}}">
|
||||
<i class="glyphicon glyphicon-th-list"></i>
|
||||
</button>
|
||||
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-flat btn-sm dropdown-toggle" type="button" id="dropDownMenuLang" data-toggle="dropdown" aria-expanded="true">
|
||||
<i class="glyphicon glyphicon-globe mr2"></i>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu scrollable-menu animated fast fadeIn pull-right" role="menu" aria-labelledby="dropDownMenuLang">
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('en')">English</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('zh_tw')">正體中文</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('zh_cn')">简体中文</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('es')">Español</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('pt')">Portugues</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('fr')">Français</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('de')">Deutsch</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('he')">עברי</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('it')">italiano</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('sk')">Slovenčina</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('ru')">русский</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('ua')">український</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('tr')">Türkçe</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('fa')">فارسی</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="" ng-click="changeLanguage('pl')">Polski</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-flat btn-sm dropdown-toggle" type="button" id="more" data-toggle="dropdown" aria-expanded="true">
|
||||
<i class="glyphicon glyphicon-option-vertical"></i>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu scrollable-menu animated fast fadeIn pull-right" role="menu" aria-labelledby="more">
|
||||
<li role="presentation" ng-show="config.allowedActions.createFolder" ng-click="modal('newfolder') && prepareNewFolder()">
|
||||
<a href="" role="menuitem" tabindex="-1">
|
||||
<i class="glyphicon glyphicon-plus"></i> {{"new_folder" | translate}}
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" ng-show="config.allowedActions.upload" ng-click="modal('uploadfile')">
|
||||
<a href="" role="menuitem" tabindex="-1">
|
||||
<i class="glyphicon glyphicon-cloud-upload"></i> {{"upload_files" | translate}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
20
static/filemanager_app/src/templates/sidebar.html
Normal file
20
static/filemanager_app/src/templates/sidebar.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<ul class="nav nav-sidebar file-tree-root">
|
||||
<li ng-repeat="item in fileNavigator.history" ng-include="'folder-branch-item'" ng-class="{'active': item.name == fileNavigator.currentPath.join('/')}"></li>
|
||||
</ul>
|
||||
|
||||
<script type="text/ng-template" id="folder-branch-item">
|
||||
<a href="" ng-click="fileNavigator.folderClick(item.item)" class="animated fast fadeInDown">
|
||||
|
||||
<span class="point">
|
||||
<i class="glyphicon glyphicon-chevron-down" ng-show="isInThisPath(item.name)"></i>
|
||||
<i class="glyphicon glyphicon-chevron-right" ng-show="!isInThisPath(item.name)"></i>
|
||||
</span>
|
||||
|
||||
<i class="glyphicon glyphicon-folder-open mr2" ng-show="isInThisPath(item.name)"></i>
|
||||
<i class="glyphicon glyphicon-folder-close mr2" ng-show="!isInThisPath(item.name)"></i>
|
||||
{{ (item.name.split('/').pop() || fileNavigator.getBasePath().join('/') || '/') | strLimit : 30 }}
|
||||
</a>
|
||||
<ul class="nav nav-sidebar">
|
||||
<li ng-repeat="item in item.nodes" ng-include="'folder-branch-item'" ng-class="{'active': item.name == fileNavigator.currentPath.join('/')}"></li>
|
||||
</ul>
|
||||
</script>
|
||||
5
static/filemanager_app/src/templates/spinner.html
Normal file
5
static/filemanager_app/src/templates/spinner.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<div class="spinner-wrapper col-xs-12">
|
||||
<svg class="spinner-container" style="width:65px;height:65px" viewBox="0 0 44 44">
|
||||
<circle class="path" cx="22" cy="22" r="20" fill="none" stroke-width="4"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
Reference in New Issue
Block a user