adminpanel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +13 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +34 -0
  5. data/Rakefile +1 -0
  6. data/adminpanel.gemspec +32 -0
  7. data/app/assets/fonts/.DS_Store +0 -0
  8. data/app/assets/fonts/FontAwesome.otf +0 -0
  9. data/app/assets/fonts/fontawesome-webfont.eot +0 -0
  10. data/app/assets/fonts/fontawesome-webfont.svg +255 -0
  11. data/app/assets/fonts/fontawesome-webfont.ttf +0 -0
  12. data/app/assets/fonts/fontawesome-webfont.woff +0 -0
  13. data/app/assets/images/adminpanel/alpha.png +0 -0
  14. data/app/assets/images/adminpanel/arrows-active.png +0 -0
  15. data/app/assets/images/adminpanel/arrows-normal.png +0 -0
  16. data/app/assets/images/adminpanel/bgnoise.png +0 -0
  17. data/app/assets/images/adminpanel/crop.gif +0 -0
  18. data/app/assets/images/adminpanel/dialogs.png +0 -0
  19. data/app/assets/images/adminpanel/dotted.png +0 -0
  20. data/app/assets/images/adminpanel/favicon.ico +0 -0
  21. data/app/assets/images/adminpanel/glyphicons-halflings-white.png +0 -0
  22. data/app/assets/images/adminpanel/glyphicons-halflings.png +0 -0
  23. data/app/assets/images/adminpanel/gritter-light.png +0 -0
  24. data/app/assets/images/adminpanel/gritter-long.png +0 -0
  25. data/app/assets/images/adminpanel/gritter.png +0 -0
  26. data/app/assets/images/adminpanel/hue.png +0 -0
  27. data/app/assets/images/adminpanel/icons-big.png +0 -0
  28. data/app/assets/images/adminpanel/icons-small.png +0 -0
  29. data/app/assets/images/adminpanel/ie-spacer.gif +0 -0
  30. data/app/assets/images/adminpanel/odinn.jpg +0 -0
  31. data/app/assets/images/adminpanel/pattern.jpg +0 -0
  32. data/app/assets/images/adminpanel/pattern_transp.png +0 -0
  33. data/app/assets/images/adminpanel/progress.gif +0 -0
  34. data/app/assets/images/adminpanel/quicklook-bg.png +0 -0
  35. data/app/assets/images/adminpanel/quicklook-icons.png +0 -0
  36. data/app/assets/images/adminpanel/rails.png +0 -0
  37. data/app/assets/images/adminpanel/resize.png +0 -0
  38. data/app/assets/images/adminpanel/saturation.png +0 -0
  39. data/app/assets/images/adminpanel/select2.png +0 -0
  40. data/app/assets/images/adminpanel/select2x2.png +0 -0
  41. data/app/assets/images/adminpanel/sidebar.png +0 -0
  42. data/app/assets/images/adminpanel/sort_asc.png +0 -0
  43. data/app/assets/images/adminpanel/sort_asc_disabled.png +0 -0
  44. data/app/assets/images/adminpanel/sort_both.png +0 -0
  45. data/app/assets/images/adminpanel/sort_desc.png +0 -0
  46. data/app/assets/images/adminpanel/sort_desc_disabled.png +0 -0
  47. data/app/assets/images/adminpanel/spinner-mini.gif +0 -0
  48. data/app/assets/images/adminpanel/spinner.gif +0 -0
  49. data/app/assets/images/adminpanel/toolbar.png +0 -0
  50. data/app/assets/javascripts/adminpanel/bootstrap-datepicker.js +1159 -0
  51. data/app/assets/javascripts/adminpanel/bootstrap-timepicker.js +803 -0
  52. data/app/assets/javascripts/adminpanel/bootstrap.js +2170 -0
  53. data/app/assets/javascripts/adminpanel/imagesloaded.js +13 -0
  54. data/app/assets/javascripts/adminpanel/init_editor.js +28 -0
  55. data/app/assets/javascripts/adminpanel/jquery.dataTables.min.js +155 -0
  56. data/app/assets/javascripts/adminpanel/jquery.facybox.js +395 -0
  57. data/app/assets/javascripts/adminpanel/jquery.masonry.min.js +10 -0
  58. data/app/assets/javascripts/adminpanel/jquery.slimscroll.min.js +14 -0
  59. data/app/assets/javascripts/adminpanel/medium-editor.js +703 -0
  60. data/app/assets/javascripts/adminpanel/products.js +14 -0
  61. data/app/assets/javascripts/adminpanel/realm.js +90 -0
  62. data/app/assets/javascripts/adminpanel/tables.js +126 -0
  63. data/app/assets/javascripts/application-admin.js +16 -0
  64. data/app/assets/stylesheets/adminpanel/_clearfix.css.scss +8 -0
  65. data/app/assets/stylesheets/adminpanel/alertify.css +242 -0
  66. data/app/assets/stylesheets/adminpanel/bootstrap.css +6103 -0
  67. data/app/assets/stylesheets/adminpanel/colorpicker.css +7 -0
  68. data/app/assets/stylesheets/adminpanel/datepicker.css +9 -0
  69. data/app/assets/stylesheets/adminpanel/elfinder.min.css +59 -0
  70. data/app/assets/stylesheets/adminpanel/facybox.css +146 -0
  71. data/app/assets/stylesheets/adminpanel/font-awesome.min.css +34 -0
  72. data/app/assets/stylesheets/adminpanel/fullcalendar.css +618 -0
  73. data/app/assets/stylesheets/adminpanel/fullcalendar.print.css +61 -0
  74. data/app/assets/stylesheets/adminpanel/medium-editor.css.scss +1 -0
  75. data/app/assets/stylesheets/adminpanel/select2.css +524 -0
  76. data/app/assets/stylesheets/adminpanel/theme.css +1563 -0
  77. data/app/assets/stylesheets/adminpanel/timepicker.css +82 -0
  78. data/app/assets/stylesheets/application-admin.css +14 -0
  79. data/app/controllers/adminpanel/application_controller.rb +18 -0
  80. data/app/controllers/adminpanel/categories_controller.rb +41 -0
  81. data/app/controllers/adminpanel/galleries_controller.rb +45 -0
  82. data/app/controllers/adminpanel/products_controller.rb +87 -0
  83. data/app/controllers/adminpanel/sections_controller.rb +46 -0
  84. data/app/controllers/adminpanel/sessions_controller.rb +26 -0
  85. data/app/controllers/adminpanel/users_controller.rb +85 -0
  86. data/app/helpers/adminpanel/application_helper.rb +73 -0
  87. data/app/helpers/custom_form_builder.rb +219 -0
  88. data/app/models/adminpanel/category.rb +7 -0
  89. data/app/models/adminpanel/contact.rb +25 -0
  90. data/app/models/adminpanel/gallery.rb +10 -0
  91. data/app/models/adminpanel/image.rb +6 -0
  92. data/app/models/adminpanel/product.rb +24 -0
  93. data/app/models/adminpanel/section.rb +16 -0
  94. data/app/models/adminpanel/user.rb +35 -0
  95. data/app/uploaders/adminpanel/gallery_uploader.rb +56 -0
  96. data/app/uploaders/adminpanel/image_uploader.rb +63 -0
  97. data/app/uploaders/adminpanel/section_uploader.rb +56 -0
  98. data/app/views/adminpanel/.DS_Store +0 -0
  99. data/app/views/adminpanel/categories/edit.html.erb +18 -0
  100. data/app/views/adminpanel/categories/index.html.erb +55 -0
  101. data/app/views/adminpanel/categories/new.html.erb +18 -0
  102. data/app/views/adminpanel/categories/show.html.erb +0 -0
  103. data/app/views/adminpanel/galleries/create.html.erb +2 -0
  104. data/app/views/adminpanel/galleries/delete.html.erb +2 -0
  105. data/app/views/adminpanel/galleries/edit.html.erb +26 -0
  106. data/app/views/adminpanel/galleries/index.html.erb +60 -0
  107. data/app/views/adminpanel/galleries/new.html.erb +18 -0
  108. data/app/views/adminpanel/galleries/show.html.erb +18 -0
  109. data/app/views/adminpanel/galleries/update.html.erb +2 -0
  110. data/app/views/adminpanel/products/.DS_Store +0 -0
  111. data/app/views/adminpanel/products/_image_fields.html.erb +24 -0
  112. data/app/views/adminpanel/products/_product_form.html.erb +31 -0
  113. data/app/views/adminpanel/products/edit.html.erb +10 -0
  114. data/app/views/adminpanel/products/index.html.erb +57 -0
  115. data/app/views/adminpanel/products/new.html.erb +10 -0
  116. data/app/views/adminpanel/products/show.html.erb +61 -0
  117. data/app/views/adminpanel/sections/_image_fields.html.erb +24 -0
  118. data/app/views/adminpanel/sections/create.html.erb +2 -0
  119. data/app/views/adminpanel/sections/destroy.html.erb +2 -0
  120. data/app/views/adminpanel/sections/edit.html.erb +40 -0
  121. data/app/views/adminpanel/sections/index.html.erb +38 -0
  122. data/app/views/adminpanel/sections/new.html.erb +27 -0
  123. data/app/views/adminpanel/sections/show.html.erb +28 -0
  124. data/app/views/adminpanel/sections/update.html.erb +2 -0
  125. data/app/views/adminpanel/sessions/new.html.erb +26 -0
  126. data/app/views/adminpanel/users/_form.html.erb +33 -0
  127. data/app/views/adminpanel/users/edit.html.erb +22 -0
  128. data/app/views/adminpanel/users/index.html.erb +55 -0
  129. data/app/views/adminpanel/users/new.html.erb +22 -0
  130. data/app/views/adminpanel/users/show.html.erb +21 -0
  131. data/app/views/layouts/_shim.html.erb +4 -0
  132. data/app/views/layouts/_side_menu.html.erb +45 -0
  133. data/app/views/layouts/_top_bar.html.erb +43 -0
  134. data/app/views/layouts/admin.html.erb +45 -0
  135. data/app/views/shared/_breadcrumb.html.erb +6 -0
  136. data/app/views/shared/_error_messages.html.erb +17 -0
  137. data/config/locales/en.yml +5 -0
  138. data/config/locales/es.yml +202 -0
  139. data/config/routes.rb +11 -0
  140. data/lib/adminpanel.rb +8 -0
  141. data/lib/adminpanel/engine.rb +5 -0
  142. data/lib/adminpanel/version.rb +3 -0
  143. metadata +349 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * jQuery Masonry v2.1.06
