2019-10-09 03:04:46 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
((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')
|
|
|
|
|
|
2019-10-12 06:38:48 +03:00
|
|
|
var widgets = require('features/ui-widgets')
|
|
|
|
|
|
|
|
|
|
var browse = require('lib/widget/browse')
|
|
|
|
|
|
2019-10-09 03:04:46 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
2019-10-12 06:38:48 +03:00
|
|
|
// XXX should these be sortable and how???
|
|
|
|
|
// ...relative placement (i.e. "before <GID>")???
|
|
|
|
|
// XXX should these be importable from fs???
|
|
|
|
|
// i.e. exported as json to <title>.virt and imported back...
|
|
|
|
|
// ...might be a good idea to add custom import/export handlers...
|
|
|
|
|
//
|
2019-10-12 03:34:19 +03:00
|
|
|
var VirtualBlocksActions = actions.Actions({
|
2019-10-09 03:04:46 +03:00
|
|
|
// construction of new "virtual images"...
|
|
|
|
|
//
|
|
|
|
|
// XXX do better arg processing -- handle metadata correctly...
|
|
|
|
|
// XXX add export support for this type of stuff...
|
2019-10-09 03:25:53 +03:00
|
|
|
// text -> file.txt
|
2019-10-12 06:38:48 +03:00
|
|
|
makeVirtualBlock: ['- $Virtual block/',
|
2019-10-09 03:04:46 +03:00
|
|
|
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)
|
2019-10-12 06:38:48 +03:00
|
|
|
this.markChanged
|
|
|
|
|
&& this.markChanged('images', [gid])
|
2019-10-09 03:04:46 +03:00
|
|
|
|
|
|
|
|
// focus new image...
|
|
|
|
|
// NOTE: this should update the view too...
|
|
|
|
|
this.focusImage(gid)
|
|
|
|
|
}],
|
|
|
|
|
|
2019-10-12 06:38:48 +03:00
|
|
|
// XXX this is enabled only in crop mode as there is no way to delete
|
|
|
|
|
// a block but possible to create one...
|
|
|
|
|
// ...should we add a .removeBlock(..) action???
|
|
|
|
|
makeVirtualBlank: ['Virtual block/50:Add blank $after',
|
|
|
|
|
core.doc`
|
|
|
|
|
|
|
|
|
|
`,
|
|
|
|
|
{ browseMode: function(){ return !this.collection && 'disabled' }, },
|
2019-10-09 03:04:46 +03:00
|
|
|
function(ref, offset){
|
|
|
|
|
this.makeVirtualBlock(ref, offset, {
|
|
|
|
|
type: 'virtual',
|
|
|
|
|
path: null,
|
|
|
|
|
}) }],
|
2019-10-12 06:38:48 +03:00
|
|
|
makeVirtualBlankBefore: ['Virtual block/51:Add blank $before',
|
|
|
|
|
{ browseMode: 'makeVirtualBlank', },
|
|
|
|
|
'makeVirtualBlank: $0 "before"'],
|
2019-10-09 03:39:20 +03:00
|
|
|
|
2019-10-09 03:04:46 +03:00
|
|
|
// XXX export...
|
|
|
|
|
})
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
var VirtualBlocks =
|
|
|
|
|
module.VirtualBlocks = core.ImageGridFeatures.Feature({
|
2019-10-09 03:04:46 +03:00
|
|
|
title: '',
|
|
|
|
|
doc: '',
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
tag: 'virtual-blocks',
|
2019-10-09 03:04:46 +03:00
|
|
|
depends: [
|
|
|
|
|
'edit',
|
|
|
|
|
],
|
|
|
|
|
suggested: [
|
2019-10-12 03:34:19 +03:00
|
|
|
'ui-virtual-blocks',
|
|
|
|
|
'ui-virtual-blocks-edit',
|
2019-10-09 03:04:46 +03:00
|
|
|
],
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
actions: VirtualBlocksActions,
|
2019-10-09 03:04:46 +03:00
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
var VirtualBlocksUIActions = actions.Actions({
|
2019-10-10 00:35:53 +03:00
|
|
|
config: {
|
2019-10-12 03:34:19 +03:00
|
|
|
// Threshold text length at which
|
2019-10-10 00:35:53 +03:00
|
|
|
'virtual-text-fit-area-threshold': 100,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
__virtual_block_processors__: {
|
2019-10-10 06:07:17 +03:00
|
|
|
// Text handler is designed to process plain or lightly
|
2019-10-10 00:35:53 +03:00
|
|
|
// formatted text.
|
|
|
|
|
//
|
|
|
|
|
// This will:
|
|
|
|
|
// - replace '\n' with '<br>'
|
|
|
|
|
// - adjust font size to fit the image block
|
|
|
|
|
//
|
|
|
|
|
// NOTE: the processor is allowed to only modify image block
|
|
|
|
|
// content, anything else would require cleanup...
|
2019-10-10 06:07:17 +03:00
|
|
|
//
|
2019-10-10 00:35:53 +03:00
|
|
|
// XXX might be a good idea to add action param to enable
|
|
|
|
|
// handlers to do things like 'setup', 'cleanup', ...
|
2019-10-10 06:07:17 +03:00
|
|
|
text: function(image, dom){
|
2019-10-10 00:35:53 +03:00
|
|
|
if(!image.text){
|
|
|
|
|
return dom }
|
|
|
|
|
|
|
|
|
|
// threshold after which we try to fill the volume...
|
|
|
|
|
var C = this.config['virtual-text-fit-area-threshold'] || 100
|
|
|
|
|
|
|
|
|
|
// construct a basic text element...
|
|
|
|
|
var text = document.createElement('div')
|
|
|
|
|
text.innerHTML = image.text
|
|
|
|
|
.replace(/\n/g, '<br>\n')
|
|
|
|
|
dom[0].innerHTML = ''
|
|
|
|
|
dom[0].appendChild(text)
|
|
|
|
|
|
|
|
|
|
// scale the text if it is small...
|
|
|
|
|
var R = dom[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
|
2019-10-10 16:54:50 +03:00
|
|
|
|
2019-10-10 00:35:53 +03:00
|
|
|
text.style.fontSize = `${ 100*s }%`
|
|
|
|
|
// prioritize width...
|
|
|
|
|
text.style.width = '100%'
|
|
|
|
|
|
|
|
|
|
return dom
|
|
|
|
|
},
|
|
|
|
|
},
|
2019-10-12 06:38:48 +03:00
|
|
|
updateVirtualBlock: ['- Virtual block/',
|
2019-10-10 00:35:53 +03:00
|
|
|
function(gid, dom, image){
|
|
|
|
|
image = image || this.images[gid] || {}
|
|
|
|
|
|
|
|
|
|
if(image.type != 'virtual'){
|
|
|
|
|
return actions.UNDEFINED }
|
|
|
|
|
|
|
|
|
|
var p = (this.__virtual_block_processors__
|
2019-10-12 03:34:19 +03:00
|
|
|
|| VirtualBlocksUIActions.__virtual_block_processors__
|
2019-10-10 00:35:53 +03:00
|
|
|
|| {})
|
2019-10-10 06:07:17 +03:00
|
|
|
p = p[image.format] || p['text']
|
2019-10-10 00:35:53 +03:00
|
|
|
return p instanceof Function ?
|
|
|
|
|
p.call(this, image, dom)
|
|
|
|
|
: dom }],
|
|
|
|
|
|
2019-10-10 06:07:17 +03:00
|
|
|
metadataSection: [
|
|
|
|
|
{ sortedActionPriority: 80 },
|
|
|
|
|
function(make, gid, image){
|
|
|
|
|
var that = this
|
|
|
|
|
if(!image || image.type != 'virtual'){
|
|
|
|
|
return }
|
|
|
|
|
|
|
|
|
|
make.Separator()
|
2019-10-12 06:38:48 +03:00
|
|
|
this.editVirtualBlockText ?
|
|
|
|
|
// editable...
|
|
|
|
|
this.editVirtualBlockText(make, gid, image)
|
|
|
|
|
// view only...
|
|
|
|
|
: make(['Te$xt:', image.text])
|
2019-10-10 06:07:17 +03:00
|
|
|
}],
|
2019-10-09 03:04:46 +03:00
|
|
|
})
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
// NOTE: this is independent of 'virtual-blocks'...
|
|
|
|
|
var VirtualBlocksUI =
|
|
|
|
|
module.VirtualBlocksUI = core.ImageGridFeatures.Feature({
|
2019-10-09 03:04:46 +03:00
|
|
|
title: '',
|
|
|
|
|
doc: '',
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
tag: 'ui-virtual-blocks',
|
2019-10-09 03:04:46 +03:00
|
|
|
depends: [
|
|
|
|
|
'ui',
|
2019-10-10 00:35:53 +03:00
|
|
|
],
|
|
|
|
|
suggested: [
|
2019-10-12 03:34:19 +03:00
|
|
|
'virtual-blocks',
|
|
|
|
|
'ui-virtual-blocks-edit',
|
2019-10-09 03:04:46 +03:00
|
|
|
],
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
actions: VirtualBlocksUIActions,
|
2019-10-09 03:04:46 +03:00
|
|
|
|
|
|
|
|
handlers: [
|
|
|
|
|
['updateImage',
|
2019-10-10 00:35:53 +03:00
|
|
|
function(_, gid, dom){
|
2019-10-09 03:04:46 +03:00
|
|
|
var image = this.images[gid] || {}
|
|
|
|
|
|
|
|
|
|
// set image content...
|
|
|
|
|
if(image.type == 'virtual' && image.text){
|
2019-10-10 00:35:53 +03:00
|
|
|
this.updateVirtualBlock(gid, dom, image)
|
2019-10-09 03:04:46 +03:00
|
|
|
|
|
|
|
|
// clear reused image content...
|
2019-10-10 00:35:53 +03:00
|
|
|
} else if(dom[0].innerHTML != ''){
|
|
|
|
|
dom[0].innerHTML = ''
|
2019-10-09 03:04:46 +03:00
|
|
|
}
|
|
|
|
|
}],
|
|
|
|
|
],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-10-10 06:07:17 +03:00
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
var VirtualBlocksEditUIActions = actions.Actions({
|
2019-10-12 06:38:48 +03:00
|
|
|
// XXX this is a good candidate for inlineing (browse2)
|
|
|
|
|
// XXX should we also add a preview (preview constructor from metadata)???
|
|
|
|
|
// XXX should we do a sanity check for image type???
|
|
|
|
|
editVirtualBlockText: ['Virtual block/$Edit text...',
|
|
|
|
|
{ browseMode: function(){
|
|
|
|
|
return (this.image || {}).type != 'virtual' && 'disabled' }, },
|
|
|
|
|
widgets.makeUIDialog(function(gid){
|
|
|
|
|
var that = this
|
|
|
|
|
|
|
|
|
|
var _make = function(make, gid, image){
|
|
|
|
|
make.Editable(['Te$xt:', image.text], {
|
|
|
|
|
start_on: 'open',
|
|
|
|
|
edit_text: 'last',
|
|
|
|
|
multiline: true,
|
|
|
|
|
reset_on_commit: false,
|
|
|
|
|
editdone: function(evt, value){
|
|
|
|
|
image.text = value
|
|
|
|
|
// mark image as changed...
|
|
|
|
|
that.markChanged
|
|
|
|
|
&& that.markChanged('images', [gid])
|
|
|
|
|
// refresh views...
|
|
|
|
|
make.dialog.updatePreview
|
|
|
|
|
&& make.dialog.updatePreview()
|
|
|
|
|
that.refresh(gid)
|
|
|
|
|
}, }) }
|
|
|
|
|
|
|
|
|
|
// XXX should this be a more specific test???
|
|
|
|
|
return arguments[0] instanceof Function?
|
|
|
|
|
// inline...
|
|
|
|
|
_make.call(this, ...arguments)
|
|
|
|
|
// dialog...
|
|
|
|
|
: browse.makeLister(null,
|
|
|
|
|
function(p, make){
|
|
|
|
|
var gid = gid || that.current
|
|
|
|
|
var data = data || that.images[gid]
|
|
|
|
|
|
|
|
|
|
_make(make, gid, data)
|
|
|
|
|
}, {
|
|
|
|
|
cls: 'table-view',
|
|
|
|
|
})
|
|
|
|
|
.close(function(){
|
|
|
|
|
that.refresh(gid) }) })],
|
2019-10-10 06:07:17 +03:00
|
|
|
})
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
// NOTE: this is independent of 'virtual-blocks'...
|
|
|
|
|
var VirtualBlocksEditUI =
|
|
|
|
|
module.VirtualBlocksEditUI = core.ImageGridFeatures.Feature({
|
2019-10-10 06:07:17 +03:00
|
|
|
title: '',
|
|
|
|
|
doc: '',
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
tag: 'ui-virtual-blocks-edit',
|
2019-10-10 06:07:17 +03:00
|
|
|
depends: [
|
|
|
|
|
'ui',
|
2019-10-12 03:34:19 +03:00
|
|
|
'ui-virtual-blocks',
|
|
|
|
|
'virtual-blocks',
|
2019-10-10 06:07:17 +03:00
|
|
|
],
|
|
|
|
|
|
2019-10-12 03:34:19 +03:00
|
|
|
actions: VirtualBlocksEditUIActions,
|
2019-10-10 06:07:17 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
2019-10-09 03:04:46 +03:00
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* vim:set ts=4 sw=4 : */ return module })
|