Github user sjcorbett commented on a diff in the pull request:
https://github.com/apache/incubator-brooklyn/pull/156#discussion_r17302702
--- Diff: usage/jsgui/src/main/webapp/assets/js/view/entity-config.js ---
@@ -22,146 +22,473 @@
* @type {*}
*/
define([
- "underscore", "jquery", "backbone", "brooklyn-utils",
- "view/viewutils", "model/config-summary", "text!tpl/apps/config.html",
+ "underscore", "jquery", "backbone", "brooklyn-utils", "zeroclipboard",
"view/viewutils",
+ "model/config-summary", "text!tpl/apps/config.html",
"text!tpl/apps/config-name.html",
"jquery-datatables", "datatables-extensions"
-], function (_, $, Backbone, Util, ViewUtils, ConfigSummary, ConfigHtml) {
+], function (_, $, Backbone, Util, ZeroClipboard, ViewUtils,
ConfigSummary, ConfigHtml, ConfigNameHtml) {
+ // TODO consider extracting all such usages to a shared ZeroClipboard
wrapper?
+ ZeroClipboard.config({ moviePath: 'assets/js/libs/ZeroClipboard.swf'
});
+
+ var configHtml = _.template(ConfigHtml),
+ configNameHtml = _.template(ConfigNameHtml);
+
+ // TODO refactor to share code w entity-sensors.js
+ // in meantime, see notes there!
var EntityConfigView = Backbone.View.extend({
- template:_.template(ConfigHtml),
+ template: configHtml,
configMetadata:{},
refreshActive:true,
+ zeroClipboard: null,
+
events:{
'click .refresh':'refreshNow',
'click .filterEmpty':'toggleFilterEmpty',
- 'click .toggleAutoRefresh':'toggleAutoRefresh'
+ 'click .toggleAutoRefresh':'toggleAutoRefresh',
+
+ 'mouseup .valueOpen':'valueOpen',
+ 'mouseover #config-table tbody tr':'noteFloatMenuActive',
+ 'mouseout #config-table tbody tr':'noteFloatMenuSeemsInactive',
+ 'mouseover .floatGroup':'noteFloatMenuActive',
+ 'mouseout .floatGroup':'noteFloatMenuSeemsInactive',
+ 'mouseover .clipboard-item':'noteFloatMenuActiveCI',
+ 'mouseout .clipboard-item':'noteFloatMenuSeemsInactiveCI',
+ 'mouseover .hasFloatLeft':'showFloatLeft',
+ 'mouseover .hasFloatDown':'enterFloatDown',
+ 'mouseout .hasFloatDown':'exitFloatDown',
+ 'mouseup .light-popup-menu-item':'closeFloatMenuNow',
},
+
initialize:function () {
- _.bindAll(this)
- this.$el.html(this.template({ }));
+ _.bindAll(this);
+ this.$el.html(this.template());
+
var that = this,
$table = this.$('#config-table');
that.table = ViewUtils.myDataTable($table, {
"fnRowCallback": function( nRow, aData, iDisplayIndex,
iDisplayIndexFull ) {
- $(nRow).attr('id', aData[0])
+ $(nRow).attr('id', aData[0]);
$('td',nRow).each(function(i,v){
- if (i==1) $(v).attr('class','config-actions');
- if (i==2) $(v).attr('class','config-value');
- })
+ if (i==1) $(v).attr('class','config-value');
+ });
return nRow;
},
"aoColumnDefs": [
- { // name, with tooltip
+ { // name (with tooltip)
"mRender": function ( data, type, row
) {
- // name (column 1) should have
tooltip title
- return '<span class="config-name"
'+
- 'rel="tooltip" title='+
- (data['description'] ?
-
'"<b>'+Util.escape(data['description'])+'</b><br/>' : '')+
-
'('+Util.escape(data['type'])+')" data-placement="left">'+
-
Util.escape(data['name'])+'</span>';
+ var actions =
that.getConfigActions(data.name);
+ var context = _.extend(data, {
+ description:
data['description'], type: data['type']});
+ return configNameHtml(context);
},
"aTargets": [ 1 ]
},
- { // actions (just one, json link hard
coded here apart from url)
- "mRender": function ( link, type, row
) {
- if (link=="") return "";
- var text=""
- var icon="icon-file"
- var title="JSON direct link"
- var actionsText =
- "<a
href='"+Util.escape(link)+"'"+
- "
class='"+Util.escape(icon)+"'"+
- "
title='"+Util.escape(title)+"'>"+
-
Util.escape(text)+"</a>\n";
- //just one action here
- return actionsText;
- },
- "aTargets": [ 2 ]
- },
{ // value
"mRender": function ( data, type, row
) {
- return Util.toDisplayString(data)
+ var escapedValue =
Util.toDisplayString(data);
+ if (type!='display')
+ return escapedValue;
+
+ var hasEscapedValue =
(escapedValue!=null && (""+escapedValue).length > 0);
+ configName = row[0],
+ actions =
that.getConfigActions(configName);
+
+ // datatables doesn't seem to
expose any way to modify the html in place for a cell,
+ // so we rebuild
+
+ var result = "<span
class='value'>"+(hasEscapedValue ? escapedValue : '')+"</span>";
+ if (actions.open)
+ result = "<a
href='"+actions.open+"'>" + result + "</a>";
+ if (escapedValue==null ||
escapedValue.length < 3)
+ // include whitespace so we
can click on it, if it's really small
+ result +=
" ";
+
+ var $row =
$('tr[id="'+configName+'"]');
+ var existing =
$row.find('.dynamic-contents');
+ // for the json url, use the full
url (relative to window.location.href)
+ var jsonUrl = actions.json ? new
URI(actions.json).resolve(new URI(window.location.href)).toString() : null;
+ // prefer to update in place, so
menus don't disappear, also more efficient
+ // (but if menu is changed, we do
recreate it)
+ if (existing.length>0) {
+ if
(that.checkFloatMenuUpToDate($row, actions.open, '.actions-open',
'open-target') &&
+
that.checkFloatMenuUpToDate($row, escapedValue, '.actions-copy') &&
+
that.checkFloatMenuUpToDate($row, actions.json, '.actions-json-open',
'open-target') &&
+
that.checkFloatMenuUpToDate($row, jsonUrl, '.actions-json-copy', 'copy-value'))
{
+// log("updating in place
"+configName)
+ existing.html(result);
+ return
$row.find('td.config-value').html();
+ }
+ }
+
+ // build the menu - either
because it is the first time, or the actions are stale
+// log("creating "+configName);
+
+ var downMenu = "";
+ if (actions.open)
+ downMenu += "<div
class='light-popup-menu-item valueOpen actions-open'
open-target='"+actions.open+"'>" +
+ "Open</div>";
+ if (hasEscapedValue) downMenu +=
+ "<div
class='light-popup-menu-item handy valueCopy actions-copy clipboard-item'>Copy
Value</div>";
+ if (actions.json) downMenu +=
+ "<div
class='light-popup-menu-item handy valueOpen actions-json-open'
open-target='"+actions.json+"'>" +
+ "Open REST Link</div>";
+ if (actions.json &&
hasEscapedValue) downMenu +=
+ "<div
class='light-popup-menu-item handy valueCopy actions-json-copy clipboard-item'
copy-value='"+
+ jsonUrl+"'>Copy REST
Link</div>";
+ if (downMenu=="") {
+// log("no actions for
"+configName);
+ downMenu +=
+ "<div
class='light-popup-menu-item'>(no actions)</div>";
+ }
+ downMenu = "<div
class='floatDown'><div class='light-popup'><div class='light-popup-body'>"
+ + downMenu +
+ "</div></div></div>";
+ result = "<span
class='hasFloatLeft handy dynamic-contents'>" + result +
+ "</span>" +
+ "<div
class='floatLeft'><span class='icon-chevron-down hasFloatDown'></span>" +
+ downMenu +
+ "</div>";
+ result = "<div
class='floatGroup'>" + result + "</div>";
+ // also see updateFloatMenus
which wires up the JS for these classes
+
+ return result;
},
- "aTargets": [ 3 ]
+ "aTargets": [ 2 ]
},
// ID in column 0 is standard (assumed in
ViewUtils)
- { "bVisible": false, "aTargets": [ 0 ]
/* hide id column */ }
+ { "bVisible": false, "aTargets": [ 0 ] }
]
});
- ViewUtils.addFilterEmptyButton(that.table);
- ViewUtils.addAutoRefreshButton(that.table);
- ViewUtils.addRefreshButton(that.table);
- that.loadConfigMetadata();
- that.updateConfigPeriodically();
- that.toggleFilterEmpty();
- },
- render:function () {
- this.updateConfigNow();
+
+ this.zeroClipboard = new ZeroClipboard();
+ this.zeroClipboard.on( "dataRequested" , function(client) {
+ var text = $(this).attr('copy-value');
+ if (!text) text =
$(this).closest('.floatGroup').find('.value').html();
+ try {
+// log("Copying text '"+text+"' to clipboard");
+ client.setText(text);
+
+ var $widget = $(this);
+ var oldHtml = $widget.html();
+ var fnRestore = _.once(function() {
$widget.html(oldHtml); });
+ // show the word copied for feedback;
+ // NB this occurs on mousedown, due to how flash
plugin works
+ // (same style of feedback and interaction as github)
+ // the other "clicks" are now triggered by *mouseup*
+ $widget.html('<b>Copied!</b>');
+ setTimeout(fnRestore, 3000);
+
+ // these listeners stay registered until page is
reloaded
+ // but they do nothing after first run, due to use of
_.once
+ // however the timeout is good enough, and actually
desired
+ // because on corner case of
mousedown-moveaway-mouseup,
+ // we want to keep the feedback; so they work, but are
disabled for now.
+ // (remove once we are happy with this behaviour,
since Feb 2014)
+// that.zeroClipboard.on( "mouseout", fnRestore);
+// that.zeroClipboard.on( "mouseup", fnRestore);
+ } catch (e) {
+ log("Zeroclipboard failure; falling back to prompt
mechanism");
+ log(e);
+ Util.promptCopyToClipboard(text);
+ }
+ });
+ // these seem to arrive delayed sometimes, so we also work
with the clipboard-item class events
+ this.zeroClipboard.on( "mouseover", function() {
that.noteFloatMenuZeroClipboardItem(true, this); } );
+ this.zeroClipboard.on( "mouseout", function() {
that.noteFloatMenuZeroClipboardItem(false, this); } );
+ this.zeroClipboard.on( "mouseup", function() {
that.closeFloatMenuNow(); } );
+
+ ViewUtils.addFilterEmptyButton(this.table);
+ ViewUtils.addAutoRefreshButton(this.table);
+ ViewUtils.addRefreshButton(this.table);
--- End diff --
The refresh button seems to do nothing.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---