Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
941f68c
Adding omero.web.open_with to settings.py
will-moore May 4, 2016
8a1bf79
decorator parses settings.OPEN_WITH
will-moore May 4, 2016
1095f60
ome.tree.js uses OPEN_WITH in right-click menu
will-moore May 4, 2016
3aa4d13
flake8 fix
will-moore May 4, 2016
6ebb349
Add support for 'open with' scripts
will-moore May 30, 2016
08f2fcd
Support external urls. try/excpet reverse(url)
will-moore May 30, 2016
4f7e56f
Add action handling to 'open_with' plugins
will-moore May 30, 2016
ee70460
Add TEMP example openwith.js
will-moore May 30, 2016
8a567a7
remove 'script' from hardcoded OMERO.figure openwith
will-moore May 30, 2016
a7cd108
Added fileannotation support to 'open with'
will-moore Jun 17, 2016
3826a91
Add default handling of 'open with...' for file annotations
will-moore Jun 20, 2016
3eaa0be
Remove fileannotation support from open_with
will-moore Jul 4, 2016
52a1cc6
Only pass {id, name, type} to script functions
will-moore Jul 4, 2016
87e9dcd
Wrap isEnabled() and handleAction() in try/catch
will-moore Jul 4, 2016
9497b42
Removing default items from settings.OPEN_WITH
will-moore Jul 4, 2016
94f67dc
Load open_with options via JSON
will-moore Sep 27, 2016
dbc6d74
Merge remote-tracking branch 'origin/develop' into open_with
will-moore Sep 27, 2016
66810ac
Update settings OPEN_WITH doc string and remove 'print'
will-moore Sep 27, 2016
32a5b66
Small fixes, removing try/except, delete openwith.js
will-moore Sep 27, 2016
b14e765
Simplify action function wrapping
will-moore Sep 27, 2016
90019c4
Move OME.setOpenWithEnabledHandler() etc to actions.js
will-moore Sep 28, 2016
bd98e31
Test script_url for 'http...' or use static()
will-moore Sep 28, 2016
08915a2
Fix usage of config 'supported_objects' instead of 'objects'
will-moore Sep 30, 2016
fb3e6e1
Fix handling of Open with: 'supported_objects' in jsTree menu
will-moore Sep 30, 2016
7d9d836
Remove default 'supported_objects'. Now required
will-moore Oct 3, 2016
31344bf
Always return after open_with action()
will-moore Oct 3, 2016
d3664af
Merge remote-tracking branch 'origin/develop' into open_with
will-moore Oct 5, 2016
b19fc2e
Add doc string to urls.py
will-moore Oct 5, 2016
6855cac
Use urlProvider instead of actionHandler for Open with
will-moore Oct 12, 2016
e33d722
Add 'Image viewer' to 'open_with' settings
will-moore Oct 12, 2016
e86448b
Open with plugins enabled=false if error in script
will-moore Oct 12, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions components/tools/OmeroWeb/omeroweb/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,21 @@ def leave_none_unset_int(s):
("Django view which handles display of, or redirection to, the "
"desired full image viewer.")],

# OPEN WITH
"omero.web.open_with":
["OPEN_WITH",
('[["Image viewer", "webindex", {"supported_objects": ["image"],'
'"script_url": "webclient/javascript/ome.openwith_viewer.js"}]]'),
json.loads,
("A list of viewers that can be used to display selected Images "
"or other objects. Each viewer is defined as "
"``[\"Name\", \"url\", options]``. Url is reverse(url). "
"Selected objects are added to the url as ?image=:1&image=2"
"Objects supported must be specified in options with"
"E.g. ``{\"supported_objects\":[\"images\"]}`` "
"to enable viewer for one or more images, "
"``{\"target\":\"_blank\"}`` to open in new tab.")],

# PIPELINE 1.3.20

# Pipeline is an asset packaging library for Django, providing both CSS
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

// openwith.js


