mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-12 05:20: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]
|
hyphaData, isOld = HyphaStorage[hyphaName]
|
||||||
newName = CanonicalName(rq.PostFormValue("new-name"))
|
newName = CanonicalName(rq.PostFormValue("new-name"))
|
||||||
_, newNameIsUsed = HyphaStorage[newName]
|
_, newNameIsUsed = HyphaStorage[newName]
|
||||||
|
recursive bool
|
||||||
)
|
)
|
||||||
|
if rq.PostFormValue("recursive") == "true" {
|
||||||
|
recursive = true
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case newNameIsUsed:
|
case newNameIsUsed:
|
||||||
HttpErr(w, http.StatusBadRequest, hyphaName, "Error: hypha exists",
|
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",
|
HttpErr(w, http.StatusBadRequest, hyphaName, "Error: invalid name",
|
||||||
"Invalid new name. Names cannot contain characters <code>^?!:#@><*|\"\\'&%</code>")
|
"Invalid new name. Names cannot contain characters <code>^?!:#@><*|\"\\'&%</code>")
|
||||||
default:
|
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)
|
http.Redirect(w, rq, "/page/"+newName, http.StatusSeeOther)
|
||||||
} else {
|
} else {
|
||||||
HttpErr(w, http.StatusInternalServerError, hyphaName,
|
HttpErr(w, http.StatusInternalServerError, hyphaName,
|
||||||
|
67
hypha.go
67
hypha.go
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/bouncepaw/mycorrhiza/gemtext"
|
"github.com/bouncepaw/mycorrhiza/gemtext"
|
||||||
"github.com/bouncepaw/mycorrhiza/history"
|
"github.com/bouncepaw/mycorrhiza/history"
|
||||||
|
"github.com/bouncepaw/mycorrhiza/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -52,25 +53,61 @@ func (hd *HyphaData) DeleteHypha(hyphaName string) *history.HistoryOp {
|
|||||||
return hop
|
return hop
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenameHypha renames hypha from old name `hyphaName` to `newName` and makes a history record about that.
|
func findHyphaeToRename(hyphaName string, recursive bool) []string {
|
||||||
func (hd *HyphaData) RenameHypha(hyphaName, newName string) *history.HistoryOp {
|
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 (
|
var (
|
||||||
newTextPath = strings.Replace(hd.textPath, hyphaName, newName, 1)
|
replaceName = func(str string) string {
|
||||||
newBinaryPath = strings.Replace(hd.binaryPath, hyphaName, newName, 1)
|
return strings.Replace(str, hyphaName, newName, 1)
|
||||||
hop = history.Operation(history.TypeRenameHypha).
|
}
|
||||||
WithFilesRenamed(map[string]string{
|
hyphaNames = findHyphaeToRename(hyphaName, recursive)
|
||||||
hd.textPath: newTextPath,
|
renameMap = renamingPairs(hyphaNames, replaceName)
|
||||||
hd.binaryPath: newBinaryPath,
|
renameMsg = "Rename ‘%s’ to ‘%s’"
|
||||||
}).
|
hop = history.Operation(history.TypeRenameHypha)
|
||||||
WithMsg(fmt.Sprintf("Rename ‘%s’ to ‘%s’", hyphaName, newName)).
|
)
|
||||||
|
if recursive {
|
||||||
|
renameMsg += " recursively"
|
||||||
|
}
|
||||||
|
hop.WithFilesRenamed(renameMap).
|
||||||
|
WithMsg(fmt.Sprintf(renameMsg, hyphaName, newName)).
|
||||||
WithSignature("anon").
|
WithSignature("anon").
|
||||||
Apply()
|
Apply()
|
||||||
)
|
|
||||||
if len(hop.Errs) == 0 {
|
if len(hop.Errs) == 0 {
|
||||||
hd.textPath = newTextPath
|
relocateHyphaData(hyphaNames, replaceName)
|
||||||
hd.binaryPath = newBinaryPath
|
|
||||||
HyphaStorage[newName] = hd
|
|
||||||
delete(HyphaStorage, hyphaName)
|
|
||||||
}
|
}
|
||||||
return hop
|
return hop
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,20 @@ This dialog is to be shown to a user when they try to rename a hypha.
|
|||||||
<section>
|
<section>
|
||||||
<h1>Rename {%s hyphaName %}</h1>
|
<h1>Rename {%s hyphaName %}</h1>
|
||||||
<form action="/rename-confirm/{%s hyphaName %}" method="post" enctype="multipart/form-data">
|
<form action="/rename-confirm/{%s hyphaName %}" method="post" enctype="multipart/form-data">
|
||||||
<label for="new-name">New name:</label>
|
<fieldset>
|
||||||
|
<legend>New name</legend>
|
||||||
<input type="text" value="{%s hyphaName %}" required autofocus id="new-name" name="new-name"/>
|
<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"/>
|
<input type="submit"/>
|
||||||
</form>
|
</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>
|
</section>
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
{%= cannotRenameDueToNonExistence(hyphaName) %}
|
{%= cannotRenameDueToNonExistence(hyphaName) %}
|
||||||
|
@ -44,103 +44,112 @@ func StreamRenameAskHTML(qw422016 *qt422016.Writer, hyphaName string, isOld bool
|
|||||||
qw422016.E().S(hyphaName)
|
qw422016.E().S(hyphaName)
|
||||||
//line templates/rename.qtpl:8
|
//line templates/rename.qtpl:8
|
||||||
qw422016.N().S(`" method="post" enctype="multipart/form-data">
|
qw422016.N().S(`" method="post" enctype="multipart/form-data">
|
||||||
<label for="new-name">New name:</label>
|
<fieldset>
|
||||||
|
<legend>New name</legend>
|
||||||
<input type="text" value="`)
|
<input type="text" value="`)
|
||||||
//line templates/rename.qtpl:10
|
//line templates/rename.qtpl:11
|
||||||
qw422016.E().S(hyphaName)
|
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"/>
|
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"/>
|
<input type="submit"/>
|
||||||
</form>
|
</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>
|
</section>
|
||||||
`)
|
`)
|
||||||
//line templates/rename.qtpl:15
|
//line templates/rename.qtpl:24
|
||||||
} else {
|
} else {
|
||||||
//line templates/rename.qtpl:15
|
//line templates/rename.qtpl:24
|
||||||
qw422016.N().S(` `)
|
qw422016.N().S(` `)
|
||||||
//line templates/rename.qtpl:16
|
//line templates/rename.qtpl:25
|
||||||
streamcannotRenameDueToNonExistence(qw422016, hyphaName)
|
streamcannotRenameDueToNonExistence(qw422016, hyphaName)
|
||||||
//line templates/rename.qtpl:16
|
//line templates/rename.qtpl:25
|
||||||
qw422016.N().S(`
|
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>
|
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) {
|
func WriteRenameAskHTML(qq422016 qtio422016.Writer, hyphaName string, isOld bool) {
|
||||||
//line templates/rename.qtpl:19
|
//line templates/rename.qtpl:28
|
||||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
//line templates/rename.qtpl:19
|
//line templates/rename.qtpl:28
|
||||||
StreamRenameAskHTML(qw422016, hyphaName, isOld)
|
StreamRenameAskHTML(qw422016, hyphaName, isOld)
|
||||||
//line templates/rename.qtpl:19
|
//line templates/rename.qtpl:28
|
||||||
qt422016.ReleaseWriter(qw422016)
|
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 {
|
func RenameAskHTML(hyphaName string, isOld bool) string {
|
||||||
//line templates/rename.qtpl:19
|
//line templates/rename.qtpl:28
|
||||||
qb422016 := qt422016.AcquireByteBuffer()
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
//line templates/rename.qtpl:19
|
//line templates/rename.qtpl:28
|
||||||
WriteRenameAskHTML(qb422016, hyphaName, isOld)
|
WriteRenameAskHTML(qb422016, hyphaName, isOld)
|
||||||
//line templates/rename.qtpl:19
|
//line templates/rename.qtpl:28
|
||||||
qs422016 := string(qb422016.B)
|
qs422016 := string(qb422016.B)
|
||||||
//line templates/rename.qtpl:19
|
//line templates/rename.qtpl:28
|
||||||
qt422016.ReleaseByteBuffer(qb422016)
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
//line templates/rename.qtpl:19
|
//line templates/rename.qtpl:28
|
||||||
return qs422016
|
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) {
|
func streamcannotRenameDueToNonExistence(qw422016 *qt422016.Writer, hyphaName string) {
|
||||||
//line templates/rename.qtpl:21
|
//line templates/rename.qtpl:30
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<section>
|
<section>
|
||||||
<h1>Cannot rename `)
|
<h1>Cannot rename `)
|
||||||
//line templates/rename.qtpl:23
|
//line templates/rename.qtpl:32
|
||||||
qw422016.E().S(hyphaName)
|
qw422016.E().S(hyphaName)
|
||||||
//line templates/rename.qtpl:23
|
//line templates/rename.qtpl:32
|
||||||
qw422016.N().S(`</h1>
|
qw422016.N().S(`</h1>
|
||||||
<p>This hypha does not exist.</p>
|
<p>This hypha does not exist.</p>
|
||||||
<p><a href="/page/`)
|
<p><a href="/page/`)
|
||||||
//line templates/rename.qtpl:25
|
//line templates/rename.qtpl:34
|
||||||
qw422016.E().S(hyphaName)
|
qw422016.E().S(hyphaName)
|
||||||
//line templates/rename.qtpl:25
|
//line templates/rename.qtpl:34
|
||||||
qw422016.N().S(`">Go back</a></p>
|
qw422016.N().S(`">Go back</a></p>
|
||||||
</section>
|
</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) {
|
func writecannotRenameDueToNonExistence(qq422016 qtio422016.Writer, hyphaName string) {
|
||||||
//line templates/rename.qtpl:27
|
//line templates/rename.qtpl:36
|
||||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
//line templates/rename.qtpl:27
|
//line templates/rename.qtpl:36
|
||||||
streamcannotRenameDueToNonExistence(qw422016, hyphaName)
|
streamcannotRenameDueToNonExistence(qw422016, hyphaName)
|
||||||
//line templates/rename.qtpl:27
|
//line templates/rename.qtpl:36
|
||||||
qt422016.ReleaseWriter(qw422016)
|
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 {
|
func cannotRenameDueToNonExistence(hyphaName string) string {
|
||||||
//line templates/rename.qtpl:27
|
//line templates/rename.qtpl:36
|
||||||
qb422016 := qt422016.AcquireByteBuffer()
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
//line templates/rename.qtpl:27
|
//line templates/rename.qtpl:36
|
||||||
writecannotRenameDueToNonExistence(qb422016, hyphaName)
|
writecannotRenameDueToNonExistence(qb422016, hyphaName)
|
||||||
//line templates/rename.qtpl:27
|
//line templates/rename.qtpl:36
|
||||||
qs422016 := string(qb422016.B)
|
qs422016 := string(qb422016.B)
|
||||||
//line templates/rename.qtpl:27
|
//line templates/rename.qtpl:36
|
||||||
qt422016.ReleaseByteBuffer(qb422016)
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
//line templates/rename.qtpl:27
|
//line templates/rename.qtpl:36
|
||||||
return qs422016
|
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.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(page))
|
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