diff --git a/ui (gen4)/features/base.js b/ui (gen4)/features/base.js index adddd9df..d953327d 100755 --- a/ui (gen4)/features/base.js +++ b/ui (gen4)/features/base.js @@ -959,6 +959,41 @@ module.CropActions = actions.Actions({ // // XXX check undo... do we actually need it??? crop: ['Crop/Crop', + core.doc`Crop current state and push it to the crop stack + + A crop is a copy of the data state. When a crop is made the old + state is pushed to the crop stack and a new state is set in it + its place. + + If true (flatten) is passed as the last argument the crop will + be flattened, i.e. ribbons will be merged. + + This is the base crop action/event, so this should be called by + any action implementing a crop. + + Make a full crop... + .crop() + .crop(true) + -> this + + Make a crop keeping only the list of images... + .crop(images) + .crop(images, true) + -> this + + Make a crop and use the given data object... + NOTE: data must be an instance of data.Data + .crop(data) + .crop(data, true) + -> this + + NOTE: this is used as a basis for all the crop operations, so + there is no need to bind to anything but this to handle a + crop unless specific action is required for a specific crop + operation. + NOTE: this is an in-place operation, to make a crop in a new + instance use .clone().crop(..) + `, {undo: 'uncrop'}, function(list, flatten){ list = list || this.data.getImages() diff --git a/ui (gen4)/features/ui-widgets.js b/ui (gen4)/features/ui-widgets.js index cc8881f5..052ae1dd 100755 --- a/ui (gen4)/features/ui-widgets.js +++ b/ui (gen4)/features/ui-widgets.js @@ -481,7 +481,7 @@ var DialogsActions = actions.Actions({ // Get modal container... // // Protocol: - // - get the last modal widgets (CSS selector: .modal-widget) + // - get the last (top) modal widgets (CSS selector: .modal-widget) // - return one of the following: // .data('widget-controller') // element @@ -609,7 +609,9 @@ var DialogsActions = actions.Actions({ .append($('') .text(doc[action][0])) .append($('
') - .text('Features: ' + that.getHandlerSourceTags(action).join(', '))) + .text('Features: ' + + that.getHandlerSourceTags(action) + .join(', '))) .append($('
')) // parse the action doc... .append($('
')
diff --git a/ui (gen4)/features/ui.js b/ui (gen4)/features/ui.js
index 68f4127c..29d6ca2c 100755
--- a/ui (gen4)/features/ui.js	
+++ b/ui (gen4)/features/ui.js	
@@ -1090,9 +1090,12 @@ module.Viewer = core.ImageGridFeatures.Feature({
 					delete this.__viewer_resize
 				}
 			}],
-		// force browser to redraw images after resize...
+		/*/ force browser to redraw images after resize...
+		// NOTE: this fixes a bug where images are not always updated 
+		// 		when off-screen...
 		['resizingDone',
 			function(){ this.scale = this.scale }],
+		//*/
 		// manage the .crop-mode css class...
 		['crop uncrop',
 			function(){
diff --git a/ui (gen4)/lib/widget/browse.js b/ui (gen4)/lib/widget/browse.js
index f7821c22..d3843a37 100755
--- a/ui (gen4)/lib/widget/browse.js	
+++ b/ui (gen4)/lib/widget/browse.js	
@@ -208,6 +208,14 @@ function(text, options){
 // 		// (see: util.makeEditable(..) for more info)
 //		clear_on_edit: false,
 //
+//		// Events to stop propagating up...
+//		//
+//		// This is useful to prevent actions that start should an edit 
+//		// from triggering something else in the dialog...
+//		//
+//		// If false, nothing will get stopped...
+//		stop_propagation: 'open',
+//
 // 		// Called when editing is abrted... 
 // 		editaborted: ,
 //
@@ -223,6 +231,7 @@ function(text, options){
 	options = options || {}
 	var dialog = this.dialog
 	var start_on = options.start_on || 'select'
+	var stop_propagation = options.stop_propagation === false ? false : 'open'
 
 	var getEditable = function(){
 		var editable = elem.find('.text')
@@ -274,6 +283,10 @@ function(text, options){
 					options.abort_on_deselect !== false ? 'edit-abort' : 'edit-commit')
 		})
 
+	stop_propagation
+		&& elem
+			.on(stop_propagation, function(e){ e.stopPropagation() })
+
 	return elem
 }
 
@@ -313,7 +326,6 @@ function(text, options){
 // 		...
 // 	}
 //
-// XXX should this 
 Items.List =
 function(data, options){
 	var make = this
@@ -387,6 +399,11 @@ function(data, options){
 //
 // options format:
 // 	{
+// 		// List identifier, used when multiple lists are drawn in one 
+// 		// dialog...
+// 		// XXX not used yet...
+// 		list_id: ,
+//
 // 		// If true (default), display the "new..." item, if string set 
 // 		// it as item text...
 // 		new_item: |,
@@ -486,6 +503,14 @@ function(data, options){
 // 		if multiple lists need to be edited use multiple (nested) 
 // 		dialogs (one per list)...
 //
+// XXX should this be usable more than once per dialog???
+// 		...would need to:
+// 			- identify and route actions to correct list
+// 			- optionally route actions to list combinations
+//			- identify lists (item attr -> list index)
+//			- store list data by list identifier...
+//			- take care of cases where lists are re-ordered or not 
+//				drawn in some cases -- can't simply use index as id...
 Items.EditableList =
 function(list, options){
 	var make = this
@@ -504,7 +529,12 @@ function(list, options){
 			|| lst
 	}
 
-	var to_remove = dialog.__to_remove = dialog.__to_remove || []
+	dialog.__list = dialog.__list || {}
+	dialog.__to_remove = dialog.__to_remove || {}
+
+	var id = options.list_id || 'default' 
+
+	var to_remove = dialog.__to_remove[id] = dialog.__to_remove[id] || []
 
 	// make a copy of options, to keep it safe from changes we are going
 	// to make...
@@ -524,7 +554,7 @@ function(list, options){
 	// 		or discrete and not done as they come in...
 	lst = !editable ? Object.keys(lst) : lst.slice()
 
-	dialog.__list = lst
+	dialog.__list[id] = lst
 
 	var buttons = options.buttons = (options.buttons || []).slice()
 	var _buttons = {}
@@ -532,7 +562,7 @@ function(list, options){
 	// manual sorting buttons...
 	if(editable && !options.sort){
 		var move = function(p, offset){
-			var l = dialog.__list
+			var l = dialog.__list[id]
 			var i = l.indexOf(p)
 
 			// not in list...
@@ -573,7 +603,7 @@ function(list, options){
 					'⤒'
 					: options.to_top_button,
 				function(p, e){
-					var d = move(p, -dialog.__list.length)
+					var d = move(p, -dialog.__list[id].length)
 					d && e.prevAll().eq(Math.abs(d+1)).before(e)
 				}])
 
@@ -583,7 +613,7 @@ function(list, options){
 					'⤓' 
 					: options.to_bottom_button,
 				function(p, e){
-					var d = move(p, dialog.__list.length)
+					var d = move(p, dialog.__list[id].length)
 					d && e.nextAll().eq(Math.abs(d)).before(e)
 				}])
 
@@ -647,7 +677,7 @@ function(list, options){
 					return
 				}
 
-				lst = dialog.__list
+				lst = dialog.__list[id]
 
 				// list length limit
 				if(options.length_limit 
@@ -686,7 +716,7 @@ function(list, options){
 
 				lst = write(list, lst)
 
-				dialog.__list = lst
+				dialog.__list[id] = lst
 
 				// update list and select new value...
 				dialog.update()
@@ -715,7 +745,7 @@ function(list, options){
 					return
 				}
 
-				lst = dialog.__list
+				lst = dialog.__list[id]
 
 				// remove items...
 				to_remove.forEach(function(e){