Add edit function in web view

This commit is contained in:
Radhi Fadlillah 2018-02-13 16:14:08 +07:00
parent 59208fb377
commit 5a2fed1888
6 changed files with 221 additions and 135 deletions

View file

@ -88,5 +88,6 @@ func addBookmark(url, title, excerpt string, tags []string, offline bool) (book
return book, err return book, err
} }
bookmark.Modified = time.Now().UTC().Format("2006-01-02 15:04:05")
return bookmark, nil return bookmark, nil
} }

View file

@ -28,6 +28,7 @@ var (
router.GET("/webfonts/*filepath", serveFiles) router.GET("/webfonts/*filepath", serveFiles)
router.GET("/api/bookmarks", apiGetBookmarks) router.GET("/api/bookmarks", apiGetBookmarks)
router.POST("/api/bookmarks", apiInsertBookmarks) router.POST("/api/bookmarks", apiInsertBookmarks)
router.PUT("/api/bookmarks", apiUpdateBookmarks)
// Route for panic // Route for panic
router.PanicHandler = func(w http.ResponseWriter, r *http.Request, arg interface{}) { router.PanicHandler = func(w http.ResponseWriter, r *http.Request, arg interface{}) {
@ -80,3 +81,25 @@ func apiInsertBookmarks(w http.ResponseWriter, r *http.Request, ps httprouter.Pa
err = json.NewEncoder(w).Encode(&book) err = json.NewEncoder(w).Encode(&book)
checkError(err) checkError(err)
} }
func apiUpdateBookmarks(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// Decode request
request := model.Bookmark{}
err := json.NewDecoder(r.Body).Decode(&request)
checkError(err)
// Convert tags and ID
id := []string{fmt.Sprintf("%d", request.ID)}
tags := make([]string, len(request.Tags))
for i, tag := range request.Tags {
tags[i] = tag.Name
}
// Update bookmark
bookmarks, err := updateBookmarks(id, request.URL, request.Title, request.Excerpt, tags, false)
checkError(err)
// Return new saved result
err = json.NewEncoder(w).Encode(&bookmarks[0])
checkError(err)
}

View file

@ -58,16 +58,37 @@ var (
} }
} }
// Read bookmarks from database // Update bookmarks
bookmarks, err := DB.GetBookmarks(db.GetBookmarksOptions{WithContents: true}, args...) bookmarks, err := updateBookmarks(args, url, title, excerpt, tags, offline)
if err != nil { if err != nil {
cError.Println(err) cError.Println(err)
return return
} }
printBookmark(bookmarks...)
},
}
)
func init() {
updateCmd.Flags().StringP("url", "u", "", "New URL for this bookmark.")
updateCmd.Flags().StringP("title", "i", "", "New title for this bookmark.")
updateCmd.Flags().StringP("excerpt", "e", "", "New excerpt for this bookmark.")
updateCmd.Flags().StringSliceP("tags", "t", []string{}, "Comma-separated tags for this bookmark.")
updateCmd.Flags().BoolP("offline", "o", false, "Update bookmark without fetching data from internet.")
updateCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt and update ALL bookmarks")
rootCmd.AddCommand(updateCmd)
}
func updateBookmarks(indices []string, url, title, excerpt string, tags []string, offline bool) ([]model.Bookmark, error) {
// Read bookmarks from database
bookmarks, err := DB.GetBookmarks(db.GetBookmarksOptions{WithContents: true}, indices...)
if err != nil {
return []model.Bookmark{}, err
}
if len(bookmarks) == 0 { if len(bookmarks) == 0 {
cError.Println("No matching index found") return []model.Bookmark{}, fmt.Errorf("No matching index found")
return
} }
if url != "" && len(bookmarks) == 1 { if url != "" && len(bookmarks) == 1 {
@ -157,21 +178,8 @@ var (
err = DB.UpdateBookmarks(bookmarks) err = DB.UpdateBookmarks(bookmarks)
if err != nil { if err != nil {
cError.Println("Failed to update bookmarks:", err) return []model.Bookmark{}, fmt.Errorf("Failed to update bookmarks: %v", err)
return
} }
printBookmark(bookmarks...) return bookmarks, nil
},
}
)
func init() {
updateCmd.Flags().StringP("url", "u", "", "New URL for this bookmark.")
updateCmd.Flags().StringP("title", "i", "", "New title for this bookmark.")
updateCmd.Flags().StringP("excerpt", "e", "", "New excerpt for this bookmark.")
updateCmd.Flags().StringSliceP("tags", "t", []string{}, "Comma-separated tags for this bookmark.")
updateCmd.Flags().BoolP("offline", "o", false, "Update bookmark without fetching data from internet.")
updateCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt and update ALL bookmarks")
rootCmd.AddCommand(updateCmd)
} }

