mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-09 18:02:50 +01:00
clean up getting rid of old UI code
This commit is contained in:
parent
3f9b1d804a
commit
0da15743f9
16 changed files with 10 additions and 1199 deletions
4
modules/gems/capitalize.js
Normal file
4
modules/gems/capitalize.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export default function capitalize(str) {
|
||||
if (!str) return;
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
|
@ -3,12 +3,12 @@ import connect from 'ui/connect';
|
|||
import Fa from 'ui/components/Fa';
|
||||
import {TOKENS as UI_TOKENS} from '../uiEntryPointsPlugin';
|
||||
import {TOKENS as ACTION_TOKENS} from '../../actions/actionSystemPlugin';
|
||||
import Toolbar, {ToolbarButton} from "../../../../../modules/ui/components/Toolbar";
|
||||
import ImgIcon from "../../../../../modules/ui/components/ImgIcon";
|
||||
import {toIdAndOverrides} from "../../actions/actionRef";
|
||||
import {capitalize} from "../../ui/utils";
|
||||
import {mapActionBehavior} from "../../actions/actionButtonBehavior";
|
||||
import {DEFAULT_MAPPER} from "../../../../../modules/ui/connect";
|
||||
import Toolbar, {ToolbarButton} from '../../../../../modules/ui/components/Toolbar';
|
||||
import ImgIcon from '../../../../../modules/ui/components/ImgIcon';
|
||||
import {toIdAndOverrides} from '../../actions/actionRef';
|
||||
import {mapActionBehavior} from '../../actions/actionButtonBehavior';
|
||||
import {DEFAULT_MAPPER} from '../../../../../modules/ui/connect';
|
||||
import capitalize from '../../../../../modules/gems/capitalize';
|
||||
|
||||
|
||||
function ConfigurableToolbar({actions, small, ...props}) {
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
import {cssIconsToClasses} from '../ui/utils'
|
||||
import {EventData} from '../ui/utils'
|
||||
|
||||
|
||||
export default function Menu(menuActions, inputManager) {
|
||||
this.inputManager = inputManager;
|
||||
this.node = $('<div>', {
|
||||
'class' : 'menu'
|
||||
});
|
||||
let container = $('<div>', {'class': 'menu-container'});
|
||||
this.node.append(container);
|
||||
let separatorAllowed = false;
|
||||
for (var i = 0; i < menuActions.length; i++) {
|
||||
var action = menuActions[i];
|
||||
if (action.type == 'separator') {
|
||||
container.append($('<div>', {'class': 'menu-separator'}));
|
||||
separatorAllowed = false;
|
||||
continue;
|
||||
}
|
||||
separatorAllowed = i != menuActions.length - 1;
|
||||
let menuItem = $('<div>', {'class' : 'menu-item action-item'});
|
||||
menuItem.data('action', action.id);
|
||||
menuItem.addClass('icon16-left');
|
||||
if (action.icon32 != undefined) {
|
||||
menuItem.css({
|
||||
'background-image' : 'url('+action.icon32+')'
|
||||
});
|
||||
} else if (action.cssIcons != undefined) {
|
||||
menuItem.append($('<i>', {'class': 'fa ' + cssIconsToClasses(action.cssIcons)})).append(' ');
|
||||
} else {
|
||||
}
|
||||
menuItem.append($('<span>',{text: action.label, class: 'menu-text'}));
|
||||
var hotkey = this.inputManager.keymap[action.id];
|
||||
if (hotkey) {
|
||||
hotkey = hotkey.replace(/\s/g, '');
|
||||
if (hotkey.length < 15) {
|
||||
menuItem.append($('<span>',{text: hotkey,'class' : 'action-hotkey-info'}));
|
||||
}
|
||||
}
|
||||
|
||||
container.append(menuItem);
|
||||
this.inputManager.app.actionManager.subscribe(action.id, (state) => {
|
||||
if (state.enabled) {
|
||||
menuItem.removeClass('action-disabled');
|
||||
} else {
|
||||
menuItem.addClass('action-disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
this.node.hide();
|
||||
$('body').append(this.node);
|
||||
};
|
||||
|
||||
Menu.prototype.show = function(app, event) {
|
||||
this.node.removeClass('menu-flat-top');
|
||||
this.node.removeClass('menu-flat-bottom');
|
||||
this.node.show(); //node should be visible to get right dimensions
|
||||
const r = Math.round;
|
||||
let button = EventData.get(event, 'initiator');
|
||||
if (button != undefined) {
|
||||
var off = button.offset();
|
||||
var orientation = button.data('menuOrientation');
|
||||
if (orientation == 'up') {
|
||||
this.node.addClass('menu-flat-bottom');
|
||||
this.node.offset({
|
||||
left: r(off.left),
|
||||
top: r(off.top - this.node.outerHeight())
|
||||
});
|
||||
} else if (orientation == 'down') {
|
||||
this.node.addClass('menu-flat-top');
|
||||
this.node.offset({
|
||||
left: r(off.left),
|
||||
top: r(off.top + button.outerHeight())
|
||||
});
|
||||
} else {
|
||||
let mouseInfo = this.inputManager.mouseInfo;
|
||||
let screenOff = $(document).outerHeight() - (mouseInfo.pageX + this.node.outerHeight());
|
||||
if (screenOff > 0) {
|
||||
screenOff = 0;
|
||||
}
|
||||
let x = mouseInfo.pageX;
|
||||
if (x + this.node.outerWidth()) {
|
||||
|
||||
}
|
||||
this.node.offset({
|
||||
left: mouseInfo.pageX,
|
||||
top: mouseInfo.pageY + screenOff
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let mouseInfo = this.inputManager.mouseInfo;
|
||||
this.node.offset({
|
||||
left: r(mouseInfo.pageX - this.node.outerWidth() / 2),
|
||||
top: r(mouseInfo.pageY - this.node.outerHeight() / 2)
|
||||
});
|
||||
}
|
||||
this.inputManager.registerOpenMenu(this);
|
||||
};
|
||||
|
||||
|
|
@ -1,318 +0,0 @@
|
|||
import {sprintf} from 'sprintf'
|
||||
|
||||
export const BINDING_CALLBACK = 'OnBind';
|
||||
|
||||
export function Bind(node, data, policy) {
|
||||
const scope = getScope(node);
|
||||
const props = Object.getOwnPropertyNames(data);
|
||||
for (let prop of props) {
|
||||
if (prop == BINDING_CALLBACK) continue;
|
||||
let value = data[prop];
|
||||
if (Array.isArray(value)) {
|
||||
const nodesToBind = scope.nestedScopes[prop];
|
||||
if (!nodesToBind) continue;
|
||||
for (let nodeToBind of nodesToBind) {
|
||||
BindArray(nodeToBind, value, policy);
|
||||
}
|
||||
} else if (typeof value === 'object') {
|
||||
const nodesToBind = scope.nestedScopes[prop];
|
||||
if (!nodesToBind) continue;
|
||||
for (let nodeToBind of nodesToBind) {
|
||||
Bind(nodeToBind, value, policy);
|
||||
}
|
||||
} else {
|
||||
const bindCallbacks = scope.bindings[prop];
|
||||
if (!bindCallbacks) continue;
|
||||
for (let bindCallback of bindCallbacks) {
|
||||
bindCallback(value, policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
var callback = data[BINDING_CALLBACK];
|
||||
if (callback) {
|
||||
callback(node, data, policy)
|
||||
}
|
||||
}
|
||||
|
||||
export function BindArray(node, array, policy) {
|
||||
let scope = getScope(node);
|
||||
let template = detachTemplate(node);
|
||||
|
||||
function createFromTemplate(id) {
|
||||
const child = template.clone();
|
||||
child.attr('data-bind-scope', id);
|
||||
scope.nestedScopes[id] = [child];
|
||||
return child;
|
||||
}
|
||||
|
||||
const children = node.children();
|
||||
let domPointer = 0;
|
||||
for (let dataPointer = 0; dataPointer < array.length; dataPointer++) {
|
||||
const value = array[dataPointer];
|
||||
let domItem;
|
||||
if (domPointer == children.length) {
|
||||
domItem = createFromTemplate(value.id);
|
||||
node.append(domItem);
|
||||
} else {
|
||||
domItem = children.eq(domPointer);
|
||||
var domItemId = domItem.attr('data-bind-scope');
|
||||
if (domItemId != value.id) {
|
||||
domItem = scope.nestedScopes[value.id];
|
||||
if (!domItem) {
|
||||
domItem = createFromTemplate(value.id);
|
||||
} else {
|
||||
domItem = domItem[0];
|
||||
}
|
||||
if (domPointer == 0) {
|
||||
node.prepend(domItem);
|
||||
} else {
|
||||
children.eq(domPointer - 1).after(domItem);
|
||||
}
|
||||
}
|
||||
domPointer ++;
|
||||
}
|
||||
Bind(domItem, value, policy);
|
||||
}
|
||||
//clean up
|
||||
for (; domPointer < children.length; domPointer++) {
|
||||
let item = children.eq(domPointer);
|
||||
item.remove();
|
||||
delete scope[item.attr('data-bind-scope')];
|
||||
}
|
||||
}
|
||||
|
||||
function detachTemplate(node) {
|
||||
let template = node.data("BindingTemplate");
|
||||
if (!template) {
|
||||
template = node.children();
|
||||
template.detach();
|
||||
node.data("BindingTemplate", template);
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
function clearScope(dom) {
|
||||
dom.removeData('BindingScope');
|
||||
}
|
||||
|
||||
function getScope(dom) {
|
||||
let scope = dom.data('BindingScope');
|
||||
if (!scope) {
|
||||
scope = index(dom);
|
||||
dom.data('BindingScope', scope);
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
function detectBinder(def) {
|
||||
for (let binder of BINDERS) {
|
||||
if (def.startsWith(binder.prefix)) {
|
||||
return binder;
|
||||
}
|
||||
}
|
||||
return DEFAULT_BINDER;
|
||||
}
|
||||
|
||||
function setupBindings(bindings, bindingsDefinition, node) {
|
||||
bindingsDefinition.split(',').forEach(defStr => {
|
||||
defStr = defStr.trim();
|
||||
const binder = detectBinder(defStr);
|
||||
const def = parseBindDefinition(defStr.substring(binder.prefix.length));
|
||||
addToList(bindings, def.dataKey, (value, policy) => {
|
||||
policy = adjustPolicyForNode(policy, def.policy);
|
||||
const formattedValue = format(def.formatters, value);
|
||||
binder.apply(node, formattedValue, policy, def.key);
|
||||
});
|
||||
binder.init(node);
|
||||
});
|
||||
}
|
||||
|
||||
function index(dom) {
|
||||
const scope = new Scope();
|
||||
//do bfs
|
||||
const queue = [];
|
||||
function advance(node) {
|
||||
let bindingsDefinition = node.attr('data-bind');
|
||||
if (bindingsDefinition) {
|
||||
setupBindings(scope.bindings, bindingsDefinition, node)
|
||||
}
|
||||
node.children().each((i, e) => queue.push($(e)))
|
||||
}
|
||||
advance(dom);
|
||||
while (queue.length != 0) {
|
||||
let list = false;
|
||||
let node = queue.shift();
|
||||
var nestedScope = node.attr('data-bind-scope');
|
||||
if (!nestedScope) {
|
||||
nestedScope = node.attr('data-bind-list');
|
||||
list = true;
|
||||
}
|
||||
if (nestedScope) {
|
||||
addToList(scope.nestedScopes, nestedScope, node);
|
||||
if (list) {
|
||||
detachTemplate(node);
|
||||
}
|
||||
} else {
|
||||
advance(node);
|
||||
}
|
||||
}
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
function adjustPolicyForNode(propagatedPolicy, nodePolicy) {
|
||||
let policy = propagatedPolicy || DEFAULT_POLICY;
|
||||
if (nodePolicy) {
|
||||
policy = Object.assign({}, policy, nodePolicy);
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
||||
function addToList(map, key, value) {
|
||||
let list = map[key];
|
||||
if (!list) {
|
||||
list = [];
|
||||
map[key] = list;
|
||||
}
|
||||
list.push(value);
|
||||
}
|
||||
|
||||
const DEFAULT_POLICY = {
|
||||
hideEmpty: true
|
||||
};
|
||||
|
||||
export const FORMATTERS = {
|
||||
capitalize: (s) => s.replace(/\b\w/g, l => l.toUpperCase()),
|
||||
uppercase: (s) => s.toUpperCase(),
|
||||
'css-url': (s) => 'url(' + s + ')'
|
||||
};
|
||||
|
||||
function parseDataLink(str, def) {
|
||||
const idx = str.indexOf('|');
|
||||
if (idx == -1) {
|
||||
def.dataKey = str.trim();
|
||||
def.formatters = [];
|
||||
} else {
|
||||
def.dataKey = str.substring(0, idx).trim();
|
||||
def.formatters = str.substring(idx + 1).split('|').map(s => s.trim());
|
||||
}
|
||||
}
|
||||
|
||||
function parsePolicy(policyStr) {
|
||||
const policy = {};
|
||||
policyStr.split('&').forEach(p => {
|
||||
p = p.trim();
|
||||
let eqIdx = p.indexOf('=');
|
||||
if (eqIdx == -1) {
|
||||
policy[p] = true;
|
||||
} else {
|
||||
policy[p.substring(0, eqIdx)] = p.substring(eqIdx + 1);
|
||||
}
|
||||
});
|
||||
return policy;
|
||||
}
|
||||
|
||||
function parseBindDefinition(str) {
|
||||
const def = {};
|
||||
let qmIdx = str.indexOf('?');
|
||||
if (qmIdx != -1) {
|
||||
def.policy = parsePolicy(str.substring(qmIdx + 1));
|
||||
str = str.substring(0, qmIdx);
|
||||
}
|
||||
const colonIdx = str.indexOf(':');
|
||||
if (colonIdx == -1) {
|
||||
parseDataLink(str, def);
|
||||
} else {
|
||||
def.key = str.substring(0, colonIdx).trim();
|
||||
parseDataLink(str.substring(colonIdx + 1), def);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
function format(formatters, value) {
|
||||
for (let formatterKey of formatters) {
|
||||
const formatter = FORMATTERS[formatterKey];
|
||||
if (formatter) {
|
||||
value = formatter(value);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
const DEFAULT_BINDER = {
|
||||
prefix: '',
|
||||
apply: (node, value, policy) => {
|
||||
let templateData = node.attr('data-bind-template');
|
||||
|
||||
var isEmpty = value === '' || value === undefined || value === null;
|
||||
if (isEmpty) {
|
||||
node.text('');
|
||||
} else {
|
||||
if (templateData) {
|
||||
value = sprintf(templateData, value);
|
||||
}
|
||||
node.text(value);
|
||||
}
|
||||
if (isEmpty && policy.hideEmpty) {
|
||||
node.hide();
|
||||
} else {
|
||||
node.show();
|
||||
}
|
||||
},
|
||||
init: (node) => {
|
||||
let template = node.text();
|
||||
if (template) {
|
||||
node.attr('data-bind-template', template);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const BINDERS = [
|
||||
{
|
||||
prefix: '@',
|
||||
apply: (node, value, policy, key) => node.attr(key, value),
|
||||
init: (node) => {}
|
||||
},
|
||||
|
||||
{
|
||||
prefix: '$',
|
||||
apply: (node, value, policy, key) => node.css(key, value),
|
||||
init: (node) => {}
|
||||
},
|
||||
|
||||
{
|
||||
prefix: '!',
|
||||
apply: (node, value, policy, key) => value ? node.addClass(key) : node.removeClass(key),
|
||||
init: (node) => {}
|
||||
},
|
||||
|
||||
DEFAULT_BINDER
|
||||
];
|
||||
|
||||
|
||||
|
||||
export function Scope() {
|
||||
this.bindings = {};
|
||||
this.nestedScopes = {};
|
||||
}
|
||||
|
||||
function example(dom) {
|
||||
let initState = {
|
||||
title : 'this is title',
|
||||
users : [
|
||||
{id: 1, name: 'Peach', email: 'Peach@ooo.com'},
|
||||
{id: 2, name: 'Melon', email: 'Melon@ooo.com'},
|
||||
{id: 3, name: 'Berry', email: 'Berry@ooo.com'},
|
||||
{id: 4, name: 'Apple', email: 'Apple@ooo.com'},
|
||||
{id: 5, name: 'Banana', email: 'Banana@ooo.com'}
|
||||
]
|
||||
};
|
||||
|
||||
Bind(dom, initState);
|
||||
//reordering, removing, updating provided attributes
|
||||
Bind(dom, {users: [ {id:3}, {id:1, name: 'Peach-Beach'}, {id:2} ]});
|
||||
//only content update
|
||||
Bind(dom, {users: {
|
||||
'3' : {name: 'updated', email: 'light@update.com'}
|
||||
}});
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
import {cssIconsToClasses} from '../ui/utils'
|
||||
|
||||
export default function ControlBar(app, bar) {
|
||||
this.app = app;
|
||||
this.bar = bar;
|
||||
}
|
||||
|
||||
ControlBar.prototype.add = function(actionName, left, overrides) {
|
||||
let action = this.app.actionManager.actions[actionName];
|
||||
if (action == undefined) return;
|
||||
if (overrides != undefined) {
|
||||
action = Object.assign({}, action, overrides);
|
||||
}
|
||||
const btn = $('<div>', {'class': 'button'});
|
||||
if (action.cssIcons != undefined) {
|
||||
btn.append($('<i>', {'class': 'fa ' + cssIconsToClasses(action.cssIcons)}));
|
||||
}
|
||||
if (action.label != undefined && action.label != null) {
|
||||
if (action.cssIcons != undefined) {
|
||||
btn.append(' ');
|
||||
}
|
||||
btn.append(action.label);
|
||||
}
|
||||
var to = this.bar.find(left ? '.left-group' : '.right-group');
|
||||
to.append(btn);
|
||||
if (action.type == 'binary') {
|
||||
this.app.bus.subscribe(action.property, (show) => {
|
||||
btn.removeClass('button-selected');
|
||||
if (show) {
|
||||
btn.addClass('button-selected');
|
||||
}
|
||||
})(this.app.state[action.property]);
|
||||
} else if (action.type == 'menu') {
|
||||
btn.data('menuOrientation', 'up');
|
||||
}
|
||||
btn.addClass('action-item');
|
||||
btn.data('action', actionName);
|
||||
return btn;
|
||||
};
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
import * as tk from '../../ui/toolkit'
|
||||
import * as cad_utils from '../cad-utils'
|
||||
import * as math from '../../math/math'
|
||||
import * as workbench from '../craft/mesh/workbench'
|
||||
import ToolBar from './toolbar'
|
||||
import * as MenuConfig from '../menu/menu-config'
|
||||
import * as Operations from '../craft/operations'
|
||||
import Menu from '../menu/menu'
|
||||
import {ExtrudeWizard, CutWizard} from '../craft/brep/wizards/cut-extrude-wizard'
|
||||
|
||||
import {RevolveWizard} from '../craft/brep/wizards/revolve-wizard'
|
||||
import {PlaneWizard} from '../craft/brep/wizards/plane-wizard'
|
||||
import {BoxWizard} from '../craft/brep/wizards/box'
|
||||
import {SphereWizard} from '../craft/mesh/wizards/sphere'
|
||||
import {TransformWizard} from '../craft/mesh/wizards/transform'
|
||||
import {ImportWizard} from '../craft/mesh/wizards/import'
|
||||
import {LoadTemplate} from './utils'
|
||||
import {BindArray} from './bind'
|
||||
import {SolidList} from './solid-list'
|
||||
import {ModificationsPanel} from './modifications-panel'
|
||||
|
||||
function UI(app) {
|
||||
this.app = app;
|
||||
this.viewer = app.viewer;
|
||||
var mainBox = this.mainBox = new tk.Panel();
|
||||
mainBox.root.css({height : '100%'});
|
||||
$('#right-panel').append(mainBox.root);
|
||||
var modelFolder = new tk.Folder("Model");
|
||||
this.solidList = new SolidList(this.app);
|
||||
modelFolder.content.append(this.solidList.dom);
|
||||
|
||||
tk.add(mainBox, modelFolder);
|
||||
let modificationsPanel = new ModificationsPanel(this.app);
|
||||
mainBox.content.append(modificationsPanel.dom);
|
||||
|
||||
var toolbarVertOffset = 10; //this.mainBox.root.position().top;
|
||||
|
||||
this.registerMenuActions(MenuConfig);
|
||||
|
||||
this.craftToolBar = this.createCraftToolBar(toolbarVertOffset);
|
||||
this.createBoolToolBar(this.craftToolBar.node.position().top + this.craftToolBar.node.height() + 20);
|
||||
this.createMiscToolBar(toolbarVertOffset);
|
||||
this.fillControlBar();
|
||||
var ui = this;
|
||||
|
||||
this.app.bus.subscribe("showSketches", (enabled) => {
|
||||
var solids = app.findAllSolidsOnScene();
|
||||
for (var i = 0; i < solids.length; i++) {
|
||||
for (var j = 0; j < solids[i].sceneFaces.length; j++) {
|
||||
var face = solids[i].sceneFaces[j];
|
||||
if (face.sketch3DGroup != null) face.sketch3DGroup.visible = enabled;
|
||||
}
|
||||
}
|
||||
app.viewer.render();
|
||||
});
|
||||
|
||||
app.bus.subscribe('selection_solid', function([solid]) {
|
||||
if (solid) {
|
||||
ui.registerWizard(new TransformWizard(app.viewer, solid));
|
||||
}
|
||||
});
|
||||
registerOperations(app);
|
||||
}
|
||||
|
||||
function registerOperations(app) {
|
||||
const opNames = Object.keys(Operations);
|
||||
for (let opName of opNames) {
|
||||
console.log('Registering Operation ' + opName);
|
||||
app.craft.registerOperation(opName, Operations[opName].action);
|
||||
}
|
||||
}
|
||||
|
||||
UI.prototype.createCraftToolBar = function (vertPos) {
|
||||
var toolBar = new ToolBar(this.app);
|
||||
toolBar.add(this.app.actionManager.actions['PLANE']);
|
||||
toolBar.add(this.app.actionManager.actions['EditFace']);
|
||||
toolBar.add(this.app.actionManager.actions['EXTRUDE']);
|
||||
toolBar.add(this.app.actionManager.actions['CUT']);
|
||||
toolBar.add(this.app.actionManager.actions['REVOLVE']);
|
||||
|
||||
|
||||
$('#viewer-container').append(toolBar.node);
|
||||
toolBar.node.css({left: '10px',top : vertPos + 'px'});
|
||||
return toolBar;
|
||||
};
|
||||
|
||||
UI.prototype.createMiscToolBar = function (vertPos) {
|
||||
var toolBar = new ToolBar(this.app);
|
||||
toolBar.addFa(this.app.actionManager.actions['Save']);
|
||||
toolBar.addFa(this.app.actionManager.actions['StlExport']);
|
||||
$('#viewer-container').append(toolBar.node);
|
||||
toolBar.node.css({top : vertPos + 'px'});
|
||||
toolBar.node.css({right: '10px', 'font-size': '16px'});
|
||||
return toolBar;
|
||||
};
|
||||
|
||||
UI.prototype.createBoolToolBar = function(vertPos) {
|
||||
var toolBar = new ToolBar(this.app);
|
||||
toolBar.add(this.app.actionManager.actions['INTERSECTION']);
|
||||
toolBar.add(this.app.actionManager.actions['DIFFERENCE']);
|
||||
toolBar.add(this.app.actionManager.actions['UNION']);
|
||||
$('#viewer-container').append(toolBar.node);
|
||||
toolBar.node.css({left: '10px', top : vertPos + 'px'});
|
||||
return toolBar;
|
||||
};
|
||||
|
||||
UI.prototype.registerMenuActions = function(menuConfig) {
|
||||
for (let menuName in menuConfig) {
|
||||
const m = menuConfig[menuName];
|
||||
var action = Object.assign({'type' : 'menu'}, m);
|
||||
delete action['actions'];
|
||||
action.menu = new Menu(
|
||||
m.actions.map((a) => this.app.actionManager.actions[a])
|
||||
.filter((a) => a != undefined), this.app.inputManager);
|
||||
this.app.actionManager.registerAction('menu.' + menuName, action);
|
||||
}
|
||||
};
|
||||
|
||||
UI.prototype.fillControlBar = function() {
|
||||
const LEFT = true;
|
||||
const RIGHT = !LEFT;
|
||||
this.app.controlBar.add('Info', RIGHT, {'label': null});
|
||||
this.app.controlBar.add('RefreshSketches', RIGHT, {'label': null});
|
||||
this.app.controlBar.add('ShowSketches', RIGHT, {'label': 'sketches'});
|
||||
this.app.controlBar.add('DeselectAll', RIGHT, {'label': null});
|
||||
this.app.controlBar.add('ToggleCameraMode', RIGHT, {'label': null});
|
||||
this.app.controlBar.add('menu.file', LEFT);
|
||||
this.app.controlBar.add('menu.craft', LEFT);
|
||||
this.app.controlBar.add('menu.boolean', LEFT);
|
||||
this.app.controlBar.add('menu.primitives', LEFT);
|
||||
this.app.controlBar.add('Donate', LEFT);
|
||||
this.app.controlBar.add('GitHub', LEFT);
|
||||
};
|
||||
|
||||
UI.prototype.registerWizard = function(wizard, overridingHistory) {
|
||||
wizard.box.root.css({left : (this.mainBox.root.width() + this.craftToolBar.node.width() + 30) + 'px', top : 0});
|
||||
var craft = this.app.craft;
|
||||
wizard.overridingHistory = overridingHistory;
|
||||
wizard.focus();
|
||||
if (this.registeredWizard != undefined) {
|
||||
if (!this.registeredWizard.disposed) {
|
||||
this.registeredWizard.dispose();
|
||||
}
|
||||
}
|
||||
this.registeredWizard = wizard;
|
||||
return wizard;
|
||||
};
|
||||
|
||||
UI.prototype.getInfoForOp = function(op) {
|
||||
var p = op.params;
|
||||
var opDef = Operations[op.type];
|
||||
if (opDef && opDef.info) {
|
||||
return op.type + ' ' + opDef.info(p);
|
||||
}
|
||||
return op.type;
|
||||
};
|
||||
|
||||
UI.prototype.initOperation = function(op) {
|
||||
var selection = this.app.getFaceSelection();
|
||||
return this.createWizard(op, false, undefined, selection[0]);
|
||||
};
|
||||
|
||||
UI.prototype.createWizardForOperation = function(op) {
|
||||
var initParams = op.params;
|
||||
var face = op.face !== undefined ? this.app.findFace(op.face) : null;
|
||||
if (face != null) {
|
||||
this.app.context.bus.dispatch('selection_face', [face]);
|
||||
}
|
||||
return this.createWizard(op.type, true, initParams, face);
|
||||
};
|
||||
|
||||
UI.prototype.createWizard = function(type, overridingHistory, initParams, face) {
|
||||
let wizard = null;
|
||||
if ('CUT' === type) {
|
||||
wizard = new CutWizard(this.app, initParams);
|
||||
} else if ('EXTRUDE' === type) {
|
||||
wizard = new ExtrudeWizard(this.app, initParams);
|
||||
} else if ('REVOLVE' === type) {
|
||||
wizard = new RevolveWizard(this.app, face, initParams);
|
||||
} else if ('PLANE' === type) {
|
||||
wizard = new PlaneWizard(this.app, initParams);
|
||||
} else if ('BOX' === type) {
|
||||
wizard = new BoxWizard(this.app, initParams);
|
||||
} else if ('SPHERE' === type) {
|
||||
wizard = new SphereWizard(this.app.viewer, initParams);
|
||||
} else if ('IMPORT_STL' === type) {
|
||||
wizard = new ImportWizard(this.app.viewer, initParams);
|
||||
} else {
|
||||
console.log('unknown operation');
|
||||
}
|
||||
if (wizard != null) {
|
||||
this.registerWizard(wizard, overridingHistory);
|
||||
}
|
||||
return wizard;
|
||||
};
|
||||
|
||||
export {UI}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
import {jwerty} from 'jwerty'
|
||||
import {keymap} from '../keyboard/keymaps/default'
|
||||
import {Bind} from './bind'
|
||||
import {MessageSink} from './message-sink'
|
||||
import {LoadTemplate, DefaultMouseEvent, EventData, fit} from './utils'
|
||||
|
||||
export function InputManager(app) {
|
||||
this.app = app;
|
||||
this.openMenus = [];
|
||||
this.keymap = keymap;
|
||||
this.mouseInfo = new DefaultMouseEvent();
|
||||
this.requestedActionInfo = null;
|
||||
this.actionInfoDom = $(LoadTemplate('action-info')({}));
|
||||
this.messageSink = new MessageSink(this);
|
||||
this.context = null;
|
||||
$(() => {
|
||||
$(document)
|
||||
.on('keydown', (e) => this.handleKeyPress(e))
|
||||
.on('mousedown', (e) => this.clear(e))
|
||||
.on('click', '.context-click', (e) => this.context = $(e.currentTarget))
|
||||
.on('mouseenter', '.context-hover', (e) => this.context = $(e.currentTarget))
|
||||
.on('mouseleave', '.context-hover', (e) => this.context = null)
|
||||
.on('mouseenter', '.action-item', (e) => this.showActionInfo($(e.currentTarget)))
|
||||
.on('mouseleave', '.action-item', (e) => this.hideActionInfo())
|
||||
.on('mousemove', (e) => this.mouseInfo = e)
|
||||
.on('click', '.action-item', (e) => this.handleActionClick(e))
|
||||
.on('contextmenu', '.action-item', (e) => {return this.handleRightClick(e)});
|
||||
});
|
||||
}
|
||||
|
||||
InputManager.prototype.handleKeyPress = function(e) {
|
||||
switch (e.keyCode) {
|
||||
case 27 : this.clear(); break;
|
||||
}
|
||||
|
||||
for (let action in this.keymap) {
|
||||
if (jwerty.is(this.keymap[action], e)) {
|
||||
setTimeout(() => this.app.actionManager.run(action, e), 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
InputManager.prototype.clear = function(e) {
|
||||
if (e != undefined && $(e.target).closest('.menu-item').length != 0) {
|
||||
return;
|
||||
}
|
||||
this.clearMenus();
|
||||
this.requestedActionInfo = null;
|
||||
this.messageSink.hide();
|
||||
};
|
||||
|
||||
InputManager.prototype.clearMenus = function() {
|
||||
if (this.openMenus.length != 0) {
|
||||
for (let openMenu of this.openMenus) {
|
||||
openMenu.node.hide();
|
||||
}
|
||||
this.openMenus = [];
|
||||
}
|
||||
};
|
||||
|
||||
InputManager.prototype.handleRightClick = function(e) {
|
||||
if ($(event.currentTarget).hasClass('.right-click-action')) {
|
||||
e.preventDefault();
|
||||
this.handleActionClick(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
InputManager.prototype.handleActionClick = function(event) {
|
||||
this.mouseInfo = event;
|
||||
var target = $(event.currentTarget);
|
||||
var action = target.data('action');
|
||||
if (action != undefined) {
|
||||
this.clear();
|
||||
EventData.set(event, 'initiator', target);
|
||||
this.app.actionManager.run(action, event);
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
InputManager.prototype.registerOpenMenu = function(menu) {
|
||||
fit(menu.node, $('body'));
|
||||
this.openMenus.push(menu);
|
||||
};
|
||||
|
||||
InputManager.prototype.hideActionInfo = function() {
|
||||
this.requestedActionInfo = null;
|
||||
this.messageSink.hide();
|
||||
};
|
||||
|
||||
InputManager.prototype.showActionInfo = function(el) {
|
||||
var action = el.data('action');
|
||||
if (action) {
|
||||
this.requestInfo(action);
|
||||
}
|
||||
};
|
||||
|
||||
InputManager.prototype.requestInfo = function(actionRequest) {
|
||||
if (this.requestedActionInfo == actionRequest) {
|
||||
return;
|
||||
}
|
||||
this.requestedActionInfo = actionRequest;
|
||||
setTimeout(() => {
|
||||
const actionId = this.requestedActionInfo;
|
||||
this.requestedActionInfo = null;
|
||||
if (actionId != null ) {
|
||||
const action = this.app.actionManager.actions[actionId];
|
||||
const hotKey = this.keymap[actionId];
|
||||
if (action && (action.state.hint || action.info || hotKey)) {
|
||||
Bind(this.actionInfoDom, {
|
||||
hint: action.state.hint,
|
||||
info: action.info,
|
||||
hotKey: hotKey
|
||||
});
|
||||
this.messageSink.showContent(this.actionInfoDom);
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
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.empty();
|
||||
this.node.append(dom);
|
||||
this.show();
|
||||
};
|
||||
|
||||
MessageSink.prototype.info = function(text) {
|
||||
this.node.children().detach();
|
||||
this.node.html(text);
|
||||
this.show();
|
||||
};
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
import {LoadTemplate} from './utils'
|
||||
import {Bind} from './bind'
|
||||
import * as Operations from '../craft/operations'
|
||||
|
||||
export function ModificationsPanel(app) {
|
||||
this.app = app;
|
||||
this.dom = $(LoadTemplate('modifications')({}));
|
||||
this.buttonsBlock = this.dom.find(".tc-buttons-block");
|
||||
var buttons = this.buttonsBlock.find(".tc-block-btn");
|
||||
buttons.eq(0).click(() => app.craft.finishHistoryEditing());
|
||||
this.buttonsBlock.hide();
|
||||
this.historyWizard = null;
|
||||
|
||||
this.app.bus.subscribe("craft", () => {
|
||||
this.updateList();
|
||||
this.updateHistoryPointer();
|
||||
});
|
||||
|
||||
this.app.bus.subscribe("historyShrink", () => {
|
||||
this.updateList();
|
||||
});
|
||||
|
||||
this.app.bus.subscribe("refreshSketch", () => {
|
||||
if (this.historyWizard != null) {
|
||||
var craft = this.app.craft;
|
||||
var op = JSON.parse(JSON.stringify(craft.history[craft.historyPointer]));
|
||||
op.protoParams = this.historyWizard.getParams();
|
||||
this.historyWizard.dispose();
|
||||
this.historyWizard = this.app.ui.createWizardForOperation(op, app);
|
||||
}
|
||||
});
|
||||
|
||||
Bind(this.dom, {});
|
||||
}
|
||||
|
||||
ModificationsPanel.prototype.updateList = function() {
|
||||
let modifications = [];
|
||||
for (let i = 0; i < this.app.craft.history.length; i++) {
|
||||
let op = this.app.craft.history[i];
|
||||
let m = {
|
||||
id : i,
|
||||
info: this.app.ui.getInfoForOp(op),
|
||||
OnBind : (dom, data) => {
|
||||
const icon = getIconForOp(op);
|
||||
if (icon) {
|
||||
dom.css('background-image', 'url('+ icon+')');
|
||||
}
|
||||
if (!op.face) {
|
||||
dom.find('.require-face').addClass('action-disabled');
|
||||
}
|
||||
}
|
||||
};
|
||||
modifications.push(m);
|
||||
}
|
||||
Bind(this.dom, {modifications});
|
||||
};
|
||||
|
||||
ModificationsPanel.prototype.updateHistoryPointer = function() {
|
||||
if (this.historyWizard != null) {
|
||||
this.historyWizard.dispose();
|
||||
this.historyWizard = null;
|
||||
}
|
||||
var modificationRows = this.dom.find('.modification-item');
|
||||
modificationRows.removeClass('history-selected');
|
||||
|
||||
var craft = this.app.craft;
|
||||
var historyEditMode = craft.historyPointer != craft.history.length;
|
||||
if (historyEditMode) {
|
||||
modificationRows.eq(craft.historyPointer).addClass('history-selected');
|
||||
var op = craft.history[craft.historyPointer];
|
||||
this.historyWizard = this.app.ui.createWizardForOperation(op);
|
||||
this.buttonsBlock.show();
|
||||
} else {
|
||||
this.buttonsBlock.hide();
|
||||
}
|
||||
};
|
||||
|
||||
function getIconForOp(op) {
|
||||
var opDef = Operations[op.type];
|
||||
if (!opDef || !opDef.icon) {
|
||||
return null;
|
||||
}
|
||||
return opDef.icon + '32.png';
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import {LoadTemplate} from './utils'
|
||||
import {BindArray} from './bind'
|
||||
|
||||
export function SolidList(app) {
|
||||
this.app = app;
|
||||
app.bus.subscribe('solid-list', (data) => this.onChange(data));
|
||||
this.dom = $(LoadTemplate('solid-list')({}));
|
||||
BindArray(this.dom, []);
|
||||
}
|
||||
|
||||
SolidList.prototype.onChange = function(data) {
|
||||
let domData = data.solids.map(s => ({id: s.id}));
|
||||
domData.forEach(s => {
|
||||
let toRefresh = data.needRefresh.find(nr => nr.id == s.id);
|
||||
if (toRefresh) {
|
||||
Object.assign(s, this.getFullInfo(toRefresh));
|
||||
}
|
||||
});
|
||||
BindArray(this.dom, domData);
|
||||
};
|
||||
|
||||
SolidList.prototype.getFullInfo = function(solid) {
|
||||
return {
|
||||
id: solid.id,
|
||||
type: solid.tCadType,
|
||||
sketches: this.app.findSketches(solid).map(id => ({id}))
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
export default function TabSwitcher(tabBar, defaultView) {
|
||||
this.tabBar = tabBar;
|
||||
var defaultTab = $('<div>', {
|
||||
'class': 'tab',
|
||||
text: '3D View'
|
||||
});
|
||||
this.defaultViewHandle = new ViewHandle(defaultView, defaultTab);
|
||||
defaultTab.click(() => {
|
||||
this.defaultViewHandle.show(this);
|
||||
});
|
||||
this.tabBar.append(defaultTab);
|
||||
this.markSelected(defaultTab);
|
||||
|
||||
this.detachedViews = {};
|
||||
}
|
||||
|
||||
function idToName(id) {
|
||||
var match = /\$+$/.exec(id);
|
||||
if (match == null) return id;
|
||||
var beenCraftedTimes = match[0].length;
|
||||
function to27Base(n) {
|
||||
if (n == 0) return "";
|
||||
var rad = n % 27;
|
||||
return to27Base(Math.floor(n / 27)) + String.fromCharCode(65 + rad);
|
||||
}
|
||||
return id.replace(/\$+$/, '') + to27Base(beenCraftedTimes);
|
||||
}
|
||||
|
||||
TabSwitcher.prototype.showSketch = function(sketchURL, sketchId) {
|
||||
var tab = this.tabBar.find('[data-sketch-id="'+sketchId+'"]');
|
||||
var detachedView = this.detachedViews[sketchId];
|
||||
if (detachedView !== undefined) {
|
||||
if (!detachedView.closed) {
|
||||
detachedView.focus();
|
||||
return;
|
||||
} else {
|
||||
delete this.detachedViews[sketchId];
|
||||
}
|
||||
}
|
||||
if (tab.length == 0) {
|
||||
tab = $('<div>', {'class': 'tab', text : 'Sketch ' + idToName(sketchId)})
|
||||
.append(' ')
|
||||
.append($('<i>', {'class': 'fa fa-expand expand'}))
|
||||
.append(' ')
|
||||
.append($('<i>', {'class': 'fa fa-close close'}));
|
||||
tab.attr('data-sketch-id', sketchId);
|
||||
var url = "sketcher.html#" + sketchURL;
|
||||
|
||||
var view = $('<div>', {'class': 'app-tab-view'})
|
||||
.append($('<iframe>', {css:{
|
||||
width: '100%', height: '100%'
|
||||
}}));
|
||||
view.insertAfter($('.app-tab-view').last());
|
||||
view.find('iframe').attr('src', url);
|
||||
var viewHandle = new ViewHandle(view, tab);
|
||||
tab.on('click', () => viewHandle.show(this));
|
||||
this.tabBar.append(tab);
|
||||
var close = () => {
|
||||
view.remove();
|
||||
tab.remove();
|
||||
this.defaultViewHandle.show(this);
|
||||
};
|
||||
tab.find('.expand').click(() => {
|
||||
close();
|
||||
this.detachedViews[sketchId] = window.open(url, sketchId, "height=900,width=1200")
|
||||
});
|
||||
tab.find('.close').click(close);
|
||||
}
|
||||
tab.click();
|
||||
};
|
||||
|
||||
TabSwitcher.prototype.markSelected = function(tab) {
|
||||
this.tabBar.find('.tab').removeClass('tab-selected');
|
||||
tab.addClass('tab-selected');
|
||||
};
|
||||
|
||||
function ViewHandle(view, tab) {
|
||||
this.view = view;
|
||||
this.tab = tab;
|
||||
}
|
||||
|
||||
ViewHandle.prototype.show = function(tabSwitcher) {
|
||||
tabSwitcher.markSelected(this.tab);
|
||||
$('.app-tab-view').not(this.view).hide();
|
||||
this.view.show();
|
||||
};
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<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">hotkey: %s</div>
|
||||
</div>
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<div class="tc-folder">
|
||||
<div class="tc-row tc-title">Modifications</div>
|
||||
<div class="tc-list" data-bind-list="modifications">
|
||||
<div class="tc-row tc-pseudo-btn modification-item context-hover action-item" data-action="SetHistoryPointer" data-bind="@data-modification: id">
|
||||
<span data-bind="info" style="float: left"></span>
|
||||
<span style="float: right" class="modification-right-buttons">
|
||||
<i class="fa fa-edit modification-button action-item" data-action="OpenHistoryWizard"></i>
|
||||
<i class="fa fa-image modification-button action-item require-face" data-action="EditOperationSketch"></i>
|
||||
<i class="fa fa-remove modification-button action-item danger" data-action="RemoveModification"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tc-row tc-ctrl tc-buttons-block">
|
||||
<span class="tc-block-btn active-btn">Finish History Editing</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<div class="tc-list solid-list">
|
||||
<div>
|
||||
<div class="tc-row tc-pseudo-btn solid-item action-item context-click"
|
||||
data-action="menu.SolidContext"
|
||||
data-bind="id, @data-id: id">Solid %s</div>
|
||||
<div class="sketch-list" data-bind-list="sketches">
|
||||
<div class="tc-row tc-pseudo-btn sketch-item" data-bind="id, @data-id: id" >Sketch %s</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
import {capitalize, cssIconsToClasses} from './utils'
|
||||
|
||||
export default function ToolBar(app) {
|
||||
this.app = app;
|
||||
this.node = $('<div>', {
|
||||
css :{
|
||||
'position': 'absolute',
|
||||
'background-color': 'rgba(255, 255, 255, 0.5)',
|
||||
'padding': '5px',
|
||||
'border-radius' : '5px'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ToolBar.prototype.add = function(action) {
|
||||
if (!action) return;
|
||||
var btn = $('<div>', {
|
||||
'class': 'tc-toolbar-btn tc-squeezed-text',
|
||||
text : capitalize(action.label),
|
||||
css: ToolBar.buttonCss({
|
||||
'background-image': 'url('+action.icon96+')',
|
||||
'background-repeat': 'no-repeat',
|
||||
'background-position-x': 'center',
|
||||
'background-position-y': 'top',
|
||||
'background-size': '48px 48px'
|
||||
})
|
||||
});
|
||||
this.setUp(btn, action);
|
||||
this.node.append(btn);
|
||||
return btn;
|
||||
};
|
||||
|
||||
ToolBar.prototype.setUp = function(btn, action) {
|
||||
btn.addClass('action-item');
|
||||
btn.attr('data-action', action.id);
|
||||
this.app.actionManager.subscribe(action.id, (state) => {
|
||||
if (state.enabled) {
|
||||
btn.removeClass('action-disabled');
|
||||
} else {
|
||||
btn.addClass('action-disabled');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ToolBar.prototype.addFa = function(action) {
|
||||
if (!action || !action.cssIcons) return;
|
||||
var btn = $('<div>', {
|
||||
'class': 'tc-toolbar-btn',
|
||||
css : {
|
||||
'border-radius' : '5px',
|
||||
'padding' : '5px'
|
||||
}
|
||||
});
|
||||
btn.append($('<i>', {
|
||||
'class' : 'fa ' + cssIconsToClasses(action.cssIcons),
|
||||
css: {
|
||||
'vertical-align': 'middle'
|
||||
}
|
||||
}));
|
||||
this.setUp(btn, action);
|
||||
this.node.append(btn);
|
||||
return btn;
|
||||
};
|
||||
|
||||
ToolBar.buttonCss = function(css) {
|
||||
return Object.assign(css, {
|
||||
'border-radius' : '5px',
|
||||
'width': '53px',
|
||||
'padding-top' : '48px',
|
||||
'margin-top' : '5px'
|
||||
})
|
||||
};
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
export function DefaultMouseEvent() {
|
||||
var viewer = $('#viewer-container');
|
||||
var off = viewer.offset();
|
||||
const r = Math.round;
|
||||
this.type = 'click';
|
||||
this.canBubble = true;
|
||||
this.cancelable = true;
|
||||
this.detail = 1;
|
||||
this.screenX = r(off.left + viewer.width() / 2);
|
||||
this.screenY = r(off.top + viewer.height() / 2);
|
||||
this.clientX = this.screenX;
|
||||
this.clientY = this.screenY;
|
||||
this.pageX = this.screenX;
|
||||
this.pageY = this.screenY;
|
||||
this.ctrlKey = false;
|
||||
this.altKey = false;
|
||||
this.shiftKey = false;
|
||||
this.metaKey = false;
|
||||
this.button = 0;
|
||||
this.relatedTarget = null;
|
||||
}
|
||||
|
||||
export const EventData = {
|
||||
|
||||
get: function(event, key) {
|
||||
if (event.data) {
|
||||
return event.data[key];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
set: function(event, key, value) {
|
||||
if (!event.data) {
|
||||
event.data = {};
|
||||
}
|
||||
event.data[key] = value;
|
||||
}
|
||||
};
|
||||
|
||||
export function fit(el, relativeEl) {
|
||||
const span = 5;
|
||||
var relOff = relativeEl.offset();
|
||||
var off = el.offset();
|
||||
|
||||
var needToSet = false;
|
||||
if (off.left < relOff.left ) {
|
||||
off.left = relOff.left + span;
|
||||
needToSet = true;
|
||||
}
|
||||
const right = relOff.left + relativeEl.width() - span;
|
||||
var outerWidth = el.outerWidth();
|
||||
if (off.left + outerWidth >= right) {
|
||||
off.left = right - outerWidth;
|
||||
needToSet = true;
|
||||
}
|
||||
if (off.top < relOff.top + span) {
|
||||
off.top = relOff.top + span;
|
||||
needToSet = true;
|
||||
}
|
||||
var bottom = relOff.top + relativeEl.height() - span;
|
||||
var outerHeight = el.outerHeight();
|
||||
if (off.top + outerHeight >= bottom) {
|
||||
off.top = bottom - outerHeight;
|
||||
needToSet = true;
|
||||
}
|
||||
if (needToSet) {
|
||||
el.css({
|
||||
left: off.left + 'px',
|
||||
top: off.top + 'px'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function capitalize(str) {
|
||||
if (!str) return;
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
export function cssIconsToClasses(cssIcons) {
|
||||
return cssIcons.map((i)=> 'fa-'+i).join(' ')
|
||||
}
|
||||
|
||||
export function LoadTemplate(name) {
|
||||
return require('./tmpl/' + name + '.html');
|
||||
}
|
||||
Loading…
Reference in a new issue