Bug 38706

Summary: Replace UserJS system preference with snippets
Product: Koha Reporter: Lucas Gass (lukeg) <lucas>
Component: Architecture, internals, and plumbingAssignee: Lisette Scheer <lisette>
Status: ASSIGNED --- QA Contact: Testopia <testopia>
Severity: enhancement    
Priority: P5 - low CC: andrew, blawlor, bywater, cbrannon, dcook, hacheng, kebliss, lisette, magnus, marion.durand, martin.renvoize, mathsabypro, michael.skarupianski, michaela.sieber, paul.derscheid, sally.healey, sspohn
Version: MainKeywords: roadmap_25_11
Hardware: All   
OS: All   
See Also: https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=39538
GIT URL: Change sponsored?: ---
Patch complexity: --- Documentation contact:
Documentation submission: Text to go in the release notes:
Version(s) released in:
Circulation function:
Bug Depends on: 40293    
Bug Blocks: 39538    

Description Lucas Gass (lukeg) 2024-12-13 20:55:37 UTC
Currently the UserJS's are just a big blob of JS with each piece unrelated to the next. 

It would be nice if we replaced the system preference with individual "snippets". These could live somewhere like HTML customizations.

This would bring more organization to JS customization. It could also allow staff to see how created/edited/deleted certain blocks much easier.

It could also make it easier to incorporate different permission checks for who can create/edit/delete JS. 

See Bug 34536.
Comment 1 David Cook 2024-12-15 23:36:07 UTC
+1

--

It could be interesting to have enabled/disabled options as well. Sure, in theory, you can always just comment out the code you want to disable, but depending on how you've done your code comments this can actually be a bit of a pain. Having an easy way to turn these on/off could potentially be handy.

--

This is a bit of a tangent, but this could also allow us to enhance the UserJS feature. For instance, if we could toggle on 'type="module"', then we'd be able to add support for user-defined ES6 modules. 

