-
Notifications
You must be signed in to change notification settings - Fork 20
Refactored Javascript in a more modern and modular way #865
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
smallsaucepan
wants to merge
7
commits into
MLTSHP:master
Choose a base branch
from
smallsaucepan:modern-js
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
4ec6468
Low hanging fruit tidy up. Define a few implicitly defined variables.…
smallsaucepan 7732108
Pulled several jquery prototype extension "classes" out into seperate…
smallsaucepan 0e11ca6
Pulled several IIFE and struct type structures out as well.
smallsaucepan 22de7df
Hook modules back into main.js. Most existing functionality should wo…
smallsaucepan 91a78fe
Removed IIFE wrapper, now redundant given we're including the JS as a…
smallsaucepan e7daabd
Converted any jQuery extended objects into plain JS modules. Dependin…
smallsaucepan 5c5402a
General conversion to more modern JS e.g. var -> let.+ const, templat…
smallsaucepan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| /** | ||
| * Functionality for "Invite A New Member" form shown in the sidebar of a shake | ||
| * the current user is an editor of. Lets the user type in a few characters, see | ||
| * an autocompleted list of matching usernames to pick from, and finally sends | ||
| * an invitation via the backend. | ||
| */ | ||
|
|
||
| // Invite Member widget for the Shake administrator. | ||
| const $mainModule = $("#shake-invite-member"); | ||
| const $inputField = $mainModule.find(".input-text"); | ||
| const $inviteButton = $mainModule.find(".invite-button"); | ||
| const $shakeResults = $mainModule.find(".shake-results"); | ||
| const $form = $mainModule.find("form"); | ||
| const $title = $mainModule.find("h3"); | ||
| let searchResults = []; | ||
| let lastSearch = ""; | ||
|
|
||
| const InviteMember = { | ||
| attachEvents: function () { | ||
| $inputField.keyup((ev) => this.searchNames(ev)); | ||
| $form.submit((ev) => this.submitForm()); | ||
| $shakeResults.click((ev) => this.selectUser($(ev.target).text())); | ||
| $inviteButton.click(() => { | ||
| this.sendInvite(); | ||
| return false; | ||
| }); | ||
| }, | ||
|
|
||
| searchNames: async function () { | ||
| if ($inputField.val() == "") { | ||
| this.clearResults(); | ||
| this.clearInput(); | ||
| return false; | ||
| } | ||
|
|
||
| // don't search again if field hasn't changed. | ||
| if ($inputField.val() == lastSearch) { | ||
| return false; | ||
| } | ||
| lastSearch = $inputField.val(); | ||
|
|
||
| const data = $form.serialize(); | ||
| const resp = await fetch("/account/quick_name_search", { | ||
| method: "POST", | ||
| body: new URLSearchParams(data), | ||
| }); | ||
| const json = await resp.json(); | ||
|
|
||
| if ("users" in json) { | ||
| this.updateResults(json["users"]); | ||
| } | ||
| }, | ||
|
|
||
| updateResults: function (users) { | ||
| searchResults = users; | ||
| if (searchResults.length == 0) { | ||
| this.clearResults(); | ||
| } else { | ||
| this.renderResults(); | ||
| } | ||
| }, | ||
|
|
||
| renderResults: function () { | ||
| $shakeResults.html("").show(); | ||
| for (let i = 0; i < searchResults.length; i++) { | ||
| $shakeResults.append( | ||
| `<li> | ||
| <img src="${searchResults[i].profile_image_url}" | ||
| width="24" height="24"> | ||
| <span>${searchResults[i].name}</span> | ||
| </li>`, | ||
| ); | ||
| } | ||
| }, | ||
|
|
||
| selectUser: function (userName) { | ||
| this.clearResults(); | ||
| $inputField.val(userName); | ||
| $inviteButton.removeAttr("disabled"); | ||
| }, | ||
|
|
||
| submitForm: function (ev) { | ||
| if ( | ||
| searchResults.length == 1 && | ||
| searchResults[0].name == $inputField.val() | ||
| ) { | ||
| this.selectUser(searchResults[0].name); | ||
| this.sendInvite(); | ||
| this.clearResults(); | ||
| } | ||
| return false; | ||
| }, | ||
|
|
||
| clearResults: function () { | ||
| lastSearch = ""; | ||
| $shakeResults.hide().html(""); | ||
| }, | ||
|
|
||
| clearInput: function () { | ||
| $inputField.val(""); | ||
| $inviteButton.attr("disabled", "disabled"); | ||
| }, | ||
|
|
||
| sendInvite: async function () { | ||
| if ($inviteButton.disabled) { | ||
| return false; | ||
| } else { | ||
| const url = $form.attr("action"); | ||
| const data = $form.serialize(); | ||
|
|
||
| await fetch(url, { | ||
| method: "POST", | ||
| body: new URLSearchParams(data), | ||
| }); | ||
|
|
||
| this.dataSent(); | ||
| return false; | ||
| } | ||
| }, | ||
|
|
||
| dataSent: function () { | ||
| $title.html("Your invitation has been sent"); | ||
| this.clearInput(); | ||
| this.clearResults(); | ||
| }, | ||
| }; | ||
|
|
||
| export { InviteMember }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| import { applyHoverForVideo } from "./common.js"; | ||
|
|
||
| /** | ||
| * Functionality associated with NSFW covers. Called on to attach event | ||
| * handlers to any posts that the server has generated a NSFW cover for. | ||
| */ | ||
|
|
||
| const NSFWCover = { | ||
| attachEvents($root) { | ||
| // Per invocation functions that will close over the context dependent | ||
| // variables defined above. | ||
| function clickShowImage(ev) { | ||
| var location = document.location, | ||
| basePath = location.protocol + "//" + location.host, | ||
| filePath = $(ev.target).attr("href"); | ||
| // Going to leave this as a jquery get rather than migrate to fetch | ||
| // right away. The two implementations behave differently and only | ||
| // the existing method seems to work with /services/oembed | ||
| $.get( | ||
| basePath + | ||
| "/services/oembed?include_embed=1&url=" + | ||
| escape(basePath + filePath), | ||
| (resp) => loadImage(resp), | ||
| "json", | ||
| ); | ||
| return false; | ||
| } | ||
|
|
||
| function loadImage(response) { | ||
| var parent = $root.parent(), | ||
| parentHeight = parent.height(); | ||
|
|
||
| if (response["type"] === "photo") { | ||
| parent | ||
| .css("min-height", parentHeight + "px") | ||
| .html( | ||
| '<img class="unsized" src="' + response["url"] + '">', | ||
| ); | ||
| } else if (response["embed_html"]) { | ||
| parent | ||
| .css("min-height", parentHeight + "px") | ||
| .html( | ||
| '<div class="data-wrapper">' + | ||
| response["embed_html"] + | ||
| "</div>", | ||
| ); | ||
| } else if (response["type"] === "video") { | ||
| var content = parent | ||
| .css("min-height", parentHeight + "px") | ||
| .html( | ||
| response["html"].replace( | ||
| /<source /g, | ||
| '<source onerror="fallbackImage(this)" ', | ||
| ), | ||
| ); | ||
| applyHoverForVideo(content.find("video.autoplay")); | ||
| } | ||
| } | ||
|
|
||
| // Attach any event handlers. | ||
| $root.delegate("a", "click", (ev) => clickShowImage(ev)); | ||
| }, | ||
| }; | ||
|
|
||
| export { NSFWCover }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| /** | ||
| * Functionality associated with the new post panel that pops up on any page | ||
| * allowing the user to post a new image or video to one of their shakes. | ||
| * | ||
| * Takes care of adding event listeners to the new post button, as well as to | ||
| * the shake dropdowns on both the image and video sides of the dialog. The new | ||
| * post dropdown slides in from the top of the screen. | ||
| */ | ||
| let $newPostPanel; | ||
| let $newPostPanelInner; | ||
| let $newPostButton; | ||
| let $saveVideoForm; | ||
| let $saveVideoFormButton; | ||
| let $postVideoForm; | ||
| let $postVideoFormButton; | ||
| let $uploadImageInput; | ||
| let $linkToVideo; | ||
| let $videoShakeId; | ||
| let $shakeSelector; | ||
|
|
||
| function removeEvents() { | ||
| $saveVideoFormButton.unbind(); | ||
| $postVideoFormButton.unbind(); | ||
| $shakeSelector.unbind(); | ||
| $linkToVideo.unbind(); | ||
| } | ||
|
|
||
| function initDom() { | ||
| $newPostPanel = $("#new-post-panel"); | ||
| $newPostPanelInner = $("#new-post-panel .new-post-panel--inner"); | ||
| $newPostButton = $("#new-post-button"); | ||
| // upload image | ||
| $uploadImageInput = $("#upload-image-input"); | ||
| // link to video | ||
| $linkToVideo = $("#link-to-video"); | ||
| $videoShakeId = $("#video-shake-id"); | ||
| // video preview screen | ||
| $saveVideoForm = $("#new-post-panel .save-video-form"); | ||
| $saveVideoFormButton = $("#new-post-panel .save-video-form .btn"); | ||
| $postVideoForm = $("#new-post-panel .post-video-form"); | ||
| $postVideoFormButton = $("#new-post-panel .post-video-form .btn"); | ||
| // shake selector | ||
| $shakeSelector = $(".shake-selector"); | ||
| } | ||
|
|
||
| function initEvents() { | ||
| // The events that are inside the panel that we want to initialize | ||
| // when the panel loads. These are the events that are subject | ||
| // to change depending on content that is loaded. | ||
|
|
||
| // Video upload step 1. | ||
| // Called when user clicks "video" link and takes them to a new form where | ||
| // they can enter the video url. | ||
| $linkToVideo.click(function () { | ||
| NewPostPanel.loadPostVideo(); | ||
| return false; | ||
| }); | ||
|
|
||
| // Video upload step 2. | ||
| // Called when the user clicks "Go get it!" button which takes the user to a | ||
| // new form containing a preview of the video. | ||
| $saveVideoFormButton.click(function (e) { | ||
| NewPostPanel.submitSaveVideo(); | ||
| return false; | ||
| }); | ||
|
|
||
| // Video upload step 3. | ||
| // Called when the user clicks "Yes! Post it please!" which uploads the | ||
| // video via submitPostVideo(). | ||
| $postVideoFormButton.click(function (e) { | ||
| NewPostPanel.submitPostVideo(); | ||
| return false; | ||
| }); | ||
|
|
||
| // Uploads the image file upon selection by the file upload dialog. | ||
| $uploadImageInput.change(function () { | ||
| $(this).closest("form").submit(); | ||
| }); | ||
|
|
||
| $shakeSelector.click(NewPostPanel.toggleShakeSelector); | ||
| $shakeSelector.find("ul a").click(NewPostPanel.chooseShake); | ||
| } | ||
|
|
||
| const NewPostPanel = { | ||
| attachEvents: function () { | ||
| initDom(); | ||
|
|
||
| $newPostButton.click(function () { | ||
| NewPostPanel.loadNewPost(); | ||
| return false; | ||
| }); | ||
|
|
||
| // We don't want click event on panel to bubble up to body | ||
| // since a click to body closes the panel. | ||
| $newPostPanel.click(function (ev) { | ||
| ev.stopPropagation(); | ||
| }); | ||
| }, | ||
|
|
||
| toggleShakeSelector: function (ev) { | ||
| $(this).toggleClass("is-active").find("ul").toggle(); | ||
| ev.stopPropagation(); | ||
| ev.preventDefault(); | ||
| }, | ||
|
|
||
| // Sets the text of the shake to the chosen one and | ||
| // sets a hidden input field with the proper shake id. | ||
| chooseShake: function () { | ||
| const $shakeSelector = $(this).parents(".shake-selector"); | ||
| const $selectedShake = $shakeSelector.find(".green"); | ||
| const $selectedShakeInput = $shakeSelector.find("input"); | ||
| const name = $(this).html(); | ||
| const id = $(this) | ||
| .attr("id") | ||
| .replace(/[^0-9]+/, ""); | ||
| $selectedShake.html(name); | ||
| $selectedShakeInput.val(id); | ||
| }, | ||
|
|
||
| // Renders step 1 of image / video upload process - shake choice and file | ||
| // type. | ||
| loadNewPost: async function () { | ||
| var url = "/tools/new-post"; | ||
| const resp = await fetch(url); | ||
|
|
||
| this.refreshPanel(await resp.text()); | ||
| this.expandPanel(); | ||
| return false; | ||
| }, | ||
|
|
||
| // Renders step 2 of the video upload process - entering the url. | ||
| loadPostVideo: async function () { | ||
| let shakeSuffix = ""; | ||
| if ($videoShakeId.length > 0) { | ||
| shakeSuffix = "?shake_id=" + $videoShakeId.val(); | ||
| } | ||
| const url = `/tools/save-video${shakeSuffix}`; | ||
|
|
||
| const resp = await fetch(url); | ||
| this.refreshPanel(await resp.text()); | ||
| this.expandPanel(); | ||
| }, | ||
|
|
||
| expandPanel: function () { | ||
| $newPostPanel.slideDown(); | ||
| var that = this; | ||
| $("body").one("click", $.proxy(this.close_panel, this)); | ||
| // we want to hide anything with a video since we can't | ||
| // overlap things like youtube embeds, which is an iframe | ||
| // that has an absolutely positioned flash element inside. | ||
| $(".the-image iframe").each(function () { | ||
| $(this).parent().css("height", $(this).height()); | ||
| $(this).parent().css("width", $(this).width()); | ||
| $(this).hide(); | ||
| }); | ||
| }, | ||
|
|
||
| close_panel: function () { | ||
| $newPostPanel.hide(); | ||
| removeEvents(); | ||
| // show the videos again. | ||
| $(".the-image iframe").show(); | ||
| }, | ||
|
|
||
| // Renders step 3 of the video upload process - previewing the video. | ||
| submitSaveVideo: async function () { | ||
| const url = $saveVideoForm.attr("action"); | ||
| const data = $saveVideoForm.serialize(); | ||
|
|
||
| const resp = await fetch(`${url}?${new URLSearchParams(data)}`); | ||
| this.refreshPanel(await resp.text()); | ||
| }, | ||
|
|
||
| // Final step of video upload - submitting the post details to the server. | ||
| submitPostVideo: async function () { | ||
| const url = $postVideoForm.attr("action"); | ||
| const data = $postVideoForm.serialize(); | ||
| $postVideoFormButton.unbind("click").find("span").html("Posting..."); | ||
|
|
||
| const resp = await fetch(url, { | ||
| method: "POST", | ||
| body: new URLSearchParams(data), | ||
| }); | ||
| const json = await resp.json(); | ||
|
|
||
| // Redirect to the new post permalink page. | ||
| document.location = | ||
| document.location.protocol + | ||
| `//${document.location.host}${json["path"]}`; | ||
| }, | ||
|
|
||
| refreshPanel: function (html) { | ||
| $newPostPanelInner.html(html); | ||
| removeEvents(); | ||
| initDom(); | ||
| initEvents(); | ||
| }, | ||
| }; | ||
|
|
||
| export { NewPostPanel }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we change all the remaining
vars tolets?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will definitely do this, and make it an eslint rule. Prob left this as wasn't changing the $.get just yet and trying to minimise diffs.