added topic traversal (Read New/Next Topic), untested
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Amsterdam Web Communities System
|
||||
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// Package ui holds the support for the Amsterdam user interface, wrapping Echo and Jet templates.
|
||||
package ui
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"git.erbosoft.com/amy/amsterdam/database"
|
||||
"github.com/bits-and-blooms/bitset"
|
||||
)
|
||||
|
||||
// TopicTraverser is the data structure that allows us to navigate to "next" topics.
|
||||
type TopicTraverser interface {
|
||||
FirstTopic() int16
|
||||
NextTopic(int16) int16
|
||||
ClearTopic(int16)
|
||||
UnclearTopic(int16)
|
||||
}
|
||||
|
||||
// topicTraverser is the internal data structure that implements TopicTraverser.
|
||||
type topicTraverser struct {
|
||||
lock sync.RWMutex
|
||||
topics []int16
|
||||
active *bitset.BitSet
|
||||
}
|
||||
|
||||
// NewTopicTraverser creates the traverser data structure from the topic listing.
|
||||
func NewTopicTraverser(topics []*database.TopicSummary) TopicTraverser {
|
||||
trav := topicTraverser{
|
||||
topics: make([]int16, 0, len(topics)),
|
||||
active: bitset.New(uint(len(topics))),
|
||||
}
|
||||
p := 0
|
||||
for _, t := range topics {
|
||||
if t.Unread > 0 {
|
||||
trav.topics = append(trav.topics, t.Number)
|
||||
trav.active.Set(uint(p))
|
||||
p++
|
||||
}
|
||||
}
|
||||
return &trav
|
||||
}
|
||||
|
||||
// FirstTopic returns the first unread topic number in the traverser.
|
||||
func (trav *topicTraverser) FirstTopic() int16 {
|
||||
trav.lock.RLock()
|
||||
defer trav.lock.RUnlock()
|
||||
i, b := trav.active.NextSet(0)
|
||||
if b {
|
||||
return trav.topics[i]
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// NextTopic returns the unread topic number in the traverser after the specified one.
|
||||
func (trav *topicTraverser) NextTopic(cur int16) int16 {
|
||||
trav.lock.RLock()
|
||||
defer trav.lock.RUnlock()
|
||||
seeking := false
|
||||
for i, v := range trav.topics {
|
||||
if v == cur {
|
||||
seeking = true
|
||||
} else if seeking && trav.active.Test(uint(i)) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return trav.FirstTopic() // look from the beginning
|
||||
}
|
||||
|
||||
// ClearTopic clears the specified topic number from the traverser.
|
||||
func (trav *topicTraverser) ClearTopic(num int16) {
|
||||
trav.lock.Lock()
|
||||
defer trav.lock.Unlock()
|
||||
for i, v := range trav.topics {
|
||||
if v == num {
|
||||
trav.active.Clear(uint(i))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UnclearTopic restores the specified topic number to the traverser.
|
||||
func (trav *topicTraverser) UnclearTopic(num int16) {
|
||||
trav.lock.Lock()
|
||||
defer trav.lock.Unlock()
|
||||
for i, v := range trav.topics {
|
||||
if v == num {
|
||||
trav.active.Set(uint(i))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -24,13 +24,13 @@
|
||||
class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded text-sm font-medium transition-colors">
|
||||
{{ if isTopicHidden }}Show Topic{{ else }}Hide Topic{{ end }}
|
||||
</a>
|
||||
{{ if false }}{* TODO *}
|
||||
<a href="/TODO"
|
||||
{{ if isset(urlNextTopic) }}
|
||||
<a href="{{ urlNextTopic }}"
|
||||
class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded text-sm font-medium transition-colors">Next Topic</a>
|
||||
{{ if false }}{* TODO *}
|
||||
<a href="/TODO"
|
||||
class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded text-sm font-medium transition-colors">Next & Keep New</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if isset(urlNextKeepNew) }}
|
||||
<a href="{{ urlNextKeepNew }}"
|
||||
class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded text-sm font-medium transition-colors">Next & Keep New</a>
|
||||
{{ end }}
|
||||
<a href="/TODO"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded text-sm font-medium transition-colors">Find</a>
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
Add Topic
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ if isset(urlReadNew) }}
|
||||
<a href="{{ urlReadNew }}"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded text-sm font-medium transition-colors">
|
||||
Read New
|
||||
</a>
|
||||
{{ end }}
|
||||
<a href="/TODO/find"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded text-sm font-medium transition-colors">
|
||||
Find
|
||||
|
||||
Reference in New Issue
Block a user