I've create this code in HTML
<div class="margin-bottom"><p class="title"><strong>Picture</strong></p>
<div class="textbox-group margin-bottom">
<span class="textbox-group-addon pointer" id="basic-addon"><div class="dropzones"><div class="info"><i class="fa fa-upload" title="Picture Preview"></i></div></div></span>
<input id="preview" class="textbox" name="preview" value="" type="text" aria-describedby="basic-addon">
</div><div class="loading-modal text-center"><i class="fa fa-spinner fa-pulse fa-3x fa-fw"><span class="sr-only"></span></i> Uploading...</div>
and here is my imguruploads.js
/* Imgur Upload Script */
(function (root, factory) {
"use strict";
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.Imgur = factory();
}
}(this, function () {
"use strict";
var Imgur = function (options) {
if (!this || !(this instanceof Imgur)) {
return new Imgur(options);
}
if (!options) {
options = {};
}
if (!options.clientid) {
throw 'Provide a valid Client Id here: https://api.imgur.com/';
}
this.clientid = options.clientid;
this.endpoint = 'https://api.imgur.com/3/image';
this.callback = options.callback || undefined;
this.dropzones = document.querySelectorAll('.dropzones');
this.info = document.querySelectorAll('.info');
this.run();
};
Imgur.prototype = {
createEls: function (name, props, text) {
var el = document.createElement(name), p;
for (p in props) {
if (props.hasOwnProperty(p)) {
el[p] = props[p];
}
}
if (text) {
el.appendChild(document.createTextNode(text));
}
return el;
},
insertAfter: function (referenceNode, newNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
},
post: function (path, data, callback) {
var xhttp = new XMLHttpRequest();
xhttp.open('POST', path, true);
xhttp.setRequestHeader('Authorization', 'Client-ID ' + this.clientid);
xhttp.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status >= 200 && this.status < 300) {
var response = '';
try {
response = JSON.parse(this.responseText);
} catch (err) {
response = this.responseText;
}
callback.call(window, response);
} else {
throw new Error(this.status + " - " + this.statusText);
}
}
};
xhttp.send(data);
xhttp = null;
},
createDragZone: function () {
var input;
input = this.createEls('input', {type: 'file', className: 'input', accept: 'image/*'});
Array.prototype.forEach.call(this.dropzones, function (zone) {
zone.appendChild(input);
this.status(zone);
this.upload(zone);
}.bind(this));
},
loading: function () {
var div, i, span;
div = this.createEls('div', {className: 'loading-modals'});
i = this.createEls('i', {className: 'fa fa-spinner fa-pulse fa-3x fa-fw'});
span = this.createEls('span', {className: 'sr-only'});
div.appendChild(i);
i.appendChild(span);
document.body.appendChild(div);
},
status: function (el) {
var div = this.createEls('div', {className: 'statuss'});
this.insertAfter(el, div);
},
matchFiles: function (file, zone) {
var status = zone.nextSibling;
if (file.type.match(/image/) && file.type !== 'image/svg+xml') {
document.body.classList.add('loading');
status.classList.remove('pm_alert', 'red_alert');
status.innerHTML = '';
var fd = new FormData();
fd.append('image', file);
this.post(this.endpoint, fd, function (data) {
document.body.classList.remove('loading');
typeof this.callback === 'function' && this.callback.call(this, data);
}.bind(this));
} else {
status.classList.remove('pm_alert');
status.classList.add('red_alert');
status.innerHTML = 'Invalid archive';
}
},
upload: function (zone) {
var events = ['dragenter', 'dragleave', 'dragover', 'drop'],
file, target, i, len;
zone.addEventListener('change', function (e) {
if (e.target && e.target.nodeName === 'INPUT' && e.target.type === 'file') {
target = e.target.files;
for (i = 0, len = target.length; i < len; i += 1) {
file = target[i];
this.matchFiles(file, zone);
}
}
}.bind(this), false);
events.map(function (event) {
zone.addEventListener(event, function (e) {
if (e.target && e.target.nodeName === 'INPUT' && e.target.type === 'file') {
if (event === 'dragleave' || event === 'drop') {
e.target.parentNode.classList.remove('dropzone-dragging');
} else {
e.target.parentNode.classList.add('dropzone-dragging');
}
}
}, false);
});
},
run: function () {
var loadingModal = document.querySelector('.loading-modal');
if (!loadingModal) {
this.loading();
}
this.createDragZone();
}
};
return Imgur;
}));
var feedback = function(res) {
textarea: '',
document.textarea = $('#preview');
if (res.success === true) {
var wahaha = res.data.link.replace();
document.text.add( wahaha );
document.querySelector('.status').classList.add('bg-success');
document.querySelector('.status').innerHTML =
'<div class="text-left">Copy dan Paste kan link gambar <i class="fa fa-hand-o-down fa-fw"></i> ke form <strong>atas</strong> <i class="fa fa-hand-o-up fa-fw"></i></div>' + '<div class="text-center scaleimages padding-topbottom"><input class="textbox image-url media-heading" value=' + wahaha + '/>' + '<img class="img" src=' + wahaha + '/>';
}
};
new Imgur({
clientid: '3da90edf4016361', //You can change this ClientID
callback: feedback
});
this code work well but not work like what I want, I want when the image uploaded successfully then the link "wahaha" added to this input form
<input id="preview" class="textbox" name="preview" value="" type="text" aria-describedby="basic-addon">
Yes there are input form show when it finish upload, but what I want is the text added to another input form
anyone have an idea to fix this?
just add this code
document.getElementById('gambar_preview').value = wahaha;
and everything work like what I want
Related
I want to check the inputs for each tab.
My code so far: jsfiddle
$(document).ready(function () {
var tabs = $("#mytabs").tabs();
var validator = $("#formItem").validate();
$(".next-button").click(function () {
//var selected = $("#tabs").tabs("option", "selected");
//$("#tabs").tabs("option", "selected", selected + 1);
var valid = true;
var i = 0;
var $inputs = $(this).closest("div").find("input");
$inputs.each(function () {
if (!validator.element(this) && valid) {
valid = false;
}
});
if (valid) {
$("#mytabs").tabs("option", "current", 1);
}
});
//use link to submit form instead of button
$("button[id=finish_button]").click(function () {
$(this).parents("form").submit();
});
});
You need to find closest div but with class i.e tab-content or you can use the respective id as in your current implementation there is a next button for each tab. So use unique id of your div.
You currently have following defined which is incorrect,
var $inputs = $(this).closest("div").find("input");
Fix it to,
$(".next-button").click(function() {
//var selected = $("#tabs").tabs("option", "selected");
//$("#tabs").tabs("option", "selected", selected + 1);
var valid = true;
var i = 0;
var $inputs = $(this).closest("div#tabs-1").find("input");
//var $inputs = $(this).closest("div.tab-content").find("input");
$inputs.each(function() {
if (!validator.element(this) && valid) {
valid = false;
}
});
if (valid) {
$("#mytabs").tabs("option", "current", 1);
}
});
try this code.
here's a codepen
and Here's the code. It is not working here for some reason but you can see it working in codepen
+function ($) {
'use strict';
// VALIDATOR CLASS DEFINITION
// ==========================
var Validator = function (element, options) {
this.$element = $(element)
this.options = options
options.errors = $.extend({}, Validator.DEFAULTS.errors, options.errors)
for (var custom in options.custom) {
if (!options.errors[custom]) throw new Error('Missing default error message for custom validator: ' + custom)
}
$.extend(Validator.VALIDATORS, options.custom)
this.$element.attr('novalidate', true) // disable automatic native validation
this.toggleSubmit()
this.$element.on('input.bs.validator change.bs.validator focusout.bs.validator', $.proxy(this.validateInput, this))
this.$element.on('submit.bs.validator', $.proxy(this.onSubmit, this))
this.$element.find('[data-match]').each(function () {
var $this = $(this)
var target = $this.data('match')
$(target).on('input.bs.validator', function (e) {
$this.val() && $this.trigger('input.bs.validator')
})
})
}
Validator.INPUT_SELECTOR = ':input:not([type="submit"], button):enabled:visible'
Validator.DEFAULTS = {
delay: 500,
html: false,
disable: true,
custom: {},
errors: {
match: 'Does not match',
minlength: 'Not long enough'
},
feedback: {
success: 'glyphicon-ok',
error: 'glyphicon-remove'
}
}
Validator.VALIDATORS = {
'native': function ($el) {
var el = $el[0]
return el.checkValidity ? el.checkValidity() : true
},
'match': function ($el) {
var target = $el.data('match')
return !$el.val() || $el.val() === $(target).val()
},
'minlength': function ($el) {
var minlength = $el.data('minlength')
return !$el.val() || $el.val().length >= minlength
}
}
Validator.prototype.validateInput = function (e) {
var $el = $(e.target)
var prevErrors = $el.data('bs.validator.errors')
var errors
if ($el.is('[type="radio"]')) $el = this.$element.find('input[name="' + $el.attr('name') + '"]')
this.$element.trigger(e = $.Event('validate.bs.validator', {relatedTarget: $el[0]}))
if (e.isDefaultPrevented()) return
var self = this
this.runValidators($el).done(function (errors) {
$el.data('bs.validator.errors', errors)
errors.length ? self.showErrors($el) : self.clearErrors($el)
if (!prevErrors || errors.toString() !== prevErrors.toString()) {
e = errors.length
? $.Event('invalid.bs.validator', {relatedTarget: $el[0], detail: errors})
: $.Event('valid.bs.validator', {relatedTarget: $el[0], detail: prevErrors})
self.$element.trigger(e)
}
self.toggleSubmit()
self.$element.trigger($.Event('validated.bs.validator', {relatedTarget: $el[0]}))
})
}
Validator.prototype.runValidators = function ($el) {
var errors = []
var deferred = $.Deferred()
var options = this.options
$el.data('bs.validator.deferred') && $el.data('bs.validator.deferred').reject()
$el.data('bs.validator.deferred', deferred)
function getErrorMessage(key) {
return $el.data(key + '-error')
|| $el.data('error')
|| key == 'native' && $el[0].validationMessage
|| options.errors[key]
}
$.each(Validator.VALIDATORS, $.proxy(function (key, validator) {
if (($el.data(key) || key == 'native') && !validator.call(this, $el)) {
var error = getErrorMessage(key)
!~errors.indexOf(error) && errors.push(error)
}
}, this))
if (!errors.length && $el.val() && $el.data('remote')) {
this.defer($el, function () {
var data = {}
data[$el.attr('name')] = $el.val()
$.get($el.data('remote'), data)
.fail(function (jqXHR, textStatus, error) { errors.push(getErrorMessage('remote') || error) })
.always(function () { deferred.resolve(errors)})
})
} else deferred.resolve(errors)
return deferred.promise()
}
Validator.prototype.validate = function () {
var delay = this.options.delay
this.options.delay = 0
this.$element.find(Validator.INPUT_SELECTOR).trigger('input.bs.validator')
this.options.delay = delay
return this
}
Validator.prototype.showErrors = function ($el) {
var method = this.options.html ? 'html' : 'text'
this.defer($el, function () {
var $group = $el.closest('.form-group')
var $block = $group.find('.help-block.with-errors')
var $feedback = $group.find('.form-control-feedback')
var errors = $el.data('bs.validator.errors')
if (!errors.length) return
errors = $('<ul/>')
.addClass('list-unstyled')
.append($.map(errors, function (error) { return $('<li/>')[method](error) }))
$block.data('bs.validator.originalContent') === undefined && $block.data('bs.validator.originalContent', $block.html())
$block.empty().append(errors)
$group.addClass('has-error')
$feedback.length
&& $feedback.removeClass(this.options.feedback.success)
&& $feedback.addClass(this.options.feedback.error)
&& $group.removeClass('has-success')
})
}
Validator.prototype.clearErrors = function ($el) {
var $group = $el.closest('.form-group')
var $block = $group.find('.help-block.with-errors')
var $feedback = $group.find('.form-control-feedback')
$block.html($block.data('bs.validator.originalContent'))
$group.removeClass('has-error')
$feedback.length
&& $feedback.removeClass(this.options.feedback.error)
&& $feedback.addClass(this.options.feedback.success)
&& $group.addClass('has-success')
}
Validator.prototype.hasErrors = function () {
function fieldErrors() {
return !!($(this).data('bs.validator.errors') || []).length
}
return !!this.$element.find(Validator.INPUT_SELECTOR).filter(fieldErrors).length
}
Validator.prototype.isIncomplete = function () {
function fieldIncomplete() {
return this.type === 'checkbox' ? !this.checked :
this.type === 'radio' ? !$('[name="' + this.name + '"]:checked').length :
$.trim(this.value) === ''
}
return !!this.$element.find(Validator.INPUT_SELECTOR).filter('[required]').filter(fieldIncomplete).length
}
Validator.prototype.onSubmit = function (e) {
this.validate()
if (this.isIncomplete() || this.hasErrors()) e.preventDefault()
}
Validator.prototype.toggleSubmit = function () {
if(!this.options.disable) return
var $btn = $('button[type="submit"], input[type="submit"]')
.filter('[form="' + this.$element.attr('id') + '"]')
.add(this.$element.find('input[type="submit"], button[type="submit"]'))
$btn.toggleClass('disabled', this.isIncomplete() || this.hasErrors())
}
Validator.prototype.defer = function ($el, callback) {
callback = $.proxy(callback, this)
if (!this.options.delay) return callback()
window.clearTimeout($el.data('bs.validator.timeout'))
$el.data('bs.validator.timeout', window.setTimeout(callback, this.options.delay))
}
Validator.prototype.destroy = function () {
this.$element
.removeAttr('novalidate')
.removeData('bs.validator')
.off('.bs.validator')
this.$element.find(Validator.INPUT_SELECTOR)
.off('.bs.validator')
.removeData(['bs.validator.errors', 'bs.validator.deferred'])
.each(function () {
var $this = $(this)
var timeout = $this.data('bs.validator.timeout')
window.clearTimeout(timeout) && $this.removeData('bs.validator.timeout')
})
this.$element.find('.help-block.with-errors').each(function () {
var $this = $(this)
var originalContent = $this.data('bs.validator.originalContent')
$this
.removeData('bs.validator.originalContent')
.html(originalContent)
})
this.$element.find('input[type="submit"], button[type="submit"]').removeClass('disabled')
this.$element.find('.has-error').removeClass('has-error')
return this
}
// VALIDATOR PLUGIN DEFINITION
// ===========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var options = $.extend({}, Validator.DEFAULTS, $this.data(), typeof option == 'object' && option)
var data = $this.data('bs.validator')
if (!data && option == 'destroy') return
if (!data) $this.data('bs.validator', (data = new Validator(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.validator
$.fn.validator = Plugin
$.fn.validator.Constructor = Validator
// VALIDATOR NO CONFLICT
// =====================
$.fn.validator.noConflict = function () {
$.fn.validator = old
return this
}
// VALIDATOR DATA-API
// ==================
$(window).on('load', function () {
$('form[data-toggle="validator"]').each(function () {
var $form = $(this)
Plugin.call($form, $form.data())
})
})
}(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="contact-form">
<form data-toggle="validator" action="contact_script" method="post" role="form">
<div class="form-group">
<input name="name" type="text" class="form-control input-lg" placeholder="Your Name" required>
</div>
<div class="form-group">
<input name="email" type="email" class="form-control input-lg" placeholder="E-mail" required>
</div>
<div class="form-group">
<input name="phone" type="text" class="form-control input-lg" placeholder="Contact No." required>
</div>
<div class="form-group">
<input name="subject" type="text" class="form-control input-lg" placeholder="Subject" required>
</div>
<div class="form-group">
<textarea name="message" class="form-control input-lg" rows="5" placeholder="Message"></textarea>
</div>
<button type="submit" class="btn wow bounceInRight" data-wow-delay="0.8s">Send</button>
</form>
</div>
I am using a plugin for live search .. everything is working fine .. i just want to add a loading png that appear on start of ajax request and disappear on results ..
please help me to customize the code just to add class where form id="search-kb-form" .. and remove the class when results are completed.
<form id="search-kb-form" class="search-kb-form" method="get" action="<?php echo home_url('/'); ?>" autocomplete="off">
<div class="wrapper-kb-fields">
<input type="text" id="s" name="s" placeholder="Search what you’re looking for" title="* Please enter a search term!">
<input type="submit" class="submit-button-kb" value="">
</div>
<div id="search-error-container"></div>
</form>
This is the plugin code
jQuery.fn.liveSearch = function (conf) {
var config = jQuery.extend({
url: {'jquery-live-search-result': 'search-results.php?q='},
id: 'jquery-live-search',
duration: 400,
typeDelay: 200,
loadingClass: 'loading',
onSlideUp: function () {},
uptadePosition: false,
minLength: 0,
width: null
}, conf);
if (typeof(config.url) == "string") {
config.url = { 'jquery-live-search-result': config.url }
} else if (typeof(config.url) == "object") {
if (typeof(config.url.length) == "number") {
var urls = {}
for (var i = 0; i < config.url.length; i++) {
urls['jquery-live-search-result-' + i] = config.url[i];
}
config.url = urls;
}
}
var searchStatus = {};
var liveSearch = jQuery('#' + config.id);
var loadingRequestCounter = 0;
// Create live-search if it doesn't exist
if (!liveSearch.length) {
liveSearch = jQuery('<div id="' + config.id + '"></div>')
.appendTo(document.body)
.hide()
.slideUp(0);
for (key in config.url) {
liveSearch.append('<div id="' + key + '"></div>');
searchStatus[key] = false;
}
// Close live-search when clicking outside it
jQuery(document.body).click(function(event) {
var clicked = jQuery(event.target);
if (!(clicked.is('#' + config.id) || clicked.parents('#' + config.id).length || clicked.is('input'))) {
liveSearch.slideUp(config.duration, function () {
config.onSlideUp();
});
}
});
}
return this.each(function () {
var input = jQuery(this).attr('autocomplete', 'off');
var liveSearchPaddingBorderHoriz = parseInt(liveSearch.css('paddingLeft'), 10) + parseInt(liveSearch.css('paddingRight'), 10) + parseInt(liveSearch.css('borderLeftWidth'), 10) + parseInt(liveSearch.css('borderRightWidth'), 10);
// Re calculates live search's position
var repositionLiveSearch = function () {
var tmpOffset = input.offset();
var tmpWidth = input.outerWidth();
if (config.width != null) {
tmpWidth = config.width;
}
var inputDim = {
left: tmpOffset.left,
top: tmpOffset.top,
width: tmpWidth,
height: input.outerHeight()
};
inputDim.topPos = inputDim.top + inputDim.height;
inputDim.totalWidth = inputDim.width - liveSearchPaddingBorderHoriz;
liveSearch.css({
position: 'absolute',
left: inputDim.left + 'px',
top: inputDim.topPos + 'px',
width: inputDim.totalWidth + 'px'
});
};
var showOrHideLiveSearch = function () {
if (loadingRequestCounter == 0) {
showStatus = false;
for (key in config.url) {
if( searchStatus[key] == true ) {
showStatus = true;
break;
}
}
if (showStatus == true) {
for (key in config.url) {
if( searchStatus[key] == false ) {
liveSearch.find('#' + key).html('');
}
}
showLiveSearch();
} else {
hideLiveSearch();
}
}
};
// Shows live-search for this input
var showLiveSearch = function () {
// Always reposition the live-search every time it is shown
// in case user has resized browser-window or zoomed in or whatever
repositionLiveSearch();
// We need to bind a resize-event every time live search is shown
// so it resizes based on the correct input element
jQuery(window).unbind('resize', repositionLiveSearch);
jQuery(window).bind('resize', repositionLiveSearch);
liveSearch.slideDown(config.duration)
};
// Hides live-search for this input
var hideLiveSearch = function () {
liveSearch.slideUp(config.duration, function () {
config.onSlideUp();
for (key in config.url) {
liveSearch.find('#' + key).html('');
}
});
};
input
// On focus, if the live-search is empty, perform an new search
// If not, just slide it down. Only do this if there's something in the input
.focus(function () {
if (this.value.length > config.minLength ) {
showOrHideLiveSearch();
}
})
// Auto update live-search onkeyup
.keyup(function () {
// Don't update live-search if it's got the same value as last time
if (this.value != this.lastValue) {
input.addClass(config.loadingClass);
var q = this.value;
// Stop previous ajax-request
if (this.timer) {
clearTimeout(this.timer);
}
if( q.length > config.minLength ) {
// Start a new ajax-request in X ms
this.timer = setTimeout(function () {
for (url_key in config.url) {
loadingRequestCounter += 1;
jQuery.ajax({
key: url_key,
url: config.url[url_key] + q,
success: function(data){
if (data.length) {
searchStatus[this.key] = true;
liveSearch.find("#" + this.key).html(data);
} else {
searchStatus[this.key] = false;
}
loadingRequestCounter -= 1;
showOrHideLiveSearch();
}
});
}
}, config.typeDelay);
}
else {
for (url_key in config.url) {
searchStatus[url_key] = false;
}
hideLiveSearch();
}
this.lastValue = this.value;
}
});
});
};
add a background to the loading class
.loading {
background:url('http://path_to_your_picture');
}
I'm trying to implement drag and drop angular directive to my application that to render d3 collapsible tree. Now I'm using basic Input method that user can load file from local machine. And with "Input" everything works and renders fine, but I've got requirements that I have to implement drop zone, so I found in internet this example, cause the example has been provided for images, I've a little modified it for json files:
<div id="left-input" class="dropzone" file-dropzone="[application/json]" file="json" file-name="applicationFileName" data-max-file-size="3">
<span>Drop Image Here</span></div>
<span class="dropzone">{{applicationFileName}}</span>
and set it up for d3 library but how I can see thru console.log my variable is underfined, so if I'm checking variable in directive:
reader = new FileReader();
reader.onload = function(evt) {
scope.file = evt.target.result;
console.log(scope.file);
if (checkSize(size) && isTypeValid(type)) {
return scope.$apply(function() {
scope.file = evt.target.result;
if (angular.isString(scope.fileName)) {
return scope.fileName = name;
}
});
}
};
so console.log(scope.file) return me exactly my variable
but when I'm using this variable in controller inside of d3 function:
$scope.load_left = function () {
// Get JSON data
console.log('['+ $scope.file +']');
root = $scope.file;
treeData = JSON.parse(root);
//d3.json($scope.result, function (error, treeData) {
it returns me undefined
so where did I mistake?
this my dnd directive:
app.directive('fileDropzone', function() {
return {
restrict: '',
scope: {
file: '=',
fileName: '='
},
link: function(scope, element, attrs) {
var checkSize, isTypeValid, processDragOverOrEnter, validMimeTypes;
processDragOverOrEnter = function(event) {
if (event != null) {
event.preventDefault();
}
event.dataTransfer.effectAllowed = 'copy';
return false;
};
validMimeTypes = attrs.fileDropzone;
checkSize = function(size) {
var _ref;
if (((_ref = attrs.maxFileSize) === (void 0) || _ref === '') || (size / 1024) / 1024 < attrs.maxFileSize) {
return true;
} else {
alert("File must be smaller than " + attrs.maxFileSize + " MB");
return false;
}
};
isTypeValid = function(type) {
if ((validMimeTypes === (void 0) || validMimeTypes === '') || validMimeTypes.indexOf(type) > -1) {
return true;
} else {
alert("Invalid file type. File must be one of following types " + validMimeTypes);
return false;
}
};
element.bind('dragover', processDragOverOrEnter);
element.bind('dragenter', processDragOverOrEnter);
return element.bind('drop', function(event) {
var file, name, reader, size, type;
if (event != null) {
event.preventDefault();
}
reader = new FileReader();
reader.onload = function(evt) {
scope.file = evt.target.result;
console.log(scope.file);
if (checkSize(size) && isTypeValid(type)) {
return scope.$apply(function() {
scope.file = evt.target.result;
if (angular.isString(scope.fileName)) {
return scope.fileName = name;
}
});
}
};
console.log('['+ scope.file +']');
file = event.dataTransfer.files[0];
//console.log('['+ file +']');
name = file.name;
type = file.type;
size = file.size;
reader.readAsText(file);
//reader.readAsDataURL(file);
return false;
});
}
};
});
and thru this function I'm rendering my d3 tree
$scope.load_left = function () {
// Get JSON data
console.log('['+ $scope.file +']');
root = $scope.file;
treeData = JSON.parse(root);
//d3.json($scope.result, function (error, treeData) {
Also I'm providing code with my old Input method
<div style="display: flex">
<input type="file" id="left-input"/>
<button class="btn btn-info" ng-click="load_left()">Load It</button>
</div>
$scope.leftWindow = function (e) {
var file = e.target.files[0];
if (!file) {
return;
}
var reader = new FileReader();
reader.onload = function (e) {
var leftcontent = e.target.result;
displayLeftContents(leftcontent);
};
reader.readAsText(file);
};
function displayLeftContents(leftcontent) {
$scope.leftContent = JSON.parse(leftcontent);
$scope.$apply();
}
document.getElementById('left-input')
.addEventListener('change', $scope.leftWindow, false);
$scope.load_left = function () {
// Get JSON data
root = JSON.stringify($scope.leftContent);
//console.log('['+ root +']');
treeData = JSON.parse(root);
//console.log(treeData);
//d3.json($scope.result, function (error, treeData) {
Just want to post how I've resolved this problem, may be somebody will need it.
so I'have added on more directive for reading files and then set up the variable to d3 function inside controller, so the full code looks like:
app.directive('fileDropzone', function() {
return {
restrict: '',
scope: {
file: '=',
fileName: '='
},
link: function(scope, element, attrs) {
var checkSize, isTypeValid, processDragOverOrEnter, validMimeTypes;
processDragOverOrEnter = function(event) {
if (event != null) {
event.preventDefault();
}
event.dataTransfer.effectAllowed = 'copy';
return false;
};
validMimeTypes = attrs.fileDropzone;
checkSize = function(size) {
var _ref;
if (((_ref = attrs.maxFileSize) === (void 0) || _ref === '') || (size / 1024) / 1024 < attrs.maxFileSize) {
return true;
} else {
alert("File must be smaller than " + attrs.maxFileSize + " MB");
return false;
}
};
isTypeValid = function(type) {
if ((validMimeTypes === (void 0) || validMimeTypes === '') || validMimeTypes.indexOf(type) > -1) {
return true;
} else {
alert("Invalid file type. File must be one of following types " + validMimeTypes);
return false;
}
};
element.bind('dragover', processDragOverOrEnter);
element.bind('dragenter', processDragOverOrEnter);
//console.log(element.bind('dragenter', processDragOverOrEnter));
return element.bind('drop', function(event) {
var file, name, reader, size, type;
if (event != null) {
event.preventDefault();
}
reader = new FileReader();
reader.onload = function(evt) {
scope.$apply(function() {
$LeftfileDrop = evt.target.result;
$RightfileDrop = evt.target.result;
});
if (checkSize(size) && isTypeValid(type)) {
return scope.$apply(function() {
scope.file = evt.target.result;
if (angular.isString(scope.fileName)) {
return scope.fileName = name;
}
});
}
};
file = event.dataTransfer.files[0];
console.log(file);
name = file.name;
type = file.type;
size = file.size;
reader.readAsText(file);
return false;
});
}
};
});
app.directive('onReadFile', function ($parse) {
return {
restrict: 'A',
scope: false,
link: function(scope, element, attrs) {
var fn = $parse(attrs.onReadFile);
element.on('change', function(onChangeEvent) {
var reader = new FileReader();
reader.onload = function(onLoadEvent) {
scope.$apply(function() {
fn(scope, {$fileContent:onLoadEvent.target.result});
});
};
reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0]);
});
}
};
});
and d3 function:
// Get JSON data
root = $LeftfileDrop;
treeData = JSON.parse(root);
//d3.json($scope.result, function (error, treeData) {
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://stackoverflow.com"url: "http://stackoverflow.com"url_description: "Q&A for professional and enthusiast programmers"url_image: "http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon#2.png?v=ea71a5211a91&a"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.
I suspect $e.url_title() is causing the error, as far as I know, url_title() isn't a method you can call on jQuery instances.
Presumably you meant to access a variable instead.
I couldn’t find an issue in your scripts, other than the undefined function call, so I basically rewrote the whole thing myself, which seems to work: http://jsbin.com/nexujuhefo/2/edit?js,console,output
I think the problem is Taggd weird logic ;)
Fields now remember data: http://jsbin.com/hosipiyuqa/1/edit?js,console,output
Hi i have this little plugin installed:
(function($) {
$.fn.tagfield = function(options) {
if (options && options.add) {
this.each(function(i, elem) {
add_tags(elem, options.add);
});
} if (options && options.remove) {
this.each(function(i, elem) {
remove_tags(elem, options.add);
});
} else {
this.each(function(i, elem) {
var initial_tags = $(elem).val();
$(elem).val('');
tagfield(this, $(elem));
$(initial_tags.split(',')).each(function(i, v) {
v = $.trim(v);
if (v !== '') add_tags(elem, v);
})
});
}
};
var KEYS = {
"enter": "\r".charCodeAt(0),
"space": " ".charCodeAt(0),
"comma": 188,
"backspace": 8
};
var tagfield_id_for = function(real_input) {
return $(real_input).attr('id') + '_tagfield';
};
var add_tags = function(real_input, text) {
remove_tags(real_input, text);
var tag = $('<span class="tag">').append('<span class="text">' + text +'</span>'),
close = $('<a class="close" href="#">X</a>');
close.click(function(e) {
remove_tags(real_input, text);
});
tag.append(close);
$('#' + tagfield_id_for(real_input) + " .tags").append(tag);
real_input = $(real_input);
real_input.val(($.trim(real_input.val()) === '' ? [] : real_input.val().split(',')).concat([text]).join(','));
};
var remove_tags = function(real_input, text) {
$('#' + tagfield_id_for(real_input) + " .tags .tag").each(function(i, v) {
v = $(v);
if (v.find('.text').html() === text) {
v.remove();
real_input = $(real_input);
var tags = $(real_input.val().split(',')).filter(function(i, v) {
return v !== text;
});
real_input.val(Array.prototype.join.call(tags));
}
});
};
var tagfield = function(real_input, elem) {
var tagfield = $('<div class="tagfield">').attr('id', tagfield_id_for(real_input)),
input = $('<input type="text"/>'),
buffer = $('<span class="buffer">'),
tags = $('<span class="tags">');
tagfield.append(tags);
tagfield.append(buffer);
tagfield.append(input);
tagfield.click(function(e) {
input.focus();
});
var check_add_tag = function() {
if (buffer.html()) {
var tag_text = buffer.html();
buffer.html('');
add_tags(real_input, tag_text);
}
};
var add_tag = function(text) {
};
input.keydown(function(e) {
if (e.which === KEYS.enter || e.which === KEYS.space || e.which === KEYS.comma) {
e.preventDefault();
check_add_tag();
}
if (e.which === KEYS.backspace) {
if (buffer.html() === "") {
remove_tags(real_input, tagfield.find('.tag').last().find('.text').html());
} else {
var s = buffer.html();
buffer.html(s.slice(0, s.length-1));
}
}
});
input.blur(check_add_tag);
input.keyup(function(e) {
buffer.append(input.val());
input.val('');
});
$(real_input).hide().after(tagfield);
};
})(jQuery);
does anyone can show me how can i call the methods add_tags() and remove_tags() ?
thanks
$("selector").tagfield({remove:someobject});
$("selector").tagfield({add:someobject});
but the "remove" thing will not work i think, since the second "if" in fn.tagfield watches for "options.remove" but removes the "options.add" ...