// This example 'enabledHandler' code is not needed since we configure
// {'supported_objects': ['image']} to only enable the viewer when a
// single image is selected.
// However, it can be used if you need more flexibility to set enable/disable
// status of your Open with option.
// OME.setOpenWithEnabledHandler("Image viewer", function(selected) {
// // selected is a list of {'id':1, 'name': 'test.tiff', 'type': 'image'}
// // Only enabled for single objects...
// if (selected.length !== 1) return false;
// // Only enable for images
// return (selected[0].type !== 'image') return false;
// });


// We have already configured the base url to be 'webindex' /webclient/ so
// we just need to add 'img_detail/' and the selected image ID
OME.setOpenWithUrlProvider("Image viewer", function(selected, url) {
url += "img_detail/" + selected[0].id + "/";
return url;
});
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,79 @@ $(function() {
}
}
};
if (WEBCLIENT.OPEN_WITH.length > 0) {
// build a submenu of viewers...
var viewers = WEBCLIENT.OPEN_WITH.map(function(v){
return {
"label": v.label,
"action": function() {
var inst = $.jstree.reference('#dataTree'),
sel = inst.get_selected(true),
dtypes = sel.map(function(s){
return s.type + "=" + s.data.id;
}),
query = dtypes.join("&"),
// default url includes objects in query
url = v.url + "?" + query;
// if plugin has added a url provider,
// use it to update the url...
if (v.getUrl) {
// prepare json of selected objects to pass to function
var selJson = sel.map(function(s){
// var o = $.extend({}, s.data.obj);
var o = {'id': s.data.obj.id,
'name': s.data.obj.name,
'type': s.type};
return o;
});
url = v.getUrl(selJson, v.url);
}
// ...otherwise we use default handling...
if (v.target) {
// E.g. target '_blank' tries to open in a new tab
window.open(url, v.target);
} else {
OME.openPopup(url);
}
},
"_disabled": function() {
var sel = $.jstree.reference('#dataTree').get_selected(true),
// selType = 'image' or 'images' or 'dataset'
selType = sel.reduce(function(prev, s){
return s.type + (sel.length > 1 ? "s" : "");
}, "undefined"),
enabled = false;
if (typeof v.isEnabled === "function") {
// If plugin has provided a function 'isEnabled'...
// prepare json of selected objects to pass to function
var selJson = sel.map(function(s){
var o = {'id': s.data.obj.id,
'name': s.data.obj.name,
'type': s.type};
return o;
});
enabled = v.isEnabled(selJson);
return !enabled;
}
// ...Otherwise if supported_objects list is configured...
// v.supported_objects is ['image'] or ['dataset', 'images'] etc.
if (typeof v.supported_objects === "object" && v.supported_objects.length > 0) {
enabled = v.supported_objects.reduce(function(prev, supported){
// E.g. If supported_objects is 'images'...
return prev || supported.indexOf(selType) > -1; // ... selType 'image' OR 'images' are > -1
}, false);
}
return !enabled;
}
};
});
config["open_with"] = {
"label": "Open With...",
"_disabled": false,
"action": false,
"submenu": viewers
};
}

// List of permissions related disabling
// use canLink, canDelete etc classes on each node to enable/disable right-click menu
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,38 @@ OME.hideScriptList = function() {
$("#scriptList").hide();
};

// Helper can be used by 'open with' plugins to add isEnabled()
// handlers to the OPEN_WITH object.
OME.setOpenWithEnabledHandler = function(label, fn) {
// look for label in OPEN_WITH
WEBCLIENT.OPEN_WITH.forEach(function(ow){
if (ow.label === label) {
ow.isEnabled = function() {
// wrap fn with try/catch, since error here will break jsTree menu
var args = Array.from(arguments);
var enabled = false;
try {
enabled = fn.apply(this, args);
} catch (e) {
// Give user a clue as to what went wrong
console.log("Open with " + label + ": " + e);
}
return enabled;
}
}
});
};
// Helper can be used by 'open with' plugins to provide
// a url for the selected objects
OME.setOpenWithUrlProvider = function(label, fn) {
// look for label in OPEN_WITH
WEBCLIENT.OPEN_WITH.forEach(function(ow){
if (ow.label === label) {
ow.getUrl = fn;
}
});
};

