// 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); });