diff --git a/dist/main.css b/dist/main.css index 2c174bd..e2ed91e 100644 Binary files a/dist/main.css and b/dist/main.css differ diff --git a/dist/main.js b/dist/main.js index 3ca47e1..124f86c 100644 Binary files a/dist/main.js and b/dist/main.js differ diff --git a/src/bower.json b/src/bower.json index 12cfb2d..708452c 100644 --- a/src/bower.json +++ b/src/bower.json @@ -5,6 +5,7 @@ "jQuery": "~2.1.3", "js-md5": "~1.1.0", "mousetrap": "~1.4.6", - "basicContext": "~2.0.2" + "basicContext": "~2.0.2", + "basicModal": "~2.0.0" } } diff --git a/src/gulpfile.js b/src/gulpfile.js index 79d1444..b2a4411 100644 --- a/src/gulpfile.js +++ b/src/gulpfile.js @@ -74,6 +74,7 @@ paths.main = { 'bower_components/mousetrap/mousetrap.min.js', 'bower_components/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js', 'bower_components/basicContext/dist/basicContext.min.js', + 'bower_components/basicModal/dist/basicModal.min.js', '../src/scripts/*.js' ], coffee: [ @@ -88,6 +89,7 @@ paths.main = { ], styles: [ 'bower_components/basicContext/src/styles/main.scss', + 'bower_components/basicModal/src/styles/main.scss', '../src/styles/main.scss' ] } diff --git a/src/scripts/album.js b/src/scripts/album.js index cd4a161..3b28656 100644 --- a/src/scripts/album.js +++ b/src/scripts/album.js @@ -99,116 +99,138 @@ album.parse = function() { album.add = function() { - var title, - params, - buttons, - isNumber = function(n) { return !isNaN(parseFloat(n)) && isFinite(n) }; + var action; - buttons = [ - ['Create Album', function() { + action = function(data) { - title = $('.message input.text').val(); + var params, + isNumber = function(n) { return !isNaN(parseFloat(n)) && isFinite(n) }; - if (title.length===0) title = 'Untitled'; + basicModal.close(); - modal.close(); + if (data.title.length===0) data.title = 'Untitled'; - params = 'addAlbum&title=' + escape(encodeURI(title)); - lychee.api(params, function(data) { + params = 'addAlbum&title=' + escape(encodeURI(data.title)); + lychee.api(params, function(data) { - // Avoid first album to be true - if (data===true) data = 1; + // Avoid first album to be true + if (data===true) data = 1; - if (data!==false&&isNumber(data)) { - albums.refresh(); - lychee.goto(data); - } else { - lychee.error(null, params, data); - } + if (data!==false&&isNumber(data)) { + albums.refresh(); + lychee.goto(data); + } else { + lychee.error(null, params, data); + } - }); + }); - }], - ['Cancel', function() {}] - ]; + } - modal.show('New Album', "Enter a title for this album: ", buttons); + basicModal.show({ + body: "
Enter a title for the new album:
", + buttons: { + action: { + title: 'Create Album', + fn: action + }, + cancel: { + title: 'Cancel', + fn: basicModal.close + } + } + }); } album.delete = function(albumIDs) { - var params, - buttons, - albumTitle; + var action = {}, + cancel = {}, + msg = '', + albumTitle = ''; if (!albumIDs) return false; if (albumIDs instanceof Array===false) albumIDs = [albumIDs]; - buttons = [ - ['', function() { + action.fn = function() { - params = 'deleteAlbum&albumIDs=' + albumIDs; - lychee.api(params, function(data) { + var params; - if (visible.albums()) { + basicModal.close(); - albumIDs.forEach(function(id) { - albums.json.num--; - view.albums.content.delete(id); - delete albums.json.content[id]; - }); + params = 'deleteAlbum&albumIDs=' + albumIDs; + lychee.api(params, function(data) { - } else { + if (visible.albums()) { - albums.refresh(); - lychee.goto(''); + albumIDs.forEach(function(id) { + albums.json.num--; + view.albums.content.delete(id); + delete albums.json.content[id]; + }); - } + } else { - if (data!==true) lychee.error(null, params, data); + albums.refresh(); + lychee.goto(''); - }); + } - }], - ['', function() {}] - ]; + if (data!==true) lychee.error(null, params, data); + + }); + + } if (albumIDs.toString()==='0') { - buttons[0][0] = 'Clear Unsorted'; - buttons[1][0] = 'Keep Unsorted'; + action.title = 'Clear Unsorted'; + cancel.title = 'Keep Unsorted'; - modal.show('Clear Unsorted', "Are you sure you want to delete all photos from 'Unsorted'?Are you sure you want to delete all photos from 'Unsorted'?
This action can't be undone!
Are you sure you want to delete the album '" + albumTitle + "' and all of the photos it contains? This action can't be undone!
"; } else { - buttons[0][0] = 'Delete Albums and Photos'; - buttons[1][0] = 'Keep Albums'; + action.title = 'Delete Albums and Photos'; + cancel.title = 'Keep Albums'; - modal.show('Delete Albums', "Are you sure you want to delete all " + albumIDs.length + " selected albums and all of the photos they contain? This action can't be undone!", buttons); + msg = "Are you sure you want to delete all " + albumIDs.length + " selected albums and all of the photos they contain? This action can't be undone!
"; } + basicModal.show({ + body: msg, + buttons: { + action: { + title: action.title, + fn: action.fn, + class: 'red' + }, + cancel: { + title: cancel.title, + fn: basicModal.close + } + } + }); + } album.setTitle = function(albumIDs) { var oldTitle = '', - newTitle, - params, - buttons; + input; if (!albumIDs) return false; if (albumIDs instanceof Array===false) albumIDs = [albumIDs]; @@ -224,50 +246,68 @@ album.setTitle = function(albumIDs) { } - buttons = [ - ['Set Title', function() { + action = function(data) { - // Get input - newTitle = $('.message input.text').val(); + var params, + newTitle; - // Remove html from input - newTitle = lychee.removeHTML(newTitle); + basicModal.close(); - // Set to Untitled when empty - newTitle = (newTitle==='') ? 'Untitled' : newTitle; + // Get input + newTitle = data.title; - if (visible.album()) { + // Remove html from input + newTitle = lychee.removeHTML(newTitle); - album.json.title = newTitle; - view.album.title(); + // Set to Untitled when empty + newTitle = (newTitle==='') ? 'Untitled' : newTitle; - if (albums.json) { - var id = albumIDs[0]; - albums.json.content[id].title = newTitle; - } + if (visible.album()) { - } else if (visible.albums()) { - - albumIDs.forEach(function(id) { - albums.json.content[id].title = newTitle; - view.albums.content.title(id); - }); + album.json.title = newTitle; + view.album.title(); + if (albums.json) { + var id = albumIDs[0]; + albums.json.content[id].title = newTitle; } - params = 'setAlbumTitle&albumIDs=' + albumIDs + '&title=' + escape(encodeURI(newTitle)); - lychee.api(params, function(data) { - - if (data!==true) lychee.error(null, params, data); + } else if (visible.albums()) { + albumIDs.forEach(function(id) { + albums.json.content[id].title = newTitle; + view.albums.content.title(id); }); - }], - ['Cancel', function() {}] - ]; + } - if (albumIDs.length===1) modal.show('Set Title', "Enter a new title for this album: ", buttons); - else modal.show('Set Titles', "Enter a title for all " + albumIDs.length + " selected album: ", buttons); + params = 'setAlbumTitle&albumIDs=' + albumIDs + '&title=' + escape(encodeURI(newTitle)); + lychee.api(params, function(data) { + + if (data!==true) lychee.error(null, params, data); + + }); + + } + + input = ""; + + if (albumIDs.length===1) msg = "Enter a new title for this album: " + msg + "
"; + else msg = "Enter a title for all " + albumIDs.length + " selected albums: " + msg +"
"; + + basicModal.show({ + body: msg, + buttons: { + action: { + title: 'Set title', + fn: action + }, + cancel: { + title: 'Cancel', + fn: basicModal.close + } + } + }); } diff --git a/src/scripts/init.js b/src/scripts/init.js index 64d09d8..611e752 100755 --- a/src/scripts/init.js +++ b/src/scripts/init.js @@ -71,8 +71,8 @@ $(document).ready(function() { Mousetrap .bind('left', function() { if (visible.photo()) $('#imageview a#previous').click() }) .bind('right', function() { if (visible.photo()) $('#imageview a#next').click() }) - .bind(['u', 'ctrl+u'], function() { $('#upload_files').click() }) - .bind(['s', 'ctrl+s', 'f', 'ctrl+f'], function(e) { + .bind('u', function() { $('#upload_files').click() }) + .bind(['s', 'f'], function(e) { if (visible.photo()) { header.dom('#button_star').click(); } else if (visible.albums()) { @@ -80,23 +80,23 @@ $(document).ready(function() { header.dom('#search').focus(); } }) - .bind(['r', 'ctrl+r'], function(e) { + .bind('r', function(e) { e.preventDefault(); if (visible.album()) album.setTitle(album.getID()); else if (visible.photo()) photo.setTitle([photo.getID()]); }) - .bind(['d', 'ctrl+d'], function(e) { + .bind('d', function(e) { e.preventDefault(); if (visible.photo()) photo.setDescription(photo.getID()); else if (visible.album()) album.setDescription(album.getID()); }) - .bind(['t', 'ctrl+t'], function(e) { + .bind('t', function(e) { if (visible.photo()) { e.preventDefault(); photo.editTags([photo.getID()]); } }) - .bind(['i', 'ctrl+i'], function() { + .bind('i', function() { if (visible.infobox()) view.infobox.hide(); else if (visible.multiselect()) return false; else if (visible.infoboxbutton()) view.infobox.show(); @@ -111,12 +111,12 @@ $(document).ready(function() { }); Mousetrap.bindGlobal('enter', function() { - if ($('.message .button.active').length) $('.message .button.active').addClass('pressed').click() + if (basicModal.visible()===true) basicModal.action(); }); Mousetrap.bindGlobal(['esc', 'command+up'], function(e) { e.preventDefault(); - if (visible.message()&&$('.message .close').length>0) modal.close(); + if (basicModal.visible()===true) basicModal.cancel(); else if (visible.contextMenu()) contextMenu.close(); else if (visible.infobox()) view.infobox.hide(); else if (visible.photo()) lychee.goto(album.getID()); diff --git a/src/scripts/lychee.js b/src/scripts/lychee.js index bbbbb0e..4349ccf 100644 --- a/src/scripts/lychee.js +++ b/src/scripts/lychee.js @@ -274,12 +274,12 @@ lychee.setMode = function(mode) { .off('drop'); Mousetrap - .unbind(['u', 'ctrl+u']) - .unbind(['s', 'ctrl+s']) - .unbind(['f', 'ctrl+f']) - .unbind(['r', 'ctrl+r']) - .unbind(['d', 'ctrl+d']) - .unbind(['t', 'ctrl+t']) + .unbind('u') + .unbind('s') + .unbind('f') + .unbind('r') + .unbind('d') + .unbind('t') .unbind(['command+backspace', 'ctrl+backspace']) .unbind(['command+a', 'ctrl+a']); @@ -290,7 +290,7 @@ lychee.setMode = function(mode) { } else if (mode==='view') { - Mousetrap.unbind('esc'); + Mousetrap.unbind(['esc', 'command+up']); $('#button_back, a#next, a#previous').remove(); $('.no_content').remove(); diff --git a/src/scripts/upload.js b/src/scripts/upload.js index fbed445..2f8b1e4 100755 --- a/src/scripts/upload.js +++ b/src/scripts/upload.js @@ -229,86 +229,36 @@ upload.start = { url: function() { var albumID = album.getID(), - params, - extension, - buttons, - link, - files = []; + action; if (albumID===false) albumID = 0; - buttons = [ - ['Import', function() { + action = function(data) { - link = $('.message input.text').val(); + var params, + extension, + files = []; - if (link&&link.length>3) { + basicModal.close(); - extension = link.split('.').pop(); - if (extension!=='jpeg'&&extension!=='jpg'&&extension!=='png'&&extension!=='gif'&&extension!=='webp') { - loadingBar.show('error', 'The file format of this link is not supported.'); - return false; - } + if (data.link&&data.link.length>3) { - files[0] = { - name: link, - supported: true - } - - upload.show('Importing URL', files, function() { - $('.upload_message .rows .row .status').html('Importing'); - }); - - params = 'importUrl&url=' + escape(encodeURI(link)) + '&albumID=' + albumID; - lychee.api(params, function(data) { - - upload.close(); - upload.notify('Import complete'); - - albums.refresh(); - - if (album.getID()===false) lychee.goto('0'); - else album.load(albumID); - - if (data!==true) lychee.error(null, params, data); - - }); - - } else loadingBar.show('error', 'Link to short or too long. Please try another one!'); - - }], - ['Cancel', function() {}] - ]; - - modal.show('Import from Link', "Please enter the direct link to a photo to import it: ", buttons); - - }, - - server: function() { - - var albumID = album.getID(), - params, - buttons, - files = [], - path; - - if (albumID===false) albumID = 0; - - buttons = [ - ['Import', function() { - - path = $('.message input.text').val(); + extension = data.link.split('.').pop(); + if (extension!=='jpeg'&&extension!=='jpg'&&extension!=='png'&&extension!=='gif'&&extension!=='webp') { + loadingBar.show('error', 'The file format of this link is not supported.'); + return false; + } files[0] = { - name: path, + name: data.link, supported: true - }; + } - upload.show('Importing from server', files, function() { + upload.show('Importing URL', files, function() { $('.upload_message .rows .row .status').html('Importing'); }); - params = 'importServer&albumID=' + albumID + '&path=' + escape(encodeURI(path)); + params = 'importUrl&url=' + escape(encodeURI(data.link)) + '&albumID=' + albumID; lychee.api(params, function(data) { upload.close(); @@ -316,24 +266,90 @@ upload.start = { albums.refresh(); - if (data==='Notice: Import only contains albums!') { - if (visible.albums()) lychee.load(); - else lychee.goto(''); - } - else if (album.getID()===false) lychee.goto('0'); + if (album.getID()===false) lychee.goto('0'); else album.load(albumID); - if (data==='Notice: Import only contains albums!') return true; - else if (data==='Warning: Folder empty!') lychee.error('Folder empty. No photos imported!', params, data); - else if (data!==true) lychee.error(null, params, data); + if (data!==true) lychee.error(null, params, data); }); - }], - ['Cancel', function() {}] - ]; + } else loadingBar.show('error', 'Link to short or too long. Please try another one!'); - modal.show('Import from Server', "This action will import all photos, folders and sub-folders which are located in the following directory. The original files will be deleted after the import when possible. ", buttons); + } + + basicModal.show({ + body: "Please enter the direct link to a photo to import it:
", + buttons: { + action: { + title: 'Import', + fn: action + }, + cancel: { + title: 'Cancel', + fn: basicModal.close + } + } + }); + + }, + + server: function() { + + var albumID = album.getID(), + action; + + if (albumID===false) albumID = 0; + + action = function(data) { + + var params, + files = []; + + files[0] = { + name: data.path, + supported: true + }; + + upload.show('Importing from server', files, function() { + $('.upload_message .rows .row .status').html('Importing'); + }); + + params = 'importServer&albumID=' + albumID + '&path=' + escape(encodeURI(data.path)); + lychee.api(params, function(data) { + + upload.close(); + upload.notify('Import complete'); + + albums.refresh(); + + if (data==='Notice: Import only contains albums!') { + if (visible.albums()) lychee.load(); + else lychee.goto(''); + } + else if (album.getID()===false) lychee.goto('0'); + else album.load(albumID); + + if (data==='Notice: Import only contains albums!') return true; + else if (data==='Warning: Folder empty!') lychee.error('Folder empty. No photos imported!', params, data); + else if (data!==true) lychee.error(null, params, data); + + }); + + } + + basicModal.show({ + body: "This action will import all photos, folders and sub-folders which are located in the following directory. The original files will be deleted after the import when possible.
", + buttons: { + action: { + title: 'Import', + fn: action + }, + cancel: { + title: 'Cancel', + fn: basicModal.close + } + } + }); }, diff --git a/src/styles/_content.scss b/src/styles/_content.scss index 185717b..b33ab7d 100644 --- a/src/styles/_content.scss +++ b/src/styles/_content.scss @@ -136,7 +136,7 @@ .iconic { fill: #fff; width: 21px; - filter: drop-shadow( 0 -1px 0 black(.1) ); + filter: drop-shadow($shadowLight); } } @@ -148,7 +148,7 @@ width: 100%; opacity: 0; border-top: 1px solid white(.02); - box-shadow: 0 -1px 0 0 black(.2); + box-shadow: $shadow; &:first-child { margin-top: 10px; @@ -162,7 +162,7 @@ color: white(.6); font-size: 14px; font-weight: bold; - text-shadow: 0 -1px 0 black(.1); + text-shadow: $shadow; } } diff --git a/src/styles/_contextmenu.scss b/src/styles/_contextmenu.scss index ce1e003..3c1d705 100644 --- a/src/styles/_contextmenu.scss +++ b/src/styles/_contextmenu.scss @@ -15,9 +15,9 @@ /* Item ------------------------------------------------*/ tr { margin-bottom: 2px; - color: #eee; + color: white(.9); font-size: 14px; - text-shadow: 0 -1px 0px black(.1); + text-shadow: $shadowLight; &.separator { background: black(.2); @@ -28,7 +28,7 @@ tr td { padding: 7px 25px 6px 12px; min-width: auto; - color: #fff; + color: white(1); border-radius: 0; transition: none; diff --git a/src/styles/_etc.scss b/src/styles/_etc.scss index fffa722..7b0fbb9 100644 --- a/src/styles/_etc.scss +++ b/src/styles/_etc.scss @@ -12,9 +12,13 @@ } /* Vars ------------------------------------------------*/ +// Properties +$shadowLight: 0 -1px 0 black(.1); +$shadow: 0 -1px 0 black(.2); + // Colors $colorBlue: #2293EC; -$colorRed: #d02a32; +$colorRed: #d92c34; // Animations $timing: cubic-bezier(.51, .92, .24, 1); diff --git a/src/styles/_header.scss b/src/styles/_header.scss index bd15322..7c0508f 100644 --- a/src/styles/_header.scss +++ b/src/styles/_header.scss @@ -42,7 +42,7 @@ header { font-size: 16px; font-weight: bold; text-align: center; - text-shadow: 0 -1px 0 black(.2); + text-shadow: $shadow; z-index: 1; .iconic { @@ -50,7 +50,7 @@ header { margin: 0 0 0 10px; width: 10px; fill: white(.5); - filter: drop-shadow(0 -1px 0 black(.2)); + filter: drop-shadow($shadow); transition: fill .2s ease-out; } @@ -84,7 +84,7 @@ header { .iconic { fill: white(.5); - filter: drop-shadow(0 -1px 0 black(.2)); + filter: drop-shadow($shadow); transition: fill .2s ease-out; } @@ -149,7 +149,7 @@ header { margin: 13px 9px; color: #888; font-size: 13px; - text-shadow: 0 -1px 0 black(.2); + text-shadow: $shadow; border-radius: 100px; display: none; cursor: pointer; diff --git a/src/styles/_infobox.scss b/src/styles/_infobox.scss index b3d8f0f..ece2eb7 100644 --- a/src/styles/_infobox.scss +++ b/src/styles/_infobox.scss @@ -43,7 +43,7 @@ .iconic { fill: white(.5); - filter: drop-shadow(0 -1px 0 black(.2)); + filter: drop-shadow($shadow); transition: fill .2s ease-out; } @@ -73,7 +73,7 @@ font-size: 16px; font-weight: bold; text-align: center; - text-shadow: 0 -1px 0 black(.2); + text-shadow: $shadow; } .header .close { @@ -84,7 +84,7 @@ .iconic { fill: #888; - filter: drop-shadow(0 -1px 0 black(.2)); + filter: drop-shadow($shadow); transition: fill .2s ease-out; } @@ -97,7 +97,7 @@ padding: 12px 0 8px; width: 100%; border-top: 1px solid white(.02); - box-shadow: 0 -1px 0 0 black(.2); + box-shadow: $shadow; h1 { margin: 0 0 0 20px; diff --git a/src/styles/_message.scss b/src/styles/_message.scss index a5b0695..26076d7 100644 --- a/src/styles/_message.scss +++ b/src/styles/_message.scss @@ -2,6 +2,80 @@ * @copyright 2014 by Tobias Reich */ +.basicModalContainer { + background-color: black(.85); +} + +.basicModal { + + background: linear-gradient(to bottom, #444, #333); + + border: 1px solid black(.7); + border-bottom: 1px solid black(.8); + box-shadow: 0 1px 4px black(.2), inset 0 1px 0 white(.05); + + p { + display: block; + padding: 42px 30px 40px; + color: white(.9); + font-size: 14px; + text-align: left; + text-shadow: $shadow; + line-height: 20px; + + b { + font-weight: bold; + color: white(1); + } + + a { + color: white(.9); + text-decoration: none; + border-bottom: 1px dashed #888; + } + } + + .basicModal__button { + padding: 13px 0 15px; + background: black(.02); + color: white(.5); + text-shadow: $shadow; + border-top: 1px solid black(.2); + box-shadow: inset 0 1px 0 white(.02); + + &:hover { background: white(.02); } + + &:active, + &--active { background: black(.1); } + + basicModal__action { + color: $colorBlue; + box-shadow: inset 0 1px 0 white(.02), inset 1px 0 0 black(.2); + } + + basicModal__action.red { color: $colorRed; } + + } + + /* Input ------------------------------------------------*/ + input.text { + width: calc(100% - 4px); + padding: 9px 2px; + margin: 10px 0; + background-color: transparent; + color: #fff; + text-shadow: $shadow; + border: none; + border-bottom: 1px solid black(.4); + border-radius: 0; + box-shadow: 0 1px 0 white(.08); + outline: none; + + &:focus { border-bottom-color: $colorBlue; } + } + +} + .message_overlay { position: fixed; width: 100%; @@ -112,7 +186,7 @@ margin-top: 10px; background-color: transparent; color: #fff; - text-shadow: 0 -1px 0 black(.3); + text-shadow: $shadow; border: none; box-shadow: 0 1px 0 white(.1); border-bottom: 1px solid #222;