Skip to content

Javascript in PlaceCal

aaaaargZombies edited this page Aug 9, 2022 · 9 revisions

A list of the JS that is used in the PC frontend.

platform Libraries

  • jQuery
  • Hotwire/Turbolinks
  • vueJS

components that are our code

  • Datatables (renders tables on admin pages)
  • Select2 - input box for choosing partners, tags, etc on admin pages
  • Opening times selector
  • cocoon - nested forms
  • pagination (?)
  • maps on public site.

Libraries installed but not used

ansi-regex

  • introduced by commit 4d63c20
  • exists in package.json & yarn.lock
  • rg "import.\*ansi-regex" - no results
  • rg "require.\*ansi-regex" - no results
  • git grep "import.*ansi-regex" $(git rev-list --all) - no results
  • git grep "require.*ansi-regex" $(git rev-list --all) - no results

async

  • introduced by commit eb09b2f0
  • a very common word so less confident about this
  • exists in package.json & yarn.lock
  • rg "import.\*async" - no results
  • rg "require.\*async" - no results
  • git grep "import.*async" $(git rev-list --all) - no results
  • git grep "require.*async" $(git rev-list --all) - no results

"cocoon": "^0.1.1"

  • introduced by commit 990abe27
  • was this added by mistake? Perhaps someone meant to add @nathanvda/cocoon.
  • library repo, 12 commits last updated 9 years ago.
  • exists in package.json & yarn.lock
  • rg "import.\*^(@nathanvda/)cocoon" - no results
  • rg "require.\*^(@nathanvda/)cocoon" - no results
  • git grep "import.*^(@nathanvda/)cocoon" $(git rev-list --all) - no results
  • git grep "require.*^(@nathanvda/)cocoon" $(git rev-list --all) - no results

esbuild-rails

  • introduced by commit 810e5b10
  • would be called as a plugin in esbuild.config.js
  • exists in package.json & yarn.lock
  • rg "import.\*esbuild-rails" - no results
  • rg "require.\*esbuild-rails" - no results
  • git grep "import.\*esbuild-rails" $(git rev-list --all) - no results
  • git grep "require.*esbuild-rails" $(git rev-list --all) - no results

minimist

  • introduced by commit 4d63c20
  • exists in package.json & yarn.lock
  • rg "import.\*minimist" - no results
  • rg "require.\*minimist" - no results
  • git grep "import.\*minimist" $(git rev-list --all) - no results
  • git grep "require.*minimist" $(git rev-list --all) - no results

rocket chat

  • exists in ./app/views/layouts/_rocket_chat.html.erb
  • was last referenced in app/views/layouts/application.html.erb in commit 251bd2f

google maps

Loading external js via script tags in

  • app/views/admin/partners/_form.html.erb
  • also in the head tag

Code we have wrote but not used

app/javascript/src/ward-picker.js

  • app/javascript/admin.js:22 imports ./src/ward-picker.js
  • ./src/ward-picker.js attaches a vue app to a dom element with an id of js-ward-picker
  • rg -l ward-picker only provides the following files.
app/javascript/admin.js
app/javascript/src/ward-picker.js
  • Looks like it was removed from app/views/admin/neighbourhoods/new.html.erb and app/views/admin/neighbourhoods/edit.html.erb in commit 0bb508c
  • which should mean app/inputs/vue_string_input.rb is also no longer in use.

app/javascript/src/behaviors/behaviors.map.js

  • this is a commented out file

app/javascript/src/calendar-form.js

  • app/javascript/admin.js:21 imports ./src/calendar-form.js
  • ./src/calendar-form.js adds an event listener for turbo:load but the body of the callback has been commented out.
  • It would have attached a vue app to a dom element with an id of js-calendar-form
  • a dom element with that id exists in app/views/admin/calendars/_form.html.erb it is probably a good idea to remove the id in case it causes conflict in the future.

app/javascript/src/behaviors/behaviors.place.js

  • The places url points to the partners controller and no longer loads
  • There is a behaviors.partners.js with the same code and more that does get loaded. I assume this has replaced it.

Libraries we might be using

"popper.js": "1.16.1"

  • introduced by commit 810e5b10
  • exists in package.json & yarn.lock & Gemfile.lock as popper_js (1.16.0)
  • popper_js (>= 1.14.3, < 2) appears in Gemfile.lock and looks to be a dependency of bootstrap (4.4.1)
  • rg "import.\*popper" - no results
  • rg "require.\*popper" - no results
  • git grep "import.\*popper" $(git rev-list --all) - no results
  • git grep "require.*popper" $(git rev-list --all)
