1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-20 13:49:42 +02:00

click handlers for content links

This commit is contained in:
Harvey Kandola 2016-10-26 17:31:05 -07:00
parent c27de6bcab
commit 899b4f978c
27 changed files with 265 additions and 83 deletions

View file

@ -17,6 +17,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
documentService: Ember.inject.service('document'), documentService: Ember.inject.service('document'),
sectionService: Ember.inject.service('section'), sectionService: Ember.inject.service('section'),
appMeta: Ember.inject.service(), appMeta: Ember.inject.service(),
link: Ember.inject.service(),
/* Parameters */ /* Parameters */
document: null, document: null,
// pages: [], // pages: [],
@ -50,6 +51,10 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
}); });
}, },
didRender() {
this.contentLinkHandler();
},
willDestroyElement() { willDestroyElement() {
this.destroyTooltips(); this.destroyTooltips();
@ -60,6 +65,32 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
} }
}, },
contentLinkHandler() {
let links = this.get('link');
let doc = this.get('document');
let self = this;
$("a[data-documize='true']").off('click').on('click', function() {
let link = links.getLinkObject(this);
// local link? exists?
if (link.linkType === "section" && link.documentId === doc.get('id')) {
let exists = self.get('pages').findBy('id', link.targetId);
if (_.isUndefined(exists) || link.orphan) {
self.showNotification('Broken link!');
return false;
} else {
self.attrs.gotoPage(link.targetId);
return false;
}
}
links.linkClick(doc, link);
return false;
});
},
actions: { actions: {
confirmDeleteAttachment(id, name) { confirmDeleteAttachment(id, name) {
this.set('deleteAttachment', { this.set('deleteAttachment', {

View file

@ -18,20 +18,34 @@ const {
export default Ember.Component.extend(TooltipMixin, { export default Ember.Component.extend(TooltipMixin, {
link: service(), link: service(),
hasSections: false,
hasAttachments: false,
linkName: '', linkName: '',
keywords: '', keywords: '',
selection: null, selection: null,
tabs: [
{ label: 'Section', selected: true },
{ label: 'Attachment', selected: false },
{ label: 'Search', selected: false }
],
showSections: Ember.computed('tabs.@each.selected', function() {
return this.get('tabs').findBy('label', 'Section').selected;
}),
showAttachments: Ember.computed('tabs.@each.selected', function() {
return this.get('tabs').findBy('label', 'Attachment').selected;
}),
showSearch: Ember.computed('tabs.@each.selected', function() {
return this.get('tabs').findBy('label', 'Search').selected;
}),
init() { init() {
this._super(...arguments); this._super(...arguments);
let self = this; let self = this;
let folderId = this.get('folder.id');
let documentId = this.get('document.id'); let documentId = this.get('document.id');
let pageId = this.get('page.id'); let pageId = this.get('page.id');
this.get('link').getCandidates(documentId, pageId).then(function (candidates) { this.get('link').getCandidates(folderId, documentId, pageId).then(function (candidates) {
self.set('candidates', candidates); self.set('candidates', candidates);
self.set('hasSections', is.not.null(candidates.pages) && candidates.pages.length); self.set('hasSections', is.not.null(candidates.pages) && candidates.pages.length);
self.set('hasAttachments', is.not.null(candidates.attachments) && candidates.attachments.length); self.set('hasAttachments', is.not.null(candidates.attachments) && candidates.attachments.length);
@ -69,6 +83,10 @@ export default Ember.Component.extend(TooltipMixin, {
} }
return this.get('onInsertLink')(selection); return this.get('onInsertLink')(selection);
},
onTabSelect(tabs) {
this.set('tabs', tabs);
} }
} }
}); });

View file

@ -0,0 +1,32 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
export default Ember.Component.extend({
myWidth: Ember.computed('tabs', function() {
let count = this.get('tabs.length');
let width = 95 / count;
return Ember.String.htmlSafe("width: " + `${width}%;`);
}),
actions: {
onTabSelect(tab) {
this.get('tabs').forEach(t => {
Ember.set(t, 'selected', false);
});
Ember.set(tab, 'selected', true);
this.attrs.onTabSelect(this.get('tabs'));
}
}
});

View file

@ -18,6 +18,6 @@ export function initialize(application) {
export default { export default {
name: 'eventBus', name: 'eventBus',
after: 'session', after: 'application',
initialize: initialize initialize: initialize
}; };

View file

@ -0,0 +1,20 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
export function initialize(application) {
application.inject('component', 'router', 'router:main');
application.inject('service', 'router', 'router:main');
}
export default {
name: 'route-injector',
initialize: initialize
};

View file

@ -16,7 +16,6 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
documentService: Ember.inject.service('document'), documentService: Ember.inject.service('document'),
folderService: Ember.inject.service('folder'), folderService: Ember.inject.service('folder'),
userService: Ember.inject.service('user'), userService: Ember.inject.service('user'),
pages: [], pages: [],
attachments: [], attachments: [],
users: [], users: [],
@ -107,14 +106,5 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
controller.set('meta', meta); controller.set('meta', meta);
this.browser.setMetaDescription(model.get('excerpt')); this.browser.setMetaDescription(model.get('excerpt'));
},
// Document view needs all white background!
activate() {
Ember.$('html').addClass('background-color-white');
},
deactivate() {
Ember.$('html').removeClass('background-color-white');
} }
}); });

View file

@ -20,6 +20,7 @@
{{document/document-view document=model pages=pages attachments=attachments folder=folder folders=folders {{document/document-view document=model pages=pages attachments=attachments folder=folder folders=folders
isEditor=isEditor isEditor=isEditor
gotoPage=(action 'gotoPage')
onAttachmentDeleted=(action 'onAttachmentDeleted') onAttachmentDeleted=(action 'onAttachmentDeleted')
onDeletePage=(action 'onPageDeleted')}} onDeletePage=(action 'onPageDeleted')}}
{{/layout/zone-content}} {{/layout/zone-content}}

View file

@ -25,6 +25,7 @@ export default Ember.Service.extend({
appId: config.APP.intercomKey, appId: config.APP.intercomKey,
init() { init() {
this._super(...arguments);
this.start(); this.start();
}, },

View file

@ -28,5 +28,9 @@ export default Ember.Service.extend({
}(wait, times); }(wait, times);
setTimeout(interv, wait); setTimeout(interv, wait);
},
showNotification(msg) {
this.get('eventBus').publish('notifyUser', msg);
} }
}); });

View file

@ -13,6 +13,7 @@ import Ember from 'ember';
export default Ember.Service.extend(Ember.Evented, { export default Ember.Service.extend(Ember.Evented, {
init() { init() {
this._super(...arguments);
let _this = this; let _this = this;
window.addEventListener("scroll", _.throttle(function() { window.addEventListener("scroll", _.throttle(function() {

View file

@ -19,10 +19,11 @@ export default Ember.Service.extend({
sessionService: service('session'), sessionService: service('session'),
ajax: service(), ajax: service(),
appMeta: service(), appMeta: service(),
store: service(),
// Returns candidate links using provided parameters // Returns candidate links using provided parameters
getCandidates(documentId, pageId /*, keywords*/ ) { getCandidates(folderId, documentId, pageId /*, keywords*/ ) {
return this.get('ajax').request(`links/${documentId}/${pageId}`, { return this.get('ajax').request(`links/${folderId}/${documentId}/${pageId}`, {
method: 'GET' method: 'GET'
}).then((response) => { }).then((response) => {
return response; return response;
@ -35,45 +36,85 @@ export default Ember.Service.extend({
let endpoint = this.get('appMeta').get('endpoint'); let endpoint = this.get('appMeta').get('endpoint');
let orgId = this.get('appMeta').get('orgId'); let orgId = this.get('appMeta').get('orgId');
if (link.linkType === "section") { if (link.linkType === "section" || link.linkType === "document") {
href = `/link/${link.linkType}/${link.id}`; href = `/link/${link.linkType}/${link.id}`;
result = `<a data-documize='true' data-link-space-id='${link.folderId}' data-link-id='${link.id}' data-link-document-id='${link.documentId}' data-link-target-id='${link.targetId}' data-link-type='${link.linkType}' href='${href}'>${link.title}</a>`;
} }
if (link.linkType === "file") { if (link.linkType === "file") {
href = `${endpoint}/public/attachments/${orgId}/${link.targetId}`; href = `${endpoint}/public/attachments/${orgId}/${link.targetId}`;
} result = `<a data-documize='true' data-link-space-id='${link.folderId}' data-link-id='${link.id}' data-link-document-id='${link.documentId}' data-link-target-id='${link.targetId}' data-link-type='${link.linkType}' href='${href}'>${link.title}</a>`;
if (link.linkType === "document") {
href = `/link/${link.linkType}/${link.id}`;
} }
result = `<a data-documize='true' data-link-id='${link.id}' data-link-document-id='${link.documentId}' data-link-target-id='${link.targetId}' data-link-type='${link.linkType}' href='${href}'>${link.title}</a>`;
return result; return result;
},
getLinkObject(a) {
let link = {
linkId: a.attributes["data-link-id"].value,
linkType: a.attributes["data-link-type"].value,
documentId: a.attributes["data-link-document-id"].value,
folderId: a.attributes["data-link-space-id"].value,
targetId: a.attributes["data-link-target-id"].value,
url: a.attributes["href"].value,
orphan: false
};
link.orphan = _.isEmpty(link.linkId) || _.isEmpty(link.documentId) || _.isEmpty(link.folderId) || _.isEmpty(link.targetId);
return link;
},
linkClick(doc, link) {
if (link.orphan) {
return;
}
let router = this.get('router');
let targetFolder = this.get('store').peekRecord('folder', link.folderId);
let targetDocument = this.get('store').peekRecord('document', link.documentId);
let folderSlug = is.null(targetFolder) ? "s" : targetFolder.get('slug');
let documentSlug = is.null(targetDocument) ? "d" : targetDocument.get('slug');
// handle section link
if (link.linkType === "section") {
let options = {};
options['page'] = link.targetId;
router.transitionTo('document', link.folderId, folderSlug, link.documentId, documentSlug, { queryParams: options });
return;
}
// handle document link
if (link.inkType === "document") {
router.transitionTo('document', link.folderId, folderSlug, link.documentId, documentSlug);
return;
}
// handle attachment links
if (link.linkType === "file") {
window.location.href = link.url;
return;
}
} }
}); });
/* /*
link handler
- implement link redirect handler --
- for documents: client-side detect
- for sections:
- for attachments: direct link
-
onDelete document/section/file:
- mark link table row as ORPHAN
- doc view: meta data fetch to load orphaned content
Keyword search results - docs, section, files Keyword search results - docs, section, files
we should not redirect to a link that is in the same document! The link id's get ZERO'd in Page.Body whenever:
what happens if we delete attachment? - doc is moved to different space
UpdatePage(): find and persist links from saved content - doc is deleted (set to ZERO and marked as orphan)
- page is deleted (set to ZERO and marked as orphan)
- page is moved to different doc (update data-document-id attribute value)
- attachment is deleted (remove HREF)
1. We need to deal with links server-side link/section/{documentId}/{sectionId}:
2. We need to click on links in the browser and 'navigate' to linked content - if ZERO id show notification
- store previous positions -- localStorage, dropdown menu?
editor.insertContent('&nbsp;<b>It\'s my button!</b>&nbsp;'); Markdown editor support
Selects the first paragraph found
tinyMCE.activeEditor.selection.select(tinyMCE.activeEditor.dom.select('p')[0]); permission checks:
can view space
can view document
*/ */

View file

@ -41,6 +41,8 @@ export default SimpleAuthSession.extend({
}), }),
init: function () { init: function () {
this._super(...arguments);
this.set('isMac', is.mac()); this.set('isMac', is.mac());
this.set('isMobile', is.mobile()); this.set('isMobile', is.mobile());
}, },

View file

@ -196,7 +196,7 @@ $i: 100;
.width-#{$i} { .width-#{$i} {
width: #{$i}#{"%"}; width: #{$i}#{"%"};
} }
$i: $i - 2; $i: $i - 1;
} }
.no-outline { .no-outline {

View file

@ -1,10 +1,10 @@
.edit-tools { .edit-tools {
margin: 15px 0 0 20px; margin: 0 0 0 20px;
min-height: 500px; min-height: 500px;
} }
.content-linker-dialog { .content-linker-dialog {
width: 300px; width: 350px;
height: 400px; height: 400px;
overflow-y: auto; overflow-y: auto;

View file

@ -0,0 +1,27 @@
.widget-tab {
width: 100%;
margin: 0;
padding: 0 5px;
text-align: center;
border-bottom: 1px solid $color-border;
> .tab {
display: inline-block;
margin: 0;
padding: 5px 10px;
color: $color-off-black;
text-align: center;
cursor: pointer;
@include ease-in();
&:hover {
background-color: $color-off-white;
color: $color-link;
}
}
> .selected {
background-color: $color-off-white;
color: $color-link;
}
}

View file

@ -71,3 +71,4 @@
@import "widget-table"; @import "widget-table";
@import "widget-tooltip"; @import "widget-tooltip";
@import "widget-checkbox"; @import "widget-checkbox";
@import "widget-tab";

View file

@ -4,15 +4,14 @@
<i class="material-icons color-white">link</i> <i class="material-icons color-white">link</i>
</div> </div>
{{#dropdown-dialog target="content-linker-button" focusOn="content-linker-search" position="bottom right" button="Insert" color="flat-blue" onAction=(action 'onInsertLink')}} {{#dropdown-dialog target="content-linker-button" position="bottom right" button="Insert" color="flat-blue" onAction=(action 'onInsertLink')}}
<div class="content-linker-dialog"> <div class="content-linker-dialog">
<form> <form>
<div class="input-control"> {{ui/ui-tab tabs=tabs onTabSelect=(action 'onTabSelect')}}
<label>Insert Link</label>
<div class="tip">Choose content below or search</div> <div class="margin-top-40" />
{{focus-input id="content-linker-search" type="input" value=keywords placeholder="keyword search"}}
</div> {{#if showSections}}
{{#if hasSections}}
<ul class="link-list"> <ul class="link-list">
{{#each candidates.pages as |p|}} {{#each candidates.pages as |p|}}
<li class="link-item" {{ action 'setSelection' p }}> <li class="link-item" {{ action 'setSelection' p }}>
@ -23,7 +22,8 @@
{{/each}} {{/each}}
</ul> </ul>
{{/if}} {{/if}}
{{#if hasAttachments}}
{{#if showAttachments}}
<ul class="link-list"> <ul class="link-list">
{{#each candidates.attachments as |a|}} {{#each candidates.attachments as |a|}}
<li class="link-item" {{ action 'setSelection' a }}> <li class="link-item" {{ action 'setSelection' a }}>
@ -35,6 +35,15 @@
{{/each}} {{/each}}
</ul> </ul>
{{/if}} {{/if}}
{{#if showSearch}}
<div class="input-control">
<label>Search</label>
<div class="tip">keywords</div>
{{focus-input id="content-linker-search" type="input" value=keywords placeholder="keyword search"}}
</div>
{{/if}}
<div class="hide regular-button button-blue pull-right" {{ action 'onInsertLink' }}>Insert</div> <div class="hide regular-button button-blue pull-right" {{ action 'onInsertLink' }}>Insert</div>
<div class="hide clearfix" /> <div class="hide clearfix" />
</form> </form>

View file

@ -0,0 +1,5 @@
<ul class="widget-tab">
{{#each tabs as |tab|}}
<li style={{myWidth}} class="tab {{if tab.selected 'selected'}}" {{action 'onTabSelect' tab}}>{{tab.label}}</li>
{{/each}}
</ul>

View file

@ -29,6 +29,7 @@ func GetLinkCandidates(w http.ResponseWriter, r *http.Request) {
p := request.GetPersister(r) p := request.GetPersister(r)
params := mux.Vars(r) params := mux.Vars(r)
folderID := params["folderID"]
documentID := params["documentID"] documentID := params["documentID"]
pageID := params["pageID"] pageID := params["pageID"]
@ -68,6 +69,7 @@ func GetLinkCandidates(w http.ResponseWriter, r *http.Request) {
if p.RefID != pageID { if p.RefID != pageID {
c := entity.LinkCandidate{ c := entity.LinkCandidate{
RefID: util.UniqueID(), RefID: util.UniqueID(),
FolderID: folderID,
DocumentID: documentID, DocumentID: documentID,
TargetID: p.RefID, TargetID: p.RefID,
LinkType: "section", LinkType: "section",
@ -95,6 +97,7 @@ func GetLinkCandidates(w http.ResponseWriter, r *http.Request) {
for _, f := range files { for _, f := range files {
c := entity.LinkCandidate{ c := entity.LinkCandidate{
RefID: util.UniqueID(), RefID: util.UniqueID(),
FolderID: folderID,
DocumentID: documentID, DocumentID: documentID,
TargetID: f.RefID, TargetID: f.RefID,
LinkType: "file", LinkType: "file",
@ -124,13 +127,3 @@ func GetLinkCandidates(w http.ResponseWriter, r *http.Request) {
util.WriteSuccessBytes(w, json) util.WriteSuccessBytes(w, json)
} }
/*
DocumentID string `json:"documentId"`
PageID string `json:"pageId"`
FileID string `json:"fileId"`
LinkType string `json:"linkType"`
Title string `json:"caption"` // what we label the link
Context string `json:"context"` // additional context (e.g. excerpt, parent)
*/

View file

@ -213,7 +213,7 @@ func init() {
log.IfErr(Add(RoutePrefixPrivate, "sections/refresh", []string{"GET", "OPTIONS"}, nil, RefreshSections)) log.IfErr(Add(RoutePrefixPrivate, "sections/refresh", []string{"GET", "OPTIONS"}, nil, RefreshSections))
// Links // Links
log.IfErr(Add(RoutePrefixPrivate, "links/{documentID}/{pageID}", []string{"GET", "OPTIONS"}, nil, GetLinkCandidates)) log.IfErr(Add(RoutePrefixPrivate, "links/{folderID}/{documentID}/{pageID}", []string{"GET", "OPTIONS"}, nil, GetLinkCandidates))
// Global installation-wide config // Global installation-wide config
log.IfErr(Add(RoutePrefixPrivate, "global", []string{"GET", "OPTIONS"}, nil, GetGlobalConfig)) log.IfErr(Add(RoutePrefixPrivate, "global", []string{"GET", "OPTIONS"}, nil, GetGlobalConfig))

View file

@ -347,6 +347,7 @@ type SitemapDocument struct {
type Link struct { type Link struct {
BaseEntity BaseEntity
OrgID string `json:"orgId"` OrgID string `json:"orgId"`
FolderID string `json:"folderId"`
UserID string `json:"userId"` UserID string `json:"userId"`
LinkType string `json:"linkType"` LinkType string `json:"linkType"`
SourceID string `json:"sourceId"` SourceID string `json:"sourceId"`
@ -359,6 +360,7 @@ type Link struct {
type LinkCandidate struct { type LinkCandidate struct {
RefID string `json:"id"` RefID string `json:"id"`
LinkType string `json:"linkType"` LinkType string `json:"linkType"`
FolderID string `json:"folderId"`
DocumentID string `json:"documentId"` DocumentID string `json:"documentId"`
TargetID string `json:"targetId"` TargetID string `json:"targetId"`
Title string `json:"title"` // what we label the link Title string `json:"title"` // what we label the link

View file

@ -27,7 +27,7 @@ func (p *Persister) AddContentLink(l entity.Link) (err error) {
l.Created = time.Now().UTC() l.Created = time.Now().UTC()
l.Revised = time.Now().UTC() l.Revised = time.Now().UTC()
stmt, err := p.Context.Transaction.Preparex("INSERT INTO link (refid, orgid, userid, sourceid, documentid, targetid, linktype, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)") stmt, err := p.Context.Transaction.Preparex("INSERT INTO link (refid, orgid, folderid, userid, sourceid, documentid, targetid, linktype, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
defer utility.Close(stmt) defer utility.Close(stmt)
if err != nil { if err != nil {
@ -35,7 +35,7 @@ func (p *Persister) AddContentLink(l entity.Link) (err error) {
return return
} }
_, err = stmt.Exec(l.RefID, l.OrgID, l.UserID, l.SourceID, l.DocumentID, l.TargetID, l.LinkType, l.Created, l.Revised) _, err = stmt.Exec(l.RefID, l.OrgID, l.FolderID, l.UserID, l.SourceID, l.DocumentID, l.TargetID, l.LinkType, l.Created, l.Revised)
if err != nil { if err != nil {
log.Error("Unable to execute insert for link", err) log.Error("Unable to execute insert for link", err)
@ -49,7 +49,7 @@ func (p *Persister) AddContentLink(l entity.Link) (err error) {
func (p *Persister) GetReferencedLinks(sectionID string) (links []entity.Link, err error) { func (p *Persister) GetReferencedLinks(sectionID string) (links []entity.Link, err error) {
err = nil err = nil
sql := "SELECT id,refid,orgid,userid,sourceid,documentid,targetid,linktype,orphan,created,revised from link WHERE orgid=? AND sourceid=?" sql := "SELECT id,refid,orgid,folderid,userid,sourceid,documentid,targetid,linktype,orphan,created,revised from link WHERE orgid=? AND sourceid=?"
err = Db.Select(&links, sql, p.Context.OrgID, sectionID) err = Db.Select(&links, sql, p.Context.OrgID, sectionID)
@ -65,7 +65,7 @@ func (p *Persister) GetReferencedLinks(sectionID string) (links []entity.Link, e
func (p *Persister) GetContentLinksForSection(sectionID string) (links []entity.Link, err error) { func (p *Persister) GetContentLinksForSection(sectionID string) (links []entity.Link, err error) {
err = nil err = nil
sql := "SELECT id,refid,orgid,userid,sourceid,documentid,targetid,linktype,orphan,created,revised from link WHERE orgid=? AND sectionid=?" sql := "SELECT id,refid,orgid,folderid,userid,sourceid,documentid,targetid,linktype,orphan,created,revised from link WHERE orgid=? AND sectionid=?"
err = Db.Select(&links, sql, p.Context.OrgID, sectionID) err = Db.Select(&links, sql, p.Context.OrgID, sectionID)
@ -81,7 +81,7 @@ func (p *Persister) GetContentLinksForSection(sectionID string) (links []entity.
func (p *Persister) GetContentLinksForDocument(documentID string) (links []entity.Link, err error) { func (p *Persister) GetContentLinksForDocument(documentID string) (links []entity.Link, err error) {
err = nil err = nil
sql := "SELECT id,refid,orgid,userid,sourceid,documentid,targetid,linktype,orphan,created,revised from link WHERE orgid=? AND documentid=?" sql := "SELECT id,refid,orgid,folderid,userid,sourceid,documentid,targetid,linktype,orphan,created,revised from link WHERE orgid=? AND documentid=?"
err = Db.Select(&links, sql, p.Context.OrgID, documentID) err = Db.Select(&links, sql, p.Context.OrgID, documentID)

View file

@ -287,7 +287,7 @@ func (p *Persister) UpdatePage(page entity.Page, refID, userID string, skipRevis
//} //}
//} //}
// fimnd any content links // find any content links in the HTML
links := util.GetContentLinks(page.Body) links := util.GetContentLinks(page.Body)
// delete previous content links for this page // delete previous content links for this page

View file

@ -14,11 +14,11 @@ package util
import "testing" import "testing"
func TestHTMLEncoding(t *testing.T) { func TestHTMLEncoding(t *testing.T) {
html(t, "<script>alert('test')</script>", "&lt;script&gt;alert(&#39;test&#39;)&lt;/script&gt;") testHTML(t, "<script>alert('test')</script>", "&lt;script&gt;alert(&#39;test&#39;)&lt;/script&gt;")
text(t, "<script>alert('test')</script>", "<script>alert('test')</script>") text(t, "<script>alert('test')</script>", "<script>alert('test')</script>")
} }
func html(t *testing.T, in, out string) { func testHTML(t *testing.T, in, out string) {
got := EncodeHTMLString(in) got := EncodeHTMLString(in)
if got != out { if got != out {
t.Errorf("EncodeHTMLString `%s` got `%s` expected `%s`\n", in, got, out) t.Errorf("EncodeHTMLString `%s` got `%s` expected `%s`\n", in, got, out)

View file

@ -60,6 +60,8 @@ func getLink(t html.Token) (ok bool, link entity.Link) {
ok = true ok = true
case "data-link-id": case "data-link-id":
link.RefID = strings.TrimSpace(a.Val) link.RefID = strings.TrimSpace(a.Val)
case "data-link-space-id":
link.FolderID = strings.TrimSpace(a.Val)
case "data-link-document-id": case "data-link-document-id":
link.DocumentID = strings.TrimSpace(a.Val) link.DocumentID = strings.TrimSpace(a.Val)
case "data-link-target-id": case "data-link-target-id":

View file

@ -319,7 +319,8 @@ CREATE TABLE IF NOT EXISTS `link` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`refid` CHAR(16) NOT NULL COLLATE utf8_bin, `refid` CHAR(16) NOT NULL COLLATE utf8_bin,
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin, `orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
`userid` CHAR(16) DEFAULT '' COLLATE utf8_bin, `folderid` CHAR(16) NOT NULL COLLATE utf8_bin,
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
`sourceid` CHAR(16) NOT NULL COLLATE utf8_bin, `sourceid` CHAR(16) NOT NULL COLLATE utf8_bin,
`linktype` CHAR(16) NOT NULL COLLATE utf8_bin, `linktype` CHAR(16) NOT NULL COLLATE utf8_bin,
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin, `documentid` CHAR(16) NOT NULL COLLATE utf8_bin,

View file

@ -5,7 +5,8 @@ CREATE TABLE IF NOT EXISTS `link` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`refid` CHAR(16) NOT NULL COLLATE utf8_bin, `refid` CHAR(16) NOT NULL COLLATE utf8_bin,
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin, `orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
`userid` CHAR(16) DEFAULT '' COLLATE utf8_bin, `folderid` CHAR(16) NOT NULL COLLATE utf8_bin,
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
`sourceid` CHAR(16) NOT NULL COLLATE utf8_bin, `sourceid` CHAR(16) NOT NULL COLLATE utf8_bin,
`linktype` CHAR(16) NOT NULL COLLATE utf8_bin, `linktype` CHAR(16) NOT NULL COLLATE utf8_bin,
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin, `documentid` CHAR(16) NOT NULL COLLATE utf8_bin,