mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-24 09:26:43 +01:00
tooltip UI
This commit is contained in:
parent
e5485dd9be
commit
941edf908d
10 changed files with 114 additions and 43 deletions
|
|
@ -38,8 +38,10 @@
|
|||
"webpack-dev-server": "1.15.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"sprintf": "0.1.5",
|
||||
"diff-match-patch": "1.0.0",
|
||||
"numeric": "1.2.6",
|
||||
"jwerty": "0.3.2"
|
||||
"jwerty": "0.3.2",
|
||||
"mustache-loader": "0.3.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ ActionManager.prototype.run = function(actionId, event) {
|
|||
if (action.state.enabled) {
|
||||
action.__handler(this.app, event);
|
||||
} else {
|
||||
this.app.inputManager.info("action '"+actionId+"' is disabled and can't be launched<br>" + action.state.hint);
|
||||
this.app.inputManager.messageSink.info("action '"+actionId+"' is disabled and can't be launched<br>" + action.state.hint);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
26
web/app/3d/ui/bind.js
Normal file
26
web/app/3d/ui/bind.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import {sprintf} from 'sprintf'
|
||||
|
||||
export function Bind(dom, data, policy) {
|
||||
if (!policy) policy = DEFAULT_POLICY;
|
||||
const props = Object.getOwnPropertyNames(data);
|
||||
for (let prop of props) {
|
||||
const node = $(dom).find('[data-bind="'+prop+'"]');
|
||||
if (node.length == 0) continue;
|
||||
let value = data[prop];
|
||||
if (!policy.hideEmptyValue || value || value === 0) {
|
||||
var format = node.attr('bind-format');
|
||||
if (format) {
|
||||
value = sprintf(format, value);
|
||||
}
|
||||
node.text(value);
|
||||
node.show();
|
||||
} else {
|
||||
node.text('');
|
||||
node.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_POLICY = {
|
||||
hideEmptyValue: true
|
||||
};
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import {jwerty} from 'jwerty'
|
||||
import {keymap} from './keymaps/default'
|
||||
import {DefaultMouseEvent, EventData, fit} from './utils'
|
||||
import {Bind} from './bind'
|
||||
import {MessageSink} from './message-sink'
|
||||
import {LoadTemplate, DefaultMouseEvent, EventData, fit} from './utils'
|
||||
|
||||
export function InputManager(app) {
|
||||
this.app = app;
|
||||
|
|
@ -8,19 +10,20 @@ export function InputManager(app) {
|
|||
this.keymap = keymap;
|
||||
this.mouseInfo = new DefaultMouseEvent();
|
||||
this.requestedActionInfo = null;
|
||||
this.actionInfoDom = $(LoadTemplate('action-info')({}));
|
||||
this.messageSink = new MessageSink(this);
|
||||
$(() => {
|
||||
$(document)
|
||||
.on('keydown', (e) => this.handleKeyPress(e))
|
||||
.on('mousedown', (e) => this.clear(e))
|
||||
.on('mouseenter', '.action-item', (e) => this.showActionInfo($(e.target)))
|
||||
.on('mouseleave', '.action-item', (e) => this.emptyInfo())
|
||||
.on('mouseleave', '.action-item', (e) => this.hideActionInfo())
|
||||
.on('mousemove', (e) => this.mouseInfo = e)
|
||||
.on('click', '.action-item', (e) => this.handleActionClick(e));
|
||||
});
|
||||
}
|
||||
|
||||
InputManager.prototype.handleKeyPress = function(e) {
|
||||
console.log(e.keyCode);
|
||||
switch (e.keyCode) {
|
||||
case 27 : this.clear(); break;
|
||||
}
|
||||
|
|
@ -44,7 +47,7 @@ InputManager.prototype.clear = function(e) {
|
|||
this.openMenus = [];
|
||||
}
|
||||
this.requestedActionInfo = null;
|
||||
$('#message-sink').hide();
|
||||
this.messageSink.hide();
|
||||
};
|
||||
|
||||
InputManager.prototype.handleActionClick = function(event) {
|
||||
|
|
@ -62,39 +65,21 @@ InputManager.prototype.registerOpenMenu = function(menu) {
|
|||
this.openMenus.push(menu);
|
||||
};
|
||||
|
||||
InputManager.messageSink = function() {
|
||||
return $('#message-sink');
|
||||
};
|
||||
|
||||
InputManager.prototype.emptyInfo = function() {
|
||||
InputManager.prototype.hideActionInfo = function() {
|
||||
this.requestedActionInfo = null;
|
||||
var messageSink = InputManager.messageSink();
|
||||
messageSink.empty();
|
||||
messageSink.hide();
|
||||
this.messageSink.hide();
|
||||
};
|
||||
|
||||
InputManager.prototype.showActionInfo = function(el) {
|
||||
//show hint immediately and deffer showing the full info
|
||||
var hint = el.data('actionHint');
|
||||
if (hint) {
|
||||
InputManager.messageSink().text(hint);
|
||||
this.showMessageSinkAround();
|
||||
}
|
||||
//var hint = el.data('actionHint');
|
||||
//if (hint) {
|
||||
// InputManager.messageSink().text(hint);
|
||||
// this.showMessageSinkAround();
|
||||
//}
|
||||
this.requestInfo(el.data('action'));
|
||||
};
|
||||
|
||||
InputManager.prototype.info = function(text) {
|
||||
InputManager.messageSink().html(text);
|
||||
this.showMessageSinkAround();
|
||||
};
|
||||
|
||||
InputManager.prototype.showMessageSinkAround = function() {
|
||||
var messageSink = InputManager.messageSink();
|
||||
messageSink.show();
|
||||
messageSink.offset({left: this.mouseInfo.pageX + 10, top: this.mouseInfo.pageY + 10});
|
||||
fit(messageSink, $('body'));
|
||||
};
|
||||
|
||||
InputManager.prototype.requestInfo = function(action) {
|
||||
this.requestedActionInfo = action;
|
||||
setTimeout(() => {
|
||||
|
|
@ -103,13 +88,14 @@ InputManager.prototype.requestInfo = function(action) {
|
|||
if (actionId != null) {
|
||||
const action = this.app.actionManager.actions[actionId];
|
||||
if (action) {
|
||||
var hotkey = this.keymap[actionId];
|
||||
InputManager.messageSink().html(
|
||||
(action.state.hint ? action.state.hint : '') +
|
||||
('<div>' + action.info + '</div>') +
|
||||
(hotkey ? '<div >hotkey: ' + hotkey + '</div>' : ''));
|
||||
this.showMessageSinkAround();
|
||||
var hotKey = this.keymap[actionId];
|
||||
Bind(this.actionInfoDom, {
|
||||
hint: action.state.hint,
|
||||
info: action.info,
|
||||
hotKey: hotKey
|
||||
});
|
||||
this.messageSink.showContent(this.actionInfoDom);
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}, 500);
|
||||
};
|
||||
29
web/app/3d/ui/message-sink.js
Normal file
29
web/app/3d/ui/message-sink.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import {fit} from './utils'
|
||||
|
||||
export function MessageSink(inputManager) {
|
||||
this.inputManager = inputManager;
|
||||
this.node = $('<div>', {'class': 'message-sink'});
|
||||
$('body').append(this.node);
|
||||
}
|
||||
|
||||
MessageSink.prototype.show = function() {
|
||||
this.node.show();
|
||||
this.node.offset({left: this.inputManager.mouseInfo.pageX + 10, top: this.inputManager.mouseInfo.pageY + 10});
|
||||
fit(this.node, $('body'));
|
||||
};
|
||||
|
||||
MessageSink.prototype.hide = function() {
|
||||
this.node.hide();
|
||||
};
|
||||
|
||||
MessageSink.prototype.showContent = function(dom) {
|
||||
this.node.children().detach();
|
||||
this.node.append(dom);
|
||||
this.show();
|
||||
};
|
||||
|
||||
MessageSink.prototype.info = function(text) {
|
||||
this.node.children().detach();
|
||||
this.node.html(text);
|
||||
this.show();
|
||||
};
|
||||
5
web/app/3d/ui/tmpl/action-info.html
Normal file
5
web/app/3d/ui/tmpl/action-info.html
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<div class="action-info">
|
||||
<div class="action-info-hint" data-bind="hint"></div>
|
||||
<div class="action-info-info" data-bind="info"></div>
|
||||
<div class="action-info-hotkey" data-bind="hotKey" bind-format="hotkey: %s"></div>
|
||||
</div>
|
||||
|
|
@ -70,5 +70,8 @@ export function fit(el, relativeEl) {
|
|||
top: off.top + 'px'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
export function LoadTemplate(name) {
|
||||
return require('./tmpl/' + name + '.html');
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@
|
|||
@control-button-border: 1px solid #2c2c2c;
|
||||
@menu-border-radius: 3px;
|
||||
|
||||
@suppressed-color: #888;
|
||||
|
||||
.no-selection {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
|
|
@ -187,13 +189,13 @@ body {
|
|||
}
|
||||
|
||||
.menu-item.action-disabled {
|
||||
color: #888;
|
||||
color: @suppressed-color;
|
||||
}
|
||||
|
||||
.menu-item .action-hotkey-info {
|
||||
float: right;
|
||||
padding-left: 15px;
|
||||
color: #888;
|
||||
color: @suppressed-color;
|
||||
font-size: 9px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
|
@ -206,16 +208,31 @@ body {
|
|||
padding-left: 25px;
|
||||
}
|
||||
|
||||
#message-sink {
|
||||
.message-sink {
|
||||
display: none;
|
||||
position: absolute;
|
||||
max-width: 400px;
|
||||
padding: 5px;
|
||||
padding: 2px 5px 2px 5px;
|
||||
.aux-win;
|
||||
color: #ccc;
|
||||
white-space: nowrap;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.action-info > div {
|
||||
padding: 3px 0 3px 0;
|
||||
}
|
||||
.action-info-hotkey {
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
color: @suppressed-color;
|
||||
}
|
||||
|
||||
.action-info-hint {
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
color: #E1A4A4;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="tab-switcher"></div>
|
||||
<div id="message-sink"></div>
|
||||
<a id="downloader" style="display: none;" ></a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ module.exports = {
|
|||
{
|
||||
test: /\.less$/,
|
||||
loader: "style!css!less"
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
loader: 'mustache'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue