This commit is contained in:
flash 2023-11-19 16:57:31 +00:00
commit fa97b961cb
66 changed files with 1713 additions and 0 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
[Tt]humbs.db
[Dd]esktop.ini
.DS_Store

54
public/_inc/out.php Normal file
View file

@ -0,0 +1,54 @@
<?php
if(empty($_curr_page))
$_curr_page = '';
if(empty($_head_nav))
$_head_nav = [
'home' => [
'href' => './',
'text' => 'Home',
],
'downloads' => [
'href' => './downloads.php',
'text' => 'Downloads',
],
'changelog' => [
'href' => './changelog.php',
'text' => 'Changelog',
],
'repository' => [
'href' => 'https://github.com/flashwave/topmostfriend',
'text' => 'Repository',
],
];
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title><?=(empty($title) ? '' : ($title . ' :: '));?>Top Most Friend</title>
<link href="style.css" rel="stylesheet" type="text/css"/>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<?php if(!empty($description)): ?>
<meta name="description" content="<?=$description;?>"/>
<?php endif; ?>
</head>
<body>
<div id="_tmf" class="tmf tmf--<?=$_curr_page;?>">
<div class="tmf-head">
<div class="tmf-head-nav">
<?php foreach($_head_nav as $id => $info): ?>
<li<?php if($id === $_curr_page) { echo ' class="current"'; } ?>><a href="<?=$info['href'];?>" id="_nav_<?=$id;?>"><?=$info['text'];?></a></li>
<?php endforeach; ?>
</div>
<div class="tmf-head-logo">
<h1>Top Most Friend</h1>
</div>
</div>
<div class="tmf-body"><?=(!empty($body) ? $body : (function_exists('get_tmf_body') ? get_tmf_body() : ''));?></div>
<div class="tmf-foot">
&copy; <a href="//flash.moe">flashwave</a> 2020-<?=date("Y\r\n");?>
</div>
</div>
</body>
</html>

BIN
public/about.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
public/arrow_refresh.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 B

40
public/changelog.php Normal file
View file

@ -0,0 +1,40 @@
<?php
$_curr_page = 'changelog';
$title = 'Changelog';
$description = 'This page describes changes that have been made between versions of Top Most Friend.';
$files = glob('dl/*/changelog.txt');
rsort($files);
$indent = "\r\n ";
$body = "{$indent}<h2>{$title}</h2>"
. "{$indent}<p>{$description}</p>";
foreach($files as $fileName) {
$file = fopen($fileName, 'rb');
$header = trim(fgets($file));
if(empty($header))
continue;
[$version, $date] = explode(' - ', $header, 2);
$versionId = $version;
$date = strtotime($date);
$body .= sprintf('%s<h3 id="%s"><a href="#%s">%s &mdash; <time datetime="%s">%s</time></a></h3>', $indent, $versionId, $versionId, $version, date('c', $date), date('Y-m-d', $date));
while(($line = fgets($file)) !== false) {
$line = trim($line);
if(empty($line))
continue;
[$stamp, $line] = explode(' ', $line, 2);
$body .= sprintf('%s<p><code>%s</code> %s</p>', $indent, $stamp, $line);
}
fclose($file);
}
$body .= substr($indent, 0, -4);
require_once __DIR__ . '/_inc/out.php';

BIN
public/cog.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

View file

@ -0,0 +1 @@
c5e76254a2951676173559fa1a3da82b092759c2dfbed75e00f6228655b1cbb8

View file

@ -0,0 +1,3 @@
v1.0.0 - 2020-01-05
[+] Initial Release.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
e8a9d9d957c855b716952b763011d9eed0ffd1c26f483e17440dc3c2f4791187

View file

@ -0,0 +1,5 @@
v1.1.0 - 2020-01-06
[+] Added ability to register a hotkey to toggle the currently active window between always on top and not.
[+] Added a couple registry values for customisation and hidden list items.
[*] Ensuring that only one instance is running.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
5635e10be9fd1facea623018fc230ab3173edd74a255b40ce82f2b9998ad7b63

View file

@ -0,0 +1,7 @@
v1.2.0 - 2020-01-07
[+] Added option to always ask for admin on start.
[+] Added error message when topmost toggle fails, if it fails and the process isn't running as administrator it'll ask to elevate.
[+] Added --reset-admin cli flag to revert always admin status.
[+] Added --hwnd= cli flag which allows for toggling a window's topmost status immediately. Used by the elevation prompt.
[+] Added --stop cli flag to close the program after processing cli flags.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
e4798d009d24ec412b5d4c1eb3e46764a863529ac4a1b5b3e82da35484f2af83

View file

@ -0,0 +1,4 @@
v1.3.0 - 2020-01-12
[+] Added notification balloon on hotkey toggle, disabled by default on Windows 10 and beyond.
[-] Removed useless left click handler.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
be300d3cd83e689cfd7a2eee6a4f906187b24ce13f1257da6202298af444b03d

View file

@ -0,0 +1,6 @@
v1.4.0 - 2020-06-10
[+] Added hotkey indicator, if used the notification area icon will temporarily change to the affected window's icon.
[-] Removed hidden ShowExplorerMisc registry switch, explorer windows are now just listed like any other.
[-] Removed static exclusion for windows with the title Program Manager or Start.
[+] Added manual title blacklisting system, titles in the previously mentioned change are added to it by default but can be removed if desired.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
bd8c5e1e0592c86811bfeb4b6953bfec93a52bd37e18155ddc2a7ba8d429ab27

View file

@ -0,0 +1,3 @@
v1.4.1 - 2020-06-10
[*] Fixed oversight in initial title blacklist generation on Windows Vista and 7.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
31290efe7874a3e9eda78abe5498ec3a99c0022d4ae4c53ada922a6ef4855407

View file

@ -0,0 +1,3 @@
v1.4.2 - 2020-07-10
[+] Added ability to bind the Windows key for the hotkey combination.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
fb997a5d83f89c4f633d124b73a85a71404c8e3a5a514982e1f05ae3a547aa56

View file

@ -0,0 +1,5 @@
v1.5.0 - 2021-02-04
[+] Added toggle to disable the window list in the context menu.
[+] Added manual refresh button for the window list.
[*] Greatly improved window list loading speed.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
11ccbad5a3f6cebce01152eee24466f75f26185d74b3220249b018c1990e31fe

View file

@ -0,0 +1,3 @@
v1.5.1 - 2021-02-04
[*] Fixed massive oversight.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
7184ead43fdb9315eb2f972ee2c893ac16c8122ff4b411c58727dae05ee5b727

View file

@ -0,0 +1,11 @@
v1.6.0 - 2021-07-09
[+] Added localisation system.
[+] Added Dutch language support.
[+] Added a first-run window that runs the user through common configuration options on first start.
[+] Added an option to revert top most states to before Top Most Friend edited it upon closing the program. Thank you <a href="https://github.com/Fransiscu">Fransiscu</a> for the idea and a reference implementation!
[+] Added the option to start Top Most Friend with Windows on log in.
[*] TopMostFriend will only run as administrator when necessary rather than always. Though, an option to always run as administrator still remains.
[*] Changed order of toggle options in the settings window.
[*] Windows created by Top Most Friend are now always on top themselves, obviously you can alter this again with the hot key if you want to.
[*] Altered layout of the blacklist editor slightly to make it look more natural.

Binary file not shown.

BIN
public/door_in.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

80
public/downloads.php Normal file
View file

@ -0,0 +1,80 @@
<?php
$_curr_page = 'downloads';
$title = 'Downloads';
$description = 'This page lists all version of Top Most Friend available for download, with the latest version at the top.';
$files = glob('dl/*/TopMostFriend.exe');
rsort($files);
$indent = "\r\n ";
$body = "{$indent}<h2>{$title}</h2>"
. "{$indent}<p>{$description}</p>"
. "{$indent}<p>Microsoft Windows XP Service Pack 3 and newer are supported, provided <a class=\"tmf-external\" href=\"https://www.microsoft.com/download/details.aspx?id=17851\" target=\"_blank\" rel=\"noopener\">.NET Framework 4.0</a> is installed.</p>"
. "{$indent}<span id=\"latest\"></span>";
foreach($files as $fileName) {
$folderName = dirname($fileName);
$changlogName = $folderName . DIRECTORY_SEPARATOR . 'changelog.txt';
$changelog = fopen($changlogName, 'rb');
if(!$changelog)
continue;
$versionInfo = fgets($changelog);
fclose($changelog);
if($versionInfo === false)
continue;
$versionInfo = trim($versionInfo);
if(empty($versionInfo))
continue;
$buttonClasses = [];
if(empty($hadLatest)) {
$hadLatest = true;
$isLatest = true;
$latestText = ' <a href="#latest">Latest!</a>';
$buttonClasses[] = 'tmf-button-latest';
} else {
$isLatest = false;
$latestText = '';
}
[$version, $date] = explode(' - ', $versionInfo, 2);
$versionId = $version;
$date = strtotime($date);
$sourceArchive = $folderName . '/topmostfriend-' . substr($version, 1) . '.zip';
$sha256File = $fileName . '.sha256';
$sha256Hash = is_file($sha256File) ? trim(file_get_contents($sha256File)) : '';
$body .= sprintf('%s<h3 id="%s"><a href="#%s">%s &mdash; <time datetime="%s">%s</time></a>%s</h3>', $indent, $versionId, $versionId, $version, date('c', $date), date('Y-m-d', $date), $latestText);
if(empty($sha256Hash))
$body .= '<p>SHA256 hash is missing.</p>';
else {
$sha256HashFile = hash_file('sha256', $fileName);
$sha256HashMatches = hash_equals($sha256Hash, $sha256HashFile) ? '' : ' <b>(does not match with actual file)</b>';
$body .= sprintf('<p>SHA256: <code>%s</code>%s</p>', $sha256Hash, $sha256HashMatches);
}
$body .= $indent . '<ul class="tmf-buttons' . (empty($buttonClasses) ? '' : (' ' . implode(' ', $buttonClasses))) .'">';
$indent .= ' ';
$body .= sprintf('%s<li class="tmf-button tmf-button-major"><a href="./%s">Download %s</a></li>', $indent, $fileName, $version);
$body .= sprintf('%s<li class="tmf-button"><a href="./changelog.php#%s">Changelog</a></li>', $indent, $version);
if(is_file($sourceArchive))
$body .= sprintf('%s<li class="tmf-button"><a href="./%s">Source Code (.zip)</a></li>', $indent, $sourceArchive);
$indent = substr($indent, 0, -4);
$body .= $indent . '</ul>'
. $indent . '<div class="tmf-clear"></div>';
}
$indent = substr($indent, 0, -4);
$body .= $indent;
require_once __DIR__ . '/_inc/out.php';

BIN
public/gradient.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

BIN
public/help.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 B

BIN
public/icon.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

39
public/index.php Normal file
View file

@ -0,0 +1,39 @@
<?php
$_curr_page = 'home';
$description = 'Top Most Friend is a utility for making windows always be on top, forcefully.';
$indent = "\r\n ";
$body = $indent . '<h2>Home</h2>'
. $indent . '<p>Top Most Friend is the next instalment in the friend family of utilities. This friend runs in your system notification area and allows you to force any visible window of any process to always be on top with a simple right click menu or the press of a hotkey.</p>';
$body .= $indent . '<div class="tmf-godownload">'
. $indent . ' <a href="./downloads.php#latest">Get the latest version!</a>'
. $indent . '</div>';
$body .= $indent . '<h3>Tray Area</h3>';
$body .= $indent . '<img src="./ss-main-160.jpg" alt="Main UI in v1.6.0"/>';
$body .= $indent . '<p>Top Most Friend runs in your system tray area. When right clicking on it you\'re presented with a menu that contains all currently open windows as well as a number of actions.</p>';
$body .= $indent . '<p>Clicking any of the windows will toggle its always on top status, Refresh will reload the window list without dismissing the menu, Settings will open the settings menu displayed below, About shows the about window displayed in the screenshot, and Quit closes the program.</p>';
$body .= $indent . '<div class="tmf-clear"></div>';
$body .= $indent . '<h3>Settings</h3>';
$body .= $indent . '<img src="./ss-settings-160.jpg" alt="Settings in v1.6.0"/>';
$body .= $indent . '<p>In the settings you can alter program behaviour, set a global hotkey that will toggle the always on top status of whichever window currently has focus and open the title blacklist window.</p>';
$body .= $indent . '<p>Some windows require administrator privileges to have their top most status toggled, normally the program will prompt you if this is needed but you can also choose to always make the program start itself as administrator. This will have no effect on version of Windows before Vista.</p>';
$body .= $indent . '<p>You can also choose to omit the program list from the taskbar menu if you only plan on using the hotkey functionality, this will make the menu open ever so slightly faster.</p>';
$body .= $indent . '<p>The other options are fairly self explanatory, if you\'ve accidentally SHIFT+CLICK\'d a window onto the title blacklist you can just open the submenu and remove it again.</p>';
$body .= $indent . '<div class="tmf-clear"></div>';
$body .= $indent . '<h3>Title Blacklisting</h3>';
$body .= $indent . '<img src="./ss-settings-blacklist-160.jpg" alt="Title blacklist in v1.6.0"/>';
$body .= $indent . '<p>The title blacklist functions as a way to keep the list in the menu clean, it does not affect anything in regards to the hotkey. Depending on your version of Windows, a number of items may be added by default which are either invisible windows or cannot be toggled at all.</p>';
$body .= $indent . '<p>You can add, edit and remove entries using a simple text entry screen, as described in the previous section you can also SHIFT+CLICK things in the program list if enable.</p>';
$body .= $indent . '<div class="tmf-clear"></div>';
if(!empty($_GET['sim']))
$body .= $indent . '<script src="./simulator.js" charset="utf-8"></script>';
$body .= substr($indent, 0, -4);
require_once __DIR__ . '/_inc/out.php';

56
public/index_old.php Normal file
View file

@ -0,0 +1,56 @@
<!doctype html>
<title>Top Most Friend</title>
<img src="site-head.png" alt="Top Most Friend" style="margin-bottom: 2px;"/><br/>
<a href="./">Home</a> -
<a href="//github.com/flashwave/topmostfriend">Source</a>
<hr/>
<p>Top Most Friend is the next instalment in the friend family of utilities. This friend runs in your system notification area and allows you to force any visible window of any process to always be on top with a simple right click menu or the press of a hotkey.</p>
<p><a href="./TopMostFriend.exe">Download for .NET Framework 4.0</a> (this is <b>not</b> a permalink, SHA256: <code><?=hash_file('sha256', 'TopMostFriend.exe');?></code>)</p>
<hr/>
<h2>Changelog</h2>
<h3>v1.5.1 &mdash; 2021-02-04</h3>
<p>
<code>[*]</code> Fixed massive oversight.
</p>
<h3>v1.5.0 &mdash; 2021-02-04</h3>
<p>
<code>[+]</code> Added toggle to disable the window list in the context menu.<br/>
<code>[+]</code> Added manual refresh button for the window list.<br/>
<code>[*]</code> Greatly improved window list loading speed.
</p>
<h3>v1.4.2 &mdash; 2020-07-10</h3>
<p>
<code>[+]</code> Added ability to bind the Windows key for the hotkey combination.
</p>
<h3>v1.4.1 &mdash; 2020-06-10</h3>
<p>
<code>[*]</code> Fixed oversight in initial title blacklist generation on Windows Vista and 7.
</p>
<h3>v1.4.0 &mdash; 2020-06-10</h3>
<p>
<code>[+]</code> Added hotkey indicator, if used the notification area icon will temporarily change to the affected window's icon.<br/>
<code>[-]</code> Removed hidden <code>ShowExplorerMisc</code> registry switch, explorer windows are now just listed like any other.<br/>
<code>[-]</code> Removed static exclusion for windows with the title <code>Program Manager</code> or <code>Start</code>.<br/>
<code>[+]</code> Added manual title blacklisting system, titles in the previously mentioned change are added to it by default but can be removed if desired.
</p>
<h3>v1.3.0 &mdash; 2020-01-12</h3>
<p>
<code>[+]</code> Added notification balloon on hotkey toggle, disabled by default on Windows 10 and beyond.<br/>
<code>[-]</code> Removed useless left click handler.
</p>
<h3>v1.2.0 &mdash; 2020-01-07</h3>
<p>
<code>[+]</code> Added option to always ask for admin on start.<br/>
<code>[+]</code> Added error message when topmost toggle fails, if it fails and the process isn't running as administrator it'll ask to elevate.<br/>
<code>[+]</code> Added <code>--reset-admin</code> cli flag to revert always admin status.<br/>
<code>[+]</code> Added <code>--hwnd=</code> cli flag which allows for toggling a window's topmost status immediately. Used by the elevation prompt.<br/>
<code>[+]</code> Added <code>--stop</code> cli flag to close the program after processing cli flags.
</p>
<h3>v1.1.0 &mdash; 2020-01-06</h3>
<p>
<code>[+]</code> Added ability to register a hotkey to toggle the currently active window between always on top and not.<br/>
<code>[+]</code> Added a couple registry values for customisation and hidden list items.<br/>
<code>[*]</code> Ensuring that only one instance is running.
</p>
<h3>v1.0.0 &mdash; 2020-01-05</h3>
<p><code>[+]</code> Initial Release</p>

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
public/pattern.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

897
public/simulator.js Normal file
View file

