spud_core 0.8.28 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/app/assets/javascripts/spud/admin/application.js +80 -39
  2. data/app/assets/javascripts/spud/admin/editor.js +91 -0
  3. data/app/assets/libs/bootstrap/css/bootstrap-responsive.css +799 -397
  4. data/app/assets/libs/bootstrap/css/bootstrap.css +3275 -1372
  5. data/app/assets/libs/bootstrap/img/glyphicons-halflings-white.png +0 -0
  6. data/app/assets/libs/bootstrap/img/glyphicons-halflings.png +0 -0
  7. data/app/assets/libs/bootstrap/js/bootstrap.js +716 -417
  8. data/app/assets/libs/datepicker/css/datepicker.css +223 -0
  9. data/app/assets/libs/datepicker/js/bootstrap-datepicker.js +779 -0
  10. data/app/assets/libs/datepicker/less/datepicker.less +122 -0
  11. data/app/assets/libs/jquery-ui/css/flick/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  12. data/app/assets/libs/jquery-ui/css/flick/images/ui-bg_flat_0_eeeeee_40x100.png +0 -0
  13. data/app/assets/libs/jquery-ui/css/flick/images/ui-bg_flat_55_ffffff_40x100.png +0 -0
  14. data/app/assets/libs/jquery-ui/css/flick/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  15. data/app/assets/libs/jquery-ui/css/flick/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  16. data/app/assets/libs/jquery-ui/css/flick/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png +0 -0
  17. data/app/assets/libs/jquery-ui/css/flick/images/ui-bg_highlight-soft_25_0073ea_1x100.png +0 -0
  18. data/app/assets/libs/jquery-ui/css/flick/images/ui-bg_highlight-soft_50_dddddd_1x100.png +0 -0
  19. data/app/assets/libs/jquery-ui/css/flick/images/ui-icons_0073ea_256x240.png +0 -0
  20. data/app/assets/libs/jquery-ui/css/flick/images/ui-icons_454545_256x240.png +0 -0
  21. data/app/assets/libs/jquery-ui/css/flick/images/ui-icons_666666_256x240.png +0 -0
  22. data/app/assets/libs/jquery-ui/css/flick/images/ui-icons_ff0084_256x240.png +0 -0
  23. data/app/assets/libs/jquery-ui/css/flick/images/ui-icons_ffffff_256x240.png +0 -0
  24. data/app/assets/libs/jquery-ui/css/flick/jquery-ui-1.9.1.custom.css +297 -0
  25. data/app/assets/libs/jquery-ui/css/flick/jquery-ui-1.9.1.custom.min.css +5 -0
  26. data/app/assets/libs/jquery-ui/js/jquery-ui-1.9.1.custom.js +4870 -0
  27. data/app/assets/libs/jquery-ui/js/jquery-ui-1.9.1.custom.min.js +6 -0
  28. data/app/assets/stylesheets/spud/admin/application.css +22 -4
  29. data/app/controllers/spud/admin/application_controller.rb +13 -4
  30. data/app/controllers/spud/admin/dashboard_controller.rb +1 -1
  31. data/app/controllers/spud/admin/users_controller.rb +4 -9
  32. data/app/controllers/spud/setup_controller.rb +3 -4
  33. data/app/models/spud_admin_permission.rb +1 -1
  34. data/app/models/spud_user.rb +4 -2
  35. data/app/views/layouts/spud/admin/application.html.erb +24 -5
  36. data/app/views/spud/admin/users/_edit.html.erb +2 -4
  37. data/app/views/spud/admin/users/_new.html.erb +3 -5
  38. data/app/views/spud/admin/users/index.html.erb +6 -5
  39. data/lib/spud_core/belongs_to_app.rb +9 -6
  40. data/lib/spud_core/configuration.rb +23 -1
  41. data/lib/spud_core/engine.rb +20 -28
  42. data/lib/spud_core/version.rb +1 -1
  43. data/spec/dummy/log/development.log +15 -37
  44. data/spec/dummy/log/test.log +72841 -25918
  45. metadata +25 -101
  46. data/app/assets/libs/bootstrap/css/bootstrap-responsive.min.css +0 -12
  47. data/app/assets/libs/bootstrap/css/bootstrap.min.css +0 -689
  48. data/app/assets/libs/bootstrap/js/bootstrap.min.js +0 -6
  49. data/app/assets/libs/tiny_mce/plugins/autosave/editor_plugin.js +0 -1
  50. data/app/assets/libs/tiny_mce/plugins/autosave/editor_plugin_src.js +0 -431
  51. data/app/assets/libs/tiny_mce/plugins/autosave/langs/en.js +0 -4
  52. data/app/assets/libs/tiny_mce/plugins/bbcode/editor_plugin.js +0 -1
  53. data/app/assets/libs/tiny_mce/plugins/bbcode/editor_plugin_src.js +0 -120
  54. data/app/assets/libs/tiny_mce/plugins/emotions/editor_plugin.js +0 -1
  55. data/app/assets/libs/tiny_mce/plugins/emotions/editor_plugin_src.js +0 -43
  56. data/app/assets/libs/tiny_mce/plugins/emotions/emotions.htm +0 -42
  57. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-cool.gif +0 -0
  58. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-cry.gif +0 -0
  59. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-embarassed.gif +0 -0
  60. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-foot-in-mouth.gif +0 -0
  61. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-frown.gif +0 -0
  62. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-innocent.gif +0 -0
  63. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-kiss.gif +0 -0
  64. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-laughing.gif +0 -0
  65. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-money-mouth.gif +0 -0
  66. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-sealed.gif +0 -0
  67. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-smile.gif +0 -0
  68. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-surprised.gif +0 -0
  69. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-tongue-out.gif +0 -0
  70. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-undecided.gif +0 -0
  71. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-wink.gif +0 -0
  72. data/app/assets/libs/tiny_mce/plugins/emotions/img/smiley-yell.gif +0 -0
  73. data/app/assets/libs/tiny_mce/plugins/emotions/js/emotions.js +0 -43
  74. data/app/assets/libs/tiny_mce/plugins/emotions/langs/en_dlg.js +0 -1
  75. data/app/assets/libs/tiny_mce/plugins/fullpage/css/fullpage.css +0 -143
  76. data/app/assets/libs/tiny_mce/plugins/fullpage/editor_plugin.js +0 -1
  77. data/app/assets/libs/tiny_mce/plugins/fullpage/editor_plugin_src.js +0 -405
  78. data/app/assets/libs/tiny_mce/plugins/fullpage/fullpage.htm +0 -259
  79. data/app/assets/libs/tiny_mce/plugins/fullpage/js/fullpage.js +0 -232
  80. data/app/assets/libs/tiny_mce/plugins/fullpage/langs/en_dlg.js +0 -1
  81. data/app/assets/libs/tiny_mce/plugins/fullscreen/editor_plugin.js +0 -1
  82. data/app/assets/libs/tiny_mce/plugins/fullscreen/editor_plugin_src.js +0 -159
  83. data/app/assets/libs/tiny_mce/plugins/fullscreen/fullscreen.htm +0 -110
  84. data/app/assets/libs/tiny_mce/plugins/insertdatetime/editor_plugin.js +0 -1
  85. data/app/assets/libs/tiny_mce/plugins/insertdatetime/editor_plugin_src.js +0 -83
  86. data/app/assets/libs/tiny_mce/plugins/legacyoutput/editor_plugin.js +0 -1
  87. data/app/assets/libs/tiny_mce/plugins/legacyoutput/editor_plugin_src.js +0 -139
  88. data/app/assets/libs/tiny_mce/plugins/nonbreaking/editor_plugin.js +0 -1
  89. data/app/assets/libs/tiny_mce/plugins/nonbreaking/editor_plugin_src.js +0 -54
  90. data/app/assets/libs/tiny_mce/plugins/noneditable/editor_plugin.js +0 -1
  91. data/app/assets/libs/tiny_mce/plugins/noneditable/editor_plugin_src.js +0 -454
  92. data/app/assets/libs/tiny_mce/plugins/pagebreak/editor_plugin.js +0 -1
  93. data/app/assets/libs/tiny_mce/plugins/pagebreak/editor_plugin_src.js +0 -74
  94. data/app/assets/libs/tiny_mce/plugins/preview/editor_plugin.js +0 -1
  95. data/app/assets/libs/tiny_mce/plugins/preview/editor_plugin_src.js +0 -53
  96. data/app/assets/libs/tiny_mce/plugins/preview/example.html +0 -28
  97. data/app/assets/libs/tiny_mce/plugins/preview/jscripts/embed.js +0 -73
  98. data/app/assets/libs/tiny_mce/plugins/preview/preview.html +0 -17
  99. data/app/assets/libs/tiny_mce/plugins/print/editor_plugin.js +0 -1
  100. data/app/assets/libs/tiny_mce/plugins/print/editor_plugin_src.js +0 -34
  101. data/app/assets/libs/tiny_mce/plugins/save/editor_plugin.js +0 -1
  102. data/app/assets/libs/tiny_mce/plugins/save/editor_plugin_src.js +0 -101
  103. data/app/assets/libs/tiny_mce/plugins/searchreplace/css/searchreplace.css +0 -6
  104. data/app/assets/libs/tiny_mce/plugins/searchreplace/editor_plugin.js +0 -1
  105. data/app/assets/libs/tiny_mce/plugins/searchreplace/editor_plugin_src.js +0 -61
  106. data/app/assets/libs/tiny_mce/plugins/searchreplace/js/searchreplace.js +0 -142
  107. data/app/assets/libs/tiny_mce/plugins/searchreplace/langs/en_dlg.js +0 -1
  108. data/app/assets/libs/tiny_mce/plugins/searchreplace/searchreplace.htm +0 -100
  109. data/app/assets/libs/tiny_mce/plugins/tabfocus/editor_plugin.js +0 -1
  110. data/app/assets/libs/tiny_mce/plugins/tabfocus/editor_plugin_src.js +0 -122
  111. data/app/assets/libs/tiny_mce/plugins/template/blank.htm +0 -12
  112. data/app/assets/libs/tiny_mce/plugins/template/css/template.css +0 -23
  113. data/app/assets/libs/tiny_mce/plugins/template/editor_plugin.js +0 -1
  114. data/app/assets/libs/tiny_mce/plugins/template/editor_plugin_src.js +0 -159
  115. data/app/assets/libs/tiny_mce/plugins/template/js/template.js +0 -106
  116. data/app/assets/libs/tiny_mce/plugins/template/langs/en_dlg.js +0 -1
  117. data/app/assets/libs/tiny_mce/plugins/template/template.htm +0 -31
  118. data/app/assets/libs/tiny_mce/plugins/visualblocks/css/visualblocks.css +0 -21
  119. data/app/assets/libs/tiny_mce/plugins/visualblocks/editor_plugin.js +0 -1
  120. data/app/assets/libs/tiny_mce/plugins/visualblocks/editor_plugin_src.js +0 -63
  121. data/app/assets/libs/tiny_mce/plugins/visualchars/editor_plugin.js +0 -1
  122. data/app/assets/libs/tiny_mce/plugins/visualchars/editor_plugin_src.js +0 -83
  123. data/app/assets/libs/tiny_mce/plugins/wordcount/editor_plugin.js +0 -1
  124. data/app/assets/libs/tiny_mce/plugins/wordcount/editor_plugin_src.js +0 -122
  125. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/abbr.htm +0 -142
  126. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/acronym.htm +0 -142
  127. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/attributes.htm +0 -149
  128. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/cite.htm +0 -142
  129. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/css/attributes.css +0 -11
  130. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/css/popup.css +0 -9
  131. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/del.htm +0 -162
  132. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/editor_plugin.js +0 -1
  133. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js +0 -132
  134. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/ins.htm +0 -162
  135. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/js/abbr.js +0 -28
  136. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/js/acronym.js +0 -28
  137. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/js/attributes.js +0 -111
  138. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/js/cite.js +0 -28
  139. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/js/del.js +0 -53
  140. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/js/element_common.js +0 -229
  141. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/js/ins.js +0 -53
  142. data/app/assets/libs/tiny_mce/plugins/xhtmlxtras/langs/en_dlg.js +0 -1
