diff --git a/index.html b/index.html index 8f6d9e5..1cd5e00 100644 --- a/index.html +++ b/index.html @@ -25,6 +25,7 @@ + @@ -38,7 +39,7 @@ - +

logo @@ -71,10 +72,10 @@
- +
- +
@@ -86,19 +87,19 @@
-
+
@@ -122,7 +123,7 @@
To start using glowing bear, please enable the relay plugin in your WeeChat client:
 /set relay.network.password yourpassword
-/relay add weechat {{ port || 9001 }}
+/relay add weechat {{ settings.port || 9001 }}
 
WeeChat version 0.4.2 or higher is required.
The communication goes directly between your browser and your WeeChat relay in plain text. Check the instructions below for help on setting up encrypted communication. @@ -157,18 +158,18 @@

If you check the encryption box, the communication between browser and WeeChat will be encrypted with TLS.

-

Note: If you are using a self-signed certificate, you have to visit https://{{ host || 'weechathost' }}:{{ port || 'relayport' }}/ in your browser first to add a security exception. You can close that tab once you confirmed the certificate, no content will appear. The necessity of this process is a bug in Firefox and other browsers.

+

Note: If you are using a self-signed certificate, you have to visit https://{{ settings.host || 'weechathost' }}:{{ settings.port || 'relayport' }}/ in your browser first to add a security exception. You can close that tab once you confirmed the certificate, no content will appear. The necessity of this process is a bug in Firefox and other browsers.

Setup: If you want to use an encrypted session you first have to set up the relay to use TLS. You basically have two options: a self-signed certificate is easier to set up, but requires manual security exceptions. Using a certificate that is trusted by your browser requires more setup, but offers greater convenience later on and does not require security exceptions. You can find a guide to set up WeeChat with a free trusted certificate from StartSSL here. Should you wish to use a self-signed certificate instead, execute the following commands in a shell on the same host and as the user running WeeChat:

 $ mkdir -p ~/.weechat/ssl
 $ cd ~/.weechat/ssl
-$ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out relay.pem -subj "/CN={{host || 'your weechat host'}}/"
+$ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out relay.pem -subj "/CN={{settings.host || 'your weechat host'}}/"
 
-

If WeeChat is already running, you can reload the certificate and private key and set up an encrypted relay on port {{ port || 9001 }} with these WeeChat commands:

+

If WeeChat is already running, you can reload the certificate and private key and set up an encrypted relay on port {{ settings.port || 9001 }} with these WeeChat commands:

 /set relay.network.password yourpassword
 /relay sslcertkey
-/relay add ssl.weechat {{ port || 9001 }}
+/relay add ssl.weechat {{ settings.port || 9001 }}
 
