jquery.custom.imitate.editor-v1.0.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. 自定义工具
  3. I am liangzhenyu
  4. 2018-05-25
  5. */
  6. /*
  7. 插件 - 仿sublime和notepad++
  8. 兼容:IE9+
  9. 使用方法说明:
  10. 1.此插件基于jQuery编写,使用时需要先导入jQuery;
  11. 2.$(selector).initTextarea();//编辑框的样式是根据textarea的样式获取,所以textarea的样式根据自己所需而配置
  12. */
  13. ;(function ($, window, document, undefined) {
  14. var ImitateEditor = function (ele) {
  15. var rW = 35;
  16. this.$textarea = $(ele).attr({"wrap": "off"});
  17. this.$container = $("<div></div>").css({
  18. "position": this.$textarea.css("position") === ("absolute" || "fixed") ? this.$textarea.css("position") : "relative",
  19. "display": this.$textarea.css("display") === "inline" ? "inline-block" : this.$textarea.css("display"),
  20. "width": this.$textarea.outerWidth(true),
  21. "height": this.$textarea.outerHeight(true),
  22. "margin-top": this.$textarea.css("margin-top"),
  23. "margin-right": this.$textarea.css("margin-right"),
  24. "margin-bottom": this.$textarea.css("margin-bottom"),
  25. "margin-left": this.$textarea.css("margin-left"),
  26. }).attr("name", "textarea");
  27. this.$textarea.css({
  28. "position": "absolute",
  29. "top": "0",
  30. "left": "0",
  31. "white-space": "pre",
  32. "resize": "none",
  33. "line-height": this.$textarea.css("font-size"),
  34. "outline": "none",
  35. "width": this.$textarea.width() - rW - 3,
  36. "padding-left": rW + 3,
  37. "margin": "0",
  38. "z-index": 1,
  39. "overflow": "auto"
  40. });
  41. this.$rowsNav = $("<div></div>").css({
  42. "position": "absolute",
  43. "top": tools.isFire() || tools.isIE() ? this.$textarea.css("border-top-width") : "0",
  44. "left": tools.isFire() || tools.isIE() ? this.$textarea.css("border-left-width") : "0",
  45. "padding-left": 0,
  46. "padding-right": 0,
  47. "padding-top": tools.parseVal(this.$textarea.css("padding-top")),
  48. "padding-bottom": tools.parseVal(this.$textarea.css("padding-bottom")),
  49. "background-color": tools.navColor(this.$textarea.css("background-color")),
  50. "border": this.$textarea.css("border"),
  51. "border-right": "none",
  52. "float": "left",
  53. "width": rW,
  54. "height": this.$textarea.height() + 'px',
  55. "z-index": 2
  56. });
  57. this.$rows = $("<div></div>").css({
  58. "color": tools.hoverColor(this.$textarea.css("color"), .8),
  59. "width": rW,
  60. "height": this.$textarea.height(),
  61. "font-size": this.$textarea.css("font-size"),
  62. "line-height": this.$textarea.css("line-height"),
  63. "overflow": "hidden",
  64. "margin": 0,
  65. "text-align": "center",
  66. "font-family": "仿宋",
  67. "display": "inline-block"
  68. });
  69. };
  70. ImitateEditor.prototype = {
  71. initEvent: function () {
  72. var _this = this;
  73. _this.$textarea.wrap(_this.$container).on('keydown', function () {
  74. _this.inputText();
  75. }).on('scroll', function () {
  76. _this.syncScroll();
  77. }).on('click', function () {
  78. _this.syncIndex();
  79. }).on('keyup', function () {
  80. _this.inputText();
  81. _this.syncIndex();
  82. });
  83. _this.$rowsNav.append(_this.$rows).insertBefore(_this.$textarea).on("mousewheel DOMMouseScroll", function (e) {
  84. var delta = (e.originalEvent.wheelDelta && (e.originalEvent.wheelDelta > 0 ? 1 : -1)) || // chrome & ie
  85. (e.originalEvent.detail && (e.originalEvent.detail > 0 ? -1 : 1));// firefox
  86. var oft = delta > 0 ? -10 : 10, idx = 0;
  87. var dynamic = setInterval(function () {
  88. _this.$textarea.get(0).scrollTop += oft;
  89. if (idx++ >= 10) {
  90. clearInterval(dynamic);
  91. _this.syncScroll();
  92. }
  93. }, 10);
  94. });
  95. _this.inputText();
  96. },
  97. inputText: function () {
  98. var _this = this;
  99. setTimeout(function () {
  100. var value = _this.$textarea.val();
  101. value.match(/\n/g) ? _this.updateLine(value.match(/\n/g).length + 1) : _this.updateLine(1);
  102. _this.syncScroll();
  103. }, 0);
  104. },
  105. updateLine: function (count) {
  106. var rowLen = this.$rows.children().length, i = rowLen;
  107. if (count > rowLen) for (; i < count; i++) this.$rows.append("<div style='cursor:default;text-align: right;padding-right: 5px;'>" + (i + 1) + "</div>");
  108. if (count < rowLen) for (; i > count; i--) this.$rows.children().eq(i - 1).remove();
  109. },
  110. syncScroll: function () {
  111. this.$rows.children().eq(0).css("margin-top", -(this.$textarea.scrollTop()) + "px");
  112. var curH = this.$textarea.innerHeight(),
  113. paddingBottom = parseInt(this.$textarea.css("padding-bottom").toString().replace("px", ""));
  114. if (this.$textarea.get(0).scrollWidth > this.$textarea.innerWidth()) {
  115. curH = this.$textarea.innerHeight() - 17;
  116. this.$rows.css("height", curH - paddingBottom);
  117. this.$rowsNav.css({
  118. "height": curH - paddingBottom,
  119. "padding-bottom": 0,
  120. "border-bottom": "none",
  121. });
  122. } else {
  123. this.$rows.css("height", curH - paddingBottom * 2);
  124. this.$rowsNav.css({
  125. "height": curH - paddingBottom * 2,
  126. "padding-bottom": paddingBottom,
  127. "border-bottom": this.$textarea.css("border-bottom"),
  128. });
  129. }
  130. },
  131. syncIndex: function () {
  132. var start = this.$textarea.get(0).selectionStart;
  133. // if (tools.isIE() <= 8) {
  134. // var selection = document.selection;
  135. // range = selection.createRange();
  136. // var stored_range = range.duplicate();
  137. // stored_range.moveToElementText(this.$textarea.get(0));
  138. // stored_range.setEndPoint('EndToEnd', range);
  139. // console.log(stored_range)
  140. // start = stored_range.text.length - range.text.length;
  141. // var cur = stored_range.text.split("\n").length;
  142. // if (cur >= 2) start -= (cur - 1);
  143. // }
  144. var line = this.$textarea.val().substring(0, start).split("\n").length;
  145. this.$rows.children().eq(line - 1).css("background-color", tools.hoverColor(this.$rowsNav.css("background-color"), 0.9))
  146. .siblings().css("background-color", "transparent");
  147. }
  148. };
  149. var tools = {
  150. toRgb: function (color) {
  151. eval(function (p, a, c, k, e, d) {
  152. e = function (c) {
  153. return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
  154. };
  155. if (!''.replace(/^/, String)) {
  156. while (c--) d[e(c)] = k[c] || e(c);
  157. k = [function (e) {
  158. return d[e]
  159. }];
  160. e = function () {
  161. return '\\w+'
  162. };
  163. c = 1;
  164. }
  165. while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]);
  166. return p;
  167. }('28 29={2a:{r:4,g:p,b:1},27:{r:3,g:B,b:W},23:{r:0,g:1,b:1},24:{r:i,g:1,b:26},2b:{r:4,g:1,b:1},2g:{r:6,g:6,b:d},2h:{r:1,g:y,b:Y},2i:{r:0,g:0,b:0},2f:{r:1,g:B,b:7},2c:{r:0,g:0,b:1},2d:{r:2e,g:43,b:1Q},1R:{r:s,g:42,b:42},1S:{r:n,g:N,b:D},1P:{r:1M,g:1N,b:l},1O:{r:i,g:1,b:0},1T:{r:u,g:a,b:30},1Y:{r:1,g:i,b:1Z},22:{r:P,g:1X,b:1U},1V:{r:1,g:p,b:d},1W:{r:d,g:20,b:15},2C:{r:0,g:1,b:1},2D:{r:0,g:0,b:5},2E:{r:0,g:5,b:5},2B:{r:N,g:2y,b:11},2z:{r:z,g:z,b:z},2A:{r:0,g:P,b:0},2F:{r:2K,g:2L,b:q},2M:{r:5,g:0,b:5},2J:{r:13,g:q,b:47},2G:{r:1,g:F,b:0},2H:{r:S,g:o,b:14},2I:{r:5,g:0,b:0},2n:{r:2o,g:2p,b:I},2m:{r:m,g:J,b:m},2j:{r:10,g:2k,b:5},2l:{r:47,g:Q,b:Q},2q:{r:0,g:C,b:A},2v:{r:2w,g:0,b:h},2x:{r:1,g:20,b:w},2u:{r:0,g:12,b:1},2r:{r:a,g:a,b:a},2s:{r:30,g:e,b:1},2t:{r:A,g:1L,b:1i},1h:{r:V,g:34,b:34},1g:{r:1,g:3,b:4},1n:{r:34,g:5,b:34},1o:{r:1,g:0,b:1},1m:{r:d,g:d,b:d},16:{r:p,g:p,b:1},1b:{r:1,g:W,b:0},1E:{r:v,g:s,b:32},1F:{r:2,g:2,b:2},1C:{r:0,g:2,b:0},1G:{r:x,g:1,b:47},1H:{r:4,g:1,b:4},1t:{r:1,g:a,b:G},1u:{r:7,g:M,b:M},1r:{r:1y,g:0,b:E},1v:{r:1,g:1,b:4},1w:{r:4,g:9,b:F},1z:{r:9,g:9,b:3},1D:{r:1,g:4,b:6},1p:{r:1c,g:1a,b:0},1d:{r:1,g:3,b:7},1e:{r:x,g:f,b:9},1k:{r:4,g:2,b:2},1l:{r:j,g:1,b:1},1J:{r:3,g:3,b:u},1K:{r:h,g:h,b:h},1I:{r:e,g:8,b:e},1A:{r:1,g:1s,b:1x},1q:{r:1,g:l,b:I},1B:{r:32,g:V,b:t},18:{r:D,g:C,b:3},17:{r:1f,g:c,b:1},1j:{r:4o,g:4t,b:S},3Q:{r:X,g:Y,b:n},3P:{r:1,g:1,b:j},3S:{r:0,g:1,b:0},3K:{r:o,g:7,b:o},3X:{r:3,g:4,b:9},40:{r:1,g:0,b:1},3Y:{r:2,g:0,b:0},3Z:{r:3V,g:7,b:t},3W:{r:0,g:0,b:7},49:{r:4a,g:13,b:h},4b:{r:w,g:c,b:f},41:{r:15,g:K,b:44},48:{r:3U,g:3L,b:8},3M:{r:0,g:3,b:U},3N:{r:10,g:A,b:14},3I:{r:3J,g:21,b:R},3R:{r:25,g:25,b:c},3T:{r:6,g:1,b:3},3O:{r:1,g:y,b:H},4c:{r:1,g:y,b:4s},4u:{r:1,g:n,b:x},4p:{r:0,g:0,b:2},4q:{r:4r,g:6,b:9},4x:{r:2,g:2,b:0},4w:{r:q,g:4v,b:35},4g:{r:1,g:s,b:0},4h:{r:1,g:L,b:0},4f:{r:v,g:c,b:4d},4e:{r:8,g:4i,b:t},4m:{r:T,g:4n,b:T},4l:{r:4j,g:8,b:8},4k:{r:f,g:c,b:w},37:{r:1,g:38,b:39},31:{r:1,g:v,b:33},36:{r:7,g:R,b:3a},3e:{r:1,g:k,b:3f},3g:{r:Z,g:l,b:Z},3b:{r:X,g:j,b:9},3c:{r:2,g:0,b:2},3d:{r:1,g:0,b:0},2Q:{r:J,g:m,b:m},2R:{r:2S,g:a,b:H},2N:{r:5,g:L,b:19},2O:{r:3,g:2,b:2P},2T:{r:2X,g:2Y,b:2Z},2U:{r:46,g:5,b:2V},2W:{r:1,g:6,b:8},3h:{r:l,g:3y,b:45},3z:{r:k,g:k,b:k},3A:{r:D,g:C,b:B},3v:{r:3w,g:3x,b:7},3B:{r:c,g:2,b:e},3F:{r:1,g:3,b:3},3G:{r:0,g:1,b:i},3H:{r:3C,g:E,b:G},3D:{r:u,g:G,b:F},3E:{r:0,g:2,b:2},3l:{r:f,g:12,b:f},3m:{r:1,g:3n,b:3i},3j:{r:3k,g:j,b:O},3o:{r:8,g:E,b:8},3s:{r:O,g:32,b:e},3t:{r:6,g:n,b:K},3u:{r:1,g:1,b:1},3p:{r:6,g:6,b:6},3q:{r:1,g:1,b:0},3r:{r:U,g:7,b:o}};', 62, 282, '|255|128|250|240|139|245|205|238|230|105||112|220|144|216||211|127|224|192|160|143|222|50|248|107||165|170|210|218|147|173|228|169|209|235|206|135|130|140|180|225|122|188|179|69|92|184|208|100|79|133|153|152|154|178|215|176|196|221|72||191|85|204|60|ghostwhite|lightslateblue|lightskyblue||252|gold|124|lemonchiffon|lightblue|132|floralwhite|firebrick|117|lightslategray|lightcoral|lightcyan|gainsboro|forestgreen|fuchsia|lawngreen|lightsalmon|indigo|182|hotpink|indianred|ivory|khaki|193|75|lavender|lightpink|lightseagreen|green|lavenderblush|goldenrod|gray|greenyellow|honeydew|lightgreen|lightgoldenrodyellow|lightgrey|146|95|158|chartreuse|cadetblue|226|brown|burlywood|chocolate|237|cornsilk|crimson|149|coral|80|||cornflowerblue|aqua|aquamarine||212|antiquewhite|var|EN_COLOR|aliceblue|azure|blue|blueviolet|138|blanchedalmond|beige|bisque|black|darkslateblue|61|darkslategray|darkseagreen|darksalmon|233|150|darkturquoise|dimgray|dodgerblue|feldspar|deepskyblue|darkviolet|148|deeppink|134|darkgray|darkgreen|darkgoldenrod|cyan|darkblue|darkcyan|darkkhaki|darkorange|darkorchid|darkred|darkolivegreen|189|183|darkmagenta|saddlebrown|salmon|114|rosybrown|royalblue|65|sandybrown|seagreen|87|seashell|244|164|96||peachpuff||185|||peru|papayawhip|239|213|63|powderblue|purple|red|pink|203|plum|sienna|71|turquoise|64|thistle|tomato|99|violet|whitesmoke|yellow|yellowgreen|violetred|wheat|white|slateblue|106|90|82|silver|skyblue|slategray|70|tan|teal|snow|springgreen|steelblue|mediumvioletred|199|limegreen|104|mediumspringgreen|mediumturquoise|mistyrose|lightyellow|lightsteelblue|midnightblue|lime|mintcream|123|102|mediumblue|linen|maroon|mediumaquamarine|magenta|mediumseagreen|||113||||mediumslateblue|mediumorchid|186|mediumpurple|moccasin|214|palegoldenrod|orchid|orange|orangered|232|175|palevioletred|paleturquoise|palegreen|251|119|navy|oldlace|253|181|136|navajowhite|142|olivedrab|olive'.split('|'), 0, {}));
  168. var sColor = color.toLowerCase().replace(/\s/g, "");
  169. if (sColor && /^#([0-9a-f]{3}|[0-9a-f]{6})$/.test(sColor)) {
  170. if (sColor.length === 4) {
  171. var sColorNew = "#";
  172. for (var i = 1; i < 4; i += 1) sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
  173. sColor = sColorNew;
  174. }
  175. var sColorChange = [];
  176. for (var i = 1; i < 7; i += 2) sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
  177. return {r: parseInt(sColorChange[0]), g: parseInt(sColorChange[1]), b: parseInt(sColorChange[2])};
  178. } else if (sColor.indexOf("rgb") >= 0) {
  179. var arrRgb = sColor.replace("rgb(", "").replace(")", "").replace(/%/g, "").split(",");
  180. if (sColor.indexOf("%") >= 0) {
  181. return {
  182. r: parseInt(arrRgb[0] / 100 * 255),
  183. g: parseInt(arrRgb[1] / 100 * 255),
  184. b: parseInt(arrRgb[2] / 100 * 255)
  185. };
  186. }
  187. return {r: parseInt(arrRgb[0]), g: parseInt(arrRgb[1]), b: parseInt(arrRgb[2])};
  188. } else {
  189. if (!EN_COLOR[sColor]) return null;
  190. return EN_COLOR[sColor];
  191. }
  192. },
  193. hoverColor: function (color, oft) {
  194. oft = oft || 0.5;
  195. var rgb = this.toRgb(color);
  196. var r = rgb.r, g = rgb.g, b = rgb.b;
  197. if (r <= 50 && g <= 50 && b <= 50) return "rgb(" + parseInt((50 + r) * oft) + "," + parseInt((50 + g) * oft) + "," + parseInt((50 + b) * oft) + ")";
  198. return "rgb(" + parseInt(r * oft) + "," + parseInt(g * oft) + "," + parseInt(b * oft) + ")";//暗颜色
  199. },
  200. navColor: function (color) {
  201. var rgb = this.toRgb(color);
  202. if (rgb.r > 234 && rgb.g > 234 && rgb.b > 234) return "rgb(234,234,234)";
  203. if (rgb.r < 50 && rgb.g < 50 && rgb.b < 50) return "rgb(50,50,50)";
  204. return color;
  205. },
  206. parseVal: function (val) {
  207. if (!val) return 0;
  208. return parseInt(val.toString().replace("px", ""));
  209. },
  210. isIE: function () {
  211. var userAgent = navigator.userAgent;
  212. var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器
  213. var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
  214. var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
  215. if (isEdge) return "edge";
  216. if (isIE11) return 11;
  217. if (isIE) {
  218. var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
  219. reIE.test(userAgent);
  220. var fIEVersion = parseInt(RegExp["$1"]);
  221. if (fIEVersion === 7) return 7;
  222. else if (fIEVersion === 8) return 8;
  223. else if (fIEVersion === 9) return 9;
  224. else if (fIEVersion === 10) return 10;
  225. else return 0;
  226. }
  227. return false;
  228. },
  229. isFire: function () {
  230. return navigator.userAgent.indexOf("Firefox") > -1;
  231. }
  232. };
  233. $.fn.initTextarea = function () {
  234. this.each(function () {
  235. var $this = $(this), imitateEditor = $this.data('lzyTextarea');
  236. if (!imitateEditor) {
  237. imitateEditor = new ImitateEditor($this);
  238. $this.data('lzyTextarea', imitateEditor);
  239. }
  240. imitateEditor.initEvent();
  241. });
  242. }
  243. })(jQuery, window, document);