radiant-forum-extension 1.2.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/README.md +37 -56
  2. data/VERSION +1 -1
  3. data/app/controllers/forum_base_controller.rb +78 -0
  4. data/app/controllers/forums_controller.rb +5 -34
  5. data/app/controllers/posts_controller.rb +61 -153
  6. data/app/controllers/topics_controller.rb +6 -63
  7. data/app/helpers/forum_helper.rb +24 -48
  8. data/app/models/forum.rb +5 -18
  9. data/app/models/post.rb +53 -55
  10. data/app/models/post_attachment.rb +9 -6
  11. data/app/models/topic.rb +20 -113
  12. data/app/views/admin/reader_configuration/_edit_forum.html.haml +4 -2
  13. data/app/views/admin/reader_configuration/_forum.html.haml +6 -2
  14. data/app/views/forums/_forum.html.haml +14 -20
  15. data/app/views/forums/_latest.html.haml +12 -0
  16. data/app/views/forums/_standard_parts.html.haml +49 -0
  17. data/app/views/forums/index.html.haml +16 -24
  18. data/app/views/forums/show.html.haml +18 -28
  19. data/app/views/pages/_comment.html.haml +1 -1
  20. data/app/views/posts/_attachments.html.haml +13 -0
  21. data/app/views/posts/_confirm_delete.html.haml +10 -0
  22. data/app/views/posts/_context.html.haml +16 -0
  23. data/app/views/posts/_edit_links.html.haml +11 -0
  24. data/app/views/posts/_form.html.haml +40 -2
  25. data/app/views/posts/_latest.html.haml +10 -17
  26. data/app/views/posts/_new_attachment.html.haml +2 -0
  27. data/app/views/posts/_post.html.haml +25 -60
  28. data/app/views/posts/{_search.html.haml → _search_form.html.haml} +1 -1
  29. data/app/views/posts/_uploader.html.haml +2 -2
  30. data/app/views/posts/edit.html.haml +26 -13
  31. data/app/views/posts/index.html.haml +19 -27
  32. data/app/views/posts/new.html.haml +27 -7
  33. data/app/views/posts/remove.html.haml +27 -0
  34. data/app/views/posts/show.html.haml +20 -7
  35. data/app/views/readers/_forum_messages.html.haml +20 -0
  36. data/app/views/readers/_messages_summary.html.haml +3 -0
  37. data/app/views/topics/_context.html.haml +12 -0
  38. data/app/views/topics/_latest.html.haml +14 -16
  39. data/app/views/topics/_locked.html.haml +1 -1
  40. data/app/views/topics/_replies.html.haml +6 -0
  41. data/app/views/topics/_reply.html.haml +23 -0
  42. data/app/views/topics/_topic.html.haml +14 -43
  43. data/app/views/topics/_voices.html.haml +5 -0
  44. data/app/views/topics/index.html.haml +11 -24
  45. data/app/views/topics/show.html.haml +25 -38
  46. data/config/initializers/radiant_config.rb +5 -1
  47. data/config/locales/en.yml +73 -27
  48. data/config/routes.rb +3 -4
  49. data/db/migrate/20101222160900_page_posts.rb +21 -0
  50. data/db/migrate/20101222163605_no_comment_forum.rb +10 -0
  51. data/db/migrate/20110105103827_topic_merely_associative.rb +23 -0
  52. data/db/migrate/20110111080550_detach_observer.rb +11 -0
  53. data/db/migrate/20110127113852_import_attachments.rb +9 -0
  54. data/forum_extension.rb +12 -13
  55. data/lib/commentable_model.rb +98 -0
  56. data/lib/forum_page.rb +2 -22
  57. data/lib/forum_reader_sessions_controller.rb +14 -0
  58. data/lib/forum_readers_controller.rb +2 -9
  59. data/lib/forum_red_cloth3.rb +23 -4
  60. data/lib/forum_red_cloth4.rb +23 -4
  61. data/lib/forum_tags.rb +298 -194
  62. data/lib/sanitize/config/forum.rb +47 -0
  63. data/public/images/furniture/blank.png +0 -0
  64. data/public/images/furniture/emoticons.png +0 -0
  65. data/public/javascripts/forum.js +349 -93
  66. data/public/javascripts/jquery.tools.min.js +195 -0
  67. data/public/punymce/blank.htm +1 -0
  68. data/public/punymce/css/content.css +4 -0
  69. data/public/punymce/css/editor.css +58 -0
  70. data/public/punymce/i18n/sv.js +28 -0
  71. data/public/punymce/img/icons.gif +0 -0
  72. data/public/punymce/img/icons_uncompressed.png +0 -0
  73. data/public/punymce/plugins/bbcode.js +1 -0
  74. data/public/punymce/plugins/bbcode_src.js +50 -0
  75. data/public/punymce/plugins/editsource/css/editor.css +3 -0
  76. data/public/punymce/plugins/editsource/editsource.js +1 -0
  77. data/public/punymce/plugins/editsource/editsource_src.js +81 -0
  78. data/public/punymce/plugins/editsource/img/icons.gif +0 -0
  79. data/public/punymce/plugins/emoticons/css/content.css +13 -0
  80. data/public/punymce/plugins/emoticons/css/editor.css +17 -0
  81. data/public/punymce/plugins/emoticons/emoticons.js +1 -0
  82. data/public/punymce/plugins/emoticons/emoticons_src.js +303 -0
  83. data/public/punymce/plugins/emoticons/img/emoticons.gif +0 -0
  84. data/public/punymce/plugins/emoticons/img/emoticons.png +0 -0
  85. data/public/punymce/plugins/emoticons/img/trans.gif +0 -0
  86. data/public/punymce/plugins/entities.js +1 -0
  87. data/public/punymce/plugins/entities_src.js +37 -0
  88. data/public/punymce/plugins/forceblocks.js +1 -0
  89. data/public/punymce/plugins/forceblocks_src.js +465 -0
  90. data/public/punymce/plugins/forcenl.js +1 -0
  91. data/public/punymce/plugins/forcenl_src.js +26 -0
  92. data/public/punymce/plugins/image/css/editor.css +1 -0
  93. data/public/punymce/plugins/image/image.js +1 -0
  94. data/public/punymce/plugins/image/image_src.js +30 -0
  95. data/public/punymce/plugins/image/img/icons.gif +0 -0
  96. data/public/punymce/plugins/link/css/editor.css +2 -0
  97. data/public/punymce/plugins/link/img/icons.gif +0 -0
  98. data/public/punymce/plugins/link/link.js +1 -0
  99. data/public/punymce/plugins/link/link_src.js +36 -0
  100. data/public/punymce/plugins/paste.js +1 -0
  101. data/public/punymce/plugins/paste_src.js +169 -0
  102. data/public/punymce/plugins/protect.js +1 -0
  103. data/public/punymce/plugins/protect_src.js +30 -0
  104. data/public/punymce/plugins/safari2x.js +1 -0
  105. data/public/punymce/plugins/safari2x_src.js +284 -0
  106. data/public/punymce/plugins/tabfocus.js +1 -0
  107. data/public/punymce/plugins/tabfocus_src.js +45 -0
  108. data/public/punymce/plugins/textcolor/css/editor.css +7 -0
  109. data/public/punymce/plugins/textcolor/img/icons.gif +0 -0
  110. data/public/punymce/plugins/textcolor/textcolor.js +1 -0
  111. data/public/punymce/plugins/textcolor/textcolor_src.js +73 -0
  112. data/public/punymce/puny_mce.js +1 -0
  113. data/public/punymce/puny_mce_full.js +1 -0
  114. data/public/punymce/puny_mce_src.js +1460 -0
  115. data/public/stylesheets/sass/forum.sass +175 -169
  116. data/radiant-forum-extension.gemspec +81 -19
  117. data/spec/controllers/admin/forums_controller_spec.rb +2 -2
  118. data/spec/controllers/forums_controller_spec.rb +3 -6
  119. data/spec/controllers/posts_controller_spec.rb +76 -59
  120. data/spec/controllers/topics_controller_spec.rb +4 -95
  121. data/spec/datasets/forum_readers_dataset.rb +1 -0
  122. data/spec/datasets/forums_dataset.rb +91 -10
  123. data/spec/lib/commentable_model_spec.rb +88 -0
  124. data/spec/lib/forum_page_spec.rb +2 -34
  125. data/spec/lib/forum_site_spec.rb +2 -3
  126. data/spec/lib/forum_tags_spec.rb +35 -0
  127. data/spec/models/forum_spec.rb +31 -20
  128. data/spec/models/post_spec.rb +40 -39
  129. data/spec/models/topic_spec.rb +29 -71
  130. data/spec/spec_helper.rb +10 -1
  131. metadata +84 -22
  132. data/app/views/posts/_reply.html.haml +0 -35
  133. data/app/views/posts/_upload.html.haml +0 -2
  134. data/app/views/posts/preview.html.haml +0 -32
  135. data/app/views/posts/search.html.haml +0 -63
  136. data/app/views/posts/search.rss.builder +0 -14
  137. data/app/views/topics/_form.html.haml +0 -30
  138. data/app/views/topics/_help.html.haml +0 -8
  139. data/app/views/topics/comments.html.haml +0 -6
  140. data/app/views/topics/edit.html.haml +0 -26
  141. data/app/views/topics/new.html.haml +0 -56
  142. data/spec/datasets/forum_pages_dataset.rb +0 -11
  143. data/spec/datasets/posts_dataset.rb +0 -31
  144. data/spec/datasets/topics_dataset.rb +0 -37
