spud_core 0.8.28 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
- })();