WP Better Emails - Version 0.2

Version Description

  • WP TinyMCE editor support
    • HTML editor with CodeMirror as a TinyMCE plugin
    • Live preview (> WP 3.1)
    • Include filter to add your own tag replacements
    • Help moved to contextual help
    • Translations for german, hebrew
    • Improved template email clients support
Download this release

Release Info

Developer nlemoine
Plugin Icon 128x128 WP Better Emails
Version 0.2
Comparing to
See all releases

Code changes from version 0.1.3 to 0.2

Files changed (107) hide show
  1. css/wpbe-admin-style.css +24 -54
  2. email_template.php +0 -49
  3. js/jquery.cookie.js +0 -96
  4. js/wpbe-admin-script.js +42 -17
  5. langs/wp-better-emails-de_DE.mo +0 -0
  6. langs/wp-better-emails-de_DE.po +196 -0
  7. langs/wp-better-emails-fr_FR.mo +0 -0
  8. langs/wp-better-emails-fr_FR.po +124 -164
  9. langs/wp-better-emails-he_IL.mo +0 -0
  10. langs/wp-better-emails-he_IL.po +197 -0
  11. langs/wp-better-emails-nl_NL.mo +0 -0
  12. langs/wp-better-emails-nl_NL.po +0 -236
  13. langs/wp-better-emails.mo +0 -0
  14. langs/wp-better-emails.pot +105 -144
  15. markitup/jquery.markitup.js +0 -565
  16. markitup/sets/html/images/bold.png +0 -0
  17. markitup/sets/html/images/clean.png +0 -0
  18. markitup/sets/html/images/h1.png +0 -0
  19. markitup/sets/html/images/h2.png +0 -0
  20. markitup/sets/html/images/h3.png +0 -0
  21. markitup/sets/html/images/h4.png +0 -0
  22. markitup/sets/html/images/h5.png +0 -0
  23. markitup/sets/html/images/h6.png +0 -0
  24. markitup/sets/html/images/image.png +0 -0
  25. markitup/sets/html/images/italic.png +0 -0
  26. markitup/sets/html/images/link.png +0 -0
  27. markitup/sets/html/images/list-bullet.png +0 -0
  28. markitup/sets/html/images/list-item.png +0 -0
  29. markitup/sets/html/images/list-numeric.png +0 -0
  30. markitup/sets/html/images/paragraph.png +0 -0
  31. markitup/sets/html/images/picture.png +0 -0
  32. markitup/sets/html/images/preview.png +0 -0
  33. markitup/sets/html/images/stroke.png +0 -0
  34. markitup/sets/html/readme.txt +0 -11
  35. markitup/sets/html/set.js +0 -39
  36. markitup/sets/html/style.css +0 -59
  37. markitup/skins/markitup/images/bg-container.png +0 -0
  38. markitup/skins/markitup/images/bg-editor-bbcode.png +0 -0
  39. markitup/skins/markitup/images/bg-editor-dotclear.png +0 -0
  40. markitup/skins/markitup/images/bg-editor-html.png +0 -0
  41. markitup/skins/markitup/images/bg-editor-json.png +0 -0
  42. markitup/skins/markitup/images/bg-editor-markdown.png +0 -0
  43. markitup/skins/markitup/images/bg-editor-textile.png +0 -0
  44. markitup/skins/markitup/images/bg-editor-wiki.png +0 -0
  45. markitup/skins/markitup/images/bg-editor-xml.png +0 -0
  46. markitup/skins/markitup/images/bg-editor.png +0 -0
  47. markitup/skins/markitup/images/handle.png +0 -0
  48. markitup/skins/markitup/images/menu.png +0 -0
  49. markitup/skins/markitup/images/submenu.png +0 -0
  50. markitup/skins/markitup/style.css +0 -147
  51. markitup/skins/simple/images/handle.png +0 -0
  52. markitup/skins/simple/images/menu.png +0 -0
  53. markitup/skins/simple/images/submenu.png +0 -0
  54. markitup/skins/simple/style.css +0 -118
  55. markitup/templates/preview.html +0 -1
  56. preview.html +0 -0
  57. readme.txt +76 -22
  58. screenshot-1.png +0 -0
  59. screenshot-2.png +0 -0
  60. screenshot-3.png +0 -0
  61. screenshot-4.png +0 -0
  62. screenshot-5.png +0 -0
  63. templates/template-1.html +61 -0
  64. templates/template-1.php +56 -0
  65. tinymce-plugins/3.3.x/fullpage/css/fullpage.css +182 -0
  66. tinymce-plugins/3.3.x/fullpage/editor_plugin.js +1 -0
  67. tinymce-plugins/3.3.x/fullpage/editor_plugin_src.js +182 -0
  68. tinymce-plugins/3.3.x/fullpage/fullpage.htm +571 -0
  69. tinymce-plugins/3.3.x/fullpage/js/fullpage.js +471 -0
  70. tinymce-plugins/3.3.x/fullpage/langs/en_dlg.js +85 -0
  71. tinymce-plugins/3.4.x/fullpage/css/fullpage.css +143 -0
  72. tinymce-plugins/3.4.x/fullpage/editor_plugin.js +1 -0
  73. tinymce-plugins/3.4.x/fullpage/editor_plugin_src.js +399 -0
  74. tinymce-plugins/3.4.x/fullpage/fullpage.htm +259 -0
  75. tinymce-plugins/3.4.x/fullpage/js/fullpage.js +232 -0
  76. tinymce-plugins/3.4.x/fullpage/langs/en_dlg.js +85 -0
  77. tinymce-plugins/cmseditor/editor_plugin.js +84 -0
  78. tinymce-plugins/cmseditor/img/ed-bg.gif +0 -0
  79. tinymce-plugins/cmseditor/img/html.gif +0 -0
  80. tinymce-plugins/cmseditor/js/LICENSE +19 -0
  81. tinymce-plugins/cmseditor/js/README.md +6 -0
  82. tinymce-plugins/cmseditor/js/codemirror-compressed.js +1 -0
  83. tinymce-plugins/cmseditor/js/lib/codemirror.css +82 -0
  84. tinymce-plugins/cmseditor/js/lib/codemirror.js +2157 -0
  85. tinymce-plugins/cmseditor/js/lib/overlay.js +51 -0
  86. tinymce-plugins/cmseditor/js/lib/runmode.js +27 -0
  87. tinymce-plugins/cmseditor/js/mode/css/css.js +124 -0
  88. tinymce-plugins/cmseditor/js/mode/css/index.html +56 -0
  89. tinymce-plugins/cmseditor/js/mode/htmlmixed/htmlmixed.js +79 -0
  90. tinymce-plugins/cmseditor/js/mode/htmlmixed/index.html +52 -0
  91. tinymce-plugins/cmseditor/js/mode/javascript/index.html +78 -0
  92. tinymce-plugins/cmseditor/js/mode/javascript/javascript.js +348 -0
  93. tinymce-plugins/cmseditor/js/mode/php/index.html +49 -0
  94. tinymce-plugins/cmseditor/js/mode/php/php.js +115 -0
  95. tinymce-plugins/cmseditor/js/mode/xml/index.html +42 -0
  96. tinymce-plugins/cmseditor/js/mode/xml/xml.js +231 -0
  97. tinymce-plugins/cmseditor/js/mode/xmlpure/index.html +60 -0
  98. tinymce-plugins/cmseditor/js/mode/xmlpure/xmlpure.js +481 -0
  99. tinymce-plugins/cmseditor/js/theme/default.css +19 -0
  100. tinymce-plugins/cmseditor/js/theme/elegant.css +9 -0
  101. tinymce-plugins/cmseditor/js/theme/neat.css +8 -0
  102. tinymce-plugins/cmseditor/js/theme/night.css +20 -0
  103. tinymce-plugins/cmseditor/langs/en.js +3 -0
  104. tinymce-plugins/cmseditor/langs/en_dlg.js +3 -0
  105. wpbe-options.php +45 -77
  106. wpbe.php +495 -301
  107. wpbe_template.html +0 -47
css/wpbe-admin-style.css CHANGED
@@ -1,57 +1,27 @@
1
- #wpbe_options_tabs {
2
- overflow: hidden;
3
- height: 100%;
4
- margin: 20px 0;
5
- }
6
- #wpbe_options_tabs .wpbe_tabs_titles {
7
- float: left;
8
- width: 97%;
9
- height: 32px;
10
- margin: 0 0 20px 0;
11
- padding: 0 0 0 15px;
12
- border-bottom: solid 1px #ccc;
13
- }
14
- #wpbe_options_tabs .wpbe_tabs_titles li {
15
- float: left;
16
- height: 31px;
17
- line-height: 31px;
18
- padding: 0;
19
- margin: 0 3px 0 0;
20
- border: solid 1px #ccc;
21
- background: #fff;
22
- -moz-border-radius: 4px 4px 0 0;
23
- -webkit-border-radius: 4px 4px 0 0;
24
- border-radius: 4px 4px 0 0;
25
- }
26
- #wpbe_options_tabs .wpbe_tabs_titles a {
27
- color: #ccc;
28
- text-decoration: none;
29
- font-size: 14px;
30
- display: block;
31
- padding: 0 20px;
32
- border-bottom: none;
33
- }
34
- #wpbe_options_tabs ul li.ui-state-active {
35
- background: #f9f9f9;
36
- border-bottom: 1px solid #f9f9f9;
37
- }
38
- #wpbe_options_tabs .ui-state-active a {
39
- color: #333;
40
- }
41
- #wpbe_options_tabs .ui-state-active a:hover,
42
- #wpbe_options_tabs a:hover {
43
- color: #D54E21;
44
- }
45
- .wpbe_tab_content {
46
- padding: 0 20px;
47
- }
48
- .markItUpPreviewFrame {
49
- border: solid 1px #ddd;
50
- }
51
  #wpbe_preview_email {
52
- width: 250px;
53
- vertical-align: middle;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
55
- #wpbe_options_form #ajax-loading {
56
- vertical-align: middle;
57
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  #wpbe_preview_email {
2
+ vertical-align: middle;
3
+ }
4
+ #wpbe_ajax_loading {
5
+ vertical-align: middle;
6
+ }
7
+ #wpbe_preview_message {
8
+ width: 80%;
9
+ }
10
+ #wpbe_support {
11
+ color: #777;
12
+ border-top: solid 1px #DFDFDF;
13
+ }
14
+ #wpbe_template_tbl {
15
+ border: solid 1px #ccc;
16
+ overflow: auto;
17
+ }
18
+ #wpbe_template {
19
+ width: 100%;
20
+ height: 410px;
21
+ }
22
+ #wpbe_template_container {
23
+ width: 80%;
24
  }
25
+ #wpbe_preview_template {
26
+ font-weight: normal;
27
  }
email_template.php DELETED
@@ -1,49 +0,0 @@
1
- <?php
2
- $template = '<html>
3
- <body bgcolor="#f9f9f9" link="#21759B" alink="#21759B" vlink="#21759B" marginheight="0" topmargin="0" marginwidth="0" leftmargin="0" style="margin: 0px; background-color: #f9f9f9; font-family: Helvetica, Arial, sans-serif;">
4
- <table cellpadding="0" cellspacing="0" width="100%" bgcolor="#f9f9f9" border="0">
5
- <tr>
6
- <td style="padding:15px;" align="center">
7
- <center>
8
- <table width="550" cellpadding="0" bgcolor="#ffffff" cellspacing="0" >
9
- <tr>
10
- <td>
11
- <div style="border:solid 1px #d9d9d9;">
12
- <table id="header" width="100%;" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="line-height:1.5;font-size:12px;font-family: Helvetica, Arial, sans-serif;border:solid 1px #FFFFFF;">
13
- <tr>
14
- <td colspan="2" background="%blog_url%/wp-admin/images/white-grad-active.png" height="30">&nbsp;</td>
15
- </tr>
16
- <tr >
17
- <td style="line-height:32px;padding: 0 0 0 30px;" valign="baseline">
18
- <span style="font-size:32px;"><a href="%blog_url%" style="text-decoration:none;" target="_blank">%blog_name%</a></span>
19
- </td>
20
- <td style="padding: 0 30px 0 0;" align="right" valign="baseline">
21
- <span style="font-size:14px;color:#777777">%blog_description%</span>
22
- </td>
23
- </tr>
24
- </table>
25
- <table id="content" width="100%;" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="color:#444;line-height:1.5;font-size:12px;font-family: Arial, sans-serif;padding:20px 30px 0 30px;">
26
- <tr>
27
- <td colspan="2" style="padding:20px 0;border-top: solid 1px #d9d9d9">%content%</td>
28
- </tr>
29
- </table>
30
- <table id="footer" width="100%;" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="line-height:1.5;font-size:12px;font-family: Arial, sans-serif;padding:0 30px 15px 30px;">
31
- <tr style="font-size:11px;color:#777777;">
32
- <td style="border-top: solid 1px #d9d9d9;" colspan="2">
33
- <img style="padding:15px 0 0 0" height="32" width="32" src="%blog_url%/wp-admin/images/wp-logo.png" align="right" alt="' . __('Powered by Wordpress', 'wpbe') . '" />
34
- <div style="padding:15px 0 1px 0"><img height="13" width="13" style="vertical-align: middle;" src="%blog_url%/wp-admin/images/date-button.gif" alt="' . __('Date') . '" /> ' . __('Email sent the', 'wpbe') . ' %date% @ %time%</div>
35
- <div><img height="12" width="12" style="vertical-align: middle;" src="%blog_url%/wp-admin/images/comment-grey-bubble.png" alt="' . __('Contact') . '" /> ' . __('For any request, please contact', 'wpbe') . ' <a href="mailto:%admin_email%">%admin_email%</a></div>
36
- </td>
37
- </tr>
38
- </table>
39
- </div>
40
- </td>
41
- </tr>
42
- </table>
43
- </center>
44
- </td>
45
- </tr>
46
- </table>
47
- </body>
48
- </html>';
49
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/jquery.cookie.js DELETED
@@ -1,96 +0,0 @@
1
- /**
2
- * Cookie plugin
3
- *
4
- * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
5
- * Dual licensed under the MIT and GPL licenses:
6
- * http://www.opensource.org/licenses/mit-license.php
7
- * http://www.gnu.org/licenses/gpl.html
8
- *
9
- */
10
-
11
- /**
12
- * Create a cookie with the given name and value and other optional parameters.
13
- *
14
- * @example $.cookie('the_cookie', 'the_value');
15
- * @desc Set the value of a cookie.
16
- * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
17
- * @desc Create a cookie with all available options.
18
- * @example $.cookie('the_cookie', 'the_value');
19
- * @desc Create a session cookie.
20
- * @example $.cookie('the_cookie', null);
21
- * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
22
- * used when the cookie was set.
23
- *
24
- * @param String name The name of the cookie.
25
- * @param String value The value of the cookie.
26
- * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
27
- * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
28
- * If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
29
- * If set to null or omitted, the cookie will be a session cookie and will not be retained
30
- * when the the browser exits.
31
- * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
32
- * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
33
- * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
34
- * require a secure protocol (like HTTPS).
35
- * @type undefined
36
- *
37
- * @name $.cookie
38
- * @cat Plugins/Cookie
39
- * @author Klaus Hartl/klaus.hartl@stilbuero.de
40
- */
41
-
42
- /**
43
- * Get the value of a cookie with the given name.
44
- *
45
- * @example $.cookie('the_cookie');
46
- * @desc Get the value of a cookie.
47
- *
48
- * @param String name The name of the cookie.
49
- * @return The value of the cookie.
50
- * @type String
51
- *
52
- * @name $.cookie
53
- * @cat Plugins/Cookie
54
- * @author Klaus Hartl/klaus.hartl@stilbuero.de
55
- */
56
- jQuery.cookie = function(name, value, options) {
57
- if (typeof value != 'undefined') { // name and value given, set cookie
58
- options = options || {};
59
- if (value === null) {
60
- value = '';
61
- options.expires = -1;
62
- }
63
- var expires = '';
64
- if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
65
- var date;
66
- if (typeof options.expires == 'number') {
67
- date = new Date();
68
- date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
69
- } else {
70
- date = options.expires;
71
- }
72
- expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
73
- }
74
- // CAUTION: Needed to parenthesize options.path and options.domain
75
- // in the following expressions, otherwise they evaluate to undefined
76
- // in the packed version for some reason...
77
- var path = options.path ? '; path=' + (options.path) : '';
78
- var domain = options.domain ? '; domain=' + (options.domain) : '';
79
- var secure = options.secure ? '; secure' : '';
80
- document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
81
- } else { // only name given, get cookie
82
- var cookieValue = null;
83
- if (document.cookie && document.cookie != '') {
84
- var cookies = document.cookie.split(';');
85
- for (var i = 0; i < cookies.length; i++) {
86
- var cookie = jQuery.trim(cookies[i]);
87
- // Does this cookie string begin with the name we want?
88
- if (cookie.substring(0, name.length + 1) == (name + '=')) {
89
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
90
- break;
91
- }
92
- }
93
- }
94
- return cookieValue;
95
- }
96
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/wpbe-admin-script.js CHANGED
@@ -1,27 +1,52 @@
1
- jQuery(document).ready(function(){
2
- // Tabs
3
- jQuery('#wpbe_options_tabs').tabs( { cookie: { expires: 1 } } );
4
 
5
- jQuery('#wpbe_template').markItUp(mySettings);
6
-
7
- // AJAX
8
- jQuery('#wpbe_send_preview').click(function(e) {
9
- var email = jQuery('#wpbe_preview_email').val();
10
- var preview_nonce = jQuery('#wpbe_nonce_preview').val();
11
- jQuery.ajax({
12
  type: 'post',
13
- url: 'admin-ajax.php',
14
  data: {
15
- action: 'send_preview',
16
  preview_email: email,
17
- _ajax_nonce: preview_nonce
 
 
 
18
  },
19
- beforeSend: function() { jQuery('#ajax-loading').css('visibility', 'visible'); },
20
- complete: function() { jQuery('#ajax-loading').css('visibility', 'hidden');},
21
- success: function(html){
22
- jQuery('#wpbe_preview_message').html(jQuery(html).fadeIn());
 
23
  }
24
  });
 
 
 
 
25
  e.preventDefault();
 
26
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  });
1
+ jQuery(document).ready(function($){
 
 
2
 
3
+ // Send email preview
4
+ $('#wpbe_send_preview').click(function(e) {
5
+ e.preventDefault();
6
+ var email = $('#wpbe_email_preview_field').val(), message = $('#wpbe_preview_message'), loading = $('#wpbe_ajax_loading');
7
+ $.ajax({
 
 
8
  type: 'post',
9
+ url: wpbe_ajax_vars.url,
10
  data: {
11
+ action: wpbe_ajax_vars.action,
12
  preview_email: email,
13
+ _ajax_nonce: wpbe_ajax_vars.nonce
14
+ },
15
+ beforeSend: function() {
16
+ loading.css('visibility', 'visible');
17
  },
18
+ complete: function() {
19
+ loading.css('visibility', 'hidden');
20
+ },
21
+ success: function(data) {
22
+ message.append(data);
23
  }
24
  });
25
+ });
26
+
27
+ // Trigger help
28
+ $('#wpbe_help').bind('click', function(e){
29
  e.preventDefault();
30
+ $('a#contextual-help-link').trigger('click');
31
  });
32
+
33
+ // Thickbox preview
34
+ $('#wpbe_preview_template').live('click', function(e) {
35
+ e.preventDefault();
36
+ var preview_iframe = $('#TB_iframeContent');
37
+ if( preview_iframe.length ) {
38
+ var template;
39
+ if (typeof(tinyMCE) != 'undefined') {
40
+ if( tinyMCE.activeEditor && !tinyMCE.activeEditor.isHidden() )
41
+ template = tinyMCE.activeEditor.getContent();
42
+ else
43
+ template = $('.wpbe_template').val();
44
+ }
45
+ preview_iframe = preview_iframe[preview_iframe.length - 1].contentWindow || frame[preview_iframe.length - 1];
46
+ preview_iframe.document.open();
47
+ preview_iframe.document.write( template );
48
+ preview_iframe.document.close();
49
+ }
50
+ });
51
+
52
  });
langs/wp-better-emails-de_DE.mo ADDED
Binary file
langs/wp-better-emails-de_DE.po ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2010
2
+ # This file is distributed under the same license as the package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: WP Better Emails\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-better-emails\n"
7
+ "POT-Creation-Date: 2011-09-06 23:22:41+00:00\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2011-09-12 17:26+0100\n"
12
+ "Last-Translator: \n"
13
+ "Language-Team: Robert Tremmel <robert.tremmel@gmx.net>\n"
14
+ "X-Poedit-Language: German\n"
15
+
16
+ #: wpbe-options.php:2
17
+ #: wpbe.php:158
18
+ msgid "Email settings"
19
+ msgstr "E-Mail-Einstellungen"
20
+
21
+ #: wpbe-options.php:9
22
+ msgid "Set your own sender name and email address. Default Wordpress values will be used if empty."
23
+ msgstr "Bitte den Name des Absenders und E-Mail-Adresse eintragen. Bei leeren Feldern werden die Standard-Wordpress-Einstellungen benutzt."
24
+
25
+ #: wpbe-options.php:12
26
+ msgid "Name"
27
+ msgstr "Name des Absenders"
28
+
29
+ #: wpbe-options.php:16
30
+ msgid "Email address"
31
+ msgstr "E-Mail des Absenders"
32
+
33
+ #: wpbe-options.php:22
34
+ msgid "HTML Template"
35
+ msgstr "HTML Design-Vorlage"
36
+
37
+ #: wpbe-options.php:24
38
+ msgid "Live template preview"
39
+ msgstr "Vorschau"
40
+
41
+ #: wpbe-options.php:24
42
+ msgid "Live preview"
43
+ msgstr "Vorschau"
44
+
45
+ #: wpbe-options.php:26
46
+ msgid "Edit the HTML email template if you want to customize it. You might have a look at the <a href=\"#\" id=\"wpbe_help\">help tab</a> for further information."
47
+ msgstr "Es steht Ihnen frei, die E-Mail-HTML-Designvorlage für Ihre eigenen Zwecke zu bearbeiten. Nutzen Sie dazu auch die weiteren Informationen im Hilfe-Tab."
48
+
49
+ #: wpbe-options.php:35
50
+ msgid "Send an email preview to"
51
+ msgstr "Aktuelle Vorschau als E-Mail"
52
+
53
+ #: wpbe-options.php:39
54
+ msgid "Send"
55
+ msgstr "Absenden"
56
+
57
+ #: wpbe-options.php:41
58
+ msgid "You must save your template before sending an email preview."
59
+ msgstr "Design-Vorlage bitte vor dem Absenden speichern."
60
+
61
+ #: wpbe-options.php:46
62
+ msgid "Save Changes"
63
+ msgstr "Änderungen speichern"
64
+
65
+ #: wpbe-options.php:52
66
+ msgid "Support & bug report"
67
+ msgstr "Hilfe & Fehlerreport"
68
+
69
+ #: wpbe-options.php:53
70
+ msgid "If you have any idea to improve this plugin or any bug to report, please email me at : <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
71
+ msgstr "Sie haben einen Vorschlag zur Verbesserung des Plug-ins oder möchten einen Fehler melden? Bitte senden Sie eine E-Mail an: <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
72
+
73
+ #: wpbe-options.php:55
74
+ msgid "You like this plugin ? You use it in a business context ? Please, consider a <a href=\"%s\" target=\"_blank\" rel=\"external\">donation</a>."
75
+ msgstr "Gefällt Ihnen dieses Plug-in? Nutzen Sie es für gewerbliche Zwecke? Ich freue mich über Ihre Spende. <a href=\"%s\" target=\"_blank\" rel=\"external\">Jetzt spenden</a>."
76
+
77
+ #: templates/template-1.php:33
78
+ msgid "Date"
79
+ msgstr "Datum"
80
+
81
+ #: templates/template-1.php:33
82
+ msgid "Email sent"
83
+ msgstr "Die E-Mail wurde versandt am"
84
+
85
+ #: templates/template-1.php:34
86
+ msgid "Contact"
87
+ msgstr "Kontakt"
88
+
89
+ #: templates/template-1.php:34
90
+ msgid "For any requests, please contact"
91
+ msgstr "Für Fragen und Hilfe wenden Sie sich bitte an:"
92
+
93
+ #: wpbe.php:131
94
+ msgid "Settings"
95
+ msgstr "Einstellungen"
96
+
97
+ #: wpbe.php:147
98
+ msgid "WP Better Emails requires WordPress 2.8 or newer."
99
+ msgstr "WP Better Emails benötigt Version Wordpress 2.8 oder aktueller."
100
+
101
+ #: wpbe.php:147
102
+ msgid "Upgrade your Wordpress installation."
103
+ msgstr "Wordpress aktualisieren"
104
+
105
+ #: wpbe.php:158
106
+ msgid "WP Better Emails"
107
+ msgstr "WP Better Emails"
108
+
109
+ #: wpbe.php:228
110
+ msgid "Please enter a valid sender email address."
111
+ msgstr "Bitte tragen Sie eine korrekte E-Mail-Adresse ein."
112
+
113
+ #: wpbe.php:238
114
+ msgid "Template is empty"
115
+ msgstr "Die Design-Vorlage ist leer."
116
+
117
+ #: wpbe.php:241
118
+ msgid "No content tag found. The %content% tag is required in your template"
119
+ msgstr "Kein 'Inhalt' gefunden. Es wird %content% für Ihre Design-Vorlage benötigt."
120
+
121
+ #: wpbe.php:259
122
+ msgid "Please enter an email"
123
+ msgstr "Bitte geben Sie eine korrekte E-Mail-Adresse ein"
124
+
125
+ #: wpbe.php:261
126
+ msgid "Please enter a valid email"
127
+ msgstr "Bitte geben Sie eine korrekte E-Mail-Adresse an"
128
+
129
+ #: wpbe.php:262
130
+ msgid "Hey !"
131
+ msgstr "Hey !"
132
+
133
+ #: wpbe.php:264
134
+ msgid "This is a sample email to test your HTML template."
135
+ msgstr "Das ist eine Test-E-Mail zur Vorschau Ihrer Design-Vorlage in HTML."
136
+
137
+ #: wpbe.php:266
138
+ msgid "If you're not skilled in HTML/CSS email coding, I strongly recommend to leave the default template as it is. It has been tested on various and popular email clients like Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, and many more."
139
+ msgstr "Sollten Sie wenig Erfahrung mit HTML/CSS-Codes haben, empfehle ich Ihnen, die Standard-Einstellungen der Design-Vorlage beizubehalten. Es wurde in gebräuchlichen E-Mail-Anwendungen getestet. Zum Beispiel: Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook und viele andere."
140
+
141
+ #: wpbe.php:268
142
+ msgid "If you have any problems or any suggestions to improve this plugin, please let me know."
143
+ msgstr "Sollten bei Ihnen Probleme auftreten oder haben Sie Verbesserungsvorschläge für das Plug-in? Kontaktieren Sie mich."
144
+
145
+ #: wpbe.php:269
146
+ msgid "Email template preview"
147
+ msgstr "E-Mail-Design-Vorlage in der Vorschau"
148
+
149
+ #: wpbe.php:270
150
+ msgid "An email preview has been successfully sent to %s"
151
+ msgstr "Eine E-Mail-Vorschau wurde erfolgreich an diese Adresse versandt: %s"
152
+
153
+ #: wpbe.php:273
154
+ msgid "An error occured while sending email. Please check your server configuration."
155
+ msgstr "Ein Fehler ist beim Senden der E-Mail aufgetreten. Bitte überprüfen Sie Ihre Server-Einstellungen."
156
+
157
+ #: wpbe.php:410
158
+ msgid "Some dynamic tags can be included in your email template :"
159
+ msgstr "Sie können dynamische HTML-Befehle in Ihre E-Mail-Design-Vorlage einfügen:"
160
+
161
+ #: wpbe.php:412
162
+ msgid "<strong>%content%</strong> : will be replaced with the message content."
163
+ msgstr "<strong>%content%</strong> : Wird vom Message-Text ersetzt."
164
+
165
+ #: wpbe.php:413
166
+ msgid "NOTE: The content tag is <strong>required</strong>, WP Better Emails will be automatically desactivated if no content tag is found."
167
+ msgstr "Achtung: Inhalt wird <strong>benötigt</strong>, WP Better Emails wird automatisch deaktiviert, wenn kein Inhalt gefunden wird."
168
+
169
+ #: wpbe.php:414
170
+ msgid "<strong>%blog_url%</strong> : will be replaced with your blog URL."
171
+ msgstr "<strong>%blog_url%</strong> : Ihre Blog-URL wird eingefügt."
172
+
173
+ #: wpbe.php:415
174
+ msgid "<strong>%home_url%</strong> : will be replaced with your home URL."
175
+ msgstr "<strong>%home_url%</strong> : Ihre Homepage-URL wird eingefügt."
176
+
177
+ #: wpbe.php:416
178
+ msgid "<strong>%blog_name%</strong> : will be replaced with your blog name."
179
+ msgstr "<strong>%blog_name%</strong> : Ihr Blog-Namen wird eingefügt."
180
+
181
+ #: wpbe.php:417
182
+ msgid "<strong>%blog_description%</strong> : will be replaced with your blog description."
183
+ msgstr "<strong>%blog_description%</strong> : Ihr Blog wird eingefügt."
184
+
185
+ #: wpbe.php:418
186
+ msgid "<strong>%admin_email%</strong> : will be replaced with admin email."
187
+ msgstr "<strong>%admin_email%</strong> : die Administrator-E-Mail wird eingefügt."
188
+
189
+ #: wpbe.php:419
190
+ msgid "<strong>%date%</strong> : will be replaced with current date, as formatted in <a href=\"options-general.php\">general options</a>."
191
+ msgstr "<strong>%date%</strong> : das aktuelle Datum wird eingefügt, in der Form <a href=\"options-general.php\">general options</a>."
192
+
193
+ #: wpbe.php:420
194
+ msgid "<strong>%time%</strong> : will be replaced with current time, as formatted in <a href=\"options-general.php\">general options</a>."
195
+ msgstr "<strong>%time%</strong> : die aktuelle Zeit wird eingefügt, in der Form <a href=\"options-general.php\">general options</a>."
196
+
langs/wp-better-emails-fr_FR.mo CHANGED
Binary file
langs/wp-better-emails-fr_FR.po CHANGED
@@ -1,236 +1,196 @@
1
- # Translation of the WordPress plugin by .
2
- # Copyright (C) 2010
3
  # This file is distributed under the same license as the package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
5
- #
6
  msgid ""
7
  msgstr ""
8
  "Project-Id-Version: WP Better Emails\n"
9
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-better-emails\n"
10
- "POT-Creation-Date: 2010-11-29 15:16+0000\n"
11
- "PO-Revision-Date: 2010-11-29 19:45+0100\n"
12
- "Last-Translator: Nicolas Lemoine <nico@yamoy.org>\n"
13
- "Language-Team: ArtyShow <plugins@artyshow-studio.fr>\n"
14
  "MIME-Version: 1.0\n"
15
- "Content-Type: text/plain; charset=utf-8\n"
16
  "Content-Transfer-Encoding: 8bit\n"
 
 
 
17
  "X-Poedit-Language: French\n"
18
- "X-Poedit-Country: FRANCE\n"
19
-
20
- #: email_template.php:33
21
- msgid "Powered by Wordpress"
22
- msgstr "Propulsé par Wordpress"
23
-
24
- #: email_template.php:34
25
- msgid "Date"
26
- msgstr "Date"
27
-
28
- #: email_template.php:34
29
- msgid "Email sent the"
30
- msgstr "Email envoyé le"
31
-
32
- #: email_template.php:35
33
- msgid "Contact"
34
- msgstr "Contact"
35
-
36
- #: email_template.php:35
37
- msgid "For any request, please contact"
38
- msgstr "Pour toute demande, contactez"
39
 
40
  #: wpbe-options.php:2
41
- msgid "Email options"
42
- msgstr "Options email"
 
43
 
44
  #: wpbe-options.php:9
45
- msgid "Sender options"
46
- msgstr "Options envoyeur"
47
-
48
- #: wpbe-options.php:10
49
- msgid "Template options"
50
- msgstr "Options du modèle"
51
-
52
- #: wpbe-options.php:11
53
- msgid "Help & support"
54
- msgstr "Aide & support"
55
-
56
- #: wpbe-options.php:14
57
- msgid "Change the Wordpress default behavior when sending emails to users (i.e. comment notifications, lost password, etc.), set your own sender name and email address."
58
- msgstr "Modifiez le comportement par défaut de Wordpress lors de l'envoi d'emails aux utilisateurs (notifications, mot de passe perdu, etc.), configurez votre propre nom d'envoyeur et adresse email d'envoyeur."
59
-
60
- #: wpbe-options.php:17
61
- msgid "From name"
62
- msgstr "Nom"
63
 
64
- #: wpbe-options.php:17
65
- #: wpbe-options.php:21
66
- msgid "required"
67
- msgstr "requis"
68
 
69
- #: wpbe-options.php:21
70
- msgid "From email address"
71
  msgstr "Adresse email"
72
 
73
- #: wpbe-options.php:29
74
- msgid "Template variables"
75
- msgstr "Variables du modèle"
76
 
77
- #: wpbe-options.php:31
78
- msgid "Some dynamic tags can be included in your email template :"
79
- msgstr "Des tags dynamiques peuvent être utilisés dans votre modèle d'email :"
80
 
81
- #: wpbe-options.php:33
82
- msgid "<strong>%content%</strong> : will be replaced by the message content."
83
- msgstr "<strong>%content%</strong> : sera remplacé par le contenu du message."
84
 
85
- #: wpbe-options.php:34
86
- msgid "NOTE: The content tag is <strong>required</strong>, WP Better Emails will be automatically desactivated if no content tag is found."
87
- msgstr "NOTE: Le tag \"content\" est <strong>requis</strong>, WP Better Emails sera automatiquement désactivé si ce tag n'est pas trouvé dans le modèle."
88
 
89
  #: wpbe-options.php:35
90
- msgid "<strong>%blog_url%</strong> : will be replaced by your blog URL."
91
- msgstr "<strong>%blog_url%</strong> : sera remplacé par l'URL de votre blog."
92
-
93
- #: wpbe-options.php:36
94
- msgid "<strong>%blog_name%</strong> : will be replaced by your blog name."
95
- msgstr "<strong>%blog_name%</strong> : sera remplacé par le nom de votre blog."
96
-
97
- #: wpbe-options.php:37
98
- msgid "<strong>%blog_description%</strong> : will be replaced by your blog description."
99
- msgstr "<strong>%blog_description%</strong> : will be replaced by your blog description."
100
-
101
- #: wpbe-options.php:38
102
- msgid "<strong>%admin_email%</strong> : will be replaced by admin email."
103
- msgstr "<strong>%admin_email%</strong> : sera remplacé par l'email de l'admin."
104
-
105
- #: wpbe-options.php:39
106
- msgid "<strong>%date%</strong> : will be replaced by current date, as formatted in <a href=\"options-general.php\">general options</a>."
107
- msgstr "<strong>%date%</strong> : sera remplacé par la date courante, formatée telle que spécifié dans les <a href=\"options-general.php\">options générales</a>."
108
-
109
- #: wpbe-options.php:40
110
- msgid "<strong>%time%</strong> : will be replaced by current time, as formatted in <a href=\"options-general.php\">general options</a>."
111
- msgstr "<strong>%time%</strong> : sera remplacé par l'heure courante, formatée telle que spécifié dans les <a href=\"options-general.php\">options générales</a>."
112
-
113
- #: wpbe-options.php:46
114
- msgid "HTML Template"
115
- msgstr "Modèle HTML"
116
-
117
- #: wpbe-options.php:51
118
  msgid "Send an email preview to"
119
  msgstr "Envoyer un aperçu à"
120
 
121
- #: wpbe-options.php:54
122
  msgid "Send"
123
  msgstr "Envoyer"
124
 
125
- #: wpbe-options.php:56
126
  msgid "You must save your template before sending an email preview."
127
- msgstr "Vous devez enregistrer votre modèle avant d'envoyer un aperçu."
128
-
129
- #: wpbe-options.php:64
130
- msgid "Designing & coding email templates"
131
- msgstr "Concevoir & coder des modèles d'emails"
132
-
133
- #: wpbe-options.php:65
134
- msgid "Here are a few ressources about email formatting :"
135
- msgstr "Voici quelques ressources à propos du codage pour email :"
136
 
137
- #: wpbe-options.php:67
138
- msgid "<a href=\"http://www.campaignmonitor.com/resources/\" target=\"_blank\">http://www.campaignmonitor.com/resources/</a>"
139
- msgstr ""
140
-
141
- #: wpbe-options.php:68
142
- msgid "<a href=\"http://articles.sitepoint.com/article/code-html-email-newsletters/\" target=\"_blank\">http://articles.sitepoint.com/article/code-html-email-newsletters/</a>"
143
- msgstr ""
144
-
145
- #: wpbe-options.php:70
146
- msgid "Converting HTML templates"
147
- msgstr "Convertir des modèles HTML"
148
-
149
- #: wpbe-options.php:71
150
- msgid "Coding HTML for emails requires CSS styles to be inline. Here's a tool powered by MailChimp that will convert your styles placed in the <code>&lt;head&gt;</code> tag to inline : "
151
- msgstr "Coder du HTML pour les emails requiert que les styles CSS soient intégrés \"inline\". Voici un outil proposé par MailChimp qui convertit les styles placés dans la balise <code>&lt;head&gt;</code> en styles \"inline\" :"
152
-
153
- #: wpbe-options.php:73
154
- msgid "<a href=\"http://www.mailchimp.com/labs/inlinecss.php\" target=\"_blank\">http://www.mailchimp.com/labs/inlinecss.php</a>"
155
- msgstr ""
156
 
157
- #: wpbe-options.php:75
158
- msgid "Requests & Bug report"
159
- msgstr "Demandes & report de bugs"
160
 
161
- #: wpbe-options.php:76
162
  msgid "If you have any idea to improve this plugin or any bug to report, please email me at : <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
163
  msgstr "Si vous avez des idées d'amélioration ou des bugs à mentionner, envoyez-moi un email à <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
164
 
165
- #: wpbe-options.php:77
166
- msgid "Credits"
167
- msgstr "Crédits"
168
 
169
- #: wpbe-options.php:79
170
- msgid "MarkItUp! : jQuery HTML editor <a href=\"http://markitup.jaysalvat.com/home/\" target=\"_blank\">http://markitup.jaysalvat.com/home/</a>"
171
- msgstr "MarkItUp! : Editeur HTML jQuery <a href=\"http://markitup.jaysalvat.com/home/\" target=\"_blank\">http://markitup.jaysalvat.com/home/</a>"
172
 
173
- #: wpbe-options.php:84
174
- msgid "Save Changes"
175
- msgstr "Enregistrer les modifications"
176
 
177
- #: wpbe.php:47
 
 
 
 
 
 
 
 
178
  msgid "Settings"
179
  msgstr "Configuration"
180
 
181
- #: wpbe.php:64
182
  msgid "WP Better Emails requires WordPress 2.8 or newer."
183
- msgstr "WP Better Emails requiert Wordpress 2.8 ou ultérieur."
 
 
 
 
184
 
185
- #: wpbe.php:149
186
- msgid "Please enter a sender email address."
187
- msgstr "Veuillez entrer une adresse email valide."
188
 
189
- #: wpbe.php:152
190
  msgid "Please enter a valid sender email address."
191
  msgstr "Veuillez entrer une adresse email valide pour l'envoyeur."
192
 
193
- #: wpbe.php:162
194
  msgid "Template is empty"
195
  msgstr "Le modèle est vide"
196
 
197
- #: wpbe.php:165
198
- msgid "No content tag found. Please insert the %content% tag in your template"
199
  msgstr "Aucun tag de contenu n'a été trouvé. Veuillez insérer le tag %content% dans votre template."
200
 
201
- #: wpbe.php:181
202
  msgid "Please enter an email"
203
  msgstr "Veuillez entrer un email"
204
 
205
- #: wpbe.php:183
206
  msgid "Please enter a valid email"
207
  msgstr "Veuillez entrer un email valide"
208
 
209
- #: wpbe.php:184
210
  msgid "Hey !"
211
  msgstr "Hey !"
212
 
213
- #: wpbe.php:186
214
- msgid "This is a sample email to test your template."
215
  msgstr "Ceci un email factice pour tester votre modèle."
216
 
217
- #: wpbe.php:188
218
- msgid "If you're not skilled in HTML/CSS email coding, I strongly recommend to leave the default template as it is. It has been tested on various and popular email clients like Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, and many more. "
219
  msgstr "Si vous n'êtes pas compétent en intégraiton HTML/CSS, je vous recommande vivement de laisser le modèle tel qu'il est. Il a été testé sur de nombreux et populaires clients mail comme Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, et bien plus encore."
220
 
221
- #: wpbe.php:190
222
- msgid "If you have any problem or any suggestions to improve this plugin, please let me know."
223
- msgstr "Si vous avez un problèmes ou des suggestions d'améliorations, n'hésitez pas à m'en faire part."
224
 
225
- #: wpbe.php:192
226
  msgid "Email template preview"
227
  msgstr "Aperçu du modèle d'email"
228
 
229
- #: wpbe.php:193
230
- msgid "An email preview has been successfully sent to "
231
- msgstr "Un email d'aperçu a été envoyé avec succès à "
232
 
233
- #: wpbe.php:195
234
  msgid "An error occured while sending email. Please check your server configuration."
235
  msgstr "Une erreur a eu lieu lors de l'envoi. Vérifiez la configuration de votre serveur."
236
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2010
 
2
  # This file is distributed under the same license as the package.
 
 
3
  msgid ""
4
  msgstr ""
5
  "Project-Id-Version: WP Better Emails\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-better-emails\n"
7
+ "POT-Creation-Date: 2011-09-06 23:22:41+00:00\n"
 
 
 
8
  "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2011-09-12 17:26+0100\n"
12
+ "Last-Translator: \n"
13
+ "Language-Team: Nicolas Lemoine <plugins@artyshow-studio.fr>\n"
14
  "X-Poedit-Language: French\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  #: wpbe-options.php:2
17
+ #: wpbe.php:158
18
+ msgid "Email settings"
19
+ msgstr "Configuration des emails"
20
 
21
  #: wpbe-options.php:9
22
+ msgid "Set your own sender name and email address. Default Wordpress values will be used if empty."
23
+ msgstr "Définissez votre propre nom d'envoyeur et adresse email d'envoyeur. Les valeurs par défaut de Wordpress seront utilisées si les champs sont laissés vides."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ #: wpbe-options.php:12
26
+ msgid "Name"
27
+ msgstr " Nom"
 
28
 
29
+ #: wpbe-options.php:16
30
+ msgid "Email address"
31
  msgstr "Adresse email"
32
 
33
+ #: wpbe-options.php:22
34
+ msgid "HTML Template"
35
+ msgstr "Modèle HTML"
36
 
37
+ #: wpbe-options.php:24
38
+ msgid "Live template preview"
39
+ msgstr "Aperçu rapide du modèle"
40
 
41
+ #: wpbe-options.php:24
42
+ msgid "Live preview"
43
+ msgstr "Aperçu"
44
 
45
+ #: wpbe-options.php:26
46
+ msgid "Edit the HTML email template if you want to customize it. You might have a look at the <a href=\"#\" id=\"wpbe_help\">help tab</a> for further information."
47
+ msgstr "Editer le modèle HTML si vous souhaitez le personnaliser. <a href=\"#\" id=\"wpbe_help\">Consultez l'aide</a> pour plus d'information."
48
 
49
  #: wpbe-options.php:35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  msgid "Send an email preview to"
51
  msgstr "Envoyer un aperçu à"
52
 
53
+ #: wpbe-options.php:39
54
  msgid "Send"
55
  msgstr "Envoyer"
56
 
57
+ #: wpbe-options.php:41
58
  msgid "You must save your template before sending an email preview."
59
+ msgstr "Vous devez enregistrer le modèle avant d'envoyer un aperçu."
 
 
 
 
 
 
 
 
60
 
61
+ #: wpbe-options.php:46
62
+ msgid "Save Changes"
63
+ msgstr "Enregistrer les modifications"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ #: wpbe-options.php:52
66
+ msgid "Support & bug report"
67
+ msgstr "Support & report de bugs"
68
 
69
+ #: wpbe-options.php:53
70
  msgid "If you have any idea to improve this plugin or any bug to report, please email me at : <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
71
  msgstr "Si vous avez des idées d'amélioration ou des bugs à mentionner, envoyez-moi un email à <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
72
 
73
+ #: wpbe-options.php:55
74
+ msgid "You like this plugin ? You use it in a business context ? Please, consider a <a href=\"%s\" target=\"_blank\" rel=\"external\">donation</a>."
75
+ msgstr "Vous aimez ce plugin ? Vous l'utilisez dans un contexte professionnel ? Considérez un <a href=\"%s\" target=\"_blank\" rel=\"external\">don</a>."
76
 
77
+ #: templates/template-1.php:33
78
+ msgid "Date"
79
+ msgstr "Date"
80
 
81
+ #: templates/template-1.php:33
82
+ msgid "Email sent"
83
+ msgstr "Email envoyé le"
84
 
85
+ #: templates/template-1.php:34
86
+ msgid "Contact"
87
+ msgstr "Contact"
88
+
89
+ #: templates/template-1.php:34
90
+ msgid "For any requests, please contact"
91
+ msgstr "Pour toute demande, contactez"
92
+
93
+ #: wpbe.php:131
94
  msgid "Settings"
95
  msgstr "Configuration"
96
 
97
+ #: wpbe.php:147
98
  msgid "WP Better Emails requires WordPress 2.8 or newer."
99
+ msgstr "WP Better Emails requiert Wordpress 2.8 ou une version plus récente."
100
+
101
+ #: wpbe.php:147
102
+ msgid "Upgrade your Wordpress installation."
103
+ msgstr "Mettez à jour votre installation de Wordpress."
104
 
105
+ #: wpbe.php:158
106
+ msgid "WP Better Emails"
107
+ msgstr "WP Better Emails"
108
 
109
+ #: wpbe.php:228
110
  msgid "Please enter a valid sender email address."
111
  msgstr "Veuillez entrer une adresse email valide pour l'envoyeur."
112
 
113
+ #: wpbe.php:238
114
  msgid "Template is empty"
115
  msgstr "Le modèle est vide"
116
 
117
+ #: wpbe.php:241
118
+ msgid "No content tag found. The %content% tag is required in your template"
119
  msgstr "Aucun tag de contenu n'a été trouvé. Veuillez insérer le tag %content% dans votre template."
120
 
121
+ #: wpbe.php:259
122
  msgid "Please enter an email"
123
  msgstr "Veuillez entrer un email"
124
 
125
+ #: wpbe.php:261
126
  msgid "Please enter a valid email"
127
  msgstr "Veuillez entrer un email valide"
128
 
129
+ #: wpbe.php:262
130
  msgid "Hey !"
131
  msgstr "Hey !"
132
 
133
+ #: wpbe.php:264
134
+ msgid "This is a sample email to test your HTML template."
135
  msgstr "Ceci un email factice pour tester votre modèle."
136
 
137
+ #: wpbe.php:266
138
+ msgid "If you're not skilled in HTML/CSS email coding, I strongly recommend to leave the default template as it is. It has been tested on various and popular email clients like Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, and many more."
139
  msgstr "Si vous n'êtes pas compétent en intégraiton HTML/CSS, je vous recommande vivement de laisser le modèle tel qu'il est. Il a été testé sur de nombreux et populaires clients mail comme Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, et bien plus encore."
140
 
141
+ #: wpbe.php:268
142
+ msgid "If you have any problems or any suggestions to improve this plugin, please let me know."
143
+ msgstr "Si vous recontrez un problèmes ou des suggestions d'améliorations, n'hésitez pas à m'en faire part."
144
 
145
+ #: wpbe.php:269
146
  msgid "Email template preview"
147
  msgstr "Aperçu du modèle d'email"
148
 
149
+ #: wpbe.php:270
150
+ msgid "An email preview has been successfully sent to %s"
151
+ msgstr "Un email d'aperçu vient d'être envoyé avec succès à %s"
152
 
153
+ #: wpbe.php:273
154
  msgid "An error occured while sending email. Please check your server configuration."
155
  msgstr "Une erreur a eu lieu lors de l'envoi. Vérifiez la configuration de votre serveur."
156
 
157
+ #: wpbe.php:410
158
+ msgid "Some dynamic tags can be included in your email template :"
159
+ msgstr "Des tags dynamiques peuvent être inclus dans votre template :"
160
+
161
+ #: wpbe.php:412
162
+ msgid "<strong>%content%</strong> : will be replaced with the message content."
163
+ msgstr "<strong>%content%</strong> : sera remplacé par le contenu du message."
164
+
165
+ #: wpbe.php:413
166
+ msgid "NOTE: The content tag is <strong>required</strong>, WP Better Emails will be automatically desactivated if no content tag is found."
167
+ msgstr "NOTE: Le tag \"content\" est <strong>requis</strong>, WP Better Emails sera automatiquement désactivé si ce tag n'est pas trouvé dans le modèle."
168
+
169
+ #: wpbe.php:414
170
+ msgid "<strong>%blog_url%</strong> : will be replaced with your blog URL."
171
+ msgstr "<strong>%blog_url%</strong> : sera remplacé par l'URL de votre blog."
172
+
173
+ #: wpbe.php:415
174
+ msgid "<strong>%home_url%</strong> : will be replaced with your home URL."
175
+ msgstr "<strong>%home_url%</strong> : sera remplacé par l'URL d'accueil de votre blog."
176
+
177
+ #: wpbe.php:416
178
+ msgid "<strong>%blog_name%</strong> : will be replaced with your blog name."
179
+ msgstr "<strong>%blog_name%</strong> : sera remplacé par le nom de votre blog."
180
+
181
+ #: wpbe.php:417
182
+ msgid "<strong>%blog_description%</strong> : will be replaced with your blog description."
183
+ msgstr "<strong>%blog_description%</strong> : sera remplacé par la description de votre blog."
184
+
185
+ #: wpbe.php:418
186
+ msgid "<strong>%admin_email%</strong> : will be replaced with admin email."
187
+ msgstr "<strong>%admin_email%</strong> : sera remplacé par l'email de l'administrateur."
188
+
189
+ #: wpbe.php:419
190
+ msgid "<strong>%date%</strong> : will be replaced with current date, as formatted in <a href=\"options-general.php\">general options</a>."
191
+ msgstr "<strong>%date%</strong> : sera remplacé par la date courante, telle que formatée dans les <a href=\"options-general.php\">options générales</a>."
192
+
193
+ #: wpbe.php:420
194
+ msgid "<strong>%time%</strong> : will be replaced with current time, as formatted in <a href=\"options-general.php\">general options</a>."
195
+ msgstr "<strong>%time%</strong> : sera remplacé par l'heure courante, telle que formatée dans les <a href=\"options-general.php\">options générales</a>."
196
+
langs/wp-better-emails-he_IL.mo ADDED
Binary file
langs/wp-better-emails-he_IL.po ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2010
2
+ # This file is distributed under the same license as the package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: WP-Better-Emails\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-better-emails\n"
7
+ "POT-Creation-Date: 2011-09-06 23:22:41+00:00\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2011-09-12 17:26+0100\n"
12
+ "Last-Translator: \n"
13
+ "Language-Team: Avi Ben-Avraham <avi@nrich.co.il>\n"
14
+ "X-Poedit-Language: Hebrew\n"
15
+ "X-Poedit-Country: ISRAEL\n"
16
+
17
+ #: wpbe-options.php:2
18
+ #: wpbe.php:158
19
+ msgid "Email settings"
20
+ msgstr "הגדרות מייל"
21
+
22
+ #: wpbe-options.php:9
23
+ msgid "Set your own sender name and email address. Default Wordpress values will be used if empty."
24
+ msgstr "קבע בעצמך את שם השולח וכתובת המייל. אם תשאיר שדות אלה ריקים ייעשה שימוש בערכי ברירת המחדל של וורדפרס."
25
+
26
+ #: wpbe-options.php:12
27
+ msgid "Name"
28
+ msgstr "שם השולח"
29
+
30
+ #: wpbe-options.php:16
31
+ msgid "Email address"
32
+ msgstr "כתובת המייל של השולח"
33
+
34
+ #: wpbe-options.php:22
35
+ msgid "HTML Template"
36
+ msgstr "HTML תבנית"
37
+
38
+ #: wpbe-options.php:24
39
+ msgid "Live template preview"
40
+ msgstr "תצוגה מוקדמת אמיתית של התבנית"
41
+
42
+ #: wpbe-options.php:24
43
+ msgid "Live preview"
44
+ msgstr "לחיות תצוגה מקדימה"
45
+
46
+ #: wpbe-options.php:26
47
+ msgid "Edit the HTML email template if you want to customize it. You might have a look at <a href=\"#\" id=\"wpbe_help\">help tab</a> for further information."
48
+ msgstr ""
49
+
50
+ #: wpbe-options.php:35
51
+ msgid "Send an email preview to"
52
+ msgstr "שלח תצוגה מקדימה במייל ל"
53
+
54
+ #: wpbe-options.php:39
55
+ msgid "Send"
56
+ msgstr "שלח"
57
+
58
+ #: wpbe-options.php:41
59
+ msgid "You must save your template before sending an email preview."
60
+ msgstr "הינך חייב לשמור את התבנית לפני שליחה תצוגה מוקדמת של מייל"
61
+
62
+ #: wpbe-options.php:46
63
+ msgid "Save Changes"
64
+ msgstr "שמור שינויים"
65
+
66
+ #: wpbe-options.php:52
67
+ msgid "Support & bug report"
68
+ msgstr "תמיכה ודיווח על בעיות"
69
+
70
+ #: wpbe-options.php:53
71
+ msgid "If you have any idea to improve this plugin or any bug to report, please email me at : <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
72
+ msgstr "אם יש לך רעיון כיצד לשפר את התוסף או אם מצאת באג, שלח לי מייל ל: <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
73
+
74
+ #: wpbe-options.php:55
75
+ msgid "You like this plugin ? You use it in a business context ? Please, consider a <a href=\"%s\" target=\"_blank\" rel=\"external\">donation</a>."
76
+ msgstr "אהבת את התוסף? משתמש בתוסף לצרכים עסקיים? אנא שקול <a href=\"%s\" target=\"_blank\" rel=\"external\">לתרום</a>."
77
+
78
+ #: templates/template-1.php:33
79
+ msgid "Date"
80
+ msgstr "תאריך"
81
+
82
+ #: templates/template-1.php:33
83
+ msgid "Email sent"
84
+ msgstr "נשלח במייל"
85
+
86
+ #: templates/template-1.php:34
87
+ msgid "Contact"
88
+ msgstr "צור קשר"
89
+
90
+ #: templates/template-1.php:34
91
+ msgid "For any requests, please contact"
92
+ msgstr "בכל בקשה, אנא צור קשר"
93
+
94
+ #: wpbe.php:131
95
+ msgid "Settings"
96
+ msgstr "הגדרות"
97
+
98
+ #: wpbe.php:147
99
+ msgid "WP Better Emails requires WordPress 2.8 or newer."
100
+ msgstr "WP Better Emails עובד רק על וורדפרס 2.8 ומעלה"
101
+
102
+ #: wpbe.php:147
103
+ msgid "Upgrade your Wordpress installation."
104
+ msgstr "שדרג את התקנת הוורדפרס שברשותך"
105
+
106
+ #: wpbe.php:158
107
+ msgid "WP Better Emails"
108
+ msgstr "WP Better Emails"
109
+
110
+ #: wpbe.php:228
111
+ msgid "Please enter a valid sender email address."
112
+ msgstr "אנא הזן כתובת מייל חוקית של השולח"
113
+
114
+ #: wpbe.php:238
115
+ msgid "Template is empty"
116
+ msgstr "התבנית ריקה"
117
+
118
+ #: wpbe.php:241
119
+ msgid "No content tag found. The %content% tag is required in your template"
120
+ msgstr "לא נמצאו תגיות תוכן. התגית %content% נדרשת בתבנית שלך"
121
+
122
+ #: wpbe.php:259
123
+ msgid "Please enter an email"
124
+ msgstr "אנא הזן דואר אלקטרוני"
125
+
126
+ #: wpbe.php:261
127
+ msgid "Please enter a valid email"
128
+ msgstr "אנא הזן כתובת דואר אלקטרוני חוקית"
129
+
130
+ #: wpbe.php:262
131
+ msgid "Hey !"
132
+ msgstr "היי!"
133
+
134
+ #: wpbe.php:264
135
+ msgid "This is a sample email to test your HTML template."
136
+ msgstr "זהו מייל לדוגמה לבחינת תבנית ה- HTML שיצרת"
137
+
138
+ #: wpbe.php:266
139
+ msgid "If you're not skilled in HTML/CSS email coding, I strongly recommend to leave the default template as it is. It has been tested on various and popular email clients like Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, and many more."
140
+ msgstr "אם אין לך ניסיון בכתיבת HTML/CSS, אני ממליץ בחום להשאיר את תבנית ברירת המחדל כמו שהיא. התבנית נבחנה בהצלחה על מגוון תוכנות וממשקי מייל כמו ג'ימייל, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook ועוד רבים אחרים."
141
+
142
+ #: wpbe.php:268
143
+ msgid "If you have any problems or any suggestions to improve this plugin, please let me know."
144
+ msgstr "אם הינך נתקל בכל בעיה או יש לך הצעות לשיפור, אנא הודע לי"
145
+
146
+ #: wpbe.php:269
147
+ msgid "Email template preview"
148
+ msgstr "תצוגה מוקדמת של תבנית המייל"
149
+
150
+ #: wpbe.php:270
151
+ msgid "An email preview has been successfully sent to %s"
152
+ msgstr "An email preview has been successfully sent to %s"
153
+
154
+ #: wpbe.php:273
155
+ msgid "An error occured while sending email. Please check your server configuration."
156
+ msgstr "שגיאה ארעה בזמן שליחת המייל. אנא בדוק את הגדרות השרת שלך"
157
+
158
+ #: wpbe.php:410
159
+ msgid "Some dynamic tags can be included in your email template :"
160
+ msgstr "ניתן לכלול מספר תגיות דינמיות בתבנית המייל שלך"
161
+
162
+ #: wpbe.php:412
163
+ msgid "<strong>%content%</strong> : will be replaced with the message content."
164
+ msgstr "<strong>%content%</strong>: יוחלף בתוכן ההודעה"
165
+
166
+ #: wpbe.php:413
167
+ msgid "NOTE: The content tag is <strong>required</strong>, WP Better Emails will be automatically desactivated if no content tag is found."
168
+ msgstr "שים לב: תגית התוכן היא <strong>required</strong>.WP Better Emails לא יופעל אם לא תימצא כל תגית תוכן."
169
+
170
+ #: wpbe.php:414
171
+ msgid "<strong>%blog_url%</strong> : will be replaced with your blog URL."
172
+ msgstr "<strong>%blog_url%</strong>: יוחלף בכתובת הבלוג שלך"
173
+
174
+ #: wpbe.php:415
175
+ msgid "<strong>%home_url%</strong> : will be replaced with your home URL."
176
+ msgstr "<strong>%home_url%</strong>: יוחלף בכתובת הבית שלך"
177
+
178
+ #: wpbe.php:416
179
+ msgid "<strong>%blog_name%</strong> : will be replaced with your blog name."
180
+ msgstr "<strong>%blog_name%</strong>: יוחלף בשם הבלוג שלך"
181
+
182
+ #: wpbe.php:417
183
+ msgid "<strong>%blog_description%</strong> : will be replaced with your blog description."
184
+ msgstr "<strong>%blog_description%</strong>: יוחלף בתיאור הבלוג שלך"
185
+
186
+ #: wpbe.php:418
187
+ msgid "<strong>%admin_email%</strong> : will be replaced with admin email."
188
+ msgstr "<strong>%admin_email%</strong>: יוחלף בכתובת המייל של המנהל"
189
+
190
+ #: wpbe.php:419
191
+ msgid "<strong>%date%</strong> : will be replaced with current date, as formatted in <a href=\"options-general.php\">general options</a>."
192
+ msgstr "<strong>%date%</strong>: יוחלף בתאריך הנוכחי כמוגדר ב- <a href=\"options-general.php\">אפשרויות כלליות</a>."
193
+
194
+ #: wpbe.php:420
195
+ msgid "<strong>%time%</strong> : will be replaced with current time, as formatted in <a href=\"options-general.php\">general options</a>."
196
+ msgstr "<strong>%time%</strong>: יוחלף בזמן הנוכחי, כמוגדר ב-<a href=\"options-general.php\">אפשרויות כלליות</a>."
197
+
langs/wp-better-emails-nl_NL.mo DELETED
Binary file
langs/wp-better-emails-nl_NL.po DELETED
@@ -1,236 +0,0 @@
1
- # Translation of the WordPress plugin by .
2
- # Copyright (C) 2010
3
- # This file is distributed under the same license as the package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
5
- #
6
- msgid ""
7
- msgstr ""
8
- "Project-Id-Version: WP Better Emails\n"
9
- "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-better-emails\n"
10
- "POT-Creation-Date: 2010-11-29 15:16+0000\n"
11
- "PO-Revision-Date: 2011-01-07 22:39+0100\n"
12
- "Last-Translator: Glenn Mulleners <info@wp-expert.nl>\n"
13
- "Language-Team: Glenn Mulleners <info@wp-expert.nl>\n"
14
- "MIME-Version: 1.0\n"
15
- "Content-Type: text/plain; charset=utf-8\n"
16
- "Content-Transfer-Encoding: 8bit\n"
17
- "X-Poedit-Language: Dutch\n"
18
- "X-Poedit-Country: NETHERLANDS\n"
19
-
20
- #: email_template.php:33
21
- msgid "Powered by Wordpress"
22
- msgstr "Powered by WordPress"
23
-
24
- #: email_template.php:34
25
- msgid "Date"
26
- msgstr "Datum"
27
-
28
- #: email_template.php:34
29
- msgid "Email sent the"
30
- msgstr "E-mail verstuurd"
31
-
32
- #: email_template.php:35
33
- msgid "Contact"
34
- msgstr "Contact"
35
-
36
- #: email_template.php:35
37
- msgid "For any request, please contact"
38
- msgstr "Voor eventuele vragen kun je contact opnemen met"
39
-
40
- #: wpbe-options.php:2
41
- msgid "Email options"
42
- msgstr "E-mail opties"
43
-
44
- #: wpbe-options.php:9
45
- msgid "Sender options"
46
- msgstr "Afzender opties"
47
-
48
- #: wpbe-options.php:10
49
- msgid "Template options"
50
- msgstr "Sjabloon opties"
51
-
52
- #: wpbe-options.php:11
53
- msgid "Help & support"
54
- msgstr "Hulp & ondersteuning"
55
-
56
- #: wpbe-options.php:14
57
- msgid "Change the Wordpress default behavior when sending emails to users (i.e. comment notifications, lost password, etc.), set your own sender name and email address."
58
- msgstr "Wijzig het standaard gedrag van WordPress bij het verzenden van e-mails naar gebruikers (bijv. reactie notificaties, wachtwoord kwijt, etc), stel je eigen naam en e-mailadres in als afzender."
59
-
60
- #: wpbe-options.php:17
61
- msgid "From name"
62
- msgstr "Afzender"
63
-
64
- #: wpbe-options.php:17
65
- #: wpbe-options.php:21
66
- msgid "required"
67
- msgstr "verplicht"
68
-
69
- #: wpbe-options.php:21
70
- msgid "From email address"
71
- msgstr "Afzender e-mailadres"
72
-
73
- #: wpbe-options.php:29
74
- msgid "Template variables"
75
- msgstr "Sjabloon variabelen"
76
-
77
- #: wpbe-options.php:31
78
- msgid "Some dynamic tags can be included in your email template :"
79
- msgstr "Sommige dynamische tags kunnen worden opgenomen in je e-mail sjabloon:"
80
-
81
- #: wpbe-options.php:33
82
- msgid "<strong>%content%</strong> : will be replaced by the message content."
83
- msgstr "<strong>%content%</strong> : zal worden vervangen door het bericht."
84
-
85
- #: wpbe-options.php:34
86
- msgid "NOTE: The content tag is <strong>required</strong>, WP Better Emails will be automatically desactivated if no content tag is found."
87
- msgstr "LET OP: De inhoud tag is <strong>verplicht</strong>, WP Better Emails zal automatisch worden gedeactiveerd als de inhoud tag niet is gevonden."
88
-
89
- #: wpbe-options.php:35
90
- msgid "<strong>%blog_url%</strong> : will be replaced by your blog URL."
91
- msgstr "<strong>%blog_url%</strong> : zal worden vervangen door de site URL."
92
-
93
- #: wpbe-options.php:36
94
- msgid "<strong>%blog_name%</strong> : will be replaced by your blog name."
95
- msgstr "<strong>%blog_name%</strong> : zal worden vervangen door je site naam."
96
-
97
- #: wpbe-options.php:37
98
- msgid "<strong>%blog_description%</strong> : will be replaced by your blog description."
99
- msgstr "<strong>%blog_description%</strong> : zal worden vervangen door je site beschrijving."
100
-
101
- #: wpbe-options.php:38
102
- msgid "<strong>%admin_email%</strong> : will be replaced by admin email."
103
- msgstr "<strong>%admin_email%</strong> : zal worden vervangen door het e-mailadres van de beheerder."
104
-
105
- #: wpbe-options.php:39
106
- msgid "<strong>%date%</strong> : will be replaced by current date, as formatted in <a href=\"options-general.php\">general options</a>."
107
- msgstr "<strong>%date%</strong> : zal worden vervangen door de huidige datum, zoals opgegeven in de <a href=\"options-general.php\">algemene instellingen</a>."
108
-
109
- #: wpbe-options.php:40
110
- msgid "<strong>%time%</strong> : will be replaced by current time, as formatted in <a href=\"options-general.php\">general options</a>."
111
- msgstr "<strong>%date%</strong> : zal worden vervangen door de huidige tijd, zoals opgegeven in de <a href=\"options-general.php\">algemene instellingen</a>."
112
-
113
- #: wpbe-options.php:46
114
- msgid "HTML Template"
115
- msgstr "HTML Sjabloon"
116
-
117
- #: wpbe-options.php:51
118
- msgid "Send an email preview to"
119
- msgstr "Stuur e-mail voorbeeld naar"
120
-
121
- #: wpbe-options.php:54
122
- msgid "Send"
123
- msgstr "Verstuur"
124
-
125
- #: wpbe-options.php:56
126
- msgid "You must save your template before sending an email preview."
127
- msgstr "Je sjabloon moet worden opgeslagen voor het versturen van een e-mail voorbeeld."
128
-
129
- #: wpbe-options.php:64
130
- msgid "Designing & coding email templates"
131
- msgstr "Ontwerpen en coderen van e-mail sjablonen"
132
-
133
- #: wpbe-options.php:65
134
- msgid "Here are a few ressources about email formatting :"
135
- msgstr "Hier zijn een paar bronnen over e-mail opmaak:"
136
-
137
- #: wpbe-options.php:67
138
- msgid "<a href=\"http://www.campaignmonitor.com/resources/\" target=\"_blank\">http://www.campaignmonitor.com/resources/</a>"
139
- msgstr "<a href=\"http://www.campaignmonitor.com/resources/\" target=\"_blank\">http://www.campaignmonitor.com/resources/</a>"
140
-
141
- #: wpbe-options.php:68
142
- msgid "<a href=\"http://articles.sitepoint.com/article/code-html-email-newsletters/\" target=\"_blank\">http://articles.sitepoint.com/article/code-html-email-newsletters/</a>"
143
- msgstr "<a href=\"http://articles.sitepoint.com/article/code-html-email-newsletters/\" target=\"_blank\">http://articles.sitepoint.com/article/code-html-email-newsletters/</a>"
144
-
145
- #: wpbe-options.php:70
146
- msgid "Converting HTML templates"
147
- msgstr "HTML sjabloon omzetten"
148
-
149
- #: wpbe-options.php:71
150
- msgid "Coding HTML for emails requires CSS styles to be inline. Here's a tool powered by MailChimp that will convert your styles placed in the <code>&lt;head&gt;</code> tag to inline : "
151
- msgstr "Het coderen van HTML e-mails vereist inline CSS stijlen. Hier is een tool van MailChimp die je stijlen in de <code>&lt;head&gt;</code> tag naar inline stijlen omzet:"
152
-
153
- #: wpbe-options.php:73
154
- msgid "<a href=\"http://www.mailchimp.com/labs/inlinecss.php\" target=\"_blank\">http://www.mailchimp.com/labs/inlinecss.php</a>"
155
- msgstr "<a href=\"http://www.mailchimp.com/labs/inlinecss.php\" target=\"_blank\">http://www.mailchimp.com/labs/inlinecss.php</a>"
156
-
157
- #: wpbe-options.php:75
158
- msgid "Requests & Bug report"
159
- msgstr "Verzoeken & foutmeldingen"
160
-
161
- #: wpbe-options.php:76
162
- msgid "If you have any idea to improve this plugin or any bug to report, please email me at : <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
163
- msgstr "Als je een idee hebt om deze plugin te verbeteren of als je een fout wilt melden, stuur me een e-mail: <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
164
-
165
- #: wpbe-options.php:77
166
- msgid "Credits"
167
- msgstr "Dank aan"
168
-
169
- #: wpbe-options.php:79
170
- msgid "MarkItUp! : jQuery HTML editor <a href=\"http://markitup.jaysalvat.com/home/\" target=\"_blank\">http://markitup.jaysalvat.com/home/</a>"
171
- msgstr "MarkItUp! : jQuery HTML editor <a href=\"http://markitup.jaysalvat.com/home/\" target=\"_blank\">http://markitup.jaysalvat.com/home/</a>"
172
-
173
- #: wpbe-options.php:84
174
- msgid "Save Changes"
175
- msgstr "Wijzigingen opslaan"
176
-
177
- #: wpbe.php:47
178
- msgid "Settings"
179
- msgstr "Instellingen"
180
-
181
- #: wpbe.php:64
182
- msgid "WP Better Emails requires WordPress 2.8 or newer."
183
- msgstr "WP Better Emails vereist WordPress 2.8 of hoger."
184
-
185
- #: wpbe.php:149
186
- msgid "Please enter a sender email address."
187
- msgstr "Vul een afzender e-mailadres in."
188
-
189
- #: wpbe.php:152
190
- msgid "Please enter a valid sender email address."
191
- msgstr "Vul een geldig afzender e-mailadres in."
192
-
193
- #: wpbe.php:162
194
- msgid "Template is empty"
195
- msgstr "Sjabloon ontbreekt."
196
-
197
- #: wpbe.php:165
198
- msgid "No content tag found. Please insert the %content% tag in your template"
199
- msgstr "Geen inhoud tag gevonden. Plaats de %content% tag in je sjabloon"
200
-
201
- #: wpbe.php:181
202
- msgid "Please enter an email"
203
- msgstr "Vul een e-mailadres in"
204
-
205
- #: wpbe.php:183
206
- msgid "Please enter a valid email"
207
- msgstr "Vul een geldig e-mailadres in"
208
-
209
- #: wpbe.php:184
210
- msgid "Hey !"
211
- msgstr "Hey!"
212
-
213
- #: wpbe.php:186
214
- msgid "This is a sample email to test your template."
215
- msgstr "Dit is een voorbeeld e-mail om je sjabloon te testen."
216
-
217
- #: wpbe.php:188
218
- msgid "If you're not skilled in HTML/CSS email coding, I strongly recommend to leave the default template as it is. It has been tested on various and popular email clients like Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, and many more. "
219
- msgstr "Als je niet goed bent in HTML/CSS raad ik je sterk aan om het standaard sjabloon te laten zoals hij is. Het is getest op verschillende en populaire e-mailclients, zoals Gmail, Yahoo Mail, Hotmail / Live, Thunderbird, Apple Mail, Outlook, en nog veel meer."
220
-
221
- #: wpbe.php:190
222
- msgid "If you have any problem or any suggestions to improve this plugin, please let me know."
223
- msgstr "Als je problemen tegenkomt of suggesties hebt om deze plugin te verbeteren, laat het me weten."
224
-
225
- #: wpbe.php:192
226
- msgid "Email template preview"
227
- msgstr "E-mail sjabloon vooraf bekijken"
228
-
229
- #: wpbe.php:193
230
- msgid "An email preview has been successfully sent to "
231
- msgstr "E-mail voorbeeld succesvol verstuurd naar"
232
-
233
- #: wpbe.php:195
234
- msgid "An error occured while sending email. Please check your server configuration."
235
- msgstr "Er is een fout opgetreden bij het verzenden van de e-mail. Controleer de server configuratie."
236
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
langs/wp-better-emails.mo CHANGED
Binary file
langs/wp-better-emails.pot CHANGED
@@ -1,234 +1,195 @@
1
- # Translation of the WordPress plugin by .
2
- # Copyright (C) 2010
3
  # This file is distributed under the same license as the package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
5
- #
6
  msgid ""
7
  msgstr ""
8
- "Project-Id-Version: \n"
9
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-better-emails\n"
10
- "POT-Creation-Date: 2010-11-29 15:16+0000\n"
11
- "PO-Revision-Date: 2010-11-29 16:44+0100\n"
12
- "Last-Translator: Nicolas Lemoine <nico@yamoy.org>\n"
13
- "Language-Team: LANGUAGE <LL@li.org>\n"
14
  "MIME-Version: 1.0\n"
15
- "Content-Type: text/plain; charset=utf-8\n"
16
  "Content-Transfer-Encoding: 8bit\n"
17
-
18
- #: email_template.php:33
19
- msgid "Powered by Wordpress"
20
- msgstr "Propulsé par Wordpress"
21
-
22
- #: email_template.php:34
23
- msgid "Date"
24
- msgstr "Date"
25
-
26
- #: email_template.php:34
27
- msgid "Email sent the"
28
- msgstr "Email envoyé le"
29
-
30
- #: email_template.php:35
31
- msgid "Contact"
32
- msgstr "Contact"
33
-
34
- #: email_template.php:35
35
- msgid "For any request, please contact"
36
- msgstr "Pour toute demande, contactez"
37
 
38
  #: wpbe-options.php:2
39
- msgid "Email options"
40
- msgstr "Options email"
 
41
 
42
  #: wpbe-options.php:9
43
- msgid "Sender options"
44
- msgstr "Options envoyeur"
45
-
46
- #: wpbe-options.php:10
47
- msgid "Template options"
48
- msgstr "Options du modèle"
49
-
50
- #: wpbe-options.php:11
51
- msgid "Help & support"
52
- msgstr "Aide & support"
53
-
54
- #: wpbe-options.php:14
55
- msgid "Change the Wordpress default behavior when sending emails to users (i.e. comment notifications, lost password, etc.), set your own sender name and email address."
56
- msgstr "Modifiez le comportement par défaut de Wordpress lors de l'envoi d'emails aux utilisateurs (notifications, mot de passe perdu, etc.), configurez votre propre nom d'envoyeur et adresse email d'envoyeur."
57
-
58
- #: wpbe-options.php:17
59
- msgid "From name"
60
- msgstr "Nom"
61
 
62
- #: wpbe-options.php:17
63
- #: wpbe-options.php:21
64
- msgid "required"
65
- msgstr "requis"
66
 
67
- #: wpbe-options.php:21
68
- msgid "From email address"
69
- msgstr "Adresse email"
70
 
71
- #: wpbe-options.php:29
72
- msgid "Template variables"
73
- msgstr "Variables du modèle"
74
 
75
- #: wpbe-options.php:31
76
- msgid "Some dynamic tags can be included in your email template :"
77
- msgstr "Des tags dynamiques peuvent être utilisés dans votre modèle d'email :"
78
 
79
- #: wpbe-options.php:33
80
- msgid "<strong>%content%</strong> : will be replaced by the message content."
81
- msgstr "<strong>%content%</strong> : sera remplacé par le contenu du message."
82
 
83
- #: wpbe-options.php:34
84
- msgid "NOTE: The content tag is <strong>required</strong>, WP Better Emails will be automatically desactivated if no content tag is found."
85
- msgstr "NOTE: Le tag \"content\" est <strong>requis</strong>, WP Better Emails sera automatiquement désactivé si ce tag n'est pas trouvé dans le modèle."
86
 
87
  #: wpbe-options.php:35
88
- msgid "<strong>%blog_url%</strong> : will be replaced by your blog URL."
89
- msgstr "<strong>%blog_url%</strong> : sera remplacé par l'URL de votre blog."
90
 
91
- #: wpbe-options.php:36
92
- msgid "<strong>%blog_name%</strong> : will be replaced by your blog name."
93
- msgstr "<strong>%blog_name%</strong> : sera remplacé par le nom de votre blog."
94
 
95
- #: wpbe-options.php:37
96
- msgid "<strong>%blog_description%</strong> : will be replaced by your blog description."
97
  msgstr ""
98
 
99
- #: wpbe-options.php:38
100
- msgid "<strong>%admin_email%</strong> : will be replaced by admin email."
101
  msgstr ""
102
 
103
- #: wpbe-options.php:39
104
- msgid "<strong>%date%</strong> : will be replaced by current date, as formatted in <a href=\"options-general.php\">general options</a>."
105
  msgstr ""
106
 
107
- #: wpbe-options.php:40
108
- msgid "<strong>%time%</strong> : will be replaced by current time, as formatted in <a href=\"options-general.php\">general options</a>."
109
  msgstr ""
110
 
111
- #: wpbe-options.php:46
112
- msgid "HTML Template"
113
  msgstr ""
114
 
115
- #: wpbe-options.php:51
116
- msgid "Send an email preview to"
117
  msgstr ""
118
 
119
- #: wpbe-options.php:54
120
- msgid "Send"
121
  msgstr ""
122
 
123
- #: wpbe-options.php:56
124
- msgid "You must save your template before sending an email preview."
125
  msgstr ""
126
 
127
- #: wpbe-options.php:64
128
- msgid "Designing & coding email templates"
129
  msgstr ""
130
 
131
- #: wpbe-options.php:65
132
- msgid "Here are a few ressources about email formatting :"
133
  msgstr ""
134
 
135
- #: wpbe-options.php:67
136
- msgid "<a href=\"http://www.campaignmonitor.com/resources/\" target=\"_blank\">http://www.campaignmonitor.com/resources/</a>"
137
  msgstr ""
138
 
139
- #: wpbe-options.php:68
140
- msgid "<a href=\"http://articles.sitepoint.com/article/code-html-email-newsletters/\" target=\"_blank\">http://articles.sitepoint.com/article/code-html-email-newsletters/</a>"
141
  msgstr ""
142
 
143
- #: wpbe-options.php:70
144
- msgid "Converting HTML templates"
145
  msgstr ""
146
 
147
- #: wpbe-options.php:71
148
- msgid "Coding HTML for emails requires CSS styles to be inline. Here's a tool powered by MailChimp that will convert your styles placed in the <code>&lt;head&gt;</code> tag to inline : "
149
  msgstr ""
150
 
151
- #: wpbe-options.php:73
152
- msgid "<a href=\"http://www.mailchimp.com/labs/inlinecss.php\" target=\"_blank\">http://www.mailchimp.com/labs/inlinecss.php</a>"
153
  msgstr ""
154
 
155
- #: wpbe-options.php:75
156
- msgid "Requests & Bug report"
157
  msgstr ""
158
 
159
- #: wpbe-options.php:76
160
- msgid "If you have any idea to improve this plugin or any bug to report, please email me at : <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
161
  msgstr ""
162
 
163
- #: wpbe-options.php:77
164
- msgid "Credits"
165
  msgstr ""
166
 
167
- #: wpbe-options.php:79
168
- msgid "MarkItUp! : jQuery HTML editor <a href=\"http://markitup.jaysalvat.com/home/\" target=\"_blank\">http://markitup.jaysalvat.com/home/</a>"
169
  msgstr ""
170
 
171
- #: wpbe-options.php:84
172
- msgid "Save Changes"
173
  msgstr ""
174
 
175
- #: wpbe.php:47
176
- msgid "Settings"
177
  msgstr ""
178
 
179
- #: wpbe.php:64
180
- msgid "WP Better Emails requires WordPress 2.8 or newer."
181
  msgstr ""
182
 
183
- #: wpbe.php:149
184
- msgid "Please enter a sender email address."
185
  msgstr ""
186
 
187
- #: wpbe.php:152
188
- msgid "Please enter a valid sender email address."
189
  msgstr ""
190
 
191
- #: wpbe.php:162
192
- msgid "Template is empty"
193
  msgstr ""
194
 
195
- #: wpbe.php:165
196
- msgid "No content tag found. Please insert the %content% tag in your template"
197
  msgstr ""
198
 
199
- #: wpbe.php:181
200
- msgid "Please enter an email"
201
  msgstr ""
202
 
203
- #: wpbe.php:183
204
- msgid "Please enter a valid email"
205
  msgstr ""
206
 
207
- #: wpbe.php:184
208
- msgid "Hey !"
209
  msgstr ""
210
 
211
- #: wpbe.php:186
212
- msgid "This is a sample email to test your template."
213
  msgstr ""
214
 
215
- #: wpbe.php:188
216
- msgid "If you're not skilled in HTML/CSS email coding, I strongly recommend to leave the default template as it is. It has been tested on various and popular email clients like Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, and many more. "
217
  msgstr ""
218
 
219
- #: wpbe.php:190
220
- msgid "If you have any problem or any suggestions to improve this plugin, please let me know."
221
  msgstr ""
222
 
223
- #: wpbe.php:192
224
- msgid "Email template preview"
225
  msgstr ""
226
 
227
- #: wpbe.php:193
228
- msgid "An email preview has been successfully sent to "
229
  msgstr ""
230
 
231
- #: wpbe.php:195
232
- msgid "An error occured while sending email. Please check your server configuration."
233
  msgstr ""
234
 
1
+ # Copyright (C) 2010
 
2
  # This file is distributed under the same license as the package.
 
 
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WP Better Emails\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-better-emails\n"
7
+ "POT-Creation-Date: 2011-09-06 23:22:41+00:00\n"
 
 
 
8
  "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2011-09-12 17:37+0100\n"
12
+ "Last-Translator: \n"
13
+ "Language-Team: Team <plugins@artyshow-studio.fr>\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  #: wpbe-options.php:2
16
+ #: wpbe.php:158
17
+ msgid "Email settings"
18
+ msgstr ""
19
 
20
  #: wpbe-options.php:9
21
+ msgid "Set your own sender name and email address. Default Wordpress values will be used if empty."
22
+ msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ #: wpbe-options.php:12
25
+ msgid "Name"
26
+ msgstr ""
 
27
 
28
+ #: wpbe-options.php:16
29
+ msgid "Email address"
30
+ msgstr ""
31
 
32
+ #: wpbe-options.php:22
33
+ msgid "HTML Template"
34
+ msgstr ""
35
 
36
+ #: wpbe-options.php:24
37
+ msgid "Live template preview"
38
+ msgstr ""
39
 
40
+ #: wpbe-options.php:24
41
+ msgid "Live preview"
42
+ msgstr ""
43
 
44
+ #: wpbe-options.php:26
45
+ msgid "Edit the HTML email template if you want to customize it. You might have a look at <a href="#" id="wpbe_help">help tab</a> for further information."
46
+ msgstr ""
47
 
48
  #: wpbe-options.php:35
49
+ msgid "Send an email preview to"
50
+ msgstr ""
51
 
52
+ #: wpbe-options.php:39
53
+ msgid "Send"
54
+ msgstr ""
55
 
56
+ #: wpbe-options.php:41
57
+ msgid "You must save your template before sending an email preview."
58
  msgstr ""
59
 
60
+ #: wpbe-options.php:46
61
+ msgid "Save Changes"
62
  msgstr ""
63
 
64
+ #: wpbe-options.php:52
65
+ msgid "Support & bug report"
66
  msgstr ""
67
 
68
+ #: wpbe-options.php:53
69
+ msgid "If you have any idea to improve this plugin or any bug to report, please email me at : <a href=\"mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]\">plugins@artyshow-studio.fr</a>"
70
  msgstr ""
71
 
72
+ #: wpbe-options.php:55
73
+ msgid "You like this plugin ? You use it in a business context ? Please, consider a <a href=\"%s\" target=\"_blank\" rel=\"external\">donation</a>."
74
  msgstr ""
75
 
76
+ #: templates/template-1.php:33
77
+ msgid "Date"
78
  msgstr ""
79
 
80
+ #: templates/template-1.php:33
81
+ msgid "Email sent"
82
  msgstr ""
83
 
84
+ #: templates/template-1.php:34
85
+ msgid "Contact"
86
  msgstr ""
87
 
88
+ #: templates/template-1.php:34
89
+ msgid "For any requests, please contact"
90
  msgstr ""
91
 
92
+ #: wpbe.php:131
93
+ msgid "Settings"
94
  msgstr ""
95
 
96
+ #: wpbe.php:147
97
+ msgid "WP Better Emails requires WordPress 2.8 or newer."
98
  msgstr ""
99
 
100
+ #: wpbe.php:147
101
+ msgid "Upgrade your Wordpress installation."
102
  msgstr ""
103
 
104
+ #: wpbe.php:158
105
+ msgid "WP Better Emails"
106
  msgstr ""
107
 
108
+ #: wpbe.php:228
109
+ msgid "Please enter a valid sender email address."
110
  msgstr ""
111
 
112
+ #: wpbe.php:238
113
+ msgid "Template is empty"
114
  msgstr ""
115
 
116
+ #: wpbe.php:241
117
+ msgid "No content tag found. The %content% tag is required in your template"
118
  msgstr ""
119
 
120
+ #: wpbe.php:259
121
+ msgid "Please enter an email"
122
  msgstr ""
123
 
124
+ #: wpbe.php:261
125
+ msgid "Please enter a valid email"
126
  msgstr ""
127
 
128
+ #: wpbe.php:262
129
+ msgid "Hey !"
130
  msgstr ""
131
 
132
+ #: wpbe.php:264
133
+ msgid "This is a sample email to test your HTML template."
134
  msgstr ""
135
 
136
+ #: wpbe.php:266
137
+ msgid "If you're not skilled in HTML/CSS email coding, I strongly recommend to leave the default template as it is. It has been tested on various and popular email clients like Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, and many more."
138
  msgstr ""
139
 
140
+ #: wpbe.php:268
141
+ msgid "If you have any problems or any suggestions to improve this plugin, please let me know."
142
  msgstr ""
143
 
144
+ #: wpbe.php:269
145
+ msgid "Email template preview"
146
  msgstr ""
147
 
148
+ #: wpbe.php:270
149
+ msgid "An email preview has been successfully sent to %s"
150
  msgstr ""
151
 
152
+ #: wpbe.php:273
153
+ msgid "An error occured while sending email. Please check your server configuration."
154
  msgstr ""
155
 
156
+ #: wpbe.php:410
157
+ msgid "Some dynamic tags can be included in your email template :"
158
  msgstr ""
159
 
160
+ #: wpbe.php:412
161
+ msgid "<strong>%content%</strong> : will be replaced with the message content."
162
  msgstr ""
163
 
164
+ #: wpbe.php:413
165
+ msgid "NOTE: The content tag is <strong>required</strong>, WP Better Emails will be automatically desactivated if no content tag is found."
166
  msgstr ""
167
 
168
+ #: wpbe.php:414
169
+ msgid "<strong>%blog_url%</strong> : will be replaced with your blog URL."
170
  msgstr ""
171
 
172
+ #: wpbe.php:415
173
+ msgid "<strong>%home_url%</strong> : will be replaced with your home URL."
174
  msgstr ""
175
 
176
+ #: wpbe.php:416
177
+ msgid "<strong>%blog_name%</strong> : will be replaced with your blog name."
178
  msgstr ""
179
 
180
+ #: wpbe.php:417
181
+ msgid "<strong>%blog_description%</strong> : will be replaced with your blog description."
182
  msgstr ""
183
 
184
+ #: wpbe.php:418
185
+ msgid "<strong>%admin_email%</strong> : will be replaced with admin email."
186
  msgstr ""
187
 
188
+ #: wpbe.php:419
189
+ msgid "<strong>%date%</strong> : will be replaced with current date, as formatted in <a href=\"options-general.php\">general options</a>."
190
  msgstr ""
191
 
192
+ #: wpbe.php:420
193
+ msgid "<strong>%time%</strong> : will be replaced with current time, as formatted in <a href=\"options-general.php\">general options</a>."
194
  msgstr ""
195
 
markitup/jquery.markitup.js DELETED
@@ -1,565 +0,0 @@
1
- // ----------------------------------------------------------------------------
2
- // markItUp! Universal MarkUp Engine, JQuery plugin
3
- // v 1.1.x
4
- // Dual licensed under the MIT and GPL licenses.
5
- // ----------------------------------------------------------------------------
6
- // Copyright (C) 2007-2010 Jay Salvat
7
- // http://markitup.jaysalvat.com/
8
- // ----------------------------------------------------------------------------
9
- // Permission is hereby granted, free of charge, to any person obtaining a copy
10
- // of this software and associated documentation files (the "Software"), to deal
11
- // in the Software without restriction, including without limitation the rights
12
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
- // copies of the Software, and to permit persons to whom the Software is
14
- // furnished to do so, subject to the following conditions:
15
- //
16
- // The above copyright notice and this permission notice shall be included in
17
- // all copies or substantial portions of the Software.
18
- //
19
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
- // THE SOFTWARE.
26
- // ----------------------------------------------------------------------------
27
-
28
- (function($) {
29
- $.fn.markItUp = function(settings, extraSettings) {
30
- var options, ctrlKey, shiftKey, altKey;
31
- ctrlKey = shiftKey = altKey = false;
32
-
33
- options = { id: '',
34
- nameSpace: '',
35
- root: '',
36
- previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes'
37
- previewAutoRefresh: true,
38
- previewPosition: 'before',
39
- previewTemplatePath: '~/templates/preview.html',
40
- previewParserPath: '',
41
- previewParserVar: 'data',
42
- resizeHandle: true,
43
- beforeInsert: '',
44
- afterInsert: '',
45
- onEnter: {},
46
- onShiftEnter: {},
47
- onCtrlEnter: {},
48
- onTab: {},
49
- markupSet: [ { /* set */ } ]
50
- };
51
- $.extend(options, settings, extraSettings);
52
-
53
- // compute markItUp! path
54
- if (!options.root) {
55
- $('script').each(function(a, tag) {
56
- miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/);
57
- if (miuScript !== null) {
58
- options.root = miuScript[1];
59
- }
60
- });
61
- }
62
-
63
- return this.each(function() {
64
- var $$, textarea, levels, scrollPosition, caretPosition, caretOffset,
65
- clicked, hash, header, footer, previewWindow, template, iFrame, abort;
66
- $$ = $(this);
67
- textarea = this;
68
- levels = [];
69
- abort = false;
70
- scrollPosition = caretPosition = 0;
71
- caretOffset = -1;
72
-
73
- options.previewParserPath = localize(options.previewParserPath);
74
- options.previewTemplatePath = localize(options.previewTemplatePath);
75
-
76
- // apply the computed path to ~/
77
- function localize(data, inText) {
78
- if (inText) {
79
- return data.replace(/("|')~\//g, "$1"+options.root);
80
- }
81
- return data.replace(/^~\//, options.root);
82
- }
83
-
84
- // init and build editor
85
- function init() {
86
- id = ''; nameSpace = '';
87
- if (options.id) {
88
- id = 'id="'+options.id+'"';
89
- } else if ($$.attr("id")) {
90
- id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"';
91
-
92
- }
93
- if (options.nameSpace) {
94
- nameSpace = 'class="'+options.nameSpace+'"';
95
- }
96
- $$.wrap('<div '+nameSpace+'></div>');
97
- $$.wrap('<div '+id+' class="markItUp"></div>');
98
- $$.wrap('<div class="markItUpContainer"></div>');
99
- $$.addClass("markItUpEditor");
100
-
101
- // add the header before the textarea
102
- header = $('<div class="markItUpHeader"></div>').insertBefore($$);
103
- $(dropMenus(options.markupSet)).appendTo(header);
104
-
105
- // add the footer after the textarea
106
- footer = $('<div class="markItUpFooter"></div>').insertAfter($$);
107
-
108
- // add the resize handle after textarea
109
- if (options.resizeHandle === true && $.browser.safari !== true) {
110
- resizeHandle = $('<div class="markItUpResizeHandle"></div>')
111
- .insertAfter($$)
112
- .bind("mousedown", function(e) {
113
- var h = $$.height(), y = e.clientY, mouseMove, mouseUp;
114
- mouseMove = function(e) {
115
- $$.css("height", Math.max(20, e.clientY+h-y)+"px");
116
- return false;
117
- };
118
- mouseUp = function(e) {
119
- $("html").unbind("mousemove", mouseMove).unbind("mouseup", mouseUp);
120
- return false;
121
- };
122
- $("html").bind("mousemove", mouseMove).bind("mouseup", mouseUp);
123
- });
124
- footer.append(resizeHandle);
125
- }
126
-
127
- // listen key events
128
- $$.keydown(keyPressed).keyup(keyPressed);
129
-
130
- // bind an event to catch external calls
131
- $$.bind("insertion", function(e, settings) {
132
- if (settings.target !== false) {
133
- get();
134
- }
135
- if (textarea === $.markItUp.focused) {
136
- markup(settings);
137
- }
138
- });
139
-
140
- // remember the last focus
141
- $$.focus(function() {
142
- $.markItUp.focused = this;
143
- });
144
- }
145
-
146
- // recursively build header with dropMenus from markupset
147
- function dropMenus(markupSet) {
148
- var ul = $('<ul></ul>'), i = 0;
149
- $('li:hover > ul', ul).css('display', 'block');
150
- $.each(markupSet, function() {
151
- var button = this, t = '', title, li, j;
152
- title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||'');
153
- key = (button.key) ? 'accesskey="'+button.key+'"' : '';
154
- if (button.separator) {
155
- li = $('<li class="markItUpSeparator">'+(button.separator||'')+'</li>').appendTo(ul);
156
- } else {
157
- i++;
158
- for (j = levels.length -1; j >= 0; j--) {
159
- t += levels[j]+"-";
160
- }
161
- li = $('<li class="markItUpButton markItUpButton'+t+(i)+' '+(button.className||'')+'"><a href="" '+key+' title="'+title+'">'+(button.name||'')+'</a></li>')
162
- .bind("contextmenu", function() { // prevent contextmenu on mac and allow ctrl+click
163
- return false;
164
- }).click(function() {
165
- return false;
166
- }).bind("focusin", function(){
167
- $$.focus();
168
- }).mousedown(function() {
169
- if (button.call) {
170
- eval(button.call)();
171
- }
172
- setTimeout(function() { markup(button) },1);
173
- return false;
174
- }).hover(function() {
175
- $('> ul', this).show();
176
- $(document).one('click', function() { // close dropmenu if click outside
177
- $('ul ul', header).hide();
178
- }
179
- );
180
- }, function() {
181
- $('> ul', this).hide();
182
- }
183
- ).appendTo(ul);
184
- if (button.dropMenu) {
185
- levels.push(i);
186
- $(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu));
187
- }
188
- }
189
- });
190
- levels.pop();
191
- return ul;
192
- }
193
-
194
- // markItUp! markups
195
- function magicMarkups(string) {
196
- if (string) {
197
- string = string.toString();
198
- string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g,
199
- function(x, a) {
200
- var b = a.split('|!|');
201
- if (altKey === true) {
202
- return (b[1] !== undefined) ? b[1] : b[0];
203
- } else {
204
- return (b[1] === undefined) ? "" : b[0];
205
- }
206
- }
207
- );
208
- // [![prompt]!], [![prompt:!:value]!]
209
- string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g,
210
- function(x, a) {
211
- var b = a.split(':!:');
212
- if (abort === true) {
213
- return false;
214
- }
215
- value = prompt(b[0], (b[1]) ? b[1] : '');
216
- if (value === null) {
217
- abort = true;
218
- }
219
- return value;
220
- }
221
- );
222
- return string;
223
- }
224
- return "";
225
- }
226
-
227
- // prepare action
228
- function prepare(action) {
229
- if ($.isFunction(action)) {
230
- action = action(hash);
231
- }
232
- return magicMarkups(action);
233
- }
234
-
235
- // build block to insert
236
- function build(string) {
237
- openWith = prepare(clicked.openWith);
238
- placeHolder = prepare(clicked.placeHolder);
239
- replaceWith = prepare(clicked.replaceWith);
240
- closeWith = prepare(clicked.closeWith);
241
- if (replaceWith !== "") {
242
- block = openWith + replaceWith + closeWith;
243
- } else if (selection === '' && placeHolder !== '') {
244
- block = openWith + placeHolder + closeWith;
245
- } else {
246
- block = openWith + (string||selection) + closeWith;
247
- }
248
- return { block:block,
249
- openWith:openWith,
250
- replaceWith:replaceWith,
251
- placeHolder:placeHolder,
252
- closeWith:closeWith
253
- };
254
- }
255
-
256
- // define markup to insert
257
- function markup(button) {
258
- var len, j, n, i;
259
- hash = clicked = button;
260
- get();
261
-
262
- $.extend(hash, { line:"",
263
- root:options.root,
264
- textarea:textarea,
265
- selection:(selection||''),
266
- caretPosition:caretPosition,
267
- ctrlKey:ctrlKey,
268
- shiftKey:shiftKey,
269
- altKey:altKey
270
- }
271
- );
272
- // callbacks before insertion
273
- prepare(options.beforeInsert);
274
- prepare(clicked.beforeInsert);
275
- if (ctrlKey === true && shiftKey === true) {
276
- prepare(clicked.beforeMultiInsert);
277
- }
278
- $.extend(hash, { line:1 });
279
-
280
- if (ctrlKey === true && shiftKey === true) {
281
- lines = selection.split(/\r?\n/);
282
- for (j = 0, n = lines.length, i = 0; i < n; i++) {
283
- if ($.trim(lines[i]) !== '') {
284
- $.extend(hash, { line:++j, selection:lines[i] } );
285
- lines[i] = build(lines[i]).block;
286
- } else {
287
- lines[i] = "";
288
- }
289
- }
290
- string = { block:lines.join('\n')};
291
- start = caretPosition;
292
- len = string.block.length + (($.browser.opera) ? n-1 : 0);
293
- } else if (ctrlKey === true) {
294
- string = build(selection);
295
- start = caretPosition + string.openWith.length;
296
- len = string.block.length - string.openWith.length - string.closeWith.length;
297
- len -= fixIeBug(string.block);
298
- } else if (shiftKey === true) {
299
- string = build(selection);
300
- start = caretPosition;
301
- len = string.block.length;
302
- len -= fixIeBug(string.block);
303
- } else {
304
- string = build(selection);
305
- start = caretPosition + string.block.length ;
306
- len = 0;
307
- start -= fixIeBug(string.block);
308
- }
309
- if ((selection === '' && string.replaceWith === '')) {
310
- caretOffset += fixOperaBug(string.block);
311
-
312
- start = caretPosition + string.openWith.length;
313
- len = string.block.length - string.openWith.length - string.closeWith.length;
314
-
315
- caretOffset = $$.val().substring(caretPosition, $$.val().length).length;
316
- caretOffset -= fixOperaBug($$.val().substring(0, caretPosition));
317
- }
318
- $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } );
319
-
320
- if (string.block !== selection && abort === false) {
321
- insert(string.block);
322
- set(start, len);
323
- } else {
324
- caretOffset = -1;
325
- }
326
- get();
327
-
328
- $.extend(hash, { line:'', selection:selection });
329
-
330
- // callbacks after insertion
331
- if (ctrlKey === true && shiftKey === true) {
332
- prepare(clicked.afterMultiInsert);
333
- }
334
- prepare(clicked.afterInsert);
335
- prepare(options.afterInsert);
336
-
337
- // refresh preview if opened
338
- if (previewWindow && options.previewAutoRefresh) {
339
- refreshPreview();
340
- }
341
-
342
- // reinit keyevent
343
- shiftKey = altKey = ctrlKey = abort = false;
344
- }
345
-
346
- // Substract linefeed in Opera
347
- function fixOperaBug(string) {
348
- if ($.browser.opera) {
349
- return string.length - string.replace(/\n*/g, '').length;
350
- }
351
- return 0;
352
- }
353
- // Substract linefeed in IE
354
- function fixIeBug(string) {
355
- if ($.browser.msie) {
356
- return string.length - string.replace(/\r/g, '').length;
357
- }
358
- return 0;
359
- }
360
-
361
- // add markup
362
- function insert(block) {
363
- if (document.selection) {
364
- var newSelection = document.selection.createRange();
365
- newSelection.text = block;
366
- } else {
367
- textarea.value = textarea.value.substring(0, caretPosition) + block + textarea.value.substring(caretPosition + selection.length, textarea.value.length);
368
- }
369
- }
370
-
371
- // set a selection
372
- function set(start, len) {
373
- if (textarea.createTextRange){
374
- // quick fix to make it work on Opera 9.5
375
- if ($.browser.opera && $.browser.version >= 9.5 && len == 0) {
376
- return false;
377
- }
378
- range = textarea.createTextRange();
379
- range.collapse(true);
380
- range.moveStart('character', start);
381
- range.moveEnd('character', len);
382
- range.select();
383
- } else if (textarea.setSelectionRange ){
384
- textarea.setSelectionRange(start, start + len);
385
- }
386
- textarea.scrollTop = scrollPosition;
387
- textarea.focus();
388
- }
389
-
390
- // get the selection
391
- function get() {
392
- textarea.focus();
393
-
394
- scrollPosition = textarea.scrollTop;
395
- if (document.selection) {
396
- selection = document.selection;
397
- if ($.browser.msie) { // ie
398
- var range = selection.createRange();
399
- var stored_range = range.duplicate();
400
- stored_range.moveToElementText(textarea);
401
- stored_range.setEndPoint('EndToEnd', range);
402
- var s = stored_range.text.length - range.text.length;
403
-
404
- caretPosition = s - (textarea.value.substr(0, s).length - textarea.value.substr(0, s).replace(/\r/g, '').length);
405
- selection = range.text;
406
- } else { // opera
407
- caretPosition = textarea.selectionStart;
408
- }
409
- } else { // gecko & webkit
410
- caretPosition = textarea.selectionStart;
411
- selection = textarea.value.substring(caretPosition, textarea.selectionEnd);
412
- }
413
- return selection;
414
- }
415
-
416
- // open preview window
417
- function preview() {
418
- if (!previewWindow || previewWindow.closed) {
419
- if (options.previewInWindow) {
420
- previewWindow = window.open('', 'preview', options.previewInWindow);
421
- $(window).unload(function() {
422
- previewWindow.close();
423
- });
424
- } else {
425
- iFrame = $('<iframe class="markItUpPreviewFrame"></iframe>');
426
- if (options.previewPosition == 'after') {
427
- iFrame.insertAfter(footer);
428
- } else {
429
- iFrame.insertBefore(header);
430
- }
431
- previewWindow = iFrame[iFrame.length - 1].contentWindow || frame[iFrame.length - 1];
432
- }
433
- } else if (altKey === true) {
434
- if (iFrame) {
435
- iFrame.remove();
436
- } else {
437
- previewWindow.close();
438
- }
439
- previewWindow = iFrame = false;
440
- }
441
- if (!options.previewAutoRefresh) {
442
- refreshPreview();
443
- }
444
- if (options.previewInWindow) {
445
- previewWindow.focus();
446
- }
447
- }
448
-
449
- // refresh Preview window
450
- function refreshPreview() {
451
- renderPreview();
452
- }
453
-
454
- function renderPreview() {
455
- var phtml;
456
- if (options.previewParserPath !== '') {
457
- $.ajax( {
458
- type: 'POST',
459
- url: options.previewParserPath,
460
- data: options.previewParserVar+'='+encodeURIComponent($$.val()),
461
- success: function(data) {
462
- writeInPreview( localize(data, 1) );
463
- }
464
- } );
465
- } else {
466
- if (!template) {
467
- $.ajax( {
468
- url: options.previewTemplatePath,
469
- success: function(data) {
470
- writeInPreview( localize(data, 1).replace(/<!-- content -->/g, $$.val()) );
471
- }
472
- } );
473
- }
474
- }
475
- return false;
476
- }
477
-
478
- function writeInPreview(data) {
479
- if (previewWindow.document) {
480
- try {
481
- sp = previewWindow.document.documentElement.scrollTop
482
- } catch(e) {
483
- sp = 0;
484
- }
485
- previewWindow.document.open();
486
- previewWindow.document.write(data);
487
- previewWindow.document.close();
488
- previewWindow.document.documentElement.scrollTop = sp;
489
- }
490
- }
491
-
492
- // set keys pressed
493
- function keyPressed(e) {
494
- shiftKey = e.shiftKey;
495
- altKey = e.altKey;
496
- ctrlKey = (!(e.altKey && e.ctrlKey)) ? e.ctrlKey : false;
497
-
498
- if (e.type === 'keydown') {
499
- if (ctrlKey === true) {
500
- li = $("a[accesskey="+String.fromCharCode(e.keyCode)+"]", header).parent('li');
501
- if (li.length !== 0) {
502
- ctrlKey = false;
503
- setTimeout(function() {
504
- li.triggerHandler('mousedown');
505
- },1);
506
- return false;
507
- }
508
- }
509
- if (e.keyCode === 13 || e.keyCode === 10) { // Enter key
510
- if (ctrlKey === true) { // Enter + Ctrl
511
- ctrlKey = false;
512
- markup(options.onCtrlEnter);
513
- return options.onCtrlEnter.keepDefault;
514
- } else if (shiftKey === true) { // Enter + Shift
515
- shiftKey = false;
516
- markup(options.onShiftEnter);
517
- return options.onShiftEnter.keepDefault;
518
- } else { // only Enter
519
- markup(options.onEnter);
520
- return options.onEnter.keepDefault;
521
- }
522
- }
523
- if (e.keyCode === 9) { // Tab key
524
- if (shiftKey == true || ctrlKey == true || altKey == true) {
525
- return false;
526
- }
527
- if (caretOffset !== -1) {
528
- get();
529
- caretOffset = $$.val().length - caretOffset;
530
- set(caretOffset, 0);
531
- caretOffset = -1;
532
- return false;
533
- } else {
534
- markup(options.onTab);
535
- return options.onTab.keepDefault;
536
- }
537
- }
538
- }
539
- }
540
-
541
- init();
542
- });
543
- };
544
-
545
- $.fn.markItUpRemove = function() {
546
- return this.each(function() {
547
- var $$ = $(this).unbind().removeClass('markItUpEditor');
548
- $$.parent('div').parent('div.markItUp').parent('div').replaceWith($$);
549
- }
550
- );
551
- };
552
-
553
- $.markItUp = function(settings) {
554
- var options = { target:false };
555
- $.extend(options, settings);
556
- if (options.target) {
557
- return $(options.target).each(function() {
558
- $(this).focus();
559
- $(this).trigger('insertion', [options]);
560
- });
561
- } else {
562
- $('textarea').trigger('insertion', [options]);
563
- }
564
- };
565
- })(jQuery);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
markitup/sets/html/images/bold.png DELETED
Binary file
markitup/sets/html/images/clean.png DELETED
Binary file
markitup/sets/html/images/h1.png DELETED
Binary file
markitup/sets/html/images/h2.png DELETED
Binary file
markitup/sets/html/images/h3.png DELETED
Binary file
markitup/sets/html/images/h4.png DELETED
Binary file
markitup/sets/html/images/h5.png DELETED
Binary file
markitup/sets/html/images/h6.png DELETED
Binary file
markitup/sets/html/images/image.png DELETED
Binary file
markitup/sets/html/images/italic.png DELETED
Binary file
markitup/sets/html/images/link.png DELETED
Binary file
markitup/sets/html/images/list-bullet.png DELETED
Binary file
markitup/sets/html/images/list-item.png DELETED
Binary file
markitup/sets/html/images/list-numeric.png DELETED
Binary file
markitup/sets/html/images/paragraph.png DELETED
Binary file
markitup/sets/html/images/picture.png DELETED
Binary file
markitup/sets/html/images/preview.png DELETED
Binary file
markitup/sets/html/images/stroke.png DELETED
Binary file
markitup/sets/html/readme.txt DELETED
@@ -1,11 +0,0 @@
1
- Markup language:
2
- Html
3
-
4
- Description:
5
- A basic Html markup set with Headings, Paragraph, Bold, Italic, Stroke through, Picture, Link, List, Clean button, Preview button.
6
-
7
- Install:
8
- - Download the zip file
9
- - Unzip it in your markItUp! sets folder
10
- - Modify your JS link to point at this set.js
11
- - Modify your CSS link to point at this style.css
 
 
 
 
 
 
 
 
 
 
 
markitup/sets/html/set.js DELETED
@@ -1,39 +0,0 @@
1
- // ----------------------------------------------------------------------------
2
- // markItUp!
3
- // ----------------------------------------------------------------------------
4
- // Copyright (C) 2008 Jay Salvat
5
- // http://markitup.jaysalvat.com/
6
- // ----------------------------------------------------------------------------
7
- // Html tags
8
- // http://en.wikipedia.org/wiki/html
9
- // ----------------------------------------------------------------------------
10
- // Basic set. Feel free to add more tags
11
- // ----------------------------------------------------------------------------
12
- mySettings = {
13
- onShiftEnter: {keepDefault:false, replaceWith:'<br />\n'},
14
- onCtrlEnter: {keepDefault:false, openWith:'\n<p>', closeWith:'</p>\n'},
15
- onTab: {keepDefault:false, openWith:' '},
16
- markupSet: [
17
- {name:'Heading 1', key:'1', openWith:'<h1(!( class="[![Class]!]")!)>', closeWith:'</h1>', placeHolder:'Your title here...' },
18
- {name:'Heading 2', key:'2', openWith:'<h2(!( class="[![Class]!]")!)>', closeWith:'</h2>', placeHolder:'Your title here...' },
19
- {name:'Heading 3', key:'3', openWith:'<h3(!( class="[![Class]!]")!)>', closeWith:'</h3>', placeHolder:'Your title here...' },
20
- {name:'Heading 4', key:'4', openWith:'<h4(!( class="[![Class]!]")!)>', closeWith:'</h4>', placeHolder:'Your title here...' },
21
- {name:'Heading 5', key:'5', openWith:'<h5(!( class="[![Class]!]")!)>', closeWith:'</h5>', placeHolder:'Your title here...' },
22
- {name:'Heading 6', key:'6', openWith:'<h6(!( class="[![Class]!]")!)>', closeWith:'</h6>', placeHolder:'Your title here...' },
23
- {name:'Paragraph', openWith:'<p(!( class="[![Class]!]")!)>', closeWith:'</p>' },
24
- {separator:'---------------' },
25
- {name:'Bold', key:'B', openWith:'(!(<strong>|!|<b>)!)', closeWith:'(!(</strong>|!|</b>)!)' },
26
- {name:'Italic', key:'I', openWith:'(!(<em>|!|<i>)!)', closeWith:'(!(</em>|!|</i>)!)' },
27
- {name:'Stroke through', key:'S', openWith:'<del>', closeWith:'</del>' },
28
- {separator:'---------------' },
29
- {name:'Ul', openWith:'<ul>\n', closeWith:'</ul>\n' },
30
- {name:'Ol', openWith:'<ol>\n', closeWith:'</ol>\n' },
31
- {name:'Li', openWith:'<li>', closeWith:'</li>' },
32
- {separator:'---------------' },
33
- {name:'Picture', key:'P', replaceWith:'<img src="[![Source:!:http://]!]" alt="[![Alternative text]!]" />' },
34
- {name:'Link', key:'L', openWith:'<a href="[![Link:!:http://]!]"(!( title="[![Title]!]")!)>', closeWith:'</a>', placeHolder:'Your text to link...' },
35
- {separator:'---------------' },
36
- {name:'Clean', className:'clean', replaceWith:function(markitup) { return markitup.selection.replace(/<(.*?)>/g, "") } },
37
- {name:'Preview', className:'preview', call:'preview' }
38
- ]
39
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
markitup/sets/html/style.css DELETED
@@ -1,59 +0,0 @@
1
- /* -------------------------------------------------------------------
2
- // markItUp!
3
- // By Jay Salvat - http://markitup.jaysalvat.com/
4
- // ------------------------------------------------------------------*/
5
- .markItUp .markItUpButton1 a {
6
- background-image:url(images/h1.png);
7
- }
8
- .markItUp .markItUpButton2 a {
9
- background-image:url(images/h2.png);
10
- }
11
- .markItUp .markItUpButton3 a {
12
- background-image:url(images/h3.png);
13
- }
14
- .markItUp .markItUpButton4 a {
15
- background-image:url(images/h4.png);
16
- }
17
- .markItUp .markItUpButton5 a {
18
- background-image:url(images/h5.png);
19
- }
20
- .markItUp .markItUpButton6 a {
21
- background-image:url(images/h6.png);
22
- }
23
- .markItUp .markItUpButton7 a {
24
- background-image:url(images/paragraph.png);
25
- }
26
-
27
- .markItUp .markItUpButton8 a {
28
- background-image:url(images/bold.png);
29
- }
30
- .markItUp .markItUpButton9 a {
31
- background-image:url(images/italic.png);
32
- }
33
- .markItUp .markItUpButton10 a {
34
- background-image:url(images/stroke.png);
35
- }
36
-
37
- .markItUp .markItUpButton11 a {
38
- background-image:url(images/list-bullet.png);
39
- }
40
- .markItUp .markItUpButton12 a {
41
- background-image:url(images/list-numeric.png);
42
- }
43
- .markItUp .markItUpButton13 a {
44
- background-image:url(images/list-item.png);
45
- }
46
-
47
- .markItUp .markItUpButton14 a {
48
- background-image:url(images/picture.png);
49
- }
50
- .markItUp .markItUpButton15 a {
51
- background-image:url(images/link.png);
52
- }
53
-
54
- .markItUp .clean a {
55
- background-image:url(images/clean.png);
56
- }
57
- .markItUp .preview a {
58
- background-image:url(images/preview.png);
59
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
markitup/skins/markitup/images/bg-container.png DELETED
Binary file
markitup/skins/markitup/images/bg-editor-bbcode.png DELETED
Binary file
markitup/skins/markitup/images/bg-editor-dotclear.png DELETED
Binary file
markitup/skins/markitup/images/bg-editor-html.png DELETED
Binary file
markitup/skins/markitup/images/bg-editor-json.png DELETED
Binary file
markitup/skins/markitup/images/bg-editor-markdown.png DELETED
Binary file
markitup/skins/markitup/images/bg-editor-textile.png DELETED
Binary file
markitup/skins/markitup/images/bg-editor-wiki.png DELETED
Binary file
markitup/skins/markitup/images/bg-editor-xml.png DELETED
Binary file
markitup/skins/markitup/images/bg-editor.png DELETED
Binary file
markitup/skins/markitup/images/handle.png DELETED
Binary file
markitup/skins/markitup/images/menu.png DELETED
Binary file
markitup/skins/markitup/images/submenu.png DELETED
Binary file
markitup/skins/markitup/style.css DELETED
@@ -1,147 +0,0 @@
1
- /* -------------------------------------------------------------------
2
- // markItUp! Universal MarkUp Engine, JQuery plugin
3
- // By Jay Salvat - http://markitup.jaysalvat.com/
4
- // ------------------------------------------------------------------*/
5
- .markItUp * {
6
- margin:0px; padding:0px;
7
- outline:none;
8
- }
9
- .markItUp a:link,
10
- .markItUp a:visited {
11
- color:#000;
12
- text-decoration:none;
13
- }
14
- .markItUp {
15
- width:700px;
16
- margin:5px 0 5px 0;
17
- border:5px solid #F5F5F5;
18
- }
19
- .markItUpContainer {
20
- border:1px solid #3C769D;
21
- background:#FFF url(images/bg-container.png) repeat-x top left;
22
- padding:5px 5px 2px 5px;
23
- font:11px Verdana, Arial, Helvetica, sans-serif;
24
- }
25
- .markItUpEditor {
26
- font:12px 'Courier New', Courier, monospace;
27
- padding:5px 5px 5px 35px;
28
- border:3px solid #3C769D;
29
- width:643px;
30
- height:320px;
31
- background:#FFF url(images/bg-editor.png) no-repeat;
32
- clear:both;
33
- line-height:18px;
34
- overflow:auto;
35
- }
36
- .markItUpPreviewFrame {
37
- overflow:auto;
38
- background-color:#FFFFFF;
39
- border:1px solid #3C769D;
40
- width:99.9%;
41
- height:300px;
42
- margin:5px 0;
43
- }
44
- .markItUpFooter {
45
- width:100%;
46
- cursor:n-resize;
47
- }
48
- .markItUpResizeHandle {
49
- overflow:hidden;
50
- width:22px; height:5px;
51
- margin-left:auto;
52
- margin-right:auto;
53
- background-image:url(images/handle.png);
54
- cursor:n-resize;
55
- }
56
- /***************************************************************************************/
57
- /* first row of buttons */
58
- .markItUpHeader ul li {
59
- list-style:none;
60
- float:left;
61
- position:relative;
62
- }
63
- .markItUpHeader ul li ul{
64
- display:none;
65
- }
66
- .markItUpHeader ul li:hover > ul{
67
- display:block;
68
- }
69
- .markItUpHeader ul .markItUpDropMenu {
70
- background:transparent url(images/menu.png) no-repeat 115% 50%;
71
- margin-right:5px;
72
- }
73
- .markItUpHeader ul .markItUpDropMenu li {
74
- margin-right:0px;
75
- }
76
- .markItUpHeader ul .markItUpSeparator {
77
- margin:0 10px;
78
- width:1px;
79
- height:16px;
80
- overflow:hidden;
81
- background-color:#CCC;
82
- }
83
- .markItUpHeader ul ul .markItUpSeparator {
84
- width:auto; height:1px;
85
- margin:0px;
86
- }
87
- /* next rows of buttons */
88
- .markItUpHeader ul ul {
89
- display:none;
90
- position:absolute;
91
- top:18px; left:0px;
92
- background:#F5F5F5;
93
- border:1px solid #3C769D;
94
- height:inherit;
95
- }
96
- .markItUpHeader ul ul li {
97
- float:none;
98
- border-bottom:1px solid #3C769D;
99
- }
100
- .markItUpHeader ul ul .markItUpDropMenu {
101
- background:#F5F5F5 url(images/submenu.png) no-repeat 100% 50%;
102
- }
103
- /* next rows of buttons */
104
- .markItUpHeader ul ul ul {
105
- position:absolute;
106
- top:-1px; left:150px;
107
- }
108
- .markItUpHeader ul ul ul li {
109
- float:none;
110
- }
111
- .markItUpHeader ul a {
112
- display:block;
113
- width:16px; height:16px;
114
- text-indent:-10000px;
115
- background-repeat:no-repeat;
116
- padding:3px;
117
- margin:0px;
118
- }
119
- .markItUpHeader ul ul a {
120
- display:block;
121
- padding-left:0px;
122
- text-indent:0;
123
- width:120px;
124
- padding:5px 5px 5px 25px;
125
- background-position:2px 50%;
126
- }
127
- .markItUpHeader ul ul a:hover {
128
- color:#FFF;
129
- background-color:#3C769D;
130
- }
131
- /***************************************************************************************/
132
- .html .markItUpEditor {
133
- background-image:url(images/bg-editor-html.png);
134
- }
135
- .markdown .markItUpEditor {
136
- background-image:url(images/bg-editor-markdown.png);
137
- }
138
- .textile .markItUpEditor {
139
- background-image:url(images/bg-editor-textile.png);
140
- }
141
- .bbcode .markItUpEditor {
142
- background-image:url(images/bg-editor-bbcode.png);
143
- }
144
- .wiki .markItUpEditor,
145
- .dotclear .markItUpEditor {
146
- background-image:url(images/bg-editor-wiki.png);
147
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
markitup/skins/simple/images/handle.png DELETED
Binary file
markitup/skins/simple/images/menu.png DELETED
Binary file
markitup/skins/simple/images/submenu.png DELETED
Binary file
markitup/skins/simple/style.css DELETED
@@ -1,118 +0,0 @@
1
- /* -------------------------------------------------------------------
2
- // markItUp! Universal MarkUp Engine, JQuery plugin
3
- // By Jay Salvat - http://markitup.jaysalvat.com/
4
- // ------------------------------------------------------------------*/
5
- .markItUp * {
6
- margin:0px; padding:0px;
7
- outline:none;
8
- }
9
- .markItUp a:link,
10
- .markItUp a:visited {
11
- color:#000;
12
- text-decoration:none;
13
- }
14
- .markItUp {
15
- width:700px;
16
- margin:5px 0 5px 0;
17
- }
18
- .markItUpContainer {
19
- font:11px Verdana, Arial, Helvetica, sans-serif;
20
- }
21
- .markItUpEditor {
22
- font:12px 'Courier New', Courier, monospace;
23
- padding:5px;
24
- width:690px;
25
- height:320px;
26
- clear:both;
27
- line-height:18px;
28
- overflow:auto;
29
- }
30
- .markItUpPreviewFrame {
31
- overflow:auto;
32
- background-color:#FFF;
33
- width:99.9%;
34
- height:300px;
35
- margin:5px 0;
36
- }
37
- .markItUpFooter {
38
- width:100%;
39
- }
40
- .markItUpResizeHandle {
41
- overflow:hidden;
42
- width:22px; height:5px;
43
- margin-left:auto;
44
- margin-right:auto;
45
- background-image:url(images/handle.png);
46
- cursor:n-resize;
47
- }
48
- /***************************************************************************************/
49
- /* first row of buttons */
50
- .markItUpHeader ul li {
51
- list-style:none;
52
- float:left;
53
- position:relative;
54
- }
55
- .markItUpHeader ul li:hover > ul{
56
- display:block;
57
- }
58
- .markItUpHeader ul .markItUpDropMenu {
59
- background:transparent url(images/menu.png) no-repeat 115% 50%;
60
- margin-right:5px;
61
- }
62
- .markItUpHeader ul .markItUpDropMenu li {
63
- margin-right:0px;
64
- }
65
- /* next rows of buttons */
66
- .markItUpHeader ul ul {
67
- display:none;
68
- position:absolute;
69
- top:18px; left:0px;
70
- background:#FFF;
71
- border:1px solid #000;
72
- }
73
- .markItUpHeader ul ul li {
74
- float:none;
75
- border-bottom:1px solid #000;
76
- }
77
- .markItUpHeader ul ul .markItUpDropMenu {
78
- background:#FFF url(images/submenu.png) no-repeat 100% 50%;
79
- }
80
- .markItUpHeader ul .markItUpSeparator {
81
- margin:0 10px;
82
- width:1px;
83
- height:16px;
84
- overflow:hidden;
85
- background-color:#CCC;
86
- }
87
- .markItUpHeader ul ul .markItUpSeparator {
88
- width:auto; height:1px;
89
- margin:0px;
90
- }
91
- /* next rows of buttons */
92
- .markItUpHeader ul ul ul {
93
- position:absolute;
94
- top:-1px; left:150px;
95
- }
96
- .markItUpHeader ul ul ul li {
97
- float:none;
98
- }
99
- .markItUpHeader ul a {
100
- display:block;
101
- width:16px; height:16px;
102
- text-indent:-10000px;
103
- background-repeat:no-repeat;
104
- padding:3px;
105
- margin:0px;
106
- }
107
- .markItUpHeader ul ul a {
108
- display:block;
109
- padding-left:0px;
110
- text-indent:0;
111
- width:120px;
112
- padding:5px 5px 5px 25px;
113
- background-position:2px 50%;
114
- }
115
- .markItUpHeader ul ul a:hover {
116
- color:#FFF;
117
- background-color:#000;
118
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
markitup/templates/preview.html DELETED
@@ -1 +0,0 @@
1
- <!-- content -->
 
preview.html ADDED
File without changes
readme.txt CHANGED
@@ -1,8 +1,9 @@
1
  === WP Better Emails ===
2
- Tags: email, emails, templates, notification, html emails, html, wp_mail, wpmu, multisite
 
3
  Requires at least: 2.8
4
- Tested up to: 3.1
5
- Stable tag: 0.1.3
6
 
7
  Adds a customizable good looking HTML template to all WP default plain/text emails and lets you set
8
  a custom sender name and email address.
@@ -10,23 +11,26 @@ Adds a customizable good looking HTML template to all WP default plain/text emai
10
  == Description ==
11
 
12
  All emails from Wordpress (lost password, notifications, etc.) are sent by default in text/plain format. WP Better
13
- Emails wraps them with a much better looking customizable **HTML template** and lets you also set your own **sender name** and **email address**.
14
 
15
  * WP Better Emails comes with a default simple and clean template that has been tested on various and popular email clients
16
  like Gmail, Yahoo Mail, Hotmail/Live, AOL, Outlook, Apple Mail and many more. This to ensure your emails will always display
17
  nicely in your recipient mailbox. But you can of course design your own.
18
- * WP Better Emails lets you send sample emails to test and preview your own custom template.
19
- * All emails sent by this plugin are as 'multipart' so email clients that don't support HTML can read them.
20
- * You can include some variables in your template such as your blog URL, blog name, blog description, admin email or date and time. They will all be
 
 
21
  replaced when sending the email.
22
- * The default template is included as an HTML file in the plugin folder (wpbe_template.html), feel free to edit it with your favorite editor.
23
- * Clean uninstall process, doesn't leave some useless data in your database when deleted, so try it !
 
24
 
25
- = Examples usages : =
26
 
27
  * Add some ads/sponsored links to every email sent with wordpress
28
  * Include some banners to promote a special event or feature of your website
29
- * Brand the emails of your website or client website
30
 
31
  = Internationalization =
32
 
@@ -34,43 +38,93 @@ WP Better Emails is currently available in :
34
 
35
  * English
36
  * French
37
- * Dutch by [Glenn Mulleners](http://wp-expert.nl "Glenn Mulleners")
 
38
 
39
  I'm looking for translators to extend to other languages. If you have translated the plugin in your language or want to,
40
  please let me know : plugins [ at ] artyshow-studio.fr
41
 
 
 
 
 
42
  == Installation ==
43
 
44
  1. Extract and upload the `wp-better-emails` folder to the `/wp-content/plugins/` directory
45
- 2. Activate the plugin through the 'Plugins' menu in WordPress
46
- 3. Set a sender email and name, defaults are respectively 'wordpress@yourdomain.com' and 'Your Blog Title'
47
  4. (Optional) Edit your own email template. See the screenshot tab to have a look at the default template
48
- 5. Every emails going out of your Wordpress Blog (notifications, lost password, etc.) looks better now !
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
  == Frequently Asked Questions ==
51
 
52
  = What if recipient can't read HTML emails ? =
53
 
54
- WP Better Emails sends all emails in both formats ('multipart', i.e. HTML and plain text) so that email can be displayed in every email client.
55
 
56
  = Why are the emails still sent in plain text format ? =
57
 
58
  Be sure to include the **%content%** tag in your template. WP Better Emails wrap the content with the template, if no tag
59
  is found, sending HTML emails is automatically desactivated.
60
 
61
- = My custom email template doesn't look the same in Gmail and other email clients ? =
62
 
63
- For example, Gmail strips everything before the `<body>` tag so if you included styles there, they won't be applied.
64
- I included a few helpful links in the 'Help & support' tab, you will find complete information about coding for emails.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  == Screenshots ==
67
 
68
- 1. The default template that comes with WP Better Emails. Tested on many email clients like Gmail, Yahoo!, Live/Hotmail, etc.
69
- 2. Sender option screen.
70
- 3. Edit template screen.
 
 
71
 
72
  == Changelog ==
73
 
 
 
 
 
 
 
 
 
 
74
  = 0.1.3 =
75
  * Sender email and name are now optional
76
  * Fixes replacing URLs of plain text content to handle https protocol
1
  === WP Better Emails ===
2
+ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=7Q49VJQNRCQ8E&lc=FR&item_name=ArtyShow&item_number=wp%2dbetter%2demails&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted
3
+ Tags: email, emails, html emails, templates, notification, wp_mail, wpmu, multisite
4
  Requires at least: 2.8
5
+ Tested up to: 3.2+
6
+ Stable tag: 0.2
7
 
8
  Adds a customizable good looking HTML template to all WP default plain/text emails and lets you set
9
  a custom sender name and email address.
11
  == Description ==
12
 
13
  All emails from Wordpress (lost password, notifications, etc.) are sent by default in text/plain format. WP Better
14
+ Emails wraps them with a much better looking customizable **HTML email template** and lets you also set your own **sender name** and **email address**.
15
 
16
  * WP Better Emails comes with a default simple and clean template that has been tested on various and popular email clients
17
  like Gmail, Yahoo Mail, Hotmail/Live, AOL, Outlook, Apple Mail and many more. This to ensure your emails will always display
18
  nicely in your recipient mailbox. But you can of course design your own.
19
+ * WP Better Emails lets you send sample emails to test and preview your own custom HTML email template.
20
+ * Watch your HTML email template during editing with the live preview.
21
+ * Fancy HTML editor with CodeMirror syntax highlighting.
22
+ * All emails sent by this plugin are sent as 'multipart' so that email clients that don't support HTML can read them.
23
+ * Include some dynamic tags in your template such as your blog URL, home URL, blog name, blog description, admin email or date and time. They will all be
24
  replaced when sending the email.
25
+ * Add your own tags with Wordpress filters (see [FAQ](http://wordpress.org/extend/plugins/wp-better-emails/faq/) for usage).
26
+ * The default template is included as an HTML file in the plugin folder, feel free to edit it with your favorite editor.
27
+ * Clean uninstall process, doesn't leave some useless data in your database when deleted, you can easily give it a try !
28
 
29
+ = Example usages : =
30
 
31
  * Add some ads/sponsored links to every email sent with wordpress
32
  * Include some banners to promote a special event or feature of your website
33
+ * Brand your emails to your website or client website
34
 
35
  = Internationalization =
36
 
38
 
39
  * English
40
  * French
41
+ * German - [Robert Tremmel](http://roberttremmel.de/ "Robert Tremmel")
42
+ * Hebrew - [Avi Ben-Avraham](mailto:avi@nrich.co.il "Avi Ben-Avraham")
43
 
44
  I'm looking for translators to extend to other languages. If you have translated the plugin in your language or want to,
45
  please let me know : plugins [ at ] artyshow-studio.fr
46
 
47
+ = Credits =
48
+
49
+ [CodeMirror](http://codemirror.net/ "CodeMirror") library
50
+
51
  == Installation ==
52
 
53
  1. Extract and upload the `wp-better-emails` folder to the `/wp-content/plugins/` directory
54
+ 2. Activate the plugin through the 'Plugins' menu in the WordPress admin panel
55
+ 3. (Optional) Set a sender email and name, if none, wordpress defaults will be used : 'wordpress@yourdomain.com' and 'Your Blog Title'
56
  4. (Optional) Edit your own email template. See the screenshot tab to have a look at the default template
57
+ 5. Every email going out from your Wordpress Blog (notifications, lost password, etc.) looks better now !
58
+
59
+ == Upgrade Notice ==
60
+
61
+ If you're using the default template provided with WP Better Emails, you should delete the plugin and reinstall it to make sure you have the lastest template improvements.
62
+
63
+ If you have customized the HTML template and want to keep it, just update.
64
+
65
+ = Manual update =
66
+
67
+ 1. Delete the plugin `wp-better-emails` folder under the `/wp-content/plugins/` directory
68
+ 2. Upload the last version and activate it
69
+
70
+ = Automatic update =
71
+
72
+ Just use the Wordpress automatic plugin update system
73
 
74
  == Frequently Asked Questions ==
75
 
76
  = What if recipient can't read HTML emails ? =
77
 
78
+ WP Better Emails sends all emails in both formats ('multipart', i.e. HTML and plain text) so that emails can be displayed in every email client.
79
 
80
  = Why are the emails still sent in plain text format ? =
81
 
82
  Be sure to include the **%content%** tag in your template. WP Better Emails wrap the content with the template, if no tag
83
  is found, sending HTML emails is automatically desactivated.
84
 
85
+ = How does WP Better Emails interact with others plugins ? =
86
 
87
+ WP Better Emails wraps every "plain/text" email sent with the Wordpress function `wp_mail()`.
88
+
89
+ = I totally messed up with the template, how can I get the original one ? =
90
+
91
+ Just delete and reinstall the plugin from the admin panel.
92
+
93
+ = How can I add my own tags ? =
94
+
95
+ You can filter the tags array and add your replacements. Let's say you want to randomly display some sponsored links somewhere in your email template:
96
+
97
+ add_filter('wpbe_tags', 'add_my_tags');
98
+ function add_my_tags( $tags ) {
99
+ $ads = array('<a href="#">Sponsored link 1</a>', '<a href="#">Sponsored link 2</a>', '<a href="#">Sponsored link 3</a>');
100
+ $tags['sponsored_link'] = $ads[array_rand($ads, 1)];
101
+ return $tags;
102
+ }
103
+
104
+ The key of the array `sponsored_link` will be a new tag (`%sponsored_link%`) you can include. It will be randomly replaced with one of your sponsored links.
105
+
106
+ The example above is taking sponsored links as an additinonal content but you can imagine anything like including lastest posts, a quote of the day or whatever.
107
+ You can place this function in your functions.php theme file or in a plugin.
108
 
109
  == Screenshots ==
110
 
111
+ 1. The default template provided with WP Better Emails. Tested on many email clients like Gmail, Yahoo!, Live/Hotmail, etc.
112
+ 2. WP Better Emails settings screen with the default WP TinyMCE editor.
113
+ 3. Editor in source mode using CodeMirror syntax highlighting.
114
+ 4. Live preview your template in a thickbox.
115
+ 5. Help tab with information about available tags.
116
 
117
  == Changelog ==
118
 
119
+ = 0.2 =
120
+ * WP TinyMCE editor support
121
+ * HTML editor with CodeMirror as a TinyMCE plugin
122
+ * Live preview (> WP 3.1)
123
+ * Include filter to add your own tag replacements
124
+ * Help moved to contextual help
125
+ * Translations for german, hebrew
126
+ * Improved template email clients support
127
+
128
  = 0.1.3 =
129
  * Sender email and name are now optional
130
  * Fixes replacing URLs of plain text content to handle https protocol
screenshot-1.png CHANGED
Binary file
screenshot-2.png CHANGED
Binary file
screenshot-3.png CHANGED
Binary file
screenshot-4.png ADDED
Binary file
screenshot-5.png ADDED
Binary file
templates/template-1.html ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html;UTF-8" />
5
+ </head>
6
+ <body style="margin: 0px; background-color: #F4F3F4; font-family: Helvetica, Arial, sans-serif; font-size:12px;" text="#444444" bgcolor="#F4F3F4" link="#21759B" alink="#21759B" vlink="#21759B" marginheight="0" topmargin="0" marginwidth="0" leftmargin="0">
7
+ <table cellpadding="0" cellspacing="0" width="100%" bgcolor="#F4F3F4" border="0">
8
+ <tr>
9
+ <td style="padding:15px;">
10
+ <center>
11
+ <table width="550" cellpadding="0" bgcolor="#ffffff" cellspacing="0">
12
+ <tr>
13
+ <td align="left">
14
+ <div style="border:solid 1px #d9d9d9;">
15
+ <table id="header" width="100%" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="line-height:1.6;font-size:12px;font-family: Helvetica, Arial, sans-serif;border:solid 1px #FFFFFF;color:#444;">
16
+ <tr>
17
+ <td colspan="2" background="%blog_url%/wp-admin/images/white-grad-active.png" height="30" style="color: #ffffff;" valign="bottom">.</td>
18
+ </tr>
19
+ <tr>
20
+ <td style="line-height:32px;padding-left:30px;" valign="baseline"><span style="font-size:32px;"><a href="%blog_url%" style="text-decoration:none;" target="_blank">Wordpress 3.2.1</a></span></td>
21
+ <td style="padding-right:30px;" align="right" valign="baseline"><span style="font-size:14px;color:#777777">Un site utilisant WordPress</span></td>
22
+ </tr>
23
+ </table>
24
+ <table id="content" width="490" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="margin-top:15px;margin-right:30px; margin-left:30px;color:#444;line-height:1.6;font-size:12px;font-family: Arial, sans-serif;color: #444;">
25
+ <tr>
26
+ <td colspan="2" style="border-top: solid 1px #d9d9d9">
27
+ <div style="padding:15px 0;">
28
+ Hey !<br />
29
+
30
+ <br />
31
+ Das ist eine Test-E-Mail zur Vorschau Ihrer Design-Vorlage in HTML.<br />
32
+ <br />
33
+ Sollten Sie wenig Erfahrung mit HTML/CSS-Codes haben, empfehle ich Ihnen, die Standard-Einstellungen der Design-Vorlage beizubehalten. Es wurde in gebräuchlichen E-Mail-Anwendungen getestet. Zum Beispiel: Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook und viele andere.<br />
34
+ <br />
35
+ Sollten bei Ihnen Probleme auftreten oder haben Sie Verbesserungsvorschläge für das Plug-in? Kontaktieren Sie mich.
36
+ </div>
37
+ </td>
38
+ </tr>
39
+ </table>
40
+ <table id="footer" width="490" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="line-height:1.5;font-size:12px;font-family: Arial, sans-serif;margin-right:30px;margin-left:30px;">
41
+ <tr style="font-size:11px;color:#999999;">
42
+ <td style="border-top: solid 1px #d9d9d9;" colspan="2">
43
+ <img style="padding-top:28px;" height="16" width="16" src="%blog_url%/wp-admin/images/wp-logo.png" align="right" alt="WP" />
44
+ <div style="padding-top:15px; padding-bottom:1px;"><img height="13" width="13" style="vertical-align: middle;" src="%blog_url%/wp-admin/images/date-button.gif" alt="Datum" /> Email sent %date% @ %time%</div>
45
+ <div><img height="12" width="12" style="vertical-align: middle;" src="%blog_url%/wp-admin/images/comment-grey-bubble.png" alt="Kontakt" /> For any requests, please contact <a href="mailto:plugins@artyshow-studio.fr">plugins@artyshow-studio.fr</a></div>
46
+ </td>
47
+ </tr>
48
+ <tr>
49
+ <td colspan="2" height="15" style="color: #ffffff;">.</td>
50
+ </tr>
51
+ </table>
52
+ </div>
53
+ </td>
54
+ </tr>
55
+ </table>
56
+ </center>
57
+ </td>
58
+ </tr>
59
+ </table>
60
+ </body>
61
+ </html>
templates/template-1.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $template = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html;' . get_option('blog_charset') . '" />
6
+ </head>
7
+ <body style="margin: 0px; background-color: #F4F3F4; font-family: Helvetica, Arial, sans-serif; font-size:12px;" text="#444444" bgcolor="#F4F3F4" link="#21759B" alink="#21759B" vlink="#21759B" marginheight="0" topmargin="0" marginwidth="0" leftmargin="0">
8
+ <table cellpadding="0" cellspacing="0" width="100%" bgcolor="#F4F3F4" border="0">
9
+ <tr>
10
+ <td style="padding:15px;">
11
+ <center>
12
+ <table width="550" cellpadding="0" bgcolor="#ffffff" cellspacing="0">
13
+ <tr>
14
+ <td align="left">
15
+ <div style="border:solid 1px #d9d9d9;">
16
+ <table id="header" width="100%" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="line-height:1.6;font-size:12px;font-family: Helvetica, Arial, sans-serif;border:solid 1px #FFFFFF;color:#444;">
17
+ <tr>
18
+ <td colspan="2" background="' . admin_url('images/white-grad-active.png') . '" height="30" style="color:#ffffff;" valign="bottom">.</td>
19
+ </tr>
20
+ <tr>
21
+ <td style="line-height:32px;padding-left:30px;" valign="baseline"><span style="font-size:32px;"><a href="%blog_url%" style="text-decoration:none;" target="_blank">%blog_name%</a></span></td>
22
+ <td style="padding-right:30px;" align="right" valign="baseline"><span style="font-size:14px;color:#777777">%blog_description%</span></td>
23
+ </tr>
24
+ </table>
25
+ <table id="content" width="490" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="margin-top:15px;margin-right:30px; margin-left:30px;color:#444;line-height:1.6;font-size:12px;font-family: Arial, sans-serif;color: #444;">
26
+ <tr>
27
+ <td colspan="2" style="border-top: solid 1px #d9d9d9">
28
+ <div style="padding:15px 0;">
29
+ %content%
30
+ </div>
31
+ </td>
32
+ </tr>
33
+ </table>
34
+ <table id="footer" width="490" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="line-height:1.5;font-size:12px;font-family: Arial, sans-serif;margin-right:30px;margin-left:30px;">
35
+ <tr style="font-size:11px;color:#999999;">
36
+ <td style="border-top: solid 1px #d9d9d9;" colspan="2">
37
+ <img style="padding-top:28px;" height="16" width="16" src="'. admin_url('/images/wp-logo.png') . '" align="right" alt="WP" />
38
+ <div style="padding-top:15px; padding-bottom:1px;"><img height="13" width="13" style="vertical-align: middle;" src="' . admin_url('images/date-button.gif') . '" alt="' . esc_attr__('Date', 'wp-better-emails') . '" /> ' . esc_attr__('Email sent', 'wp-better-emails') . ' %date% @ %time%</div>
39
+ <div><img height="12" width="12" style="vertical-align: middle;" src="' . admin_url('images/comment-grey-bubble.png') . '" alt="' . esc_attr__('Contact', 'wp-better-emails') . '" /> ' . __('For any requests, please contact', 'wp-better-emails') . ' <a href="mailto:%admin_email%">%admin_email%</a></div>
40
+ </td>
41
+ </tr>
42
+ <tr>
43
+ <td colspan="2" style="color:#ffffff;" height="15">.</td>
44
+ </tr>
45
+ </table>
46
+ </div>
47
+ </td>
48
+ </tr>
49
+ </table>
50
+ </center>
51
+ </td>
52
+ </tr>
53
+ </table>
54
+ </body>
55
+ </html>';
56
+ ?>
tinymce-plugins/3.3.x/fullpage/css/fullpage.css ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Hide the advanced tab */
2
+ #advanced_tab {
3
+ display: none;
4
+ }
5
+
6
+ #metatitle, #metakeywords, #metadescription, #metaauthor, #metacopyright {
7
+ width: 280px;
8
+ }
9
+
10
+ #doctype, #docencoding {
11
+ width: 200px;
12
+ }
13
+
14
+ #langcode {
15
+ width: 30px;
16
+ }
17
+
18
+ #bgimage {
19
+ width: 220px;
20
+ }
21
+
22
+ #fontface {
23
+ width: 240px;
24
+ }
25
+
26
+ #leftmargin, #rightmargin, #topmargin, #bottommargin {
27
+ width: 50px;
28
+ }
29
+
30
+ .panel_wrapper div.current {
31
+ height: 400px;
32
+ }
33
+
34
+ #stylesheet, #style {
35
+ width: 240px;
36
+ }
37
+
38
+ /* Head list classes */
39
+
40
+ .headlistwrapper {
41
+ width: 100%;
42
+ }
43
+
44
+ .addbutton, .removebutton, .moveupbutton, .movedownbutton {
45
+ border-top: 1px solid;
46
+ border-left: 1px solid;
47
+ border-bottom: 1px solid;
48
+ border-right: 1px solid;
49
+ border-color: #F0F0EE;
50
+ cursor: default;
51
+ display: block;
52
+ width: 20px;
53
+ height: 20px;
54
+ }
55
+
56
+ #doctypes {
57
+ width: 200px;
58
+ }
59
+
60
+ .addbutton:hover, .removebutton:hover, .moveupbutton:hover, .movedownbutton:hover {
61
+ border: 1px solid #0A246A;
62
+ background-color: #B6BDD2;
63
+ }
64
+
65
+ .addbutton {
66
+ background-image: url('../images/add.gif');
67
+ float: left;
68
+ margin-right: 3px;
69
+ }
70
+
71
+ .removebutton {
72
+ background-image: url('../images/remove.gif');
73
+ float: left;
74
+ }
75
+
76
+ .moveupbutton {
77
+ background-image: url('../images/move_up.gif');
78
+ float: left;
79
+ margin-right: 3px;
80
+ }
81
+
82
+ .movedownbutton {
83
+ background-image: url('../images/move_down.gif');
84
+ float: left;
85
+ }
86
+
87
+ .selected {
88
+ border: 1px solid #0A246A;
89
+ background-color: #B6BDD2;
90
+ }
91
+
92
+ .toolbar {
93
+ width: 100%;
94
+ }
95
+
96
+ #headlist {
97
+ width: 100%;
98
+ margin-top: 3px;
99
+ font-size: 11px;
100
+ }
101
+
102
+ #info, #title_element, #meta_element, #script_element, #style_element, #base_element, #link_element, #comment_element, #unknown_element {
103
+ display: none;
104
+ }
105
+
106
+ #addmenu {
107
+ position: absolute;
108
+ border: 1px solid gray;
109
+ display: none;
110
+ z-index: 100;
111
+ background-color: white;
112
+ }
113
+
114
+ #addmenu a {
115
+ display: block;
116
+ width: 100%;
117
+ line-height: 20px;
118
+ text-decoration: none;
119
+ background-color: white;
120
+ }
121
+
122
+ #addmenu a:hover {
123
+ background-color: #B6BDD2;
124
+ color: black;
125
+ }
126
+
127
+ #addmenu span {
128
+ padding-left: 10px;
129
+ padding-right: 10px;
130
+ }
131
+
132
+ #updateElementPanel {
133
+ display: none;
134
+ }
135
+
136
+ #script_element .panel_wrapper div.current {
137
+ height: 108px;
138
+ }
139
+
140
+ #style_element .panel_wrapper div.current {
141
+ height: 108px;
142
+ }
143
+
144
+ #link_element .panel_wrapper div.current {
145
+ height: 140px;
146
+ }
147
+
148
+ #element_script_value {
149
+ width: 100%;
150
+ height: 100px;
151
+ }
152
+
153
+ #element_comment_value {
154
+ width: 100%;
155
+ height: 120px;
156
+ }
157
+
158
+ #element_style_value {
159
+ width: 100%;
160
+ height: 100px;
161
+ }
162
+
163
+ #element_title, #element_script_src, #element_meta_name, #element_meta_content, #element_base_href, #element_link_href, #element_link_title {
164
+ width: 250px;
165
+ }
166
+
167
+ .updateElementButton {
168
+ margin-top: 3px;
169
+ }
170
+
171
+ /* MSIE specific styles */
172
+
173
+ * html .addbutton, * html .removebutton, * html .moveupbutton, * html .movedownbutton {
174
+ width: 22px;
175
+ height: 22px;
176
+ }
177
+
178
+ textarea {
179
+ height: 55px;
180
+ }
181
+
182
+ .panel_wrapper div.current {height:420px;}
tinymce-plugins/3.3.x/fullpage/editor_plugin.js ADDED
@@ -0,0 +1 @@
 
1
+ (function(){tinymce.create("tinymce.plugins.FullPagePlugin",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceFullPageProperties",function(){a.windowManager.open({file:b+"/fullpage.htm",width:430+parseInt(a.getLang("fullpage.delta_width",0)),height:495+parseInt(a.getLang("fullpage.delta_height",0)),inline:1},{plugin_url:b,head_html:c.head})});a.addButton("fullpage",{title:"fullpage.desc",cmd:"mceFullPageProperties"});a.onBeforeSetContent.add(c._setContent,c);a.onSetContent.add(c._setBodyAttribs,c);a.onGetContent.add(c._getContent,c)},getInfo:function(){return{longname:"Fullpage",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_setBodyAttribs:function(d,a){var l,c,e,g,b,h,j,f=this.head.match(/body(.*?)>/i);if(f&&f[1]){l=f[1].match(/\s*(\w+\s*=\s*".*?"|\w+\s*=\s*'.*?'|\w+\s*=\s*\w+|\w+)\s*/g);if(l){for(c=0,e=l.length;c<e;c++){g=l[c].split("=");b=g[0].replace(/\s/,"");h=g[1];if(h){h=h.replace(/^\s+/,"").replace(/\s+$/,"");j=h.match(/^["'](.*)["']$/);if(j){h=j[1]}}else{h=b}d.dom.setAttrib(d.getBody(),"style",h)}}}},_createSerializer:function(){return new tinymce.dom.Serializer({dom:this.editor.dom,apply_source_formatting:true})},_setContent:function(d,b){var i=this,a,l,f=b.content,h,j="";if(b.format=="raw"&&i.head){return}if(b.source_view&&d.getParam("fullpage_hide_in_source_view")){return}f=f.replace(/<(\/?)BODY/gi,"<$1body");a=f.indexOf("<body");if(a!=-1){a=f.indexOf(">",a);i.head=f.substring(0,a+1);var k=0,g;i.css="";while((k=i.head.indexOf("<style",k))!=-1){k=f.indexOf(">",k)+1;if((g=i.head.indexOf("</style",k))==-1){break}i.css+=i.head.substring(k,g);k=g}l=f.indexOf("</body",a);if(l==-1){l=f.length}b.content=f.substring(a+1,l);i.foot=f.substring(l);function e(c){return c.replace(/<\/?[A-Z]+/g,function(m){return m.toLowerCase()})}i.head=e(i.head);i.foot=e(i.foot)}else{i.head="";if(d.getParam("fullpage_default_xml_pi")){i.head+='<?xml version="1.0" encoding="'+d.getParam("fullpage_default_encoding","ISO-8859-1")+'" ?>\n'}i.head+=d.getParam("fullpage_default_doctype",'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');i.head+="\n<html>\n<head>\n<title>"+d.getParam("fullpage_default_title","Untitled document")+"</title>\n";if(h=d.getParam("fullpage_default_encoding")){i.head+='<meta http-equiv="Content-Type" content="'+h+'" />\n'}if(h=d.getParam("fullpage_default_font_family")){j+="font-family: "+h+";"}if(h=d.getParam("fullpage_default_font_size")){j+="font-size: "+h+";"}if(h=d.getParam("fullpage_default_text_color")){j+="color: "+h+";"}i.head+="</head>\n<body"+(j?' style="'+j+'"':"")+">\n";i.foot="\n</body>\n</html>"}},_getContent:function(a,c){var b=this;if(!c.source_view||!a.getParam("fullpage_hide_in_source_view")){c.content=tinymce.trim(b.head)+"\n"+tinymce.trim(c.content)+"\n"+tinymce.trim(b.foot);if(b.css){b._setStyle(a,b.css)}}},_setStyle:function(a,b){a.dom.remove("injectedCSS");var d=a.dom.doc,c=d.createElement("style");c.type="text/css";c.id="injectedCSS";if(c.styleSheet){c.styleSheet.cssText=b}else{c.appendChild(d.createTextNode(b))}d.getElementsByTagName("head")[0].appendChild(c)}});tinymce.PluginManager.add("fullpage",tinymce.plugins.FullPagePlugin)})();
tinymce-plugins/3.3.x/fullpage/editor_plugin_src.js ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * editor_plugin_src.js
3
+ *
4
+ * Copyright 2009, Moxiecode Systems AB
5
+ * Released under LGPL License.
6
+ *
7
+ * License: http://tinymce.moxiecode.com/license
8
+ * Contributing: http://tinymce.moxiecode.com/contributing
9
+ */
10
+
11
+ (function() {
12
+ tinymce.create('tinymce.plugins.FullPagePlugin', {
13
+ init : function(ed, url) {
14
+ var t = this;
15
+
16
+ t.editor = ed;
17
+
18
+ // Register commands
19
+ ed.addCommand('mceFullPageProperties', function() {
20
+ ed.windowManager.open({
21
+ file : url + '/fullpage.htm',
22
+ width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)),
23
+ height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)),
24
+ inline : 1
25
+ }, {
26
+ plugin_url : url,
27
+ head_html : t.head
28
+ });
29
+ });
30
+
31
+ // Register buttons
32
+ ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'});
33
+
34
+ ed.onBeforeSetContent.add(t._setContent, t);
35
+ ed.onSetContent.add(t._setBodyAttribs, t);
36
+ ed.onGetContent.add(t._getContent, t);
37
+ },
38
+
39
+ getInfo : function() {
40
+ return {
41
+ longname : 'Fullpage',
42
+ author : 'Moxiecode Systems AB',
43
+ authorurl : 'http://tinymce.moxiecode.com',
44
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage',
45
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
46
+ };
47
+ },
48
+
49
+ // Private plugin internal methods
50
+
51
+ _setBodyAttribs : function(ed, o) {
52
+ var bdattr, i, len, kv, k, v, t, attr = this.head.match(/body(.*?)>/i);
53
+
54
+ if (attr && attr[1]) {
55
+ bdattr = attr[1].match(/\s*(\w+\s*=\s*".*?"|\w+\s*=\s*'.*?'|\w+\s*=\s*\w+|\w+)\s*/g);
56
+
57
+ if (bdattr) {
58
+ for(i = 0, len = bdattr.length; i < len; i++) {
59
+ kv = bdattr[i].split('=');
60
+ k = kv[0].replace(/\s/,'');
61
+ v = kv[1];
62
+
63
+ if (v) {
64
+ v = v.replace(/^\s+/,'').replace(/\s+$/,'');
65
+ t = v.match(/^["'](.*)["']$/);
66
+
67
+ if (t)
68
+ v = t[1];
69
+ } else
70
+ v = k;
71
+
72
+ ed.dom.setAttrib(ed.getBody(), 'style', v);
73
+ }
74
+ }
75
+ }
76
+ },
77
+
78
+ _createSerializer : function() {
79
+ return new tinymce.dom.Serializer({
80
+ dom : this.editor.dom,
81
+ apply_source_formatting : true
82
+ });
83
+ },
84
+
85
+ _setContent : function(ed, o) {
86
+ var t = this, sp, ep, c = o.content, v, st = '';
87
+
88
+ // Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate
89
+ if (o.format == 'raw' && t.head)
90
+ return;
91
+
92
+ if (o.source_view && ed.getParam('fullpage_hide_in_source_view'))
93
+ return;
94
+
95
+ // Parse out head, body and footer
96
+ c = c.replace(/<(\/?)BODY/gi, '<$1body');
97
+ sp = c.indexOf('<body');
98
+
99
+ if (sp != -1) {
100
+ sp = c.indexOf('>', sp);
101
+ t.head = c.substring(0, sp + 1);
102
+
103
+ // Concatenate all <style>'s text into t.css
104
+ var ss = 0, es;
105
+ t.css = '';
106
+ while ((ss = t.head.indexOf('<style', ss)) != -1) {
107
+ ss = c.indexOf('>', ss) + 1;
108
+ if ( (es = t.head.indexOf('</style', ss)) == -1)
109
+ break;
110
+ t.css += t.head.substring(ss, es);
111
+ ss = es;
112
+ }
113
+
114
+ ep = c.indexOf('</body', sp);
115
+ if (ep == -1)
116
+ ep = c.length;
117
+
118
+ o.content = c.substring(sp + 1, ep);
119
+ t.foot = c.substring(ep);
120
+
121
+ function low(s) {
122
+ return s.replace(/<\/?[A-Z]+/g, function(a) {
123
+ return a.toLowerCase();
124
+ })
125
+ };
126
+
127
+ t.head = low(t.head);
128
+ t.foot = low(t.foot);
129
+ } else {
130
+ t.head = '';
131
+ if (ed.getParam('fullpage_default_xml_pi'))
132
+ t.head += '<?xml version="1.0" encoding="' + ed.getParam('fullpage_default_encoding', 'ISO-8859-1') + '" ?>\n';
133
+
134
+ t.head += ed.getParam('fullpage_default_doctype', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
135
+ t.head += '\n<html>\n<head>\n<title>' + ed.getParam('fullpage_default_title', 'Untitled document') + '</title>\n';
136
+
137
+ if (v = ed.getParam('fullpage_default_encoding'))
138
+ t.head += '<meta http-equiv="Content-Type" content="' + v + '" />\n';
139
+
140
+ if (v = ed.getParam('fullpage_default_font_family'))
141
+ st += 'font-family: ' + v + ';';
142
+
143
+ if (v = ed.getParam('fullpage_default_font_size'))
144
+ st += 'font-size: ' + v + ';';
145
+
146
+ if (v = ed.getParam('fullpage_default_text_color'))
147
+ st += 'color: ' + v + ';';
148
+
149
+ t.head += '</head>\n<body' + (st ? ' style="' + st + '"' : '') + '>\n';
150
+ t.foot = '\n</body>\n</html>';
151
+ }
152
+ },
153
+
154
+ _getContent : function(ed, o) {
155
+ var t = this;
156
+
157
+ if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view')) {
158
+ o.content = tinymce.trim(t.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(t.foot);
159
+
160
+ if (t.css)
161
+ t._setStyle(ed, t.css);
162
+ }
163
+ },
164
+
165
+ _setStyle : function(ed, css) {
166
+ ed.dom.remove('injectedCSS');
167
+ var doc = ed.dom.doc, style = doc.createElement('style');
168
+ style.type = 'text/css';
169
+ style.id = 'injectedCSS';
170
+
171
+ if (style.styleSheet) // IE
172
+ style.styleSheet.cssText = css;
173
+ else // other browsers
174
+ style.appendChild(doc.createTextNode(css));
175
+
176
+ doc.getElementsByTagName('head')[0].appendChild(style);
177
+ }
178
+ });
179
+
180
+ // Register plugin
181
+ tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin);
182
+ })();
tinymce-plugins/3.3.x/fullpage/fullpage.htm ADDED
@@ -0,0 +1,571 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <title>{#fullpage_dlg.title}</title>
5
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
6
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
7
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
8
+ <script type="text/javascript" src="js/fullpage.js"></script>
9
+ <link href="css/fullpage.css" rel="stylesheet" type="text/css" />
10
+ </head>
11
+ <body id="advlink" style="display: none">
12
+ <form onsubmit="updateAction();return false;" name="fullpage" action="#">
13
+ <div class="tabs">
14
+ <ul>
15
+ <li id="meta_tab" class="current"><span><a href="javascript:mcTabs.displayTab('meta_tab','meta_panel');" onmousedown="return false;">{#fullpage_dlg.meta_tab}</a></span></li>
16
+ <li id="appearance_tab"><span><a href="javascript:mcTabs.displayTab('appearance_tab','appearance_panel');" onmousedown="return false;">{#fullpage_dlg.appearance_tab}</a></span></li>
17
+ <li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{#fullpage_dlg.advanced_tab}</a></span></li>
18
+ </ul>
19
+ </div>
20
+
21
+ <div class="panel_wrapper">
22
+ <div id="meta_panel" class="panel current">
23
+ <fieldset>
24
+ <legend>{#fullpage_dlg.meta_props}</legend>
25
+
26
+ <table border="0" cellpadding="4" cellspacing="0">
27
+ <tr>
28
+ <td class="nowrap"><label for="metatitle">{#fullpage_dlg.meta_title}</label>&nbsp;</td>
29
+ <td><input type="text" id="metatitle" name="metatitle" value="" class="mceFocus" /></td>
30
+ </tr>
31
+ <tr>
32
+ <td class="nowrap"><label for="metakeywords">{#fullpage_dlg.meta_keywords}</label>&nbsp;</td>
33
+ <td><textarea id="metakeywords" name="metakeywords" rows="4"></textarea></td>
34
+ </tr>
35
+ <tr>
36
+ <td class="nowrap"><label for="metadescription">{#fullpage_dlg.meta_description}</label>&nbsp;</td>
37
+ <td><textarea id="metadescription" name="metadescription" rows="4"></textarea></td>
38
+ </tr>
39
+ <tr>
40
+ <td class="nowrap"><label for="metaauthor">{#fullpage_dlg.author}</label>&nbsp;</td>
41
+ <td><input type="text" id="metaauthor" name="metaauthor" value="" /></td>
42
+ </tr>
43
+ <tr>
44
+ <td class="nowrap"><label for="metacopyright">{#fullpage_dlg.copyright}</label>&nbsp;</td>
45
+ <td><input type="text" id="metacopyright" name="metacopyright" value="" /></td>
46
+ </tr>
47
+ <tr>
48
+ <td class="nowrap"><label for="metarobots">{#fullpage_dlg.meta_robots}</label>&nbsp;</td>
49
+ <td>
50
+ <select id="metarobots" name="metarobots">
51
+ <option value="">{#not_set}</option>
52
+ <option value="index,follow">{#fullpage_dlg.meta_index_follow}</option>
53
+ <option value="index,nofollow">{#fullpage_dlg.meta_index_nofollow}</option>
54
+ <option value="noindex,follow">{#fullpage_dlg.meta_noindex_follow}</option>
55
+ <option value="noindex,nofollow">{#fullpage_dlg.meta_noindex_nofollow}</option>
56
+ </select>
57
+ </td>
58
+ </tr>
59
+ </table>
60
+ </fieldset>
61
+
62
+ <fieldset>
63
+ <legend>{#fullpage_dlg.langprops}</legend>
64
+
65
+ <table border="0" cellpadding="4" cellspacing="0">
66
+ <tr>
67
+ <td class="column1"><label for="docencoding">{#fullpage_dlg.encoding}</label></td>
68
+ <td>
69
+ <select id="docencoding" name="docencoding">
70
+ <option value="">{#not_set}</option>
71
+ </select>
72
+ </td>
73
+ </tr>
74
+ <tr>
75
+ <td class="nowrap"><label for="doctypes">{#fullpage_dlg.doctypes}</label>&nbsp;</td>
76
+ <td>
77
+ <select id="doctypes" name="doctypes">
78
+ <option value="">{#not_set}</option>
79
+ </select>
80
+ </td>
81
+ </tr>
82
+ <tr>
83
+ <td class="nowrap"><label for="langcode">{#fullpage_dlg.langcode}</label>&nbsp;</td>
84
+ <td><input type="text" id="langcode" name="langcode" value="" /></td>
85
+ </tr>
86
+ <tr>
87
+ <td class="column1"><label for="langdir">{#fullpage_dlg.langdir}</label></td>
88
+ <td>
89
+ <select id="langdir" name="langdir">
90
+ <option value="">{#not_set}</option>
91
+ <option value="ltr">{#fullpage_dlg.ltr}</option>
92
+ <option value="rtl">{#fullpage_dlg.rtl}</option>
93
+ </select>
94
+ </td>
95
+ </tr>
96
+ <tr>
97
+ <td class="nowrap"><label for="xml_pi">{#fullpage_dlg.xml_pi}</label>&nbsp;</td>
98
+ <td><input type="checkbox" id="xml_pi" name="xml_pi" class="checkbox" /></td>
99
+ </tr>
100
+ </table>
101
+ </fieldset>
102
+ </div>
103
+
104
+ <div id="appearance_panel" class="panel">
105
+ <fieldset>
106
+ <legend>{#fullpage_dlg.appearance_textprops}</legend>
107
+
108
+ <table border="0" cellpadding="4" cellspacing="0">
109
+ <tr>
110
+ <td class="column1"><label for="fontface">{#fullpage_dlg.fontface}</label></td>
111
+ <td>
112
+ <select id="fontface" name="fontface" onchange="changedStyleField(this);">
113
+ <option value="">{#not_set}</option>
114
+ </select>
115
+ </td>
116
+ </tr>
117
+
118
+ <tr>
119
+ <td class="column1"><label for="fontsize">{#fullpage_dlg.fontsize}</label></td>
120
+ <td>
121
+ <select id="fontsize" name="fontsize" onchange="changedStyleField(this);">
122
+ <option value="">{#not_set}</option>
123
+ </select>
124
+ </td>
125
+ </tr>
126
+
127
+ <tr>
128
+ <td class="column1"><label for="textcolor">{#fullpage_dlg.textcolor}</label></td>
129
+ <td>
130
+ <table border="0" cellpadding="0" cellspacing="0">
131
+ <tr>
132
+ <td><input id="textcolor" name="textcolor" type="text" value="" size="9" onchange="updateColor('textcolor_pick','textcolor');changedStyleField(this);" /></td>
133
+ <td id="textcolor_pickcontainer">&nbsp;</td>
134
+ </tr>
135
+ </table>
136
+ </td>
137
+ </tr>
138
+ </table>
139
+ </fieldset>
140
+
141
+ <fieldset>
142
+ <legend>{#fullpage_dlg.appearance_bgprops}</legend>
143
+
144
+ <table border="0" cellpadding="4" cellspacing="0">
145
+ <tr>
146
+ <td class="column1"><label for="bgimage">{#fullpage_dlg.bgimage}</label></td>
147
+ <td>
148
+ <table border="0" cellpadding="0" cellspacing="0">
149
+ <tr>
150
+ <td><input id="bgimage" name="bgimage" type="text" value="" onchange="changedStyleField(this);" /></td>
151
+ <td id="bgimage_pickcontainer">&nbsp;</td>
152
+ </tr>
153
+ </table>
154
+ </td>
155
+ </tr>
156
+ <tr>
157
+ <td class="column1"><label for="bgcolor">{#fullpage_dlg.bgcolor}</label></td>
158
+ <td>
159
+ <table border="0" cellpadding="0" cellspacing="0">
160
+ <tr>
161
+ <td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');changedStyleField(this);" /></td>
162
+ <td id="bgcolor_pickcontainer">&nbsp;</td>
163
+ </tr>
164
+ </table>
165
+ </td>
166
+ </tr>
167
+ </table>
168
+ </fieldset>
169
+
170
+ <fieldset>
171
+ <legend>{#fullpage_dlg.appearance_marginprops}</legend>
172
+
173
+ <table border="0" cellpadding="4" cellspacing="0">
174
+ <tr>
175
+ <td class="column1"><label for="leftmargin">{#fullpage_dlg.left_margin}</label></td>
176
+ <td><input id="leftmargin" name="leftmargin" type="text" value="" onchange="changedStyleField(this);" /></td>
177
+ <td class="column1"><label for="rightmargin">{#fullpage_dlg.right_margin}</label></td>
178
+ <td><input id="rightmargin" name="rightmargin" type="text" value="" onchange="changedStyleField(this);" /></td>
179
+ </tr>
180
+ <tr>
181
+ <td class="column1"><label for="topmargin">{#fullpage_dlg.top_margin}</label></td>
182
+ <td><input id="topmargin" name="topmargin" type="text" value="" onchange="changedStyleField(this);" /></td>
183
+ <td class="column1"><label for="bottommargin">{#fullpage_dlg.bottom_margin}</label></td>
184
+ <td><input id="bottommargin" name="bottommargin" type="text" value="" onchange="changedStyleField(this);" /></td>
185
+ </tr>
186
+ </table>
187
+ </fieldset>
188
+
189
+ <fieldset>
190
+ <legend>{#fullpage_dlg.appearance_linkprops}</legend>
191
+
192
+ <table border="0" cellpadding="4" cellspacing="0">
193
+ <tr>
194
+ <td class="column1"><label for="link_color">{#fullpage_dlg.link_color}</label></td>
195
+ <td>
196
+ <table border="0" cellpadding="0" cellspacing="0">
197
+ <tr>
198
+ <td><input id="link_color" name="link_color" type="text" value="" size="9" onchange="updateColor('link_color_pick','link_color');changedStyleField(this);" /></td>
199
+ <td id="link_color_pickcontainer">&nbsp;</td>
200
+ </tr>
201
+ </table>
202
+ </td>
203
+
204
+ <td class="column1"><label for="visited_color">{#fullpage_dlg.visited_color}</label></td>
205
+ <td>
206
+ <table border="0" cellpadding="0" cellspacing="0">
207
+ <tr>
208
+ <td><input id="visited_color" name="visited_color" type="text" value="" size="9" onchange="updateColor('visited_color_pick','visited_color');changedStyleField(this);" /></td>
209
+ <td id="visited_color_pickcontainer">&nbsp;</td>
210
+ </tr>
211
+ </table>
212
+ </td>
213
+ </tr>
214
+
215
+ <tr>
216
+ <td class="column1"><label for="active_color">{#fullpage_dlg.active_color}</label></td>
217
+ <td>
218
+ <table border="0" cellpadding="0" cellspacing="0">
219
+ <tr>
220
+ <td><input id="active_color" name="active_color" type="text" value="" size="9" onchange="updateColor('active_color_pick','active_color');changedStyleField(this);" /></td>
221
+ <td id="active_color_pickcontainer">&nbsp;</td>
222
+ </tr>
223
+ </table>
224
+ </td>
225
+
226
+ <td>&nbsp;</td>
227
+ <td>&nbsp;</td>
228
+
229
+ <!-- <td class="column1"><label for="hover_color">{#fullpage_dlg.hover_color}</label></td>
230
+ <td>
231
+ <table border="0" cellpadding="0" cellspacing="0">
232
+ <tr>
233
+ <td><input id="hover_color" name="hover_color" type="text" value="" size="9" onchange="changedStyleField(this);" /></td>
234
+ <td id="hover_color_pickcontainer">&nbsp;</td>
235
+ </tr>
236
+ </table>
237
+ </td> -->
238
+ </tr>
239
+ </table>
240
+ </fieldset>
241
+
242
+ <fieldset>
243
+ <legend>{#fullpage_dlg.appearance_style}</legend>
244
+
245
+ <table border="0" cellpadding="4" cellspacing="0">
246
+ <tr>
247
+ <td class="column1"><label for="stylesheet">{#fullpage_dlg.stylesheet}</label></td>
248
+ <td><table border="0" cellpadding="0" cellspacing="0">
249
+ <tr>
250
+ <td><input id="stylesheet" name="stylesheet" type="text" value="" /></td>
251
+ <td id="stylesheet_browsercontainer">&nbsp;</td>
252
+ </tr>
253
+ </table></td>
254
+ </tr>
255
+ <tr>
256
+ <td class="column1"><label for="style">{#fullpage_dlg.style}</label></td>
257
+ <td><input id="style" name="style" type="text" value="" onchange="changedStyleField(this);" /></td>
258
+ </tr>
259
+ </table>
260
+ </fieldset>
261
+ </div>
262
+
263
+ <div id="advanced_panel" class="panel">
264
+ <div id="addmenu">
265
+ <table border="0" cellpadding="0" cellspacing="0">
266
+ <tr><td><a href="javascript:addHeadElm('title');" onmousedown="return false;"><span>{#fullpage_dlg.add_title}</span></a></td></tr>
267
+ <tr><td><a href="javascript:addHeadElm('meta');" onmousedown="return false;"><span>{#fullpage_dlg.add_meta}</span></a></td></tr>
268
+ <tr><td><a href="javascript:addHeadElm('script');" onmousedown="return false;"><span>{#fullpage_dlg.add_script}</span></a></td></tr>
269
+ <tr><td><a href="javascript:addHeadElm('style');" onmousedown="return false;"><span>{#fullpage_dlg.add_style}</span></a></td></tr>
270
+ <tr><td><a href="javascript:addHeadElm('link');" onmousedown="return false;"><span>{#fullpage_dlg.add_link}</span></a></td></tr>
271
+ <tr><td><a href="javascript:addHeadElm('base');" onmousedown="return false;"><span>{#fullpage_dlg.add_base}</span></a></td></tr>
272
+ <tr><td><a href="javascript:addHeadElm('comment');" onmousedown="return false;"><span>{#fullpage_dlg.add_comment}</span></a></td></tr>
273
+ </table>
274
+ </div>
275
+
276
+ <fieldset>
277
+ <legend>{#fullpage_dlg.head_elements}</legend>
278
+
279
+ <div class="headlistwrapper">
280
+ <div class="toolbar">
281
+ <div style="float: left">
282
+ <a id="addbutton" href="javascript:showAddMenu();" onmousedown="return false;" class="addbutton" title="{#fullpage_dlg.add}"></a>
283
+ <a href="#" onmousedown="return false;" class="removebutton" title="{#fullpage_dlg.remove}"></a>
284
+ </div>
285
+ <div style="float: right">
286
+ <a href="#" onmousedown="return false;" class="moveupbutton" title="{#fullpage_dlg.moveup}"></a>
287
+ <a href="#" onmousedown="return false;" class="movedownbutton" title="{#fullpage_dlg.movedown}"></a>
288
+ </div>
289
+ <br style="clear: both" />
290
+ </div>
291
+ <select id="headlist" size="26" onchange="updateHeadElm(this.options[this.selectedIndex].value);">
292
+ <option value="title_0">&lt;title&gt;Some title bla bla bla&lt;/title&gt;</option>
293
+ <option value="meta_1">&lt;meta name="keywords"&gt;Some bla bla bla&lt;/meta&gt;</option>
294
+ <option value="meta_2">&lt;meta name="description"&gt;Some bla bla bla bla bla bla bla bla bla&lt;/meta&gt;</option>
295
+ <option value="script_3">&lt;script language=&quot;javascript&quot;&gt;...&lt;/script&gt;</option>
296
+ <option value="style_4">&lt;style&gt;...&lt;/style&gt;</option>
297
+ <option value="base_5">&lt;base href="." /&gt;</option>
298
+ <option value="comment_6">&lt;!-- ... --&gt;</option>
299
+ <option value="link_7">&lt;link href="." /&gt;</option>
300
+ </select>
301
+ </div>
302
+ </fieldset>
303
+
304
+ <fieldset id="meta_element">
305
+ <legend>{#fullpage_dlg.meta_element}</legend>
306
+
307
+ <table border="0" cellpadding="4" cellspacing="0">
308
+ <tr>
309
+ <td class="column1"><label for="element_meta_type">{#fullpage_dlg.type}</label></td>
310
+ <td><select id="element_meta_type">
311
+ <option value="name">name</option>
312
+ <option value="http-equiv">http-equiv</option>
313
+ </select></td>
314
+ </tr>
315
+ <tr>
316
+ <td class="column1"><label for="element_meta_name">{#fullpage_dlg.name}</label></td>
317
+ <td><input id="element_meta_name" name="element_meta_name" type="text" value="" /></td>
318
+ </tr>
319
+ <tr>
320
+ <td class="column1"><label for="element_meta_content">{#fullpage_dlg.content}</label></td>
321
+ <td><input id="element_meta_content" name="element_meta_content" type="text" value="" /></td>
322
+ </tr>
323
+ </table>
324
+
325
+ <input type="button" id="meta_updateelement" class="updateElementButton" name="update" value="{#update}" onclick="updateElement();" />
326
+ </fieldset>
327
+
328
+ <fieldset id="title_element">
329
+ <legend>{#fullpage_dlg.title_element}</legend>
330
+
331
+ <table border="0" cellpadding="4" cellspacing="0">
332
+ <tr>
333
+ <td class="column1"><label for="element_title">{#fullpage_dlg.meta_title}</label></td>
334
+ <td><input id="element_title" name="element_title" type="text" value="" /></td>
335
+ </tr>
336
+ </table>
337
+
338
+ <input type="button" id="title_updateelement" class="updateElementButton" name="update" value="{#update}" onclick="updateElement();" />
339
+ </fieldset>
340
+
341
+ <fieldset id="script_element">
342
+ <legend>{#fullpage_dlg.script_element}</legend>
343
+
344
+ <div class="tabs">
345
+ <ul>
346
+ <li id="script_props_tab" class="current"><span><a href="javascript:mcTabs.displayTab('script_props_tab','script_props_panel');" onmousedown="return false;">{#fullpage_dlg.properties}</a></span></li>
347
+ <li id="script_value_tab"><span><a href="javascript:mcTabs.displayTab('script_value_tab','script_value_panel');" onmousedown="return false;">{#fullpage_dlg.value}</a></span></li>
348
+ </ul>
349
+ </div>
350
+
351
+ <br style="clear: both" />
352
+
353
+ <div class="panel_wrapper">
354
+ <div id="script_props_panel" class="panel current">
355
+ <table border="0" cellpadding="4" cellspacing="0">
356
+ <tr>
357
+ <td class="column1"><label for="element_script_type">{#fullpage_dlg.type}</label></td>
358
+ <td><select id="element_script_type">
359
+ <option value="text/javascript">text/javascript</option>
360
+ <option value="text/jscript">text/jscript</option>
361
+ <option value="text/vbscript">text/vbscript</option>
362
+ <option value="text/vbs">text/vbs</option>
363
+ <option value="text/ecmascript">text/ecmascript</option>
364
+ <option value="text/xml">text/xml</option>
365
+ </select></td>
366
+ </tr>
367
+ <tr>
368
+ <td class="column1"><label for="element_script_src">{#fullpage_dlg.src}</label></td>
369
+ <td><table border="0" cellpadding="0" cellspacing="0">
370
+ <tr>
371
+ <td><input id="element_script_src" name="element_script_src" type="text" value="" /></td>
372
+ <td id="script_src_pickcontainer">&nbsp;</td>
373
+ </tr>
374
+ </table></td>
375
+ </tr>
376
+ <tr>
377
+ <td class="column1"><label for="element_script_charset">{#fullpage_dlg.charset}</label></td>
378
+ <td><select id="element_script_charset"><option value="">{#not_set}</option></select></td>
379
+ </tr>
380
+ <tr>
381
+ <td class="column1"><label for="element_script_defer">{#fullpage_dlg.defer}</label></td>
382
+ <td><input type="checkbox" id="element_script_defer" name="element_script_defer" class="checkbox" /></td>
383
+ </tr>
384
+ </table>
385
+ </div>
386
+
387
+ <div id="script_value_panel" class="panel">
388
+ <textarea id="element_script_value"></textarea>
389
+ </div>
390
+ </div>
391
+
392
+ <input type="button" id="script_updateelement" class="updateElementButton" name="update" value="{#update}" onclick="updateElement();" />
393
+ </fieldset>
394
+
395
+ <fieldset id="style_element">
396
+ <legend>{#fullpage_dlg.style_element}</legend>
397
+
398
+ <div class="tabs">
399
+ <ul>
400
+ <li id="style_props_tab" class="current"><span><a href="javascript:mcTabs.displayTab('style_props_tab','style_props_panel');" onmousedown="return false;">{#fullpage_dlg.properties}</a></span></li>
401
+ <li id="style_value_tab"><span><a href="javascript:mcTabs.displayTab('style_value_tab','style_value_panel');" onmousedown="return false;">{#fullpage_dlg.value}</a></span></li>
402
+ </ul>
403
+ </div>
404
+
405
+ <br style="clear: both" />
406
+
407
+ <div class="panel_wrapper">
408
+ <div id="style_props_panel" class="panel current">
409
+ <table border="0" cellpadding="4" cellspacing="0">
410
+ <tr>
411
+ <td class="column1"><label for="element_style_type">{#fullpage_dlg.type}</label></td>
412
+ <td><select id="element_style_type">
413
+ <option value="text/css">text/css</option>
414
+ </select></td>
415
+ </tr>
416
+ <tr>
417
+ <td class="column1"><label for="element_style_media">{#fullpage_dlg.media}</label></td>
418
+ <td><select id="element_style_media"></select></td>
419
+ </tr>
420
+ </table>
421
+ </div>
422
+
423
+ <div id="style_value_panel" class="panel">
424
+ <textarea id="element_style_value"></textarea>
425
+ </div>
426
+ </div>
427
+
428
+ <input type="button" id="style_updateelement" class="updateElementButton" name="update" value="{#update}" onclick="updateElement();" />
429
+ </fieldset>
430
+
431
+ <fieldset id="base_element">
432
+ <legend>{#fullpage_dlg.base_element}</legend>
433
+
434
+ <table border="0" cellpadding="4" cellspacing="0">
435
+ <tr>
436
+ <td class="column1"><label for="element_base_href">{#fullpage_dlg.href}</label></td>
437
+ <td><input id="element_base_href" name="element_base_href" type="text" value="" /></td>
438
+ </tr>
439
+ <tr>
440
+ <td class="column1"><label for="element_base_target">{#fullpage_dlg.target}</label></td>
441
+ <td><input id="element_base_target" name="element_base_target" type="text" value="" /></td>
442
+ </tr>
443
+ </table>
444
+
445
+ <input type="button" id="base_updateelement" class="updateElementButton" name="update" value="{#update}" onclick="updateElement();" />
446
+ </fieldset>
447
+
448
+ <fieldset id="link_element">
449
+ <legend>{#fullpage_dlg.link_element}</legend>
450
+
451
+ <div class="tabs">
452
+ <ul>
453
+ <li id="link_general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('link_general_tab','link_general_panel');" onmousedown="return false;">{#fullpage_dlg.general_props}</a></span></li>
454
+ <li id="link_advanced_tab"><span><a href="javascript:mcTabs.displayTab('link_advanced_tab','link_advanced_panel');" onmousedown="return false;">{#fullpage_dlg.advanced_props}</a></span></li>
455
+ </ul>
456
+ </div>
457
+
458
+ <br style="clear: both" />
459
+
460
+ <div class="panel_wrapper">
461
+ <div id="link_general_panel" class="panel current">
462
+ <table border="0" cellpadding="4" cellspacing="0">
463
+ <tr>
464
+ <td class="column1"><label for="element_link_href">{#fullpage_dlg.href}</label></td>
465
+ <td><table border="0" cellpadding="0" cellspacing="0">
466
+ <tr>
467
+ <td><input id="element_link_href" name="element_link_href" type="text" value="" /></td>
468
+ <td id="link_href_pickcontainer">&nbsp;</td>
469
+ </tr>
470
+ </table></td>
471
+ </tr>
472
+ <tr>
473
+ <td class="column1"><label for="element_link_title">{#fullpage_dlg.meta_title}</label></td>
474
+ <td><input id="element_link_title" name="element_link_title" type="text" value="" /></td>
475
+ </tr>
476
+ <tr>
477
+ <td class="column1"><label for="element_link_type">{#fullpage_dlg.type}</label></td>
478
+ <td><select id="element_link_type" name="element_link_type">
479
+ <option value="text/css">text/css</option>
480
+ <option value="text/javascript">text/javascript</option>
481
+ </select></td>
482
+ </tr>
483
+ <tr>
484
+ <td class="column1"><label for="element_link_media">{#fullpage_dlg.media}</label></td>
485
+ <td><select id="element_link_media" name="element_link_media"></select></td>
486
+ </tr>
487
+ <tr>
488
+ <td><label for="element_style_rel">{#fullpage_dlg.rel}</label></td>
489
+ <td><select id="element_style_rel" name="element_style_rel">
490
+ <option value="">{#not_set}</option>
491
+ <option value="stylesheet">Stylesheet</option>
492
+ <option value="alternate">Alternate</option>
493
+ <option value="designates">Designates</option>
494
+ <option value="start">Start</option>
495
+ <option value="next">Next</option>
496
+ <option value="prev">Prev</option>
497
+ <option value="contents">Contents</option>
498
+ <option value="index">Index</option>
499
+ <option value="glossary">Glossary</option>
500
+ <option value="copyright">Copyright</option>
501
+ <option value="chapter">Chapter</option>
502
+ <option value="subsection">Subsection</option>
503
+ <option value="appendix">Appendix</option>
504
+ <option value="help">Help</option>
505
+ <option value="bookmark">Bookmark</option>
506
+ </select>
507
+ </td>
508
+ </tr>
509
+ </table>
510
+ </div>
511
+
512
+ <div id="link_advanced_panel" class="panel">
513
+ <table border="0" cellpadding="4" cellspacing="0">
514
+ <tr>
515
+ <td class="column1"><label for="element_link_charset">{#fullpage_dlg.charset}</label></td>
516
+ <td><select id="element_link_charset"><option value="">{#not_set}</option></select></td>
517
+ </tr>
518
+ <tr>
519
+ <td class="column1"><label for="element_link_hreflang">{#fullpage_dlg.hreflang}</label></td>
520
+ <td><input id="element_link_hreflang" name="element_link_hreflang" type="text" value="" /></td>
521
+ </tr>
522
+ <tr>
523
+ <td class="column1"><label for="element_link_target">{#fullpage_dlg.target}</label></td>
524
+ <td><input id="element_link_target" name="element_link_target" type="text" value="" /></td>
525
+ </tr>
526
+ <tr>
527
+ <td><label for="element_style_rev">{#fullpage_dlg.rev}</label></td>
528
+ <td><select id="element_style_rev" name="element_style_rev">
529
+ <option value="">{#not_set}</option>
530
+ <option value="alternate">Alternate</option>
531
+ <option value="designates">Designates</option>
532
+ <option value="stylesheet">Stylesheet</option>
533
+ <option value="start">Start</option>
534
+ <option value="next">Next</option>
535
+ <option value="prev">Prev</option>
536
+ <option value="contents">Contents</option>
537
+ <option value="index">Index</option>
538
+ <option value="glossary">Glossary</option>
539
+ <option value="copyright">Copyright</option>
540
+ <option value="chapter">Chapter</option>
541
+ <option value="subsection">Subsection</option>
542
+ <option value="appendix">Appendix</option>
543
+ <option value="help">Help</option>
544
+ <option value="bookmark">Bookmark</option>
545
+ </select>
546
+ </td>
547
+ </tr>
548
+ </table>
549
+ </div>
550
+ </div>
551
+
552
+ <input type="button" id="link_updateelement" class="updateElementButton" name="update" value="{#update}" onclick="updateElement();" />
553
+ </fieldset>
554
+
555
+ <fieldset id="comment_element">
556
+ <legend>{#fullpage_dlg.comment_element}</legend>
557
+
558
+ <textarea id="element_comment_value"></textarea>
559
+
560
+ <input type="button" id="comment_updateelement" class="updateElementButton" name="update" value="{#update}" onclick="updateElement();" />
561
+ </fieldset>
562
+ </div>
563
+ </div>
564
+
565
+ <div class="mceActionPanel">
566
+ <input type="submit" id="insert" name="update" value="{#update}" />
567
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
568
+ </div>
569
+ </form>
570
+ </body>
571
+ </html>
tinymce-plugins/3.3.x/fullpage/js/fullpage.js ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * fullpage.js
3
+ *
4
+ * Copyright 2009, Moxiecode Systems AB
5
+ * Released under LGPL License.
6
+ *
7
+ * License: http://tinymce.moxiecode.com/license
8
+ * Contributing: http://tinymce.moxiecode.com/contributing
9
+ */
10
+
11
+ tinyMCEPopup.requireLangPack();
12
+
13
+ var doc;
14
+
15
+ var defaultDocTypes =
16
+ 'XHTML 1.0 Transitional=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">,' +
17
+ 'XHTML 1.0 Frameset=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">,' +
18
+ 'XHTML 1.0 Strict=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">,' +
19
+ 'XHTML 1.1=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">,' +
20
+ 'HTML 4.01 Transitional=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">,' +
21
+ 'HTML 4.01 Strict=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">,' +
22
+ 'HTML 4.01 Frameset=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">';
23
+
24
+ var defaultEncodings =
25
+ 'Western european (iso-8859-1)=iso-8859-1,' +
26
+ 'Central European (iso-8859-2)=iso-8859-2,' +
27
+ 'Unicode (UTF-8)=utf-8,' +
28
+ 'Chinese traditional (Big5)=big5,' +
29
+ 'Cyrillic (iso-8859-5)=iso-8859-5,' +
30
+ 'Japanese (iso-2022-jp)=iso-2022-jp,' +
31
+ 'Greek (iso-8859-7)=iso-8859-7,' +
32
+ 'Korean (iso-2022-kr)=iso-2022-kr,' +
33
+ 'ASCII (us-ascii)=us-ascii';
34
+
35
+ var defaultMediaTypes =
36
+ 'all=all,' +
37
+ 'screen=screen,' +
38
+ 'print=print,' +
39
+ 'tty=tty,' +
40
+ 'tv=tv,' +
41
+ 'projection=projection,' +
42
+ 'handheld=handheld,' +
43
+ 'braille=braille,' +
44
+ 'aural=aural';
45
+
46
+ var defaultFontNames = 'Arial=arial,helvetica,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,times new roman,times,serif;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times,serif;Verdana=verdana,arial,helvetica,sans-serif;Impact=impact;WingDings=wingdings';
47
+ var defaultFontSizes = '10px,11px,12px,13px,14px,15px,16px';
48
+
49
+ function init() {
50
+ var f = document.forms['fullpage'], el = f.elements, e, i, p, doctypes, encodings, mediaTypes, fonts, ed = tinyMCEPopup.editor, dom = tinyMCEPopup.dom, style;
51
+
52
+ // Setup doctype select box
53
+ doctypes = ed.getParam("fullpage_doctypes", defaultDocTypes).split(',');
54
+ for (i=0; i<doctypes.length; i++) {
55
+ p = doctypes[i].split('=');
56
+
57
+ if (p.length > 1)
58
+ addSelectValue(f, 'doctypes', p[0], p[1]);
59
+ }
60
+
61
+ // Setup fonts select box
62
+ fonts = ed.getParam("fullpage_fonts", defaultFontNames).split(';');
63
+ for (i=0; i<fonts.length; i++) {
64
+ p = fonts[i].split('=');
65
+
66
+ if (p.length > 1)
67
+ addSelectValue(f, 'fontface', p[0], p[1]);
68
+ }
69
+
70
+ // Setup fontsize select box
71
+ fonts = ed.getParam("fullpage_fontsizes", defaultFontSizes).split(',');
72
+ for (i=0; i<fonts.length; i++)
73
+ addSelectValue(f, 'fontsize', fonts[i], fonts[i]);
74
+
75
+ // Setup mediatype select boxs
76
+ mediaTypes = ed.getParam("fullpage_media_types", defaultMediaTypes).split(',');
77
+ for (i=0; i<mediaTypes.length; i++) {
78
+ p = mediaTypes[i].split('=');
79
+
80
+ if (p.length > 1) {
81
+ addSelectValue(f, 'element_style_media', p[0], p[1]);
82
+ addSelectValue(f, 'element_link_media', p[0], p[1]);
83
+ }
84
+ }
85
+
86
+ // Setup encodings select box
87
+ encodings = ed.getParam("fullpage_encodings", defaultEncodings).split(',');
88
+ for (i=0; i<encodings.length; i++) {
89
+ p = encodings[i].split('=');
90
+
91
+ if (p.length > 1) {
92
+ addSelectValue(f, 'docencoding', p[0], p[1]);
93
+ addSelectValue(f, 'element_script_charset', p[0], p[1]);
94
+ addSelectValue(f, 'element_link_charset', p[0], p[1]);
95
+ }
96
+ }
97
+
98
+ document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
99
+ document.getElementById('link_color_pickcontainer').innerHTML = getColorPickerHTML('link_color_pick','link_color');
100
+ //document.getElementById('hover_color_pickcontainer').innerHTML = getColorPickerHTML('hover_color_pick','hover_color');
101
+ document.getElementById('visited_color_pickcontainer').innerHTML = getColorPickerHTML('visited_color_pick','visited_color');
102
+ document.getElementById('active_color_pickcontainer').innerHTML = getColorPickerHTML('active_color_pick','active_color');
103
+ document.getElementById('textcolor_pickcontainer').innerHTML = getColorPickerHTML('textcolor_pick','textcolor');
104
+ document.getElementById('stylesheet_browsercontainer').innerHTML = getBrowserHTML('stylesheetbrowser','stylesheet','file','fullpage');
105
+ document.getElementById('link_href_pickcontainer').innerHTML = getBrowserHTML('link_href_browser','element_link_href','file','fullpage');
106
+ document.getElementById('script_src_pickcontainer').innerHTML = getBrowserHTML('script_src_browser','element_script_src','file','fullpage');
107
+ document.getElementById('bgimage_pickcontainer').innerHTML = getBrowserHTML('bgimage_browser','bgimage','image','fullpage');
108
+
109
+ // Resize some elements
110
+ if (isVisible('stylesheetbrowser'))
111
+ document.getElementById('stylesheet').style.width = '220px';
112
+
113
+ if (isVisible('link_href_browser'))
114
+ document.getElementById('element_link_href').style.width = '230px';
115
+
116
+ if (isVisible('bgimage_browser'))
117
+ document.getElementById('bgimage').style.width = '210px';
118
+
119
+ // Add iframe
120
+ dom.add(document.body, 'iframe', {id : 'documentIframe', src : 'javascript:""', style : {display : 'none'}});
121
+ doc = dom.get('documentIframe').contentWindow.document;
122
+ h = tinyMCEPopup.getWindowArg('head_html');
123
+
124
+ // Preprocess the HTML disable scripts and urls
125
+ h = h.replace(/<script>/gi, '<script type="text/javascript">');
126
+ h = h.replace(/type=([\"\'])?/gi, 'type=$1-mce-');
127
+ h = h.replace(/(src=|href=)/g, '_mce_$1');
128
+
129
+ // Write in the content in the iframe
130
+ doc.write(h + '</body></html>');
131
+ doc.close();
132
+
133
+ // Parse xml and doctype
134
+ xmlVer = getReItem(/<\?\s*?xml.*?version\s*?=\s*?"(.*?)".*?\?>/gi, h, 1);
135
+ xmlEnc = getReItem(/<\?\s*?xml.*?encoding\s*?=\s*?"(.*?)".*?\?>/gi, h, 1);
136
+ docType = getReItem(/<\!DOCTYPE.*?>/gi, h.replace(/\n/g, ''), 0).replace(/ +/g, ' ');
137
+ f.langcode.value = getReItem(/lang="(.*?)"/gi, h, 1);
138
+
139
+ // Parse title
140
+ if (e = doc.getElementsByTagName('title')[0])
141
+ el.metatitle.value = e.textContent || e.text;
142
+
143
+ // Parse meta
144
+ tinymce.each(doc.getElementsByTagName('meta'), function(n) {
145
+ var na = (n.getAttribute('name', 2) || '').toLowerCase(), va = n.getAttribute('content', 2), eq = n.getAttribute('httpEquiv', 2) || '';
146
+
147
+ e = el['meta' + na];
148
+
149
+ if (na == 'robots') {
150
+ selectByValue(f, 'metarobots', tinymce.trim(va), true, true);
151
+ return;
152
+ }
153
+
154
+ switch (eq.toLowerCase()) {
155
+ case "content-type":
156
+ tmp = getReItem(/charset\s*=\s*(.*)\s*/gi, va, 1);
157
+
158
+ // Override XML encoding
159
+ if (tmp != "")
160
+ xmlEnc = tmp;
161
+
162
+ return;
163
+ }
164
+
165
+ if (e)
166
+ e.value = va;
167
+ });
168
+
169
+ selectByValue(f, 'doctypes', docType, true, true);
170
+ selectByValue(f, 'docencoding', xmlEnc, true, true);
171
+ selectByValue(f, 'langdir', doc.body.getAttribute('dir', 2) || '', true, true);
172
+
173
+ if (xmlVer != '')
174
+ el.xml_pi.checked = true;
175
+
176
+ // Parse appearance
177
+
178
+ // Parse primary stylesheet
179
+ tinymce.each(doc.getElementsByTagName("link"), function(l) {
180
+ var m = l.getAttribute('media', 2) || '', t = l.getAttribute('type', 2) || '';
181
+
182
+ if (t == "-mce-text/css" && (m == "" || m == "screen" || m == "all") && (l.getAttribute('rel', 2) || '') == "stylesheet") {
183
+ f.stylesheet.value = l.getAttribute('_mce_href', 2) || '';
184
+ return false;
185
+ }
186
+ });
187
+
188
+ // Get from style elements
189
+ tinymce.each(doc.getElementsByTagName("style"), function(st) {
190
+ var tmp = parseStyleElement(st);
191
+
192
+ for (x=0; x<tmp.length; x++) {
193
+ if (tmp[x].rule.indexOf('a:visited') != -1 && tmp[x].data['color'])
194
+ f.visited_color.value = tmp[x].data['color'];
195
+
196
+ if (tmp[x].rule.indexOf('a:link') != -1 && tmp[x].data['color'])
197
+ f.link_color.value = tmp[x].data['color'];
198
+
199
+ if (tmp[x].rule.indexOf('a:active') != -1 && tmp[x].data['color'])
200
+ f.active_color.value = tmp[x].data['color'];
201
+ }
202
+ });
203
+
204
+ f.textcolor.value = tinyMCEPopup.dom.getAttrib(doc.body, "text");
205
+ f.active_color.value = tinyMCEPopup.dom.getAttrib(doc.body, "alink");
206
+ f.link_color.value = tinyMCEPopup.dom.getAttrib(doc.body, "link");
207
+ f.visited_color.value = tinyMCEPopup.dom.getAttrib(doc.body, "vlink");
208
+ f.bgcolor.value = tinyMCEPopup.dom.getAttrib(doc.body, "bgcolor");
209
+ f.bgimage.value = tinyMCEPopup.dom.getAttrib(doc.body, "background");
210
+
211
+ // Get from style info
212
+ style = tinyMCEPopup.dom.parseStyle(tinyMCEPopup.dom.getAttrib(doc.body, 'style'));
213
+
214
+ if (style['font-family'])
215
+ selectByValue(f, 'fontface', style['font-family'], true, true);
216
+ else
217
+ selectByValue(f, 'fontface', ed.getParam("fullpage_default_fontface", ""), true, true);
218
+
219
+ if (style['font-size'])
220
+ selectByValue(f, 'fontsize', style['font-size'], true, true);
221
+ else
222
+ selectByValue(f, 'fontsize', ed.getParam("fullpage_default_fontsize", ""), true, true);
223
+
224
+ if (style['color'])
225
+ f.textcolor.value = convertRGBToHex(style['color']);
226
+
227
+ if (style['background-image'])
228
+ f.bgimage.value = style['background-image'].replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
229
+
230
+ if (style['background-color'])
231
+ f.bgcolor.value = style['background-color'];
232
+
233
+ if (style['margin']) {
234
+ tmp = style['margin'].replace(/[^0-9 ]/g, '');
235
+ tmp = tmp.split(/ +/);
236
+ f.topmargin.value = tmp.length > 0 ? tmp[0] : '';
237
+ f.rightmargin.value = tmp.length > 1 ? tmp[1] : tmp[0];
238
+ f.bottommargin.value = tmp.length > 2 ? tmp[2] : tmp[0];
239
+ f.leftmargin.value = tmp.length > 3 ? tmp[3] : tmp[0];
240
+ }
241
+
242
+ if (style['margin-left'])
243
+ f.leftmargin.value = style['margin-left'].replace(/[^0-9]/g, '');
244
+
245
+ if (style['margin-right'])
246
+ f.rightmargin.value = style['margin-right'].replace(/[^0-9]/g, '');
247
+
248
+ if (style['margin-top'])
249
+ f.topmargin.value = style['margin-top'].replace(/[^0-9]/g, '');
250
+
251
+ if (style['margin-bottom'])
252
+ f.bottommargin.value = style['margin-bottom'].replace(/[^0-9]/g, '');
253
+
254
+ f.style.value = tinyMCEPopup.dom.serializeStyle(style);
255
+
256
+ // Update colors
257
+ updateColor('textcolor_pick', 'textcolor');
258
+ updateColor('bgcolor_pick', 'bgcolor');
259
+ updateColor('visited_color_pick', 'visited_color');
260
+ updateColor('active_color_pick', 'active_color');
261
+ updateColor('link_color_pick', 'link_color');
262
+ }
263
+
264
+ function getReItem(r, s, i) {
265
+ var c = r.exec(s);
266
+
267
+ if (c && c.length > i)
268
+ return c[i];
269
+
270
+ return '';
271
+ }
272
+
273
+ function updateAction() {
274
+ var f = document.forms[0], nl, i, h, v, s, head, html, l, tmp, addlink = true, ser;
275
+
276
+ head = doc.getElementsByTagName('head')[0];
277
+
278
+ // Fix scripts without a type
279
+ nl = doc.getElementsByTagName('script');
280
+ for (i=0; i<nl.length; i++) {
281
+ if (tinyMCEPopup.dom.getAttrib(nl[i], '_mce_type') == '')
282
+ nl[i].setAttribute('_mce_type', 'text/javascript');
283
+ }
284
+
285
+ // Get primary stylesheet
286
+ nl = doc.getElementsByTagName("link");
287
+ for (i=0; i<nl.length; i++) {
288
+ l = nl[i];
289
+
290
+ tmp = tinyMCEPopup.dom.getAttrib(l, 'media');
291
+
292
+ if (tinyMCEPopup.dom.getAttrib(l, '_mce_type') == "text/css" && (tmp == "" || tmp == "screen" || tmp == "all") && tinyMCEPopup.dom.getAttrib(l, 'rel') == "stylesheet") {
293
+ addlink = false;
294
+
295
+ if (f.stylesheet.value == '')
296
+ l.parentNode.removeChild(l);
297
+ else
298
+ l.setAttribute('_mce_href', f.stylesheet.value);
299
+
300
+ break;
301
+ }
302
+ }
303
+
304
+ // Add new link
305
+ if (f.stylesheet.value != '') {
306
+ l = doc.createElement('link');
307
+
308
+ l.setAttribute('type', 'text/css');
309
+ l.setAttribute('_mce_href', f.stylesheet.value);
310
+ l.setAttribute('rel', 'stylesheet');
311
+
312
+ head.appendChild(l);
313
+ }
314
+
315
+ setMeta(head, 'keywords', f.metakeywords.value);
316
+ setMeta(head, 'description', f.metadescription.value);
317
+ setMeta(head, 'author', f.metaauthor.value);
318
+ setMeta(head, 'copyright', f.metacopyright.value);
319
+ setMeta(head, 'robots', getSelectValue(f, 'metarobots'));
320
+ setMeta(head, 'Content-Type', getSelectValue(f, 'docencoding'));
321
+
322
+ doc.body.dir = getSelectValue(f, 'langdir');
323
+ doc.body.style.cssText = f.style.value;
324
+
325
+ doc.body.setAttribute('vLink', f.visited_color.value);
326
+ doc.body.setAttribute('link', f.link_color.value);
327
+ doc.body.setAttribute('text', f.textcolor.value);
328
+ doc.body.setAttribute('aLink', f.active_color.value);
329
+
330
+ doc.body.style.fontFamily = getSelectValue(f, 'fontface');
331
+ doc.body.style.fontSize = getSelectValue(f, 'fontsize');
332
+ doc.body.style.backgroundColor = f.bgcolor.value;
333
+
334
+ if (f.leftmargin.value != '')
335
+ doc.body.style.marginLeft = f.leftmargin.value + 'px';
336
+
337
+ if (f.rightmargin.value != '')
338
+ doc.body.style.marginRight = f.rightmargin.value + 'px';
339
+
340
+ if (f.bottommargin.value != '')
341
+ doc.body.style.marginBottom = f.bottommargin.value + 'px';
342
+
343
+ if (f.topmargin.value != '')
344
+ doc.body.style.marginTop = f.topmargin.value + 'px';
345
+
346
+ html = doc.getElementsByTagName('html')[0];
347
+ html.setAttribute('lang', f.langcode.value);
348
+ html.setAttribute('xml:lang', f.langcode.value);
349
+
350
+ if (f.bgimage.value != '')
351
+ doc.body.style.backgroundImage = "url('" + f.bgimage.value + "')";
352
+ else
353
+ doc.body.style.backgroundImage = '';
354
+
355
+ ser = tinyMCEPopup.editor.plugins.fullpage._createSerializer();
356
+ ser.setRules('-title,meta[http-equiv|name|content],base[href|target],link[href|rel|type|title|media],style[type],script[type|language|src],html[lang|xml::lang|xmlns],body[style|dir|vlink|link|text|alink],head');
357
+
358
+ h = ser.serialize(doc.documentElement);
359
+ h = h.substring(0, h.lastIndexOf('</body>'));
360
+
361
+ if (h.indexOf('<title>') == -1)
362
+ h = h.replace(/<head.*?>/, '$&\n' + '<title>' + tinyMCEPopup.dom.encode(f.metatitle.value) + '</title>');
363
+ else
364
+ h = h.replace(/<title>(.*?)<\/title>/, '<title>' + tinyMCEPopup.dom.encode(f.metatitle.value) + '</title>');
365
+
366
+ if ((v = getSelectValue(f, 'doctypes')) != '')
367
+ h = v + '\n' + h;
368
+
369
+ if (f.xml_pi.checked) {
370
+ s = '<?xml version="1.0"';
371
+
372
+ if ((v = getSelectValue(f, 'docencoding')) != '')
373
+ s += ' encoding="' + v + '"';
374
+
375
+ s += '?>\n';
376
+ h = s + h;
377
+ }
378
+
379
+ h = h.replace(/type=\"\-mce\-/gi, 'type="');
380
+
381
+ tinyMCEPopup.editor.plugins.fullpage.head = h;
382
+ tinyMCEPopup.editor.plugins.fullpage._setBodyAttribs(tinyMCEPopup.editor, {});
383
+ tinyMCEPopup.close();
384
+ }
385
+
386
+ function changedStyleField(field) {
387
+ }
388
+
389
+ function setMeta(he, k, v) {
390
+ var nl, i, m;
391
+
392
+ nl = he.getElementsByTagName('meta');
393
+ for (i=0; i<nl.length; i++) {
394
+ if (k == 'Content-Type' && tinyMCEPopup.dom.getAttrib(nl[i], 'http-equiv') == k) {
395
+ if (v == '')
396
+ nl[i].parentNode.removeChild(nl[i]);
397
+ else
398
+ nl[i].setAttribute('content', "text/html; charset=" + v);
399
+
400
+ return;
401
+ }
402
+
403
+ if (tinyMCEPopup.dom.getAttrib(nl[i], 'name') == k) {
404
+ if (v == '')
405
+ nl[i].parentNode.removeChild(nl[i]);
406
+ else
407
+ nl[i].setAttribute('content', v);
408
+ return;
409
+ }
410
+ }
411
+
412
+ if (v == '')
413
+ return;
414
+
415
+ m = doc.createElement('meta');
416
+
417
+ if (k == 'Content-Type')
418
+ m.httpEquiv = k;
419
+ else
420
+ m.setAttribute('name', k);
421
+
422
+ m.setAttribute('content', v);
423
+ he.appendChild(m);
424
+ }
425
+
426
+ function parseStyleElement(e) {
427
+ var v = e.innerHTML;
428
+ var p, i, r;
429
+
430
+ v = v.replace(/<!--/gi, '');
431
+ v = v.replace(/-->/gi, '');
432
+ v = v.replace(/[\n\r]/gi, '');
433
+ v = v.replace(/\s+/gi, ' ');
434
+
435
+ r = [];
436
+ p = v.split(/{|}/);
437
+
438
+ for (i=0; i<p.length; i+=2) {
439
+ if (p[i] != "")
440
+ r[r.length] = {rule : tinymce.trim(p[i]), data : tinyMCEPopup.dom.parseStyle(p[i+1])};
441
+ }
442
+
443
+ return r;
444
+ }
445
+
446
+ function serializeStyleElement(d) {
447
+ var i, s, st;
448
+
449
+ s = '<!--\n';
450
+
451
+ for (i=0; i<d.length; i++) {
452
+ s += d[i].rule + ' {\n';
453
+
454
+ st = tinyMCE.serializeStyle(d[i].data);
455
+
456
+ if (st != '')
457
+ st += ';';
458
+
459
+ s += st.replace(/;/g, ';\n');
460
+ s += '}\n';
461
+
462
+ if (i != d.length - 1)
463
+ s += '\n';
464
+ }
465
+
466
+ s += '\n-->';
467
+
468
+ return s;
469
+ }
470
+
471
+ tinyMCEPopup.onInit.add(init);
tinymce-plugins/3.3.x/fullpage/langs/en_dlg.js ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ tinyMCE.addI18n('en.fullpage_dlg',{
2
+ title:"Document properties",
3
+ meta_tab:"General",
4
+ appearance_tab:"Appearance",
5
+ advanced_tab:"Advanced",
6
+ meta_props:"Meta information",
7
+ langprops:"Language and encoding",
8
+ meta_title:"Title",
9
+ meta_keywords:"Keywords",
10
+ meta_description:"Description",
11
+ meta_robots:"Robots",
12
+ doctypes:"Doctype",
13
+ langcode:"Language code",
14
+ langdir:"Language direction",
15
+ ltr:"Left to right",
16
+ rtl:"Right to left",
17
+ xml_pi:"XML declaration",
18
+ encoding:"Character encoding",
19
+ appearance_bgprops:"Background properties",
20
+ appearance_marginprops:"Body margins",
21
+ appearance_linkprops:"Link colors",
22
+ appearance_textprops:"Text properties",
23
+ bgcolor:"Background color",
24
+ bgimage:"Background image",
25
+ left_margin:"Left margin",
26
+ right_margin:"Right margin",
27
+ top_margin:"Top margin",
28
+ bottom_margin:"Bottom margin",
29
+ text_color:"Text color",
30
+ font_size:"Font size",
31
+ font_face:"Font face",
32
+ link_color:"Link color",
33
+ hover_color:"Hover color",
34
+ visited_color:"Visited color",
35
+ active_color:"Active color",
36
+ textcolor:"Color",
37
+ fontsize:"Font size",
38
+ fontface:"Font family",
39
+ meta_index_follow:"Index and follow the links",
40
+ meta_index_nofollow:"Index and don't follow the links",
41
+ meta_noindex_follow:"Do not index but follow the links",
42
+ meta_noindex_nofollow:"Do not index and don\'t follow the links",
43
+ appearance_style:"Stylesheet and style properties",
44
+ stylesheet:"Stylesheet",
45
+ style:"Style",
46
+ author:"Author",
47
+ copyright:"Copyright",
48
+ add:"Add new element",
49
+ remove:"Remove selected element",
50
+ moveup:"Move selected element up",
51
+ movedown:"Move selected element down",
52
+ head_elements:"Head elements",
53
+ info:"Information",
54
+ add_title:"Title element",
55
+ add_meta:"Meta element",
56
+ add_script:"Script element",
57
+ add_style:"Style element",
58
+ add_link:"Link element",
59
+ add_base:"Base element",
60
+ add_comment:"Comment node",
61
+ title_element:"Title element",
62
+ script_element:"Script element",
63
+ style_element:"Style element",
64
+ base_element:"Base element",
65
+ link_element:"Link element",
66
+ meta_element:"Meta element",
67
+ comment_element:"Comment",
68
+ src:"Src",
69
+ language:"Language",
70
+ href:"Href",
71
+ target:"Target",
72
+ type:"Type",
73
+ charset:"Charset",
74
+ defer:"Defer",
75
+ media:"Media",
76
+ properties:"Properties",
77
+ name:"Name",
78
+ value:"Value",
79
+ content:"Content",
80
+ rel:"Rel",
81
+ rev:"Rev",
82
+ hreflang:"Href lang",
83
+ general_props:"General",
84
+ advanced_props:"Advanced"
85
+ });
tinymce-plugins/3.4.x/fullpage/css/fullpage.css ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Hide the advanced tab */
2
+ #advanced_tab {
3
+ display: none;
4
+ }
5
+
6
+ #metatitle, #metakeywords, #metadescription, #metaauthor, #metacopyright {
7
+ width: 280px;
8
+ }
9
+
10
+ #doctype, #docencoding {
11
+ width: 200px;
12
+ }
13
+
14
+ #langcode {
15
+ width: 30px;
16
+ }
17
+
18
+ #bgimage {
19
+ width: 220px;
20
+ }
21
+
22
+ #fontface {
23
+ width: 240px;
24
+ }
25
+
26
+ #leftmargin, #rightmargin, #topmargin, #bottommargin {
27
+ width: 50px;
28
+ }
29
+
30
+ .panel_wrapper div.current {
31
+ height: 400px;
32
+ }
33
+
34
+ #stylesheet, #style {
35
+ width: 240px;
36
+ }
37
+
38
+ #doctypes {
39
+ width: 200px;
40
+ }
41
+
42
+ /* Head list classes */
43
+
44
+ .headlistwrapper {
45
+ width: 100%;
46
+ }
47
+
48
+ .selected {
49
+ border: 1px solid #0A246A;
50
+ background-color: #B6BDD2;
51
+ }
52
+
53
+ .toolbar {
54
+ width: 100%;
55
+ }
56
+
57
+ #headlist {
58
+ width: 100%;
59
+ margin-top: 3px;
60
+ font-size: 11px;
61
+ }
62
+
63
+ #info, #title_element, #meta_element, #script_element, #style_element, #base_element, #link_element, #comment_element, #unknown_element {
64
+ display: none;
65
+ }
66
+
67
+ #addmenu {
68
+ position: absolute;
69
+ border: 1px solid gray;
70
+ display: none;
71
+ z-index: 100;
72
+ background-color: white;
73
+ }
74
+
75
+ #addmenu a {
76
+ display: block;
77
+ width: 100%;
78
+ line-height: 20px;
79
+ text-decoration: none;
80
+ background-color: white;
81
+ }
82
+
83
+ #addmenu a:hover {
84
+ background-color: #B6BDD2;
85
+ color: black;
86
+ }
87
+
88
+ #addmenu span {
89
+ padding-left: 10px;
90
+ padding-right: 10px;
91
+ }
92
+
93
+ #updateElementPanel {
94
+ display: none;
95
+ }
96
+
97
+ #script_element .panel_wrapper div.current {
98
+ height: 108px;
99
+ }
100
+
101
+ #style_element .panel_wrapper div.current {
102
+ height: 108px;
103
+ }
104
+
105
+ #link_element .panel_wrapper div.current {
106
+ height: 140px;
107
+ }
108
+
109
+ #element_script_value {
110
+ width: 100%;
111
+ height: 100px;
112
+ }
113
+
114
+ #element_comment_value {
115
+ width: 100%;
116
+ height: 120px;
117
+ }
118
+
119
+ #element_style_value {
120
+ width: 100%;
121
+ height: 100px;
122
+ }
123
+
124
+ #element_title, #element_script_src, #element_meta_name, #element_meta_content, #element_base_href, #element_link_href, #element_link_title {
125
+ width: 250px;
126
+ }
127
+
128
+ .updateElementButton {
129
+ margin-top: 3px;
130
+ }
131
+
132
+ /* MSIE specific styles */
133
+
134
+ * html .addbutton, * html .removebutton, * html .moveupbutton, * html .movedownbutton {
135
+ width: 22px;
136
+ height: 22px;
137
+ }
138
+
139
+ textarea {
140
+ height: 55px;
141
+ }
142
+
143
+ .panel_wrapper div.current {height:420px;}
tinymce-plugins/3.4.x/fullpage/editor_plugin.js ADDED
@@ -0,0 +1 @@
 
1
+ (function(){var b=tinymce.each,a=tinymce.html.Node;tinymce.create("tinymce.plugins.FullPagePlugin",{init:function(c,d){var e=this;e.editor=c;c.addCommand("mceFullPageProperties",function(){c.windowManager.open({file:d+"/fullpage.htm",width:430+parseInt(c.getLang("fullpage.delta_width",0)),height:495+parseInt(c.getLang("fullpage.delta_height",0)),inline:1},{plugin_url:d,data:e._htmlToData()})});c.addButton("fullpage",{title:"fullpage.desc",cmd:"mceFullPageProperties"});c.onBeforeSetContent.add(e._setContent,e);c.onGetContent.add(e._getContent,e)},getInfo:function(){return{longname:"Fullpage",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_htmlToData:function(){var f=this._parseHeader(),h={},c,i,g,e=this.editor;function d(l,j){var k=l.attr(j);return k||""}h.fontface=e.getParam("fullpage_default_fontface","");h.fontsize=e.getParam("fullpage_default_fontsize","");i=f.firstChild;if(i.type==7){h.xml_pi=true;g=/encoding="([^"]+)"/.exec(i.value);if(g){h.docencoding=g[1]}}i=f.getAll("#doctype")[0];if(i){h.doctype="<!DOCTYPE"+i.value+">"}i=f.getAll("title")[0];if(i&&i.firstChild){h.metatitle=i.firstChild.value}b(f.getAll("meta"),function(m){var k=m.attr("name"),j=m.attr("http-equiv"),l;if(k){h["meta"+k.toLowerCase()]=m.attr("content")}else{if(j=="Content-Type"){l=/charset\s*=\s*(.*)\s*/gi.exec(m.attr("content"));if(l){h.docencoding=l[1]}}}});i=f.getAll("html")[0];if(i){h.langcode=d(i,"lang")||d(i,"xml:lang")}i=f.getAll("link")[0];if(i&&i.attr("rel")=="stylesheet"){h.stylesheet=i.attr("href")}i=f.getAll("body")[0];if(i){h.langdir=d(i,"dir");h.style=d(i,"style");h.visited_color=d(i,"vlink");h.link_color=d(i,"link");h.active_color=d(i,"alink")}return h},_dataToHtml:function(g){var f,d,h,j,k,e=this.editor.dom;function c(n,l,m){n.attr(l,m?m:undefined)}function i(l){if(d.firstChild){d.insert(l,d.firstChild)}else{d.append(l)}}f=this._parseHeader();d=f.getAll("head")[0];if(!d){j=f.getAll("html")[0];d=new a("head",1);if(j.firstChild){j.insert(d,j.firstChild,true)}else{j.append(d)}}j=f.firstChild;if(g.xml_pi){k='version="1.0"';if(g.docencoding){k+=' encoding="'+g.docencoding+'"'}if(j.type!=7){j=new a("xml",7);f.insert(j,f.firstChild,true)}j.value=k}else{if(j&&j.type==7){j.remove()}}j=f.getAll("#doctype")[0];if(g.doctype){if(!j){j=new a("#doctype",10);if(g.xml_pi){f.insert(j,f.firstChild)}else{i(j)}}j.value=g.doctype.substring(9,g.doctype.length-1)}else{if(j){j.remove()}}j=f.getAll("title")[0];if(g.metatitle){if(!j){j=new a("title",1);j.append(new a("#text",3)).value=g.metatitle;i(j)}}if(g.docencoding){j=null;b(f.getAll("meta"),function(l){if(l.attr("http-equiv")=="Content-Type"){j=l}});if(!j){j=new a("meta",1);j.attr("http-equiv","Content-Type");j.shortEnded=true;i(j)}j.attr("content","text/html; charset="+g.docencoding)}b("keywords,description,author,copyright,robots".split(","),function(m){var l=f.getAll("meta"),n,p,o=g["meta"+m];for(n=0;n<l.length;n++){p=l[n];if(p.attr("name")==m){if(o){p.attr("content",o)}else{p.remove()}return}}if(o){j=new a("meta",1);j.attr("name",m);j.attr("content",o);j.shortEnded=true;i(j)}});j=f.getAll("link")[0];if(j&&j.attr("rel")=="stylesheet"){if(g.stylesheet){j.attr("href",g.stylesheet)}else{j.remove()}}else{if(g.stylesheet){j=new a("link",1);j.attr({rel:"stylesheet",text:"text/css",href:g.stylesheet});j.shortEnded=true;i(j)}}j=f.getAll("body")[0];if(j){c(j,"dir",g.langdir);c(j,"style",g.style);c(j,"vlink",g.visited_color);c(j,"link",g.link_color);c(j,"alink",g.active_color);e.setAttribs(this.editor.getBody(),{style:g.style,dir:g.dir,vLink:g.visited_color,link:g.link_color,aLink:g.active_color})}j=f.getAll("html")[0];if(j){c(j,"lang",g.langcode);c(j,"xml:lang",g.langcode)}h=new tinymce.html.Serializer({validate:false,indent:true,apply_source_formatting:true,indent_before:"head,html,body,meta,title,script,link,style",indent_after:"head,html,body,meta,title,script,link,style"}).serialize(f);this.head=h.substring(0,h.indexOf("</body>"))},_parseHeader:function(){return new tinymce.html.DomParser({validate:false,root_name:"#document"}).parse(this.head)},_setContent:function(g,d){var m=this,i,c,h=d.content,f,l="",e=m.editor.dom,j;function k(n){return n.replace(/<\/?[A-Z]+/g,function(o){return o.toLowerCase()})}if(d.format=="raw"&&m.head){return}if(d.source_view&&g.getParam("fullpage_hide_in_source_view")){return}h=h.replace(/<(\/?)BODY/gi,"<$1body");i=h.indexOf("<body");if(i!=-1){i=h.indexOf(">",i);m.head=k(h.substring(0,i+1));c=h.indexOf("</body",i);if(c==-1){c=h.length}d.content=h.substring(i+1,c);m.foot=k(h.substring(c))}else{m.head=this._getDefaultHeader();m.foot="\n</body>\n</html>"}f=m._parseHeader();b(f.getAll("style"),function(n){if(n.firstChild){l+=n.firstChild.value}});j=f.getAll("body")[0];if(j){e.setAttribs(m.editor.getBody(),{style:j.attr("style")||"",dir:j.attr("dir")||"",vLink:j.attr("vlink")||"",link:j.attr("link")||"",aLink:j.attr("alink")||""})}if(l){e.add(m.editor.getDoc().getElementsByTagName("head")[0],"style",{id:"fullpage_styles"},l)}else{e.remove("fullpage_styles")}},_getDefaultHeader:function(){var f="",c=this.editor,e,d="";if(c.getParam("fullpage_default_xml_pi")){f+='<?xml version="1.0" encoding="'+c.getParam("fullpage_default_encoding","ISO-8859-1")+'" ?>\n'}f+=c.getParam("fullpage_default_doctype",'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');f+="\n<html>\n<head>\n";if(e=c.getParam("fullpage_default_title")){f+="<title>"+e+"</title>\n"}if(e=c.getParam("fullpage_default_encoding")){f+='<meta http-equiv="Content-Type" content="text/html; charset='+e+'" />\n'}if(e=c.getParam("fullpage_default_font_family")){d+="font-family: "+e+";"}if(e=c.getParam("fullpage_default_font_size")){d+="font-size: "+e+";"}if(e=c.getParam("fullpage_default_text_color")){d+="color: "+e+";"}f+="</head>\n<body"+(d?' style="'+d+'"':"")+">\n";return f},_getContent:function(d,e){var c=this;if(!e.source_view||!d.getParam("fullpage_hide_in_source_view")){e.content=tinymce.trim(c.head)+"\n"+tinymce.trim(e.content)+"\n"+tinymce.trim(c.foot)}}});tinymce.PluginManager.add("fullpage",tinymce.plugins.FullPagePlugin)})();
tinymce-plugins/3.4.x/fullpage/editor_plugin_src.js ADDED
@@ -0,0 +1,399 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * editor_plugin_src.js
3
+ *
4
+ * Copyright 2009, Moxiecode Systems AB
5
+ * Released under LGPL License.
6
+ *
7
+ * License: http://tinymce.moxiecode.com/license
8
+ * Contributing: http://tinymce.moxiecode.com/contributing
9
+ */
10
+
11
+ (function() {
12
+ var each = tinymce.each, Node = tinymce.html.Node;
13
+
14
+ tinymce.create('tinymce.plugins.FullPagePlugin', {
15
+ init : function(ed, url) {
16
+ var t = this;
17
+
18
+ t.editor = ed;
19
+
20
+ // Register commands
21
+ ed.addCommand('mceFullPageProperties', function() {
22
+ ed.windowManager.open({
23
+ file : url + '/fullpage.htm',
24
+ width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)),
25
+ height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)),
26
+ inline : 1
27
+ }, {
28
+ plugin_url : url,
29
+ data : t._htmlToData()
30
+ });
31
+ });
32
+
33
+ // Register buttons
34
+ ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'});
35
+
36
+ ed.onBeforeSetContent.add(t._setContent, t);
37
+ ed.onGetContent.add(t._getContent, t);
38
+ },
39
+
40
+ getInfo : function() {
41
+ return {
42
+ longname : 'Fullpage',
43
+ author : 'Moxiecode Systems AB',
44
+ authorurl : 'http://tinymce.moxiecode.com',
45
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage',
46
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
47
+ };
48
+ },
49
+
50
+ // Private plugin internal methods
51
+
52
+ _htmlToData : function() {
53
+ var headerFragment = this._parseHeader(), data = {}, nodes, elm, matches, editor = this.editor;
54
+
55
+ function getAttr(elm, name) {
56
+ var value = elm.attr(name);
57
+
58
+ return value || '';
59
+ };
60
+
61
+ // Default some values
62
+ data.fontface = editor.getParam("fullpage_default_fontface", "");
63
+ data.fontsize = editor.getParam("fullpage_default_fontsize", "");
64
+
65
+ // Parse XML PI
66
+ elm = headerFragment.firstChild;
67
+ if (elm.type == 7) {
68
+ data.xml_pi = true;
69
+ matches = /encoding="([^"]+)"/.exec(elm.value);
70
+ if (matches)
71
+ data.docencoding = matches[1];
72
+ }
73
+
74
+ // Parse doctype
75
+ elm = headerFragment.getAll('#doctype')[0];
76
+ if (elm)
77
+ data.doctype = '<!DOCTYPE' + elm.value + ">";
78
+
79
+ // Parse title element
80
+ elm = headerFragment.getAll('title')[0];
81
+ if (elm && elm.firstChild) {
82
+ data.metatitle = elm.firstChild.value;
83
+ }
84
+
85
+ // Parse meta elements
86
+ each(headerFragment.getAll('meta'), function(meta) {
87
+ var name = meta.attr('name'), httpEquiv = meta.attr('http-equiv'), matches;
88
+
89
+ if (name)
90
+ data['meta' + name.toLowerCase()] = meta.attr('content');
91
+ else if (httpEquiv == "Content-Type") {
92
+ matches = /charset\s*=\s*(.*)\s*/gi.exec(meta.attr('content'));
93
+
94
+ if (matches)
95
+ data.docencoding = matches[1];
96
+ }
97
+ });
98
+
99
+ // Parse html attribs
100
+ elm = headerFragment.getAll('html')[0];
101
+ if (elm)
102
+ data.langcode = getAttr(elm, 'lang') || getAttr(elm, 'xml:lang');
103
+
104
+ // Parse stylesheet
105
+ elm = headerFragment.getAll('link')[0];
106
+ if (elm && elm.attr('rel') == 'stylesheet')
107
+ data.stylesheet = elm.attr('href');
108
+
109
+ // Parse body parts
110
+ elm = headerFragment.getAll('body')[0];
111
+ if (elm) {
112
+ data.langdir = getAttr(elm, 'dir');
113
+ data.style = getAttr(elm, 'style');
114
+ data.visited_color = getAttr(elm, 'vlink');
115
+ data.link_color = getAttr(elm, 'link');
116
+ data.active_color = getAttr(elm, 'alink');
117
+ }
118
+
119
+ return data;
120
+ },
121
+
122
+ _dataToHtml : function(data) {
123
+ var headerFragment, headElement, html, elm, value, dom = this.editor.dom;
124
+
125
+ function setAttr(elm, name, value) {
126
+ elm.attr(name, value ? value : undefined);
127
+ };
128
+
129
+ function addHeadNode(node) {
130
+ if (headElement.firstChild)
131
+ headElement.insert(node, headElement.firstChild);
132
+ else
133
+ headElement.append(node);
134
+ };
135
+
136
+ headerFragment = this._parseHeader();
137
+ headElement = headerFragment.getAll('head')[0];
138
+ if (!headElement) {
139
+ elm = headerFragment.getAll('html')[0];
140
+ headElement = new Node('head', 1);
141
+
142
+ if (elm.firstChild)
143
+ elm.insert(headElement, elm.firstChild, true);
144
+ else
145
+ elm.append(headElement);
146
+ }
147
+
148
+ // Add/update/remove XML-PI
149
+ elm = headerFragment.firstChild;
150
+ if (data.xml_pi) {
151
+ value = 'version="1.0"';
152
+
153
+ if (data.docencoding)
154
+ value += ' encoding="' + data.docencoding + '"';
155
+
156
+ if (elm.type != 7) {
157
+ elm = new Node('xml', 7);
158
+ headerFragment.insert(elm, headerFragment.firstChild, true);
159
+ }
160
+
161
+ elm.value = value;
162
+ } else if (elm && elm.type == 7)
163
+ elm.remove();
164
+
165
+ // Add/update/remove doctype
166
+ elm = headerFragment.getAll('#doctype')[0];
167
+ if (data.doctype) {
168
+ if (!elm) {
169
+ elm = new Node('#doctype', 10);
170
+
171
+ if (data.xml_pi)
172
+ headerFragment.insert(elm, headerFragment.firstChild);
173
+ else
174
+ addHeadNode(elm);
175
+ }
176
+
177
+ elm.value = data.doctype.substring(9, data.doctype.length - 1);
178
+ } else if (elm)
179
+ elm.remove();
180
+
181
+ // Add/update/remove title
182
+ elm = headerFragment.getAll('title')[0];
183
+ if (data.metatitle) {
184
+ if (!elm) {
185
+ elm = new Node('title', 1);
186
+ elm.append(new Node('#text', 3)).value = data.metatitle;
187
+ addHeadNode(elm);
188
+ }
189
+ }
190
+
191
+ // Add meta encoding
192
+ if (data.docencoding) {
193
+ elm = null;
194
+ each(headerFragment.getAll('meta'), function(meta) {
195
+ if (meta.attr('http-equiv') == 'Content-Type')
196
+ elm = meta;
197
+ });
198
+
199
+ if (!elm) {
200
+ elm = new Node('meta', 1);
201
+ elm.attr('http-equiv', 'Content-Type');
202
+ elm.shortEnded = true;
203
+ addHeadNode(elm);
204
+ }
205
+
206
+ elm.attr('content', 'text/html; charset=' + data.docencoding);
207
+ }
208
+
209
+ // Add/update/remove meta
210
+ each('keywords,description,author,copyright,robots'.split(','), function(name) {
211
+ var nodes = headerFragment.getAll('meta'), i, meta, value = data['meta' + name];
212
+
213
+ for (i = 0; i < nodes.length; i++) {
214
+ meta = nodes[i];
215
+
216
+ if (meta.attr('name') == name) {
217
+ if (value)
218
+ meta.attr('content', value);
219
+ else
220
+ meta.remove();
221
+
222
+ return;
223
+ }
224
+ }
225
+
226
+ if (value) {
227
+ elm = new Node('meta', 1);
228
+ elm.attr('name', name);
229
+ elm.attr('content', value);
230
+ elm.shortEnded = true;
231
+
232
+ addHeadNode(elm);
233
+ }
234
+ });
235
+
236
+ // Add/update/delete link
237
+ elm = headerFragment.getAll('link')[0];
238
+ if (elm && elm.attr('rel') == 'stylesheet') {
239
+ if (data.stylesheet)
240
+ elm.attr('href', data.stylesheet);
241
+ else
242
+ elm.remove();
243
+ } else if (data.stylesheet) {
244
+ elm = new Node('link', 1);
245
+ elm.attr({
246
+ rel : 'stylesheet',
247
+ text : 'text/css',
248
+ href : data.stylesheet
249
+ });
250
+ elm.shortEnded = true;
251
+
252
+ addHeadNode(elm);
253
+ }
254
+
255
+ // Update body attributes
256
+ elm = headerFragment.getAll('body')[0];
257
+ if (elm) {
258
+ setAttr(elm, 'dir', data.langdir);
259
+ setAttr(elm, 'style', data.style);
260
+ setAttr(elm, 'vlink', data.visited_color);
261
+ setAttr(elm, 'link', data.link_color);
262
+ setAttr(elm, 'alink', data.active_color);
263
+
264
+ // Update iframe body as well
265
+ dom.setAttribs(this.editor.getBody(), {
266
+ style : data.style,
267
+ dir : data.dir,
268
+ vLink : data.visited_color,
269
+ link : data.link_color,
270
+ aLink : data.active_color
271
+ });
272
+ }
273
+
274
+ // Set html attributes
275
+ elm = headerFragment.getAll('html')[0];
276
+ if (elm) {
277
+ setAttr(elm, 'lang', data.langcode);
278
+ setAttr(elm, 'xml:lang', data.langcode);
279
+ }
280
+
281
+ // Serialize header fragment and crop away body part
282
+ html = new tinymce.html.Serializer({
283
+ validate: false,
284
+ indent: true,
285
+ apply_source_formatting : true,
286
+ indent_before: 'head,html,body,meta,title,script,link,style',
287
+ indent_after: 'head,html,body,meta,title,script,link,style'
288
+ }).serialize(headerFragment);
289
+
290
+ this.head = html.substring(0, html.indexOf('</body>'));
291
+ },
292
+
293
+ _parseHeader : function() {
294
+ // Parse the contents with a DOM parser
295
+ return new tinymce.html.DomParser({
296
+ validate: false,
297
+ root_name: '#document'
298
+ }).parse(this.head);
299
+ },
300
+
301
+ _setContent : function(ed, o) {
302
+ var self = this, startPos, endPos, content = o.content, headerFragment, styles = '', dom = self.editor.dom, elm;
303
+
304
+ function low(s) {
305
+ return s.replace(/<\/?[A-Z]+/g, function(a) {
306
+ return a.toLowerCase();
307
+ })
308
+ };
309
+
310
+ // Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate
311
+ if (o.format == 'raw' && self.head)
312
+ return;
313
+
314
+ if (o.source_view && ed.getParam('fullpage_hide_in_source_view'))
315
+ return;
316
+
317
+ // Parse out head, body and footer
318
+ content = content.replace(/<(\/?)BODY/gi, '<$1body');
319
+ startPos = content.indexOf('<body');
320
+
321
+ if (startPos != -1) {
322
+ startPos = content.indexOf('>', startPos);
323
+ self.head = low(content.substring(0, startPos + 1));
324
+
325
+ endPos = content.indexOf('</body', startPos);
326
+ if (endPos == -1)
327
+ endPos = content.length;
328
+
329
+ o.content = content.substring(startPos + 1, endPos);
330
+ self.foot = low(content.substring(endPos));
331
+ } else {
332
+ self.head = this._getDefaultHeader();
333
+ self.foot = '\n</body>\n</html>';
334
+ }
335
+
336
+ // Parse header and update iframe
337
+ headerFragment = self._parseHeader();
338
+ each(headerFragment.getAll('style'), function(node) {
339
+ if (node.firstChild)
340
+ styles += node.firstChild.value;
341
+ });
342
+
343
+ elm = headerFragment.getAll('body')[0];
344
+ if (elm) {
345
+ dom.setAttribs(self.editor.getBody(), {
346
+ style : elm.attr('style') || '',
347
+ dir : elm.attr('dir') || '',
348
+ vLink : elm.attr('vlink') || '',
349
+ link : elm.attr('link') || '',
350
+ aLink : elm.attr('alink') || ''
351
+ });
352
+ }
353
+
354
+ if (styles)
355
+ dom.add(self.editor.getDoc().getElementsByTagName('head')[0], 'style', {id : 'fullpage_styles'}, styles);
356
+ else
357
+ dom.remove('fullpage_styles');
358
+ },
359
+
360
+ _getDefaultHeader : function() {
361
+ var header = '', editor = this.editor, value, styles = '';
362
+
363
+ if (editor.getParam('fullpage_default_xml_pi'))
364
+ header += '<?xml version="1.0" encoding="' + editor.getParam('fullpage_default_encoding', 'ISO-8859-1') + '" ?>\n';
365
+
366
+ header += editor.getParam('fullpage_default_doctype', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
367
+ header += '\n<html>\n<head>\n';
368
+
369
+ if (value = editor.getParam('fullpage_default_title'))
370
+ header += '<title>' + value + '</title>\n';
371
+
372
+ if (value = editor.getParam('fullpage_default_encoding'))
373
+ header += '<meta http-equiv="Content-Type" content="text/html; charset=' + value + '" />\n';
374
+
375
+ if (value = editor.getParam('fullpage_default_font_family'))
376
+ styles += 'font-family: ' + value + ';';
377
+
378
+ if (value = editor.getParam('fullpage_default_font_size'))
379
+ styles += 'font-size: ' + value + ';';
380
+
381
+ if (value = editor.getParam('fullpage_default_text_color'))
382
+ styles += 'color: ' + value + ';';
383
+
384
+ header += '</head>\n<body' + (styles ? ' style="' + styles + '"' : '') + '>\n';
385
+
386
+ return header;
387
+ },
388
+
389
+ _getContent : function(ed, o) {
390
+ var self = this;
391
+
392
+ if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view'))
393
+ o.content = tinymce.trim(self.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(self.foot);
394
+ }
395
+ });
396
+
397
+ // Register plugin
398
+ tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin);
399
+ })();
tinymce-plugins/3.4.x/fullpage/fullpage.htm ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <title>{#fullpage_dlg.title}</title>
5
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
6
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
7
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
8
+ <script type="text/javascript" src="js/fullpage.js"></script>
9
+ <link href="css/fullpage.css" rel="stylesheet" type="text/css" />
10
+ </head>
11
+ <body id="fullpage" style="display: none">
12
+ <form onsubmit="FullPageDialog.update();return false;" name="fullpage" action="#">
13
+ <div class="tabs">
14
+ <ul>
15
+ <li id="meta_tab" class="current"><span><a href="javascript:mcTabs.displayTab('meta_tab','meta_panel');" onmousedown="return false;">{#fullpage_dlg.meta_tab}</a></span></li>
16
+ <li id="appearance_tab"><span><a href="javascript:mcTabs.displayTab('appearance_tab','appearance_panel');" onmousedown="return false;">{#fullpage_dlg.appearance_tab}</a></span></li>
17
+ </ul>
18
+ </div>
19
+
20
+ <div class="panel_wrapper">
21
+ <div id="meta_panel" class="panel current">
22
+ <fieldset>
23
+ <legend>{#fullpage_dlg.meta_props}</legend>
24
+
25
+ <table border="0" cellpadding="4" cellspacing="0">
26
+ <tr>
27
+ <td class="nowrap"><label for="metatitle">{#fullpage_dlg.meta_title}</label>&nbsp;</td>
28
+ <td><input type="text" id="metatitle" name="metatitle" value="" class="mceFocus" /></td>
29
+ </tr>
30
+ <tr>
31
+ <td class="nowrap"><label for="metakeywords">{#fullpage_dlg.meta_keywords}</label>&nbsp;</td>
32
+ <td><textarea id="metakeywords" name="metakeywords" rows="4"></textarea></td>
33
+ </tr>
34
+ <tr>
35
+ <td class="nowrap"><label for="metadescription">{#fullpage_dlg.meta_description}</label>&nbsp;</td>
36
+ <td><textarea id="metadescription" name="metadescription" rows="4"></textarea></td>
37
+ </tr>
38
+ <tr>
39
+ <td class="nowrap"><label for="metaauthor">{#fullpage_dlg.author}</label>&nbsp;</td>
40
+ <td><input type="text" id="metaauthor" name="metaauthor" value="" /></td>
41
+ </tr>
42
+ <tr>
43
+ <td class="nowrap"><label for="metacopyright">{#fullpage_dlg.copyright}</label>&nbsp;</td>
44
+ <td><input type="text" id="metacopyright" name="metacopyright" value="" /></td>
45
+ </tr>
46
+ <tr>
47
+ <td class="nowrap"><label for="metarobots">{#fullpage_dlg.meta_robots}</label>&nbsp;</td>
48
+ <td>
49
+ <select id="metarobots" name="metarobots">
50
+ <option value="">{#not_set}</option>
51
+ <option value="index,follow">{#fullpage_dlg.meta_index_follow}</option>
52
+ <option value="index,nofollow">{#fullpage_dlg.meta_index_nofollow}</option>
53
+ <option value="noindex,follow">{#fullpage_dlg.meta_noindex_follow}</option>
54
+ <option value="noindex,nofollow">{#fullpage_dlg.meta_noindex_nofollow}</option>
55
+ </select>
56
+ </td>
57
+ </tr>
58
+ </table>
59
+ </fieldset>
60
+
61
+ <fieldset>
62
+ <legend>{#fullpage_dlg.langprops}</legend>
63
+
64
+ <table border="0" cellpadding="4" cellspacing="0">
65
+ <tr>
66
+ <td class="column1"><label for="docencoding">{#fullpage_dlg.encoding}</label></td>
67
+ <td>
68
+ <select id="docencoding" name="docencoding">
69
+ <option value="">{#not_set}</option>
70
+ </select>
71
+ </td>
72
+ </tr>
73
+ <tr>
74
+ <td class="nowrap"><label for="doctype">{#fullpage_dlg.doctypes}</label>&nbsp;</td>
75
+ <td>
76
+ <select id="doctype" name="doctype">
77
+ <option value="">{#not_set}</option>
78
+ </select>
79
+ </td>
80
+ </tr>
81
+ <tr>
82
+ <td class="nowrap"><label for="langcode">{#fullpage_dlg.langcode}</label>&nbsp;</td>
83
+ <td><input type="text" id="langcode" name="langcode" value="" /></td>
84
+ </tr>
85
+ <tr>
86
+ <td class="column1"><label for="langdir">{#fullpage_dlg.langdir}</label></td>
87
+ <td>
88
+ <select id="langdir" name="langdir">
89
+ <option value="">{#not_set}</option>
90
+ <option value="ltr">{#fullpage_dlg.ltr}</option>
91
+ <option value="rtl">{#fullpage_dlg.rtl}</option>
92
+ </select>
93
+ </td>
94
+ </tr>
95
+ <tr>
96
+ <td class="nowrap"><label for="xml_pi">{#fullpage_dlg.xml_pi}</label>&nbsp;</td>
97
+ <td><input type="checkbox" id="xml_pi" name="xml_pi" class="checkbox" /></td>
98
+ </tr>
99
+ </table>
100
+ </fieldset>
101
+ </div>
102
+
103
+ <div id="appearance_panel" class="panel">
104
+ <fieldset>
105
+ <legend>{#fullpage_dlg.appearance_textprops}</legend>
106
+
107
+ <table border="0" cellpadding="4" cellspacing="0">
108
+ <tr>
109
+ <td class="column1"><label for="fontface">{#fullpage_dlg.fontface}</label></td>
110
+ <td>
111
+ <select id="fontface" name="fontface" onchange="FullPageDialog.changedStyleProp();">
112
+ <option value="">{#not_set}</option>
113
+ </select>
114
+ </td>
115
+ </tr>
116
+
117
+ <tr>
118
+ <td class="column1"><label for="fontsize">{#fullpage_dlg.fontsize}</label></td>
119
+ <td>
120
+ <select id="fontsize" name="fontsize" onchange="FullPageDialog.changedStyleProp();">
121
+ <option value="">{#not_set}</option>
122
+ </select>
123
+ </td>
124
+ </tr>
125
+
126
+ <tr>
127
+ <td class="column1"><label for="textcolor">{#fullpage_dlg.textcolor}</label></td>
128
+ <td>
129
+ <table border="0" cellpadding="0" cellspacing="0">
130
+ <tr>
131
+ <td><input id="textcolor" name="textcolor" type="text" value="" size="9" onchange="updateColor('textcolor_pick','textcolor');FullPageDialog.changedStyleProp();" /></td>
132
+ <td id="textcolor_pickcontainer">&nbsp;</td>
133
+ </tr>
134
+ </table>
135
+ </td>
136
+ </tr>
137
+ </table>
138
+ </fieldset>
139
+
140
+ <fieldset>
141
+ <legend>{#fullpage_dlg.appearance_bgprops}</legend>
142
+
143
+ <table border="0" cellpadding="4" cellspacing="0">
144
+ <tr>
145
+ <td class="column1"><label for="bgimage">{#fullpage_dlg.bgimage}</label></td>
146
+ <td>
147
+ <table border="0" cellpadding="0" cellspacing="0">
148
+ <tr>
149
+ <td><input id="bgimage" name="bgimage" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
150
+ <td id="bgimage_pickcontainer">&nbsp;</td>
151
+ </tr>
152
+ </table>
153
+ </td>
154
+ </tr>
155
+ <tr>
156
+ <td class="column1"><label for="bgcolor">{#fullpage_dlg.bgcolor}</label></td>
157
+ <td>
158
+ <table border="0" cellpadding="0" cellspacing="0">
159
+ <tr>
160
+ <td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');FullPageDialog.changedStyleProp();" /></td>
161
+ <td id="bgcolor_pickcontainer">&nbsp;</td>
162
+ </tr>
163
+ </table>
164
+ </td>
165
+ </tr>
166
+ </table>
167
+ </fieldset>
168
+
169
+ <fieldset>
170
+ <legend>{#fullpage_dlg.appearance_marginprops}</legend>
171
+
172
+ <table border="0" cellpadding="4" cellspacing="0">
173
+ <tr>
174
+ <td class="column1"><label for="leftmargin">{#fullpage_dlg.left_margin}</label></td>
175
+ <td><input id="leftmargin" name="leftmargin" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
176
+ <td class="column1"><label for="rightmargin">{#fullpage_dlg.right_margin}</label></td>
177
+ <td><input id="rightmargin" name="rightmargin" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
178
+ </tr>
179
+ <tr>
180
+ <td class="column1"><label for="topmargin">{#fullpage_dlg.top_margin}</label></td>
181
+ <td><input id="topmargin" name="topmargin" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
182
+ <td class="column1"><label for="bottommargin">{#fullpage_dlg.bottom_margin}</label></td>
183
+ <td><input id="bottommargin" name="bottommargin" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
184
+ </tr>
185
+ </table>
186
+ </fieldset>
187
+
188
+ <fieldset>
189
+ <legend>{#fullpage_dlg.appearance_linkprops}</legend>
190
+
191
+ <table border="0" cellpadding="4" cellspacing="0">
192
+ <tr>
193
+ <td class="column1"><label for="link_color">{#fullpage_dlg.link_color}</label></td>
194
+ <td>
195
+ <table border="0" cellpadding="0" cellspacing="0">
196
+ <tr>
197
+ <td><input id="link_color" name="link_color" type="text" value="" size="9" onchange="updateColor('link_color_pick','link_color');FullPageDialog.changedStyleProp();" /></td>
198
+ <td id="link_color_pickcontainer">&nbsp;</td>
199
+ </tr>
200
+ </table>
201
+ </td>
202
+
203
+ <td class="column1"><label for="visited_color">{#fullpage_dlg.visited_color}</label></td>
204
+ <td>
205
+ <table border="0" cellpadding="0" cellspacing="0">
206
+ <tr>
207
+ <td><input id="visited_color" name="visited_color" type="text" value="" size="9" onchange="updateColor('visited_color_pick','visited_color');FullPageDialog.changedStyleProp();" /></td>
208
+ <td id="visited_color_pickcontainer">&nbsp;</td>
209
+ </tr>
210
+ </table>
211
+ </td>
212
+ </tr>
213
+
214
+ <tr>
215
+ <td class="column1"><label for="active_color">{#fullpage_dlg.active_color}</label></td>
216
+ <td>
217
+ <table border="0" cellpadding="0" cellspacing="0">
218
+ <tr>
219
+ <td><input id="active_color" name="active_color" type="text" value="" size="9" onchange="updateColor('active_color_pick','active_color');FullPageDialog.changedStyleProp();" /></td>
220
+ <td id="active_color_pickcontainer">&nbsp;</td>
221
+ </tr>
222
+ </table>
223
+ </td>
224
+
225
+ <td>&nbsp;</td>
226
+ <td>&nbsp;</td>
227
+ </tr>
228
+ </table>
229
+ </fieldset>
230
+
231
+ <fieldset>
232
+ <legend>{#fullpage_dlg.appearance_style}</legend>
233
+
234
+ <table border="0" cellpadding="4" cellspacing="0">
235
+ <tr>
236
+ <td class="column1"><label for="stylesheet">{#fullpage_dlg.stylesheet}</label></td>
237
+ <td><table border="0" cellpadding="0" cellspacing="0">
238
+ <tr>
239
+ <td><input id="stylesheet" name="stylesheet" type="text" value="" /></td>
240
+ <td id="stylesheet_browsercontainer">&nbsp;</td>
241
+ </tr>
242
+ </table></td>
243
+ </tr>
244
+ <tr>
245
+ <td class="column1"><label for="style">{#fullpage_dlg.style}</label></td>
246
+ <td><input id="style" name="style" type="text" value="" onchange="FullPageDialog.changedStyle();" /></td>
247
+ </tr>
248
+ </table>
249
+ </fieldset>
250
+ </div>
251
+ </div>
252
+
253
+ <div class="mceActionPanel">
254
+ <input type="submit" id="insert" name="update" value="{#update}" />
255
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
256
+ </div>
257
+ </form>
258
+ </body>
259
+ </html>
tinymce-plugins/3.4.x/fullpage/js/fullpage.js ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * fullpage.js
3
+ *
4
+ * Copyright 2009, Moxiecode Systems AB
5
+ * Released under LGPL License.
6
+ *
7
+ * License: http://tinymce.moxiecode.com/license
8
+ * Contributing: http://tinymce.moxiecode.com/contributing
9
+ */
10
+
11
+ (function() {
12
+ tinyMCEPopup.requireLangPack();
13
+
14
+ var defaultDocTypes =
15
+ 'XHTML 1.0 Transitional=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">,' +
16
+ 'XHTML 1.0 Frameset=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">,' +
17
+ 'XHTML 1.0 Strict=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">,' +
18
+ 'XHTML 1.1=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">,' +
19
+ 'HTML 4.01 Transitional=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">,' +
20
+ 'HTML 4.01 Strict=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">,' +
21
+ 'HTML 4.01 Frameset=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">';
22
+
23
+ var defaultEncodings =
24
+ 'Western european (iso-8859-1)=iso-8859-1,' +
25
+ 'Central European (iso-8859-2)=iso-8859-2,' +
26
+ 'Unicode (UTF-8)=utf-8,' +
27
+ 'Chinese traditional (Big5)=big5,' +
28
+ 'Cyrillic (iso-8859-5)=iso-8859-5,' +
29
+ 'Japanese (iso-2022-jp)=iso-2022-jp,' +
30
+ 'Greek (iso-8859-7)=iso-8859-7,' +
31
+ 'Korean (iso-2022-kr)=iso-2022-kr,' +
32
+ 'ASCII (us-ascii)=us-ascii';
33
+
34
+ var defaultFontNames = 'Arial=arial,helvetica,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,times new roman,times,serif;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times,serif;Verdana=verdana,arial,helvetica,sans-serif;Impact=impact;WingDings=wingdings';
35
+ var defaultFontSizes = '10px,11px,12px,13px,14px,15px,16px';
36
+
37
+ function setVal(id, value) {
38
+ var elm = document.getElementById(id);
39
+
40
+ if (elm) {
41
+ value = value || '';
42
+
43
+ if (elm.nodeName == "SELECT")
44
+ selectByValue(document.forms[0], id, value);
45
+ else if (elm.type == "checkbox")
46
+ elm.checked = !!value;
47
+ else
48
+ elm.value = value;
49
+ }
50
+ };
51
+
52
+ function getVal(id) {
53
+ var elm = document.getElementById(id);
54
+
55
+ if (elm.nodeName == "SELECT")
56
+ return elm.options[elm.selectedIndex].value;
57
+
58
+ if (elm.type == "checkbox")
59
+ return elm.checked;
60
+
61
+ return elm.value;
62
+ };
63
+
64
+ window.FullPageDialog = {
65
+ changedStyle : function() {
66
+ var val, styles = tinyMCEPopup.editor.dom.parseStyle(getVal('style'));
67
+
68
+ setVal('fontface', styles['font-face']);
69
+ setVal('fontsize', styles['font-size']);
70
+ setVal('textcolor', styles['color']);
71
+
72
+ if (val = styles['background-image'])
73
+ setVal('bgimage', val.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1"));
74
+ else
75
+ setVal('bgimage', '');
76
+
77
+ setVal('bgcolor', styles['background-color']);
78
+
79
+ // Reset margin form elements
80
+ setVal('topmargin', '');
81
+ setVal('rightmargin', '');
82
+ setVal('bottommargin', '');
83
+ setVal('leftmargin', '');
84
+
85
+ // Expand margin
86
+ if (val = styles['margin']) {
87
+ val = val.split(' ');
88
+ styles['margin-top'] = val[0] || '';
89
+ styles['margin-right'] = val[1] || val[0] || '';
90
+ styles['margin-bottom'] = val[2] || val[0] || '';
91
+ styles['margin-left'] = val[3] || val[0] || '';
92
+ }
93
+
94
+ if (val = styles['margin-top'])
95
+ setVal('topmargin', val.replace(/px/, ''));
96
+
97
+ if (val = styles['margin-right'])
98
+ setVal('rightmargin', val.replace(/px/, ''));
99
+
100
+ if (val = styles['margin-bottom'])
101
+ setVal('bottommargin', val.replace(/px/, ''));
102
+
103
+ if (val = styles['margin-left'])
104
+ setVal('leftmargin', val.replace(/px/, ''));
105
+
106
+ updateColor('bgcolor_pick', 'bgcolor');
107
+ updateColor('textcolor_pick', 'textcolor');
108
+ },
109
+
110
+ changedStyleProp : function() {
111
+ var val, dom = tinyMCEPopup.editor.dom, styles = dom.parseStyle(getVal('style'));
112
+
113
+ styles['font-face'] = getVal('fontface');
114
+ styles['font-size'] = getVal('fontsize');
115
+ styles['color'] = getVal('textcolor');
116
+ styles['background-color'] = getVal('bgcolor');
117
+
118
+ if (val = getVal('bgimage'))
119
+ styles['background-image'] = "url('" + val + "')";
120
+ else
121
+ styles['background-image'] = '';
122
+
123
+ delete styles['margin'];
124
+
125
+ if (val = getVal('topmargin'))
126
+ styles['margin-top'] = val + "px";
127
+ else
128
+ styles['margin-top'] = '';
129
+
130
+ if (val = getVal('rightmargin'))
131
+ styles['margin-right'] = val + "px";
132
+ else
133
+ styles['margin-right'] = '';
134
+
135
+ if (val = getVal('bottommargin'))
136
+ styles['margin-bottom'] = val + "px";
137
+ else
138
+ styles['margin-bottom'] = '';
139
+
140
+ if (val = getVal('leftmargin'))
141
+ styles['margin-left'] = val + "px";
142
+ else
143
+ styles['margin-left'] = '';
144
+
145
+ // Serialize, parse and reserialize this will compress redundant styles
146
+ setVal('style', dom.serializeStyle(dom.parseStyle(dom.serializeStyle(styles))));
147
+ this.changedStyle();
148
+ },
149
+
150
+ update : function() {
151
+ var data = {};
152
+
153
+ tinymce.each(tinyMCEPopup.dom.select('select,input,textarea'), function(node) {
154
+ data[node.id] = getVal(node.id);
155
+ });
156
+
157
+ tinyMCEPopup.editor.plugins.fullpage._dataToHtml(data);
158
+ tinyMCEPopup.close();
159
+ }
160
+ };
161
+
162
+ function init() {
163
+ var form = document.forms[0], i, item, list, editor = tinyMCEPopup.editor;
164
+
165
+ // Setup doctype select box
166
+ list = editor.getParam("fullpage_doctypes", defaultDocTypes).split(',');
167
+ for (i = 0; i < list.length; i++) {
168
+ item = list[i].split('=');
169
+
170
+ if (item.length > 1)
171
+ addSelectValue(form, 'doctype', item[0], item[1]);
172
+ }
173
+
174
+ // Setup fonts select box
175
+ list = editor.getParam("fullpage_fonts", defaultFontNames).split(';');
176
+ for (i = 0; i < list.length; i++) {
177
+ item = list[i].split('=');
178
+
179
+ if (item.length > 1)
180
+ addSelectValue(form, 'fontface', item[0], item[1]);
181
+ }
182
+
183
+ // Setup fontsize select box
184
+ list = editor.getParam("fullpage_fontsizes", defaultFontSizes).split(',');
185
+ for (i = 0; i < list.length; i++)
186
+ addSelectValue(form, 'fontsize', list[i], list[i]);
187
+
188
+ // Setup encodings select box
189
+ list = editor.getParam("fullpage_encodings", defaultEncodings).split(',');
190
+ for (i = 0; i < list.length; i++) {
191
+ item = list[i].split('=');
192
+
193
+ if (item.length > 1)
194
+ addSelectValue(form, 'docencoding', item[0], item[1]);
195
+ }
196
+
197
+ // Setup color pickers
198
+ document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
199
+ document.getElementById('link_color_pickcontainer').innerHTML = getColorPickerHTML('link_color_pick','link_color');
200
+ document.getElementById('visited_color_pickcontainer').innerHTML = getColorPickerHTML('visited_color_pick','visited_color');
201
+ document.getElementById('active_color_pickcontainer').innerHTML = getColorPickerHTML('active_color_pick','active_color');
202
+ document.getElementById('textcolor_pickcontainer').innerHTML = getColorPickerHTML('textcolor_pick','textcolor');
203
+ document.getElementById('stylesheet_browsercontainer').innerHTML = getBrowserHTML('stylesheetbrowser','stylesheet','file','fullpage');
204
+ document.getElementById('bgimage_pickcontainer').innerHTML = getBrowserHTML('bgimage_browser','bgimage','image','fullpage');
205
+
206
+ // Resize some elements
207
+ if (isVisible('stylesheetbrowser'))
208
+ document.getElementById('stylesheet').style.width = '220px';
209
+
210
+ if (isVisible('link_href_browser'))
211
+ document.getElementById('element_link_href').style.width = '230px';
212
+
213
+ if (isVisible('bgimage_browser'))
214
+ document.getElementById('bgimage').style.width = '210px';
215
+
216
+ // Update form
217
+ tinymce.each(tinyMCEPopup.getWindowArg('data'), function(value, key) {
218
+ setVal(key, value);
219
+ });
220
+
221
+ FullPageDialog.changedStyle();
222
+
223
+ // Update colors
224
+ updateColor('textcolor_pick', 'textcolor');
225
+ updateColor('bgcolor_pick', 'bgcolor');
226
+ updateColor('visited_color_pick', 'visited_color');
227
+ updateColor('active_color_pick', 'active_color');
228
+ updateColor('link_color_pick', 'link_color');
229
+ };
230
+
231
+ tinyMCEPopup.onInit.add(init);
232
+ })();
tinymce-plugins/3.4.x/fullpage/langs/en_dlg.js ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ tinyMCE.addI18n('en.fullpage_dlg',{
2
+ title:"Document properties",
3
+ meta_tab:"General",
4
+ appearance_tab:"Appearance",
5
+ advanced_tab:"Advanced",
6
+ meta_props:"Meta information",
7
+ langprops:"Language and encoding",
8
+ meta_title:"Title",
9
+ meta_keywords:"Keywords",
10
+ meta_description:"Description",
11
+ meta_robots:"Robots",
12
+ doctypes:"Doctype",
13
+ langcode:"Language code",
14
+ langdir:"Language direction",
15
+ ltr:"Left to right",
16
+ rtl:"Right to left",
17
+ xml_pi:"XML declaration",
18
+ encoding:"Character encoding",
19
+ appearance_bgprops:"Background properties",
20
+ appearance_marginprops:"Body margins",
21
+ appearance_linkprops:"Link colors",
22
+ appearance_textprops:"Text properties",
23
+ bgcolor:"Background color",
24
+ bgimage:"Background image",
25
+ left_margin:"Left margin",
26
+ right_margin:"Right margin",
27
+ top_margin:"Top margin",
28
+ bottom_margin:"Bottom margin",
29
+ text_color:"Text color",
30
+ font_size:"Font size",
31
+ font_face:"Font face",
32
+ link_color:"Link color",
33
+ hover_color:"Hover color",
34
+ visited_color:"Visited color",
35
+ active_color:"Active color",
36
+ textcolor:"Color",
37
+ fontsize:"Font size",
38
+ fontface:"Font family",
39
+ meta_index_follow:"Index and follow the links",
40
+ meta_index_nofollow:"Index and don't follow the links",
41
+ meta_noindex_follow:"Do not index but follow the links",
42
+ meta_noindex_nofollow:"Do not index and don\'t follow the links",
43
+ appearance_style:"Stylesheet and style properties",
44
+ stylesheet:"Stylesheet",
45
+ style:"Style",
46
+ author:"Author",
47
+ copyright:"Copyright",
48
+ add:"Add new element",
49
+ remove:"Remove selected element",
50
+ moveup:"Move selected element up",
51
+ movedown:"Move selected element down",
52
+ head_elements:"Head elements",
53
+ info:"Information",
54
+ add_title:"Title element",
55
+ add_meta:"Meta element",
56
+ add_script:"Script element",
57
+ add_style:"Style element",
58
+ add_link:"Link element",
59
+ add_base:"Base element",
60
+ add_comment:"Comment node",
61
+ title_element:"Title element",
62
+ script_element:"Script element",
63
+ style_element:"Style element",
64
+ base_element:"Base element",
65
+ link_element:"Link element",
66
+ meta_element:"Meta element",
67
+ comment_element:"Comment",
68
+ src:"Src",
69
+ language:"Language",
70
+ href:"Href",
71
+ target:"Target",
72
+ type:"Type",
73
+ charset:"Charset",
74
+ defer:"Defer",
75
+ media:"Media",
76
+ properties:"Properties",
77
+ name:"Name",
78
+ value:"Value",
79
+ content:"Content",
80
+ rel:"Rel",
81
+ rev:"Rev",
82
+ hreflang:"Href lang",
83
+ general_props:"General",
84
+ advanced_props:"Advanced"
85
+ });
tinymce-plugins/cmseditor/editor_plugin.js ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ (function() {
3
+ tinymce.PluginManager.requireLangPack('cmseditor');
4
+ tinymce.create('tinymce.plugins.cmseditor', {
5
+ init : function(ed, url) {
6
+ var t = this;
7
+ t.editor = ed;
8
+
9
+ // load JS
10
+ tinymce.DOM.add(tinymce.DOM.select('head'), 'script', {src: url + '/js/codemirror-compressed.js'});
11
+ //tinymce.DOM.add(tinymce.DOM.select('head'), 'script', {src: url + '/js/lib/codemirror.js'});
12
+ //tinymce.DOM.add(tinymce.DOM.select('head'), 'script', {src: url + '/js/mode/xml/xml.js'});
13
+ //tinymce.DOM.add(tinymce.DOM.select('head'), 'script', {src: url + '/js/mode/css/css.js'});
14
+ //tinymce.DOM.add(tinymce.DOM.select('head'), 'script', {src: url + '/js/mode/javascript/javascript.js'});
15
+ //tinymce.DOM.add(tinymce.DOM.select('head'), 'script', {src: url + '/js/mode/htmlmixed/htmlmixed.js'});
16
+
17
+ // load CSS
18
+ tinymce.DOM.loadCSS(url + '/js/lib/codemirror.css');
19
+ tinymce.DOM.loadCSS(url + '/js/theme/default.css');
20
+
21
+ ed.addCommand('cmseditor', function() {
22
+ t.initEditor();
23
+ }, t );
24
+
25
+ ed.addButton('cmseditor', {
26
+ title : 'CodeMirror Source Editor',
27
+ cmd : 'cmseditor',
28
+ image : url + '/img/html.gif'
29
+ });
30
+ },
31
+ initEditor : function(){
32
+ var t = this, ed = t.editor, id = ed.getElement().id, cm = document.getElementById(id);
33
+
34
+ ed.hide();
35
+
36
+ t.cmEditor = CodeMirror.fromTextArea( cm, {
37
+ matchBrackets: true,
38
+ lineNumbers : true,
39
+ mode : 'text/html'
40
+ });
41
+ t.indentAll();
42
+ t.cmEditor.refresh();
43
+ var close_btn = t.initToolBar();
44
+ close_btn.onclick = function() {
45
+ t.closeEditor(t);
46
+ };
47
+ },
48
+ initToolBar: function() {
49
+ var t = this;
50
+ t.cmWrapper = t.cmEditor.getWrapperElement();
51
+ t.cmWrapper.style.width = '100%';
52
+
53
+ t.cmWrapper.cmToolBar = document.createElement("div");
54
+ t.cmWrapper.cmToolBar.style.width = '100%';
55
+ t.cmWrapper.cmToolBar.className = 'CodeMirror-ToolBar';
56
+ t.cmWrapper.parentNode.insertBefore(t.cmWrapper.cmToolBar, t.cmWrapper);
57
+ return tinymce.DOM.add(t.cmWrapper.cmToolBar, 'input', { type: 'button', value: 'x', 'class': 'CodeMirror-ToolBar-close' });
58
+ },
59
+ closeEditor: function(t) {
60
+ var ed = t.editor;
61
+ ed.show();
62
+ ed.setContent(t.cmEditor.getValue());
63
+ t.cmWrapper.parentNode.removeChild(t.cmWrapper.cmToolBar);
64
+ t.cmWrapper.parentNode.removeChild(t.cmWrapper);
65
+ t.cmEditor = null;
66
+ },
67
+ indentAll: function() {
68
+ var lineCount = this.cmEditor.lineCount();
69
+ for(var line = 0; line < lineCount; line++) {
70
+ this.cmEditor.indentLine(line);
71
+ }
72
+ },
73
+ getInfo : function() {
74
+ return {
75
+ longname : 'CodeMirror Source Editor',
76
+ author : 'Nicolas Lemoine',
77
+ authorurl : 'http://wordpress.org/extend/plugins/wp-better-emails/',
78
+ infourl : 'http://wordpress.org/extend/plugins/wp-better-emails/',
79
+ version : '0.1'
80
+ };
81
+ }
82
+ });
83
+ tinymce.PluginManager.add('cmseditor', tinymce.plugins.cmseditor);
84
+ })();
tinymce-plugins/cmseditor/img/ed-bg.gif ADDED
Binary file
tinymce-plugins/cmseditor/img/html.gif ADDED
Binary file
tinymce-plugins/cmseditor/js/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (C) 2011 by Marijn Haverbeke <marijnh@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
tinymce-plugins/cmseditor/js/README.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ # CodeMirror 2
2
+
3
+ CodeMirror 2 is a rewrite of [CodeMirror
4
+ 1](http://github.com/marijnh/CodeMirror). The docs live
5
+ [here](http://codemirror.net/manual.html), and the project page is
6
+ [http://codemirror.net/](http://codemirror.net/).
tinymce-plugins/cmseditor/js/codemirror-compressed.js ADDED
@@ -0,0 +1 @@
 
1
+ var CodeMirror=function(){function a(b,c){function bv(a){return a>=0&&a<$.length}function bx(a){ba=null;var b={line:0,ch:0};bH(b,{line:$.length-1,ch:$[$.length-1].text.length},N(a),b,b),ba=new j,bg=!0}function by(a){var b=[];for(var c=0,d=$.length;c<d;++c)b.push($[c].text);return b.join("\n")}function bz(a){function h(){bW(),bg=!0,j(),k()}function i(a){var b=cH(a,!0);if(b&&!G(b,e)){bb||bF(),e=b,ce(d,b),bg=!1;var c=b$();if(b.line>=c.to||b.line<c.from)f=setTimeout(cU(function(){i(a)}),150)}}for(var b=p(a);b!=w;b=b.parentNode)if(b.parentNode==J&&b!=Q)return;var c=bf;bf=null;for(var b=p(a);b!=w;b=b.parentNode)if(b.parentNode==S)return g.onGutterClick&&g.onGutterClick(bw,M(S.childNodes,b)+bl,a),m(a);var d=cH(a);switch(q(a)){case 3:u&&!z&&cI(a);return;case 2:d&&cg(d.line,d.ch,!0);return}if(!d){p(a)==D&&m(a);return}bb||bF(),m(a);if(c&&+(new Date)-c<400)return cn(d.line);cg(d.line,d.ch,!0);var e=d,f,j=r(n,"mousemove",cU(function(a){clearTimeout(f),m(a),i(a)}),!0),k=r(n,"mouseup",cU(function(a){clearTimeout(f);var b=cH(a);b&&ce(d,b),m(a),h()}),!0)}function bA(a){var b=cH(a);if(!b)return;cm(b),m(a),bf=+(new Date)}function bB(a){a.preventDefault();var b=cH(a,!0),c=a.dataTransfer.files;if(!b||g.readOnly)return;if(c&&c.length&&window.FileReader&&window.File){function d(a,c){var d=new FileReader;d.onload=function(){f[c]=d.result,++h==e&&bM(f.join(""),ci(b),ci(b))},d.readAsText(a)}var e=c.length,f=Array(e),h=0;for(var i=0;i<e;++i)d(c[i],i)}else try{var f=a.dataTransfer.getData("Text");f&&bM(f,b,b)}catch(a){}}function bC(a){bb||bF();var b=a.keyCode;v&&b==27&&(a.returnValue=!1);var c=(z?a.metaKey:a.ctrlKey)&&!a.altKey,d=a.ctrlKey||a.altKey||a.metaKey;b==16||a.shiftKey?bd=bd||(bc.inverted?bc.to:bc.from):bd=null;if(g.onKeyEvent&&g.onKeyEvent(bw,l(a)))return;if(b==33||b==34)return cj(b==34),m(a);if(c&&(b==36||b==35||z&&(b==38||b==40)))return ck(b==36||b==38),m(a);if(c&&b==65)return cl(),m(a);if(!g.readOnly){if(!d&&b==13)return;if(!d&&b==9&&cp(a.shiftKey))return m(a);if(c&&b==90)return bJ(),m(a);if(c&&(a.shiftKey&&b==90||b==89))return bK(),m(a)}if(b==36&&g.smartHome)return cq(),m(a);bo=(c?"c":"")+(a.altKey?"a":"")+b;if(bc.inverted&&A[bo]===!0){var e=O(C);e&&(be={anchor:e.start},P(C,e.start,e.start))}!c&&!a.altKey&&(bo=null),bT(bo)}function bD(a){if(g.onKeyEvent&&g.onKeyEvent(bw,l(a)))return;be&&(be=null,bg=!0),a.keyCode==16&&(bd=null)}function bE(a){if(g.onKeyEvent&&g.onKeyEvent(bw,l(a)))return;if(g.electricChars&&Z.electricChars){var b=String.fromCharCode(a.charCode==null?a.keyCode:a.charCode);Z.electricChars.indexOf(b)>-1&&setTimeout(cU(function(){cr(bc.to.line,"smart")}),50)}var c=a.keyCode;c==13?(g.readOnly||co(),m(a)):!a.ctrlKey&&!a.altKey&&!a.metaKey&&c==9&&g.tabMode!="default"?m(a):bT(bo)}function bF(){if(g.readOnly=="nocursor")return;bb||(g.onFocus&&g.onFocus(bw),bb=!0,w.className.search(/\bCodeMirror-focused\b/)==-1&&(w.className+=" CodeMirror-focused"),bk||bV()),bS(),cJ()}function bG(){bb&&(g.onBlur&&g.onBlur(bw),bb=!1,w.className=w.className.replace(" CodeMirror-focused","")),clearInterval(Y),setTimeout(function(){bb||(bd=null)},150)}function bH(a,b,c,d,e){if(ba){var f=[];for(var h=a.line,i=b.line+1;h<i;++h)f.push($[h].text);ba.addChange(a.line,c.length,f);while(ba.done.length>g.undoDepth)ba.done.shift()}bL(a,b,c,d,e)}function bI(a,b){var c=a.pop();if(c){var d=[],e=c.start+c.added;for(var f=c.start;f<e;++f)d.push($[f].text);b.push({start:c.start,added:c.old.length,old:d});var g=ci({line:c.start+c.old.length-1,ch:L(d[d.length-1],c.old[c.old.length-1])});bL({line:c.start,ch:0},{line:e-1,ch:$[e-1].text.length},c.old,g,g),bg=!0}}function bJ(){bI(ba.done,ba.undone)}function bK(){bI(ba.undone,ba.done)}function bL(a,b,c,d,e){function s(a){return a<=Math.min(b.line,b.line+q)?a:a+q}var f=!1,g=br.length;for(var i=a.line;i<=b.line;++i)if($[i].text.length==g){f=!0;break}var j=b.line-a.line,k=$[a.line],l=$[b.line];if(k==l)if(c.length==1)k.replace(a.ch,b.ch,c[0]);else{l=k.split(b.ch,c[c.length-1]);var m=[a.line+1,j];k.replace(a.ch,k.text.length,c[0]);for(var i=1,n=c.length-1;i<n;++i)m.push(new h(c[i]));m.push(l),$.splice.apply($,m)}else if(c.length==1)k.replace(a.ch,k.text.length,c[0]+l.text.slice(b.ch)),$.splice(a.line+1,j);else{var m=[a.line+1,j-1];k.replace(a.ch,k.text.length,c[0]),l.replace(0,b.ch,c[c.length-1]);for(var i=1,n=c.length-1;i<n;++i)m.push(new h(c[i]));$.splice.apply($,m)}for(var i=a.line,n=i+c.length;i<n;++i){var o=$[i].text;o.length>g&&(br=o,g=o.length,bs=null,f=!1)}if(f){g=0,br="",bs=null;for(var i=0,n=$.length;i<n;++i){var o=$[i].text;o.length>g&&(g=o.length,br=o)}}var p=[],q=c.length-j-1;for(var i=0,o=_.length;i<o;++i){var r=_[i];r<a.line?p.push(r):r>b.line&&p.push(r+q)}c.length<5?(cO(a.line,a.line+c.length),p.push(a.line+c.length)):p.push(a.line),_=p,cQ(100),bh.push({from:a.line,to:b.line+1,diff:q}),bi={from:a,to:b,text:c},cf(d,e,s(bc.from.line),s(bc.to.line)),J.style.height=$.length*cE()+2*cF()+"px"}function bM(a,b,c){function d(d){if(H(d,b))return d;if(!H(c,d))return e;var f=d.line+a.length-(c.line-b.line)-1,g=d.ch;return d.line==c.line&&(g+=a[a.length-1].length-(c.ch-(c.line==b.line?b.ch:0))),{line:f,ch:g}}b=ci(b),c?c=ci(c):c=b,a=N(a);var e;return bO(a,b,c,function(a){return e=a,{from:d(bc.from),to:d(bc.to)}}),e}function bN(a,b){bO(N(a),bc.from,bc.to,function(a){return b=="end"?{from:a,to:a}:b=="start"?{from:bc.from,to:bc.from}:{from:bc.from,to:a}})}function bO(a,b,c,d){var e=a.length==1?a[0].length+b.ch:a[a.length-1].length,f=d({line:b.line+a.length-1,ch:e});bH(b,c,a,f.from,f.to)}function bP(a,b){var c=a.line,d=b.line;if(c==d)return $[c].text.slice(a.ch,b.ch);var e=[$[c].text.slice(a.ch)];for(var f=c+1;f<d;++f)e.push($[f].text);return e.push($[d].text.slice(0,b.ch)),e.join("\n")}function bQ(){return bP(bc.from,bc.to)}function bS(){if(bR)return;W.set(2e3,function(){cR(),bU(),bb&&bS(),cS()})}function bT(a){function c(){cR();var d=bU();d&&a&&(d=="moved"&&A[a]==null&&(A[a]=!0),d=="changed"&&(A[a]=!1)),!d&&!b?(b=!0,W.set(80,c)):(bR=!1,bS()),cS()}var b=!1;bR=!0,W.set(20,c)}function bU(){function f(a,c){var d=0;for(;;){var e=b.indexOf("\n",d);if(e==-1||(b.charAt(e-1)=="\r"?e-1:e)>=a)return{line:c,ch:a-d};++c,d=e+1}}if(bk||!bb)return;var a=!1,b=C.value,c=O(C);if(!c)return!1;var a=bp.text!=b,d=be,e=a||c.start!=bp.start||c.end!=(d?bp.start:bp.end);if(!e&&!d)return!1;if(a){bd=be=null;if(g.readOnly)return bg=!0,"changed"}var h=f(c.start,bp.from),i=f(c.end,bp.from);if(d){var j=c.start==d.anchor?i:h,k=bd?bc.to:c.start==d.anchor?h:i;(bc.inverted=H(j,k))?(h=j,i=k):(be=null,h=k,i=j)}h.line==i.line&&h.line==bc.from.line&&h.line==bc.to.line&&!bd&&(bg=!1);if(a){var l=0,m=b.length,n=Math.min(m,bp.text.length),o,p=bp.from,q=-1;while(l<n&&(o=b.charAt(l))==bp.text.charAt(l))++l,o=="\n"&&(p++,q=l);var r=q>-1?l-q:l,s=bp.to-1,t=bp.text.length;for(;;){o=bp.text.charAt(t);if(b.charAt(m)!=o){++m,++t;break}o=="\n"&&s--;if(t<=l||m<=l)break;--m,--t}var q=bp.text.lastIndexOf("\n",t-1),u=q==-1?t:t-q-1;bH({line:p,ch:r},{line:s,ch:u},N(b.slice(l,m)),h,i);if(p!=s||h.line!=p)bg=!0}else cf(h,i);return bp.text=b,bp.start=c.start,bp.end=c.end,a?"changed":e?"moved":!1}function bV(){var a=[],b=Math.max(0,bc.from.line-1),c=Math.min($.length,bc.to.line+2);for(var d=b;d<c;++d)a.push($[d].text);a=C.value=a.join(x);var e=bc.from.ch,f=bc.to.ch;for(var d=b;d<bc.from.line;++d)e+=x.length+$[d].text.length;for(var d=b;d<bc.to.line;++d)f+=x.length+$[d].text.length;bp={text:a,from:b,to:c,start:e,end:f},P(C,e,be?e:f)}function bW(){g.readOnly!="nocursor"&&C.focus()}function bX(){if(!U.getBoundingClientRect)return;var a=U.getBoundingClientRect(),b=window.innerHeight||document.body.offsetHeight||document.documentElement.offsetHeight;(a.top<0||a.bottom>b)&&U.scrollIntoView()}function bY(){var a=cC(bc.inverted?bc.from:bc.to);return bZ(a.x,a.y,a.x,a.yBot)}function bZ(a,b,c,d){var e=cG(),f=cF(),h=cE();b+=f,d+=f,a+=e,c+=e;var i=D.clientHeight,j=D.scrollTop,k=!1,l=!0;b<j?(D.scrollTop=Math.max(0,b-2*h),k=!0):d>j+i&&(D.scrollTop=d+h-i,k=!0);var m=D.clientWidth,n=D.scrollLeft,o=g.fixedGutter?R.clientWidth:0;return a<n+o?(a<50&&(a=0),D.scrollLeft=Math.max(0,a-10-o),k=!0):c>m+n&&(D.scrollLeft=c+10-m,k=!0,c>J.clientWidth&&(l=!1)),k&&g.onScroll&&g.onScroll(bw),l}function b$(){var a=cE(),b=D.scrollTop-cF();return{from:Math.min($.length,Math.max(0,Math.floor(b/a))),to:Math.min($.length,Math.ceil((b+D.clientHeight)/a))}}function b_(a){if(!D.clientWidth){bl=bm=0;return}var b=a===!0?[]:[{from:bl,to:bm,domStart:0}];for(var c=0,d=a.length||0;c<d;++c){var e=a[c],f=[],g=e.diff||0;for(var h=0,i=b.length;h<i;++h){var j=b[h];e.to<=j.from?f.push({from:j.from+g,to:j.to+g,domStart:j.domStart}):j.to<=e.from?f.push(j):(e.from>j.from&&f.push({from:j.from,to:e.from,domStart:j.domStart}),e.to<j.to&&f.push({from:e.to+g,to:j.to+g,domStart:j.domStart+(e.to-j.from)}))}b=f}var k=b$(),l=Math.min(bl,Math.max(k.from-3,0)),m=Math.min($.length,Math.max(bm,k.to+3)),n=[],o=0,p=bm-bl,q=l,r=0;for(var c=0,d=b.length;c<d;++c){var j=b[c];if(j.to<=l)continue;if(j.from>=m)break;if(j.domStart>o||j.from>q)n.push({from:q,to:j.from,domSize:j.domStart-o,domStart:o}),r+=j.from-q;q=j.to,o=j.domStart+(j.to-j.from)}if(o!=p||q!=m)r+=Math.abs(m-q),n.push({from:q,to:m,domSize:p-o,domStart:o});if(!n.length)return;V.style.display="none",r>(k.to-k.from)*.3?ca(l=Math.max(k.from-10,0),m=Math.min(k.to+7,$.length)):cb(n),V.style.display="";var s=l!=bl||m!=bm||bn!=D.clientHeight;bl=l,bm=m,Q.style.top=l*cE()+"px",s&&(bn=D.clientHeight,J.style.height=$.length*cE()+2*cF()+"px"),(s||n.length)&&cc(),bs==null&&(bs=cz(br)),bs>D.clientWidth?(T.style.width=bs+"px",J.style.width="",J.style.width=D.scrollWidth+"px"):T.style.width=J.style.width="";if(V.childNodes.length!=bm-bl)throw new Error("BAD PATCH! "+JSON.stringify(n)+" size="+(bm-bl)+" nodes="+V.childNodes.length);cd()}function ca(a,b){var c=[],d={line:a,ch:0},e=H(bc.from,d)&&!H(bc.to,d);for(var f=a;f<b;++f){var g=null,h=null;e?(g=0,bc.to.line==f&&(e=!1,h=bc.to.ch)):bc.from.line==f&&(bc.to.line==f?(g=bc.from.ch,h=bc.to.ch):(e=!0,g=bc.from.ch)),c.push($[f].getHTML(g,h,!0))}V.innerHTML=c.join("")}function cb(a){var b=bc.from.line,c=bc.to.line,d=0,e=t&&n.createElement("div");for(var f=0,g=a.length;f<g;++f){var h=a[f],i=h.to-h.from-h.domSize,j=V.childNodes[h.domStart+h.domSize+d]||null;if(t)for(var k=Math.max(-i,h.domSize);k>0;--k)V.removeChild(j?j.previousSibling:V.lastChild);else if(i){for(var k=Math.max(0,i);k>0;--k)V.insertBefore(n.createElement("pre"),j);for(var k=Math.max(0,-i);k>0;--k)V.removeChild(j?j.previousSibling:V.lastChild)}var l=V.childNodes[h.domStart+d],m=b<h.from&&c>=h.from;for(var k=h.from;k<h.to;++k){var o=null,p=null;m?(o=0,c==k&&(m=!1,p=bc.to.ch)):b==k&&(c==k?(o=bc.from.ch,p=bc.to.ch):(m=!0,o=bc.from.ch)),t?(e.innerHTML=$[k].getHTML(o,p,!0),V.insertBefore(e.firstChild,j)):(l.innerHTML=$[k].getHTML(o,p,!1),l.className=$[k].className||"",l=l.nextSibling)}d+=i}}function cc(){if(!g.gutter&&!g.lineNumbers)return;var a=Q.offsetHeight,b=D.clientHeight;R.style.height=(a-b<2?b:a)+"px";var c=[];for(var d=bl;d<Math.max(bm,bl+1);++d){var e=$[d].gutterMarker,f=g.lineNumbers?d+g.firstLineNumber:null;e&&e.text?f=e.text.replace("%N%",f!=null?f:""):f==null&&(f="\u00a0"),c.push(e&&e.style?'<pre class="'+e.style+'">':"<pre>",f,"</pre>")}R.style.display="none",S.innerHTML=c.join("");var h=String($.length).length,i=S.firstChild,j=F(i),k="";while(j.length+k.length<h)k+="\u00a0";k&&i.insertBefore(n.createTextNode(k),i.firstChild),R.style.display="",T.style.marginLeft=R.offsetWidth+"px"}function cd(){var a=bc.inverted?bc.from:bc.to,b=cE(),c=cA(a.line,a.ch);B.style.top=a.line*b-D.scrollTop+"px",B.style.left=c-D.scrollLeft+"px",G(bc.from,bc.to)?(U.style.top=(a.line-bl)*b+"px",U.style.left=c+"px",U.style.display=""):U.style.display="none"}function ce(a,b){var c=bd&&ci(bd);c&&(H(c,a)?a=c:H(b,c)&&(b=c)),cf(a,b)}function cf(a,b,c,d){if(G(bc.from,a)&&G(bc.to,b))return;if(H(b,a)){var e=b;b=a,a=e}G(a,b)?bc.inverted=!1:G(a,bc.to)?bc.inverted=!1:G(b,bc.from)&&(bc.inverted=!0),c==null&&(c=bc.from.line,d=bc.to.line),G(a,b)?G(bc.from,bc.to)||bh.push({from:c,to:d+1}):G(bc.from,bc.to)?bh.push({from:a.line,to:b.line+1}):(G(a,bc.from)||(a.line<c?bh.push({from:a.line,to:Math.min(b.line,c)+1}):bh.push({from:c,to:Math.min(d,a.line)+1})),G(b,bc.to)||(b.line<d?bh.push({from:Math.max(c,a.line),to:d+1}):bh.push({from:Math.max(a.line,d),to:b.line+1}))),bc.from=a,bc.to=b,bj=!0}function cg(a,b,c){var d=ci({line:a,ch:b||0});(c?ce:cf)(d,d)}function ch(a){return Math.max(0,Math.min(a,$.length-1))}function ci(a){if(a.line<0)return{line:0,ch:0};if(a.line>=$.length)return{line:$.length-1,ch:$[$.length-1].text.length};var b=a.ch,c=$[a.line].text.length;return b==null||b>c?{line:a.line,ch:c}:b<0?{line:a.line,ch:0}:a}function cj(a){var b=Math.floor(D.clientHeight/cE()),c=bc.inverted?bc.from:bc.to;cg(c.line+Math.max(b-1,1)*(a?1:-1),c.ch,!0)}function ck(a){var b=a?{line:0,ch:0}:{line:$.length-1,ch:$[$.length-1].text.length};ce(b,b)}function cl(){var a=$.length-1;cf({line:0,ch:0},{line:a,ch:$[a].text.length})}function cm(a){var b=$[a.line].text,c=a.ch,d=a.ch;while(c>0&&/\w/.test(b.charAt(c-1)))--c;while(d<b.length&&/\w/.test(b.charAt(d)))++d;ce({line:a.line,ch:c},{line:a.line,ch:d})}function cn(a){ce({line:a,ch:0},{line:a,ch:$[a].text.length})}function co(){bN("\n","end"),g.enterMode!="flat"&&cr(bc.from.line,g.enterMode=="keep"?"prev":"smart")}function cp(a){function b(a){if(G(bc.from,bc.to))return cr(bc.from.line,a);var b=bc.to.line-(bc.to.ch?0:1);for(var c=bc.from.line;c<=b;++c)cr(c,a)}bd=null;switch(g.tabMode){case"default":return!1;case"indent":b("smart");break;case"classic":if(G(bc.from,bc.to)){a?cr(bc.from.line,"smart"):bN("\t","end");break};case"shift":b(a?"subtract":"add")}return!0}function cq(){var a=Math.max(0,$[bc.from.line].text.search(/\S/));cg(bc.from.line,bc.from.ch<=a&&bc.from.ch?0:a,!0)}function cr(a,b){if(b=="smart")if(!Z.indent)b="prev";else var c=cN(a);var d=$[a],e=d.indentation(),f=d.text.match(/^\s*/)[0],h;b=="prev"?a?h=$[a-1].indentation():h=0:b=="smart"?h=Z.indent(c,d.text.slice(f.length)):b=="add"?h=e+g.indentUnit:b=="subtract"&&(h=e-g.indentUnit),h=Math.max(0,h);var i=h-e;if(!i){if(bc.from.line!=a&&bc.to.line!=a)return;var j=f}else{var j="",k=0;if(g.indentWithTabs)for(var l=Math.floor(h/y);l;--l)k+=y,j+="\t";while(k<h)++k,j+=" "}bM(j,{line:a,ch:0},{line:a,ch:f.length})}function cs(){Z=a.getMode(g,g.mode);for(var b=0,c=$.length;b<c;++b)$[b].stateAfter=null;_=[0],cQ()}function ct(){var a=g.gutter||g.lineNumbers;R.style.display=a?"":"none",a?cc():V.parentNode.style.marginLeft=0}function cu(a,b,c){function e(a,b,c,e){var a=$[a],f=a.addMark(b,c,e);f.line=a,d.push(f)}a=ci(a),b=ci(b);var d=[];if(a.line==b.line)e(a.line,a.ch,b.ch,c);else{e(a.line,a.ch,null,c);for(var f=a.line+1,g=b.line;f<g;++f)e(f,0,null,c);e(b.line,0,b.ch,c)}return bh.push({from:a.line,to:b.line+1}),function(){var a,b;for(var c=0;c<d.length;++c){var e=d[c],f=M($,e.line);e.line.removeMark(e),f>-1&&(a==null&&(a=f),b=f)}a!=null&&bh.push({from:a,to:b+1})}}function cv(a,b,c){return typeof a=="number"&&(a=$[ch(a)]),a.gutterMarker={text:b,style:c},cc(),a}function cw(a){typeof a=="number"&&(a=$[ch(a)]),a.gutterMarker=null,cc()}function cx(a,b){if(typeof a=="number"){var c=a;a=$[ch(a)]}else{var c=M($,a);if(c==-1)return null}return a.className!=b&&(a.className=b,bh.push({from:c,to:c+1})),a}function cy(a){if(typeof a=="number"){var b=a;a=$[a];if(!a)return null}else{var b=M($,a);if(b==-1)return null}var c=a.gutterMarker;return{line:b,text:a.text,markerText:c&&c.text,markerClass:c&&c.style}}function cz(a){return K.innerHTML="<pre><span>x</span></pre>",K.firstChild.firstChild.firstChild.nodeValue=a,K.firstChild.firstChild.offsetWidth||10}function cA(a,b){return b==0?0:(K.innerHTML="<pre><span>"+$[a].getHTML(null,null,!1,b)+"</span></pre>",K.firstChild.firstChild.offsetWidth)}function cB(a,b){function e(a){return K.innerHTML="<pre><span>"+c.getHTML(null,null,!1,a)+"</span></pre>",K.firstChild.firstChild.offsetWidth}if(b<=0)return 0;var c=$[a],d=c.text,f=0,g=0,h=d.length,i,j=Math.min(h,Math.ceil(b/cz("x")));for(;;){var k=e(j);if(k<=b&&j<h)j=Math.min(h,Math.ceil(j*1.2));else{i=k,h=j;break}}if(b>i)return h;j=Math.floor(h*.8),k=e(j),k<b&&(f=j,g=k);for(;;){if(h-f<=1)return i-b>b-g?f:h;var l=Math.ceil((f+h)/2),m=e(l);m>b?(h=l,i=m):(f=l,g=m)}}function cC(a,b){var c=cE(),d=a.line-(b?bl:0);return{x:cA(a.line,a.ch),y:d*c,yBot:(d+1)*c}}function cD(a){var b=cC(a,!0),c=E(T);return{x:c.left+b.x,y:c.top+b.y,yBot:c.top+b.yBot}}function cE(){var a=V.childNodes.length;return a?V.offsetHeight/a||1:(K.innerHTML="<pre>x</pre>",K.firstChild.offsetHeight||1)}function cF(){return T.offsetTop}function cG(){return T.offsetLeft}function cH(a,b){var c=E(D,!0),d,e;try{d=a.clientX,e=a.clientY}catch(a){return null}if(!b&&(d-c.left>D.clientWidth||e-c.top>D.clientHeight))return null;var f=E(T,!0),g=bl+Math.floor((e-f.top)/cE());return ci({line:g,ch:cB(ch(g),d-f.left)})}function cI(a){function e(){var a=N(C.value).join("\n");a!=d&&cU(bN)(a,"end"),B.style.position="relative",C.style.cssText=c,bk=!1,bV(),bS()}var b=cH(a);if(!b||window.opera)return;(G(bc.from,bc.to)||H(b,bc.from)||!H(b,bc.to))&&cU(cg)(b.line,b.ch);var c=C.style.cssText;B.style.position="absolute",C.style.cssText="position: fixed; width: 30px; height: 30px; top: "+(a.clientY-5)+"px; left: "+(a.clientX-5)+"px; z-index: 1000; background: white; "+"border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",bk=!0;var d=C.value=bQ();bW(),P(C,0,C.value.length);if(u){o(a);var f=r(window,"mouseup",function(){f(),setTimeout(e,20)},!0)}else setTimeout(e,50)}function cJ(){clearInterval(Y);var a=!0;U.style.visibility="",Y=setInterval(function(){U.style.visibility=(a=!a)?"":"hidden"},650)}function cL(a){function p(a,b,c){if(!a.text)return;var d=a.styles,e=g?0:a.text.length-1,f;for(var i=g?0:d.length-2,j=g?d.length:-2;i!=j;i+=2*h){var k=d[i];if(d[i+1]!=null&&d[i+1]!=m){e+=h*k.length;continue}for(var l=g?0:k.length-1,p=g?k.length:-1;l!=p;l+=h,e+=h)if(e>=b&&e<c&&o.test(f=k.charAt(l))){var q=cK[f];if(q.charAt(1)==">"==g)n.push(f);else{if(n.pop()!=q.charAt(0))return{pos:e,match:!1};if(!n.length)return{pos:e,match:!0}}}}}var b=bc.inverted?bc.from:bc.to,c=$[b.line],d=b.ch-1,e=d>=0&&cK[c.text.charAt(d)]||cK[c.text.charAt(++d)];if(!e)return;var f=e.charAt(0),g=e.charAt(1)==">",h=g?1:-1,i=c.styles;for(var j=d+1,k=0,l=i.length;k<l;k+=2)if((j-=i[k].length)<=0){var m=i[k+1];break}var n=[c.text.charAt(d)],o=/[(){}[\]]/;for(var k=b.line,l=g?Math.min(k+100,$.length):Math.max(-1,k-100);k!=l;k+=h){var c=$[k],q=k==b.line,r=p(c,q&&g?d+1:0,q&&!g?d:c.text.length);if(r)break}r||(r={pos:null,match:!1});var m=r.match?"CodeMirror-matchingbracket":"CodeMirror-nonmatchingbracket",s=cu({line:b.line,ch:d},{line:b.line,ch:d+1},m),t=r.pos!=null?cu({line:k,ch:r.pos},{line:k,ch:r.pos+1},m):function(){},u=cU(function(){s(),t()});a?setTimeout(u,800):bq=u}function cM(a){var b,c;for(var d=a,e=a-40;d>e;--d){if(d==0)return 0;var f=$[d-1];if(f.stateAfter)return d;var g=f.indentation();if(c==null||b>g)c=d-1,b=g}return c}function cN(a){var b=cM(a),c=b&&$[b-1].stateAfter;c?c=e(Z,c):c=f(Z);for(var d=b;d<a;++d){var g=$[d];g.highlight(Z,c),g.stateAfter=e(Z,c)}return a<$.length&&!$[a].stateAfter&&_.push(a),c}function cO(a,b){var c=cN(a);for(var d=a;d<b;++d){var f=$[d];f.highlight(Z,c),f.stateAfter=e(Z,c)}}function cP(){var a=+(new Date)+g.workTime,b=_.length;while(_.length){if(!$[bl].stateAfter)var c=bl;else var c=_.pop();if(c>=$.length)continue;var d=cM(c),h=d&&$[d-1].stateAfter;h?h=e(Z,h):h=f(Z);var i=0,j=Z.compareStates,k=!1;for(var l=d,m=$.length;l<m;++l){var n=$[l],o=n.stateAfter;if(+(new Date)>a){_.push(l),cQ(g.workDelay),k&&bh.push({from:c,to:l+1});return}var p=n.highlight(Z,h);p&&(k=!0),n.stateAfter=e(Z,h);if(j){if(o&&j(o,h))break}else if(p!==!1||!o)i=0;else if(++i>3)break}k&&bh.push({from:c,to:l+1})}b&&g.onHighlightComplete&&g.onHighlightComplete(bw)}function cQ(a){if(!_.length)return;X.set(a,cU(cP))}function cR(){bg=null,bh=[],bi=bj=!1}function cS(){var a=!1;bj&&(a=!bY()),bh.length?b_(bh):bj&&cd(),a&&bY(),bj&&(bX(),cJ()),bb&&!bk&&(bg===!0||bg!==!1&&bj)&&bV(),bj&&g.matchBrackets&&setTimeout(cU(function(){bq&&(bq(),bq=null),cL(!1)}),20);var b=bi;bj&&g.onCursorActivity&&g.onCursorActivity(bw),b&&g.onChange&&bw&&g.onChange(bw,b)}function cU(a){return function(){cT++||cR();try{var b=a.apply(this,arguments)}finally{--cT||cS()}return b}}function cV(a,b,c){this.atOccurrence=!1,c==null&&(c=typeof a=="string"&&a==a.toLowerCase()),b&&typeof b=="object"?b=ci(b):b={line:0,ch:0},this.pos={from:b,to:b};if(typeof a!="string")this.matches=function(b,c){if(b){var d=$[c.line].text.slice(0,c.ch),e=d.match(a),f=0;while(e){var g=d.indexOf(e[0]);f+=g,d=d.slice(g+1);var h=d.match(a);if(h)e=h;else break;f++}}else var d=$[c.line].text.slice(c.ch),e=d.match(a),f=e&&c.ch+d.indexOf(e[0]);if(e)return{from:{line:c.line,ch:f},to:{line:c.line,ch:f+e[0].length},match:e}};else{c&&(a=a.toLowerCase());var d=c?function(a){return a.toLowerCase()}:function(a){return a},e=a.split("\n");e.length==1?this.matches=function(b,c){var e=d($[c.line].text),f=a.length,g;if(b?c.ch>=f&&(g=e.lastIndexOf(a,c.ch-f))!=-1:(g=e.indexOf(a,c.ch))!=-1)return{from:{line:c.line,ch:g},to:{line:c.line,ch:g+f}}}:this.matches=function(a,b){var c=b.line,f=a?e.length-1:0,g=e[f],h=d($[c].text),i=a?h.indexOf(g)+g.length:h.lastIndexOf(g);if(a?i>=b.ch||i!=g.length:i<=b.ch||i!=h.length-g.length)return;for(;;){if(a?!c:c==$.length-1)return;h=d($[c+=a?-1:1].text),g=e[a?--f:++f];if(f>0&&f<e.length-1){if(h!=g)return;continue}var j=a?h.lastIndexOf(g):h.indexOf(g)+g.length;if(a?j!=h.length-g.length:j!=g.length)return;var k={line:b.line,ch:i},l={line:c,ch:j};return{from:a?l:k,to:a?k:l}}}}}var g={},i=a.defaults;for(var k in i)i.hasOwnProperty(k)&&(g[k]=(c&&c.hasOwnProperty(k)?c:i)[k]);var n=g.document,w=n.createElement("div");w.className="CodeMirror",w.innerHTML='<div style="overflow: hidden; position: relative; width: 1px; height: 0px;"><textarea style="position: absolute; width: 2px;" wrap="off"></textarea></div><div class="CodeMirror-scroll cm-s-'+g.theme+'">'+'<div style="position: relative">'+'<div style="position: absolute; height: 0; width: 0; overflow: hidden;"></div>'+'<div style="position: relative">'+'<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>'+'<div class="CodeMirror-lines"><div style="position: relative">'+'<pre class="CodeMirror-cursor">&#160;</pre>'+"<div></div>"+"</div></div></div></div></div>",b.appendChild?b.appendChild(w):b(w);var B=w.firstChild,C=B.firstChild,D=w.lastChild,J=D.firstChild,K=J.firstChild,Q=K.nextSibling,R=Q.firstChild,S=R.firstChild,T=R.nextSibling.firstChild,U=T.firstChild,V=U.nextSibling;g.tabindex!=null&&(C.tabindex=g.tabindex),!g.gutter&&!g.lineNumbers&&(R.style.display="none");var W=new s,X=new s,Y,Z,$=[new h("")],_,ba=new j,bb;cs();var bc={from:{line:0,ch:0},to:{line:0,ch:0},inverted:!1},bd,be,bf,bg,bh,bi,bj,bk,bl=0,bm=0,bn=0,bo=null,bp,bq,br="",bs;cU(function(){bx(g.value||""),bg=!1})(),r(D,"mousedown",cU(bz)),u||r(D,"contextmenu",cI),r(J,"dblclick",cU(bA)),r(D,"scroll",function(){b_([]),g.fixedGutter&&(R.style.left=D.scrollLeft+"px"),g.onScroll&&g.onScroll(bw)}),r(window,"resize",function(){b_(!0)}),r(C,"keyup",cU(bD)),r(C,"keydown",cU(bC)),r(C,"keypress",cU(bE)),r(C,"focus",bF),r(C,"blur",bG),r(D,"dragenter",o),r(D,"dragover",o),r(D,"drop",cU(bB)),r(D,"paste",function(){bW(),bT()}),r(C,"paste",function(){bT()}),r(C,"cut",function(){bT()});var bt;try{bt=n.activeElement==C}catch(bu){}bt?setTimeout(bF,20):bG();var bw={getValue:by,setValue:cU(bx),getSelection:bQ,replaceSelection:cU(bN),focus:function(){bW(),bF(),bT()},setOption:function(a,b){g[a]=b,a=="lineNumbers"||a=="gutter"||a=="firstLineNumber"?ct():a=="mode"||a=="indentUnit"?cs():a=="readOnly"&&b=="nocursor"?C.blur():a=="theme"&&(D.className=D.className.replace(/cm-s-\w+/,"cm-s-"+b))},getOption:function(a){return g[a]},undo:cU(bJ),redo:cU(bK),indentLine:cU(function(a,b){bv(a)&&cr(a,b==null?"smart":b?"add":"subtract")}),historySize:function(){return{undo:ba.done.length,redo:ba.undone.length}},matchBrackets:cU(function(){cL(!0)}),getTokenAt:function(a){return a=ci(a),$[a.line].getTokenAt(Z,cN(a.line),a.ch)},getStateAfter:function(a){return a=ch(a==null?$.length-1:a),cN(a+1)},cursorCoords:function(a){return a==null&&(a=bc.inverted),cD(a?bc.from:bc.to)},charCoords:function(a){return cD(ci(a))},coordsChar:function(a){var b=E(T),c=ch(Math.min($.length-1,bl+Math.floor((a.y-b.top)/cE())));return ci({line:c,ch:cB(ch(c),a.x-b.left)})},getSearchCursor:function(a,b,c){return new cV(a,b,c)},markText:cU(function(a,b,c){return cU(cu(a,b,c))}),setMarker:cv,clearMarker:cw,setLineClass:cU(cx),lineInfo:cy,addWidget:function(a,b,c,d){a=cC(ci(a));var e=a.yBot,f=a.x;b.style.position="absolute",J.appendChild(b),b.style.left=f+"px";if(d=="over")e=a.y;else if(d=="near"){var g=Math.max(D.offsetHeight,$.length*cE()),h=Math.max(J.clientWidth,T.clientWidth)-cG();a.yBot+b.offsetHeight>g&&a.y>b.offsetHeight&&(e=a.y-b.offsetHeight),f+b.offsetWidth>h&&(f=h-b.offsetWidth)}b.style.top=e+cF()+"px",b.style.left=f+cG()+"px",c&&bZ(f,e,f+b.offsetWidth,e+b.offsetHeight)},lineCount:function(){return $.length},getCursor:function(a){return a==null&&(a=bc.inverted),I(a?bc.from:bc.to)},somethingSelected:function(){return!G(bc.from,bc.to)},setCursor:cU(function(a,b){b==null&&typeof a.line=="number"?cg(a.line,a.ch):cg(a,b)}),setSelection:cU(function(a,b){cf(ci(a),ci(b||a))}),getLine:function(a){if(bv(a))return $[a].text},setLine:cU(function(a,b){bv(a)&&bM(b,{line:a,ch:0},{line:a,ch:$[a].text.length})}),removeLine:cU(function(a){bv(a)&&bM("",{line:a,ch:0},ci({line:a+1,ch:0}))}),replaceRange:cU(bM),getRange:function(a,b){return bP(ci(a),ci(b))},operation:function(a){return cU(a)()},refresh:function(){b_(!0)},getInputField:function(){return C},getWrapperElement:function(){return w},getScrollerElement:function(){return D},getGutterElement:function(){return R}},bR=!1,cK={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"},cT=0;cV.prototype={findNext:function(){return this.find(!1)},findPrevious:function(){return this.find(!0)},find:function(a){function d(a){var c={line:a,ch:0};return b.pos={from:c,to:c},b.atOccurrence=!1,!1}var b=this,c=ci(a?this.pos.from:this.pos.to);for(;;){if(this.pos=this.matches(a,c))return this.atOccurrence=!0,this.pos.match||!0;if(a){if(!c.line)return d(0);c={line:c.line-1,ch:$[c.line-1].text.length}}else{if(c.line==$.length-1)return d($.length);c={line:c.line+1,ch:0}}}},from:function(){if(this.atOccurrence)return I(this.pos.from)},to:function(){if(this.atOccurrence)return I(this.pos.to)},replace:function(a){var b=this;this.atOccurrence&&cU(function(){b.pos.to=bM(a,b.pos.from,b.pos.to)})()}};for(var cW in d)d.propertyIsEnumerable(cW)&&!bw.propertyIsEnumerable(cW)&&(bw[cW]=d[cW]);return bw}function e(a,b){if(b===!0)return b;if(a.copyState)return a.copyState(b);var c={};for(var d in b){var e=b[d];e instanceof Array&&(e=e.concat([])),c[d]=e}return c}function f(a,b,c){return a.startState?a.startState(b,c):!0}function g(a){this.pos=this.start=0,this.string=a}function h(a,b){this.styles=b||[a,null],this.stateAfter=null,this.text=a,this.marked=this.gutterMarker=this.className=null}function i(a,b,c,d){for(var e=0,f=0,g=0;f<b;e+=2){var h=c[e],i=f+h.length;g==0?(i>a&&d.push(h.slice(a-f,Math.min(h.length,b-f)),c[e+1]),i>=a&&(g=1)):g==1&&(i>b?d.push(h.slice(0,b-f),c[e+1]):d.push(h,c[e+1])),f=i}}function j(){this.time=0,this.done=[],this.undone=[]}function k(){o(this)}function l(a){return a.stop||(a.stop=k),a}function m(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function n(a){a.stopPropagation?a.stopPropagation():a.cancelBubble=!0}function o(a){m(a),n(a)}function p(a){return a.target||a.srcElement}function q(a){if(a.which)return a.which;if(a.button&1)return 1;if(a.button&2)return 3;if(a.button&4)return 2}function r(a,b,c,d){function e(a){c(a||window.event)}if(typeof a.addEventListener=="function"){a.addEventListener(b,e,!1);if(d)return function(){a.removeEventListener(b,e,!1)}}else{a.attachEvent("on"+b,e);if(d)return function(){a.detachEvent("on"+b,e)}}}function s(){this.id=null}function C(a,b){b==null&&(b=a.search(/[^\s\u00a0]/),b==-1&&(b=a.length));for(var c=0,d=0;c<b;++c)a.charAt(c)=="\t"?d+=y-d%y:++d;return d}function D(a){return a.currentStyle?a.currentStyle:window.getComputedStyle(a,null)}function E(a,b){var c=a.ownerDocument.body,d=0,e=0,f=!1;for(var g=a;g;g=g.offsetParent)d+=g.offsetLeft,e+=g.offsetTop,b&&D(g).position=="fixed"&&(f=!0);var h=b&&!f?null:c;for(var g=a.parentNode;g!=h;g=g.parentNode)g.scrollLeft!=null&&(d-=g.scrollLeft,e-=g.scrollTop);return{left:d,top:e}}function F(a){return a.textContent||a.innerText||a.nodeValue||""}function G(a,b){return a.line==b.line&&a.ch==b.ch}function H(a,b){return a.line<b.line||a.line==b.line&&a.ch<b.ch}function I(a){return{line:a.line,ch:a.ch}}function K(a){return J.innerText=J.textContent=a,J.innerHTML}function L(a,b){if(!b)return a?a.length:0;if(!a)return b.length;for(var c=a.length,d=b.length;c>=0&&d>=0;--c,--d)if(a.charAt(c)!=b.charAt(d))break;return d+1}function M(a,b){if(a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;c<d;++c)if(a[c]==b)return c;return-1}a.defaults={value:"",mode:null,theme:"default",indentUnit:2,indentWithTabs:!1,tabMode:"classic",enterMode:"indent",electricChars:!0,onKeyEvent:null,lineNumbers:!1,gutter:!1,fixedGutter:!1,firstLineNumber:1,readOnly:!1,smartHome:!0,onChange:null,onCursorActivity:null,onGutterClick:null,onHighlightComplete:null,onFocus:null,onBlur:null,onScroll:null,matchBrackets:!1,workTime:100,workDelay:200,undoDepth:40,tabindex:null,document:window.document};var b={},c={};a.defineMode=function(c,d){!a.defaults.mode&&c!="null"&&(a.defaults.mode=c),b[c]=d},a.defineMIME=function(a,b){c[a]=b},a.getMode=function(d,e){typeof e=="string"&&c.hasOwnProperty(e)&&(e=c[e]);if(typeof e=="string")var f=e,g={};else if(e!=null)var f=e.name,g=e;var h=b[f];return h?h(d,g||{}):(window.console&&console.warn("No mode "+f+" found, falling back to plain text."),a.getMode(d,"text/plain"))},a.listModes=function(){var a=[];for(var c in b)b.propertyIsEnumerable(c)&&a.push(c);return a},a.listMIMEs=function(){var a=[];for(var b in c)c.propertyIsEnumerable(b)&&a.push(b);return a};var d={};a.defineExtension=function(a,b){d[a]=b},a.fromTextArea=function(b,c){function d(){b.value=h.getValue()}c||(c={}),c.value=b.value,!c.tabindex&&b.tabindex&&(c.tabindex=b.tabindex);if(b.form){var e=r(b.form,"submit",d,!0);if(typeof b.form.submit=="function"){var f=b.form.submit;function g(){d(),b.form.submit=f,b.form.submit(),b.form.submit=g}b.form.submit=g}}b.style.display="none";var h=a(function(a){b.parentNode.insertBefore(a,b.nextSibling)},c);return h.save=d,h.toTextArea=function(){d(),b.parentNode.removeChild(h.getWrapperElement()),b.style.display="",b.form&&(e(),typeof b.form.submit=="function"&&(b.form.submit=f))},h},a.startState=f,a.copyState=e,g.prototype={eol:function(){return this.pos>=this.string.length},sol:function(){return this.pos==0},peek:function(){return this.string.charAt(this.pos)},next:function(){if(this.pos<this.string.length)return this.string.charAt(this.pos++)},eat:function(a){var b=this.string.charAt(this.pos);if(typeof a=="string")var c=b==a;else var c=b&&(a.test?a.test(b):a(b));if(c)return++this.pos,b},eatWhile:function(a){var b=this.pos;while(this.eat(a));return this.pos>b},eatSpace:function(){var a=this.pos;while(/[\s\u00a0]/.test(this.string.charAt(this.pos)))++this.pos;return this.pos>a},skipToEnd:function(){this.pos=this.string.length},skipTo:function(a){var b=this.string.indexOf(a,this.pos);if(b>-1)return this.pos=b,!0},backUp:function(a){this.pos-=a},column:function(){return C(this.string,this.start)},indentation:function(){return C(this.string)},match:function(a,b,c){if(typeof a!="string"){var e=this.string.slice(this.pos).match(a);return e&&b!==!1&&(this.pos+=e[0].length),e}function d(a){return c?a.toLowerCase():a}if(d(this.string).indexOf(d(a),this.pos)==this.pos)return b!==!1&&(this.pos+=a.length),!0},current:function(){return this.string.slice(this.start,this.pos)}},a.StringStream=g,h.prototype={replace:function(a,b,c){var d=[],e=this.marked;i(0,a,this.styles,d),c&&d.push(c,null),i(b,this.text.length,this.styles,d),this.styles=d,this.text=this.text.slice(0,a)+c+this.text.slice(b),this.stateAfter=null;if(e){var f=c.length-(b-a),g=this.text.length;function h(a){return a<=Math.min(b,b+f)?a:a+f}for(var j=0;j<e.length;++j){var k=e[j],l=!1;k.from>=g?l=!0:(k.from=h(k.from),k.to!=null&&(k.to=h(k.to)));if(l||k.from>=k.to)e.splice(j,1),j--}}},split:function(a,b){var c=[b,null];return i(a,this.text.length,this.styles,c),new h(b+this.text.slice(a),c)},addMark:function(a,b,c){var d=this.marked,e={from:a,to:b,style:c};return this.marked==null&&(this.marked=[]),this.marked.push(e),this.marked.sort(function(a,b){return a.from-b.from}),e},removeMark:function(a){var b=this.marked;if(!b)return;for(var c=0;c<b.length;++c)if(b[c]==a){b.splice(c,1);break}},highlight:function(a,b){var c=new g(this.text),d=this.styles,e=0,f=!1,h=d[0],i;this.text==""&&a.blankLine&&a.blankLine(b);while(!c.eol()){var j=a.token(c,b),k=this.text.slice(c.start,c.pos);c.start=c.pos,e&&d[e-1]==j?d[e-2]+=k:k&&(!f&&(d[e+1]!=j||e&&d[e-2]!=i)&&(f=!0),d[e++]=k,d[e++]=j,i=h,h=d[e]);if(c.pos>5e3){d[e++]=this.text.slice(c.pos),d[e++]=null;break}}return d.length!=e&&(d.length=e,f=!0),e&&d[e-2]!=i&&(f=!0),f||(d.length<5&&this.text.length<10?null:!1)},getTokenAt:function(a,b,c){var d=this.text,e=new g(d);while(e.pos<c&&!e.eol()){e.start=e.pos;var f=a.token(e,b)}return{start:e.start,end:e.pos,string:e.current(),className:f||null,state:b}},indentation:function(){return C(this.text)},getHTML:function(a,b,c,d){function f(a,b){if(!a)return;b?e.push('<span class="',b,'">',K(a),"</span>"):e.push(K(a))}var e=[];c&&e.push(this.className?'<pre class="'+this.className+'">':"<pre>");var g=this.styles,h=this.text,i=this.marked;a==b&&(a=null);var j=h.length;d!=null&&(j=Math.min(d,j));if(!h&&d==null)f(" ",a!=null&&b==null?"CodeMirror-selected":null);else if(!i&&a==null)for(var k=0,l=0;l<j;k+=2){var m=g[k],n=m.length;l+n>j&&(m=m.slice(0,j-l)),l+=n,f(m,"cm-"+g[k+1])}else{var o=0,k=0,p="",q,r=0,s=-1,t=null;function u(){i&&(s+=1,t=s<i.length?i[s]:null)}u();while(o<j){var v=j,w="";if(a!=null)if(a>o)v=a;else if(b==null||b>o)w=" CodeMirror-selected",b!=null&&(v=Math.min(v,b));while(t&&t.to!=null&&t.to<=o)u();t&&(t.from>o?v=Math.min(v,t.from):(w+=" "+t.style,t.to!=null&&(v=Math.min(v,t.to))));for(;;){var x=o+p.length,y=q;w&&(y=q?q+w:w),f(x>v?p.slice(0,v-o):p,y);if(x>=v){p=p.slice(v-o),o=v;break}o=x,p=g[k++],q="cm-"+g[k++]}}a!=null&&b==null&&f(" ","CodeMirror-selected")}return c&&e.push("</pre>"),e.join("")}},j.prototype={addChange:function(a,b,c){this.undone.length=0;var d=+(new Date),e=this.done[this.done.length-1];if(d-this.time>400||!e||e.start>a+b||e.start+e.added<a-e.added+e.old.length)this.done.push({start:a,added:b,old:c});else{var f=0;if(a<e.start){for(var g=e.start-a-1;g>=0;--g)e.old.unshift(c[g]);e.added+=e.start-a,e.start=a}else e.start<a&&(f=a-e.start,b+=f);for(var g=e.added-f,h=c.length;g<h;++g)e.old.push(c[g]);e.added<b&&(e.added=b)}this.time=d}},s.prototype={set:function(a,b){clearTimeout(this.id),this.id=setTimeout(b,a)}};var t=function(){var a=document.createElement("pre");return a.innerHTML=" ",!a.innerHTML}(),u=/gecko\/\d{7}/i.test(navigator.userAgent),v=/MSIE \d/.test(navigator.userAgent),w=/Apple Computer/.test(navigator.vendor),x="\n";(function(){var a=document.createElement("textarea");a.value="foo\nbar",a.value.indexOf("\r")>-1&&(x="\r\n")})();var y=8,z=/Mac/.test(navigator.platform),A={};for(var B=35;B<=40;++B)A[B]=A["c"+B]=!0;var J=document.createElement("div");a.htmlEscape=K;var N,O,P;return"\n\nb".split(/\n/).length!=3?N=function(a){var b=0,c,d=[];while((c=a.indexOf("\n",b))>-1)d.push(a.slice(b,a.charAt(c-1)=="\r"?c-1:c)),b=c+1;return d.push(a.slice(b)),d}:N=function(a){return a.split(/\r?\n/)},a.splitLines=N,window.getSelection?(O=function(a){try{return{start:a.selectionStart,end:a.selectionEnd}}catch(b){return null}},w?P=function(a,b,c){b==c?a.setSelectionRange(b,c):(a.setSelectionRange(b,c-1),window.getSelection().modify("extend","forward","character"))}:P=function(a,b,c){try{a.setSelectionRange(b,c)}catch(d){}}):(O=function(a){try{var b=a.ownerDocument.selection.createRange()}catch(c){return null}if(!b||b.parentElement()!=a)return null;var d=a.value,e=d.length,f=a.createTextRange();f.moveToBookmark(b.getBookmark());var g=a.createTextRange();g.collapse(!1);if(f.compareEndPoints("StartToEnd",g)>-1)return{start:e,end:e};var h=-f.moveStart("character",-e);for(var i=d.indexOf("\r");i>-1&&i<h;i=d.indexOf("\r",i+1),h++);if(f.compareEndPoints("EndToEnd",g)>-1)return{start:h,end:e};var j=-f.moveEnd("character",-e);for(var i=d.indexOf("\r");i>-1&&i<j;i=d.indexOf("\r",i+1),j++);return{start:h,end:j}},P=function(a,b,c){var d=a.createTextRange();d.collapse(!0);var e=d.duplicate(),f=0,g=a.value;for(var h=g.indexOf("\n");h>-1&&h<b;h=g.indexOf("\n",h+1))++f;d.move("character",b-f);for(;h>-1&&h<c;h=g.indexOf("\n",h+1))++f;e.move("character",c-f),d.setEndPoint("EndToEnd",e),d.select()}),a.defineMode("null",function(){return{token:function(a){a.skipToEnd()}}}),a.defineMIME("text/plain","null"),a}();CodeMirror.defineMode("javascript",function(a,b){function g(a,b,c){return b.tokenize=c,c(a,b)}function h(a,b){var c=!1,d;while((d=a.next())!=null){if(d==b&&!c)return!1;c=!c&&d=="\\"}return c}function k(a,b,c){return i=a,j=c,b}function l(a,b){var c=a.next();if(c=='"'||c=="'")return g(a,b,m(c));if(/[\[\]{}\(\),;\:\.]/.test(c))return k(c);if(c=="0"&&a.eat(/x/i))return a.eatWhile(/[\da-f]/i),k("number","number");if(/\d/.test(c))return a.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/),k("number","number");if(c=="/")return a.eat("*")?g(a,b,n):a.eat("/")?(a.skipToEnd(),k("comment","comment")):b.reAllowed?(h(a,"/"),a.eatWhile(/[gimy]/),k("regexp","string")):(a.eatWhile(f),k("operator",null,a.current()));if(f.test(c))return a.eatWhile(f),k("operator",null,a.current());a.eatWhile(/[\w\$_]/);var d=a.current(),i=e.propertyIsEnumerable(d)&&e[d];return i?k(i.type,i.style,d):k("variable","variable",d)}function m(a){return function(b,c){return h(b,a)||(c.tokenize=l),k("string","string")}}function n(a,b){var c=!1,d;while(d=a.next()){if(d=="/"&&c){b.tokenize=l;break}c=d=="*"}return k("comment","comment")}function p(a,b,c,d,e,f){this.indented=a,this.column=b,this.type=c,this.prev=e,this.info=f,d!=null&&(this.align=d)}function q(a,b){for(var c=a.localVars;c;c=c.next)if(c.name==b)return!0}function r(a,b,c,e,f){var g=a.cc;s.state=a,s.stream=f,s.marked=null,s.cc=g,a.lexical.hasOwnProperty("align")||(a.lexical.align=!0);for(;;){var h=g.length?g.pop():d?D:C;if(h(c,e)){while(g.length&&g[g.length-1].lex)g.pop()();return s.marked?s.marked:c=="variable"&&q(a,e)?"variable-2":b}}}function t(){for(var a=arguments.length-1;a>=0;a--)s.cc.push(arguments[a])}function u(){return t.apply(null,arguments),!0}function v(a){var b=s.state;if(b.context){s.marked="def";for(var c=b.localVars;c;c=c.next)if(c.name==a)return;b.localVars={name:a,next:b.localVars}}}function x(){s.state.context||(s.state.localVars=w),s.state.context={prev:s.state.context,vars:s.state.localVars}}function y(){s.state.localVars=s.state.context.vars,s.state.context=s.state.context.prev}function z(a,b){var c=function(){var c=s.state;c.lexical=new p(c.indented,s.stream.column(),a,null,c.lexical,b)};return c.lex=!0,c}function A(){var a=s.state;a.lexical.prev&&(a.lexical.type==")"&&(a.indented=a.lexical.indented),a.lexical=a.lexical.prev)}function B(a){return function b(b){return b==a?u():a==";"?t():u(arguments.callee)}}function C(a){return a=="var"?u(z("vardef"),K,B(";"),A):a=="keyword a"?u(z("form"),D,C,A):a=="keyword b"?u(z("form"),C,A):a=="{"?u(z("}"),J,A):a==";"?u():a=="function"?u(Q):a=="for"?u(z("form"),B("("),z(")"),M,B(")"),A,C,A):a=="variable"?u(z("stat"),F):a=="switch"?u(z("form"),D,z("}","switch"),B("{"),J,A,A):a=="case"?u(D,B(":")):a=="default"?u(B(":")):a=="catch"?u(z("form"),x,B("("),R,B(")"),C,A,y):t(z("stat"),D,B(";"),A)}function D(a){return o.hasOwnProperty(a)?u(E):a=="function"?u(Q):a=="keyword c"?u(D):a=="("?u(z(")"),D,B(")"),A,E):a=="operator"?u(D):a=="["?u(z("]"),I(D,"]"),A,E):a=="{"?u(z("}"),I(H,"}"),A,E):u()}function E(a,b){if(a=="operator"&&/\+\+|--/.test(b))return u(E);if(a=="operator")return u(D);if(a==";")return;if(a=="(")return u(z(")"),I(D,")"),A,E);if(a==".")return u(G,E);if(a=="[")return u(z("]"),D,B("]"),A,E)}function F(a){return a==":"?u(A,C):t(E,B(";"),A)}function G(a){if(a=="variable")return s.marked="property",u()}function H(a){a=="variable"&&(s.marked="property");if(o.hasOwnProperty(a))return u(B(":"),D)}function I(a,b){function c(d){return d==","?u(a,c):d==b?u():u(B(b))}return function d(d){return d==b?u():t(a,c)}}function J(a){return a=="}"?u():t(C,J)}function K(a,b){return a=="variable"?(v(b),u(L)):u()}function L(a,b){if(b=="=")return u(D,L);if(a==",")return u(K)}function M(a){return a=="var"?u(K,O):a==";"?t(O):a=="variable"?u(N):t(O)}function N(a,b){return b=="in"?u(D):u(E,O)}function O(a,b){return a==";"?u(P):b=="in"?u(D):u(D,B(";"),P)}function P(a){a!=")"&&u(D)}function Q(a,b){if(a=="variable")return v(b),u(Q);if(a=="(")return u(z(")"),x,I(R,")"),A,C,y)}function R(a,b){if(a=="variable")return v(b),u()}var c=a.indentUnit,d=b.json,e=function(){function a(a){return{type:a,style:"keyword"}}var b=a("keyword a"),c=a("keyword b"),d=a("keyword c"),e=a("operator"),f={type:"atom",style:"atom"};return{"if":b,"while":b,"with":b,"else":c,"do":c,"try":c,"finally":c,"return":d,"break":d,"continue":d,"new":d,"delete":d,"throw":d,"var":a("var"),"function":a("function"),"catch":a("catch"),"for":a("for"),"switch":a("switch"),"case":a("case"),"default":a("default"),"in":e,"typeof":e,"instanceof":e,"true":f,"false":f,"null":f,"undefined":f,NaN:f,Infinity:f}}(),f=/[+\-*&%=<>!?|]/,i,j,o={atom:!0,number:!0,variable:!0,string:!0,regexp:!0},s={state:null,column:null,marked:null,cc:null},w={name:"this",next:{name:"arguments"}};return A.lex=!0,{startState:function(a){return{tokenize:l,reAllowed:!0,cc:[],lexical:new p((a||0)-c,0,"block",!1),localVars:null,context:null,indented:0}},token:function(a,b){a.sol()&&(b.lexical.hasOwnProperty("align")||(b.lexical.align=!1),b.indented=a.indentation());if(a.eatSpace())return null;var c=b.tokenize(a,b);return i=="comment"?c:(b.reAllowed=i=="operator"||i=="keyword c"||i.match(/^[\[{}\(,;:]$/),r(b,c,i,j,a))},indent:function(a,b){if(a.tokenize!=l)return 0;var d=b&&b.charAt(0),e=a.lexical,f=e.type,g=d==f;return f=="vardef"?e.indented+4:f=="form"&&d=="{"?e.indented:f=="stat"||f=="form"?e.indented+c:e.info=="switch"&&!g?e.indented+(/^(?:case|default)\b/.test(b)?c:2*c):e.align?e.column+(g?0:1):e.indented+(g?0:c)},electricChars:":{}"}}),CodeMirror.defineMIME("text/javascript","javascript"),CodeMirror.defineMIME("application/json",{name:"javascript",json:!0}),CodeMirror.defineMode("xml",function(a,b){function h(a,b){function c(c){return b.tokenize=c,c(a,b)}var d=a.next();if(d=="<"){if(a.eat("!"))return a.eat("[")?a.match("CDATA[")?c(k("atom","]]>")):null:a.match("--")?c(k("comment","-->")):a.match("DOCTYPE",!0,!0)?(a.eatWhile(/[\w\._\-]/),c(k("meta",">"))):null;if(a.eat("?"))return a.eatWhile(/[\w\._\-]/),b.tokenize=k("meta","?>"),"meta";g=a.eat("/")?"closeTag":"openTag",a.eatSpace(),f="";var e;while(e=a.eat(/[^\s\u00a0=<>\"\'\/?]/))f+=e;return b.tokenize=i,"tag"}return d=="&"?(a.eatWhile(/[^;]/),a.eat(";"),"atom"):(a.eatWhile(/[^&<]/),null)}function i(a,b){var c=a.next();return c==">"||c=="/"&&a.eat(">")?(b.tokenize=h,g=c==">"?"endTag":"selfcloseTag","tag"):c=="="?(g="equals",null):/[\'\"]/.test(c)?(b.tokenize=j(c),b.tokenize(a,b)):(a.eatWhile(/[^\s\u00a0=<>\"\'\/?]/),"word")}function j(a){return function(b,c){while(!b.eol())if(b.next()==a){c.tokenize=i;break}return"string"}}function k(a,b){return function(c,d){while(!c.eol()){if(c.match(b)){d.tokenize=h;break}c.next()}return a}}function n(){for(var a=arguments.length-1;a>=0;a--)l.cc.push(arguments[a])}function o(){return n.apply(null,arguments),!0}function p(a,b){var c=d.doNotIndent.hasOwnProperty(a)||l.context&&l.context.noIndent;l.context={prev:l.context,tagName:a,indent:l.indented,startOfLine:b,noIndent:c}}function q(){l.context&&(l.context=l.context.prev)}function r(a){if(a=="openTag")return l.tagName=f,o(u,s(l.startOfLine));if(a=="closeTag"){var b=!1;return l.context?b=l.context.tagName!=f:b=!0,b&&(m="error"),o(t(b))}return a=="string"?((!l.context||l.context.name!="!cdata")&&p("!cdata"),l.tokenize==h&&q(),o()):o()}function s(a){return function(b){return b=="selfcloseTag"||b=="endTag"&&d.autoSelfClosers.hasOwnProperty(l.tagName.toLowerCase())?o():b=="endTag"?(p(l.tagName,a),o()):o()}}function t(a){return function(b){return a&&(m="error"),b=="endTag"?(q(),o()):n()}}function u(a){return a=="word"?(m="attribute",o(u)):a=="equals"?o(v,u):n()}function v(a){return a=="word"&&d.allowUnquoted?(m="string",o()):a=="string"?o(w):n()}function w(a){return a=="string"?o(w):n()}var c=a.indentUnit,d=b.htmlMode?{autoSelfClosers:{br:!0,img:!0,hr:!0,link:!0,input:!0,meta:!0,col:!0,frame:!0,base:!0,area:!0},doNotIndent:{pre:!0,"!cdata":!0},allowUnquoted:!0}:{autoSelfClosers:{},doNotIndent:{"!cdata":!0},allowUnquoted:!1},e=b.alignCDATA,f,g,l,m;return{startState:function(){return{tokenize:h,cc:[],indented:0,startOfLine:!0,tagName:null,context:null}},token:function(a,b){a.sol()&&(b.startOfLine=!0,b.indented=a.indentation());if(a.eatSpace())return null;m=g=f=null;var c=b.tokenize(a,b);if((c||g)&&c!="comment"){l=b;for(;;){var d=b.cc.pop()||r;if(d(g||c))break}}return b.startOfLine=!1,m||c},indent:function(a,b){var d=a.context;if(d&&d.noIndent)return 0;if(e&&/<!\[CDATA\[/.test(b))return 0;d&&/^<\//.test(b)&&(d=d.prev);while(d&&!d.startOfLine)d=d.prev;return d?d.indent+c:0},compareStates:function(a,b){if(a.indented!=b.indented)return!1;for(var c=a.context,d=b.context;;c=c.prev,d=d.prev){if(!c||!d)return c==d;if(c.tagName!=d.tagName)return!1}},electricChars:"/"}}),CodeMirror.defineMIME("application/xml","xml"),CodeMirror.defineMIME("text/html",{name:"xml",htmlMode:!0}),CodeMirror.defineMode("css",function(a){function d(a,b){return c=b,a}function e(a,b){var c=a.next();if(c=="@")return a.eatWhile(/\w/),d("meta",a.current());if(c=="/"&&a.eat("*"))return b.tokenize=f,f(a,b);if(c=="<"&&a.eat("!"))return b.tokenize=g,g(a,b);if(c=="=")d(null,"compare");else return c!="~"&&c!="|"||!a.eat("=")?c=='"'||c=="'"?(b.tokenize=h(c),b.tokenize(a,b)):c=="#"?(a.eatWhile(/\w/),d("atom","hash")):c=="!"?(a.match(/^\s*\w*/),d("keyword","important")):/\d/.test(c)?(a.eatWhile(/[\w.%]/),d("number","unit")):/[,.+>*\/]/.test(c)?d(null,"select-op"):/[;{}:\[\]]/.test(c)?d(null,c):(a.eatWhile(/[\w\\\-_]/),d("variable","variable")):d(null,"compare")}function f(a,b){var c=!1,f;while((f=a.next())!=null){if(c&&f=="/"){b.tokenize=e;break}c=f=="*"}return d("comment","comment")}function g(a,b){var c=0,f;while((f=a.next())!=null){if(c>=2&&f==">"){b.tokenize=e;break}c=f=="-"?c+1:0}return d("comment","comment")}function h(a){return function(b,c){var f=!1,g;while((g=b.next())!=null){if(g==a&&!f)break;f=!f&&g=="\\"}return f||(c.tokenize=e),d("string","string")}}var b=a.indentUnit,c;return{startState:function(a){return{tokenize:e,baseIndent:a||0,stack:[]}},token:function(a,b){if(a.eatSpace())return null;var d=b.tokenize(a,b),e=b.stack[b.stack.length-1];if(c=="hash"&&e=="rule")d="atom";else if(d=="variable")if(e=="rule")d="number";else if(!e||e=="@media{")d="tag";return e=="rule"&&/^[\{\};]$/.test(c)&&b.stack.pop(),c=="{"?e=="@media"?b.stack[b.stack.length-1]="@media{":b.stack.push("{"):c=="}"?b.stack.pop():c=="@media"?b.stack.push("@media"):e=="{"&&c!="comment"&&b.stack.push("rule"),d},indent:function(a,c){var d=a.stack.length;return/^\}/.test(c)&&(d-=a.stack[a.stack.length-1]=="rule"?2:1),a.baseIndent+d*b},electricChars:"}"}}),CodeMirror.defineMIME("text/css","css"),CodeMirror.defineMode("htmlmixed",function(a,b){function f(a,b){var f=c.token(a,b.htmlState);return f=="tag"&&a.current()==">"&&b.htmlState.context&&(/^script$/i.test(b.htmlState.context.tagName)?(b.token=h,b.localState=d.startState(c.indent(b.htmlState,"")),b.mode="javascript"):/^style$/i.test(b.htmlState.context.tagName)&&(b.token=i,b.localState=e.startState(c.indent(b.htmlState,"")),b.mode="css")),f}function g(a,b,c){var d=a.current(),e=d.search(b);return e>-1&&a.backUp(d.length-e),c}function h(a,b){return a.match(/^<\/\s*script\s*>/i,!1)?(b.token=f,b.curState=null,b.mode="html",f(a,b)):g(a,/<\/\s*script\s*>/,d.token(a,b.localState))}function i(a,b){return a.match(/^<\/\s*style\s*>/i,!1)?(b.token=f,b.localState=null,b.mode="html",f(a,b)):g(a,/<\/\s*style\s*>/,e.token(a,b.localState))}var c=CodeMirror.getMode(a,{name:"xml",htmlMode:!0}),d=CodeMirror.getMode(a,"javascript"),e=CodeMirror.getMode(a,"css");return{startState:function(){var a=c.startState();return{token:f,localState:null,mode:"html",htmlState:a}},copyState:function(a){if(a.localState)var b=CodeMirror.copyState(a.token==i?e:d,a.localState);return{token:a.token,localState:b,mode:a.mode,htmlState:CodeMirror.copyState(c,a.htmlState)}},token:function(a,b){return b.token(a,b)},indent:function(a,b){return a.token==f||/^\s*<\//.test(b)?c.indent(a.htmlState,b):a.token==h?d.indent(a.localState,b):e.indent(a.localState,b)},electricChars:"/{}:"}}),CodeMirror.defineMIME("text/html","htmlmixed")
tinymce-plugins/cmseditor/js/lib/codemirror.css ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .CodeMirror {
2
+ line-height: 1em;
3
+ font-family: monospace;
4
+ }
5
+
6
+ .CodeMirror-scroll {
7
+ overflow: auto;
8
+ height: 380px;
9
+ /* This is needed to prevent an IE[67] bug where the scrolled content
10
+ is visible outside of the scrolling box. */
11
+ position: relative;
12
+ }
13
+
14
+ .CodeMirror-gutter {
15
+ position: absolute; left: 0; top: 0;
16
+ background-color: #f7f7f7;
17
+ border-right: 1px solid #eee;
18
+ min-width: 2em;
19
+ height: 100%;
20
+ }
21
+ .CodeMirror-gutter-text {
22
+ color: #aaa;
23
+ text-align: right;
24
+ padding: .4em .2em .4em .4em;
25
+ }
26
+ .CodeMirror-lines {
27
+ padding: .4em;
28
+ }
29
+
30
+ .CodeMirror pre {
31
+ -moz-border-radius: 0;
32
+ -webkit-border-radius: 0;
33
+ -o-border-radius: 0;
34
+ border-radius: 0;
35
+ border-width: 0; margin: 0; padding: 0; background: transparent;
36
+ font-family: inherit;
37
+ font-size: inherit;
38
+ padding: 0; margin: 0;
39
+ white-space: pre;
40
+ word-wrap: normal;
41
+ }
42
+
43
+ .CodeMirror textarea {
44
+ font-family: inherit !important;
45
+ font-size: inherit !important;
46
+ }
47
+
48
+ .CodeMirror-cursor {
49
+ z-index: 10;
50
+ position: absolute;
51
+ visibility: hidden;
52
+ border-left: 1px solid black !important;
53
+ }
54
+ .CodeMirror-focused .CodeMirror-cursor {
55
+ visibility: visible;
56
+ }
57
+
58
+ span.CodeMirror-selected {
59
+ background: #ccc !important;
60
+ color: HighlightText !important;
61
+ }
62
+ .CodeMirror-focused span.CodeMirror-selected {
63
+ background: Highlight !important;
64
+ }
65
+
66
+ .CodeMirror-matchingbracket {color: #0f0 !important;}
67
+ .CodeMirror-nonmatchingbracket {color: #f22 !important;}
68
+
69
+
70
+ /* Tool bar */
71
+
72
+ .CodeMirror-ToolBar {
73
+ background: #eee url(../../img/ed-bg.gif) repeat-x;
74
+ border: solid 1px #ccc;
75
+ height: 30px;
76
+ text-align: right;
77
+ }
78
+ .CodeMirror-ToolBar-close {
79
+ margin: 3px;
80
+ padding: 2px 3px;
81
+ cursor: pointer;
82
+ }
tinymce-plugins/cmseditor/js/lib/codemirror.js ADDED
@@ -0,0 +1,2157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // All functions that need access to the editor's state live inside
2
+ // the CodeMirror function. Below that, at the bottom of the file,
3
+ // some utilities are defined.
4
+
5
+ // CodeMirror is the only global var we claim
6
+ var CodeMirror = (function() {
7
+ // This is the function that produces an editor instance. It's
8
+ // closure is used to store the editor state.
9
+ function CodeMirror(place, givenOptions) {
10
+ // Determine effective options based on given values and defaults.
11
+ var options = {}, defaults = CodeMirror.defaults;
12
+ for (var opt in defaults)
13
+ if (defaults.hasOwnProperty(opt))
14
+ options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
15
+
16
+ var targetDocument = options["document"];
17
+ // The element in which the editor lives.
18
+ var wrapper = targetDocument.createElement("div");
19
+ wrapper.className = "CodeMirror";
20
+ // This mess creates the base DOM structure for the editor.
21
+ wrapper.innerHTML =
22
+ '<div style="overflow: hidden; position: relative; width: 1px; height: 0px;">' + // Wraps and hides input textarea
23
+ '<textarea style="position: absolute; width: 2px;" wrap="off"></textarea></div>' +
24
+ '<div class="CodeMirror-scroll cm-s-' + options.theme + '">' +
25
+ '<div style="position: relative">' + // Set to the height of the text, causes scrolling
26
+ '<div style="position: absolute; height: 0; width: 0; overflow: hidden;"></div>' +
27
+ '<div style="position: relative">' + // Moved around its parent to cover visible view
28
+ '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
29
+ // Provides positioning relative to (visible) text origin
30
+ '<div class="CodeMirror-lines"><div style="position: relative">' +
31
+ '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
32
+ '<div></div>' + // This DIV contains the actual code
33
+ '</div></div></div></div></div>';
34
+ if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
35
+ // I've never seen more elegant code in my life.
36
+ var inputDiv = wrapper.firstChild, input = inputDiv.firstChild,
37
+ scroller = wrapper.lastChild, code = scroller.firstChild,
38
+ measure = code.firstChild, mover = measure.nextSibling,
39
+ gutter = mover.firstChild, gutterText = gutter.firstChild,
40
+ lineSpace = gutter.nextSibling.firstChild,
41
+ cursor = lineSpace.firstChild, lineDiv = cursor.nextSibling;
42
+ if (options.tabindex != null) input.tabindex = options.tabindex;
43
+ if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
44
+
45
+ // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
46
+ var poll = new Delayed(), highlight = new Delayed(), blinker;
47
+
48
+ // mode holds a mode API object. lines an array of Line objects
49
+ // (see Line constructor), work an array of lines that should be
50
+ // parsed, and history the undo history (instance of History
51
+ // constructor).
52
+ var mode, lines = [new Line("")], work, history = new History(), focused;
53
+ loadMode();
54
+ // The selection. These are always maintained to point at valid
55
+ // positions. Inverted is used to remember that the user is
56
+ // selecting bottom-to-top.
57
+ var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
58
+ // Selection-related flags. shiftSelecting obviously tracks
59
+ // whether the user is holding shift. reducedSelection is a hack
60
+ // to get around the fact that we can't create inverted
61
+ // selections. See below.
62
+ var shiftSelecting, reducedSelection, lastDoubleClick;
63
+ // Variables used by startOperation/endOperation to track what
64
+ // happened during the operation.
65
+ var updateInput, changes, textChanged, selectionChanged, leaveInputAlone;
66
+ // Current visible range (may be bigger than the view window).
67
+ var showingFrom = 0, showingTo = 0, lastHeight = 0, curKeyId = null;
68
+ // editing will hold an object describing the things we put in the
69
+ // textarea, to help figure out whether something changed.
70
+ // bracketHighlighted is used to remember that a backet has been
71
+ // marked.
72
+ var editing, bracketHighlighted;
73
+ // Tracks the maximum line length so that the horizontal scrollbar
74
+ // can be kept static when scrolling.
75
+ var maxLine = "", maxWidth;
76
+
77
+ // Initialize the content.
78
+ operation(function(){setValue(options.value || ""); updateInput = false;})();
79
+
80
+ // Register our event handlers.
81
+ connect(scroller, "mousedown", operation(onMouseDown));
82
+ // Gecko browsers fire contextmenu *after* opening the menu, at
83
+ // which point we can't mess with it anymore. Context menu is
84
+ // handled in onMouseDown for Gecko.
85
+ if (!gecko) connect(scroller, "contextmenu", onContextMenu);
86
+ connect(code, "dblclick", operation(onDblClick));
87
+ connect(scroller, "scroll", function() {updateDisplay([]); if (options.onScroll) options.onScroll(instance);});
88
+ connect(window, "resize", function() {updateDisplay(true);});
89
+ connect(input, "keyup", operation(onKeyUp));
90
+ connect(input, "keydown", operation(onKeyDown));
91
+ connect(input, "keypress", operation(onKeyPress));
92
+ connect(input, "focus", onFocus);
93
+ connect(input, "blur", onBlur);
94
+
95
+ connect(scroller, "dragenter", e_stop);
96
+ connect(scroller, "dragover", e_stop);
97
+ connect(scroller, "drop", operation(onDrop));
98
+ connect(scroller, "paste", function(){focusInput(); fastPoll();});
99
+ connect(input, "paste", function(){fastPoll();});
100
+ connect(input, "cut", function(){fastPoll();});
101
+
102
+ // IE throws unspecified error in certain cases, when
103
+ // trying to access activeElement before onload
104
+ var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
105
+ if (hasFocus) setTimeout(onFocus, 20);
106
+ else onBlur();
107
+
108
+ function isLine(l) {return l >= 0 && l < lines.length;}
109
+ // The instance object that we'll return. Mostly calls out to
110
+ // local functions in the CodeMirror function. Some do some extra
111
+ // range checking and/or clipping. operation is used to wrap the
112
+ // call so that changes it makes are tracked, and the display is
113
+ // updated afterwards.
114
+ var instance = {
115
+ getValue: getValue,
116
+ setValue: operation(setValue),
117
+ getSelection: getSelection,
118
+ replaceSelection: operation(replaceSelection),
119
+ focus: function(){focusInput(); onFocus(); fastPoll();},
120
+ setOption: function(option, value) {
121
+ options[option] = value;
122
+ if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber") gutterChanged();
123
+ else if (option == "mode" || option == "indentUnit") loadMode();
124
+ else if (option == "readOnly" && value == "nocursor") input.blur();
125
+ else if (option == "theme") scroller.className = scroller.className.replace(/cm-s-\w+/, "cm-s-" + value);
126
+ },
127
+ getOption: function(option) {return options[option];},
128
+ undo: operation(undo),
129
+ redo: operation(redo),
130
+ indentLine: operation(function(n, dir) {
131
+ if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract");
132
+ }),
133
+ historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
134
+ matchBrackets: operation(function(){matchBrackets(true);}),
135
+ getTokenAt: function(pos) {
136
+ pos = clipPos(pos);
137
+ return lines[pos.line].getTokenAt(mode, getStateBefore(pos.line), pos.ch);
138
+ },
139
+ getStateAfter: function(line) {
140
+ line = clipLine(line == null ? lines.length - 1: line);
141
+ return getStateBefore(line + 1);
142
+ },
143
+ cursorCoords: function(start){
144
+ if (start == null) start = sel.inverted;
145
+ return pageCoords(start ? sel.from : sel.to);
146
+ },
147
+ charCoords: function(pos){return pageCoords(clipPos(pos));},
148
+ coordsChar: function(coords) {
149
+ var off = eltOffset(lineSpace);
150
+ var line = clipLine(Math.min(lines.length - 1, showingFrom + Math.floor((coords.y - off.top) / lineHeight())));
151
+ return clipPos({line: line, ch: charFromX(clipLine(line), coords.x - off.left)});
152
+ },
153
+ getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
154
+ markText: operation(function(a, b, c){return operation(markText(a, b, c));}),
155
+ setMarker: addGutterMarker,
156
+ clearMarker: removeGutterMarker,
157
+ setLineClass: operation(setLineClass),
158
+ lineInfo: lineInfo,
159
+ addWidget: function(pos, node, scroll, where) {
160
+ pos = localCoords(clipPos(pos));
161
+ var top = pos.yBot, left = pos.x;
162
+ node.style.position = "absolute";
163
+ code.appendChild(node);
164
+ node.style.left = left + "px";
165
+ if (where == "over") top = pos.y;
166
+ else if (where == "near") {
167
+ var vspace = Math.max(scroller.offsetHeight, lines.length * lineHeight()),
168
+ hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft();
169
+ if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
170
+ top = pos.y - node.offsetHeight;
171
+ if (left + node.offsetWidth > hspace)
172
+ left = hspace - node.offsetWidth;
173
+ }
174
+ node.style.top = (top + paddingTop()) + "px";
175
+ node.style.left = (left + paddingLeft()) + "px";
176
+ if (scroll)
177
+ scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight);
178
+ },
179
+
180
+ lineCount: function() {return lines.length;},
181
+ getCursor: function(start) {
182
+ if (start == null) start = sel.inverted;
183
+ return copyPos(start ? sel.from : sel.to);
184
+ },
185
+ somethingSelected: function() {return !posEq(sel.from, sel.to);},
186
+ setCursor: operation(function(line, ch) {
187
+ if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch);
188
+ else setCursor(line, ch);
189
+ }),
190
+ setSelection: operation(function(from, to) {setSelection(clipPos(from), clipPos(to || from));}),
191
+ getLine: function(line) {if (isLine(line)) return lines[line].text;},
192
+ setLine: operation(function(line, text) {
193
+ if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: lines[line].text.length});
194
+ }),
195
+ removeLine: operation(function(line) {
196
+ if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
197
+ }),
198
+ replaceRange: operation(replaceRange),
199
+ getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
200
+
201
+ operation: function(f){return operation(f)();},
202
+ refresh: function(){updateDisplay(true);},
203
+ getInputField: function(){return input;},
204
+ getWrapperElement: function(){return wrapper;},
205
+ getScrollerElement: function(){return scroller;},
206
+ getGutterElement: function(){return gutter;}
207
+ };
208
+
209
+ function setValue(code) {
210
+ history = null;
211
+ var top = {line: 0, ch: 0};
212
+ updateLines(top, {line: lines.length - 1, ch: lines[lines.length-1].text.length},
213
+ splitLines(code), top, top);
214
+ history = new History();
215
+ }
216
+ function getValue(code) {
217
+ var text = [];
218
+ for (var i = 0, l = lines.length; i < l; ++i)
219
+ text.push(lines[i].text);
220
+ return text.join("\n");
221
+ }
222
+
223
+ function onMouseDown(e) {
224
+ // Check whether this is a click in a widget
225
+ for (var n = e_target(e); n != wrapper; n = n.parentNode)
226
+ if (n.parentNode == code && n != mover) return;
227
+ var ld = lastDoubleClick; lastDoubleClick = null;
228
+ // First, see if this is a click in the gutter
229
+ for (var n = e_target(e); n != wrapper; n = n.parentNode)
230
+ if (n.parentNode == gutterText) {
231
+ if (options.onGutterClick)
232
+ options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom);
233
+ return e_preventDefault(e);
234
+ }
235
+
236
+ var start = posFromMouse(e);
237
+
238
+ switch (e_button(e)) {
239
+ case 3:
240
+ if (gecko && !mac) onContextMenu(e);
241
+ return;
242
+ case 2:
243
+ if (start) setCursor(start.line, start.ch, true);
244
+ return;
245
+ }
246
+ // For button 1, if it was clicked inside the editor
247
+ // (posFromMouse returning non-null), we have to adjust the
248
+ // selection.
249
+ if (!start) {if (e_target(e) == scroller) e_preventDefault(e); return;}
250
+
251
+ if (!focused) onFocus();
252
+ e_preventDefault(e);
253
+ if (ld && +new Date - ld < 400) return selectLine(start.line);
254
+
255
+ setCursor(start.line, start.ch, true);
256
+ var last = start, going;
257
+ // And then we have to see if it's a drag event, in which case
258
+ // the dragged-over text must be selected.
259
+ function end() {
260
+ focusInput();
261
+ updateInput = true;
262
+ move(); up();
263
+ }
264
+ function extend(e) {
265
+ var cur = posFromMouse(e, true);
266
+ if (cur && !posEq(cur, last)) {
267
+ if (!focused) onFocus();
268
+ last = cur;
269
+ setSelectionUser(start, cur);
270
+ updateInput = false;
271
+ var visible = visibleLines();
272
+ if (cur.line >= visible.to || cur.line < visible.from)
273
+ going = setTimeout(operation(function(){extend(e);}), 150);
274
+ }
275
+ }
276
+
277
+ var move = connect(targetDocument, "mousemove", operation(function(e) {
278
+ clearTimeout(going);
279
+ e_preventDefault(e);
280
+ extend(e);
281
+ }), true);
282
+ var up = connect(targetDocument, "mouseup", operation(function(e) {
283
+ clearTimeout(going);
284
+ var cur = posFromMouse(e);
285
+ if (cur) setSelectionUser(start, cur);
286
+ e_preventDefault(e);
287
+ end();
288
+ }), true);
289
+ }
290
+ function onDblClick(e) {
291
+ var pos = posFromMouse(e);
292
+ if (!pos) return;
293
+ selectWordAt(pos);
294
+ e_preventDefault(e);
295
+ lastDoubleClick = +new Date;
296
+ }
297
+ function onDrop(e) {
298
+ e.preventDefault();
299
+ var pos = posFromMouse(e, true), files = e.dataTransfer.files;
300
+ if (!pos || options.readOnly) return;
301
+ if (files && files.length && window.FileReader && window.File) {
302
+ function loadFile(file, i) {
303
+ var reader = new FileReader;
304
+ reader.onload = function() {
305
+ text[i] = reader.result;
306
+ if (++read == n) replaceRange(text.join(""), clipPos(pos), clipPos(pos));
307
+ };
308
+ reader.readAsText(file);
309
+ }
310
+ var n = files.length, text = Array(n), read = 0;
311
+ for (var i = 0; i < n; ++i) loadFile(files[i], i);
312
+ }
313
+ else {
314
+ try {
315
+ var text = e.dataTransfer.getData("Text");
316
+ if (text) replaceRange(text, pos, pos);
317
+ }
318
+ catch(e){}
319
+ }
320
+ }
321
+ function onKeyDown(e) {
322
+ if (!focused) onFocus();
323
+
324
+ var code = e.keyCode;
325
+ // IE does strange things with escape.
326
+ if (ie && code == 27) { e.returnValue = false; }
327
+ // Tries to detect ctrl on non-mac, cmd on mac.
328
+ var mod = (mac ? e.metaKey : e.ctrlKey) && !e.altKey, anyMod = e.ctrlKey || e.altKey || e.metaKey;
329
+ if (code == 16 || e.shiftKey) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
330
+ else shiftSelecting = null;
331
+ // First give onKeyEvent option a chance to handle this.
332
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
333
+
334
+ if (code == 33 || code == 34) {scrollPage(code == 34); return e_preventDefault(e);} // page up/down
335
+ if (mod && ((code == 36 || code == 35) || // ctrl-home/end
336
+ mac && (code == 38 || code == 40))) { // cmd-up/down
337
+ scrollEnd(code == 36 || code == 38); return e_preventDefault(e);
338
+ }
339
+ if (mod && code == 65) {selectAll(); return e_preventDefault(e);} // ctrl-a
340
+ if (!options.readOnly) {
341
+ if (!anyMod && code == 13) {return;} // enter
342
+ if (!anyMod && code == 9 && handleTab(e.shiftKey)) return e_preventDefault(e); // tab
343
+ if (mod && code == 90) {undo(); return e_preventDefault(e);} // ctrl-z
344
+ if (mod && ((e.shiftKey && code == 90) || code == 89)) {redo(); return e_preventDefault(e);} // ctrl-shift-z, ctrl-y
345
+ }
346
+ if (code == 36) { if (options.smartHome) { smartHome(); return e_preventDefault(e); } }
347
+
348
+ // Key id to use in the movementKeys map. We also pass it to
349
+ // fastPoll in order to 'self learn'. We need this because
350
+ // reducedSelection, the hack where we collapse the selection to
351
+ // its start when it is inverted and a movement key is pressed
352
+ // (and later restore it again), shouldn't be used for
353
+ // non-movement keys.
354
+ curKeyId = (mod ? "c" : "") + (e.altKey ? "a" : "") + code;
355
+ if (sel.inverted && movementKeys[curKeyId] === true) {
356
+ var range = selRange(input);
357
+ if (range) {
358
+ reducedSelection = {anchor: range.start};
359
+ setSelRange(input, range.start, range.start);
360
+ }
361
+ }
362
+ // Don't save the key as a movementkey unless it had a modifier
363
+ if (!mod && !e.altKey) curKeyId = null;
364
+ fastPoll(curKeyId);
365
+ }
366
+ function onKeyUp(e) {
367
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
368
+ if (reducedSelection) {
369
+ reducedSelection = null;
370
+ updateInput = true;
371
+ }
372
+ if (e.keyCode == 16) shiftSelecting = null;
373
+ }
374
+ function onKeyPress(e) {
375
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
376
+ if (options.electricChars && mode.electricChars) {
377
+ var ch = String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode);
378
+ if (mode.electricChars.indexOf(ch) > -1)
379
+ setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 50);
380
+ }
381
+ var code = e.keyCode;
382
+ // Re-stop tab and enter. Necessary on some browsers.
383
+ if (code == 13) {if (!options.readOnly) handleEnter(); e_preventDefault(e);}
384
+ else if (!e.ctrlKey && !e.altKey && !e.metaKey && code == 9 && options.tabMode != "default") e_preventDefault(e);
385
+ else fastPoll(curKeyId);
386
+ }
387
+
388
+ function onFocus() {
389
+ if (options.readOnly == "nocursor") return;
390
+ if (!focused) {
391
+ if (options.onFocus) options.onFocus(instance);
392
+ focused = true;
393
+ if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
394
+ wrapper.className += " CodeMirror-focused";
395
+ if (!leaveInputAlone) prepareInput();
396
+ }
397
+ slowPoll();
398
+ restartBlink();
399
+ }
400
+ function onBlur() {
401
+ if (focused) {
402
+ if (options.onBlur) options.onBlur(instance);
403
+ focused = false;
404
+ wrapper.className = wrapper.className.replace(" CodeMirror-focused", "");
405
+ }
406
+ clearInterval(blinker);
407
+ setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
408
+ }
409
+
410
+ // Replace the range from from to to by the strings in newText.
411
+ // Afterwards, set the selection to selFrom, selTo.
412
+ function updateLines(from, to, newText, selFrom, selTo) {
413
+ if (history) {
414
+ var old = [];
415
+ for (var i = from.line, e = to.line + 1; i < e; ++i) old.push(lines[i].text);
416
+ history.addChange(from.line, newText.length, old);
417
+ while (history.done.length > options.undoDepth) history.done.shift();
418
+ }
419
+ updateLinesNoUndo(from, to, newText, selFrom, selTo);
420
+ }
421
+ function unredoHelper(from, to) {
422
+ var change = from.pop();
423
+ if (change) {
424
+ var replaced = [], end = change.start + change.added;
425
+ for (var i = change.start; i < end; ++i) replaced.push(lines[i].text);
426
+ to.push({start: change.start, added: change.old.length, old: replaced});
427
+ var pos = clipPos({line: change.start + change.old.length - 1,
428
+ ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
429
+ updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: lines[end-1].text.length}, change.old, pos, pos);
430
+ updateInput = true;
431
+ }
432
+ }
433
+ function undo() {unredoHelper(history.done, history.undone);}
434
+ function redo() {unredoHelper(history.undone, history.done);}
435
+
436
+ function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
437
+ var recomputeMaxLength = false, maxLineLength = maxLine.length;
438
+ for (var i = from.line; i <= to.line; ++i) {
439
+ if (lines[i].text.length == maxLineLength) {recomputeMaxLength = true; break;}
440
+ }
441
+
442
+ var nlines = to.line - from.line, firstLine = lines[from.line], lastLine = lines[to.line];
443
+ // First adjust the line structure, taking some care to leave highlighting intact.
444
+ if (firstLine == lastLine) {
445
+ if (newText.length == 1)
446
+ firstLine.replace(from.ch, to.ch, newText[0]);
447
+ else {
448
+ lastLine = firstLine.split(to.ch, newText[newText.length-1]);
449
+ var spliceargs = [from.line + 1, nlines];
450
+ firstLine.replace(from.ch, firstLine.text.length, newText[0]);
451
+ for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
452
+ spliceargs.push(lastLine);
453
+ lines.splice.apply(lines, spliceargs);
454
+ }
455
+ }
456
+ else if (newText.length == 1) {
457
+ firstLine.replace(from.ch, firstLine.text.length, newText[0] + lastLine.text.slice(to.ch));
458
+ lines.splice(from.line + 1, nlines);
459
+ }
460
+ else {
461
+ var spliceargs = [from.line + 1, nlines - 1];
462
+ firstLine.replace(from.ch, firstLine.text.length, newText[0]);
463
+ lastLine.replace(0, to.ch, newText[newText.length-1]);
464
+ for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
465
+ lines.splice.apply(lines, spliceargs);
466
+ }
467
+
468
+
469
+ for (var i = from.line, e = i + newText.length; i < e; ++i) {
470
+ var l = lines[i].text;
471
+ if (l.length > maxLineLength) {
472
+ maxLine = l; maxLineLength = l.length; maxWidth = null;
473
+ recomputeMaxLength = false;
474
+ }
475
+ }
476
+ if (recomputeMaxLength) {
477
+ maxLineLength = 0; maxLine = ""; maxWidth = null;
478
+ for (var i = 0, e = lines.length; i < e; ++i) {
479
+ var l = lines[i].text;
480
+ if (l.length > maxLineLength) {
481
+ maxLineLength = l.length; maxLine = l;
482
+ }
483
+ }
484
+ }
485
+
486
+ // Add these lines to the work array, so that they will be
487
+ // highlighted. Adjust work lines if lines were added/removed.
488
+ var newWork = [], lendiff = newText.length - nlines - 1;
489
+ for (var i = 0, l = work.length; i < l; ++i) {
490
+ var task = work[i];
491
+ if (task < from.line) newWork.push(task);
492
+ else if (task > to.line) newWork.push(task + lendiff);
493
+ }
494
+ if (newText.length < 5) {
495
+ highlightLines(from.line, from.line + newText.length);
496
+ newWork.push(from.line + newText.length);
497
+ } else {
498
+ newWork.push(from.line);
499
+ }
500
+ work = newWork;
501
+ startWorker(100);
502
+ // Remember that these lines changed, for updating the display
503
+ changes.push({from: from.line, to: to.line + 1, diff: lendiff});
504
+ textChanged = {from: from, to: to, text: newText};
505
+
506
+ // Update the selection
507
+ function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
508
+ setSelection(selFrom, selTo, updateLine(sel.from.line), updateLine(sel.to.line));
509
+
510
+ // Make sure the scroll-size div has the correct height.
511
+ code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
512
+ }
513
+
514
+ function replaceRange(code, from, to) {
515
+ from = clipPos(from);
516
+ if (!to) to = from; else to = clipPos(to);
517
+ code = splitLines(code);
518
+ function adjustPos(pos) {
519
+ if (posLess(pos, from)) return pos;
520
+ if (!posLess(to, pos)) return end;
521
+ var line = pos.line + code.length - (to.line - from.line) - 1;
522
+ var ch = pos.ch;
523
+ if (pos.line == to.line)
524
+ ch += code[code.length-1].length - (to.ch - (to.line == from.line ? from.ch : 0));
525
+ return {line: line, ch: ch};
526
+ }
527
+ var end;
528
+ replaceRange1(code, from, to, function(end1) {
529
+ end = end1;
530
+ return {from: adjustPos(sel.from), to: adjustPos(sel.to)};
531
+ });
532
+ return end;
533
+ }
534
+ function replaceSelection(code, collapse) {
535
+ replaceRange1(splitLines(code), sel.from, sel.to, function(end) {
536
+ if (collapse == "end") return {from: end, to: end};
537
+ else if (collapse == "start") return {from: sel.from, to: sel.from};
538
+ else return {from: sel.from, to: end};
539
+ });
540
+ }
541
+ function replaceRange1(code, from, to, computeSel) {
542
+ var endch = code.length == 1 ? code[0].length + from.ch : code[code.length-1].length;
543
+ var newSel = computeSel({line: from.line + code.length - 1, ch: endch});
544
+ updateLines(from, to, code, newSel.from, newSel.to);
545
+ }
546
+
547
+ function getRange(from, to) {
548
+ var l1 = from.line, l2 = to.line;
549
+ if (l1 == l2) return lines[l1].text.slice(from.ch, to.ch);
550
+ var code = [lines[l1].text.slice(from.ch)];
551
+ for (var i = l1 + 1; i < l2; ++i) code.push(lines[i].text);
552
+ code.push(lines[l2].text.slice(0, to.ch));
553
+ return code.join("\n");
554
+ }
555
+ function getSelection() {
556
+ return getRange(sel.from, sel.to);
557
+ }
558
+
559
+ var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
560
+ function slowPoll() {
561
+ if (pollingFast) return;
562
+ poll.set(2000, function() {
563
+ startOperation();
564
+ readInput();
565
+ if (focused) slowPoll();
566
+ endOperation();
567
+ });
568
+ }
569
+ function fastPoll(keyId) {
570
+ var missed = false;
571
+ pollingFast = true;
572
+ function p() {
573
+ startOperation();
574
+ var changed = readInput();
575
+ if (changed && keyId) {
576
+ if (changed == "moved" && movementKeys[keyId] == null) movementKeys[keyId] = true;
577
+ if (changed == "changed") movementKeys[keyId] = false;
578
+ }
579
+ if (!changed && !missed) {missed = true; poll.set(80, p);}
580
+ else {pollingFast = false; slowPoll();}
581
+ endOperation();
582
+ }
583
+ poll.set(20, p);
584
+ }
585
+
586
+ // Inspects the textarea, compares its state (content, selection)
587
+ // to the data in the editing variable, and updates the editor
588
+ // content or cursor if something changed.
589
+ function readInput() {
590
+ if (leaveInputAlone || !focused) return;
591
+ var changed = false, text = input.value, sr = selRange(input);
592
+ if (!sr) return false;
593
+ var changed = editing.text != text, rs = reducedSelection;
594
+ var moved = changed || sr.start != editing.start || sr.end != (rs ? editing.start : editing.end);
595
+ if (!moved && !rs) return false;
596
+ if (changed) {
597
+ shiftSelecting = reducedSelection = null;
598
+ if (options.readOnly) {updateInput = true; return "changed";}
599
+ }
600
+
601
+ // Compute selection start and end based on start/end offsets in textarea
602
+ function computeOffset(n, startLine) {
603
+ var pos = 0;
604
+ for (;;) {
605
+ var found = text.indexOf("\n", pos);
606
+ if (found == -1 || (text.charAt(found-1) == "\r" ? found - 1 : found) >= n)
607
+ return {line: startLine, ch: n - pos};
608
+ ++startLine;
609
+ pos = found + 1;
610
+ }
611
+ }
612
+ var from = computeOffset(sr.start, editing.from),
613
+ to = computeOffset(sr.end, editing.from);
614
+ // Here we have to take the reducedSelection hack into account,
615
+ // so that you can, for example, press shift-up at the start of
616
+ // your selection and have the right thing happen.
617
+ if (rs) {
618
+ var head = sr.start == rs.anchor ? to : from;
619
+ var tail = shiftSelecting ? sel.to : sr.start == rs.anchor ? from : to;
620
+ if (sel.inverted = posLess(head, tail)) { from = head; to = tail; }
621
+ else { reducedSelection = null; from = tail; to = head; }
622
+ }
623
+
624
+ // In some cases (cursor on same line as before), we don't have
625
+ // to update the textarea content at all.
626
+ if (from.line == to.line && from.line == sel.from.line && from.line == sel.to.line && !shiftSelecting)
627
+ updateInput = false;
628
+
629
+ // Magic mess to extract precise edited range from the changed
630
+ // string.
631
+ if (changed) {
632
+ var start = 0, end = text.length, len = Math.min(end, editing.text.length);
633
+ var c, line = editing.from, nl = -1;
634
+ while (start < len && (c = text.charAt(start)) == editing.text.charAt(start)) {
635
+ ++start;
636
+ if (c == "\n") {line++; nl = start;}
637
+ }
638
+ var ch = nl > -1 ? start - nl : start, endline = editing.to - 1, edend = editing.text.length;
639
+ for (;;) {
640
+ c = editing.text.charAt(edend);
641
+ if (text.charAt(end) != c) {++end; ++edend; break;}
642
+ if (c == "\n") endline--;
643
+ if (edend <= start || end <= start) break;
644
+ --end; --edend;
645
+ }
646
+ var nl = editing.text.lastIndexOf("\n", edend - 1), endch = nl == -1 ? edend : edend - nl - 1;
647
+ updateLines({line: line, ch: ch}, {line: endline, ch: endch}, splitLines(text.slice(start, end)), from, to);
648
+ if (line != endline || from.line != line) updateInput = true;
649
+ }
650
+ else setSelection(from, to);
651
+
652
+ editing.text = text; editing.start = sr.start; editing.end = sr.end;
653
+ return changed ? "changed" : moved ? "moved" : false;
654
+ }
655
+
656
+ // Set the textarea content and selection range to match the
657
+ // editor state.
658
+ function prepareInput() {
659
+ var text = [];
660
+ var from = Math.max(0, sel.from.line - 1), to = Math.min(lines.length, sel.to.line + 2);
661
+ for (var i = from; i < to; ++i) text.push(lines[i].text);
662
+ text = input.value = text.join(lineSep);
663
+ var startch = sel.from.ch, endch = sel.to.ch;
664
+ for (var i = from; i < sel.from.line; ++i)
665
+ startch += lineSep.length + lines[i].text.length;
666
+ for (var i = from; i < sel.to.line; ++i)
667
+ endch += lineSep.length + lines[i].text.length;
668
+ editing = {text: text, from: from, to: to, start: startch, end: endch};
669
+ setSelRange(input, startch, reducedSelection ? startch : endch);
670
+ }
671
+ function focusInput() {
672
+ if (options.readOnly != "nocursor") input.focus();
673
+ }
674
+
675
+ function scrollEditorIntoView() {
676
+ if (!cursor.getBoundingClientRect) return;
677
+ var rect = cursor.getBoundingClientRect();
678
+ var winH = window.innerHeight || document.body.offsetHeight || document.documentElement.offsetHeight;
679
+ if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
680
+ }
681
+ function scrollCursorIntoView() {
682
+ var cursor = localCoords(sel.inverted ? sel.from : sel.to);
683
+ return scrollIntoView(cursor.x, cursor.y, cursor.x, cursor.yBot);
684
+ }
685
+ function scrollIntoView(x1, y1, x2, y2) {
686
+ var pl = paddingLeft(), pt = paddingTop(), lh = lineHeight();
687
+ y1 += pt; y2 += pt; x1 += pl; x2 += pl;
688
+ var screen = scroller.clientHeight, screentop = scroller.scrollTop, scrolled = false, result = true;
689
+ if (y1 < screentop) {scroller.scrollTop = Math.max(0, y1 - 2*lh); scrolled = true;}
690
+ else if (y2 > screentop + screen) {scroller.scrollTop = y2 + lh - screen; scrolled = true;}
691
+
692
+ var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
693
+ if (x1 < screenleft) {
694
+ if (x1 < 50) x1 = 0;
695
+ scroller.scrollLeft = Math.max(0, x1 - 10);
696
+ scrolled = true;
697
+ }
698
+ else if (x2 > screenw + screenleft) {
699
+ scroller.scrollLeft = x2 + 10 - screenw;
700
+ scrolled = true;
701
+ if (x2 > code.clientWidth) result = false;
702
+ }
703
+ if (scrolled && options.onScroll) options.onScroll(instance);
704
+ return result;
705
+ }
706
+
707
+ function visibleLines() {
708
+ var lh = lineHeight(), top = scroller.scrollTop - paddingTop();
709
+ return {from: Math.min(lines.length, Math.max(0, Math.floor(top / lh))),
710
+ to: Math.min(lines.length, Math.ceil((top + scroller.clientHeight) / lh))};
711
+ }
712
+ // Uses a set of changes plus the current scroll position to
713
+ // determine which DOM updates have to be made, and makes the
714
+ // updates.
715
+ function updateDisplay(changes) {
716
+ if (!scroller.clientWidth) {
717
+ showingFrom = showingTo = 0;
718
+ return;
719
+ }
720
+ // First create a range of theoretically intact lines, and punch
721
+ // holes in that using the change info.
722
+ var intact = changes === true ? [] : [{from: showingFrom, to: showingTo, domStart: 0}];
723
+ for (var i = 0, l = changes.length || 0; i < l; ++i) {
724
+ var change = changes[i], intact2 = [], diff = change.diff || 0;
725
+ for (var j = 0, l2 = intact.length; j < l2; ++j) {
726
+ var range = intact[j];
727
+ if (change.to <= range.from)
728
+ intact2.push({from: range.from + diff, to: range.to + diff, domStart: range.domStart});
729
+ else if (range.to <= change.from)
730
+ intact2.push(range);
731
+ else {
732
+ if (change.from > range.from)
733
+ intact2.push({from: range.from, to: change.from, domStart: range.domStart})
734
+ if (change.to < range.to)
735
+ intact2.push({from: change.to + diff, to: range.to + diff,
736
+ domStart: range.domStart + (change.to - range.from)});
737
+ }
738
+ }
739
+ intact = intact2;
740
+ }
741
+
742
+ // Then, determine which lines we'd want to see, and which
743
+ // updates have to be made to get there.
744
+ var visible = visibleLines();
745
+ var from = Math.min(showingFrom, Math.max(visible.from - 3, 0)),
746
+ to = Math.min(lines.length, Math.max(showingTo, visible.to + 3)),
747
+ updates = [], domPos = 0, domEnd = showingTo - showingFrom, pos = from, changedLines = 0;
748
+
749
+ for (var i = 0, l = intact.length; i < l; ++i) {
750
+ var range = intact[i];
751
+ if (range.to <= from) continue;
752
+ if (range.from >= to) break;
753
+ if (range.domStart > domPos || range.from > pos) {
754
+ updates.push({from: pos, to: range.from, domSize: range.domStart - domPos, domStart: domPos});
755
+ changedLines += range.from - pos;
756
+ }
757
+ pos = range.to;
758
+ domPos = range.domStart + (range.to - range.from);
759
+ }
760
+ if (domPos != domEnd || pos != to) {
761
+ changedLines += Math.abs(to - pos);
762
+ updates.push({from: pos, to: to, domSize: domEnd - domPos, domStart: domPos});
763
+ }
764
+
765
+ if (!updates.length) return;
766
+ lineDiv.style.display = "none";
767
+ // If more than 30% of the screen needs update, just do a full
768
+ // redraw (which is quicker than patching)
769
+ if (changedLines > (visible.to - visible.from) * .3)
770
+ refreshDisplay(from = Math.max(visible.from - 10, 0), to = Math.min(visible.to + 7, lines.length));
771
+ // Otherwise, only update the stuff that needs updating.
772
+ else
773
+ patchDisplay(updates);
774
+ lineDiv.style.display = "";
775
+
776
+ // Position the mover div to align with the lines it's supposed
777
+ // to be showing (which will cover the visible display)
778
+ var different = from != showingFrom || to != showingTo || lastHeight != scroller.clientHeight;
779
+ showingFrom = from; showingTo = to;
780
+ mover.style.top = (from * lineHeight()) + "px";
781
+ if (different) {
782
+ lastHeight = scroller.clientHeight;
783
+ code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
784
+ }
785
+ if (different || updates.length) updateGutter();
786
+
787
+ if (maxWidth == null) maxWidth = stringWidth(maxLine);
788
+ if (maxWidth > scroller.clientWidth) {
789
+ lineSpace.style.width = maxWidth + "px";
790
+ // Needed to prevent odd wrapping/hiding of widgets placed in here.
791
+ code.style.width = "";
792
+ code.style.width = scroller.scrollWidth + "px";
793
+ } else {
794
+ lineSpace.style.width = code.style.width = "";
795
+ }
796
+
797
+ // Since this is all rather error prone, it is honoured with the
798
+ // only assertion in the whole file.
799
+ if (lineDiv.childNodes.length != showingTo - showingFrom)
800
+ throw new Error("BAD PATCH! " + JSON.stringify(updates) + " size=" + (showingTo - showingFrom) +
801
+ " nodes=" + lineDiv.childNodes.length);
802
+ updateCursor();
803
+ }
804
+
805
+ function refreshDisplay(from, to) {
806
+ var html = [], start = {line: from, ch: 0}, inSel = posLess(sel.from, start) && !posLess(sel.to, start);
807
+ for (var i = from; i < to; ++i) {
808
+ var ch1 = null, ch2 = null;
809
+ if (inSel) {
810
+ ch1 = 0;
811
+ if (sel.to.line == i) {inSel = false; ch2 = sel.to.ch;}
812
+ }
813
+ else if (sel.from.line == i) {
814
+ if (sel.to.line == i) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
815
+ else {inSel = true; ch1 = sel.from.ch;}
816
+ }
817
+ html.push(lines[i].getHTML(ch1, ch2, true));
818
+ }
819
+ lineDiv.innerHTML = html.join("");
820
+ }
821
+ function patchDisplay(updates) {
822
+ // Slightly different algorithm for IE (badInnerHTML), since
823
+ // there .innerHTML on PRE nodes is dumb, and discards
824
+ // whitespace.
825
+ var sfrom = sel.from.line, sto = sel.to.line, off = 0,
826
+ scratch = badInnerHTML && targetDocument.createElement("div");
827
+ for (var i = 0, e = updates.length; i < e; ++i) {
828
+ var rec = updates[i];
829
+ var extra = (rec.to - rec.from) - rec.domSize;
830
+ var nodeAfter = lineDiv.childNodes[rec.domStart + rec.domSize + off] || null;
831
+ if (badInnerHTML)
832
+ for (var j = Math.max(-extra, rec.domSize); j > 0; --j)
833
+ lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
834
+ else if (extra) {
835
+ for (var j = Math.max(0, extra); j > 0; --j)
836
+ lineDiv.insertBefore(targetDocument.createElement("pre"), nodeAfter);
837
+ for (var j = Math.max(0, -extra); j > 0; --j)
838
+ lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
839
+ }
840
+ var node = lineDiv.childNodes[rec.domStart + off], inSel = sfrom < rec.from && sto >= rec.from;
841
+ for (var j = rec.from; j < rec.to; ++j) {
842
+ var ch1 = null, ch2 = null;
843
+ if (inSel) {
844
+ ch1 = 0;
845
+ if (sto == j) {inSel = false; ch2 = sel.to.ch;}
846
+ }
847
+ else if (sfrom == j) {
848
+ if (sto == j) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
849
+ else {inSel = true; ch1 = sel.from.ch;}
850
+ }
851
+ if (badInnerHTML) {
852
+ scratch.innerHTML = lines[j].getHTML(ch1, ch2, true);
853
+ lineDiv.insertBefore(scratch.firstChild, nodeAfter);
854
+ }
855
+ else {
856
+ node.innerHTML = lines[j].getHTML(ch1, ch2, false);
857
+ node.className = lines[j].className || "";
858
+ node = node.nextSibling;
859
+ }
860
+ }
861
+ off += extra;
862
+ }
863
+ }
864
+
865
+ function updateGutter() {
866
+ if (!options.gutter && !options.lineNumbers) return;
867
+ var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
868
+ gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
869
+ var html = [];
870
+ for (var i = showingFrom; i < Math.max(showingTo, showingFrom + 1); ++i) {
871
+ var marker = lines[i].gutterMarker;
872
+ var text = options.lineNumbers ? i + options.firstLineNumber : null;
873
+ if (marker && marker.text)
874
+ text = marker.text.replace("%N%", text != null ? text : "");
875
+ else if (text == null)
876
+ text = "\u00a0";
877
+ html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text, "</pre>");
878
+ }
879
+ gutter.style.display = "none";
880
+ gutterText.innerHTML = html.join("");
881
+ var minwidth = String(lines.length).length, firstNode = gutterText.firstChild, val = eltText(firstNode), pad = "";
882
+ while (val.length + pad.length < minwidth) pad += "\u00a0";
883
+ if (pad) firstNode.insertBefore(targetDocument.createTextNode(pad), firstNode.firstChild);
884
+ gutter.style.display = "";
885
+ lineSpace.style.marginLeft = gutter.offsetWidth + "px";
886
+ }
887
+ function updateCursor() {
888
+ var head = sel.inverted ? sel.from : sel.to, lh = lineHeight();
889
+ var x = charX(head.line, head.ch);
890
+ inputDiv.style.top = (head.line * lh - scroller.scrollTop) + "px";
891
+ inputDiv.style.left = (x - scroller.scrollLeft) + "px";
892
+ if (posEq(sel.from, sel.to)) {
893
+ cursor.style.top = (head.line - showingFrom) * lh + "px";
894
+ cursor.style.left = x + "px";
895
+ cursor.style.display = "";
896
+ }
897
+ else cursor.style.display = "none";
898
+ }
899
+
900
+ function setSelectionUser(from, to) {
901
+ var sh = shiftSelecting && clipPos(shiftSelecting);
902
+ if (sh) {
903
+ if (posLess(sh, from)) from = sh;
904
+ else if (posLess(to, sh)) to = sh;
905
+ }
906
+ setSelection(from, to);
907
+ }
908
+ // Update the selection. Last two args are only used by
909
+ // updateLines, since they have to be expressed in the line
910
+ // numbers before the update.
911
+ function setSelection(from, to, oldFrom, oldTo) {
912
+ if (posEq(sel.from, from) && posEq(sel.to, to)) return;
913
+ if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
914
+
915
+ if (posEq(from, to)) sel.inverted = false;
916
+ else if (posEq(from, sel.to)) sel.inverted = false;
917
+ else if (posEq(to, sel.from)) sel.inverted = true;
918
+
919
+ // Some ugly logic used to only mark the lines that actually did
920
+ // see a change in selection as changed, rather than the whole
921
+ // selected range.
922
+ if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
923
+ if (posEq(from, to)) {
924
+ if (!posEq(sel.from, sel.to))
925
+ changes.push({from: oldFrom, to: oldTo + 1});
926
+ }
927
+ else if (posEq(sel.from, sel.to)) {
928
+ changes.push({from: from.line, to: to.line + 1});
929
+ }
930
+ else {
931
+ if (!posEq(from, sel.from)) {
932
+ if (from.line < oldFrom)
933
+ changes.push({from: from.line, to: Math.min(to.line, oldFrom) + 1});
934
+ else
935
+ changes.push({from: oldFrom, to: Math.min(oldTo, from.line) + 1});
936
+ }
937
+ if (!posEq(to, sel.to)) {
938
+ if (to.line < oldTo)
939
+ changes.push({from: Math.max(oldFrom, from.line), to: oldTo + 1});
940
+ else
941
+ changes.push({from: Math.max(from.line, oldTo), to: to.line + 1});
942
+ }
943
+ }
944
+ sel.from = from; sel.to = to;
945
+ selectionChanged = true;
946
+ }
947
+ function setCursor(line, ch, user) {
948
+ var pos = clipPos({line: line, ch: ch || 0});
949
+ (user ? setSelectionUser : setSelection)(pos, pos);
950
+ }
951
+
952
+ function clipLine(n) {return Math.max(0, Math.min(n, lines.length-1));}
953
+ function clipPos(pos) {
954
+ if (pos.line < 0) return {line: 0, ch: 0};
955
+ if (pos.line >= lines.length) return {line: lines.length-1, ch: lines[lines.length-1].text.length};
956
+ var ch = pos.ch, linelen = lines[pos.line].text.length;
957
+ if (ch == null || ch > linelen) return {line: pos.line, ch: linelen};
958
+ else if (ch < 0) return {line: pos.line, ch: 0};
959
+ else return pos;
960
+ }
961
+
962
+ function scrollPage(down) {
963
+ var linesPerPage = Math.floor(scroller.clientHeight / lineHeight()), head = sel.inverted ? sel.from : sel.to;
964
+ setCursor(head.line + (Math.max(linesPerPage - 1, 1) * (down ? 1 : -1)), head.ch, true);
965
+ }
966
+ function scrollEnd(top) {
967
+ var pos = top ? {line: 0, ch: 0} : {line: lines.length - 1, ch: lines[lines.length-1].text.length};
968
+ setSelectionUser(pos, pos);
969
+ }
970
+ function selectAll() {
971
+ var endLine = lines.length - 1;
972
+ setSelection({line: 0, ch: 0}, {line: endLine, ch: lines[endLine].text.length});
973
+ }
974
+ function selectWordAt(pos) {
975
+ var line = lines[pos.line].text;
976
+ var start = pos.ch, end = pos.ch;
977
+ while (start > 0 && /\w/.test(line.charAt(start - 1))) --start;
978
+ while (end < line.length && /\w/.test(line.charAt(end))) ++end;
979
+ setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end});
980
+ }
981
+ function selectLine(line) {
982
+ setSelectionUser({line: line, ch: 0}, {line: line, ch: lines[line].text.length});
983
+ }
984
+ function handleEnter() {
985
+ replaceSelection("\n", "end");
986
+ if (options.enterMode != "flat")
987
+ indentLine(sel.from.line, options.enterMode == "keep" ? "prev" : "smart");
988
+ }
989
+ function handleTab(shift) {
990
+ function indentSelected(mode) {
991
+ if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
992
+ var e = sel.to.line - (sel.to.ch ? 0 : 1);
993
+ for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
994
+ }
995
+ shiftSelecting = null;
996
+ switch (options.tabMode) {
997
+ case "default":
998
+ return false;
999
+ case "indent":
1000
+ indentSelected("smart");
1001
+ break;
1002
+ case "classic":
1003
+ if (posEq(sel.from, sel.to)) {
1004
+ if (shift) indentLine(sel.from.line, "smart");
1005
+ else replaceSelection("\t", "end");
1006
+ break;
1007
+ }
1008
+ case "shift":
1009
+ indentSelected(shift ? "subtract" : "add");
1010
+ break;
1011
+ }
1012
+ return true;
1013
+ }
1014
+ function smartHome() {
1015
+ var firstNonWS = Math.max(0, lines[sel.from.line].text.search(/\S/));
1016
+ setCursor(sel.from.line, sel.from.ch <= firstNonWS && sel.from.ch ? 0 : firstNonWS, true);
1017
+ }
1018
+
1019
+ function indentLine(n, how) {
1020
+ if (how == "smart") {
1021
+ if (!mode.indent) how = "prev";
1022
+ else var state = getStateBefore(n);
1023
+ }
1024
+
1025
+ var line = lines[n], curSpace = line.indentation(), curSpaceString = line.text.match(/^\s*/)[0], indentation;
1026
+ if (how == "prev") {
1027
+ if (n) indentation = lines[n-1].indentation();
1028
+ else indentation = 0;
1029
+ }
1030
+ else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length));
1031
+ else if (how == "add") indentation = curSpace + options.indentUnit;
1032
+ else if (how == "subtract") indentation = curSpace - options.indentUnit;
1033
+ indentation = Math.max(0, indentation);
1034
+ var diff = indentation - curSpace;
1035
+
1036
+ if (!diff) {
1037
+ if (sel.from.line != n && sel.to.line != n) return;
1038
+ var indentString = curSpaceString;
1039
+ }
1040
+ else {
1041
+ var indentString = "", pos = 0;
1042
+ if (options.indentWithTabs)
1043
+ for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
1044
+ while (pos < indentation) {++pos; indentString += " ";}
1045
+ }
1046
+
1047
+ replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
1048
+ }
1049
+
1050
+ function loadMode() {
1051
+ mode = CodeMirror.getMode(options, options.mode);
1052
+ for (var i = 0, l = lines.length; i < l; ++i)
1053
+ lines[i].stateAfter = null;
1054
+ work = [0];
1055
+ startWorker();
1056
+ }
1057
+ function gutterChanged() {
1058
+ var visible = options.gutter || options.lineNumbers;
1059
+ gutter.style.display = visible ? "" : "none";
1060
+ if (visible) updateGutter();
1061
+ else lineDiv.parentNode.style.marginLeft = 0;
1062
+ }
1063
+
1064
+ function markText(from, to, className) {
1065
+ from = clipPos(from); to = clipPos(to);
1066
+ var accum = [];
1067
+ function add(line, from, to, className) {
1068
+ var line = lines[line], mark = line.addMark(from, to, className);
1069
+ mark.line = line;
1070
+ accum.push(mark);
1071
+ }
1072
+ if (from.line == to.line) add(from.line, from.ch, to.ch, className);
1073
+ else {
1074
+ add(from.line, from.ch, null, className);
1075
+ for (var i = from.line + 1, e = to.line; i < e; ++i)
1076
+ add(i, 0, null, className);
1077
+ add(to.line, 0, to.ch, className);
1078
+ }
1079
+ changes.push({from: from.line, to: to.line + 1});
1080
+ return function() {
1081
+ var start, end;
1082
+ for (var i = 0; i < accum.length; ++i) {
1083
+ var mark = accum[i], found = indexOf(lines, mark.line);
1084
+ mark.line.removeMark(mark);
1085
+ if (found > -1) {
1086
+ if (start == null) start = found;
1087
+ end = found;
1088
+ }
1089
+ }
1090
+ if (start != null) changes.push({from: start, to: end + 1});
1091
+ };
1092
+ }
1093
+
1094
+ function addGutterMarker(line, text, className) {
1095
+ if (typeof line == "number") line = lines[clipLine(line)];
1096
+ line.gutterMarker = {text: text, style: className};
1097
+ updateGutter();
1098
+ return line;
1099
+ }
1100
+ function removeGutterMarker(line) {
1101
+ if (typeof line == "number") line = lines[clipLine(line)];
1102
+ line.gutterMarker = null;
1103
+ updateGutter();
1104
+ }
1105
+ function setLineClass(line, className) {
1106
+ if (typeof line == "number") {
1107
+ var no = line;
1108
+ line = lines[clipLine(line)];
1109
+ }
1110
+ else {
1111
+ var no = indexOf(lines, line);
1112
+ if (no == -1) return null;
1113
+ }
1114
+ if (line.className != className) {
1115
+ line.className = className;
1116
+ changes.push({from: no, to: no + 1});
1117
+ }
1118
+ return line;
1119
+ }
1120
+
1121
+ function lineInfo(line) {
1122
+ if (typeof line == "number") {
1123
+ var n = line;
1124
+ line = lines[line];
1125
+ if (!line) return null;
1126
+ }
1127
+ else {
1128
+ var n = indexOf(lines, line);
1129
+ if (n == -1) return null;
1130
+ }
1131
+ var marker = line.gutterMarker;
1132
+ return {line: n, text: line.text, markerText: marker && marker.text, markerClass: marker && marker.style};
1133
+ }
1134
+
1135
+ function stringWidth(str) {
1136
+ measure.innerHTML = "<pre><span>x</span></pre>";
1137
+ measure.firstChild.firstChild.firstChild.nodeValue = str;
1138
+ return measure.firstChild.firstChild.offsetWidth || 10;
1139
+ }
1140
+ // These are used to go from pixel positions to character
1141
+ // positions, taking varying character widths into account.
1142
+ function charX(line, pos) {
1143
+ if (pos == 0) return 0;
1144
+ measure.innerHTML = "<pre><span>" + lines[line].getHTML(null, null, false, pos) + "</span></pre>";
1145
+ return measure.firstChild.firstChild.offsetWidth;
1146
+ }
1147
+ function charFromX(line, x) {
1148
+ if (x <= 0) return 0;
1149
+ var lineObj = lines[line], text = lineObj.text;
1150
+ function getX(len) {
1151
+ measure.innerHTML = "<pre><span>" + lineObj.getHTML(null, null, false, len) + "</span></pre>";
1152
+ return measure.firstChild.firstChild.offsetWidth;
1153
+ }
1154
+ var from = 0, fromX = 0, to = text.length, toX;
1155
+ // Guess a suitable upper bound for our search.
1156
+ var estimated = Math.min(to, Math.ceil(x / stringWidth("x")));
1157
+ for (;;) {
1158
+ var estX = getX(estimated);
1159
+ if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
1160
+ else {toX = estX; to = estimated; break;}
1161
+ }
1162
+ if (x > toX) return to;
1163
+ // Try to guess a suitable lower bound as well.
1164
+ estimated = Math.floor(to * 0.8); estX = getX(estimated);
1165
+ if (estX < x) {from = estimated; fromX = estX;}
1166
+ // Do a binary search between these bounds.
1167
+ for (;;) {
1168
+ if (to - from <= 1) return (toX - x > x - fromX) ? from : to;
1169
+ var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
1170
+ if (middleX > x) {to = middle; toX = middleX;}
1171
+ else {from = middle; fromX = middleX;}
1172
+ }
1173
+ }
1174
+
1175
+ function localCoords(pos, inLineWrap) {
1176
+ var lh = lineHeight(), line = pos.line - (inLineWrap ? showingFrom : 0);
1177
+ return {x: charX(pos.line, pos.ch), y: line * lh, yBot: (line + 1) * lh};
1178
+ }
1179
+ function pageCoords(pos) {
1180
+ var local = localCoords(pos, true), off = eltOffset(lineSpace);
1181
+ return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
1182
+ }
1183
+
1184
+ function lineHeight() {
1185
+ var nlines = lineDiv.childNodes.length;
1186
+ if (nlines) return (lineDiv.offsetHeight / nlines) || 1;
1187
+ measure.innerHTML = "<pre>x</pre>";
1188
+ return measure.firstChild.offsetHeight || 1;
1189
+ }
1190
+ function paddingTop() {return lineSpace.offsetTop;}
1191
+ function paddingLeft() {return lineSpace.offsetLeft;}
1192
+
1193
+ function posFromMouse(e, liberal) {
1194
+ var offW = eltOffset(scroller, true), x, y;
1195
+ // Fails unpredictably on IE[67] when mouse is dragged around quickly.
1196
+ try { x = e.clientX; y = e.clientY; } catch (e) { return null; }
1197
+ // This is a mess of a heuristic to try and determine whether a
1198
+ // scroll-bar was clicked or not, and to return null if one was
1199
+ // (and !liberal).
1200
+ if (!liberal && (x - offW.left > scroller.clientWidth || y - offW.top > scroller.clientHeight))
1201
+ return null;
1202
+ var offL = eltOffset(lineSpace, true);
1203
+ var line = showingFrom + Math.floor((y - offL.top) / lineHeight());
1204
+ return clipPos({line: line, ch: charFromX(clipLine(line), x - offL.left)});
1205
+ }
1206
+ function onContextMenu(e) {
1207
+ var pos = posFromMouse(e);
1208
+ if (!pos || window.opera) return; // Opera is difficult.
1209
+ if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
1210
+ operation(setCursor)(pos.line, pos.ch);
1211
+
1212
+ var oldCSS = input.style.cssText;
1213
+ inputDiv.style.position = "absolute";
1214
+ input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
1215
+ "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " +
1216
+ "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
1217
+ leaveInputAlone = true;
1218
+ var val = input.value = getSelection();
1219
+ focusInput();
1220
+ setSelRange(input, 0, input.value.length);
1221
+ function rehide() {
1222
+ var newVal = splitLines(input.value).join("\n");
1223
+ if (newVal != val) operation(replaceSelection)(newVal, "end");
1224
+ inputDiv.style.position = "relative";
1225
+ input.style.cssText = oldCSS;
1226
+ leaveInputAlone = false;
1227
+ prepareInput();
1228
+ slowPoll();
1229
+ }
1230
+
1231
+ if (gecko) {
1232
+ e_stop(e);
1233
+ var mouseup = connect(window, "mouseup", function() {
1234
+ mouseup();
1235
+ setTimeout(rehide, 20);
1236
+ }, true);
1237
+ }
1238
+ else {
1239
+ setTimeout(rehide, 50);
1240
+ }
1241
+ }
1242
+
1243
+ // Cursor-blinking
1244
+ function restartBlink() {
1245
+ clearInterval(blinker);
1246
+ var on = true;
1247
+ cursor.style.visibility = "";
1248
+ blinker = setInterval(function() {
1249
+ cursor.style.visibility = (on = !on) ? "" : "hidden";
1250
+ }, 650);
1251
+ }
1252
+
1253
+ var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
1254
+ function matchBrackets(autoclear) {
1255
+ var head = sel.inverted ? sel.from : sel.to, line = lines[head.line], pos = head.ch - 1;
1256
+ var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
1257
+ if (!match) return;
1258
+ var ch = match.charAt(0), forward = match.charAt(1) == ">", d = forward ? 1 : -1, st = line.styles;
1259
+ for (var off = pos + 1, i = 0, e = st.length; i < e; i+=2)
1260
+ if ((off -= st[i].length) <= 0) {var style = st[i+1]; break;}
1261
+
1262
+ var stack = [line.text.charAt(pos)], re = /[(){}[\]]/;
1263
+ function scan(line, from, to) {
1264
+ if (!line.text) return;
1265
+ var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
1266
+ for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
1267
+ var text = st[i];
1268
+ if (st[i+1] != null && st[i+1] != style) {pos += d * text.length; continue;}
1269
+ for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
1270
+ if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
1271
+ var match = matching[cur];
1272
+ if (match.charAt(1) == ">" == forward) stack.push(cur);
1273
+ else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false};
1274
+ else if (!stack.length) return {pos: pos, match: true};
1275
+ }
1276
+ }
1277
+ }
1278
+ }
1279
+ for (var i = head.line, e = forward ? Math.min(i + 100, lines.length) : Math.max(-1, i - 100); i != e; i+=d) {
1280
+ var line = lines[i], first = i == head.line;
1281
+ var found = scan(line, first && forward ? pos + 1 : 0, first && !forward ? pos : line.text.length);
1282
+ if (found) break;
1283
+ }
1284
+ if (!found) found = {pos: null, match: false};
1285
+ var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
1286
+ var one = markText({line: head.line, ch: pos}, {line: head.line, ch: pos+1}, style),
1287
+ two = found.pos != null
1288
+ ? markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style)
1289
+ : function() {};
1290
+ var clear = operation(function(){one(); two();});
1291
+ if (autoclear) setTimeout(clear, 800);
1292
+ else bracketHighlighted = clear;
1293
+ }
1294
+
1295
+ // Finds the line to start with when starting a parse. Tries to
1296
+ // find a line with a stateAfter, so that it can start with a
1297
+ // valid state. If that fails, it returns the line with the
1298
+ // smallest indentation, which tends to need the least context to
1299
+ // parse correctly.
1300
+ function findStartLine(n) {
1301
+ var minindent, minline;
1302
+ for (var search = n, lim = n - 40; search > lim; --search) {
1303
+ if (search == 0) return 0;
1304
+ var line = lines[search-1];
1305
+ if (line.stateAfter) return search;
1306
+ var indented = line.indentation();
1307
+ if (minline == null || minindent > indented) {
1308
+ minline = search - 1;
1309
+ minindent = indented;
1310
+ }
1311
+ }
1312
+ return minline;
1313
+ }
1314
+ function getStateBefore(n) {
1315
+ var start = findStartLine(n), state = start && lines[start-1].stateAfter;
1316
+ if (!state) state = startState(mode);
1317
+ else state = copyState(mode, state);
1318
+ for (var i = start; i < n; ++i) {
1319
+ var line = lines[i];
1320
+ line.highlight(mode, state);
1321
+ line.stateAfter = copyState(mode, state);
1322
+ }
1323
+ if (n < lines.length && !lines[n].stateAfter) work.push(n);
1324
+ return state;
1325
+ }
1326
+ function highlightLines(start, end) {
1327
+ var state = getStateBefore(start);
1328
+ for (var i = start; i < end; ++i) {
1329
+ var line = lines[i];
1330
+ line.highlight(mode, state);
1331
+ line.stateAfter = copyState(mode, state);
1332
+ }
1333
+ }
1334
+ function highlightWorker() {
1335
+ var end = +new Date + options.workTime;
1336
+ var foundWork = work.length;
1337
+ while (work.length) {
1338
+ if (!lines[showingFrom].stateAfter) var task = showingFrom;
1339
+ else var task = work.pop();
1340
+ if (task >= lines.length) continue;
1341
+ var start = findStartLine(task), state = start && lines[start-1].stateAfter;
1342
+ if (state) state = copyState(mode, state);
1343
+ else state = startState(mode);
1344
+
1345
+ var unchanged = 0, compare = mode.compareStates, realChange = false;
1346
+ for (var i = start, l = lines.length; i < l; ++i) {
1347
+ var line = lines[i], hadState = line.stateAfter;
1348
+ if (+new Date > end) {
1349
+ work.push(i);
1350
+ startWorker(options.workDelay);
1351
+ if (realChange) changes.push({from: task, to: i + 1});
1352
+ return;
1353
+ }
1354
+ var changed = line.highlight(mode, state);
1355
+ if (changed) realChange = true;
1356
+ line.stateAfter = copyState(mode, state);
1357
+ if (compare) {
1358
+ if (hadState && compare(hadState, state)) break;
1359
+ } else {
1360
+ if (changed !== false || !hadState) unchanged = 0;
1361
+ else if (++unchanged > 3) break;
1362
+ }
1363
+ }
1364
+ if (realChange) changes.push({from: task, to: i + 1});
1365
+ }
1366
+ if (foundWork && options.onHighlightComplete)
1367
+ options.onHighlightComplete(instance);
1368
+ }
1369
+ function startWorker(time) {
1370
+ if (!work.length) return;
1371
+ highlight.set(time, operation(highlightWorker));
1372
+ }
1373
+
1374
+ // Operations are used to wrap changes in such a way that each
1375
+ // change won't have to update the cursor and display (which would
1376
+ // be awkward, slow, and error-prone), but instead updates are
1377
+ // batched and then all combined and executed at once.
1378
+ function startOperation() {
1379
+ updateInput = null; changes = []; textChanged = selectionChanged = false;
1380
+ }
1381
+ function endOperation() {
1382
+ var reScroll = false;
1383
+ if (selectionChanged) reScroll = !scrollCursorIntoView();
1384
+ if (changes.length) updateDisplay(changes);
1385
+ else if (selectionChanged) updateCursor();
1386
+ if (reScroll) scrollCursorIntoView();
1387
+ if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
1388
+
1389
+ // updateInput can be set to a boolean value to force/prevent an
1390
+ // update.
1391
+ if (focused && !leaveInputAlone &&
1392
+ (updateInput === true || (updateInput !== false && selectionChanged)))
1393
+ prepareInput();
1394
+
1395
+ if (selectionChanged && options.matchBrackets)
1396
+ setTimeout(operation(function() {
1397
+ if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
1398
+ matchBrackets(false);
1399
+ }), 20);
1400
+ var tc = textChanged; // textChanged can be reset by cursoractivity callback
1401
+ if (selectionChanged && options.onCursorActivity)
1402
+ options.onCursorActivity(instance);
1403
+ if (tc && options.onChange && instance)
1404
+ options.onChange(instance, tc);
1405
+ }
1406
+ var nestedOperation = 0;
1407
+ function operation(f) {
1408
+ return function() {
1409
+ if (!nestedOperation++) startOperation();
1410
+ try {var result = f.apply(this, arguments);}
1411
+ finally {if (!--nestedOperation) endOperation();}
1412
+ return result;
1413
+ };
1414
+ }
1415
+
1416
+ function SearchCursor(query, pos, caseFold) {
1417
+ this.atOccurrence = false;
1418
+ if (caseFold == null) caseFold = typeof query == "string" && query == query.toLowerCase();
1419
+
1420
+ if (pos && typeof pos == "object") pos = clipPos(pos);
1421
+ else pos = {line: 0, ch: 0};
1422
+ this.pos = {from: pos, to: pos};
1423
+
1424
+ // The matches method is filled in based on the type of query.
1425
+ // It takes a position and a direction, and returns an object
1426
+ // describing the next occurrence of the query, or null if no
1427
+ // more matches were found.
1428
+ if (typeof query != "string") // Regexp match
1429
+ this.matches = function(reverse, pos) {
1430
+ if (reverse) {
1431
+ var line = lines[pos.line].text.slice(0, pos.ch), match = line.match(query), start = 0;
1432
+ while (match) {
1433
+ var ind = line.indexOf(match[0]);
1434
+ start += ind;
1435
+ line = line.slice(ind + 1);
1436
+ var newmatch = line.match(query);
1437
+ if (newmatch) match = newmatch;
1438
+ else break;
1439
+ start++;
1440
+ }
1441
+ }
1442
+ else {
1443
+ var line = lines[pos.line].text.slice(pos.ch), match = line.match(query),
1444
+ start = match && pos.ch + line.indexOf(match[0]);
1445
+ }
1446
+ if (match)
1447
+ return {from: {line: pos.line, ch: start},
1448
+ to: {line: pos.line, ch: start + match[0].length},
1449
+ match: match};
1450
+ };
1451
+ else { // String query
1452
+ if (caseFold) query = query.toLowerCase();
1453
+ var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
1454
+ var target = query.split("\n");
1455
+ // Different methods for single-line and multi-line queries
1456
+ if (target.length == 1)
1457
+ this.matches = function(reverse, pos) {
1458
+ var line = fold(lines[pos.line].text), len = query.length, match;
1459
+ if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
1460
+ : (match = line.indexOf(query, pos.ch)) != -1)
1461
+ return {from: {line: pos.line, ch: match},
1462
+ to: {line: pos.line, ch: match + len}};
1463
+ };
1464
+ else
1465
+ this.matches = function(reverse, pos) {
1466
+ var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(lines[ln].text);
1467
+ var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
1468
+ if (reverse ? offsetA >= pos.ch || offsetA != match.length
1469
+ : offsetA <= pos.ch || offsetA != line.length - match.length)
1470
+ return;
1471
+ for (;;) {
1472
+ if (reverse ? !ln : ln == lines.length - 1) return;
1473
+ line = fold(lines[ln += reverse ? -1 : 1].text);
1474
+ match = target[reverse ? --idx : ++idx];
1475
+ if (idx > 0 && idx < target.length - 1) {
1476
+ if (line != match) return;
1477
+ else continue;
1478
+ }
1479
+ var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
1480
+ if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
1481
+ return;
1482
+ var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
1483
+ return {from: reverse ? end : start, to: reverse ? start : end};
1484
+ }
1485
+ };
1486
+ }
1487
+ }
1488
+
1489
+ SearchCursor.prototype = {
1490
+ findNext: function() {return this.find(false);},
1491
+ findPrevious: function() {return this.find(true);},
1492
+
1493
+ find: function(reverse) {
1494
+ var self = this, pos = clipPos(reverse ? this.pos.from : this.pos.to);
1495
+ function savePosAndFail(line) {
1496
+ var pos = {line: line, ch: 0};
1497
+ self.pos = {from: pos, to: pos};
1498
+ self.atOccurrence = false;
1499
+ return false;
1500
+ }
1501
+
1502
+ for (;;) {
1503
+ if (this.pos = this.matches(reverse, pos)) {
1504
+ this.atOccurrence = true;
1505
+ return this.pos.match || true;
1506
+ }
1507
+ if (reverse) {
1508
+ if (!pos.line) return savePosAndFail(0);
1509
+ pos = {line: pos.line-1, ch: lines[pos.line-1].text.length};
1510
+ }
1511
+ else {
1512
+ if (pos.line == lines.length - 1) return savePosAndFail(lines.length);
1513
+ pos = {line: pos.line+1, ch: 0};
1514
+ }
1515
+ }
1516
+ },
1517
+
1518
+ from: function() {if (this.atOccurrence) return copyPos(this.pos.from);},
1519
+ to: function() {if (this.atOccurrence) return copyPos(this.pos.to);},
1520
+
1521
+ replace: function(newText) {
1522
+ var self = this;
1523
+ if (this.atOccurrence)
1524
+ operation(function() {
1525
+ self.pos.to = replaceRange(newText, self.pos.from, self.pos.to);
1526
+ })();
1527
+ }
1528
+ };
1529
+
1530
+ for (var ext in extensions)
1531
+ if (extensions.propertyIsEnumerable(ext) &&
1532
+ !instance.propertyIsEnumerable(ext))
1533
+ instance[ext] = extensions[ext];
1534
+ return instance;
1535
+ } // (end of function CodeMirror)
1536
+
1537
+ // The default configuration options.
1538
+ CodeMirror.defaults = {
1539
+ value: "",
1540
+ mode: null,
1541
+ theme: "default",
1542
+ indentUnit: 2,
1543
+ indentWithTabs: false,
1544
+ tabMode: "classic",
1545
+ enterMode: "indent",
1546
+ electricChars: true,
1547
+ onKeyEvent: null,
1548
+ lineNumbers: false,
1549
+ gutter: false,
1550
+ firstLineNumber: 1,
1551
+ readOnly: false,
1552
+ smartHome: true,
1553
+ onChange: null,
1554
+ onCursorActivity: null,
1555
+ onGutterClick: null,
1556
+ onHighlightComplete: null,
1557
+ onFocus: null, onBlur: null, onScroll: null,
1558
+ matchBrackets: false,
1559
+ workTime: 100,
1560
+ workDelay: 200,
1561
+ undoDepth: 40,
1562
+ tabindex: null,
1563
+ document: window.document
1564
+ };
1565
+
1566
+ // Known modes, by name and by MIME
1567
+ var modes = {}, mimeModes = {};
1568
+ CodeMirror.defineMode = function(name, mode) {
1569
+ if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
1570
+ modes[name] = mode;
1571
+ };
1572
+ CodeMirror.defineMIME = function(mime, spec) {
1573
+ mimeModes[mime] = spec;
1574
+ };
1575
+ CodeMirror.getMode = function(options, spec) {
1576
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
1577
+ spec = mimeModes[spec];
1578
+ if (typeof spec == "string")
1579
+ var mname = spec, config = {};
1580
+ else if (spec != null)
1581
+ var mname = spec.name, config = spec;
1582
+ var mfactory = modes[mname];
1583
+ if (!mfactory) {
1584
+ if (window.console) console.warn("No mode " + mname + " found, falling back to plain text.");
1585
+ return CodeMirror.getMode(options, "text/plain");
1586
+ }
1587
+ return mfactory(options, config || {});
1588
+ };
1589
+ CodeMirror.listModes = function() {
1590
+ var list = [];
1591
+ for (var m in modes)
1592
+ if (modes.propertyIsEnumerable(m)) list.push(m);
1593
+ return list;
1594
+ };
1595
+ CodeMirror.listMIMEs = function() {
1596
+ var list = [];
1597
+ for (var m in mimeModes)
1598
+ if (mimeModes.propertyIsEnumerable(m)) list.push(m);
1599
+ return list;
1600
+ };
1601
+
1602
+ var extensions = {};
1603
+ CodeMirror.defineExtension = function(name, func) {
1604
+ extensions[name] = func;
1605
+ };
1606
+
1607
+ CodeMirror.fromTextArea = function(textarea, options) {
1608
+ if (!options) options = {};
1609
+ options.value = textarea.value;
1610
+ if (!options.tabindex && textarea.tabindex)
1611
+ options.tabindex = textarea.tabindex;
1612
+
1613
+ function save() {textarea.value = instance.getValue();}
1614
+ if (textarea.form) {
1615
+ // Deplorable hack to make the submit method do the right thing.
1616
+ var rmSubmit = connect(textarea.form, "submit", save, true);
1617
+ if (typeof textarea.form.submit == "function") {
1618
+ var realSubmit = textarea.form.submit;
1619
+ function wrappedSubmit() {
1620
+ save();
1621
+ textarea.form.submit = realSubmit;
1622
+ textarea.form.submit();
1623
+ textarea.form.submit = wrappedSubmit;
1624
+ }
1625
+ textarea.form.submit = wrappedSubmit;
1626
+ }
1627
+ }
1628
+
1629
+ textarea.style.display = "none";
1630
+ var instance = CodeMirror(function(node) {
1631
+ textarea.parentNode.insertBefore(node, textarea.nextSibling);
1632
+ }, options);
1633
+ instance.save = save;
1634
+ instance.toTextArea = function() {
1635
+ save();
1636
+ textarea.parentNode.removeChild(instance.getWrapperElement());
1637
+ textarea.style.display = "";
1638
+ if (textarea.form) {
1639
+ rmSubmit();
1640
+ if (typeof textarea.form.submit == "function")
1641
+ textarea.form.submit = realSubmit;
1642
+ }
1643
+ };
1644
+ return instance;
1645
+ };
1646
+
1647
+ // Utility functions for working with state. Exported because modes
1648
+ // sometimes need to do this.
1649
+ function copyState(mode, state) {
1650
+ if (state === true) return state;
1651
+ if (mode.copyState) return mode.copyState(state);
1652
+ var nstate = {};
1653
+ for (var n in state) {
1654
+ var val = state[n];
1655
+ if (val instanceof Array) val = val.concat([]);
1656
+ nstate[n] = val;
1657
+ }
1658
+ return nstate;
1659
+ }
1660
+ CodeMirror.startState = startState;
1661
+ function startState(mode, a1, a2) {
1662
+ return mode.startState ? mode.startState(a1, a2) : true;
1663
+ }
1664
+ CodeMirror.copyState = copyState;
1665
+
1666
+ // The character stream used by a mode's parser.
1667
+ function StringStream(string) {
1668
+ this.pos = this.start = 0;
1669
+ this.string = string;
1670
+ }
1671
+ StringStream.prototype = {
1672
+ eol: function() {return this.pos >= this.string.length;},
1673
+ sol: function() {return this.pos == 0;},
1674
+ peek: function() {return this.string.charAt(this.pos);},
1675
+ next: function() {
1676
+ if (this.pos < this.string.length)
1677
+ return this.string.charAt(this.pos++);
1678
+ },
1679
+ eat: function(match) {
1680
+ var ch = this.string.charAt(this.pos);
1681
+ if (typeof match == "string") var ok = ch == match;
1682
+ else var ok = ch && (match.test ? match.test(ch) : match(ch));
1683
+ if (ok) {++this.pos; return ch;}
1684
+ },
1685
+ eatWhile: function(match) {
1686
+ var start = this.pos;
1687
+ while (this.eat(match)){}
1688
+ return this.pos > start;
1689
+ },
1690
+ eatSpace: function() {
1691
+ var start = this.pos;
1692
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
1693
+ return this.pos > start;
1694
+ },
1695
+ skipToEnd: function() {this.pos = this.string.length;},
1696
+ skipTo: function(ch) {
1697
+ var found = this.string.indexOf(ch, this.pos);
1698
+ if (found > -1) {this.pos = found; return true;}
1699
+ },
1700
+ backUp: function(n) {this.pos -= n;},
1701
+ column: function() {return countColumn(this.string, this.start);},
1702
+ indentation: function() {return countColumn(this.string);},
1703
+ match: function(pattern, consume, caseInsensitive) {
1704
+ if (typeof pattern == "string") {
1705
+ function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
1706
+ if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
1707
+ if (consume !== false) this.pos += pattern.length;
1708
+ return true;
1709
+ }
1710
+ }
1711
+ else {
1712
+ var match = this.string.slice(this.pos).match(pattern);
1713
+ if (match && consume !== false) this.pos += match[0].length;
1714
+ return match;
1715
+ }
1716
+ },
1717
+ current: function(){return this.string.slice(this.start, this.pos);}
1718
+ };
1719
+ CodeMirror.StringStream = StringStream;
1720
+
1721
+ // Line objects. These hold state related to a line, including
1722
+ // highlighting info (the styles array).
1723
+ function Line(text, styles) {
1724
+ this.styles = styles || [text, null];
1725
+ this.stateAfter = null;
1726
+ this.text = text;
1727
+ this.marked = this.gutterMarker = this.className = null;
1728
+ }
1729
+ Line.prototype = {
1730
+ // Replace a piece of a line, keeping the styles around it intact.
1731
+ replace: function(from, to, text) {
1732
+ var st = [], mk = this.marked;
1733
+ copyStyles(0, from, this.styles, st);
1734
+ if (text) st.push(text, null);
1735
+ copyStyles(to, this.text.length, this.styles, st);
1736
+ this.styles = st;
1737
+ this.text = this.text.slice(0, from) + text + this.text.slice(to);
1738
+ this.stateAfter = null;
1739
+ if (mk) {
1740
+ var diff = text.length - (to - from), end = this.text.length;
1741
+ function fix(n) {return n <= Math.min(to, to + diff) ? n : n + diff;}
1742
+ for (var i = 0; i < mk.length; ++i) {
1743
+ var mark = mk[i], del = false;
1744
+ if (mark.from >= end) del = true;
1745
+ else {mark.from = fix(mark.from); if (mark.to != null) mark.to = fix(mark.to);}
1746
+ if (del || mark.from >= mark.to) {mk.splice(i, 1); i--;}
1747
+ }
1748
+ }
1749
+ },
1750
+ // Split a line in two, again keeping styles intact.
1751
+ split: function(pos, textBefore) {
1752
+ var st = [textBefore, null];
1753
+ copyStyles(pos, this.text.length, this.styles, st);
1754
+ return new Line(textBefore + this.text.slice(pos), st);
1755
+ },
1756
+ addMark: function(from, to, style) {
1757
+ var mk = this.marked, mark = {from: from, to: to, style: style};
1758
+ if (this.marked == null) this.marked = [];
1759
+ this.marked.push(mark);
1760
+ this.marked.sort(function(a, b){return a.from - b.from;});
1761
+ return mark;
1762
+ },
1763
+ removeMark: function(mark) {
1764
+ var mk = this.marked;
1765
+ if (!mk) return;
1766
+ for (var i = 0; i < mk.length; ++i)
1767
+ if (mk[i] == mark) {mk.splice(i, 1); break;}
1768
+ },
1769
+ // Run the given mode's parser over a line, update the styles
1770
+ // array, which contains alternating fragments of text and CSS
1771
+ // classes.
1772
+ highlight: function(mode, state) {
1773
+ var stream = new StringStream(this.text), st = this.styles, pos = 0;
1774
+ var changed = false, curWord = st[0], prevWord;
1775
+ if (this.text == "" && mode.blankLine) mode.blankLine(state);
1776
+ while (!stream.eol()) {
1777
+ var style = mode.token(stream, state);
1778
+ var substr = this.text.slice(stream.start, stream.pos);
1779
+ stream.start = stream.pos;
1780
+ if (pos && st[pos-1] == style)
1781
+ st[pos-2] += substr;
1782
+ else if (substr) {
1783
+ if (!changed && (st[pos+1] != style || (pos && st[pos-2] != prevWord))) changed = true;
1784
+ st[pos++] = substr; st[pos++] = style;
1785
+ prevWord = curWord; curWord = st[pos];
1786
+ }
1787
+ // Give up when line is ridiculously long
1788
+ if (stream.pos > 5000) {
1789
+ st[pos++] = this.text.slice(stream.pos); st[pos++] = null;
1790
+ break;
1791
+ }
1792
+ }
1793
+ if (st.length != pos) {st.length = pos; changed = true;}
1794
+ if (pos && st[pos-2] != prevWord) changed = true;
1795
+ // Short lines with simple highlights return null, and are
1796
+ // counted as changed by the driver because they are likely to
1797
+ // highlight the same way in various contexts.
1798
+ return changed || (st.length < 5 && this.text.length < 10 ? null : false);
1799
+ },
1800
+ // Fetch the parser token for a given character. Useful for hacks
1801
+ // that want to inspect the mode state (say, for completion).
1802
+ getTokenAt: function(mode, state, ch) {
1803
+ var txt = this.text, stream = new StringStream(txt);
1804
+ while (stream.pos < ch && !stream.eol()) {
1805
+ stream.start = stream.pos;
1806
+ var style = mode.token(stream, state);
1807
+ }
1808
+ return {start: stream.start,
1809
+ end: stream.pos,
1810
+ string: stream.current(),
1811
+ className: style || null,
1812
+ state: state};
1813
+ },
1814
+ indentation: function() {return countColumn(this.text);},
1815
+ // Produces an HTML fragment for the line, taking selection,
1816
+ // marking, and highlighting into account.
1817
+ getHTML: function(sfrom, sto, includePre, endAt) {
1818
+ var html = [];
1819
+ if (includePre)
1820
+ html.push(this.className ? '<pre class="' + this.className + '">': "<pre>");
1821
+ function span(text, style) {
1822
+ if (!text) return;
1823
+ if (style) html.push('<span class="', style, '">', htmlEscape(text), "</span>");
1824
+ else html.push(htmlEscape(text));
1825
+ }
1826
+ var st = this.styles, allText = this.text, marked = this.marked;
1827
+ if (sfrom == sto) sfrom = null;
1828
+ var len = allText.length;
1829
+ if (endAt != null) len = Math.min(endAt, len);
1830
+
1831
+ if (!allText && endAt == null)
1832
+ span(" ", sfrom != null && sto == null ? "CodeMirror-selected" : null);
1833
+ else if (!marked && sfrom == null)
1834
+ for (var i = 0, ch = 0; ch < len; i+=2) {
1835
+ var str = st[i], l = str.length;
1836
+ if (ch + l > len) str = str.slice(0, len - ch);
1837
+ ch += l;
1838
+ span(str, "cm-" + st[i+1]);
1839
+ }
1840
+ else {
1841
+ var pos = 0, i = 0, text = "", style, sg = 0;
1842
+ var markpos = -1, mark = null;
1843
+ function nextMark() {
1844
+ if (marked) {
1845
+ markpos += 1;
1846
+ mark = (markpos < marked.length) ? marked[markpos] : null;
1847
+ }
1848
+ }
1849
+ nextMark();
1850
+ while (pos < len) {
1851
+ var upto = len;
1852
+ var extraStyle = "";
1853
+ if (sfrom != null) {
1854
+ if (sfrom > pos) upto = sfrom;
1855
+ else if (sto == null || sto > pos) {
1856
+ extraStyle = " CodeMirror-selected";
1857
+ if (sto != null) upto = Math.min(upto, sto);
1858
+ }
1859
+ }
1860
+ while (mark && mark.to != null && mark.to <= pos) nextMark();
1861
+ if (mark) {
1862
+ if (mark.from > pos) upto = Math.min(upto, mark.from);
1863
+ else {
1864
+ extraStyle += " " + mark.style;
1865
+ if (mark.to != null) upto = Math.min(upto, mark.to);
1866
+ }
1867
+ }
1868
+ for (;;) {
1869
+ var end = pos + text.length;
1870
+ var appliedStyle = style;
1871
+ if (extraStyle) appliedStyle = style ? style + extraStyle : extraStyle;
1872
+ span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
1873
+ if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
1874
+ pos = end;
1875
+ text = st[i++]; style = "cm-" + st[i++];
1876
+ }
1877
+ }
1878
+ if (sfrom != null && sto == null) span(" ", "CodeMirror-selected");
1879
+ }
1880
+ if (includePre) html.push("</pre>");
1881
+ return html.join("");
1882
+ }
1883
+ };
1884
+ // Utility used by replace and split above
1885
+ function copyStyles(from, to, source, dest) {
1886
+ for (var i = 0, pos = 0, state = 0; pos < to; i+=2) {
1887
+ var part = source[i], end = pos + part.length;
1888
+ if (state == 0) {
1889
+ if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
1890
+ if (end >= from) state = 1;
1891
+ }
1892
+ else if (state == 1) {
1893
+ if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
1894
+ else dest.push(part, source[i+1]);
1895
+ }
1896
+ pos = end;
1897
+ }
1898
+ }
1899
+
1900
+ // The history object 'chunks' changes that are made close together
1901
+ // and at almost the same time into bigger undoable units.
1902
+ function History() {
1903
+ this.time = 0;
1904
+ this.done = []; this.undone = [];
1905
+ }
1906
+ History.prototype = {
1907
+ addChange: function(start, added, old) {
1908
+ this.undone.length = 0;
1909
+ var time = +new Date, last = this.done[this.done.length - 1];
1910
+ if (time - this.time > 400 || !last ||
1911
+ last.start > start + added || last.start + last.added < start - last.added + last.old.length)
1912
+ this.done.push({start: start, added: added, old: old});
1913
+ else {
1914
+ var oldoff = 0;
1915
+ if (start < last.start) {
1916
+ for (var i = last.start - start - 1; i >= 0; --i)
1917
+ last.old.unshift(old[i]);
1918
+ last.added += last.start - start;
1919
+ last.start = start;
1920
+ }
1921
+ else if (last.start < start) {
1922
+ oldoff = start - last.start;
1923
+ added += oldoff;
1924
+ }
1925
+ for (var i = last.added - oldoff, e = old.length; i < e; ++i)
1926
+ last.old.push(old[i]);
1927
+ if (last.added < added) last.added = added;
1928
+ }
1929
+ this.time = time;
1930
+ }
1931
+ };
1932
+
1933
+ function stopMethod() {e_stop(this);}
1934
+ // Ensure an event has a stop method.
1935
+ function addStop(event) {
1936
+ if (!event.stop) event.stop = stopMethod;
1937
+ return event;
1938
+ }
1939
+
1940
+ function e_preventDefault(e) {
1941
+ if (e.preventDefault) e.preventDefault();
1942
+ else e.returnValue = false;
1943
+ }
1944
+ function e_stopPropagation(e) {
1945
+ if (e.stopPropagation) e.stopPropagation();
1946
+ else e.cancelBubble = true;
1947
+ }
1948
+ function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
1949
+ function e_target(e) {return e.target || e.srcElement;}
1950
+ function e_button(e) {
1951
+ if (e.which) return e.which;
1952
+ else if (e.button & 1) return 1;
1953
+ else if (e.button & 2) return 3;
1954
+ else if (e.button & 4) return 2;
1955
+ }
1956
+
1957
+ // Event handler registration. If disconnect is true, it'll return a
1958
+ // function that unregisters the handler.
1959
+ function connect(node, type, handler, disconnect) {
1960
+ function wrapHandler(event) {handler(event || window.event);}
1961
+ if (typeof node.addEventListener == "function") {
1962
+ node.addEventListener(type, wrapHandler, false);
1963
+ if (disconnect) return function() {node.removeEventListener(type, wrapHandler, false);};
1964
+ }
1965
+ else {
1966
+ node.attachEvent("on" + type, wrapHandler);
1967
+ if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
1968
+ }
1969
+ }
1970
+
1971
+ function Delayed() {this.id = null;}
1972
+ Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
1973
+
1974
+ // Some IE versions don't preserve whitespace when setting the
1975
+ // innerHTML of a PRE tag.
1976
+ var badInnerHTML = (function() {
1977
+ var pre = document.createElement("pre");
1978
+ pre.innerHTML = " "; return !pre.innerHTML;
1979
+ })();
1980
+
1981
+ var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
1982
+ var ie = /MSIE \d/.test(navigator.userAgent);
1983
+ var safari = /Apple Computer/.test(navigator.vendor);
1984
+
1985
+ var lineSep = "\n";
1986
+ // Feature-detect whether newlines in textareas are converted to \r\n
1987
+ (function () {
1988
+ var te = document.createElement("textarea");
1989
+ te.value = "foo\nbar";
1990
+ if (te.value.indexOf("\r") > -1) lineSep = "\r\n";
1991
+ }());
1992
+
1993
+ var tabSize = 8;
1994
+ var mac = /Mac/.test(navigator.platform);
1995
+ var movementKeys = {};
1996
+ for (var i = 35; i <= 40; ++i)
1997
+ movementKeys[i] = movementKeys["c" + i] = true;
1998
+
1999
+ // Counts the column offset in a string, taking tabs into account.
2000
+ // Used mostly to find indentation.
2001
+ function countColumn(string, end) {
2002
+ if (end == null) {
2003
+ end = string.search(/[^\s\u00a0]/);
2004
+ if (end == -1) end = string.length;
2005
+ }
2006
+ for (var i = 0, n = 0; i < end; ++i) {
2007
+ if (string.charAt(i) == "\t") n += tabSize - (n % tabSize);
2008
+ else ++n;
2009
+ }
2010
+ return n;
2011
+ }
2012
+
2013
+ function computedStyle(elt) {
2014
+ if (elt.currentStyle) return elt.currentStyle;
2015
+ return window.getComputedStyle(elt, null);
2016
+ }
2017
+ // Find the position of an element by following the offsetParent chain.
2018
+ // If screen==true, it returns screen (rather than page) coordinates.
2019
+ function eltOffset(node, screen) {
2020
+ var doc = node.ownerDocument.body;
2021
+ var x = 0, y = 0, skipDoc = false;
2022
+ for (var n = node; n; n = n.offsetParent) {
2023
+ x += n.offsetLeft; y += n.offsetTop;
2024
+ if (screen && computedStyle(n).position == "fixed")
2025
+ skipDoc = true;
2026
+ }
2027
+ var e = screen && !skipDoc ? null : doc;
2028
+ for (var n = node.parentNode; n != e; n = n.parentNode)
2029
+ if (n.scrollLeft != null) { x -= n.scrollLeft; y -= n.scrollTop;}
2030
+ return {left: x, top: y};
2031
+ }
2032
+ // Get a node's text content.
2033
+ function eltText(node) {
2034
+ return node.textContent || node.innerText || node.nodeValue || "";
2035
+ }
2036
+
2037
+ // Operations on {line, ch} objects.
2038
+ function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
2039
+ function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
2040
+ function copyPos(x) {return {line: x.line, ch: x.ch};}
2041
+
2042
+ var escapeElement = document.createElement("div");
2043
+ function htmlEscape(str) {
2044
+ escapeElement.innerText = escapeElement.textContent = str;
2045
+ return escapeElement.innerHTML;
2046
+ }
2047
+ CodeMirror.htmlEscape = htmlEscape;
2048
+
2049
+ // Used to position the cursor after an undo/redo by finding the
2050
+ // last edited character.
2051
+ function editEnd(from, to) {
2052
+ if (!to) return from ? from.length : 0;
2053
+ if (!from) return to.length;
2054
+ for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j)
2055
+ if (from.charAt(i) != to.charAt(j)) break;
2056
+ return j + 1;
2057
+ }
2058
+
2059
+ function indexOf(collection, elt) {
2060
+ if (collection.indexOf) return collection.indexOf(elt);
2061
+ for (var i = 0, e = collection.length; i < e; ++i)
2062
+ if (collection[i] == elt) return i;
2063
+ return -1;
2064
+ }
2065
+
2066
+ // See if "".split is the broken IE version, if so, provide an
2067
+ // alternative way to split lines.
2068
+ var splitLines, selRange, setSelRange;
2069
+ if ("\n\nb".split(/\n/).length != 3)
2070
+ splitLines = function(string) {
2071
+ var pos = 0, nl, result = [];
2072
+ while ((nl = string.indexOf("\n", pos)) > -1) {
2073
+ result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl));
2074
+ pos = nl + 1;
2075
+ }
2076
+ result.push(string.slice(pos));
2077
+ return result;
2078
+ };
2079
+ else
2080
+ splitLines = function(string){return string.split(/\r?\n/);};
2081
+ CodeMirror.splitLines = splitLines;
2082
+
2083
+ // Sane model of finding and setting the selection in a textarea
2084
+ if (window.getSelection) {
2085
+ selRange = function(te) {
2086
+ try {return {start: te.selectionStart, end: te.selectionEnd};}
2087
+ catch(e) {return null;}
2088
+ };
2089
+ if (safari)
2090
+ // On Safari, selection set with setSelectionRange are in a sort
2091
+ // of limbo wrt their anchor. If you press shift-left in them,
2092
+ // the anchor is put at the end, and the selection expanded to
2093
+ // the left. If you press shift-right, the anchor ends up at the
2094
+ // front. This is not what CodeMirror wants, so it does a
2095
+ // spurious modify() call to get out of limbo.
2096
+ setSelRange = function(te, start, end) {
2097
+ if (start == end)
2098
+ te.setSelectionRange(start, end);
2099
+ else {
2100
+ te.setSelectionRange(start, end - 1);
2101
+ window.getSelection().modify("extend", "forward", "character");
2102
+ }
2103
+ };
2104
+ else
2105
+ setSelRange = function(te, start, end) {
2106
+ try {te.setSelectionRange(start, end);}
2107
+ catch(e) {} // Fails on Firefox when textarea isn't part of the document
2108
+ };
2109
+ }
2110
+ // IE model. Don't ask.
2111
+ else {
2112
+ selRange = function(te) {
2113
+ try {var range = te.ownerDocument.selection.createRange();}
2114
+ catch(e) {return null;}
2115
+ if (!range || range.parentElement() != te) return null;
2116
+ var val = te.value, len = val.length, localRange = te.createTextRange();
2117
+ localRange.moveToBookmark(range.getBookmark());
2118
+ var endRange = te.createTextRange();
2119
+ endRange.collapse(false);
2120
+
2121
+ if (localRange.compareEndPoints("StartToEnd", endRange) > -1)
2122
+ return {start: len, end: len};
2123
+
2124
+ var start = -localRange.moveStart("character", -len);
2125
+ for (var i = val.indexOf("\r"); i > -1 && i < start; i = val.indexOf("\r", i+1), start++) {}
2126
+
2127
+ if (localRange.compareEndPoints("EndToEnd", endRange) > -1)
2128
+ return {start: start, end: len};
2129
+
2130
+ var end = -localRange.moveEnd("character", -len);
2131
+ for (var i = val.indexOf("\r"); i > -1 && i < end; i = val.indexOf("\r", i+1), end++) {}
2132
+ return {start: start, end: end};
2133
+ };
2134
+ setSelRange = function(te, start, end) {
2135
+ var range = te.createTextRange();
2136
+ range.collapse(true);
2137
+ var endrange = range.duplicate();
2138
+ var newlines = 0, txt = te.value;
2139
+ for (var pos = txt.indexOf("\n"); pos > -1 && pos < start; pos = txt.indexOf("\n", pos + 1))
2140
+ ++newlines;
2141
+ range.move("character", start - newlines);
2142
+ for (; pos > -1 && pos < end; pos = txt.indexOf("\n", pos + 1))
2143
+ ++newlines;
2144
+ endrange.move("character", end - newlines);
2145
+ range.setEndPoint("EndToEnd", endrange);
2146
+ range.select();
2147
+ };
2148
+ }
2149
+
2150
+ CodeMirror.defineMode("null", function() {
2151
+ return {token: function(stream) {stream.skipToEnd();}};
2152
+ });
2153
+ CodeMirror.defineMIME("text/plain", "null");
2154
+
2155
+ return CodeMirror;
2156
+ })()
2157
+ ;
tinymce-plugins/cmseditor/js/lib/overlay.js ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Utility function that allows modes to be combined. The mode given
2
+ // as the base argument takes care of most of the normal mode
3
+ // functionality, but a second (typically simple) mode is used, which
4
+ // can override the style of text. Both modes get to parse all of the
5
+ // text, but when both assign a non-null style to a piece of code, the
6
+ // overlay wins, unless the combine argument was true, in which case
7
+ // the styles are combined.
8
+
9
+ CodeMirror.overlayParser = function(base, overlay, combine) {
10
+ return {
11
+ startState: function() {
12
+ return {
13
+ base: CodeMirror.startState(base),
14
+ overlay: CodeMirror.startState(overlay),
15
+ basePos: 0, baseCur: null,
16
+ overlayPos: 0, overlayCur: null
17
+ };
18
+ },
19
+ copyState: function(state) {
20
+ return {
21
+ base: CodeMirror.copyState(base, state.base),
22
+ overlay: CodeMirror.copyState(overlay, state.overlay),
23
+ basePos: state.basePos, baseCur: null,
24
+ overlayPos: state.overlayPos, overlayCur: null
25
+ };
26
+ },
27
+
28
+ token: function(stream, state) {
29
+ if (stream.start == state.basePos) {
30
+ state.baseCur = base.token(stream, state.base);
31
+ state.basePos = stream.pos;
32
+ }
33
+ if (stream.start == state.overlayPos) {
34
+ stream.pos = stream.start;
35
+ state.overlayCur = overlay.token(stream, state.overlay);
36
+ state.overlayPos = stream.pos;
37
+ }
38
+ stream.pos = Math.min(state.basePos, state.overlayPos);
39
+ if (stream.eol()) state.basePos = state.overlayPos = 0;
40
+
41
+ if (state.overlayCur == null) return state.baseCur;
42
+ if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
43
+ else return state.overlayCur;
44
+ },
45
+
46
+ indent: function(state, textAfter) {
47
+ return base.indent(state.base, textAfter);
48
+ },
49
+ electricChars: base.electricChars
50
+ };
51
+ };
tinymce-plugins/cmseditor/js/lib/runmode.js ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CodeMirror.runMode = function(string, modespec, callback) {
2
+ var mode = CodeMirror.getMode({indentUnit: 2}, modespec);
3
+ var isNode = callback.nodeType == 1;
4
+ if (isNode) {
5
+ var node = callback, accum = [];
6
+ callback = function(string, style) {
7
+ if (string == "\n")
8
+ accum.push("<br>");
9
+ else if (style)
10
+ accum.push("<span class=\"cm-" + CodeMirror.htmlEscape(style) + "\">" + CodeMirror.htmlEscape(string) + "</span>");
11
+ else
12
+ accum.push(CodeMirror.htmlEscape(string));
13
+ }
14
+ }
15
+ var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
16
+ for (var i = 0, e = lines.length; i < e; ++i) {
17
+ if (i) callback("\n");
18
+ var stream = new CodeMirror.StringStream(lines[i]);
19
+ while (!stream.eol()) {
20
+ var style = mode.token(stream, state);
21
+ callback(stream.current(), style);
22
+ stream.start = stream.pos;
23
+ }
24
+ }
25
+ if (isNode)
26
+ node.innerHTML = accum.join("");
27
+ };
tinymce-plugins/cmseditor/js/mode/css/css.js ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CodeMirror.defineMode("css", function(config) {
2
+ var indentUnit = config.indentUnit, type;
3
+ function ret(style, tp) {type = tp; return style;}
4
+
5
+ function tokenBase(stream, state) {
6
+ var ch = stream.next();
7
+ if (ch == "@") {stream.eatWhile(/\w/); return ret("meta", stream.current());}
8
+ else if (ch == "/" && stream.eat("*")) {
9
+ state.tokenize = tokenCComment;
10
+ return tokenCComment(stream, state);
11
+ }
12
+ else if (ch == "<" && stream.eat("!")) {
13
+ state.tokenize = tokenSGMLComment;
14
+ return tokenSGMLComment(stream, state);
15
+ }
16
+ else if (ch == "=") ret(null, "compare");
17
+ else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
18
+ else if (ch == "\"" || ch == "'") {
19
+ state.tokenize = tokenString(ch);
20
+ return state.tokenize(stream, state);
21
+ }
22
+ else if (ch == "#") {
23
+ stream.eatWhile(/\w/);
24
+ return ret("atom", "hash");
25
+ }
26
+ else if (ch == "!") {
27
+ stream.match(/^\s*\w*/);
28
+ return ret("keyword", "important");
29
+ }
30
+ else if (/\d/.test(ch)) {
31
+ stream.eatWhile(/[\w.%]/);
32
+ return ret("number", "unit");
33
+ }
34
+ else if (/[,.+>*\/]/.test(ch)) {
35
+ return ret(null, "select-op");
36
+ }
37
+ else if (/[;{}:\[\]]/.test(ch)) {
38
+ return ret(null, ch);
39
+ }
40
+ else {
41
+ stream.eatWhile(/[\w\\\-_]/);
42
+ return ret("variable", "variable");
43
+ }
44
+ }
45
+
46
+ function tokenCComment(stream, state) {
47
+ var maybeEnd = false, ch;
48
+ while ((ch = stream.next()) != null) {
49
+ if (maybeEnd && ch == "/") {
50
+ state.tokenize = tokenBase;
51
+ break;
52
+ }
53
+ maybeEnd = (ch == "*");
54
+ }
55
+ return ret("comment", "comment");
56
+ }
57
+
58
+ function tokenSGMLComment(stream, state) {
59
+ var dashes = 0, ch;
60
+ while ((ch = stream.next()) != null) {
61
+ if (dashes >= 2 && ch == ">") {
62
+ state.tokenize = tokenBase;
63
+ break;
64
+ }
65
+ dashes = (ch == "-") ? dashes + 1 : 0;
66
+ }
67
+ return ret("comment", "comment");
68
+ }
69
+
70
+ function tokenString(quote) {
71
+ return function(stream, state) {
72
+ var escaped = false, ch;
73
+ while ((ch = stream.next()) != null) {
74
+ if (ch == quote && !escaped)
75
+ break;
76
+ escaped = !escaped && ch == "\\";
77
+ }
78
+ if (!escaped) state.tokenize = tokenBase;
79
+ return ret("string", "string");
80
+ };
81
+ }
82
+
83
+ return {
84
+ startState: function(base) {
85
+ return {tokenize: tokenBase,
86
+ baseIndent: base || 0,
87
+ stack: []};
88
+ },
89
+
90
+ token: function(stream, state) {
91
+ if (stream.eatSpace()) return null;
92
+ var style = state.tokenize(stream, state);
93
+
94
+ var context = state.stack[state.stack.length-1];
95
+ if (type == "hash" && context == "rule") style = "atom";
96
+ else if (style == "variable") {
97
+ if (context == "rule") style = "number";
98
+ else if (!context || context == "@media{") style = "tag";
99
+ }
100
+
101
+ if (context == "rule" && /^[\{\};]$/.test(type))
102
+ state.stack.pop();
103
+ if (type == "{") {
104
+ if (context == "@media") state.stack[state.stack.length-1] = "@media{";
105
+ else state.stack.push("{");
106
+ }
107
+ else if (type == "}") state.stack.pop();
108
+ else if (type == "@media") state.stack.push("@media");
109
+ else if (context == "{" && type != "comment") state.stack.push("rule");
110
+ return style;
111
+ },
112
+
113
+ indent: function(state, textAfter) {
114
+ var n = state.stack.length;
115
+ if (/^\}/.test(textAfter))
116
+ n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
117
+ return state.baseIndent + n * indentUnit;
118
+ },
119
+
120
+ electricChars: "}"
121
+ };
122
+ });
123
+
124
+ CodeMirror.defineMIME("text/css", "css");
tinymce-plugins/cmseditor/js/mode/css/index.html ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>CodeMirror 2: CSS mode</title>
5
+ <link rel="stylesheet" href="../../lib/codemirror.css">
6
+ <script src="../../lib/codemirror.js"></script>
7
+ <script src="css.js"></script>
8
+ <link rel="stylesheet" href="../../theme/default.css">
9
+ <style>.CodeMirror {background: #f8f8f8;}</style>
10
+ <link rel="stylesheet" href="../../css/docs.css">
11
+ </head>
12
+ <body>
13
+ <h1>CodeMirror 2: CSS mode</h1>
14
+ <form><textarea id="code" name="code">
15
+ /* Some example CSS */
16
+
17
+ @import url("something.css");
18
+
19
+ body {
20
+ margin: 0;
21
+ padding: 3em 6em;
22
+ font-family: tahoma, arial, sans-serif;
23
+ color: #000;
24
+ }
25
+
26
+ #navigation a {
27
+ font-weight: bold;
28
+ text-decoration: none !important;
29
+ }
30
+
31
+ h1 {
32
+ font-size: 2.5em;
33
+ }
34
+
35
+ h2 {
36
+ font-size: 1.7em;
37
+ }
38
+
39
+ h1:before, h2:before {
40
+ content: "::";
41
+ }
42
+
43
+ code {
44
+ font-family: courier, monospace;
45
+ font-size: 80%;
46
+ color: #418A8A;
47
+ }
48
+ </textarea></form>
49
+ <script>
50
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
51
+ </script>
52
+
53
+ <p><strong>MIME types defined:</strong> <code>text/css</code>.</p>
54
+
55
+ </body>
56
+ </html>
tinymce-plugins/cmseditor/js/mode/htmlmixed/htmlmixed.js ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
2
+ var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
3
+ var jsMode = CodeMirror.getMode(config, "javascript");
4
+ var cssMode = CodeMirror.getMode(config, "css");
5
+
6
+ function html(stream, state) {
7
+ var style = htmlMode.token(stream, state.htmlState);
8
+ if (style == "tag" && stream.current() == ">" && state.htmlState.context) {
9
+ if (/^script$/i.test(state.htmlState.context.tagName)) {
10
+ state.token = javascript;
11
+ state.localState = jsMode.startState(htmlMode.indent(state.htmlState, ""));
12
+ state.mode = "javascript";
13
+ }
14
+ else if (/^style$/i.test(state.htmlState.context.tagName)) {
15
+ state.token = css;
16
+ state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
17
+ state.mode = "css";
18
+ }
19
+ }
20
+ return style;
21
+ }
22
+ function maybeBackup(stream, pat, style) {
23
+ var cur = stream.current();
24
+ var close = cur.search(pat);
25
+ if (close > -1) stream.backUp(cur.length - close);
26
+ return style;
27
+ }
28
+ function javascript(stream, state) {
29
+ if (stream.match(/^<\/\s*script\s*>/i, false)) {
30
+ state.token = html;
31
+ state.curState = null;
32
+ state.mode = "html";
33
+ return html(stream, state);
34
+ }
35
+ return maybeBackup(stream, /<\/\s*script\s*>/,
36
+ jsMode.token(stream, state.localState));
37
+ }
38
+ function css(stream, state) {
39
+ if (stream.match(/^<\/\s*style\s*>/i, false)) {
40
+ state.token = html;
41
+ state.localState = null;
42
+ state.mode = "html";
43
+ return html(stream, state);
44
+ }
45
+ return maybeBackup(stream, /<\/\s*style\s*>/,
46
+ cssMode.token(stream, state.localState));
47
+ }
48
+
49
+ return {
50
+ startState: function() {
51
+ var state = htmlMode.startState();
52
+ return {token: html, localState: null, mode: "html", htmlState: state};
53
+ },
54
+
55
+ copyState: function(state) {
56
+ if (state.localState)
57
+ var local = CodeMirror.copyState(state.token == css ? cssMode : jsMode, state.localState);
58
+ return {token: state.token, localState: local, mode: state.mode,
59
+ htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
60
+ },
61
+
62
+ token: function(stream, state) {
63
+ return state.token(stream, state);
64
+ },
65
+
66
+ indent: function(state, textAfter) {
67
+ if (state.token == html || /^\s*<\//.test(textAfter))
68
+ return htmlMode.indent(state.htmlState, textAfter);
69
+ else if (state.token == javascript)
70
+ return jsMode.indent(state.localState, textAfter);
71
+ else
72
+ return cssMode.indent(state.localState, textAfter);
73
+ },
74
+
75
+ electricChars: "/{}:"
76
+ }
77
+ });
78
+
79
+ CodeMirror.defineMIME("text/html", "htmlmixed");
tinymce-plugins/cmseditor/js/mode/htmlmixed/index.html ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>CodeMirror 2: HTML mixed mode</title>
5
+ <link rel="stylesheet" href="../../lib/codemirror.css">
6
+ <script src="../../lib/codemirror.js"></script>
7
+ <script src="../xml/xml.js"></script>
8
+ <script src="../javascript/javascript.js"></script>
9
+ <script src="../css/css.js"></script>
10
+ <link rel="stylesheet" href="../../theme/default.css">
11
+ <script src="htmlmixed.js"></script>
12
+ <link rel="stylesheet" href="../../css/docs.css">
13
+ <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
14
+ </head>
15
+ <body>
16
+ <h1>CodeMirror 2: HTML mixed mode</h1>
17
+ <form><textarea id="code" name="code">
18
+ <html style="color: green">
19
+ <!-- this is a comment -->
20
+ <head>
21
+ <title>Mixed HTML Example</title>
22
+ <style type="text/css">
23
+ h1 {font-family: comic sans; color: #f0f;}
24
+ div {background: yellow !important;}
25
+ body {
26
+ max-width: 50em;
27
+ margin: 1em 2em 1em 5em;
28
+ }
29
+ </style>
30
+ </head>
31
+ <body>
32
+ <h1>Mixed HTML Example</h1>
33
+ <script>
34
+ function jsFunc(arg1, arg2) {
35
+ if (arg1 && arg2) document.body.innerHTML = "achoo";
36
+ }
37
+ </script>
38
+ </body>
39
+ </html>
40
+ </textarea></form>
41
+ <script>
42
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", tabMode: "indent"});
43
+ </script>
44
+
45
+ <p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p>
46
+
47
+ <p><strong>MIME types defined:</strong> <code>text/html</code>
48
+ (redefined, only takes effect if you load this parser after the
49
+ XML parser).</p>
50
+
51
+ </body>
52
+ </html>
tinymce-plugins/cmseditor/js/mode/javascript/index.html ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>CodeMirror 2: JavaScript mode</title>
5
+ <link rel="stylesheet" href="../../lib/codemirror.css">
6
+ <script src="../../lib/codemirror.js"></script>
7
+ <script src="javascript.js"></script>
8
+ <link rel="stylesheet" href="../../theme/default.css">
9
+ <link rel="stylesheet" href="../../css/docs.css">
10
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
11
+ </head>
12
+ <body>
13
+ <h1>CodeMirror 2: JavaScript mode</h1>
14
+
15
+ <div><textarea id="code" name="code">
16
+ // Demo code (the actual new parser character stream implementation)
17
+
18
+ function StringStream(string) {
19
+ this.pos = 0;
20
+ this.string = string;
21
+ }
22
+
23
+ StringStream.prototype = {
24
+ done: function() {return this.pos >= this.string.length;},
25
+ peek: function() {return this.string.charAt(this.pos);},
26
+ next: function() {
27
+ if (this.pos &lt; this.string.length)
28
+ return this.string.charAt(this.pos++);
29
+ },
30
+ eat: function(match) {
31
+ var ch = this.string.charAt(this.pos);
32
+ if (typeof match == "string") var ok = ch == match;
33
+ else var ok = ch &amp;&amp; match.test ? match.test(ch) : match(ch);
34
+ if (ok) {this.pos++; return ch;}
35
+ },
36
+ eatWhile: function(match) {
37
+ var start = this.pos;
38
+ while (this.eat(match));
39
+ if (this.pos > start) return this.string.slice(start, this.pos);
40
+ },
41
+ backUp: function(n) {this.pos -= n;},
42
+ column: function() {return this.pos;},
43
+ eatSpace: function() {
44
+ var start = this.pos;
45
+ while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
46
+ return this.pos - start;
47
+ },
48
+ match: function(pattern, consume, caseInsensitive) {
49
+ if (typeof pattern == "string") {
50
+ function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
51
+ if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
52
+ if (consume !== false) this.pos += str.length;
53
+ return true;
54
+ }
55
+ }
56
+ else {
57
+ var match = this.string.slice(this.pos).match(pattern);
58
+ if (match &amp;&amp; consume !== false) this.pos += match[0].length;
59
+ return match;
60
+ }
61
+ }
62
+ };
63
+ </textarea></div>
64
+
65
+ <script>
66
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
67
+ lineNumbers: true,
68
+ matchBrackets: true
69
+ });
70
+ </script>
71
+
72
+ <p>JavaScript mode supports a single configuration
73
+ option, <code>json</code>, which will set the mode to expect JSON
74
+ data rather than a JavaScript program.</p>
75
+
76
+ <p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>.</p>
77
+ </body>
78
+ </html>
tinymce-plugins/cmseditor/js/mode/javascript/javascript.js ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CodeMirror.defineMode("javascript", function(config, parserConfig) {
2
+ var indentUnit = config.indentUnit;
3
+ var jsonMode = parserConfig.json;
4
+
5
+ // Tokenizer
6
+
7
+ var keywords = function(){
8
+ function kw(type) {return {type: type, style: "keyword"};}
9
+ var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
10
+ var operator = kw("operator"), atom = {type: "atom", style: "atom"};
11
+ return {
12
+ "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
13
+ "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
14
+ "var": kw("var"), "function": kw("function"), "catch": kw("catch"),
15
+ "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
16
+ "in": operator, "typeof": operator, "instanceof": operator,
17
+ "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
18
+ };
19
+ }();
20
+
21
+ var isOperatorChar = /[+\-*&%=<>!?|]/;
22
+
23
+ function chain(stream, state, f) {
24
+ state.tokenize = f;
25
+ return f(stream, state);
26
+ }
27
+
28
+ function nextUntilUnescaped(stream, end) {
29
+ var escaped = false, next;
30
+ while ((next = stream.next()) != null) {
31
+ if (next == end && !escaped)
32
+ return false;
33
+ escaped = !escaped && next == "\\";
34
+ }
35
+ return escaped;
36
+ }
37
+
38
+ // Used as scratch variables to communicate multiple values without
39
+ // consing up tons of objects.
40
+ var type, content;
41
+ function ret(tp, style, cont) {
42
+ type = tp; content = cont;
43
+ return style;
44
+ }
45
+
46
+ function jsTokenBase(stream, state) {
47
+ var ch = stream.next();
48
+ if (ch == '"' || ch == "'")
49
+ return chain(stream, state, jsTokenString(ch));
50
+ else if (/[\[\]{}\(\),;\:\.]/.test(ch))
51
+ return ret(ch);
52
+ else if (ch == "0" && stream.eat(/x/i)) {
53
+ stream.eatWhile(/[\da-f]/i);
54
+ return ret("number", "number");
55
+ }
56
+ else if (/\d/.test(ch)) {
57
+ stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);
58
+ return ret("number", "number");
59
+ }
60
+ else if (ch == "/") {
61
+ if (stream.eat("*")) {
62
+ return chain(stream, state, jsTokenComment);
63
+ }
64
+ else if (stream.eat("/")) {
65
+ stream.skipToEnd();
66
+ return ret("comment", "comment");
67
+ }
68
+ else if (state.reAllowed) {
69
+ nextUntilUnescaped(stream, "/");
70
+ stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
71
+ return ret("regexp", "string");
72
+ }
73
+ else {
74
+ stream.eatWhile(isOperatorChar);
75
+ return ret("operator", null, stream.current());
76
+ }
77
+ }
78
+ else if (isOperatorChar.test(ch)) {
79
+ stream.eatWhile(isOperatorChar);
80
+ return ret("operator", null, stream.current());
81
+ }
82
+ else {
83
+ stream.eatWhile(/[\w\$_]/);
84
+ var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
85
+ return known ? ret(known.type, known.style, word) :
86
+ ret("variable", "variable", word);
87
+ }
88
+ }
89
+
90
+ function jsTokenString(quote) {
91
+ return function(stream, state) {
92
+ if (!nextUntilUnescaped(stream, quote))
93
+ state.tokenize = jsTokenBase;
94
+ return ret("string", "string");
95
+ };
96
+ }
97
+
98
+ function jsTokenComment(stream, state) {
99
+ var maybeEnd = false, ch;
100
+ while (ch = stream.next()) {
101
+ if (ch == "/" && maybeEnd) {
102
+ state.tokenize = jsTokenBase;
103
+ break;
104
+ }
105
+ maybeEnd = (ch == "*");
106
+ }
107
+ return ret("comment", "comment");
108
+ }
109
+
110
+ // Parser
111
+
112
+ var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
113
+
114
+ function JSLexical(indented, column, type, align, prev, info) {
115
+ this.indented = indented;
116
+ this.column = column;
117
+ this.type = type;
118
+ this.prev = prev;
119
+ this.info = info;
120
+ if (align != null) this.align = align;
121
+ }
122
+
123
+ function inScope(state, varname) {
124
+ for (var v = state.localVars; v; v = v.next)
125
+ if (v.name == varname) return true;
126
+ }
127
+
128
+ function parseJS(state, style, type, content, stream) {
129
+ var cc = state.cc;
130
+ // Communicate our context to the combinators.
131
+ // (Less wasteful than consing up a hundred closures on every call.)
132
+ cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
133
+
134
+ if (!state.lexical.hasOwnProperty("align"))
135
+ state.lexical.align = true;
136
+
137
+ while(true) {
138
+ var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
139
+ if (combinator(type, content)) {
140
+ while(cc.length && cc[cc.length - 1].lex)
141
+ cc.pop()();
142
+ if (cx.marked) return cx.marked;
143
+ if (type == "variable" && inScope(state, content)) return "variable-2";
144
+ return style;
145
+ }
146
+ }
147
+ }
148
+
149
+ // Combinator utils
150
+
151
+ var cx = {state: null, column: null, marked: null, cc: null};
152
+ function pass() {
153
+ for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
154
+ }
155
+ function cont() {
156
+ pass.apply(null, arguments);
157
+ return true;
158
+ }
159
+ function register(varname) {
160
+ var state = cx.state;
161
+ if (state.context) {
162
+ cx.marked = "def";
163
+ for (var v = state.localVars; v; v = v.next)
164
+ if (v.name == varname) return;
165
+ state.localVars = {name: varname, next: state.localVars};
166
+ }
167
+ }
168
+
169
+ // Combinators
170
+
171
+ var defaultVars = {name: "this", next: {name: "arguments"}};
172
+ function pushcontext() {
173
+ if (!cx.state.context) cx.state.localVars = defaultVars;
174
+ cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
175
+ }
176
+ function popcontext() {
177
+ cx.state.localVars = cx.state.context.vars;
178
+ cx.state.context = cx.state.context.prev;
179
+ }
180
+ function pushlex(type, info) {
181
+ var result = function() {
182
+ var state = cx.state;
183
+ state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
184
+ };
185
+ result.lex = true;
186
+ return result;
187
+ }
188
+ function poplex() {
189
+ var state = cx.state;
190
+ if (state.lexical.prev) {
191
+ if (state.lexical.type == ")")
192
+ state.indented = state.lexical.indented;
193
+ state.lexical = state.lexical.prev;
194
+ }
195
+ }
196
+ poplex.lex = true;
197
+
198
+ function expect(wanted) {
199
+ return function expecting(type) {
200
+ if (type == wanted) return cont();
201
+ else if (wanted == ";") return pass();
202
+ else return cont(arguments.callee);
203
+ };
204
+ }
205
+
206
+ function statement(type) {
207
+ if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
208
+ if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
209
+ if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
210
+ if (type == "{") return cont(pushlex("}"), block, poplex);
211
+ if (type == ";") return cont();
212
+ if (type == "function") return cont(functiondef);
213
+ if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
214
+ poplex, statement, poplex);
215
+ if (type == "variable") return cont(pushlex("stat"), maybelabel);
216
+ if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
217
+ block, poplex, poplex);
218
+ if (type == "case") return cont(expression, expect(":"));
219
+ if (type == "default") return cont(expect(":"));
220
+ if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
221
+ statement, poplex, popcontext);
222
+ return pass(pushlex("stat"), expression, expect(";"), poplex);
223
+ }
224
+ function expression(type) {
225
+ if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
226
+ if (type == "function") return cont(functiondef);
227
+ if (type == "keyword c") return cont(expression);
228
+ if (type == "(") return cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
229
+ if (type == "operator") return cont(expression);
230
+ if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
231
+ if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
232
+ return cont();
233
+ }
234
+ function maybeoperator(type, value) {
235
+ if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
236
+ if (type == "operator") return cont(expression);
237
+ if (type == ";") return;
238
+ if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
239
+ if (type == ".") return cont(property, maybeoperator);
240
+ if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
241
+ }
242
+ function maybelabel(type) {
243
+ if (type == ":") return cont(poplex, statement);
244
+ return pass(maybeoperator, expect(";"), poplex);
245
+ }
246
+ function property(type) {
247
+ if (type == "variable") {cx.marked = "property"; return cont();}
248
+ }
249
+ function objprop(type) {
250
+ if (type == "variable") cx.marked = "property";
251
+ if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
252
+ }
253
+ function commasep(what, end) {
254
+ function proceed(type) {
255
+ if (type == ",") return cont(what, proceed);
256
+ if (type == end) return cont();
257
+ return cont(expect(end));
258
+ }
259
+ return function commaSeparated(type) {
260
+ if (type == end) return cont();
261
+ else return pass(what, proceed);
262
+ };
263
+ }
264
+ function block(type) {
265
+ if (type == "}") return cont();
266
+ return pass(statement, block);
267
+ }
268
+ function vardef1(type, value) {
269
+ if (type == "variable"){register(value); return cont(vardef2);}
270
+ return cont();
271
+ }
272
+ function vardef2(type, value) {
273
+ if (value == "=") return cont(expression, vardef2);
274
+ if (type == ",") return cont(vardef1);
275
+ }
276
+ function forspec1(type) {
277
+ if (type == "var") return cont(vardef1, forspec2);
278
+ if (type == ";") return pass(forspec2);
279
+ if (type == "variable") return cont(formaybein);
280
+ return pass(forspec2);
281
+ }
282
+ function formaybein(type, value) {
283
+ if (value == "in") return cont(expression);
284
+ return cont(maybeoperator, forspec2);
285
+ }
286
+ function forspec2(type, value) {
287
+ if (type == ";") return cont(forspec3);
288
+ if (value == "in") return cont(expression);
289
+ return cont(expression, expect(";"), forspec3);
290
+ }
291
+ function forspec3(type) {
292
+ if (type != ")") cont(expression);
293
+ }
294
+ function functiondef(type, value) {
295
+ if (type == "variable") {register(value); return cont(functiondef);}
296
+ if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
297
+ }
298
+ function funarg(type, value) {
299
+ if (type == "variable") {register(value); return cont();}
300
+ }
301
+
302
+ // Interface
303
+
304
+ return {
305
+ startState: function(basecolumn) {
306
+ return {
307
+ tokenize: jsTokenBase,
308
+ reAllowed: true,
309
+ cc: [],
310
+ lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
311
+ localVars: null,
312
+ context: null,
313
+ indented: 0
314
+ };
315
+ },
316
+
317
+ token: function(stream, state) {
318
+ if (stream.sol()) {
319
+ if (!state.lexical.hasOwnProperty("align"))
320
+ state.lexical.align = false;
321
+ state.indented = stream.indentation();
322
+ }
323
+ if (stream.eatSpace()) return null;
324
+ var style = state.tokenize(stream, state);
325
+ if (type == "comment") return style;
326
+ state.reAllowed = type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/);
327
+ return parseJS(state, style, type, content, stream);
328
+ },
329
+
330
+ indent: function(state, textAfter) {
331
+ if (state.tokenize != jsTokenBase) return 0;
332
+ var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
333
+ type = lexical.type, closing = firstChar == type;
334
+ if (type == "vardef") return lexical.indented + 4;
335
+ else if (type == "form" && firstChar == "{") return lexical.indented;
336
+ else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
337
+ else if (lexical.info == "switch" && !closing)
338
+ return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
339
+ else if (lexical.align) return lexical.column + (closing ? 0 : 1);
340
+ else return lexical.indented + (closing ? 0 : indentUnit);
341
+ },
342
+
343
+ electricChars: ":{}"
344
+ };
345
+ });
346
+
347
+ CodeMirror.defineMIME("text/javascript", "javascript");
348
+ CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
tinymce-plugins/cmseditor/js/mode/php/index.html ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>CodeMirror 2: PHP mode</title>
5
+ <link rel="stylesheet" href="../../lib/codemirror.css">
6
+ <script src="../../lib/codemirror.js"></script>
7
+ <script src="../xml/xml.js"></script>
8
+ <script src="../javascript/javascript.js"></script>
9
+ <script src="../css/css.js"></script>
10
+ <script src="../clike/clike.js"></script>
11
+ <script src="php.js"></script>
12
+ <link rel="stylesheet" href="../../theme/default.css">
13
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
14
+ <link rel="stylesheet" href="../../css/docs.css">
15
+ </head>
16
+ <body>
17
+ <h1>CodeMirror 2: PHP mode</h1>
18
+
19
+ <form><textarea id="code" name="code">
20
+ <?php
21
+ function hello($who) {
22
+ return "Hello " . $who;
23
+ }
24
+ ?>
25
+ <p>The program says <?= hello("World") ?>.</p>
26
+ <script>
27
+ alert("And here is some JS code"); // also colored
28
+ </script>
29
+ </textarea></form>
30
+
31
+ <script>
32
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
33
+ lineNumbers: true,
34
+ matchBrackets: true,
35
+ mode: "application/x-httpd-php",
36
+ indentUnit: 8,
37
+ indentWithTabs: true,
38
+ enterMode: "keep",
39
+ tabMode: "shift"
40
+ });
41
+ </script>
42
+
43
+ <p>Simple HTML/PHP mode based on
44
+ the <a href="../clike/">C-like</a> mode. Depends on XML,
45
+ JavaScript, CSS, and C-like modes.</p>
46
+
47
+ <p><strong>MIME types defined:</strong> <code>application/x-httpd-php</code> (HTML with PHP code), <code>text/x-php</code> (plain, non-wrapped PHP code).</p>
48
+ </body>
49
+ </html>
tinymce-plugins/cmseditor/js/mode/php/php.js ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function() {
2
+ function keywords(str) {
3
+ var obj = {}, words = str.split(" ");
4
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
5
+ return obj;
6
+ }
7
+ function heredoc(delim) {
8
+ return function(stream, state) {
9
+ if (stream.match(delim)) state.tokenize = null;
10
+ else stream.skipToEnd();
11
+ return "string";
12
+ }
13
+ }
14
+ var phpConfig = {
15
+ name: "clike",
16
+ keywords: keywords("abstract and array as break case catch cfunction class clone const continue declare " +
17
+ "default do else elseif enddeclare endfor endforeach endif endswitch endwhile extends " +
18
+ "final for foreach function global goto if implements interface instanceof namespace " +
19
+ "new or private protected public static switch throw try use var while xor return"),
20
+ blockKeywords: keywords("catch do else elseif for foreach if switch try while"),
21
+ atoms: keywords("true false null"),
22
+ multiLineStrings: true,
23
+ hooks: {
24
+ "$": function(stream, state) {
25
+ stream.eatWhile(/[\w\$_]/);
26
+ return "variable-2";
27
+ },
28
+ "<": function(stream, state) {
29
+ if (stream.match(/<</)) {
30
+ stream.eatWhile(/[\w\.]/);
31
+ state.tokenize = heredoc(stream.current().slice(3));
32
+ return state.tokenize(stream, state);
33
+ }
34
+ return false;
35
+ }
36
+ }
37
+ };
38
+
39
+ CodeMirror.defineMode("php", function(config, parserConfig) {
40
+ var htmlMode = CodeMirror.getMode(config, "text/html");
41
+ var jsMode = CodeMirror.getMode(config, "text/javascript");
42
+ var cssMode = CodeMirror.getMode(config, "text/css");
43
+ var phpMode = CodeMirror.getMode(config, phpConfig);
44
+
45
+ function dispatch(stream, state) { // TODO open PHP inside text/css
46
+ if (state.curMode == htmlMode) {
47
+ var style = htmlMode.token(stream, state.curState);
48
+ if (style == "meta" && /^<\?/.test(stream.current())) {
49
+ state.curMode = phpMode;
50
+ state.curState = state.php;
51
+ state.curClose = /^\?>/;
52
+ state.mode = 'php';
53
+ }
54
+ else if (style == "tag" && stream.current() == ">" && state.curState.context) {
55
+ if (/^script$/i.test(state.curState.context.tagName)) {
56
+ state.curMode = jsMode;
57
+ state.curState = jsMode.startState(htmlMode.indent(state.curState, ""));
58
+ state.curClose = /^<\/\s*script\s*>/i;
59
+ state.mode = 'javascript';
60
+ }
61
+ else if (/^style$/i.test(state.curState.context.tagName)) {
62
+ state.curMode = cssMode;
63
+ state.curState = cssMode.startState(htmlMode.indent(state.curState, ""));
64
+ state.curClose = /^<\/\s*style\s*>/i;
65
+ state.mode = 'css';
66
+ }
67
+ }
68
+ return style;
69
+ }
70
+ else if (stream.match(state.curClose, false)) {
71
+ state.curMode = htmlMode;
72
+ state.curState = state.html;
73
+ state.curClose = null;
74
+ state.mode = 'html';
75
+ return dispatch(stream, state);
76
+ }
77
+ else return state.curMode.token(stream, state.curState);
78
+ }
79
+
80
+ return {
81
+ startState: function() {
82
+ var html = htmlMode.startState();
83
+ return {html: html,
84
+ php: phpMode.startState(),
85
+ curMode: parserConfig.startOpen ? phpMode : htmlMode,
86
+ curState: parserConfig.startOpen ? phpMode.startState() : html,
87
+ curClose: parserConfig.startOpen ? /^\?>/ : null,
88
+ mode: parserConfig.startOpen ? 'php' : 'html'}
89
+ },
90
+
91
+ copyState: function(state) {
92
+ var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html),
93
+ php = state.php, phpNew = CodeMirror.copyState(phpMode, php), cur;
94
+ if (state.curState == html) cur = htmlNew;
95
+ else if (state.curState == php) cur = phpNew;
96
+ else cur = CodeMirror.copyState(state.curMode, state.curState);
97
+ return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, curClose: state.curClose};
98
+ },
99
+
100
+ token: dispatch,
101
+
102
+ indent: function(state, textAfter) {
103
+ if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
104
+ (state.curMode == phpMode && /^\?>/.test(textAfter)))
105
+ return htmlMode.indent(state.html, textAfter);
106
+ return state.curMode.indent(state.curState, textAfter);
107
+ },
108
+
109
+ electricChars: "/{}:"
110
+ }
111
+ });
112
+ CodeMirror.defineMIME("application/x-httpd-php", "php");
113
+ CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true});
114
+ CodeMirror.defineMIME("text/x-php", phpConfig);
115
+ })();
tinymce-plugins/cmseditor/js/mode/xml/index.html ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>CodeMirror 2: XML mode</title>
5
+ <link rel="stylesheet" href="../../lib/codemirror.css">
6
+ <script src="../../lib/codemirror.js"></script>
7
+ <script src="xml.js"></script>
8
+ <link rel="stylesheet" href="../../theme/default.css">
9
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10
+ <link rel="stylesheet" href="../../css/docs.css">
11
+ </head>
12
+ <body>
13
+ <h1>CodeMirror 2: XML mode</h1>
14
+ <form><textarea id="code" name="code">
15
+ &lt;html style="color: green"&gt;
16
+ &lt;!-- this is a comment --&gt;
17
+ &lt;head&gt;
18
+ &lt;title&gt;HTML Example&lt;/title&gt;
19
+ &lt;/head&gt;
20
+ &lt;body&gt;
21
+ The indentation tries to be &lt;em&gt;somewhat &amp;quot;do what
22
+ I mean&amp;quot;&lt;/em&gt;... but might not match your style.
23
+ &lt;/body&gt;
24
+ &lt;/html&gt;
25
+ </textarea></form>
26
+ <script>
27
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: {name: "xml", htmlMode: true}});
28
+ </script>
29
+ <p>The XML mode supports two configuration parameters:</p>
30
+ <dl>
31
+ <dt><code>htmlMode (boolean)</code></dt>
32
+ <dd>This switches the mode to parse HTML instead of XML. This
33
+ means attributes do not have to be quoted, and some elements
34
+ (such as <code>br</code>) do not require a closing tag.</dd>
35
+ <dt><code>alignCDATA (boolean)</code></dt>
36
+ <dd>Setting this to true will force the opening tag of CDATA
37
+ blocks to not be indented.</dd>
38
+ </dl>
39
+
40
+ <p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/html</code>.</p>
41
+ </body>
42
+ </html>
tinymce-plugins/cmseditor/js/mode/xml/xml.js ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CodeMirror.defineMode("xml", function(config, parserConfig) {
2
+ var indentUnit = config.indentUnit;
3
+ var Kludges = parserConfig.htmlMode ? {
4
+ autoSelfClosers: {"br": true, "img": true, "hr": true, "link": true, "input": true,
5
+ "meta": true, "col": true, "frame": true, "base": true, "area": true},
6
+ doNotIndent: {"pre": true, "!cdata": true},
7
+ allowUnquoted: true
8
+ } : {autoSelfClosers: {}, doNotIndent: {"!cdata": true}, allowUnquoted: false};
9
+ var alignCDATA = parserConfig.alignCDATA;
10
+
11
+ // Return variables for tokenizers
12
+ var tagName, type;
13
+
14
+ function inText(stream, state) {
15
+ function chain(parser) {
16
+ state.tokenize = parser;
17
+ return parser(stream, state);
18
+ }
19
+
20
+ var ch = stream.next();
21
+ if (ch == "<") {
22
+ if (stream.eat("!")) {
23
+ if (stream.eat("[")) {
24
+ if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
25
+ else return null;
26
+ }
27
+ else if (stream.match("--")) return chain(inBlock("comment", "-->"));
28
+ else if (stream.match("DOCTYPE", true, true)) {
29
+ stream.eatWhile(/[\w\._\-]/);
30
+ return chain(inBlock("meta", ">"));
31
+ }
32
+ else return null;
33
+ }
34
+ else if (stream.eat("?")) {
35
+ stream.eatWhile(/[\w\._\-]/);
36
+ state.tokenize = inBlock("meta", "?>");
37
+ return "meta";
38
+ }
39
+ else {
40
+ type = stream.eat("/") ? "closeTag" : "openTag";
41
+ stream.eatSpace();
42
+ tagName = "";
43
+ var c;
44
+ while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
45
+ state.tokenize = inTag;
46
+ return "tag";
47
+ }
48
+ }
49
+ else if (ch == "&") {
50
+ stream.eatWhile(/[^;]/);
51
+ stream.eat(";");
52
+ return "atom";
53
+ }
54
+ else {
55
+ stream.eatWhile(/[^&<]/);
56
+ return null;
57
+ }
58
+ }
59
+
60
+ function inTag(stream, state) {
61
+ var ch = stream.next();
62
+ if (ch == ">" || (ch == "/" && stream.eat(">"))) {
63
+ state.tokenize = inText;
64
+ type = ch == ">" ? "endTag" : "selfcloseTag";
65
+ return "tag";
66
+ }
67
+ else if (ch == "=") {
68
+ type = "equals";
69
+ return null;
70
+ }
71
+ else if (/[\'\"]/.test(ch)) {
72
+ state.tokenize = inAttribute(ch);
73
+ return state.tokenize(stream, state);
74
+ }
75
+ else {
76
+ stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
77
+ return "word";
78
+ }
79
+ }
80
+
81
+ function inAttribute(quote) {
82
+ return function(stream, state) {
83
+ while (!stream.eol()) {
84
+ if (stream.next() == quote) {
85
+ state.tokenize = inTag;
86
+ break;
87
+ }
88
+ }
89
+ return "string";
90
+ };
91
+ }
92
+
93
+ function inBlock(style, terminator) {
94
+ return function(stream, state) {
95
+ while (!stream.eol()) {
96
+ if (stream.match(terminator)) {
97
+ state.tokenize = inText;
98
+ break;
99
+ }
100
+ stream.next();
101
+ }
102
+ return style;
103
+ };
104
+ }
105
+
106
+ var curState, setStyle;
107
+ function pass() {
108
+ for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
109
+ }
110
+ function cont() {
111
+ pass.apply(null, arguments);
112
+ return true;
113
+ }
114
+
115
+ function pushContext(tagName, startOfLine) {
116
+ var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
117
+ curState.context = {
118
+ prev: curState.context,
119
+ tagName: tagName,
120
+ indent: curState.indented,
121
+ startOfLine: startOfLine,
122
+ noIndent: noIndent
123
+ };
124
+ }
125
+ function popContext() {
126
+ if (curState.context) curState.context = curState.context.prev;
127
+ }
128
+
129
+ function element(type) {
130
+ if (type == "openTag") {curState.tagName = tagName; return cont(attributes, endtag(curState.startOfLine));}
131
+ else if (type == "closeTag") {
132
+ var err = false;
133
+ if (curState.context) {
134
+ err = curState.context.tagName != tagName;
135
+ popContext();
136
+ } else {
137
+ err = true;
138
+ }
139
+ if (err) setStyle = "error";
140
+ return cont(endclosetag(err));
141
+ }
142
+ else if (type == "string") {
143
+ if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
144
+ if (curState.tokenize == inText) popContext();
145
+ return cont();
146
+ }
147
+ else return cont();
148
+ }
149
+ function endtag(startOfLine) {
150
+ return function(type) {
151
+ if (type == "selfcloseTag" ||
152
+ (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase())))
153
+ return cont();
154
+ if (type == "endTag") {pushContext(curState.tagName, startOfLine); return cont();}
155
+ return cont();
156
+ };
157
+ }
158
+ function endclosetag(err) {
159
+ return function(type) {
160
+ if (err) setStyle = "error";
161
+ if (type == "endTag") return cont();
162
+ return pass();
163
+ }
164
+ }
165
+
166
+ function attributes(type) {
167
+ if (type == "word") {setStyle = "attribute"; return cont(attributes);}
168
+ if (type == "equals") return cont(attvalue, attributes);
169
+ return pass();
170
+ }
171
+ function attvalue(type) {
172
+ if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
173
+ if (type == "string") return cont(attvaluemaybe);
174
+ return pass();
175
+ }
176
+ function attvaluemaybe(type) {
177
+ if (type == "string") return cont(attvaluemaybe);
178
+ else return pass();
179
+ }
180
+
181
+ return {
182
+ startState: function() {
183
+ return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
184
+ },
185
+
186
+ token: function(stream, state) {
187
+ if (stream.sol()) {
188
+ state.startOfLine = true;
189
+ state.indented = stream.indentation();
190
+ }
191
+ if (stream.eatSpace()) return null;
192
+
193
+ setStyle = type = tagName = null;
194
+ var style = state.tokenize(stream, state);
195
+ if ((style || type) && style != "comment") {
196
+ curState = state;
197
+ while (true) {
198
+ var comb = state.cc.pop() || element;
199
+ if (comb(type || style)) break;
200
+ }
201
+ }
202
+ state.startOfLine = false;
203
+ return setStyle || style;
204
+ },
205
+
206
+ indent: function(state, textAfter) {
207
+ var context = state.context;
208
+ if (context && context.noIndent) return 0;
209
+ if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
210
+ if (context && /^<\//.test(textAfter))
211
+ context = context.prev;
212
+ while (context && !context.startOfLine)
213
+ context = context.prev;
214
+ if (context) return context.indent + indentUnit;
215
+ else return 0;
216
+ },
217
+
218
+ compareStates: function(a, b) {
219
+ if (a.indented != b.indented || a.tagName != b.tagName) return false;
220
+ for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
221
+ if (!ca || !cb) return ca == cb;
222
+ if (ca.tagName != cb.tagName) return false;
223
+ }
224
+ },
225
+
226
+ electricChars: "/"
227
+ };
228
+ });
229
+
230
+ CodeMirror.defineMIME("application/xml", "xml");
231
+ CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
tinymce-plugins/cmseditor/js/mode/xmlpure/index.html ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>CodeMirror 2: Pure XML mode</title>
5
+ <link rel="stylesheet" href="../../lib/codemirror.css">
6
+ <script src="../../lib/codemirror.js"></script>
7
+ <script src="xmlpure.js"></script>
8
+ <link rel="stylesheet" href="../../theme/default.css">
9
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10
+ <link rel="stylesheet" href="../../css/docs.css">
11
+ </head>
12
+ <body>
13
+ <h1>CodeMirror 2: XML mode</h1>
14
+ <form><textarea id="code" name="code">
15
+ &lt;?xml version="1.0" encoding="UTF-8" standalone="no" ?&gt;
16
+
17
+ &lt;!-- This is the pure XML mode,
18
+ and we're inside a comment! --&gt;
19
+
20
+ &lt;catalog&gt;
21
+ &lt;books&gt;
22
+ &lt;book id="bk01"&gt;
23
+ &lt;title&gt;Lord of Light&lt;/title&gt;
24
+ &lt;author&gt;Roger Zelazny&lt;/author&gt;
25
+ &lt;year&gt;1967&lt;/year&gt;
26
+ &lt;description&gt;&lt;![CDATA[This is a great book, really!!]]&gt;&lt;/description&gt;
27
+ &lt;/book&gt;
28
+ &lt;/books&gt;
29
+ &lt;/catalog&gt;
30
+ </textarea></form>
31
+ <script>
32
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: {name: "xmlpure"}});
33
+ </script>
34
+
35
+ <p>This is my XML parser, based on the original:</p>
36
+ <ul>
37
+ <li>No html mode - this is pure xml</li>
38
+ <li>Illegal attributes and element names are errors</li>
39
+ <li>Attributes must have a value</li>
40
+ <li>XML declaration supported (e.g.: <b>&lt;?xml version="1.0" encoding="utf-8" standalone="no" ?&gt;</b>)</li>
41
+ <li>CDATA and comment blocks are not indented (except for their start-tag)</li>
42
+ <li>Better handling of errors per line with the state object - provides good infrastructure for extending it</li>
43
+ </ul>
44
+
45
+ <p>What's missing:</p>
46
+ <ul>
47
+ <li>Make sure only a single root element exists at the document level</li>
48
+ <li>Multi-line attributes should NOT indent</li>
49
+ <li>Start tags are not painted red when they have no matching end tags (is this really wrong?)</li>
50
+ </ul>
51
+
52
+ <p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/xml</code>.</p>
53
+
54
+ <p><b>@author</b>: Dror BG (<i>deebug dot dev at gmail dot com</i>)<br/>
55
+ <p><b>@date</b>: August, 2011<br/>
56
+ <p><b>@github</b>: <a href='https://github.com/deebugger/CodeMirror2' target='blank'>https://github.com/deebugger/CodeMirror2</a></p>
57
+
58
+ <p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/xml</code>.</p>
59
+ </body>
60
+ </html>
tinymce-plugins/cmseditor/js/mode/xmlpure/xmlpure.js ADDED
@@ -0,0 +1,481 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * xmlpure.js
3
+ *
4
+ * Building upon and improving the CodeMirror 2 XML parser
5
+ * @author: Dror BG (deebug.dev@gmail.com)
6
+ * @date: August, 2011
7
+ */
8
+
9
+ CodeMirror.defineMode("xmlpure", function(config, parserConfig) {
10
+ // constants
11
+ var STYLE_ERROR = "error";
12
+ var STYLE_INSTRUCTION = "comment";
13
+ var STYLE_COMMENT = "comment";
14
+ var STYLE_ELEMENT_NAME = "tag";
15
+ var STYLE_ATTRIBUTE = "attribute";
16
+ var STYLE_WORD = "string";
17
+ var STYLE_TEXT = "atom";
18
+
19
+ var TAG_INSTRUCTION = "!instruction";
20
+ var TAG_CDATA = "!cdata";
21
+ var TAG_COMMENT = "!comment";
22
+ var TAG_TEXT = "!text";
23
+
24
+ var doNotIndent = {
25
+ "!cdata": true,
26
+ "!comment": true,
27
+ "!text": true,
28
+ "!instruction": true
29
+ };
30
+
31
+ // options
32
+ var indentUnit = config.indentUnit;
33
+
34
+ ///////////////////////////////////////////////////////////////////////////
35
+ // helper functions
36
+
37
+ // chain a parser to another parser
38
+ function chain(stream, state, parser) {
39
+ state.tokenize = parser;
40
+ return parser(stream, state);
41
+ }
42
+
43
+ // parse a block (comment, CDATA or text)
44
+ function inBlock(style, terminator, nextTokenize) {
45
+ return function(stream, state) {
46
+ while (!stream.eol()) {
47
+ if (stream.match(terminator)) {
48
+ popContext(state);
49
+ state.tokenize = nextTokenize;
50
+ break;
51
+ }
52
+ stream.next();
53
+ }
54
+ return style;
55
+ };
56
+ }
57
+
58
+ // go down a level in the document
59
+ // (hint: look at who calls this function to know what the contexts are)
60
+ function pushContext(state, tagName) {
61
+ var noIndent = doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.doIndent);
62
+ var newContext = {
63
+ tagName: tagName,
64
+ prev: state.context,
65
+ indent: state.context ? state.context.indent + indentUnit : 0,
66
+ lineNumber: state.lineNumber,
67
+ indented: state.indented,
68
+ noIndent: noIndent
69
+ };
70
+ state.context = newContext;
71
+ }
72
+
73
+ // go up a level in the document
74
+ function popContext(state) {
75
+ if (state.context) {
76
+ var oldContext = state.context;
77
+ state.context = oldContext.prev;
78
+ return oldContext;
79
+ }
80
+
81
+ // we shouldn't be here - it means we didn't have a context to pop
82
+ return null;
83
+ }
84
+
85
+ // return true if the current token is seperated from the tokens before it
86
+ // which means either this is the start of the line, or there is at least
87
+ // one space or tab character behind the token
88
+ // otherwise returns false
89
+ function isTokenSeparated(stream) {
90
+ return stream.sol() ||
91
+ stream.string.charAt(stream.start - 1) == " " ||
92
+ stream.string.charAt(stream.start - 1) == "\t";
93
+ }
94
+
95
+ ///////////////////////////////////////////////////////////////////////////
96
+ // context: document
97
+ //
98
+ // an XML document can contain:
99
+ // - a single declaration (if defined, it must be the very first line)
100
+ // - exactly one root element
101
+ // @todo try to actually limit the number of root elements to 1
102
+ // - zero or more comments
103
+ function parseDocument(stream, state) {
104
+ if(stream.eat("<")) {
105
+ if(stream.eat("?")) {
106
+ // processing instruction
107
+ pushContext(state, TAG_INSTRUCTION);
108
+ state.tokenize = parseProcessingInstructionStartTag;
109
+ return STYLE_INSTRUCTION;
110
+ } else if(stream.match("!--")) {
111
+ // new context: comment
112
+ pushContext(state, TAG_COMMENT);
113
+ return chain(stream, state, inBlock(STYLE_COMMENT, "-->", parseDocument));
114
+ } else if(stream.eatSpace() || stream.eol() ) {
115
+ stream.skipToEnd();
116
+ return STYLE_ERROR;
117
+ } else {
118
+ // element
119
+ state.tokenize = parseElementTagName;
120
+ return STYLE_ELEMENT_NAME;
121
+ }
122
+ }
123
+
124
+ // error on line
125
+ stream.skipToEnd();
126
+ return STYLE_ERROR;
127
+ }
128
+
129
+ ///////////////////////////////////////////////////////////////////////////
130
+ // context: XML element start-tag or end-tag
131
+ //
132
+ // - element start-tag can contain attributes
133
+ // - element start-tag may self-close (or start an element block if it doesn't)
134
+ // - element end-tag can contain only the tag name
135
+ function parseElementTagName(stream, state) {
136
+ // get the name of the tag
137
+ var startPos = stream.pos;
138
+ if(stream.match(/^[a-zA-Z_:][-a-zA-Z0-9_:.]*/)) {
139
+ // element start-tag
140
+ var tagName = stream.string.substring(startPos, stream.pos);
141
+ pushContext(state, tagName);
142
+ state.tokenize = parseElement;
143
+ return STYLE_ELEMENT_NAME;
144
+ } else if(stream.match(/^\/[a-zA-Z_:][-a-zA-Z0-9_:.]*( )*>/)) {
145
+ // element end-tag
146
+ var endTagName = stream.string.substring(startPos + 1, stream.pos - 1).trim();
147
+ var oldContext = popContext(state);
148
+ state.tokenize = state.context == null ? parseDocument : parseElementBlock;
149
+ if(oldContext == null || endTagName != oldContext.tagName) {
150
+ // the start and end tag names should match - error
151
+ return STYLE_ERROR;
152
+ }
153
+ return STYLE_ELEMENT_NAME;
154
+ } else {
155
+ // no tag name - error
156
+ state.tokenize = state.context == null ? parseDocument : parseElementBlock;
157
+ stream.eatWhile(/[^>]/);
158
+ stream.eat(">");
159
+ return STYLE_ERROR;
160
+ }
161
+
162
+ stream.skipToEnd();
163
+ return null;
164
+ }
165
+
166
+ function parseElement(stream, state) {
167
+ if(stream.match(/^\/>/)) {
168
+ // self-closing tag
169
+ popContext(state);
170
+ state.tokenize = state.context == null ? parseDocument : parseElementBlock;
171
+ return STYLE_ELEMENT_NAME;
172
+ } else if(stream.eat(/^>/)) {
173
+ state.tokenize = parseElementBlock;
174
+ return STYLE_ELEMENT_NAME;
175
+ } else if(isTokenSeparated(stream) && stream.match(/^[a-zA-Z_:][-a-zA-Z0-9_:.]*( )*=/)) {
176
+ // attribute
177
+ state.tokenize = parseAttribute;
178
+ return STYLE_ATTRIBUTE;
179
+ }
180
+
181
+ // no other options - this is an error
182
+ state.tokenize = state.context == null ? parseDocument : parseDocument;
183
+ stream.eatWhile(/[^>]/);
184
+ stream.eat(">");
185
+ return STYLE_ERROR;
186
+ }
187
+
188
+ ///////////////////////////////////////////////////////////////////////////
189
+ // context: attribute
190
+ //
191
+ // attribute values may contain everything, except:
192
+ // - the ending quote (with ' or ") - this marks the end of the value
193
+ // - the character "<" - should never appear
194
+ // - ampersand ("&") - unless it starts a reference: a string that ends with a semi-colon (";")
195
+ // ---> note: this parser is lax in what may be put into a reference string,
196
+ // ---> consult http://www.w3.org/TR/REC-xml/#NT-Reference if you want to make it tighter
197
+ function parseAttribute(stream, state) {
198
+ var quote = stream.next();
199
+ if(quote != "\"" && quote != "'") {
200
+ // attribute must be quoted
201
+ stream.skipToEnd();
202
+ state.tokenize = parseElement;
203
+ return STYLE_ERROR;
204
+ }
205
+
206
+ state.tokParams.quote = quote;
207
+ state.tokenize = parseAttributeValue;
208
+ return STYLE_WORD;
209
+ }
210
+
211
+ // @todo: find out whether this attribute value spans multiple lines,
212
+ // and if so, push a context for it in order not to indent it
213
+ // (or something of the sort..)
214
+ function parseAttributeValue(stream, state) {
215
+ var ch = "";
216
+ while(!stream.eol()) {
217
+ ch = stream.next();
218
+ if(ch == state.tokParams.quote) {
219
+ // end quote found
220
+ state.tokenize = parseElement;
221
+ return STYLE_WORD;
222
+ } else if(ch == "<") {
223
+ // can't have less-than signs in an attribute value, ever
224
+ stream.skipToEnd()
225
+ state.tokenize = parseElement;
226
+ return STYLE_ERROR;
227
+ } else if(ch == "&") {
228
+ // reference - look for a semi-colon, or return error if none found
229
+ ch = stream.next();
230
+
231
+ // make sure that semi-colon isn't right after the ampersand
232
+ if(ch == ';') {
233
+ stream.skipToEnd()
234
+ state.tokenize = parseElement;
235
+ return STYLE_ERROR;
236
+ }
237
+
238
+ // make sure no less-than characters slipped in
239
+ while(!stream.eol() && ch != ";") {
240
+ if(ch == "<") {
241
+ // can't have less-than signs in an attribute value, ever
242
+ stream.skipToEnd()
243
+ state.tokenize = parseElement;
244
+ return STYLE_ERROR;
245
+ }
246
+ ch = stream.next();
247
+ }
248
+ if(stream.eol() && ch != ";") {
249
+ // no ampersand found - error
250
+ stream.skipToEnd();
251
+ state.tokenize = parseElement;
252
+ return STYLE_ERROR;
253
+ }
254
+ }
255
+ }
256
+
257
+ // attribute value continues to next line
258
+ return STYLE_WORD;
259
+ }
260
+
261
+ ///////////////////////////////////////////////////////////////////////////
262
+ // context: element block
263
+ //
264
+ // a block can contain:
265
+ // - elements
266
+ // - text
267
+ // - CDATA sections
268
+ // - comments
269
+ function parseElementBlock(stream, state) {
270
+ if(stream.eat("<")) {
271
+ if(stream.match("?")) {
272
+ pushContext(state, TAG_INSTRUCTION);
273
+ state.tokenize = parseProcessingInstructionStartTag;
274
+ return STYLE_INSTRUCTION;
275
+ } else if(stream.match("!--")) {
276
+ // new context: comment
277
+ pushContext(state, TAG_COMMENT);
278
+ return chain(stream, state, inBlock(STYLE_COMMENT, "-->",
279
+ state.context == null ? parseDocument : parseElementBlock));
280
+ } else if(stream.match("![CDATA[")) {
281
+ // new context: CDATA section
282
+ pushContext(state, TAG_CDATA);
283
+ return chain(stream, state, inBlock(STYLE_TEXT, "]]>",
284
+ state.context == null ? parseDocument : parseElementBlock));
285
+ } else if(stream.eatSpace() || stream.eol() ) {
286
+ stream.skipToEnd();
287
+ return STYLE_ERROR;
288
+ } else {
289
+ // element
290
+ state.tokenize = parseElementTagName;
291
+ return STYLE_ELEMENT_NAME;
292
+ }
293
+ } else {
294
+ // new context: text
295
+ pushContext(state, TAG_TEXT);
296
+ state.tokenize = parseText;
297
+ return null;
298
+ }
299
+
300
+ state.tokenize = state.context == null ? parseDocument : parseElementBlock;
301
+ stream.skipToEnd();
302
+ return null;
303
+ }
304
+
305
+ function parseText(stream, state) {
306
+ stream.eatWhile(/[^<]/);
307
+ if(!stream.eol()) {
308
+ // we cannot possibly be in the document context,
309
+ // just inside an element block
310
+ popContext(state);
311
+ state.tokenize = parseElementBlock;
312
+ }
313
+ return STYLE_TEXT;
314
+ }
315
+
316
+ ///////////////////////////////////////////////////////////////////////////
317
+ // context: XML processing instructions
318
+ //
319
+ // XML processing instructions (PIs) allow documents to contain instructions for applications.
320
+ // PI format: <?name data?>
321
+ // - 'name' can be anything other than 'xml' (case-insensitive)
322
+ // - 'data' can be anything which doesn't contain '?>'
323
+ // XML declaration is a special PI (see XML declaration context below)
324
+ function parseProcessingInstructionStartTag(stream, state) {
325
+ if(stream.match("xml", true, true)) {
326
+ // xml declaration
327
+ if(state.lineNumber > 1 || stream.pos > 5) {
328
+ state.tokenize = parseDocument;
329
+ stream.skipToEnd();
330
+ return STYLE_ERROR;
331
+ } else {
332
+ state.tokenize = parseDeclarationVersion;
333
+ return STYLE_INSTRUCTION;
334
+ }
335
+ }
336
+
337
+ // regular processing instruction
338
+ if(isTokenSeparated(stream) || stream.match("?>")) {
339
+ // we have a space after the start-tag, or nothing but the end-tag
340
+ // either way - error!
341
+ state.tokenize = parseDocument;
342
+ stream.skipToEnd();
343
+ return STYLE_ERROR;
344
+ }
345
+
346
+ state.tokenize = parseProcessingInstructionBody;
347
+ return STYLE_INSTRUCTION;
348
+ }
349
+
350
+ function parseProcessingInstructionBody(stream, state) {
351
+ stream.eatWhile(/[^?]/);
352
+ if(stream.eat("?")) {
353
+ if(stream.eat(">")) {
354
+ popContext(state);
355
+ state.tokenize = state.context == null ? parseDocument : parseElementBlock;
356
+ }
357
+ }
358
+ return STYLE_INSTRUCTION;
359
+ }
360
+
361
+
362
+ ///////////////////////////////////////////////////////////////////////////
363
+ // context: XML declaration
364
+ //
365
+ // XML declaration is of the following format:
366
+ // <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
367
+ // - must start at the first character of the first line
368
+ // - may span multiple lines
369
+ // - must include 'version'
370
+ // - may include 'encoding' and 'standalone' (in that order after 'version')
371
+ // - attribute names must be lowercase
372
+ // - cannot contain anything else on the line
373
+ function parseDeclarationVersion(stream, state) {
374
+ state.tokenize = parseDeclarationEncoding;
375
+
376
+ if(isTokenSeparated(stream) && stream.match(/^version( )*=( )*"([a-zA-Z0-9_.:]|\-)+"/)) {
377
+ return STYLE_INSTRUCTION;
378
+ }
379
+ stream.skipToEnd();
380
+ return STYLE_ERROR;
381
+ }
382
+
383
+ function parseDeclarationEncoding(stream, state) {
384
+ state.tokenize = parseDeclarationStandalone;
385
+
386
+ if(isTokenSeparated(stream) && stream.match(/^encoding( )*=( )*"[A-Za-z]([A-Za-z0-9._]|\-)*"/)) {
387
+ return STYLE_INSTRUCTION;
388
+ }
389
+ return null;
390
+ }
391
+
392
+ function parseDeclarationStandalone(stream, state) {
393
+ state.tokenize = parseDeclarationEndTag;
394
+
395
+ if(isTokenSeparated(stream) && stream.match(/^standalone( )*=( )*"(yes|no)"/)) {
396
+ return STYLE_INSTRUCTION;
397
+ }
398
+ return null;
399
+ }
400
+
401
+ function parseDeclarationEndTag(stream, state) {
402
+ state.tokenize = parseDocument;
403
+
404
+ if(stream.match("?>") && stream.eol()) {
405
+ popContext(state);
406
+ return STYLE_INSTRUCTION;
407
+ }
408
+ stream.skipToEnd();
409
+ return STYLE_ERROR;
410
+ }
411
+
412
+ ///////////////////////////////////////////////////////////////////////////
413
+ // returned object
414
+ return {
415
+ electricChars: "/",
416
+
417
+ startState: function() {
418
+ return {
419
+ tokenize: parseDocument,
420
+ tokParams: {},
421
+ lineNumber: 0,
422
+ lineError: false,
423
+ context: null,
424
+ indented: 0
425
+ };
426
+ },
427
+
428
+ token: function(stream, state) {
429
+ if(stream.sol()) {
430
+ // initialize a new line
431
+ state.lineNumber++;
432
+ state.lineError = false;
433
+ state.indented = stream.indentation();
434
+ }
435
+
436
+ // eat all (the spaces) you can
437
+ if(stream.eatSpace()) return null;
438
+
439
+ // run the current tokenize function, according to the state
440
+ var style = state.tokenize(stream, state);
441
+
442
+ // is there an error somewhere in the line?
443
+ state.lineError = (state.lineError || style == "error");
444
+
445
+ return style;
446
+ },
447
+
448
+ blankLine: function(state) {
449
+ // blank lines are lines too!
450
+ state.lineNumber++;
451
+ state.lineError = false;
452
+ },
453
+
454
+ indent: function(state, textAfter) {
455
+ if(state.context) {
456
+ if(state.context.noIndent == true) {
457
+ // do not indent - no return value at all
458
+ return;
459
+ }
460
+ if(textAfter.match(/^<\/.*/)) {
461
+ // eng-tag - indent back to last context
462
+ return state.context.indent;
463
+ }
464
+ // indent to last context + regular indent unit
465
+ return state.context.indent + indentUnit;
466
+ }
467
+ return 0;
468
+ },
469
+
470
+ compareStates: function(a, b) {
471
+ if (a.indented != b.indented) return false;
472
+ for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
473
+ if (!ca || !cb) return ca == cb;
474
+ if (ca.tagName != cb.tagName) return false;
475
+ }
476
+ }
477
+ };
478
+ });
479
+
480
+ CodeMirror.defineMIME("application/xml", "purexml");
481
+ CodeMirror.defineMIME("text/xml", "purexml");
tinymce-plugins/cmseditor/js/theme/default.css ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .cm-s-default span.cm-keyword {color: #708;}
2
+ .cm-s-default span.cm-atom {color: #219;}
3
+ .cm-s-default span.cm-number {color: #164;}
4
+ .cm-s-default span.cm-def {color: #00f;}
5
+ .cm-s-default span.cm-variable {color: black;}
6
+ .cm-s-default span.cm-variable-2 {color: #05a;}
7
+ .cm-s-default span.cm-variable-3 {color: #0a5;}
8
+ .cm-s-default span.cm-property {color: black;}
9
+ .cm-s-default span.cm-operator {color: black;}
10
+ .cm-s-default span.cm-comment {color: #a50;}
11
+ .cm-s-default span.cm-string {color: #a11;}
12
+ .cm-s-default span.cm-string-2 {color: #f50;}
13
+ .cm-s-default span.cm-meta {color: #555;}
14
+ .cm-s-default span.cm-error {color: #f00;}
15
+ .cm-s-default span.cm-qualifier {color: #555;}
16
+ .cm-s-default span.cm-builtin {color: #30a;}
17
+ .cm-s-default span.cm-bracket {color: #cc7;}
18
+ .cm-s-default span.cm-tag {color: #170;}
19
+ .cm-s-default span.cm-attribute {color: #00c;}
tinymce-plugins/cmseditor/js/theme/elegant.css ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ .cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;}
2
+ .cm-s-elegant span.cm-comment {color: #262;font-style: italic;}
3
+ .cm-s-elegant span.cm-meta {color: #555;font-style: italic;}
4
+ .cm-s-elegant span.cm-variable {color: black;}
5
+ .cm-s-elegant span.cm-variable-2 {color: #b11;}
6
+ .cm-s-elegant span.cm-qualifier {color: #555;}
7
+ .cm-s-elegant span.cm-keyword {color: #730;}
8
+ .cm-s-elegant span.cm-builtin {color: #30a;}
9
+ .cm-s-elegant span.cm-error {background-color: #fdd;}
tinymce-plugins/cmseditor/js/theme/neat.css ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ .cm-s-neat span.cm-comment { color: #a86; }
2
+ .cm-s-neat span.cm-keyword { font-weight: bold; color: blue; }
3
+ .cm-s-neat span.cm-string { color: #a22; }
4
+ .cm-s-neat span.cm-builtin { font-weight: bold; color: #077; }
5
+ .cm-s-neat span.cm-special { font-weight: bold; color: #0aa; }
6
+ .cm-s-neat span.cm-variable { color: black; }
7
+ .cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }
8
+ .cm-s-neat span.cm-meta {color: #555;}
tinymce-plugins/cmseditor/js/theme/night.css ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Loosely based on the Midnight Textmate theme */
2
+
3
+ .cm-s-night { background: #0a001f; color: #f8f8f8; }
4
+ .cm-s-night span.CodeMirror-selected { background: #a8f !important; }
5
+ .cm-s-night .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
6
+ .cm-s-night .CodeMirror-gutter-text { color: #f8f8f8; }
7
+ .cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; }
8
+
9
+ .cm-s-night span.cm-comment { color: #6900a1; }
10
+ .cm-s-night span.cm-atom { color: #845dc4; }
11
+ .cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }
12
+ .cm-s-night span.cm-keyword { color: #599eff; }
13
+ .cm-s-night span.cm-string { color: #37f14a; }
14
+ .cm-s-night span.cm-meta { color: #7678e2; }
15
+ .cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
16
+ .cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }
17
+ .cm-s-night span.cm-error { color: #9d1e15; }
18
+ .cm-s-night span.cm-bracket { color: #8da6ce; }
19
+ .cm-s-night span.cm-comment { color: #6900a1; }
20
+ .cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
tinymce-plugins/cmseditor/langs/en.js ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ tinyMCE.addI18n('en.example',{
2
+ desc : 'This is just a template button'
3
+ });
tinymce-plugins/cmseditor/langs/en_dlg.js ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ tinyMCE.addI18n('en.example_dlg',{
2
+ title : 'This is just a example title'
3
+ });
wpbe-options.php CHANGED
@@ -1,87 +1,55 @@
1
  <div class="wrap">
2
- <h2><?php _e('Email options', 'wp-better-emails'); ?></h2>
3
 
4
  <form method="post" action="options.php" id="wpbe_options_form">
5
  <?php settings_fields('wpbe_full_options'); ?>
6
- <?php $options = get_option('wpbe_options'); ?>
7
- <div id="wpbe_options_tabs">
8
- <ul class="wpbe_tabs_titles">
9
- <li><a href="#tab1"><?php _e('Sender options', 'wp-better-emails'); ?></a></li>
10
- <li><a href="#tab2"><?php _e('Template options', 'wp-better-emails'); ?></a></li>
11
- <li><a href="#tab3"><?php _e('Help & support', 'wp-better-emails'); ?></a></li>
12
- </ul>
13
- <div id="tab1" class="wpbe_tab_content">
14
- <p><?php _e('Change the Wordpress default behavior when sending emails to users (i.e. comment notifications, lost password, etc.), set your own sender name and email address.', 'wp-better-emails'); ?></p>
15
- <table class="form-table">
16
- <tr valign="top" class="form-field">
17
- <th scope="row"><label for="wpbe_from_name"><?php _e('From name', 'wp-better-emails'); ?></label></th>
18
- <td><input type="text" id="wpbe_from_name" class="regular-text" name="wpbe_options[from_name]" value="<?php echo $options['from_name']; ?>" /></td>
19
- </tr>
20
- <tr valign="top" class="form-field">
21
- <th scope="row"><label for="wpbe_from_email"><?php _e('From email address', 'wp-better-emails'); ?></label></th>
22
- <td><input type="text" id="wpbe_from_email" class="regular-text" name="wpbe_options[from_email]" value="<?php echo $options['from_email']; ?>" /></td>
23
- </tr>
24
- </table>
25
- </div>
26
- <div id="tab2" class="wpbe_tab_content">
27
- <table class="form-table">
28
- <tr valign="top">
29
- <th role="row"><?php _e('Template variables', 'wp-better-emails'); ?></th>
30
- <td>
31
- <p><?php _e('Some dynamic tags can be included in your email template :', 'wp-better-emails'); ?></p>
32
- <ul>
33
- <li><?php _e('<strong>%content%</strong> : will be replaced by the message content.', 'wp-better-emails'); ?><br />
34
- <span class="description"><?php _e('NOTE: The content tag is <strong>required</strong>, WP Better Emails will be automatically desactivated if no content tag is found.', 'wp-better-emails'); ?></span></li>
35
- <li><?php _e('<strong>%blog_url%</strong> : will be replaced by your blog URL.', 'wp-better-emails'); ?></li>
36
- <li><?php _e('<strong>%blog_name%</strong> : will be replaced by your blog name.', 'wp-better-emails'); ?></li>
37
- <li><?php _e('<strong>%blog_description%</strong> : will be replaced by your blog description.', 'wp-better-emails'); ?></li>
38
- <li><?php _e('<strong>%admin_email%</strong> : will be replaced by admin email.', 'wp-better-emails'); ?></li>
39
- <li><?php _e('<strong>%date%</strong> : will be replaced by current date, as formatted in <a href="options-general.php">general options</a>.', 'wp-better-emails'); ?></li>
40
- <li><?php _e('<strong>%time%</strong> : will be replaced by current time, as formatted in <a href="options-general.php">general options</a>.', 'wp-better-emails'); ?></li>
41
- </ul>
42
- </td>
43
- </tr>
44
- <tr valign="top">
45
- <th scope="row">
46
- <label for="wpbe_template"><?php _e('HTML Template', 'wp-better-emails'); ?></label>
47
- </th>
48
- <td>
49
- <textarea id="wpbe_template" name="wpbe_options[template]" cols="80" rows="20"><?php echo $options['template']; ?></textarea>
50
- <p>
51
- <label for="wpbe_preview_email"><?php _e('Send an email preview to', 'wp-better-emails'); ?></label>
52
- <input type="hidden" id="wpbe_nonce_preview" name="_ajax_nonce" value="<?php echo wp_create_nonce( 'email_preview' ); ?>" />
53
- <input type="text" id="wpbe_preview_email" name="wpbe_preview_email" value="<?php echo get_option('admin_email'); ?>" />
54
- <a href="javascript:void(0);" class="button" id="wpbe_send_preview"><?php _e('Send', 'wp-better-emails'); ?></a><span id="loading"></span>
55
- <img src="<?php echo get_option('siteurl'); ?>/wp-admin/images/wpspin_light.gif" id="ajax-loading" style="visibility: hidden;" alt="Loading" />
56
- <br /><span class="description"><?php __('You must save your template before sending an email preview.', 'wp-better-emails'); ?></span>
57
- <span id="wpbe_preview_message"></span>
58
- </p>
59
- </td>
60
- </tr>
61
- </table>
62
- </div>
63
- <div id="tab3" class="wpbe_tab_content">
64
- <h3><?php _e('Designing & coding email templates', 'wp-better-emails'); ?></h3>
65
- <p><?php _e('Here are a few ressources about email formatting :', 'wp-better-emails') ?></p>
66
- <ul>
67
- <li><a href="http://www.campaignmonitor.com/resources/" target="_blank">http://www.campaignmonitor.com/resources/</a></li>
68
- <li><a href="http://articles.sitepoint.com/article/code-html-email-newsletters/" target="_blank">http://articles.sitepoint.com/article/code-html-email-newsletters/</a></li>
69
- </ul>
70
- <h3><?php _e('Converting HTML templates', 'wp-better-emails'); ?></h3>
71
- <p><?php _e('Coding HTML for emails requires CSS styles to be inline. Here\'s a tool powered by MailChimp that will convert your styles placed in the <code>&lt;head&gt;</code> tag to inline : ', 'wp-better-emails'); ?></p>
72
- <ul>
73
- <li><?php _e('<a href="http://www.mailchimp.com/labs/inlinecss.php" target="_blank">http://www.mailchimp.com/labs/inlinecss.php</a>', 'wp-better-emails'); ?></li>
74
- </ul>
75
- <h3><?php _e('Requests & Bug report', 'wp-better-emails'); ?></h3>
76
- <p><?php _e('If you have any idea to improve this plugin or any bug to report, please email me at : <a href="mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]">plugins@artyshow-studio.fr</a>', 'wp-better-emails'); ?></p>
77
- <h3><?php _e('Credits', 'wp-better-emails'); ?></h3>
78
- <ul>
79
- <li><?php _e('MarkItUp! : jQuery HTML editor <a href="http://markitup.jaysalvat.com/home/" target="_blank">http://markitup.jaysalvat.com/home/</a>', 'wp-better-emails'); ?></li>
80
- </ul>
81
- </div>
82
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  <p class="submit">
84
  <input type="submit" class="button-primary" value="<?php _e('Save Changes', 'wp-better-emails') ?>" />
85
  </p>
86
  </form>
 
 
 
 
 
 
 
87
  </div>
1
  <div class="wrap">
2
+ <h2><?php _e('Email settings', 'wp-better-emails'); ?></h2>
3
 
4
  <form method="post" action="options.php" id="wpbe_options_form">
5
  <?php settings_fields('wpbe_full_options'); ?>
6
+
7
+ <!-- Sender options -->
8
+ <p style="margin-bottom: 0;"><?php _e('Set your own sender name and email address. Default Wordpress values will be used if empty.', 'wp-better-emails'); ?></p>
9
+ <table class="form-table">
10
+ <tr valign="top">
11
+ <th scope="row"><label for="wpbe_from_name"><?php _e('Name', 'wp-better-emails'); ?></label></th>
12
+ <td><input type="text" id="wpbe_from_name" class="regular-text" name="wpbe_options[from_name]" value="<?php esc_attr_e($this->options['from_name']); ?>" /></td>
13
+ </tr>
14
+ <tr valign="top">
15
+ <th scope="row"><label for="wpbe_from_email"><?php _e('Email address', 'wp-better-emails'); ?></label></th>
16
+ <td><input type="text" id="wpbe_from_email" class="regular-text" name="wpbe_options[from_email]" value="<?php echo esc_attr_e($this->options['from_email']); ?>" /></td>
17
+ </tr>
18
+ </table>
19
+
20
+ <!-- Template -->
21
+ <h3 class="wpbe_title"><?php _e('HTML Template', 'wp-better-emails'); ?>
22
+ <?php if( version_compare($wp_version, '3.1', '>') ): ?>
23
+ <a class="thickbox button" title="<?php esc_attr_e('Live template preview', 'wp-better-emails'); ?>" id="wpbe_preview_template" href="<?php echo plugins_url('preview.html?keepThis=true&TB_iframe=true&height=400&width=700', __FILE__); ?>"><?php _e('Live preview', 'wp-better-emails'); ?></a>
24
+ <?php endif; ?>
25
+ </h3>
26
+ <p><?php _e('Edit the HTML email template if you want to customize it. You might have a look at the <a href="#" id="wpbe_help">help tab</a> for further information.', 'wp-better-emails'); ?></p>
27
+ <div id="wpbe_template_container">
28
+ <?php $this->template_editor() ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  </div>
30
+ <div id="wpbe_preview_message"></div>
31
+ <table class="form-table">
32
+ <tr valign="top">
33
+ <th scope="row">
34
+ <label for="wpbe_email_preview_field"><?php _e('Send an email preview to', 'wp-better-emails'); ?></label>
35
+ </th>
36
+ <td>
37
+ <input type="text" id="wpbe_email_preview_field" name="wpbe_preview_email" class="regular-text" value="<?php esc_attr_e(get_option('admin_email')); ?>" />
38
+ <a href="javascript:void(0);" class="button" id="wpbe_send_preview"><?php _e('Send', 'wp-better-emails'); ?></a><span id="wpbe_loading"></span>
39
+ <img src="<?php echo admin_url('images/wpspin_light.gif'); ?>" id="wpbe_ajax_loading" style="visibility: hidden;" alt="Loading" />
40
+ <br /><span class="description"><?php _e('You must save your template before sending an email preview.', 'wp-better-emails'); ?></span>
41
+ </td>
42
+ </tr>
43
+ </table>
44
  <p class="submit">
45
  <input type="submit" class="button-primary" value="<?php _e('Save Changes', 'wp-better-emails') ?>" />
46
  </p>
47
  </form>
48
+ <!-- Support -->
49
+ <div id="wpbe_support">
50
+ <h3><?php _e('Support & bug report', 'wp-better-emails'); ?></h3>
51
+ <p><?php _e('If you have any idea to improve this plugin or any bug to report, please email me at : <a href="mailto:plugins@artyshow-studio.fr?subject=[wp-better-emails]">plugins@artyshow-studio.fr</a>', 'wp-better-emails'); ?></p>
52
+ <?php $donation_link = 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=7Q49VJQNRCQ8E&lc=FR&item_name=ArtyShow&item_number=wp%2dbetter%2demails&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted'; ?>
53
+ <p><?php printf(__('You like this plugin ? You use it in a business context ? Please, consider a <a href="%s" target="_blank" rel="external">donation</a>.', 'wp-better-emails'), $donation_link ); ?></p>
54
+ </div>
55
  </div>
wpbe.php CHANGED
@@ -1,334 +1,528 @@
1
  <?php
2
  /*
3
- Plugin Name: WP Better Emails
4
- Plugin URI: http://wordpress.org/extend/plugins/wp-better-emails/
5
- Description: Beautify the default text/plain WP mails into fully customizable HTML emails.
6
- Version: 0.1.3
7
- Author: ArtyShow
8
- Author URI: http://wordpress.org/extend/plugins/wp-better-emails/
9
- */
10
-
11
- /**
12
- * Hooks & actions
13
  */
14
- register_activation_hook(__FILE__,'wpbe_register_options');
15
- add_action('init', 'wpbe_init_textdomain');
16
- add_action('admin_init', 'wpbe_plugin_init');
17
- add_action('admin_menu', 'wpbe_add_settings_page');
18
- add_action('wp_ajax_send_preview', 'wpbe_ajax_send_preview');
19
- add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'wpbe_add_settings_link');
20
- add_filter('wp_mail_from_name', 'wpbe_set_from_name');
21
- add_filter('wp_mail_from', 'wpbe_set_from_email');
22
- add_filter('wp_mail_content_type', 'wpbe_set_content_type');
23
-
24
- /**
25
- * Load the text domain for i18n
26
- *
27
- * @since 0.1.1
28
- */
29
- function wpbe_init_textdomain() {
30
- load_plugin_textdomain( 'wp-better-emails', null, basename(dirname(__FILE__)) . '/langs/' );
31
- }
32
 
33
- /**
34
- * Init plugin options to white list our options & register our script
35
- *
36
- * @since 0.1
37
- */
38
- function wpbe_plugin_init() {
39
- register_setting('wpbe_full_options', 'wpbe_options', 'wpbe_options_validate');
40
- wp_register_script('wpbe-admin-script', plugins_url('js/wpbe-admin-script.js', __FILE__), array('jquery'), null, true);
41
- wp_register_script('jquery-cookie', plugins_url('js/jquery.cookie.js', __FILE__), array('jquery'), null, true);
42
- wp_register_script('jquery-markitup', plugins_url('markitup/jquery.markitup.js', __FILE__), array('jquery'), null, true);
43
- wp_register_script('markitup-set', plugins_url('markitup/sets/html/set.js', __FILE__), array('jquery'), null, true);
44
- wp_register_style('wpbe-admin-style', plugins_url('css/wpbe-admin-style.css', __FILE__));
45
- wp_register_style('markitup-skin', plugins_url('markitup/skins/simple/style.css', __FILE__));
46
- wp_register_style('markitup-skin-toolbar', plugins_url('markitup/sets/html/style.css', __FILE__));
47
- }
48
 
49
- /**
50
- * Add a settings link in the plugins page
51
- *
52
- * @since 0.1
53
- *
54
- * @param array $links Plugin links
55
- * @return array Plugins links with settings added
56
- */
57
- function wpbe_add_settings_link( $links ) {
58
- $links[] = '<a href="options-general.php?page=wpbe_options">' . __('Settings', 'wp-better-emails') . '</a>';
59
- return $links;
60
- }
61
 
62
- /**
63
- * Register options on plugin activation
64
- *
65
- * @since 0.1
66
  */
67
- function wpbe_register_options() {
68
- global $wp_version;
69
- // Prevent activation if requirements are not met
70
- // WP 2.8 required
71
- if (version_compare($wp_version, '2.8', '<=')) {
72
- if (function_exists('deactivate_plugins')) {
73
- deactivate_plugins(__FILE__);
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  }
75
- die(__('WP Better Emails requires WordPress 2.8 or newer.', 'wp-better-emails'));
76
- }
77
 
78
- $template = '';
79
- @include('email_template.php');
80
- $domain = strtolower( $_SERVER['SERVER_NAME'] );
81
- if ( substr( $domain, 0, 4 ) == 'www.' ) {
82
- $domain = substr( $domain, 4 );
83
- }
84
- $title = get_option('blogname');
85
- $wpbe_options = array (
86
- 'from_email' => 'wordpress@' . $domain,
87
- 'from_name' => $title,
88
- 'template' => $template
89
- );
90
- if( get_option('wpbe_options') == null ) {
91
- add_option('wpbe_options', $wpbe_options);
92
- }
93
- }
94
 
95
- /**
96
- * Get options
97
- */
98
- $wpbe_options = get_option('wpbe_options');
99
 
100
- /**
101
- * Add option page to the built in settings menu
102
- *
103
- * @since 0.1
104
- */
105
- function wpbe_add_settings_page() {
106
- $page = add_options_page(__('Email Options', 'wp-better-emails'), __('Email Options', 'wp-better-emails'), 'administrator', 'wpbe_options', 'wpbe_options_page');
107
- add_action('admin_print_scripts-' . $page, 'wpbe_admin_print_script');
108
- add_action('admin_print_styles-' . $page, 'wpbe_admin_print_style');
109
- }
110
 
111
- /**
112
- * Enqueue the script to display it on the options page
113
- *
114
- * @since 0.1
115
- */
116
- function wpbe_admin_print_script() {
117
- //wp_enqueue_script('thickbox');
118
- wp_enqueue_script('jquery-cookie');
119
- wp_enqueue_script('jquery-ui-core');
120
- wp_enqueue_script('jquery-ui-tabs');
121
- wp_enqueue_script('jquery-markitup');
122
- wp_enqueue_script('markitup-set');
123
- wp_enqueue_script('wpbe-admin-script');
124
- }
 
125
 
126
- /**
127
- * Enqueue the style to display it on the options page
128
- *
129
- * @since 0.1
130
- */
131
- function wpbe_admin_print_style() {
132
- wp_enqueue_style('wpbe-admin-style');
133
- //wp_enqueue_style('thickbox');
134
- wp_enqueue_style('markitup-skin');
135
- wp_enqueue_style('markitup-skin-toolbar');
136
- }
137
 
138
- /**
139
- * Include admin options page
140
- *
141
- * @since 0.1
142
- */
143
- function wpbe_options_page() {
144
- include('wpbe-options.php');
145
- }
 
 
 
 
 
 
 
 
146
 
147
- /**
148
- * Sanitize each option value
149
- *
150
- * @since 0.1
151
- * @param array $input The options returned by the options page
152
- * @return array $input Sanitized values
153
- */
154
- function wpbe_options_validate( $input ) {
 
 
155
 
156
- $from_email = strtolower($input['from_email']);
 
 
 
 
 
 
 
 
 
 
 
157
 
158
- // Checking emails
159
- if ( !empty($from_email) && !is_email($from_email) ) {
160
- add_settings_error('wpbe_options', 'settings_updated', __('Please enter a valid sender email address.', 'wp-better-emails'));
161
- $input['from_email'] = '';
162
- } else {
163
- $input['from_email'] = sanitize_email($from_email);
164
- }
 
 
 
 
 
 
 
 
 
165
 
166
- // Check name
167
- $input['from_name'] = esc_html($input['from_name']);
 
 
 
 
 
 
 
 
168
 
169
- if( empty($input['template']) )
170
- add_settings_error('wpbe_options', 'settings_updated', __('Template is empty', 'wp-better-emails'));
171
- // Check if %content% tag is the template body
172
- elseif ( strpos( $input['template'], '%content%') === false )
173
- add_settings_error('wpbe_options', 'settings_updated', __('No content tag found. Please insert the %content% tag in your template', 'wp-better-emails'));
174
- $input['template'] = $input['template'];
 
 
 
 
 
 
 
175
 
176
- return $input;
177
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
- /**
180
- * Send a email preview to test your template
181
- *
182
- * @since 0.1
183
- * @param string $email
184
- */
185
- function wpbe_ajax_send_preview( $email ) {
186
- check_ajax_referer( 'email_preview' );
187
- $preview_email = sanitize_email($_POST['preview_email']);
188
- if( empty($preview_email) )
189
- die( '<div class="error"><p>' . __('Please enter an email', 'wp-better-emails') . '</p></div>' );
190
- if( !is_email($preview_email) )
191
- die( '<div class="error"><p>' . __('Please enter a valid email', 'wp-better-emails') . '</p></div>' );
192
- $message = __('Hey !', 'wp-better-emails');
193
- $message .= "\r\n\r\n";
194
- $message .= __('This is a sample email to test your template.', 'wp-better-emails');
195
- $message .= "\r\n\r\n";
196
- $message .= __('If you\'re not skilled in HTML/CSS email coding, I strongly recommend to leave the default template as it is. It has been tested on various and popular email clients like Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, and many more. ', 'wp-better-emails');
197
- $message .= "\r\n\r\n";
198
- $message .= __('If you have any problem or any suggestions to improve this plugin, please let me know.', 'wp-better-emails');
199
- $message .= "\r\n\r\n";
200
- if( wp_mail( $preview_email, '[' . wp_specialchars_decode(get_option('blogname'), ENT_QUOTES) . '] - ' . __('Email template preview', 'wp-better-emails'), $message) )
201
- die('<div class="updated"><p>' . __('An email preview has been successfully sent to ' . $preview_email, 'wp-better-emails') . '</p></div>');
202
- else
203
- die( '<div class="error"><p>' . __('An error occured while sending email. Please check your server configuration.', 'wp-better-emails') . '</p></div>' );
204
- }
205
 
206
- /**
207
- * Add the HTML template to the message body.
208
- * Looks for %message% into the template and replace it with the message
209
- *
210
- * @since 0.1
211
- * @global array $wpbe_options
212
- * @param string $body The message to templatize
213
- * @return string $email The email surrounded by template
214
- */
215
- function wpbe_email_templatize( $body ) {
216
- global $wpbe_options;
217
- $template = '';
218
- if( isset ($wpbe_options['template']) && !empty($wpbe_options['template']) )
219
- $template .= $wpbe_options['template'];
220
- $html_email = str_replace('%content%', $body, $template);
221
- return $html_email;
222
- }
223
 
224
- /**
225
- * Replace variables in the template
226
- *
227
- * @since 0.1
228
- * @param string $template Template with variables
229
- * @return string Template with variables replaced
230
- */
231
- function wpbe_template_replacement( $template ) {
232
- $to_replace = array(
233
- 'blog_url' => get_option('siteurl'),
234
- 'blog_name' => get_option('blogname'),
235
- 'blog_description' => get_option('blogdescription'),
236
- 'admin_email' => get_option('admin_email'),
237
- 'date' => date_i18n( get_option('date_format') ),
238
- 'time' => date_i18n( get_option('time_format') )
239
- );
240
- foreach ( $to_replace as $tag => $var ) {
241
- $template = str_replace('%' . $tag . '%', $var, $template);
242
- }
243
- return $template;
244
- }
245
 
246
- /**
247
- * Checks the WP Better Emails options to activate the new mail function
248
- *
249
- * @since 0.1
250
- * @return bool
251
- */
252
- function wpbe_check_template() {
253
- global $wpbe_options;
254
- if ( strpos( $wpbe_options['template'], '%content%') === false || empty($wpbe_options['template']) )
255
- return false;
256
- return true;
257
- }
258
 
259
- /**
260
- * Replaces sender email if set & valid
261
- *
262
- * @since 0.1
263
- * @global array $wpbe_options
264
- * @param string $from_email
265
- * @return string
266
- */
267
- function wpbe_set_from_email( $from_email ) {
268
- global $wpbe_options;
269
- if ( !empty($wpbe_options['from_email']) && is_email( $wpbe_options['from_email'] ) )
270
- return $wpbe_options['from_email'];
271
- return $from_email;
272
- }
273
 
274
- /**
275
- * Replaces sender name if set
276
- *
277
- * @since 0.1
278
- * @global array $wpbe_options
279
- * @param string $from_name
280
- * @return string
281
- */
282
- function wpbe_set_from_name( $from_name ) {
283
- global $wpbe_options;
284
- if ( !empty($wpbe_options['from_name']) )
285
- return wp_specialchars_decode($wpbe_options['from_name'], ENT_QUOTES);
286
- return $from_name;
287
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
 
289
- /**
290
- * Always set content type to HTML
291
- *
292
- * @since 0.1
293
- * @param string $content_type
294
- * @return string $content_type
295
- */
296
- function wpbe_set_content_type( $content_type ) {
297
- // Only convert if the message is text/plain and the template is ok
298
- if( $content_type == 'text/plain' && wpbe_check_template() === true ) {
299
- add_action('phpmailer_init', 'wpbe_send_html');
300
- return $content_type = 'text/html';
301
  }
302
- return $content_type;
303
- }
304
 
305
- /**
306
- * Add the email template and set it multipart
307
- *
308
- * @since 0.1
309
- * @param object $phpmailer
310
- */
311
- function wpbe_send_html( $phpmailer ) {
312
- // Set the original plain text message
313
- $phpmailer->AltBody = wp_specialchars_decode($phpmailer->Body, ENT_QUOTES);
314
- // Clean < and > around text links in WP 3.1
315
- $phpmailer->Body = wpbe_esc_textlinks($phpmailer->Body);
316
- // Convert line breaks & make links clickable
317
- $phpmailer->Body = nl2br ( make_clickable ($phpmailer->Body) );
318
- // Add template to message
319
- $phpmailer->Body = wpbe_email_templatize($phpmailer->Body);
320
- // Replace variables in email
321
- $phpmailer->Body = wpbe_template_replacement($phpmailer->Body);
322
  }
323
 
324
- /**
325
- * Replaces the < & > of the 3.1 email text links
326
- *
327
- * @since 0.1.2
328
- * @param string $body
329
- * @return string
330
- */
331
- function wpbe_esc_textlinks( $body ) {
332
- return preg_replace('#<(https?://[^*]+)>#', '$1', $body);
333
  }
334
  ?>
1
  <?php
2
  /*
3
+ Plugin Name: WP Better Emails
4
+ Plugin URI: http://wordpress.org/extend/plugins/wp-better-emails/
5
+ Description: Beautify the default text/plain WP mails into fully customizable HTML emails.
6
+ Version: 0.2
7
+ Author: ArtyShow
8
+ Author URI: http://wordpress.org/extend/plugins/wp-better-emails/
9
+ License: GPLv2
 
 
 
10
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ /*
13
+ Copyright (c) 2011 Nicolas Lemoine.
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ This program is free software; you can redistribute it and/or
16
+ modify it under the terms of the GNU General Public License
17
+ as published by the Free Software Foundation; either version 2
18
+ of the License, or (at your option) any later version.
19
+
20
+ This program is distributed in the hope that it will be useful,
21
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
+ GNU General Public License for more details.
 
 
 
24
 
25
+ You should have received a copy of the GNU General Public License
26
+ along with this program; if not, write to the Free Software
27
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
28
  */
29
+
30
+ if (!class_exists('WP_Better_Emails')) {
31
+
32
+ if (!defined('WPBE_JS_URL'))
33
+ define('WPBE_JS_URL', plugin_dir_url(__FILE__) . 'js');
34
+ if (!defined('WPBE_CSS_URL'))
35
+ define('WPBE_CSS_URL', plugin_dir_url(__FILE__) . 'css');
36
+
37
+ class WP_Better_Emails {
38
+
39
+ var $options = array();
40
+ var $page = '';
41
+
42
+ /**
43
+ * Construct function (old way)
44
+ *
45
+ * @since 0.2
46
+ */
47
+ function WP_Better_Emails() {
48
+ $this->__construct();
49
  }
 
 
50
 
51
+ /**
52
+ * Construct function
53
+ *
54
+ * @since 0.2
55
+ */
56
+ function __construct() {
57
+ global $wp_version;
58
+
59
+ $this->get_options();
60
+
61
+ // Front end filter
62
+ add_filter('wp_mail_from_name', array(&$this, 'set_from_name'));
63
+ add_filter('wp_mail_from', array($this, 'set_from_email'));
64
+ add_filter('wp_mail_content_type', array(&$this, 'set_content_type'));
 
 
65
 
66
+ if (!is_admin())
67
+ return;
 
 
68
 
69
+ // Load translations
70
+ load_plugin_textdomain('wp-better-emails', null, basename(dirname(__FILE__)) . '/langs/');
 
 
 
 
 
 
 
 
71
 
72
+ // Actions
73
+ add_action('admin_init', array(&$this, 'init'));
74
+ add_action('admin_menu', array(&$this, 'admin_menu'));
75
+ add_action('wp_ajax_send_preview', array(&$this, 'ajax_send_preview'));
76
+ add_action("admin_head", array(&$this, 'load_wp_tiny_mce'));
77
+ if( version_compare($wp_version, '3.2', '<') && version_compare($wp_version, '3.0', '>') )
78
+ add_action( 'admin_print_footer_scripts', 'wp_tiny_mce_preload_dialogs');
79
+
80
+ // Filters
81
+ add_filter('plugin_action_links_' . plugin_basename(__FILE__), array(&$this, 'settings_link'));
82
+ add_filter('contextual_help', array(&$this, 'contextual_help'), 10, 3);
83
+ add_filter('mce_external_plugins', array(&$this, 'tinymce_plugins'));
84
+ add_filter('mce_buttons', array(&$this, 'tinymce_buttons'));
85
+ add_filter('tiny_mce_before_init', array(&$this, 'tinymce_config'));
86
+ }
87
 
88
+ /**
89
+ * Get recorded options
90
+ *
91
+ * @since 0.2
92
+ */
93
+ function get_options() {
94
+ $this->options = get_option('wpbe_options');
95
+ }
 
 
 
96
 
97
+ /**
98
+ * Set the default options
99
+ *
100
+ * @since 0.2
101
+ */
102
+ function set_options() {
103
+ $template = '';
104
+ @require('templates/template-1.php');
105
+ $this->options = array(
106
+ 'from_email' => '',
107
+ 'from_name' => '',
108
+ 'template' => $template
109
+ );
110
+ if (get_option('wpbe_options') == null)
111
+ add_option('wpbe_options', $this->options);
112
+ }
113
 
114
+ /**
115
+ * Init plugin options to white list our options & register our script
116
+ *
117
+ * @since 0.1
118
+ */
119
+ function init() {
120
+ register_setting('wpbe_full_options', 'wpbe_options', array(&$this, 'validate_options'));
121
+ wp_register_script('wpbe-admin-script', WPBE_JS_URL . '/wpbe-admin-script.js', array('jquery', 'thickbox'), null, true);
122
+ wp_register_style('wpbe-admin-style', WPBE_CSS_URL . '/wpbe-admin-style.css');
123
+ }
124
 
125
+ /**
126
+ * Settings link in the plugins page
127
+ *
128
+ * @since 0.1
129
+ *
130
+ * @param array $links Plugin links
131
+ * @return array Plugins links with settings added
132
+ */
133
+ function settings_link($links) {
134
+ $links[] = '<a href="options-general.php?page=wpbe_options">' . __('Settings', 'wp-better-emails') . '</a>';
135
+ return $links;
136
+ }
137
 
138
+ /**
139
+ * Record options on plugin activation
140
+ *
141
+ * @since 0.1
142
+ * @global $wp_version
143
+ */
144
+ function install() {
145
+ global $wp_version;
146
+ // Prevent activation if requirements are not met
147
+ // WP 2.8 required
148
+ if (version_compare($wp_version, '2.8', '<=')) {
149
+ deactivate_plugins(__FILE__);
150
+ wp_die(__('WP Better Emails requires WordPress 2.8 or newer.', 'wp-better-emails'), __('Upgrade your Wordpress installation.', 'wp-better-emails'));
151
+ }
152
+ $this->set_options();
153
+ }
154
 
155
+ /**
156
+ * Option page to the built-in settings menu
157
+ *
158
+ * @since 0.1
159
+ */
160
+ function admin_menu() {
161
+ $this->page = add_options_page(__('Email settings', 'wp-better-emails'), __('WP Better Emails', 'wp-better-emails'), 'administrator', 'wpbe_options', array(&$this, 'admin_page'));
162
+ add_action('admin_print_scripts-' . $this->page, array(&$this, 'admin_print_script'));
163
+ add_action('admin_print_styles-' . $this->page, array(&$this, 'admin_print_style'));
164
+ }
165
 
166
+ /**
167
+ * Check if we're on the plugin page
168
+ *
169
+ * @since 0.2
170
+ * @global type $page_hook
171
+ * @return type
172
+ */
173
+ function is_wpbe_page() {
174
+ global $page_hook;
175
+ if ($page_hook == $this->page)
176
+ return true;
177
+ return false;
178
+ }
179
 
180
+ /**
181
+ * Enqueue the script to display it on the options page
182
+ * Add Javascript to handle AJAX email preview
183
+ *
184
+ * @since 0.1
185
+ */
186
+ function admin_print_script() {
187
+ wp_enqueue_script('wpbe-admin-script');
188
+ $protocol = isset($_SERVER["HTTPS"]) ? 'https://' : 'http://';
189
+ $ajax_vars = array(
190
+ 'url' => admin_url('admin-ajax.php', $protocol),
191
+ 'nonce' => wp_create_nonce('email_preview'),
192
+ 'action' => 'send_preview'
193
+ );
194
+ wp_localize_script('wpbe-admin-script', 'wpbe_ajax_vars', $ajax_vars);
195
+ }
196
 
197
+ /**
198
+ * Enqueue the style to display it on the options page
199
+ *
200
+ * @since 0.1
201
+ */
202
+ function admin_print_style() {
203
+ wp_enqueue_style('wpbe-admin-style');
204
+ wp_enqueue_style('thickbox');
205
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
+ /**
208
+ * Include admin options page
209
+ *
210
+ * @since 0.1
211
+ * @global $wp_version
212
+ */
213
+ function admin_page() {
214
+ global $wp_version;
215
+ require('wpbe-options.php');
216
+ }
 
 
 
 
 
 
 
217
 
218
+ /**
219
+ * Sanitize each option value
220
+ *
221
+ * @since 0.1
222
+ * @param array $input The options returned by the options page
223
+ * @return array $input Sanitized values
224
+ */
225
+ function validate_options($input) {
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
+ $from_email = strtolower($input['from_email']);
 
 
 
 
 
 
 
 
 
 
 
228
 
229
+ // Checking emails
230
+ if (!empty($from_email) && !is_email($from_email)) {
231
+ add_settings_error('wpbe_options', 'settings_updated', __('Please enter a valid sender email address.', 'wp-better-emails'), 'error');
232
+ $input['from_email'] = '';
233
+ } else {
234
+ $input['from_email'] = sanitize_email($from_email);
235
+ }
 
 
 
 
 
 
 
236
 
237
+ // Check name
238
+ $input['from_name'] = esc_html($input['from_name']);
239
+
240
+ if (empty($input['template']))
241
+ add_settings_error('wpbe_options', 'settings_updated', __('Template is empty', 'wp-better-emails'));
242
+ // Check if %content% tag is the template body
243
+ elseif (strpos($input['template'], '%content%') === false)
244
+ add_settings_error('wpbe_options', 'settings_updated', __('No content tag found. The %content% tag is required in your template', 'wp-better-emails'));
245
+ $input['template'] = $input['template'];
246
+
247
+ return $input;
248
+ }
249
+
250
+ /**
251
+ * Send a email preview to test the template
252
+ *
253
+ * @since 0.1
254
+ * @param string $email
255
+ */
256
+ function ajax_send_preview($email) {
257
+ if (!current_user_can('manage_options'))
258
+ die();
259
+ check_ajax_referer('email_preview');
260
+ $preview_email = sanitize_email($_POST['preview_email']);
261
+ if (empty($preview_email))
262
+ die('<div class="error"><p>' . __('Please enter an email', 'wp-better-emails') . '</p></div>');
263
+ if (!is_email($preview_email))
264
+ die('<div class="error"><p>' . __('Please enter a valid email', 'wp-better-emails') . '</p></div>');
265
+ $message = __('Hey !', 'wp-better-emails');
266
+ $message .= "\r\n\r\n";
267
+ $message .= __('This is a sample email to test your HTML template.', 'wp-better-emails');
268
+ $message .= "\r\n\r\n";
269
+ $message .= __('If you\'re not skilled in HTML/CSS email coding, I strongly recommend to leave the default template as it is. It has been tested on various and popular email clients like Gmail, Yahoo Mail, Hotmail/Live, Thunderbird, Apple Mail, Outlook, and many more.', 'wp-better-emails');
270
+ $message .= "\r\n\r\n";
271
+ $message .= __('If you have any problems or any suggestions to improve this plugin, please let me know.', 'wp-better-emails');
272
+ $message .= "\r\n\r\n";
273
+ if (wp_mail($preview_email, '[' . wp_specialchars_decode(get_option('blogname'), ENT_QUOTES) . '] - ' . __('Email template preview', 'wp-better-emails'), $message))
274
+ die('<div class="updated"><p>' . sprintf(__('An email preview has been successfully sent to %s' , 'wp-better-emails'), esc_attr($preview_email) ) . '</p></div>');
275
+ else
276
+ die('<div class="error"><p>' . __('An error occured while sending email. Please check your server configuration.', 'wp-better-emails') . '</p></div>');
277
+ }
278
+
279
+ /**
280
+ * Replace variables in the template
281
+ *
282
+ * @since 0.1
283
+ * @param string $template Template with variables
284
+ * @return string Template with variables replaced
285
+ */
286
+ function template_vars_replacement($template) {
287
+ $to_replace = array(
288
+ 'blog_url' => get_option('siteurl'),
289
+ 'home_url' => get_option('home'),
290
+ 'blog_name' => get_option('blogname'),
291
+ 'blog_description' => get_option('blogdescription'),
292
+ 'admin_email' => get_option('admin_email'),
293
+ 'date' => date_i18n(get_option('date_format')),
294
+ 'time' => date_i18n(get_option('time_format'))
295
+ );
296
+ $to_replace = apply_filters('wpbe_tags', $to_replace);
297
+ foreach ($to_replace as $tag => $var)
298
+ $template = str_replace('%' . $tag . '%', $var, $template);
299
+ return $template;
300
+ }
301
+
302
+ /**
303
+ * Checks the WP Better Emails options
304
+ *
305
+ * @since 0.1
306
+ * @return bool
307
+ */
308
+ function check_template() {
309
+ if (strpos($this->options['template'], '%content%') === false || empty($this->options['template']))
310
+ return false;
311
+ return true;
312
+ }
313
+
314
+ /**
315
+ * Add the HTML template to the message body.
316
+ * Looks for %message% into the template and replace it with the message
317
+ *
318
+ * @since 0.1
319
+ * @param string $body The message to templatize
320
+ * @return string $email The email surrounded by template
321
+ */
322
+ function set_email_template($body) {
323
+ $template = '';
324
+ if (isset($this->options['template']) && !empty($this->options['template']))
325
+ $template .= $this->options['template'];
326
+ return str_replace('%content%', $body, $template);
327
+ }
328
+
329
+ /**
330
+ * Replaces sender email if set & valid
331
+ *
332
+ * @since 0.1
333
+ * @param string $from_email
334
+ * @return string
335
+ */
336
+ function set_from_email($from_email) {
337
+ if (!empty($this->options['from_email']) && is_email($this->options['from_email']))
338
+ return $this->options['from_email'];
339
+ return $from_email;
340
+ }
341
+
342
+ /**
343
+ * Replaces sender name if set
344
+ *
345
+ * @since 0.1
346
+ * @param string $from_name
347
+ * @return string
348
+ */
349
+ function set_from_name($from_name) {
350
+ if (!empty($this->options['from_name']))
351
+ return wp_specialchars_decode($this->options['from_name'], ENT_QUOTES);
352
+ return $from_name;
353
+ }
354
+
355
+ /**
356
+ * Always set content type to HTML
357
+ *
358
+ * @since 0.1
359
+ * @param string $content_type
360
+ * @return string $content_type
361
+ */
362
+ function set_content_type($content_type) {
363
+ // Only convert if the message is text/plain and the template is ok
364
+ if ($content_type == 'text/plain' && $this->check_template() === true) {
365
+ add_action('phpmailer_init', array(&$this, 'send_html'));
366
+ return $content_type = 'text/html';
367
+ }
368
+ return $content_type;
369
+ }
370
+
371
+ /**
372
+ * Add the email template and set it multipart
373
+ *
374
+ * @since 0.1
375
+ * @param object $phpmailer
376
+ */
377
+ function send_html($phpmailer) {
378
+ // Set the original plain text message
379
+ $phpmailer->AltBody = wp_specialchars_decode($phpmailer->Body, ENT_QUOTES);
380
+ // Clean < and > around text links in WP 3.1
381
+ $phpmailer->Body = $this->esc_textlinks($phpmailer->Body);
382
+ // Convert line breaks & make links clickable
383
+ $phpmailer->Body = nl2br(make_clickable($phpmailer->Body));
384
+ // Add template to message
385
+ $phpmailer->Body = $this->set_email_template($phpmailer->Body);
386
+ // Replace variables in email
387
+ $phpmailer->Body = $this->template_vars_replacement($phpmailer->Body);
388
+ }
389
+
390
+ /**
391
+ * Replaces the < & > of the 3.1 email text links
392
+ *
393
+ * @since 0.1.2
394
+ * @param string $body
395
+ * @return string
396
+ */
397
+ function esc_textlinks($body) {
398
+ return preg_replace('#<(https?://[^*]+)>#', '$1', $body);
399
+ }
400
+
401
+ /**
402
+ * Help on template variables in contextual help
403
+ *
404
+ * @since 0.2
405
+ * @global string $page
406
+ * @param string $contextual_help
407
+ * @param string $screen_id
408
+ * @param string $screen
409
+ */
410
+ function contextual_help($contextual_help, $screen_id, $screen) {
411
+ if (!$this->is_wpbe_page())
412
+ return $contextual_help;
413
+ return '<p>' . __('Some dynamic tags can be included in your email template :', 'wp-better-emails') . '</p>
414
+ <ul>
415
+ <li>' . __('<strong>%content%</strong> : will be replaced with the message content.', 'wp-better-emails') . '<br />
416
+ <span class="description"> ' . __('NOTE: The content tag is <strong>required</strong>, WP Better Emails will be automatically desactivated if no content tag is found.', 'wp-better-emails') . '</span></li>
417
+ <li>' . __('<strong>%blog_url%</strong> : will be replaced with your blog URL.', 'wp-better-emails') . '</li>
418
+ <li>' . __('<strong>%home_url%</strong> : will be replaced with your home URL.', 'wp-better-emails') . '</li>
419
+ <li>' . __('<strong>%blog_name%</strong> : will be replaced with your blog name.', 'wp-better-emails') . '</li>
420
+ <li>' . __('<strong>%blog_description%</strong> : will be replaced with your blog description.', 'wp-better-emails') . '</li>
421
+ <li>' . __('<strong>%admin_email%</strong> : will be replaced with admin email.', 'wp-better-emails') . '</li>
422
+ <li>' . __('<strong>%date%</strong> : will be replaced with current date, as formatted in <a href="options-general.php">general options</a>.', 'wp-better-emails') . '</li>
423
+ <li>' . __('<strong>%time%</strong> : will be replaced with current time, as formatted in <a href="options-general.php">general options</a>.', 'wp-better-emails') . '</li>
424
+ </ul>';
425
+ }
426
+
427
+ /**
428
+ * TinyMCE plugins
429
+ *
430
+ * Editing HTML emails requires some more plugins from TinyMCE:
431
+ * - fullpage to handle html, meta, body tags
432
+ * - codemirror for editing source
433
+ *
434
+ * @since 0.2
435
+ * @param array $external_plugins
436
+ * @return array
437
+ */
438
+ function tinymce_plugins($external_plugins) {
439
+ global $wp_version;
440
+ if (!$this->is_wpbe_page())
441
+ return $external_plugins;
442
+
443
+ $fullpage = array();
444
+ if (version_compare($wp_version, '3.2', '<'))
445
+ $fullpage = array('fullpage' => plugins_url('tinymce-plugins/3.3.x/fullpage/editor_plugin.js', __FILE__));
446
+ else
447
+ $fullpage = array('fullpage' => plugins_url('tinymce-plugins/3.4.x/fullpage/editor_plugin.js', __FILE__));
448
+
449
+ $cmseditor = array('cmseditor' => plugins_url('tinymce-plugins/cmseditor/editor_plugin.js', __FILE__));
450
+ $external_plugins = $external_plugins + $fullpage + $cmseditor;
451
+ return $external_plugins;
452
+ }
453
+
454
+ /**
455
+ * Button to the TinyMCE toolbar
456
+ *
457
+ * @since 0.2
458
+ * @global string $page
459
+ * @global type $page_hook
460
+ * @param type $buttons
461
+ * @return type
462
+ */
463
+ function tinymce_buttons($buttons) {
464
+ if ($this->is_wpbe_page())
465
+ array_push($buttons, 'cmseditor');
466
+ return $buttons;
467
+ }
468
+
469
+ /**
470
+ * Prevent TinyMCE from removing line breaks
471
+ *
472
+ * @param array $init
473
+ * @return boolean
474
+ */
475
+ function tinymce_config($init) {
476
+ if (!$this->is_wpbe_page())
477
+ return $init;
478
+ $init['remove_linebreaks'] = false;
479
+ $init['content_css'] = ''; // WP =< 3.0
480
+ if ( isset($init['extended_valid_elements']) )
481
+ $init['extended_valid_elements'] = $init['extended_valid_elements'] . ',td[*]';
482
+ return $init;
483
+ }
484
+
485
+ /**
486
+ * Load WP tinyMCE editor
487
+ *
488
+ * @since 0.2
489
+ */
490
+ function load_wp_tiny_mce() {
491
+ if (!$this->is_wpbe_page())
492
+ return;
493
+ $settings = array(
494
+ 'editor_selector' => 'wpbe_template',
495
+ 'height' => '400'
496
+ );
497
+ wp_tiny_mce(false, $settings);
498
+ }
499
+
500
+ /**
501
+ * Print WP TinyMCE editor to edit template
502
+ *
503
+ * @since 0.2
504
+ * @global string $wp_version
505
+ */
506
+ function template_editor() {
507
+ global $wp_version;
508
+
509
+ if (version_compare($wp_version, '3.3', '<')) {
510
+ ?>
511
+ <textarea id="wpbe_template" class="wpbe_template" name="wpbe_options[template]" cols="80" rows="10"><?php echo $this->options['template']; ?></textarea>
512
+ <?php
513
+ } else {
514
+ // WP >= 3.3
515
+ $settings = array('wpautop' => false, 'editor_class' => 'wpbe_template', 'quicktags' => true);
516
+ wp_editor($template, 'wpbe_options[template]', $settings);
517
+ }
518
+ }
519
 
 
 
 
 
 
 
 
 
 
 
 
 
520
  }
 
 
521
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
522
  }
523
 
524
+ if (class_exists('WP_Better_Emails')) {
525
+ $wp_better_emails = new WP_Better_Emails();
526
+ register_activation_hook(__FILE__, array($wp_better_emails, 'install'));
 
 
 
 
 
 
527
  }
528
  ?>
wpbe_template.html DELETED
@@ -1,47 +0,0 @@
1
- <html>
2
- <body bgcolor="#f9f9f9" link="#21759B" alink="#21759B" vlink="#21759B" marginheight="0" topmargin="0" marginwidth="0" leftmargin="0" style="margin: 0px; background-color: #f9f9f9; font-family: Helvetica, Arial, sans-serif;">
3
- <table cellpadding="0" cellspacing="0" width="100%" bgcolor="#f9f9f9" border="0">
4
- <tr>
5
- <td style="padding:15px;" align="center">
6
- <center>
7
- <table width="550" cellpadding="0" bgcolor="#ffffff" cellspacing="0" >
8
- <tr>
9
- <td>
10
- <div style="border:solid 1px #d9d9d9;">
11
- <table id="header" width="100%;" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="line-height:1.5;font-size:12px;font-family: Helvetica, Arial, sans-serif;border:solid 1px #FFFFFF;">
12
- <tr>
13
- <td colspan="2" background="%blog_url%/wp-admin/images/white-grad-active.png" height="30">&nbsp;</td>
14
- </tr>
15
- <tr >
16
- <td style="line-height:32px;padding: 0 0 0 30px;" valign="baseline">
17
- <span style="font-size:32px;"><a href="%blog_url%" style="text-decoration:none;" target="_blank">%blog_name%</a></span>
18
- </td>
19
- <td style="padding: 0 30px 0 0;" align="right" valign="baseline">
20
- <span style="font-size:14px;color:#777777">%blog_description%</span>
21
- </td>
22
- </tr>
23
- </table>
24
- <table id="content" width="100%;" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="color:#444;line-height:1.5;font-size:12px;font-family: Arial, sans-serif;padding:20px 30px 0 30px;">
25
- <tr>
26
- <td colspan="2" style="padding:20px 0;border-top: solid 1px #d9d9d9">%content%</td>
27
- </tr>
28
- </table>
29
- <table id="footer" width="100%;" border="0" cellpadding="0" bgcolor="#ffffff" cellspacing="0" style="line-height:1.5;font-size:12px;font-family: Arial, sans-serif;padding:0 30px 15px 30px;">
30
- <tr style="font-size:11px;color:#777777;">
31
- <td style="border-top: solid 1px #d9d9d9;" colspan="2">
32
- <img style="padding:15px 0 0 0" height="32" width="32" src="%blog_url%/wp-admin/images/wp-logo.png" align="right" alt="Powered by Wordpress" />
33
- <div style="padding:15px 0 1px 0"><img height="13" width="13" style="vertical-align: middle;" src="%blog_url%/wp-admin/images/date-button.gif" alt="Date" /> Email sent the %date% @ %time%</div>
34
- <div><img height="12" width="12" style="vertical-align: middle;" src="%blog_url%/wp-admin/images/comment-grey-bubble.png" alt="Request" /> For any request, please contact <a href="mailto:%admin_email%">%admin_email%</a></div>
35
- </td>
36
- </tr>
37
- </table>
38
- </div>
39
- </td>
40
- </tr>
41
- </table>
42
- </center>
43
- </td>
44
- </tr>
45
- </table>
46
- </body>
47
- </html>