@@ -213,7 +214,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
- brand + brand
@@ -255,7 +256,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
- +
@@ -306,12 +307,12 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
- +
- +
@@ -321,7 +322,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
- +
@@ -331,7 +332,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
@@ -341,17 +342,17 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
-
    +
    • @@ -363,7 +364,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
      @@ -373,7 +374,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
      @@ -383,7 +384,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
      @@ -393,7 +394,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
      @@ -403,7 +404,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
      @@ -413,7 +414,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
      @@ -423,7 +424,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
      diff --git a/js/glowingbear.js b/js/glowingbear.js index 1e7fc3a..ae4a92a 100644 --- a/js/glowingbear.js +++ b/js/glowingbear.js @@ -12,10 +12,12 @@ weechat.config(['$compileProvider', function ($compileProvider) { } }]); -weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', '$log', 'models', 'connection', 'notifications', 'utils', function ($rootScope, $scope, $store, $timeout, $log, models, connection, notifications, utils) { +weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', '$log', 'models', 'connection', 'notifications', 'utils', 'settings', + function ($rootScope, $scope, $store, $timeout, $log, models, connection, notifications, utils, settings) { $scope.command = ''; $scope.themes = ['dark', 'light']; + $scope.settings = settings; // From: http://stackoverflow.com/a/18539624 by StackOverflow user "plantian" $rootScope.countWatchers = function () { @@ -193,7 +195,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', // we will send a /buffer bufferName command every time // the user switches a buffer. This will ensure that notifications // are cleared in the buffer the user switches to - if ($scope.hotlistsync && ab.fullName) { + if (settings.hotlistsync && ab.fullName) { connection.sendCoreCommand('/buffer ' + ab.fullName); } @@ -215,7 +217,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', $rootScope.$on('notificationChanged', function() { notifications.updateTitle(); - if ($scope.useFavico && $rootScope.favico) { + if (settings.useFavico && $rootScope.favico) { notifications.updateFavico(); } }); @@ -246,72 +248,31 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', $rootScope.iterCandidate = null; - $store.bind($scope, "host", "localhost"); - $store.bind($scope, "port", "9001"); - $store.bind($scope, "proto", "weechat"); - $store.bind($scope, "ssl", (window.location.protocol === "https:")); - $store.bind($scope, "savepassword", false); - if ($scope.savepassword) { - $store.bind($scope, "password", ""); + if (settings.savepassword) { + $scope.$watch('password', function() { + settings.password = $scope.password; + }); + settings.addCallback('password', function(password) { + $scope.password = password; + }); + $scope.password = settings.password; + } else { + settings.password = ''; } - $store.bind($scope, "autoconnect", false); - - // If we are on mobile change some defaults - // We use 968 px as the cutoff, which should match the value in glowingbear.css - var nonicklist = false; - var noembed = false; - var showtimestamp = true; $rootScope.wasMobileUi = false; - if (utils.isMobileUi()) { - nonicklist = true; - noembed = true; $rootScope.wasMobileUi = true; } - - // Save setting for displaying only buffers with unread messages - $store.bind($scope, "onlyUnread", false); - - // Save setting for syncing hotlist - $store.bind($scope, "hotlistsync", true); - // Save setting for displaying nicklist - $store.bind($scope, "nonicklist", nonicklist); - // Save setting for displaying embeds - $store.bind($scope, "noembed", noembed); - // Save setting for channel ordering - $store.bind($scope, "orderbyserver", true); - // Save setting for updating favicon - $store.bind($scope, "useFavico", true); - // Save setting for showtimestamp - $store.bind($scope, "showtimestamp", showtimestamp); - // Save setting for showing seconds on timestamps - $store.bind($scope, "showtimestampSeconds", false); - // Save setting for playing sound on notification - $store.bind($scope, "soundnotification", false); - // Save setting for font family - $store.bind($scope, "fontfamily"); - // Save setting for theme - $store.bind($scope, "theme", 'dark'); - // Save setting for font size - $store.bind($scope, "fontsize", "14px"); - // Save setting for readline keybindings - $store.bind($scope, "readlineBindings", false); - // Save settings for non-native Emoji support - $store.bind($scope, "enableJSEmoji", false); - - if (!$scope.fontfamily) { + if (!settings.fontfamily) { if (utils.isMobileUi()) { - $scope.fontfamily = 'sans-serif'; + settings.fontfamily = 'sans-serif'; } else { - $scope.fontfamily = "Inconsolata, Consolas, Monaco, Ubuntu Mono, monospace"; + settings.fontfamily = "Inconsolata, Consolas, Monaco, Ubuntu Mono, monospace"; } } - // Save setting for displaying embeds in rootScope so it can be used from service - $rootScope.auto_display_embedded_content = $scope.noembed === false; - $scope.isSidebarVisible = function() { return document.getElementById('content').getAttribute('sidebar-state') === 'visible'; }; @@ -333,9 +294,8 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', document.getElementById('content').setAttribute('sidebar-state', 'hidden'); } }; - // This also fires on page load - $scope.$watch('autoconnect', function() { - if ($scope.autoconnect && !$rootScope.connected && !$rootScope.sslError && !$rootScope.securityError && !$rootScope.errorMessage) { + settings.addCallback('autoconnect', function(autoconnect) { + if (autoconnect && !$rootScope.connected && !$rootScope.sslError && !$rootScope.securityError && !$rootScope.errorMessage) { $scope.connect(); } }); @@ -354,35 +314,31 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', // Open and close panels while on mobile devices through swiping $scope.openNick = function() { if (utils.isMobileUi()) { - if ($scope.nonicklist) { - $scope.nonicklist = false; + if (settings.nonicklist) { + settings.nonicklist = false; } } }; $scope.closeNick = function() { if (utils.isMobileUi()) { - if (!$scope.nonicklist) { - $scope.nonicklist = true; + if (!settings.nonicklist) { + settings.nonicklist = true; } } }; - // Watch model and update show setting when it changes - $scope.$watch('noembed', function() { - $rootScope.auto_display_embedded_content = $scope.noembed === false; - }); // Watch model and update channel sorting when it changes - $scope.$watch('orderbyserver', function() { - $rootScope.predicate = $scope.orderbyserver ? 'serverSortKey' : 'number'; + settings.addCallback('orderbyserver', function(orderbyserver) { + $rootScope.predicate = orderbyserver ? 'serverSortKey' : 'number'; }); - $scope.$watch('useFavico', function() { + settings.addCallback('useFavico', function(useFavico) { // this check is necessary as this is called on page load, too if (!$rootScope.connected) { return; } - if ($scope.useFavico) { + if (useFavico) { notifications.updateFavico(); } else { $rootScope.favico.reset(); @@ -390,17 +346,12 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', }); // Update font family when changed - $scope.$watch('fontfamily', function() { - utils.changeClassStyle('favorite-font', 'fontFamily', $scope.fontfamily); + settings.addCallback('fontfamily', function(fontfamily) { + utils.changeClassStyle('favorite-font', 'fontFamily', fontfamily); }); // Update font size when changed - $scope.$watch('fontsize', function() { - utils.changeClassStyle('favorite-font', 'fontSize', $scope.fontsize); - }); - // Crude scoping hack. The keypress listener does not live in the same scope as - // the checkbox, so we need to transfer this between scopes here. - $scope.$watch('readlineBindings', function() { - $rootScope.readlineBindings = $scope.readlineBindings; + settings.addCallback('fontsize', function(fontsize) { + utils.changeClassStyle('favorite-font', 'fontSize', fontsize); }); $scope.setActiveBuffer = function(bufferId, key) { @@ -526,7 +477,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', $rootScope.errorMessage = false; $rootScope.bufferBottom = true; $scope.connectbutton = 'Connecting ...'; - connection.connect($scope.host, $scope.port, $scope.password, $scope.ssl); + connection.connect(settings.host, settings.port, $scope.password, settings.ssl); }; $scope.disconnect = function() { $scope.connectbutton = 'Connect'; @@ -594,7 +545,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', if ($scope.search && $scope.search !== "") { return true; } - if ($scope.onlyUnread) { + if (settings.onlyUnread) { // Always show current buffer in list if (models.getActiveBuffer() === buffer) { return true; @@ -609,7 +560,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', }; // Watch model and update show setting when it changes - $scope.$watch('nonicklist', function() { + settings.addCallback('nonicklist', function() { $scope.showNicklist = $scope.updateShowNicklist(); // restore bottom view if ($rootScope.connected && $rootScope.bufferBottom) { @@ -628,7 +579,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', return false; } // Check if option no nicklist is set - if ($scope.nonicklist) { + if (settings.nonicklist) { return false; } // Check if nicklist is empty @@ -662,7 +613,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout', }; // Helper function since the keypress handler is in a different scope $rootScope.toggleNicklist = function() { - $scope.nonicklist = !$scope.nonicklist; + settings.nonicklist = !settings.nonicklist; }; diff --git a/js/inputbar.js b/js/inputbar.js index e65a327..ab4394a 100644 --- a/js/inputbar.js +++ b/js/inputbar.js @@ -14,13 +14,14 @@ weechat.directive('inputBar', function() { command: '=command' }, - controller: ['$rootScope', '$scope', '$element', '$log', 'connection', 'models', 'IrcUtils', function($rootScope, + controller: ['$rootScope', '$scope', '$element', '$log', 'connection', 'models', 'IrcUtils', 'settings', function($rootScope, $scope, $element, //XXX do we need this? don't seem to be using it $log, connection, //XXX we should eliminate this dependency and use signals instead models, - IrcUtils) { + IrcUtils, + settings) { /* * Returns the input element @@ -340,7 +341,7 @@ weechat.directive('inputBar', function() { } // Some readline keybindings - if ($rootScope.readlineBindings && $event.ctrlKey && !$event.altKey && !$event.shiftKey && document.activeElement === inputNode) { + if (settings.readlineBindings && $event.ctrlKey && !$event.altKey && !$event.shiftKey && document.activeElement === inputNode) { // get current caret position caretPos = inputNode.selectionStart; // Ctrl-a diff --git a/js/localstorage.js b/js/localstorage.js index 4f2a9da..0c1218e 100644 --- a/js/localstorage.js +++ b/js/localstorage.js @@ -81,6 +81,16 @@ ls.factory("$store", ["$parse", function($parse){ storage.removeItem(key); return true; }, + /** + * Enumerate all keys + */ + enumerateKeys: function() { + var keys = []; + for (var i = 0, len = storage.length; i < len; ++i) { + keys.push(storage.key(i)); + } + return keys; + }, /** * Bind - lets you directly bind a localStorage value to a $scope variable * @param $scope - the current scope you want the variable available in diff --git a/js/notifications.js b/js/notifications.js index 00cfb32..739a651 100644 --- a/js/notifications.js +++ b/js/notifications.js @@ -1,9 +1,8 @@ var weechat = angular.module('weechat'); -weechat.factory('notifications', ['$rootScope', '$log', 'models', function($rootScope, $log, models) { - var notifications = []; - +weechat.factory('notifications', ['$rootScope', '$log', 'models', 'settings', function($rootScope, $log, models, settings) { // Ask for permission to display desktop notifications + var notifications = []; var requestNotificationPermission = function() { // Firefox if (window.Notification) { @@ -135,7 +134,7 @@ weechat.factory('notifications', ['$rootScope', '$log', 'models', function($root delete notifications[this.id]; }; - if ($rootScope.soundnotification) { + if (settings.soundnotification) { // TODO fill in a sound file var audioFile = "assets/audio/sonar"; var soundHTML = ''; @@ -153,10 +152,10 @@ weechat.factory('notifications', ['$rootScope', '$log', 'models', function($root }; return { - requestNotificationPermission: requestNotificationPermission, - updateTitle: updateTitle, - updateFavico: updateFavico, - createHighlight: createHighlight, + requestNotificationPermission: requestNotificationPermission, + updateTitle: updateTitle, + updateFavico: updateFavico, + createHighlight: createHighlight, cancelAll: cancelAll, }; }]); diff --git a/js/plugin-directive.js b/js/plugin-directive.js index f61cba4..94d19f5 100644 --- a/js/plugin-directive.js +++ b/js/plugin-directive.js @@ -3,7 +3,7 @@ var weechat = angular.module('weechat'); -weechat.directive('plugin', ['$rootScope', function($rootScope) { +weechat.directive('plugin', ['$rootScope', 'settings', function($rootScope, settings) { /* * Plugin directive * Shows additional plugin content @@ -20,7 +20,7 @@ weechat.directive('plugin', ['$rootScope', function($rootScope) { $scope.displayedContent = ""; // Auto-display embedded content only if it isn't NSFW - $scope.plugin.visible = $rootScope.auto_display_embedded_content && !$scope.plugin.nsfw; + $scope.plugin.visible = !settings.noembed && !$scope.plugin.nsfw; // user-accessible hash key that is a valid CSS class name $scope.plugin.className = "embed_" + $scope.plugin.$$hashKey.replace(':','_'); diff --git a/js/settings.js b/js/settings.js new file mode 100644 index 0000000..3da50d3 --- /dev/null +++ b/js/settings.js @@ -0,0 +1,59 @@ +(function() { +'use strict'; + +var weechat = angular.module('weechat'); + +weechat.factory('settings', ['$store', '$rootScope', function($store, $rootScope) { + var that = this; + this.callbacks = {}; + + // Define a property for a setting, retrieving it on read + // and writing it to localStorage on write + var defineProperty = function(key) { + Object.defineProperty(that, key, { + enumerable: true, + key: key, + get: function() { + return $store.get(key); + }, + set: function(newVal) { + $store.set(key, newVal); + // Call any callbacks + var callbacks = that.callbacks[key]; + for (var i = 0; callbacks !== undefined && i < callbacks.length; i++) { + callbacks[i](newVal); + } + // Update the page (might be needed) + setTimeout(function() { + $rootScope.$apply(); + }, 0); + } + }); + }; + + // Define properties for all settings + var keys = $store.enumerateKeys(); + for (var keyIdx in keys) { + var key = keys[keyIdx]; + defineProperty(key); + } + + // Add a callback to be called whenever the value is changed + // It's like a free $watch and used to be called the observer + // pattern, but I guess that's too old-school for JS kids :> + this.addCallback = function(key, callback, callNow) { + if (this.callbacks[key] === undefined) { + this.callbacks[key] = [callback]; + } else { + this.callbacks[key].push(callback); + } + // call now to emulate $watch behaviour + setTimeout(function() { + callback($store.get(key)); + }, 0); + }; + + return this; +}]); + +})();