ox-html: Prevent spurious target below headlines
* lisp/ox-html.el (org-html-headline): (org-html-link): Do not insert an additional target. * lisp/ox-publish.el (org-publish-resolve-external-link): Add an optional argument. * lisp/ox.el (org-export-get-reference): Improve docstring. * testing/examples/pub/a.org: * testing/examples/pub/b.org: New files. * testing/lisp/test-ox-publish.el (test-org-publish/resolve-external-link): New test.
This commit is contained in:
parent
b3ab012d69
commit
007bbddbcc
|
@ -58,6 +58,10 @@ size.
|
|||
,#+STARTUP: shrink
|
||||
#+END_EXAMPLE
|
||||
|
||||
** Miscellaneous
|
||||
|
||||
*** ~org-publish-resolve-external-link~ accepts a new optional argument.
|
||||
|
||||
* Version 9.1
|
||||
|
||||
** Incompatible changes
|
||||
|
|
|
@ -2599,18 +2599,8 @@ holding contextual information."
|
|||
(full-text (funcall (plist-get info :html-format-headline-function)
|
||||
todo todo-type priority text tags info))
|
||||
(contents (or contents ""))
|
||||
(ids (delq nil
|
||||
(list (org-element-property :CUSTOM_ID headline)
|
||||
(org-export-get-reference headline info)
|
||||
(org-element-property :ID headline))))
|
||||
(preferred-id (car ids))
|
||||
(extra-ids
|
||||
(mapconcat
|
||||
(lambda (id)
|
||||
(org-html--anchor
|
||||
(if (org-uuidgen-p id) (concat "ID-" id) id)
|
||||
nil nil info))
|
||||
(cdr ids) "")))
|
||||
(id (or (org-element-property :CUSTOM_ID headline)
|
||||
(org-export-get-reference headline info))))
|
||||
(if (org-export-low-level-p headline info)
|
||||
;; This is a deep sub-tree: export it as a list item.
|
||||
(let* ((html-type (if numberedp "ol" "ul")))
|
||||
|
@ -2619,11 +2609,9 @@ holding contextual information."
|
|||
(apply #'format "<%s class=\"org-%s\">\n"
|
||||
(make-list 2 html-type)))
|
||||
(org-html-format-list-item
|
||||
contents (if numberedp 'ordered 'unordered)
|
||||
nil info nil
|
||||
(concat (org-html--anchor preferred-id nil nil info)
|
||||
extra-ids
|
||||
full-text)) "\n"
|
||||
contents (if numberedp 'ordered 'unordered)
|
||||
nil info nil
|
||||
(concat (org-html--anchor id nil nil info) full-text)) "\n"
|
||||
(and (org-export-last-sibling-p headline info)
|
||||
(format "</%s>\n" html-type))))
|
||||
;; Standard headline. Export it as a section.
|
||||
|
@ -2636,10 +2624,9 @@ holding contextual information."
|
|||
(concat (format "outline-%d" level)
|
||||
(and extra-class " ")
|
||||
extra-class)
|
||||
(format "\n<h%d id=\"%s\">%s%s</h%d>\n"
|
||||
(format "\n<h%d id=\"%s\">%s</h%d>\n"
|
||||
level
|
||||
preferred-id
|
||||
extra-ids
|
||||
id
|
||||
(concat
|
||||
(and numberedp
|
||||
(format
|
||||
|
@ -3010,16 +2997,11 @@ INFO is a plist holding contextual information. See
|
|||
;; relative to a custom-id, a headline title, a name or
|
||||
;; a target.
|
||||
(let ((option (org-element-property :search-option link)))
|
||||
(cond ((not option) raw-path)
|
||||
;; Since HTML back-end use custom-id value as-is,
|
||||
;; resolving is them is trivial.
|
||||
((eq (string-to-char option) ?#) (concat raw-path option))
|
||||
(t
|
||||
(concat raw-path
|
||||
"#"
|
||||
(org-publish-resolve-external-link
|
||||
option
|
||||
(org-element-property :path link)))))))
|
||||
(if (not option) raw-path
|
||||
(let ((path (org-element-property :path link)))
|
||||
(concat raw-path
|
||||
"#"
|
||||
(org-publish-resolve-external-link option path t))))))
|
||||
(t raw-path)))
|
||||
;; Extract attributes from parent's paragraph. HACK: Only do
|
||||
;; this for the first link in parent (inner image link for
|
||||
|
|
|
@ -1131,7 +1131,7 @@ This function is meant to be used as a final output filter. See
|
|||
;; Return output unchanged.
|
||||
output)
|
||||
|
||||
(defun org-publish-resolve-external-link (search file)
|
||||
(defun org-publish-resolve-external-link (search file &optional prefer-custom)
|
||||
"Return reference for element matching string SEARCH in FILE.
|
||||
|
||||
Return value is an internal reference, as a string.
|
||||
|
@ -1139,18 +1139,31 @@ Return value is an internal reference, as a string.
|
|||
This function allows resolving external links with a search
|
||||
option, e.g.,
|
||||
|
||||
[[file.org::*heading][description]]
|
||||
[[file.org::#custom-id][description]]
|
||||
[[file.org::fuzzy][description]]
|
||||
[[file:file.org::*heading][description]]
|
||||
[[file:file.org::#custom-id][description]]
|
||||
[[file:file.org::fuzzy][description]]
|
||||
|
||||
When PREFER-CUSTOM is non-nil, and SEARCH targets a headline in
|
||||
FILE, return its custom ID, if any.
|
||||
|
||||
It only makes sense to use this if export back-end builds
|
||||
references with `org-export-get-reference'."
|
||||
(if (not org-publish-cache)
|
||||
(progn
|
||||
(message "Reference %S in file %S cannot be resolved without publishing"
|
||||
search
|
||||
file)
|
||||
"MissingReference")
|
||||
(cond
|
||||
((and prefer-custom
|
||||
(if (string-prefix-p "#" search)
|
||||
(substring search 1)
|
||||
(with-current-buffer (find-file-noselect file)
|
||||
(org-with-point-at 1
|
||||
(org-link-search search nil t)
|
||||
(and (org-at-heading-p)
|
||||
(org-string-nw-p (org-entry-get (point) "CUSTOM_ID"))))))))
|
||||
((not org-publish-cache)
|
||||
(progn
|
||||
(message "Reference %S in file %S cannot be resolved without publishing"
|
||||
search
|
||||
file)
|
||||
"MissingReference"))
|
||||
(t
|
||||
(let* ((filename (file-truename file))
|
||||
(crossrefs
|
||||
(org-publish-cache-get-file-property filename :crossrefs nil t))
|
||||
|
@ -1167,7 +1180,7 @@ references with `org-export-get-reference'."
|
|||
(let ((new (org-export-new-reference crossrefs)))
|
||||
(dolist (cell cells) (push (cons cell new) crossrefs))
|
||||
(org-publish-cache-set-file-property filename :crossrefs crossrefs)
|
||||
(org-export-format-reference new))))))
|
||||
(org-export-format-reference new)))))))
|
||||
|
||||
|
||||
|
||||
|
|
16
lisp/ox.el
16
lisp/ox.el
|
@ -4436,9 +4436,19 @@ REFERENCE is a number representing a reference, as returned by
|
|||
DATUM is either an element or an object. INFO is the current
|
||||
export state, as a plist.
|
||||
|
||||
This function checks `:crossrefs' property in INFO for search
|
||||
cells matching DATUM before creating a new reference. Returned
|
||||
reference consists of alphanumeric characters only."
|
||||
References for the current document are stored in
|
||||
`:internal-references' property. Its value is an alist with
|
||||
associations of the following types:
|
||||
|
||||
(REFERENCE . DATUM) and (SEARCH-CELL . ID)
|
||||
|
||||
REFERENCE is the reference string to be used for object or
|
||||
element DATUM. SEARCH-CELL is a search cell, as returned by
|
||||
`org-export-search-cells'. ID is a number or a string uniquely
|
||||
identifying DATUM within the document.
|
||||
|
||||
This function also checks `:crossrefs' property for search cells
|
||||
matching DATUM before creating a new reference."
|
||||
(let ((cache (plist-get info :internal-references)))
|
||||
(or (car (rassq datum cache))
|
||||
(let* ((crossrefs (plist-get info :crossrefs))
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
#+title: A
|
||||
#+date: <2014-03-04 Tue>
|
||||
|
||||
Contents
|
||||
* Headline1
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: a1
|
||||
:END:
|
||||
|
||||
[[file:b.org::*Headline1]]
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#+title: b
|
||||
#+date: <2012-03-29 Thu>
|
||||
|
||||
* Headline1
|
||||
|
||||
[[file:a.org::#a1]]
|
||||
|
|
|
@ -94,7 +94,6 @@ Unless set otherwise in PROPERTIES, `:base-directory' is set to
|
|||
(cl-remove-if #'file-directory-p
|
||||
(directory-files dir))))))))
|
||||
|
||||
|
||||
|
||||
;;; Site-map
|
||||
|
||||
|
@ -327,6 +326,68 @@ Unless set otherwise in PROPERTIES, `:base-directory' is set to
|
|||
(insert-file-contents (expand-file-name "sitemap.org" dir))
|
||||
(buffer-string)))))))
|
||||
|
||||
|
||||
;;; Cross references
|
||||
|
||||
(ert-deftest test-org-publish/resolve-external-link ()
|
||||
"Test `org-publish-resolve-external-link' specifications."
|
||||
;; Function should preserve internal reference when used between
|
||||
;; published files.
|
||||
(should
|
||||
(apply
|
||||
#'equal
|
||||
(let* ((ids nil)
|
||||
(backend
|
||||
(org-export-create-backend
|
||||
:transcoders
|
||||
'((headline . (lambda (h c i)
|
||||
(concat (org-export-get-reference h i) " " c)))
|
||||
(paragraph . (lambda (p c i) c))
|
||||
(section . (lambda (s c i) c))
|
||||
(link . (lambda (l c i)
|
||||
(let ((option (org-element-property :search-option l))
|
||||
(path (org-element-property :path l)))
|
||||
(and option
|
||||
(org-publish-resolve-external-link
|
||||
option path))))))))
|
||||
(publish
|
||||
(lambda (plist filename pub-dir)
|
||||
(org-publish-org-to backend filename ".test" plist pub-dir))))
|
||||
(org-test-publish
|
||||
(list :publishing-function (list publish))
|
||||
(lambda (dir)
|
||||
(cl-subseq
|
||||
(split-string
|
||||
(mapconcat (lambda (f) (org-file-contents (expand-file-name f dir)))
|
||||
(directory-files dir nil "\\.test\\'")
|
||||
" "))
|
||||
1 3))))))
|
||||
;; When optional argument PREFER-CUSTOM is non-nil, use custom ID
|
||||
;; instead of internal reference, whenever possible.
|
||||
(should
|
||||
(equal
|
||||
"a1"
|
||||
(let* ((ids nil)
|
||||
(backend
|
||||
(org-export-create-backend
|
||||
:transcoders
|
||||
'((headline . (lambda (h c i) c))
|
||||
(paragraph . (lambda (p c i) c))
|
||||
(section . (lambda (s c i) c))
|
||||
(link . (lambda (l c i)
|
||||
(let ((option (org-element-property :search-option l))
|
||||
(path (org-element-property :path l)))
|
||||
(when option
|
||||
(throw :exit (org-publish-resolve-external-link
|
||||
option path t)))))))))
|
||||
(publish
|
||||
(lambda (plist filename pub-dir)
|
||||
(push (catch :exit
|
||||
(org-publish-org-to backend filename ".test" plist pub-dir))
|
||||
ids))))
|
||||
(org-test-publish (list :publishing-function (list publish)) #'ignore)
|
||||
(car ids)))))
|
||||
|
||||
|
||||
;;; Tools
|
||||
|
||||
|
|
Loading…
Reference in New Issue