diff --git a/Gemfile b/Gemfile index dc28acd5f..4f54b0034 100755 --- a/Gemfile +++ b/Gemfile @@ -89,3 +89,5 @@ group :test do gem 'capybara' gem 'selenium-webdriver' end + +gem 'importmap-rails', '~> 2.0' diff --git a/Gemfile.lock b/Gemfile.lock index 02eb9d4ff..69de8ac34 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -182,6 +182,10 @@ GEM thor i18n (1.14.1) concurrent-ruby (~> 1.0) + importmap-rails (2.0.1) + actionpack (>= 6.0.0) + activesupport (>= 6.0.0) + railties (>= 6.0.0) intercom-rails (0.4.2) activesupport (> 3.0) io-console (0.7.2) @@ -505,6 +509,7 @@ DEPENDENCIES devise_invitable (~> 2.0) font-awesome-sass gabba + importmap-rails (~> 2.0) intercom-rails jbuilder (~> 2.7) jquery-rails diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 4268d2c77..642ce2235 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,3 +1,7 @@ //= link_tree ../images //= link application.js //= link 'application.css' +//= link_tree ../../javascript .js +//= link_tree ../../../vendor/javascript .js + +//= link local-time/app/assets/javascripts/local-time.es2017-umd.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 5cc4ea896..c9af3cf77 100755 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,6 +11,9 @@ // about supported directives. // // The long list of requires for the main Angular 1 application has been moved to core.js. +// +// We have introduced importmaps, which live in application2.js. This should probably be migrated +// over to that file assuming import maps works the way we are hoping! //= require bootstrap/dist/js/bootstrap.bundle //= require jquery @@ -23,5 +26,3 @@ //= require codemirror/lib/codemirror //= require codemirror/mode/javascript/javascript - -//= require local-time/app/assets/javascripts/local-time diff --git a/app/javascript/application2.js b/app/javascript/application2.js new file mode 100644 index 000000000..8e441626e --- /dev/null +++ b/app/javascript/application2.js @@ -0,0 +1,10 @@ +// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails +// This is a importmap version of the classic application.js so that we can have +// both sprockets and importmaps at the same time. + + +// Note: the file in vendor/javascript/vendored-local-time.js is the one that was downloaded via +// importmap pin. See https://github.com/basecamp/local_time/issues/113 for others who suggested +// remaining it +import LocalTime from "local-time" +LocalTime.start() diff --git a/app/views/admin/announcements/edit.html.erb b/app/views/admin/announcements/edit.html.erb index eaad14b5d..0d881f75e 100644 --- a/app/views/admin/announcements/edit.html.erb +++ b/app/views/admin/announcements/edit.html.erb @@ -7,7 +7,7 @@
<%= form.label :text, class: 'form-label' %> - <%= form.text_field :text, required: true, class: 'form-control' %> + <%= form.text_area :text, required: true, rows: 5, class: 'form-control' %>
The announcement. You can use HTML and emojis.
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 4c477acd8..d8bbf4c53 100755 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,9 +1,9 @@ - + -<%= favicon_link_tag asset_path "favicon.ico" %> + <%= favicon_link_tag asset_path "favicon.ico" %> <% if flash[:unfurl] %> @@ -54,9 +54,11 @@ -<%= stylesheet_link_tag 'application', media: 'all' %> -<%= csrf_meta_tags %> -<%= javascript_include_tag 'application' %> + <%= stylesheet_link_tag 'application', media: 'all' %> + <%= csrf_meta_tags %> + <%= javascript_importmap_tags 'application2' %> + <%= javascript_include_tag 'application' %> + diff --git a/bin/importmap b/bin/importmap new file mode 100755 index 000000000..36502ab16 --- /dev/null +++ b/bin/importmap @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +require_relative "../config/application" +require "importmap/commands" diff --git a/config/importmap.rb b/config/importmap.rb new file mode 100644 index 000000000..f303acace --- /dev/null +++ b/config/importmap.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# Pin npm packages by running ./bin/importmap + +pin 'application2', preload: true +pin "local-time", to: "vendored-local-time.js"# @3.0.2 diff --git a/package.json b/package.json index 26e631062..abf198dbb 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "d3-tip": "~0.9.1", "file-saver": "^2.0.5", "jquery": "~3.7.0", - "local-time": "^2.1.0", + "local-time": "^3.0.0", "ng-json-explorer": "http://github.com/o19s/ng-json-explorer", "ng-tags-input": "3.2.0", "ngclipboard": "^2.0.0", diff --git a/spec/karma/config/unit.js b/spec/karma/config/unit.js index 34f34184f..be9ffa1cf 100644 --- a/spec/karma/config/unit.js +++ b/spec/karma/config/unit.js @@ -19,7 +19,7 @@ module.exports = function(config) { // to run a single one files: [ 'tmp/assets/core*.js', - 'tmp/assets/application*.js', + 'tmp/assets/application.js', 'tmp/assets/application_spec*.js', 'spec/javascripts/mock/*.js', 'spec/javascripts/**/*_spec.js', @@ -28,7 +28,7 @@ module.exports = function(config) { // list of files to exclude exclude: [ - + '**/application2.js', // ignore this importmap related file when running core JS app tests ], diff --git a/vendor/javascript/.keep b/vendor/javascript/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/javascript/vendored-local-time.js b/vendor/javascript/vendored-local-time.js new file mode 100644 index 000000000..3776cc68e --- /dev/null +++ b/vendor/javascript/vendored-local-time.js @@ -0,0 +1,2 @@ +var t;t={config:{},run:function(){return this.getController().processElements()},process:function(...t){var e,r,a;for(r=0,a=t.length;r11?"pm":"am")).toUpperCase();case"P":return M("time."+(n>11?"pm":"am"));case"S":return p(o,l);case"w":return a;case"y":return p(u%100,l);case"Y":return u;case"Z":return S(t)}}))},p=function(t,e){return"-"===e?t:`0${t}`.slice(-2)},S=function(t){var e,r,a;return(r=h(t))?g[r]:(a=y(t,{allowGMT:!1}))||(a=v(t))?a:(e=y(t,{allowGMT:!0}))?e:""},h=function(t){return Object.keys(g).find((function(e){return b?new Date(t).toLocaleString("en-US",{timeZoneName:"long"}).includes(e):t.toString().includes(e)}))},y=function(t,{allowGMT:e}){var r;if(b&&(r=new Date(t).toLocaleString("en-US",{timeZoneName:"short"}).split(" ").pop(),e||!r.includes("GMT")))return r},v=function(t){var e,r,a,n,s;return(e=null!=(r=(s=t.toString()).match(/\(([\w\s]+)\)$/))?r[1]:void 0)?/\s/.test(e)?e.match(/\b(\w)/g).join(""):e:(e=null!=(a=s.match(/(\w{3,4})\s\d{4}$/))?a[1]:void 0)||(e=null!=(n=s.match(/(UTC[\+\-]\d+)/))?n[1]:void 0)?e:void 0},L.CalendarDate=class{static fromDate(t){return new this(t.getFullYear(),t.getMonth()+1,t.getDate())}static today(){return this.fromDate(new Date)}constructor(t,e,r){this.date=new Date(Date.UTC(t,e-1)),this.date.setUTCDate(r),this.year=this.date.getUTCFullYear(),this.month=this.date.getUTCMonth()+1,this.day=this.date.getUTCDate(),this.value=this.date.getTime()}equals(t){return(null!=t?t.value:void 0)===this.value}is(t){return this.equals(t)}isToday(){return this.is(this.constructor.today())}occursOnSameYearAs(t){return this.year===(null!=t?t.year:void 0)}occursThisYear(){return this.occursOnSameYearAs(this.constructor.today())}daysSince(t){if(t)return(this.date-t.date)/864e5}daysPassed(){return this.constructor.today().daysSince(this)}},({strftime:E,translate:I,getI18nValue:w,config:D}=L),L.RelativeTime=class{constructor(t){this.date=t,this.calendarDate=L.CalendarDate.fromDate(this.date)}toString(){var t,e;return(e=this.toTimeElapsedString())?I("time.elapsed",{time:e}):(t=this.toWeekdayString())?(e=this.toTimeString(),I("datetime.at",{date:t,time:e})):I("date.on",{date:this.toDateString()})}toTimeOrDateString(){return this.calendarDate.isToday()?this.toTimeString():this.toDateString()}toTimeElapsedString(){var t,e,r,a,n;return r=(new Date).getTime()-this.date.getTime(),a=Math.round(r/1e3),e=Math.round(a/60),t=Math.round(e/60),r<0?null:a<10?(n=I("time.second"),I("time.singular",{time:n})):a<45?`${a} ${I("time.seconds")}`:a<90?(n=I("time.minute"),I("time.singular",{time:n})):e<45?`${e} ${I("time.minutes")}`:e<90?(n=I("time.hour"),I("time.singularAn",{time:n})):t<24?`${t} ${I("time.hours")}`:""}toWeekdayString(){switch(this.calendarDate.daysPassed()){case 0:return I("date.today");case 1:return I("date.yesterday");case-1:return I("date.tomorrow");case 2:case 3:case 4:case 5:case 6:return E(this.date,"%A");default:return""}}toDateString(){var t;return t=this.calendarDate.occursThisYear()?w("date.formats.thisYear"):w("date.formats.default"),E(this.date,t)}toTimeString(){var t;return t=D.useFormat24?"default_24h":"default",E(this.date,w(`time.formats.${t}`))}},({elementMatchesSelector:C}=L),L.PageObserver=class{constructor(t,e){this.processMutations=this.processMutations.bind(this),this.processInsertion=this.processInsertion.bind(this),this.selector=t,this.callback=e}start(){if(!this.started)return this.observeWithMutationObserver()||this.observeWithMutationEvent(),this.started=!0}observeWithMutationObserver(){if("undefined"!=typeof MutationObserver&&null!==MutationObserver)return new MutationObserver(this.processMutations).observe(document.documentElement,{childList:!0,subtree:!0}),!0}observeWithMutationEvent(){return addEventListener("DOMNodeInserted",this.processInsertion,!1),!0}findSignificantElements(t){var e;return e=[],(null!=t?t.nodeType:void 0)===Node.ELEMENT_NODE&&(C(t,this.selector)&&e.push(t),e.push(...t.querySelectorAll(this.selector))),e}processMutations(t){var e,r,a,n,s,i,o,u;for(e=[],r=0,n=t.length;r