emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* another blog exporter
@ 2014-02-07 17:10 Robert Klein
  2014-02-07 17:35 ` Rasmus
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Robert Klein @ 2014-02-07 17:10 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 461 bytes --]

Hi,

around the org-mode 8.0 release I began to write a new blog exporter
using the new export framework.

I wanted one feature org2blog didn't offer, support for different syntax
highlighters, and i wanted to learn about the new exporter and Emacs
programming.

Around Christmas I did some polishing to make it ready for a greater public.

Would there a place for it in contrib/ or is it better suited for a
github repository?

Thanks and best regards
Robert


[-- Attachment #2: ox-blog.el --]
[-- Type: text/x-emacs-lisp, Size: 47221 bytes --]

;;; ox-blog.el --- Blog Back-End for Org Export Engine

;; Copyright (C) 2013, 2014  Robert Klein

;; Author: Robert Klein <roklein at roklein dot de>
;; Keywords: WordPress, HTML

;; This file is not part of GNU Emacs.

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;; This library implements an blog back-end for the Org
;; generic exporter.

;; To test it, run:
;;
;;   M-x org-blog-export-as-html
;;
;; in an Org mode buffer.  See ox.el and ox-html.el for more details
;; on how this exporter works.
\f
;;; Code:
(require 'ox-html)  ;; in turn requires ox-publish and ox.
(require 'xml-rpc)
; (require 'wp-xml-rpc)
; (require 'cl)

(org-export-define-derived-backend 'blog 'html
  :menu-entry
  '(?b "Export to WP Blog Presentation"
       ((?H "To temporary buffer" org-blog-export-as-html)
	(?h "To file" org-blog-export-to-html)
        (?d "To blog as draft" org-blog-export-to-blog-as-draft)
        (?p "To blog and publish" org-blog-export-to-blog-as-publish)
	(?o "To file and open"
	    (lambda (a s v b)
	      (if a (org-blog-export-to-html t s v b)
		(org-open-file (org-blog-export-to-html nil s v b)))))))
  :options-alist
  '((:blog-url "BLOG_URL" nil nil t)
    (:blog-username "BLOG_USERNAME" nil nil t)
    (:blog-id "BLOG_ID" nil nil t)
    (:blog-password "BLOG_PASSWORD" nil nil t)
    (:blog-post-id "BLOG_POST_ID" nil nil t)
    (:blog-publish-datetime "BLOG_PUBLISH_DATETIME" nil nil t)
    (:blog-post-type "BLOG_POST_TYPE" "post-type" org-blog-post-type t)
    (:blog-syntax-highlighter "BLOG_SYNTAX_HIGHLIGHTER" "bloghl"
                              org-blog-syntax-highlighter t)
    (:blog-timezone "BLOG_TIMEZONE" "blogtz" nil t)
    (:blog-tags "BLOG_TAGS" nil org-blog-tags newline)
    (:blog-confirm-new-tags "BLOG_CONFIRM_NEW_TAGS" nil
                            org-blog-confirm-new-tags t)
    (:blog-categories "BLOG_CATEGORIES" nil org-blog-categories newline)
    (:blog-confirm-new-categories "BLOG_CONFIRM_NEW_CATEGORIES"
                                  nil org-blog-confirm-new-categories t)
    (:blog-use-tags-as-categories "BLOG_USE_TAGS_AS_CATEGORIES" nil nil t)
    (:blog-upload-filetypes "BLOG_UPLOAD_FILETYPES" nil org-blog-upload-filetypes split))
  :translate-alist
  '(;(inner-template . org-blog-inner-template) ;; use org-html-inner-template
    (example-block . org-blog-example-block)
    (keyword . org-blog-keyword)
    (latex-environment . org-blog-latex-environment)
    (latex-fragment . org-blog-latex-fragment)
    (link . org-blog-link)
    (src-block . org-blog-src-block)
    (template . org-blog-template)))


\f
;;; Internal variables

;(defvar org-blog-id 1
;  "ID of blog.  Typically 1.")


(defvar org-blog-files-to-upload nil
  "A list containing the file names to upload to the blog.")


(defvar org-blog-image-list nil
  "Images to upload/change URL in buffer.")

\f
;;; User Configuration Variables

(defgroup org-export-blog nil
  "Options for exporting Org mode files to a wordpress based blog."
  :tag "Org Export Blog"
  :group 'org-export)

(defcustom org-blog-project-alist nil
  "Association list to control blog publication behavior.
Eash element of the alist is a blog 'project.'  The CAR of each
element is a string, uniquely identifying the project.  The CDR
of each element is in the following form:

1. A well-formed property list with an even number of elements,
   alternating keys and values, specifying parameters for the
   publishing process.

When a property is given a value in `org-blog-project-alist',
its setting overrides the value of the corresponding user
variable (if any) during publishing.  However, options set within
a file override everything.

Most properties are optional, but some should always be set:

  `:base-directory'

    Directory containing publishing source files.

  `:blog-url'

    Blog where posts will be published.

  `:blog-id'

    Blog ID; usually `1'.

