NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name dAmn Tab Logger
// @namespace MiloticScale
// @author Jonathon Braswell
// @description Allows you to see all messages directed toward you neatly in a floating modal.
// @include http://chat.deviantart.com/chat/*
// @version 1.1
// ==/UserScript==
// Parent function to append to the DOM on init
var script = document.createElement('script');
var helperScript = freeFunctionString((function(){
// Pertinent object to house the utility functions.
dAmn_TabLogger = {
// version
// Returns: String
// Purpose: Shortcut for version
version: "v.1.1",
// testers
// Returns: Array
// Purpose: Keeps track of script testers who helped out. Might implement something special
// for them at a later time.
testers: ['pickley', 'deviant-garde', 'darkalchemistninja', 'romaji', 'farand', 'ricsmond', 'lady-ra', 'princejose', 'moronicglasskiller', 'kristenspork'],
// updateStatus
// Arguments: Boolean status
// Returns: void
// Purpose: Toggle text and styling of the on/off button in the modal
updateStatus: function(status) {
if(status)
$('#dAmn_TabLoggerStatus')
.removeAttr('style')
.css(dAmn_TabLogger.CSS.status)
.css(dAmn_TabLogger.CSS.onStatus)
.text("on");
else
$('#dAmn_TabLoggerStatus')
.removeAttr('style')
.css(dAmn_TabLogger.CSS.status)
.css(dAmn_TabLogger.CSS.offStatus)
.text("off");
},
// addLog
// Arguments: Object info
// Returns: void
// Purpose: Collect message information from the DOM and reflect it in the modal. Calls this.playSound
addLog: function(info) {
$('#dAmn_TabLoggerLogs .no-logs').hide();
var infoString = info.time + " [" + info.chat + "] <<i></i>" + info.from + "<i></i>> " + info.message;
var newLog = $('<span/>')
.addClass('log')
.html(infoString + "<hr>")
.appendTo($('#dAmn_TabLoggerLogs'));
},
// clearLog
// Arguments: none
// Returns: void
// Purpose: Empty the modal of logs
clearLog: function() {
$('#dAmn_TabLoggerLogs .log, #dAmn_TabLoggerLogs hr').remove();
$('#dAmn_TabLoggerLogs .no-logs').fadeIn();
this.notify("Cleared tab logs");
},
// showLog
// Arguments: none
// Returns: void
// Purpose: Display the modal
showLog: function() {
$('#dAmn_TabLoggerModal').fadeIn();
},
// hideLog
// Arguments: none
// Returns: void
// Purpose: Hide the modal
hideLog: function() {
$('#dAmn_TabLoggerModal').fadeOut();
},
// showPreferences
// Arguments: none
// Returns: void
// Purpose: Show the preferences modal
showPreferences: function() {
$('#dAmn_TabLoggerLogs').hide('fast');
$('#dAmn_TabLoggerPreferencesModal').show('fast');
},
// hidePreferences
// Arguments: none
// Returns: void
// Purpose: Hide the preferences modal
hidePreferences: function() {
$('#dAmn_TabLoggerPreferencesModal').hide('fast');
$('#dAmn_TabLoggerLogs').show('fast');
},
// start
// Arguments: Boolean doNotify
// Returns: void
// Purpose: Turns on logging, instantiates a MutationObserver. The MutationObserver
// calls this.addLog when the user is tabbed. Flips the on bit in localStorage.
// Calls this.notify and this.updateStatus
startLog: function(doNotify) {
if(localStorage.dAmn_TabLoggerStatus !== "on") {
localStorage.dAmn_TabLoggerStatus = "on";
this.updateStatus(true);
if(doNotify)
this.notify("Started logging tabs");
}
},
// stop
// Arguments: Boolean doNotify
// Returns: void
// Purpose: Deletes the MutationObserver on the chat window. Flips the bit
// in localStorage. Calls this.notify and this.updateStatus
stopLog: function(doNotify) {
if(localStorage.dAmn_TabLoggerStatus !== "off") {
localStorage.dAmn_TabLoggerStatus = "off";
this.updateStatus(false);
if(doNotify)
this.notify("Stopped logging tabs");
}
},
// notify
// Arguments: String message
// Returns: void
// Purpose: Appends message to the chat window. Attaches onclick event to the message
// which removes the element from the DOM. Make sure the window stays at the bottom, too.
notify: function(message) {
var notification = $('<div/>')
.addClass('msg part')
.css('font-weight', 'bold')
.html('<span style="font-size: 90%">' + this.getTimestamp() + '</span>' + ' *** ' + message + ' *');
$(notification).appendTo($('.damncrc-chat'));
$('.damncrc-chat-window').each(function(i, cWindow) {
$(cWindow).animate({ scrollTop: $('.damncrc-chat').eq(i).height() }, 'fast');
});
},
// getTimestamp
// Arguments: none
// Returns: String
// Purpose: Generates a timestamp
getTimestamp: function() {
function checkTime(time) {
return (time < 10 ? "0" + time : time);
}
var now = new Date();
var h = now.getHours();
h = h % 12;
h = checkTime(h);
h = h ? h : 12;
h = (h == "00" ? 12 : h);
var m = checkTime(now.getMinutes());
var s = checkTime(now.getSeconds());
var ampm = (now.getHours() >= 12 ? 'PM' : 'AM');
return (h + ':' + m + ':' + s + ' ' + ampm);
},
// CSS
// Purpose: House all CSS styling necessary in this user script as objects
CSS: {
logModal: {
'position': 'absolute',
'top': '50%',
'left': '50%',
'margin-top': '-200px',
'margin-left': '-35%',
'z-index': '9999',
'border': '1px solid #000',
'border-radius': '8px',
'text-align': 'center',
'display': 'none',
'background': '#bbc2bb',
'box-shadow': '0px 0px 10px #000',
'width': '60%',
'min-height': '100px'
},
logContainer: {
'padding': '20px',
'margin': '10px',
'background': '#fafffa',
'color': '#000',
'font-size': '13px',
'text-align': 'left',
'overflow': 'auto',
'min-height': '80%',
'min-width': '80%',
'max-height': '300px'
},
preferencesModal: {
'z-index': '99999',
'text-align': 'left',
'box-shadow': '0px 0px 5px #000',
'padding': '20px',
'width': '30%',
'position': 'initial',
'margin': '0 auto',
'margin-top': '20px',
'margin-bottom': '20px',
'background': '#fafffa'
},
status: {
'margin': '10px',
'border': '1px solid #000',
'border-radius': '50px',
'height': '15px',
'width': '35px',
'float': 'left',
'cursor': 'pointer',
'color': '#fafffa',
'text-align': 'center'
},
onStatus: {
'background': '#00cc00'
},
offStatus: {
'background': '#cc0000'
},
clearButton: {
'margin': '10px',
'border': '1px solid #000',
'border-radius': '50px',
'height': '15px',
'width': '35px',
'position': 'absolute',
'top': '0',
'left': '50px',
'cursor': 'pointer',
'background': '#fafffa',
'text-align': 'center'
},
preferencesButton: {
'margin': '10px',
'border': '1px solid #000',
'border-radius': '50px',
'height': '15px',
'width': '85px',
'position': 'absolute',
'top': '0',
'left': '100px',
'cursor': 'pointer',
'background': '#bbc2bb',
'text-align': 'center'
}
},
// bindCommands
// Arguments: none
// Returns: void
// Purpose: Binds chat commands to the relevant object methods
// Full credit for this model to electricjonny - http://electricjonny.deviantart.com
bindCommands: function() {
// Bind the chat commands to our object
dAmnChanChat.prototype.loggerCommands_Init = dAmnChanChat.prototype.Init;
dAmnChanChat.prototype.Init = function(cr, name, parent_el) {
this.loggerCommands_Init(cr, name, parent_el);
var cie = this.input;
cie.cmds['tablogger']=[0];
};
dAmnChatInput_onKey_loggerCommands = dAmnChatInput_onKey;
dAmnChatInput_onKey = function(e, kc, force) {
var el = this.chatinput_el;
if (kc == 13 && (force || !this.multiline || e.shiftKey || e.ctrlKey)) {
var input = el.value;
var args = /^\/(\S*)\s*(.*)$/i.exec(input);
if (args) {
var cmd = args[1];
var param = args[2];
var did = false;
if (cmd) {
if(cmd == "tablogger" && !param) {
dAmn_TabLogger.showLog();
}
switch (param) {
case 'on':
case 'start':
dAmn_TabLogger.startLog(true);
did = true;
break;
case 'off':
case 'stop':
dAmn_TabLogger.stopLog(true);
did = true;
break;
case 'clear':
case 'empty':
dAmn_TabLogger.clearLog();
break;
}
if (did) {
if (el.value) {
el.value = '';
el.focus();
};
};
};
};
};
if (!did) {
return this.onKey_loggerCommands(e, kc, force) ? true: false;
} else {
return false;
};
};
dAmnChatInput.prototype.onKey = dAmnChatInput_onKey;
dAmnChatInput.prototype.onKey_loggerCommands = dAmnChatInput_onKey_loggerCommands;
},
// bindTabs
// Arguments: none
// Returns: void
// Purpose: Binds message events.
bindTabs: function() {
dAmnChat_onData_alert = dAmnChat_onData;
dAmnChat_onData = function ( pkt ){
this.onData_alert(pkt);
if (pkt.param == this.ns) {
switch (pkt.cmd) {
case 'recv':
var recv = dAmn_ParsePacket(pkt.body);
var ns = pkt.param;
var isPchat = (ns[0] == "p");
var whiteListOn;
var isInWhiteList;
// Make sure the packet being parsed here is not just data retrieval
if(pkt.body.substring(0,3) == "msg" || pkt.body.substring(0,6) == "action") {
// The below line is taken from dAmn's own code to determine whether your username is in the message
// Added "i" argument for case-insensitive
if(-1 != recv.body.search(RegExp("([^A-Za-z]+|^)" + dAmn_Client_Username + "([^A-Za-z]+|$|s$|s[^A-Za-z]+)" , "i")) || isPchat){
if(localStorage.dAmn_TabLoggerStatus == "on" && !isPchat) {
var info = {};
info.time = dAmn_TabLogger.getTimestamp();
info.from = (typeof dAmnChats[ns].members.members[recv.args.from].name !== "undefined" ? dAmnChats[ns].members.members[recv.args.from].name : dAmn_Client_Username);
info.chat = ns.replace("chat:", "#");
// Need to parse thumbs, links, emotes, etc.
dAmnChanChat.prototype.FormatMsg(recv.body, function(t) {
info.message = t;
}.bind(this));
// Don't log if you tab yourself.
// Or if you have white list enabled and the user is not in it.
if(info.from !== dAmn_Client_Username) {
whiteListOn = dAmn_TabLoggerPreferences.whiteList;
isInWhiteList = $.inArray(info.from.toLowerCase(), localStorage.dAmn_TabLoggerWhiteList.split(',')) > -1;
if((whiteListOn && isInWhiteList) || !whiteListOn) {
dAmn_TabLogger.addLog(info);
}
}
}
// Don't make the noise if you tab yourself.
// Or if you have white list enabled and the user is not in it.
if(dAmn_TabLoggerPreferences.tabNoise && (recv.args.from !== dAmn_Client_Username)) {
whiteListOn = dAmn_TabLoggerPreferences.whiteList;
isInWhiteList = $.inArray(recv.args.from.toLowerCase(), localStorage.dAmn_TabLoggerWhiteList.split(',')) > 1;
if((whiteListOn && isInWhiteList) || !whiteListOn) {
dAmn_TabLogger.playSound();
}
}
// Switch the active chat tab to the source chat if preferred
if(dAmn_TabLoggerPreferences.autoSwitch && (recv.args.from !== dAmn_Client_Username) && !isPchat)
$('.tabbar').find('a:contains("' + ns.replace("chat:", "#") + '")').click();
}
}
}
}
};
dAmnChat.prototype.onData=dAmnChat_onData;
dAmnChat.prototype.onData_alert=dAmnChat_onData_alert;
},
// savePreferences
// Arguments: none
// Returns: void
// Purpose: Constructs an object based on the preferences modal and stores in localStorage
savePreferences: function() {
var savedPreferences = {
onAway: $('input.onAway').is(':checked'),
onBack: $('input.onBack').is(':checked'),
bindCommands: $('input.bindCommands').is(':checked'),
tabNoise: $('input.tabNoise').is(':checked'),
autoSwitch: $('input.autoSwitch').is(':checked'),
whiteList: $('input.whiteList').is(':checked')
};
localStorage.dAmn_TabLoggerPreferences = JSON.stringify(savedPreferences);
$('.preferenceMessage').html('<b>Saved</b>');
this.getPreferences();
if(dAmn_TabLoggerPreferences.whiteList) this.bindWhiteList();
},
// playSound
// Arguments: none
// Returns: void
// Purpose: Play the audio element
playSound: function() {
document.getElementById('dAmn_TabLoggerSound').play();
},
// getPreferences
// Arguments: none
// Returns: void
// Purpose: Load existing preferences for future use.
getPreferences: function() {
dAmn_TabLoggerPreferences = JSON.parse(localStorage.dAmn_TabLoggerPreferences);
},
// dependencies
// Purpose: House all the filepaths of this script's dependencies
dependencies: {
js: [
'//code.jquery.com/ui/1.11.4/jquery-ui.js',
],
css: [
'//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css',
'//code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css',
]
},
// includeDependencies
// Arguments: none
// Returns: void
// Purpose: Include all this script's dependencies
includeDependencies: function() {
var jsFiles = this.dependencies.js;
var cssFiles = this.dependencies.css;
$(cssFiles).each(function(i, ext) {
$('<link/>').attr('href', ext).appendTo('head');
});
$(jsFiles).each(function(i, ext) {
$('<script/>').attr('type', 'text/javascript').attr('src', ext).appendTo('body');
});
},
// bindWhiteList
// Arguments: none
// Returns: void
// Purpose: Bind event on the correct DOM elements for whitelist management
bindWhiteList: function() {
// Add event listener to username spans to control whitelist if enabled
$(document).click(function(event) {
if(dAmn_TabLoggerPreferences.whiteList && $(event.target).hasClass('username')) {
if(event.shiftKey && $(event.target).text() !== dAmn_Client_Username) {
event.preventDefault();
event.stopPropagation();
var message, response, recipient, isInWhiteList, whiteList;
whiteList = (localStorage.dAmn_TabLoggerWhiteList === "" ? [] : localStorage.dAmn_TabLoggerWhiteList.split(','));
recipient = $(event.target).text().toLowerCase();
isInWhiteList = $.inArray(recipient, whiteList) > -1;
message = "Would you like to " + (isInWhiteList ? "remove" : "add") + " " + recipient + " " + (isInWhiteList ? "from" : "to") + " your dAmn Tab Logger White List?";
response = confirm(message);
if(response) {
if(!isInWhiteList) {
whiteList.push(recipient);
} else {
whiteList.reverse();
whiteList.splice(recipient, 1);
}
dAmn_TabLogger.saveWhiteList(whiteList);
}
}
}
});
},
// saveWhiteList
// Arguments: Object whitelist
// Returns: void
// Purpose: Save the passed in object as the new white list
saveWhiteList: function(whitelist) {
localStorage.dAmn_TabLoggerWhiteList = whitelist.join(',');
this.notify("White List updated");
},
// init
// Arguments: none
// Returns: void
// Purpose: Does everything. :D
init: function() {
// Create our "database" to store the on/off bit.
localStorage.dAmn_TabLoggerStatus = "";
if(!localStorage.dAmn_TabLoggerPreferences) localStorage.dAmn_TabLoggerPreferences = JSON.stringify({onAway: false, onBack: false, bindCommands: false, tabNoise: false, autoSwitch: false, whiteList: false});
if(!localStorage.dAmn_TabLoggerWhiteList) localStorage.dAmn_TabLoggerWhiteList = "";
this.getPreferences();
// Bind commands
if(dAmn_TabLoggerPreferences.bindCommands)
this.bindCommands();
// Start listening for tabs
this.bindTabs();
// Include the script dependencies
this.includeDependencies();
// Initialize context menus
if(dAmn_TabLoggerPreferences.whiteList)
this.bindWhiteList();
// jQuery extension to re-center the modal
$.fn.center = function () {
$(this).css(dAmn_TabLogger.CSS.logModal);
return $(this).fadeIn();
};
// jQuery extension to tell if the modal header text is fully visible on the screen
$.fn.isFullyVisible = function() {
var off, et, el, eh, ew, wh, ww, wx, wy;
off = this.offset();
et = off.top;
el = off.left;
eh = this.height();
ew = this.width();
wh = window.innerHeight;
ww = window.innerWidth;
wx = window.pageXOffset;
wy = window.pageYOffset;
return (et >= wy && el >= wx && et + eh <= wh + wy && el + ew <= ww + wx);
};
// Create div element that will serve as the header of the modal.
// Append the header text and the X button to close the modal.
var modalTitle = $('<div/>')
.css('border-bottom','1px solid #000')
.css('background', 'linear-gradient(to bottom, #9eb1a3, #607465)')
.css('border-top-left-radius', '8px')
.css('border-top-right-radius', '8px')
.attr('id', 'dAmn_TabLoggerModalHeader')
.append($('<div class="modalHeader" style="display: inline-block; margin: 10px; font-size: 20px;">dAmn Tab Logger</div>'))
.append($('<span style="float: right; font-size: 25px; margin-right: 10px; cursor: pointer;" onclick="dAmn_TabLogger.hideLog()">×</span>'));
// Create div element to display when there are no logs stored in the modal.
var noLogs = $('<div/>')
.addClass('no-logs')
.html('<center>No logs!</center>')
.css('font-style', 'italic');
// Create the modal div.
// Append modalTitle and the div to house the actual log text.
// Append credit div to the bottom of the modal.
// Implement jQuery draggable. Only drag by the modal header, do not allow
// the modal to let the page scroll, and reposition the entire modal
// to the default position if any part of the modal header is off screen
// when the modal is dropped by the user.
var resultsModal = $('<div/>')
.attr('id', 'dAmn_TabLoggerModal')
.css(dAmn_TabLogger.CSS.logModal)
.append(modalTitle)
.append($('<div/>')
.attr('id', 'dAmn_TabLoggerLogs')
.css(dAmn_TabLogger.CSS.logContainer)
.append(noLogs))
.append($('<sub/>')
.attr('id', 'dAmn_TabLoggerInfo')
.attr('style', 'color: #98a39f !important; float: left;')
.html(dAmn_TabLogger.version + ' by <a href="http://miloticscale.deviantart.com">MiloticScale</a><span class="user-symbol senior"></span></a><br/>')
.after($('<div style="clear:both;display:none;"></div>')))
.appendTo($('body'))
.draggable({
scroll: false,
handle: '#dAmn_TabLoggerModalHeader',
stop: function() {
if(!$('#dAmn_TabLoggerModalHeader .modalHeader').isFullyVisible()) $(this).center();
}
});
// Create div element that will serve as a clear button. Add onclick event listener to call this.clearLog
var clearButton = $('<div/>')
.attr('id', 'dAmn_TabLoggerClear')
.css(dAmn_TabLogger.CSS.clearButton)
.html('clear')
.click(function() {
dAmn_TabLogger.clearLog();
})
.prependTo(resultsModal);
// Create a link element and attach an onclick event listerner to it that shows the modal.
// Ensure that all chat windows get the link via setInterval.
// Pseudo-detection of /setaway appended
var insertLink = setInterval(function() {
$('.damncrc-iconbar-ctrls').each(function(i, el) {
if($(el).find('.dAmn_TabLoggerLink').length < 1) {
if(localStorage.dAmn_TabLogger == "on") {
dAmn_TabLogger.stopLog(false);
dAmn_TabLogger.startLog(false);
}
var loggerLink = $('<a/>')
.addClass('dAmn_TabLoggerLink')
.css('cursor', 'pointer')
.html('Tab Log')
.click(function() {
dAmn_TabLogger.showLog();
})
.prependTo($(el))
.after(' <b>|</b> ');
// Monitor the ctrls span and start logging on pseudo-detection of /setaway
var awayTargets = document.querySelectorAll('.superdamn-awayspace');
var awayObserver = new MutationObserver(function(mutations) {
$(mutations).each(function(i, mutation) {
if(mutation.addedNodes.length > 0) {
if(dAmn_TabLoggerPreferences.onAway) dAmn_TabLogger.startLog(true);
} else {
if(dAmn_TabLoggerPreferences.onBack) dAmn_TabLogger.stopLog(true);
}
});
});
$(awayTargets).each(function(i, target) {
awayObserver.observe(target, {attributes: true, childList: true, characterData: true});
});
}
});
}, 1000);
// Create div element that will serve as the status icon in the modal.
// Give it some text based on our bit in storage.
// Attach onclick event listener to it which starts/stops logging
// depending on our bit in storage.
// Prepend this to the modal.
var statusIcon = $('<div/>')
.attr('id','dAmn_TabLoggerStatus')
.css(dAmn_TabLogger.CSS.status)
.css(localStorage.dAmn_TabLoggerStatus == "on" ? dAmn_TabLogger.CSS.onStatus : dAmn_TabLogger.CSS.offStatus)
.html(localStorage.dAmn_TabLoggerStatus == "on" ? "on" : "off")
.click(function() {
if(localStorage.dAmn_TabLoggerStatus == "on")
dAmn_TabLogger.stopLog(true);
else
dAmn_TabLogger.startLog(true);
})
.prependTo(resultsModal);
// Create div element that will serve as the preferences button in the modal.
var preferencesButton = $('<div/>')
.attr('id', 'dAmn_TabLoggerPreferencesButton')
.css(dAmn_TabLogger.CSS.preferencesButton)
.html('preferences')
.click(function() {
dAmn_TabLogger.showPreferences();
})
.prependTo(resultsModal);
// Create preferences modal
var preferencesModal = $('<div/>')
.attr('id', 'dAmn_TabLoggerPreferencesModal')
.css(dAmn_TabLogger.CSS.logModal)
.css(dAmn_TabLogger.CSS.preferencesModal)
.append(typeof MiddleMan !== "undefined" ? '<div class="preference"><input type="checkbox" class="onAway" /> Automatically start logging on /setaway</div><hr />' : '')
.append(typeof MiddleMan !== "undefined" ? '<div class="preference"><input type="checkbox" class="onBack" /> Automatically stop logging on /setback</div><hr />' : '')
.append('<div class="preference"><input type="checkbox" class="autoSwitch" /> Automatically switch to a chat I\'m tabbed in</div><hr />')
.append('<div class="preference"><input type="checkbox" class="bindCommands" /> Enable chat commands</div><hr />')
.append('<div class="preference"><input type="checkbox" class="whiteList" /> Enable white list</div><hr />')
.append('<div class="preference"><input type="checkbox" class="tabNoise" /> Play sound when I\'m tabbed <br/><sub>(Volume: Shift + ↑/↓)</sub></div><hr/>')
.append('<div style="float: left; border: 1px solid #000; border-radius: 5px; color: #fafffa; background: #00cc00; padding: 5px; cursor: pointer;" onclick="dAmn_TabLogger.savePreferences()">Save</div>')
.append('<div style="display: inline-block; margin-left: 10px; border: 1px solid #000; border-radius: 5px; color: #000; background: #fafffa; padding: 5px; cursor: pointer;" onclick="dAmn_TabLogger.hidePreferences(); $(\'.preferenceMessage\').html(\'\');">Close</div>')
.append('<div style="margin-left: 30px; display: inline-block" class="preferenceMessage"></div>')
.appendTo(resultsModal);
// Check the checkboxes based on current preferences
var set = ['onAway', 'onBack', 'bindCommands', 'tabNoise', 'autoSwitch', 'whiteList'];
$(set).each(function(i, s) {
$('input.' + s).prop('checked', dAmn_TabLoggerPreferences[s]);
});
// Create audio element to play when tabbed.
$('<audio/>')
.attr('id', 'dAmn_TabLoggerSound')
.attr('src', 'http://jonbraswell.com/scripts/tabbed.wav')
.attr('preload', 'auto')
.appendTo($('body'));
// Add event listener to the document to control the sound volume.
$(document).on('keyup', function(event) {
if(dAmn_TabLoggerPreferences.tabNoise) {
var sound = document.getElementById('dAmn_TabLoggerSound');
var shift = event.shiftKey;
var plus = (event.keyCode == '38');
var minus = (event.keyCode == '40');
if(shift && plus) {
if(sound.volume < 1) {
sound.volume += 0.1;
dAmn_TabLogger.notify("Notification sound volume increased");
sound.play();
} else {
dAmn_TabLogger.notify("Max notification sound volume reached");
}
}
if(shift && minus) {
if(sound.volume > 0.1) {
sound.volume -= 0.1;
dAmn_TabLogger.notify("Notification sound volume decreased");
sound.play();
} else {
dAmn_TabLogger.notify("Min notification sound volume reached");
}
}
}
});
}
};
DWait.ready(['jms/pages/chat07/chatpage.js', 'jms/pages/chat07/dAmn.js', 'jms/pages/chat07/dAmnChat.js'], function() {
// Initialize!
dAmn_TabLogger.init();
});
}).toString());
// Append our housing function to to the DOM as a child of the head element.
script.appendChild(document.createTextNode(helperScript));
document.getElementsByTagName('head')[0].appendChild(script);
// from electricnet's SuperdAmn.
function freeFunctionString(str){
return str.replace(/^\s*function\s*\(\)\s*\{/, "").replace(/\}\s*$/, "");
}