(I'm curious how ES6 module imports from external URLs work with Content-Security-Policy...)

That said, I don't know how much of a value add this really would be. It just popped into my mind, as I was writing some ES6 modules last week, which made it easy to share code around my codebase without interfering/polluting the global namespace. 

Anyway, just food for thought.
Comment 2 David Cook 2024-12-16 01:57:16 UTC
(Aside: Of course, today is the day I learn that you can actually use dynamic imports in regular Javascript code...so even less utility for making the snippets appear as modules...)
Comment 3 Magnus Enger 2024-12-16 07:28:19 UTC
+1 I think it would make sense to do the same for UserCSS? And have one smippet go to either the OPAC or staff, or both?
Comment 4 Andrew Fuerste-Henry 2024-12-16 14:12:13 UTC
(In reply to Magnus Enger from comment #3)
> +1 I think it would make sense to do the same for UserCSS? And have one
> smippet go to either the OPAC or staff, or both?

I like the idea of doing the same to UserCSS.

I also like the idea of giving the user the choice of where to apply those snippets. I suppose we'd want to cover all the varieties of those sysprefs, though:
SelfCheckInUserCSS
SCOUserCSS
OPACUserCSS
IntranetUserCSS

SelfCheckInUserJS
SCOUserJS
OPACUserJS
IntranetSlipPrinterJS
IntranetUserJS
Comment 5 David Cook 2024-12-16 23:03:39 UTC
(In reply to Magnus Enger from comment #3)
> +1 I think it would make sense to do the same for UserCSS? And have one
> smippet go to either the OPAC or staff, or both?

This would be a problem when we implement Content-Security-Policy. Each individual snippet will need its own type indicated.
Comment 6 David Cook 2024-12-16 23:04:35 UTC
(In reply to David Cook from comment #5)
> (In reply to Magnus Enger from comment #3)
> > +1 I think it would make sense to do the same for UserCSS? And have one
> > smippet go to either the OPAC or staff, or both?
> 
> This would be a problem when we implement Content-Security-Policy. Each
> individual snippet will need its own type indicated.

I might be misinterpreting what you're saying though.

Overall, yes for doing it for UserCSS as well. Just so long as the snippets are clearly marked as CSS or Javascript.
Comment 7 David Cook 2024-12-16 23:05:31 UTC
(In reply to Andrew Fuerste-Henry from comment #4)
> I also like the idea of giving the user the choice of where to apply those
> snippets. I suppose we'd want to cover all the varieties of those sysprefs,

There's also the question of branch-level CSS and Javascript and how that fits into this...
Comment 8 Andrew Fuerste-Henry 2024-12-17 16:23:32 UTC
(In reply to David Cook from comment #7)
> (In reply to Andrew Fuerste-Henry from comment #4)
> > I also like the idea of giving the user the choice of where to apply those
> > snippets. I suppose we'd want to cover all the varieties of those sysprefs,
> 
> There's also the question of branch-level CSS and Javascript and how that
> fits into this...

True! I forgot that OPAC CSS and JS had been added to branches. In the structure we're ideating here it would make sense to pull that out of the branches setup and instead let each snippet be limited to one or more branches.
Comment 9 David Cook 2024-12-17 22:17:50 UTC
(In reply to Andrew Fuerste-Henry from comment #8)
> True! I forgot that OPAC CSS and JS had been added to branches. In the
> structure we're ideating here it would make sense to pull that out of the
> branches setup and instead let each snippet be limited to one or more
> branches.

Yep, I'd agree.
Comment 10 Christopher Brannon 2025-05-14 17:56:29 UTC
I'm wondering how this would affect those of us that reuse functions and gathered content in multiple parts.  Would something that is defined in one snippet be able to be called from another, or should we have a global snippet?
Comment 11 David Cook 2025-05-14 23:07:13 UTC
(In reply to Christopher Brannon from comment #10)
> I'm wondering how this would affect those of us that reuse functions and
> gathered content in multiple parts.  Would something that is defined in one
> snippet be able to be called from another, or should we have a global
> snippet?

It'll depend a bit on how the feature is implemented and how you implement your Javascript, but overall it'll probably be doable.
Comment 12 David Cook 2025-05-14 23:15:43 UTC
With snippets, I wonder if we'd want a way to specify "type" so that we could make it a ES6 module or not. 

Of course, with inline Javascript, there's limited utility with an anonymous module, since you can't import/export it. The main benefit would be importing other ES modules and having a stricter context (ie not polluting the global context).

it could be interesting trying to implement the snippets as .js files, so rather than displaying it as an inline <script> tag, it would be <script src="/path/to/perl/endpoint_for_serving_static_javascript">.

In fact... that gets extra interesting because if we did "Staff interface and OPAC" like with the "News", you could actually define 1 set of functions/modules and then re-use them across the interfaces. Of course, that might have limited utility as well. 

Anyway, just some blue sky thinking there...
Comment 13 David Cook 2025-05-14 23:16:30 UTC
(In reply to Magnus Enger from comment #3)
> +1 I think it would make sense to do the same for UserCSS? And have one
> smippet go to either the OPAC or staff, or both?

Magnus way ahead of me there in terms of the locations hehe
Comment 14 Christopher Brannon 2025-05-14 23:36:38 UTC
I could see some potential pitfalls if IDs and classes are not consistent between the two.  Not everything has been consistent.  It's getting better, I think, but I've seen enough differences where I've had to target things differently from one side to the other.
Comment 15 Steve, OSLRI, USA 2025-05-14 23:48:48 UTC
We use snippets in Aspen and have 50+ individual Aspen sites in our instances.  Some snippets apply to all and some apply to one site or even one page on one site.  We use naming conventions to clearly indicate what applies to what.  That same could apply here, e.g., 

1. opac - advanced search
2. staff - custom facets
3. both - custom footer
4. both - custom batman sound effects
...
Comment 16 Lisette Scheer 2025-06-03 14:38:12 UTC
A few notes about the scope of this bug + some things I'd like to do as followups after:

-New table (or as part of additional contents, unsure at this point) for snippets
-Interface for editing, including codemirror (subset of additional contents interface)
-Initial upgrade will make one big snippet
-Set up a delimter-based snippet splitter so users can define where they want snippets split and run it on demand.
-Confirm global variables work/document how to make them work if anything special is needed
- Permissions
- Move the branch js into this
-Separate try/catch for each snippet so one breaking doesn't break all
-- Log in console which snippet is failing for troubleshooting


My plan was not to have a "Both" locations option because there's too many different names/structure, but we could set it up and possibly note that there's differences in the names/classes of things sometimes. 


Later to do:
- Multiselect for libraries/select library groups (probably for all additional contents)
- Define module/specific pages for code to load on (example: lots of label renaming on patron edit screens, being able to define to only those specific ones or at least modules for those could be helpful)
- Show on branches which snippets are all branches/specific to that branch? Not sure if this would be helpful, but large systems might find it helpful to be able to see all additional contents that are shown on a particular branch?
Comment 17 Mathieu Saby 2025-06-06 07:23:58 UTC
In my library we have just 1 line in the UserJS, a call to a _big_ js file (with  $.getScript) located in public/js
We are happy with that because it allows us to version the js code outside Koha.
Same thing with the CSS...

I am not sure to understand well what you're planning, but would our way of doing things still be possible?
Comment 18 Lisette Scheer 2025-06-06 13:52:21 UTC
(In reply to Mathieu Saby from comment #17)
> In my library we have just 1 line in the UserJS, a call to a _big_ js file
> (with  $.getScript) located in public/js
> We are happy with that because it allows us to version the js code outside
> Koha.
> Same thing with the CSS...
> 
> I am not sure to understand well what you're planning, but would our way of
> doing things still be possible?

That should still work, you'd just have one snippet with the current line.
Comment 19 David Cook 2025-06-10 00:40:34 UTC
(In reply to Mathieu Saby from comment #17)
> In my library we have just 1 line in the UserJS, a call to a _big_ js file
> (with  $.getScript) located in public/js
> We are happy with that because it allows us to version the js code outside
> Koha.
> Same thing with the CSS...
> 
> I am not sure to understand well what you're planning, but would our way of
> doing things still be possible?

Mathiew, I'm curious why you would do it using UserJS and not opacheader or opaccredits?
Comment 20 Mathieu Saby 2025-06-10 09:25:29 UTC
This is the practice of our service provider Biblibre ;-)
I suppose we could do things differently, so I'll ask them.