Some properties control details of the Org publishing process,
and are equivalent to the corresponding user variables listed in
the right column.  Back-end specific properties may also be
included.  See the back-end documentation for more information.

  :user-name              `org-blog-username'
  :syntax-highlighter     `org-blog-syntax-highlighter'
  :tags                   `org-blog-tags'
  :confirm-new-tags       `org-blog-confirm-new-tags'
  :categories             `org-blog-categories'
  :confirm-new-categories `org-blog0confirm-new-categories'
  :upload-filetypes       `org-blog-upload-filetypes'"
  :group 'org-export-blog
  :type 'alist)




(defcustom org-blog-post-type "post"
  "Post yype of blog post (post/page).
Defaults to \"post\"."
  :group 'org-export-blog
  :type '(choice
          (const :tag "Post" "post")
          (const :tag "Page" "page")))

(defcustom org-blog-syntax-highlighter "org-mode"
  "Syntax highlighter to be used.
Defaults to \"org-mode\"."
  :group 'org-export-blog
  :type '(choice
          (const :tag "org-mode" "org-mode")
          (const :tag "WP-Syntax" "wp-syntax")
          (const :tag "Alex Gorbatchev's SyntaxHighlighter" "syntaxhighlighter")
          (const :tag "wordpress.com SyntaxHighlighter" "wordpress.com")))


(defcustom org-blog-tags ""
  "Tags for the blog post."
  :group 'org-export-blog
  :type 'string)

(defcustom org-blog-confirm-new-tags nil
  "When non-nil new tags must be confirmed by the user."
  :group 'org-export-blog
  :type 'boolean)

(defcustom org-blog-categories ""
  "Categories for the blog post."
  :group 'org-export-blog
  :type 'string)

(defcustom org-blog-confirm-new-categories t
  "When non-nil new categories must be confirmed by the user."
  :group 'org-export-blog
  :type 'boolean)

(defcustom org-blog-upload-filetypes '("jpg" "jpeg" "png" "gif"
                                       "pdf" "doc" "docx" "odt"
                                       "xls" "xslx"
                                       "ppt" "pptx" "pps" "ppsx"
                                       "mp3" "m4a" "ogg" "wav"
                                       "mp4" "m4v" "mov" "wmv" "avi"
                                       "mpg" "ogv" "3gp" "3g2")
  "file types to upload to blog when linked via file://"
  :group 'org-export-blog
  :type 'list)
\f

(defconst org-blog-syntax-highlighter-alist
 ; "
 ; 
 ;   - beginning-of-tag, e.g. '<'
 ;   - ending of tag, e.g. '>'
 ;   - tag, e.g. 'pre'
 ;   - tag end marker, e.g. '/'
 ;   - keyword for language, e.g. 'class' (for <pre class=...)
 ;   - default class, if no language defined
 ;   - list of supported highlighter language identifiers
 ;     (for org-mode a list of major emacs mode languages; they'll
 ;      be colorized w/ htmlize.el )
 ;   - alist mapping of org-babel language identifier and
 ;     highlighter language identifier
 ; 
 ;"
  '(("org-mode" .
     ("<" ">" "pre" "/" "class" "example"
      (list "asymptote" "awk" "C" "cpp" "calc" "clojure" "css" "ditaa" "dot"
            "emacs-lisp" "euklides" "formus" "F90" "gnuplot" "haskell" "java"
            "js" "latex" "ledger" "ly" "lisp" "makefile" "mathomatic" "matlab" "max"
            "mscgen" "ocaml" "octave" "org" "oz" "perl" "picolisp" "plantuml"
            "python" "R" "ruby" "sass" "scheme" "shen" "sh" "sql" "sqlite"
            "tcl"
            ;; above are the official babel and babel contrib languages
            ;; below are more names of emacs langeage-modes which can be edited
            ;; in latex src blocks, but not executed.
            "html" "nxhtml" "nxml")
      (list ("text" . "example"))))
    ("syntaxhighlighter" .
     ("[" "]" "sourcecode" "/" "language"
       "text"
       (list "actionscript3" "as3"
             "applescript"
             "bash" "shell"
             "c#" "c-sharp" "csharp"
             "coldfusion""cf"
             "cpp" "c"
             "css"
             "delphi" "pascal" "pas"
             "diff" "patch"
             "erl" "erlang"
             "groovy"
             "js" "jscript" "javascript"
             "java"
             "jfx" "javafx"
             "perl" "Perl" "pl"
             "php"
             "text" "plain"
             "powershell" "ps"
             "py" "python"
             "ruby" "rails" "ror" "rb"
             "sass" "scss"
             "scala"
             "sql"
             "vb" "vbnet"
             "xml" "xhtml" "xslt" "html")
       (list ("C" . "c")
             ("R" . "r")
             ("emacs-lisp" . "lisp")
             ("elisp" . "lisp")
             ("sh" . "bash"))))
    ("wordpress.com" .
     ("[" "]" "code" "/" "language"
       "text"
       (list "actionscript3" "bash" "clojure" "coldfusion" "cpp" "csharp"
             "css" "delphi" "erlang" "fsharp" "diff" "groovy" "html"
             "javascript" "java" "javafx" "matlab" "objc" "perl" "php"
             "text" "powershell" "python" "r" "ruby" "scala" "sql" "vb"
             "xml")
       (list ("R" . "r")
             ("emacs-lisp" . "lisp")
             ("elisp" . "lisp")
             ("sh" . "bash"))))
    ("wp-syntax" . 
     ("<" ">" "pre" "/" "lang"
       "text"
       (list "4cs" "6502acme" "6502kickass" "6502tasm" "68000devpac" "abap"
             "actionscript3" "actionscript" "ada" "algol68" "apache"
             "applescript" "apt_sources" "arm" "asm" "asp" "asymptote"
             "autoconf" "autohotkey" "autoit" "avisynth" "awk" "bascomavr"
             "bash" "basic4gl" "bf" "bibtex" "blitzbasic" "bnf" "boo"
             "caddcl" "cadlisp" "cfdg" "cfm" "chaiscript" "cil"
             "c_loadrunner" "clojure" "c_mac" "cmake" "cobol" "coffeescript"
             "c" "cpp" "cpp-qt" "csharp" "css" "cuesheet" "dcl" "dcpu16"
             "dcs" "delphi" "diff" "div" "dos" "dot" "d" "ecmascript"
             "eiffel" "email" "epc" "e" "erlang" "euphoria" "f1" "falcon"
             "fo" "fortran" "freebasic" "freeswitch" "fsharp" "gambas" "gdb"
             "genero" "genie" "gettext" "glsl" "gml" "gnuplot" "go" "groovy"
             "gwbasic" "haskell" "haxe" "hicest" "hq9plus" "html4strict"
             "html5" "icon" "idl" "ini" "inno" "intercal" "io" "java5"
             "java" "javascript" "j" "jquery" "kixtart" "klonec" "klonecpp"
             "latex" "lb" "ldif" "lisp" "llvm" "locobasic" "logtalk"
             "lolcode" "lotusformulas" "lotusscript" "lscript" "lsl2" "lua"
             "m68k" "magiksf" "make" "mapbasic" "matlab" "mirc" "mmix"
             "modula2" "modula3" "mpasm" "mxml" "mysql" "nagios" "netrexx"
             "newlisp" "nsis" "oberon2" "objc" "objeck" "ocaml-brief"
             "ocaml" "octave" "oobas" "oorexx" "oracle11" "oracle8"
             "oxygene" "oz" "parasail" "parigp" "pascal" "pcre" "perl6"
             "perl" "per" "pf" "php-brief" "php" "pic16" "pike"
             "pixelbender" "pli" "plsql" "postgresql" "povray"
             "powerbuilder" "powershell" "proftpd" "progress" "prolog"
             "properties" "providex" "purebasic" "pycon" "pys60" "python"
             "qbasic" "q" "rails" "rebol" "reg" "rexx" "robots" "rpmspec"
             "rsplus" "ruby" "sas" "scala" "scheme" "scilab" "sdlbasic"
             "smalltalk" "smarty" "spark" "sparql" "sql" "stonescript"
             "systemverilog" "tcl" "teraterm" "text" "thinbasic" "tsql"
             "typoscript" "unicon" "upc" "urbi" "uscript" "vala" "vbnet"
             "vb" "vedit" "verilog" "vhdl" "vim" "visualfoxpro"
             "visualprolog" "whitespace" "whois" "winbatch" "xbasic" "xml"
             "xorg_conf" "xpp" "yaml" "z80" "zxbasic")
       (list ("emacs-lisp" . "lisp")
             ("elisp" . "lisp")
             ("sh" . "bash"))))))

;; e.g.
;;(nth 1 (cdr (assoc "syntaxhighlighter" org-blog-syntax-highlighter-alist)))
;;(nth 2 (cdr (assoc "syntaxhighlighter" org-blog-syntax-highlighter-alist)))
;;(nth 3 (cdr (assoc "syntaxhighlighter" org-blog-syntax-highlighter-alist)))
;;(nth 4 (cdr (assoc "syntaxhighlighter" org-blog-syntax-highlighter-alist)))
;;(nth 5 (cdr (assoc "syntaxhighlighter" org-blog-syntax-highlighter-alist)))
;;(nth 6 (cdr (assoc "syntaxhighlighter" org-blog-syntax-highlighter-alist)))
;;(nth 7 (cdr (assoc "syntaxhighlighter" org-blog-syntax-highlighter-alist)))
;;(cdr (assoc "emacs-lisp" (nth 8 (cdr (assoc "syntaxhighlighter" org-blog-syntax-highlighter-alist)))))
;;;; nth > anzahl der elemente = nil
;;(nth 10 (cdr (assoc "syntaxhighlighter" org-blog-syntax-highlighter-alist)))



\f
;;; Internal Functions
(defun org-blog--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."
  ;; #+CAPTION: support (see
  ;;            http://codex.wordpress.org/Wrapping_Text_Around_Images)
  (message "attributes in format-image: %s" attributes)
  (cdar
   (add-to-list
    'org-blog-image-list
    `(,source
      .
      ,(org-html-close-tag
        "img"
        (org-html--make-attribute-string
         ;; attributes first, because we want the style to
         ;; be added without the quotes.
         (org-combine-plists
          attributes
          (let ((tmplist
                 (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))))
                (align  (org-element-interpret-data (plist-get attributes :align)))
                (style  (org-element-interpret-data (plist-get attributes :style))))
            (when (not (string= "" align))
              (add-to-list 'tmplist (concat "align" align))
              (add-to-list 'tmplist :class))
            (when (not (string= "" style))
              (add-to-list 'tmplist (substring style 1 -1))
              (add-to-list 'tmplist :style))
            tmplist)))
        info)))))

\f
;;; Transcode Functions

;;;; Example Block

(defun org-blog-example-block (example-block contents info)
  "Transcode a EXAMPLE-BLOCK element from Org to HTML.
CONTENTS is nil.  INFO is a plist holding contextual
information."
  (if (org-export-read-attribute :attr_html example-block :textarea)
      (org-html--textarea-block example-block)
    ;;; beginnin here we need org/wp-syntac/syntaxhl information!!!!
    (format "<pre class=\"example\">\n%s</pre>"
	    (org-html-format-code example-block info))))

;;;; Latex Environment

(defun org-blog-latex-environment (latex-environment contents info)
  "Transcode a LATEX-ENVIRONMENT element from Org to HTML.
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)))
	(attributes (org-combine-plists
                     (org-export-read-attribute :attr_html latex-environment)
                     (org-export-read-attribute :attr_blog latex-environment))))
    (case processing-type
      ((t mathjax)
       (org-html-format-latex latex-frag 'mathjax info))
      ((dvipng imagemagick)
       (let ((formula-link
	      (org-html-format-latex latex-frag processing-type info)))
	 (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-blog--format-image
	     (match-string 1 formula-link) attributes info) info))))
      (t latex-frag))))


