diff --git a/lib/comment_paragraph_plugin.rb b/lib/comment_paragraph_plugin.rb index ba9c7ff..dc3dfad 100644 --- a/lib/comment_paragraph_plugin.rb +++ b/lib/comment_paragraph_plugin.rb @@ -21,14 +21,13 @@ class CommentParagraphPlugin < Noosfero::Plugin end def js_files - 'comment_paragraph_macro.js' + ['comment_paragraph_macro', 'rangy-core', 'rangy-cssclassapplier', 'rangy-serializer'] end def stylesheet? true end - end require_dependency 'comment_paragraph_plugin/macros/allow_comment' diff --git a/public/comment_paragraph_macro.js b/public/comment_paragraph_macro.js index a7e4c9f..6817bc9 100644 --- a/public/comment_paragraph_macro.js +++ b/public/comment_paragraph_macro.js @@ -1,7 +1,51 @@ var comment_paragraph_anchor; jQuery(document).ready(function($) { - jQuery('.autoexpand-text-area').autosize(); + rangy.init(); + cssApplier = rangy.createCssClassApplier("commented-area", {normalize: false}); + var rootElement; + +// $('.bt-marker').click(function(){ +// console.log($(this).data('paragraph-id')); +// rootElement = $('#' + 'comment_paragraph' + $(this).data('paragraph-id')).get(0); +// cssApplier.toggleSelection(); +// var selObj = rangy.getSelection(); +// var se = rangy.serializeSelection(selObj, true,rootElement); +// //$('#result').val(se); +// }); + + + //Undo previous highlight from the paragraph + $('.comment_paragraph').mousedown(function(){ + $(this).find('.commented-area').replaceWith(function() { + return $(this).html(); + }); + }); + + //highlight area from the paragraph + $('.comment_paragraph').mouseup(function(){ + rootElement = $(this).get(0); + console.log(rootElement) + cssApplier.toggleSelection(); + var selObj = rangy.getSelection(); + var selected_area = rangy.serializeSelection(selObj, true,rootElement); + + alert(selected_area) + + form = jQuery(this).parent().find('form'); + if (form.find('input.selected_area').length === 0){ + jQuery('').attr({ + class: 'selected_area', + name: 'comment[comment_paragraph_selected_area]', + value: selected_area + }).appendTo(form) + }else{ + form.find('input.selected_area').val(selected_area) + } + rootElement.focus(); + }); + + var anchor = window.location.hash; if(anchor.length==0) return; @@ -21,8 +65,20 @@ jQuery(document).ready(function($) { $.scrollTo(button); } }); + + }); +function selectAreaForComment(paragraph){ +// console.log(this) +// alert("Paragrafo " + paragraph) +// cssApplier.toggleSelection(); +// saveSelection(); +// var selObj = rangy.getSelection(); +// var se = rangy.serializeSelection(selObj, true,rootElement); +} + + function toggleParagraph(paragraph) { var div = jQuery('div.comments_list_toggle_paragraph_'+paragraph); var visible = div.is(':visible'); @@ -41,290 +97,19 @@ function loadCompleted(paragraph) { } } + + //Return a string with the beggining and the end of the selection of a text area separated by colon function getSelectionBounderies(textareaId){ - var textarea = document.getElementById(textareaId); - if ('selectionStart' in textarea) { - // check whether some text is selected in the textarea - if (textarea.selectionStart != textarea.selectionEnd) { - alert(textarea.selectionStart + ":" + textarea.selectionEnd) - return textarea.selectionStart + ":" + textarea.selectionEnd; - } - } +// var textarea = document.getElementById(textareaId); +// if ('selectionStart' in textarea) { +// // check whether some text is selected in the textarea +// if (textarea.selectionStart != textarea.selectionEnd) { +// alert(textarea.selectionStart + ":" + textarea.selectionEnd) +// return textarea.selectionStart + ":" + textarea.selectionEnd; +// } +// } return false } - -/*! - Autosize v1.18.9 - 2014-05-27 - Automatically adjust textarea height based on user input. - (c) 2014 Jack Moore - http://www.jacklmoore.com/autosize - license: http://www.opensource.org/licenses/mit-license.php -*/ -(function ($) { - var - defaults = { - className: 'autosizejs', - id: 'autosizejs', - append: '\n', - callback: false, - resizeDelay: 10, - placeholder: true - }, - - // border:0 is unnecessary, but avoids a bug in Firefox on OSX - copy = '', - - // line-height is conditionally included because IE7/IE8/old Opera do not return the correct value. - typographyStyles = [ - 'fontFamily', - 'fontSize', - 'fontWeight', - 'fontStyle', - 'letterSpacing', - 'textTransform', - 'wordSpacing', - 'textIndent' - ], - - // to keep track which textarea is being mirrored when adjust() is called. - mirrored, - - // the mirror element, which is used to calculate what size the mirrored element should be. - mirror = $(copy).data('autosize', true)[0]; - - // test that line-height can be accurately copied. - mirror.style.lineHeight = '99px'; - if ($(mirror).css('lineHeight') === '99px') { - typographyStyles.push('lineHeight'); - } - mirror.style.lineHeight = ''; - - $.fn.autosize = function (options) { - if (!this.length) { - return this; - } - - options = $.extend({}, defaults, options || {}); - - if (mirror.parentNode !== document.body) { - $(document.body).append(mirror); - } - - return this.each(function () { - var - ta = this, - $ta = $(ta), - maxHeight, - minHeight, - boxOffset = 0, - callback = $.isFunction(options.callback), - originalStyles = { - height: ta.style.height, - overflow: ta.style.overflow, - overflowY: ta.style.overflowY, - wordWrap: ta.style.wordWrap, - resize: ta.style.resize - }, - timeout, - width = $ta.width(), - taResize = $ta.css('resize'); - - if ($ta.data('autosize')) { - // exit if autosize has already been applied, or if the textarea is the mirror element. - return; - } - $ta.data('autosize', true); - - if ($ta.css('box-sizing') === 'border-box' || $ta.css('-moz-box-sizing') === 'border-box' || $ta.css('-webkit-box-sizing') === 'border-box'){ - boxOffset = $ta.outerHeight() - $ta.height(); - } - - // IE8 and lower return 'auto', which parses to NaN, if no min-height is set. - minHeight = Math.max(parseInt($ta.css('minHeight'), 10) - boxOffset || 0, $ta.height()); - - $ta.css({ - overflow: 'hidden', - overflowY: 'hidden', - wordWrap: 'break-word' // horizontal overflow is hidden, so break-word is necessary for handling words longer than the textarea width - }); - - if (taResize === 'vertical') { - $ta.css('resize','none'); - } else if (taResize === 'both') { - $ta.css('resize', 'horizontal'); - } - - // The mirror width must exactly match the textarea width, so using getBoundingClientRect because it doesn't round the sub-pixel value. - // window.getComputedStyle, getBoundingClientRect returning a width are unsupported, but also unneeded in IE8 and lower. - function setWidth() { - var width; - var style = window.getComputedStyle ? window.getComputedStyle(ta, null) : false; - - if (style) { - - width = ta.getBoundingClientRect().width; - - if (width === 0 || typeof width !== 'number') { - width = parseInt(style.width,10); - } - - $.each(['paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth'], function(i,val){ - width -= parseInt(style[val],10); - }); - } else { - width = $ta.width(); - } - - mirror.style.width = Math.max(width,0) + 'px'; - } - - function initMirror() { - var styles = {}; - - mirrored = ta; - mirror.className = options.className; - mirror.id = options.id; - maxHeight = parseInt($ta.css('maxHeight'), 10); - - // mirror is a duplicate textarea located off-screen that - // is automatically updated to contain the same text as the - // original textarea. mirror always has a height of 0. - // This gives a cross-browser supported way getting the actual - // height of the text, through the scrollTop property. - $.each(typographyStyles, function(i,val){ - styles[val] = $ta.css(val); - }); - - $(mirror).css(styles).attr('wrap', $ta.attr('wrap')); - - setWidth(); - - // Chrome-specific fix: - // When the textarea y-overflow is hidden, Chrome doesn't reflow the text to account for the space - // made available by removing the scrollbar. This workaround triggers the reflow for Chrome. - if (window.chrome) { - var width = ta.style.width; - ta.style.width = '0px'; - var ignore = ta.offsetWidth; - ta.style.width = width; - } - } - - // Using mainly bare JS in this function because it is going - // to fire very often while typing, and needs to very efficient. - function adjust() { - var height, original; - - if (mirrored !== ta) { - initMirror(); - } else { - setWidth(); - } - - if (!ta.value && options.placeholder) { - // If the textarea is empty, copy the placeholder text into - // the mirror control and use that for sizing so that we - // don't end up with placeholder getting trimmed. - mirror.value = ($ta.attr("placeholder") || '') + options.append; - } else { - mirror.value = ta.value + options.append; - } - - mirror.style.overflowY = ta.style.overflowY; - original = parseInt(ta.style.height,10); - - // Setting scrollTop to zero is needed in IE8 and lower for the next step to be accurately applied - mirror.scrollTop = 0; - - mirror.scrollTop = 9e4; - - // Using scrollTop rather than scrollHeight because scrollHeight is non-standard and includes padding. - height = mirror.scrollTop; - - if (maxHeight && height > maxHeight) { - ta.style.overflowY = 'scroll'; - height = maxHeight; - } else { - ta.style.overflowY = 'hidden'; - if (height < minHeight) { - height = minHeight; - } - } - - height += boxOffset; - - if (original !== height) { - ta.style.height = height + 'px'; - if (callback) { - options.callback.call(ta,ta); - } - } - } - - function resize () { - clearTimeout(timeout); - timeout = setTimeout(function(){ - var newWidth = $ta.width(); - - if (newWidth !== width) { - width = newWidth; - adjust(); - } - }, parseInt(options.resizeDelay,10)); - } - - if ('onpropertychange' in ta) { - if ('oninput' in ta) { - // Detects IE9. IE9 does not fire onpropertychange or oninput for deletions, - // so binding to onkeyup to catch most of those occasions. There is no way that I - // know of to detect something like 'cut' in IE9. - $ta.on('input.autosize keyup.autosize', adjust); - } else { - // IE7 / IE8 - $ta.on('propertychange.autosize', function(){ - if(event.propertyName === 'value'){ - adjust(); - } - }); - } - } else { - // Modern Browsers - $ta.on('input.autosize', adjust); - } - - // Set options.resizeDelay to false if using fixed-width textarea elements. - // Uses a timeout and width check to reduce the amount of times adjust needs to be called after window resize. - - if (options.resizeDelay !== false) { - $(window).on('resize.autosize', resize); - } - - // Event for manual triggering if needed. - // Should only be needed when the value of the textarea is changed through JavaScript rather than user input. - $ta.on('autosize.resize', adjust); - - // Event for manual triggering that also forces the styles to update as well. - // Should only be needed if one of typography styles of the textarea change, and the textarea is already the target of the adjust method. - $ta.on('autosize.resizeIncludeStyle', function() { - mirrored = null; - adjust(); - }); - - $ta.on('autosize.destroy', function(){ - mirrored = null; - clearTimeout(timeout); - $(window).off('resize', resize); - $ta - .off('autosize') - .off('.autosize') - .css(originalStyles) - .removeData('autosize'); - }); - - // Call adjust in case the textarea already contains text. - adjust(); - }); - }; -}(window.jQuery || window.$)); // jQuery or jQuery-like library, such as Zepto \ No newline at end of file diff --git a/public/jquery.autosize.js b/public/jquery.autosize.js deleted file mode 100644 index 27b341b..0000000 --- a/public/jquery.autosize.js +++ /dev/null @@ -1,272 +0,0 @@ -/*! - Autosize v1.18.9 - 2014-05-27 - Automatically adjust textarea height based on user input. - (c) 2014 Jack Moore - http://www.jacklmoore.com/autosize - license: http://www.opensource.org/licenses/mit-license.php -*/ -(function ($) { - var - defaults = { - className: 'autosizejs', - id: 'autosizejs', - append: '\n', - callback: false, - resizeDelay: 10, - placeholder: true - }, - - // border:0 is unnecessary, but avoids a bug in Firefox on OSX - copy = '', - - // line-height is conditionally included because IE7/IE8/old Opera do not return the correct value. - typographyStyles = [ - 'fontFamily', - 'fontSize', - 'fontWeight', - 'fontStyle', - 'letterSpacing', - 'textTransform', - 'wordSpacing', - 'textIndent' - ], - - // to keep track which textarea is being mirrored when adjust() is called. - mirrored, - - // the mirror element, which is used to calculate what size the mirrored element should be. - mirror = $(copy).data('autosize', true)[0]; - - // test that line-height can be accurately copied. - mirror.style.lineHeight = '99px'; - if ($(mirror).css('lineHeight') === '99px') { - typographyStyles.push('lineHeight'); - } - mirror.style.lineHeight = ''; - - $.fn.autosize = function (options) { - if (!this.length) { - return this; - } - - options = $.extend({}, defaults, options || {}); - - if (mirror.parentNode !== document.body) { - $(document.body).append(mirror); - } - - return this.each(function () { - var - ta = this, - $ta = $(ta), - maxHeight, - minHeight, - boxOffset = 0, - callback = $.isFunction(options.callback), - originalStyles = { - height: ta.style.height, - overflow: ta.style.overflow, - overflowY: ta.style.overflowY, - wordWrap: ta.style.wordWrap, - resize: ta.style.resize - }, - timeout, - width = $ta.width(), - taResize = $ta.css('resize'); - - if ($ta.data('autosize')) { - // exit if autosize has already been applied, or if the textarea is the mirror element. - return; - } - $ta.data('autosize', true); - - if ($ta.css('box-sizing') === 'border-box' || $ta.css('-moz-box-sizing') === 'border-box' || $ta.css('-webkit-box-sizing') === 'border-box'){ - boxOffset = $ta.outerHeight() - $ta.height(); - } - - // IE8 and lower return 'auto', which parses to NaN, if no min-height is set. - minHeight = Math.max(parseInt($ta.css('minHeight'), 10) - boxOffset || 0, $ta.height()); - - $ta.css({ - overflow: 'hidden', - overflowY: 'hidden', - wordWrap: 'break-word' // horizontal overflow is hidden, so break-word is necessary for handling words longer than the textarea width - }); - - if (taResize === 'vertical') { - $ta.css('resize','none'); - } else if (taResize === 'both') { - $ta.css('resize', 'horizontal'); - } - - // The mirror width must exactly match the textarea width, so using getBoundingClientRect because it doesn't round the sub-pixel value. - // window.getComputedStyle, getBoundingClientRect returning a width are unsupported, but also unneeded in IE8 and lower. - function setWidth() { - var width; - var style = window.getComputedStyle ? window.getComputedStyle(ta, null) : false; - - if (style) { - - width = ta.getBoundingClientRect().width; - - if (width === 0 || typeof width !== 'number') { - width = parseInt(style.width,10); - } - - $.each(['paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth'], function(i,val){ - width -= parseInt(style[val],10); - }); - } else { - width = $ta.width(); - } - - mirror.style.width = Math.max(width,0) + 'px'; - } - - function initMirror() { - var styles = {}; - - mirrored = ta; - mirror.className = options.className; - mirror.id = options.id; - maxHeight = parseInt($ta.css('maxHeight'), 10); - - // mirror is a duplicate textarea located off-screen that - // is automatically updated to contain the same text as the - // original textarea. mirror always has a height of 0. - // This gives a cross-browser supported way getting the actual - // height of the text, through the scrollTop property. - $.each(typographyStyles, function(i,val){ - styles[val] = $ta.css(val); - }); - - $(mirror).css(styles).attr('wrap', $ta.attr('wrap')); - - setWidth(); - - // Chrome-specific fix: - // When the textarea y-overflow is hidden, Chrome doesn't reflow the text to account for the space - // made available by removing the scrollbar. This workaround triggers the reflow for Chrome. - if (window.chrome) { - var width = ta.style.width; - ta.style.width = '0px'; - var ignore = ta.offsetWidth; - ta.style.width = width; - } - } - - // Using mainly bare JS in this function because it is going - // to fire very often while typing, and needs to very efficient. - function adjust() { - var height, original; - - if (mirrored !== ta) { - initMirror(); - } else { - setWidth(); - } - - if (!ta.value && options.placeholder) { - // If the textarea is empty, copy the placeholder text into - // the mirror control and use that for sizing so that we - // don't end up with placeholder getting trimmed. - mirror.value = ($ta.attr("placeholder") || '') + options.append; - } else { - mirror.value = ta.value + options.append; - } - - mirror.style.overflowY = ta.style.overflowY; - original = parseInt(ta.style.height,10); - - // Setting scrollTop to zero is needed in IE8 and lower for the next step to be accurately applied - mirror.scrollTop = 0; - - mirror.scrollTop = 9e4; - - // Using scrollTop rather than scrollHeight because scrollHeight is non-standard and includes padding. - height = mirror.scrollTop; - - if (maxHeight && height > maxHeight) { - ta.style.overflowY = 'scroll'; - height = maxHeight; - } else { - ta.style.overflowY = 'hidden'; - if (height < minHeight) { - height = minHeight; - } - } - - height += boxOffset; - - if (original !== height) { - ta.style.height = height + 'px'; - if (callback) { - options.callback.call(ta,ta); - } - } - } - - function resize () { - clearTimeout(timeout); - timeout = setTimeout(function(){ - var newWidth = $ta.width(); - - if (newWidth !== width) { - width = newWidth; - adjust(); - } - }, parseInt(options.resizeDelay,10)); - } - - if ('onpropertychange' in ta) { - if ('oninput' in ta) { - // Detects IE9. IE9 does not fire onpropertychange or oninput for deletions, - // so binding to onkeyup to catch most of those occasions. There is no way that I - // know of to detect something like 'cut' in IE9. - $ta.on('input.autosize keyup.autosize', adjust); - } else { - // IE7 / IE8 - $ta.on('propertychange.autosize', function(){ - if(event.propertyName === 'value'){ - adjust(); - } - }); - } - } else { - // Modern Browsers - $ta.on('input.autosize', adjust); - } - - // Set options.resizeDelay to false if using fixed-width textarea elements. - // Uses a timeout and width check to reduce the amount of times adjust needs to be called after window resize. - - if (options.resizeDelay !== false) { - $(window).on('resize.autosize', resize); - } - - // Event for manual triggering if needed. - // Should only be needed when the value of the textarea is changed through JavaScript rather than user input. - $ta.on('autosize.resize', adjust); - - // Event for manual triggering that also forces the styles to update as well. - // Should only be needed if one of typography styles of the textarea change, and the textarea is already the target of the adjust method. - $ta.on('autosize.resizeIncludeStyle', function() { - mirrored = null; - adjust(); - }); - - $ta.on('autosize.destroy', function(){ - mirrored = null; - clearTimeout(timeout); - $(window).off('resize', resize); - $ta - .off('autosize') - .off('.autosize') - .css(originalStyles) - .removeData('autosize'); - }); - - // Call adjust in case the textarea already contains text. - adjust(); - }); - }; -}(window.jQuery || window.$)); // jQuery or jQuery-like library, such as Zepto diff --git a/public/rangy-core.js b/public/rangy-core.js new file mode 100644 index 0000000..8549d10 --- /dev/null +++ b/public/rangy-core.js @@ -0,0 +1,94 @@ +/* + Rangy, a cross-browser JavaScript range and selection library + http://code.google.com/p/rangy/ + + Copyright 2012, Tim Down + Licensed under the MIT license. + Version: 1.2.3 + Build date: 26 February 2012 +*/ +window.rangy=function(){function l(p,u){var w=typeof p[u];return w=="function"||!!(w=="object"&&p[u])||w=="unknown"}function K(p,u){return!!(typeof p[u]=="object"&&p[u])}function H(p,u){return typeof p[u]!="undefined"}function I(p){return function(u,w){for(var B=w.length;B--;)if(!p(u,w[B]))return false;return true}}function z(p){return p&&A(p,x)&&v(p,t)}function C(p){window.alert("Rangy not supported in your browser. Reason: "+p);c.initialized=true;c.supported=false}function N(){if(!c.initialized){var p, +u=false,w=false;if(l(document,"createRange")){p=document.createRange();if(A(p,n)&&v(p,i))u=true;p.detach()}if((p=K(document,"body")?document.body:document.getElementsByTagName("body")[0])&&l(p,"createTextRange")){p=p.createTextRange();if(z(p))w=true}!u&&!w&&C("Neither Range nor TextRange are implemented");c.initialized=true;c.features={implementsDomRange:u,implementsTextRange:w};u=k.concat(f);w=0;for(p=u.length;w
["+c.childNodes.length+"]":c.nodeName}function n(c){this._next=this.root=c}function t(c,f){this.node=c;this.offset=f}function x(c){this.code=this[c];
+this.codeName=c;this.message="DOMException: "+this.codeName}var A=l.util;A.areHostMethods(document,["createDocumentFragment","createElement","createTextNode"])||K.fail("document missing a Node creation method");A.isHostMethod(document,"getElementsByTagName")||K.fail("document missing getElementsByTagName method");var q=document.createElement("div");A.areHostMethods(q,["insertBefore","appendChild","cloneNode"])||K.fail("Incomplete Element implementation");A.isHostProperty(q,"innerHTML")||K.fail("Element is missing innerHTML property");
+q=document.createTextNode("test");A.areHostMethods(q,["splitText","deleteData","insertData","appendData","cloneNode"])||K.fail("Incomplete Text Node implementation");var v=function(c,f){for(var k=c.length;k--;)if(c[k]===f)return true;return false};n.prototype={_current:null,hasNext:function(){return!!this._next},next:function(){var c=this._current=this._next,f;if(this._current)if(f=c.firstChild)this._next=f;else{for(f=null;c!==this.root&&!(f=c.nextSibling);)c=c.parentNode;this._next=f}return this._current},
+detach:function(){this._current=this._next=this.root=null}};t.prototype={equals:function(c){return this.node===c.node&this.offset==c.offset},inspect:function(){return"[DomPosition("+i(this.node)+":"+this.offset+")]"}};x.prototype={INDEX_SIZE_ERR:1,HIERARCHY_REQUEST_ERR:3,WRONG_DOCUMENT_ERR:4,NO_MODIFICATION_ALLOWED_ERR:7,NOT_FOUND_ERR:8,NOT_SUPPORTED_ERR:9,INVALID_STATE_ERR:11};x.prototype.toString=function(){return this.message};l.dom={arrayContains:v,isHtmlNamespace:function(c){var f;return typeof c.namespaceURI==
+"undefined"||(f=c.namespaceURI)===null||f=="http://www.w3.org/1999/xhtml"},parentElement:function(c){c=c.parentNode;return c.nodeType==1?c:null},getNodeIndex:H,getNodeLength:function(c){var f;return C(c)?c.length:(f=c.childNodes)?f.length:0},getCommonAncestor:I,isAncestorOf:function(c,f,k){for(f=k?f:f.parentNode;f;)if(f===c)return true;else f=f.parentNode;return false},getClosestAncestorIn:z,isCharacterDataNode:C,insertAfter:N,splitDataNode:function(c,f){var k=c.cloneNode(false);k.deleteData(0,f);
+c.deleteData(f,c.length-f);N(k,c);return k},getDocument:O,getWindow:function(c){c=O(c);if(typeof c.defaultView!="undefined")return c.defaultView;else if(typeof c.parentWindow!="undefined")return c.parentWindow;else throw Error("Cannot get a window object for node");},getIframeWindow:function(c){if(typeof c.contentWindow!="undefined")return c.contentWindow;else if(typeof c.contentDocument!="undefined")return c.contentDocument.defaultView;else throw Error("getIframeWindow: No Window object found for iframe element");
+},getIframeDocument:function(c){if(typeof c.contentDocument!="undefined")return c.contentDocument;else if(typeof c.contentWindow!="undefined")return c.contentWindow.document;else throw Error("getIframeWindow: No Document object found for iframe element");},getBody:function(c){return A.isHostObject(c,"body")?c.body:c.getElementsByTagName("body")[0]},getRootContainer:function(c){for(var f;f=c.parentNode;)c=f;return c},comparePoints:function(c,f,k,r){var L;if(c==k)return f===r?0:f