// feedback.js
// 2013, Kázmér Rapavi, https://github.com/ivoviz/feedback
// Licensed under the MIT license.
// Version 2.0
(function($){
$.feedback = function(options) {
var settings = $.extend({
mantis_project_id: 0,
ajaxURL: 'http://mantis.designpark.pl/dp',
postBrowserInfo: true,
postHTML: false,
postURL: true,
proxy: undefined,
letterRendering: false,
initButtonText: 'Feedback',
strokeStyle: 'black',
shadowColor: 'black',
shadowOffsetX: 1,
shadowOffsetY: 1,
shadowBlur: 10,
lineJoin: 'bevel',
lineWidth: 3,
html2canvasURL: 'http://mantis.designpark.pl/dp/html2canvas.min.js',
zoomDetectURL: 'http://mantis.designpark.pl/dp/detect-zoom.js',
feedbackButton: '.feedback-btn',
showDescriptionModal: false,
isDraggable: false,
onScreenshotTaken: function(){},
tpl: {
description: '
Feedback
Feedback umożliwia przesłanie nam sugestii na temat tworzonej strony internetowej.
Opisz dokładnie problem:
Proszę uzupełnić opis.
',
highlighter: 'Feedback
Zaloguj się do systemu Mantis
Zaznacz na stronie elementy, które chcesz oznaczyć na przesłanym screenie
',
overview: 'Feedback
Opis
Dodatkowe informaje
Brak
Informacje o przeglądarce
Informacje o stronie
Struktura strony
Screenshot
Dodaj proszę opis.
',
submitSuccess: '',
submitError: '',
loginError: ''
},
onClose: function() {},
screenshotStroke: true,
highlightElement: true,
initialBox: true
}, options);
var supportedBrowser = !!window.HTMLCanvasElement;
var isFeedbackButtonNative = settings.feedbackButton == '.feedback-btn';
var _html2canvas = false;
if (supportedBrowser) {
if(isFeedbackButtonNative) {
$('body').append('');
}
$(document).on('click', settings.feedbackButton, function(){
if(isFeedbackButtonNative) {
$(this).hide();
}
if (!_html2canvas) {
$.getScript(settings.html2canvasURL, function() {
_html2canvas = true;
});
}
var canDraw = false,
img = '',
h = $(document).height(),
w = $(document).width(),
tpl = '';
if (settings.initialBox) {
tpl += settings.tpl.description;
}
tpl += settings.tpl.highlighter + settings.tpl.overview + '
';
$('body').append(tpl);
moduleStyle = {
'position': 'absolute',
'left': '0px',
'top': '0px'
};
canvasAttr = {
'width': w,
'height': h
};
$('#feedback-module').css(moduleStyle);
$('#feedback-canvas').attr(canvasAttr).css('z-index', '30000');
if (!settings.initialBox) {
$('#feedback-highlighter-back').remove();
canDraw = true;
$('#feedback-canvas').css('cursor', 'crosshair');
$('#feedback-helpers').show();
$('#feedback-welcome').hide();
$('#feedback-highlighter').show();
}
if( sessionStorage.getItem('login') ){
$('.feedback-logo').text('Feedback ('+sessionStorage.getItem('name')+')');
$('#feedback-login-page').remove();
$('#feedback-start-page').show();
}
if(settings.isDraggable) {
$('#feedback-highlighter').on('mousedown', function(e) {
var $d = $(this).addClass('feedback-draggable'),
drag_h = $d.outerHeight(),
drag_w = $d.outerWidth(),
pos_y = $d.offset().top + drag_h - e.pageY,
pos_x = $d.offset().left + drag_w - e.pageX;
$d.css('z-index', 40000).parents().on('mousemove', function(e) {
_top = e.pageY + pos_y - drag_h;
_left = e.pageX + pos_x - drag_w;
_bottom = drag_h - e.pageY;
_right = drag_w - e.pageX;
if (_left < 0) _left = 0;
if (_top < 0) _top = 0;
if (_right > $(window).width())
_left = $(window).width() - drag_w;
if (_left > $(window).width() - drag_w)
_left = $(window).width() - drag_w;
if (_bottom > $(document).height())
_top = $(document).height() - drag_h;
if (_top > $(document).height() - drag_h)
_top = $(document).height() - drag_h;
$('.feedback-draggable').offset({
top: _top,
left: _left
}).on("mouseup", function() {
$(this).removeClass('feedback-draggable');
});
});
e.preventDefault();
}).on('mouseup', function(){
$(this).removeClass('feedback-draggable');
$(this).parents().off('mousemove mousedown');
});
}
var ctx = $('#feedback-canvas')[0].getContext('2d');
ctx.fillStyle = 'rgba(102,102,102,0.5)';
ctx.fillRect(0, 0, $('#feedback-canvas').width(), $('#feedback-canvas').height());
rect = {};
drag = false;
highlight = 1,
post = {};
if (settings.postBrowserInfo) {
post.browser = {};
post.browser.appCodeName = navigator.appCodeName;
post.browser.appName = navigator.appName;
post.browser.appVersion = navigator.appVersion;
post.browser.cookieEnabled = navigator.cookieEnabled;
post.browser.onLine = navigator.onLine;
post.browser.platform = navigator.platform;
post.browser.userAgent = navigator.userAgent;
post.browser.resolution = window.innerWidth + 'x' + window.innerHeight;
post.browser.plugins = [];
post.browser.URL = window.location.href;
$.each(navigator.plugins, function(i) {
post.browser.plugins.push(navigator.plugins[i].name);
});
$('#feedback-browser-info').show();
}
$.getScript(settings.zoomDetectURL, function(){
post.browser.zoom= ((window.detectZoom.zoom().toFixed(2)) * 100 ) + '%';
});
if (settings.postURL) {
post.url = document.URL;
$('#feedback-page-info').show();
}
if (settings.postHTML) {
post.html = $('html').html();
$('#feedback-page-structure').show();
}
if (!settings.postBrowserInfo && !settings.postURL && !settings.postHTML)
$('#feedback-additional-none').show();
$(document).on('mousedown', '#feedback-canvas', function(e) {
if (canDraw) {
rect.startX = e.pageX - $(this).offset().left;
rect.startY = e.pageY - $(this).offset().top;
rect.w = 0;
rect.h = 0;
drag = true;
}
});
$(document).on('mouseup', function(){
if (canDraw) {
drag = false;
var dtop = rect.startY,
dleft = rect.startX,
dwidth = rect.w,
dheight = rect.h;
dtype = 'highlight';
if (dwidth == 0 || dheight == 0) return;
if (dwidth < 0) {
dleft += dwidth;
dwidth *= -1;
}
if (dheight < 0) {
dtop += dheight;
dheight *= -1;
}
if (dtop + dheight > $(document).height())
dheight = $(document).height() - dtop;
if (dleft + dwidth > $(document).width())
dwidth = $(document).width() - dleft;
if (highlight == 0)
dtype = 'blackout';
if( typeof dtop != 'undefined' ){
$('#feedback-helpers').append('');
}
redraw(ctx);
rect.w = 0;
}
});
$(document).on('mousemove', function(e) {
if (canDraw && drag) {
$('#feedback-highlighter').css('cursor', 'default');
rect.w = (e.pageX - $('#feedback-canvas').offset().left) - rect.startX;
rect.h = (e.pageY - $('#feedback-canvas').offset().top) - rect.startY;
ctx.clearRect(0, 0, $('#feedback-canvas').width(), $('#feedback-canvas').height());
ctx.fillStyle = 'rgba(102,102,102,0.5)';
ctx.fillRect(0, 0, $('#feedback-canvas').width(), $('#feedback-canvas').height());
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'highlight')
drawlines(ctx, parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
});
if (highlight==1) {
drawlines(ctx, rect.startX, rect.startY, rect.w, rect.h);
ctx.clearRect(rect.startX, rect.startY, rect.w, rect.h);
}
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'highlight')
ctx.clearRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
});
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'blackout') {
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height())
}
});
if (highlight == 0) {
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
}
}
});
if (settings.highlightElement) {
var highlighted = [],
tmpHighlighted = [],
hidx = 0;
$(document).on('mousemove click', '#feedback-canvas',function(e) {
if (canDraw) {
redraw(ctx);
tmpHighlighted = [];
$('#feedback-canvas').css('cursor', 'crosshair');
$('* :not(body,script,iframe,div,section,.feedback-btn,#feedback-module *)').each(function(){
if ($(this).attr('data-highlighted') === 'true')
return;
if (e.pageX > $(this).offset().left && e.pageX < $(this).offset().left + $(this).width() && e.pageY > $(this).offset().top + parseInt($(this).css('padding-top'), 10) && e.pageY < $(this).offset().top + $(this).height() + parseInt($(this).css('padding-top'), 10)) {
tmpHighlighted.push($(this));
}
});
var $toHighlight = tmpHighlighted[tmpHighlighted.length - 1];
if ($toHighlight && !drag) {
$('#feedback-canvas').css('cursor', 'pointer');
var _x = $toHighlight.offset().left - 2,
_y = $toHighlight.offset().top - 2,
_w = $toHighlight.width() + parseInt($toHighlight.css('padding-left'), 10) + parseInt($toHighlight.css('padding-right'), 10) + 6,
_h = $toHighlight.height() + parseInt($toHighlight.css('padding-top'), 10) + parseInt($toHighlight.css('padding-bottom'), 10) + 6;
if (highlight == 1) {
drawlines(ctx, _x, _y, _w, _h);
ctx.clearRect(_x, _y, _w, _h);
dtype = 'highlight';
}
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'highlight')
ctx.clearRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
});
if (highlight == 0) {
dtype = 'blackout';
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(_x, _y, _w, _h);
}
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'blackout') {
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
}
});
if (e.type == 'click' && e.pageX == rect.startX && e.pageY == rect.startY) {
$('#feedback-helpers').append('');
highlighted.push(hidx);
++hidx;
redraw(ctx);
}
}
}
});
}
$(document).on('submit', '#feedback-login-page form', function() {
var l = $('input[name="login"]',this).val();
var p = $('input[name="pass"]',this).val();
$.ajax({
url: settings.ajaxURL+'/login.php',
dataType: 'json',
type: 'POST',
data: $(this).serialize(),
success: function(d) {
sessionStorage.setItem('login', l);
sessionStorage.setItem('pass', p);
sessionStorage.setItem('name', d.name);
$('#feedback-login-page').remove();
$('#feedback-start-page').show();
},
error: function(){
$('#feedback-module').append(settings.tpl.loginError);
}
});
return false;
});
$(document).on('mouseleave', 'body,#feedback-canvas', function() {
redraw(ctx);
});
$(document).on('mouseenter', '.feedback-helper', function() {
redraw(ctx);
});
$(document).on('click', '#feedback-welcome-next', function() {
if ($('#feedback-note').val().length > 0) {
canDraw = true;
$('#feedback-canvas').css('cursor', 'crosshair');
$('#feedback-helpers').show();
$('#feedback-welcome').hide();
$('#feedback-highlighter').show();
}
else {
$('#feedback-welcome-error').show();
}
});
$(document).on('mouseenter mouseleave', '.feedback-helper', function(e) {
if (drag)
return;
rect.w = 0;
rect.h = 0;
if (e.type === 'mouseenter') {
$(this).css('z-index', '30001');
$(this).append('');
$(this).append('');
$(this).find('#feedback-close').css({
'top' : -1 * ($(this).find('#feedback-close').height() / 2) + 'px',
'left' : $(this).width() - ($(this).find('#feedback-close').width() / 2) + 'px'
});
if ($(this).attr('data-type') == 'blackout') {
/* redraw white */
ctx.clearRect(0, 0, $('#feedback-canvas').width(), $('#feedback-canvas').height());
ctx.fillStyle = 'rgba(102,102,102,0.5)';
ctx.fillRect(0, 0, $('#feedback-canvas').width(), $('#feedback-canvas').height());
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'highlight')
drawlines(ctx, parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
});
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'highlight')
ctx.clearRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
});
ctx.clearRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height())
ctx.fillStyle = 'rgba(0,0,0,0.75)';
ctx.fillRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
ignore = $(this).attr('data-time');
/* redraw black */
$('.feedback-helper').each(function() {
if ($(this).attr('data-time') == ignore)
return true;
if ($(this).attr('data-type') == 'blackout') {
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height())
}
});
}
}
else {
$(this).css('z-index','30000');
$(this).children().remove();
if ($(this).attr('data-type') == 'blackout') {
redraw(ctx);
}
}
});
$(document).on('click', '#feedback-close', function() {
if (settings.highlightElement && $(this).parent().attr('data-highlight-id'))
var _hidx = $(this).parent().attr('data-highlight-id');
$(this).parent().remove();
if (settings.highlightElement && _hidx)
$('[data-highlight-id="' + _hidx + '"]').removeAttr('data-highlighted').removeAttr('data-highlight-id');
redraw(ctx);
});
$('#feedback-module').on('click', '.feedback-wizard-close,.feedback-close-btn', function() {
close();
});
$(document).on('selectstart dragstart', document, function(e) {
e.preventDefault();
});
$(document).on('click', '#feedback-highlighter-back', function() {
canDraw = false;
$('#feedback-canvas').css('cursor', 'default');
$('#feedback-helpers').hide();
$('#feedback-highlighter').hide();
$('#feedback-welcome-error').hide();
$('#feedback-welcome').show();
});
$(document).on('mousedown', '.feedback-sethighlight', function() {
highlight = 1;
$(this).addClass('feedback-active');
$('.feedback-setblackout').removeClass('feedback-active');
});
$(document).on('mousedown', '.feedback-setblackout', function() {
highlight = 0;
$(this).addClass('feedback-active');
$('.feedback-sethighlight').removeClass('feedback-active');
});
$(document).on('click', '#feedback-highlighter-next', function() {
canDraw = false;
$('#feedback-canvas').css('cursor', 'default');
var sy = $(document).scrollTop(),
dh = $(window).height();
$('#feedback-helpers').hide();
$('#feedback-highlighter').hide();
if (!settings.screenshotStroke) {
redraw(ctx, false);
}
html2canvas($('body'), {
onrendered: function(canvas) {
if (!settings.screenshotStroke) {
redraw(ctx);
}
if( $('#feedback-helpers > div').length ){
// jeśli coś zaznaczono
_canvas = $('').hide().appendTo('body');
_ctx = _canvas.get(0).getContext('2d');
_ctx.drawImage(canvas, 0, sy, w, dh, 0, 0, w, dh);
img = _canvas.get(0).toDataURL();
$(document).scrollTop(sy);
post.img = img;
settings.onScreenshotTaken(post.img);
settings.showDescriptionModal = true;
}
if(settings.showDescriptionModal) {
$('#feedback-canvas-tmp').remove();
$('#feedback-overview').show();
$('#feedback-overview-description-text>textarea').remove();
$('#feedback-overview-screenshot>img').remove();
$('').insertAfter('#feedback-overview-description-text h3:eq(0)');
$('#feedback-overview-screenshot').append('
');
}
else {
$('#feedback-submit').trigger('click');
//$('#feedback-module').remove();
//close();
if( $('#feedback-helpers > div').length ){
_canvas.remove();
}
}
},
proxy: settings.proxy,
letterRendering: settings.letterRendering
});
});
$(document).on('click', '#feedback-overview-back', function(e) {
canDraw = true;
$('#feedback-canvas').css('cursor', 'crosshair');
$('#feedback-overview').hide();
$('#feedback-helpers').show();
$('#feedback-highlighter').show();
$('#feedback-overview-error').hide();
});
$(document).on('keyup', '#feedback-note-tmp,#feedback-overview-note', function(e) {
var tx;
if (e.target.id === 'feedback-note-tmp')
tx = $('#feedback-note-tmp').val();
else {
tx = $('#feedback-overview-note').val();
$('#feedback-note-tmp').val(tx);
}
$('#feedback-note').val(tx);
});
$(document).on('click', '#feedback-submit', function() {
canDraw = false;
if ($('#feedback-note').val().length > 0) {
$('#feedback-submit-success,#feedback-submit-error').remove();
$('#feedback-overview').hide();
if( $('#feedback-helpers > div').length ){
// jeśli coś zaznaczono
post.img = img;
}
post.note = $('#feedback-note').val();
post.title = $('#feedback-title-tmp').val();
post.login = sessionStorage.getItem('login');
post.pass = sessionStorage.getItem('pass');
post.project = settings.mantis_project_id;
var data = {feedback: JSON.stringify(post)};
$.ajax({
url: settings.ajaxURL+'/index.php',
dataType: 'json',
type: 'POST',
data: data,
success: function() {
$('#feedback-module').append(settings.tpl.submitSuccess);
},
error: function(){
$('#feedback-module').append(settings.tpl.submitError);
}
});
}
else {
$('#feedback-overview-error').show();
}
});
});
}
function close() {
//$('#feedback-submit-error').hide();
//return false;
canDraw = false;
$(document).off('mouseenter mouseleave', '.feedback-helper');
$(document).off('mouseup keyup');
$(document).off('mousedown', '.feedback-setblackout');
$(document).off('mousedown', '.feedback-sethighlight');
$(document).off('mousedown click', '#feedback-close');
$(document).off('mousedown', '#feedback-canvas');
$(document).off('click', '#feedback-highlighter-next');
$(document).off('click', '#feedback-highlighter-back');
$(document).off('click', '#feedback-welcome-next');
$(document).off('click', '#feedback-overview-back');
$(document).off('mouseleave', 'body');
$(document).off('mouseenter', '.feedback-helper');
$(document).off('selectstart dragstart', document);
$('#feedback-module').off('click', '.feedback-wizard-close,.feedback-close-btn');
$(document).off('click', '#feedback-submit');
if (settings.highlightElement) {
$(document).off('click', '#feedback-canvas');
$(document).off('mousemove', '#feedback-canvas');
}
$('[data-highlighted="true"]').removeAttr('data-highlight-id').removeAttr('data-highlighted');
$('#feedback-module').remove();
$('.feedback-btn').show();
settings.onClose.call(this);
}
function redraw(ctx, border) {
border = typeof border !== 'undefined' ? border : true;
ctx.clearRect(0, 0, $('#feedback-canvas').width(), $('#feedback-canvas').height());
ctx.fillStyle = 'rgba(102,102,102,0.5)';
ctx.fillRect(0, 0, $('#feedback-canvas').width(), $('#feedback-canvas').height());
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'highlight')
if (border)
drawlines(ctx, parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
});
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'highlight')
ctx.clearRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
});
$('.feedback-helper').each(function() {
if ($(this).attr('data-type') == 'blackout') {
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(parseInt($(this).css('left'), 10), parseInt($(this).css('top'), 10), $(this).width(), $(this).height());
}
});
}
function drawlines(ctx, x, y, w, h) {
ctx.strokeStyle = settings.strokeStyle;
ctx.shadowColor = settings.shadowColor;
ctx.shadowOffsetX = settings.shadowOffsetX;
ctx.shadowOffsetY = settings.shadowOffsetY;
ctx.shadowBlur = settings.shadowBlur;
ctx.lineJoin = settings.lineJoin;
ctx.lineWidth = settings.lineWidth;
ctx.strokeRect(x,y,w,h);
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 0;
ctx.lineWidth = 1;
}
};
}(jQuery));