File diff suppressed because one or more lines are too long

View file

@ -26,19 +26,20 @@
</div> </div>
</div> </div>
<div id="main"> <div id="main">
<div id="new-bookmark"> <div id="input-bookmark">
<input type="text" v-model="newBookmark.url" placeholder="URL for the bookmark"> <p v-if="inputBookmark.url !== ''">{{inputBookmark.id === -1 ? 'New bookmark' : 'Edit bookmark'}}</p>
<template v-if="newBookmark.url !== ''"> <input type="text" ref="inputURL" v-model="inputBookmark.url" placeholder="URL for the bookmark">
<input type="text" v-model="newBookmark.title" placeholder="Custom bookmark title (optional)"> <template v-if="inputBookmark.url !== ''">
<input type="text" v-model="newBookmark.tags" placeholder="Space separated tags for this bookmark (optional)"> <input type="text" v-model="inputBookmark.title" placeholder="Custom bookmark title (optional)">
<textarea name="excerpt" v-model="newBookmark.excerpt" placeholder="Excerpt for this bookmark (optional)"></textarea> <input type="text" v-model="inputBookmark.tags" placeholder="Space separated tags for this bookmark (optional)">
<textarea name="excerpt" v-model="inputBookmark.excerpt" placeholder="Excerpt for this bookmark (optional)"></textarea>
<div class="button-area"> <div class="button-area">
<div class="spacer"></div> <div class="spacer"></div>
<a v-if="newBookmark.loading"> <a v-if="inputBookmark.loading">
<i class="fas fa-fw fa-spinner fa-spin"></i> <i class="fas fa-fw fa-spinner fa-spin"></i>
</a> </a>
<template v-else> <template v-else>
<a class="button">Cancel</a> <a class="button" @click="clearInputBookmark">Cancel</a>
<a class="button" @click="saveBookmark">Done</a> <a class="button" @click="saveBookmark">Done</a>
</template> </template>
</div> </div>
@ -46,7 +47,7 @@
</div> </div>
<div id="grid"> <div id="grid">
<div v-for="column in gridColumns" class="column"> <div v-for="column in gridColumns" class="column">
<div v-for="item in column" class="bookmark"> <div v-for="item in column" class="bookmark" :ref="'bookmark-'+item.index">
<a href="#" class="checkbox"> <a href="#" class="checkbox">
<i class="fas fa-check"></i> <i class="fas fa-check"></i>
</a> </a>
@ -60,7 +61,7 @@
<a v-for="tag in item.tags" href="#">{{tag.name}}</a> <a v-for="tag in item.tags" href="#">{{tag.name}}</a>
</div> </div>
<div class="bookmark-menu"> <div class="bookmark-menu">
<a href="#"> <a href="#" @click="editBookmark(item.index)">
<i class="fas fa-pencil-alt"></i> <i class="fas fa-pencil-alt"></i>
</a> </a>
<a href="#"> <a href="#">
@ -89,7 +90,9 @@
windowWidth: 0, windowWidth: 0,
loading: true, loading: true,
bookmarks: [], bookmarks: [],
newBookmark: { inputBookmark: {
index: -1,
id: -1,
url: "", url: "",
title: "", title: "",
tags: "", tags: "",
@ -111,12 +114,12 @@
}); });
}, },
saveBookmark: function () { saveBookmark: function () {
if (this.newBookmark.loading) return; if (this.inputBookmark.loading) return;
this.newBookmark.loading = true; this.inputBookmark.loading = true;
if (this.newBookmark.url === "") return; if (this.inputBookmark.url === "") return;
var tags = this.newBookmark.tags.replace(/\s+/g, ""), var tags = this.inputBookmark.tags.replace(/\s+/g, " "),
listTag = tags === "" ? [] : listTag = tags.split(/\s+/g), listTag = tags === "" ? [] : listTag = tags.split(/\s+/g),
finalTag = []; finalTag = [];
@ -126,29 +129,64 @@
}); });
} }
instance.post('/api/bookmarks', { instance.request({
url: this.newBookmark.url, method: this.inputBookmark.id === -1 ? 'post' : 'put',
title: this.newBookmark.title, url: '/api/bookmarks',
excerpt: this.newBookmark.excerpt, timeout: 15000,
data: {
id: this.inputBookmark.id,
url: this.inputBookmark.url,
title: this.inputBookmark.title,
excerpt: this.inputBookmark.excerpt,
tags: finalTag tags: finalTag
}, { }
timeout: 15000
}) })
.then(function (response) { .then(function (response) {
app.clearNewBookmark(); var idx = app.inputBookmark.index;
app.bookmarks.unshift(response.data);
if (idx === -1) app.bookmarks.unshift(response.data);
else app.bookmarks.splice(idx, 1, response.data);
app.clearInputBookmark();
}) })
.catch(function (error) { .catch(function (error) {
app.clearNewBookmark();
console.log(error); console.log(error);
}); });
}, },
clearNewBookmark: function () { clearInputBookmark: function () {
this.newBookmark.url = ""; var idx = this.inputBookmark.index;
this.newBookmark.title = "";
this.newBookmark.tags = ""; this.inputBookmark.index = -1;
this.newBookmark.excerpt = ""; this.inputBookmark.id = -1;
this.newBookmark.loading = false; this.inputBookmark.url = "";
this.inputBookmark.title = "";
this.inputBookmark.tags = "";
this.inputBookmark.excerpt = "";
this.inputBookmark.loading = false;
if (idx !== -1) app.$nextTick(function () {
var bookmarkItem = app.$refs['bookmark-' + idx];
bookmarkItem[0].scrollIntoView();
})
},
editBookmark: function (idx) {
var bookmark = this.bookmarks[idx],
tags = [];
for (var i = 0; i < bookmark.tags.length; i++) {
tags.push(bookmark.tags[i].name);
}
this.inputBookmark.index = idx;
this.inputBookmark.id = bookmark.id;
this.inputBookmark.url = bookmark.url;
this.inputBookmark.title = bookmark.title;
this.inputBookmark.tags = tags.join(" ");
this.inputBookmark.excerpt = bookmark.excerpt;
this.$nextTick(function () {
app.$refs.inputURL.focus();
});
}, },
bookmarkTime: function (book) { bookmarkTime: function (book) {
var time = book.modified, var time = book.modified,
@ -199,6 +237,7 @@
for (var i = 0; i < this.bookmarks.length; i++) { for (var i = 0; i < this.bookmarks.length; i++) {
var bookmark = this.bookmarks[i]; var bookmark = this.bookmarks[i];
bookmark.index = i;
finalContent[currentColumn].push(bookmark); finalContent[currentColumn].push(bookmark);
currentColumn += 1; currentColumn += 1;
@ -208,6 +247,14 @@
return finalContent; return finalContent;
} }
}, },
watch: {
'inputBookmark.url': function (newURL) {
if (newURL === "") this.clearInputBookmark();
else this.$nextTick(function () {
app.$refs.inputURL.focus();
});
}
},
mounted: function () { mounted: function () {
this.windowWidth = window.innerWidth; this.windowWidth = window.innerWidth;
window.addEventListener('resize', function () { window.addEventListener('resize', function () {

View file

@ -80,7 +80,7 @@
margin-top: @headerHeight; margin-top: @headerHeight;
display: flex; display: flex;
flex-flow: column nowrap; flex-flow: column nowrap;
#new-bookmark { #input-bookmark {
align-self: center; align-self: center;
max-width: 600px; max-width: 600px;
width: 100%; width: 100%;
@ -89,6 +89,12 @@
margin: 32px 8px 20px; margin: 32px 8px 20px;
background-color: @headerInputBg; background-color: @headerInputBg;
outline: 1px solid @border; outline: 1px solid @border;
>p {
color: @fontColor;
font-weight: 600;
text-transform: uppercase;
padding: 16px;
}
input[type=text], input[type=text],
textarea { textarea {
outline: 1px solid @border; outline: 1px solid @border;
@ -177,6 +183,7 @@
padding: 16px; padding: 16px;
display: flex; display: flex;
flex-flow: column nowrap; flex-flow: column nowrap;
border-bottom: 1px solid @border;
.bookmark-time { .bookmark-time {
color: @fontLightColor; color: @fontLightColor;
font-size: 0.9em; font-size: 0.9em;
@ -232,15 +239,14 @@
} }
} }
.bookmark-excerpt { .bookmark-excerpt {
padding: 16px; padding: 16px 16px 0;
color: @fontColor; color: @fontColor;
border-top: 1px solid @border;
} }
.bookmark-tags { .bookmark-tags {
display: flex; display: flex;
flex-flow: row wrap; flex-flow: row wrap;
padding: 0 12px 12px; padding: 12px 12px 0;
margin-top: -4px; margin-bottom: -4px;
a { a {
font-size: 0.9em; font-size: 0.9em;
padding: 4px; padding: 4px;
@ -258,6 +264,7 @@
flex-flow: row nowrap; flex-flow: row nowrap;
border-top: 1px solid @border; border-top: 1px solid @border;
visibility: hidden; visibility: hidden;
margin-top: 16px;
a { a {
display: block; display: block;
flex: 1 0; flex: 1 0;