mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-11-03 21:00:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			812 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			812 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
/**********************************************************************
 | 
						|
* 
 | 
						|
*
 | 
						|
*
 | 
						|
**********************************************************************/
 | 
						|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
 | 
						|
(function(require){ var module={} // make module AMD/node compatible...
 | 
						|
/*********************************************************************/
 | 
						|
 | 
						|
var toggler = require('lib/toggler')
 | 
						|
var actions = require('lib/actions')
 | 
						|
var features = require('lib/features')
 | 
						|
var keyboard = require('lib/keyboard')
 | 
						|
 | 
						|
var data = require('imagegrid/data')
 | 
						|
var images = require('imagegrid/images')
 | 
						|
var ribbons = require('imagegrid/ribbons')
 | 
						|
 | 
						|
var core = require('features/core')
 | 
						|
var base = require('features/base')
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*********************************************************************/
 | 
						|
 | 
						|
var makeStateIndicator = function(type){
 | 
						|
	return $('<div>')
 | 
						|
		.addClass('state-indicator-container ' + type || '')
 | 
						|
}
 | 
						|
 | 
						|
// XXX do we need this???
 | 
						|
var makeStateIndicatorItem = function(container, type, text){
 | 
						|
	var item = $('<div>')
 | 
						|
			.addClass('item '+ type || '')
 | 
						|
			.attr('text', text)
 | 
						|
	this.dom.find('.state-indicator-container.'+container)
 | 
						|
		.append(item)
 | 
						|
	return item
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
 | 
						|
// XXX revise how/where info is displayed...
 | 
						|
var StatusBarActions = actions.Actions({
 | 
						|
	config: {
 | 
						|
		'status-bar-mode': 'full',
 | 
						|
		'status-bar-modes': [
 | 
						|
			'none',
 | 
						|
			'minimal',
 | 
						|
			'full',
 | 
						|
		],
 | 
						|
		// XXX make different configurations for different modes instead 
 | 
						|
		// 		of hiding some items... (???)
 | 
						|
		'status-bar-items': [
 | 
						|
			'index',
 | 
						|
			'ribbon',
 | 
						|
			'changes',
 | 
						|
			'gid',
 | 
						|
			'path',
 | 
						|
 | 
						|
			// separates left/right aligned elements...
 | 
						|
			'---',
 | 
						|
 | 
						|
			'edit-mode',
 | 
						|
			'mark',
 | 
						|
			'bookmark',
 | 
						|
		],
 | 
						|
 | 
						|
		// XXX not sure about this...
 | 
						|
		'status-bar-full-only': [
 | 
						|
			'gid',
 | 
						|
			'path',
 | 
						|
		],
 | 
						|
 | 
						|
		'status-bar-index': {
 | 
						|
			'mode': 'normal',
 | 
						|
 | 
						|
			// NOTE: this would need to reconstruct the status bar for 
 | 
						|
			// 		changes to take effect, i.e. call .resetStatusBar()
 | 
						|
			// XXX might be a good idea to run an editor on click on
 | 
						|
			// 		touch devices...
 | 
						|
			'editable': true,
 | 
						|
 | 
						|
			'live-update-on-edit': false,
 | 
						|
		},
 | 
						|
 | 
						|
		'status-bar-ribbon-count': true,
 | 
						|
 | 
						|
		'status-bar-changes-text': '*',
 | 
						|
	},
 | 
						|
 | 
						|
	__statusbar_elements__: {
 | 
						|
		/* item template...
 | 
						|
		item: function(item){
 | 
						|
			// cleanup...
 | 
						|
			if(item == null){
 | 
						|
				// XXX
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			// setup the item DOM...
 | 
						|
			if(typeof(item) == typeof('str')){
 | 
						|
				var type = item
 | 
						|
				item = $('<span>')
 | 
						|
					.addClass('item-example')
 | 
						|
					.attr('type', item)
 | 
						|
					.text('example')
 | 
						|
 | 
						|
			// get stuff from the item...
 | 
						|
			} else {
 | 
						|
				var type = item.attr('type')
 | 
						|
			}
 | 
						|
 | 
						|
			// update the item...
 | 
						|
			// XXX
 | 
						|
 | 
						|
			return item
 | 
						|
		},
 | 
						|
		*/
 | 
						|
		index: function(item, gid, img){
 | 
						|
			// cleanup...
 | 
						|
			if(item == null){
 | 
						|
				return 
 | 
						|
			}
 | 
						|
 | 
						|
			var that = this
 | 
						|
			gid = gid || this.current
 | 
						|
 | 
						|
			// make an element...
 | 
						|
			if(typeof(item) == typeof('str')){
 | 
						|
				var type = item
 | 
						|
				item = $('<span>')
 | 
						|
					.addClass(type)
 | 
						|
					.append(!(this.config['status-bar-index'] || {})['editable'] ?
 | 
						|
						// not-editable...
 | 
						|
						$('<span>')
 | 
						|
							.addClass('position')
 | 
						|
							.attr('info', 'Image number (click to toggle ribbon/global)')
 | 
						|
							// toggle index state...
 | 
						|
							.click(function(){
 | 
						|
								that.toggleStatusBarIndexMode()
 | 
						|
								that.updateStatusBar()
 | 
						|
							})
 | 
						|
						// editable...
 | 
						|
						: $('<span>')
 | 
						|
							.addClass('position editable')
 | 
						|
							.attr('info', 'Image number (click to edit)')
 | 
						|
							.makeEditable({
 | 
						|
								propagate_unhandled_keys: false,
 | 
						|
								reset_on_done: false,
 | 
						|
							})
 | 
						|
							// select image when done...
 | 
						|
							.on('edit-commit', function(_, text){
 | 
						|
								var i = parseInt(text)
 | 
						|
								i = i >= 1 ? i-1
 | 
						|
									: i == null ? 'current'
 | 
						|
									: i
 | 
						|
								that.focusImage(i, 
 | 
						|
									item.hasClass('global') ? 'global' : undefined)
 | 
						|
							})
 | 
						|
							// update image position...
 | 
						|
							// XXX this appears to be run in the node context...
 | 
						|
							.keyup(function(){
 | 
						|
								// XXX KeyboardEvent does not appear to have this...
 | 
						|
								//event.stopPropagation()
 | 
						|
 | 
						|
								if((that.config['status-bar-index'] || {})['live-update-on-edit']){
 | 
						|
									var i = parseInt($(this).text())
 | 
						|
									i = i >= 1 ? i-1
 | 
						|
										: i == null ? 'current'
 | 
						|
										: i
 | 
						|
									that.focusImage(i,
 | 
						|
										item.hasClass('global') ? 'global' : undefined)
 | 
						|
								}
 | 
						|
							})
 | 
						|
							.focus(function(){
 | 
						|
								$(this).selectText()
 | 
						|
							})
 | 
						|
							.blur(function(){
 | 
						|
								that.updateStatusBar()
 | 
						|
							}))
 | 
						|
					.append($('<span>')
 | 
						|
						.addClass('length')
 | 
						|
						.attr('info', 'Image count (click to toggle ribbon/global)')
 | 
						|
						// toggle index state...
 | 
						|
						.click(function(){
 | 
						|
							that.toggleStatusBarIndexMode()
 | 
						|
							that.updateStatusBar()
 | 
						|
						}))
 | 
						|
 | 
						|
			} else {
 | 
						|
				var type = item.attr('type')
 | 
						|
			}
 | 
						|
 | 
						|
			// NOTE: using .toggleStatusBarIndexMode(..) here will fall
 | 
						|
			// 		into an infinite recursion...
 | 
						|
			var cls = (that.config['status-bar-index'] || {})['mode'] || 'normal'
 | 
						|
 | 
						|
			// global index...
 | 
						|
			if(cls == 'global'){
 | 
						|
				var i = this.data ? this.data.getImageOrder(gid) : -1
 | 
						|
				var l = this.data ? this.data.length : 0
 | 
						|
 | 
						|
			// ribbon index...
 | 
						|
			} else {
 | 
						|
				var i = this.data ? this.data.getImageOrder('ribbon', gid) : -1
 | 
						|
				var l = this.data ? this.data.getImages(gid).len : 0
 | 
						|
			}
 | 
						|
 | 
						|
			// update...
 | 
						|
			item
 | 
						|
				.addClass(cls)
 | 
						|
				.removeClass(cls != 'normal' ? 'normal' : 'global')
 | 
						|
				.find('.position:not(:focus)')
 | 
						|
					.text(i >= 0 ? i+1 : '-')
 | 
						|
					.end()
 | 
						|
				.find('.length')
 | 
						|
					.text(l > 0 ? ('/' + l) : '')
 | 
						|
 | 
						|
			return item
 | 
						|
		},
 | 
						|
		ribbon: function(item, gid, img){
 | 
						|
			// cleanup...
 | 
						|
			if(item == null){
 | 
						|
				return 
 | 
						|
			}
 | 
						|
 | 
						|
			var that = this
 | 
						|
 | 
						|
			// get ribbon number...
 | 
						|
			var n = (this.data && this.data.ribbon_order.length > 0) ? 
 | 
						|
				this.data.getRibbonOrder(gid || this.current) 
 | 
						|
				: null
 | 
						|
			var t = (this.config['status-bar-ribbon-count'] && this.data) ?
 | 
						|
			   	this.data.ribbon_order.length 
 | 
						|
				: null
 | 
						|
 | 
						|
			// make an element...
 | 
						|
			if(typeof(item) == typeof('str')){
 | 
						|
				item = $('<span>')
 | 
						|
					.addClass('ribbon-index')
 | 
						|
					.append($('<span>')
 | 
						|
						.addClass('ribbon-number')
 | 
						|
						.attr('info', 'Current ribbon (click to edit)')
 | 
						|
						.makeEditable({
 | 
						|
							propagate_unhandled_keys: false,
 | 
						|
							reset_on_done: false,
 | 
						|
						})
 | 
						|
						.on('edit-commit', function(_, text){
 | 
						|
							var i = parseInt(text)
 | 
						|
							i = i >= 1 ? i-1
 | 
						|
								: i == null ? 'current'
 | 
						|
								: i
 | 
						|
							that.focusRibbon(text == '*' ? that.base : i)
 | 
						|
						})
 | 
						|
						.focus(function(){
 | 
						|
							$(this).selectText()
 | 
						|
						})
 | 
						|
						.blur(function(){
 | 
						|
							that.updateStatusBar()
 | 
						|
						}))
 | 
						|
					.append($('<span>')
 | 
						|
						.addClass('ribbon-count')
 | 
						|
						.attr('info', 'Ribbon count'))
 | 
						|
			}
 | 
						|
 | 
						|
			item
 | 
						|
				.find('.ribbon-number')
 | 
						|
					.html(n != null ? n+1 : '-') 
 | 
						|
					.end()
 | 
						|
				.find('.ribbon-count')
 | 
						|
					.html(t || '') 
 | 
						|
 | 
						|
			// flag the base ribbon...
 | 
						|
			// NOTE: for some reason can't get jQuery .prop(..)/.removeProp(..)
 | 
						|
			// 		to work here...
 | 
						|
			if(this.data && this.data.base 
 | 
						|
					&& this.data.getRibbon(gid) == this.base){
 | 
						|
				item[0].setAttribute('base', '')
 | 
						|
 | 
						|
			} else {
 | 
						|
				item[0].removeAttribute('base')
 | 
						|
			}
 | 
						|
 | 
						|
			return item
 | 
						|
		},
 | 
						|
		changes: function(item, gid, img){
 | 
						|
			// cleanup...
 | 
						|
			if(item == null){
 | 
						|
				return 
 | 
						|
			}
 | 
						|
 | 
						|
			if(typeof(item) == typeof('str')){
 | 
						|
				item = $('<span>')
 | 
						|
					.addClass('changes')
 | 
						|
					.attr('info', 'Unsaved changes')
 | 
						|
			}
 | 
						|
 | 
						|
			//item.html(this.changes !== false ? 
 | 
						|
			//	this.config['status-bar-changes-text'] || '*' 
 | 
						|
			//	: '')
 | 
						|
			// XXX not yet sure about .hasOwnProperty(..) here...
 | 
						|
			item.html(this.hasOwnProperty('changes') && this.changes !== false ? 
 | 
						|
				this.config['status-bar-changes-text'] || '*' 
 | 
						|
				: '')
 | 
						|
 | 
						|
			return item
 | 
						|
		},
 | 
						|
		// XXX handle path correctly...
 | 
						|
		gid: function(item, gid, img){
 | 
						|
			// cleanup...
 | 
						|
			if(item == null){
 | 
						|
				return 
 | 
						|
			}
 | 
						|
 | 
						|
			var that = this
 | 
						|
			gid = gid || this.current
 | 
						|
			img = img || (this.images && gid in this.images && this.images[gid])
 | 
						|
 | 
						|
			// make an element...
 | 
						|
			if(typeof(item) == typeof('str')){
 | 
						|
				var type = item
 | 
						|
				item = $('<span>')
 | 
						|
					.addClass(type + ' expanding-text ')
 | 
						|
					.attr('info', type == 'gid' ? 'Image GID'
 | 
						|
							: type == 'path'? 'Image filename/path'
 | 
						|
							: '')
 | 
						|
					.append($('<span class="shown">'))
 | 
						|
					.append($('<span class="hidden">')
 | 
						|
						// select the text...
 | 
						|
						// XXX should this also copy???
 | 
						|
						.click(function(){
 | 
						|
							$(this).selectText()
 | 
						|
						}))
 | 
						|
 | 
						|
			} else {
 | 
						|
				var type = item.attr('type')
 | 
						|
			}
 | 
						|
 | 
						|
			// update...
 | 
						|
			var txt = ''
 | 
						|
			var text = ''
 | 
						|
 | 
						|
			// gid..
 | 
						|
			if(type == 'gid'){
 | 
						|
				txt = gid ? gid.slice(-6) : '-'
 | 
						|
				text = gid || '-'
 | 
						|
 | 
						|
			// path...
 | 
						|
			// XXX use generic, platform independent path processing...
 | 
						|
			} else if(type == 'path'){
 | 
						|
				// XXX revise this...
 | 
						|
				text = (img && img.path && ((img.base_path || '') +'/'+ img.path) || '---')
 | 
						|
					// remove /./
 | 
						|
					.replace(/[\\\/]\.[\\\/]/, '/')
 | 
						|
				txt = img && ((img.name || '') + (img.ext || '')) || text.split(/[\\\/]/).pop()
 | 
						|
			}
 | 
						|
 | 
						|
			item.find('.shown').text(txt)
 | 
						|
			item.find('.hidden').text(text)
 | 
						|
 | 
						|
			return item
 | 
						|
		},
 | 
						|
		path: 'gid',
 | 
						|
		'edit-mode': function(item){
 | 
						|
			// cleanup...
 | 
						|
			if(item == null){
 | 
						|
				this.__edit_mode_indicator_update
 | 
						|
					&& this.off('keyPress', this.__edit_mode_indicator_update)
 | 
						|
				delete this.__edit_mode_indicator_update
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			var update = this.__edit_mode_indicator_update = this.__edit_mode_indicator_update 
 | 
						|
				|| (function(){
 | 
						|
					var caps = this.keyboard.capslock
 | 
						|
					caps = typeof(event) != 'undefined' && event.getModifierState ? 
 | 
						|
						event.getModifierState('CapsLock')
 | 
						|
						: caps
 | 
						|
					item
 | 
						|
						.attr('info', 'Edit mode ' 
 | 
						|
							+ (caps ? 'on' : 'off')
 | 
						|
							+ ' (Click to update / Press CapsLock to toggle)')
 | 
						|
						[caps ? 'addClass' : 'removeClass']('on')
 | 
						|
				}).bind(this)
 | 
						|
 | 
						|
 | 
						|
			if(typeof(item) == typeof('str')){
 | 
						|
				var type = item
 | 
						|
				item = $('<span>')
 | 
						|
					.addClass('capslock-state expanding-text')
 | 
						|
					.append($('<span class="shown">')
 | 
						|
						.text('E'))
 | 
						|
					.append($('<span class="hidden">')
 | 
						|
						.text('Edit mode'))
 | 
						|
					.click(update)
 | 
						|
 | 
						|
				// XXX need a way to cleanly unhandle this...
 | 
						|
				this.on('keyPress', update)
 | 
						|
			}
 | 
						|
 | 
						|
			update()
 | 
						|
 | 
						|
			return item
 | 
						|
		},
 | 
						|
		// XXX show menu in the appropriate corner...
 | 
						|
		mark: function(item, gid, img){
 | 
						|
			// cleanup...
 | 
						|
			if(item == null){
 | 
						|
				return 
 | 
						|
			}
 | 
						|
 | 
						|
			gid = gid || this.current
 | 
						|
			var that = this
 | 
						|
 | 
						|
			if(typeof(item) == typeof('str')){
 | 
						|
				var type = item
 | 
						|
				item = $('<span>')
 | 
						|
					.addClass(type + 'ed')
 | 
						|
					.attr('info', 'Image '
 | 
						|
						+(type == 'mark' ? 'selection' : 'bookmark')
 | 
						|
						+' status (click to toggle)')
 | 
						|
					.click(function(){
 | 
						|
						that['toggle'+type.capitalize()]()
 | 
						|
					})
 | 
						|
					// toggle action menu...
 | 
						|
					// XXX show this in the appropriate corner...
 | 
						|
					.on('contextmenu', function(){
 | 
						|
						event.preventDefault()
 | 
						|
						event.stopPropagation()
 | 
						|
 | 
						|
						that.browseActions('/'+ type.capitalize() +'/')
 | 
						|
					})
 | 
						|
 | 
						|
			} else {
 | 
						|
				var type = item.attr('type')
 | 
						|
			}
 | 
						|
 | 
						|
			// NOTE: we are not using .toggleMark('?') and friends 
 | 
						|
			// 		here to avoid recursion as we might be handling 
 | 
						|
			// 		them here...
 | 
						|
			// 		...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'
 | 
						|
			item[tags.indexOf(tag) < 0 ?
 | 
						|
					'removeClass' 
 | 
						|
					: 'addClass']('on')
 | 
						|
 | 
						|
			return item
 | 
						|
		},
 | 
						|
		bookmark: 'mark', 
 | 
						|
	},
 | 
						|
 | 
						|
	// NOTE: to reset the status bar cycle through 'none' mode to 
 | 
						|
	// 		reconstruct all the items.
 | 
						|
	toggleStatusBar: ['Interface/Status bar mode',
 | 
						|
		toggler.CSSClassToggler(
 | 
						|
			// get/construct status bar...
 | 
						|
			// XXX change class...
 | 
						|
			function(){ 
 | 
						|
				// no viewer yet...
 | 
						|
				if(!this.ribbons || !this.dom){
 | 
						|
					return $()
 | 
						|
				}
 | 
						|
 | 
						|
				var bar = this.dom.find('.state-indicator-container.global-info') 
 | 
						|
				if(bar.length == 0){
 | 
						|
					bar = makeStateIndicator('global-info overlay-info statusbar') 
 | 
						|
						.addClass(this.config['status-bar-mode'] 
 | 
						|
							|| this.config['status-bar-modes'][0] 
 | 
						|
							|| '')
 | 
						|
						.on('mouseover', function(){
 | 
						|
							var t = $(event.target)
 | 
						|
							
 | 
						|
							var info = t.attr('info') 
 | 
						|
								|| t.parents('.overlay-info, [info]').first().attr('info')
 | 
						|
 | 
						|
							if(info){
 | 
						|
								bar.find('.info').text(info)
 | 
						|
							}
 | 
						|
						})
 | 
						|
						.on('mouseout', function(){
 | 
						|
							bar.find('.info').empty()
 | 
						|
						})
 | 
						|
						.appendTo(this.dom)
 | 
						|
				}
 | 
						|
				return bar
 | 
						|
			}, 
 | 
						|
			function(){ return this.config['status-bar-modes'] },
 | 
						|
			// XXX check if we will be getting gid reliably...
 | 
						|
			function(state, bar, gid){ 
 | 
						|
				// do not do anything unless the status bar exists...
 | 
						|
				if(bar.length == 0){
 | 
						|
					return
 | 
						|
				}
 | 
						|
				var that = this
 | 
						|
				this.config['status-bar-mode'] = state 
 | 
						|
 | 
						|
				var _getHandler = function(key){
 | 
						|
					var elems = that.__statusbar_elements__ || {}
 | 
						|
					var base_elems = StatusBarActions.__statusbar_elements__ || {}
 | 
						|
 | 
						|
					var handler = elems[key] || base_elems[key]
 | 
						|
 | 
						|
					if(handler == null){
 | 
						|
						return
 | 
						|
					}
 | 
						|
 | 
						|
					// handle aliases...
 | 
						|
					var seen = []
 | 
						|
					while(typeof(handler) == typeof('str')){
 | 
						|
						seen.push(handler)
 | 
						|
						var handler = elems[handler] || base_elems[handler]
 | 
						|
						// check for loops...
 | 
						|
						if(seen.indexOf(handler) >= 0){
 | 
						|
							console.error('state indicator alias loop detected at:', key)
 | 
						|
							handler = null
 | 
						|
							break
 | 
						|
						}
 | 
						|
					}
 | 
						|
 | 
						|
					return handler
 | 
						|
				}
 | 
						|
 | 
						|
				// destroy...
 | 
						|
				if(state == 'none'){
 | 
						|
					// notify items that they are removed...
 | 
						|
					bar.children()
 | 
						|
						.each(function(i, item){
 | 
						|
							item = $(item)
 | 
						|
							var type = item.attr('type') 
 | 
						|
 | 
						|
							if(type == null){
 | 
						|
								return
 | 
						|
							}
 | 
						|
 | 
						|
							var handler = _getHandler(type)
 | 
						|
 | 
						|
							if(handler != null){
 | 
						|
								handler.call(that, null) 
 | 
						|
							}
 | 
						|
						})
 | 
						|
					bar.empty()
 | 
						|
 | 
						|
				// build/update...
 | 
						|
				} else {
 | 
						|
					gid = gid || this.current
 | 
						|
					var img = this.images && this.images[gid]
 | 
						|
 | 
						|
					// build...
 | 
						|
					if(bar.children().length <= 0){
 | 
						|
						var items = this.config['status-bar-items'].slice()
 | 
						|
 | 
						|
						// rearrange the tail section...
 | 
						|
						// NOTE: this is here as we need to push the floated
 | 
						|
						// 		right items in reverse order...
 | 
						|
						var i = items.indexOf('---')
 | 
						|
						items = i >= 0 ? 
 | 
						|
							items.concat(items.splice(i+1, items.length).reverse())
 | 
						|
							: items
 | 
						|
 | 
						|
						items.forEach(function(item){
 | 
						|
							// spacer...
 | 
						|
							if(item == '---'){
 | 
						|
								//item = $('<span class="spacer">')
 | 
						|
								item = $('<span class="spacer info">')
 | 
						|
 | 
						|
							// info items...
 | 
						|
							} else {
 | 
						|
								var handler = _getHandler(item)
 | 
						|
 | 
						|
								var type = item
 | 
						|
								item = (handler ? 
 | 
						|
										handler.call(that, item, gid, img) 
 | 
						|
										: $('<span>'))
 | 
						|
									.attr('type', item)
 | 
						|
 | 
						|
								if('status-bar-full-only' in that.config 
 | 
						|
										&& that.config['status-bar-full-only'].indexOf(type) >= 0){
 | 
						|
									item.addClass('full-only')
 | 
						|
								}
 | 
						|
							}
 | 
						|
 | 
						|
							bar.append(item)
 | 
						|
						})
 | 
						|
 | 
						|
					// update...
 | 
						|
					} else {
 | 
						|
						var items = bar.children()
 | 
						|
							.each(function(i, item){
 | 
						|
								item = $(item)
 | 
						|
								var type = item.attr('type') 
 | 
						|
 | 
						|
								if(type == null){
 | 
						|
									return
 | 
						|
								}
 | 
						|
 | 
						|
								var handler = _getHandler(type)
 | 
						|
 | 
						|
								if(handler != null){
 | 
						|
									handler.call(that, item, gid, img) 
 | 
						|
								}
 | 
						|
							})
 | 
						|
					}
 | 
						|
				}
 | 
						|
			})],	
 | 
						|
	updateStatusBar: ['- Interface/Update satus bar',
 | 
						|
		function(){ this.toggleStatusBar('!') }],
 | 
						|
 | 
						|
	resetStatusBar: ['Interface/Reset status bar',
 | 
						|
		function(){
 | 
						|
			var mode = this.toggleStatusBar('?')
 | 
						|
			this.toggleStatusBar('none')
 | 
						|
			this.toggleStatusBar(mode)
 | 
						|
		}],
 | 
						|
 | 
						|
	// XXX should these be here???
 | 
						|
	// XXX should this show a dialog???
 | 
						|
	editStatusBarIndex: ['- Interface/Edit image focus position in statusbar',
 | 
						|
		function(){
 | 
						|
			if((this.config['status-bar-index'] || {} )['editable']){
 | 
						|
				this.toggleStatusBar('?') == 'none' && this.toggleStatusBar()
 | 
						|
 | 
						|
				// XXX do this better...
 | 
						|
				this.dom.find('.global-info .index .position').focus().click()
 | 
						|
			}
 | 
						|
		}],
 | 
						|
	editStatusBarRibbon: ['- Interface/Edit ribbon focus position in statusbar',
 | 
						|
		function(){
 | 
						|
			this.toggleStatusBar('?') == 'none' && this.toggleStatusBar()
 | 
						|
 | 
						|
			// XXX do this better...
 | 
						|
			this.dom.find('.global-info .ribbon-number').focus().click()
 | 
						|
		}],
 | 
						|
	toggleStatusBarIndexMode: ['Interface/Status bar index mode',
 | 
						|
		toggler.CSSClassToggler(
 | 
						|
			function(){ return this.dom.find('.global-info .index') },
 | 
						|
			['normal', 'global'],
 | 
						|
			function(state){
 | 
						|
				this.toggleStatusBar('?') == 'none' && this.toggleStatusBar()
 | 
						|
 | 
						|
				// prepare for saving the config...
 | 
						|
				this.config['status-bar-index'] = 
 | 
						|
					JSON.parse(JSON.stringify(this.config['status-bar-index']))
 | 
						|
				this.config['status-bar-index']['mode'] = state
 | 
						|
 | 
						|
				this.updateStatusBar()
 | 
						|
			})],
 | 
						|
 | 
						|
	// XXX revise...
 | 
						|
	showStatusBarInfo: ['- Interface/',
 | 
						|
		function(text){
 | 
						|
			var bar = this.dom.find('.state-indicator-container.global-info') 
 | 
						|
 | 
						|
			if(text){
 | 
						|
				bar.find('.info').text(text)
 | 
						|
 | 
						|
			} else {
 | 
						|
				bar.find('.info').empty()
 | 
						|
			}
 | 
						|
		}],
 | 
						|
})
 | 
						|
 | 
						|
var StatusBar = 
 | 
						|
module.StatusBar = core.ImageGridFeatures.Feature({
 | 
						|
	title: '',
 | 
						|
	doc: '',
 | 
						|
 | 
						|
	tag: 'ui-status-bar',
 | 
						|
	depends: [
 | 
						|
		'ui',
 | 
						|
 | 
						|
		// XXX this is here to enable context menu 
 | 
						|
		// 		see: StatusBarActions.__statusbar_elements__.mark(..)
 | 
						|
		'ui-browse-actions',
 | 
						|
	],
 | 
						|
 | 
						|
	actions: StatusBarActions,
 | 
						|
 | 
						|
	handlers: [
 | 
						|
		['start',
 | 
						|
			function(){
 | 
						|
				this.toggleStatusBar(this.config['status-bar-mode'])
 | 
						|
			}],
 | 
						|
		['focusImage clear markChanged',
 | 
						|
			function(){
 | 
						|
				this.updateStatusBar()
 | 
						|
			}],
 | 
						|
		[[
 | 
						|
			'tag',
 | 
						|
			'untag',
 | 
						|
		],
 | 
						|
			function(res, tags, gids){
 | 
						|
				// trigger only when current image is affected...
 | 
						|
				if(gids.constructor === Array 
 | 
						|
						&& (gids.indexOf('current') >= 0 
 | 
						|
							|| gids.indexOf(this.current) >= 0)
 | 
						|
						|| this.data.getImage(gids) == this.current){
 | 
						|
					this.updateStatusBar()
 | 
						|
				}
 | 
						|
			}],
 | 
						|
 | 
						|
		['ribbonPanning.post',
 | 
						|
			function(_, gid){
 | 
						|
				gid == this.data.getRibbon() && this.updateStatusBar()
 | 
						|
			}],
 | 
						|
 | 
						|
		// Workspace...
 | 
						|
		['saveWorkspace',
 | 
						|
			core.makeWorkspaceConfigWriter(
 | 
						|
				function(){ return Object.keys(StatusBar.config) })],
 | 
						|
		['loadWorkspace',
 | 
						|
			core.makeWorkspaceConfigLoader(
 | 
						|
				function(){ 
 | 
						|
					return Object.keys(StatusBar.config) },
 | 
						|
				function(workspace){
 | 
						|
					// XXX not sure about this protocol yet...
 | 
						|
					if(this.workspace == 'ui-chrome-hidden'){
 | 
						|
						this.toggleStatusBar('none')
 | 
						|
 | 
						|
					} else {
 | 
						|
						'status-bar-mode' in workspace ?
 | 
						|
							this.toggleStatusBar(workspace['status-bar-mode'])
 | 
						|
							: this.toggleStatusBar(this.config['status-bar-mode'])
 | 
						|
					}
 | 
						|
				})],
 | 
						|
	],
 | 
						|
})
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//---------------------------------------------------------------------
 | 
						|
 | 
						|
// XXX
 | 
						|
var GlobalStateIndicator = 
 | 
						|
module.GlobalStateIndicator = core.ImageGridFeatures.Feature({
 | 
						|
	title: '',
 | 
						|
	doc: '',
 | 
						|
 | 
						|
	tag: 'ui-global-state-indicator',
 | 
						|
	depends: [
 | 
						|
		'ui'
 | 
						|
		//'ui-single-image-view',
 | 
						|
	],
 | 
						|
})
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//---------------------------------------------------------------------
 | 
						|
// XXX
 | 
						|
// XXX might also be a good idea to use the similar mechanism for tips...
 | 
						|
 | 
						|
var StatusLogActions = actions.Actions({
 | 
						|
	config: {
 | 
						|
		// NOTE: if this is 0 then do not trim the log...
 | 
						|
		'ui-status-log-size': 100,
 | 
						|
 | 
						|
		'ui-status-fade': 1000,
 | 
						|
	},
 | 
						|
 | 
						|
	// XXX should this be here or in a separate feature???
 | 
						|
	statusLog: ['Interface/Show status log',
 | 
						|
		function(){
 | 
						|
			// XXX use list
 | 
						|
		}],
 | 
						|
	clearStatusLog: ['Interface/Clear status log',
 | 
						|
		function(){
 | 
						|
			delete this.__status_log
 | 
						|
		}],
 | 
						|
	statusMessage: ['- Interface/',
 | 
						|
		function(){
 | 
						|
			var msg = args2array(arguments)
 | 
						|
			if(msg.len == 0){
 | 
						|
				return
 | 
						|
			}
 | 
						|
			var log = this.__status_log = this.__status_log || []
 | 
						|
			
 | 
						|
			// XXX should we convert here and how???
 | 
						|
			log.push(msg.join(' '))
 | 
						|
 | 
						|
			// truncate the log...
 | 
						|
			var s = this.config['ui-status-log-size']
 | 
						|
			if(s != 0 && log.length > (s || 100)){
 | 
						|
				log.splice(0, log.length - (s || 100))
 | 
						|
			}
 | 
						|
 | 
						|
			// XXX show the message above the status bar (same style)...
 | 
						|
			// XXX
 | 
						|
		}],
 | 
						|
})
 | 
						|
 | 
						|
var StatusLog = 
 | 
						|
module.StatusLog = core.ImageGridFeatures.Feature({
 | 
						|
	title: '',
 | 
						|
	doc: '',
 | 
						|
 | 
						|
	tag: 'ui-status-log',
 | 
						|
	depends: [
 | 
						|
		'ui'
 | 
						|
	],
 | 
						|
 | 
						|
	actions: StatusLogActions,
 | 
						|
})
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**********************************************************************
 | 
						|
* vim:set ts=4 sw=4 :                               */ return module })
 |