OME.toggleFileAnnotationCheckboxes = function(event) {
var checkboxes = $("#fileanns_container input[type=checkbox]");
checkboxes.toggle().prop("checked", false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,24 @@
{% if page_size %}
var PAGE_SIZE = {{ page_size }};
{% endif %}


// ** "Open With" config used by E.g. ome.tree.js **
// Loaded scripts can call OME.setOpenWithEnabledHandler and/or
// OME.setOpenWithActionHandler to override default behaviour
WEBCLIENT.OPEN_WITH = [];
$.getJSON("{% url 'webgateway.views.open_with_options' %}", function(data){
if (data && data.open_with_options) {
WEBCLIENT.OPEN_WITH = data.open_with_options;
// Try to load scripts if specified:
WEBCLIENT.OPEN_WITH.forEach(function(ow){
if (ow.script_url) {
$.getScript(ow.script_url);
}
})
}
});

$(document).ready(function(){
// initially hidden
$("#user_dropdown ul").css('visibility', 'hidden');
Expand Down
9 changes: 8 additions & 1 deletion components/tools/OmeroWeb/omeroweb/webgateway/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,13 @@
'client' is a list of paths for original files on the client when imported
"""

open_with_options = url(r'^open_with/$', 'webgateway.views.open_with_options',
name='open_with_options')
"""
This makes the settings.OPEN_WITH configuration available via json
"""


get_image_rdefs_json = url(r'^get_image_rdefs_json/(?P<img_id>[0-9]+)/$',
'webgateway.views.get_image_rdefs_json',
name="webgateway_get_image_rdefs_json")
Expand Down Expand Up @@ -470,7 +477,7 @@
annotations,
table_query,
object_table_query,

open_with_options,
# Debug stuff

)
41 changes: 40 additions & 1 deletion components/tools/OmeroWeb/omeroweb/webgateway/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from django.http import HttpResponseRedirect, HttpResponseNotAllowed, Http404
from django.template import loader as template_loader
from django.views.decorators.http import require_POST
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse, NoReverseMatch
from django.conf import settings
from django.template import RequestContext as Context
from django.core.servers.basehttp import FileWrapper
Expand All @@ -33,6 +33,7 @@
from plategrid import PlateGrid
from omero_version import build_year
from marshal import imageMarshal, shapeMarshal, rgb_int2rgba
from django.contrib.staticfiles.templatetags.staticfiles import static

try:
from hashlib import md5
Expand Down Expand Up @@ -1522,6 +1523,44 @@ def projectDetail_json(request, pid, conn=None, **kwargs):
return rv


@jsonp
def open_with_options(request, **kwargs):
"""
Make the settings.OPEN_WITH available via JSON
"""
open_with = settings.OPEN_WITH
viewers = []
for ow in open_with:
if len(ow) < 2:
continue
viewer = {}
viewer['label'] = ow[0]
try:
viewer['url'] = reverse(ow[1])
except NoReverseMatch:
viewer['url'] = ow[1]
# try non-essential parameters...
# NB: Need supported_objects OR script_url to enable plugin
try:
if len(ow) > 2:
if 'supported_objects' in ow[2]:
viewer['supported_objects'] = ow[2]['supported_objects']
if 'target' in ow[2]:
viewer['target'] = ow[2]['target']
if 'script_url' in ow[2]:
# If we have an absolute url, use it...
if ow[2]['script_url'].startswith('http'):
viewer['script_url'] = ow[2]['script_url']
else:
# ...otherwise, assume within static
viewer['script_url'] = static(ow[2]['script_url'])
except:
# ignore invalid params
pass
viewers.append(viewer)
return {'open_with_options': viewers}


def searchOptFromRequest(request):
"""
Returns a dict of options for searching, based on
Expand Down