UNPKG

universal-web-template

Version:

An universal web proejct template - let you quickly set up a project using Handlebars, sass and ReactJS for front-end templating. It can be adopted with most modern CMS.

1,205 lines (1,060 loc) 43.4 kB
/*! * Fancyform - jQuery Plugin * Simple and fancy form styling alternative * * Examples and documentation at: https://github.com/Lutrasoft/Fancyform * * Copyright (c) 2010-2015 - Lutrasoft * * Version: 1.4.3 * Requires: jQuery v1.6.1+ * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html */ (function ($) { $.simpleEllipsis = function (t, c) { return t.length < c ? t : t.substring(0, c) + "..."; } var _touch = !!('ontouchstart' in window), _removeClasses = function(){ var _this = $(this), options = _this.data("options") || _this.data("settings"), k; for(k in options) { _this.parent().removeClass(k); } }; $.fn.extend({ /* Get the caret on an textarea */ caret: function (start, end) { var elem = this[0], val = this.val(), r, re, rc; if (elem) { // get caret range if (typeof start == "undefined") { if (elem.selectionStart) { start = elem.selectionStart; end = elem.selectionEnd; } // <= IE 8 else if (document.selection) { this.focus(); r = document.selection.createRange(); if (r == null) { return { start: 0, end: e.value.length, length: 0 } } re = elem.createTextRange(); rc = re.duplicate(); re.moveToBookmark(r.getBookmark()); rc.setEndPoint('EndToStart', re); // IE counts a line (not \n or \r) as 1 extra character return { start: rc.text.length - (rc.text.split("\n").length + 1) + 2, end: rc.text.length + r.text.length - (rc.text.split("\n").length + 1) + 2, length: r.text.length, text: r.text }; } } // set caret range else { if (typeof end != "number") end = -1; if (typeof start != "number" || start < 0) start = 0; if (end > val.length) end = val.length; end = Math.max(start, end); start = Math.min(start, end); elem.focus(); if (elem.selectionStart) { elem.selectionStart = start; elem.selectionEnd = end; } else if (document.selection) { r = elem.createTextRange(); r.collapse(true); r.moveStart("character", start); r.moveEnd("character", end - start); r.select(); } } return { start: start, end: end }; } }, /* Replace checkboxes with images */ transformCheckbox: function (settings) { var defaults = { base : "image", // Can be image/class checked: "", unchecked: "", disabledChecked: "", disabledUnchecked: "", tristateHalfChecked: "", changeHandler: function (is_checked) { }, trigger: "self", // Can be self, parent tristate: 0 }, options = $.extend(defaults, settings), method = { // Handling the image setImage: function () { var cb = $(this), settings = cb.data('settings'), src; if (cb.is(":disabled")) { src = cb.is(":checked") ? "disabledChecked" : "disabledUnchecked"; } else if (cb.hasClass("half-checked")) // Tri-state image { src = "tristateHalfChecked"; } else if (cb.is(":checked")) { src = "checked"; } else { src = "unchecked"; } if( settings.base == "image" ) { cb.next().attr("src", settings[src]); } else { _removeClasses.call(this); cb.parent().addClass(src); } }, setProp: function (el, name, bool) { $(el).prop(name, bool).change(); method.setImage.call(el); // Checked and radio, change others if( name == "checked" && !$(el).data('settings').type ) { $("[name='" + $(el).attr("name") + "']").each(function(){ method.setImage.call(this); }); } }, // Handling the check/uncheck/disable/enable functions uncheck: function () { method.setProp(this, "checked", 0); }, check: function () { method.setProp(this, "checked", 1); }, disable: function () { method.setProp(this, "disabled", 1); }, enable: function () { method.setProp(this, "disabled", 0); }, // Clicking the image imageClick: function () { var _this = $(this), settings = _this.data('settings'); if (!_this.is(":disabled")) { if (_this.is(":checked") && settings.type) { method.uncheck.call(_this); options.changeHandler.call(_this, 1); } else { method.check.call(_this); options.changeHandler.call(_this, 0); } method.handleTriState.call(_this); } }, // Tristate handleTriState: function () { var cb = $(this), settings = cb.data('settings'), li = cb.parent(), ul = li.find("ul"), pli = li.closest("li"); if (settings.tristate) { // Fix children if (cb.hasClass("half-checked") || cb.is(":checked")) { cb.removeClass("half-checked"); method.check.call(cb); ul.find("input:checkbox").removeClass("half-checked").each(method.check); } else if (cb.not(":checked")) { cb.removeClass("half-checked"); ul.find("input:checkbox").each(method.uncheck); } ul.find("input:checkbox").each(method.setImage); // Fix parents if (cb.parent().parent().parent().is("li")) { method.handleTriStateLevel.call(cb.parent().parent().parent()); } cb.trigger("transformCheckbox.tristate"); } }, // Handle all including parent levels handleTriStateLevel: function (upwards) { var _this = $(this), firstCheckbox = _this.find("input:checkbox").first(), ul = _this.find("ul"), inputs = ul.find("input:checkbox"), checked = inputs.filter(":checked"); if( upwards !== false || inputs.length) { firstCheckbox.removeClass("half-checked"); if (inputs.length == checked.length) { method.check.call(firstCheckbox); } else if (checked.length) { firstCheckbox.addClass("half-checked"); } else { method.uncheck.call(firstCheckbox); } method.setImage.call(firstCheckbox); if (upwards !== false && _this.parent().parent().is("li")) { method.handleTriStateLevel.call(_this.parent().parent()); } } } } return this.each(function () { if (typeof settings == "string") { method[settings].call(this); } else { var _this = $(this); // Is already initialized if (!_this.data("tf.init")) { // set initialized _this.data("tf.init", 1) .data("settings", options); options.type = _this.is("[type=checkbox]"); // Radio hide _this.hide(); // Afbeelding if( options.base == "image" ) { _this.after("<img />"); } else { _this.wrap("<span class='trans-element-" + (options.type ? "checkbox" : "radio") + "' />"); } method.setImage.call(this); if (settings.tristate) { method.handleTriStateLevel.call(_this.parent(), false); } if( options.base == "image" ) { switch (options.trigger) { case "parent": _this.parent().click($.proxy(method.imageClick, this)); break; case "self": _this.next("img").click($.proxy(method.imageClick, this)); break; } } else { switch (options.trigger) { case "parent": _this.parent().parent().click($.proxy(method.imageClick, this)); break; case "self": _this.parent().click($.proxy(method.imageClick, this)); break; } } } } }); }, /* Replace select with list ========================= HTML will look like <ul> <li><span>Selected value</span> <ul> <li data-settings='{"alwaysvisible" : true}'><span>Option</span></li> <li><span>Option</span></li> </ul> </li> </ul> */ transformSelect: function (opts) { var defaults = { dropDownClass: "transformSelect", showFirstItemInDrop: 1, acceptManualInput: 0, useManualInputAsFilter: 0, subTemplate: function (option) { if ($(this)[0].type == "select-multiple") { return "<span><input type='checkbox' value='" + $(option).val() + "' " + ($(option).is(":selected") ? "checked='checked'" : "") + " name='" + $(this).attr("name").replace("_backup", "") + "' /><ins />" + $(option).text() + "</span>"; } else { return "<span>" + $(option).text() + "</span>"; } }, initValue: function () { return $(this).text(); }, valueTemplate: function () { return $(this).text(); }, ellipsisLength: null, addDropdownToBody: 0 }; var options = $(this).data("settings"), method = { init: function () { // Generate HTML var _this = this, t = $(_this), selectedIndex = 0, selectedOption = t.find("option:first"); // Hide mezelf t.hide(); if (t.find("option:selected").length && _this.type != "select-multiple") { selectedOption = t.find("option:selected"); selectedIndex = t.find("option").index(selectedOption); } // Maak een ul aan var ul = "<ul class='" + options.dropDownClass + " trans-element'><li>"; if (options.acceptManualInput && !_touch) { var value = t.data("value") || options.initValue.call(selectedOption); ul += "<ins></ins><input type='text' name='" + t.attr("name").replace("_backup", "") + "' value='" + value + "' />"; // Save old select if (t.attr("name").indexOf("_backup") < 0) { t.attr("name", t.attr("name") + "_backup"); } } else { if (options.ellipsisLength) { ul += "<span title=\"" + selectedOption.text() + "\">" + $.simpleEllipsis(options.initValue.call(selectedOption), options.ellipsisLength) + "</span>"; } else { ul += "<span>" + options.initValue.call(selectedOption) + "</span>"; } } ul += "<ul style='display: none;'>"; t.children().each(function (i) { if (!i && !options.showFirstItemInDrop) { // Don't do anything when you don't wanna show the first element } else { ul += method[ this.tagName == "OPTION" ? "getLIOptionChild" : "getLIOptgroupChildren" ].call(_this, this); } }); ul += "</ul></li></ul>"; var $ul = $(ul), $lis = $ul.find("ul li:not(.group)"), $inp = $ul.find("input"); t.after($ul); // Bind handlers if (t.is(":disabled")) { method.disabled.call(_this, 1); } if (_this.type == "select-multiple" && !_touch) { if (t.attr("name") && t.attr("name").indexOf("_backup") == -1) { t.attr("name", t.attr("name") + "_backup"); } $lis.click(method.selectCheckbox); } else { $lis.click(method.selectNewValue); $inp.click(method.openDrop) .keydown(function (e) { // Tab or enter if ($.inArray(e.which, [9, 13]) >= 0) method.closeAllDropdowns(); }) .prev("ins") .click(method.openDrop); } if (options.useManualInputAsFilter) { $inp.keyup(method.filterByInput); } $ul.find("input").keydown(method.navigateThroughDropdown) $ul.find("span:first").click(method.openDrop); // Set data if we use addDropdownToBody option $ul.find("ul:first").data("trans-element", $ul).addClass("transformSelectDropdown"); $ul.data("trans-element-drop", $ul.find("ul:first")); if (options.addDropdownToBody) { $ul.find("ul:first").appendTo("body"); } // Check if there is already an event $("html").unbind("click.transformSelect").bind("click.transformSelect", method.closeDropDowns) // Bind hotkeys if ($.hotkeys && !$("body").data("trans-element-select")) { $("body").data("trans-element-select", 1); $(document) .bind("keydown", "up", function (e) { var ul = $(".trans-focused"), select, selectedIndex; // Only enable on trans-element without input if (!ul.length || ul.find("input").length) return 0; select = ul.prevAll("select").first(); selectedIndex = select[0].selectedIndex - 1 if (selectedIndex < 0) { selectedIndex = select.find("option").length - 1; } method.selectIndex.call(select, selectedIndex); return 0; }) .bind("keydown", "down", function (e) { var ul = $(".trans-focused"), select, selectedIndex; // Only enable on trans-element without input if (!ul.length || ul.find("input").length) return 0; select = ul.prevAll("select").first(); selectedIndex = select[0].selectedIndex + 1 if (selectedIndex > select.find("option").length - 1) { selectedIndex = 0; } method.selectIndex.call(select, selectedIndex); return 0; }); } // Gebruik native selects if (_touch) { if (!options.showFirstItemInDrop) { t.find("option:first").remove(); } t .appendTo($ul.find("li:first")) .show() .css({ opacity: 0, position: "absolute", width: "100%", height: "100%", left: 0, top: 0 }); $ul.find("li:first").css({ position: "relative" }); t.change(method.mobileChange); } }, getUL: function () { return _touch ? $(this).closest("ul") : $(this).next(".trans-element:first"); }, getSelect: function ($ul) { return _touch ? $ul.find("select") : $ul.prevAll("select:first"); }, disabled: function (disabled) { method.getUL.call(this)[disabled ? "addClass" : "removeClass"]("disabled"); }, repaint: function () { var ul = method.getUL.call(this); if (_touch) { ul.before(this); } if( ul.data("trans-element-drop") ) { ul.data("trans-element-drop").remove(); } ul.remove(); method.init.call(this); }, filterByInput: function () { var _this = $(this), val = _this.val().toLowerCase(), ul = _this.closest("ul"), drop = ul.data("trans-element-drop"), li = drop.find("li"); // val == "" if (!val) { li.show(); } else { li.each(function () { var _li = $(this); if (!!_li.data("settings").alwaysvisible) { _li.show(); } else { _li[_li.text().toLowerCase().indexOf(val) < 0 ? "hide" : "show"](); } }); } }, navigateThroughDropdown: function (e) { var ul = $(this).closest("ul"), drop = ul.data("trans-element-drop"), sel = drop.find(".active"); switch (e.which) { case 40: /* DOWN */ if (sel.length) { sel = sel.nextAll(":not(:hidden):first"); } if (!sel.length) { sel = drop.find("li:not(:hidden):first"); } var ToScroll = sel.prevAll(":not(:hidden)").length * sel.height() - (drop.height() - sel.height()), isVisible = (sel.prevAll(":not(:hidden)").length * sel.height()) > drop.scrollTop() && (sel.prevAll(":not(:hidden)").length * sel.height()) < drop.scrollTop() + drop.height(); if (!isVisible) { drop.scrollTop(ToScroll); } this.lastKeyIsUpOrDown = true; break; case 38: /* UP */ if (sel.length) { sel = sel.prevAll(":not(:hidden):first"); } if (!sel.length) { sel = drop.find("li:not(:hidden):last"); } var ToScroll = sel.prevAll(":not(:hidden)").length * sel.height(), isVisible = (sel.prevAll(":not(:hidden)").length * sel.height()) > drop.scrollTop() && (sel.prevAll(":not(:hidden)").length * sel.height()) < drop.scrollTop() + drop.height(); if (!isVisible) { drop.scrollTop(ToScroll); } this.lastKeyIsUpOrDown = true; break; case 13: /* ENTER = SELECT */ if (this.lastKeyIsUpOrDown) { method.selectIndex.call(ul.prevAll("select:first"), sel.index()); } var fn = ul.prev().data("settings").onSubmit; if (fn) { fn.call(this); } this.lastKeyIsUpOrDown = false; break; default: this.lastKeyIsUpOrDown = false; break; } sel.addClass("active").siblings().removeClass("active"); }, selectIndex: function (index) { var select = $(this), ul = method.getUL.call(this), drop = ul.data("trans-element-drop"); try { drop.find("li").filter(function () { }).first().trigger("click"); return $(this).text() == select.find("option").eq(index).text(); } catch (e) { } }, selectValue: function (value) { var select = $(this), ul = method.getUL.call(this), drop = ul.data("trans-element-drop"); method.selectIndex.call(this, select.find(value ? "option[value='" + value + "']" : "option:not([value])").index()); }, /* * GET option child */ getLIOptionChild: function (option) { var settings = $(option).attr("data-settings") || '', cls = ($(option).attr('class') || '') + ($(option).is(":selected") ? ' selected' : ''); return "<li data-settings='" + settings + "' class='" + cls + "'>" + options.subTemplate.call(this, $(option)) + "</li>"; }, /* * GET optgroup children */ getLIOptgroupChildren: function (group) { var _this = this, li = "<li class='group'><span>" + $(group).attr("label") + "</span><ul>"; $(group).find("option").each(function () { li += method.getLIOptionChild.call(_this, this); }); li += "</ul></li>"; return li; }, getLIIndex: function (el) { var index = 0, group = el.closest(".group"), sel; if (group.length) { index = el.closest(".transformSelectDropdown").find("li").index(el) - group.prevAll(".group").length - 1; } else { index = el.parent().find("li").index(el) - el.prevAll(".group").length; } if (!options.showFirstItemInDrop) { index += 1; } return index; }, /* * Select a new value */ selectNewValue: function () { var _this = $(this), $drop = _this.closest(".transformSelectDropdown"), $ul = $drop.data("trans-element"), select = method.getSelect($ul), index = method.getLIIndex(_this); select[0].selectedIndex = index; // If it has an input, there is no span used for value holding if ($ul.find("input[type=text]").length) { $ul.find("input").val(options.valueTemplate.call(_this)); } else { sel = select.find("option:selected"); $ul .find("span:first") .html( options.ellipsisLength ? $.simpleEllipsis(options.valueTemplate.call(sel), options.ellipsisLength) : options.valueTemplate.call(sel) ); } // Set selected $drop.find(".selected").removeClass("selected"); _this.addClass("selected"); method.closeAllDropdowns(); // Trigger onchange select.trigger("change"); $(".trans-element").removeClass("trans-focused"); $ul.addClass("trans-focused"); // Update validator if ($.fn.validate && select.closest("form").length) { select.valid(); } }, mobileChange: function () { var select = $(this), $ul = method.getUL.call(this), sel = select.find("option:selected"); if (this.type != "select-multiple") { $ul .find("span:first") .html( options.ellipsisLength ? $.simpleEllipsis(options.valueTemplate.call(sel), options.ellipsisLength) : options.valueTemplate.call(sel) ); } }, selectCheckbox: function (e) { var _this = $(this), $drop = _this.closest(".transformSelectDropdown"), $ul = $drop.data("trans-element"), select = method.getSelect($ul), t = _this.closest("li"), checkbox = t.find(":checkbox"), index, group; if ($(e.target).is("li")) { t = _this; } index = method.getLIIndex(t); if (!$(e.target).is(":checkbox")) { checkbox.prop("checked", !checkbox.is(":checked")); } select.find("option").eq(index).prop("selected", checkbox.is(":checked")); if (checkbox.data("tfc.init")) { checkbox.transformCheckbox("setImage"); } if (!$(e.target).is(":checkbox")) { checkbox.change(); } select.change(); }, /* * Open clicked dropdown * and Close all others */ openDrop: function () { var UL = $(this).closest(".trans-element"), childUL = UL.data("trans-element-drop"), childLI = $(this).parent(); if (UL.hasClass("disabled")) { return 0; } // Close on second click if (childLI.hasClass("open") && !$(this).is("input")) { method.closeAllDropdowns(); } // Open on first click else { childLI .css({ 'z-index': 1200 }) .addClass("open"); childUL.css({ 'z-index': 1200 }).show(); method.hideAllOtherDropdowns.call(this); } if (options.addDropdownToBody) { childUL.css({ position: "absolute", top: childLI.offset().top + childLI.outerHeight(), left: childLI.offset().left }); } }, /* * Hide all elements except this element */ hideAllOtherDropdowns: function () { // Hide elements with the same class var allElements = $("body").find("*"), elIndex = allElements.index($(this).parent()); $("body").find("ul.trans-element").each(function () { var childUL = $(this).data("trans-element-drop"); if (elIndex - 1 != allElements.index($(this))) { childUL .hide() .css('z-index', 0) .parent() .css('z-index', 0) .removeClass("open"); } }); }, /* * Close all dropdowns */ closeDropDowns: function (e) { if (!$(e.target).closest(".trans-element").length) { method.closeAllDropdowns(); } }, closeAllDropdowns: function () { $("ul.trans-element").each(function () { $(this).data("trans-element-drop").hide(); $(this).find("li:first").removeClass("open") }).removeClass("trans-focused"); } } if (typeof opts == "string") { method[opts].apply(this, Array.prototype.slice.call(arguments, 1)) return this; } return this.each(function () { var _this = $(this); // Is already initialized if (!_this.data("tfs.init")) { options = $.extend(defaults, opts); _this.data("settings", options); // set initialized _this.data("tfs.init", 1); // Call init functions method.init.call(this); } }); }, /* Transform a input:file to your own layout ============================================ Basic CSS: <style> .customInput { display: inline-block; font-size: 12px; } .customInput .inputPath { width: 150px; padding: 4px; display: inline-block; border: 1px solid #ABADB3; background-color: #FFF; overflow: hidden; vertical-align: bottom; white-space: nowrap; -o-text-overflow: ellipsis; text-overflow: ellipsis; } .customInput .inputButton { display: inline-block; padding: 4px; border: 1px solid #ABADB3; background-color: #CCC; vertical-align: bottom; } </style> */ transformFile: function (options) { var method = { file: function (fn, cssClass) { return this.each(function () { var el = $(this), holder = $('<div></div>').appendTo(el).css({ position: 'absolute', overflow: 'hidden', '-moz-opacity': '0', filter: 'alpha(opacity: 0)', opacity: '0', zoom: '1', width: el.outerWidth() + 'px', height: el.outerHeight() + 'px', 'z-index': 1 }), wid = 0, inp, addInput = function () { var current = inp = holder.html('<input ' + (window.FormData ? 'multiple ' : '') + 'type="file" style="border:none; position:absolute">').find('input'); wid = wid || current.width(); current.change(function () { current.unbind('change'); addInput(); fn(current[0]); }); }, position = function (e) { holder.offset(el.offset()); if (e) { inp.offset({ left: e.pageX - wid + 25, top: e.pageY - 10 }); addMouseOver(); } }, addMouseOver = function () { el.addClass(cssClass + 'MouseOver'); }, removeMouseOver = function () { el.removeClass(cssClass + 'MouseOver'); }; addInput(); el.mouseover(position); el.mousemove(position); el.mouseout(removeMouseOver); position(); }); } }; return this.each(function (i) { // Is already initialized if (!$(this).data("tff.init")) { // set initialized $(this).data("tff.init", 1); // var el = $(this).hide(), id = null, name = el.attr('name'), cssClass = (!options ? 'customInput' : (options.cssClass ? options.cssClass : 'customInput')), label = (!options ? 'Browse...' : (options.label ? options.label : 'Browse...')); if (!el.attr('id')) { el.attr('id', 'custom_input_file_' + (new Date().getTime()) + Math.floor(Math.random() * 100000)); } id = el.attr('id'); el.after('<span id="' + id + '_custom_input" class="' + cssClass + '"><span class="inputPath" id="' + id + '_custom_input_path">&nbsp;</span><span class="inputButton">' + label + '</span></span>'); method.file.call($('#' + id + '_custom_input'), function (inp) { inp.id = id; inp.name = name; $('#' + id).replaceWith(inp) .removeAttr('style').hide(); $('#' + id + '_custom_input_path').html($('#' + id).val().replace(/\\/g, '/').replace(/.*\//, '')); }, cssClass); } }); }, /* Replace a textarea */ transformTextarea: function (options, arg1) { var defaults = { hiddenTextareaClass: "hiddenTextarea" }, settings = $.extend(defaults, options), method = { // Init the module init: function () { var _this = $(this); // This only happens in IE if (_this.css("line-height") == "normal") { _this.css("line-height", "12px"); } // Set the CSS var CSS = { 'line-height': _this.css("line-height"), 'font-family': _this.css("font-family"), 'font-size': _this.css("font-size"), "border": "1px solid black", "width": _this.width(), "letter-spacing": _this.css("letter-spacing"), "text-indent": _this.css("text-indent"), "padding": _this.css("padding"), "overflow": "hidden", "white-space": _this.css("white-space") }; _this // Add a new textarea .css(CSS) .keyup(method.keyup) .keydown(method.keyup) .bind("mousewheel", method.mousewheel) // Append a div .after($("<div />")) .next() .addClass(settings.hiddenTextareaClass) .css(CSS) .css("width", _this.width() - 5) // Minus 5 because there is some none typeable padding? .hide() }, // Mousewheel mousewheel: function (e, delta) { e.preventDefault(); var lineHeight = $(this).css("line-height"), scrollTo = $(this)[0].scrollTop + (parseFloat(lineHeight) * (delta * -1)); method.scrollToPx.call(this, scrollTo); }, // Used to scroll keyup: function (e) { // Check if it has to scroll // Arrow keys down have to scroll down / up (only if to far) /* Keys: 37, 38, 39, 40 = Arrow keys (L,U,R,D) 13 = Enter */ if ($.inArray(e.which, [37, 38, 39, 40]) >= 0) { method.checkCaretScroll.call(this); } else { method.checkScroll.call(this, e.which); } method.scrollCallBack.call(this); }, /* Check cursor position to scroll */ checkCaretScroll: function () { var src = $(this), caretStart = src.caret().start, val = src.val(), sTop = src.scrollTop(), lHeight = parseInt(src.css("line-height")), textBefore = val.substr(0, caretStart), textAfter = val.substr(caretStart), tar = src.next("." + settings.hiddenTextareaClass), vScroll; // First or last element (don't do anything) if ( caretStart ) { // Also pick the first char of a row if (val.substr(caretStart - 1, 1) == '\n') { textBefore = val.substr(0, caretStart + 1); } method.toDiv.call(this, 0, textBefore, textAfter); // If you go through the bottom if (tar.height() > (src.height() + sTop)) { vScroll = sTop + lHeight; } // if you go through the top else if (tar.height() <= sTop) { vScroll = sTop - lHeight; } // Scroll the px if (vScroll) { method.scrollToPx.call(this, vScroll); } } }, // Check the old and new height if it needs to scroll checkScroll: function (key) { // Scroll if needed var src = $(this), tar = src.next("." + settings.hiddenTextareaClass), // Put into the div to check new height caretStart = src.caret().start, v = src.val(), textBefore = v.substr(0, caretStart), textAfter = v.substr(caretStart); method.toDiv.call(this, 1, textBefore, textAfter); // If your halfway the scroll, then dont scroll if ( (src.scrollTop() + src.height()) > tar.height() ) { return; } // Scroll if needed if (tar.data("old-height") != tar.data("new-height")) { var scrollDiff = tar.data("new-height") - tar.data("old-height"); method.scrollToPx.call(this, src.scrollTop() + scrollDiff); } }, // Place the value of the textarea into the DIV toDiv: function (setHeight, html, textAfter) { var src = $(this), tar = src.next("." + settings.hiddenTextareaClass), regEnter = /\n/g, regSpace = /\s\s/g, regSingleSpace = /\s/g, res = src.val(), appendEnter = 0, appendEnterSpace = 0, brXHTML = "<br />"; if (html) res = html; // If last key is enter // or last key is space, and key before that was enter, then add enter if (regEnter.test(res.substring(res.length - 1))) { appendEnter = 1; } if ( regEnter.test(res.substring(res.length - 2, res.length - 1)) && regSingleSpace.test(res.substring(res.length - 1)) ) { appendEnterSpace = 1; } // Set old and new height + set the content if (setHeight) tar.data("old-height", tar.height()); res = res .replace(regEnter, "<br>") // No space or it will be replaced by the function below .replace(regSpace, "&nbsp; ") .replace(regSpace, "&nbsp; ") // 2x because 1x can result in: &nbsp;(space)(space) and that is not seen within the div .replace(/<br>/ig, brXHTML); tar.html(res); if ((appendEnter || appendEnterSpace) && $.trim(textAfter)) { if (appendEnterSpace && $.browser.msie) tar.append(brXHTML); tar.append(brXHTML); } if (setHeight) { tar.data("new-height", tar.height()); } }, // Scroll to a given percentage scrollToPercentage: function (perc) { // Between 0 and 100 if (perc >= 0 && perc <= 100) { var src = $(this), tar = src.next("." + settings.hiddenTextareaClass), maxScroll = parseFloat(src[0].scrollHeight) - src.height(), scrollT = maxScroll * perc / 100; // Round on a row method.scrollToPx.call(this, scrollT); } }, // Scroll to given PX scrollToPx: function (px) { var _this = this; // Round on a row $(_this).scrollTop(method.roundToLineHeight.call(_this, px)); method.scrollCallBack.call(_this); }, // Round to line height roundToLineHeight: function (num) { var lh = parseInt($(this).css("line-height")); return Math.ceil(num / lh) * lh; }, // Reset to default remove: function () { $(this) .unbind("keyup") .css({ overflow: "auto", border: "" }) .next("div") .remove(); }, scrollCallBack: function () { var _this = this, _$this = $(_this), _this0 = _$this[0], maxScroll = parseFloat(_this0.scrollHeight) - _$this.height(), percentage = parseFloat(_this0.scrollTop) / maxScroll * 100; percentage = percentage > 100 ? 100 : percentage; percentage = percentage < 0 ? 0 : percentage; percentage = isNaN(percentage) ? 100 : percentage; _$this.trigger("scrollToPx", [_this0.scrollTop, percentage]); } }; if (typeof options == "string") { method[options].call(this, arg1); return this; } return this.each(function () { if (!$(this).next().hasClass(settings.hiddenTextareaClass)) { method.init.call(this); method.toDiv.call(this, 1); } }); } }); // Radio and checkbox now use the same function $.fn.transformRadio = $.fn.transformCheckbox; })(jQuery);