@@ -0,0 +1,17 @@
1
+ .punymce a.emoticons { background: url('../img/emoticons.png') 0 0; }
2
+
3
+ /* Menu */
4
+ div.punymce_emoticons { position: absolute; display: none; background-color: white; border: 1px solid #F0F0EE;}
5
+ .punymce a.emoticon { display: block; width: 16px; height: 16px; }
6
+ .punymce a.happy { background: url('../img/emoticons.png') no-repeat 0 0; }
7
+ .punymce a.unhappy { background: url('../img/emoticons.png') no-repeat -16px 0; }
8
+ .punymce a.sad { background: url('../img/emoticons.png') no-repeat -32px 0; }
9
+ .punymce a.grin { background: url('../img/emoticons.png') no-repeat -48px 0; }
10
+ .punymce a.surprised { background: url('../img/emoticons.png') no-repeat -64px 0; }
11
+ .punymce a.wink { background: url('../img/emoticons.png') no-repeat -80px 0; }
12
+ .punymce a.halfhappy { background: url('../img/emoticons.png') no-repeat -96px 0; }
13
+ .punymce a.tongue { background: url('../img/emoticons.png') no-repeat -112px 0; }
14
+ .punymce a.lol { background: url('../img/emoticons.png') no-repeat -128px 0; }
15
+ .punymce a.mad { background: url('../img/emoticons.png') no-repeat -144px 0; }
16
+ .punymce a.shocked { background: url('../img/emoticons.png') no-repeat -160px 0; }
17
+ .punymce a.cool { background: url('../img/emoticons.png') no-repeat -176px 0; }
@@ -0,0 +1 @@
1
+ (function(a){a.plugins.Emoticons=function(e){var k=a.Event,i,g,c,b,m,j,l,d;i=a.each;g=a.extend;c=a.isIE;b=a.isGecko;l=a.DOM;this.settings=m=g({emoticons:{happy:[":)"],neutral:[":|"],sad:[":("],grin:[":D"],surprised:[":O"],wink:[";)"],devil:["}:)"],tongue:[":P"],lol:[':@'],mad:[':['],shocked:['8|'],cool:['B]']},row_length:4,trans_img:a.baseURL+"plugins/emoticons/img/trans.gif",skip_css:0,auto_convert:1},e.settings.emoticons);if(!m.skip_css){l.loadCSS(a.baseURL+"/plugins/emoticons/css/editor.css")}j="";i(m.emoticons,function(h){i(h,function(n){if(j.length!=0){j+="|"}j+=n.replace(/([^a-zA-Z0-9])/g,"\\$1")})});j=new RegExp(j,"g");g(e.commands,{mceEmoticons:function(B,A,y){var q,C=this,h=e.settings.id,o=l.getPos(y.target),z,w;if(e.hideMenu){return e.hideMenu()}function x(n){e.hideMenu=null;k.remove(document,"click",x);k.remove(e.getDoc(),"click",x);l.get(h+"_memoticons").style.display="none";return 1}q=l.get(h+"_memoticons");if(!q){q=l.get(h+"_t");q=l.add(document.body,"div",{id:h+"_memoticons","class":"punymce_emoticons punymce"});q=l.add(q,"table",{"class":"punymce"});q=l.add(q,"tbody");z=m.row_length;i(m.emoticons,function(p,n){if(z==m.row_length){r=l.add(q,"tr");z=0}z++;k.add(l.add(l.add(r,"td"),"a",{href:"#","class":"emoticon "+n}),"mousedown",function(t){x.call(C);e.selection.setNode(e.dom.create("img",{title:p[0]||n,src:m.trans_img,"class":"emoticon "+n}));return k.cancel(t)})})}k.add(document,"click",x,C);k.add(e.getDoc(),"click",x,C);e.hideMenu=x;s=l.get(h+"_memoticons").style;s.left=o.x+"px";s.top=(o.y+y.target.clientHeight+2)+"px";s.display="block"}});function f(h){var n;i(m.emoticons,function(p,o){i(p,function(q){if(q==h){n=o;return false}});return !n});return n}e.onPreProcess.add(function(p,q){var n=q.node.getElementsByTagName("img"),h=[];i(n,function(o){h.push(o)});i(h,function(t){var o=e.dom.getAttr(t,"class");if(o&&o.indexOf("emoticon")!=-1){t.parentNode.replaceChild(e.getDoc().createTextNode(t.getAttribute("title")),t)}})});e.onSetContent.add(function(n,p){var h=[];d=p.content.replace(/(<\/?[^>]+>|:\/\/)/g,function(o){return o.replace(j,function(q){var t=f(q);if(t){h.push(q);return"�"+h.length+"�"}return q})});d=d.replace(j,function(o){return'<img src="'+m.trans_img+'" title="'+o+'" class="emoticon '+f(o)+'" />'});d=d.replace(/�([^�]+)�/g,function(q,o){return h[parseInt(o)-1]});p.content=d});e.onInit.add(function(){var h=e.dom;if(!m.skip_css){h.loadCSS(a.baseURL+"/plugins/emoticons/css/content.css")}k.add(e.getDoc(),"controlselect",function(n){if(h.getAttr(n.target,"class").indexOf("emoticon")!=-1){return k.cancel(n)}});if(b){k.add(e.getDoc(),"mousedown",function(n){if(h.getAttr(n.target,"class").indexOf("emoticon")!=-1){e.getDoc().execCommand("enableObjectResizing",false,false);return k.cancel(n)}else{e.getDoc().execCommand("enableObjectResizing",false,true)}});k.add(e.getDoc(),"keydown",function(u){var y=e.selection,v=y.getSel(),w=e.getDoc(),o=y.getRng(),x,p,q,t;x=o.startContainer;p=o.startOffset;if(x.nodeType==1){return}if(x){if(u.keyCode==39&&p==x.nodeValue.length){q=x.nextSibling;if(q&&q.nodeName=="IMG"){q=q.nextSibling;o=w.createRange();o.setStart(q,0);o.setEnd(q,0);v.removeAllRanges();v.addRange(o);return k.cancel(u)}}if(u.keyCode==37&&p==0){q=x.previousSibling;if(q&&q.nodeName=="IMG"){q=q.previousSibling;t=q.nodeValue.length;o=w.createRange();o.setStart(q,t);o.setEnd(q,t);v.removeAllRanges();v.addRange(o);return k.cancel(u)}}}})}k.add(e.getDoc(),"keypress",function(t){var p,x,o,w,v=e.getDoc(),u=e.selection,y=u.getSel(),n=u.getRng();function q(C){var B,A,z;if(!c){B=n.startContainer;A=n.startOffset;z=n.endOffset;if(A>0&&B.nodeType==3){return B.nodeValue.substring(Math.max(0,A+C),z)}}else{n=n.duplicate();n.moveStart("character",C);return n.text}}if(a.isOldWebKit||!m.auto_convert){return true}if(/(ttp|ftp):/i.test(q(-4))){return}o=q(-1);p=o+String.fromCharCode(t.charCode||t.keyCode);j.lastIndex=0;if(!o||!j.test(p)||w=="/"){return}if(x=f(p)){if(!c){n.setStart(n.startContainer,n.startOffset-1);y.removeAllRanges();y.addRange(n)}else{n=e.selection.getRng();n.moveStart("character",-1);n.select()}e.selection.setNode(h.create("img",{id:"emoticon",title:p,src:m.trans_img,"class":"emoticon "+x}));p=h.get("emoticon");h.setAttr(p,"id","");e.selection.select(p);e.selection.collapse(0);return k.cancel(t)}})});g(e.tools,{emoticons:{cmd:"mceEmoticons",title:a.I18n.emoticons}})};a.extend(a.I18n,{emoticons:"Insert emoticon"})})(punymce);
@@ -0,0 +1,303 @@
1
+ (function(punymce) {
2
+ punymce.plugins.Emoticons = function(ed) {
3
+ var Event = punymce.Event, each, extend, isIE, isGecko, st, emoReg, DOM, h;
4
+
5
+ each = punymce.each;
6
+ extend = punymce.extend;
7
+ isIE = punymce.isIE;
8
+ isGecko = punymce.isGecko;
9
+ DOM = punymce.DOM;
10
+
11
+ // Default settings
12
+ this.settings = st = extend({
13
+ emoticons : {
14
+ happy : [':)', '=)'],
15
+ unhappy : [':|', '=|'],
16
+ sad : [':(','=('],
17
+ grin : [':D', '=D'],
18
+ surprised : [':o',':O','=o', '=O'],
19
+ wink : [';)'],
20
+ halfhappy : [':/', '=/'],
21
+ tongue : [':P', ':p', '=P', '=p'],
22
+ lol : [':0'],
23
+ mad : [':['],
24
+ shocked : ['8|'],
25
+ cool : ['B]']
26
+ },
27
+ row_length : 4,
28
+ trans_img : punymce.baseURL + 'plugins/emoticons/img/trans.gif',
29
+ skip_css : 0,
30
+ auto_convert : 1
31
+ }, ed.settings.emoticons);
32
+
33
+ if (!st.skip_css)
34
+ DOM.loadCSS(punymce.baseURL + '/plugins/emoticons/css/editor.css');
35
+
36
+ // Build regexp from emoticons
37
+ emoReg = '';
38
+ each(st.emoticons, function(v) {
39
+ each(v, function(v) {
40
+ if (emoReg.length != 0)
41
+ emoReg += '|';
42
+
43
+ emoReg += v.replace(/([^a-zA-Z0-9])/g, '\\$1');
44
+ });
45
+ });
46
+ emoReg = new RegExp(emoReg, 'g');
47
+
48
+ // Add commands
49
+ extend(ed.commands, {
50
+ mceEmoticons : function(u, v, e) {
51
+ var n, t = this, id = ed.settings.id, p = DOM.getPos(e.target), co, cb;
52
+
53
+ if (ed.hideMenu)
54
+ return ed.hideMenu();
55
+
56
+ function hide(e) {
57
+ ed.hideMenu = null;
58
+ Event.remove(document, 'click', hide);
59
+ Event.remove(ed.getDoc(), 'click', hide);
60
+ DOM.get(id + '_memoticons').style.display = 'none';
61
+ return 1;
62
+ };
63
+
64
+ n = DOM.get(id + '_memoticons');
65
+ if (!n) {
66
+ n = DOM.get(id + '_t');
67
+ n = DOM.add(document.body, 'div', {id : id + '_memoticons', 'class' : 'punymce_emoticons punymce'});
68
+ n = DOM.add(n, 'table', {'class' : 'punymce'});
69
+ n = DOM.add(n, 'tbody');
70
+ co = st.row_length;
71
+ each(st.emoticons, function(c, k) {
72
+ if (co == st.row_length) {
73
+ r = DOM.add(n, 'tr');
74
+ co = 0;
75
+ }
76
+
77
+ co++;
78
+
79
+ Event.add(DOM.add(DOM.add(r, 'td'), 'a', {href : '#', 'class' : 'emoticon ' + k}), 'mousedown', function(e) {
80
+ hide.call(t);
81
+
82
+ ed.selection.setNode(ed.dom.create('img', { title : c[0] || k, src : st.trans_img, 'class' : 'emoticon ' + k }));
83
+
84
+ return Event.cancel(e);
85
+ });
86
+ });
87
+ }
88
+
89
+ Event.add(document, 'click', hide, t);
90
+ Event.add(ed.getDoc(), 'click', hide, t);
91
+ ed.hideMenu = hide;
92
+
93
+ s = DOM.get(id + '_memoticons').style;
94
+ s.left = p.x + 'px';
95
+ s.top = (p.y + e.target.clientHeight + 2) + 'px';
96
+ s.display = 'block';
97
+ }
98
+ });
99
+
100
+ function find(e) {
101
+ var c;
102
+
103
+ each(st.emoticons, function(v, k) {
104
+ each(v, function(v) {
105
+ if (v == e) {
106
+ c = k;
107
+ return false;
108
+ }
109
+ });
110
+
111
+ return !c;
112
+ });
113
+
114
+ return c;
115
+ };
116
+
117
+ ed.onPreProcess.add(function(se, o) {
118
+ var nl = o.node.getElementsByTagName('img'), a = [];
119
+
120
+ each(nl, function(n) {
121
+ a.push(n);
122
+ });
123
+
124
+ each(a, function(n) {
125
+ var c = ed.dom.getAttr(n, 'class');
126
+
127
+ if (c && c.indexOf('emoticon') != -1) {
128
+ n.parentNode.replaceChild(ed.getDoc().createTextNode(n.getAttribute('title')), n);
129
+ }
130
+ });
131
+ });
132
+
133
+ ed.onSetContent.add(function(ed, o) {
134
+ var ar = [];
135
+
136
+ // Store away all tags and URL parts (://)
137
+ h = o.content.replace(/(<\/?[^>]+>|:\/\/)/g, function(a) {
138
+ return a.replace(emoReg, function(a) {
139
+ var c = find(a);
140
+
141
+ if (c) {
142
+ ar.push(a);
143
+ return '�' + ar.length + '�';
144
+ }
145
+
146
+ return a;
147
+ });
148
+ });
149
+
150
+ // Replace emoticons in remaining text nodes
151
+ h = h.replace(emoReg, function(a) {
152
+ return '<img src="' + st.trans_img + '" title="' + a + '" class="emoticon ' + find(a) + '" />';
153
+ });
154
+
155
+ // Restore attribs
156
+ h = h.replace(/�([^�]+)�/g, function(a, b) {
157
+ return ar[parseInt(b) - 1];
158
+ });
159
+
160
+ o.content = h;
161
+ });
162
+
163
+ ed.onInit.add(function() {
164
+ var DOM = ed.dom;
165
+
166
+ if (!st.skip_css)
167
+ DOM.loadCSS(punymce.baseURL + '/plugins/emoticons/css/content.css');
168
+
169
+ // Disable selection on emoticons in IE
170
+ Event.add(ed.getDoc(), 'controlselect', function(e) {
171
+ if (DOM.getAttr(e.target, 'class').indexOf('emoticon') != -1)
172
+ return Event.cancel(e);
173
+ });
174
+
175
+ if (isGecko) {
176
+ // Disable selection of emoticons in Gecko
177
+ Event.add(ed.getDoc(), 'mousedown', function(e) {
178
+ if (DOM.getAttr(e.target, 'class').indexOf('emoticon') != -1) {
179
+ ed.getDoc().execCommand('enableObjectResizing', false, false);
180
+ return Event.cancel(e);
181
+ } else
182
+ ed.getDoc().execCommand('enableObjectResizing', false, true);
183
+ });
184
+
185
+ // Fix for bug: https://bugzilla.mozilla.org/show_bug.cgi?id=392569
186
+ Event.add(ed.getDoc(), 'keydown', function(e) {
187
+ var s = ed.selection, se = s.getSel(), d = ed.getDoc(), r = s.getRng(), sc, so, n, l;
188
+
189
+ sc = r.startContainer;
190
+ so = r.startOffset;
191
+
192
+ // Element instead of text just pass it though
193
+ if (sc.nodeType == 1)
194
+ return;
195
+
196
+ if (sc) {
197
+ // Right key
198
+ if (e.keyCode == 39 && so == sc.nodeValue.length) {
199
+ n = sc.nextSibling;
200
+ if (n && n.nodeName == 'IMG') {
201
+ n = n.nextSibling;
202
+
203
+ r = d.createRange();
204
+ r.setStart(n, 0);
205
+ r.setEnd(n, 0);
206
+
207
+ se.removeAllRanges();
208
+ se.addRange(r);
209
+
210
+ return Event.cancel(e);
211
+ }
212
+ }
213
+
214
+ // Left key
215
+ if (e.keyCode == 37 && so == 0) {
216
+ n = sc.previousSibling;
217
+ if (n && n.nodeName == 'IMG') {
218
+ n = n.previousSibling;
219
+ l = n.nodeValue.length;
220
+
221
+ r = d.createRange();
222
+ r.setStart(n, l);
223
+ r.setEnd(n, l);
224
+
225
+ se.removeAllRanges();
226
+ se.addRange(r);
227
+
228
+ return Event.cancel(e);
229
+ }
230
+ }
231
+ }
232
+ });
233
+ }
234
+
235
+ Event.add(ed.getDoc(), 'keypress', function(e) {
236
+ var em, cls, lc, lc2, d = ed.getDoc(), se = ed.selection, s = se.getSel(), r = se.getRng();
237
+
238
+ function getStr(pos) {
239
+ var sn, so, eo;
240
+
241
+ if (!isIE) {
242
+ sn = r.startContainer;
243
+ so = r.startOffset;
244
+ eo = r.endOffset;
245
+
246
+ if (so > 0 && sn.nodeType == 3)
247
+ return sn.nodeValue.substring(Math.max(0, so + pos), eo);
248
+ } else {
249
+ r = r.duplicate();
250
+ r.moveStart('character', pos);
251
+
252
+ return r.text;
253
+ }
254
+ };
255
+
256
+ // Check if Safari 2.x
257
+ if (punymce.isOldWebKit || !st.auto_convert)
258
+ return true;
259
+
260
+ // If http/ftp
261
+ if (/(ttp|ftp):/i.test(getStr(-4)))
262
+ return;
263
+
264
+ lc = getStr(-1);
265
+ em = lc + String.fromCharCode(e.charCode || e.keyCode);
266
+ emoReg.lastIndex = 0;
267
+
268
+ if (!lc || !emoReg.test(em) || lc2 == '/')
269
+ return;
270
+
271
+ if (cls = find(em)) {
272
+ if (!isIE) {
273
+ r.setStart(r.startContainer, r.startOffset - 1);
274
+ s.removeAllRanges();
275
+ s.addRange(r);
276
+ } else {
277
+ r = ed.selection.getRng();
278
+ r.moveStart('character', -1);
279
+ r.select();
280
+ }
281
+
282
+ ed.selection.setNode(DOM.create('img', { id : 'emoticon', title : em, src : st.trans_img, 'class' : 'emoticon ' + cls }));
283
+
284
+ em = DOM.get('emoticon');
285
+ DOM.setAttr(em, 'id', '');
286
+ ed.selection.select(em);
287
+ ed.selection.collapse(0);
288
+
289
+ return Event.cancel(e);
290
+ }
291
+ });
292
+ });
293
+
294
+ extend(ed.tools, {
295
+ emoticons : {cmd : 'mceEmoticons', title : punymce.I18n.emoticons}
296
+ });
297
+ };
298
+
299
+ // English i18n strings
300
+ punymce.extend(punymce.I18n, {
301
+ emoticons : 'Insert emoticon'
302
+ });
303
+ })(punymce);
@@ -0,0 +1 @@
1
+ (function(a){a.plugins.Entities=function(e){var j,c,h="",b={},f,d,g;j=e.settings;j.entities="named";g=j.entity_list;if(!g){g="160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro"}c=g.split(",");for(f=0;f<c.length;f+=2){b[String.fromCharCode(c[f])]=c[f+1];d=parseInt(c[f]).toString(16);h+="\\u"+"0000".substring(d.length)+d}h=new RegExp("["+h+"]","g");e.onGetContent.add(function(i,k){if(k.format=="html"){k.content=k.content.replace(h,function(l){var m;if(m=b[l]){l="&"+m+";"}return l})}})}})(punymce);
@@ -0,0 +1,37 @@
1
+ (function(punymce) {
2
+ punymce.plugins.Entities = function(ed) {
3
+ var s, a, re = '', l = {}, i, v, el;
4
+
5
+ s = ed.settings;
6
+
7
+ // Force named
8
+ s.entities = 'named';
9
+ el = s.entity_list;
10
+
11
+ if (!el)
12
+ el = '160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro';
13
+
14
+ // Build regex and lookup array
15
+ a = el.split(',');
16
+ for (i=0; i<a.length; i+=2) {
17
+ l[String.fromCharCode(a[i])] = a[i + 1];
18
+
19
+ v = parseInt(a[i]).toString(16);
20
+ re += '\\u' + '0000'.substring(v.length) + v;
21
+ }
22
+ re = new RegExp('[' + re + ']', 'g');
23
+
24
+ ed.onGetContent.add(function(ed, o) {
25
+ if (o.format == 'html') {
26
+ o.content = o.content.replace(re, function(a) {
27
+ var v;
28
+
29
+ if (v = l[a])
30
+ a = '&' + v + ';';
31
+
32
+ return a;
33
+ });
34
+ }
35
+ });
36
+ };
37
+ })(punymce);
@@ -0,0 +1 @@
1
+ (function(a){a.plugins.ForceBlocks=function(d){var v=a.Event,s,g=this;var n,k,u,q;var c,r,p;n=a.isIE;k=a.isGecko;u=a.isOpera;q=a.isWebKit;c=a.each;r=a.extend;this.settings=p=r({element:"P"},d.settings.forceblocks);d.onPreInit.add(m,g);if(!n){d.onSetContent.add(function(t,w){if(w.format=="html"){w.content=w.content.replace(/<p>[\s\u00a0]+<\/p>/g,"<p><br /></p>")}})}d.onPostProcess.add(function(t,w){w.content=w.content.replace(/<p><\/p>/g,"<p>\u00a0</p>")});function m(){s=d.dom;v.add(d.getDoc(),"keyup",j);d.onSetContent.add(j);d.onBeforeGetContent.add(j);if(!n){d.onPreProcess.add(function(t,w){c(w.node.getElementsByTagName("br"),function(y){var x=y.parentNode;if(x&&x.nodeName=="p"&&(x.childNodes.length==1||x.lastChild==y)){x.replaceChild(t.getDoc().createTextNode("\u00a0"),y)}})});v.add(d.getDoc(),"keypress",function(t){if(t.keyCode==13&&!t.shiftKey){if(!o(t)){return v.cancel(t)}}});if(k){v.add(d.getDoc(),"keydown",function(t){if((t.keyCode==8||t.keyCode==46)&&!t.shiftKey){h(t,t.keyCode==8)}})}}}function b(x){var y,t;y=x.document;t=y.compatMode=="CSS1Compat"?y.documentElement:y.body;return{x:x.pageXOffset||t.scrollLeft,y:x.pageYOffset||t.scrollTop,w:x.innerWidth||t.clientWidth,h:x.innerHeight||t.clientHeight}}function l(B,y,z){var x=d.getDoc().createTreeWalker(B,4,null,false),B,A=-1;while(B=x.nextNode()){A++;if(y==0&&B==z){return A}if(y==1&&A==z){return B}}return -1}function j(){var C=this,O=d.getBody(),L=d.getDoc(),R=d.selection,D=R.getSel(),E=R.getRng(),P=-2,A,J,w,x,M=-16777215;var N,y,Q,I,F,z=O.childNodes,H,G,B;for(H=z.length-1;H>=0;H--){N=z[H];if(N.nodeType==3||(!f(N)&&N.nodeType!=8)){if(!y){if(N.nodeType!=3||/[^\s]/g.test(N.nodeValue)){if(P==-2&&E){if(!n){if(E.startContainer.nodeType==1&&(G=E.startContainer.childNodes[E.startOffset])&&G.nodeType==1){B=G.getAttribute("id");G.setAttribute("id","__mce")}else{if(d.dom.getParent(E.startContainer,function(t){return t===O})){J=E.startOffset;w=E.endOffset;P=l(O,0,E.startContainer);A=l(O,0,E.endContainer)}}}else{x=L.body.createTextRange();x.moveToElementText(O);x.collapse(1);Q=x.move("character",M)*-1;x=E.duplicate();x.collapse(1);I=x.move("character",M)*-1;x=E.duplicate();x.collapse(0);F=(x.move("character",M)*-1)-I;P=I-Q;A=F}}y=d.dom.create(p.element);y.appendChild(N.cloneNode(1));N.parentNode.replaceChild(y,N)}}else{if(y.hasChildNodes()){y.insertBefore(N,y.firstChild)}else{y.appendChild(N)}}}else{y=null}}if(P!=-2){if(!n){y=O.getElementsByTagName(p.element)[0];E=L.createRange();if(P!=-1){E.setStart(l(O,1,P),J)}else{E.setStart(y,0)}if(A!=-1){E.setEnd(l(O,1,A),w)}else{E.setEnd(y,0)}if(D){D.removeAllRanges();D.addRange(E)}}else{try{E=D.createRange();E.moveToElementText(O);E.collapse(1);E.moveStart("character",P);E.moveEnd("character",A);E.select()}catch(K){}}}else{if(!n&&(G=d.dom.get("__mce"))){if(B){G.setAttribute("id",B)}else{G.removeAttribute("id")}E=L.createRange();E.setStartBefore(G);E.setEndBefore(G);R.setRng(E)}}}function f(t){return t.nodeType==1&&/^(H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CODE|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(t.nodeName)}function e(t){return s.getParent(t,function(w){return f(w)})}function i(t){t=t.innerHTML;t=t.replace(/<img|hr|table/g,"d");t=t.replace(/<[^>]+>/g,"");return t.replace(/[ \t\r\n]+/g,"")==""}function o(O){var P=d.getDoc(),G=d.selection.getSel(),H=d.selection.getRng(),Q=P.body;var K,L,I,N,M,z,w,A,C,t,E,R,x,B,J,D,F;if(a.isOldWebKit){return true}K=P.createRange();K.setStart(G.anchorNode,G.anchorOffset);K.collapse(true);L=P.createRange();L.setStart(G.focusNode,G.focusOffset);L.collapse(true);I=K.compareBoundaryPoints(K.START_TO_END,L)<0;N=I?G.anchorNode:G.focusNode;M=I?G.anchorOffset:G.focusOffset;z=I?G.focusNode:G.anchorNode;w=I?G.focusOffset:G.anchorOffset;N=N.nodeName=="BODY"?N.firstChild:N;z=z.nodeName=="BODY"?z.firstChild:z;A=e(N);C=e(z);t=A?A.nodeName:p.element;if(s.getParent(A,function(y){return/OL|UL/.test(y.nodeName)})){return true}if(A&&(A.nodeName=="CAPTION"||/absolute|relative|static/gi.test(A.style.position))){t=p.element;A=null}if(C&&(C.nodeName=="CAPTION"||/absolute|relative|static/gi.test(C.style.position))){t=p.element;C=null}if(/(TD|TABLE|TH|CAPTION)/.test(t)||(A&&t=="DIV"&&/left|right/gi.test(A.style.cssFloat))){t=p.element;A=C=null}E=(A&&A.nodeName==t)?A.cloneNode(0):P.createElement(t);R=(C&&C.nodeName==t)?C.cloneNode(0):P.createElement(t);R.id="";if(/^(H[1-6])$/.test(t)&&N.nodeValue&&M==N.nodeValue.length){R=P.createElement(p.element)}J=x=N;do{if(J==Q||J.nodeType==9||f(J)||/(TD|TABLE|TH|CAPTION)/.test(J.nodeName)){break}x=J}while((J=J.previousSibling?J.previousSibling:J.parentNode));J=B=z;do{if(J==Q||J.nodeType==9||f(J)||/(TD|TABLE|TH|CAPTION)/.test(J.nodeName)){break}B=J}while((J=J.nextSibling?J.nextSibling:J.parentNode));if(x.nodeName==t){K.setStart(x,0)}else{K.setStartBefore(x)}K.setEnd(N,M);E.appendChild(K.cloneContents());L.setEndAfter(B);L.setStart(z,w);R.appendChild(L.cloneContents());H=P.createRange();if(!x.previousSibling&&x.parentNode.nodeName==t){H.setStartBefore(x.parentNode)}else{if(K.startContainer.nodeName==t&&K.startOffset==0){H.setStartBefore(K.startContainer)}else{H.setStart(K.startContainer,K.startOffset)}}if(!B.nextSibling&&B.parentNode.nodeName==t){H.setEndAfter(B.parentNode)}else{H.setEnd(L.endContainer,L.endOffset)}H.deleteContents();if(E.firstChild&&E.firstChild.nodeName==t){E.innerHTML=E.firstChild.innerHTML}if(R.firstChild&&R.firstChild.nodeName==t){R.innerHTML=R.firstChild.innerHTML}if(i(E)){E.innerHTML=u?" <br />":"<br />"}if(i(R)){R.innerHTML=u?" <br />":"<br />"}if(u){H.insertNode(E);H.insertNode(R)}else{H.insertNode(R);H.insertNode(E)}R.normalize();E.normalize();H=P.createRange();H.selectNodeContents(R);H.collapse(1);G.removeAllRanges();G.addRange(H);vp=b(d.getWin());D=d.dom.getPos(R).y;F=R.clientHeight;if(D<vp.y||D+F>vp.y+vp.h){d.getWin().scrollTo(0,D<vp.y?D:D-vp.h+25)}return false}function h(y,E){var B=d.getBody(),x,z=d.selection,t=z.getRng(),A=t.startContainer,x,C,D;if(A&&f(A)&&!/^(TD|TH)$/.test(A.nodeName)&&E){if(A.childNodes.length==0||(A.childNodes.length==1&&A.firstChild.nodeName=="BR")){x=A;while((x=x.previousSibling)&&!f(x)){}if(x){if(A!=B.firstChild){C=d.getDoc().createTreeWalker(x,NodeFilter.SHOW_TEXT,null,false);while(D=C.nextNode()){x=D}t=d.getDoc().createRange();t.setStart(x,x.nodeValue?x.nodeValue.length:0);t.setEnd(x,x.nodeValue?x.nodeValue.length:0);z.getSel().removeAllRanges();z.getSel().addRange(t);A.parentNode.removeChild(A)}return v.cancel(y)}}}function F(w){var G;w=w.target;if(w&&w.parentNode&&w.nodeName=="BR"&&(x=e(w))){G=w.previousSibling;v.remove(B,"DOMNodeInserted",F);if(G&&G.nodeType==3&&/\s+$/.test(G.nodeValue)){return}if(w.previousSibling||w.nextSibling){w.parentNode.removeChild(w)}}}v._add(B,"DOMNodeInserted",F);window.setTimeout(function(){v._remove(B,"DOMNodeInserted",F)},1)}}})(punymce);
@@ -0,0 +1,465 @@
1
+ (function(punymce) {
2
+ punymce.plugins.ForceBlocks = function(ed) {
3
+ var Event = punymce.Event, DOM, t = this;
4
+ var isIE, isGecko, isOpera, isWebKit;
5
+ var each, extend, st;
6
+
7
+ isIE = punymce.isIE;
8
+ isGecko = punymce.isGecko;
9
+ isOpera = punymce.isOpera;
10
+ isWebKit = punymce.isWebKit;
11
+ each = punymce.each;
12
+ extend = punymce.extend;
13
+
14
+ // Default settings
15
+ this.settings = st = extend({
16
+ element : 'P'
17
+ }, ed.settings.forceblocks);
18
+
19
+ ed.onPreInit.add(setup, t);
20
+
21
+ if (!isIE) {
22
+ ed.onSetContent.add(function(ed, o) {
23
+ if (o.format == 'html')
24
+ o.content = o.content.replace(/<p>[\s\u00a0]+<\/p>/g, '<p><br /></p>');
25
+ });
26
+ }
27
+
28
+ ed.onPostProcess.add(function(ed, o) {
29
+ o.content = o.content.replace(/<p><\/p>/g, '<p>\u00a0</p>');
30
+ });
31
+
32
+ function setup() {
33
+ DOM = ed.dom;
34
+
35
+ // Force root blocks when typing and when getting output
36
+ Event.add(ed.getDoc(), 'keyup', forceRoots);
37
+ ed.onSetContent.add(forceRoots);
38
+ ed.onBeforeGetContent.add(forceRoots);
39
+
40
+ if (!isIE) {
41
+ ed.onPreProcess.add(function(ed, o) {
42
+ each(o.node.getElementsByTagName('br'), function(n) {
43
+ var p = n.parentNode;
44
+
45
+ if (p && p.nodeName == 'p' && (p.childNodes.length == 1 || p.lastChild == n)) {
46
+ p.replaceChild(ed.getDoc().createTextNode('\u00a0'), n);
47
+ }
48
+ });
49
+ });
50
+
51
+ Event.add(ed.getDoc(), 'keypress', function(e) {
52
+ if (e.keyCode == 13 && !e.shiftKey) {
53
+ if (!insertPara(e))
54
+ return Event.cancel(e);
55
+ }
56
+ });
57
+
58
+ if (isGecko) {
59
+ Event.add(ed.getDoc(), 'keydown', function(e) {
60
+ if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey)
61
+ backspaceDelete(e, e.keyCode == 8);
62
+ });
63
+ }
64
+ }
65
+ };
66
+
67
+ function getViewPort(w) {
68
+ var d, b;
69
+
70
+ d = w.document;
71
+ b = d.compatMode == "CSS1Compat" ? d.documentElement : d.body;
72
+
73
+ // Returns viewport size excluding scrollbars
74
+ return {
75
+ x : w.pageXOffset || b.scrollLeft,
76
+ y : w.pageYOffset || b.scrollTop,
77
+ w : w.innerWidth || b.clientWidth,
78
+ h : w.innerHeight || b.clientHeight
79
+ };
80
+ };
81
+
82
+ function find(n, t, s) {
83
+ var w = ed.getDoc().createTreeWalker(n, 4, null, false), n, c = -1;
84
+
85
+ while (n = w.nextNode()) {
86
+ c++;
87
+
88
+ // Index by node
89
+ if (t == 0 && n == s)
90
+ return c;
91
+
92
+ // Node by index
93
+ if (t == 1 && c == s)
94
+ return n;
95
+ }
96
+
97
+ return -1;
98
+ };
99
+
100
+ function forceRoots() {
101
+ var t = this, b = ed.getBody(), d = ed.getDoc(), se = ed.selection, s = se.getSel(), r = se.getRng(), si = -2, ei, so, eo, tr, c = -0xFFFFFF;
102
+ var nx, bl, bp, sp, le, nl = b.childNodes, i, n, eid;
103
+
104
+ // Fix for bug #1863847
105
+ //if (e && e.keyCode == 13)
106
+ // return true;
107
+
108
+ // Wrap non blocks into blocks
109
+ for (i = nl.length - 1; i >= 0; i--) {
110
+ nx = nl[i];
111
+
112
+ // Is text or non block element
113
+ if (nx.nodeType == 3 || (!isBlock(nx) && nx.nodeType != 8)) {
114
+ if (!bl) {
115
+ // Create new block but ignore whitespace
116
+ if (nx.nodeType != 3 || /[^\s]/g.test(nx.nodeValue)) {
117
+ // Store selection
118
+ if (si == -2 && r) {
119
+ if (!isIE) {
120
+ // If selection is element then mark it
121
+ if (r.startContainer.nodeType == 1 && (n = r.startContainer.childNodes[r.startOffset]) && n.nodeType == 1) {
122
+ // Save the id of the selected element
123
+ eid = n.getAttribute("id");
124
+ n.setAttribute("id", "__mce");
125
+ } else {
126
+ // If element is inside body, might not be the case in contentEdiable mode
127
+ if (ed.dom.getParent(r.startContainer, function(e) {return e === b;})) {
128
+ so = r.startOffset;
129
+ eo = r.endOffset;
130
+ si = find(b, 0, r.startContainer);
131
+ ei = find(b, 0, r.endContainer);
132
+ }
133
+ }
134
+ } else {
135
+ tr = d.body.createTextRange();
136
+ tr.moveToElementText(b);
137
+ tr.collapse(1);
138
+ bp = tr.move('character', c) * -1;
139
+
140
+ tr = r.duplicate();
141
+ tr.collapse(1);
142
+ sp = tr.move('character', c) * -1;
143
+
144
+ tr = r.duplicate();
145
+ tr.collapse(0);
146
+ le = (tr.move('character', c) * -1) - sp;
147
+
148
+ si = sp - bp;
149
+ ei = le;
150
+ }
151
+ }
152
+
153
+ bl = ed.dom.create(st.element);
154
+ bl.appendChild(nx.cloneNode(1));
155
+ nx.parentNode.replaceChild(bl, nx);
156
+ }
157
+ } else {
158
+ if (bl.hasChildNodes())
159
+ bl.insertBefore(nx, bl.firstChild);
160
+ else
161
+ bl.appendChild(nx);
162
+ }
163
+ } else
164
+ bl = null; // Time to create new block
165
+ }
166
+
167
+ // Restore selection
168
+ if (si != -2) {
169
+ if (!isIE) {
170
+ bl = b.getElementsByTagName(st.element)[0];
171
+ r = d.createRange();
172
+
173
+ // Select last location or generated block
174
+ if (si != -1)
175
+ r.setStart(find(b, 1, si), so);
176
+ else
177
+ r.setStart(bl, 0);
178
+
179
+ // Select last location or generated block
180
+ if (ei != -1)
181
+ r.setEnd(find(b, 1, ei), eo);
182
+ else
183
+ r.setEnd(bl, 0);
184
+
185
+ if (s) {
186
+ s.removeAllRanges();
187
+ s.addRange(r);
188
+ }
189
+ } else {
190
+ try {
191
+ r = s.createRange();
192
+ r.moveToElementText(b);
193
+ r.collapse(1);
194
+ r.moveStart('character', si);
195
+ r.moveEnd('character', ei);
196
+ r.select();
197
+ } catch (ex) {
198
+ // Ignore
199
+ }
200
+ }
201
+ } else if (!isIE && (n = ed.dom.get('__mce'))) {
202
+ // Restore the id of the selected element
203
+ if (eid)
204
+ n.setAttribute('id', eid);
205
+ else
206
+ n.removeAttribute('id');
207
+
208
+ // Move caret before selected element
209
+ r = d.createRange();
210
+ r.setStartBefore(n);
211
+ r.setEndBefore(n);
212
+ se.setRng(r);
213
+ }
214
+ };
215
+
216
+ function isBlock(n) {
217
+ return n.nodeType == 1 && /^(H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CODE|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n.nodeName);
218
+ };
219
+
220
+ function getParentBlock(n) {
221
+ return DOM.getParent(n, function(n) {
222
+ return isBlock(n);
223
+ });
224
+ };
225
+
226
+ function isEmpty(n) {
227
+ n = n.innerHTML;
228
+ n = n.replace(/<img|hr|table/g, 'd'); // Keep these
229
+ n = n.replace(/<[^>]+>/g, ''); // Remove all tags
230
+
231
+ return n.replace(/[ \t\r\n]+/g, '') == '';
232
+ };
233
+
234
+ function insertPara(e) {
235
+ var d = ed.getDoc(), s = ed.selection.getSel(), r = ed.selection.getRng(), b = d.body;
236
+ var rb, ra, dir, sn, so, en, eo, sb, eb, bn, bef, aft, sc, ec, n, y, ch;
237
+
238
+ // Check if Safari 2.x
239
+ if (punymce.isOldWebKit)
240
+ return true;
241
+
242
+ // Setup before range
243
+ rb = d.createRange();
244
+ rb.setStart(s.anchorNode, s.anchorOffset);
245
+ rb.collapse(true);
246
+
247
+ // Setup after range
248
+ ra = d.createRange();
249
+ ra.setStart(s.focusNode, s.focusOffset);
250
+ ra.collapse(true);
251
+
252
+ // Setup start/end points
253
+ dir = rb.compareBoundaryPoints(rb.START_TO_END, ra) < 0;
254
+ sn = dir ? s.anchorNode : s.focusNode;
255
+ so = dir ? s.anchorOffset : s.focusOffset;
256
+ en = dir ? s.focusNode : s.anchorNode;
257
+ eo = dir ? s.focusOffset : s.anchorOffset;
258
+
259
+ // Never use body as start or end node
260
+ sn = sn.nodeName == "BODY" ? sn.firstChild : sn;
261
+ en = en.nodeName == "BODY" ? en.firstChild : en;
262
+
263
+ // Get start and end blocks
264
+ sb = getParentBlock(sn);
265
+ eb = getParentBlock(en);
266
+ bn = sb ? sb.nodeName : st.element; // Get block name to create
267
+
268
+ // Return inside list use default browser behavior
269
+ if (DOM.getParent(sb, function(n) { return /OL|UL/.test(n.nodeName); }))
270
+ return true;
271
+
272
+ // If caption or absolute layers then always generate new blocks within
273
+ if (sb && (sb.nodeName == 'CAPTION' || /absolute|relative|static/gi.test(sb.style.position))) {
274
+ bn = st.element;
275
+ sb = null;
276
+ }
277
+
278
+ // If caption or absolute layers then always generate new blocks within
279
+ if (eb && (eb.nodeName == 'CAPTION' || /absolute|relative|static/gi.test(eb.style.position))) {
280
+ bn = st.element;
281
+ eb = null;
282
+ }
283
+
284
+ // Use P instead
285
+ if (/(TD|TABLE|TH|CAPTION)/.test(bn) || (sb && bn == "DIV" && /left|right/gi.test(sb.style.cssFloat))) {
286
+ bn = st.element;
287
+ sb = eb = null;
288
+ }
289
+
290
+ // Setup new before and after blocks
291
+ bef = (sb && sb.nodeName == bn) ? sb.cloneNode(0) : d.createElement(bn);
292
+ aft = (eb && eb.nodeName == bn) ? eb.cloneNode(0) : d.createElement(bn);
293
+
294
+ // Remove id from after clone
295
+ aft.id = '';
296
+
297
+ // Is header and cursor is at the end, then force paragraph under
298
+ if (/^(H[1-6])$/.test(bn) && sn.nodeValue && so == sn.nodeValue.length)
299
+ aft = d.createElement(st.element);
300
+
301
+ // Find start chop node
302
+ n = sc = sn;
303
+ do {
304
+ if (n == b || n.nodeType == 9 || isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
305
+ break;
306
+
307
+ sc = n;
308
+ } while ((n = n.previousSibling ? n.previousSibling : n.parentNode));
309
+
310
+ // Find end chop node
311
+ n = ec = en;
312
+ do {
313
+ if (n == b || n.nodeType == 9 || isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
314
+ break;
315
+
316
+ ec = n;
317
+ } while ((n = n.nextSibling ? n.nextSibling : n.parentNode));
318
+
319
+ // Place first chop part into before block element
320
+ if (sc.nodeName == bn)
321
+ rb.setStart(sc, 0);
322
+ else
323
+ rb.setStartBefore(sc);
324
+
325
+ rb.setEnd(sn, so);
326
+ bef.appendChild(rb.cloneContents());
327
+
328
+ // Place secnd chop part within new block element
329
+ ra.setEndAfter(ec);
330
+ ra.setStart(en, eo);
331
+ aft.appendChild(ra.cloneContents());
332
+
333
+ // Create range around everything
334
+ r = d.createRange();
335
+ if (!sc.previousSibling && sc.parentNode.nodeName == bn) {
336
+ r.setStartBefore(sc.parentNode);
337
+ } else {
338
+ if (rb.startContainer.nodeName == bn && rb.startOffset == 0)
339
+ r.setStartBefore(rb.startContainer);
340
+ else
341
+ r.setStart(rb.startContainer, rb.startOffset);
342
+ }
343
+
344
+ if (!ec.nextSibling && ec.parentNode.nodeName == bn)
345
+ r.setEndAfter(ec.parentNode);
346
+ else
347
+ r.setEnd(ra.endContainer, ra.endOffset);
348
+
349
+ // Delete and replace it with new block elements
350
+ r.deleteContents();
351
+
352
+ // Never wrap blocks in blocks
353
+ if (bef.firstChild && bef.firstChild.nodeName == bn)
354
+ bef.innerHTML = bef.firstChild.innerHTML;
355
+
356
+ if (aft.firstChild && aft.firstChild.nodeName == bn)
357
+ aft.innerHTML = aft.firstChild.innerHTML;
358
+
359
+ // Padd empty blocks
360
+ if (isEmpty(bef))
361
+ bef.innerHTML = isOpera ? ' <br />' : '<br />'; // Extra space for Opera
362
+
363
+ if (isEmpty(aft))
364
+ aft.innerHTML = isOpera ? ' <br />' : '<br />'; // Extra space for Opera
365
+
366
+ // Opera needs this one backwards
367
+ if (isOpera) {
368
+ r.insertNode(bef);
369
+ r.insertNode(aft);
370
+ } else {
371
+ r.insertNode(aft);
372
+ r.insertNode(bef);
373
+ }
374
+
375
+ // Normalize
376
+ aft.normalize();
377
+ bef.normalize();
378
+
379
+ // Move cursor and scroll into view
380
+ r = d.createRange();
381
+ r.selectNodeContents(aft);
382
+ r.collapse(1);
383
+ s.removeAllRanges();
384
+ s.addRange(r);
385
+ //aft.scrollIntoView(0);
386
+
387
+ // scrollIntoView seems to scroll the parent window in most browsers now including FF 3.0b4 so it's time to stop using it and do it our selfs
388
+ vp = getViewPort(ed.getWin());
389
+ y = ed.dom.getPos(aft).y;
390
+ ch = aft.clientHeight;
391
+
392
+ // Is element within viewport
393
+ if (y < vp.y || y + ch > vp.y + vp.h)
394
+ ed.getWin().scrollTo(0, y < vp.y ? y : y - vp.h + 25); // Needs to be hardcoded to roughly one line of text if a huge text block is broken into two blocks
395
+
396
+ return false;
397
+ };
398
+
399
+ function backspaceDelete(e, bs) {
400
+ var b = ed.getBody(), n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn;
401
+
402
+ // The caret sometimes gets stuck in Gecko if you delete empty paragraphs
403
+ // This workaround removes the element by hand and moves the caret to the previous element
404
+ if (sc && isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) {
405
+ if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) {
406
+ // Find previous block element
407
+ n = sc;
408
+ while ((n = n.previousSibling) && !isBlock(n)) ;
409
+
410
+ if (n) {
411
+ if (sc != b.firstChild) {
412
+ // Find last text node
413
+ w = ed.getDoc().createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
414
+ while (tn = w.nextNode())
415
+ n = tn;
416
+
417
+ // Place caret at the end of last text node
418
+ r = ed.getDoc().createRange();
419
+ r.setStart(n, n.nodeValue ? n.nodeValue.length : 0);
420
+ r.setEnd(n, n.nodeValue ? n.nodeValue.length : 0);
421
+ se.getSel().removeAllRanges();
422
+ se.getSel().addRange(r);
423
+
424
+ // Remove the target container
425
+ sc.parentNode.removeChild(sc);
426
+ }
427
+
428
+ return Event.cancel(e);
429
+ }
430
+ }
431
+ }
432
+
433
+ // Gecko generates BR elements here and there, we don't like those so lets remove them
434
+ function handler(e) {
435
+ var pr;
436
+
437
+ e = e.target;
438
+
439
+ // A new BR was created in a block element, remove it
440
+ if (e && e.parentNode && e.nodeName == 'BR' && (n = getParentBlock(e))) {
441
+ pr = e.previousSibling;
442
+
443
+ Event.remove(b, 'DOMNodeInserted', handler);
444
+
445
+ // Is there whitespace at the end of the node before then we might need the pesky BR
446
+ // to place the caret at a correct location see bug: #2013943
447
+ if (pr && pr.nodeType == 3 && /\s+$/.test(pr.nodeValue))
448
+ return;
449
+
450
+ // Only remove BR elements that got inserted in the middle of the text
451
+ if (e.previousSibling || e.nextSibling)
452
+ e.parentNode.removeChild(e);
453
+ }
454
+ };
455
+
456
+ // Listen for new nodes
457
+ Event._add(b, 'DOMNodeInserted', handler);
458
+
459
+ // Remove listener
460
+ window.setTimeout(function() {
461
+ Event._remove(b, 'DOMNodeInserted', handler);
462
+ }, 1);
463
+ };
464
+ };
465
+ })(punymce);