From 3d501c980f64986ffb53f73060b69c3eabd33737 Mon Sep 17 00:00:00 2001 From: zneix <44851575+zneix@users.noreply.github.com> Date: Sat, 5 Sep 2020 18:13:49 +0200 Subject: [PATCH] Made app.js proper Class, added support for non-absolute path Something that would solve relevant upstream issues/prs: seejohnrun/haste-server#53 seejohnrun/haste-server#140 --- static/application.js | 642 +++++++++++++++++++++--------------------- static/index.html | 15 +- 2 files changed, 329 insertions(+), 328 deletions(-) diff --git a/static/application.js b/static/application.js index 006a73b..57bb751 100644 --- a/static/application.js +++ b/static/application.js @@ -1,160 +1,332 @@ /* global $, hljs, window, document */ - ///// represents a single document - -let haste_document = function(){ - this.locked = false; -}; - -// Escapes HTML tag characters -haste_document.prototype.htmlEscape = function(s){ - return s - .replace(/&/g, '&') - .replace(/>/g, '>') - .replace(//g, '>') + .replace(/${msg}`); - $('#messages').prepend(msgBox); - setTimeout(function(){ - msgBox.slideUp('fast', function(){ $(this).remove(); }); - }, 3000); -}; - -// Show the light key -haste.prototype.lightKey = function(){ - this.configureKey(['new', 'save']); -}; - -// Show the full key -haste.prototype.fullKey = function(){ - this.configureKey(['new', 'duplicate', 'twitter', 'raw']); -}; - -// Set the key up for certain things to be enabled -haste.prototype.configureKey = enable => { - let $this; - $('#box2 .function').each(function(){ - $this = $(this); - for (const el of enable){ - if ($this.hasClass(el)){ - $this.addClass('enabled'); - return true; - } - } - $this.removeClass('enabled'); - }); -}; - -// Remove the current document (if there is one) -// and set up for a new one -haste.prototype.newDocument = function(hideHistory){ - this.$box.hide(); - this.doc = new haste_document(); - if (!hideHistory){ - window.history.pushState(null, this.appName, '/'); +class haste { + constructor(appName, options){ + this.appName = appName; + this.$textarea = $('textarea'); + this.$box = $('#box'); + this.$code = $('#box code'); + this.$linenos = $('#linenos'); + this.options = options; + this.configureShortcuts(); + this.configureButtons(); + // If twitter is disabled, hide the button + if (!options.twitter) $('#box2 .twitter').hide(); + this.baseUrl = options.baseUrl || '/'; } - this.setTitle(); - this.lightKey(); - this.$textarea.val('').show('fast', function(){ - this.focus(); - }); - this.removeLineNumbers(); -}; + // Set the page title - include the appName + setTitle(ext){ + document.title = `${this.appName}${ext ? ` - ${ext}` : ''}`; + } + // Show a message box + showMessage(msg, cls){ + let msgBox = $(`
  • ${msg}
  • `); + $('#messages').prepend(msgBox); + setTimeout(function (){ + msgBox.slideUp('fast', function (){ $(this).remove(); }); + }, 3000); + } + // Show the light key + lightKey(){ + this.configureKey(['new', 'save']); + } + // Show the full key + fullKey(){ + this.configureKey(['new', 'duplicate', 'twitter', 'raw']); + } + // Set the key up for certain things to be enabled + configureKey(enable){ + let $this; + $('#box2 .function').each(function (){ + $this = $(this); + for (const el of enable){ + if ($this.hasClass(el)){ + $this.addClass('enabled'); + return true; + } + } + $this.removeClass('enabled'); + }); + } + // Remove the current document (if there is one) + // and set up for a new one + newDocument(hideHistory){ + this.$box.hide(); + this.doc = new haste_document(this); + if (!hideHistory){ + window.history.pushState(null, this.appName, this.baseUrl); + } + this.setTitle(); + this.lightKey(); + this.$textarea.val('').show('fast', function (){ + this.focus(); + }); + this.removeLineNumbers(); + } + // Look up the extension preferred for a type + // If not found, return the type itself - which we'll place as the extension + lookupExtensionByType(type){ + for (let key in haste.extensionMap){ + if (haste.extensionMap[key] == type) + return key; + } + return type; + } + // Look up the type for a given extension + // If not found, return the extension - which we'll attempt to use as the type + lookupTypeByExtension(ext){ + return haste.extensionMap[ext] || ext; + } + // Add line numbers to the document + // For the specified number of lines + addLineNumbers(lineCount){ + let h = ''; + for (let i = 0; i < lineCount; i++){ + h += (i + 1).toString() + '
    '; + } + $('#linenos').html(h); + } + // Remove the line numbers + removeLineNumbers(){ + $('#linenos').html('>'); + } + // Load a document and show it + loadDocument(key){ + // Split the key up + let parts = key.split('.', 2); + // Ask for what we want + let _this = this; + _this.doc = new haste_document(this); + _this.doc.load(parts[0], function (ret){ + if (ret){ + _this.$code.html(ret.value); + _this.setTitle(ret.key); + _this.fullKey(); + _this.$textarea.val('').hide(); + _this.$box.show().focus(); + _this.addLineNumbers(ret.lineCount); + } + else { + _this.newDocument(); + } + }, this.lookupTypeByExtension(parts[1])); + } + // Duplicate the current document - only if locked + duplicateDocument(){ + if (this.doc.locked){ + let currentData = this.doc.data; + this.newDocument(); + this.$textarea.val(currentData); + } + } + // Lock the current document + lockDocument(){ + let _this = this; + this.doc.save(this.$textarea.val(), function (err, ret){ + if (err){ + _this.showMessage(err.message, 'error'); + } + else if (ret){ + _this.$code.html(ret.value); + _this.setTitle(ret.key); + let file = _this.baseUrl + ret.key; + if (ret.language){ + file += `.${_this.lookupExtensionByType(ret.language)}`; + } + window.history.pushState(null, `${_this.appName}-${ret.key}`, file); + _this.fullKey(); + _this.$textarea.val('').hide(); + _this.$box.show().focus(); + _this.addLineNumbers(ret.lineCount); + } + }); + } + configureButtons(){ + let _this = this; + this.buttons = [ + { + $where: $('#box2 .save'), + label: 'Save', + shortcutDescription: 'control + s', + shortcut: function (evt){ + return evt.ctrlKey && (evt.keyCode == 83); + }, + action: function (){ + if (_this.$textarea.val().replace(/^\s+|\s+$/g, '') != ''){ + _this.lockDocument(); + } + } + }, + { + $where: $('#box2 .new'), + label: 'New', + shortcut: function (evt){ + return evt.ctrlKey && evt.keyCode == 78; + }, + shortcutDescription: 'control + n', + action: function (){ + _this.newDocument(!_this.doc.key); + } + }, + { + $where: $('#box2 .duplicate'), + label: 'Duplicate & Edit', + shortcut: function (evt){ + return _this.doc.locked && evt.ctrlKey && evt.keyCode == 68; + }, + shortcutDescription: 'control + d', + action: function (){ + _this.duplicateDocument(); + } + }, + { + $where: $('#box2 .raw'), + label: 'Just Text', + shortcut: function (evt){ + return evt.ctrlKey && evt.shiftKey && evt.keyCode == 82; + }, + shortcutDescription: 'control + shift + r', + action: function (){ + window.location.href = `${_this.baseUrl}raw/${_this.doc.key}`; + } + }, + { + $where: $('#box2 .twitter'), + label: 'Twitter', + shortcut: function (evt){ + return _this.options.twitter && _this.doc.locked && evt.shiftKey && evt.ctrlKey && evt.keyCode == 84; + }, + shortcutDescription: 'control + shift + t', + action: function (){ + window.open(`https://twitter.com/share?url=${encodeURI(window.location.href)}`); + } + } + ]; + for (const button of this.buttons){ + this.configureButton(button); + } + } + configureButton(options){ + // Handle the click action + options.$where.click(function (evt){ + evt.preventDefault(); + if (!options.clickDisabled && $(this).hasClass('enabled')){ + options.action(); + } + }); + // Show the label + options.$where.mouseenter(function (){ + $('#box3 .label').text(options.label); + $('#box3 .shortcut').text(options.shortcutDescription || ''); + $('#box3').show(); + $(this).append($('#pointer').remove().show()); + }); + // Hide the label + options.$where.mouseleave(function (){ + $('#box3').hide(); + $('#pointer').hide(); + }); + } + // Configure keyboard shortcuts for the textarea + configureShortcuts(){ + let _this = this; + $(document.body).keydown(function (evt){ + for (const button of _this.buttons){ + if (button.shortcut && button.shortcut(evt)){ + evt.preventDefault(); + button.action(); + return; + } + } + }); + } +} // Map of common extensions // Note: this list does not need to include anything that IS its extension, @@ -170,191 +342,15 @@ haste.extensionMap = { swift: 'swift' }; -// Look up the extension preferred for a type -// If not found, return the type itself - which we'll place as the extension -haste.prototype.lookupExtensionByType = function(type){ - for (let key in haste.extensionMap){ - if (haste.extensionMap[key] == type) return key; - } - return type; -}; -// Look up the type for a given extension -// If not found, return the extension - which we'll attempt to use as the type -haste.prototype.lookupTypeByExtension = function(ext){ - return haste.extensionMap[ext] || ext; -}; -// Add line numbers to the document -// For the specified number of lines -haste.prototype.addLineNumbers = function(lineCount){ - let h = ''; - for (let i = 0; i < lineCount; i++){ - h += (i + 1).toString() + '
    '; - } - $('#linenos').html(h); -}; -// Remove the line numbers -haste.prototype.removeLineNumbers = function(){ - $('#linenos').html('>'); -}; -// Load a document and show it -haste.prototype.loadDocument = function(key){ - // Split the key up - let parts = key.split('.', 2); - // Ask for what we want - let _this = this; - _this.doc = new haste_document(); - _this.doc.load(parts[0], function(ret){ - if (ret){ - _this.$code.html(ret.value); - _this.setTitle(ret.key); - _this.fullKey(); - _this.$textarea.val('').hide(); - _this.$box.show().focus(); - _this.addLineNumbers(ret.lineCount); - } - else { - _this.newDocument(); - } - }, this.lookupTypeByExtension(parts[1])); -}; -// Duplicate the current document - only if locked -haste.prototype.duplicateDocument = function(){ - if (this.doc.locked){ - let currentData = this.doc.data; - this.newDocument(); - this.$textarea.val(currentData); - } -}; -// Lock the current document -haste.prototype.lockDocument = function(){ - let _this = this; - this.doc.save(this.$textarea.val(), function(err, ret){ - if (err){ - _this.showMessage(err.message, 'error'); - } - else if (ret){ - _this.$code.html(ret.value); - _this.setTitle(ret.key); - let file = `/${ret.key}`; - if (ret.language){ - file += `.${_this.lookupExtensionByType(ret.language)}`; - } - window.history.pushState(null, `${_this.appName}-${ret.key}`, file); - _this.fullKey(); - _this.$textarea.val('').hide(); - _this.$box.show().focus(); - _this.addLineNumbers(ret.lineCount); - } - }); -}; -haste.prototype.configureButtons = function(){ - let _this = this; - this.buttons = [ - { - $where: $('#box2 .save'), - label: 'Save', - shortcutDescription: 'control + s', - shortcut: function(evt){ - return evt.ctrlKey && (evt.keyCode == 83); - }, - action: function(){ - if (_this.$textarea.val().replace(/^\s+|\s+$/g, '') != ''){ - _this.lockDocument(); - } - } - }, - { - $where: $('#box2 .new'), - label: 'New', - shortcut: function(evt){ - return evt.ctrlKey && evt.keyCode == 78; - }, - shortcutDescription: 'control + n', - action: function(){ - _this.newDocument(!_this.doc.key); - } - }, - { - $where: $('#box2 .duplicate'), - label: 'Duplicate & Edit', - shortcut: function(evt){ - return _this.doc.locked && evt.ctrlKey && evt.keyCode == 68; - }, - shortcutDescription: 'control + d', - action: function(){ - _this.duplicateDocument(); - } - }, - { - $where: $('#box2 .raw'), - label: 'Just Text', - shortcut: function(evt){ - return evt.ctrlKey && evt.shiftKey && evt.keyCode == 82; - }, - shortcutDescription: 'control + shift + r', - action: function(){ - window.location.href = `/raw/${_this.doc.key}`; - } - }, - { - $where: $('#box2 .twitter'), - label: 'Twitter', - shortcut: function(evt){ - return _this.options.twitter && _this.doc.locked && evt.shiftKey && evt.ctrlKey && evt.keyCode == 84; - }, - shortcutDescription: 'control + shift + t', - action: function(){ - window.open(`https://twitter.com/share?url=${encodeURI(window.location.href)}`); - } - } - ]; - for (const button of this.buttons){ - this.configureButton(button); - } -}; -haste.prototype.configureButton = function(options){ - // Handle the click action - options.$where.click(function(evt){ - evt.preventDefault(); - if (!options.clickDisabled && $(this).hasClass('enabled')){ - options.action(); - } - }); - // Show the label - options.$where.mouseenter(function(){ - $('#box3 .label').text(options.label); - $('#box3 .shortcut').text(options.shortcutDescription || ''); - $('#box3').show(); - $(this).append($('#pointer').remove().show()); - }); - // Hide the label - options.$where.mouseleave(function(){ - $('#box3').hide(); - $('#pointer').hide(); - }); -}; -// Configure keyboard shortcuts for the textarea -haste.prototype.configureShortcuts = function(){ - let _this = this; - $(document.body).keydown(function(evt){ - for (const button of _this.buttons){ - if (button.shortcut && button.shortcut(evt)){ - evt.preventDefault(); - button.action(); - return; - } - } - }); -}; ///// Tab behavior in the textarea - 2 spaces per tab $(function(){ diff --git a/static/index.html b/static/index.html index ff41e78..11e230c 100644 --- a/static/index.html +++ b/static/index.html @@ -17,9 +17,9 @@ let app = null; // Handle pops let handlePop = function(evt){ - let path = evt.target.location.pathname; - if (path == '/'){ app.newDocument(true); } - else { app.loadDocument(path.substring(1, path.length)); } + let path = evt.target.location.href; + if (path == app.baseUrl) app.newDocument(true); + else app.loadDocument(path.split('/').slice(-1)[0]); }; // Set up the pop state to handle loads, skipping the first load // to make chrome behave like others: @@ -31,7 +31,12 @@ }, 1000); // Construct app and load initial path $(function(){ - app = new haste('hastebin', { twitter: true }); + let baseUrl = window.location.href.split('/'); + console.log(baseUrl); + baseUrl = baseUrl.slice(0, baseUrl.length - 1).join('/') + '/'; + console.log(baseUrl); + // baseUrl = 'https://plazatest.zneix.eu/haste/'; + app = new haste('hastebin', { twitter: true, baseUrl: baseUrl }); handlePop({ target: window }); }); @@ -44,7 +49,7 @@
    - +