Skip to content

unpoly/unpoly-backlog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Next

  • Typo "dimissing" in UpdateLayer?

  • Fix flakey test: up.Layer.Modal > styles > scrollbars while an overlay is open > consistently shifts and unshifts if multiple overlays are opened and closed concurrently

  • [ok] Wrong deprecation: https://unpoly.com/up.Request.prototype.loadPage

    • It was #navigate that was deprecated

[ok] - Consider publishing { previousLocation }

[ok] - I think the message "Aborting requests within fragment" now also appears if there is nothing to abort => It is designed to always fire, in case a listener is interested

  • [ok] Run up-switch before up-submit or up-validate

    • It's weird because up-validate already schedules a timeout? => No switch (via up.watch) also schedules macrotask
  • Phased rendering [ok] - Do all mutations before starting compilation, preprocessing, etc.

    • Decide who calls postprocess
      • Doesn't make sense in UpdateSteps
    • Render macros before setting location, so we can set [up-href] and [up-alias]
    • Update lifecycle chart
    • Test that we can keep focus in all step variants (especially those that use wrappers)
    • Test that we can call focus functions in all step variants
    • Test that we can call scroll functions in all step variants
    • Test that we can apply transitions when swapping children
    • Test that { finished } delays by transition/animation in all step variants
    • Test that macros are called in all step variants
    • Test that compilers are called in all step variants
    • Test that destructors are called in all step variants
    • Test that the bounds variants don't keep an in the DOM
    • Can we replace _executeSwapChildrenStep with a regular swapStep if both new and old element only have a single element child?
    • How does { scroll: 'target' } or { focus: 'target' } work with wrappers?
  • Leverage new phased rendering logic

    • Scroll functions should be able to scroll secondary fragments
    • Focus functions should be able to scroll secondary fragments
    • Compiler functions should see secondary fragments after update
    • Compiler functions should see hungry fragments after update
    • Run macros immediately after mutation
      • So we can set [up-href] and [up-alias]
    • Move scrollMap out of steps, into UpdateLayer / UpdateLayer
    • Allow scrollMap to update arbitrary fragments?
    • Stop reversing in steps
  • Docs: /layer-option is more like "Targeting layers"

  • Docs: Sizes in /customizing-overlays#overlay-sizes should be in fixed width

  • Test that morph() and animate() respect the default duration

  • When we scroll to a hash (on load or in reaction to history changes), we should also focus() the new fragment

    • There is an issue for that

[ik] - We can replace up.util.reverse() with Array#toReversed()

[ok] - We have e.cleanJQuery() without an argument

  • Check whether this is needed anyway
  • Then document change

[ok] - up:fragment:kept log: Should be silent or have more details

  • Possibly offer up.destroy(remove: false) for morphdom integration

  • Why do we sometimes log uppercase %O?

[ok] - Offer [up-scroll-map=...] and { scrollMap }

  • Think about exposing dataMap

    • Would it be [data-map] or [use-data-map]?
      • I think attr would be [use-data-map], but option would just be { dataMap }
  • Think about exposing placeHolderMap and previewMap

    • previewMap is weird as an attribute: up-preview-map="{ '.foo': 'preview { attr: 'value' }'
      • I think we would need to allow nested objects here, e.g. { '.foo': { 'edit-task': { attr: 'value' } } }
  • Multi-pane layouts

    • Do this now or wait until we do zone/frame?

    • Offer { scroll: 'target-attrs' } to read scroll settings from fragment

      • This should be part of { scroll: 'auto' }
      • This cannot set 'auto'
    • Offer { history: 'target-attrs' } to read history settings from fragment

      • This should be part of { history: 'auto' }
  • Focus in multi-pane layout

    • We currently only focus for the first step
    • But we should allow focusing a secondary fragment
  • Rework execution order in multi-step upgrades

    • Compilers, Scroll fns etc. should see DOM mutations from subsequent steps
    • I want central control for this order:
      1. doCommit()
      2. doMutate()
      3. doUpdateViewport()
      4. compile()
      5. scrollAndFocus() This can now
      6. startFinish()
  • Expose up.util.mapObject()

    • Tests
    • Docs
  • Think about introducing a light way of [up-zone] or [up-frame]

    • I just want the auto-targeting
    • We might still need :frame, :zone, -if-frame etc.
    • up.fragment.config.frameSelectors
  • Should up-switch run for disabled elements?

    • What about up.watch()?
    • What about up-validate?
    • upWatchIncludeDisabled?
    • Or have [up-faux-disabled] on the element, so it is parsed by up.Params?
      • Maybe even offer up.form.disable(element, { faux: true })
      • Is there a better name like [up-force-params]
  • Consider bringing the offline polling into the library

    • Also a prop up.network.offline or something?
    • But we need to make it opt-in?
      • Would up.network.offline need to raise or return "unknown"?
  • Improve docs and tests of offline/loaded events

    • Test and document that up:fragment:offline does not run when preloading
    • Test and document that up:request:loaded does NOT run when loading from cache
    • Test and document that up:fragment:loaded DOES run when loading from cache
      • Vs. preloading?
    • undefined log message: up:fragment:offline Cannot load fragment from GET /notes/229: undefined
  • Consider bringing the flash nonce pattern into the library

    • [up-flash=uid]
    • But what I really want is to change the cached response text
  • Meta props

    • meta.ok
    • meta props for up:fragment:inserted
  • Keeping scroll positions

    • Offer { scroll: 'keep' } (similiar to { focus: 'keep' })
    • Should up.reload() default to { scroll: 'keep', focus: 'keep' }
      • focus: 'keep' might already be a default
  • Test that an untargetable [up-keep] prints a warning, but does not crash the render pass

  • Use onAccepted with JS string?

    • At least support X-Up-Open-Layer with callbacks
    • Or support actions, effects
  • Merge [up-peel="accept|dismiss"]

    • Worry about setting the value another time
  • [up-accept-selector]

    • [up-accept-element]
    • data becomes acceptance value
  • [up-accept-on] => [up-accept-event] ?

  • fade-out should take current opacity into account

  • Use AI to make a typo and wording pass over the docs

  • rails.js does not convert on forms and submit buttons

    function convertDataAttr(dataAttr, upAttr) { up.macro('[' + dataAttr + ']:is(form, input[type=submit], button[type=submit], button:not([type])', function(confirmable) { let form = up.form.get(confirmable) if (up.form.isSubmittable(form)) { up.element.setMissingAttr(form, upAttr, confirmable.getAttribute(dataAttr)) confirmable.removeAttribute(dataAttr) } }) }

    convertDataAttr('data-confirm', 'up-confirm') convertDataAttr('data-method', 'up-method')

  • It would be nice to have a macro? for live validation

  • Support { scroll: 5 } and { scroll: -5 }

    • Ambiguity: Could either be "current + 5" / "current -5" or it could be "scroll to 5" / "scroll to end minus 5"
  • Do watchers fire when fields become disabled / not disabled?

  • New demo

    • Clean up
    • Share on forum
    • Say thanks to Philip

