diff --git a/ui (gen4)/css/experimenting.css b/ui (gen4)/css/experimenting.css
index 3b916514..c9a142d9 100755
--- a/ui (gen4)/css/experimenting.css
+++ b/ui (gen4)/css/experimenting.css
@@ -524,8 +524,6 @@ body {
-
-
/* DEBUG stuff... */
.container-center {
position: absolute;
diff --git a/ui (gen4)/css/layout.less b/ui (gen4)/css/layout.less
index cf3fcff1..c17774ac 100755
--- a/ui (gen4)/css/layout.less
+++ b/ui (gen4)/css/layout.less
@@ -695,8 +695,10 @@ stretching in width... */
box-sizing: border-box;
color: white;
-
- text-shadow: black 0.1em 0.1em 0.4em, black 0.1em 0.1em;
+ /* XXX do we need this???
+ text-shadow:
+ black 0.1em 0.1em 0.4em,
+ black 0.1em 0.1em; */
/* NOTE: we can't set the bg color here because it will get
affected by filters... */
@@ -705,6 +707,28 @@ stretching in width... */
border: solid @image-border transparent;
}
+.image {
+ padding: @single-image-indicator-size;
+}
+.image div {
+ display: block;
+ position: absolute;
+
+ max-width: @image-tile-size;
+ width: auto;
+ max-height: @image-tile-size;
+ height: auto;
+
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%,-50%);
+
+ white-space: normal;
+ text-align: center;
+ text-overflow: ellipsis;
+ /*font-size: 2vh;*/
+}
+
.crisp-resize .image {
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
@@ -2042,7 +2066,10 @@ progress:not(value)::-webkit-progress-bar {
/* XXX this is by no means final... */
/*@import "theme-light";*/
-.viewer,
+.light.single-image-mode.viewer .image,
+.light.transparent-ribbon.viewer .image {
+ color: black;
+}
.light.viewer,
.light.viewer .overlay-block .background {
background: white;
diff --git a/ui (gen4)/features/all.js b/ui (gen4)/features/all.js
index 012ce6fe..70e20af6 100755
--- a/ui (gen4)/features/all.js
+++ b/ui (gen4)/features/all.js
@@ -48,6 +48,9 @@ require('features/external-editor')
require('features/metadata')
require('features/meta')
+// XXX EXPERIMENTAL...
+require('features/virtual-images')
+
require('features/experimental')
require('features/tests')
require('features/demo')
diff --git a/ui (gen4)/features/experimental.js b/ui (gen4)/features/experimental.js
index 2b8aa166..2286bcbb 100755
--- a/ui (gen4)/features/experimental.js
+++ b/ui (gen4)/features/experimental.js
@@ -122,71 +122,6 @@ var ExperimentActions = actions.Actions({
function(){
}],
-
-
- // construction of new "virtual images"...
- //
- // XXX should this be restricted to collections???
- // XXX should these be importable???
- // i.e. exported as json to
.virt and imported back...
- // ...might be a good idea to add custom import/export handlers...
- //
- // XXX do better arg processing -- handle metadata correctly...
- // XXX add export support for this type of stuff...
- // XXX add default named templates...
- // XXX add svg templates...
- // - blank (white/black/gray/...)
- // - title
- // - text
- // XXX move to 'virtual-images' feature...
- makeVirtualImage: ['Experimental/',
- function(ref, offset, metadata){
- ref = ref || 'current'
- offset = offset || 'after'
- offset = offset == 'after' ?
- 1
- : offset == 'before' ?
- 0
- : typeof(offset) == typeof(123) ?
- offset
- : 0
- // XXX revise...
- metadata = arguments[arguments.length-1] instanceof Object ?
- arguments[arguments.length-1]
- : null
-
- var data = this.data
-
- ref = data.getImage(ref)
- var r = data.getRibbon(ref)
-
- var gid = data.newGID()
-
- // place image into data...
- var order = data.order
- order.splice(order.indexOf(ref)+offset,0, gid)
- var ribbon = data.ribbons[r]
- ribbon.splice(ribbon.indexOf(ref)+offset,0, gid)
-
- // update data...
- data.updateImagePositions()
-
- // update metadata...
- metadata
- && (this.images[gid] = metadata)
-
- // focus new image...
- // NOTE: this should update the view too...
- this.focusImage(gid)
- }],
- // XXX
- makeVirtualBlank: ['Experimental/',
- function(){
- }],
- // XXX
- makeVirtualText: ['Experimental/',
- function(){
- }],
})
var ExperimentFeature =
diff --git a/ui (gen4)/features/meta.js b/ui (gen4)/features/meta.js
index a801f4b5..99715a45 100755
--- a/ui (gen4)/features/meta.js
+++ b/ui (gen4)/features/meta.js
@@ -163,6 +163,7 @@ core.ImageGridFeatures.Feature('imagegrid-testing', [
'ui-preview-filters',
'url-history',
'external-editor',
+ 'virtual-images',
// experimental features...
//'ui-range',
diff --git a/ui (gen4)/features/virtual-images.js b/ui (gen4)/features/virtual-images.js
new file mode 100644
index 00000000..9c98191f
--- /dev/null
+++ b/ui (gen4)/features/virtual-images.js
@@ -0,0 +1,187 @@
+/**********************************************************************
+*
+*
+*
+**********************************************************************/
+((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
+(function(require){ var module={} // make module AMD/node compatible...
+/*********************************************************************/
+
+var actions = require('lib/actions')
+var features = require('lib/features')
+
+var core = require('features/core')
+
+
+
+/*********************************************************************/
+
+// XXX revise menu placement...
+var VirtualImagesActions = actions.Actions({
+ // construction of new "virtual images"...
+ //
+ // XXX should this be restricted to collections???
+ // XXX should these be importable from fs???
+ // i.e. exported as json to .virt and imported back...
+ // ...might be a good idea to add custom import/export handlers...
+ //
+ // XXX do better arg processing -- handle metadata correctly...
+ // XXX add export support for this type of stuff...
+ // XXX add default named templates...
+ // XXX add svg templates???
+ makeVirtualBlock: ['- Virtual/',
+ function(ref, offset, metadata){
+ ref = ref || 'current'
+ offset = offset || 'after'
+ offset = offset == 'after' ?
+ 1
+ : offset == 'before' ?
+ 0
+ : typeof(offset) == typeof(123) ?
+ offset
+ : 0
+ // XXX revise...
+ metadata = arguments[arguments.length-1] instanceof Object ?
+ arguments[arguments.length-1]
+ : null
+
+ var data = this.data
+
+ ref = data.getImage(ref)
+ var r = data.getRibbon(ref)
+
+ var gid = data.newGID()
+
+ // place image into data...
+ var order = data.order
+ order.splice(order.indexOf(ref)+offset,0, gid)
+ var ribbon = data.ribbons[r]
+ ribbon.splice(ribbon.indexOf(ref)+offset,0, gid)
+
+ // update data...
+ data.updateImagePositions()
+
+ // update metadata...
+ metadata
+ && (this.images[gid] = metadata)
+
+ // focus new image...
+ // NOTE: this should update the view too...
+ this.focusImage(gid)
+ }],
+
+ // XXX
+ makeVirtualBlank: ['Virtual/Add blank after',
+ core.doc``,
+ //{ browseMode: function(){ return !this.collection && 'disabled' }, },
+ function(ref, offset){
+ this.makeVirtualBlock(ref, offset, {
+ type: 'virtual',
+ path: null,
+ }) }],
+ makeVirtualText: ['Virtual/Add text block after',
+ core.doc`
+
+ NOTE: this was not designed for complex HTML, only use simple
+ formatted text.`,
+ //{ browseMode: function(){ return !this.collection && 'disabled' }, },
+ function(text, ref, offset){
+ this.makeVirtualBlock(ref, offset, {
+ type: 'virtual',
+ path: null,
+ text: text || '',
+ }) }],
+
+ // XXX virtual block editor UI...
+ // XXX
+
+
+ // XXX export...
+})
+
+var VirtualImages =
+module.VirtualImages = core.ImageGridFeatures.Feature({
+ title: '',
+ doc: '',
+
+ tag: 'virtual-images',
+ depends: [
+ 'edit',
+ // XXX
+ ],
+ suggested: [
+ 'ui-virtual-images',
+ ],
+
+ actions: VirtualImagesActions,
+
+})
+
+
+
+
+//---------------------------------------------------------------------
+
+var VirtualImagesUIActions = actions.Actions({
+ // XXX
+})
+
+var VirtualImagesUI =
+module.VirtualImagesUI = core.ImageGridFeatures.Feature({
+ title: '',
+ doc: '',
+
+ tag: 'ui-virtual-images',
+ depends: [
+ 'ui',
+ 'virtual-images'
+ ],
+
+ actions: VirtualImagesUIActions,
+
+ handlers: [
+ ['updateImage',
+ function(res, gid, img){
+ var image = this.images[gid] || {}
+
+ // set image content...
+ if(image.type == 'virtual' && image.text){
+ var text = document.createElement('div')
+ text.innerHTML = image.text
+ img[0].innerHTML = ''
+ img[0].appendChild(text)
+
+ // threshold after which we try to fill the volume...
+ var C = 100
+
+ // scale the text if it is small...
+ var R = img[0].offsetHeight * 0.8
+ var r = image.text.length > C ?
+ Math.max(
+ text.offsetWidth,
+ text.offsetHeight,
+ // keep large text blocks roughly square-ish...
+ Math.sqrt(text.scrollHeight * text.scrollWidth))
+ : Math.max(
+ text.offsetWidth,
+ text.offsetHeight,
+ text.scrollHeight,
+ text.scrollWidth)
+ var s = R/r
+ text.style.fontSize = `${ 100*s }%`
+ // prioritize width...
+ text.style.width = '100%'
+
+ // clear reused image content...
+ } else if(img[0].innerHTML != ''){
+ img[0].innerHTML = ''
+ }
+ }],
+ ],
+})
+
+
+
+
+/**********************************************************************
+* vim:set ts=4 sw=4 : */ return module })
diff --git a/ui (gen4)/imagegrid/images.js b/ui (gen4)/imagegrid/images.js
index 1ceebb29..898300ca 100755
--- a/ui (gen4)/imagegrid/images.js
+++ b/ui (gen4)/imagegrid/images.js
@@ -495,6 +495,12 @@ module.ImagesPrototype = {
//gid = gid == null ? getImageGID(): gid
//size = size == null ? getVisibleImageSize('max') : size
img_data = img_data == null ? this[gid] : img_data
+ img_data = img_data || IMAGE_DATA
+
+ // if path is explicitly null there are no previews...
+ if(img_data.path === null){
+ return undefined
+ }
// if no usable images are available use STUB data...
if(!img_data
diff --git a/ui (gen4)/imagegrid/ribbons.js b/ui (gen4)/imagegrid/ribbons.js
index 89fa15e7..da8f6408 100755
--- a/ui (gen4)/imagegrid/ribbons.js
+++ b/ui (gen4)/imagegrid/ribbons.js
@@ -1514,126 +1514,12 @@ var RibbonsPrototype = {
// .correctImageProportionsForRotation(..)
//
// .updateImageIndicators(..)
- _updateImage: function(image, gid, size, sync){
- image = (image == '*' ? this.viewer.find(IMAGE)
- : image == null
- || typeof(image) == typeof('str') ? this.getImage(image)
- : $(image))
- sync = sync == null ? this.load_img_sync : sync
- size = size == null ? this.getVisibleImageSize('max') : size
-
- var that = this
- return $(image.map(function(){
- var image = this instanceof String
- || typeof(this) == typeof('str')
- ? that.getImage(this+'')
- : $(this)
- if(image.length == 0){
- return
- }
- var old_gid = that.elemGID(image)
-
- // same image -- update...
- if(old_gid == gid || gid == null){
- var gid = old_gid
-
- // reuse for different image -- reconstruct...
- } else {
- // remove old marks...
- if(typeof(old_gid) == typeof('str')){
- that.getImageMarks(old_gid).remove()
- }
- // reset gid...
- image
- .attr('gid', JSON.stringify(gid)
- // this removes the extra quots...
- .replace(/^"(.*)"$/g, '$1'))
- .css({
- // clear the old preview...
- 'background-image': '',
- })
- }
-
- // if no images data defined drop out...
- if(that.images == null){
- return image[0]
- }
-
- // get the image data...
- var img_data = that.images[gid]
- if(img_data == null){
- img_data = images.IMAGE_DATA
- }
-
- // if we are a group, get the cover...
- // NOTE: groups can be nested...
- var seen = []
- while(img_data.type == 'group'){
- // error, recursive group...
- if(seen.indexOf(img_data.id) >= 0){
- img_data = images.IMAGE_DATA
- console.error('Recursive group:', gid)
- break
- }
- seen.push(img_data.id)
-
- img_data = that.images[img_data.cover]
- }
-
- // image state...
- //that.rotateImage(image, img_data.orientation == null ? 0 : img_data.orientation)
- //that.flipImage(image, img_data.flipped == null ? [] : img_data.flipped)
- image.attr({
- orientation: img_data.orientation == null ? '' : img_data.orientation*1,
- flipped: (img_data.flipped == null ? [] : img_data.flipped).join(', '),
- })
-
- // preview...
- var p_url = that.images.getBestPreview(img_data.id, size, img_data, true).url
-
- // update the preview if it's a new image or...
- // XXX this should be pushed as far back as possible...
- if(old_gid != gid
- // the new preview (p_url) is different to current...
- // NOTE: this may not work correctly for relative urls...
- || image.css('background-image').indexOf(util.path2url(p_url)) < 0){
- // sync load...
- if(sync){
- that._loadImagePreviewURL(image, p_url)
-
- // async load...
- } else {
- // NOTE: storing the url in .data() makes the image load the
- // last requested preview and in a case when we manage to
- // call updateImage(...) on the same element multiple times
- // before the previews get loaded...
- // ...setting the data().loading is sync while loading an
- // image is not, and if several loads are done in sequence
- // there is no guarantee that they will happen in the same
- // order as requested...
- image.data().loading = p_url
- setTimeout(function(){
- that._loadImagePreviewURL(image, image.data().loading)
- }, 0)
- }
- }
-
- // NOTE: this only has effect on non-square image blocks...
- // XXX this needs the loaded image, thus should be done right
- // after preview loading...
- // XXX preview loading is async, is this the right
- // place for this??
- // ...this is also done in .rotateImage(..) above...
- that.correctImageProportionsForRotation(image)
-
- // marks and other indicators...
- that.updateImageIndicators(gid, image)
-
- return image[0]
- }))
- },
+ //
// XXX add options for images to preload and only then do the update...
// XXX really slow for very large numbers of input images/gids...
+ // XXX add support for basic image templating here...
+ // ...templates for blank images, text blocks and other stuff,
+ // this would best be done by simply filling in SVG templates...
updateImage: function(image, gid, size, sync, callback){
var that = this
var imgs = this.viewer.find(IMAGE)
@@ -1729,8 +1615,13 @@ var RibbonsPrototype = {
//will_change.push('transform')
// stage background image update...
- var p_url = that.images.getBestPreview(img_data.id, size, img_data, true).url
- if(old_gid != gid
+ // XXX add support for basic templating here...
+ var p_url = (that.images.getBestPreview(img_data.id, size, img_data, true) || {}).url
+ // no preview -> reset bg...
+ if(p_url == null){
+ image[0].style.backgroundImage = ''
+
+ } else if(old_gid != gid
// the new preview (p_url) is different to current...
// NOTE: this may not work correctly for relative urls...
|| image.css('background-image').indexOf(util.path2url(p_url)) < 0){