@ -0,0 +1,897 @@
// An attempt was made to make this entirely function in IE8, I gave up at the polishing stage
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if(!Object.keys) {
Object.keys = (function() {
'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function(obj) {
if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) {
throw new TypeError('Object.keys called on non-object');
}
var result = [], prop, i;
for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop);
}
}
if (hasDontEnumBug) {
for (i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i]);
}
}
}
return result;
};
}());
}
var tmfBindEvent = function(subject, name, callback) {
if(document.attachEvent)
return subject.attachEvent('on' + name, callback);
return subject.addEventListener(name, callback);
};
var tmfOnReady = function(callback) {
if(document.attachEvent)
document.attachEvent('onreadystatechange', function() {
if(document.readyState === 'complete')
callback();
});
else
document.addEventListener('DOMContentLoaded', function() {
callback();
});
};
var tmfCreateElement = function(elemInfo) {
elemInfo = elemInfo || {};
var elem = document.createElement(elemInfo.tag || 'div');
if(elemInfo.props) {
var propKeys = Object.keys(elemInfo.props);
for(var i = 0; i < propKeys.length; i++) {
var propKey = propKeys[i];
if(elemInfo.props[propKey] === undefined
|| elemInfo.props[propKey] === null)
continue;
switch(typeof elemInfo.props[propKey]) {
case 'function':
tmfBindEvent(
elem,
propKey.substring(0, 2) === 'on'
? propKey.substring(2).toLowerCase()
: propKey,
elemInfo.props[propKey]
);
break;
default:
elem.setAttribute(propKey === 'className' ? 'class' : propKey, elemInfo.props[propKey]);
break;
}
}
}
if(elemInfo.children) {
var children = elemInfo.children;
if(Object.prototype.toString.call(children) !== '[object Array]')
children = [children];
for(var i = 0; i < children.length; i++) {
var child = children[i];
if(typeof child === 'undefined')
continue;
switch(typeof child) {
case 'string':
elem.appendChild(document.createTextNode(child));
break;
case 'object':
if(child instanceof Element)
elem.appendChild(child);
else if(child.getElement)
elem.appendChild(child.getElement());
else
elem.appendChild(tmfCreateElement(child));
break;
default:
elem.appendChild(document.createTextNode(child.toString()));
break;
}
}
}
if(elemInfo.created)
elemInfo.created(elem);
return elem;
};
var tmfClientRectangle = function() {
if(typeof window.innerWidth !== 'undefined')
return [window.innerWidth, window.innerHeight];
if(typeof document.documentElement !== 'undefined'
&& typeof document.documentElement.clientWidth !== 'undefined'
&& document.documentElement.clientWidth !== 0)
return [document.documentElement.clientWidth, document.documentElement.clientHeight];
var body = document.getElementsByTagName('body')[0];
return [body.clientWidth, body.clientHeight];
};
var tmfIs12HourClockValue = null;
var tmfIs12Hour = function() {
if(typeof window.tmfIs12HourClockValue === 'boolean')
return window.tmfIs12HourClockValue;
var d = new Date;
return window.tmfIs12HourClockValue = !!(d.toLocaleTimeString().match(/am|pm/i) || d.toString().match(/am|pm/i));
};
var tmfTimeString = function() {
var date = new Date,
str = '',
stupid = tmfIs12Hour(),
dumb = '',
hours = date.getHours(),
mins = date.getMinutes();
if(stupid) {
dumb = hours > 11 ? 'pm' : 'am';
if(hours === 0)
hours = 12;
}
str = hours.toString() + ':';
if(mins < 10)
str += '0';
str += mins.toString();
if(stupid)
str += ' ' + dumb;
return str;
};
var tmfSetElemText = function(elem, text) {
if(typeof elem.textContent !== 'undefined')
elem.textContent = text;
else if(typeof elem.innerText !== 'undefined')
elem.innerText = text;
else {
elem.innerHTML = '';
elem.appendChild(document.createTextNode(text));
}
};
var tmfCreateMenuItem = function(name, icon, click) {
var item = tmfCreateElement({
props: { className: 'tmfs-menu-item' },
children: [
{
props: { className: 'tmfs-menu-item-icon' },
children: {
tag: 'img',
props: {
src: icon,
alt: name,
},
},
},
{
props: { className: 'tmfs-menu-item-text' },
children: name,
},
],
});
tmfBindEvent(item, 'click', click);
return item;
};
var tmfRemoveElement = function(elem) {
if(elem && elem.parentNode)
elem.parentNode.removeChild(elem);
};
var tmfGetCentrePosition = function(width, height) {
var rect = tmfClientRectangle();
rect[0] /= 2;
rect[1] /= 2;
rect[0] -= Math.ceil(width / 2);
rect[1] -= Math.ceil(height / 2);
return rect;
};
var tmfGetCentrePositionStyle = function(width, height) {
var rect = tmfGetCentrePosition(width, height);
return 'top: ' + rect[1].toString() + 'px; left: ' + rect[0].toString() + 'px;';
};
var tmfShowAbout = function() {
var about = tmfCreateElement({
props: {
className: 'tmfs-about',
style: tmfGetCentrePositionStyle(445, 120),
},
children: [
{
props: {
className: 'tmfs-about-drag',
onmousedown: function() {
tmfSetDragging(about);
},
},
},
{
props: { className: 'tmfs-about-version' },
children: [
'v1.5.1',
{ tag: 'br' },
'Simulator',
],
},
{
tag: 'input',
props: {
className: 'tmfs-about-button tmfs-about-button-donate',
type: 'button',
value: 'Donate',
onClick: function() {
tmfRemoveElement(about);
document.getElementById('_nav_donate').click();
},
},
},
{
tag: 'input',
props: {
className: 'tmfs-about-button tmfs-about-button-website',
type: 'button',
value: 'Website',
onClick: function() {
tmfRemoveElement(about);
// should this do anything? we're already there lol
},
},
},
{
tag: 'input',
props: {
className: 'tmfs-about-button tmfs-about-button-close',
type: 'button',
value: 'Close',
onClick: function() {
tmfRemoveElement(about);
},
},
},
{
tag: 'a',
props: {
className: 'tmfs-about-credit',
href: '//flash.moe',
target: '_blank',
rel: 'noopener',
},
},
{
tag: 'a',
props: {
className: 'tmfs-about-credit tmfs-about-credit-fff',
href: 'http://www.famfamfam.com/lab/icons/silk/',
target: '_blank',
rel: 'noopener',
},
},
],
});
document.body.appendChild(about);
};
var tmfCtxMenu = null;
var tmfShowCtxMenu = function(xpos, ypos) {
tmfDestroyCtxMenu();
var refresh = tmfCreateMenuItem('Refresh', './arrow_refresh.gif', function() {
// can this do anything?
}), settings = tmfCreateMenuItem('Settings', './cog.gif', function() {
tmfDestroyCtxMenu();
tmfShowSettings();
}), about = tmfCreateMenuItem('About', './help.gif', function() {
tmfDestroyCtxMenu();
tmfShowAbout();
}), quit = tmfCreateMenuItem('Quit', './door_in.gif', function() {
tmfDestroyCtxMenu();
tmfDestroySysIcon();
});
tmfCtxMenu = tmfCreateElement({
props: {
className: 'tmfs-menu',
},
children: [
refresh,
settings,
about,
quit,
],
});
document.body.appendChild(tmfCtxMenu);
xpos -= tmfCtxMenu.offsetWidth;
ypos -= tmfCtxMenu.offsetHeight;
tmfCtxMenu.style.top = ypos.toString() + 'px';
tmfCtxMenu.style.left = xpos.toString() + 'px';
};
var tmfDestroyCtxMenu = function() {
if(tmfCtxMenu)
tmfRemoveElement(tmfCtxMenu);
tmfCtxMenu = null;
};
var tmfSysIcon = null;
var tmfDestroySysIcon = function() {
if(tmfSysIcon)
tmfRemoveElement(tmfSysIcon);
tmfSysIcon = null;
};
var tmfDragging = null, tmfDragLastX = 0, tmfDragLastY = 0;
var tmfSetDragging = function(elem) {
//tmfDragging = elem;
};
var tmfStopDragging = function() {
tmfDragging = null;
};
var tmfDragHandler = function(ev) {
var movX = ev.screenX - tmfDragLastX,
movY = ev.screenY - tmfDragLastY;
tmfDragLastX = ev.screenX;
tmfDragLastY = ev.screenY;
if(tmfDragging === null)
return;
var xpos = tmfDragging.offsetLeft + movX,
ypos = tmfDragging.offsetTop + movY;
tmfDragging.style.left = xpos.toString() + 'px';
tmfDragging.style.top = ypos.toString() + 'px';
};
var tmfCreateWindow = function(title, className, width, height, closeHandler) {
var frame, body = tmfCreateElement({
props: { className: 'tmfs-window-body' },
});
if(!closeHandler)
closeHandler = function() {
tmfRemoveElement(frame);
};
frame = tmfCreateElement({
props: {
className: 'tmfs-window ' + className,
style: tmfGetCentrePositionStyle(width, height),
},
children: [
{
props: {
className: 'tmfs-window-title',
onmousedown: function() {
tmfSetDragging(frame);
},
},
children: [
{
tag: 'img',
props: {
className: 'tmfs-window-title-icon',
alt: 'ico',
src: './icon.gif',
},
},
{
props: {
className: 'tmfs-window-title-close',
onclick: closeHandler,
},
children: 'X',
},
{
props: {
className: 'tmfs-window-title-text',
},
children: title.toString(),
},
],
},
body,
],
});
document.body.appendChild(frame);
return {
frame: frame,
body: body,
};
};
var tmfCreateFieldset = function(title, className) {
var body = tmfCreateElement({
props: {
className: 'tmfs-fieldset-body',
}
});
var frame = tmfCreateElement({
tag: 'fieldset',
props: {
className: 'tmfs-fieldset ' + className,
},
children: [
{
tag: 'legend',
props: {
className: 'tmfs-fieldset-title',
},
children: title.toString()
},
body,
],
});
return {
frame: frame,
body: body,
};
};
var tmfCreateCheckbox = function(className, label, state, enabled, onChange) {
return tmfCreateElement({
tag: 'label',
props: {
className: 'tmfs-checkbox ' + className,
},
children: [
{
tag: 'input',
props: {
type: 'checkbox',
className: 'tmfs-checkbox-input',
checked: state ? true : undefined,
disabled: enabled ? undefined : true,
onchange: function(ev) { onChange(ev.target.checked) },
},
},
{
props: {
className: 'tmfs-checkbox-label',
},
children: label.toString(),
}
],
});
};
var tmfSettingsWindow = null;
var tmfCloseSettings = function() {
if(tmfSettingsWindow === null)
return;
tmfRemoveElement(tmfSettingsWindow);
tmfSettingsWindow = null;
};
var tmfShowSettings = function() {
tmfCloseSettings();
var wnd = tmfCreateWindow('Top Most Friend Settings', 'tmfs-settings', 436, 323),
settings = tmfConfig;
tmfSettingsWindow = wnd.frame;
var hotkeys = tmfCreateFieldset('Hotkeys', 'tmfs-settings-fieldset tmfs-settings-hotkeys'),
flags = tmfCreateFieldset('Flags', 'tmfs-settings-fieldset tmfs-settings-flags'),
blacklist = tmfCreateFieldset('Blacklist', 'tmfs-settings-fieldset tmfs-settings-blacklist');
var hotKeyChar = String.fromCharCode((settings.ForegroundHotKey & 0xFFFF0000) >> 16);
hotkeys.body.appendChild(tmfCreateElement({
props: {
className: 'tmfs-settings-hotkey-label',
},
children: 'Toggle always on top status on active window',
}));
hotkeys.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
id: '_settings_hotkey_key',
type: 'text',
value: hotKeyChar,
className: 'tmfs-settings-hotkey-key',
onkeydown: function(ev) {
var keyCode = (typeof ev.key !== 'undefined')
? ev.key.toUpperCase().charCodeAt(0)
: ev.keyCode;
settings.ForegroundHotKey &= 0xFFFF;
settings.ForegroundHotKey |= keyCode << 16;
ev.target.value = String.fromCharCode(keyCode);
if(ev.preventDefault)
ev.preventDefault();
return false;
},
}
}));
hotkeys.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
id: '_settings_hotkey_ctrl',
type: 'button',
value: 'CTRL',
className: 'tmfs-settings-hotkey-mod tmfs-settings-hotkey-mod-ctrl' + ((settings.ForegroundHotKey & 0x2) ? ' pressed' : ''),
onclick: function(ev) {
if(settings.ForegroundHotKey & 0x2) {
ev.target.className = ev.target.className.replace(' pressed', '');
settings.ForegroundHotKey &= ~0x2;
} else {
ev.target.className += ' pressed';
settings.ForegroundHotKey |= 0x2;
}
},
}
}));
hotkeys.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
id: '_settings_hotkey_alt',
type: 'button',
value: 'ALT',
className: 'tmfs-settings-hotkey-mod tmfs-settings-hotkey-mod-alt' + ((settings.ForegroundHotKey & 0x1) ? ' pressed' : ''),
onclick: function(ev) {
if(settings.ForegroundHotKey & 0x1) {
ev.target.className = ev.target.className.replace(' pressed', '');
settings.ForegroundHotKey &= ~0x1;
} else {
ev.target.className += ' pressed';
settings.ForegroundHotKey |= 0x1;
}
},
}
}));
hotkeys.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
id: '_settings_hotkey_shift',
type: 'button',
value: 'SHIFT',
className: 'tmfs-settings-hotkey-mod tmfs-settings-hotkey-mod-shift' + ((settings.ForegroundHotKey & 0x4) ? ' pressed' : ''),
onclick: function(ev) {
if(settings.ForegroundHotKey & 0x4) {
ev.target.className = ev.target.className.replace(' pressed', '');
settings.ForegroundHotKey &= ~0x4;
} else {
ev.target.className += ' pressed';
settings.ForegroundHotKey |= 0x4;
}
},
}
}));
hotkeys.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
id: '_settings_hotkey_win',
type: 'button',
value: 'WIN',
className: 'tmfs-settings-hotkey-mod tmfs-settings-hotkey-mod-win' + ((settings.ForegroundHotKey & 0x8) ? ' pressed' : ''),
onclick: function(ev) {
if(settings.ForegroundHotKey & 0x8) {
ev.target.className = ev.target.className.replace(' pressed', '');
settings.ForegroundHotKey &= ~0x8;
} else {
ev.target.className += ' pressed';
settings.ForegroundHotKey |= 0x8;
}
},
}
}));
hotkeys.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
value: 'Reset',
className: 'tmfs-settings-hotkey-reset',
onclick: function(ev) {
settings.ForegroundHotKey = 0;
document.getElementById('_settings_hotkey_key').value = '';
var meow = ['ctrl', 'alt', 'shift', 'win'];
for(var i = 0; i < meow.length; ++i) {
var mewow = document.getElementById('_settings_hotkey_' + meow[i]);
mewow.className = mewow.className.replace(' pressed', '');
}
},
}
}));
flags.body.appendChild(tmfCreateCheckbox('tmfs-settings-checkbox tmfs-settings-checkbox-admin', 'Always run as administrator', settings.RunAsAdministrator, true, function(state) { settings.RunAsAdministrator = state; }));
flags.body.appendChild(tmfCreateCheckbox('tmfs-settings-checkbox tmfs-settings-checkbox-hotkey', 'Show notification when using toggle hotkey', settings.ShowNotificationOnHotKey, true, function(state) { settings.ShowNotificationOnHotKey = state; }));
flags.body.appendChild(tmfCreateCheckbox('tmfs-settings-checkbox tmfs-settings-checkbox-shiftclick', 'SHIFT+CLICK items in the list to add to the title blacklist', settings.ShiftClickToBlacklist, true, function(state) { settings.ShiftClickToBlacklist = state; }));
flags.body.appendChild(tmfCreateCheckbox('tmfs-settings-checkbox tmfs-settings-checkbox-icon', 'Show icon of window affected by hotkey', settings.ShowHotkeyIcon, true, function(state) { settings.ShowHotkeyIcon = state; }));
flags.body.appendChild(tmfCreateCheckbox('tmfs-settings-checkbox tmfs-settings-checkbox-list', 'Show list of open windows in the task bar context menu', settings.ShowWindowList, false, function(state) { settings.ShowWindowList = state; }));
blacklist.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
value: 'Manage...',
className: 'tmfs-settings-button tmfs-settings-blacklist-button',
onclick: function() {
tmfShowBlacklist();
},
},
}));
wnd.body.appendChild(hotkeys.frame);
wnd.body.appendChild(flags.frame);
wnd.body.appendChild(blacklist.frame);
wnd.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
className: 'tmfs-settings-button tmfs-settings-button-ok',
value: 'OK',
onclick: function() {
tmfConfig = settings;
tmfCloseSettings();
},
}
}));
wnd.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
className: 'tmfs-settings-button tmfs-settings-button-cancel',
value: 'Cancel',
onclick: function() {
tmfCloseSettings();
},
}
}));
wnd.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
className: 'tmfs-settings-button tmfs-settings-button-apply',
value: 'Apply',
onclick: function() {
tmfConfig = settings;
},
}
}));
//tmfShowBlacklist();
};
var tmfBlacklistWindow = null;
var tmfCloseBlacklist = function() {
if(tmfBlacklistWindow === null)
return;
tmfRemoveElement(tmfBlacklistWindow);
tmfBlacklistWindow = null;
};
var tmfShowBlacklist = function() {
tmfCloseBlacklist();
var wnd = tmfCreateWindow('Title Blacklist', 'tmfs-blacklist', 418, 230),
blacklist = tmfConfig.TitleBlacklist,
listView = tmfCreateElement({
tag: 'select',
props: {
className: 'tmfs-blacklist-list',
size: 15,
},
});
tmfBlacklistWindow = wnd.frame;
wnd.body.appendChild(listView);
var refreshList = function() {
listView.innerHTML = '';
for(var i = 0; i < blacklist.length; ++i)
listView.appendChild(tmfCreateElement({
tag: 'option',
children: blacklist[i].toString(),
}));
};
refreshList();
wnd.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
className: 'tmfs-blacklist-button tmfs-blacklist-button-add',
value: 'Add',
onclick: function() {
var title = prompt('Add new entry...');
if(title && blacklist.indexOf(title) < 0)
blacklist.push(title);
refreshList();
},
},
}));
wnd.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
className: 'tmfs-blacklist-button tmfs-blacklist-button-edit',
value: 'Edit',
onclick: function() {
var selected = blacklist.indexOf(listView.value);
if(selected < 0)
return;
var title = prompt('Editing ' + listView.value + '...');
if(title && blacklist.indexOf(title) < 0) {
blacklist.splice(selected, 1);
blacklist.push(title);
}
refreshList();
},
},
}));
wnd.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
className: 'tmfs-blacklist-button tmfs-blacklist-button-remove',
value: 'Remove',
onclick: function() {
var selected = blacklist.indexOf(listView.value);
if(selected < 0)
return;
blacklist.splice(selected, 1);
refreshList();
},
},
}));
wnd.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
className: 'tmfs-blacklist-button tmfs-blacklist-button-done',
value: 'Done',
onclick: function() {
tmfConfig.TitleBlacklist = blacklist;
tmfCloseBlacklist();
},
},
}));
wnd.body.appendChild(tmfCreateElement({
tag: 'input',
props: {
type: 'button',
className: 'tmfs-blacklist-button tmfs-blacklist-button-cancel',
value: 'Cancel',
onclick: function() {
tmfCloseBlacklist();
},
},
}));
};
var tmfConfig = {
ForegroundHotKey: 0,
RunAsAdministrator: false,
ShowNotificationOnHotKey: true,
ShiftClickToBlacklist: true,
ShowHotkeyIcon: true,
ShowWindowList: false,
TitleBlacklist: [
'Start',
'Program Manager',
'Windows Shell Experience Host',
],
};
tmfOnReady(function(ev) {
var rect = tmfClientRectangle();
if(rect[1] > rect[0]) // height is larger than width, we're presemably running on a phone
return;
var clock = tmfCreateElement({
props: { className: 'tmfs-clock' },
children: tmfTimeString(),
});
tmfSysIcon = tmfCreateElement({
tag: 'img',
props: {
className: 'tmfs-icon',
alt: 'TopMostFriend',
title: 'Top Most Application Manager',
src: './icon.gif',
},
});
var taskbar = tmfCreateElement({
props: { className: 'tmfs' },
children: {
props: { className: 'tmfs-inner' },
children: [
{
props: { className: 'tmfs-left' },
children: {
props: { className: 'tmfs-start' },
children: [
{
tag: 'img',
props: {
alt: '',
src: './start.gif',
},
},
'Start',
],
},
},
{
props: { className: 'tmfs-right' },
children: {
props: { className: 'tmfs-systray' },
children: [
tmfSysIcon,
clock,
],
},
},
{ props: { className: 'tmf-clear' } },
]
},
});
document.getElementById('_tmf').style.paddingBottom = '30px';
document.body.appendChild(taskbar);
/*tmfBindEvent(tmfSysIcon, 'click', function(ev) {
if(ev.shiftKey)
return true;
tmfShowCtxMenu(ev.clientX, ev.clientY);
if(ev.preventDefault)
ev.preventDefault();
return false;
});*/
tmfBindEvent(tmfSysIcon, 'contextmenu', function(ev) {
if(ev.shiftKey)
return true;
tmfShowCtxMenu(ev.clientX, ev.clientY);
if(ev.preventDefault)
ev.preventDefault();
return false;
});
tmfBindEvent(document, 'mousemove', tmfDragHandler);
tmfBindEvent(document, 'mouseup', tmfStopDragging);
setInterval(function() {
tmfSetElemText(clock, tmfTimeString());
}, 1000);
});