;;;; Latex Fragment

(defun org-blog-latex-fragment (latex-fragment contents info)
  "Transcode a LATEX-FRAGMENT object from Org to HTML.
CONTENTS is nil.  INFO is a plist holding contextual information."
  (let ((latex-frag (org-element-property :value latex-fragment))
	(processing-type (plist-get info :with-latex)))
    (case processing-type
      ((t mathjax)
       (org-html-format-latex latex-frag 'mathjax info))
      ((dvipng imagemagick)
       (let ((formula-link
	      (org-html-format-latex latex-frag processing-type info)))
	 (when (and formula-link (string-match "file:\\([^]]*\\)" formula-link))
	   (org-blog--format-image (match-string 1 formula-link) nil info))))
      (t latex-frag))))

;;;; Link

(defun org-blog-link (link desc info)
  "Transcode a LINK object from Org to HTML.

DESC is the description part of the link, or the empty string.
INFO is a plist holding contextual information.  See
`org-export-data'."
  (let* ((home (when (plist-get info :html-link-home)
		 (org-trim (plist-get info :html-link-home))))
	 (use-abs-url (plist-get info :html-link-use-abs-url))
	 (link-org-files-as-html-maybe
	  (function
	   (lambda (raw-path info)
	     "Treat links to `file.org' as links to `file.html', if needed.
           See `org-html-link-org-files-as-html'."
	     (cond
	      ((and org-html-link-org-files-as-html
		    (string= ".org"
			     (downcase (file-name-extension raw-path "."))))
	       (concat (file-name-sans-extension raw-path) "."
		       (plist-get info :html-extension)))
	      (t raw-path)))))
	 (type (org-element-property :type link))
	 (raw-path (org-element-property :path link))
	 ;; Ensure DESC really exists, or set it to nil.
	 (desc (org-string-nw-p desc))
	 (path
	  (cond
	   ((member type '("http" "https" "ftp" "mailto"))
	    (concat type ":" raw-path))
	   ((string= type "file")
	    ;; Links to ".org" files are just that in 'blog export,
	    ;; so we do not set the raw-path to a .html link.
            ;;
	    ;; If file path is absolute, prepend it with protocol
	    ;; component - "file://".
	    (cond ((file-name-absolute-p raw-path)
		   (setq raw-path
			 (concat "file://" (expand-file-name
					    raw-path))))
		  ((and home use-abs-url)
		   (setq raw-path (concat (file-name-as-directory home) raw-path))))
	    ;; Add search option, if any.  A search option can be
	    ;; relative to a custom-id or a headline title.  Any other
	    ;; option is ignored.
	    (let ((option (org-element-property :search-option link)))
	      (cond ((not option) raw-path)
		    ((eq (aref option 0) ?#) (concat raw-path option))
		    ;; External fuzzy link: try to resolve it if path
		    ;; belongs to current project, if any.
		    ((eq (aref option 0) ?*)
		     (concat
		      raw-path
		      (let ((numbers
			     (org-publish-resolve-external-fuzzy-link
			      (org-element-property :path link) option)))
			(and numbers (concat "#sec-"
					     (mapconcat 'number-to-string
							numbers "-"))))))
		    (t raw-path))))
	   (t raw-path)))
	 ;; Extract attributes from parent's paragraph.  HACK: Only do
	 ;; this for the first link in parent (inner image link for
	 ;; inline images).  This is needed as long as attributes
	 ;; cannot be set on a per link basis.
	 (attributes-plist
	  (let* ((parent (org-export-get-parent-element link))
		 (link (let ((container (org-export-get-parent link)))
			 (if (and (eq (org-element-type container) 'link)
				  (org-html-inline-image-p link info))
			     container
			   link))))
	    (and (eq (org-element-map parent 'link 'identity info t) link)
		 (org-combine-plists
                     (org-export-read-attribute :attr_html parent)
                     (org-export-read-attribute :attr_blog parent)))))
	 (attributes
	  (let ((attr (org-html--make-attribute-string attributes-plist)))
	    (if (org-string-nw-p attr) (concat " " attr) "")))
	 protocol)
    (cond
     ;; Image file.
     ((and org-html-inline-images
	   (org-export-inline-image-p link org-html-inline-image-rules))
      (org-blog--format-image path attributes-plist info))
     ;; Radio target: Transcode target's contents and use them as
     ;; link's description.
     ((string= type "radio")
      (let ((destination (org-export-resolve-radio-link link info)))
	(when destination
	  (format "<a href=\"#%s\"%s>%s</a>"
		  (org-export-solidify-link-text path)
		  attributes
		  (org-export-data (org-element-contents destination) info)))))
     ;; Links pointing to a headline: Find destination and build
     ;; appropriate referencing command.
     ((member type '("custom-id" "fuzzy" "id"))
      (let ((destination (if (string= type "fuzzy")
			     (org-export-resolve-fuzzy-link link info)
			   (org-export-resolve-id-link link info))))
	(case (org-element-type destination)
	  ;; ID link points to an external file.
	  (plain-text
	   (let ((fragment (concat "ID-" path))
		 ;; Treat links to ".org" files as ".html", if needed.
		 (path (funcall link-org-files-as-html-maybe
				destination info)))
	     (format "<a href=\"%s#%s\"%s>%s</a>"
		     path fragment attributes (or desc destination))))
	  ;; Fuzzy link points nowhere.
	  ((nil)
	   (format "<i>%s</i>"
		   (or desc
		       (org-export-data
			(org-element-property :raw-link link) info))))
	  ;; Link points to a headline.
	  (headline
	   (let ((href
		  ;; What href to use?
		  (cond
		   ;; Case 1: Headline is linked via it's CUSTOM_ID
		   ;; property.  Use CUSTOM_ID.
		   ((string= type "custom-id")
		    (org-element-property :CUSTOM_ID destination))
		   ;; Case 2: Headline is linked via it's ID property
		   ;; or through other means.  Use the default href.
		   ((member type '("id" "fuzzy"))
		    (format "sec-%s"
			    (mapconcat 'number-to-string
				       (org-export-get-headline-number
					destination info) "-")))
		   (t (error "Shouldn't reach here"))))
		 ;; What description to use?
		 (desc
		  ;; Case 1: Headline is numbered and LINK has no
		  ;; description.  Display section number.
		  (if (and (org-export-numbered-headline-p destination info)
			   (not desc))
		      (mapconcat 'number-to-string
				 (org-export-get-headline-number
				  destination info) ".")
		    ;; Case 2: Either the headline is un-numbered or
		    ;; LINK has a custom description.  Display LINK's
		    ;; description or headline's title.
		    (or desc (org-export-data (org-element-property
					       :title destination) info)))))
	     (format "<a href=\"#%s\"%s>%s</a>"
		     (org-export-solidify-link-text href) attributes desc)))
	  ;; Fuzzy link points to a target or an element.
	  (t
	   (let* ((path (org-export-solidify-link-text path))
		  (org-html-standalone-image-predicate 'org-html--has-caption-p)
		  (number (cond
			   (desc nil)
			   ((org-html-standalone-image-p destination info)
			    (org-export-get-ordinal
			     (org-element-map destination 'link
			       'identity info t)
			     info 'link 'org-html-standalone-image-p))
			   (t (org-export-get-ordinal
			       destination info nil 'org-html--has-caption-p))))
		  (desc (cond (desc)
			      ((not number) "No description for this link")
			      ((numberp number) (number-to-string number))
			      (t (mapconcat 'number-to-string number ".")))))
	     (format "<a href=\"#%s\"%s>%s</a>" path attributes desc))))))
     ;; Coderef: replace link with the reference name or the
     ;; equivalent line number.
     ((string= type "coderef")
      (let ((fragment (concat "coderef-" path)))
	(format "<a href=\"#%s\"%s%s>%s</a>"
		fragment
		(org-trim
		 (format (concat "class=\"coderef\""
				 " onmouseover=\"CodeHighlightOn(this, '%s');\""
				 " onmouseout=\"CodeHighlightOff(this, '%s');\"")
			 fragment fragment))
		attributes
		(format (org-export-get-coderef-format path desc)
			(org-export-resolve-coderef path info)))))
     ;; File: links to upload to the blog
     ((string= type "file")
      ;; Add blog allowed links to org-blog-files-to-upload list.
      (dolist (upload-type org-blog-upload-filetypes html-link)
        (let ((string-to-match (concat "." upload-type)))
          (message "upload type: %s \n" upload-type)
          (message "condition1: %s\n" (> (length raw-path)  (length string-to-match)))
          (message "string to match: %s\n" string-to-match)
          (message "substring: %s \n" (substring raw-path
                                         (- (length string-to-match))))
          (when (and (> (length raw-path)  (length string-to-match))
                     (string= string-to-match
                              (substring raw-path
                                         (- (length string-to-match)))))
            (message "upload: match!\n")
            (setq html-link
                  (concat "<a href=\""
                          raw-path
                          "\">"
                          desc
                          "</a>")))))
      (cdar (add-to-list 'org-blog-files-to-upload 
                         `(,raw-path . ,html-link)))
      (format "%s" html-link))
     ;; Link type is handled by a special function.
     ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
      (funcall protocol (org-link-unescape path) desc 'html))
     ;; External link with a description part.
     ((and path desc) (format "<a href=\"%s\"%s>%s</a>" path attributes desc))
     ;; External link without a description part.
     (path (format "<a href=\"%s\"%s>%s</a>" path attributes path))
     ;; No path, only description.  Try to do something useful.
     (t (format "<i>%s</i>" desc)))))

