diff --git a/css/glowingbear.css b/css/glowingbear.css
index 46e1243..a6d10d8 100644
--- a/css/glowingbear.css
+++ b/css/glowingbear.css
@@ -84,6 +84,25 @@ input[type=text], input[type=password], #sendMessage {
margin-bottom: 5px !important;
}
+.btn-send-image {
+ position: relative;
+ overflow: hidden;
+ cursor: pointer;
+}
+
+.imgur-upload {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ cursor: inherit;
+ font-size: 1000px !important;
+ height: 300px;
+ margin: 0;
+ padding: 0;
+ opacity: 0;
+ filter: ~"alpha(opacity=0)";
+}
+
.input-group {
width: 100%;
}
@@ -157,6 +176,14 @@ input[type=text], input[type=password], #sendMessage {
padding-right: 6px;
}
+.upload-error {
+ width: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 4;
+}
+
#sidebar {
position: fixed;
width: 140px;
@@ -330,6 +357,25 @@ td.time {
padding-right: 100px;
}
+#inputform {
+ position: relative;
+}
+
+#imgur-upload-progress {
+ width: 100%;
+ height: auto;
+ position: absolute;
+ bottom: 100%;
+ left: 0;
+}
+
+ .imgur-progress-bar {
+ width: 0%;
+ height: 5px;
+ margin-top: 1px;
+ background: #428BCA;
+ }
+
/* fix for mobile firefox which ignores :hover */
.nav-pills > li > a:active, .nav-pills > li > a:active span {
text-decoration: none;
diff --git a/css/themes/dark.css b/css/themes/dark.css
index 9e196f7..f219459 100644
--- a/css/themes/dark.css
+++ b/css/themes/dark.css
@@ -72,12 +72,13 @@ input[type=text], input[type=password], #sendMessage, .badge {
box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.1), 0px 1px 7px 0px rgba(0, 0, 0, 0.8) inset;
}
-input[type=text], input[type=password], #sendMessage, .badge, .btn-send {
+input[type=text], input[type=password], #sendMessage, .badge, .btn-send, .btn-send-image {
color: #ccc;
background: none repeat scroll 0% 0% rgba(0, 0, 0, 0.3);
}
-.btn-send:hover, .btn-send:focus {
+.btn-send:hover, .btn-send:focus,
+.btn-send-image:hover, .btn-send-image:focus {
background-color: #555;
color: white;
}
@@ -271,7 +272,7 @@ input[type=text], input[type=password], #sendMessage, .badge, .btn-send {
.cob-chat {
}
.cob-chat_time {
- color: #999;
+ color: #999;
}
.cob-chat_time_delimiters {
}
diff --git a/css/themes/light.css b/css/themes/light.css
index b292136..6a5c109 100644
--- a/css/themes/light.css
+++ b/css/themes/light.css
@@ -22,7 +22,8 @@ html {
background-color: #222;
}
-.btn-send {
+.btn-send,
+.btn-send-image, {
background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.3);
color: #428BCA;
}
@@ -257,7 +258,7 @@ select.form-control, select option, input[type=text], input[type=password], #sen
.cob-chat {
}
.cob-chat_time {
- color: #999;
+ color: #999;
}
.cob-chat_time_delimiters {
}
diff --git a/directives/input.html b/directives/input.html
index 9b23817..38a76f7 100644
--- a/directives/input.html
+++ b/directives/input.html
@@ -1,9 +1,14 @@
-
diff --git a/index.html b/index.html
index fa71eb2..223280e 100644
--- a/index.html
+++ b/index.html
@@ -33,14 +33,20 @@
+
+
+
+
+
Upload error: Image upload failed.
+
@@ -257,7 +263,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
-
+
-
diff --git a/js/file-change.js b/js/file-change.js
new file mode 100644
index 0000000..1b22359
--- /dev/null
+++ b/js/file-change.js
@@ -0,0 +1,23 @@
+(function() {
+'use strict';
+
+var weechat = angular.module('weechat');
+
+weechat.directive('fileChange', ['$parse', function($parse) {
+
+ return {
+ restrict: 'A',
+ link: function ($scope, element, attrs) {
+ var attrHandler = $parse(attrs.fileChange);
+ var handler = function (e) {
+ $scope.$apply(function () {
+ attrHandler($scope, { $event: e, files: e.target.files });
+ });
+ };
+ element[0].addEventListener('change', handler, false);
+ }
+ };
+
+ }]);
+
+})();
diff --git a/js/imgur-drop-directive.js b/js/imgur-drop-directive.js
new file mode 100644
index 0000000..7e114d0
--- /dev/null
+++ b/js/imgur-drop-directive.js
@@ -0,0 +1,49 @@
+(function() {
+'use strict';
+
+var weechat = angular.module('weechat');
+
+weechat.directive('imgurDrop', ['connection','imgur','$rootScope', function(connection, imgur, $rootScope) {
+ return {
+ restrict: 'A',
+ link: function($scope, element, attr) {
+ var elem = element[0];
+ elem.ondragover = function () { this.classList.add('imgur-drop-hover'); return false; };
+ elem.ondragend = function () { this.classList.remove('imgur-drop-hover'); return false; };
+ elem.ondrop = function(e) {
+ // Remove hover class
+ this.classList.remove('imgur-drop-hover');
+
+ // Get files
+ var files = e.dataTransfer.files;
+
+ // Stop default behaviour
+ e.stopPropagation();
+ e.preventDefault();
+
+ // Send image url after upload
+ var sendImageUrl = function(imageUrl) {
+
+ // Send image
+ if(imageUrl !== undefined && imageUrl !== '') {
+ $rootScope.insertAtCaret(String(imageUrl));
+ }
+
+ };
+
+ // Check files
+ if(typeof files !== "undefined" && files.length > 0) {
+
+ // Loop through files
+ for (var i = 0; i < files.length; i++) {
+ // Upload to imgur
+ imgur.process(files[i], sendImageUrl);
+ }
+
+ }
+ };
+ }
+ };
+}]);
+
+})();
diff --git a/js/imgur.js b/js/imgur.js
new file mode 100644
index 0000000..a5a0fd0
--- /dev/null
+++ b/js/imgur.js
@@ -0,0 +1,128 @@
+(function() {
+'use strict';
+
+var weechat = angular.module('weechat');
+
+weechat.factory('imgur', ['$rootScope', function($rootScope) {
+
+ var process = function(image, callback) {
+
+ // Is it an image?
+ if (!image || !image.type.match(/image.*/)) return;
+
+ // New file reader
+ var reader = new FileReader();
+
+ // When image is read
+ reader.onload = function (event) {
+ var image = event.target.result.split(',')[1];
+ upload(image, callback);
+ };
+
+ // Read image as data url
+ reader.readAsDataURL(image);
+
+ };
+
+ // Upload image to imgur from base64
+ var upload = function( base64img, callback ) {
+ // Set client ID (Glowing Bear)
+ var clientId = "164efef8979cd4b";
+
+ // Progress bars container
+ var progressBars = document.getElementById("imgur-upload-progress"),
+ currentProgressBar = document.createElement("div");
+
+ // Set progress bar attributes
+ currentProgressBar.className='imgur-progress-bar';
+ currentProgressBar.style.width = '0';
+
+ // Append progress bar
+ progressBars.appendChild(currentProgressBar);
+
+ // Create new form data
+ var fd = new FormData();
+ fd.append("image", base64img); // Append the file
+ fd.append("type", "base64"); // Set image type to base64
+
+ // Create new XMLHttpRequest
+ var xhttp = new XMLHttpRequest();
+
+ // Post request to imgur api
+ xhttp.open("POST", "https://api.imgur.com/3/image", true);
+
+ // Set headers
+ xhttp.setRequestHeader("Authorization", "Client-ID " + clientId);
+ xhttp.setRequestHeader("Accept", "application/json");
+
+ // Handler for response
+ xhttp.onload = function() {
+
+ // Remove progress bar
+ currentProgressBar.parentNode.removeChild(currentProgressBar);
+
+ // Check state and response status
+ if(xhttp.status === 200) {
+
+ // Get response text
+ var response = JSON.parse(xhttp.responseText);
+
+ // Send link as message
+ if( response.data && response.data.link ) {
+
+ if (callback && typeof(callback) === "function") {
+ callback(response.data.link);
+ }
+
+ } else {
+ showErrorMsg();
+ }
+
+ } else {
+ showErrorMsg();
+ }
+
+ };
+
+ if( "upload" in xhttp ) {
+
+ // Set progress
+ xhttp.upload.onprogress = function (event) {
+
+ // Check if we can compute progress
+ if (event.lengthComputable) {
+ // Complete in percent
+ var complete = (event.loaded / event.total * 100 | 0);
+
+ // Set progress bar width
+ currentProgressBar.style.width = complete + '%';
+ }
+ };
+
+ }
+
+ // Send request with form data
+ xhttp.send(fd);
+
+ };
+
+ var showErrorMsg = function() {
+ // Show error msg
+ $rootScope.uploadError = true;
+ $rootScope.$apply();
+
+ // Hide after 5 seconds
+ setTimeout(function(){
+ // Hide error msg
+ $rootScope.uploadError = false;
+ $rootScope.$apply();
+ }, 5000);
+ };
+
+ return {
+ process: process
+ };
+
+}]);
+
+})();
diff --git a/js/inputbar.js b/js/inputbar.js
index e57144a..9d18506 100644
--- a/js/inputbar.js
+++ b/js/inputbar.js
@@ -14,11 +14,12 @@ weechat.directive('inputBar', function() {
command: '=command'
},
- controller: ['$rootScope', '$scope', '$element', '$log', 'connection', 'models', 'IrcUtils', 'settings', function($rootScope,
+ controller: ['$rootScope', '$scope', '$element', '$log', 'connection', 'imgur', '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
+ imgur,
models,
IrcUtils,
settings) {
@@ -69,6 +70,49 @@ weechat.directive('inputBar', function() {
}, 0);
};
+ $rootScope.insertAtCaret = function(toInsert) {
+ // caret position in the input bar
+ var inputNode = $scope.getInputNode(),
+ caretPos = inputNode.selectionStart;
+
+ var prefix = $scope.command.substring(0, caretPos),
+ suffix = $scope.command.substring(caretPos, $scope.command.length);
+ // Add spaces if missing
+ if (prefix.length > 0 && prefix[prefix.length - 1] !== ' ') {
+ prefix += ' ';
+ }
+ if (suffix.length > 0 && suffix[0] !== ' ') {
+ suffix = ' '.concat(suffix);
+ }
+ $scope.command = prefix + toInsert + suffix;
+
+ setTimeout(function() {
+ inputNode.focus();
+ var pos = $scope.command.length - suffix.length;
+ inputNode.setSelectionRange(pos, pos);
+ // force refresh?
+ $scope.$apply();
+ }, 0);
+ };
+
+ $scope.uploadImage = function($event, files) {
+ // Send image url after upload
+ var sendImageUrl = function(imageUrl) {
+ // Send image
+ if(imageUrl !== undefined && imageUrl !== '') {
+ $rootScope.insertAtCaret(String(imageUrl));
+ }
+ };
+
+ if(typeof files !== "undefined" && files.length > 0) {
+ // Loop through files
+ for (var i = 0; i < files.length; i++) {
+ // Process image
+ imgur.process(files[i], sendImageUrl);
+ }
+
+ }
+ };
// Send the message to the websocket
$scope.sendMessage = function() {