yeehaw it's done
This commit is contained in:
@@ -24,16 +24,13 @@
|
||||
extra = ` tooltip-${this.get('tooltip-side')}`
|
||||
if (this.get('grid'))
|
||||
extra += ' gridable'
|
||||
if (this.get('enabled')) {
|
||||
const state = this.get('state')
|
||||
const style = this.get('style')
|
||||
if (!state) {
|
||||
return `active normal ${style} ${extra}`
|
||||
} else {
|
||||
return `inactive ${state} ${extra}`
|
||||
}
|
||||
const state = this.get('state')
|
||||
const style = this.get('style')
|
||||
const active_class = this.get('enabled') ? 'active' : 'inactive'
|
||||
if (!state) {
|
||||
return `${active_class} normal ${style} ${extra}`
|
||||
} else {
|
||||
return `inactive disabled ${extra}`
|
||||
return `${active_class} ${state} ${extra}`
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -4,11 +4,21 @@ buttoncolor(selector, color)
|
||||
&.{selector}
|
||||
transition: background-color 0.5s
|
||||
background-color: color
|
||||
&.{selector}.active:hover,
|
||||
&.{selector}.active:focus
|
||||
transition: background-color 0.25s
|
||||
background-color: lighten(color, button-lighten-hover)
|
||||
outline: 0
|
||||
&.active:hover,
|
||||
&.active:focus
|
||||
transition: background-color 0.25s
|
||||
background-color: lighten(color, button-lighten-hover)
|
||||
outline: 0
|
||||
|
||||
if selector is not 'disabled'
|
||||
&:not(.active)
|
||||
background-image: repeating-linear-gradient(
|
||||
-45deg,
|
||||
color,
|
||||
color 1px,
|
||||
button-color-disabled 1px,
|
||||
button-color-disabled 2px
|
||||
)
|
||||
|
||||
span.button
|
||||
@extend {context} $fontReset
|
||||
|
||||
@@ -4,22 +4,22 @@ import { resize } from 'util/dragresize'
|
||||
|
||||
component.exports = {
|
||||
oninit () {
|
||||
const onresize = resize.bind(this)
|
||||
const onrelease = () => this.set({ resize: false, x: null, y: null })
|
||||
const onresize = resize.bind(this);
|
||||
const onrelease = () => {
|
||||
this.set({
|
||||
resize: false,
|
||||
x: null,
|
||||
y: null,
|
||||
});
|
||||
document.removeEventListener('mousemove', onresize);
|
||||
document.removeEventListener('mouseup', onrelease);
|
||||
};
|
||||
|
||||
this.observe('config.fancy', (newkey, oldkey, keypath) => {
|
||||
winset(this.get('config.window'), 'can-resize', !newkey)
|
||||
|
||||
if (newkey) {
|
||||
document.addEventListener('mousemove', onresize)
|
||||
document.addEventListener('mouseup', onrelease)
|
||||
} else {
|
||||
document.removeEventListener('mousemove', onresize)
|
||||
document.removeEventListener('mouseup', onrelease)
|
||||
}
|
||||
})
|
||||
|
||||
this.on('resize', () => this.toggle('resize'))
|
||||
this.on('resize', () => {
|
||||
this.toggle('resize');
|
||||
document.addEventListener('mousemove', onresize);
|
||||
document.addEventListener('mouseup', onrelease);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -32,12 +32,6 @@ section
|
||||
@extend $cell
|
||||
width: 100%
|
||||
|
||||
.compressedcell
|
||||
@extend $cell
|
||||
&:not(:first-child)
|
||||
text-align: center
|
||||
padding-top: 0px
|
||||
|
||||
.cell
|
||||
@extend $cell
|
||||
&:not(:first-child)
|
||||
@@ -47,3 +41,4 @@ section
|
||||
width: 75px
|
||||
&:not(:last-child)
|
||||
padding-right: 4px
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { UI_INTERACTIVE, UI_UPDATE, UI_DISABLED } from 'util/constants'
|
||||
import { href, winset } from 'util/byond'
|
||||
import { drag } from 'util/dragresize'
|
||||
import { href, winget, winset, runCommand } from 'util/byond'
|
||||
import { drag, lock } from 'util/dragresize'
|
||||
|
||||
component.exports = {
|
||||
computed: {
|
||||
@@ -15,12 +15,31 @@ component.exports = {
|
||||
}
|
||||
},
|
||||
oninit () {
|
||||
// Calculate offset between the "browser's screen space" and
|
||||
// "BYOND screen space".
|
||||
// This is necessary, because Windows 10 taskbar decreases the effective
|
||||
// height by about 40px. If taskbar is located at the top and you try
|
||||
// to drag a TGUI window, it rapidly propels itself to the bottom of
|
||||
// the screen and gets stuck.
|
||||
// See: https://github.com/tgstation/tgstation/issues/44038
|
||||
this.set('screenOffsetX', 0);
|
||||
this.set('screenOffsetY', 0);
|
||||
winget(this.get('config.window'), 'pos')
|
||||
.then(pos => {
|
||||
this.set('screenOffsetX', pos.x - window.screenX);
|
||||
this.set('screenOffsetY', pos.y - window.screenY);
|
||||
|
||||
// If the window starts off screen, pull it back.
|
||||
let {x, y} = lock(window.screenLeft, window.screenTop)
|
||||
if (x !== window.screenLeft || y !== window.screenTop) {
|
||||
winset(this.get('config.window'), 'pos', `${x},${y}`);
|
||||
}
|
||||
});
|
||||
|
||||
const ondrag = drag.bind(this)
|
||||
const onrelease = (event) => this.set({ drag: false, x: null, y: null })
|
||||
|
||||
this.observe('config.fancy', (newkey, oldkey, keypath) => {
|
||||
winset(this.get('config.window'), 'titlebar', !newkey && this.get('config.titlebar'))
|
||||
|
||||
if (newkey) {
|
||||
document.addEventListener('mousemove', ondrag)
|
||||
document.addEventListener('mouseup', onrelease)
|
||||
@@ -36,7 +55,7 @@ component.exports = {
|
||||
},
|
||||
close () {
|
||||
winset(this.get('config.window'), 'is-visible', false)
|
||||
window.location.href = href({command: `uiclose ${this.get('config.ref')}`}, 'winset')
|
||||
runCommand(`uiclose ${this.get('config.ref')}`)
|
||||
},
|
||||
minimize () {
|
||||
winset(this.get('config.window'), 'is-minimized', true)
|
||||
@@ -46,13 +65,14 @@ component.exports = {
|
||||
}
|
||||
</script>
|
||||
|
||||
{{#if config.titlebar}}
|
||||
<header class='titlebar' on-mousedown='drag'>
|
||||
<i class='statusicon fa fa-eye fa-2x {{visualStatus}}'></i>
|
||||
<span class='title'>{{yield}}</span>
|
||||
{{#if config.fancy}}
|
||||
<i class='minimize fa fa-minus fa-2x' on-click='minimize'></i>
|
||||
<i class='close fa fa-close fa-2x' on-click='close'></i>
|
||||
{{/if}}
|
||||
</header>
|
||||
{{/if}}
|
||||
<header class='titlebar' on-mousedown='drag'>
|
||||
<i class='statusicon fa fa-eye fa-2x {{visualStatus}}'></i>
|
||||
<span class='title'>{{yield}}</span>
|
||||
{{#if config.fancy}}
|
||||
<i class='minimize fa fa-minus fa-2x' on-click='minimize'></i>
|
||||
<i class='close fa fa-close fa-2x' on-click='close'></i>
|
||||
{{else}}
|
||||
<i class='minimize no-icons' on-click='minimize'></i>
|
||||
<i class='close no-icons' on-click='close'></i>
|
||||
{{/if}}
|
||||
</header>
|
||||
|
||||
@@ -49,17 +49,17 @@ header.titlebar
|
||||
top: 4px
|
||||
right: 12px
|
||||
|
||||
/.no-icons header.titlebar
|
||||
.statusicon
|
||||
header.titlebar
|
||||
.statusicon.no-icons
|
||||
font-size: 20px
|
||||
&::after
|
||||
content: "O"
|
||||
.minimize
|
||||
.minimize.no-icons
|
||||
top: -2px
|
||||
font-size: 20px
|
||||
&::after
|
||||
content: "—"
|
||||
.close
|
||||
.close.no-icons
|
||||
font-size: 20px
|
||||
&::after
|
||||
content: "X"
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
<span>Otherwise, click 'No Frills' below to disable potentially incompatible features (and this message).</span>
|
||||
<hr/>
|
||||
<ui-button icon='close' action='tgui:nofrills'>No Frills</ui-button>
|
||||
<ui-button icon='internet-explorer' action='tgui:link' params='{"url": "http://windows.microsoft.com/en-us/internet-explorer/download-ie"}'>
|
||||
<ui-button action='tgui:link' params='{"url": "http://windows.microsoft.com/en-us/internet-explorer/download-ie"}'>
|
||||
Upgrade IE</ui-button>
|
||||
<ui-button icon='edge' action='tgui:link' params='{"url": "https://dev.windows.com/en-us/microsoft-edge/tools/vms"}'>
|
||||
<ui-button action='tgui:link' params='{"url": "https://dev.windows.com/en-us/microsoft-edge/tools/vms"}'>
|
||||
IE VMs</ui-button>
|
||||
<ui-button icon='info' action='tgui:link' params='{"url": "https://support.microsoft.com/en-us/lifecycle#gp/Microsoft-Internet-Explorer"}'>
|
||||
EOL Info</ui-button>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
&.airlock_electronics
|
||||
table
|
||||
width: 100%
|
||||
border-spacing: 2px
|
||||
th
|
||||
text-align: left
|
||||
td
|
||||
vertical-align: top
|
||||
.button
|
||||
margin-top: 4px
|
||||
@@ -45,3 +45,4 @@ body.clockwork
|
||||
background-color-end 100%)
|
||||
@import "util/*"
|
||||
@import "components/*"
|
||||
@import "interfaces/*"
|
||||
|
||||
@@ -3,5 +3,7 @@ body.nanotrasen
|
||||
linear-gradient(to bottom,
|
||||
background-color-start 0%,
|
||||
background-color-end 100%)
|
||||
|
||||
@import "util/*"
|
||||
@import "components/*"
|
||||
@import "interfaces/*"
|
||||
|
||||
@@ -28,3 +28,4 @@ body.syndicate
|
||||
background-color-end 100%)
|
||||
@import "util/*"
|
||||
@import "components/*"
|
||||
@import "interfaces/*"
|
||||
|
||||
+44
-27
@@ -13,22 +13,35 @@ Object.assign(Math, require('util/math'))
|
||||
// Set up the initialize function. This is either called below if JSON is provided
|
||||
// inline, or called by the server if it was not.
|
||||
import TGUI from 'tgui.ract'
|
||||
window.initialize = (dataString) => {
|
||||
// Don't run twice.
|
||||
window.tgui = window.tgui || new TGUI({
|
||||
el: '#container',
|
||||
data () {
|
||||
const initial = JSON.parse(dataString)
|
||||
return {
|
||||
constants: require('util/constants'),
|
||||
text: require('util/text'),
|
||||
config: initial.config,
|
||||
data: initial.data,
|
||||
adata: initial.data
|
||||
}
|
||||
|
||||
// This thing was a part of an old index.html
|
||||
window.update = window.initialize = dataString => {
|
||||
const data = JSON.parse(dataString);
|
||||
// Initialize
|
||||
if (!window.tgui) {
|
||||
window.tgui = new TGUI({
|
||||
el: '#container',
|
||||
data () {
|
||||
const initial = data;
|
||||
return {
|
||||
constants: require('util/constants'),
|
||||
text: require('util/text'),
|
||||
config: initial.config,
|
||||
data: initial.data,
|
||||
adata: initial.data,
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
// Update
|
||||
if (window.tgui) {
|
||||
window.tgui.set('config', data.config);
|
||||
if (typeof data.data !== 'undefined') {
|
||||
window.tgui.set('data', data.data);
|
||||
window.tgui.animate('adata', data.data);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Try to find data in the page. If the JSON was inlined, load it.
|
||||
const holder = document.getElementById('data')
|
||||
@@ -38,16 +51,20 @@ if (data !== '{}') {
|
||||
window.initialize(data)
|
||||
holder.remove()
|
||||
}
|
||||
// Let the server know we're set up. This also sends data if it was not inlined.
|
||||
import { act } from 'util/byond'
|
||||
act(ref, 'tgui:initialize')
|
||||
|
||||
// Load fonts.
|
||||
import { loadCSS } from 'fg-loadcss'
|
||||
loadCSS('font-awesome.min.css')
|
||||
// Handle font loads.
|
||||
import FontFaceObserver from 'fontfaceobserver'
|
||||
const fontawesome = new FontFaceObserver('FontAwesome')
|
||||
fontawesome.check('\uf240')
|
||||
.then(() => document.body.classList.add('icons'))
|
||||
.catch(() => document.body.classList.add('no-icons'))
|
||||
// Let the server know we're set up.
|
||||
// This also sends data if it was not inlined.
|
||||
// NOTE: This is currently handled by tgui-next. Only initialize if
|
||||
// we were loaded by tgui-fallback.html.
|
||||
import { act } from 'util/byond';
|
||||
import { loadCSS } from 'fg-loadcss';
|
||||
|
||||
if (window.tguiFallback) {
|
||||
act(ref, 'tgui:initialize');
|
||||
// Load fonts.
|
||||
loadCSS('v4shim.css')
|
||||
loadCSS('font-awesome.css')
|
||||
}
|
||||
else {
|
||||
act(ref, 'tgui:update');
|
||||
}
|
||||
|
||||
+2
-8
@@ -4,7 +4,6 @@
|
||||
|
||||
<script>
|
||||
import { winset } from 'util/byond'
|
||||
import { lock } from 'util/dragresize'
|
||||
|
||||
component.exports = {
|
||||
components: {
|
||||
@@ -30,6 +29,7 @@ component.exports = {
|
||||
const interfaces = require('interfaces/**/*.ract', { mode: 'hash' })
|
||||
if (requested in interfaces) {
|
||||
this.components.interface = interfaces[requested] // Use the interface specified in the config...
|
||||
document.body.classList.add(requested) //Name of the interface class for interface-level css
|
||||
} else {
|
||||
this.components.interface = interfaces.error // ...unless it does not exist.
|
||||
}
|
||||
@@ -41,12 +41,6 @@ component.exports = {
|
||||
})
|
||||
},
|
||||
oncomplete () {
|
||||
// If the window starts off screen, pull it back.
|
||||
if (this.get('config.locked')) {
|
||||
let {x, y} = lock(window.screenLeft, window.screenTop)
|
||||
winset(this.get('config.window'), 'pos', `${x},${y}`)
|
||||
}
|
||||
|
||||
// Give focus back to the map.
|
||||
winset('mapwindow.map', 'focus', true)
|
||||
}
|
||||
@@ -58,6 +52,6 @@ component.exports = {
|
||||
<warnings/>
|
||||
<interface/>
|
||||
</main>
|
||||
{{#if config.titlebar}}
|
||||
{{#if config.fancy}}
|
||||
<resize/>
|
||||
{{/if}}
|
||||
|
||||
+8
-8
@@ -71,14 +71,14 @@ bar-color-border = royal-blue
|
||||
bar-color-background = dark-gray
|
||||
|
||||
// Buttons
|
||||
button-color-normal = royal-blue
|
||||
button-color-disabled = light-gray
|
||||
button-color-selected = green
|
||||
button-color-caution = yellow
|
||||
button-color-danger = dark-red
|
||||
button-color-border = dark-gray
|
||||
button-lighten-hover = 15%
|
||||
button-alpha-disabled = .75
|
||||
button-color-normal = royal-blue
|
||||
button-color-disabled = light-gray
|
||||
button-color-selected = green
|
||||
button-color-caution = yellow
|
||||
button-color-danger = dark-red
|
||||
button-color-border = dark-gray
|
||||
button-lighten-hover = 15%
|
||||
button-desaturate-inactive = 50%
|
||||
|
||||
// Input
|
||||
input-color-text = black
|
||||
|
||||
+65
-11
@@ -1,16 +1,70 @@
|
||||
const encode = encodeURIComponent
|
||||
|
||||
// Helper to generate a BYOND href given 'params' as an object (with an optional 'url' for eg winset).
|
||||
export function href (params = {}, url = '') {
|
||||
return `byond://${url}?` + Object.keys(params).map(key => `${encode(key)}=${encode(params[key])}`).join('&')
|
||||
}
|
||||
// Helper to generate a BYOND href given 'params' as an object
|
||||
// (with an optional 'url' for eg winset).
|
||||
export const href = (url, params = {}) => {
|
||||
return `byond://${url || ''}?`
|
||||
+ Object.keys(params)
|
||||
.map(key => `${encode(key)}=${encode(params[key])}`)
|
||||
.join('&');
|
||||
};
|
||||
|
||||
// Helper to make a BYOND ui_act() call on the UI 'src' given an 'action' and optional 'params'.
|
||||
export function act (src, action, params = {}) {
|
||||
window.location.href = href(Object.assign({ src, action }, params))
|
||||
}
|
||||
// Helper to make a BYOND ui_act() call on the UI 'src' given an 'action'
|
||||
// and optional 'params'.
|
||||
export const act = (src, action, params = {}) => {
|
||||
window.location.href = href('', Object.assign({ src, action }, params))
|
||||
};
|
||||
|
||||
/**
|
||||
* A high-level abstraction of BYJAX. Makes a call to BYOND and returns
|
||||
* a promise, which (if endpoint has a callback parameter) resolves
|
||||
* with the return value of that call.
|
||||
*/
|
||||
export const callByond = (url, params = {}) => {
|
||||
// Create a callback array if it doesn't exist yet
|
||||
window.byondCallbacks = window.byondCallbacks || [];
|
||||
// Create a Promise and push its resolve function into callback array
|
||||
const callbackIndex = window.byondCallbacks.length;
|
||||
const promise = new Promise(resolve => {
|
||||
// TODO: Fix a potential memory leak
|
||||
window.byondCallbacks.push(resolve);
|
||||
});
|
||||
// Call BYOND client
|
||||
window.location.href = href(url || '', Object.assign({}, params, {
|
||||
callback: `byondCallbacks[${callbackIndex}]`,
|
||||
}));
|
||||
// Return promise (awaitable)
|
||||
return promise;
|
||||
};
|
||||
|
||||
export const runCommand = command => callByond('winset', { command });
|
||||
|
||||
/**
|
||||
* A simple debug print.
|
||||
*
|
||||
* TODO: Find a better way to debug print.
|
||||
* Right now we just print into the game chat.
|
||||
*/
|
||||
export const debugPrint = (...args) => {
|
||||
const str = args
|
||||
.map(arg => {
|
||||
if (typeof arg === 'string') {
|
||||
return arg
|
||||
}
|
||||
return JSON.stringify(arg);
|
||||
})
|
||||
.join(' ');
|
||||
return runCommand('Me [debugPrint] ' + str);
|
||||
};
|
||||
|
||||
export const winget = (win, key) => {
|
||||
return callByond('winget', { id: win, property: key })
|
||||
.then(obj => obj[key]);
|
||||
};
|
||||
|
||||
// Helper to make a BYOND winset() call on 'window', setting 'key' to 'value'
|
||||
export function winset (win, key, value) {
|
||||
window.location.href = href({[`${win}.${key}`]: value}, 'winset')
|
||||
}
|
||||
export const winset = (win, key, value) => {
|
||||
window.location.href = href('winset', {
|
||||
[`${win}.${key}`]: value,
|
||||
});
|
||||
};
|
||||
|
||||
+18
-10
@@ -17,17 +17,25 @@ export function lock (x, y) {
|
||||
}
|
||||
|
||||
export function drag (event) {
|
||||
event.preventDefault()
|
||||
|
||||
if (!this.get('drag')) return
|
||||
|
||||
if (this.get('x')) {
|
||||
let x = (event.screenX - this.get('x')) + window.screenLeft
|
||||
let y = (event.screenY - this.get('y')) + window.screenTop
|
||||
if (this.get('config.locked')) ({x, y} = lock(x, y)) // Lock to primary monitor.
|
||||
winset(this.get('config.window'), 'pos', `${x},${y}`)
|
||||
event.preventDefault();
|
||||
if (!this.get('drag')) {
|
||||
return;
|
||||
}
|
||||
if (this.get('x')) {
|
||||
let x = event.screenX
|
||||
+ this.get('x')
|
||||
+ this.get('screenOffsetX');
|
||||
let y = event.screenY
|
||||
+ this.get('y')
|
||||
+ this.get('screenOffsetY');
|
||||
winset(this.get('config.window'), 'pos', `${x},${y}`);
|
||||
}
|
||||
else {
|
||||
this.set({
|
||||
x: window.screenLeft - event.screenX,
|
||||
y: window.screenTop - event.screenY,
|
||||
});
|
||||
}
|
||||
this.set({ x: event.screenX, y: event.screenY })
|
||||
}
|
||||
|
||||
export function sane (x, y) {
|
||||
|
||||
@@ -9,7 +9,7 @@ div[data-tooltip], span[data-tooltip]
|
||||
padding: 10px
|
||||
transform: translateX(-50%)
|
||||
pointer-events: none
|
||||
|
||||
|
||||
visibility: hidden
|
||||
opacity: 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user