;;;; Keyword

(defun org-blog-keyword (keyword contents info)
  "Transcode a KEYWORD element from Org to HTML.
CONTENTS is nil.  INFO is a plist holding contextual information."
  (let ((key (org-element-property :key keyword))
	(value (org-element-property :value keyword)))

    (cond ((string= key "BLOG")  value)
          ((string= key "BLOG_MORE") "<!--more-->")
          ((string= key "BLOG_DOC_LINK")
               (let* ((first-blank (string-match " " value))
                      (doctype (substring value 0 first-blank))
                      (desc (substring value (1+ first-blank)))
                      (raw-path (concat (substring
                                         buffer-file-name 0 -3)
                                        doctype))
                      (html-link (concat "<a href=\""
                                         raw-path
                                         "\">"
                                         desc
                                         "</a>")))
                 (add-to-list 'org-blog-files-to-upload 
                              `(,raw-path . ,html-link))
                 (format "%s" html-link)))
          (t (org-html-keyword keyword contents info)))))
  
;;;; Src Block

(defun org-blog-src-block (src-block contents info)
  "Transcode a SRC-BLOCK element from Org to HTML.
CONTENTS holds the contents of the item.  INFO is a plist holding
contextual information."
  ;; NOTE; a set label disturbs wp-syntax rendering.
  ;; CHECK for syntax highlighter
  (if (org-export-read-attribute :attr_html src-block :textarea)
      (org-html--textarea-block src-block)
    (let* ((highlighter (or (plist-get info :blog-syntax-highlighter)
                            "org-mode"))
           (hlall (assoc highlighter org-blog-syntax-highlighter-alist))
           (hl (cdr hlall))
           (lang (or (cdr (assoc (org-element-property :language src-block)
                                 (nth 7 hl)))
                     (car (member (org-element-property :language src-block)
                                  (nth 6 hl)))
                     (nth 5 hl)))
	  (caption (org-export-get-caption src-block))
	  (code (if (equal "org-mode" (car hlall))
                    (org-html-format-code src-block info)
                  (car (org-export-unravel-code src-block))))
	  (label (let ((lbl (org-element-property :name src-block)))
		   (if (not lbl) ""
		     (format " id=\"%s\""
			     (org-export-solidify-link-text lbl))))))
      ;; (eq lang nil) should only occur with invalid highlighters
      (if (eq lang nil)
          (format "<pre class=\"example\"%s>\n%s</pre>" label code)
	(format
	 "<div class=\"org-src-container\">\n%s%s\n</div>"
	 (if (not caption) ""
	   (format "<label class=\"org-src-name\">%s</label>"
		   (org-export-data caption info)))
         (format (concat "\n"
                         (nth 0 hl) (nth 2 hl)
                         " "
                         (nth 4 hl)
                         "=\""
                         ;; org-mode uses src class and src- prefix in source
                         ;; block class names
                         (if (and (string= highlighter "org-mode")
                                  (not (string= lang "example")))
                             "src src-")
                         "%s\"%s"
                         (nth 1 hl) ;; end of beginning tag
                         "%s"
                         (nth 0 hl) (nth 3 hl) (nth 2 hl) (nth 1 hl))
                 lang
                 ;; wp-syntax doesn't like foreign attributes in its <pre> tags
                 (if (string= highlighter "wp-syntax")
                     ""
                   label)
                 code))))))

\f
;;; helper functions for export
(defun org-blog-wp-call (blog-access api-component &rest args)
  (apply #'xml-rpc-method-call
         (cdr (assoc :xmlrpc-url blog-access))
         api-component
         (cdr (assoc :blog-id blog-access))
         (cdr (assoc :username blog-access))
         (cdr (assoc :password blog-access))
         args))

(defun org-blog-get-blog-project-from-filename (filename)
  "Return the blog project that FILENAME belongs to."
  ; copied from org-publish
  (let ((filename (expand-file-name filename))
        blog-project)
    (dolist (prj org-blog-project-alist)
      (print org-blog-project-alist)
      (print prj)
      (let ((b (expand-file-name (file-name-as-directory
                                  (plist-get (cdr prj) :base-directory)))))
        (when (string= filename
                            (expand-file-name filename b))
          (setq blog-project prj))))
    blog-project))


;;If you got options in MY FILE inthe form of
;;#+OPTION_NAME: a, b, two words, something else
;;#+OPTION_NAME: and, comma, at end,
;;#+OPTION_NAME: for, example
;;
;;
;;(:option-name is the KEYWORD in the options alist, cf. ox.el)
;;
;;you will get them now as
;;'( \"a\" \"b\" \"two words\" \"something else\" \"and\" \"comma\" \"at end\" \"for " "example").


(defun org-blog-taxonomy-terms-as-list (taxonomy ext-plist)
  "Fetch TAXONOMY (tags or categories) from FILE as a list"
  (mapcar 'org-trim
          (split-string
           (replace-regexp-in-string ", *" ","
                                     (or
                                      (plist-get ext-plist taxonomy)
                                      ""))
           "[,\n]"
           t)))


(defun org-blog-fetch-taxonomy-terms (blog-access taxonomy)
  "Fetches all terms in a TAXONOMY from blog.

TAXONOMY is  e.g. \"post_tag\" or \"category\""
  (mapcar (lambda (term)
            (cdr (assoc "name" term)))
          (org-blog-wp-call blog-access "wp.getTerms" taxonomy)))


(defun org-blog-create-taxonomy-term-list (blog-access taxonomy term-list confirm-p)
  "Creates a list of terms for TAXONOMY using TERM-LIST.

TAXONOMY can be either \"post_tag\" org \"category\".

Returns a alist '((taxonomy . term1) (taxonomy . term2))
for use in the wp.newPost and wp.editPost XML-RPC calls."
  (let* ((existing-terms (org-blog-fetch-taxonomy-terms blog-access taxonomy))
         (taxinfo (assoc taxonomy
                         '(("post_tag" "Tag")
                           ("category" "Category")))))

    (let ((terms
           (mapcar (lambda (term)
                     (let ((term-to-use nil))
                       (dolist (blog-term existing-terms)
                         (when (string= (downcase term)
                                        (downcase blog-term))
                           (setq term-to-use blog-term)))
                       (or term-to-use
                           (if confirm-p
                               (and (y-or-n-p
                                     (format "%s `%s 'not known to blog.  Add it? "
                                             (second taxinfo)
                                             term))
                                    term)
                             term))))
                   term-list)))
      (when terms (remove nil `(,taxonomy . ,terms))))))


(defun org-blog-post-exists-p (blog-access post-id)
  (let ((post-id-exists t))
    (condition-case err
        (org-blog-wp-call blog-access "wp.getPost"  post-id '("post_id"))
      (error err
             (equal (car (cdr err))
                    "XML-RPC fault `Invalid post ID.'")
             (setq post-id-exists nil)))
    post-id-exists))


