From b20ae9f2cc1af67250af9917541b071ab778f36f Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Mon, 1 Jul 2013 22:51:26 +0200 Subject: [PATCH] ox-html: Fix standalone hyperlinked images * lisp/ox-html.el (org-html-inline-images): Change default value and remove `maybe'. (org-html-format-inline-image): Remove functions. (org-html--wrap-image, org-html--format-image, org-html-inline-image-p): New functions. (org-html-latex-environment, org-html-latex-fragment): Use new functions. (org-html-standalone-image-p): Use new functions. Also remove an unused optional argument. (org-html-link, org-html-paragraph): Correctly export hyperlinked images. This patch permits the back-end to recognize links like: [[http://orgmode.org][http://orgmode.org/img/org-mode-unicorn-logo.png]] as standalone, so they can get wrapped within a proper environment and get captions. Thanks to Kodi Arfer for reporting it. --- lisp/ox-html.el | 257 +++++++++++++++++++++++++++----------------------------- 1 file changed, 124 insertions(+), 133 deletions(-) diff --git a/lisp/ox-html.el b/lisp/ox-html.el index 4753e66..b8d927f 100644 --- a/lisp/ox-html.el +++ b/lisp/ox-html.el @@ -713,16 +713,14 @@ When nil, the links still point to the plain `.org' file." ;;;; Links :: Inline images -(defcustom org-html-inline-images 'maybe +(defcustom org-html-inline-images t "Non-nil means inline images into exported HTML pages. This is done using an tag. When nil, an anchor with href is used to -link to the image. If this option is `maybe', then images in links with -an empty description will be inlined, while images with a description will -be linked only." +link to the image." :group 'org-export-html - :type '(choice (const :tag "Never" nil) - (const :tag "Always" t) - (const :tag "When there is no description" maybe))) + :version "24.4" + :package-version '(Org . "8.1") + :type 'boolean) (defcustom org-html-inline-image-rules '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'") @@ -1326,39 +1324,43 @@ attributes with a nil value will be omitted from the result." "\"" """ (org-html-encode-plain-text item)))) (setcar output (format "%s=\"%s\"" key value)))))))) -(defun org-html-format-inline-image (src info &optional - caption label attr standalone-p) - "Format an inline image from SRC. -CAPTION, LABEL and ATTR are optional arguments providing the -caption, the label and the attribute of the image. -When STANDALONE-P is t, wrap the into a
...
." - (let* ((id (if (not label) "" - (format " id=\"%s\"" (org-export-solidify-link-text label)))) - (attr (concat attr - (format " src=\"%s\"" src) - (cond - ((string-match "\\%s%s\n" - "\n%s%s\n") - id (format "\n

%s

" img) - (if (and caption (not (string= caption ""))) - (format (if html5-fancy - "\n
%s
" - "\n

%s

") caption) "")))) - (t (org-html-close-tag "img" (concat attr id) info))))) +(defun org-html--wrap-image (contents info &optional caption label) + "Wrap CONTENTS string within an appropriate environment for images. +INFO is a plist used as a communication channel. When optional +arguments CAPTION and LABEL are given, use them for caption and +\"id\" attribute." + (let ((html5-fancy (and (org-html-html5-p info) + (plist-get info :html-html5-fancy)))) + (format (if html5-fancy "\n%s%s\n" + "\n%s%s\n") + ;; ID. + (if (not (org-string-nw-p label)) "" + (format " id=\"%s\"" (org-export-solidify-link-text label))) + ;; Contents. + (format "\n

%s

" contents) + ;; Caption. + (if (not (org-string-nw-p caption)) "" + (format (if html5-fancy "\n
%s
" + "\n

%s

") + caption))))) + +(defun org-html--format-image (source attributes info) + "Return \"img\" tag with given SOURCE and ATTRIBUTES. +SOURCE is a string specifying the location of the image. +ATTRIBUTES is a plist, as returned by +`org-export-read-attribute'. INFO is a plist used as +a communication channel." + (org-html-close-tag + "img" + (org-html--make-attribute-string + (org-combine-plists + (list :src source + :alt (if (string-match-p "^ltxpng/" source) + (org-html-encode-plain-text + (org-find-text-property-in-string 'org-latex-src source)) + (file-name-nondirectory source))) + attributes)) + info)) (defun org-html--textarea-block (element) "Transcode ELEMENT into a textarea block. @@ -2478,21 +2480,19 @@ CONTENTS is nil. INFO is a plist holding contextual information." (let ((processing-type (plist-get info :with-latex)) (latex-frag (org-remove-indentation (org-element-property :value latex-environment))) - (caption (org-export-data - (org-export-get-caption latex-environment) info)) - (attr nil) ; FIXME - (label (org-element-property :name latex-environment))) - (cond - ((memq processing-type '(t mathjax)) - (org-html-format-latex latex-frag 'mathjax)) - ((eq processing-type 'dvipng) - (let* ((formula-link (org-html-format-latex - latex-frag processing-type))) - (when (and formula-link - (string-match "file:\\([^]]*\\)" formula-link)) - (org-html-format-inline-image - (match-string 1 formula-link) info caption label attr t)))) - (t latex-frag)))) + (attributes (org-export-read-attribute :attr_html latex-environment))) + (case processing-type + ((t mathjax) + (org-html-format-latex latex-frag 'mathjax)) + (dvipng + (let ((formula-link (org-html-format-latex latex-frag processing-type))) + (when (and formula-link (string-match "file:\\([^]]*\\)" formula-link)) + ;; Do not provide a caption or a name to be consistent with + ;; `mathjax' handling. + (org-html--wrap-image + (org-html--format-image + (match-string 1 formula-link) attributes info) info)))) + (t latex-frag)))) ;;;; Latex Fragment @@ -2505,12 +2505,9 @@ CONTENTS is nil. INFO is a plist holding contextual information." ((t mathjax) (org-html-format-latex latex-frag 'mathjax)) (dvipng - (let* ((formula-link (org-html-format-latex - latex-frag processing-type))) - (when (and formula-link - (string-match "file:\\([^]]*\\)" formula-link)) - (org-html-format-inline-image - (match-string 1 formula-link) info)))) + (let ((formula-link (org-html-format-latex latex-frag processing-type))) + (when (and formula-link (string-match "file:\\([^]]*\\)" formula-link)) + (org-html--format-image (match-string 1 formula-link) nil info)))) (t latex-frag)))) ;;;; Line Break @@ -2522,41 +2519,30 @@ CONTENTS is nil. INFO is a plist holding contextual information." ;;;; Link -(defun org-html-link--inline-image (link desc info) - "Return HTML code for an inline image. - -LINK is the link pointing to the inline image. INFO is a plist -used as a communication channel. - -Inline images can have these attributes: - -#+ATTR_HTML: :width 100px :height 100px :alt \"Alt description\"." - (let* ((type (org-element-property :type link)) - (raw-path (org-element-property :path link)) - (path (cond ((member type '("http" "https")) - (concat type ":" raw-path)) - ((file-name-absolute-p raw-path) - (expand-file-name raw-path)) - (t raw-path))) - (parent (org-export-get-parent-element link)) - (caption - (let ((raw (org-export-data (org-export-get-caption parent) info)) - (org-html-standalone-image-predicate 'org-html--has-caption-p)) - (if (not (org-string-nw-p raw)) raw - (concat (format (org-html--translate "Figure %d:" info) - (org-export-get-ordinal - link info nil 'org-html-standalone-image-p)) - " " raw)))) - (label (org-element-property :name parent))) - ;; Return proper string, depending on DISPOSITION. - (org-html-format-inline-image - path info caption label - (org-html--make-attribute-string - (org-export-read-attribute :attr_html parent)) - (org-html-standalone-image-p link info)))) +(defun org-html-inline-image-p (link info) + "Non-nil when LINK stands for an inline image. +INFO is a plist used as a communication channel. LINK is an +inline image when it has no description and targets an image +file (see `org-html-inline-image-rules' for more information), or +if its description is a single link targeting an image file." + (if (not (org-element-contents link)) + (org-export-inline-image-p link org-html-inline-image-rules) + (not + (let ((link-count 0)) + (org-element-map (org-element-contents link) + (cons 'plain-text org-element-all-objects) + (lambda (obj) + (case (org-element-type obj) + (plain-text (org-string-nw-p obj)) + (link (if (= link-count 1) t + (incf link-count) + (not (org-export-inline-image-p + obj org-html-inline-image-rules)))) + (otherwise t))) + info t))))) (defvar org-html-standalone-image-predicate) -(defun org-html-standalone-image-p (element info &optional predicate) +(defun org-html-standalone-image-p (element info) "Test if ELEMENT is a standalone image for the purpose HTML export. INFO is a plist holding contextual information. @@ -2570,34 +2556,29 @@ whitespaces. Return nil, otherwise. -Bind `org-html-standalone-image-predicate' to constrain -paragraph further. For example, to check for only captioned -standalone images, do the following. +Bind `org-html-standalone-image-predicate' to constrain paragraph +further. For example, to check for only captioned standalone +images, set it to: - \(setq org-html-standalone-image-predicate - \(lambda \(paragraph\) - \(org-element-property :caption paragraph\)\)\)" + \(lambda (paragraph) (org-element-property :caption paragraph))" (let ((paragraph (case (org-element-type element) (paragraph element) - (link (and (org-export-inline-image-p - element org-html-inline-image-rules) - (org-export-get-parent element))) - (t nil)))) - (when (eq (org-element-type paragraph) 'paragraph) - (when (or (not (and (boundp 'org-html-standalone-image-predicate) - (functionp org-html-standalone-image-predicate))) - (funcall org-html-standalone-image-predicate paragraph)) - (let ((contents (org-element-contents paragraph))) - (loop for x in contents - with inline-image-count = 0 - always (cond - ((eq (org-element-type x) 'plain-text) - (not (org-string-nw-p x))) - ((eq (org-element-type x) 'link) - (when (org-export-inline-image-p - x org-html-inline-image-rules) - (= (incf inline-image-count) 1))) - (t nil)))))))) + (link (and (org-html-inline-image-p element info) + (org-export-get-parent element)))))) + (and (eq (org-element-type paragraph) 'paragraph) + (or (not (and (boundp 'org-html-standalone-image-predicate) + (functionp org-html-standalone-image-predicate))) + (funcall org-html-standalone-image-predicate paragraph)) + (not (let ((link-count 0)) + (org-element-map (org-element-contents paragraph) + (cons 'plain-text org-element-all-objects) + (lambda (obj) (case (org-element-type obj) + (plain-text (org-string-nw-p obj)) + (link + (or (> (incf link-count) 1) + (not (org-html-inline-image-p obj info)))) + (otherwise t))) + info 'first-match 'link)))))) (defun org-html-link (link desc info) "Transcode a LINK object from Org to HTML. @@ -2656,22 +2637,17 @@ INFO is a plist holding contextual information. See ;; Extract attributes from parent's paragraph. HACK: Only do ;; this for the first link in parent. This is needed as long ;; as attributes cannot be set on a per link basis. - (attributes + (attributes-plist (let ((parent (org-export-get-parent-element link))) - (if (not (eq (org-element-map parent 'link 'identity info t) link)) - "" - (let ((att (org-html--make-attribute-string - (org-export-read-attribute :attr_html parent)))) - (cond ((not (org-string-nw-p att)) "") - ((and desc (string-match (regexp-quote att) desc)) "") - (t (concat " " att))))))) + (and (eq (org-element-map parent 'link 'identity info t) link) + (org-export-read-attribute :attr_html parent)))) + (attributes (org-html--make-attribute-string attributes-plist)) protocol) (cond ;; Image file. - ((and (or (eq t org-html-inline-images) - (and org-html-inline-images (not desc))) + ((and org-html-inline-images (org-export-inline-image-p link org-html-inline-image-rules)) - (org-html-link--inline-image link desc info)) + (org-html--format-image path attributes-plist info)) ;; Radio target: Transcode target's contents and use them as ;; link's description. ((string= type "radio") @@ -2791,11 +2767,26 @@ the plist used as a communication channel." ((and (eq (org-element-type parent) 'item) (= (org-element-property :begin paragraph) (org-element-property :contents-begin parent))) - ;; leading paragraph in a list item have no tags + ;; Leading paragraph in a list item have no tags. contents) ((org-html-standalone-image-p paragraph info) - ;; standalone image - contents) + ;; Standalone image. + (let ((caption + (let ((raw (org-export-data + (org-export-get-caption paragraph) info)) + (org-html-standalone-image-predicate + 'org-html--has-caption-p)) + (if (not (org-string-nw-p raw)) raw + (concat + (format (org-html--translate "Figure %d:" info) + (org-export-get-ordinal + (org-element-map paragraph 'link + 'identity info t) + info nil 'org-html-standalone-image-p)) + " " raw)))) + (label (org-element-property :name paragraph))) + (org-html--wrap-image contents info caption label))) + ;; Regular paragraph. (t (format "\n%s

" extra contents))))) ;;;; Plain List -- 1.8.3.2