]> git.rkrishnan.org Git - .emacs.d.git/blob - emacs/nxhtml/nxhtml/nxhtml-mode.el
063be3c13dd93725fb7b480a552f0465cb7f0ace
[.emacs.d.git] / emacs / nxhtml / nxhtml / nxhtml-mode.el
1 ;;; nxhtml-mode.el --- Edit XHTML files
2 ;;
3 ;; Author: Lennart Borgman (lennart O borgman A gmail O com)
4 ;; Parts are from Peter Heslin (see below)
5 ;; Created: 2005-08-05
6 ;;Version:
7 ;; Last-Updated: 2008-12-28 Sun
8 ;; Keywords: languages
9 ;;
10 ;;
11 ;;
12 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 ;;
14 ;;; Commentary:
15 ;;
16 ;;  The purpose of nxhtml.el is to add some features that are useful
17 ;;  when editing XHTML files to nxml-mode.  For more information see
18 ;;  `nxhtml-mode'.
19 ;;
20 ;;
21 ;;  Usage:
22 ;;
23 ;;  See the file readme.txt in the directory above this file. Or, if
24 ;;  you do not have that follow the instructions below.
25
26
27 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
28 ;;
29 ;;; History:
30 ;;
31 ;; 2006-04-25: Added completion for href, src etc. Removed xhtmlin.
32
33
34 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
35 ;;
36 ;; This file is not part of Emacs
37 ;;
38 ;; This program is free software; you can redistribute it and/or
39 ;; modify it under the terms of the GNU General Public License as
40 ;; published by the Free Software Foundation; either version 2, or (at
41 ;; your option) any later version.
42 ;;
43 ;; This program is distributed in the hope that it will be useful, but
44 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
45 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
46 ;; General Public License for more details.
47 ;;
48 ;; You should have received a copy of the GNU General Public License
49 ;; along with this program; see the file COPYING.  If not, write to
50 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
51 ;; Boston, MA 02111-1307, USA.
52
53
54 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
55 ;;
56 ;;; Code:
57
58 (eval-when-compile (require 'cl))
59 (eval-when-compile (require 'hideshow))
60
61 (eval-when-compile (require 'appmenu-fold nil t))
62 (eval-when-compile (require 'fold-dwim nil t))
63 (eval-when-compile (require 'foldit nil t))
64 (eval-when-compile (require 'html-pagetoc nil t))
65 (eval-when-compile (require 'html-toc nil t))
66 (eval-when-compile (require 'mumamo nil t))
67 (eval-when-compile (require 'mlinks nil t))
68 (eval-when-compile (require 'nxhtml-base))
69 ;;(eval-when-compile (require 'nxhtml-menu)) ;; recursive load
70 (eval-when-compile (require 'ourcomments-util nil t))
71 (eval-and-compile (require 'typesetter nil t))
72 (eval-when-compile (require 'xhtml-help nil t))
73 (eval-when-compile (require 'popcmp nil t))
74 ;; (eval-when-compile
75 ;;   (unless (or (< emacs-major-version 23)
76 ;;               (boundp 'nxhtml-menu:version)
77 ;;               (featurep 'nxhtml-autostart))
78 ;;     (let ((efn (expand-file-name
79 ;;                 "../autostart.el"
80 ;;                 (file-name-directory
81 ;;                  (or load-file-name
82 ;;                      (when (boundp 'bytecomp-filename) bytecomp-filename)
83 ;;                      buffer-file-name)))))
84 ;;       (message "efn=%s" efn)
85 ;;       (load efn))
86 ;;     (require 'rng-valid)
87 ;;     (require 'rng-nxml)))
88
89 (require 'button)
90 (require 'loadhist)
91 (require 'nxml-mode nil t)
92 (require 'rng-nxml nil t)
93 (require 'rng-valid nil t)
94
95 ;; Require nxml things conditionally to silence byte compiler under
96 ;; Emacs 22.
97 (eval-and-compile (require 'rngalt nil t))
98
99 (require 'url-parse)
100 (require 'url-expand)
101 (require 'popcmp nil t)
102 (eval-when-compile (require 'html-imenu nil t))
103 (eval-when-compile (require 'tidy-xhtml nil t))
104 (eval-when-compile (require 'html-quote nil t))
105
106 (defun nxhtml-version ()
107   "Show nxthml version."
108   (interactive)
109   (message "nXhtml mode version %s" nxhtml-menu:version))
110
111 ;;(defun nxhtml-nxml-fontify-attribute (att &optional namespace-declaration)
112 ;;"Holds the original `nxml-fontify-attribute' function.")
113 ;;(fset 'nxhtml-nxml-fontify-attribute (symbol-function 'nxml-fontify-attribute))
114
115
116 (defun nxhtml-turn-onoff-tag-do-also (on)
117   (add-hook 'nxhtml-mode-hook 'nxhtml-check-tag-do-also)
118   (dolist (b (buffer-list))
119     (when (with-current-buffer b
120             (eq major-mode 'nxhtml-mode))
121       (if on
122           (progn
123             (add-hook 'rngalt-complete-tag-hooks 'nxhtml-complete-tag-do-also t t)
124             )
125         (remove-hook 'rngalt-complete-tag-hooks 'nxhtml-complete-tag-do-also t)
126         ))))
127
128 ;;(define-toggle nxhtml-tag-do-also t
129 (define-minor-mode nxhtml-tag-do-also
130   "When completing tag names do some more if non-nil.
131 For some tag names additional things can be done at completion to
132 speed writing up.  For example for an <img ...> tag `nxhtml-mode'
133 can prompt for src attribute and add width and height attributes
134 if this attribute points to a local file.
135
136 You can add additional elisp code for completing to
137 `nxhtml-complete-tag-do-also'."
138   :global t
139   :init-value t
140   :group 'nxhtml
141   (nxhtml-turn-onoff-tag-do-also nxhtml-tag-do-also))
142 (when nxhtml-tag-do-also (nxhtml-tag-do-also 1))
143
144 (defun nxhtml-tag-do-also-toggle ()
145   "Toggle `nxhtml-tag-do-also'."
146   (interactive)
147   (nxhtml-tag-do-also (if nxhtml-tag-do-also -1 1)))
148
149 (defun nxhtml-check-tag-do-also ()
150   (when nxhtml-tag-do-also
151     (nxhtml-turn-onoff-tag-do-also t)))
152
153
154 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
155 ;;
156 ;; Folding etc.
157
158
159 ;; This part is origially taken from
160 ;; http://www.emacswiki.org/cgi-bin/wiki/NxmlModeForXHTML and was
161 ;; originally written by Peter Heslin, but has been changed rather
162 ;; much.
163
164 ;; (defun nxhtml-hs-adjust-beg-func (pos)
165 ;;   (save-excursion
166 ;;     (save-match-data
167 ;;       ;; (search-backward "<" nil t)
168 ;;       ;; (forward-char)
169 ;;       ;; (search-forward ">" nil t)
170 ;;       )
171 ;;     (point)))
172
173 (defun nxhtml-hs-forward-sexp-func (pos)
174   (nxhtml-hs-forward-element))
175
176 (defun nxhtml-hs-forward-element ()
177   (let ((nxml-sexp-element-flag))
178     (setq nxml-sexp-element-flag (not (looking-at "<!--")))
179     (unless nil ;;(looking-at outline-regexp)
180       ;;(condition-case nil
181           (nxml-forward-balanced-item 1)
182         ;;(error nil))
183       )))
184
185 (defun nxhtml-setup-for-fold-dwim ()
186   (make-local-variable 'outline-regexp)
187   (setq outline-regexp "\\s *<\\([h][1-6]\\|html\\|body\\|head\\)\\b")
188   (make-local-variable 'outline-level)
189   (setq outline-level 'nxhtml-outline-level)
190   ;;(outline-minor-mode 1)
191   ;;(hs-minor-mode 1)
192   (setq hs-special-modes-alist (assq-delete-all 'nxhtml-mode hs-special-modes-alist))
193   (add-to-list 'hs-special-modes-alist
194                '(nxhtml-mode
195                  ;;"<!--\\|<[^/>]>\\|<[^/][^>]*[^/]>"
196                  "<!--\\|<[^/>]>\\|<[^/][^>]*"
197                  "</\\|-->"
198                  "<!--" ;; won't work on its own; uses syntax table
199                  nxhtml-hs-forward-sexp-func
200                  nil ;nxhtml-hs-adjust-beg-func
201                  ))
202   (set (make-local-variable 'hs-set-up-overlay) 'nxhtml-hs-set-up-overlay)
203   (put 'hs-set-up-overlay 'permanent-local t)
204   (when (featurep 'appmenu-fold)
205     (appmenu-fold-setup))
206   (foldit-mode 1))
207
208 (defun nxhtml-hs-start-tag-end (beg)
209   (save-excursion
210     (save-match-data
211       (goto-char beg)
212       (or (search-forward ">" (line-end-position) t)
213           (line-end-position)))))
214
215 (defun nxhtml-hs-set-up-overlay (ovl)
216   (overlay-put ovl 'priority (1+ mlinks-link-overlay-priority))
217   (when foldit-mode
218     (setq foldit-hs-start-tag-end-func 'nxhtml-hs-start-tag-end)
219     (foldit-hs-set-up-overlay ovl)))
220
221 (defun nxhtml-outline-level ()
222   ;;(message "nxhtml-outline-level=%s" (buffer-substring (match-beginning 0) (match-end 0)))(sit-for 2)
223   ;; Fix-me: What did I intend to do???
224   ;; (let ((tag (buffer-substring (match-beginning 1) (match-end 1))))
225   ;;   (if (eq (length tag) 2)
226   ;;       (- (aref tag 1) ?0)
227   ;;     0))
228   8)
229
230
231 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
232
233
234
235 (defcustom nxhtml-use-imenu t
236   "Use imenu in nxhtml-mode."
237   :type 'boolean
238   :group 'nxhtml)
239
240
241
242 (defcustom nxhtml-default-encoding 'iso-8859-1
243   "Default encoding."
244   :type 'coding-system
245   :group 'nxhtml)
246
247 (defun nxhtml-insert-empty-frames-page ()
248   "Insert an empty frames page."
249   (interactive)
250   ;;(unless (= 0 (buffer-size))
251   (unless (nxhtml-can-insert-page-here)
252     (error "Buffer is not empty"))
253   (insert
254    "<?xml version=\"1.0\" encoding=\""
255    (symbol-name nxhtml-default-encoding)
256    "\"?>
257 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"
258           \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">
259 <html xmlns=\"http://www.w3.org/1999/xhtml\">
260   <head>
261     <title></title>
262   </head>
263   <frameset cols=\"50%, 50%\">
264     <frame src=\"about:blank\" />
265     <frame src=\"about:blank\" />
266   </frameset>
267 </html>")
268   (search-backward "</title>"))
269
270 (defun nxhtml-insert-empty-page ()
271   "Insert an empty XHTML page."
272   (interactive)
273   ;;(unless (= 0 (buffer-size))
274   (unless (nxhtml-can-insert-page-here)
275     (error "Buffer is not empty"))
276   (insert
277    "<?xml version=\"1.0\" encoding=\""
278    (symbol-name nxhtml-default-encoding)
279    "\"?>
280 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
281 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
282 <html xmlns=\"http://www.w3.org/1999/xhtml\">
283   <head>
284     <title></title>
285   </head>
286   <body>
287   </body>
288 </html>")
289   (search-backward "</title>"))
290
291 (defun nxhtml-empty-page-completion ()
292   ;;(unless (= 0 (buffer-size)) (error "Buffer is not empty"))
293   (let* ((frames "Frameset page")
294          (normal "Normal page")
295          ;;(vlhead "Validation header")
296          ;;popcmp-popup-completion
297          (initial nil) ;;(unless popcmp-popup-completion normal))
298          (hist (if (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
299                    ;;(list vlhead frames normal)
300                    (list frames normal)
301                  (list frames normal)))
302          res
303          (completion-ignore-case t))
304     (setq res (popcmp-completing-read "Insert: " hist nil t initial (cons 'hist (length hist))))
305     (cond ((string= res frames)
306            (nxhtml-insert-empty-frames-page))
307           ((string= res normal)
308            (nxhtml-insert-empty-page))
309           ;;((string= res vlhead)
310           ;; (nxhtml-validation-header-mode))
311           (t
312            (error "Bad res=%s" res))))
313   (rng-auto-set-schema))
314
315
316
317 (defvar nxhtml-mode-hook nil)
318 ;;(add-hook 'nxhtml-mode-hook 'nxml-fontify-buffer)
319
320 (defun nxhtml-help ()
321   (interactive)
322   (describe-function 'nxhtml-mode))
323
324 (defvar nxhtml-current-validation-header nil)
325 (make-variable-buffer-local 'nxhtml-current-validation-header)
326 (put 'nxhtml-current-validation-header 'permanent-local t)
327
328
329 ;; FIX-ME: When should this be done? Get tidy-menu-symbol:
330 (when (featurep 'tidy-xhtml)
331   (tidy-build-menu))
332
333
334 ;; (eval-after-load 'css-mode
335 ;;   '(when (featurep 'xhtml-help)
336 ;;     (define-key css-mode-map [(control ?c) ?? ?c] 'xhtml-help-show-css-ref)
337 ;;     ))
338 ;; (add-hook 'css-mode-hook
339 ;;           (lambda ()
340 ;;             (and (featurep 'xhtml-help)
341 ;;                  (boundp 'css-mode-map)
342 ;;                  (define-key css-mode-map [(control ?c) ?? ?c]
343 ;;                    'xhtml-help-show-css-ref))))
344
345 ;; This should be run in `change-major-mode-hook'."
346 ;; (defun nxhtml-change-mode ()
347 ;;   (when (fboundp 'mlinks-mode)
348 ;;     (mlinks-mode 0)))
349
350 (when (< emacs-major-version 23)
351   (defun nxml-change-mode ()
352     ;; Remove overlays used by nxml-mode.
353     (save-excursion
354       (save-restriction
355         (widen)
356         (rng-validate-mode -1)
357         (let ((inhibit-read-only t)
358               (buffer-undo-list t)
359               (modified (buffer-modified-p)))
360           (nxml-with-invisible-motion
361             (remove-text-properties (point-min) (point-max) '(face nil)))
362           (set-buffer-modified-p modified))))))
363
364 (defcustom nxhtml-heading-element-name-regexp "[a-z]*"
365   "Used for `nxml-heading-element-name-regexp."
366   :type 'regexp
367   :group 'nxhtml)
368
369 ;; Fix-me: Put this is a separate file and load it only if nxml is
370 ;; availabe.
371 (put 'nxhtml-mode 'flyspell-mode-predicate 'sgml-mode-flyspell-verify)
372 ;;;###autoload
373 (define-derived-mode nxhtml-mode nxml-mode "nXhtml"
374   "Major mode for editing XHTML documents.
375 It is based on `nxml-mode' and adds some features that are useful
376 when editing XHTML files.\\<nxhtml-mode-map>
377
378 The XML menu contains functionality added by `nxml-mode' \(on
379 which this major mode is based).  There is also a popup menu
380 added to the \[apps] key.
381
382 The most important features are probably completion and
383 validation, which is inherited from `nxml-mode' with some small
384 addtions.  In very many situation you can use completion. To
385 access it type \\[nxml-complete]. Completion has been enhanced in
386 the following way:
387
388 - If region is active and visible then completion will surround the
389   region with the chosen tag's start and end tag.  However only the
390   starting point is checked for validity. If something is wrong after
391   insertion you will however immediately see it if you have validation
392   on.
393 - It can in some cases give assistance with attribute values.
394 - Completion can be customized, see the menus XHTML - Completion:
395   * You can use a menu popup style completion.
396   * You can have alternatives grouped.
397   * You can get a short help text shown for each alternative.
398 - There does not have to be a '<' before point for tag name
399   completion. (`nxml-mode' requires a '<' before point for tag name
400   completion.)
401 - Completes xml version and encoding.
402 - Completes in an empty buffer, ie inserts a skeleton.
403
404 Here are all key bindings in nxhtml-mode itself:
405
406 \\{nxhtml-mode-map}
407
408 Notice that other minor mode key bindings may also be active, as
409 well as emulation modes. Do \\[describe-bindings] to get a list
410 of all active key bindings. Also, *VERY IMPORTANT*, if mumamo is
411 used in the buffer each mumamo chunk has a different major mode
412 with different key bindings. You can however still see all
413 bindings with \\[describe-bindings], but you have to do that with
414 point in the mumamo chunk you want to know the key bindings in."
415   (set (make-local-variable 'nxml-heading-element-name-regexp)
416        nxhtml-heading-element-name-regexp)
417   (when (fboundp 'nxml-change-mode)
418     (add-hook 'change-major-mode-hook 'nxml-change-mode nil t))
419   ;;(add-hook 'change-major-mode-hook 'nxhtml-change-mode nil t)
420   (when (featurep 'rngalt)
421     (add-hook 'nxml-completion-hook 'rngalt-complete nil t))
422   ;;(define-key nxhtml-mode-map [(meta tab)] 'nxml-complete)
423   ;;(nxhtml-menu-mode 1)
424   (when (and nxhtml-use-imenu
425              (featurep 'html-imenu))
426     (add-hook 'nxhtml-mode-hook 'html-imenu-setup nil t))
427   ;;(mlinks-mode 1)
428   (nxhtml-setup-for-fold-dwim)
429   (when (featurep 'rngalt)
430     (set (make-local-variable 'rngalt-completing-read-tag) 'nxhtml-completing-read-tag)
431     (set (make-local-variable 'rngalt-completing-read-attribute-name) 'nxhtml-completing-read-attribute-name)
432     (set (make-local-variable 'rngalt-completing-read-attribute-value) 'nxhtml-completing-read-attribute-value)
433     (set (make-local-variable 'rngalt-complete-first-try) 'nxhtml-complete-first-try)
434     (set (make-local-variable 'rngalt-complete-last-try) 'nxhtml-complete-last-try)
435     ))
436
437 ;; Fix-me: The nxhtml-mode-map is define by define-derived-mode, but
438 ;; how should keys be added?
439
440 ;; Replace the Insert End Tag function:
441 (define-key nxhtml-mode-map [(control ?c) (control ?f)] 'rngalt-finish-element)
442
443 ;; Put completion on the normal key?
444 (define-key nxhtml-mode-map [(meta tab)] 'nxml-complete)
445 ;; Paragraphs (C-p mnemonic for paragraph)
446 (define-key nxhtml-mode-map [(control ?c) (control ?p) ?l] 'longlines-mode)
447 (define-key nxhtml-mode-map [(control ?c) (control ?p) ?f] 'fill-paragraph)
448 (define-key nxhtml-mode-map [(control ?c) (control ?p) ?u] 'unfill-paragraph)
449 ;; Html related (C-h mnemonic for html)
450 (define-key nxhtml-mode-map [(control ?c) (control ?h) ?c] 'nxhtml-save-link-to-here)
451 (define-key nxhtml-mode-map [(control ?c) (control ?h) ?v] 'nxhtml-paste-link-as-a-tag)
452 (define-key nxhtml-mode-map [(control ?c) (control ?h) ?b] 'nxhtml-browse-file)
453 (define-key nxhtml-mode-map [(control ?c) ?<] 'nxml-untag-element)
454 (when (featurep 'html-quote)
455   (define-key nxhtml-mode-map [(control ?c) (control ?q)] 'nxhtml-quote-html)
456   )
457 ;; Fix-me: Is pagetoc really that important to have its own keybindings?
458 (when (featurep 'html-pagetoc)
459   (define-key nxhtml-mode-map [(control ?c) (control ?h) ?t ?i] 'html-pagetoc-insert-toc)
460   (define-key nxhtml-mode-map [(control ?c) (control ?h) ?t ?r] 'html-pagetoc-rebuild-toc)
461   (define-key nxhtml-mode-map [(control ?c) (control ?h) ?t ?s] 'html-pagetoc-insert-style-guide)
462   )
463
464 (defun nxhtml-quote-html()
465   "Quote character(s) unsafe in html text parts.
466 If region is visible quote all characters in region. Otherwise
467 just quote current char.
468
469 Note to CUA users: See `cua-mode' for how to prevent CUA from
470 just copying region when you press C-c."
471   (interactive)
472   (if (and mark-active
473            transient-mark-mode)
474       (let* ((rb (region-beginning))
475              (re (region-end))
476              (qr (html-quote-html-string
477                   (buffer-substring-no-properties rb re))))
478         (delete-region rb re)
479         (insert qr))
480     (let ((cs (html-quote-html-char (char-after))))
481       (delete-char 1)
482       (insert cs))))
483
484 (defvar nxhtml-single-tags
485   '("base"
486     "meta"
487     "link"
488     "br"
489     "hr"
490     "frame"
491     "img"
492     "input"
493     "option"
494     "param"))
495
496 (defun nxthml-is-single-tag (tag)
497   (member tag nxhtml-single-tags))
498
499 (defvar nxhtml-help-attribute-name
500   '(("title"    "Element title")
501     ("class"   "Style class of element")
502     ("charset"  "Encoding of target")
503     ("coords"   "Defining shape")
504     ("href"   "Target URL")
505     ("hreflang"   "Language of target")
506     ("name"   "(DEPRECEATED)")
507     ("rel"   "Target's relation to document")
508     ("rev"   "Document's relation to target")
509     ("shape"   "Area shape")
510     ("target"   "Where to open target")
511     ("type"   "MIME type of target")
512
513     ("id"   "Unique id of element")
514     ("lang"   "Language code")
515     ("dir"   "Text direction")
516     ("accesskey"   "Keyboard shortcut")
517     ("tabindex"   "Tab order of element")
518
519     ("style"   "Inline style")
520     ("disabled"   "Tag initially disabled")
521     ("readonly"   "User can not modify")
522     ;;(""   "")
523
524     ("alink" "(DEPRECEATED)")
525     ("background" "(DEPRECEATED)")
526     ("bgcolor" "(DEPRECEATED)")
527     ("link" "(DEPRECEATED)")
528     ("text" "(DEPRECEATED)")
529     ("vlink" "(DEPRECEATED)")
530     ("xml:lang" "Tag content language")
531     ("cite" "URL with more info")
532     ("method" "HTTP method for sending")
533     ("accept" "Content types")
534     ("accept-charset" "Character sets")
535     ("enctype" "Encoding")
536     ))
537 (defvar nxhtml-help-attribute-name-tag
538   '(("textarea"
539      ("name" "Name for textarea")
540      )
541     ))
542
543 (defvar nxhtml-help-tag
544   (let ((h (make-hash-table :test 'equal)))
545     (puthash "html"     "Document" h)
546     (puthash "head"     "Document head" h)
547     (puthash "title"    "Document title" h)
548     (puthash "base"     "Base URL/target" h)
549     (puthash "meta"     "Meta information" h)
550     (puthash "style"    "Inline style sheet" h)
551     (puthash "link"     "Style sheet etc" h)
552     (puthash "script"   "(Java)Script code" h)
553     (puthash "noscript" "Script disabled part" h)
554     (puthash "isindex"  "(DEPRECEATED)" h)
555
556     (puthash "iframe"   "Inline frame" h)
557     (puthash "frameset" "Organize frames" h)
558     (puthash "frame"    "Sub window" h)
559     (puthash "noframes" "Substitute for frames" h)
560
561     (puthash "bdo"      "Text direction" h)
562
563     (puthash "body"     "Document body" h)
564     (puthash "a"        "Link" h)
565     (puthash "p"        "Paragraph" h)
566     (puthash "span"     "Group inline elements" h)
567     (puthash "br"       "Line break" h)
568     (puthash "hr"       "Horizontal rule" h)
569     (puthash "div"      "Division/section" h)
570     (puthash "img"      "Image" h)
571     (puthash "h1"       "Header 1" h)
572     (puthash "del"      "Deleted text" h)
573     (puthash "strike"   "(DEPRECEATED)" h)
574     (puthash "u"        "(DEPRECEATED)" h)
575     (puthash "s"        "(DEPRECEATED)" h)
576     (puthash "ins"      "Inserted text" h)
577     (puthash "sup"      "Superscript text" h)
578     (puthash "center"   "(DEPRECEATED)" h)
579     (puthash "dir"      "(DEPRECEATED)" h)
580
581     (puthash "blockquote" "Long quotation" h)
582     (puthash "q"          "Short quotation" h)
583     (puthash "pre"      "Preformatted text" h)
584     (puthash "applet"   "(DEPRECEATED)" h)
585     (puthash "basefont" "(DEPRECEATED)" h)
586     (puthash "font"     "(DEPRECEATED)" h)
587
588     ;; The following elements are all font style elements. They are
589     ;; not deprecated, but it is possible to achieve richer effects
590     ;; using style sheets.
591     (puthash "tt"       "Renders as teletype or mono spaced text" h)
592     (puthash "i"        "Renders as italic text" h)
593     (puthash "b"        "Renders as bold text" h)
594     (puthash "big"      "Renders as bigger text" h)
595     (puthash "small"    "Renders as smaller text" h)
596
597
598     ;; The following tags are not deprecated, but it is possible to
599     ;; achieve a much richer effect using style sheets:
600     (puthash "em"       "Renders as emphasized text" h)
601     (puthash "strong"   "Renders as strong emphasized text" h)
602     (puthash "dfn"      "Defines a definition term" h)
603     (puthash "code"     "Defines computer code text" h)
604     (puthash "samp"     "Defines sample computer code" h)
605     (puthash "kbd"      "Defines keyboard text" h)
606     (puthash "var"      "Defines a variable" h)
607     (puthash "cite"     "Defines a citation" h)
608
609     (puthash "ul"       "Unordered list" h)
610     (puthash "ol"       "Ordered list" h)
611     (puthash "li"       "List element" h)
612     (puthash "dl"       "Definition list" h)
613     (puthash "dt"       "Definition term" h)
614     (puthash "dd"       "Definition description" h)
615
616
617     (puthash "fieldset" "Draw box around" h)
618     (puthash "form"     "User input form" h)
619     (puthash "input"    "Input field/checkbox etc" h)
620     (puthash "textarea" "Input multiline field" h)
621     (puthash "button"   "Push button" h)
622     (puthash "label"    "Label for control" h)
623     (puthash "map"      "Client side image map" h)
624     (puthash "select"   "Drop down list" h)
625     (puthash "option"   "Option in drop down list" h)
626     (puthash "menu"     "(DEPRECEATED)" h)
627
628     (puthash "object"   "Embedded object" h)
629     (puthash "param"    "Object settings" h)
630
631     (puthash "abbr"     "Abbreviation" h)
632     (puthash "address"  "For addresses etc" h)
633     (puthash "acronym"  "May be used for lookup etc" h)
634
635     (puthash "table"    "Table" h)
636     (puthash "caption"  "Table caption" h)
637     (puthash "col"      "Table column attributes" h)
638     (puthash "colgroup"  "Table column group" h)
639     (puthash "thead"    "Table header" h)
640     (puthash "tbody"    "Table body" h)
641     (puthash "tfoot"    "Table footer" h)
642     (puthash "tr"       "Table row" h)
643     (puthash "td"       "Table cell" h)
644
645     h))
646
647 ;;;###autoload
648 (defun nxhtml-short-tag-help (tag)
649   "Display description of tag TAG.  If TAG is omitted, try tag at point."
650   (interactive
651    (let ((tag (xhtml-help-tag-at-point)))
652      (unless (stringp tag)
653        (setq tag (read-string "No tag at point. Give tag name: ")))
654      (list tag)))
655   (setq tag (downcase tag))
656   (let ((desc (gethash tag nxhtml-help-tag))
657         (use-dialog-box nil))
658     (unless desc
659       (setq desc (concat tag " -- No short description available")))
660     (when (y-or-n-p (concat desc ". Fetch more information from the Internet? "))
661       ;; Loaded by the autoloading of `xhtml-help-tag-at-point' above:
662       (xhtml-help-browse-tag tag))))
663
664 (defvar nxhtml-no-single-tags nil)
665 (defvar nxhtml-no-end-tags nil)
666
667 (defadvice rng-complete-qname-function (around nxhtml-rng-complete-qname-function-ad
668                                                (string predicate flag)
669                                                disable)
670   ;;(if (not (eq major-mode 'nxhtml-mode))
671   (if (not nxhtml-completing-with-help)
672       ad-do-it
673     (setq ad-return-value
674           (let ((alist (mapcar (lambda (name) (cons name nil))
675                                (nxhtml-rng-generate-qname-list string))))
676             (cond ((not flag)
677                    (try-completion string alist predicate))
678                   ((eq flag t)
679                    (all-completions string alist predicate))
680                   ((eq flag 'lambda)
681                    (and (assoc string alist) t)))))))
682
683
684
685
686 (defvar nxhtml-predicate-error nil)
687
688 (defun nxhtml-find-ids (file)
689   (let ((buf (find-file-noselect file)))
690     (when buf
691       (with-current-buffer buf
692         (when (eq major-mode 'nxhtml-mode)
693           (save-excursion
694             (let ((ids nil)
695                   (id-ptrn
696                    (rx space
697                        "id"
698                        (0+ space)
699                        ?=
700                        (0+ space)
701                        ?\"
702                        (submatch
703                         (1+ (not (any ?\")))
704                         )
705                        ?\"
706                        )))
707               (goto-char (point-min))
708               (while (re-search-forward id-ptrn nil t)
709                 (add-to-list 'ids (match-string-no-properties 1)))
710               ids)))))))
711
712 (defun nxhtml-read-url (&optional allowed-types initial-contents extra-predicate prompt-prefix)
713   (popcmp-mark-completing initial-contents)
714   (let ((local-ovl popcmp-mark-completing-ovl))
715     (setq popcmp-mark-completing-ovl nil)
716     (unwind-protect
717         (let* ((url-type (nxhtml-read-url-type allowed-types initial-contents))
718                (base-prompt (cond ((eq url-type 'local-file-url)
719                                    "File: ")
720                                   ((eq url-type 'id-url)
721                                    "Id: ")
722                                   ((eq url-type 'web-url)
723                                    "Web URL: ")
724                                   ((eq url-type 'mail-url)
725                                    "e-Mail address: ")
726                                   ((eq url-type 'any-url)
727                                    "Any URL-type: ")
728                                   (t
729                                    ;;(error "Internal error: bad url-type=%s" url-type)
730                                    "Unknown URL-type: ")
731                                   ))
732                prompt
733                type-predicate
734                url
735                (bad-url initial-contents)
736                (default-directory (if buffer-file-name
737                                       (file-name-directory buffer-file-name)
738                                     default-directory)))
739           (when prompt-prefix
740             (setq base-prompt (concat prompt-prefix " " base-prompt)))
741           (setq nxhtml-predicate-error "")
742           (cond ((eq url-type 'local-file-url)
743                  )
744                 ((eq url-type 'web-url)
745                  )
746                 ((eq url-type 'mail-url)
747                  (setq type-predicate 'nxhtml-mailto-predicate)
748                  (when (and (stringp bad-url)
749                             (<= 7 (length bad-url))
750                             (string= "mailto:" (substring bad-url 0 7)))
751                    (setq bad-url (substring bad-url 7)))))
752           (while (not url)
753             (setq prompt (concat nxhtml-predicate-error " " base-prompt))
754             (cond ((eq url-type 'local-file-url)
755                    (setq url (read-file-name prompt nil "" nil bad-url extra-predicate))
756                    (when (< 0 (length url))
757                      ;; Fix-me: prompt for id here
758                      (setq url (file-relative-name
759                                 (expand-file-name url)))))
760                   ((eq url-type 'id-url)
761                    (setq url (completing-read prompt (nxhtml-find-ids buffer-file-name)))
762                    (when url
763                      (setq url (concat "#" url))))
764                   ((eq url-type 'web-url)
765                    (setq url (nxhtml-read-from-minibuffer prompt bad-url nil nil
766                                                           'nxhtml-read-web-url-history
767                                                           t)))
768                   ((eq url-type 'mail-url)
769                    (setq url (nxhtml-read-from-minibuffer prompt bad-url nil nil
770                                                           'nxhtml-read-mail-url-history
771                                                           t)))
772                   (t
773                    (setq url (nxhtml-read-from-minibuffer prompt bad-url nil nil
774                                                           'nxhtml-read-url-history
775                                                           t))))
776             (when (or (and type-predicate
777                            (not (funcall type-predicate url)))
778                       (and extra-predicate
779                            (not (funcall extra-predicate url))))
780               (setq bad-url url)
781               (setq url)))
782           (when (eq url-type 'mail-url)
783             (setq url (concat "mailto:" url)))
784           url)
785       (delete-overlay local-ovl)
786       )))
787
788 (defun nxhtml-read-url-type (allowed url-beginning)
789   (assert (or (listp allowed) (eq t allowed)) t)
790   (let* ((prompt "URL-type: ")
791          (parsed-url (url-generic-parse-url url-beginning))
792          (beg-type (url-type parsed-url))
793          (allowed-u allowed)
794          (completion-ignore-case t)
795          choices
796          choice)
797     ;; (url-type (url-generic-parse-url "#some-id"))
798     ;;(lwarn t :warning "url-type=%s, pu=%s" (url-type parsed-url) parsed-url)
799     ;; Emacs 23 bug workaround Sat Jan 26 2008
800     ;;(when (eq beg-type 'cl-struct-url) (setq beg-type (elt parsed-url 1)))
801     (cond ((string= "mailto" beg-type)
802            (setq allowed-u '(?m)))
803           ((or (string= "http"  beg-type)
804                (string= "https" beg-type)
805                (string= "ftp"   beg-type))
806            (setq allowed-u '(?w)))
807           ((= 1 (length beg-type)) ;; w32
808            (setq allowed-u '(?f)))
809           ((and (null beg-type)
810                 url-beginning
811                 (= ?# (string-to-char url-beginning)))
812            (setq allowed-u '(?i)))
813           )
814     ;; Be a bit picky and hopefully helpful, check if really allowed:
815     (unless (or (eq allowed t)
816                 (equal allowed allowed-u))
817       (let ((temp-u (copy-sequence allowed-u)))
818         (dolist (a allowed)
819           (setq temp-u (delq a temp-u)))
820         (dolist (u temp-u)
821           (setq allowed-u (delq u allowed-u)))))
822     (if allowed-u
823         (when (eq allowed-u t)
824           (setq allowed-u '(?f ?i ?w ?m)))
825       (setq allowed-u '(?f ?w)))
826     (dolist (a allowed-u)
827       (cond
828        ((= a ?f)
829         (setq choices (cons "File" choices)))
830        ((= a ?i)
831         (setq choices (cons "Id" choices)))
832        ((= a ?w) (setq choices (cons "Url" choices)))
833        ((= a ?m) (setq choices (cons "Mail" choices)))
834        ))
835     (if (= 1 (length allowed-u))
836         (setq choice (car choices))
837       (setq choice (popcmp-completing-read prompt choices nil t
838                                            "" nil nil t)))
839     (cond ((string= choice "Id")
840            'id-url)
841           ((string= choice "File")
842            'local-file-url)
843           ((string= choice "Url")
844            'web-url)
845           ((string= choice "Mail")
846            'mail-url)
847           )))
848
849 (defvar nxhtml-read-url-history nil)
850 (defvar nxhtml-read-web-url-history nil)
851 (defvar nxhtml-read-mail-url-history nil)
852
853 (defconst nxhtml-in-xml-attribute-value-regex
854   (replace-regexp-in-string
855    "w"
856    xmltok-ncname-regexp
857    ;;"<w\\(?::w\\)?\
858    "<\\?xml\
859 \\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
860 \[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
861 \[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
862 \\(\"[^\"]*\\|'[^']*\\)\\="
863    t
864    t))
865
866 (defun nxhtml-mailto-predicate (url)
867   "Tries to match a mailto url.
868 This is not supposed to be entirely correct."
869   (setq nxhtml-predicate-error nil)
870   ;; Local pattern copied from gnus.
871   (let ((r (concat "^"
872                    ;;"mailto:"
873                    "[a-z0-9$%(*-=?[_][^<>\")!;:,{}]*"
874                    "\@"
875                    "\\(?:[a-z0-9\-]+\.\\)+[a-z0-9]\\{2,4\\}$"))
876         (case-fold-search t))
877     ;;(message "mailpred") (sit-for 1)
878     (if (string-match r url)
879         t
880       (setq nxhtml-predicate-error "Malformed email address.")
881       nil)))
882
883 (defcustom nxhtml-image-completion-pattern
884   "\\.\\(?:png\\|jpg\\|jpeg\\|gif\\)$"
885   "Pattern for matching image URLs in completion."
886   :type 'regexp
887   :group 'nxhtml)
888
889 (defun nxhtml-image-url-predicate (url)
890   (setq nxhtml-predicate-error nil)
891   (if (or (file-directory-p url)
892           (string-match nxhtml-image-completion-pattern url))
893       t
894     (setq nxhtml-predicate-error "Does not match image file name pattern.")
895     nil
896     ))
897
898 (defcustom nxhtml-css-completion-pattern
899   "\\.\\(?:css\\)$"
900   "Pattern for matching css URLs in completion."
901   :type 'regexp
902   :group 'nxhtml)
903
904 (defun nxhtml-css-url-predicate (url)
905   (setq nxhtml-predicate-error nil)
906   (if (or (file-directory-p url)
907           (string-match nxhtml-css-completion-pattern url))
908       t
909     (setq nxhtml-predicate-error "Does not match css file name pattern.")
910     nil
911     ))
912
913 (defcustom nxhtml-script-completion-pattern
914   "\\.\\(?:js\\)$"
915   "Pattern for matching src URLs in completion in script tags."
916   :type 'regexp
917   :group 'nxhtml)
918
919 (defun nxhtml-script-url-predicate (url)
920   (setq nxhtml-predicate-error nil)
921   (if (or (file-directory-p url)
922           (string-match nxhtml-script-completion-pattern url))
923       t
924     (setq nxhtml-predicate-error "Does not match script file name pattern.")
925     nil
926     ))
927
928 (defun nxhtml-coding-systems-complete (init default)
929   (let (coding-systems
930         hist-num
931         (n 0)
932         hist)
933     (unless (and init (< 0 (length init)))
934       (setq init default))
935     (mapc (lambda (coding-system)
936             (let ((mime-charset (coding-system-get coding-system 'mime-charset)))
937               (when mime-charset
938                 (setq coding-systems (cons
939                                       (symbol-name mime-charset)
940                                       coding-systems)))))
941           (coding-system-list t))
942     (setq coding-systems (sort coding-systems 'string=))
943     (mapc (lambda (coding-system)
944             (unless (< 0 (length coding-system))
945               (error "len=0"))
946             (setq n (1+ n))
947             (when (string= coding-system init) (setq hist-num n)))
948           coding-systems)
949     (if hist-num
950         (setq hist (cons 'coding-systems hist-num))
951       (setq hist 'coding-systems))
952     (completing-read "Encoding (coding system): "
953                      coding-systems nil t init hist)))
954
955
956 ;; Note: This function does not currently use the state provided by
957 ;; the nxml and rng functions directly.  Instead it searches the
958 ;; environment near point to decide what to do.
959 ;; (defun nxhtml-complete-and-insert ()
960 ;;   "Perform XHTML completion at point.
961 ;; This is merely an extended version of `nxml-complete' with the following changes:
962
963 ;; - If region is visible and active then completion will surround the
964 ;;   region with the chosen tag's start and end tag.  However only the
965 ;;   starting point is checked for validity. If something is wrong after
966 ;;   insertion you will however immediately see it if you have validation
967 ;;   on.
968 ;; - Can in some cases give completion help inside attribute values.
969 ;; - There does not have to be a '<' before point for tag name
970 ;;   completion. (`nxml-mode' requires a '<' before point for tag name
971 ;;   completion.)
972 ;; - For tag names there is a popup style completion available. This
973 ;;   gives a bit more guiding since it groups the alternative tags. Set
974 ;;   `popcmp-popup-completion' to use this.
975 ;; - Completes xml version and encoding.
976 ;; - Completes an empty file, ie inserts a skeleton."
977 ;;   (interactive)
978 ;;   (let (res
979 ;;         (where (nxhtml-check-where)))
980 ;;     (or (when (eq where 'in-empty-page)
981 ;;           (nxhtml-empty-page-completion))
982 ;;         (when (and mark-active
983 ;;                    transient-mark-mode
984 ;;                    (eq where 'in-text))
985 ;;           (nxhtml-insert-tag))
986 ;;         (progn
987 ;;           (cond ((memq where '(in-start-tag in-closed-start-tag in-end-tag))
988 ;;                  (re-search-forward "\\=/?[a-z]*" nil t))
989 ;;                 ((memq where '(in-attr))
990 ;;                  (re-search-forward "\\=[a-z]*=" nil t))
991 ;;                 ((memq where '(in-attr-val in-xml-attr-val))
992 ;;                  (re-search-forward "\\=[^<>\" \t\r\n]*" nil t))
993 ;;                 )
994 ;;           (when (run-hook-with-args-until-success 'nxml-completion-hook)
995 ;;             (when (re-search-backward "[^=]\"\\=" nil t)
996 ;;               (forward-char) (delete-char 1)
997 ;;               ;;(undo-start) (undo-more 1)
998 ;;               )
999 ;;             t))
1000 ;;         (when (and (not where)
1001 ;;                    (char-before)
1002 ;;                    (= ?\" (char-before)))
1003 ;;           nil)
1004 ;;         (when (or (when (char-before) (= ?> (char-before)))
1005 ;;                   (eq where 'in-text))
1006 ;;           (setq res t)
1007 ;;           (nxhtml-insert-tag))
1008 ;;         ;; Eventually we will complete on entity names here.
1009 ;;         res
1010 ;;         (progn
1011 ;;           (ding)
1012 ;;           (message "Cannot complete in this context")))))
1013
1014 (defvar nxhtml-in-proc-instr-back-regex "<\\?[^<>]*\\=")
1015 (defvar nxhtml-in-proc-instr-forw-regex "\\=[^<>]*\\?>")
1016
1017 (defconst rngalt-in-pre-attribute-value-regex
1018   (replace-regexp-in-string
1019    "w"
1020    xmltok-ncname-regexp
1021    "<w\\(?::w\\)?\
1022 \\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
1023 \[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
1024 \[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
1025 \\="
1026    t
1027    t))
1028
1029 (defun nxhtml-check-where ()
1030   "Get a state for `nxhtml-complete-last-try'."
1031   (let ((p (point))
1032         (lt-pos (save-excursion (search-backward "<" nil t)))
1033         res)
1034     (cond ((= 0 (buffer-size))
1035            (setq res 'in-empty-page))
1036           ((looking-back "<!--[^<>]*\\=" 1 t)
1037            (setq res 'in-comment))
1038           ((let ((face (get-char-property (point) 'face)))
1039              (when (memq face '(nxml-comment-content-face
1040                                 nxml-comment-delimiter-face))
1041                (setq res 'in-comment)))
1042            t)
1043           ((looking-back nxhtml-in-xml-attribute-value-regex lt-pos t)
1044            (setq res 'in-xml-attr-val))
1045           ((looking-back nxhtml-in-proc-instr-back-regex 1 t)
1046            (setq res 'in-proc-instr))
1047           ((looking-back "<!D[^>]*\\=" 1 t)
1048            (setq res 'in-doctype))
1049           ((looking-back ">[^<]*" 1 t)
1050            (setq res 'in-text))
1051           ((looking-back rng-in-start-tag-name-regex 1 t)
1052            (setq res 'in-tag-start)
1053            (when (looking-at "\\=[^<]*>")
1054              (setq res 'in-closed-start-tag)))
1055           ((looking-back rng-in-end-tag-name-regex 1 t)
1056            (setq res 'in-tag-end))
1057           ((looking-back rng-in-attribute-regex 1 t)
1058            (setq res 'in-attr))
1059           ((looking-back rng-in-attribute-value-regex 1 t)
1060            (setq res 'in-attr-val))
1061           ((looking-back rngalt-in-pre-attribute-value-regex 1 t)
1062            (setq res 'in-pre-attr-val))
1063           ((looking-back "\"")
1064            (setq res 'after-attr-val))
1065           ((and rngalt-validation-header
1066                 (looking-back "\\`[^<]*"))
1067            ;; FIX-ME: This is treated the same as in text currently,
1068            ;; but this should be checked. Maybe it is best to test
1069            ;; this here and return the relevant value?
1070            (setq res 'after-validation-header))
1071           )
1072     ;;(message "res=%s" res)(sit-for 1)
1073     (unless res
1074       (error "Could not find a state for completion"))
1075     res))
1076
1077
1078
1079 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1080 ;;; Make the completions additions cleaner:
1081
1082 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1083
1084 (defconst nxhtml-tag-sets
1085   '(("logical"
1086      "del"
1087      "ins"
1088      "abbr"
1089      "acronym"
1090      "fieldset"
1091      "blockquote"
1092      "q"
1093      "code"
1094      "samp"
1095      "cite"
1096      "kbd"
1097      "var"
1098      "dfn"
1099      "address"
1100      "em"
1101      "strong"
1102      "pre"
1103      )
1104     ("physical"
1105      "hr"
1106      "sup"
1107      "sub"
1108      "font"
1109      "basefont"
1110      "br"
1111      "big"
1112      "small"
1113      "strike"
1114      "u"
1115      "i"
1116      "b"
1117      "s"
1118      "tt"
1119      "center"
1120      "bdo"
1121      )
1122     ("scripting"
1123      "script"
1124      "noscript"
1125      "object"
1126      "applet"
1127      )
1128     ("structure"
1129      "iframe"
1130      "p"
1131      "div"
1132      "span"
1133      "h6"
1134      "h5"
1135      "h4"
1136      "h3"
1137      "h2"
1138      "h1"
1139      )
1140
1141     ("form"
1142      "isindex"
1143      "label"
1144      "button"
1145      "option"
1146      "select"
1147      "input"
1148      "textarea"
1149      "form"
1150      )
1151
1152     ("list"
1153      "dt"
1154      "dd"
1155      "li"
1156      "dir"
1157      "menu"
1158      "ol"
1159      "dl"
1160      "ul"
1161      )
1162
1163     ("link"
1164      "a"
1165      )
1166
1167     ("image"
1168      "img"
1169      "map"
1170      )
1171
1172     ("table"
1173      "table"
1174      "tr"
1175      "th"
1176      "td"
1177      "caption"
1178      "col"
1179      "colgroup"
1180      "thead"
1181      "tbody"
1182      "tfoot"
1183      )
1184
1185     ("document"
1186      "base"
1187      "style"
1188      "link"
1189      "head"
1190      "body"
1191      "frame"
1192      "frameset"
1193      "noframes"
1194      "isindex"
1195      "nextid"
1196      "meta"
1197      "title"
1198      )
1199     ))
1200
1201 (defvar nxhtml-attr-sets
1202   '(("scripting"
1203      "onblur"
1204      "onchange"
1205      "onclick"
1206      "ondblclick"
1207      "onfocus"
1208      "onkeydown"
1209      "onkeypress"
1210      "onkeyup"
1211      "onload"
1212      "onunload"
1213      "onmousedown"
1214      "onmousemove"
1215      "onmouseout"
1216      "onmouseover"
1217      "onmouseup"
1218      "onreset"
1219      "onselect"
1220      "onsubmit"
1221      )
1222     ("form"
1223      "method"
1224      "accept"
1225      "accept-charset"
1226      "enctype"
1227      )
1228     ("access"
1229      "id"
1230      "name"
1231      "disabled"
1232      "readonly")
1233     ("layout"
1234      "accesskey"
1235      "class"
1236      "coords"
1237      "shape"
1238      "style"
1239      "tabindex"
1240      "title"
1241      "align"
1242      "valign"
1243      "alink"
1244      "background"
1245      "bgcolor"
1246      "link"
1247      "text"
1248      "vlink"
1249      "compact"
1250      )
1251     ("target"
1252      "charset"
1253      "href"
1254      "hreflang"
1255      "rel"
1256      "rev"
1257      "target"
1258      "type"
1259      )
1260     ("language"
1261      "dir"
1262      "lang"
1263      "xml:lang"
1264      )
1265     ;; id
1266     ;; name
1267     ;; xml:lang
1268     ))
1269
1270 (defun nxhtml-complete-last-try ()
1271   (when rng-current-schema-file-name
1272     (let ((where (nxhtml-check-where)))
1273       (cond
1274        ;;((eq where 'after-attr-val)
1275        ;;(insert " ")
1276        ;;)
1277        ((eq where 'in-pre-attr-val)
1278         (insert ?\"))
1279        ((eq where 'in-comment)
1280         (if (not (looking-at "[^>]*<"))
1281             nil
1282           (insert " -->")
1283           t))
1284        ((eq where 'in-xml-attr-val)
1285         (let (attr
1286               delimiter
1287               val)
1288           (save-excursion
1289             (save-match-data
1290               (re-search-forward "\\=[^<> \t\r\n\"]*" nil t)))
1291           (let* ((name-start (match-beginning 1))
1292                  (name-end (match-end 1))
1293                  (colon (match-beginning 2))
1294                  (attr (buffer-substring-no-properties name-start
1295                                                        (or colon name-end)))
1296                  (value-start (1+ (match-beginning 3)))
1297                  (tag (save-excursion
1298                         (when (search-backward-regexp "<[[:alpha:]]+" nil t)
1299                           (match-string 0))))
1300                  (init (buffer-substring-no-properties value-start (point))))
1301             (setq delimiter (char-before value-start))
1302             (cond ((string= "encoding" attr)
1303                    ;; Give a default that works in browsers today
1304                    (setq val (nxhtml-coding-systems-complete
1305                               init
1306                               (symbol-name nxhtml-default-encoding))))
1307                   ((string= "version" attr)
1308                    (setq val "1.0")))
1309             (when val
1310               (insert val)
1311               t)
1312             )))
1313        ((or (memq where '(in-text
1314                           after-validation-header
1315                           in-empty-page)))
1316         (rngalt-complete-tag-region-prepare)
1317         (insert "<")
1318         (condition-case err
1319             (nxhtml-redisplay-complete)
1320           (quit
1321            (message "%s" (error-message-string err))
1322            (undo-start)
1323            (undo-more 1)
1324            (rngalt-complete-tag-region-cleanup)))
1325         t)
1326        (t
1327         ;;(message "LAST TRY where=%s" (nxhtml-check-where))(sit-for 1)
1328         nil)
1329        ))))
1330
1331 (defun nxhtml-img-tag-do-also ()
1332   (insert "alt=\"")
1333   (rngalt-validate)
1334   (insert (read-string "Alt attribute: ")
1335           "\" ")
1336   (insert "src=\"")
1337   (rngalt-validate)
1338   (let ((src (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Image")))
1339     (insert src)
1340     (insert "\"")
1341     (when (file-exists-p src)
1342       (let ((sizes (image-size (create-image (expand-file-name src)) t)))
1343         (insert
1344          " width=\""  (format "%d" (car sizes)) "\""
1345          " height=\"" (format "%d" (cdr sizes)) "\"")
1346         )))
1347   (unless (save-match-data (looking-at "[^<]\\{,200\\}>"))
1348     (insert " />")))
1349
1350 (defun nxhtml-redisplay-complete ()
1351   (rngalt-validate)
1352   (rng-cancel-timers)
1353   (message "")
1354   (redisplay t)
1355   (nxml-complete)
1356   (rng-activate-timers))
1357
1358 (defun nxhtml-read-from-minibuffer (prompt &optional
1359                                            initial-contents keymap
1360                                            read hist default-value
1361                                            inherit-input-method)
1362   (rng-cancel-timers)
1363   (message "")
1364   (let ((res (read-from-minibuffer prompt initial-contents keymap
1365                                    read hist default-value inherit-input-method)))
1366     (rng-activate-timers)
1367     res))
1368
1369 (defun nxhtml-meta-tag-do-also ()
1370   (let ((type (popcmp-completing-read
1371                "Type: "
1372                '(
1373                  ;;"Refresh/Redirect"
1374                  "HTTP Message Headers"
1375                  "Robot Rules"
1376                  "Description for Search Engines"
1377                  ))))
1378     (cond
1379      ((string= type "Description for Search Engines")
1380       (insert " name=\"Description\"")
1381       (insert " content=\"")
1382       (insert (nxhtml-read-from-minibuffer "Description: "))
1383       (insert "\" />"))
1384      ((string= type "Robot Rules")
1385       (insert " name=\"Robots\"")
1386       (insert " content=\"")
1387       (nxhtml-redisplay-complete)
1388       (insert " />"))
1389      ((string= type "HTTP Message Headers")
1390       (insert " http-equiv=\"")
1391       (nxhtml-redisplay-complete)
1392       (insert " content=\"")
1393       (insert (nxhtml-read-from-minibuffer "Content: "))
1394       (insert "\" />")))))
1395
1396 (defun nxhtml-style-tag-do-also ()
1397   (insert "type=\"text/css\"")
1398   (insert " media=\"")
1399   (nxhtml-redisplay-complete)
1400   (insert ">")
1401   (indent-according-to-mode)
1402   (insert "\n/* <![CDATA[ */")
1403   (indent-according-to-mode)
1404   (insert "\n")
1405   (indent-according-to-mode)
1406   (insert "\n/* ]]> */")
1407   (indent-according-to-mode)
1408   (insert "\n</style>")
1409   (indent-according-to-mode)
1410   (insert "\n")
1411   (end-of-line -2))
1412
1413 (defun nxhtml-script-tag-do-also ()
1414   (let ((type (popcmp-completing-read
1415                "Type: "
1416                '("Inlined"
1417                  "Linked"))))
1418     (cond
1419      ((string= type "Inlined")
1420       (insert "type=\"text/javascript\">")
1421       (indent-according-to-mode)
1422       (insert "\n// <![CDATA[")
1423       (indent-according-to-mode)
1424       (insert "\n")
1425       (indent-according-to-mode)
1426       (insert "\n// ]]>")
1427       (indent-according-to-mode)
1428       (insert "\n</script>")
1429       (indent-according-to-mode)
1430       (end-of-line -1))
1431      ((string= type "Linked")
1432       (insert "type=\"text/javascript\"")
1433       (insert " src=\"")
1434       (nxhtml-redisplay-complete)
1435       (insert "></script>")))))
1436
1437 (defun nxhtml-link-tag-do-also ()
1438   (let ((type (popcmp-completing-read "Type: "
1439                                       '(
1440                                         "Other"
1441                                         "Shortcut icon"
1442                                         "Style sheet"
1443                                         ))))
1444     (cond
1445      ((string= type "Style sheet")
1446       (insert " rel=\"Stylesheet\" ")
1447       (insert "type=\"text/css\" ")
1448       (insert "href=\"")
1449       (nxhtml-redisplay-complete)
1450       (insert " media=\"")
1451       (nxhtml-redisplay-complete)
1452       (insert " />"))
1453      ((string= type "Shortcut icon")
1454       (insert " rel=\"Shortcut Icon\" ")
1455       (insert "href=\"")
1456       (nxhtml-redisplay-complete)
1457       (insert " />"))
1458      (t
1459       (insert " ")
1460       (nxhtml-redisplay-complete)
1461       ))))
1462
1463 (defun nxhtml-input-tag-do-also ()
1464   (insert " ")
1465   (rngalt-validate)
1466   ;; type=
1467   (insert "type=\"")
1468   (nxhtml-redisplay-complete)
1469   (insert " ")
1470
1471   (let* ((choice (save-match-data
1472                    (when (looking-back "type=\"\\(.*\\)\" ")
1473                      (match-string 1)))))
1474     ;;(insert "type=\"" choice "\" ")
1475     (rngalt-validate)
1476     ;;(message "choice=%s" choice)(sit-for 2)
1477     ;; name=
1478     (when (member choice '("button" "checkbox" "file" "hidden" "image"
1479                            "password" "radio" "text"))
1480       (insert "name=\""
1481               (read-string "Name (name): ")
1482               "\" ")
1483       (rngalt-validate))
1484     ;; checked=
1485     (when (member choice '("checkbox" "radio"))
1486       (when (y-or-n-p "Checked? (checked): ")
1487         (insert "checked=\"checked\" ")
1488         (rngalt-validate)))
1489     ;; disabled=
1490     (unless (string= choice "hidden")
1491       (unless (y-or-n-p "Enabled? : ")
1492         (insert "disabled=\"disabled\" ")
1493         (rngalt-validate)))
1494     ;; readonly=
1495     (when (string= choice "text")
1496       (when (y-or-n-p "Readonly? (readonly): ")
1497         (insert "readonly=\"readonly\" "))
1498       (rngalt-validate))
1499     (when (string= choice "file")
1500       ;; accept=
1501       (require 'mailcap)
1502       (condition-case err
1503           (let ((prompt (concat
1504                          "Accept mime type, RET to stop ("
1505                          "C-g to skip"
1506                          "): "))
1507                 (mime " ")
1508                 mimes
1509                 (types (when (boundp 'mailcap-mime-extensions)
1510                          (mapcar (lambda (elt)
1511                                    (cdr elt))
1512                                  mailcap-mime-extensions))))
1513             (while (< 0 (length mime))
1514               (setq mime
1515                     (if types
1516                         (completing-read prompt types)
1517                       (read-string prompt)))
1518               (when (< 0 (length mime))
1519                 (if mimes
1520                     (setq mimes (concat mimes "," mime))
1521                   (setq mimes mime))))
1522             (when (and mimes
1523                        (< 0 (length mimes)))
1524               (insert "accept=\"" mimes "\" ")))
1525         (quit (message "Skipped accept attribute")))
1526       (rngalt-validate))
1527     (when (string= choice "image")
1528       ;; alt=
1529       (insert "alt=\"")
1530       (rngalt-validate)
1531       (insert (read-string "Alt attribute: ")
1532               "\" ")
1533       (rngalt-validate)
1534       ;; src=
1535       (insert "src=\"")
1536       (rngalt-validate)
1537       (let ((src (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Image")))
1538         (insert src)
1539         (insert "\" "))
1540       (rngalt-validate))
1541     ;; value=
1542     (cond
1543      ((member choice '("button" "reset" "submit"))
1544       (nxhtml-do-also-value "Label"))
1545      ((member choice '("checkbox" "radio"))
1546       (nxhtml-do-also-value "Result"))
1547      ((member choice '("hidden" "password" "text"))
1548       (nxhtml-do-also-value "Value"))
1549      )
1550     (insert "/>")
1551     ;;(message "type=%s" choice)(sit-for 2)
1552     ))
1553
1554 (defun nxhtml-do-also-value (label)
1555   (let ((v (read-string (concat label " (value): "))))
1556     (when (and v
1557                (< 0 (length v)))
1558       (insert " value=\"" v "\" "))))
1559
1560 (defun nxhtml-form-tag-do-also ()
1561   (insert "action=\"")
1562   (rngalt-validate)
1563   (let ((src (nxhtml-read-url nil nil nil "Action")))
1564     (insert src "\" "))
1565   )
1566
1567 (defun nxhtml-a-tag-do-also ()
1568   (insert " href=\"")
1569   (rngalt-validate)
1570   (insert (nxhtml-read-url t))
1571   (insert "\"")
1572   (let* ((pre-choices '("_blank" "_parent" "_self" "_top"))
1573          (all-choices (reverse (cons "None" (cons "Frame name" pre-choices))))
1574          choice
1575          (prompt "Target: "))
1576       (setq choice (popcmp-completing-read prompt all-choices nil t
1577                                            "" nil nil t))
1578       (unless (string= choice "None")
1579         (insert " target=\"")
1580         (cond ((member choice pre-choices)
1581                (insert choice "\""))
1582               ((string= choice "Frame name")
1583                (rngalt-validate)
1584                (insert (read-string "Frame name: ") "\""))
1585               (t (error "Uh?")))))
1586   (insert ">")
1587   (rngalt-validate)
1588   (insert (read-string "Link title: ")
1589           "</a>"))
1590
1591 (defconst nxhtml-complete-tag-do-also
1592   '(("a" nxhtml-a-tag-do-also)
1593      ;; (lambda ()
1594      ;;   (insert " href=\"")
1595      ;;   (rngalt-validate)
1596      ;;   (insert (nxhtml-read-url t))
1597      ;;   (insert "\"")))
1598     ("form" nxhtml-form-tag-do-also)
1599     ("img" nxhtml-img-tag-do-also)
1600     ("input" nxhtml-input-tag-do-also)
1601     ("link" nxhtml-link-tag-do-also)
1602     ("script" nxhtml-script-tag-do-also)
1603     ("style" nxhtml-style-tag-do-also)
1604     ("meta" nxhtml-meta-tag-do-also)
1605     )
1606   "List of functions to call at tag completion.
1607 Each element of the list have the form
1608
1609   \(TAG-NAME TAG-FUN)
1610
1611 If `nxhtml-tag-do-also' is non-nil then TAG-FUN is called after
1612 by `nxml-complete' (with the special setup of this function for
1613 `nxhtml-mode') when completing a tag with the name TAG-NAME.
1614
1615 The list is handled as an association list, ie only the first
1616 occurence of a tag name is used.")
1617
1618 (defun nxhtml-complete-tag-do-also-for-state-completion (dummy-completed)
1619   "Add this to state completion functions completed hook."
1620   (when (and nxhtml-tag-do-also
1621              (derived-mode-p 'nxhtml-mode))
1622     ;; Find out tag
1623     (let ((tag nil))
1624       (save-match-data
1625         ;;(when (looking-back "<\\([a-z]+\\)[[:blank:]]+")
1626         (when (looking-back "<\\([a-z]+\\)")
1627           (setq tag (match-string 1))))
1628       (when tag
1629         (insert " ")
1630         (nxhtml-complete-tag-do-also tag)))))
1631
1632 (defun nxhtml-complete-tag-do-also (tag)
1633   ;; First required attributes:
1634   (let ((tagrec (assoc tag nxhtml-complete-tag-do-also)))
1635     (when tagrec
1636       (funcall (cadr tagrec))))
1637   )
1638
1639
1640 ;;;###autoload
1641 (define-minor-mode nxhtml-validation-header-mode
1642   "If on use a Fictive XHTML Validation Header for the buffer.
1643 See `nxhtml-set-validation-header' for information about Fictive XHTML Validation Headers.
1644
1645 This mode may be turned on automatically in two ways:
1646 - If you try to do completion of a XHTML tag or attribute then
1647   `nxthml-mode' may ask you if you want to turn this mode on if
1648   needed.
1649 - You can also choose to have it turned on automatically whenever
1650   a mumamo multi major mode is used, see
1651   `nxhtml-validation-header-if-mumamo' for further information."
1652   :global nil
1653   :lighter " VH"
1654   :group 'nxhtml
1655   (if nxhtml-validation-header-mode
1656       (progn
1657         (unless nxhtml-current-validation-header
1658           (setq nxhtml-current-validation-header
1659                 (nxhtml-get-default-validation-header)))
1660         ;;(message "nxhtml-current-validation-header=%s" nxhtml-current-validation-header)
1661         (if nxhtml-current-validation-header
1662             (progn
1663               (nxhtml-apply-validation-header)
1664               (add-hook 'change-major-mode-hook 'nxhtml-vhm-change-major nil t)
1665               (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
1666                 (add-hook 'mumamo-change-major-mode-hook 'nxhtml-vhm-mumamo-change-major nil t)
1667                 (add-hook 'mumamo-after-change-major-mode-hook 'nxhtml-vhm-mumamo-after-change-major nil t)))
1668           (run-with-idle-timer 0 nil 'nxhtml-validation-header-empty (current-buffer))))
1669     (rngalt-set-validation-header nil)
1670     (setq nxhtml-current-validation-header nil)
1671     (remove-hook 'after-change-major-mode-hook 'nxhtml-vhm-after-change-major t)
1672     (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
1673       (remove-hook 'mumamo-change-major-mode-hook 'nxhtml-vhm-mumamo-change-major t)
1674       (remove-hook 'mumamo-after-change-major-mode-hook 'nxhtml-vhm-mumamo-after-change-major t))))
1675
1676 (defun nxhtml-can-insert-page-here ()
1677   (and (not nxhtml-validation-header-mode)
1678        (= 1 (point))
1679        (or (= 0 (buffer-size))
1680            (save-restriction
1681              (widen)
1682              (save-match-data
1683                (looking-at (rx buffer-start
1684                                (0+ space)
1685                                buffer-end)))))))
1686
1687 (defun nxhtml-complete-first-try ()
1688   (when (nxhtml-can-insert-page-here)
1689     (nxhtml-empty-page-completion)))
1690
1691 (defun nxhtml-completing-read-tag (prompt
1692                                    table
1693                                    &optional predicate require-match
1694                                    initial-input hist def inherit-input-method)
1695   (let ((popcmp-in-buffer-allowed t))
1696     (popcmp-completing-read prompt
1697                             table
1698                             predicate require-match
1699                             initial-input hist def inherit-input-method
1700                             nxhtml-help-tag
1701                             nxhtml-tag-sets)))
1702
1703 (defun nxhtml-add-required-to-attr-set (tag)
1704   (let ((missing (when tag
1705                    (rngalt-get-missing-required-attr
1706                     (nxthml-is-single-tag tag)))))
1707     (if (not missing)
1708         nxhtml-attr-sets
1709       (cons (cons "Required" missing)
1710             nxhtml-attr-sets))))
1711
1712 (defun nxhtml-get-tag-specific-attr-help (tag)
1713   (append (cdr (assoc tag nxhtml-help-attribute-name-tag)) nxhtml-help-attribute-name)
1714   )
1715
1716 (defconst nxhtml-in-start-tag-regex
1717   ;;(defconst rng-in-start-tag-name-regex
1718   (replace-regexp-in-string
1719    "w"
1720    xmltok-ncname-regexp
1721    ;; Not entirely correct since < could be part of attribute value:
1722    "<\\(w\\(?::w?\\)?\\)+ [^<]*"
1723    t
1724    t))
1725
1726 (defun nxhtml-completing-read-attribute-name (prompt
1727                                               table
1728                                               &optional predicate require-match
1729                                               initial-input hist def inherit-input-method)
1730   (let* ((tag (save-match-data
1731                 ;;(when (looking-back "<\\([a-z1-6]+\\) [^<]*")
1732                 (when (looking-back nxhtml-in-start-tag-regex)
1733                   (match-string 1))))
1734          (attr-sets (nxhtml-add-required-to-attr-set tag))
1735          (help-attr (nxhtml-get-tag-specific-attr-help tag))
1736          (popcmp-in-buffer-allowed t)
1737          )
1738     (popcmp-completing-read prompt
1739                             table
1740                             predicate require-match
1741                             initial-input hist def inherit-input-method
1742                             help-attr
1743                             attr-sets)))
1744
1745 (defun nxhtml-completing-read-attribute-value (prompt
1746                                                table
1747                                                &optional predicate require-match
1748                                                initial-input hist def inherit-input-method)
1749   (let (val)
1750     (if table
1751         (let ((popcmp-in-buffer-allowed t))
1752           (setq val (popcmp-completing-read prompt table
1753                                             predicate require-match
1754                                             initial-input hist def inherit-input-method)))
1755       (let* (init
1756              delimiter
1757              (lt-pos (save-excursion (search-backward "<" nil t)))
1758              (in-attr-val
1759               (save-excursion
1760                 (re-search-backward rng-in-attribute-value-regex lt-pos t)))
1761              (in-xml-attr-val
1762               (unless in-attr-val
1763                 (save-excursion
1764                   (re-search-backward nxhtml-in-xml-attribute-value-regex lt-pos t))))
1765              )
1766         (when (or in-attr-val in-xml-attr-val)
1767           ;;(save-match-data (save-excursion (re-search-forward "\\=[^<> \t\r\n\"]*" nil t)))
1768           (let* ((name-start (match-beginning 1))
1769                  (name-end (match-end 1))
1770                  (colon (match-beginning 2))
1771                  (attr (buffer-substring-no-properties name-start
1772                                                        (or colon name-end)))
1773                  (value-start (1+ (match-beginning 3)))
1774                  tag-start-end
1775                  (tag (save-excursion
1776                         (when (search-backward-regexp "<[[:alpha:]]+" nil t)
1777                           (setq tag-start-end (match-end 0))
1778                           (match-string-no-properties 0)))))
1779             (setq init (buffer-substring-no-properties value-start (point)))
1780             (setq delimiter (char-before value-start))
1781             (if in-xml-attr-val
1782                 (error "in-xml-attr-val should not be true here!")
1783               ;;             (cond ((string= "encoding" attr)
1784               ;;                    ;; Give a default that works in browsers today
1785               ;;                    (setq val (nxhtml-coding-systems-complete
1786               ;;                               init
1787               ;;                               (symbol-name nxhtml-default-encoding))))
1788               ;;                   ((string= "version" attr)
1789               ;;                    (setq val "1.0")))
1790               (cond ((string= "rel" attr)
1791                      (cond ((string= "<link" tag)
1792                             (setq val (nxhtml-read-link-rel))
1793                             )))
1794                     ((string= "media" attr)
1795                      (cond ((string= "<link" tag)
1796                             (setq val (nxhtml-read-link-media)))
1797                            ((string= "<style" tag)
1798                             (setq val (nxhtml-read-link-media)))
1799                            ))
1800                     ((string= "type" attr)
1801                      (cond ((string= "<link" tag)
1802                             (setq val (nxhtml-read-link-type))
1803                             )))
1804                     ((string= "http-equiv" attr)
1805                      (cond ((string= "<meta" tag)
1806                             (setq val (nxhtml-read-meta-http-equiv)))))
1807                     ((string= "content" attr)
1808                      (cond ((string= "<meta" tag)
1809                             (setq val (nxhtml-read-meta-content)))))
1810                     ((string= "scheme" attr)
1811                      (cond ((string= "<meta" tag)
1812                             (setq val (nxhtml-read-meta-scheme)))))
1813                     ((string= "name" attr)
1814                      (cond ((string= "<meta" tag)
1815                             (setq val (nxhtml-read-meta-name)))))
1816                     ((string= "href" attr)
1817                      (cond ((string= "<a" tag)
1818                             (setq val (nxhtml-read-url t init)))
1819                            ((string= "<base" tag)
1820                             (setq val (nxhtml-read-url nil init nil "Base")))
1821                            ((string= "<area" tag)
1822                             (setq val (nxhtml-read-url nil init)))
1823                            ((string= "<link" tag)
1824                             (let (predicate
1825                                   (here (point)))
1826                               (save-excursion
1827                                 (goto-char tag-start-end)
1828                                 (cond
1829                                  ((search-forward "text/css" here nil)
1830                                   (setq predicate 'nxhtml-css-url-predicate))
1831                                  ))
1832                               (setq val (nxhtml-read-url nil init predicate))))
1833                            (t
1834                             (setq val (nxhtml-read-url nil init)))))
1835                     ((string= "src" attr)
1836                      (cond ((string= "<img" tag)
1837                             (setq val (nxhtml-read-url nil init 'nxhtml-image-url-predicate "Image")))
1838                            ((string= "<script" tag)
1839                             (setq val (nxhtml-read-url nil init 'nxhtml-script-url-predicate "Script")))
1840                            ((string= "<input" tag)
1841                             (setq val (nxhtml-read-url nil init 'nxhtml-image-url-predicate "Image")))
1842                            ((string= "<frame" tag)
1843                             (setq val (nxhtml-read-url nil init nil "Frame Source")))
1844                            ((string= "<iframe" tag)
1845                             (setq val (nxhtml-read-url nil init nil "Frame Source")))
1846                            (t
1847                             (setq val (nxhtml-read-url nil init)))))))))))
1848     ;;(unless val (setq val (read-from-minibuffer prompt init)))
1849     (if (not val)
1850         (progn
1851           (message "No completion of attribute value available here")
1852           nil)
1853       val)))
1854
1855 (defun nxhtml-read-link-type ()
1856   (require 'mailcap)
1857   (let ((types (when (boundp 'mailcap-mime-extensions)
1858                  (mapcar (lambda (elt)
1859                            (cdr elt))
1860                          mailcap-mime-extensions))))
1861     (completing-read "Link type: " types nil t)))
1862
1863 (defun nxhtml-read-link-media ()
1864   (let ((types '(
1865                  "screen"
1866                  "tty"
1867                  "tv"
1868                  "projection"
1869                  "handheld"
1870                  "print"
1871                  "braille"
1872                  "aural"
1873                  "all"
1874                  )))
1875     (popcmp-completing-read "For media type: " types nil t)))
1876
1877 (defun nxhtml-read-link-rel ()
1878   (let ((predefined-linktypes '(
1879                                 "Alternate"
1880                                 "Appendix"
1881                                 "Bookmark"
1882                                 "Chapter"
1883                                 "Contents"
1884                                 "Copyright"
1885                                 "Glossary"
1886                                 "Help"
1887                                 "Index"
1888                                 "Next"
1889                                 "Prev"
1890                                 "Section"
1891                                 "Shortcut Icon"
1892                                 "Start"
1893                                 "Stylesheet"
1894                                 "Subsection"
1895                                 )))
1896     (popcmp-completing-read "Predefined LinkTypes: " predefined-linktypes nil t)))
1897
1898 (defun nxhtml-read-meta-name ()
1899   (let ((types '(
1900                  "author"
1901                  "description"
1902                  "keywords"
1903                  "generator"
1904                  "revised"
1905                  ;;"others"
1906                  )))
1907     (popcmp-completing-read "Meta name: " types nil t)))
1908
1909 (defun nxhtml-read-meta-content ()
1910   (nxhtml-read-from-minibuffer "Meta content: "))
1911
1912 (defun nxhtml-read-meta-scheme ()
1913   (nxhtml-read-from-minibuffer "Meta scheme: "))
1914
1915 (defun nxhtml-read-meta-http-equiv ()
1916   (let ((types '(
1917                  "content-type"
1918                  "expires"
1919                  "refresh"
1920                  "set-cookie"
1921                  )))
1922     (popcmp-completing-read "Meta http-equiv: " types nil t)))
1923
1924 (when nil
1925   (setq rngalt-completing-read-tag nil)
1926   (setq rngalt-complete-last-try nil)
1927   )
1928
1929
1930 (when (featurep 'typesetter)
1931   (defun typesetter-init-nxhtml-mode ()
1932     (typesetter-init-html-mode))
1933   )
1934
1935 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1936 ;;; Validation start state
1937
1938 (defcustom nxhtml-validation-headers
1939   '(
1940     ("body-iso-8859-1" .
1941      "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1942 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1943 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1944 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1945   <head>
1946     <title>Fictive XHTML Validation Header</title>
1947   </head>
1948   <body>
1949 "
1950      )
1951     ("head-iso-8859-1" .
1952      "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1953 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1954 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1955 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1956   <head>
1957 "
1958      )
1959     ("html-iso-8859-1" .
1960      "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1961 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1962 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1963 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1964 "
1965      )
1966     ;;     ("doctype-iso-8859-1" .
1967     ;;      "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1968     ;; <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1969     ;; \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1970     ;; "
1971     ;;      )
1972     ;;     ("xml-iso-8859-1" .
1973     ;;      "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1974     ;; "
1975     ;;      )
1976
1977     ("body-utf-8" .
1978      "<?xml version=\"1.0\" encoding=\"utf-8\"?>
1979 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1980 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1981 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1982   <head>
1983     <title>Fictive XHTML Validation Header</title>
1984   </head>
1985   <body>
1986 "
1987      )
1988     ("head-utf-8" .
1989      "<?xml version=\"1.0\" encoding=\"utf-8\"?>
1990 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1991 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1992 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1993   <head>
1994 "
1995      )
1996     ("head-closed-utf-8" .
1997      "<?xml version=\"1.0\" encoding=\"utf-8\"?>
1998 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1999 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
2000 <html xmlns=\"http://www.w3.org/1999/xhtml\">
2001   <head>
2002     <title></title>
2003   </head>
2004 "
2005      )
2006     ("html-utf-8" .
2007      "<?xml version=\"1.0\" encoding=\"utf-8\"?>
2008 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
2009 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
2010 <html xmlns=\"http://www.w3.org/1999/xhtml\">
2011 "
2012      )
2013     ;;     ("doctype-utf-8" .
2014     ;;      "<?xml version=\"1.0\" encoding=\"utf-8\"?>
2015     ;; <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
2016     ;; \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
2017     ;; "
2018     ;;      )
2019     ;;     ("xml-utf-8" .
2020     ;;      "<?xml version=\"1.0\" encoding=\"utf-8\"?>
2021     ;; "
2022     ;;      )
2023     )
2024   "Fictive XHTML validation headers.
2025 Used by `nxhtml-set-validation-header'."
2026   :type '(alist :key-type string :value-type string)
2027   :group 'nxhtml)
2028
2029 (defcustom nxhtml-default-validation-header nil
2030   "Default Fictive XHTML validation header.
2031 Must be nil or one of the key values in
2032 `nxhtml-validation-headers'."
2033   :type 'string
2034   :set (lambda (sym val)
2035          (if (or (null val)
2036                  (assoc val nxhtml-validation-headers))
2037              (set-default sym val)
2038            (lwarn 'nxhtml-default-validation-header
2039                   :warning "There is no Fictive XHTML Validation Header named %s" val)))
2040   :group 'nxhtml)
2041
2042 (defun nxhtml-must-have-validation-headers ()
2043   (unless nxhtml-validation-headers
2044     (error
2045      "No XHTML validation headers. Please customize nxhtml-validation-headers.")))
2046
2047 (defvar nxhtml-set-validation-header-hist nil)
2048
2049 (defcustom nxhtml-guess-validation-header-alist
2050   ;;(rx line-start (0+ blank) "<body")
2051   '(
2052     ("^[[:blank:]]*<body"   . "body-utf-8")
2053     ("^[[:blank:]]*</head>" . "head-closed-utf-8")
2054     ("^[[:blank:]]*<head"   . "head-utf-8")
2055     ("^[[:blank:]]*<html"   . "html-utf-8")
2056     )
2057   "Alist used by `nxhtml-guess-validation-header'.
2058 Alternatives are tried from top to bottom until one fits."
2059   :type '(alist :key-type (regexp :tag "If NOT found in buffer")
2060                 :value-type (string :tag "Use Fictive XHTML Validation Header"))
2061   :group 'nxhtml)
2062
2063 (defun nxhtml-guess-validation-header ()
2064   "Return Fictive XHTML validation that could fit current buffer.
2065 This guess is made by matching the entries in
2066 `nxhtml-guess-validation-header-alist' against the buffer."
2067   (nxhtml-must-have-validation-headers)
2068   (save-excursion
2069     (save-restriction
2070       (save-match-data
2071         (widen)
2072         (let (rec
2073               regexp
2074               key
2075               (guesses nxhtml-guess-validation-header-alist))
2076           (goto-char (point-min))
2077           (if (not (search-forward "</" 2000 t))
2078               (progn
2079                 (setq rec (car guesses))
2080                 (setq key (cdr rec)))
2081             (while (and guesses
2082                         (not key))
2083               (setq rec (car guesses))
2084               (setq guesses (cdr guesses))
2085               (setq regexp (car rec))
2086               (goto-char (point-min))
2087               ;; Fix-me: check for chunk and check if in string.
2088               (let (found)
2089                 (while (and (not found)
2090                             (re-search-forward regexp nil t))
2091                   ;; ensure fontified, but how?
2092                   (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
2093                     (let ((mumamo-just-changed-major nil))
2094                       ;;(unless (and (mumamo-get-existing-chunk-at (point))
2095                       (unless (and (mumamo-find-chunks (point) "guess-validation-header")
2096                                    (eq t (get-text-property (point) 'fontified)))
2097                         (mumamo-fontify-region (point-min) (+ 1000 (point))))))
2098                   (unless (memq (get-text-property (point) 'face)
2099                                 '(font-lock-comment-face
2100                                   font-lock-comment-delimiter-face
2101                                   font-lock-doc-face
2102                                   font-lock-string-face
2103                                   ))
2104                     (setq found t)))
2105                 (unless found
2106                   (setq key (cdr rec))))))
2107           ;;(unless (re-search-forward regexp nil t) (setq key (cdr rec)))))
2108           key)))))
2109
2110 (defun nxhtml-open-dir-saved-validation-headers (must-exist)
2111   "Open file with saved validation headers and return buffer."
2112   ;;(lwarn 't :warning "must-exist=%s" must-exist)
2113   (when (buffer-file-name)
2114     (let* ((dir-name (file-name-directory (buffer-file-name)))
2115            (file-name (expand-file-name "nxhtml-val-headers.el"))
2116            emacs-lisp-mode-hook)
2117       (when (or (not must-exist)
2118                 (file-exists-p file-name))
2119         (find-file-noselect file-name)))))
2120
2121 (defun nxhtml-get-saved-validation-header ()
2122   (when (buffer-file-name)
2123     (let* ((val-buf (nxhtml-open-dir-saved-validation-headers t))
2124            (file-name (file-name-nondirectory (buffer-file-name)))
2125            validation-headers)
2126       (when val-buf
2127         (with-current-buffer val-buf
2128           (eval-buffer))
2129         (cadr (assoc file-name validation-headers))))))
2130
2131 (defun nxhtml-remove-saved-validation-header ()
2132   "Removed the saved validation header.
2133 Reverse the action done by `nxhtml-save-validation-header'."
2134   (interactive)
2135   (nxhtml-update-saved-validation-header nil))
2136
2137 (defun nxhtml-save-validation-header ()
2138   "Save the current validation header.
2139 The current validation is saved for the next time you open the
2140 current file.  It is then used by `nxhtml-validation-header-mode'
2141 and `nxhtml-set-validation-header'. This means that if you have
2142 turned on `nxhtml-global-validation-header-mode' this validation
2143 header will be set automatically.
2144
2145 The saved validation header can be removed with
2146 `nxhtml-remove-saved-validation-header'.
2147
2148 * Note: There is normally no need to save the validation headers
2149   since `nxhtml-global-validation-header-mode' will add
2150   validation headers as needed most of the time."
2151   (interactive)
2152   (nxhtml-update-saved-validation-header t))
2153
2154 (defun nxhtml-update-saved-validation-header (save)
2155   (unless (buffer-file-name)
2156     (error "Validation Header can only be saved if buffer contains a file."))
2157   (let* ((val-buf (nxhtml-open-dir-saved-validation-headers nil))
2158          ;;(get-buffer-create "temp val head"))
2159          validation-headers
2160          (file-name (file-name-nondirectory (buffer-file-name)))
2161          (entry (list file-name nxhtml-current-validation-header))
2162          ;;entry-list
2163          removed
2164          )
2165     ;; Get old headers
2166     (with-current-buffer val-buf
2167       (eval-buffer))
2168     ;; Remove old value
2169     (setq validation-headers
2170           (delq nil
2171                 (mapcar (lambda (elt)
2172                           (if (string= file-name (car elt))
2173                               (progn
2174                                 (setq removed t)
2175                                 nil)
2176                             elt))
2177                         validation-headers)))
2178     ;; Add new value
2179     (when save
2180       (setq validation-headers (cons entry validation-headers)))
2181     (with-current-buffer val-buf
2182       (erase-buffer)
2183       ;;(print file-name val-buf)
2184       ;;(print nxhtml-current-validation-header val-buf)
2185       ;;(print entry val-buf)
2186       (insert "(setq validation-headers (quote")
2187       (print validation-headers val-buf)
2188       (insert "))")
2189       (basic-save-buffer)
2190       )
2191     (if save
2192         (message "Current validation header for file saved")
2193       (if removed
2194           (message "Removed saved validation header")
2195         (message "There was no saved validation header")))))
2196
2197 (defun nxhtml-get-default-validation-header ()
2198   "Return default Fictive XHTML validation header key for current buffer.
2199 If `nxhtml-default-validation-header' is non-nil then return
2200 this.  Otherwise return saved validation header if there is one
2201 or guess using `nxhtml-guess-validation-header'."
2202   (or nxhtml-default-validation-header
2203       (nxhtml-get-saved-validation-header)
2204       (nxhtml-guess-validation-header)))
2205
2206 (defun nxhtml-set-validation-header (&optional key)
2207   "Set a Fictive XHTML validation header in the buffer.
2208 Such a header is not inserted in the buffer, but is only used by
2209 validation and XHTML completion by `nxhtml-mode'.
2210
2211 The header is active for validation and completion if and only if
2212 `nxhtml-validation-header-mode' is on.
2213
2214 Note that Fictive XHTML Validation Headers are normally chosen
2215 automatically, but you can use this function to override that choice.
2216
2217 The header is chosen from `nxhtml-validation-headers'. If there
2218 is more than one you will be prompted. To set the default fictive
2219 XHTML validation header customize `nxhtml-validation-headers'.
2220
2221 If called non-interactive then the header corresponding to key
2222 KEY will be used.  If KEY is nil then it is set to
2223 `nxhtml-default-validation-header'.
2224
2225 This header can be visible or invisible in the buffer, for more
2226 information see `rngalt-show-validation-header'."
2227   (interactive
2228    (list
2229     (let ((nh (length nxhtml-validation-headers))
2230           (default (nxhtml-get-default-validation-header)))
2231       (if (> nh 1)
2232           (completing-read "XHTML validation header: "
2233                            nxhtml-validation-headers
2234                            nil
2235                            t
2236                            default
2237                            nxhtml-set-validation-header-hist)
2238         (if (not (y-or-n-p "Only one XHTML validation header is defined. Define more? "))
2239             default
2240           (customize-option 'nxhtml-validation-headers)
2241           'adding)))))
2242   ;;(lwarn 'svh2 :warning "key=%s" key)
2243   (or key
2244       (setq key (nxhtml-get-default-validation-header))
2245       (setq key (cons 'schema "XHTML")))
2246   (unless (eq key 'adding)
2247     (setq nxhtml-current-validation-header key)
2248     (nxhtml-validation-header-mode 1)
2249     (nxhtml-apply-validation-header)))
2250
2251 (defun nxhtml-apply-validation-header ()
2252   (when nxhtml-current-validation-header
2253     (setq rngalt-major-mode
2254           (if (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
2255               (mumamo-main-major-mode)
2256             major-mode))
2257     (let* ((key nxhtml-current-validation-header)
2258            (rec (unless (listp key)
2259                   (assoc key nxhtml-validation-headers)))
2260            (header (cdr rec)))
2261       (if (listp key)
2262           (let ((schema-file (rng-locate-schema-file (cdr key))))
2263             (unless schema-file
2264               (error "Could not locate schema for type id `%s'" key)) ;type-id))
2265             (rng-set-schema-file-1 schema-file))
2266         (rngalt-set-validation-header header)
2267         ))))
2268
2269 (defun nxhtml-update-validation-header ()
2270   "Update the validation header in the buffer as needed."
2271   (interactive)
2272   (let ((mode-on nxhtml-validation-header-mode))
2273     (when mode-on (nxhtml-validation-header-mode 0))
2274     (setq nxhtml-current-validation-header nil)
2275     (when mode-on (nxhtml-validation-header-mode 1))))
2276
2277 (defun nxhtml-vhm-change-major ()
2278   "Turn off `nxhtml-validation-header-mode' after change major."
2279   ;;(message "nxhtml-vhm-change-major here")
2280   (unless (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
2281     (setq nxhtml-current-validation-header nil))
2282   (run-with-idle-timer 0 nil 'nxhtml-validation-header-empty (current-buffer)))
2283 (put 'nxhtml-vhm-change-mode 'permanent-local-hook t)
2284
2285 (defun nxhtml-recheck-validation-header ()
2286   "Just turn off and on again `nxhtml-validation-header-mode'.
2287 This will adjust the XHTML validation to the code currently in
2288 the buffer."
2289   (interactive)
2290   (nxhtml-validation-header-mode -1)
2291   (nxhtml-validation-header-mode 1))
2292
2293 (defun nxhtml-validation-header-empty (buffer)
2294   "Turn off validation header mode.
2295 This is called because there was no validation header."
2296   (with-current-buffer buffer
2297     (unless nxhtml-current-validation-header
2298       ;;(message "nxhtml-validation-header-empty")
2299       (save-match-data ;; runs in timer
2300         (nxhtml-validation-header-mode -1))
2301       ;;(message "No validation header was needed")
2302       )))
2303
2304 (defun nxhtml-turn-on-validation-header-mode ()
2305   "Turn on `nxhtml-validation-header-mode'."
2306   (nxhtml-validation-header-mode 1))
2307
2308
2309 (defun nxhtml-vhm-mumamo-change-major ()
2310   (put 'rngalt-validation-header 'permanent-local t)
2311   (put 'nxhtml-validation-header-mode 'permanent-local t)
2312   (put 'nxhtml-current-validation-header 'permanent-local t)
2313   ;;(put 'nxhtml-validation-header-mode-major-mode 'permanent-local t)
2314   ;;(setq nxhtml-validation-header-mode-major-mode mumamo-set-major-running)
2315   )
2316
2317 (defun nxhtml-vhm-mumamo-after-change-major ()
2318   (put 'rngalt-validation-header 'permanent-local nil)
2319   (put 'nxhtml-validation-header-mode 'permanent-local nil)
2320   (put 'nxhtml-current-validation-header 'permanent-local nil)
2321   ;;(put 'nxhtml-validation-header-mode-major-mode 'permanent-local nil)
2322   )
2323
2324 (defcustom nxhtml-validation-headers-check 'html
2325   "Defines what check the function with the same name does.
2326 The function returns true if the condition here is met."
2327   :type '(choice :tag "Add Fictive XHTML Validation Header if:"
2328                  (const :tag "If buffer contains html" html)
2329                  (const :tag "If buffer contains html or is empty" html-empty))
2330   :group 'nxhtml)
2331
2332 ;; (defun nxhtml-validation-headers-check (buffer)
2333 ;;   "Return non-nil if buffer contains a html tag or is empty.
2334 ;; This is for use with `nxhtml-validation-header-filenames'.
2335
2336 ;; The variable `nxhtml-validation-headers-check' determines how the
2337 ;; check is made."
2338 ;;   (if (= 0 (buffer-size buffer))
2339 ;;       (eq 'html-empty nxhtml-validation-headers-check)
2340 ;;     (save-match-data
2341 ;;       (save-restriction
2342 ;;         (let ((here (point))
2343 ;;               (html nil))
2344 ;;           (goto-char (point-min))
2345 ;;           (setq html (re-search-forward "</?[a-z]+>" nil t))
2346 ;;           (goto-char here)
2347 ;;           html)))))
2348
2349 ;; (defcustom nxhtml-validation-header-filenames
2350 ;;   '(
2351 ;;     ("\.php\\'" nxhtml-validation-headers-check)
2352 ;;     ("\.rhtml\\'" nxhtml-validation-headers-check)
2353 ;;     ("\.jsp\\'" nxhtml-validation-headers-check)
2354 ;;     ("\.gsp\\'" nxhtml-validation-headers-check)
2355 ;;     )
2356 ;;   "Alist for turning on `nxhtml-validation-mode'.
2357 ;; The entries in the list should have the form
2358
2359 ;;   \(FILE-REGEXP CHECK-FUNCION)
2360
2361 ;; If buffer file name matches the regexp FILE-REGEXP and the
2362 ;; function CHECK-FUNCTION returns non-nil when called with the
2363 ;; buffer as an argument \(or CHECK-FUNCTION is nil) then
2364 ;; `nxhtml-global-validation-header-mode' will turn on
2365 ;; `nxhtml-validation-header-mode' in buffer.
2366
2367 ;; The function `nxhtml-validation-headers-check' may be a useful
2368 ;; value for CHECK-FUNCTION.
2369
2370 ;; See also `nxhtml-maybe-turn-on-validation-header'."
2371 ;;   :type '(alist :key-type regexp :tag "File name regexp"
2372 ;;                 :value-type (group (choice (const :tag "No more check" nil)
2373 ;;                                            (function :tag "Check buffer with"))))
2374 ;;   :group 'nxhtml)
2375
2376
2377
2378 ;; (defun nxhtml-maybe-turn-on-validation-header ()
2379 ;;   "Maybe turn on `nxhtml-validation-header-mode' in buffer.
2380 ;; This is called by `nxhtml-global-validation-header-mode'.
2381
2382 ;; See `nxhtml-validation-header-filenames' for how the check
2383 ;; is made."
2384 ;;   (or (and (or (and mumamo-mode
2385 ;;                     (eq (mumamo-main-major-mode) 'nxhtml-mode))
2386 ;;                (eq major-mode 'nxhtml-mode))
2387 ;;            rngalt-validation-header
2388 ;;            nxhtml-current-validation-header
2389 ;;            nxhtml-validation-header-mode
2390 ;;            (progn
2391 ;;              ;;(lwarn 'maybe :warning "quick, buffer=%s" (current-buffer))
2392 ;;              (nxhtml-validation-header-mode 1)
2393 ;;              t))
2394 ;;       (when (buffer-file-name)
2395 ;;         (unless (or ;;nxhtml-validation-header-mode
2396 ;;                  (minibufferp (current-buffer))
2397 ;;                  (string= " " (substring (buffer-name) 0 1))
2398 ;;                  (string= "*" (substring (buffer-name) 0 1))
2399 ;;                  )
2400 ;;           (when (catch 'turn-on
2401 ;;                   (save-match-data
2402 ;;                     (dolist (rec nxhtml-validation-header-filenames)
2403 ;;                       (when (string-match (car rec) (buffer-file-name))
2404 ;;                         (let ((fun (nth 1 rec)))
2405 ;;                           (if (not fun)
2406 ;;                               (progn
2407 ;;                                 ;;(lwarn 't :warning "matched %s to %s, nil" (car rec) (buffer-file-name))
2408 ;;                                 (throw 'turn-on t))
2409 ;;                             (when (funcall fun (current-buffer))
2410 ;;                               ;;(lwarn 't :warning "matched %s to %s" (car rec) (buffer-file-name))
2411 ;;                               (throw 'turn-on t))))))))
2412 ;;             ;;(lwarn 't :warning "turn on %s, buffer=%s" major-mode (current-buffer))
2413 ;;             (nxhtml-validation-header-mode 1))))))
2414
2415
2416 ;; ;; Fix-me: Is this really the way to do it? Would it not be better to
2417 ;; ;; tie this to mumamo-mode in the turn on hook there? After all
2418 ;; ;; validation headers are probably not used unless mumamo-mode is on.
2419 ;; (define-globalized-minor-mode nxhtml-global-validation-header-mode
2420 ;;   nxhtml-validation-header-mode
2421 ;;   nxhtml-maybe-turn-on-validation-header
2422 ;;   :group 'nxhtml)
2423 ;; ;; The problem with global minor modes:
2424 ;; (when (and nxhtml-global-validation-header-mode
2425 ;;            (not (boundp 'define-global-minor-mode-bug)))
2426 ;;   (nxhtml-global-validation-header-mode 1))
2427
2428
2429 (defcustom nxhtml-validation-header-mumamo-modes
2430   '(nxhtml-mode)
2431   "Main major modes for which to turn on validation header.
2432 Turn on Fictive XHTML Validation Header if main major mode for the
2433 used mumamo multi major mode is any of those in this list.
2434
2435 See `mumamo-defined-turn-on-functions' for information about
2436 mumamo multi major modes."
2437   :type '(repeat (function :tag "Main major mode in mumamo"))
2438   :group 'nxhtml)
2439
2440 (defun nxhtml-add-validation-header-if-mumamo ()
2441   "Maybe turn on validation header.
2442 See `nxhtml-validation-header-if-mumamo' for more information."
2443   ;;(nxhtml-validation-headers-check (current-buffer))
2444   (when (and (fboundp 'mumamo-main-major-mode)
2445              (memq (mumamo-main-major-mode) nxhtml-validation-header-mumamo-modes))
2446     (nxhtml-validation-header-mode 1)))
2447
2448 ;;(define-toggle nxhtml-validation-header-if-mumamo nil
2449 (define-minor-mode nxhtml-validation-header-if-mumamo
2450   "Add a fictive validation header when mumamo is used.
2451 If this variable is t then add a Fictive XHTML Validation Header
2452 \(see `nxhtml-validation-header-mode') in buffer when mumamo is
2453 used. However do this only if `mumamo-main-major-mode' is one of
2454 those in `nxhtml-validation-header-mumamo-modes'.
2455
2456 Changing this variable through custom adds/removes the function
2457 `nxhtml-add-validation-header-if-mumamo' to
2458 `mumamo-turn-on-hook'."
2459   :global t
2460   :group 'nxhtml
2461   (if nxhtml-validation-header-if-mumamo
2462       (add-hook 'mumamo-turn-on-hook 'nxhtml-add-validation-header-if-mumamo)
2463     (remove-hook 'mumamo-turn-on-hook 'nxhtml-add-validation-header-if-mumamo)))
2464
2465 (defun nxhtml-validation-header-if-mumamo-toggle ()
2466   "Toggle `nxhtml-validation-header-if-mumamo'."
2467   (interactive)
2468   (nxhtml-validation-header-if-mumamo (if nxhtml-validation-header-if-mumamo -1 1)))
2469
2470 (defun nxhtml-warnings-are-visible ()
2471   (get 'rng-error 'face))
2472
2473 (defvar nxhtml-old-rng-error-face nil)
2474 (defun nxhtml-toggle-visible-warnings ()
2475   "Toggle the red underline on validation errors.
2476 Those can be quite disturbing when using mumamo multi major modes
2477 because there will probably be many validation errors in for
2478 example a php buffer, since unfortunately the validation routines
2479 in `rng-validate-mode' from `nxml-mode' tries to validate the
2480 whole buffer as XHTML.
2481
2482 Also, because of a \(normally unimportant) bug in Emacs 22,
2483 the red underline that marks an error will sometimes span several
2484 lines instead of just marking a single character as it
2485 should. \(This bug is a problem with overlays in Emacs 22.)"
2486   (interactive)
2487   (let ((face (get 'rng-error 'face)))
2488     (if face
2489         (progn
2490           (setq nxhtml-old-rng-error-face (get 'rng-error 'face))
2491           (put 'rng-error 'face nil))
2492       (put 'rng-error 'face nxhtml-old-rng-error-face))))
2493
2494 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2495 ;;; Bug corrections
2496 ;; (defun nxml-indent-line ()
2497 ;;   "Indent current line as XML."
2498 ;;   (let ((indent (nxml-compute-indent))
2499 ;;         (from-end (- (point-max) (point))))
2500 ;;     (when indent
2501 ;;       (beginning-of-line)
2502 ;;       (let ((bol (point)))
2503 ;;         (skip-chars-forward " \t")
2504 ;;         ;; There is a problem with some lines, try a quick fix:
2505 ;;         (when (and (= 0 indent)
2506 ;;                    (not (eq (char-after) ?<)))
2507 ;;           (save-excursion
2508 ;;             (save-match-data
2509 ;;               (when (re-search-backward "^<" nil t)
2510 ;;                 (when (search-forward " ")
2511 ;;                   (setq indent (current-column))))))
2512 ;;           (when (= 0 indent)
2513 ;;             (setq indent nxml-child-indent)))
2514 ;;         ;; And sometimes nxml-compute-indent get very upset, check for
2515 ;;         ;; that:
2516 ;;         (let ((here (point)))
2517 ;;           (beginning-of-line 0)
2518 ;;           (back-to-indentation)
2519 ;;           (when (and (= indent (current-column))
2520 ;;                      (eq (char-after) ?\"))
2521 ;;             (setq indent 0))
2522 ;;           (goto-char here))
2523 ;;         (unless (= (current-column) indent)
2524 ;;           (delete-region bol (point))
2525 ;;           (indent-to indent)))
2526 ;;       (when (> (- (point-max) from-end) (point))
2527 ;;         (goto-char (- (point-max) from-end))))))
2528
2529
2530 ;; FIX-ME: untag should be in nxml-mode.el since it is in no way
2531 ;; specific to nxhtml-mode, but I do not want to change nxml-mode.el
2532 ;; at the moment.
2533
2534 (defcustom nxml-untag-select 'yes
2535   "Decide whether to select an element untagged by `nxml-untag-element'.
2536 If this variable is 'yes the element is selected after untagging
2537 the element. The mark is set at the end of the element and point
2538 at the beginning of the element.
2539
2540 If this variable is 'no then the element is not selected and
2541 point is not moved. If it is 'ask the user is asked what to do."
2542   :type '(choice (const :tag "Yes" yes)
2543                  (const :tag "No" no)
2544                  (const :tag "Ask" ask))
2545   :group 'nxml)
2546
2547 (defun nxml-untag-element (arg)
2548   "Remove start and end tag from current element.
2549 The mark is by default set to the end of the former element and
2550 point is moved to the beginning. Mark is also activated so that
2551 it is easy to surround the former element with a new tag.
2552
2553 Whether to select the old element is controlled by
2554 `nxml-untag-select'. The meaning of the values 'yes and 'no for
2555 this variable is flipped by using a universal argument.
2556
2557 Note: If you want to `undo' the untag and you use
2558 `transient-mark-mode' then you must first do something so that
2559 the region is not highlighted (for example C-g)."
2560   (interactive "*P")
2561   (let ((here (point-marker))
2562         el-start
2563         el-start-end
2564         el-end
2565         el-end-end
2566         (select t))
2567     (nxml-backward-up-element)
2568     (setq el-start (point))
2569     (nxml-forward-balanced-item)
2570     (setq el-start-end (point))
2571     (goto-char el-start)
2572     (nxml-forward-element)
2573     (setq el-end-end (point-marker))
2574     (nxml-backward-single-balanced-item)
2575     (setq el-end (point))
2576     (delete-region el-end el-end-end)
2577     (delete-region el-start el-start-end)
2578     ;; Select the element or not?
2579     (if (eq nxml-untag-select 'ask)
2580         (setq select (y-or-n-p "Select the old element? "))
2581       (when (eq nxml-untag-select 'no)
2582         (setq select nil))
2583       (when arg
2584         (setq select (not select))))
2585     (if (not select)
2586         (goto-char here)
2587       (goto-char el-end-end)
2588       (push-mark nil t t)
2589       (setq mark-active t)
2590       (setq deactivate-mark nil)
2591       (goto-char el-start))))
2592
2593 (defun nxhtml-rollover-insert-2v ()
2594   "Insert CSS rollover images.
2595 The upper half of the image will be used when mouse is out and
2596 the lower half when mouse is over the image.
2597
2598 Only CSS is used for the rollover. The CSS code is written to the
2599 header part of the file if possible, otherwise it is copied to
2600 the kill ring/clipboard.
2601
2602 The CSS code is built from a template file and the image size.
2603
2604 This might be used for example for creating a menu with
2605 alternatives vertically or horizontally.
2606
2607 Usage example:
2608
2609   If you want to make a small button style menu with images you
2610   can start like this:
2611
2612       <div id=\"mylinks\">
2613         <ul>
2614           <li>
2615      X      <a href=\"news.html\">News and Notes</a>
2616           </li>
2617           <li>
2618             <a href=\"doc.html\">Documentation</a>
2619           </li>
2620         <ul>
2621       </div>
2622
2623   Then put point at the X above (this is just a mark, should not
2624   be in your code) and call this function.
2625
2626   It will add some CSS code to in the header of your file. You
2627   may want to tweak this a little bit, see below (or place it
2628   somewhere else). It may look like this:
2629
2630     #mylinks a {
2631         /* Image */
2632         display: block;
2633         background: transparent url(\"img/mybutton.png\") 0 0 no-repeat;
2634         overflow: hidden;
2635         width: 200px;
2636         /* Text placement and size, etc */
2637         text-align: center;
2638         /* You may need to change top and bottom padding depending
2639            on font size. */
2640         padding-top: 11px;
2641         font-size: 12px;
2642         padding-bottom: 9px;
2643         text-decoration: none;
2644         white-space: nowrap;
2645         border: none;
2646     }
2647     #mylinks a:hover {
2648         background-position: 0 -35px;
2649     }
2650     #mylinks li {
2651         display: inline;
2652         padding: 0;
2653         margin: 0;
2654         float: none;
2655     }
2656
2657 For an example of usage see the file nxhtml.html that comes with
2658 nXhtml and can be opened from the nXhtml menu under
2659
2660   nXhtml / nXhtml Help and Setup / nXhtml version nn Overview"
2661   (interactive)
2662   ;; Fix-me: not quite ready yet, but should work OK."
2663   (save-excursion
2664     (let* ((tag (progn
2665                   (search-forward ">" nil t)
2666                   (unless (re-search-backward (rx "<"
2667                                                   (1+ (any "a-zA-Z:"))
2668                                                   (1+ (not (any ">")))
2669                                                   " id=\""
2670                                                   (submatch (+? anything))
2671                                                   "\"")
2672                                               nil t)
2673                     (error "Can't find tag with id backwards"))
2674                   (match-string-no-properties 0)))
2675            (tagid (match-string-no-properties 1))
2676            (tagovl (let ((ovl (make-overlay
2677                                (match-beginning 0) (match-end 0))))
2678                      (overlay-put ovl 'face 'highlight)
2679                      ovl))
2680            (head-end (save-excursion (search-backward "</head" nil t))))
2681       (unless head-end
2682         (error "Can't find end of head tag. Need this to insert css."))
2683       (sit-for 1)
2684       (unwind-protect
2685           (condition-case err
2686               (let* ((img-src (nxhtml-read-url
2687                                '(?f) nil 'nxhtml-image-url-predicate
2688                                (concat "Rollover image for \"" tag "\",")))
2689                      (img-sizes (when (file-exists-p img-src)
2690                                   (image-size (create-image
2691                                                (expand-file-name img-src))
2692                                               t)))
2693                      (class (read-string
2694                              (concat
2695                               "Class name for rollover (empty to use id="
2696                               tagid "): ")))
2697                      (rollover-spec (if (< 0 (length class))
2698                                         (concat "." class)
2699                                       (concat "#" tagid)))
2700                      img-width img-height
2701                      img-h2
2702                      img-w2
2703                      padding-top
2704                      padding-bottom
2705                      (font-size (read-number "Font size (px): " 12))
2706                      (css-template-file (read-file-name
2707                                          "CSS template file: "
2708                                          (expand-file-name "etc/templates/" nxhtml-install-dir)
2709                                          nil
2710                                          t
2711                                          "rollover-2v.css"
2712                                          ))
2713                      (center-or-pad
2714                       (if (y-or-n-p "Do you want to center the text? ")
2715                           "text-align: center"
2716                         (format "padding: %spx" (/ font-size 2))))
2717                      (hor-or-ver
2718                       (if (y-or-n-p "Do you want the alternatives shown in a vertical list? ")
2719                           "float: none"
2720                         "float: left"))
2721                      (css-template-buffer (find-file-noselect
2722                                            css-template-file))
2723                      (css-template (with-current-buffer css-template-buffer
2724                                      ;; Do not widen, let user decide.
2725                                      (buffer-substring-no-properties
2726                                       (point-min) (point-max))))
2727                      (css css-template))
2728                 (unless (file-exists-p css-template-file)
2729                   (error "Can't find file %s" css-template-file))
2730                 (if img-sizes
2731                     (progn
2732                       (setq img-width (car img-sizes))
2733                       (setq img-height (cdr img-sizes)))
2734                   (setq img-width (read-number "Width: "))
2735                   (setq img-height (read-number "Width: ")))
2736                 (setq img-h2 (/ img-height 2))
2737                 (setq img-w2 (/ img-width 2))
2738                 (setq padding-top (/ (- img-h2 font-size) 2))
2739                 ;; Fix-me: I have no idea why I have to subtract 3
2740                 ;; from bottom, but inspection with Firebug seems to
2741                 ;; say so:
2742                 (setq padding-bottom (- img-h2 padding-top font-size 3))
2743                 (setq css (replace-regexp-in-string "ROLLOVER_SPEC" rollover-spec css t t))
2744                 (setq css (replace-regexp-in-string "IMG_WIDTH_2" (number-to-string img-h2) css t t))
2745                 (setq css (replace-regexp-in-string "IMG_HEIGHT_2" (number-to-string img-h2) css t t))
2746                 (setq css (replace-regexp-in-string "IMG_WIDTH" (number-to-string img-width) css t t))
2747                 (setq css (replace-regexp-in-string "IMG_HEIGHT" (number-to-string img-height) css t t))
2748                 (setq css (replace-regexp-in-string "IMG_URL" img-src css t t))
2749                 (setq css (replace-regexp-in-string "FONT_SIZE" (number-to-string font-size) css t t))
2750                 (setq css (replace-regexp-in-string "PADDING_TOP" (number-to-string padding-top) css t t))
2751                 (setq css (replace-regexp-in-string "PADDING_BOTTOM" (number-to-string padding-bottom) css t t))
2752                 (setq css (replace-regexp-in-string "CENTER_OR_PAD" center-or-pad css t t))
2753                 (setq css (replace-regexp-in-string "HOR_OR_VER" hor-or-ver css t t))
2754                 (if head-end
2755                     (let ((this-window (selected-window)))
2756                       (find-file-other-window buffer-file-name)
2757                       (goto-char head-end)
2758                       (beginning-of-line)
2759                       (insert "<style type=\"text/css\">\n"
2760                               css
2761                               "\n</style>\n")
2762                       (select-window this-window))
2763                   (kill-new css)
2764                   (message "No place to insert CSS, copied to clipboard instead"))))
2765         (delete-overlay tagovl)
2766         ))))
2767
2768 ;; Fix-me: image border 0
2769 ;; Fix-me: SSI <!--#include file="file:///C|/EmacsW32/nxml/nxhtml/bug-tests/bug-080609.html" -->
2770 ;; Fix-me: Better a tag completion, target etc.
2771 ;; Fix-me: image map - is that possible now?
2772 ;; Fix-me: Special chars - completing on &? Or popup? Use nxml-insert-named-char
2773 ;; Fix-me: Quick table insert? A form?
2774 ;; Fix-me: Quick object insert? (applet is depreceated)
2775 ;; Fix-me: Better meta insert? Quick meta?
2776 ;; Fix-me: Quick div! Better div completion with position: static,
2777 ;;         relative, absolute and fixed - with some explanations.
2778 ;; Fix-me: Quick hr?
2779 ;; Fix-me: Import CSS? Export CSS?
2780 ;; Fix-me: Use nxhtml-js.el?
2781 ;; Fix-me: Scroll bar colors etc? See 1stPage.
2782 ;;   body {
2783 ;;     scrollbar-arrow-color: #FF6699;
2784 ;;     scrollbar-3dlight-color: #00FF33;
2785 ;;     scrollbar-highlight-color: #66FFFF;
2786 ;;     scrollbar-face-color: #6699FF;
2787 ;;     scrollbar-shadow-color: #6633CC;
2788 ;;     scrollbar-darkshadow-color: #660099;
2789 ;;     scrollbar-track-color: #CC6633;
2790 ;;     }
2791 ;; Fix-me: More quick menus: http://www.cssplay.co.uk/menus/
2792
2793 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2794 (provide 'nxhtml-mode)
2795
2796 ;;; nxhtml-mode.el ends here