BIN
public/site-head.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
public/ss-main-160.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
public/ss-main.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
public/ss-settings-160.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
public/ss-settings.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
public/start.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

483
public/style.css Normal file
View file

@ -0,0 +1,483 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
position: relative;
outline-style: none !important;
}
html,
body {
width: 100%;
height: 100%;
}
body {
background-color: #111;
color: #fff;
font: 12px/20px Tahoma, Geneva, 'Dejavu Sans', Arial, Helvetica, sans-serif;
padding-top: 2px;
}
.tmf {
max-width: 1000px;
margin: 0 auto;
}
.tmf-head {
background: #222;
padding: 2px;
}
.tmf-head-nav {
font-size: 1.4em;
}
.tmf-head-nav li {
list-style: none;
float: left;
}
.tmf-head-nav a:hover,
.tmf-head-nav a:focus,
.tmf-head-nav li.current a {
background-image: url('pattern.jpg');
background-attachment: fixed;
}
.tmf-head-nav a {
color: #fff;
text-decoration: none;
padding: 8px 10px;
display: inline-block;
}
.tmf-head-logo {
clear: both;
background-image: url('pattern.jpg');
background-attachment: fixed;
padding: 20px;
padding-top: 26px;
}
.tmf-head-logo h1 {
font-size: 0;
background-image: url('logo.png');
width: 269px;
height: 43px;
}
.tmf-clear {
clear: both;
}
.tmf-foot {
font-size: .9em;
text-align: center;
color: #555;
margin: 5px;
}
.tmf-foot a {
color: #555 !important;
text-decoration: none !important;
}
.tmf-foot a:hover,
.tmf-foot a:focus {
text-decoration: underline !important;
}
.tmf-body {
padding: 2px;
background-color: #222;
margin: 2px 0;
}
.tmf h2 {
line-height: 1.5em;
border-bottom: 1px solid #444;
}
.tmf--home h3,
.tmf--changelog h3,
.tmf--downloads h3 {
margin-top: .5em;
border-bottom: 1px solid #333;
}
.tmf--changelog a,
.tmf--downloads a {
color: #fff;
text-decoration: none;
}
.tmf--downloads h3 {
margin-top: 1em;
}
.tmf-buttons {
list-style: none;
}
.tmf-button {
float: left;
margin: 2px 1px;
}
.tmf-button a {
padding: 10px;
display: inline-block;
background-color: #555;
font-size: 1.2em;
}
.tmf-button-major a {
padding: 10px 60px;
background-color: #595;
}
.tmf-button-latest a {
padding: 20px 30px;
font-size: 1.3em;
}
.tmf-button-latest .tmf-button-major a {
padding: 20px 60px;
}
.tmf-external {
color: #77f !important;
text-decoration: none !important;
}
.tmf-external:hover,
.tmf-external:focus {
text-decoration: underline !important;
}
.tmf-external:active {
color: #f77 !important;
}
.tmf--home img {
float: right;
margin: 2px;
max-width: 100%;
}
.tmf--home p {
margin: .5em 0;
}
@media(max-width: 700px) {
.tmf--home img {
float: none !important;
margin: 2px auto;
display: block;
}
}
.tmf-godownload {
text-align: center;
}
.tmf-godownload a {
display: inline-block;
padding: 20px 60px;
background-color: #595;
font-size: 1.3em;
color: #fff;
text-decoration: none;
}
.tmfs {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #d4d0c8;
height: 30px;
color: #000;
}
.tmfs-inner {
margin-top: 1px;
border-top: 1px solid #fff;
}
.tmfs-left {
float: left;
}
.tmfs-right {
float: right;
}
.tmfs-systray {
border: 1px inset #fff;
height: 24px;
margin: 2px;
padding: 0 4px;
}
.tmfs-systray * {
float: left;
}
.tmfs-systray img {
margin-top: 2px;
margin-right: 4px;
}
.tmfs-clock {
margin-left: 2px;
}
.tmfs-start {
border: 2px outset #bbb;
height: 24px;
margin: 2px;
padding: 0 4px;
font-weight: 700;
}
.tmfs-start img {
vertical-align: bottom;
margin-right: 3px;
}
.tmfs-menu {
position: fixed;
z-index: 1000;
background: #f9f8f7;
border: 1px solid #666;
color: #000;
box-shadow: 1px 1px 2px #000;
}
.tmfs-menu-item {
height: 24px;
min-width: 120px;
}
.tmfs-menu-item-icon {
background-image: url('gradient.gif');
width: 24px;
height: 24px;
float: left;
}
.tmfs-menu-item-icon img {
margin: 4px;
vertical-align: middle;
}
.tmfs-menu-item-text {
float: left;
padding: 0 10px;
line-height: 22px;
}
.tmfs-about {
position: fixed;
background-image: url('about.jpg');
width: 445px;
height: 120px;
overflow: hidden;
}
.tmfs-about-version {
position: absolute;
top: 79px;
left: 128px;
line-height: 16px;
}
.tmfs-about-button {
position: absolute;
width: 70px;
height: 22px;
top: 88px;
}
.tmfs-about-button-close {
left: 363px;
}
.tmfs-about-button-website {
left: 286px;
}
.tmfs-about-button-donate {
left: 209px;
}
.tmfs-about-credit {
position: absolute;
width: 300px;
height: 15px;
display: block;
top: 46px;
left: 133px;
}
.tmfs-about-credit-fff {
top: 64px;
}
.tmfs-about-drag {
position: absolute;
width: 100%;
height: 100%;
}
.tmfs-window {
position: fixed;
width: 400px;
height: 400px;
overflow: hidden;
margin: 2px;
top: 0;
left: 0;
background-color: #d4d0c8;
padding: 1px;
border: 2px outset #ccc;
}
.tmfs-window-title {
background-image: linear-gradient(90deg, #000080, #1084d0);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#000080', endColorstr='#1084d0', GradientType=1);
height: 18px;
}
.tmfs-window-title-icon {
float: left;
vertical-align: middle;
width: 16px;
height: 16px;
margin: 0 2px;
z-index: 200;
}
.tmfs-window-title-text {
font-weight: 700;
font-size: .9em;
line-height: 17px;
z-index: 100;
}
.tmfs-window-title-close {
float: right;
width: 16px;
height: 14px;
border: 2px outset #ccc;
font-weight: 700;
font-size: .9em;
background-color: #d4d0c8;
z-index: 200;
line-height: 9px;
text-align: center;
color: #000;
margin: 2px;
cursor: pointer;
}
.tmfs-window-title-close:active {
border-style: inset;
}
.tmfs-blacklist {
width: 418px;
height: 230px;
}
.tmfs-blacklist-list {
font-size: .9em;
width: 318px;
height: 192px;
position: absolute;
top: 7px;
left: 88px;
}
.tmfs-blacklist-list option {
padding: 0 2px;
}
.tmfs-blacklist-button {
position: absolute;
width: 75px;
height: 23px;
left: 6px;
}
.tmfs-blacklist-button-add {
top: 7px;
}
.tmfs-blacklist-button-edit {
top: 36px;
}
.tmfs-blacklist-button-remove {
top: 65px;
}
.tmfs-blacklist-button-done {
top: 146px;
}
.tmfs-blacklist-button-cancel {
top: 175px;
}
.tmfs-fieldset-title {
color: #000;
margin: 0 5px;
}
.tmfs-checkbox {
color: #000;
display: block;
}
.tmfs-checkbox-label {
display: inline-block;
cursor: pointer;
}
.tmfs-settings {
width: 436px;
height: 323px;
}
.tmfs-settings-button {
position: absolute;
width: 75px;
height: 23px;
top: 269px;
}
.tmfs-settings-button-ok {
left: 187px;
}
.tmfs-settings-button-cancel {
left: 268px;
}
.tmfs-settings-button-apply {
left: 349px;
}
.tmfs-settings-fieldset {
position: absolute;
width: 418px;
left: 8px;
}
.tmfs-settings-hotkeys {
top: 6px;
height: 70px;
}
.tmfs-settings-flags {
top: 76px;
height: 130px;
}
.tmfs-settings-blacklist {
top: 207px;
height: 55px;
}
.tmfs-settings-blacklist-button {
left: 8px;
top: 2px;
width: 120px;
}
.tmfs-settings-checkbox .tmfs-checkbox-input {
margin: 0 7px;
}
.tmfs-settings-hotkey-label {
color: #000;
position: absolute;
top: 0;
left: 7px;
}
.tmfs-settings-hotkey-key {
width: 100px;
height: 20px;
position: absolute;
left: 7px;
top: 20px;
}
.tmfs-settings-hotkey-mod {
width: 50px;
height: 23px;
position: absolute;
top: 19px;
}
.tmfs-settings-hotkey-mod.pressed {
border: 1px solid #808080;
}
.tmfs-settings-hotkey-mod-ctrl {
left: 115px;
}
.tmfs-settings-hotkey-mod-alt {
left: 165px;
}
.tmfs-settings-hotkey-mod-shift {
left: 215px;
}
.tmfs-settings-hotkey-mod-win {
left: 265px;
}
.tmfs-settings-hotkey-reset {
width: 75px;
height: 23px;
position: absolute;
top: 19px;
left: 328px;
}