@@ -1 +0,0 @@
1
- (function(){tinymce.create("tinymce.plugins.Nonbreaking",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceNonBreaking",function(){a.execCommand("mceInsertContent",false,(a.plugins.visualchars&&a.plugins.visualchars.state)?'<span data-mce-bogus="1" class="mceItemHidden mceItemNbsp">&nbsp;</span>':"&nbsp;")});a.addButton("nonbreaking",{title:"nonbreaking.nonbreaking_desc",cmd:"mceNonBreaking"});if(a.getParam("nonbreaking_force_tab")){a.onKeyDown.add(function(d,f){if(f.keyCode==9){f.preventDefault();d.execCommand("mceNonBreaking");d.execCommand("mceNonBreaking");d.execCommand("mceNonBreaking")}})}},getInfo:function(){return{longname:"Nonbreaking space",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/nonbreaking",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("nonbreaking",tinymce.plugins.Nonbreaking)})();
@@ -1,54 +0,0 @@
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.Nonbreaking', {
13
- init : function(ed, url) {
14
- var t = this;
15
-
16
- t.editor = ed;
17
-
18
- // Register commands
19
- ed.addCommand('mceNonBreaking', function() {
20
- ed.execCommand('mceInsertContent', false, (ed.plugins.visualchars && ed.plugins.visualchars.state) ? '<span data-mce-bogus="1" class="mceItemHidden mceItemNbsp">&nbsp;</span>' : '&nbsp;');
21
- });
22
-
23
- // Register buttons
24
- ed.addButton('nonbreaking', {title : 'nonbreaking.nonbreaking_desc', cmd : 'mceNonBreaking'});
25
-
26
- if (ed.getParam('nonbreaking_force_tab')) {
27
- ed.onKeyDown.add(function(ed, e) {
28
- if (e.keyCode == 9) {
29
- e.preventDefault();
30
-
31
- ed.execCommand('mceNonBreaking');
32
- ed.execCommand('mceNonBreaking');
33
- ed.execCommand('mceNonBreaking');
34
- }
35
- });
36
- }
37
- },
38
-
39
- getInfo : function() {
40
- return {
41
- longname : 'Nonbreaking space',
42
- author : 'Moxiecode Systems AB',
43
- authorurl : 'http://tinymce.moxiecode.com',
44
- infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/nonbreaking',
45
- version : tinymce.majorVersion + "." + tinymce.minorVersion
46
- };
47
- }
48
-
49
- // Private methods
50
- });
51
-
52
- // Register plugin
53
- tinymce.PluginManager.add('nonbreaking', tinymce.plugins.Nonbreaking);
54
- })();
@@ -1 +0,0 @@
1
- (function(){var c=tinymce.dom.TreeWalker;var a="contenteditable",d="data-mce-"+a;var e=tinymce.VK;function b(n){var j=n.dom,p=n.selection,r,o="mce_noneditablecaret";r=tinymce.isGecko?"\u200B":"\uFEFF";function m(t){var s;if(t.nodeType===1){s=t.getAttribute(d);if(s&&s!=="inherit"){return s}s=t.contentEditable;if(s!=="inherit"){return s}}return null}function g(s){var t;while(s){t=m(s);if(t){return t==="false"?s:null}s=s.parentNode}}function l(s){while(s){if(s.id===o){return s}s=s.parentNode}}function k(s){var t;if(s){t=new c(s,s);for(s=t.current();s;s=t.next()){if(s.nodeType===3){return s}}}}function f(v,u){var s,t;if(m(v)==="false"){if(j.isBlock(v)){p.select(v);return}}t=j.createRng();if(m(v)==="true"){if(!v.firstChild){v.appendChild(n.getDoc().createTextNode("\u00a0"))}v=v.firstChild;u=true}s=j.create("span",{id:o,"data-mce-bogus":true},r);if(u){v.parentNode.insertBefore(s,v)}else{j.insertAfter(s,v)}t.setStart(s.firstChild,1);t.collapse(true);p.setRng(t);return s}function i(s){var v,t,u;if(s){rng=p.getRng(true);rng.setStartBefore(s);rng.setEndBefore(s);v=k(s);if(v&&v.nodeValue.charAt(0)==r){v=v.deleteData(0,1)}j.remove(s,true);p.setRng(rng)}else{t=l(p.getStart());while((s=j.get(o))&&s!==u){if(t!==s){v=k(s);if(v&&v.nodeValue.charAt(0)==r){v=v.deleteData(0,1)}j.remove(s,true)}u=s}}}function q(){var s,w,u,t,v;function x(B,D){var A,F,E,C,z;A=t.startContainer;F=t.startOffset;if(A.nodeType==3){z=A.nodeValue.length;if((F>0&&F<z)||(D?F==z:F==0)){return}}else{if(F<A.childNodes.length){var G=!D&&F>0?F-1:F;A=A.childNodes[G];if(A.hasChildNodes()){A=A.firstChild}}else{return !D?B:null}}E=new c(A,B);while(C=E[D?"prev":"next"]()){if(C.nodeType===3&&C.nodeValue.length>0){return}else{if(m(C)==="true"){return C}}}return B}i();u=p.isCollapsed();s=g(p.getStart());w=g(p.getEnd());if(s||w){t=p.getRng(true);if(u){s=s||w;var y=p.getStart();if(v=x(s,true)){f(v,true)}else{if(v=x(s,false)){f(v,false)}else{p.select(s)}}}else{t=p.getRng(true);if(s){t.setStartBefore(s)}if(w){t.setEndAfter(w)}p.setRng(t)}}}function h(y,A){var E=A.keyCode,w,B,C,u;function t(G,F){while(G=G[F?"previousSibling":"nextSibling"]){if(G.nodeType!==3||G.nodeValue.length>0){return G}}}function x(F,G){p.select(F);p.collapse(G)}C=p.getStart();u=p.getEnd();w=g(C)||g(u);if(w&&(E<112||E>124)&&E!=e.DELETE&&E!=e.BACKSPACE){if((tinymce.isMac?A.metaKey:A.ctrlKey)&&(E==67||E==88||E==86)){return}A.preventDefault();if(E==e.LEFT||E==e.RIGHT){var v=E==e.LEFT;if(y.dom.isBlock(w)){var z=v?w.previousSibling:w.nextSibling;var s=new c(z,z);var D=v?s.prev():s.next();x(D,!v)}else{x(w,v)}}}else{if(E==e.LEFT||E==e.RIGHT||E==e.BACKSPACE||E==e.DELETE){B=l(C);if(B){if(E==e.LEFT||E==e.BACKSPACE){w=t(B,true);if(w&&m(w)==="false"){A.preventDefault();if(E==e.LEFT){x(w,true)}else{j.remove(w)}}else{i(B)}}if(E==e.RIGHT||E==e.DELETE){w=t(B);if(w&&m(w)==="false"){A.preventDefault();if(E==e.RIGHT){x(w,false)}else{j.remove(w)}}else{i(B)}}}}}}n.onMouseDown.addToTop(function(s,u){var t=s.selection.getNode();if(m(t)==="false"&&t==u.target){q()}});n.onMouseUp.addToTop(q);n.onKeyDown.addToTop(h);n.onKeyUp.addToTop(q)}tinymce.create("tinymce.plugins.NonEditablePlugin",{init:function(i,k){var h,g,j;function f(m,n){var o=j.length,p=n.content,l=tinymce.trim(g);if(n.format=="raw"){return}while(o--){p=p.replace(j[o],function(s){var r=arguments,q=r[r.length-2];if(q>0&&p.charAt(q-1)=='"'){return s}return'<span class="'+l+'" data-mce-content="'+m.dom.encode(r[0])+'">'+m.dom.encode(typeof(r[1])==="string"?r[1]:r[0])+"</span>"})}n.content=p}h=" "+tinymce.trim(i.getParam("noneditable_editable_class","mceEditable"))+" ";g=" "+tinymce.trim(i.getParam("noneditable_noneditable_class","mceNonEditable"))+" ";j=i.getParam("noneditable_regexp");if(j&&!j.length){j=[j]}i.onPreInit.add(function(){b(i);if(j){i.selection.onBeforeSetContent.add(f);i.onBeforeSetContent.add(f)}i.parser.addAttributeFilter("class",function(l){var m=l.length,n,o;while(m--){o=l[m];n=" "+o.attr("class")+" ";if(n.indexOf(h)!==-1){o.attr(d,"true")}else{if(n.indexOf(g)!==-1){o.attr(d,"false")}}}});i.serializer.addAttributeFilter(d,function(l,m){var n=l.length,o;while(n--){o=l[n];if(j&&o.attr("data-mce-content")){o.name="#text";o.type=3;o.raw=true;o.value=o.attr("data-mce-content")}else{o.attr(a,null);o.attr(d,null)}}});i.parser.addAttributeFilter(a,function(l,m){var n=l.length,o;while(n--){o=l[n];o.attr(d,o.attr(a));o.attr(a,null)}})})},getInfo:function(){return{longname:"Non editable elements",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/noneditable",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("noneditable",tinymce.plugins.NonEditablePlugin)})();
@@ -1,454 +0,0 @@
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 TreeWalker = tinymce.dom.TreeWalker;
13
- var externalName = 'contenteditable', internalName = 'data-mce-' + externalName;
14
- var VK = tinymce.VK;
15
-
16
- function handleContentEditableSelection(ed) {
17
- var dom = ed.dom, selection = ed.selection, invisibleChar, caretContainerId = 'mce_noneditablecaret';
18
-
19
- // Setup invisible character use zero width space on Gecko since it doesn't change the height of the container
20
- invisibleChar = tinymce.isGecko ? '\u200B' : '\uFEFF';
21
-
22
- // Returns the content editable state of a node "true/false" or null
23
- function getContentEditable(node) {
24
- var contentEditable;
25
-
26
- // Ignore non elements
27
- if (node.nodeType === 1) {
28
- // Check for fake content editable
29
- contentEditable = node.getAttribute(internalName);
30
- if (contentEditable && contentEditable !== "inherit") {
31
- return contentEditable;
32
- }
33
-
34
- // Check for real content editable
35
- contentEditable = node.contentEditable;
36
- if (contentEditable !== "inherit") {
37
- return contentEditable;
38
- }
39
- }
40
-
41
- return null;
42
- };
43
-
44
- // Returns the noneditable parent or null if there is a editable before it or if it wasn't found
45
- function getNonEditableParent(node) {
46
- var state;
47
-
48
- while (node) {
49
- state = getContentEditable(node);
50
- if (state) {
51
- return state === "false" ? node : null;
52
- }
53
-
54
- node = node.parentNode;
55
- }
56
- };
57
-
58
- // Get caret container parent for the specified node
59
- function getParentCaretContainer(node) {
60
- while (node) {
61
- if (node.id === caretContainerId) {
62
- return node;
63
- }
64
-
65
- node = node.parentNode;
66
- }
67
- };
68
-
69
- // Finds the first text node in the specified node
70
- function findFirstTextNode(node) {
71
- var walker;
72
-
73
- if (node) {
74
- walker = new TreeWalker(node, node);
75
-
76
- for (node = walker.current(); node; node = walker.next()) {
77
- if (node.nodeType === 3) {
78
- return node;
79
- }
80
- }
81
- }
82
- };
83
-
84
- // Insert caret container before/after target or expand selection to include block
85
- function insertCaretContainerOrExpandToBlock(target, before) {
86
- var caretContainer, rng;
87
-
88
- // Select block
89
- if (getContentEditable(target) === "false") {
90
- if (dom.isBlock(target)) {
91
- selection.select(target);
92
- return;
93
- }
94
- }
95
-
96
- rng = dom.createRng();
97
-
98
- if (getContentEditable(target) === "true") {
99
- if (!target.firstChild) {
100
- target.appendChild(ed.getDoc().createTextNode('\u00a0'));
101
- }
102
-
103
- target = target.firstChild;
104
- before = true;
105
- }
106
-
107
- //caretContainer = dom.create('span', {id: caretContainerId, 'data-mce-bogus': true, style:'border: 1px solid red'}, invisibleChar);
108
- caretContainer = dom.create('span', {id: caretContainerId, 'data-mce-bogus': true}, invisibleChar);
109
-
110
- if (before) {
111
- target.parentNode.insertBefore(caretContainer, target);
112
- } else {
113
- dom.insertAfter(caretContainer, target);
114
- }
115
-
116
- rng.setStart(caretContainer.firstChild, 1);
117
- rng.collapse(true);
118
- selection.setRng(rng);
119
-
120
- return caretContainer;
121
- };
122
-
123
- // Removes any caret container except the one we might be in
124
- function removeCaretContainer(caretContainer) {
125
- var child, currentCaretContainer, lastContainer;
126
-
127
- if (caretContainer) {
128
- rng = selection.getRng(true);
129
- rng.setStartBefore(caretContainer);
130
- rng.setEndBefore(caretContainer);
131
-
132
- child = findFirstTextNode(caretContainer);
133
- if (child && child.nodeValue.charAt(0) == invisibleChar) {
134
- child = child.deleteData(0, 1);
135
- }
136
-
137
- dom.remove(caretContainer, true);
138
-
139
- selection.setRng(rng);
140
- } else {
141
- currentCaretContainer = getParentCaretContainer(selection.getStart());
142
- while ((caretContainer = dom.get(caretContainerId)) && caretContainer !== lastContainer) {
143
- if (currentCaretContainer !== caretContainer) {
144
- child = findFirstTextNode(caretContainer);
145
- if (child && child.nodeValue.charAt(0) == invisibleChar) {
146
- child = child.deleteData(0, 1);
147
- }
148
-
149
- dom.remove(caretContainer, true);
150
- }
151
-
152
- lastContainer = caretContainer;
153
- }
154
- }
155
- };
156
-
157
- // Modifies the selection to include contentEditable false elements or insert caret containers
158
- function moveSelection() {
159
- var nonEditableStart, nonEditableEnd, isCollapsed, rng, element;
160
-
161
- // Checks if there is any contents to the left/right side of caret returns the noneditable element or any editable element if it finds one inside
162
- function hasSideContent(element, left) {
163
- var container, offset, walker, node, len;
164
-
165
- container = rng.startContainer;
166
- offset = rng.startOffset;
167
-
168
- // If endpoint is in middle of text node then expand to beginning/end of element
169
- if (container.nodeType == 3) {
170
- len = container.nodeValue.length;
171
- if ((offset > 0 && offset < len) || (left ? offset == len : offset == 0)) {
172
- return;
173
- }
174
- } else {
175
- // Can we resolve the node by index
176
- if (offset < container.childNodes.length) {
177
- // Browser represents caret position as the offset at the start of an element. When moving right
178
- // this is the element we are moving into so we consider our container to be child node at offset-1
179
- var pos = !left && offset > 0 ? offset-1 : offset;
180
- container = container.childNodes[pos];
181
- if (container.hasChildNodes()) {
182
- container = container.firstChild;
183
- }
184
- } else {
185
- // If not then the caret is at the last position in it's container and the caret container should be inserted after the noneditable element
186
- return !left ? element : null;
187
- }
188
- }
189
-
190
- // Walk left/right to look for contents
191
- walker = new TreeWalker(container, element);
192
- while (node = walker[left ? 'prev' : 'next']()) {
193
- if (node.nodeType === 3 && node.nodeValue.length > 0) {
194
- return;
195
- } else if (getContentEditable(node) === "true") {
196
- // Found contentEditable=true element return this one to we can move the caret inside it
197
- return node;
198
- }
199
- }
200
-
201
- return element;
202
- };
203
-
204
- // Remove any existing caret containers
205
- removeCaretContainer();
206
-
207
- // Get noneditable start/end elements
208
- isCollapsed = selection.isCollapsed();
209
- nonEditableStart = getNonEditableParent(selection.getStart());
210
- nonEditableEnd = getNonEditableParent(selection.getEnd());
211
-
212
- // Is any fo the range endpoints noneditable
213
- if (nonEditableStart || nonEditableEnd) {
214
- rng = selection.getRng(true);
215
-
216
- // If it's a caret selection then look left/right to see if we need to move the caret out side or expand
217
- if (isCollapsed) {
218
- nonEditableStart = nonEditableStart || nonEditableEnd;
219
- var start = selection.getStart();
220
- if (element = hasSideContent(nonEditableStart, true)) {
221
- // We have no contents to the left of the caret then insert a caret container before the noneditable element
222
- insertCaretContainerOrExpandToBlock(element, true);
223
- } else if (element = hasSideContent(nonEditableStart, false)) {
224
- // We have no contents to the right of the caret then insert a caret container after the noneditable element
225
- insertCaretContainerOrExpandToBlock(element, false);
226
- } else {
227
- // We are in the middle of a noneditable so expand to select it
228
- selection.select(nonEditableStart);
229
- }
230
- } else {
231
- rng = selection.getRng(true);
232
-
233
- // Expand selection to include start non editable element
234
- if (nonEditableStart) {
235
- rng.setStartBefore(nonEditableStart);
236
- }
237
-
238
- // Expand selection to include end non editable element
239
- if (nonEditableEnd) {
240
- rng.setEndAfter(nonEditableEnd);
241
- }
242
-
243
- selection.setRng(rng);
244
- }
245
- }
246
- };
247
-
248
- function handleKey(ed, e) {
249
- var keyCode = e.keyCode, nonEditableParent, caretContainer, startElement, endElement;
250
-
251
- function getNonEmptyTextNodeSibling(node, prev) {
252
- while (node = node[prev ? 'previousSibling' : 'nextSibling']) {
253
- if (node.nodeType !== 3 || node.nodeValue.length > 0) {
254
- return node;
255
- }
256
- }
257
- };
258
-
259
- function positionCaretOnElement(element, start) {
260
- selection.select(element);
261
- selection.collapse(start);
262
- }
263
-
264
- startElement = selection.getStart()
265
- endElement = selection.getEnd();
266
-
267
- // Disable all key presses in contentEditable=false except delete or backspace
268
- nonEditableParent = getNonEditableParent(startElement) || getNonEditableParent(endElement);
269
- if (nonEditableParent && (keyCode < 112 || keyCode > 124) && keyCode != VK.DELETE && keyCode != VK.BACKSPACE) {
270
- // Is Ctrl+c, Ctrl+v or Ctrl+x then use default browser behavior
271
- if ((tinymce.isMac ? e.metaKey : e.ctrlKey) && (keyCode == 67 || keyCode == 88 || keyCode == 86)) {
272
- return;
273
- }
274
-
275
- e.preventDefault();
276
-
277
- // Arrow left/right select the element and collapse left/right
278
- if (keyCode == VK.LEFT || keyCode == VK.RIGHT) {
279
- var left = keyCode == VK.LEFT;
280
- // If a block element find previous or next element to position the caret
281
- if (ed.dom.isBlock(nonEditableParent)) {
282
- var targetElement = left ? nonEditableParent.previousSibling : nonEditableParent.nextSibling;
283
- var walker = new TreeWalker(targetElement, targetElement);
284
- var caretElement = left ? walker.prev() : walker.next();
285
- positionCaretOnElement(caretElement, !left);
286
- } else {
287
- positionCaretOnElement(nonEditableParent, left);
288
- }
289
- }
290
- } else {
291
- // Is arrow left/right, backspace or delete
292
- if (keyCode == VK.LEFT || keyCode == VK.RIGHT || keyCode == VK.BACKSPACE || keyCode == VK.DELETE) {
293
- caretContainer = getParentCaretContainer(startElement);
294
- if (caretContainer) {
295
- // Arrow left or backspace
296
- if (keyCode == VK.LEFT || keyCode == VK.BACKSPACE) {
297
- nonEditableParent = getNonEmptyTextNodeSibling(caretContainer, true);
298
-
299
- if (nonEditableParent && getContentEditable(nonEditableParent) === "false") {
300
- e.preventDefault();
301
-
302
- if (keyCode == VK.LEFT) {
303
- positionCaretOnElement(nonEditableParent, true);
304
- } else {
305
- dom.remove(nonEditableParent);
306
- }
307
- } else {
308
- removeCaretContainer(caretContainer);
309
- }
310
- }
311
-
312
- // Arrow right or delete
313
- if (keyCode == VK.RIGHT || keyCode == VK.DELETE) {
314
- nonEditableParent = getNonEmptyTextNodeSibling(caretContainer);
315
-
316
- if (nonEditableParent && getContentEditable(nonEditableParent) === "false") {
317
- e.preventDefault();
318
-
319
- if (keyCode == VK.RIGHT) {
320
- positionCaretOnElement(nonEditableParent, false);
321
- } else {
322
- dom.remove(nonEditableParent);
323
- }
324
- } else {
325
- removeCaretContainer(caretContainer);
326
- }
327
- }
328
- }
329
- }
330
- }
331
- };
332
-
333
- ed.onMouseDown.addToTop(function(ed, e) {
334
- var node = ed.selection.getNode();
335
-
336
- if (getContentEditable(node) === "false" && node == e.target) {
337
- // Expand selection on mouse down we can't block the default event since it's used for drag/drop
338
- moveSelection();
339
- }
340
- });
341
-
342
- ed.onMouseUp.addToTop(moveSelection);
343
- ed.onKeyDown.addToTop(handleKey);
344
- ed.onKeyUp.addToTop(moveSelection);
345
- };
346
-
347
- tinymce.create('tinymce.plugins.NonEditablePlugin', {
348
- init : function(ed, url) {
349
- var editClass, nonEditClass, nonEditableRegExps;
350
-
351
- // Converts configured regexps to noneditable span items
352
- function convertRegExpsToNonEditable(ed, args) {
353
- var i = nonEditableRegExps.length, content = args.content, cls = tinymce.trim(nonEditClass);
354
-
355
- // Don't replace the variables when raw is used for example on undo/redo
356
- if (args.format == "raw") {
357
- return;
358
- }
359
-
360
- while (i--) {
361
- content = content.replace(nonEditableRegExps[i], function(match) {
362
- var args = arguments, index = args[args.length - 2];
363
-
364
- // Is value inside an attribute then don't replace
365
- if (index > 0 && content.charAt(index - 1) == '"') {
366
- return match;
367
- }
368
-
369
- return '<span class="' + cls + '" data-mce-content="' + ed.dom.encode(args[0]) + '">' + ed.dom.encode(typeof(args[1]) === "string" ? args[1] : args[0]) + '</span>';
370
- });
371
- }
372
-
373
- args.content = content;
374
- };
375
-
376
- editClass = " " + tinymce.trim(ed.getParam("noneditable_editable_class", "mceEditable")) + " ";
377
- nonEditClass = " " + tinymce.trim(ed.getParam("noneditable_noneditable_class", "mceNonEditable")) + " ";
378
-
379
- // Setup noneditable regexps array
380
- nonEditableRegExps = ed.getParam("noneditable_regexp");
381
- if (nonEditableRegExps && !nonEditableRegExps.length) {
382
- nonEditableRegExps = [nonEditableRegExps];
383
- }
384
-
385
- ed.onPreInit.add(function() {
386
- handleContentEditableSelection(ed);
387
-
388
- if (nonEditableRegExps) {
389
- ed.selection.onBeforeSetContent.add(convertRegExpsToNonEditable);
390
- ed.onBeforeSetContent.add(convertRegExpsToNonEditable);
391
- }
392
-
393
- // Apply contentEditable true/false on elements with the noneditable/editable classes
394
- ed.parser.addAttributeFilter('class', function(nodes) {
395
- var i = nodes.length, className, node;
396
-
397
- while (i--) {
398
- node = nodes[i];
399
- className = " " + node.attr("class") + " ";
400
-
401
- if (className.indexOf(editClass) !== -1) {
402
- node.attr(internalName, "true");
403
- } else if (className.indexOf(nonEditClass) !== -1) {
404
- node.attr(internalName, "false");
405
- }
406
- }
407
- });
408
-
409
- // Remove internal name
410
- ed.serializer.addAttributeFilter(internalName, function(nodes, name) {
411
- var i = nodes.length, node;
412
-
413
- while (i--) {
414
- node = nodes[i];
415
-
416
- if (nonEditableRegExps && node.attr('data-mce-content')) {
417
- node.name = "#text";
418
- node.type = 3;
419
- node.raw = true;
420
- node.value = node.attr('data-mce-content');
421
- } else {
422
- node.attr(externalName, null);
423
- node.attr(internalName, null);
424
- }
425
- }
426
- });
427
-
428
- // Convert external name into internal name
429
- ed.parser.addAttributeFilter(externalName, function(nodes, name) {
430
- var i = nodes.length, node;
431
-
432
- while (i--) {
433
- node = nodes[i];
434
- node.attr(internalName, node.attr(externalName));
435
- node.attr(externalName, null);
436
- }
437
- });
438
- });
439
- },
440
-
441
- getInfo : function() {
442
- return {
443
- longname : 'Non editable elements',
444
- author : 'Moxiecode Systems AB',
445
- authorurl : 'http://tinymce.moxiecode.com',
446
- infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/noneditable',
447
- version : tinymce.majorVersion + "." + tinymce.minorVersion
448
- };
449
- }
450
- });
451
-
452
- // Register plugin
453
- tinymce.PluginManager.add('noneditable', tinymce.plugins.NonEditablePlugin);
454
- })();