diff --git a/bower.json b/bower.json index 24d76b8..f185680 100644 --- a/bower.json +++ b/bower.json @@ -1,22 +1,26 @@ { "name": "manticore", "version": "0.0.0", "dependencies": { - "angular": ">=1.2.*", - "json3": "~3.3.1", - "es5-shim": "~3.0.1", - "jquery": "~1.11.0", + "angular": "1.4.1", + "json3": "3.3.1", + "es5-shim": "4.1.7", + "jquery": "1.11.0", "bootstrap": "~3.1.1", - "angular-resource": ">=1.2.*", - "angular-cookies": ">=1.2.*", - "angular-sanitize": ">=1.2.*", - "angular-bootstrap": "~0.11.0", + "angular-resource": "1.4.1", + "angular-cookies": "1.4.1", + "angular-sanitize": "1.4.1", + "angular-bootstrap": "0.13.0", "font-awesome": ">=4.1.0", - "lodash": "~2.4.1", - "angular-ui-router": "~0.2.10" + "lodash": "3.9.3", + "angular-ui-router": "0.2.15", + "angular-file-upload": "1.1.5" }, "devDependencies": { - "angular-mocks": ">=1.2.*", - "angular-scenario": ">=1.2.*" + "angular-mocks": "1.4.1", + "angular-scenario": "1.4.1" + }, + "resolutions": { + "angular": "1.4.1" } } diff --git a/client/app/app.js b/client/app/app.js index 6b2c7a0..742c4cc 100644 --- a/client/app/app.js +++ b/client/app/app.js @@ -1,53 +1,54 @@ 'use strict'; angular.module('manticoreApp', [ 'ngCookies', 'ngResource', 'ngSanitize', 'ui.router', - 'ui.bootstrap' + 'ui.bootstrap', + 'angularFileUpload' ]) .config(function ($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider) { $urlRouterProvider .otherwise('/'); $locationProvider.html5Mode(true); $httpProvider.interceptors.push('authInterceptor'); }) .factory('authInterceptor', function ($rootScope, $q, $cookieStore, $location) { return { // Add authorization token to headers request: function (config) { config.headers = config.headers || {}; if ($cookieStore.get('token')) { config.headers.Authorization = 'Bearer ' + $cookieStore.get('token'); } return config; }, // Intercept 401s and redirect you to login responseError: function(response) { if(response.status === 401) { $location.path('/login'); // remove any stale tokens $cookieStore.remove('token'); return $q.reject(response); } else { return $q.reject(response); } } }; }) .run(function ($rootScope, $location, Auth) { // Redirect to login if route requires auth and you're not logged in $rootScope.$on('$stateChangeStart', function (event, next) { Auth.isLoggedInAsync(function(loggedIn) { if (next.authenticate && !loggedIn) { $location.path('/login'); } }); }); - }); \ No newline at end of file + }); diff --git a/client/app/app.styl b/client/app/app.styl index 26eee00..2fa5441 100644 --- a/client/app/app.styl +++ b/client/app/app.styl @@ -1,46 +1,47 @@ @import "font-awesome/css/font-awesome.css" @import "bootstrap/dist/css/bootstrap.css" // // Bootstrap Fonts // @font-face font-family: 'Glyphicons Halflings' src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot') src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff') format('woff'), url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); // // Font Awesome Fonts // @font-face font-family: 'FontAwesome' src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?v=4.1.0') src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), url('../bower_components/font-awesome/fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), url('../bower_components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), url('../bower_components/font-awesome/fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg'); font-weight: normal font-style: normal // // App-wide Styles // .browsehappy background #ccc color #000 margin 0.2em 0 padding 0.2em 0 // Component styles are injected through grunt // injector @import 'account/login/login.styl'; @import 'admin/admin.styl'; @import 'main/main.styl'; +@import 'import/import.styl'; @import 'modal/modal.styl'; // endinjector \ No newline at end of file diff --git a/client/app/main/main.styl b/client/app/main/main.styl index 7ace56d..dab28f8 100644 --- a/client/app/main/main.styl +++ b/client/app/main/main.styl @@ -1,26 +1,29 @@ .document-form margin 20px 0 #banner border-bottom none margin-top -20px #banner h1 font-size 60px letter-spacing -1px line-height 1 .hero-unit color #000 padding 30px 15px position relative text-align center text-shadow 0 1px 0 rgba(0, 0, 0, 0.1) img max-width: 100%; .footer border-top 1px solid #E5E5E5 margin-top 70px padding 30px 0 text-align center + +.btn + border-radius 0 !important diff --git a/client/components/import/import.controller.js b/client/components/import/import.controller.js new file mode 100644 index 0000000..a17caa8 --- /dev/null +++ b/client/components/import/import.controller.js @@ -0,0 +1,25 @@ +'use strict'; + +angular.module('manticoreApp') + .controller('ImportCtrl', function ($scope, FileUploader) { + var uploader = new FileUploader({ + url: '/import', + removeAfterUpload: true, + autoUpload: true + }); + + uploader.filters.push({ + name: 'sizeFilter', + fn: function (item) { + return item.size <= 10485760; // 10 Megabytes + } + }); + uploader.filters.push({ + name: 'typeFilter', + fn: function (item) { + return item.type === 'application/vnd.oasis.opendocument.text'; + } + }); + + $scope.uploader = uploader; + }); diff --git a/client/components/import/import.jade b/client/components/import/import.jade new file mode 100644 index 0000000..35ab50a --- /dev/null +++ b/client/components/import/import.jade @@ -0,0 +1,79 @@ +div.import-box(ng-controller='ImportCtrl') + .row.upload-widget + div.upload-button( + type='button' + nv-file-over='' + uploader='uploader' + ) + input( + type='file' + nv-file-select='' + uploader='uploader' + multiple + ) + | Click to select files to upload, or drag them here + + .row(ng-hide='!uploader.getNotUploadedItems().length') + table.table + thead + tr + th(width='50%') Name + th(ng-show='uploader.isHTML5') Size + th(ng-show='uploader.isHTML5') Progress + th.status Status + th.actions Actions + tbody + tr(ng-repeat='item in uploader.queue') + td.name-cell + span(tooltip='{{item.file.name}}' data-container='body') + | {{item.file.name}} + td(ng-show='uploader.isHTML5' nowrap) + | {{item.file.size/1024/1024|number:2}} MB + td(ng-show='uploader.isHTML5') + progressbar(value='item.progress') {{item.progress}}% + td.status.text-center + span(ng-show='item.isSuccess') + i.glyphicon.glyphicon-ok + span(ng-show='item.isCancel') + i.glyphicon.glyphicon-ban-circle + span(ng-show='item.isError') + i.glyphicon.glyphicon-remove + td.actions(nowrap) + button.btn.btn-success.btn-xs( + ng-click='item.upload()' + ng-disabled='item.isReady || item.isUploading || item.isSuccess' + ) + i.glyphicon.glyphicon-upload + button.btn.btn-warning.btn-xs( + ng-click='item.cancel()' + ng-disabled='!item.isUploading' + ) + i.glyphicon.glyphicon-ban-circle + button.btn.btn-danger.btn-xs( + ng-click='item.remove()' + ) + i.glyphicon.glyphicon-trash + //- div.progress-overall + progressbar(value='uploader.progress') {{uploader.progress}}% + div.btn-group.btn-group-justified + div.btn.btn-success.btn-s( + type='button' + ng-click='uploader.uploadAll()' + ng-disabled='!uploader.getNotUploadedItems().length' + ) + span.glyphicon.glyphicon-upload + | Upload all + div.btn.btn-warning.btn-s( + type='button' + ng-click='uploader.cancelAll()' + ng-disabled='!uploader.isUploading' + ) + span.glyphicon.glyphicon-ban-circle + | Cancel all + div.btn.btn-danger.btn-s( + type='button' + ng-click='uploader.removeAll()' + ng-disabled='!uploader.queue.length' + ) + span.glyphicon.glyphicon-trash + | Remove all diff --git a/client/components/import/import.styl b/client/components/import/import.styl new file mode 100644 index 0000000..993713e --- /dev/null +++ b/client/components/import/import.styl @@ -0,0 +1,55 @@ +.import-box + width 400px + .row + margin: 0 + +.upload-widget + margin-left 5px !important + margin-right 5px !important + +.upload-button + width 100% + position relative + overflow hidden + padding 20px + border 2px dashed lightgray + border-radius 5px + cursor pointer + text-align center + background-color #eee + input[type=file] + opacity 0; + position absolute + top 0 + bottom 0 + outline none + cursor inherit + display block + width 100% + height: 100% + + &:hover + border 2px dashed red + background-color #ddd + +td .progress + margin-bottom 0 + +.progress-overall progress + padding-left 8px + padding-right 8px + +th, td + border-bottom-width 1px !important + +.table .actions + display none +.status + display none + +.name-cell + max-width 0 + word-wrap break-word + text-overflow ellipsis + overflow hidden + white-space nowrap diff --git a/client/components/navbar/navbar.jade b/client/components/navbar/navbar.jade index f39c338..3fe98cb 100644 --- a/client/components/navbar/navbar.jade +++ b/client/components/navbar/navbar.jade @@ -1,34 +1,37 @@ div.navbar.navbar-default.navbar-static-top(ng-controller='NavbarCtrl') div.container div.navbar-header button.navbar-toggle(type='button', ng-click='isCollapsed = !isCollapsed') span.sr-only Toggle navigation span.icon-bar span.icon-bar span.icon-bar a.navbar-brand(href='/') manticore div#navbar-main.navbar-collapse.collapse(collapse='isCollapsed') ul.nav.navbar-nav - li(ng-repeat='item in menu', ng-class='{active: isActive(item.link)}') - a(ng-href='{{item.link}}') {{item.title}} - li(ng-show='isAdmin()', ng-class='{active: isActive("/admin")}') a(href='/admin') Admin + li.dropdown(ng-show='isLoggedIn() && isActive("/")' dropdown auto-close='disabled') + a.dropdown-toggle(href='#' dropdown-toggle role='button') + | Import + span.caret + div.dropdown-menu(ng-include='"components/import/import.html"') + ul.nav.navbar-nav.navbar-right li(ng-hide='isLoggedIn()', ng-class='{active: isActive("/signup")}') a(href='/signup') Sign up li(ng-hide='isLoggedIn()', ng-class='{active: isActive("/login")}') a(href='/login') Login li(ng-show='isLoggedIn()') p.navbar-text Hello {{ getCurrentUser().name }} li(ng-show='isLoggedIn()', ng-class='{active: isActive("/settings")}') a(href='/settings') span.glyphicon.glyphicon-cog li(ng-show='isLoggedIn()', ng-class='{active: isActive("/logout")}') - a(href='', ng-click='logout()') Logout \ No newline at end of file + a(href='', ng-click='logout()') Logout diff --git a/client/index.html b/client/index.html index 14786c6..7cc0531 100644 --- a/client/index.html +++ b/client/index.html @@ -1,68 +1,70 @@
- + + +