moved marking from 'selected' to 'marked' tag + added tag cloud...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-11-08 21:10:58 +03:00
parent 5cfc23b159
commit 700e953026
18 changed files with 179 additions and 74 deletions

View File

@ -1034,15 +1034,15 @@ stretching in width... */
}
.mark.bookmark,
.mark.selected {
.mark.marked {
width: 0px;
margin-left: 0px;
border: none;
overflow: visible;
}
.mark.bookmark:after,
.mark.selected:before,
.mark.selected:after {
.mark.marked:before,
.mark.marked:after {
display: block;
position: absolute;
content: "";
@ -1082,9 +1082,9 @@ stretching in width... */
}
/* the selected tick... */
.mark.selected:before,
.mark.selected:after {
/* the marked tick... */
.mark.marked:before,
.mark.marked:after {
top: @image-tile-size/30;
left: -@image-tile-size/15;
bottom: auto;
@ -1093,11 +1093,11 @@ stretching in width... */
.rotate(-45deg);
}
.mark.selected:before {
.mark.marked:before {
width: @image-tile-size/100;
height: @image-tile-size/50;
}
.mark.selected:after {
.mark.marked:after {
width: @image-tile-size/25;
height: @image-tile-size/100;
}
@ -1406,7 +1406,7 @@ stretching in width... */
}
/* XXX REUSE: this is the same as selected/bookmarked image markers... */
/* XXX REUSE: this is the same as marked/bookmarked image markers... */
.overlay-info .marked,
.overlay-info .marked:after,
.overlay-info .marked:before,

View File

@ -1290,7 +1290,7 @@ module.TagsEditActions = actions.Actions({
// NOTE: setting source to 'both' and mode to 'reset' is the same as
// 'images' and 'reset' as all .data tags will be lost on first
// pass...
syncTags: ['Tag/Synchoronize tags between data and images',
syncTags: ['Tag/-10:Synchoronize tags between data and images',
{journal: true},
function(source, mode){
// can't do anything if either .data or .images are not
@ -1350,8 +1350,8 @@ module.TagsEdit = core.ImageGridFeatures.Feature({
if(tags.length > 0){
this.markChanged('tags')
tags.indexOf('selected') >= 0
&& this.markChanged('selected')
tags.indexOf('marked') >= 0
&& this.markChanged('marked')
tags.indexOf('bookmark') >= 0
&& this.markChanged('bookmarked')
@ -1360,7 +1360,7 @@ module.TagsEdit = core.ImageGridFeatures.Feature({
this.markChanged('images', gids)
}],
// store .tags and .tags.selected / .tags.bookmark separately from .data...
// store .tags and .tags.marked / .tags.bookmark separately from .data...
//
// XXX see if this can be automated...
['prepareIndexForWrite',
@ -1375,9 +1375,9 @@ module.TagsEdit = core.ImageGridFeatures.Feature({
res.index.tags = res.raw.data.tags
}
// XXX should we save an empty list *iff* changes.selected is true???
if(changes === true || changes.selected){
res.index.marked = (res.raw.data.tags || {}).selected || []
// XXX should we save an empty list *iff* changes.marked is true???
if(changes === true || changes.marked){
res.index.marked = (res.raw.data.tags || {}).marked || []
}
// XXX should we save an empty list *iff* changes.bookmarked is true???
if(changes === true || changes.bookmarked){
@ -1389,7 +1389,7 @@ module.TagsEdit = core.ImageGridFeatures.Feature({
// cleanup...
if(res.index.data && res.index.data.tags){
delete res.index.data.tags.selected
delete res.index.data.tags.marked
delete res.index.data.tags.bookmark
//delete res.index.data.tags.bookmark_data
delete res.index.data.tags
@ -1399,7 +1399,7 @@ module.TagsEdit = core.ImageGridFeatures.Feature({
function(res, json){
res.data.tags = json.tags || {}
res.data.tags.selected = json.marked || []
res.data.tags.marked = json.marked || []
res.data.tags.bookmark = json.bookmarked ? json.bookmarked[0] : []
//res.data.tags.bookmark_data = json.bookmarked ? json.bookmarked[1] : {}

View File

@ -2865,7 +2865,7 @@ var CollectionMarksActions = actions.Actions({
CollectionTagsActions.config['collection-local-tags']
.concat([
'bookmark',
'selected',
'marked',
]),
'collection-transfer-changes':
@ -2875,7 +2875,7 @@ var CollectionMarksActions = actions.Actions({
CollectionActions.config['collection-transfer-changes']
.concat([
'bookmarked',
'selected',
'marked',
]),
},
@ -2883,13 +2883,13 @@ var CollectionMarksActions = actions.Actions({
collectMarked: ['- Collections|Mark/',
function(collection){
return this.collect(this.marked, collection) }],
//return this.collectTagged('selected', collection) }],
//return this.collectTagged('marked', collection) }],
uncollectMarked: ['Collections|Mark/Remove marked from collection',
{browseMode: function(){
return (!this.collection || this.marked.length == 0) && 'disabled' }},
function(collection){
return this.uncollect(this.marked, collection) }],
//return this.uncollectTagged('selected', collection) }],
//return this.uncollectTagged('marked', collection) }],
// bookmarked...
collectBookmarked: ['- Collections|Bookmark/',

View File

@ -37,7 +37,7 @@ module.demo_data = {
},
tags: {
selected: ['b', 'z'],
marked: ['b', 'z'],
bookmark: ['1', 'c', 'z'],
},

View File

@ -351,7 +351,7 @@ var ExampleUIActions = actions.Actions({
})
make('do nothing')
.addClass('selected')
.addClass('marked')
make('nested dialog...',
{
@ -767,8 +767,8 @@ var ExampleUIActions = actions.Actions({
}],
showBookmarkedInDrawer: ['Test/Show bookmarked in drawer',
function(){ this.showTaggedInDrawer('bookmark') }],
showSelectedInDrawer: ['Test/Show selected in drawer',
function(){ this.showTaggedInDrawer('selected') }],
showSelectedInDrawer: ['Test/Show marked in drawer',
function(){ this.showTaggedInDrawer('marked') }],
makePartitionAfter: ['Test/Make Partition after image',

View File

@ -2083,7 +2083,7 @@ var FileSystemWriterActions = actions.Actions({
// tags...
// XXX test: %n%(b)b%(m)m%e
.replace(
/%\(([^)]*)\)m/, tags.indexOf('selected') >= 0 ? '$1' : '')
/%\(([^)]*)\)m/, tags.indexOf('marked') >= 0 ? '$1' : '')
.replace(
/%\(([^)]*)\)b/, tags.indexOf('bookmark') >= 0 ? '$1' : '')
@ -2369,7 +2369,7 @@ var FileSystemWriterUIActions = actions.Actions({
['Marked:',
actions.formatImageName(pattern,
img,
{tags: ['selected']})],
{tags: ['marked']})],
['Bookmarked:',
actions.formatImageName(pattern,
img,
@ -2383,7 +2383,7 @@ var FileSystemWriterUIActions = actions.Actions({
img,
{
tags: [
'selected',
'marked',
'bookmark',
],
conflicts: {

View File

@ -208,6 +208,7 @@ module.GLOBAL_KEYBOARD = {
alt_F: 'browseActions: "/File/" -- File menu...',
alt_E: 'browseActions: "/Edit/" -- Edit menu...',
alt_N: 'browseActions: "/Navigate/" -- Navigate menu...',
alt_T: 'browseActions: "/Tag/" -- Tag menu...',
//alt_S: 'browseActions: "/Sort/" -- Sort menu...',
alt_shift_A: 'listActions',
@ -398,6 +399,9 @@ module.GLOBAL_KEYBOARD = {
I: 'showMetadata',
//ctrl_shift_I: 'showMetadata: "current" "full" -- Show full metadata',
// XXX
ctrl_T: 'showTagCloud',
// marking...
M: 'toggleMark',

View File

@ -230,11 +230,11 @@ var ImageMarkActions = actions.Actions({
get marked(){
if(this.data == null
|| this.data.tags == null
|| !('selected' in this.data.tags)){
|| !('marked' in this.data.tags)){
return []
}
//return this.data.tags['selected'].slice()
return this.data.getImages(this.data.tags['selected'])
//return this.data.tags['marked'].slice()
return this.data.getImages(this.data.tags['marked'])
},
markedInRibbon: ['- Mark|Ribbon/',
@ -250,16 +250,16 @@ var ImageMarkActions = actions.Actions({
prevMarked: ['Mark|Navigate/Previous marked image',
{browseMode: function(target){
return this.data.getImage('current', 'before', this.marked) == null && 'disabled' }},
function(mode){ this.prevTagged('selected', mode) }],
function(mode){ this.prevTagged('marked', mode) }],
nextMarked: ['Mark|Navigate/Next marked image',
{browseMode: function(target){
return this.data.getImage('current', 'after', this.marked) == null && 'disabled' }},
function(mode){ this.nextTagged('selected', mode) }],
function(mode){ this.nextTagged('marked', mode) }],
cropMarked: ['Mark|Crop/Crop $marked images',
{browseMode: function(target){
return this.marked.length == 0 && 'disabled' }},
function(flatten){ this.cropTagged('selected', 'any', flatten) }],
function(flatten){ this.cropTagged('marked', 'any', flatten) }],
removeMarkedFromCrop: ['Mark|Crop/Remove marked from crop',
{browseMode: function(target){
@ -320,7 +320,7 @@ var ImageMarkEditActions = actions.Actions({
//
toggleMark: ['Mark|Image/Image $mark',
undoTag('toggleMark'),
makeTagTogglerAction('selected')],
makeTagTogglerAction('marked')],
toggleMarkBlock: ['Mark/Invert $block marks',
core.doc`A block is a set of adjacent images either marked on unmarked
in the same way
@ -485,8 +485,8 @@ module.ImageMarksUI = core.ImageGridFeatures.Feature({
&& this.ribbons
.toggleImageMark(
gid,
'selected',
this.data.hasTag(gid, 'selected') ? 'on' : 'off')
'marked',
this.data.hasTag(gid, 'marked') ? 'on' : 'off')
}],
],
})
@ -563,7 +563,7 @@ var ImageBookmarkEditActions = actions.Actions({
toggleBookmarkOnMarked: ['Bookmark|Mark/-70:Toggle bookmark on maked images',
{browseMode: 'cropMarked'},
function(action){
return this.toggleBookmark(this.data.getTaggedByAny('selected'), action)
return this.toggleBookmark(this.data.getTaggedByAny('marked'), action)
}],
})

View File

@ -66,6 +66,8 @@ core.ImageGridFeatures.Feature('imagegrid-ui-minimal', [
'ui-bounds-indicators',
'ui-current-image-indicator',
'ui-tags',
])

View File

@ -11,6 +11,9 @@ var actions = require('lib/actions')
var features = require('lib/features')
var core = require('features/core')
var widgets = require('features/ui-widgets')
var browse = require('lib/widget/browse')
@ -32,7 +35,6 @@ module.PersistentTags = core.ImageGridFeatures.Feature({
depends: [
'base',
],
actions: PersistentTagsActions,
handlers: [],
@ -53,6 +55,100 @@ module.PersistentTags = core.ImageGridFeatures.Feature({
//
var TagUIActions = actions.Actions({
// XXX use global tag list... (???)
showTagCloud: ['Tag|Edit|Image/$Tags...',
core.doc`
`,
{dialogTitle: function(_, gids){
return (gids.length == 1 && gids[0] == 'marked') ?
'Marked image tags'
: gids.length > 1 ?
'Tags of: '+ gids.join(', ')
: 'Tags' }},
widgets.makeUIDialog(function(...gids){
var that = this
gids = gids.length == 0 ? ['current'] : gids
// handle 'marked' keyword...
gids = gids
.map(function(gid){
return gid == 'marked' ? that.marked : gid })
.reduce(function(res, cur){
return res.concat(cur instanceof Array ? cur : [cur]) }, [])
.unique()
// XXX
var removeTag = function(tag){
console.log('REMOVE TAG:', tag)
}
return browse.makeLister(null, function(path, make){
var tags = that.data.getTags(gids)
// tags...
// XXX make this a group...
// XXX indicate if some of the gids are tagged...
// ...need three states per tag:
// - on - all are tagged
// - partial - some are tagged
// - off - none are tagged
// XXX add key binding to delete a tag...
Object.keys(that.data.tags || {})
.sort()
.map(function(tag){
return make(tag, {
cls: tags.indexOf(tag) >= 0 ? 'tagged' : '',
style: {
opacity: tags.indexOf(tag) >= 0 ? '' : '0.3'
},
open: function(){
var e = $(this)
var on = e.css('opacity')
on = on == '' || on == '1'
e.css('opacity', on ? 0.3 : '')
on ?
that.data.untag(tag, gids)
: that.data.tag(tag, gids)
},
buttons: [
// remove tag button...
['&times;', removeTag.bind(that, tag) ],
],
})
})
make.Separator()
make.Editable('$New...', {
clear_on_edit: true,
editdone: function(evt, tag){
tag = tag.trim()
// no empty tags...
if(tag == ''){
return
}
that.data.tag(tag, gids)
// update tag list...
make.dialog
.update()
// select the new tag...
.then(function(){
make.dialog.select(tag) })
},
})
}, {
cloudView: true,
close: function(){ that.refresh() },
})
})],
showMakedTagCoud: ['Tag|Mark/$Tags of marked images...',
'showTagCloud: "marked"'],
// XXX crop/filter by tags...
// XXX
})

View File

@ -22,7 +22,7 @@ var PreCacheActions = actions.Actions({
'preload-radius': 5,
// Sources to preload...
'preload-sources': ['bookmark', 'selected'],
'preload-sources': ['bookmark', 'marked'],
},
// NOTE: this will not work from chrome when loading from a local fs...
@ -75,7 +75,7 @@ var PreCacheActions = actions.Actions({
//
// Sources supported:
// <tag> - pre-load images tagged with <tag>
// (default: ['bookmark', 'selected'])
// (default: ['bookmark', 'marked'])
// <ribbon-gid> - pre-cache from a specific ribbon
// 'ribbon' - pre-cache from current ribbon
// 'order' - pre-cache from images in order
@ -115,7 +115,7 @@ var PreCacheActions = actions.Actions({
: (this.data.getImage(target)
|| this.data.getImage(target, 'after'))
sources = sources || this.config['preload-sources'] || ['bookmark', 'selected']
sources = sources || this.config['preload-sources'] || ['bookmark', 'marked']
sources = sources.constructor !== Array ? [sources] : sources
radius = radius || this.config['preload-radius'] || 9

View File

@ -76,7 +76,7 @@ class IGRibbon extends preact.Component {
var images = data.ribbons[ribbon]
.map(function(gid){
var marks = data.tags.selected.indexOf(gid) >= 0 ?
var marks = data.tags.marked.indexOf(gid) >= 0 ?
h(IGImageMark, {
gid: gid,
type: 'selected',

View File

@ -477,7 +477,7 @@ var StatusBarActions = actions.Actions({
// ...this also simpler than handling '?' and other
// special toggler args in the handler...
var tags = this.data ? this.data.getTags(gid) : []
var tag = type == 'mark' ? 'selected' : 'bookmark'
var tag = type == 'mark' ? 'marked' : 'bookmark'
var on = item.hasClass('on')
item[tags.indexOf(tag) < 0 ?
'removeClass'

View File

@ -236,8 +236,8 @@ var VirtualDOMRibbonsPrototype = {
// XXX STUB: make this extensible...
tags.indexOf('bookmark') >= 0
&& marks.push('bookmark')
tags.indexOf('selected') >= 0
&& marks.push('selected')
tags.indexOf('marked') >= 0
&& marks.push('marked')
return marks
.map(function(type){

View File

@ -895,7 +895,7 @@ module.Dialogs = core.ImageGridFeatures.Feature({
&& this.toggleOverlayBlur(this.config['ui-overlay-blur'])
}],
['__call__',
function(res, action){
function(res, action, args){
//if(res instanceof jQuery || res instanceof widget.Widget){
// var elem = (res.dom || res)
if(res instanceof widget.Widget){
@ -904,7 +904,10 @@ module.Dialogs = core.ImageGridFeatures.Feature({
var title = this.getActionAttr(action, 'dialogTitle')
title ?
elem.attr('dialog-title', title)
elem.attr('dialog-title',
title instanceof Function ?
title.call(this, action, args)
: title)
: !elem.attr('keep-dialog-title')
&& !this.getActionAttr(action, 'keepDialogTitle')
&& elem.attr('dialog-title', this.getDocTitle(action))

View File

@ -2885,6 +2885,15 @@ var DataPrototype = {
var DataWithTagsPrototype = {
// tags store...
//
// Format:
// {
// <tag>: [<gid>, ...],
// ...
// }
tags: null,
// XXX hate manual super calls...
// ....is there a way not to say DataPrototype here???
__gid_lists: DataPrototype.__gid_lists.concat(['tags']),

View File

@ -129,35 +129,14 @@ function(data){
/* This is best kept as a separate entity...
// XXX EXPERIMENTAL...
/* XXX template...
module.VERSIONS['3.1'] =
function(data){
res = module.VERSIONS['3.0'](data)
res.version = '3.1'
res.order_list = data.order_list != null ? JSON.parse(JSON.stringify(data.order_list)) : null
return res
}
*/
/* XXX we do not have a ref to images...
module.VERSIONS['3.1'] =
function(data){
res = module.VERSIONS['3.0'](data)
var res = data.version < '3.0' ? module.VERSIONS['3.0'](data) : data
res.version = '3.1'
// XXX we do not have a ref to images here...
Object.values(res.images || {})
.forEach(function(img){
Object.keys(img.preview)
.forEach(function(res){
var p = img.preview[res]
img.preview[res] = p.indexOf('%20') >= 0 ? decodeURI(p) : p
})
})
// XXX
return res
}

View File

@ -290,7 +290,7 @@ function(text, options){
// stop_propagation: 'open',
//
// // Called when editing is abrted...
// editaborted: <func>,
// editaborted: <func(new-text)>,
//
// // Called when editing is done...
// editdone: <func>,
@ -2253,10 +2253,16 @@ var BrowserPrototype = {
// ...
// },
//
// // element attributes...
// attrs: {
// <attr>: <value>,
// ...
// },
//
// // element css style...
// style: {
// <attr>: <value>,
// }
// }
//
// <buttons> format (optional):
@ -2658,6 +2664,8 @@ var BrowserPrototype = {
opts.attrs
&& res.attr(opts.attrs)
opts.style
&& res.css(opts.style)
//--------------------------------------------- buttons ---
// button container...
@ -4027,6 +4035,10 @@ var BrowserPrototype = {
var dom = this.dom
options = this.options
// handle close event...
options.close
&& this.close(options.close)
// basic permanent interactions...
dom.find('.path')
// NOTE: these are used for full-path editing and are defined