967a932a4cd1000b994bb5b62debc65e83d127ed:app/javascript/packs/admin.js:require("popper")
666bfffa2425839aaa4a40855fd73ea0cfa6e8aa:app/javascript/packs/admin.js:require("popper")
33a025ab78ee61771a46f30ad59a3611e16b46e7:app/assets/javascripts/admin.js://= require popper
9032b95fe8c9c7e5c2ffa801832ebd22ee2a7ece:app/assets/javascripts/admin.js://= require popper

looks like it was/is being used in app/assets/builds/admin.js like this.

  // ../../node_modules/popper.js/dist/umd/popper.js
  var require_popper = __commonJS({
    "../../node_modules/popper.js/dist/umd/popper.js"(exports, module) {

Functionality

Public Facing

Pagination

Purpose

  • allows you to change the events listed by date.
  • allows you to switch between day or week view per page.
  • allows you to sort by date or name.
  • provides options for repetitive events.

JS Functionality

See app/javascript/src/components/paginator.js

A page is loaded with 7 days worth of buttons + a back and forward button. This is the amount needed to fill the screen at the parents largest possible width.

When loaded a javascript function runs to see if there is enough space to display all buttons, if not it hides some of them. This also trickers when resizing the window.

Appears

Places where events are listed.

https://hulme.placecal.org/events/ https://hulme.placecal.org/partners/ibrahim-maine-centre

It is rendered from the event_list component view.

Action to take

Turn into stimulus controller to avoid eventlisteners, potentially remove jquery in favor of vanilla JS.

Potentially move the filter markup into it's own view.

The JS functionality could also be removed in favour of scrolling with CSS.

Breadcrumbs

Purpose

To provide context for the current page in relation to site structure.

JS Functionality

see ./app/javascript/src/components/breadcrumb.js

For some reason this toggles the visibility of filter options that are rendered by the paginator component.

It also also has a function responsible for submitting the form if a radio button is toggled.

Appears

Several different pages. It is rendered by the following views.

app/components/paginator/_paginator.html.erb:4:11:
app/views/partners/places_index.html.erb:5:7:
app/views/partners/index.html.erb:5:7:
app/views/partners/show.html.erb:12:9:
app/views/collections/show.html.erb:12:7:
app/views/news/show.html.erb:7:9:

Action to take

Move filter toggle js into own stimulus controller

map / leaflet

Purpose

To show locations of events or partners.

JS Functionality

See app/javascript/src/map_handler.js and app/views/shared/_map.html.erb.

  • map_handler.js creates mapData variable on document. It then adds an eventlistener which will initialize the map at the right time.
  • app/views/shared/_map.html.erb updates mapData with a script tag in the template, and presumably triggers the map initialization.

The contents of mapData are generated by args_for_map in app/helpers/map_helper.rb

Appears

Several different pages. It is rendered by the following views.

app/views/events/show.html.erb:39:5
app/views/collections/show.html.erb:65:7
app/views/partners/places_index.html.erb:19:7
app/views/partners/show.html.erb:70:13
app/views/partners/index.html.erb:19

Action to take

Remove JS from _map view.

To move to stimulus pass mapData as value onto the dom element using the appropriate data-[controller]-[varName]-value attribute. Allow the controller life-cycle method to cause a render rather than adding an event listener at load.

Navigation

Purpose

Allow movement around the sites top level pages

JS Functionality

It adds a click function to the burger menu to toggle a class which hides/reveals the menu on smaller screens. It is mostly jquery.

See app/javascript/src/components/navigation.js and app/components/navigation/_navigation.html.erb.

Appears

Appears at the top of all public facing pages. It's rendered here.

app/views/layouts/application.html.erb

Action to take

Rewrite as a stimulus controller...

As this is common functionality with the breadcrumbs js code it might make sense to make a generic class toggling controller that serves both use cases.

Reveal

Purpose

Allows a user to expand or contract a section of content.

JS Functionality

For each element with a class of js-reveal the following functionality is added.

  • when a button is clicked it toggles an is-hidden class.

  • the buttons content is changed between 'Open to read more' or 'Close'.

  • javascript/src/reveal.js

  • views/pages/community_groups.html.erb

  • components/audience_intro/_audience_intro.html.erb

  • views/pages/our_story.html.erb

The JS code is also replicated in a script tag in views/pages/_reveal.html.erb

Appears

At the pages for these views.

  • views/pages/community_groups.html.erb
  • views/pages/our_story.html.erb

Action to take

Move to stimulus, not sure if it will be possible to use the same toggle controller as suggested above for toggling.

  • Possible that a new controller is created that only swaps the button content and then both controllers run at the same time.
  • Possible to rely on the css state, pseudo elements , and content rules to inject the correct content but that could be a bit opaque for the next person interacting with the code.
  • In a similar style the button could contain two span elements that are display: none; depending on the context of the is-hidden class. This at least follows the same principle used on the other elements.

The JS in the view should be removed.

Admin Facing

Opening Times

Purpose

UI to allow the definition of a set of opening hours.

Display opening hours in human readable form.

JS Functionality

There's a reasonable amount going on here.

See app/javascript/src/opening-times.js and app/views/admin/partners/_form.html.erb

Data is formatted with https://schema.org/OpeningHoursSpecification , See an example below

[
  {
    "@type": "OpeningHoursSpecification",
    "closes": "20:00:00",
    "dayOfWeek": "http://schema.org/Tuesday",
    "opens": "19:00:00"
  },
  {
    "@type": "OpeningHoursSpecification",
    "closes": "20:00:00",
    "dayOfWeek": "http://schema.org/Thursday",
    "opens": "19:00:00"
  }
]

When the view is built it creates a div with the above data stored with a data attribute. This is read and passed into a small Vue app to render the list of "added-days" which are human readable opening time. The view also places the same data into a hidden textarea. When a new opening time is added or one is removed this textarea is updated and the list of opening times on the page is re-rendered.

The data is submitted back to rails via the text area when the whole page form is submitted.

There are also several helper functions for converting the schema formatted data to something that can be displayed in the opening times "added-days" list. And for reversing this process to add a new entry to the schema data.

For inputting the times the Vue2 Timepicker is used. Once for opening, once for closing.

Appears

Rendered by the following views

app/views/admin/partners/edit.html.erb app/views/admin/partners/new.html.erb

Action to take

This is probably at least two stimulus controllers.

  • Time picker - Investigate if something similar exists allready.
  • Rendering the list of added days based on data attribute
  • something to update the data, push it into the textarea and tricker a re-render.

The last two are closely linked because removing and opening time is done in the display list.

Potential to change the UI for something else so long as the data ends up in the textarea.

Select2

Purpose

  • Make the select UI more visually consistent with the rest of the site when compared to the native select.
  • To Allow searching / filtering options when there are many.
  • To have a consistent UI to the above when selecting multiple options.

JS Functionality

require("select2")(window, $) make available to jquery.

This is initiated on lots of different behaviors files. There's a pattern that looks like this.

// Attach select2 to the current select2 nodes
$(".select2").each(function() {
	multiple = $(this).hasClass("multi-select");
	$(this).select2({ multiple: multiple });
});

// Attach select2 to all future select2 nodes
$(".sites_neighbourhoods").bind("cocoon:after-insert", function(_, element) {
	multiple = $(".select2", element).hasClass("multi-select");
	$(".select2", element).select2({ multiple: multiple });
});

Appears

Files which make use of select2

app/assets/stylesheets/admin.scss
app/javascript/admin.js

app/javascript/src/behaviors/behaviors.user.js
app/views/admin/users/_form.html.erb

These all use app/components/admin_new/_admin_new.html.erb & app/components/admin_edit/_admin_edit.html.erb to add the data-behaviors around the form.

app/javascript/src/behaviors/behaviors.neighbourhood.js
app/views/admin/neighbourhoods/_form.html.erb

app/javascript/src/behaviors/behaviors.collection.js
app/views/admin/collections/_form.html.erb

app/javascript/src/behaviors/behaviors.article.js
app/views/admin/articles/_form.html.erb

app/javascript/src/behaviors/behaviors.calendar.js
app/views/admin/calendars/_form.html.erb

app/javascript/src/behaviors/behaviors.partner.js
app/views/admin/partners/_form.html.erb
app/views/admin/partners/_service_area_fields.html.erb

app/javascript/src/behaviors/behaviors.site.js
app/views/admin/sites/_sites_neighbourhood_fields.html.erb
app/views/admin/sites/_form.html.erb

app/javascript/src/behaviors/behaviors.tag.js
app/views/admin/tags/_form.html.erb

Does this get called?

app/javascript/src/behaviors/behaviors.place.js // I think this is now partners????

Action to take

We want to keep select2 but we want to initiate it with stimulus.

Behaviors Dir

Purpose

It runs the correct JS on the correct page while allowing all the JS to be bundled into a single file.

JS Functionality

Appears

tk

Action to take

tk