(defun org-blog-upload-images (blog-access images)
  "Upload IMAGES to blog using BLOG-ACCESS."
  (mapc
   (lambda (image)
     (goto-char (point-max))
     (when (search-backward (cdr image) nil t)
       (search-forward (concat "src=\""
                                (car image)
                                "\"") nil t)
       (search-backward (car image) nil t)
       (delete-char (length (car image)))
       (insert
        (cdr
         (assoc
          "url"
          (let ((xml-rpc-allow-unicode-string nil)
                (raw-path (car image)))
            (with-temp-buffer
              (insert-file-contents-literally raw-path)
              (org-blog-wp-call blog-access "wp.uploadFile"
                                `(("name" .
                                   ,(file-name-nondirectory raw-path))
                                  ("type " .
                                   ,(mailcap-extension-to-mime
                                     (file-name-extension raw-path)))
                                  ("bits" . ,(buffer-string))
                                  ("overwrite" . 1))))))))))
   images))

(defun org-blog-upload-files (blog-access files)
  "Upload IMAGES to blog using BLOG-ACCESS."
  (mapc
   (lambda (file)
     (goto-char (point-max))
     (when (search-backward (cdr file) nil t)
       (search-forward (concat "href=\""
                                (car file)
                                "\"") nil t)
       (search-backward (car file) nil t)
       (delete-char (length (car file)))
       (insert
        (cdr
         (assoc
          "url"
          (let ((xml-rpc-allow-unicode-string nil)
                (raw-path (car file)))
            (with-temp-buffer
              (insert-file-contents-literally raw-path)
              (org-blog-wp-call blog-access "wp.uploadFile"
                                `(("name" .
                                   ,(file-name-nondirectory raw-path))
                                  ("type " .
                                   ,(mailcap-extension-to-mime
                                     (file-name-extension raw-path)))
                                  ("bits" . ,(buffer-string))
                                  ("overwrite" . 1))))))))))
   files))


(defun org-blog-inner-template (contents info)
  "Return body of document string after blog HTML conversion.
CONTENTS is the transcoded contents string.  INFO is a plist
holding export options."
  (concat
   ;; Table of contents.
   (let ((depth (plist-get info :with-toc)))
     (when depth (org-html-toc depth info)))
   ;; Document contents.
   contents
   ;; Footnotes section.
   (org-html-footnote-section info)))

(defun org-blog-template (contents info)
  "Return complete document string after blog HTML conversion.
CONTENTS is the transcoded contents string.  INFO is a plist
holding export options.

This function is just calling org-blog-inner-template, as
for a wordpress blog only the document body is needed.
"
  (org-blog-inner-template contents info))


\f
;;; End-user functions

;;;###autoload
(defun org-blog-export-as-html
  (&optional async subtreep visible-only body-only ext-plist)
  "Export current buffer to an blog HTML buffer.

If narrowing is active in the current buffer, only export its
narrowed part.

If a region is active, export that region.

A non-nil optional argument ASYNC means the process should happen
asynchronously.  The resulting buffer should be accessible
through the `org-export-stack' interface.

When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the headline properties
first.

When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.

When optional argument BODY-ONLY is non-nil, only write code
between \"<body>\" and \"</body>\" tags.

EXT-PLIST, when provided, is a property list with external
parameters overriding Org default settings, but still inferior to
file-local settings.

Export is done in a buffer named \"*Org BLOG Export*\", which
will be displayed when `org-export-show-temporary-export-buffer'
is non-nil."
  (interactive)
  (org-export-to-buffer 'blog "*Org Blog Export*"
   async subtreep visible-only body-only ext-plist
   (lambda () (set-auto-mode t))))