Backlog

  • Think about support for scroll-margin-top, scroll-padding-top

  • Should [up-autosubmit] work like [up-validate], in that all autosubmitters work together?

    • Use case: Different targets for different inputs
    • But get rid of form group seeking
  • Support { timing } compiler option

    • Macros must be sync
    • up.fragment.config.renderBudget
    • The budget is impossible to measure with async compilers
      • We can measure the initial frame though
    • There is Schedules#postTask() which uses { priority: 'user-blocking' | 'user-visible' | 'background' }
    • Should we just ask users to use requestIdleCallback() or await scheduler.yield() in their compilers?
  • [up-target], { target } for polling

    • Default is :origin
      • Docs should mention that you can set a target instead of relying on
    • It's may not be trivial to keep it going when forceStarted
  • external_post

    • Migrate Adminition Style for GitHub?
    • Remove mark: and result: comments
    • Remove custom headline IDs ({#...})
    • Don't prepend unpoly.com to local #fragment links
  • Experiment with logo page

  • Doc page for array params?

    • It's only relevant for watching?
  • Allow to trigger the progress bar with arbitrary promises

    • E.g. for DirectUpload integration
    • Is this related to our big job queue rework?
  • Think whether we want to offer a way to "stagger" non-blocking compilers.

    • At least for initial page view
    • Measure time and force-stagger?
    • Is this related to async compilation? So we can wait for staggered compilers with finished?
    • Support { priority: 'idle' }
  • Instead of having a long list of PREFLIGHT_KEYS and SHARED_KEYS, we could just list the very few render options that have a failVariant

    • failLayer, failFocus, failScroll, failHistory
  • Make doc pages for "Linking to fragments" and "Fragment forms" so we have main articles for related features

    • At least for links we have up.link. We don't have this for forms.
  • Think what's the desired behavior for new up.Params({ 'ids[]': [] })

    • Wenn Unpoly die Rails-Konvention kennt, wäre es IMO nicht falsch, wenn 'ids[]': [] zu ids%5D%5B= würde. (edited)
    • ja vielleicht. da er nicht direkt schicken kann sondern entries bauen muss wäre das ein eintrag mit leerem string als value? nil als value?
    • leerer string macht ids%5D%5B=. nil macht ids%5D%5B. weiß nicht was rails aus letzterem macht.
  • up-scroll="+20"

  • Test that render({ response }) throws for a failed response

  • revealPadding etc. should have function forms for the revealed element

  • Consider moving [up-nav], .up-current, [up-alias] to up.history

  • Support custom :field, :form-group selectors

    • Will we still use field-with-errors wrappers in a world with :has() ?
  • Do we have a test that [up-keep] preserves scroll positions?

    • For a non-focused element?
  • Site: Chilled links

  • Consider [up-validate-scroll] and [up-validate-focus] options

  • [up-poll] should support more ways to control client-state

    • [up-hungry=true]
    • [up-keep=true]
  • Ensure and test that peeling does not restore history entries

  • Think about: When we remember how a history state came to be (or was left?), we could undo it on back maybe?

    • I think we could do the easy case of dismissing an overlay first
      • Remember the layer stack before state is changed
        • e.g. on every render / close
          • but also on up:location:change, after e.g. hashchange has created a new stack
        • remember identifying information like [{ location, mode, size, align, position, layerUID }]
          • It could just be layerUIDs[]
      • When popping a state, check if the current stack is the previous stack, but missing some at the end
        • in this case just pop off last stack elements (no interruption)
      • Should we also allow navigation within an open layer?
      • For overlays without history, we could also push an "empty" state with the base URL
        • This way we would have something to compare against
        • This way we wouldn't need to mess with CloseWatcher
    • Re-think what this means for up:location:restore
      • Would it only be for render-restore?
      • Or would it also contain { layerStack, previousLayerStack }?
      • But then would it also contain the #reveal logic?
  • Consider [up-announce=":title"] or ["up-announce="next-headline"]

  • Consider making the docs full-width

    • Also replace the breadcrumb with a link that opens the drawer
    • Move the entire search to Algolia
  • Add a short cut [up-keep-while-same] oder [up-keep][up-keep-if="same"] or [up-keep="same"] (vs. [up-keep="match"]) or similiar to keep a fragment while the initial outer HTML is unchanged

    • But store the outerHTML before compilation
    • Maybe do some normalization of the HTML?
    • Should this be the default?
  • Think whether saveScroll and saveFocus should work on bases instead of full locations

  • Consider implementing CloseWatcher for "key" dialog closing => Yes, but CloseWatchers would need to be carefully managed with nested overlays => Maybe solve this with custom push states

  • Allow some up-attributes on submit button

    • [up-submit=false] => Make a vanilla page load
  • up.network.loadPage() could remove the form after submission

    • e.g. when starting a download
  • Should a { cache: false } setting propagate to deferred pages?

    • Deferreds can already say whether they want to use the cache
    • What about polling a fragment with 3 deferreds?
  • Think about predicting events for preload (pointer event getPredictedEvents())

  • Try to not set any [style] attribute ever to support strict CSS CSPs

    • We can still manipulate element.style.foo
    • Test if we really need to set the [style] attribute (and remove style-src-attr 'unsafe-inline')
      • I think a lot of specs use this to style fixture elements
  • Back/forward navigation restores focus should it be visible? => As always it is redundant for mouse users => This is not easily detectable, as keydown is fired after popstate => We would need to delay popstate handling by a task

  • Do we want to support up.fragment.sync() ?

    • Maybe we want an up:fragment:changed event so swaps won't cause SelectorTracker to sync twice
  • Provide an .up-hash-target or similiar to target the current #hash better than :target does => Which cases are not covered by :target?

  • up.fragment.get() could delete :maybe

  • Install instructions should also cover editor integrations

  • Docs for deferreds (/lazy-loading, up.deferred.load, [up-defer]) should not talk about "placeholder"

  • Consider hiding the focus ring for main elements by default

  • Test that we don't process { abort } when the RenderPass was aborted by { guardEvent } or { confirm }

  • I'm not sure if opening a layer with local content honors { abort }

    • E.g. start loading content on the base layer's main
    • Open a layer from a string (which makes a request with bindFragments: [base-layer's main])
    • Content on base layer is still loading
  • Think about a way to optimistically render an action that dismisses an overlay and changes something in the background

    • What about dismiss callbacks?
  • Offer a way to expand a template into an element

    • Like , but without the need to have a good selector
    • Can we somehow say that we want to replace ourselves, even when the replacement has a different selector?
      • HTML-Importe waren
    • There is no unobtrusive way to do this
  • Remove commented-out code in up.util

  • affix() and createSelector() cannot create an attribute called [content] or [text]

    • e.g. for meta[content]
    • Maybe force all attrs into { attrs } ?
      • Or allow { attrs }
  • Rework compiler docs (unpoly/unpoly#688)

    • Extract docs from up.compiler() into its own guide page /compilers "Initializing JavaScript" (with compilers)

    • Fix existing links to /up.compiler and /up.compiler#destructor

    • Make examples for all three destructor forms:

      • Returning a function
      • Returning an array of functions
      • Using up.destructor
    • Section for async compilers

      • Timing issues if the element is detached before it is compiled

      • If they return a function, it will not run as a destructor

      • Maybe asyncCompiler helper

      • Note that this will be improved in the future

      • // Registers an `up.compiler()` function that returns a promise for its destructor function.
        export default function asyncCompiler(...compilerArgs) {
          const compilerFn = compilerArgs.pop()
        
          up.compiler(...compilerArgs, (...passArgs) => {
            // Call the compiler function passed by the user.
            const returnValue = compilerFn(...passArgs)
        
            // Return a new destructor function that awaits the asynchronous
            // return value and uses the fulfillment value as a destructor.
            return async () => {
              // The async function could return different types of values:
              //
              // (1) A destructor function
              // (2) An array of destructor functions
              // (3) A value that is not a function (which we discard)
              let destructorCandidates = await returnValue
              destructorCandidates = up.util.wrapList(destructorCandidates)
        
              for (const destructorCandidate of destructorCandidates) {
                if (up.util.isFunction(destructorCandidate)) {
                  destructorCandidate()
                }
              }
            }
          })
        }
        
  • Allow to keep unpoly-migrate without logging, e.g. up.migrate.config.logLevel = 'none'

  • Improve active classes, loading classes

    • Tailwind users would love [up-active-class] [up-loading-class]
    • Maybe allow a function for config.activeClasses, config.loadingClasses
  • Make a doc page for custom elements (unpoly/unpoly#688)

    • Explain that you can just use defineElement
    • Explain that you can use compilers for simple cases
    • Show how custom elements can participate in form submissions
      • config.fieldSelectors
      • Support { name, value, disabled }
      • Note that Unpoly does not support formAssociated or formdata event, but that this will be improved in the future
  • Make a doc page for polling

    • Extract from [up-poll]
    • Own section for "Reloading when re-focusing a tab"?
  • I somehow expected up.fragment.config.runScripts to be in up.script.config.runScripts

    • We would need a new name like up.script.config.runFragmentScripts
  • Add Rust install to https://github.com/unpoly/unpoly-site/tree/master/source/install

  • Consider a callback to manipulate render options before interaction

    • Either element-specific ([up-on-follow], [up-on-submit], etc.)
    • Or generic ([up-on-use="..."], [up-setup="..."], [up-before], [up-guard], [up-on-run] [up-on-activate="..."], [up-on-start])
      • Use is short, but conflicts with [up-use-data] and does not work for polling
    • Callback to run before any render pass (see davidsums popup discussion)
      • up:render:prepare or up:render:setup or up:render:options
      • Would we rename up:fragment events to get pressure off the up:fragment namespace?
        • up:render:load
        • up:render:loaded
        • up:render:keep :(
        • up:render:offline
        • up:render:inserted :(
        • up:render:hungry :(
        • This would leave up:fragment:poll
  • FM required overriding of history from the server

    • They really wanted { navigate }, no?
      • But can we really change navigation options at that point?
  • Remove params parsing for up.watch(), support formdata, ElementInternals

    • We can just parse the entire form with new FormData(), then filter on contained elements
      • We will still need to know form fields for that, or filter on [name]
    • Replace up.Params.fromForm() with new this(new FormData(form))
  • Consider [up-zone] as an origin-aware lookup without further logic

    • Also support :zone as a new pseudo
      • Layer priority beats zone priority
    • config.zoneSelectors = ['[up-zone]', ':main]
    • config.noZoneSelectors = ['[up-zone=false]']
    • I think without an { origin } we only want to check out :main. Maybe it's not configurable?
    • Do we want to allow [up-zone="name"] (and include it in targetDerivers), or should it be [up-zone][id="foo"]?
      • If we want to get rid of [up-href] (to enable morphing), we should encourage the use of IDs
    • If we want to mount arbitrary pages to mount in an [up-zone] it should be a parent.
      • e.g. content
        • But then we would have duplicate
          • section[up-main=zone]?
  • Maybe all guardEvents should have a loadPage() method

    • So it's more discoverable then event.loadPage()
  • Consider publishing { dataMap, placeholderMap, previewMap } as @experimental

    • Check if we have tests here
    • Check whether a single { map } option (or an object target) would be superior
      • up.render({ target: { '.foo': { data: { key: 123 }, placeholder: 'spinner' }, '.bar': {} }, url: '/path' })
      • up.render({ target: { '.foo, .bar' }, dataMap: { '.foo'. { key: 123 } }, placeholderMap: { '.foo': 'spinner' }, url: '/path' })
      • up.render({ target: { '.foo, .bar' }, map: { '.foo'. { data: { key: 123 }, placeholder: '.spinner' } }, url: '/path' }) => Doing something to the primary is a very common use case and great now
  • Consider publishing up.script.clean()

    • Would we need a fallback for { layer }?
    • Supporting the use case "recompile later" is hard because then we would need to update the idempotent-compiler-fn-tracking
  • Consider removing { content } option of createFromSelector(), affix(), etc. in favor of a third argument for constructing nested things

    • When we make this change we should also fix the inconsistency that a string arg is considered HTML, but Array is considered text (and will be escaped)
  • Allow to set custom close animation from link

    • Also support (or document?) up.layer.open({ closeAnimation })
  • Consider contracting more attributes into shorthand values

    • E.g. [up-emit] and [up-emit-props] should be just one thing
    • E.g. [up-scroll] and [up-scroll-behavior] should just be one thing (but what about all the reveal attributes? reveal-snap/top/pading/max)
    • E.g. [up-transition] and [up-easing] and [up-duration] should just be one thing
  • Evtl. sollte [up-back] den letzten History-Eintrag im Root (?)-Layer nehmen?

    • Back vs. Modals allgemein betrachten
  • In the layer config, openAnimation and closeAnimation is a function, but it receives no useful args

    • Give it { layer, value }
    • Document it
  • Consider up.RenderResult#primary or up.RenderResult#fallback

    • Updating ":main" via { fallback: true } must yield #primary === true
    • So maybe #primary, #expected, #intended or similiar is a better name than #fallback
  • Rename "loading partial" to "filling partial" or similiar

    • up:partial:fill
    • up.partial.fill()
    • So "load" remains the term for sending a request
    • So we can offer [up-on-fill]
  • Consider X-Up-Redirect so we can get rid of param-transporting in unpoly-rails

    • Unpoly would track all X-Up params of request and response
  • Do we need a meta.previewing prop for compilers?

    • This would need to be a global prop because we allow arbitrary code
      • up.status.previewing
    • We could also pass it explicitly when { hello }ing from Preview functions
      • insert()
      • openLayer()
      • This would be less code than a global flag
  • Exposing the temp functions would make it easier to compose some effects without accepting an (preview) arg

    • Expose up.form.disable() (since we also expose it via Preview#disable()) => I'm not sure how useful this is in practice. Not needed in the demo.
  • Can we find a way to implement the new-task action as a server-rendered template? template = preview.cloneTemplate('#foo', { '{{text}}': params.text })

    clone = preview.cloneTemplate('#foo', { '.task-item--text': params.text }) clone = preview.cloneTemplate('#index', { 'tr': rows => rows.slice(20).forEach((row) => row.remove() })

    clone = preview.cloneTemplate('#foo') clone.querySelector('.task-item--text').innerText = params.text

    clone = preview.cloneTemplate('#index') [...clone.querySelectorAll('tr)].slice(max).forEach((row) => row.remove())

    // 169 bytes function cloneTemplate(template, processors = {}) { let result = template.content.cloneNode(true) for (let [selector, processor] of Object.entries(selectorMap)) { let matches = u.toArray(result.querySelectorAll(selector)) if (u.isFunction(processor)) { processor(matches) } else { matches[0].innerHTML = processor } } }

  • Consider publishing booleanOrString or booleanOrNumber

  • Consider waiting for custom elements to be defined

    • For focus
    • For scrolling
    • For watching
  • Support render lifecycle attributes for [up-defer] and [up-poll]

    • [up-on-loaded]
    • [up-on-rendered]
    • [up-on-finished]
    • [up-on-offline]
    • [up-on-error]
    • Right now this can be set by listening to a guardEvent and manipulating event.renderOptions
  • We often see multiple preloading entries in the log (mouseover, mousedown). Can we not log if we're already preloading?

  • Support array fields with watch()?

    • up.form.config.arrayFields = 'suffix' | 'all'
  • Does it matter that guardEvents do not set up.layer.current?

    • It should mostly be the right layer anyway, except for polling in the background or something
  • [up-validate] from a different URL

  • An a[href][up-defer] should be unclickable?

    • Remove tabindex
    • Remove pointer cursor
  • Remove isNull() and isUndefined()

    • The test is trivial, but it may be nice to not have to think aobut it
  • Allow to keep elements without remembering to mark elements as [up-keep]

    • config.keepSelectors
    • Allow { useKeep: '[up-keep], .search-input' } to keep additional elements
    • Elements can still opt out with [up-keep=false]
  • Docs: [up-transition] should document params [up-duration], [up-easing]. Same with [up-animation]?

  • Docs: up.morph() should document options.duration, options.easing. Same with up.animate()?

  • Allow up.reload() to reload multiple, potentially optional elements

    • Starting in 3.8 we could also use 3 times up.reload() and make a single request
  • Consider publishing { defaultMaybe: true } with a better name

  • Docs: Extract new doc page "Preserving state" from [up-keep] and /data#preserving-data-through-reloads

  • Docs: Installation methods may be unmaintained; Go through methods and focus on installing frontend assets

  • Docs: URLs like /up-transition should redirect to /a-up-transition

  • Should up.layer.open({ data }) set the data on the root element, not the layer element?

    • Users can still "compile" the layer element by observing up:layer:open
  • Docs: Extract /polling page from [up-poll]

  • Have a better error when Unpoly is loaded twice

    • We cannot do this when booting
    • Throw in namespace.js
  • Add a config to disable validate merging

  • Touch events can scroll the background of a drawer overlay on https://unpoly.com/

  • In a multi-step render pass, let compilers see all updated fragments

    • This would require us to delay compilation until all fragments are inserted
  • Consider whether Request#target, Request#context etc. should be setters that auto-set the corresponding header.

    • Would save code in mergeIfUnsent()
    • Would save code in setAutoHeaders()
    • We could also make #headers or #header() hallucinate new headers
      • Maybe hard since we allow write access headers[key] = value
        • Would be easier with header() and setHeader()
        • Still need to iterate over the whole thing for passing over headers to xhr
  • Consider an up:fragment:render event to modify renderOptions for all kind of passes

    • We have so many guardEvents now
    • Test that we can still modify event.renderOptions
    • Point against that name: We already have { onRendered } and that fires after DOM mutation, not before the request
    • Possibly offer originalEvent or something?
      • No! We would need to check their renderOptions for mutation. Who is interested in other events can use them.
    • Update docs: Render Flowchart
    • Update docs: Manipulate render options
  • { dismissLabel } should be able to contain HTML

    • Maybe rename to { dismissButtonContent } or something?
  • Allow variations of official layer modes

  • lightbox Layer mode

    • Where are we going to put the margin around the box, if we're not having a viewport?
  • Move custom spec helpers out of jasmine.foo() to specs.foo()

  • Unpoly Rails needs to ignore pseudo-elements

  • I think we can replace up.Rect.fromElement() with just element.getBoundingClientRect()

  • I think revalidation now loses :maybe marks. We should have more tests.

    • Case 1 => I think this is implemented
      • We're loading ".foo, .bar:maybe"
      • Server only renders ".foo"
      • Revalidation should just be for ".foo", or for ".foo, .bar:maybe"
      • It should be OK if revalidation response only contains ".foo"
    • Case 3 => I could live without this. => Or should we allow reavalidation with defaultMaybe: true ?
      • We're loading ".foo, .bar:maybe"
      • Server renders ".foo, .bar"
      • Revalidation should just be for ".foo", or for ".foo, .bar:maybe"
      • It should be OK if revalidation response only contains ".foo"
    • Case 2 => I think this is implemented
      • We're loading ".foo, .bar:maybe"
      • Server renders ".foo, .bar"
      • While we're loading .bar was removed from the page
      • Revalidation should just be for ".foo", or for ".foo, .bar:maybe"
      • It should be OK if revalidation response only contains ".foo"
  • Preserve text selection ranges when reloading / polling / revalidating

  • Should [up-poll] and up.reload() render failed responses if they match the target?

    • At least for reloading the element may actually have entered the DOM from a failed response
  • Site: Scrollbar styling https://makandracards.com/makandra/617528-chrome-121+-no-longer-supports-non-standard-scrollbar-styling

  • Per-link animation options for new layers

    • Support mutatable animation options for up:layer:dismiss, up:layer:accept
    • Parse [up-close-animation] for links that open a new layer
    • Parse [up-open-animation] as an alias for [up-animation]
  • The log message "Could not match primary target" should not appear when we're only working with fallback targets, and we happen to use the second one. E.g. first one is [up-main=modal], second one is [up-main].

  • Print a warning when we can find no better form group than the

    itself

  • Run macros (but not compilers) before history changes

    • This is super hard due to the way UpdateLayer and OpenLayer works
    • In particular we also give the guarantee that the current layer renders before other (hungry) layers
  • Give layers an [index] attribute so users don't style based on [nesting]

    • Do we give root an [index] as well?
      • We cannot use [index] here
      • [up-layer-index] would maybe a good default
        • Check vs. V4 plans
  • Docs should show DOM structure of all layer modes

  • Simplify animation API implementation with Element.animate()

    • Animation finishing could be implemented with Element#getAnimations()
    • This should also fix a regression for: Animations that fly in an element from the screen edge (move-from-top, move-from-left, etc.) no longer leave a transform style on the animated element. By @triskweline.
  • Don't allow a request payload for DELETE requests

    • Maybe make this configuratable as opinions vary here.
      • e.g. up.network.config.payloadMethods
    • Is this really important?
  • Consider parsing scroll-margin-top, scroll-margin-bottom for revealing

  • Allow [up-emit] for buttons

  • Docs: Explain how to convert JSON responses to HTML responses (discussion #562)

  • Convert .sass files to .scss

  • While morphing or destroying, disable pointer events on old element

  • Support { onLoaded }, [up-on-loaded] for polling fragments

    • Test: Can be used to skip() a polling response, polling then continues
    • Test: Can be used to preventDefault() a polling response, polling then continues
  • [up-disable] should disable links (discussion #561)

    • Within the form
    • As a stand-alone link
    • How to mark disabled links? .up-disabled ? Just [disabled]?
    • CSS: { cursor: not-allowed }
    • Also [aria-disabled=true]
    • Prevent with JS? pointer-events?
      • Also prevent keyboard focus with temporary [tabindex=-1]
    • Bootstrap already has a.disabled and users would like to take over that styling
  • Docs: Copy important up.render() options to up.layer.open() and a[up-layer=new]

    • In particular { content, fragment, url, document }
  • Look within :origin first

    • Remove similiar logic in up.FragmentProcessor: findSelector()
  • Remove [up-validate] from individual fields https://unpoly.com/up-validate#validating-multiple-fields

  • Support nonce rewriting for arbitrary attributes, e.g. up.safe_callback('124321321', '432423423')

    • But then we would need to know all the attributes we're rewriting to query them quickly
      • Or find them with XPath
    • OR we could support [up-on] with an event name and a nonce
  • Swapped body looks funny in Safari (has .up-destroying class and is grayed out with old content in inspector)

  • Allow to disable batching in validations

  • inlineStyle, setInlineStyle should work with custom properties

  • Jasmine matchers no longer get a customEqualityTesters argument

  • up.ResponseDoc: Only re-discover the origin when match is 'region'

  • Async compiler functions

    • See separate doc
    • Don't need to delay this until V4 as destructors no longer throw
  • Is the [up-keep=false] pattern good to keep?

    • E.g. for flashes: We could interrupt a keep chain this way, but then the element can never again be keepable => It's the same for polling
  • consider having dev builds with debug terser

  • Docs: /accessibility page

    • But where does it go?
    • Top-level?
  • 2024: Replace up.error.emitGlobal() with window.reportError()

  • Publish up.util.sprintf()

    • But rename it to something else, as sprintf() is something else
  • Docs: Custom input elements

    • Have your custom element expose { name } and { value }` properties (AFAIK Shoelance components already do)
    • Also { disable }
    • Make Unpoly aware of custom elements by pushing a selector to up.form.config.fieldSelectors.
    • Make Unpoly aware of custom submitt buttons by pushing a selector to up.form.config.submitButtonSelectors.
    • Limitation: One value per field. Checks for groups (.checked and .selected) are still hard-coded
  • Test that system compilers always run before user compilers => We already have macros if compilers need to use others?

  • Concepts [up-feedback] and [up-background] are overlapping

    • Should feedback: false imply background: true ?
    • Should we generalize the feedback option?
      • { feedback: ['classes', 'progress', 'custom'] }
        • But I always want classes?
  • Message when unknown target: Revalidating cached response for target "undefined"

  • Extend [up-switch] with [up-disable-for="..."] [up-enable-for="..."]

    • This is really confusing with [up-disable]
    • Or should we have an [up-switch-for] and [up-switch-effect]?
  • up:feedback:start / up:feedback:stop

    • On the layer, not an individual element
    • Needs to have reference to origin and targetElements
      • Must be the same element in :start / :stop, even if the DOM has changed in between => With .up-validating we have different points where feedback starts and ends.
      • This class does not exist. It was an idea detailed further down. => Or we could have a single up:feedback event with a promise for the duration
  • Do we want a preventable up:request:reuse event?

    • Maybe even :reused since there is no :loaded for cached requests
  • Experiment with property mangling vs. public API

    • Possibly do a unpoly.experimental-min.js ?
    • If we could test a minified version we could publish this
      • Do we really think about this when publishing?
      • This would need to be part of the regular build
  • Issue with splitting Immediate-Child-Selectors: https://makandra.slack.com/archives/C02KGPZDE/p1659097196752189

  • Can we get rid of the afterMeasure() callback?

  • Support { scroll: 'keep' }

    • Similiar to { focus: 'keep' }
    • Store scrollTops around a viewport in UpdateLayer
    • Possibly refactor tops to up.ScrollTopsCapsule
  • Check that the target (and all non-successful target attempts) are visible in the log

    • Possibly highlight
  • Do we want to support or in targets?

    • Is there any case other than [up-target], where we already have [up-fallback] ?
  • Should animations force painting?

    • I don't understand how the transitions work when we set both the first and final frame in the same JavaScript task
  • Maybe auto-submit should not navigate by default

    • How to restore this?
    • up-navigate ?
    • up-watch-navigate ?
    • up-autosubmit-navigate ?
    • Is it cool that search results would no longer get a URL update?
  • Does [up-back] use the previous layer location?

  • There was a case where { origin } should look inside an origin: up.render('.day_menu_dish_autocomplete .day_menu_dish_autocomplete--suggestions', { origin: titleInput, url: '/day_menus/suggestions' })

  • Expose up.fragment.config.renderOptions

    • Now that we have some opinion about the defaults { abort: 'target', focus: 'keep', revalidate: 'auto' }, users may want to deactivate
  • Try to have a 'hash' strategy in overlays

    • Also update doc page /focus
  • Split JavaScript => Do this after asset reconciliation

  • input.setCustomValidity() should block submission

  • Replace symlinks in dist/ with copied files

    • Not trivial, see hk/copy-dist-artifacts
  • Maybe a way to mark elements as keep before rendering?

    • This would also be up:fragment:loaded
    • Maybe a render option { useKeep: [....] }
      • With additional fragments to keep
      • Could be set both in initial render and in up:fragment:loaded
      • Would not require an [up-keep] on the other side
  • Consider keepSelectors and noKeepSelectors

    • Now that [up-keep] no longer has a value?
      • Note that we do have [up-keep] hardcoded in multiple places
  • Should we offer a way to manually add etags?

    • E.g. up.on('up:request:loaded', ({ response }) => { response.etag ||= sha1(response.body) })
    • Should this even be a default? => People can already set response.headers['ETag'], although that's not documented
  • Matching in the region of ancestors should use subtree, not just descendants of the ancestor

    • In a form we should always be able to say form:has(:origin) .descendant, even if the origin turns out to be the form itself
      • But :has() does not work like that?
  • [up-on-accepted-reload], { onAcceptedReload }

  • [up-on-accepted-validate], { onAcceptedValidate } (aber hier brauche ich immer einen param)

  • Consider removing all tagnames from public selectors

    • We already had to remove tag names of multiple-use attrs like [up-watch]
    • current
      • a[up-follow]
      • a[up-instant]
      • a[up-preload]
      • form[up-submit]
      • a[up-accept]
      • a[up-dismiss]
      • a[up-layer=new]
      • a[up-transition] __
      • form[up-transition] /
      • a[up-alias]
      • a.up-current
      • a[up-emit]
      • a[up-back]
    • deprecated
      • a[up-close]
      • a[up-drawer]
      • a[up-modal]
      • a[up-popup]
  • Can layer objects nullify their { element, tether } once closed? => This may cause async JS to throw, if that JS wants to go through the layer shortly after closing => How about we do this 10 seconds after { onFinished } or so?

  • It may be nice if guardEvents see the change's getPreflightProps().fragments

    • Either lazy with Object.definePropery() or, if we find that we're going to call getPreflightProps() anyway, just call it.
    • Can we memoize getPreflightProps() in FromURL ?
  • up.validate() always submits to the first submit button => Is this a bug or a feature that we use the same behavior as submit would?

  • When a layer reaches a close condition, should we still render [up-hungry][up-if-layer=any] elements in another layer?

    • Would be practical for flashes
    • Would be weird for API. Render events flying afterwards, we cannot communicate a RenderResult.
  • When opening a new layer, we should update [up-hungry][up-if-layer=any] elements => This is not trivial as OpenLayer cannot work with multiple steps yet => Maybe we can do a "secret UpdateLayer pass" once the layer has opened.

    • We would need to merge RenderResult objects
  • Custom attributes are not copied into [up-expand]

    • up.link.config.expandableAttributes ?
      • can also include regexp
        • maybe reuse matcher logic for badTargetClasses
      • what if you need to copy an individual class, not an attribute?
        • up:link:expanded event for custom handling?
  • up.link.config.expandableAttribute (attribute, element)

    • The element will always be a link
  • Support custom expire times via Cache-Control: stale-while-revalidate

    • Print a warning when we're discarding any other Cache-Control header format
  • Test and document [up-href]

  • Polling should automatically restart when the tab is re-focused

  • A validating fragment should get a .up-validating class

    • Group under up.feedback
    • Maybe we can have a private API
      • { feedbackLoadingClass: 'up-validating', feedbackActiveClass: false } ?
      • { feedback: { loading: 'up-validating', active: false } } ?
      • With history we have separate options { title, location }
  • Consider renaming up.fragment.config.navigateOptions to just up.fragment.config.navigate

    • There is precedence in up.layer.config.overlay
  • Firefox: Focus loss after disable is not always detectable synchronously

    • Force Repaint does not help
    • setTimeout() helps (wait for next render?)
    • We fixed this in up.form.disableWhile(), but it may still be broken for up.fragment.config.autoFocus options suffixed with "-if-lost"
  • Consider whether validation requests should be background requests by default

    • We should also have [up-watch-background]
  • Why does [up-validate=form] target the first form for some users?

Documentation

  • Should we offer a { placement: 'merge' } to merge children?

    • By selector?
    • How would that relate to recursive merging?
    • We don't need it for flashes, [up-on-keep] suffices here
      • [up-on-keep] can already support merging, morphing, etc.
        • However it's impractical to use it for regular fragment updates, you'd want .target:merge or something.
  • Example for a custom overlay

  • Activating custom JavaScript

    • (Currently sitting in up.compiler())
  • Rendering from strings

    • { document }
    • { fragment }
    • { content }
  • Preloading

    • (Currently sitting in a[up-preload])
    • On Hover
    • Programmatically
      • Example: Preload next/prev
  • Polling

    • (Currently sitting in [up-poll])
  • Options and defaults

    • Everything is opt-in
    • Navigation enables a set of new defaults
      • Navigation options are the only opinioniated defaults that are opt-out
    • config options
    • auto-options
    • Most options in up.render() can also be set via an attribute
      • JavaScript options override HTML attributes
      • If we cannot serialize an option into an attribute, you can use event.renderOptions in up:link:follow, up:form:sumit
    • Explain that you can often override renderOptions in event handlers
      • This is already explained in /render-hooks
  • Background requests

    • Background requests deprioritized over foreground requests.
    • Background requests also won't emit up:network:late events and won't trigger the progress bar.
    • Background requests are promoted to the foreground if they are a cache hit for a new, non-background request

Icebox / Tar pits

  • Allow late registrations of compilers and macros without priority => OK for compilers, but what about macros? They have an intrinsic priority (before all compilers)

  • Consider whether up.validate() promises should wait until no more solutions are pending => We would need to merge RenderResult#target in some meaningful way

  • Rename "finished" to "concluded"

  • Should up:click set up.layer.current ?

    • It would be more convenient, but it's only relevant for popups or backdrop-less modals. This is rare.
  • New onTransitioned() callback to take some load off from onFinished()

  • Move scroll positions into state

    • This gets rid of the other up.Cache usage
    • This may mean we need to lose up.viewport.restoreScroll() and { scroll: 'restore' } and { saveScroll: true }
      • Losing { scroll: 'restore' } is super sad :( => Maybe revisit when the Navigation API is supported
  • Improve polling in the background

    • It would be great to not have a timeout running while we're in the background or offline
    • It would be great to not wait up to 10 seconds when we're re-focused or regain connectivity
      • Are timeouts really paused or do they just not fire until re-focus?
      • Mobile Chrome seems to reload old tabs automatically, test this!
  • Elemente mit [up-hungry][up-layer=any] müssten wir eigentlich auch austauschen, wenn wir einen neuen Layer öffnen

    • OpenLayer kann aber gar nicht mit mehreren Steps umgehen
  • can badResponseTime be a function that takes a request? => Yes, but not trivially

  • Consider using Cache-Control: stale-while-revalidate=<seconds> to indicate how long we can use a response

    • But it could be paired like this: Cache-Control: max-age=1, stale-while-revalidate=59
    • But then again we ignore Cache-Control for all other purposes
      • E.g. Cache-Control: no-store
      • E.g. Cache-Control: max-age
      • How would Cache-Control: no-cache (equivalent of max-age=0 must-revalidate) work in connection with up.fragment.config.autoRevalidate ?
    • Maybe do a bigger workover of Cache-Control?
  • Do follow links with [target=_self]

  • up:click forking could print a warning when an a[href] is instant, but not followable

  • Is it weird that up.layer.affix appends to the first swappable element instead of the contentElement?

    • It's actually more like "appendableElement"
    • Maybe offer up.Layer#append
  • Consider exposing up.layer.contentElement

  • Do we want a shortcut macro for this:

    • It's weird for users who don't target the input. They may expect to just override the event.
    • We would need to make keepable selectors configurable to include this one
  • We could support this with more pseudo-class selectors like :form-group and :submit-button

    • :submit-button is hard to build origin-aware => It could just be a substitution with :is() / :-moz-any() & :-webkit-any()
    • :form-group is also supper hard to support in a selector like ".foo, :form-group, :bar" due to the way we hacked :has()
      • :has() is still behind a flag in Chrome and no Firefox support
  • Introduce boundaries or "softly isolated zones"

    • The idea started with: Should fragment lookups with an { origin } within a form prefer to look within the form?
      • Also related to unpoly/unpoly#197 , which would no longer work now that a form submission's orgin is the submit button instead of the form element
    • E.g.
      • Lookups within prefer to match within the boundary
      • It's a new fallback target
        • Also for errors
      • up.fragment.config.boundaryTargets = ['[up-boundary]', 'form', ':main']
      • Is this also controlled by { fallback }?
      • Maybe identification using [up-boundary=123]
        • But don't enforce this, it's not a great auto-target
      • Should this rather be [up-zone]?
        • If we ever make fully isolated containers we would call them frames
      • We could also offer :zone as a selector
      • Would we still offer { target: '.container .child' }?
        • Would we offer { target: ':zone .foo' }, since it's really the same as { target: '.foo' } ?
      • Is this a repetition of "fragment needs to know whether it is used as component or main target"?
        • We would need to fix infinite looping in expandTargets()
        • It would be nice to disable history in a zone
          • but then it's not usable as a main target
          • Disable history in a container?
            • It's weird to nest multiple containerish elements
          • => This is really already solved through { history: 'auto' }, which only updates history if updating :main
  • Rendering: allow { scrollBehavior: 'smooth' } when we're not morphing

    • Could we even allow this when morphing?
  • New up.render() options to clone from a template

    • { documentTemplate }, { fragmentTemplate }, { contentTemplate }
    • Separate doc page "Rendering from local content"
    • Fail when template cannot be found
    • But what if I really need to re-use an existing element that is then placed back into the body, like in WB?
  • Consider implementing an abortable up:navigate event

    • This would be the first feature that goes beyond "navigation is just a preset"
    • People might expect history changes to trigger this
    • Maybe think about this more
  • Replace up.hello() and up.script.clean() with MutationObserver()

  • Do we want to serialize all actions in a form?

    • up-sequence="form"
    • This would need to abortable on submit => Would be handled by existing { solo: 'target' } IF there is a request
    • This would need to abortable on form destroy => Would be handled by existing { solo: 'target' } IF there is a request
    • => This would need to be handled by up.Queue, or else there would be nothing to abort
    • => It is not sufficient to have up.form.sequence(..., callback)
    • => We would need to do something like { sequence: ElementOfSubtree }
    • => Before picking a new request, make sure no existing request exists
    • What about our old idea: { order: 'abort target', order: 'abort form', order: 'after form', order: 'after selector' } => How to say "after ElementObject" ?
    • Who would fetch the element that is 'form' or 'selector'? => up.Change.UpdateLayer#getPreflightProps(), which already loads targetElements()
    • What would we do if both was given, e.g. { solo: true, sequence: 'form' }
      • Do we forbid the combination?
      • Do we first abort, then do a squence?
      • Do we first wait, then abort? => I think this, but this also means our { solo } handling is in the wrong place. It must move to the queue.
    • Does { sequence: 'form' } also queue local content, like { solo } ?
    • We could do something like up.LocalRequest, but then local updates would no longer be sync!
    • We could not support { sequence } for local updates => YES
    • What about cached content with { sequence }?
      • We could do queue.asapLocal() which immediately executes unless there is { sequence }
    • How does queue resolve a sequence?
      • Before dispatching a request with { sequence }
      • Check if we have current requests with { sequence }
      • If any of the other requests's sequence contains our or if any other sequence is contained by ours, don't dispatch
  • Guard Events for Rendering could have a Promise for "done"

    • Is this better than setting event.renderOptions.onFinished()?
      • Yes, because onFinished may not fire for fatals or prevented up:fragment:loaded
    • How would this work together with future up.RenderRequest?
    • How would this work together with "local changes are sync"?
  • Consolidate [up-validate], [up-switch] and [up-watch] into a tree of form dependencies

    • This way we can selectively disable parts of the form
  • Functionality that checks for isDetached() should probably also check for .up-destroying

  • Improve { focus: 'keep' } so it focuses the former form group if we lose focus

    • This may be easier said than done
      • we would need to remember the original form group before the swap in the FocusCapsule
      • re-discover the form group in the new HTML
      • check that the form group is a closer match than target-if-lost
      • come up for a better name for the option (target-if-lost)
  • New event up:request:solo ?

  • Consider delaying appending of new layer elements until we have constructed all children unpoly/unpoly#314

  • Publish { onQueued }

    • We're currently only using onQueued to get the request of a rander job, so we can abort it
      • This may be removed!
    • More canonic would be if RenderJob had an abort() method
  • Wir aborten bereits laufende [up-validate] wenn das Formular submitted, wird, aber laufende Watcher-Delays warten können danach noch Dinge tun

    • Wie wäre "submit stoppt das delay"? Evtl. Warnung ausbauen: "Will not watch fields without [name]"
  • [up-emit] auf Buttons erlauben

  • Beim Schließen des Modals prevented jemand up:layer:dismiss, und dann steht "Abort Error: Close event was prevented" in der Konsole.

    • Wollen wir das schlucken?
    • Zumindest bei ui-elementen wie [up-dismiss] ?
  • DestructorPass sammelt zwar Exceptions, aber wirft am Ende. Wer fängt das dann? Der Wunsch wäre, dass das drumrumliegende up.destroy() noch zu Ende läuft, dann aber up.CompilerError wirft.

  • ConstructorPass sammelt zwar Exceptions, aber wirft am Ende. Wer fängt das dann? Der Wunsch wäre, dass das drumrumliegende up.render() oder up.hello() noch zu Ende läuft, dann aber mit up.CompilerError rejected.

  • Update "Long Story" Slides with new API

  • Doc page about "Fragments from local HTML"

    • link from [up-document], [up-fragment], [up-content], { document, fragment, content }.
  • Warn when registering compiler in [up-] namespace

  • Consider documenting errors

    • But what would be the @parent ?
    • up.CannotCompile
    • up.CannotMatch
    • up.Offline
    • up.AbortError
      • has { name: 'AbortError' }
  • Should the old "clear" be "expire" or "evict"? => We really want to push our new defaults for both => I think it should be "expire". Most users set a lower expire time.

  • remove up.util.flatMap() => No, we need it to flatMap array-like objects (e.g. arguments)

    • Do we want to move to saveState() / restoreState()?
      • I think we want to keep the [up-focus] and [up-scroll] options separate.
        • E.g. we want to focus the main element, but reset scroll.
        • This could also be fixed by revealSnap ?
      • These are eerily similar:
      • What would be the name for such an attribute?
        • [up-spotlight]
        • [up-viewport] (classes with [up-viewport]
        • [up-highlight]
        • [up-locus]
        • [up-present]
        • [up-light]
        • [up-shine]
        • [up-state] (seltsam: up-state=".element")
        • [up-point]
        • [up-pinpoint]
        • [up-attention]
        • [up-focus] also scrolls?
        • [up-show]
        • [up-view] => I think power users want to control this separately => Also we need to call it at different times => Also the auto options work differently, e.g. if there is an [autoscroll] element in the new fragment => We might offer a shortcut like [up-view] and [up-save-view] as a shortcut to set both at once
  • Replace up.rails by accepting methods / conform from data attributes in options parser => This wouldn't work in scenarios where both Rails UJS and Unpoly were active

  • No longer send X-Up-Location with every response => No we should keep sending it, as this excludes redirect-forwarded up-params

  • Consider reverting: up:request:late: Consider the time a promoted request was loading in the background => For this we would need to track when a request was promoted to the foreground

  • Do we trigger onFinished when preloading? => No, users can use the promise or onLoaded()

  • Reconsider how many lifecycle callbacks we want to parse from links

    • Benchmark up.link.followOptions()
      • console.time('parse'); for (var i = 0; i < 10000; i++) { up.link.followOptions(link) }; console.timeEnd('parse')
      • VM481:1 parse: 1091.6689453125 ms => It takes 0.1 ms => This is not a performance issue
  • Find a scenario where it's better to read the etag from [etag] instead of response.etag

    • This should not matter for revalidation after a swap
    • When reloading an arbitrary fragment, an earlier response may not be available
  • Test if browsers honor cache keys for XHR requests

    • Yes, it honors Cache-Control: max-age=...
    • We can override it for fetch()
  • With our long cache eviction background tabs could hog a lot of memory => No, since we also limit the number of cache entries to the cache never exceeds some MB

  • up.link.cacheState(link) to people can build .offline classes themselves => Users can already use up.cache.get => We could clean up Request#state and publish this for more goodness

    • Return any known up.Respone for the given link
      • It already has useful properties { evictAge }, { expireAge }?
      • We may eventually offer up.Response#revalidate()
    • Return null while the request is in flight => Or do we want an up.CacheState that also returns here?
    • It will be hard to do implement this without actually calling up.link.follow() and up.render(), since e.g. the target choice is hard and part of the cache key
      • Make this an early return in up.Change.FromURL, like with options.preload
  • Test if we can preserve element.upPolling (or at least the { forceState }) through up.reload({ data }) => It's hard since there's the case that the server no longer responds with [up-poll], but we want to keep polling when forceStarted

  • Should we delete options.data if a fallback is loaded?

    • This would also be true for other options, like a selector in focus/scroll
    • We would sometimes need to guess, e.g. { focus: ':main' } may also be a good default for a fallback => I think this is not a real case since we're not going to use { data } together with { fallback }
  • Consider moving [up-etag], [up-time] and related functions to up.protocol => While there's some merit to that, we would need to rename up.fragment.etag() to up.protocol.fragmentETag() etc. => What's with up.fragment.source()?

  • [up-hungry][up-placement] => This only makes sence when we have some form of deduping

  • What do we log when no replacement target is available? => up.render() throws an error

  • Reconsider why we don't call onRendered() for empty updates

    • Pro: Call it for every pass
      • We do still update scroll and focus, even for empty responses
        • Maybe even location?
      • We will update more in the future with head merging
      • There is no other hook for "after $things changed"
        • But nothing changed after an empty render? At least not in the DOM.
      • We can simplify docs for onRender and up-on-render
    • Con: Keep it like now
      • If we render without fallback we still need to check if up.RenderResult#fragment is defined
      • It will be super rare that the first render pass does not return anything.
        • However, we would always get empty onRendered calls for revalidation => Keep it, but improve docs
  • Maybe ship empty unpoly.es5.js und unpoly.es5.min.js that just say to use ES6 => Not worth the hassle

  • Does it make sense to have onKeep in render options? => I find it confusing to have both { onKeep } and { useKeep } in the same functions => Maybe we can find a way to merge it with { useKeep }

  • Consider up.layer.config.isolateLabels => Wait until there is a use case => Users can always just intercept click themselves

  • Consider [aria-haspopup] => This would require a compiler automatically setting this for [up-layer=new] links (and all shortcuts) => Don't do this for performance. Delegate to apps.

  • Should config.autoCache allow to cache error responses? => That's a hard question to answer

  • Get rid of response.request (which contains references to a layer), response.xhr ? => This is hard because up.cache.expire() expires requests, not responses. Hence up.Response delegates { expired } to its response.

  • Can we allow await in Callbacks?

    • new AsyncFunction()
    • This would not work trivially with the postprocessing in up.NonceableCallback
      • At least we would need to detect use of await
  • Returning 'auto' for default would be a good way to override configs with exceptions

    • request.url.endsWith('/edit') ? false : 'auto'
    • Since this already the 'autoMeans' config we cannot return 'auto' here
  • Replace u.flatten() with Array#flat() => We keep array-related utils because ours work with non-Array lists and iterators

  • Replace u.flatMap() with Array#flatMap() => We keep array-related utils because ours work with non-Array lists and iterators

  • Now that compilers have the meta arg it should be possible to give up.RenderResult new { request, response } props => Wait until we have a use case for this

  • Test synthetic ETag

  • When rendering uses elements, do we set [up-time] and [up-etag] on these wrappers?

    • We cannot really do better here, since up-wrapper children cannot be reloaded
  • Move isRenderableLayer() logic to LayerLookup

    • Consider having LayerLookup#getAll() throw if results are blank => We have a lot of code / specs that work with closed layers and sometimes normalize the layer through up.layer.get(), and now get undefined. All of this code would fail with this change.
  • Terminology for notifications

    • [up-alerts] (Bootstrap, Tailwind UI, MUI, negative connotation in Material etc.)
    • [up-flashes] (Rails, Primer [although they also use Toast])
    • [up-notifications] (Bulma, good for both success and failure, long word, may also mean passive notifications)
    • [up-messages] (too generic)
    • [up-snackbars] (Material, uncommon)
    • [up-toasts] (uncommon, also often a "boxy" kind of notification)
    • [up-callouts] (Foundation, uncommon)
  • Do we want to support changing the renderOptions in up:fragment:hungry? In that case { renderOptions } need to be { nonHungryRenderOptions } or something => We can rename the options then. If we do support this we would no longer have { renderOptions }, we would use { targetRenderOptions, hungryRenderOptions }

  • Instead of ResponseDoc#commitSteps(), could up.radio.hungrySteps() just re-compress steps with uniqBy(steps, 'selector')? => There is an edge case where different selectors could match the same elemnent

  • Introduce up:history:restore event

    • With { renderOptions }
    • Note that we used to emit this event in the past, so fix unpoly-migrate
    • Preventable for custom history handling => We already have this in up:location:restore
  • Reduce render callbacks

    • Motivation
      • It is too hard to do something when the render job settles. There is onRendered, onFinished, onError etc. However there are always cases that are covered by no callback.
      • We need to maintain and communicate two styles of callbacks
    • Expose { renderJob } on guard events
    • New event up:fragment:render / [up-on-render] that gets { renderOptions, renderJob }
      • There is no need to offer { onRender }, as the return value of up.render() is already a RenderJob
    • Deprecate callbacks
      • { onFinished }
      • { onRendered }
    • Update docs
  • Do we need a way to show a spinner for a while?

    • Maybe, but you can already do in CSS: .container:has(.up-active) .spinner { ... }
  • Do we really need to abort requests in LinkPreloader? => Yes, aborted requests can be seen in the network tab. We also found a shorter way to write it.

  • Allow the [wants-menu] compiler to be implemented without JS

    • We would need something like [up-defer][up-unless-already-there]
      • Or even a follow option?
      • Should we just check, or "only revalidate"?
      • Or should it be the default behavior? => This is really hard to do right
  • Do we dare to restore history using up.render() instead of up.navigate()? => We override as much as want to re-use

  • Do we want [up-skeleton=] ?

    • We would need to decide what to do within overlays
      • Show skeleton within overlay?
      • Animation
      • Different skeleton => Later
  • Consider renaming [up-feedback] to something else

    • Maybe always have classes?
      • This would mirror the exception of background, which is also false by default => Delay this until we need the setting for something else
  • Consider offering a { renderLayer } prop to guard events

    • This would make it easier to e.g. auto-add a preview for new layers in up:link:follow
    • Do we need to give a better name to { layer } so people understand it is not the origin layer?
      • There is { targetLayer }, but that could be confused with event.target (which happens to be the origin layer!)
      • { changeLayer }
      • { updateLayer }
      • { targetedLayer }
      • { planLayer }
      • { insertLayer }
      • { renderLayer }
    • Update docs for guardEvents
      • up:link:follow [yes]
      • up:form:submit [yes]
      • up:link:preload [yes]
      • up:deferred:load [makes no sense]
      • up:form:validate [makes no sense]
      • up:fragment:poll [makes no sense] => No, this becomes very complicated very fast
  • Consider whether { skeleton } is flexible enough for public API

  • Deprecate flatten() in favor of Array#flat(), flatMap() in favor of Array#flatMap()

    • No, we use this a lot of non-array values, in particular NodeLists
  • Do we want to keep { feedback }, [up-feedback] as an option, or applied it always?

    • It's already a navigation default
    • For programmatic up.render() calls, it's already activated by passing { origin } => We can decide this later
  • Do we want Preview#affix?

    • Check if it helps with the demo => Not for now. I'm myself moving away from affix.
  • Previews should know about placement?

    • Unsure. Later.
  • Rename "preview" to "teaser"?

    • => It's too confusing with { placeholder }
  • Test that re-attaching an helloing an destroyed element can be compiled again

    • This is not trivial because destructors would need to clean up Element#upAppliedCompilers
  • Move config.progressBar to up.status ?

    • Is it weird that up:network:late and up:network:recover events are still in the up.network package?
    • We also keep [up-disable] under up.form => Keep it there
  • What if there is user input in the reverted preview?

    • E.g. we want to show the "Edit task" input instantly, but keep input as we revert with the real thing => Preview fns could manipulate event.renderOptions => If we already have a template, we could just render a template with [up-fragment] and not make a request
  • Think whether we want to support JSON => HTML preprocessing

    • This would something like
    • This would need to disable history
  • Always run callbacks with <script> so users can use strict-dynamic => This would work, but we would violate the spirit of a CSP, even with strict-dynamic => This would execute an attacker's [up-on] callback => Don't do this!

  • Also have a up:field:switch (up:form:switch?) event

    • preventable? maybe
    • example: [readonly]
    • Expose the dependent container as { target }
    • expose { values } array, or just { field } => No, we need to selector to detect new fields
  • Make validations not expire the cache

    • This may be hard to do when we batch multiple POST requests and one of them validates
  • Consider a way to "panic" out with a developer error

    • Replace entire
    • Accept that JS stays loaded
    • Reset Unpoly so links aren't followed
    • Ask ED if this would help his case => No, he wanted to show a user-facing error that keeps that layout intact => Maybe improve card by setting document.documentElement.innerHTML = response.text => The DOM parser would discard the duplicate
    • Could this be X-Up-Target: html from the server?
      • Maybe also close layers?
      • Maybe X-Up-Panic: true => This does not work with nonce-based CSP, since BetterErrors does not use nonces
  • FormValidator: Test that we remove manually detached elements => Comment says: We do not remove solutions for which the origin no longer exists, as a delayed solution's { target } may still require an update. => Keep it that way

  • When no previous location is known, up-back could do history.back() => No, this might navigate away to another site

  • up:fragment:rendered event => This is a lot like up:fragment:inserted => Wait until we have more use cases

  • 3.11. change: When a POST request redirects to a GET route, that final GET request is now cached. => This now causes flashes to be cached => Document a mechanism to delete flashes? => Maybe offer meta.willRevalidate ? => We documented a workaround

  • Can we make a mutated event now? => We could emit a :mutated event after a change but then programmatic calls of up.hello() and up.destroy() would not emit that event

About

Tasks and design notes for Unpoly

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published