/********************************************************************** * * * **********************************************************************/ ((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') /*********************************************************************/ var RangeActions = actions.Actions({ // .makeBrace('open') // .makeBrace('open', image) // .makeBrace('close') // .makeBrace('close', image) // // XXX this should not be here... makeBrace: ['- Range/', function(type, gid){ var cls = type == 'open' ? 'brace-open' : 'brace-close' var r = this.ribbons.viewer.find('.ribbon') var brace = this.ribbons.getRibbon(gid).find('.mark.'+cls) if(brace.length == 0){ brace = $('') .addClass('mark brace '+cls) } else if(brace.length > 1){ brace = brace.detach().first() } brace .attr('gid', gid) this.ribbons.getImage(gid)[type == 'open' ? 'before' : 'after'](brace) // XXX this does not work for non-current images ... this.ribbons.preventTransitions(r) // XXX is this correct here??? this.focusImage() this.ribbons.restoreTransitions(r) }], // XXX add "brace off screen" indicators.... updateRangeIndicators: ['- Range/', function(){ var update = false var range = this.data.__range // XXX not sure if this sweeping action is the right way to // go but it sure makes things simpler... if(range == null){ update = true this.ribbons.viewer .find('.ribbon .mark.brace') .remove() } else { var that = this this.data.ribbon_order.forEach(function(r){ var a = that.data.getImage(range[0], 'after', r) var b = that.data.getImage(range[1], 'before', r) // only draw braces if some part of the ribbon is // in range... if(a != null && b != null){ that .makeBrace('open', a) .makeBrace('close', b) // remove braces from ribbon... } else { update = true that.ribbons.getRibbon(r) .find('.mark.brace') .remove() } }) } if(update){ var r = this.ribbons.viewer.find('.ribbon') // XXX this does not work for non-current images ... this.ribbons.preventTransitions(r) // XXX is this correct here??? this.focusImage() this.ribbons.restoreTransitions(r) } }], clearRange: ['Range/Clear range', // XXX not sure if this is the right way to go... {browseMode: function(){ return !this.data.__range && 'disabled' }}, function(image){ var r = this.ribbons.viewer.find('.ribbon') delete this.data.__range this.updateRangeIndicators() }], // procedure: // - set brace // when no braces set: // - sets two braces around target image // When a brace is set: // - check brace orientation and set open/close to target // - update braces on all ribbons setRangeBorder: ['Range/Set range border', function(image, type){ var image = this.data.getImage(image) var range = this.data.__range = this.data.__range || [] // no range... if(range.length == 0){ range.push(image) range.push(image) // range set... } else { var a = this.data.getImageOrder(range[0]) var b = this.data.getImageOrder(range[1]) var t = this.data.getImageOrder(image) var i = // type/range conflict... type == 'close' && t < a ? null : type == 'open' && t > b ? null // extend left/right... : t <= a ? 0 : t >= b ? 1 // set left/right limit... : type == 'open' ? 0 : type == 'close' ? 1 // narrow to the closest brace... : a - t < b - t ? 0 : 1 if(i == null){ return } range[i] = image } this.updateRangeIndicators() }], openRange: ['Range/Open range', function(image){ this.setRangeBorder(image, 'open') }], closeRange: ['Range/Close range', function(image){ this.setRangeBorder(image, 'close') }], cropRange: ['Range|Crop/Crop range', // XXX not sure if this is the right way to go... {browseMode: function(){ return !this.data.__range && 'disabled' }}, function(){ var range = this.data.__range var order = this.data.order range ? this.crop(order.slice( order.indexOf(range[0]), order.indexOf(range[1])+1)) : this.crop([]) }], cropRangeOut: ['Range|Crop/Crop out range', // XXX not sure if this is the right way to go... {browseMode: function(){ return !this.data.__range && 'disabled' }}, function(){ var range = this.data.__range var order = this.data.order range ? this.crop(order .slice(0, order.indexOf(range[0])) .concat(order.slice(order.indexOf(range[1])+1))) : this.crop() }], }) var Range = module.Range = core.ImageGridFeatures.Feature({ title: '', doc: '', tag: 'ui-range', depends: [ 'ui', ], actions: RangeActions, handlers: [ [[ 'crop', 'reload', ], function(){ this.updateRangeIndicators() }], ['updateImage', function(_, gid){ var range = this.data.__range if(this.ribbons && range && gid){ var r = this.data.getRibbon(gid) var a = gid == range[0] ? this.makeBrace('open', gid) : this.data.getImage(range[0], 'after', r) var b = gid == range[1] ? this.makeBrace('close', gid) : this.data.getImage(range[1], 'before', r) if(a != null && b != null){ gid == a && this.makeBrace('open', gid) gid == b && this.makeBrace('close', gid) } } }], ['shiftImage.pre', function(gid){ var range = this.data.__range if(this.ribbons && range){ this.ribbons.getImageMarks(gid).filter('.brace').remove() return function(){ this.updateRangeIndicators() } } }], // show/hide off-screen indicators... // XXX STUB: should we animate indicators??? ['setScale.pre', function(scale){ var range = this.data.__range if(!this.ribbons || !range){ return } this.ribbons.getRibbonLocator() .find('.range-offscreen-indicator') .hide() }], [[ 'focusImage', 'setScale', 'updateRangeIndicators', ], function(_, gid){ gid = gid || this.current var that = this var locator = this.ribbons.getRibbonLocator() var range = this.data.__range if(!this.ribbons || !range){ locator.find('.range-offscreen-indicator').remove() return } var Wr = this.ribbons.viewer.width() var W = (Wr / this.scale) / 2 var a = this.data.getImageOrder(range[0]) var b = this.data.getImageOrder(range[1]) var _make = function(gid, ribbon, direction){ var t = ribbon[0].offsetTop var h = ribbon[0].offsetHeight / 2 var i = that.data.getImageOrder(gid) var indicator = locator .find('.range-offscreen-indicator.'+direction+'[gid="'+gid+'"]') // XXX this only works if brace is loaded... if(direction == 'left'){ var brace = ribbon.find('.mark.brace-open') if(brace.length == 0 || brace.offset().left >= 0){ return indicator.remove() } } else if(direction == 'right'){ var brace = ribbon.find('.mark.brace-close') if(brace.length == 0 || brace.offset().left < Wr){ return indicator.remove() } } if(indicator.length == 0){ locator.append($('
') .addClass('range-offscreen-indicator '+direction) .attr('gid', gid)) } var css = {} css.left = (direction == 'left' ? -W : W-(indicator[0] && indicator[0].offsetWidth)) + 'px' css.top = (t + h) + 'px' that.ribbons.preventTransitions(indicator) indicator .css(css) .show() that.ribbons.restoreTransitions(indicator) return indicator } setTimeout(function(){ that.data.ribbon_order.forEach(function(gid){ var ribbon = that.ribbons.getRibbon(gid) _make(gid, ribbon, 'left') _make(gid, ribbon, 'right') }) }, 400) }], ], }) /********************************************************************** * vim:set ts=4 sw=4 : */ return module })