;;;###autoload
(defun org-blog-convert-region-to-html ()
  "Assume the current region has org-mode syntax, and convert it to blog HTML.
This can be used in any buffer.  For example, you can write an
itemized list in org-mode syntax in an blog HTML buffer and use this
command to convert it."
  (interactive)
  (org-export-replace-region-by 'blog))

;;;###autoload
(defun org-blog-export-to-html
  (&optional async subtreep visible-only body-only ext-plist)
  "Export current buffer to a blog HTML file.

If narrowing is active in the current buffer, only export its
narrowed part.

If a region is active, export that region.

A non-nil optional argument ASYNC means the process should happen
asynchronously.  The resulting file should be accessible through
the `org-export-stack' interface.

When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the headline properties
first.

When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.

When optional argument BODY-ONLY is non-nil, only write code
between \"<body>\" and \"</body>\" tags.

EXT-PLIST, when provided, is a property list with external
parameters overriding Org default settings, but still inferior to
file-local settings.

Return output file's name."
  (interactive)
  (let* ((extension (concat "." org-html-extension))
	 (file (org-export-output-file-name extension subtreep))
	 (org-export-coding-system org-html-coding-system))
    (org-export-to-file 'blog file
                        async subtreep visible-only body-only ext-plist)))

;;;###autoload
(defun org-blog-export-to-blog
  (draft-or-publish-p &optional async subtreep visible-only body-only ext-plist)
  "Export current buffer to an blog HTML buffer."
  (interactive)
  ;; fetch blog project, if available
  (let* ((project (org-blog-get-blog-project-from-filename (buffer-file-name)))
         (project-name (car project))
         (project-plist (cdr project))
         (post-environment (org-combine-plists
                            project-plist
                            (org-export-get-environment 'blog subtreep ext-plist)))
         (username (or (plist-get post-environment :blog-username)
                       (read-string (message "Enter user name for blog%s: "
                                             (if project-name
                                                 (concat " " project-name)
                                               "")))))
         (blog-access
          `((:xmlrpc-url
             . 
             ,(let ((url  (plist-get post-environment :blog-url)))
                (concat url
                        (and (not (string= "/" (substring url -1)))
                             "/")
                        "xmlrpc.php")))
            (:blog-id . ,(plist-get post-environment :blog-id))
            (:username . ,username)
            (:password
             .
             ,(or (plist-get post-environment :blog-password)
                  (read-passwd
                   (message "Enter password for user %s on blog%s: "
                            username
                            (if project-name
                                (concat " " project-name)
                              "")))))))
         (source-buffer (buffer-name))
         (post-content)
         (new-post-id))
    ;; org-blog-export-as-html does it's own subtree narrowing....
    (setq org-blog-image-list ())  ;; will be uploaded right before the post
    (setq org-blog-files-to-upload ())  ;; ditto
    (org-blog-export-as-html async subtreep visible-only body-only ext-plist)
    ;; upload images and files (and change paths in HTML)
    (org-blog-upload-images blog-access org-blog-image-list)
    (org-blog-upload-files blog-access org-blog-files-to-upload)

    (setq post-content (buffer-string))
    (set-buffer source-buffer)

    (let* ((post-id (string-to-number
                     (org-element-interpret-data
                      (plist-get post-environment :blog-post-id))))
           (post-title (org-element-interpret-data
                        (plist-get post-environment :title)))
           (publish-datetime (or (org-element-interpret-data
                                  (plist-get post-environment :blog-publish-datetime))
                                 (org-entry-get (point) "SCHEDULED")
                                 (org-entry-get (point) "DEADLINE")
                                 (org-entry-get (point) "TIMESTAMP")
                                 (org-entry-get (point) "TIMESTAMP_IA")))
           ;; TODO:
           (timezone (or (plist-get post-environment :blog-timezone)
                         0)) ;; fallback GMT
           (use-tags-as-categories (plist-get post-environment
                                              :blog-use-tags-as-categories))
           (tag-list (org-blog-create-taxonomy-term-list
                      blog-access
                      "post_tag"
                      (let ((partial-list
                             (org-blog-taxonomy-terms-as-list
                              :blog-tags
                              post-environment)))
                        (mapc (lambda (elt) (add-to-list 'partial-list elt))
                              (org-get-tags-at (point)))
                        partial-list)
                      (plist-get post-environment
                                 :blog-confirm-new-tags)))
           (category-list (if use-tags-as-categories
                              tag-list
                            (org-blog-create-taxonomy-term-list
                             blog-access "category"
                             (org-blog-taxonomy-terms-as-list :blog-categories
                                                              post-environment)
                             (plist-get post-environment :blog-confirm-new-categories))))
           (use-tags-as-categories
            (plist-get post-environment :blog-use-tags-as-categories))
           (user-role
            (cadr (assoc "roles"
                         (org-blog-wp-call blog-access "wp.getProfile" '("roles")))))
           ;; most roles may draft, contributor may submit
           ;; (aka. pending) instead of post; author and
           ;; administrator may post
           (post-status (cond ((equal draft-or-publish-p "draft") "draft")
                              ((equal "contributor" user-role) "pending")
                              ((and publish-datetime
                                    (or (equal "author" user-role)
                                        (equal "administrator" user-role)))
                               "future")
                              ((equal "author" user-role) "publish")
                              ((equal "administrator" user-role) "publish")))
           ;; the post structure list only likes (key . value) elements,
           ;; so a careful removel of nil's is in order.
           (post-struct
            (remove nil
                    `(("post_title" . ,post-title)
                      ("post_type" . ,(org-element-interpret-data
                                       (plist-get post-environment :blog-post-type)))
                      ("post_status" . ,post-status)
                      ,(when (string= post-status "future")
                         `("post_date" . (:datetime
                                          ,(apply 'encode-time
                                                  (org-parse-time-string
                                                   publish-datetime)))))
                      ("post_content" . ,post-content)
                      ,(when (or tag-list
                                 category-list)
                         `("terms_names"
                           .
                           ,(append (when (and (not use-tags-as-categories)
                                               tag-list)
                                      `(,tag-list))
                                    (when category-list
                                      `(,category-list)))))))))
      ; (print post-struct)
      (message "Post-ID: %d" post-id)
      (if (/= 0 post-id)
          (org-blog-wp-call blog-access "wp.editPost" post-id post-struct)
        (setq new-post-id
              (org-blog-wp-call blog-access "wp.newPost" post-struct)))
      (when (= post-id 0)
        (if subtreep
            (org-set-property "EXPORT_BLOG_POST_ID" new-post-id)
          (progn
            (goto-char (point-min))
            (eq (following-char) 35)
            (forward-line)
            (insert (concat "#+BLOG_POST_ID: " new-post-id "\n"))))
        (save-buffer))
      )))


;;;###autoload
(defun org-blog-export-to-blog-as-draft
   (&optional async subtreep visible-only body-only ext-plist)
   (org-blog-export-to-blog "draft" async subtreep visible-only body-only ext-plist))

;;;###autoload
(defun org-blog-export-to-blog-as-publish
  (&optional async subtreep visible-only body-only ext-plist)
  (org-blog-export-to-blog "publish" async subtreep visible-only body-only ext-plist))

;;;###autoload
(defun org-blog-publish-to-html (plist filename pub-dir)
  "Publish an org file to blog HTML.

FILENAME is the filename of the Org file to be published.  PLIST
is the property list for the given project.  PUB-DIR is the
publishing directory.

Return output file name."
  (org-publish-org-to 'blog filename
		      (concat "." (or (plist-get plist :html-extension)
				      org-html-extension "html"))
		      plist pub-dir))


(provide 'ox-blog)

;; Local variables:
;; generated-autoload-file: "org-loaddefs.el"
;; End:

;;; ox-blog.el ends here

[-- Attachment #3: ox-blog.org --]
[-- Type: application/vnd.lotus-organizer, Size: 5848 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-07 17:10 another blog exporter Robert Klein
@ 2014-02-07 17:35 ` Rasmus
  2014-02-07 19:17   ` Robert Klein
  2014-02-08  0:27 ` Ken Mankoff
  2014-02-08 20:41 ` Robert Klein
  2 siblings, 1 reply; 11+ messages in thread
From: Rasmus @ 2014-02-07 17:35 UTC (permalink / raw)
  To: emacs-orgmode

Robert Klein <roklein@roklein.de> writes:

> Hi,
>
> around the org-mode 8.0 release I began to write a new blog exporter
> using the new export framework.
>
> I wanted one feature org2blog didn't offer, support for different syntax
> highlighters, and i wanted to learn about the new exporter and Emacs
> programming.
>
> Around Christmas I did some polishing to make it ready for a greater public.

Cool.

Could you provide an example blog so that we can see the output?

> ;;; Transcode Functions
>
> ;;;; Example Block
>
> (defun org-blog-example-block (example-block contents info)
>   "Transcode a EXAMPLE-BLOCK element from Org to HTML.
> CONTENTS is nil.  INFO is a plist holding contextual
> information."
>   (if (org-export-read-attribute :attr_html example-block :textarea)
>       (org-html--textarea-block example-block)
>     ;;; beginnin here we need org/wp-syntac/syntaxhl information!!!!
>     (format "<pre class=\"example\">\n%s</pre>"
> 	    (org-html-format-code example-block info))))

Isn't this an exact copy of the corresponding entry in ox-html (Less
the name)?  Why?

> ;;;; Latex Environment
>
> (defun org-blog-latex-environment (latex-environment contents info)
>   "Transcode a LATEX-ENVIRONMENT element from Org to HTML.
> 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)))
> 	(attributes (org-combine-plists
>                      (org-export-read-attribute :attr_html latex-environment)
>                      (org-export-read-attribute :attr_blog latex-environment))))
>     (case processing-type
>       ((t mathjax)
>        (org-html-format-latex latex-frag 'mathjax info))
>       ((dvipng imagemagick)
>        (let ((formula-link
> 	      (org-html-format-latex latex-frag processing-type info)))
> 	 (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-blog--format-image
> 	     (match-string 1 formula-link) attributes info) info))))
>       (t latex-frag))))

Same.  There seems to be a couple of these. . .

Rasmus

-- 
Don't panic!!!

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-07 17:35 ` Rasmus
@ 2014-02-07 19:17   ` Robert Klein
  0 siblings, 0 replies; 11+ messages in thread
From: Robert Klein @ 2014-02-07 19:17 UTC (permalink / raw)
  To: emacs-orgmode

Hi Rasmus,


thank you very much for your feedback!

On 02/07/2014 06:35 PM, Rasmus wrote:
> Could you provide an example blog so that we can see the output?

The two latest posts ("FreeBSD" and "DHCP") at http://www.xyzzy.de/

I put the original org for download at the end of both posts.


>> ;;; Transcode Functions
>>
>> ;;;; Example Block
>>
>> (defun org-blog-example-block (example-block contents info)
>>   "Transcode a EXAMPLE-BLOCK element from Org to HTML.
>> CONTENTS is nil.  INFO is a plist holding contextual
>> information."
>>   (if (org-export-read-attribute :attr_html example-block :textarea)
>>       (org-html--textarea-block example-block)
>>     ;;; beginnin here we need org/wp-syntac/syntaxhl information!!!!
>>     (format "<pre class=\"example\">\n%s</pre>"
>> 	    (org-html-format-code example-block info))))
> 
> Isn't this an exact copy of the corresponding entry in ox-html (Less
> the name)?  Why?
> 

- org-blog-example-block /is/ an exact copy, I planned to add the
  highlighters here, too, and to support line numbers.  Forgot it :(

- org-blog-latex-environment adds support for =#+ATTR_BLOG:=

- org-blog-latex-fragment currently also is an exact copy.  I'm not sure
  mathjax works, so I put it here for further work.

- org-blog-link supports =attr_blog= and fills the list of images to be
  uploaded. (I really hated to copy this one... in an earler version I
  cl-flet-ted org-html--format-image to avoid copying this one.

for org-blog-export-[as|to]-blog, I had no choice. :)


I just found out, when I introduced scheduled posting I broke unscheduled
posting; this is the patch:

--- emacs/ox-blog.el	2014-01-21 10:57:50 +0000
+++ emacs/ox-blog.el	2014-02-07 18:38:52 +0000

@@ -1089,7 +1089,7 @@
            ;; administrator may post
            (post-status (cond ((equal draft-or-publish-p "draft") "draft")
                               ((equal "contributor" user-role) "pending")
-                              ((and publish-datetime
+                              ((and (not (string= "" publish-datetime))
                                     (or (equal "author" user-role)
                                         (equal "administrator" user-role)))
                                "future")


Best regards and thank you very much for the feedback,
Robert

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-07 17:10 another blog exporter Robert Klein
  2014-02-07 17:35 ` Rasmus
@ 2014-02-08  0:27 ` Ken Mankoff
  2014-02-08  8:40   ` Robert Klein
  2014-02-08 20:41 ` Robert Klein
  2 siblings, 1 reply; 11+ messages in thread
From: Ken Mankoff @ 2014-02-08  0:27 UTC (permalink / raw)
  To: Robert Klein; +Cc: emacs-orgmode

Hi Robert,

On Fri, 7 Feb 2014, Robert Klein wrote:
> around the org-mode 8.0 release I began to write a new blog 
> exporter using the new export framework.
>
> I wanted one feature org2blog didn't offer, support for different 
> syntax highlighters, and i wanted to learn about the new exporter 
> and Emacs programming.

Does your exporter work across multiple files (one file per post), 
or only one file?

   -k.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-08  0:27 ` Ken Mankoff
@ 2014-02-08  8:40   ` Robert Klein
  0 siblings, 0 replies; 11+ messages in thread
From: Robert Klein @ 2014-02-08  8:40 UTC (permalink / raw)
  To: mankoff; +Cc: emacs-orgmode

Hi Ken

On 02/08/2014 01:27 AM, Ken Mankoff wrote:
> Hi Robert,
> 
> On Fri, 7 Feb 2014, Robert Klein wrote:
>> around the org-mode 8.0 release I began to write a new blog exporter
>> using the new export framework.
>>
>> I wanted one feature org2blog didn't offer, support for different
>> syntax highlighters, and i wanted to learn about the new exporter and
>> Emacs programming.
> 
> Does your exporter work across multiple files (one file per post), or
> only one file?
> 
>   -k.
> 


It works both ways, just like the other exporters:

C-c C-e b ... exports the whole file
C-c C-e C-s b ... exports the current subtree

If you set up the `org-blog-project-alist', all files in the
`base-directory' can be exported.


Best regards
Robert

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-07 17:10 another blog exporter Robert Klein
  2014-02-07 17:35 ` Rasmus
  2014-02-08  0:27 ` Ken Mankoff
@ 2014-02-08 20:41 ` Robert Klein
  2014-02-09  7:55   ` Bastien
  2 siblings, 1 reply; 11+ messages in thread
From: Robert Klein @ 2014-02-08 20:41 UTC (permalink / raw)
  To: emacs-orgmode

Hi,

I put ox-blog on github:

https://github.com/roklein/ox-blog

I removed the unnecessary org-blog-example-block and added some
attributes to be used with source blocks (line numbers, highlighting of
lines, title).

Best regards
Robert



On 02/07/2014 06:10 PM, Robert Klein wrote:
> Hi,
> 
> around the org-mode 8.0 release I began to write a new blog exporter
> using the new export framework.
> 
> I wanted one feature org2blog didn't offer, support for different syntax
> highlighters, and i wanted to learn about the new exporter and Emacs
> programming.
> 
> Around Christmas I did some polishing to make it ready for a greater public.
> 
> Would there a place for it in contrib/ or is it better suited for a
> github repository?
> 
> Thanks and best regards
> Robert
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-08 20:41 ` Robert Klein
@ 2014-02-09  7:55   ` Bastien
  2014-02-09 14:25     ` Robert Klein
  0 siblings, 1 reply; 11+ messages in thread
From: Bastien @ 2014-02-09  7:55 UTC (permalink / raw)
  To: Robert Klein; +Cc: emacs-orgmode

Hi Robert,

Robert Klein <roklein@roklein.de> writes:

> I put ox-blog on github:
>
> https://github.com/roklein/ox-blog

Thanks for your work on this, looks neat.

Do you have an example website produced by ox-blog?

Also, I see you use a new #+ATTR_BLOG keyword.
Is this needed for images and such?  I'd expect
#+ATTR_HTML would be enough here, users won't
want to use both #+ATTR_HTML and #+ATTR_BLOG
I guess.

Best,

-- 
 Bastien

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-09  7:55   ` Bastien
@ 2014-02-09 14:25     ` Robert Klein
  2014-02-10  8:48       ` Bastien
  0 siblings, 1 reply; 11+ messages in thread
From: Robert Klein @ 2014-02-09 14:25 UTC (permalink / raw)
  To: Bastien; +Cc: emacs-orgmode

Hi Bastien,

On 02/09/2014 08:55 AM, Bastien wrote:
> Hi Robert,
> 
> Robert Klein <roklein@roklein.de> writes:
> 
>> I put ox-blog on github:
>>
>> https://github.com/roklein/ox-blog
> 
> Thanks for your work on this, looks neat.
> 
> Do you have an example website produced by ox-blog?
> 
> Also, I see you use a new #+ATTR_BLOG keyword.
> Is this needed for images and such?  I'd expect
> #+ATTR_HTML would be enough here, users won't
> want to use both #+ATTR_HTML and #+ATTR_BLOG
> I guess.

I posted the latest three posts on http://www.xyzzy.de using ox-blog.


I can use #+ATTR_HTML, but I wasn't sure about using new attributes,
e.g. :highlight and :lineno for source blocks.  I didn't want to pollute
ATTR_HTML with things that are of no use for the HTML exporter.

If you don't see a problem in #+ATTR_HTML, I'll happily change this.

Thanks for the feed-back!

Best regards
Robert

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-09 14:25     ` Robert Klein
@ 2014-02-10  8:48       ` Bastien
  2014-02-10 11:30         ` Nicolas Goaziou
  0 siblings, 1 reply; 11+ messages in thread
From: Bastien @ 2014-02-10  8:48 UTC (permalink / raw)
  To: Robert Klein; +Cc: emacs-orgmode

Hi Robert,

Robert Klein <roklein@roklein.de> writes:

> I posted the latest three posts on http://www.xyzzy.de using
> ox-blog.

Neat, thanks!

> I can use #+ATTR_HTML, but I wasn't sure about using new attributes,
> e.g. :highlight and :lineno for source blocks.  I didn't want to pollute
> ATTR_HTML with things that are of no use for the HTML exporter.

You're right.

Somehow this calls for a way to let a backend use several affiliated
keywords.  For example you would have:

#+ATTR_HTML: :width 400px
#+ATTR_BLOG: :lineno t

and the exporter would take both into account, letting you to simply
export to HTML without the need to add redundant information.

Nicolas, did this cross your mind?  Or maybe this is already feasible?

> If you don't see a problem in #+ATTR_HTML, I'll happily change this.

No, that will pollute the HTML export (I don't expect anything weird
in the HTML output with unknown attributes, but the document will not
validate correctly, and this is confusing anyway.)

Thanks!

-- 
 Bastien

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-10  8:48       ` Bastien
@ 2014-02-10 11:30         ` Nicolas Goaziou
  2014-03-04  9:51           ` Robert Klein
  0 siblings, 1 reply; 11+ messages in thread
From: Nicolas Goaziou @ 2014-02-10 11:30 UTC (permalink / raw)
  To: Bastien; +Cc: emacs-orgmode, Robert Klein

Hello,

Bastien <bzg@gnu.org> writes:

> Somehow this calls for a way to let a backend use several affiliated
> keywords.  For example you would have:
>
> #+ATTR_HTML: :width 400px
> #+ATTR_BLOG: :lineno t

Org already provided a syntax to number lines in source blocks. Couldn't
it be used instead?

  #+begin_src emacs-lisp -n
  ...
  #+end_src

> and the exporter would take both into account, letting you to simply
> export to HTML without the need to add redundant information.
>
> Nicolas, did this cross your mind?  Or maybe this is already feasible?

This is already feasible. See `org-beamer-plain-list' for an example.
Both #+attr_latex and #+attr_beamer are read but the latter has
precedence over the former.


Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: another blog exporter
  2014-02-10 11:30         ` Nicolas Goaziou
@ 2014-03-04  9:51           ` Robert Klein
  0 siblings, 0 replies; 11+ messages in thread
From: Robert Klein @ 2014-03-04  9:51 UTC (permalink / raw)
  To: Nicolas Goaziou, Bastien; +Cc: emacs-orgmode

Hello,

thank you very much for your feedback.


On 02/10/2014 12:30 PM, Nicolas Goaziou wrote:
> Hello,
> 
> Bastien <bzg@gnu.org> writes:
> 
>> Somehow this calls for a way to let a backend use several affiliated
>> keywords.  For example you would have:
>>
>> #+ATTR_HTML: :width 400px
>> #+ATTR_BLOG: :lineno t
> 
> Org already provided a syntax to number lines in source blocks. Couldn't
> it be used instead?
> 
>   #+begin_src emacs-lisp -n
>   ...
>   #+end_src
> 

Thanks a lot, I didn't know about this feature. Now I use the -n/+n
flags.  When using -n flag the ATTR_BLOG attribute :firstline is used as
the first line number; the default is 1 as in the LaTeX exporter.


>> and the exporter would take both into account, letting you to simply
>> export to HTML without the need to add redundant information.
>>
>> Nicolas, did this cross your mind?  Or maybe this is already feasible?
> 
> This is already feasible. See `org-beamer-plain-list' for an example.
> Both #+attr_latex and #+attr_beamer are read but the latter has
> precedence over the former.

I already use this, but I felt a need to document those attributes that
get extra treatment: wordpress uses class="alignleft" instead of HTML
align="right"  and I changed the style handling to support surrounding
double quotes ( :style "margin: 9pt; background: red;" )

Best regards
Robert

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2014-03-04  9:52 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-07 17:10 another blog exporter Robert Klein
2014-02-07 17:35 ` Rasmus
2014-02-07 19:17   ` Robert Klein
2014-02-08  0:27 ` Ken Mankoff
2014-02-08  8:40   ` Robert Klein
2014-02-08 20:41 ` Robert Klein
2014-02-09  7:55   ` Bastien
2014-02-09 14:25     ` Robert Klein
2014-02-10  8:48       ` Bastien
2014-02-10 11:30         ` Nicolas Goaziou
2014-03-04  9:51           ` Robert Klein

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).