diff --git a/ui (gen4)/css/layout.css b/ui (gen4)/css/layout.css index 56b6dc2b..a38ba22c 100644 --- a/ui (gen4)/css/layout.css +++ b/ui (gen4)/css/layout.css @@ -209,11 +209,13 @@ button:hover { width: 100%; height: 100%; } +.viewer:empty:before, +.viewer:empty:after, .ribbon-set:empty:before, .ribbon-set:empty:after { display: block; position: absolute; - content: "Nothing loaded..."; + content: attr(empty-msg); top: 50%; left: 0px; width: 100%; @@ -227,8 +229,9 @@ button:hover { opacity: 0.9; cursor: hand; } +.viewer:empty:after, .ribbon-set:empty:after { - content: "Press 'O' to load, 'F1' for help or '?' for keyboard mappings."; + content: attr(empty-help); margin-top: 5px; font-weight: normal; font-size: 16px; diff --git a/ui (gen4)/css/layout.less b/ui (gen4)/css/layout.less index 774466d6..da9a7020 100755 --- a/ui (gen4)/css/layout.less +++ b/ui (gen4)/css/layout.less @@ -320,15 +320,28 @@ button:hover { /* empty ribbon set... */ .ribbon-set:empty { - width: 100%; - height: 100%; + width: 100% !important; + height: 100% !important; + + // place at top left corner... + top: 0px !important; + left: 0px !important; + + -webkit-transform: none !important; + -moz-transform: none !important; + -o-transform: none !important; + -ms-transform: none !important; + transform: none !important; } +.viewer:empty:before, +.viewer:empty:after, .ribbon-set:empty:before, .ribbon-set:empty:after { display: block; position: absolute; - content: "Nothing loaded..."; + //content: "Nothing loaded..."; + content: attr(empty-msg); top: 50%; left: 0px; @@ -346,9 +359,11 @@ button:hover { cursor: hand; } +.viewer:empty:after, .ribbon-set:empty:after { - content: "Press 'O' to load, 'F1' for help or '?' for keyboard mappings."; + //content: "Press 'O' to load, 'F1' for help or '?' for keyboard mappings."; + content: attr(empty-help); margin-top: 5px; font-weight: normal; diff --git a/ui (gen4)/data.js b/ui (gen4)/data.js index d11f2584..996f7bce 100755 --- a/ui (gen4)/data.js +++ b/ui (gen4)/data.js @@ -608,7 +608,8 @@ var DataPrototype = { // be truncated... for(; i >= 0 && i < this.order.length; i+=step){ var cur = list[i] - if(cur == null){ + // skip undefined or unloaded images... + if(cur == null || this.getRibbon(cur) == null){ continue } offset -= 1 @@ -876,6 +877,9 @@ var DataPrototype = { // image gid... } else { var i = this.order.indexOf(target) + if(i == -1){ + return null + } var k for(k in ribbons){ if(ribbons[k][i] != null){ @@ -1872,6 +1876,28 @@ var DataWithTagsPrototype = { return res }, + crop: function(){ + var crop = DataWithTagsPrototype.__proto__.crop.apply(this, arguments) + + // make the tags mutable... + if(this.tags != null){ + crop.tags = this.tags + } + + return crop + }, + clone: function(){ + var clone = DataWithTagsPrototype.__proto__.clone.apply(this, arguments) + + if(this.tags != null){ + clone.tags = {} + for(var k in this.tags){ + clone.tags[k] = this.tags[k].slice() + } + } + + return clone + }, sortTags: function(){ var that = this diff --git a/ui (gen4)/index.html b/ui (gen4)/index.html index 3a977236..31d978cb 100755 --- a/ui (gen4)/index.html +++ b/ui (gen4)/index.html @@ -92,6 +92,7 @@ } + /* DEBUG stuff... */ .container-center { position: absolute; @@ -156,7 +157,7 @@ require('nw.gui').Window.get().showDevTools() -
+ @@ -176,7 +177,9 @@ require('nw.gui').Window.get().showDevTools() -
+ + +
diff --git a/ui (gen4)/ribbons.js b/ui (gen4)/ribbons.js index 833ecaf8..2087a8ac 100755 --- a/ui (gen4)/ribbons.js +++ b/ui (gen4)/ribbons.js @@ -18,13 +18,6 @@ var object = require('object') var data = require('data') var images = require('images') - - -// XXX STUB -var IMAGE_UPDATERS = -module.IMAGE_UPDATERS = [] - - var IMAGE = '.image:not(.clone)' var RIBBON = '.ribbon:not(.clone)' @@ -172,11 +165,12 @@ var RibbonsPrototype = { if(now){ target.removeClass('no-transitions') var t = target[0] - getComputedStyle(t).webkitTransition - getComputedStyle(t).mozTransition - getComputedStyle(t).msTransition - getComputedStyle(t).oTransition - getComputedStyle(t).transition + var s = getComputedStyle(t) + s.webkitTransition + s.mozTransition + s.msTransition + s.oTransition + s.transition // on next exec frame... } else { @@ -184,11 +178,12 @@ var RibbonsPrototype = { setTimeout(function(){ target.removeClass('no-transitions')}, 0) var t = target[0] - getComputedStyle(t).webkitTransition - getComputedStyle(t).mozTransition - getComputedStyle(t).msTransition - getComputedStyle(t).oTransition - getComputedStyle(t).transition + var s = getComputedStyle(t) + s.webkitTransition + s.mozTransition + s.msTransition + s.oTransition + s.transition } return this @@ -889,8 +884,7 @@ var RibbonsPrototype = { // Loading and updating... - // XXX this needs: - // IMAGE_UPDATERS -- make it a callback/event (node/jquery)... + // XXX is .__image_updaters the right way to go??? updateImageIndicators: function(gid, image){ gid = gid == null ? this.getElemGID() : gid image = image == null ? this.getImage() : $(image) @@ -898,9 +892,12 @@ var RibbonsPrototype = { // collect marks... image.after(this.getImageMarks(gid)) - IMAGE_UPDATERS.forEach(function(update){ - update(gid, image) - }) + + if(this.__image_updaters != null){ + this.__image_updaters.forEach(function(update){ + update(gid, image) + }) + } return image }, @@ -1109,20 +1106,25 @@ var RibbonsPrototype = { } // remove all images that we do not need... - var unloaded = $() + var unloaded = [] + var unload_marks = [] loaded = loaded .filter(function(i, img){ - if(gids.indexOf(that.getElemGID($(img))) >= 0){ + var g = that.getElemGID($(img)) + if(gids.indexOf(g) >= 0){ return true } unloaded.push(img) + unload_marks = unload_marks.concat(that.getImageMarks(g).toArray()) return false }) // remove everything in one go... - unloaded + $(unloaded) .detach() .removeClass('moving') - unloaded = unloaded.toArray() + // clear marks... + $(unload_marks) + .remove() $(gids).each(function(i, gid){ // support for sparse ribbons... @@ -1297,14 +1299,16 @@ var RibbonsPrototype = { clear: function(gids){ // clear all... if(gids == null || gids == '*'){ - this.getRibbonSet().remove() + this.preventTransitions() + setElementOffset(this.getRibbonSet(), 0, 0).children().detach() + this.restoreTransitions() // clear one or more gids... } else { gids = gids.constructor !== Array ? [gids] : gids var that = this gids.forEach(function(g){ - that.viewer.find('[gid='+JSON.stringify(g)+']').remove() + that.viewer.find('[gid='+JSON.stringify(g)+']').detach() }) } return this @@ -1763,6 +1767,18 @@ var RibbonsPrototype = { }, + setEmptyMsg: function(msg, help){ + this.viewer + .attr({ + 'empty-msg': msg || '', + 'empty-help': help || '', + }) + this.getRibbonSet() + .attr({ + 'empty-msg': msg || '', + 'empty-help': help || '', + }) + }, } diff --git a/ui (gen4)/testing.js b/ui (gen4)/testing.js index 25f62f68..22785a03 100755 --- a/ui (gen4)/testing.js +++ b/ui (gen4)/testing.js @@ -52,6 +52,11 @@ module.mock_data = { 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] }, + + tags: { + selected: ['b', 'z'], + bookmark: ['1', 'c', 'z'], + }, } Object.keys(mock_data.ribbons).forEach(function(k){ mock_data.order = mock_data.order.concat(mock_data.ribbons[k]) diff --git a/ui (gen4)/ui.js b/ui (gen4)/ui.js index b9a9c01c..283e4fd8 100755 --- a/ui (gen4)/ui.js +++ b/ui (gen4)/ui.js @@ -122,6 +122,8 @@ module.GLOBAL_KEYBOARD = { ')': 'nextImageInOrder', ',': 'prevMarked', '.': 'nextMarked', + '[': 'prevBookmarked', + ']': 'nextBookmarked', Up: { default: 'prevRibbon', shift: 'shiftImageUp', @@ -161,6 +163,8 @@ module.GLOBAL_KEYBOARD = { F2: { default: 'cropRibbon', shift: 'cropRibbonAndAbove', + ctrl: 'cropMarked', + alt: 'cropBookmarked', }, Esc: { default: 'uncrop', @@ -197,6 +201,14 @@ $(function(){ // XXX window.a = testing.setupActions() + .load({ + viewer: $('.viewer') + }) + + + // XXX for some reason this does not happen right away... + a.setEmptyMsg('Loading...') + viewer.Features.setup(a, [ // XXX I do not fully understand it yet, but PartialRibbons must be @@ -209,26 +221,34 @@ $(function(){ 'ui-partial-ribbons', 'ui-ribbon-align-to-order', 'ui-single-image-view', + + 'image-marks', + 'image-bookmarks', + + // chrome... 'ui-animation', 'ui-bounds-indicators', 'ui-current-image-indicator', - 'image-marks', - 'image-bookmarks', ]) // this publishes all the actions... //module.GLOBAL_KEYBOARD.__proto__ = a - // load some testing data... + // NOTE: we can load this in parts... a.load({ + //viewer: $('.viewer'), data: data.Data(testing.mock_data), - viewer: $('.viewer'), images: testing.makeTestImages(), }) + a.setEmptyMsg( + 'Nothing loaded...', + 'Press \'O\' to load, \'F1\' for help or \'?\' for keyboard mappings.') + + // setup base keyboard for devel, in case something breaks... $(document) .keydown( diff --git a/ui (gen4)/viewer.js b/ui (gen4)/viewer.js index 88f9d20c..20277859 100755 --- a/ui (gen4)/viewer.js +++ b/ui (gen4)/viewer.js @@ -625,6 +625,8 @@ actions.Actions(Client, { if(this.ribbons == null){ this.ribbons = ribbons.Ribbons(viewer, this.images) + // XXX is this correct??? + this.ribbons.__image_updaters = [this.updateImage.bind(this)] } this.reload() @@ -667,6 +669,8 @@ actions.Actions(Client, { if(this.ribbons == null){ this.ribbons = ribbons.Ribbons(viewer, this.images) + // XXX is this correct??? + this.ribbons.__image_updaters = [this.updateImage.bind(this)] } else { this.ribbons.clear() @@ -1010,6 +1014,17 @@ actions.Actions(Client, { this.reload() } }], + + // a shorthand... + setEmptyMsg: ['Set message to be displayed when nothing is loaded.', + function(msg, help){ this.ribbons.setEmptyMsg(msg, help) }], + + + // XXX experimental... + // ...need this to get triggered by .ribbons + // at this point manually triggering this will not do anything... + updateImage: ['', + function(gid, image){ }], }) @@ -1240,7 +1255,12 @@ module.PartialRibbons = Feature({ handlers: [ ['focusImage.pre centerImage.pre', - function(target){ + function(target, list){ + // NOTE: we have to do this as we are called BEFORE the + // actual focus change happens... + // XXX is there a better way to do this??? + target = list != null ? target = this.data.getImage(target, list) : target + this.updateRibbon(target) }], ['fitImage.pre', @@ -1811,6 +1831,7 @@ function makeTagTogglerAction(tag){ // XXX add image updater... var ImageMarkActions = actions.Actions({ + // a shorthand... // NOTE: this will return a copy... get marked(){ if(this.data == null @@ -1877,8 +1898,13 @@ module.ImageMarks = Feature({ actions: ImageMarkActions, - // XXX image update... handlers: [ + // XXX is this the right way to go??? + ['updateImage', function(gid, img){ + if(this.toggleMark(gid, '?') == 'on'){ + this.ribbons.toggleImageMark(gid, 'selected', 'on') + } + }], ], }) @@ -1887,6 +1913,7 @@ module.ImageMarks = Feature({ //--------------------------------------------------------------------- var ImageBookmarkActions = actions.Actions({ + // a shorthand... // NOTE: this will return a copy... get bookmarked(){ if(this.data == null @@ -1909,12 +1936,12 @@ var ImageBookmarkActions = actions.Actions({ }], prevBookmarked: ['', - function(mode){ this.prevTagged('bookmarked', mode) }], + function(mode){ this.prevTagged('bookmark', mode) }], nextBookmarked: ['', - function(mode){ this.nextTagged('bookmarked', mode) }], + function(mode){ this.nextTagged('bookmark', mode) }], cropBookmarked: ['', - function(flatten){ this.cropTagged('bookmarked', 'any', flatten) }], + function(flatten){ this.cropTagged('bookmark', 'any', flatten) }], }) @@ -1927,6 +1954,14 @@ module.ImageBookmarks = Feature({ actions: ImageBookmarkActions, + handlers: [ + // XXX is this the right way to go??? + ['updateImage', function(gid, img){ + if(this.toggleBookmark(gid, '?') == 'on'){ + this.ribbons.toggleImageMark(gid, 'bookmark', 'on') + } + }], + ], })