3
+ * A dynamic layout plugin for jQuery
4
+ * The flip-side of CSS Floats
5
+ * http://masonry.desandro.com
6
+ *
7
+ * Licensed under the MIT license.
8
+ * Copyright 2012 David DeSandro
9
+ */
10
+ (function(a,b,c){"use strict";var d=b.event,e;d.special.smartresize={setup:function(){b(this).bind("resize",d.special.smartresize.handler)},teardown:function(){b(this).unbind("resize",d.special.smartresize.handler)},handler:function(a,c){var d=this,f=arguments;a.type="smartresize",e&&clearTimeout(e),e=setTimeout(function(){b.event.handle.apply(d,f)},c==="execAsap"?0:100)}},b.fn.smartresize=function(a){return a?this.bind("smartresize",a):this.trigger("smartresize",["execAsap"])},b.Mason=function(a,c){this.element=b(c),this._create(a),this._init()},b.Mason.settings={isResizable:!0,isAnimated:!1,animationOptions:{queue:!1,duration:500},gutterWidth:0,isRTL:!1,isFitWidth:!1,containerStyle:{position:"relative"}},b.Mason.prototype={_filterFindBricks:function(a){var b=this.options.itemSelector;return b?a.filter(b).add(a.find(b)):a},_getBricks:function(a){var b=this._filterFindBricks(a).css({position:"absolute"}).addClass("masonry-brick");return b},_create:function(c){this.options=b.extend(!0,{},b.Mason.settings,c),this.styleQueue=[];var d=this.element[0].style;this.originalStyle={height:d.height||""};var e=this.options.containerStyle;for(var f in e)this.originalStyle[f]=d[f]||"";this.element.css(e),this.horizontalDirection=this.options.isRTL?"right":"left";var g=this.element.css("padding-"+this.horizontalDirection),h=this.element.css("padding-top");this.offset={x:g?parseInt(g,10):0,y:h?parseInt(h,10):0},this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth=="function";var i=this;setTimeout(function(){i.element.addClass("masonry")},0),this.options.isResizable&&b(a).bind("smartresize.masonry",function(){i.resize()}),this.reloadItems()},_init:function(a){this._getColumns(),this._reLayout(a)},option:function(a,c){b.isPlainObject(a)&&(this.options=b.extend(!0,this.options,a))},layout:function(a,b){for(var c=0,d=a.length;c<d;c++)this._placeBrick(a[c]);var e={};e.height=Math.max.apply(Math,this.colYs);if(this.options.isFitWidth){var f=0;c=this.cols;while(--c){if(this.colYs[c]!==0)break;f++}e.width=(this.cols-f)*this.columnWidth-this.options.gutterWidth}this.styleQueue.push({$el:this.element,style:e});var g=this.isLaidOut?this.options.isAnimated?"animate":"css":"css",h=this.options.animationOptions,i;for(c=0,d=this.styleQueue.length;c<d;c++)i=this.styleQueue[c],i.$el[g](i.style,h);this.styleQueue=[],b&&b.call(a),this.isLaidOut=!0},_getColumns:function(){var a=this.options.isFitWidth?this.element.parent():this.element,b=a.width();this.columnWidth=this.isFluid?this.options.columnWidth(b):this.options.columnWidth||this.$bricks.outerWidth(!0)||b,this.columnWidth+=this.options.gutterWidth,this.cols=Math.floor((b+this.options.gutterWidth)/this.columnWidth),this.cols=Math.max(this.cols,1)},_placeBrick:function(a){var c=b(a),d,e,f,g,h;d=Math.ceil(c.outerWidth(!0)/this.columnWidth),d=Math.min(d,this.cols);if(d===1)f=this.colYs;else{e=this.cols+1-d,f=[];for(h=0;h<e;h++)g=this.colYs.slice(h,h+d),f[h]=Math.max.apply(Math,g)}var i=Math.min.apply(Math,f),j=0;for(var k=0,l=f.length;k<l;k++)if(f[k]===i){j=k;break}var m={top:i+this.offset.y};m[this.horizontalDirection]=this.columnWidth*j+this.offset.x,this.styleQueue.push({$el:c,style:m});var n=i+c.outerHeight(!0),o=this.cols+1-l;for(k=0;k<o;k++)this.colYs[j+k]=n},resize:function(){var a=this.cols;this._getColumns(),(this.isFluid||this.cols!==a)&&this._reLayout()},_reLayout:function(a){var b=this.cols;this.colYs=[];while(b--)this.colYs.push(0);this.layout(this.$bricks,a)},reloadItems:function(){this.$bricks=this._getBricks(this.element.children())},reload:function(a){this.reloadItems(),this._init(a)},appended:function(a,b,c){if(b){this._filterFindBricks(a).css({top:this.element.height()});var d=this;setTimeout(function(){d._appended(a,c)},1)}else this._appended(a,c)},_appended:function(a,b){var c=this._getBricks(a);this.$bricks=this.$bricks.add(c),this.layout(c,b)},remove:function(a){this.$bricks=this.$bricks.not(a),a.remove()},destroy:function(){this.$bricks.removeClass("masonry-brick").each(function(){this.style.position="",this.style.top="",this.style.left=""});var c=this.element[0].style;for(var d in this.originalStyle)c[d]=this.originalStyle[d];this.element.unbind(".masonry").removeClass("masonry").removeData("masonry"),b(a).unbind(".masonry")}},b.fn.imagesLoaded=function(a){function h(){a.call(c,d)}function i(a){var c=a.target;c.src!==f&&b.inArray(c,g)===-1&&(g.push(c),--e<=0&&(setTimeout(h),d.unbind(".imagesLoaded",i)))}var c=this,d=c.find("img").add(c.filter("img")),e=d.length,f="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",g=[];return e||h(),d.bind("load.imagesLoaded error.imagesLoaded",i).each(function(){var a=this.src;this.src=f,this.src=a}),c};var f=function(b){a.console&&a.console.error(b)};b.fn.masonry=function(a){if(typeof a=="string"){var c=Array.prototype.slice.call(arguments,1);this.each(function(){var d=b.data(this,"masonry");if(!d){f("cannot call methods on masonry prior to initialization; attempted to call method '"+a+"'");return}if(!b.isFunction(d[a])||a.charAt(0)==="_"){f("no such method '"+a+"' for masonry instance");return}d[a].apply(d,c)})}else this.each(function(){var c=b.data(this,"masonry");c?(c.option(a||{}),c._init()):b.data(this,"masonry",new b.Mason(a,this))});return this}})(window,jQuery);
@@ -0,0 +1,14 @@
1
+ /*! Copyright (c) 2011 Piotr Rochala (http://rocha.la)
2
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
3
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
4
+ *
5
+ * Version: 1.0.5
6
+ *
7
+ */
8
+ (function(d){jQuery.fn.extend({slimScroll:function(m){var a=d.extend({wheelStep:20,width:"auto",height:"250px",size:"7px",color:"#000",position:"right",distance:"1px",start:"top",opacity:0.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:"#333",railOpacity:"0.2",railClass:"slimScrollRail",barClass:"slimScrollBar",wrapperClass:"slimScrollDiv",allowPageScroll:!1,scroll:0,touchScrollStep:200},m);this.each(function(){function f(h,d,f){var g=h,e=b.outerHeight()-c.outerHeight();d&&(g=parseInt(c.css("top"))+
9
+ h*parseInt(a.wheelStep)/100*c.outerHeight(),g=Math.min(Math.max(g,0),e),c.css({top:g+"px"}));j=parseInt(c.css("top"))/(b.outerHeight()-c.outerHeight());g=j*(b[0].scrollHeight-b.outerHeight());f&&(g=h,h=g/b[0].scrollHeight*b.outerHeight(),h=Math.min(Math.max(h,0),e),c.css({top:h+"px"}));b.scrollTop(g);q();l()}function r(){s=Math.max(b.outerHeight()/b[0].scrollHeight*b.outerHeight(),A);c.css({height:s+"px"})}function q(){r();clearTimeout(w);j==~~j&&(n=a.allowPageScroll,x!=j&&b.trigger("slimscroll",
10
+ 0==~~j?"top":"bottom"));x=j;s>=b.outerHeight()?n=!0:(c.stop(!0,!0).fadeIn("fast"),a.railVisible&&e.stop(!0,!0).fadeIn("fast"))}function l(){a.alwaysVisible||(w=setTimeout(function(){if((!a.disableFadeOut||!p)&&!t&&!u)c.fadeOut("slow"),e.fadeOut("slow")},1E3))}var p,t,u,w,y,s,j,x,A=30,n=!1,b=d(this);if(b.parent().hasClass("slimScrollDiv")){var k=b.scrollTop(),c=b.parent().find(".slimScrollBar"),e=b.parent().find(".slimScrollRail");r();m&&("scrollTo"in m?k=parseInt(a.scrollTo):"scrollBy"in m&&(k+=parseInt(a.scrollBy)),
11
+ f(k,!1,!0))}else{a.height="auto"==a.height?b.parent().innerHeight():a.height;k=d("<div></div>").addClass(a.wrapperClass).css({position:"relative",overflow:"hidden",width:a.width,height:a.height});b.css({overflow:"hidden",width:a.width,height:a.height});var e=d("<div></div>").addClass(a.railClass).css({width:a.size,height:"100%",position:"absolute",top:0,display:a.alwaysVisible&&a.railVisible?"block":"none","border-radius":a.size,background:a.railColor,opacity:a.railOpacity,zIndex:90}),c=d("<div></div>").addClass(a.barClass).css({background:a.color,
12
+ width:a.size,position:"absolute",top:0,opacity:a.opacity,display:a.alwaysVisible?"block":"none","border-radius":a.size,BorderRadius:a.size,MozBorderRadius:a.size,WebkitBorderRadius:a.size,zIndex:99}),z="right"==a.position?{right:a.distance}:{left:a.distance};e.css(z);c.css(z);b.wrap(k);b.parent().append(c);b.parent().append(e);c.draggable({axis:"y",containment:"parent",start:function(){u=!0},stop:function(){u=!1;l()},drag:function(){f(0,d(this).position().top,!1)}});e.hover(function(){q()},function(){l()});
13
+ c.hover(function(){t=!0},function(){t=!1});b.hover(function(){p=!0;q();l()},function(){p=!1;l()});b.bind("touchstart",function(a){a.originalEvent.touches.length&&(y=a.originalEvent.touches[0].pageY)});b.bind("touchmove",function(b){b.originalEvent.preventDefault();b.originalEvent.touches.length&&f((y-b.originalEvent.touches[0].pageY)/a.touchScrollStep,!0)});var v=function(a){if(p){a=a||window.event;var b=0;a.wheelDelta&&(b=-a.wheelDelta/120);a.detail&&(b=a.detail/3);f(b,!0);a.preventDefault&&!n&&
14
+ a.preventDefault();n||(a.returnValue=!1)}};(function(){window.addEventListener?(this.addEventListener("DOMMouseScroll",v,!1),this.addEventListener("mousewheel",v,!1)):document.attachEvent("onmousewheel",v)})();r();"bottom"==a.start?(c.css({top:b.outerHeight()-c.outerHeight()}),f(0,!0)):"object"==typeof a.start&&(f(d(a.start).position().top,null,!0),a.alwaysVisible||c.hide())}});return this}});jQuery.fn.extend({slimscroll:jQuery.fn.slimScroll})})(jQuery);
@@ -0,0 +1,703 @@
1
+ /*global console, module*/
2
+
3
+ function MediumEditor(elements, options) {
4
+ 'use strict';
5
+ return this.init(elements, options);
6
+ }
7
+
8
+ if (typeof module === 'object') {
9
+ module.exports = MediumEditor;
10
+ }
11
+
12
+ (function (window, document) {
13
+ 'use strict';
14
+
15
+ function extend(b, a) {
16
+ var prop;
17
+ if (b === undefined) {
18
+ return a;
19
+ }
20
+ for (prop in a) {
21
+ if (a.hasOwnProperty(prop) && b.hasOwnProperty(prop) === false) {
22
+ b[prop] = a[prop];
23
+ }
24
+ }
25
+ return b;
26
+ }
27
+
28
+ // http://stackoverflow.com/questions/5605401/insert-link-in-contenteditable-element
29
+ // by Tim Down
30
+ function saveSelection() {
31
+ var i,
32
+ len,
33
+ ranges,
34
+ sel = window.getSelection();
35
+ if (sel.getRangeAt && sel.rangeCount) {
36
+ ranges = [];
37
+ for (i = 0, len = sel.rangeCount; i < len; i += 1) {
38
+ ranges.push(sel.getRangeAt(i));
39
+ }
40
+ return ranges;
41
+ }
42
+ return null;
43
+ }
44
+
45
+ function restoreSelection(savedSel) {
46
+ var i,
47
+ len,
48
+ sel = window.getSelection();
49
+ if (savedSel) {
50
+ sel.removeAllRanges();
51
+ for (i = 0, len = savedSel.length; i < len; i += 1) {
52
+ sel.addRange(savedSel[i]);
53
+ }
54
+ }
55
+ }
56
+
57
+ // http://stackoverflow.com/questions/1197401/how-can-i-get-the-element-the-caret-is-in-with-javascript-when-using-contentedi
58
+ // by You
59
+ function getSelectionStart() {
60
+ var node = document.getSelection().anchorNode,
61
+ startNode = (node && node.nodeType === 3 ? node.parentNode : node);
62
+ return startNode;
63
+ }
64
+
65
+ // http://stackoverflow.com/questions/4176923/html-of-selected-text
66
+ // by Tim Down
67
+ function getSelectionHtml() {
68
+ var i,
69
+ html = '',
70
+ sel,
71
+ len,
72
+ container;
73
+ if (window.getSelection !== undefined) {
74
+ sel = window.getSelection();
75
+ if (sel.rangeCount) {
76
+ container = document.createElement('div');
77
+ for (i = 0, len = sel.rangeCount; i < len; i += 1) {
78
+ container.appendChild(sel.getRangeAt(i).cloneContents());
79
+ }
80
+ html = container.innerHTML;
81
+ }
82
+ } else if (document.selection !== undefined) {
83
+ if (document.selection.type === 'Text') {
84
+ html = document.selection.createRange().htmlText;
85
+ }
86
+ }
87
+ return html;
88
+ }
89
+
90
+ MediumEditor.prototype = {
91
+ defaults: {
92
+ allowMultiParagraphSelection: true,
93
+ anchorInputPlaceholder: 'Paste or type a link',
94
+ buttons: ['bold', 'italic', 'underline', 'anchor', 'header1', 'header2', 'quote'],
95
+ delay: 0,
96
+ diffLeft: 0,
97
+ diffTop: -10,
98
+ disableReturn: false,
99
+ disableToolbar: false,
100
+ firstHeader: 'h3',
101
+ forcePlainText: true,
102
+ placeholder: 'Type your text',
103
+ secondHeader: 'h4',
104
+ targetBlank: false
105
+ },
106
+
107
+ init: function (elements, options) {
108
+ this.elements = typeof elements === 'string' ? document.querySelectorAll(elements) : elements;
109
+ if (this.elements.length === 0) {
110
+ return;
111
+ }
112
+ this.isActive = true;
113
+ this.parentElements = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre'];
114
+ this.id = document.querySelectorAll('.medium-editor-toolbar').length + 1;
115
+ this.options = extend(options, this.defaults);
116
+ return this.initElements()
117
+ .bindSelect()
118
+ .bindPaste()
119
+ .setPlaceholders()
120
+ .bindWindowActions();
121
+ },
122
+
123
+ initElements: function () {
124
+ var i,
125
+ addToolbar = false;
126
+ for (i = 0; i < this.elements.length; i += 1) {
127
+ this.elements[i].setAttribute('contentEditable', true);
128
+ if (!this.elements[i].getAttribute('data-placeholder')) {
129
+ this.elements[i].setAttribute('data-placeholder', this.options.placeholder);
130
+ }
131
+ this.elements[i].setAttribute('data-medium-element', true);
132
+ this.bindParagraphCreation(i).bindReturn(i).bindTab(i);
133
+ if (!this.options.disableToolbar && !this.elements[i].getAttribute('data-disable-toolbar')) {
134
+ addToolbar = true;
135
+ }
136
+ }
137
+ // Init toolbar
138
+ if (addToolbar) {
139
+ this.initToolbar()
140
+ .bindButtons()
141
+ .bindAnchorForm();
142
+ }
143
+ return this;
144
+ },
145
+
146
+ serialize: function () {
147
+ var i,
148
+ elementid,
149
+ content = {};
150
+ for (i = 0; i < this.elements.length; i += 1) {
151
+ elementid = (this.elements[i].id !== '') ? this.elements[i].id : 'element-' + i;
152
+ content[elementid] = {
153
+ value: this.elements[i].innerHTML.trim()
154
+ };
155
+ }
156
+ return content;
157
+ },
158
+
159
+ bindParagraphCreation: function (index) {
160
+ var self = this;
161
+ this.elements[index].addEventListener('keyup', function (e) {
162
+ var node = getSelectionStart(),
163
+ tagName;
164
+ if (node && node.getAttribute('data-medium-element') && node.children.length === 0
165
+ && !(self.options.disableReturn || node.getAttribute('data-disable-return'))) {
166
+ document.execCommand('formatBlock', false, 'p');
167
+ }
168
+ if (e.which === 13 && !e.shiftKey) {
169
+ node = getSelectionStart();
170
+ tagName = node.tagName.toLowerCase();
171
+ if (!(self.options.disableReturn || this.getAttribute('data-disable-return'))
172
+ && tagName !== 'li') {
173
+ document.execCommand('formatBlock', false, 'p');
174
+ if (tagName === 'a') {
175
+ document.execCommand('unlink', false, null);
176
+ }
177
+ }
178
+ }
179
+ });
180
+ return this;
181
+ },
182
+
183
+ bindReturn: function (index) {
184
+ var self = this;
185
+ this.elements[index].addEventListener('keypress', function (e) {
186
+ if (e.which === 13 && !e.shiftKey) {
187
+ if (self.options.disableReturn || this.getAttribute('data-disable-return')) {
188
+ e.preventDefault();
189
+ }
190
+ }
191
+ });
192
+ return this;
193
+ },
194
+
195
+ bindTab: function (index) {
196
+ this.elements[index].addEventListener('keydown', function (e) {
197
+ if (e.which === 9) {
198
+ // Override tab only for pre nodes
199
+ var tag = getSelectionStart().tagName.toLowerCase();
200
+ if (tag === "pre") {
201
+ e.preventDefault();
202
+ document.execCommand('insertHtml', null, ' ');
203
+ }
204
+ }
205
+ });
206
+ },
207
+
208
+ buttonTemplate: function(btnType) {
209
+ var buttonTemplates = {
210
+ 'bold': '<li><button class="medium-editor-action medium-editor-action-bold" data-action="bold" data-element="b">B</button></li>',
211
+ 'italic': '<li><button class="medium-editor-action medium-editor-action-italic" data-action="italic" data-element="i">I</button></li>',
212
+ 'underline': '<li><button class="medium-editor-action medium-editor-action-underline" data-action="underline" data-element="u">U</button></li>',
213
+ 'superscript': '<li><button class="medium-editor-action medium-editor-action-superscript" data-action="superscript" data-element="sup">x<sup>1</sup></button></li>',
214
+ 'subscript': '<li><button class="medium-editor-action medium-editor-action-subscript" data-action="subscript" data-element="sub">x<sub>1</sup></button></li>',
215
+ 'anchor': '<li><button class="medium-editor-action medium-editor-action-anchor" data-action="anchor" data-element="a">#</button></li>',
216
+ 'header1': '<li><button class="medium-editor-action medium-editor-action-header1" data-action="append-' + this.options.firstHeader + '" data-element="' + this.options.firstHeader + '">h1</button></li>',
217
+ 'header2': '<li><button class="medium-editor-action medium-editor-action-header2" data-action="append-' + this.options.secondHeader + '" data-element="' + this.options.secondHeader + '">h2</button></li>',
218
+ 'quote': '<li><button class="medium-editor-action medium-editor-action-quote" data-action="append-blockquote" data-element="blockquote">&ldquo;</button></li>',
219
+ 'orderedlist': '<li><button class="medium-editor-action medium-editor-action-orderedlist" data-action="insertorderedlist" data-element="ol">1.</button></li>',
220
+ 'unorderedlist': '<li><button class="medium-editor-action medium-editor-action-unorderedlist" data-action="insertunorderedlist" data-element="ul">&bull;</button></li>',
221
+ 'pre': '<li><button class="medium-editor-action medium-editor-action-pre" data-action="append-pre" data-element="pre">0101</button></li>'
222
+ };
223
+ return buttonTemplates[btnType] || false;
224
+ },
225
+
226
+ //TODO: actionTemplate
227
+ toolbarTemplate: function () {
228
+ var btns = this.options.buttons,
229
+ html = '<ul id="medium-editor-toolbar-actions" class="medium-editor-toolbar-actions clearfix">',
230
+ i,
231
+ tpl;
232
+
233
+ for (i = 0; i < btns.length; i += 1) {
234
+ tpl = this.buttonTemplate(btns[i]);
235
+ if (tpl) {
236
+ html += tpl;
237
+ }
238
+ }
239
+ html += '</ul>' +
240
+ '<div class="medium-editor-toolbar-form-anchor" id="medium-editor-toolbar-form-anchor">' +
241
+ ' <input type="text" value="" placeholder="' + this.options.anchorInputPlaceholder + '">' +
242
+ ' <a href="#">&times;</a>' +
243
+ '</div>';
244
+ return html;
245
+ },
246
+
247
+ initToolbar: function () {
248
+ if (this.toolbar) {
249
+ return this;
250
+ }
251
+ this.toolbar = this.createToolbar();
252
+ this.keepToolbarAlive = false;
253
+ this.anchorForm = this.toolbar.querySelector('.medium-editor-toolbar-form-anchor');
254
+ this.anchorInput = this.anchorForm.querySelector('input');
255
+ this.toolbarActions = this.toolbar.querySelector('.medium-editor-toolbar-actions');
256
+ return this;
257
+ },
258
+
259
+ createToolbar: function () {
260
+ var toolbar = document.createElement('div');
261
+ toolbar.id = 'medium-editor-toolbar-' + this.id;
262
+ toolbar.className = 'medium-editor-toolbar';
263
+ toolbar.innerHTML = this.toolbarTemplate();
264
+ document.getElementsByTagName('body')[0].appendChild(toolbar);
265
+ return toolbar;
266
+ },
267
+
268
+ bindSelect: function () {
269
+ var self = this,
270
+ timer = '',
271
+ i;
272
+ this.checkSelectionWrapper = function (e) {
273
+ clearTimeout(timer);
274
+ setTimeout(function () {
275
+ self.checkSelection(e);
276
+ }, self.options.delay);
277
+ };
278
+
279
+ document.documentElement.addEventListener('mouseup', this.checkSelectionWrapper);
280
+
281
+ for (i = 0; i < this.elements.length; i += 1) {
282
+ this.elements[i].addEventListener('keyup', this.checkSelectionWrapper);
283
+ this.elements[i].addEventListener('blur', this.checkSelectionWrapper);
284
+ }
285
+ return this;
286
+ },
287
+
288
+ checkSelection: function () {
289
+ var i,
290
+ newSelection,
291
+ hasMultiParagraphs,
292
+ selectionHtml,
293
+ selectionElement;
294
+ if (this.keepToolbarAlive !== true && !this.options.disableToolbar) {
295
+ newSelection = window.getSelection();
296
+ selectionHtml = getSelectionHtml();
297
+ selectionHtml = selectionHtml.replace(/<[\S]+><\/[\S]+>/gim, '');
298
+ // Check if selection is between multi paragraph <p>.
299
+ hasMultiParagraphs = selectionHtml.match(/<(p|h[0-6]|blockquote)>([\s\S]*?)<\/(p|h[0-6]|blockquote)>/g);
300
+ hasMultiParagraphs = hasMultiParagraphs ? hasMultiParagraphs.length : 0;
301
+ if (newSelection.toString().trim() === ''
302
+ || (this.options.allowMultiParagraphSelection === false && hasMultiParagraphs)) {
303
+ this.hideToolbarActions();
304
+ } else {
305
+ selectionElement = this.getSelectionElement();
306
+ if (!selectionElement || selectionElement.getAttribute('data-disable-toolbar')) {
307
+ this.hideToolbarActions();
308
+ } else {
309
+ this.selection = newSelection;
310
+ this.selectionRange = this.selection.getRangeAt(0);
311
+ for (i = 0; i < this.elements.length; i += 1) {
312
+ if (this.elements[i] === selectionElement) {
313
+ this.setToolbarButtonStates()
314
+ .setToolbarPosition()
315
+ .showToolbarActions();
316
+ return;
317
+ }
318
+ }
319
+ this.hideToolbarActions();
320
+ }
321
+ }
322
+ }
323
+ return this;
324
+ },
325
+
326
+ getSelectionElement: function () {
327
+ var selection = window.getSelection(),
328
+ range = selection.getRangeAt(0),
329
+ current = range.commonAncestorContainer,
330
+ parent = current.parentNode,
331
+ result,
332
+ getMediumElement = function(e) {
333
+ var parent = e;
334
+ try {
335
+ while (!parent.getAttribute('data-medium-element')) {
336
+ parent = parent.parentNode;
337
+ }
338
+ } catch (errb) {
339
+ return false;
340
+ }
341
+ return parent;
342
+ };
343
+ // First try on current node
344
+ try {
345
+ if (current.getAttribute('data-medium-element')) {
346
+ result = current;
347
+ } else {
348
+ result = getMediumElement(parent);
349
+ }
350
+ // If not search in the parent nodes.
351
+ } catch (err) {
352
+ result = getMediumElement(parent);
353
+ }
354
+ return result;
355
+ },
356
+
357
+ setToolbarPosition: function () {
358
+ var buttonHeight = 50,
359
+ selection = window.getSelection(),
360
+ range = selection.getRangeAt(0),
361
+ boundary = range.getBoundingClientRect(),
362
+ defaultLeft = (this.options.diffLeft) - (this.toolbar.offsetWidth / 2),
363
+ middleBoundary = (boundary.left + boundary.right) / 2,
364
+ halfOffsetWidth = this.toolbar.offsetWidth / 2;
365
+ if (boundary.top < buttonHeight) {
366
+ this.toolbar.classList.add('medium-toolbar-arrow-over');
367
+ this.toolbar.classList.remove('medium-toolbar-arrow-under');
368
+ this.toolbar.style.top = buttonHeight + boundary.bottom - this.options.diffTop + window.pageYOffset - this.toolbar.offsetHeight + 'px';
369
+ } else {
370
+ this.toolbar.classList.add('medium-toolbar-arrow-under');
371
+ this.toolbar.classList.remove('medium-toolbar-arrow-over');
372
+ this.toolbar.style.top = boundary.top + this.options.diffTop + window.pageYOffset - this.toolbar.offsetHeight + 'px';
373
+ }
374
+ if (middleBoundary < halfOffsetWidth) {
375
+ this.toolbar.style.left = defaultLeft + halfOffsetWidth + 'px';
376
+ } else if ((window.innerWidth - middleBoundary) < halfOffsetWidth) {
377
+ this.toolbar.style.left = window.innerWidth + defaultLeft - halfOffsetWidth + 'px';
378
+ } else {
379
+ this.toolbar.style.left = defaultLeft + middleBoundary + 'px';
380
+ }
381
+ return this;
382
+ },
383
+
384
+ setToolbarButtonStates: function () {
385
+ var buttons = this.toolbarActions.querySelectorAll('button'),
386
+ i;
387
+ for (i = 0; i < buttons.length; i += 1) {
388
+ buttons[i].classList.remove('medium-editor-button-active');
389
+ }
390
+ this.checkActiveButtons();
391
+ return this;
392
+ },
393
+
394
+ checkActiveButtons: function () {
395
+ var parentNode = this.selection.anchorNode;
396
+ if (!parentNode.tagName) {
397
+ parentNode = this.selection.anchorNode.parentNode;
398
+ }
399
+ while (parentNode.tagName !== undefined && this.parentElements.indexOf(parentNode.tagName) === -1) {
400
+ this.activateButton(parentNode.tagName.toLowerCase());
401
+ parentNode = parentNode.parentNode;
402
+ }
403
+ },
404
+
405
+ activateButton: function (tag) {
406
+ var el = this.toolbar.querySelector('[data-element="' + tag + '"]');
407
+ if (el !== null && el.className.indexOf('medium-editor-button-active') === -1) {
408
+ el.className += ' medium-editor-button-active';
409
+ }
410
+ },
411
+
412
+ bindButtons: function () {
413
+ var buttons = this.toolbar.querySelectorAll('button'),
414
+ i,
415
+ self = this,
416
+ triggerAction = function (e) {
417
+ e.preventDefault();
418
+ e.stopPropagation();
419
+ if (self.selection === undefined) {
420
+ self.checkSelection(e);
421
+ }
422
+ if (this.className.indexOf('medium-editor-button-active') > -1) {
423
+ this.classList.remove('medium-editor-button-active');
424
+ } else {
425
+ this.className += ' medium-editor-button-active';
426
+ }
427
+ console.log(this.getAttribute('data-action'));
428
+ self.execAction(this.getAttribute('data-action'), e);
429
+ };
430
+ for (i = 0; i < buttons.length; i += 1) {
431
+ buttons[i].addEventListener('click', triggerAction);
432
+ }
433
+ this.setFirstAndLastItems(buttons);
434
+ return this;
435
+ },
436
+
437
+ setFirstAndLastItems: function (buttons) {
438
+ buttons[0].className += ' medium-editor-button-first';
439
+ buttons[buttons.length - 1].className += ' medium-editor-button-last';
440
+ return this;
441
+ },
442
+
443
+ execAction: function (action, e) {
444
+ if (action.indexOf('append-') > -1) {
445
+ this.execFormatBlock(action.replace('append-', ''));
446
+ this.setToolbarPosition();
447
+ this.setToolbarButtonStates();
448
+ } else if (action === 'anchor') {
449
+ this.triggerAnchorAction(e);
450
+ } else {
451
+ document.execCommand(action, false, null);
452
+ this.setToolbarPosition();
453
+ }
454
+ },
455
+
456
+ triggerAnchorAction: function () {
457
+ if (this.selection.anchorNode.parentNode.tagName.toLowerCase() === 'a') {
458
+ document.execCommand('unlink', false, null);
459
+ } else {
460
+ if (this.anchorForm.style.display === 'block') {
461
+ this.showToolbarActions();
462
+ } else {
463
+ this.showAnchorForm();
464
+ }
465
+ }
466
+ return this;
467
+ },
468
+
469
+ execFormatBlock: function (el) {
470
+ var selectionData = this.getSelectionData(this.selection.anchorNode);
471
+ // FF handles blockquote differently on formatBlock
472
+ // allowing nesting, we need to use outdent
473
+ // https://developer.mozilla.org/en-US/docs/Rich-Text_Editing_in_Mozilla
474
+ if (el === 'blockquote' && selectionData.el
475
+ && selectionData.el.parentNode.tagName.toLowerCase() === 'blockquote') {
476
+ return document.execCommand('outdent', false, null);
477
+ }
478
+ if (selectionData.tagName === el) {
479
+ el = 'p';
480
+ }
481
+ return document.execCommand('formatBlock', false, el);
482
+ },
483
+
484
+ getSelectionData: function (el) {
485
+ var tagName;
486
+
487
+ if (el && el.tagName) {
488
+ tagName = el.tagName.toLowerCase();
489
+ }
490
+
491
+ while (el && this.parentElements.indexOf(tagName) === -1) {
492
+ el = el.parentNode;
493
+ if (el && el.tagName) {
494
+ tagName = el.tagName.toLowerCase();
495
+ }
496
+ }
497
+
498
+ return {
499
+ el: el,
500
+ tagName: tagName
501
+ };
502
+ },
503
+
504
+ getFirstChild: function (el) {
505
+ var firstChild = el.firstChild;
506
+ while (firstChild !== null && firstChild.nodeType !== 1) {
507
+ firstChild = firstChild.nextSibling;
508
+ }
509
+ return firstChild;
510
+ },
511
+
512
+ bindElementToolbarEvents: function (el) {
513
+ var self = this;
514
+ el.addEventListener('mouseup', function (e) {
515
+ self.checkSelection(e);
516
+ });
517
+ el.addEventListener('keyup', function (e) {
518
+ self.checkSelection(e);
519
+ });
520
+ },
521
+
522
+ hideToolbarActions: function () {
523
+ this.keepToolbarAlive = false;
524
+ this.toolbar.classList.remove('medium-editor-toolbar-active');
525
+ },
526
+
527
+ showToolbarActions: function () {
528
+ var self = this,
529
+ timer;
530
+ this.anchorForm.style.display = 'none';
531
+ this.toolbarActions.style.display = 'block';
532
+ this.keepToolbarAlive = false;
533
+ clearTimeout(timer);
534
+ timer = setTimeout(function() {
535
+ if (!self.toolbar.classList.contains('medium-editor-toolbar-active')) {
536
+ self.toolbar.classList.add('medium-editor-toolbar-active');
537
+ }
538
+ }, 100);
539
+ },
540
+
541
+ showAnchorForm: function () {
542
+ this.toolbarActions.style.display = 'none';
543
+ this.savedSelection = saveSelection();
544
+ this.anchorForm.style.display = 'block';
545
+ this.keepToolbarAlive = true;
546
+ this.anchorInput.focus();
547
+ this.anchorInput.value = '';
548
+ },
549
+
550
+ bindAnchorForm: function () {
551
+ var linkCancel = this.anchorForm.querySelector('a'),
552
+ self = this;
553
+ this.anchorForm.addEventListener('click', function (e) {
554
+ e.stopPropagation();
555
+ });
556
+ this.anchorInput.addEventListener('keyup', function (e) {
557
+ if (e.keyCode === 13) {
558
+ e.preventDefault();
559
+ self.createLink(this);
560
+ }
561
+ });
562
+ this.anchorInput.addEventListener('blur', function (e) {
563
+ self.keepToolbarAlive = false;
564
+ self.checkSelection();
565
+ });
566
+ linkCancel.addEventListener('click', function (e) {
567
+ e.preventDefault();
568
+ self.showToolbarActions();
569
+ restoreSelection(self.savedSelection);
570
+ });
571
+ return this;
572
+ },
573
+
574
+ setTargetBlank: function () {
575
+ var el = getSelectionStart(),
576
+ i;
577
+ if (el.tagName.toLowerCase() === 'a') {
578
+ el.target = '_blank';
579
+ } else {
580
+ el = el.getElementsByTagName('a');
581
+ for (i = 0; i < el.length; i += 1) {
582
+ el[i].target = '_blank';
583
+ }
584
+ }
585
+ },
586
+
587
+ createLink: function (input) {
588
+ restoreSelection(this.savedSelection);
589
+ document.execCommand('createLink', false, input.value);
590
+ if (this.options.targetBlank) {
591
+ this.setTargetBlank();
592
+ }
593
+ this.showToolbarActions();
594
+ input.value = '';
595
+ },
596
+
597
+ bindWindowActions: function () {
598
+ var timerResize,
599
+ self = this;
600
+ window.addEventListener('resize', function () {
601
+ clearTimeout(timerResize);
602
+ timerResize = setTimeout(function () {
603
+ if (self.toolbar.classList.contains('medium-editor-toolbar-active')) {
604
+ self.setToolbarPosition();
605
+ }
606
+ }, 100);
607
+ });
608
+ return this;
609
+ },
610
+
611
+ activate: function () {
612
+ var i;
613
+ if (this.isActive) {
614
+ return;
615
+ }
616
+
617
+ if (this.toolbar !== undefined) {
618
+ this.toolbar.style.display = 'block';
619
+ }
620
+
621
+ this.isActive = true;
622
+ for (i = 0; i < this.elements.length; i += 1) {
623
+ this.elements[i].setAttribute('contentEditable', true);
624
+ }
625
+ this.bindSelect();
626
+ },
627
+
628
+ deactivate: function () {
629
+ var i;
630
+ if (!this.isActive) {
631
+ return;
632
+ }
633
+ this.isActive = false;
634
+
635
+ if (this.toolbar !== undefined) {
636
+ this.toolbar.style.display = 'none';
637
+ }
638
+
639
+ document.documentElement.removeEventListener('mouseup', this.checkSelectionWrapper);
640
+
641
+ for (i = 0; i < this.elements.length; i += 1) {
642
+ this.elements[i].removeEventListener('keyup', this.checkSelectionWrapper);
643
+ this.elements[i].removeEventListener('blur', this.checkSelectionWrapper);
644
+ this.elements[i].removeAttribute('contentEditable');
645
+ }
646
+ },
647
+
648
+ bindPaste: function () {
649
+ if (!this.options.forcePlainText) {
650
+ return this;
651
+ }
652
+ var i,
653
+ self = this,
654
+ pasteWrapper = function (e) {
655
+ var paragraphs,
656
+ html = '',
657
+ p;
658
+ e.target.classList.remove('medium-editor-placeholder');
659
+ if (e.clipboardData && e.clipboardData.getData) {
660
+ e.preventDefault();
661
+ if (!self.options.disableReturn) {
662
+ paragraphs = e.clipboardData.getData('text/plain').split(/[\r\n]/g);
663
+ for (p = 0; p < paragraphs.length; p += 1) {
664
+ if (paragraphs[p] !== '') {
665
+ html += '<p>' + paragraphs[p] + '</p>';
666
+ }
667
+ }
668
+ document.execCommand('insertHTML', false, html);
669
+ } else {
670
+ document.execCommand('insertHTML', false, e.clipboardData.getData('text/plain'));
671
+ }
672
+ }
673
+ };
674
+ for (i = 0; i < this.elements.length; i += 1) {
675
+ this.elements[i].addEventListener('paste', pasteWrapper);
676
+ }
677
+ return this;
678
+ },
679
+
680
+ setPlaceholders: function () {
681
+ var i,
682
+ activatePlaceholder = function (el) {
683
+ if (el.textContent.replace(/^\s+|\s+$/g, '') === '') {
684
+ el.classList.add('medium-editor-placeholder');
685
+ }
686
+ },
687
+ placeholderWrapper = function (e) {
688
+ this.classList.remove('medium-editor-placeholder');
689
+ if (e.type !== 'keypress') {
690
+ activatePlaceholder(this);
691
+ }
692
+ };
693
+ for (i = 0; i < this.elements.length; i += 1) {
694
+ activatePlaceholder(this.elements[i]);
695
+ this.elements[i].addEventListener('blur', placeholderWrapper);
696
+ this.elements[i].addEventListener('keypress', placeholderWrapper);
697
+ }
698
+ return this;
699
+ }
700
+
701
+ };
702
+
703
+ }(window, document));