dimanche 19 avril 2015

jQuery Taggd plugin (Edit mode) get back value in input fields

Im using the jQuery taggd plugin, so far so good. I modified a small bit, im using it in edit mode. So when a user types in a value in the textbox it checks if it is a URL or or string, if its a URL it runs a ajax call to a php file which scrapes some data from the url. Url title, description and image. I have created 3 hidden input fields which get populated once the ajax call is finished. Once you click on the SAVE icon it saves the data to the DOM. But i want it to display again once a user clicks on the tag again. At the moment its only displaying the value of the standard input field.


This is the taggd plugin with some small modifications:





/*!
* jQuery Taggd
* A helpful plugin that helps you adding 'tags' on images.
*
* License: MIT
*/

(function($) {
'use strict';

var defaults = {
edit: false,

align: {
x: 'center',
y: 'center'
},

handlers: {},

offset: {
left: 0,
top: 0
},

strings: {
save: '✓',
delete: '×'
}
};

var methods = {
show: function() {
var $this = $(this),
$label = $this.next();

$this.addClass('active');
$label.addClass('show').find('input').focus();
},

hide: function() {
var $this = $(this);

$this.removeClass('active');
$this.next().removeClass('show');
},

toggle: function() {
var $hover = $(this).next();

if($hover.hasClass('show')) {
methods.hide.call(this);
} else {
methods.show.call(this);
}
}

};


/****************************************************************
* TAGGD
****************************************************************/

var Taggd = function(element, options, data) {
var _this = this;

if(options.edit) {
options.handlers = {
click: function() {

_this.hide();
methods.show.call(this);
}
};
}

this.element = $(element);
this.options = $.extend(true, {}, defaults, options);
this.data = data;
this.initialized = false;

if(!this.element.height() || !this.element.width()) {
this.element.on('load', _this.initialize.bind(this));
} else this.initialize();
};


/****************************************************************
* INITIALISATION
****************************************************************/

Taggd.prototype.initialize = function() {
var _this = this;

this.initialized = true;

this.initWrapper();
this.addDOM();

if(this.options.edit) {
this.element.on('click', function(e) {

var poffset = $(this).parent().offset(),
x = (e.pageX - poffset.left) / _this.element.width(),
y = (e.pageY - poffset.top) / _this.element.height();

_this.addData({
x: x,
y: y,
text: '',
url: '',
url_title: '',
url_description: '',
url_image: ''
});

_this.show(_this.data.length - 1);
});
}

$(window).resize(function() {
_this.updateDOM();
});
};

Taggd.prototype.initWrapper = function() {
var wrapper = $('<div class="taggd-wrapper" />');
this.element.wrap(wrapper);

this.wrapper = this.element.parent('.taggd-wrapper');
};

Taggd.prototype.alterDOM = function() {
var _this = this;

this.wrapper.find('.taggd-item-hover').each(function() {
var $e = $(this),

$input = $('<input id="url" type="text" size="16" />')
.val($e.text()),
$url_title = $('<input type="text" id="url_title" class="url_title" />'),
$button_ok = $('<button />')
.html(_this.options.strings.save),

$url_description = $('<input type="text" class="url_description" id="url_description" />'),
$url_image = $('<input type="text" class="url_img" id="url_img" />'),
$url_preview = $('<div id="content"></div>'),
$button_delete = $('<button />')
.html(_this.options.strings.delete);


$button_delete.on('click', function() {
var x = $e.attr('data-x'),
y = $e.attr('data-y');

_this.data = $.grep(_this.data, function(v) {
return v.x != x || v.y != y;
});

_this.addDOM();
_this.element.triggerHandler('change');
});

// Typing URL timer
var typingTimer;
var doneTypingInterval = 2000;

$input.keyup(function() {
clearTimeout(typingTimer);
typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

$input.keydown(function() {
clearTimeout(typingTimer);
$url_preview.empty();
});

// Process URL scrape request
function doneTyping() {
var getUrl = $input.val();

if(isURL(getUrl)) {
console.log('Typed text is a URL');
$url_preview.append('<img src="images/loader.gif" style="width:24px; padding-top:10px; height:24px; margin:0 auto;">');


// Get url data by ajax
$.post('ajax/Crawl.php', {
'url' : getUrl
},function(data) {

$url_preview.empty();


var content = '<h3 class="url_title">' + data.title + '</h3><p class="url_description" style="font-size:11px;">' + data.description + '</p><img class="url_image" src="' + data.images + '" style="width:100%; height:auto;">';
$url_preview.append(content);

$url_title.val(data.title);
$url_description.val(data.description);
$url_image.val(data.images);
console.log(content);


}, 'json');

} else {
console.log('Typed text is a string');
}
};


function isURL(url) {

var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment locator

if(!pattern.test(url)) {
return false;
} else {
if(!/^(https?|ftp):\/\//i.test(url)) {

url = 'http://'+url;
$input.val(url);
}
return true;
}

};


$button_ok.on('click', function() {
var x = $e.attr('data-x'),
y = $e.attr('data-y'),

item = $.grep(_this.data, function(v) {
return v.x == x && v.y == y;
}).pop();

if(item) item.text = $input.val();
if(isURL(item.text)) {
if(item) item.url = item.text;
} else {
if(item) item.url = null;
}

if(item) item.url_title = $url_title.val();
if(item) item.url_description = $url_description.val();
if(item) item.url_image = $url_image.val();

_this.addDOM();
_this.element.triggerHandler('change');
//_this.hide();
});
/*$input.on('change', function() {

var x = $e.attr('data-x'),
y = $e.attr('data-y'),
item = $.grep(_this.data, function(v) {
return v.x == x && v.y == y;
}).pop();

if(item) item.text = $input.val();


_this.addDOM();
_this.element.triggerHandler('change');
});
*/
$e.empty().append($input, $button_ok, $button_delete, $url_preview, $url_title, $url_description, $url_image);


});

_this.updateDOM();

};

/****************************************************************
* DATA MANAGEMENT
****************************************************************/

Taggd.prototype.addData = function(data) {
if($.isArray(data)) {
this.data = $.merge(this.data, data);
} else {
this.data.push(data);
}

if(this.initialized) {
this.addDOM();
this.element.triggerHandler('change');
}
};

Taggd.prototype.setData = function(data) {
this.data = data;

if(this.initialized) {
this.addDOM();
}
};

Taggd.prototype.clear = function() {
if(!this.initialized) return;
this.wrapper.find('.taggd-item, .taggd-item-hover').remove();
};


/****************************************************************
* EVENTS
****************************************************************/

Taggd.prototype.on = function(event, handler) {
if(
typeof event !== 'string' ||
typeof handler !== 'function'
) return;

this.element.on(event, handler);
};


/****************************************************************
* TAGS MANAGEMENT
****************************************************************/

Taggd.prototype.iterateTags = function(a, yep) {
var func;

if($.isNumeric(a)) {
func = function(i, e) { return a === i; };
} else if(typeof a === 'string') {
func = function(i, e) { return $(e).is(a); }
} else if($.isArray(a)) {
func = function(i, e) {
var $e = $(e);
var result = false;

$.each(a, function(ai, ae) {
if(
i === ai ||
e === ae ||
$e.is(ae)
) {
result = true;
return false;
}
});

return result;
}
} else if(typeof a === 'object') {
func = function(i, e) {
var $e = $(e);
return $e.is(a);
};
} else if($.isFunction(a)) {
func = a;
} else if(!a) {
func = function() { return true; }
} else return this;

this.wrapper.find('.taggd-item').each(function(i, e) {
if(typeof yep === 'function' && func.call(this, i, e)) {
yep.call(this, i, e);
}
});

return this;
};

Taggd.prototype.show = function(a) {
return this.iterateTags(a, methods.show);
};

Taggd.prototype.hide = function(a) {
return this.iterateTags(a, methods.hide);
};

Taggd.prototype.toggle = function(a) {
return this.iterateTags(a, methods.toggle);
};

/****************************************************************
* CLEANING UP
****************************************************************/

Taggd.prototype.dispose = function() {
this.clear();
this.element.unwrap(this.wrapper);
};


/****************************************************************
* SEMI-PRIVATE
****************************************************************/

Taggd.prototype.addDOM = function() {
var _this = this;

this.clear();
this.element.css({ height: 'auto', width: 'auto' });

var height = this.element.height();
var width = this.element.width();

$.each(this.data, function(i, v) {
var $item = $('<span />');
var $hover;

if(
v.x > 1 && v.x % 1 === 0 &&
v.y > 1 && v.y % 1 === 0
) {
v.x = v.x / width;
v.y = v.y / height;
}

if(typeof v.attributes === 'object') {
$item.attr(v.attributes);
}

$item.attr({
'data-x': v.x,
'data-y': v.y
});

$item.css('position', 'absolute');
$item.addClass('taggd-item');

_this.wrapper.append($item);

if(typeof v.text === 'string' && (v.text.length > 0 || _this.options.edit)) {
$hover = $('<span class="taggd-item-hover" style="position: absolute;" />').html(v.text);

$hover.attr({
'data-x': v.x,
'data-y': v.y
});

_this.wrapper.append($hover);
}

if(typeof _this.options.handlers === 'object') {
$.each(_this.options.handlers, function(event, func) {
var handler;

if(typeof func === 'string' && methods[func]) {
handler = methods[func];
} else if(typeof func === 'function') {
handler = func;
}

$item.on(event, function(e) {
if(!handler) return;
handler.call($item, e, _this.data[i]);
});
});
}
});

this.element.removeAttr('style');

if(this.options.edit) {
this.alterDOM();

}

this.updateDOM();
};

Taggd.prototype.updateDOM = function() {
var _this = this;

this.wrapper.removeAttr('style').css({
height: this.element.height(),
width: this.element.width()
});

this.wrapper.find('span').each(function(i, e) {
var $el = $(e);

var left = $el.attr('data-x') * _this.element.width();
var top = $el.attr('data-y') * _this.element.height();

if($el.hasClass('taggd-item')) {
$el.css({
left: left - $el.outerWidth(true) / 2,
top: top - $el.outerHeight(true) / 2
});
} else if($el.hasClass('taggd-item-hover')) {
if(_this.options.align.x === 'center') {
left -= $el.outerWidth(true) / 2;
} else if(_this.options.align.x === 'right') {
left -= $el.outerWidth(true);
}

if(_this.options.align.y === 'center') {
top -= $el.outerHeight(true) / 2;
} else if(_this.options.align.y === 'bottom') {
top -= $el.outerHeight(true);
}

$el.attr('data-align', $el.outerWidth(true));

$el.css({
left: left + _this.options.offset.left,
top: top + _this.options.offset.top
});
}
});
};


/****************************************************************
* JQUERY LINK
****************************************************************/

$.fn.taggd = function(options, data) {
return new Taggd(this, options, data);
};
})(jQuery);



I thought this would do what i want, since it works with the standard text input box, using .val($e.text()), works fine but as soon as i do the same to the url_title box, for example .val($e.url_title()), i get the error below.





$input = $('<input id="url" type="text" size="16" />')
.val($e.text()),
$url_title = $('<input type="text" id="url_title" class="url_title" />'),
$button_ok = $('<button />')
.html(_this.options.strings.save),

$url_description = $('<input type="text" class="url_description" id="url_description" />'),
$url_image = $('<input type="text" class="url_img" id="url_img" />'),
$url_preview = $('<div id="content"></div>'),
$button_delete = $('<button />')
.html(_this.options.strings.delete);



But if for example i change the $url_title to





$url_title = $('<input type="text" id="url_title" class="url_title" />').val($e.url_title()),


I get a error back in the console: Uncaught TypeError: undefined is not a function


This is the init code on the main page:





$(document).ready(function() {
var options = {
edit: true,

align: {
y: 'top'
},

offset: {
top: 15
},

handlers: {
//mouseenter: 'show',
click: 'toggle'
}
};

/*var data = [
{ x: 0.22870478413068845, y: 0.41821946169772256, text: 'Eye' },
{ x: 0.51, y: 0.5, text: 'Bird' },
{ x: 0.40, y: 0.3, text: 'Water, obviously' }
];*/
var data = [];

var taggd = $('.taggd').taggd( options, data );

taggd.on('change', function() {
console.log(taggd.data);
});
});



In the console log it logs the values fine:



[Object]0: Objecttext: "http://ift.tt/gbk8l4"url: "http://ift.tt/gbk8l4"url_description: "Q&A for professional and enthusiast programmers"url_image: "http://ift.tt/1HGxN5r"url_title: "Stack Overflow"x: 0.41141586360266863y: 0.19444444444444445


I hope someone can shine a light on it and point me in the right direction of what i'm doing wrong.


To simplify it, i want to be able to have a title input and a description input for my tags, how would i achieve this?


Thank you.


Aucun commentaire:

Enregistrer un commentaire