mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-11 21:10:26 +00:00
Support recursive renaming
This commit is contained in:
parent
662a52296c
commit
62fcd6d9bc
@ -39,7 +39,11 @@ func handlerRenameConfirm(w http.ResponseWriter, rq *http.Request) {
|
||||
hyphaData, isOld = HyphaStorage[hyphaName]
|
||||
newName = CanonicalName(rq.PostFormValue("new-name"))
|
||||
_, newNameIsUsed = HyphaStorage[newName]
|
||||
recursive bool
|
||||
)
|
||||
if rq.PostFormValue("recursive") == "true" {
|
||||
recursive = true
|
||||
}
|
||||
switch {
|
||||
case newNameIsUsed:
|
||||
HttpErr(w, http.StatusBadRequest, hyphaName, "Error: hypha exists",
|
||||
@ -54,7 +58,7 @@ func handlerRenameConfirm(w http.ResponseWriter, rq *http.Request) {
|
||||
HttpErr(w, http.StatusBadRequest, hyphaName, "Error: invalid name",
|
||||
"Invalid new name. Names cannot contain characters <code>^?!:#@><*|\"\\'&%</code>")
|
||||
default:
|
||||
if hop := hyphaData.RenameHypha(hyphaName, newName); len(hop.Errs) == 0 {
|
||||
if hop := hyphaData.RenameHypha(hyphaName, newName, recursive); len(hop.Errs) == 0 {
|
||||
http.Redirect(w, rq, "/page/"+newName, http.StatusSeeOther)
|
||||
} else {
|
||||
HttpErr(w, http.StatusInternalServerError, hyphaName,
|
||||
|
69
hypha.go
69
hypha.go
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/bouncepaw/mycorrhiza/gemtext"
|
||||
"github.com/bouncepaw/mycorrhiza/history"
|
||||
"github.com/bouncepaw/mycorrhiza/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -52,25 +53,61 @@ func (hd *HyphaData) DeleteHypha(hyphaName string) *history.HistoryOp {
|
||||
return hop
|
||||
}
|
||||
|
||||
// RenameHypha renames hypha from old name `hyphaName` to `newName` and makes a history record about that.
|
||||
func (hd *HyphaData) RenameHypha(hyphaName, newName string) *history.HistoryOp {
|
||||
func findHyphaeToRename(hyphaName string, recursive bool) []string {
|
||||
hyphae := []string{hyphaName}
|
||||
if recursive {
|
||||
hyphae = append(hyphae, util.FindSubhyphae(hyphaName, IterateHyphaNamesWith)...)
|
||||
}
|
||||
return hyphae
|
||||
}
|
||||
|
||||
func renamingPairs(hyphaNames []string, replaceName func(string) string) map[string]string {
|
||||
renameMap := make(map[string]string)
|
||||
for _, hn := range hyphaNames {
|
||||
if hd, ok := HyphaStorage[hn]; ok {
|
||||
if hd.textPath != "" {
|
||||
renameMap[hd.textPath] = replaceName(hd.textPath)
|
||||
}
|
||||
if hd.binaryPath != "" {
|
||||
renameMap[hd.binaryPath] = replaceName(hd.binaryPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
return renameMap
|
||||
}
|
||||
|
||||
// word Data is plural here
|
||||
func relocateHyphaData(hyphaNames []string, replaceName func(string) string) {
|
||||
for _, hyphaName := range hyphaNames {
|
||||
if hd, ok := HyphaStorage[hyphaName]; ok {
|
||||
hd.textPath = replaceName(hd.textPath)
|
||||
hd.binaryPath = replaceName(hd.binaryPath)
|
||||
HyphaStorage[replaceName(hyphaName)] = hd
|
||||
delete(HyphaStorage, hyphaName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RenameHypha renames hypha from old name `hyphaName` to `newName` and makes a history record about that. If `recursive` is `true`, its subhyphae will be renamed the same way.
|
||||
func (hd *HyphaData) RenameHypha(hyphaName, newName string, recursive bool) *history.HistoryOp {
|
||||
var (
|
||||
newTextPath = strings.Replace(hd.textPath, hyphaName, newName, 1)
|
||||
newBinaryPath = strings.Replace(hd.binaryPath, hyphaName, newName, 1)
|
||||
hop = history.Operation(history.TypeRenameHypha).
|
||||
WithFilesRenamed(map[string]string{
|
||||
hd.textPath: newTextPath,
|
||||
hd.binaryPath: newBinaryPath,
|
||||
}).
|
||||
WithMsg(fmt.Sprintf("Rename ‘%s’ to ‘%s’", hyphaName, newName)).
|
||||
WithSignature("anon").
|
||||
Apply()
|
||||
replaceName = func(str string) string {
|
||||
return strings.Replace(str, hyphaName, newName, 1)
|
||||
}
|
||||
hyphaNames = findHyphaeToRename(hyphaName, recursive)
|
||||
renameMap = renamingPairs(hyphaNames, replaceName)
|
||||
renameMsg = "Rename ‘%s’ to ‘%s’"
|
||||
hop = history.Operation(history.TypeRenameHypha)
|
||||
)
|
||||
if recursive {
|
||||
renameMsg += " recursively"
|
||||
}
|
||||
hop.WithFilesRenamed(renameMap).
|
||||
WithMsg(fmt.Sprintf(renameMsg, hyphaName, newName)).
|
||||
WithSignature("anon").
|
||||
Apply()
|
||||
if len(hop.Errs) == 0 {
|
||||
hd.textPath = newTextPath
|
||||
hd.binaryPath = newBinaryPath
|
||||
HyphaStorage[newName] = hd
|
||||
delete(HyphaStorage, hyphaName)
|
||||
relocateHyphaData(hyphaNames, replaceName)
|
||||
}
|
||||
return hop
|
||||
}
|
||||
|
@ -6,11 +6,20 @@ This dialog is to be shown to a user when they try to rename a hypha.
|
||||
<section>
|
||||
<h1>Rename {%s hyphaName %}</h1>
|
||||
<form action="/rename-confirm/{%s hyphaName %}" method="post" enctype="multipart/form-data">
|
||||
<label for="new-name">New name:</label>
|
||||
<input type="text" value="{%s hyphaName %}" required autofocus id="new-name" name="new-name"/>
|
||||
<fieldset>
|
||||
<legend>New name</legend>
|
||||
<input type="text" value="{%s hyphaName %}" required autofocus id="new-name" name="new-name"/>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Settings</legend>
|
||||
<input type="checkbox" id="recursive" name="recursive" value="true" checked/>
|
||||
<label for="recursive">Keep subhyphae</label>
|
||||
</fieldset>
|
||||
|
||||
<p>If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.</p>
|
||||
<input type="submit"/>
|
||||
</form>
|
||||
<p>If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.</p>
|
||||
</section>
|
||||
{%- else -%}
|
||||
{%= cannotRenameDueToNonExistence(hyphaName) %}
|
||||
|
@ -44,103 +44,112 @@ func StreamRenameAskHTML(qw422016 *qt422016.Writer, hyphaName string, isOld bool
|
||||
qw422016.E().S(hyphaName)
|
||||
//line templates/rename.qtpl:8
|
||||
qw422016.N().S(`" method="post" enctype="multipart/form-data">
|
||||
<label for="new-name">New name:</label>
|
||||
<input type="text" value="`)
|
||||
//line templates/rename.qtpl:10
|
||||
<fieldset>
|
||||
<legend>New name</legend>
|
||||
<input type="text" value="`)
|
||||
//line templates/rename.qtpl:11
|
||||
qw422016.E().S(hyphaName)
|
||||
//line templates/rename.qtpl:10
|
||||
//line templates/rename.qtpl:11
|
||||
qw422016.N().S(`" required autofocus id="new-name" name="new-name"/>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Settings</legend>
|
||||
<input type="checkbox" id="recursive" name="recursive" value="true" checked/>
|
||||
<label for="recursive">Keep subhyphae</label>
|
||||
</fieldset>
|
||||
|
||||
<p>If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.</p>
|
||||
<input type="submit"/>
|
||||
</form>
|
||||
<p>If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.</p>
|
||||
</section>
|
||||
`)
|
||||
//line templates/rename.qtpl:15
|
||||
//line templates/rename.qtpl:24
|
||||
} else {
|
||||
//line templates/rename.qtpl:15
|
||||
//line templates/rename.qtpl:24
|
||||
qw422016.N().S(` `)
|
||||
//line templates/rename.qtpl:16
|
||||
//line templates/rename.qtpl:25
|
||||
streamcannotRenameDueToNonExistence(qw422016, hyphaName)
|
||||
//line templates/rename.qtpl:16
|
||||
//line templates/rename.qtpl:25
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line templates/rename.qtpl:17
|
||||
//line templates/rename.qtpl:26
|
||||
}
|
||||
//line templates/rename.qtpl:17
|
||||
//line templates/rename.qtpl:26
|
||||
qw422016.N().S(`</main>
|
||||
`)
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
}
|
||||
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
func WriteRenameAskHTML(qq422016 qtio422016.Writer, hyphaName string, isOld bool) {
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
StreamRenameAskHTML(qw422016, hyphaName, isOld)
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
}
|
||||
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
func RenameAskHTML(hyphaName string, isOld bool) string {
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
WriteRenameAskHTML(qb422016, hyphaName, isOld)
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
qs422016 := string(qb422016.B)
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
return qs422016
|
||||
//line templates/rename.qtpl:19
|
||||
//line templates/rename.qtpl:28
|
||||
}
|
||||
|
||||
//line templates/rename.qtpl:21
|
||||
//line templates/rename.qtpl:30
|
||||
func streamcannotRenameDueToNonExistence(qw422016 *qt422016.Writer, hyphaName string) {
|
||||
//line templates/rename.qtpl:21
|
||||
//line templates/rename.qtpl:30
|
||||
qw422016.N().S(`
|
||||
<section>
|
||||
<h1>Cannot rename `)
|
||||
//line templates/rename.qtpl:23
|
||||
//line templates/rename.qtpl:32
|
||||
qw422016.E().S(hyphaName)
|
||||
//line templates/rename.qtpl:23
|
||||
//line templates/rename.qtpl:32
|
||||
qw422016.N().S(`</h1>
|
||||
<p>This hypha does not exist.</p>
|
||||
<p><a href="/page/`)
|
||||
//line templates/rename.qtpl:25
|
||||
//line templates/rename.qtpl:34
|
||||
qw422016.E().S(hyphaName)
|
||||
//line templates/rename.qtpl:25
|
||||
//line templates/rename.qtpl:34
|
||||
qw422016.N().S(`">Go back</a></p>
|
||||
</section>
|
||||
`)
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
}
|
||||
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
func writecannotRenameDueToNonExistence(qq422016 qtio422016.Writer, hyphaName string) {
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
streamcannotRenameDueToNonExistence(qw422016, hyphaName)
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
}
|
||||
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
func cannotRenameDueToNonExistence(hyphaName string) string {
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
writecannotRenameDueToNonExistence(qb422016, hyphaName)
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
qs422016 := string(qb422016.B)
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
return qs422016
|
||||
//line templates/rename.qtpl:27
|
||||
//line templates/rename.qtpl:36
|
||||
}
|
||||
|
11
util/util.go
11
util/util.go
@ -25,3 +25,14 @@ func HTTP200Page(w http.ResponseWriter, page string) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(page))
|
||||
}
|
||||
|
||||
// FindSubhyphae finds names of existing hyphae given the `hyphaIterator`.
|
||||
func FindSubhyphae(hyphaName string, hyphaIterator func(func(string))) []string {
|
||||
subhyphae := make([]string, 0)
|
||||
hyphaIterator(func(otherHyphaName string) {
|
||||
if strings.HasPrefix(otherHyphaName, hyphaName+"/") {
|
||||
subhyphae = append(subhyphae, otherHyphaName)
|
||||
}
|
||||
})
|
||||
return subhyphae
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user