My jQuery callback is failing - javascript

I created a plug-in to display a Metro MessageBar and it works great. I was asked to support callbacks and added some code to the fadeIn functionality for this purpose.
For some reason, the callback shows as a valid function, but doesn't call?
HERE IS THE CONSOLE MESSAGE I AM GETTING:
this.trigger is not a function
...any help is appreciated.
THIS IS HOW TO USE THE PLUG-IN:
this.showSubmitMessage = function () {
var options = {
message: "This is a test.",
messageType: "information"
};
// self.btnSubmit.click IS a valid function!!! Use your own if you want.
nalco.es.rk.globals.messageBarManager.display(options, self.btnSubmit.click);
};
THIS IS THE OFFENDING AREA-OF-CODE IN THE PLUG-IN:
this.fadeIn = function (element, callback) {
element.prependTo(self.container).centerToScrollTop().fadeIn(self.globals.fadeDuration, function() {
if (callback != null)
if ($.isFunction(callback))
setTimeout(function () {
callback();
}, self.globals.callbackDuration);
});
};
THIS IS THE ENTIRE USER-CONTROL PLUG-IN:
Please notice the code for the file-dependency "jquery.Extensions.js" is at the bottom of this posting.
<script src="Scripts/jQuery/Core/jquery-1.6.2.min.js" type="text/javascript"></script>
<script src="Scripts/jQuery/Core/jquery.tmpl.js" type="text/javascript"></script>
<script src="Scripts/jQuery/jquery.Extensions.js" type="text/javascript"></script>
<style type="text/css">
.messageBar { background-color: #DDDDDD; color: #666666; display: none; left: 0; padding: 15px; position: absolute; top: 0; width: 932px; z-index: 1000; }
.messageBar .content { width: 100%; }
.messageBar .content td.image { width: 70px; }
.messageBar .content td.button { width: 60px; }
.messageBar .button { margin-top: 0px; }
.messageBar .content .icon { background-repeat: no-repeat; height: 31px; overflow: hidden; width: 31px; }
.messageBar .content .message { }
.messageBar .content .image { background-repeat: no-repeat; height: 10px; overflow: hidden; width: 70px; }
.messageBar.error { background-color: #FFBABA; color: #D8000C; }
.messageBar.information { background-color: #99CCFF; color: #00529B; }
.messageBar.success { background-color: #DFF2BF; color: #4F8A10; }
.messageBar.warning { background-color: #FEEFB3; color: #9F6000; }
.messageBar.error .content .icon { background-image: url('/_layouts/images/error.png'); }
.messageBar.information .content .icon { background-image: url('/_layouts/images/info.png'); }
.messageBar.success .content .icon { background-image: url('/_layouts/images/success.png'); }
.messageBar.warning .content .icon { background-image: url('/_layouts/images/warning.png'); }
</style>
<script id="template-messageBar" type="text/html">
<div class="messageBar">
<table class="content">
<tbody>
<tr>
<td>
</td>
<td>
</td>
<td>
</td>
<td class="button">
<input type="button" value="Close" class="button metroButton" />
</td>
</tr>
</tbody>
</table>
</div>
</script>
<script id="template-messageBar-icon" type="text/html">
<div class="icon">
</div>
</script>
<script id="template-messageBar-message" type="text/html">
<div class="message">
${Message}
</div>
</script>
<script id="template-messageBar-image" type="text/html">
<div class="image">
</div>
</script>
<script type="text/javascript">
;nalco.es.rk.source.MessageBarManager = (function ($) {
var publicInstances = {};
publicInstances.Controller = Controller;
function Controller(options) {
var self = this;
this.messageTypes = { error: "error", information: "information", normal: null, success: "success", warning: "warning" };
this.globals = {
callbackDuration: 2000,
fadeDuration: 700,
workingImageUrl: "url('/_layouts/images/Nalco.ES.SharePoint.UI/metro-ajax-loader-blue.gif')"
};
this.defaults = {
message: "",
messageType: self.messageTypes.normal,
showIcon: false,
showWorkingImage: false
};
this.container = $('body');
this.templateMessageBarId = '#template-messageBar';
this.templateMessageBarIconId = '#template-messageBar-icon';
this.templateMessageBarMessageId = '#template-messageBar-message';
this.templateMessageBarImageId = '#template-messageBar-image';
this.selectors = { content: '.content', closeButton: '.button', root: '.messageBar' };
this.initialize = function () {
self.display(options);
};
this.display = function (options, callback) {
var empty = {};
var settings = $.extend(empty, self.defaults, $.isPlainObject(options) ? options : empty);
if (settings.messageType != null)
if (settings.messageType.length == 0)
settings.messageType = self.messageTypes.normal;
if (settings.message.length == 0)
return;
var eleMessageBar = $(self.templateMessageBarId).tmpl(empty);
var eleContent = $(self.selectors.content, eleMessageBar);
var eleCellOne = $('td:eq(0)', eleContent);
var eleCellTwo = $('td:eq(1)', eleContent);
var eleCellThree = $('td:eq(2)', eleContent);
var eleMessage = $(self.templateMessageBarMessageId).tmpl({ Message: settings.message });
var btnClose = $(self.selectors.closeButton, eleMessageBar);
if (settings.messageType != self.messageTypes.normal) {
eleMessageBar.addClass(settings.messageType);
if (settings.showIcon) {
var eleIcon = $(self.templateMessageBarIconId).tmpl(empty);
eleCellOne.css('width', '31px');
eleIcon.appendTo(eleCellOne);
}
}
eleMessage.appendTo(eleCellTwo);
btnClose.click(function () {
eleMessageBar.fadeOut(self.globals.fadeDuration, function () {
eleMessageBar.remove();
});
});
if (settings.showWorkingImage) {
var eleImage = $(self.templateMessageBarImageId).tmpl(empty);
eleCellThree.addClass('image');
eleImage.css('background-image', self.globals.workingImageUrl);
eleImage.appendTo(eleCellThree);
}
var elePreviousMessage = $(self.selectors.root, self.container);
if (elePreviousMessage.length > 0) {
btnClose = $(self.selectors.closeButton, elePreviousMessage);
btnClose.click();
setTimeout(function () { self.fadeIn(eleMessageBar, callback); }, self.globals.fadeDuration);
}
else
self.fadeIn(eleMessageBar, callback);
};
this.fadeIn = function (element, callback) {
element.prependTo(self.container).centerToScrollTop().fadeIn(self.globals.fadeDuration, function() {
if (callback != null)
if ($.isFunction(callback))
setTimeout(function () {
callback();
}, self.globals.callbackDuration);
});
};
self.initialize();
};
return publicInstances;
})(jQuery);
function initializeMessageBarManager() {
nalco.es.rk.globals.messageBarManager = new nalco.es.rk.source.MessageBarManager.Controller();
}
$(document).ready(function () {
initializeMessageBarManager();
if (typeof (Sys) != "undefined")
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(initializeMessageBarManager);
});
</script>
THIS IS THE EXTENSIONS DEPENDENCY LISTED IN THE FILES ABOVE:
// **********************
// .centerToScrollTop
// Use -
// Centers an ELEMENT to the window's scrollTop.
//
// Example -
// $('.myElement').centerToScrollTop();
// **********************
(function ($) {
$.fn.extend({
centerToScrollTop: function (options) {
return this.each(function () {
var element = $(this);
var container = $(window);
var scrollTop = container.scrollTop();
var buffer = 30;
var top = scrollTop + buffer;
var left = (container.width() - element.outerWidth()) / 2 + container.scrollLeft();
element.css({ 'position': 'absolute', 'top': top, 'left': left });
return element;
});
}
});
})(jQuery);

This type of error occurs usually if you forgot to include some files like jquery-ui.min.js etc. Check carefully if you add all the necessary references.

Related

Getting blob image back to file

I am having problem converting image to blob and back to file, I mean when I convert image to blob and display on the page, chose which I want to keep and which I want to remove and after try to convert back to file and append to form data, nothing gets appended to formData and file type and size on new files from blob images are different, how can I change that? Thank you
$(document).on('click', '#addProduct', function(e) {
e.preventDefault();
var arr = [];
for(var q=0; q<$('.image-buttons').length; q++) {
var blob = $('.image-buttons').children('img').attr('src');
var fileOfBlob = new File([blob], 'image'+q);
arr.push(fileOfBlob);
}
if(arr.length < 4 && arr.length > 0){
var formData = new FormData();
$.each(arr, function(i, file) {
formData.append('images', file);
console.log(file);
});
console.log(formData);
return false;
}
});
$(document).on('change', '#images', function() {
var reg = /\.(gif|jpg|png|GIF|JPG|PNG|jpeg|JPEG)$/i;
var imageNameArray = [];
for(var j = 0; j<$("#images")[0].files.length; j++) {
if(!$("#images")[0].files[j].name.match(reg)){
imageNameArray.push($("#images")[0].files[j].name);
}
}
if(imageNameArray.length === 0 && $("#images")[0].size<2097152){
for(var e=0; e<$("#images")[0].files.length; e++) {
$('.img-button-holder').append('<div class="image-buttons"><img src="'+window.URL.createObjectURL($("#images")[0].files[e])+'"><div class="img-tools"><i class="fa fa-angle-double-left" aria-hidden="true"></i><i class="fa fa-angle-double-right" aria-hidden="true"></i><i class="fa fa-times removeImg" aria-hidden="true"></i></div></div>');
}
$('.image-display').append('<img src="'+window.URL.createObjectURL($("#images")[0].files[0])+'">');
}
});
$(document).on('click', '.image-buttons', function() {
var this_img = $(this).children('img').attr('src');
$('.image-buttons').css('border','1px solid #e0e0e0');
$(this).css('border','2px solid red');
$('.image-display').children('img').attr('src', this_img);
});
$(document).on('click', '.img-tools > .fa', function() {
var this_el = $(this).parent().parent();
if($(this).hasClass('removeImg')){
$(this_el).remove();
}else if($(this).hasClass('fa-angle-double-left')) {
var prev = $(this_el).prev();
$(this_el).insertBefore(prev);
}else if($(this).hasClass('fa-angle-double-right')) {
var next = $(this_el).next();
$(this_el).insertAfter(next);
}
});
.addNew {
width: 100%;
height: auto;
float: left;
}
.addNew > form {
width: 40%;
float: left;
height: auto;
margin-right: 5%;
}
.addNew > .image-display {
width: 55%;
float: right;
min-height: 300px;
height: auto;
border: 1px solid #e0e0e0;
position: relative;
}
.addNew .image-buttons {
width: 30%;
height: 80px;
margin: 10px 1.5%;
border: 1px solid #e0e0e0;
float: left;
overflow: hidden;
position: relative;
}
.img-button-holder {
width: 55%;
float: right;
}
.image-buttons > img, .image-display > img {
width: 100%;
height: 100%;
min-height: 100%;
min-width: 100%;
}
.image-display > img {
width: 100%;
height: auto;
min-height: auto;
min-width: 100%;
position: absolute;
bottom: 0; left: 0;
}
.img-tools {
color: red;
font-size: 2rem;
position: absolute;
width: 100%;
height: auto;
top: 0; left: 0;
}
.img-tools > i {
float: left;
width: 30%;
margin: 5px 1.5%;
cursor: pointer;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="addNew">
<form>
<input type="file" name="images" id="images" multiple>
<button id="addProduct">Add</button>
</form>
<div class="image-display"></div>
<div class="img-button-holder"></div>
</div>
A blobURI (that you miscalled blob in your code) is just a string.
The File object you create is just that string in a text/plain file.
You don't have to convert from a File to a blobURI to a File.
Just keep the initial Files, store them in a good ol' Array, manage them from there.
Create the blobURI only to display these Files (it's really just a pointer in the memory so your document (here <img>) knows how to access the file on the user disk, and hence can't be shared).
When you need to send the files, simoly take them from the Array you did the management with.
ps: Note that depending on your back-end, you might have to append a [] at the name of your formData key.
function sendToServer() {
var formData = new FormData(),
files = fileHandler.list; // grab them directly from our manager
// it's an Array, so use Array methods
files.forEach(function(file) {
// since you are on php, to be able to append multiple items in the same field,
// you need to append '[]' at the end of your fieldName
formData.append('images[]', file);
});
// send it to your server
var xhr = new XMLHttpRequest();
xhr.open('POST', 'your_php_script');
// xhr.send(formData);
// but from SO we will just show what's inside
if (typeof formData.getAll === 'function') {
console.log(formData.getAll('images[]'));
}
}
// A basic file manager which will expose its selected files in an Array
function FileHandler(options) {
if (!options || typeof options !== 'object')
options = {};
this.options = options;
// this is really the only important part: we use an Array to store all our files
this.list = [];
this.addButton = isValidElement(options.addButton) || $('<button>', {
text: 'Add new Files'
});
// also, we use a single file input
this.input = $('<input>', $.extend(options.input || {}, {
type: 'file',
class: 'fh-input',
multiple: true,
}));
this.items_container = isValidElement(options.items_container) || $('<div>', {
class: 'fh-item-container'
});
this.preview = this.initPreview();
this.addButton.on('click', function() {
this.input.click()
}.bind(this));
this.input.on('change', this.onchange.bind(this));
this.items_container.on('click', '.fh-item .fh-remove', this.remove.bind(this));
this.items_container.on('click', '.fh-item :not(.fh-remove)', this.handleItemClick.bind(this));
this.items_container.on('load', 'img', revokeURL);
// We don't need blobURIs for anything else than loading <img> elements,
// so we can revoke them directly at load
function revokeURL(evt) {
var url = evt.currentTarget.src;
URL.revokeObjectURL(url);
}
function isValidElement(obj) {
var $obj = $(obj);
return $obj[0] && $obj[0] instanceof Element && $obj.eq(0);
}
}
FileHandler.prototype = Object.create({
add: function addFile(file) {
if (!(file instanceof Blob))
throw new TypeError('Argument 1 must be Blob or a File');
var $item = this.generateItem(file);
this.items_container.append($item);
// store it in our Array
this.list.push(file);
this.preview.show(file);
return $item;
},
remove: function removeFile(event) {
var $target = $(event.currentTarget),
$item = $target.parents('.fh-item').eq(0),
file = $item.data('fh.file'),
index = this.list.indexOf(file);
$item.remove();
if (index > -1) {
// remove it from our Array
this.list.splice(index, 1);
}
if (this.preview.current === file) {
if (this.list.length) {
var next = index <= (this.list.length - 1) ? index : 0;
this.preview.show(this.list[next]);
} else this.preview.hide();
}
},
generateItem: function generateItem(file) {
if (!(file instanceof Blob))
throw new TypeError('Argument 1 must be Blob or a File');
var $cont = $('<div>', {
class: 'fh-item'
}),
$title = $('<span>', {
text: file.name || 'unknown-file (' + file.type + ')',
class: 'fh-file_name'
}),
$btn = $('<button>', {
class: 'fh-remove',
text: 'x',
title: 'remove',
name: 'remove item'
}),
$thumb = $('<div>', {
class: 'fh-thumb'
})
// a single time blobURI
.append($('<img>', {
src: URL.createObjectURL(file)
}));
$cont.data('fh.file', file);
return $cont.append(
$title,
$btn,
$thumb
);
},
onchange: function oninputchange(evt) {
// retrieve the Files contained in our single input
var fileList = this.input[0].files;
for (var i = 0; i < fileList.length; i++) {
this.add(fileList[i]);
}
},
handleItemClick: function handleItemClick(evt) {
var $target = $(evt.currentTarget),
$item = $target.parents('.fh-item').eq(0),
file = $item.data('fh.file');
this.preview.show(file);
},
initPreview: function() {
var $cont = $('<div>', {
class: 'fh-preview'
}),
img = new Image();
return {
container: $cont.append(img),
update: function updatePreview(url) {},
show: function show(file) {
if (!(file instanceof Blob)) {
console.warn('Not a Blob', file);
throw new TypeError('Argument 1 must be Blob or a File');
}
if (this.current !== file) {
this.current = file;
img.src = URL.createObjectURL(file);
}
$cont.show();
},
hide: function hide() {
img.src = '#';
$cont.hide();
}
};
}
});
var fileHandler = new FileHandler({
input: {
accept: 'image/*'
}
});
$('body').append(
fileHandler.addButton,
$('<button>', {
text: 'send to server'
})
.on('click', sendToServer),
fileHandler.items_container,
fileHandler.preview.container,
);
.fh-item {
border: 1px solid;
display: inline-block;
min-width: 130px;
min-height: 130px;
vertical-align: middle;
}
.fh-file_name {
display: inline-block;
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
margin: 2px 4px;
vertical-align: top;
}
.fh-remove {
box-shadow: none;
border: none;
float: right;
cursor: pointer;
}
.fh-remove:hover {
color: #CC0000;
}
.fh-thumb {
text-align: center;
width: 100%;
height: 100px;
}
.fh-thumb>img {
max-width: 100px;
max-height: 100px;
margin: 0 auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

My Javascript code doesn't run inside my MVC view

I'm having some issues implementing this template into my MVC application.
https://bootsnipp.com/snippets/featured/pinterest-like-responsive-grid
My CSS and code works fine, but the Javascript doesn't work.
I'm using a partial view to contain the code which looks like this:
#model List<Assignment_3.Models.Word>
<script type="text/javascript" src='#Url.Content("~/Scripts/ResponsiveGrid.js")'></script>
<div class="container">
<div class="row">
<div>
<section id="pinBoot">
#foreach (var word in Model)
{
<ItemTemplate>
<article class="white-panel">
<a href="#Url.Action("Detail", new { id = Word.WordId })">
<img src="#Url.Content(Idiom.Imagepath)" />
</a>
<h4 class="textwrapper">Test</h4>
<p>Language</p>
</article>
</ItemTemplate>
}
</section>
</div>
</div>
</div>
<style>
body {
background-color: #eee;
}
.textwrapper {
word-break: break-all;
}
#pinBoot {
position: relative;
max-width: 100%;
width: 100%;
}
img {
max-width: 100%;
height: auto;
}
.white-panel {
position: absolute;
background: white;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
padding: 10px;
}
.white-panel h1 {
font-size: 1em;
}
.white-panel h1 a {
color: #A92733;
}
.white-panel:hover {
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.5);
margin-top: -5px;
-webkit-transition: all 0.3s ease-in-out;
-moz-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
}
</style>
Here is the Javascript file:
$(document).ready(function () {
$('#pinBoot').pinterest_grid({
no_columns: 4,
padding_x: 10,
padding_y: 10,
margin_bottom: 50,
single_column_breakpoint: 700
});
});
usage:
$(document).ready(function () {
$('#blog-landing').pinterest_grid({
no_columns: 4
});
});
; (function ($, window, document, undefined) {
var pluginName = 'pinterest_grid',
defaults = {
padding_x: 10,
padding_y: 10,
no_columns: 3,
margin_bottom: 50,
single_column_breakpoint: 700
},
columns,
$article,
article_width;
function Plugin(element, options) {
this.element = element;
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype.init = function () {
var self = this,
resize_finish;
$(window).resize(function () {
clearTimeout(resize_finish);
resize_finish = setTimeout(function () {
self.make_layout_change(self);
}, 11);
});
self.make_layout_change(self);
setTimeout(function () {
$(window).resize();
}, 500);
};
Plugin.prototype.calculate = function (single_column_mode) {
var self = this,
tallest = 0,
row = 0,
$container = $(this.element),
container_width = $container.width();
$article = $(this.element).children();
if (single_column_mode === true) {
article_width = $container.width() - self.options.padding_x;
} else {
article_width = ($container.width() - self.options.padding_x *
self.options.no_columns) / self.options.no_columns;
}
$article.each(function () {
$(this).css('width', article_width);
});
columns = self.options.no_columns;
$article.each(function (index) {
var current_column,
left_out = 0,
top = 0,
$this = $(this),
prevAll = $this.prevAll(),
tallest = 0;
if (single_column_mode === false) {
current_column = (index % columns);
} else {
current_column = 0;
}
for (var t = 0; t < columns; t++) {
$this.removeClass('c' + t);
}
if (index % columns === 0) {
row++;
}
$this.addClass('c' + current_column);
$this.addClass('r' + row);
prevAll.each(function (index) {
if ($(this).hasClass('c' + current_column)) {
top += $(this).outerHeight() + self.options.padding_y;
}
});
if (single_column_mode === true) {
left_out = 0;
} else {
left_out = (index % columns) * (article_width +
self.options.padding_x);
}
$this.css({
'left': left_out,
'top': top
});
});
this.tallest($container);
$(window).resize();
};
Plugin.prototype.tallest = function (_container) {
var column_heights = [],
largest = 0;
for (var z = 0; z < columns; z++) {
var temp_height = 0;
_container.find('.c' + z).each(function () {
temp_height += $(this).outerHeight();
});
column_heights[z] = temp_height;
}
largest = Math.max.apply(Math, column_heights);
_container.css('height', largest + (this.options.padding_y +
this.options.margin_bottom));
};
Plugin.prototype.make_layout_change = function (_self) {
if ($(window).width() < _self.options.single_column_breakpoint) {
_self.calculate(true);
} else {
_self.calculate(false);
}
};
$.fn[pluginName] = function (options) {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new Plugin(this, options));
}
});
}
})(jQuery, window, document);
Any tips in getting the Javascript to work would be hugely appreciated!
It is a good practice to have your javascript files right before the closing body tag even though you are using jQuery and other open source libraries. Have you inspected the browser(F12 on windows) to see if the URL that you are pointing to is loading the file on the network? In MVC, you might want to put the JS file inside of bundle.config and referencing them using Bundling and Minification like the following
In Bundle.config
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/scripts").Include(
"~/Scripts/script.js");
In Application_Start Event
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
and
On the UI
#Scripts.Render("~/bundles/scripts")
This way , your JS files are minified and changes are always reflected onto the UI(Solves caching issues)
If you inspect the output html in your browser, you'll see that the url in your script tag probably doesn't resolve correctly:
<script type="text/javascript" src='#Url.Content("~/Scripts/ResponsiveGrid.js")'>
</script>
You can fix this by using a url relative to the root of the domain.
src="/Scripts/ResponsiveGrid.js"

Jump to end of progress bar when complete

I have working but ugly solution.
Idea is:
Run progress bar before ajax call
Jump to end of progress bar when complete (or fail)
Wait at 90% if ajax call is not finished yet (when finish than jump to end)
There are at least three problems in my solution:
I have to reset progress bar 'width' in 3 places.
I must have public variable (widthProgressBar)
I cannot reuse function 'startProgress' in case I want to have two progress bars at same page.
This is my solution: http://jsfiddle.net/WQXXT/5403/
var widthProgressBarPing = 0;
// handles the click event, sends the query
function getSuccessOutput() {
widthProgressBar = 0;
startProgress("pingTestBar");
$.ajax({
url: '/echo/js/?js=hello%20world!',
complete: function(response) {
widthProgressBar = 99;
},
error: function() {
widthProgressBar = 99;
},
});
return false;
}
function startProgress(barId) {
var elem = document.getElementById(barId);
var id = setInterval(frame, 15);
function frame() {
if (widthProgressBar >= 90 && widthProgressBar < 99) {}
if (widthProgressBar >= 100) {
clearInterval(id);
} else {
widthProgressBar++;
elem.style.width = widthProgressBar + '%';
elem.innerHTML = widthProgressBar * 1 + '%';
}
}
}
.testProgress {
width: 100%;
background-color: #ddd;
}
.testProgressBar {
width: 0%;
height: 30px;
background-color: #4CAF50;
text-align: center;
line-height: 30px;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
test success |
<div class="testProgress">
<div id="pingTestBar" class="testProgressBar"></div>
</div>
I believe this is the right approach, without changing unnecessary variables outside usage scope.
// handles the click event, sends the query
function getSuccessOutput() {
var bar = new Bar("pingTestBar");
$.ajax({
url: '/echo/js/?js=hello%20world!',
complete: function(response) {
bar.finish()
},
error: function() {
bar.finish()
},
});
return false;
}
function Bar(barId) {
var self = this;
self.w = 0;
var elem = document.getElementById(barId);
var id = setInterval(frame, 15);
this.finish = function(){
clearInterval(id);
self.w = 100;
changeElem()
}
function changeElem(){
elem.style.width = self.w + '%';
elem.innerHTML = self.w * 1 + '%';
}
function frame() {
if (self.w >= 90 && self.w < 99) {}
if (self.w >= 100) {
} else {
self.w++;
changeElem()
}
}
}
.testProgress {
width: 100%;
background-color: #ddd;
}
.testProgressBar {
width: 0%;
height: 30px;
background-color: #4CAF50;
text-align: center;
line-height: 30px;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
test success |
<div class="testProgress">
<div id="pingTestBar" class="testProgressBar"></div>
</div>
Here's your code modified.
I eliminated the global var widthProgressBarPing by using the width of the barId element that's always there (var widthProgressBar = elem.style.width.slice(0, -4);).
// handles the click event, sends the query
function getSuccessOutput(barId) {
widthProgressBar = 0;
startProgress(barId);
$.ajax({
url: '/echo/js/?js=hello%20world!',
complete: function(response) {
widthProgressBar = 99;
},
error: function() {
widthProgressBar = 99;
},
});
return false;
}
function startProgress(barId) {
var elem = document.getElementById(barId);
var widthProgressBar = elem.style.width.slice(0, -4);
var id = setInterval(frame, 15);
function frame() {
if (widthProgressBar >= 90 && widthProgressBar < 99) {}
if (widthProgressBar >= 100) {
clearInterval(id);
} else {
widthProgressBar++;
elem.style.width = widthProgressBar + '%';
elem.innerHTML = widthProgressBar * 1 + '%';
}
}
}
.testProgress {
width: 100%;
background-color: #ddd;
}
.testProgressBar {
width: 0%;
height: 30px;
background-color: #4CAF50;
text-align: center;
line-height: 30px;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
test success ||
<div class="testProgress">
<div id="pingTestBar" class="testProgressBar"></div>
</div>
By passing an argument to startProgress(barId) you can use the same function for different bars.
// handles the click event, sends the query
function getSuccessOutput(barId) {
widthProgressBar = 0;
startProgress(barId);
$.ajax({
url: '/echo/js/?js=hello%20world!',
complete: function(response) {
widthProgressBar = 99;
},
error: function() {
widthProgressBar = 99;
},
});
return false;
}
function startProgress(barId) {
var elem = document.getElementById(barId);
var widthProgressBar = elem.style.width.slice(0, -4);
var id = setInterval(frame, 15);
function frame() {
if (widthProgressBar >= 90 && widthProgressBar < 99) {}
if (widthProgressBar >= 100) {
clearInterval(id);
} else {
widthProgressBar++;
elem.style.width = widthProgressBar + '%';
elem.innerHTML = widthProgressBar * 1 + '%';
}
}
}
.testProgress {
width: 100%;
background-color: #ddd;
}
.testProgressBar {
width: 0%;
height: 30px;
background-color: #4CAF50;
text-align: center;
line-height: 30px;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
test success ||
test success2
<div class="testProgress">
<div id="pingTestBar" class="testProgressBar"></div>
</div>
<div class="testProgress">
<div id="pingTestBar2" class="testProgressBar"></div>
</div>
[cut] There are at least three problems in my solution:
I have to reset progress bar 'width' in 3 places
I must have public
variable (widthProgressBar)
I cannot reuse function 'startProgress' in
case I want to have two progress bars at same page.
Simply initialize/reset once when getSuccessOutput() starts
Use the width attribute stored on each bar
Pass the "bar" as arguments, so you can use many bars as you need.
Anyway, you could use .animate() in order to show the progress, so you avoid to keep interval id and the code is more readable.
Please, take a look to following snippet:
function getSuccessOutput() {
//Reset all progress bars
$(".testProgressBar").width(0);
$(".testProgressBar").text("");
//Start requests
doRequest($("#pingTestBar"), 1200);
doRequest($("#pingTestBar2"), 1500);
doRequest($("#pingTestBar3"), 800);
}
function startProgress(bar) {
bar.animate(
{
width:'100%'
},
{
step: function() {
setText(bar);
},
duration: 2000
}
);
}
function complete(bar) {
console.log("Complete " + bar.attr('id'));
bar.finish().animate(
{
width:'100%'
},
{
step: function(){
setText(bar);
}
}
);
}
function setText(bar){
var text = bar.width() / bar.parent().width() * 100;
bar.text(text.toFixed(0));
}
function mockAjax(options) {
var that = {
done: function done(callback) {
if (options.success)
setTimeout(callback, options.timeout, options.response);
return that;
},
error: function error(callback) {
if (!options.success)
setTimeout(callback, options.timeout, options.response);
return that;
}
};
return that;
}
function doRequest(bar, duration){
var mock = {
ajax: function() {
return mockAjax({
success: true,
response: {},
timeout: duration
});
}
};
startProgress(bar);
mock.ajax()
.done(
function (response) {
complete(bar);
}
)
.error(
function (response) {
complete(bar);
}
);
}
.testProgress {
width: 100%;
background-color: #ddd;
}
.testProgressBar {
width: 0%;
height: 30px;
background-color: #4CAF50;
text-align: center;
line-height: 30px;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
test success |
<div class="testProgress">
<div id="pingTestBar" class="testProgressBar"></div>
</div>
<div class="testProgress">
<div id="pingTestBar2" class="testProgressBar"></div>
</div>
<div class="testProgress">
<div id="pingTestBar3" class="testProgressBar"></div>
</div>
I hope it helps you, bye.

My hybrid app wont change pages when checking li item which contains a string

For a project im working on i want to make my hybrid app (phonegap) switch screens when the app detects the BluetoothLE signal from an Arduino. For this I made the code loop trough a couple of list items and check of the content of the li item is the same as "TEST123"(the name i gave the Arduino). If these would be the same, the app should switch to another page. I edited the code called "cordova-plugin-ble-central made by Don Coleman on GitHub) to reach this goal.
I made the code so it would scroll trough the li items within a ul, read the content and called the connect function if the string was the same as "TEST123", but my pages do not seem to switch.
Thanks for your help!
HTML:
<body>
<div class="app">
<h1>BluefruitLE</h1>
<div id="mainPage" class="show">
<ul id="deviceList">
</ul>
<button id="refreshButton">Refresh</button>
</div>
<div id="detailPage" class="hide">
<div id="resultDiv"></div>
<div>
<input type="text" id="messageInput" value="Hello"/>
<button id="sendButton">Send</button>
</div>
<button id="disconnectButton">Disconnect</button>
</div>
</div>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript">
app.initialize();
</script>
</body>
CSS:
body {
font-family: "Helvetica Neue";
font-weight: lighter;
color: #2a2a2a;
background-color: #f0f0ff;
-webkit-appearance: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-touch-callout: none; -webkit-user-select: none;
}
button {
margin: 15px;
-webkit-appearance:none;
font-size: 1.2em;
}
#mainPage {
text-align:center;
width: 100vw;
height: 100vh;
}
#detailPage {
text-align:center;
font-size: 2em;
width: 100vw;
height: 100vh;
background-color: red;
}
button {
-webkit-appearance: none;
font-size: 1.5em;
border-radius: 0;
}
#resultDiv {
font: 16px "Source Sans", helvetica, arial, sans-serif;
font-weight: 200;
display: block;
-webkit-border-radius: 6px;
width: 100%;
height: 140px;
text-align: left;
overflow: auto;
}
#mainPage.show{
display: block;
}
#mainPage.hide{
display: none;
}
#detailPage.show{
display: block;
}
#detailPage.hide{
display: none;
}
And ofcourse my JavaScript:
'use strict';
// ASCII only
function bytesToString(buffer) {
return String.fromCharCode.apply(null, new Uint8Array(buffer));
}
// ASCII only
function stringToBytes(string) {
var array = new Uint8Array(string.length);
for (var i = 0, l = string.length; i < l; i++) {
array[i] = string.charCodeAt(i);
}
return array.buffer;
}
// this is Nordic's UART service
var bluefruit = {
serviceUUID: '6e400001-b5a3-f393-e0a9-e50e24dcca9e',
txCharacteristic: '6e400002-b5a3-f393-e0a9-e50e24dcca9e', // transmit is from the phone's perspective
rxCharacteristic: '6e400003-b5a3-f393-e0a9-e50e24dcca9e' // receive is from the phone's perspective
};
var app = {
initialize: function() {
this.bindEvents();
detailPage.hidden = true;
//ale paginas hidden behalve login
},
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
refreshButton.addEventListener('touchstart', this.refreshDeviceList, false);
sendButton.addEventListener('click', this.sendData, false);
disconnectButton.addEventListener('touchstart', this.disconnect, false);
deviceList.addEventListener('touchstart', this.connect, false); // assume not scrolling
},
onDeviceReady: function() {
app.refreshDeviceList();
},
refreshDeviceList: function() {
deviceList.innerHTML = ''; // empties the list
if (cordova.platformId === 'android') { // Android filtering is broken
ble.scan([], 5, app.onDiscoverDevice, app.onError);
} else {
ble.scan([bluefruit.serviceUUID], 5, app.onDiscoverDevice, app.onError);
}
},
onDiscoverDevice: function(device) {
var listItem = document.createElement('li'),
html = '<b>' + device.name + '</b><br/>' +
'RSSI: ' + device.rssi + ' | ' +
device.id;
listItem.dataset.deviceId = device.id;
listItem.innerHTML = html;
deviceList.appendChild(listItem);
},
ulScroll: function() {
var ul = document.getElementById("deviceList");
var items = ul.getElementsByTagName("li");
for (var i = 0; i < items.length; i++) {
if ((items.textContent || items.innerText) == "TEST123"){
connect: function(e) {
var deviceId = e.target.dataset.deviceId,
onConnect = function(peripheral) {
app.determineWriteType(peripheral);
// subscribe for incoming data
ble.startNotification(deviceId, bluefruit.serviceUUID, bluefruit.rxCharacteristic, app.onData, app.onError);
sendButton.dataset.deviceId = deviceId;
disconnectButton.dataset.deviceId = deviceId;
resultDiv.innerHTML = "";
app.showDetailPage();
};
ble.connect(deviceId, onConnect, app.onError);
},
}
}
}
disconnect: function(event) {
var deviceId = event.target.dataset.deviceId;
ble.disconnect(deviceId, app.showMainPage, app.onError);
},
showMainPage: function() {
document.getElementById("mainPage").className = "show";
document.getElementById("detailPage").className = "hide";
},
showDetailPage: function() {
document.getElementById("detailPage").className = "show";
document.getElementById("mainPage").className = "hide";
},
onError: function(reason) {
alert("ERROR: " + reason);
}
};
P.S. Very sorry for the unorganized code
How i would structure the code:
var app={
devices:[], //thats were the devices are stored
onDeviceReady:refreshDeviceList,
refreshDeviceList: function() {
deviceList.innerHTML = ''; // empties the list
this.devices=[];
if (cordova.platformId === 'android') { // Android filtering is broken
ble.scan([], 5, app.onDiscoverDevice, app.onError);
} else {
ble.scan([bluefruit.serviceUUID], 5, app.onDiscoverDevice, app.onError);
}
//all devices checked, lets search ours:
var my=this.devices.find(device => { device.name=="TEST123"});
if(my){
ble.connect(my.id,app.onconnect,errorhandling);
}else{
alert("my device not found");
}
},
onDiscoverDevice: function(device) {
//add to html
var listItem = document.createElement('li'),
html = '<b>' + device.name + '</b><br/>' +
'RSSI: ' + device.rssi + ' | ' +
device.id;
listItem.innerHTML = html;
deviceList.appendChild(listItem);
//add to devices:
this.devices.push(device);
},
onconnect:function(e){
//your connect function
}
}
Additional notes:
refreshButton etc are undefined. You need to find them:
var refreshButton=document.getElementById("refreshButton");

Drag and drop picture to text and with double click to remove the text inside the box

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 />
<title>Basic Drag and Drop</title>
<style>
#drop {
min-height: 200px;
width: 200px;
border: 3px dashed #ccc;
margin: 10px;
padding: 10px;
clear: left;
}
p {
margin: 10px 0;
}
#triangle {
background: url(images/triangle.jpg) no-repeat;
}
#square {
background: url(images/square.gif) no-repeat;
}
#circle {
background: url(images/circle.jpg) no-repeat;
}
#red {
background: url(images/red.jpg) no-repeat;
}
#yellow {
background: url(images/yellow.jpg) no-repeat;
}
#green {
background: url(images/green.jpg) no-repeat;
}
.drag {
height: 48px;
width: 48px;
float: left;
-khtml-user-drag: element;
margin: 10px;
}
</style>
<script>
var addEvent = (function () {
if (document.addEventListener) {
return function (el, type, fn) {
if (el && el.nodeName || el === window) {
el.addEventListener(type, fn, false);
} else if (el && el.length) {
for (var i = 0; i < el.length; i++) {
addEvent(el[i], type, fn);
}
}
};
} else {
return function (el, type, fn) {
if (el && el.nodeName || el === window) {
el.attachEvent('on' + type, function () { return fn.call(el, window.event); });
} else if (el && el.length) {
for (var i = 0; i < el.length; i++) {
addEvent(el[i], type, fn);
}
}
};
}
})();
(function () {
var pre = document.createElement('pre');
pre.id = "view-source"
// private scope to avoid conflicts with demos
addEvent(window, 'click', function (event) {
if (event.target.hash == '#view-source') {
// event.preventDefault();
if (!document.getElementById('view-source')) {
// pre.innerHTML = ('<!DOCTYPE html>\n<html>\n' + document.documentElement.innerHTML + '\n</html>').replace(/[<>]/g, function (m) { return {'<':'<','>':'>'}[m]});
var xhr = new XMLHttpRequest();
// original source - rather than rendered source
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
pre.innerHTML = this.responseText.replace(/[<>]/g, function (m) { return {'<':'<','>':'>'}[m]});
prettyPrint();
}
};
document.body.appendChild(pre);
// really need to be sync? - I like to think so
xhr.open("GET", window.location, true);
xhr.send();
}
document.body.className = 'view-source';
var sourceTimer = setInterval(function () {
if (window.location.hash != '#view-source') {
clearInterval(sourceTimer);
document.body.className = '';
}
}, 200);
}
});
})();
</script>
<style id="jsbin-css">
</style>
</head>
<body>
<div class="drag" id="triangle" draggable="true"></div>
<div class="drag" id="square" draggable="true"></div>
<div class="drag" id="circle" draggable="true"></div>
<div class="drag" id="red" draggable="true"></div>
<div class="drag" id="yellow" draggable="true"></div>
<div class="drag" id="green" draggable="true"></div>
<div id="drop"></div>
<script>
function cancel(e) {
if (e.preventDefault) {
e.preventDefault();
}
return false;
}
var dragItems = document.querySelectorAll('[draggable=true]');
for (var i = 0; i < dragItems.length; i++) {
addEvent(dragItems[i], 'dragstart', function (event) {
// store the ID of the element, and collect it on the drop later on
event.dataTransfer.setData('Text', this.id);
});
}
var drop = document.querySelector('#drop');
// Tells the browser that we *can* drop on this target
addEvent(drop, 'dragover', cancel);
addEvent(drop, 'dragenter', cancel);
addEvent(drop, 'drop', function (e) {
if (e.preventDefault) e.preventDefault(); // stops the browser from redirecting off to the text.
this.innerHTML += '<p>' + e.dataTransfer.getData('Text') + '</p>';
return false;
});
</script>
</body>
</html>
how to double click remove the text inside the textbox by using html5? I having problem on how to remove the text out from the textbox in this html5. things can be drag and drop inside, but i want to remove the things inside that i have been dragged inside... i having problem on removing the item inside that.
Try using this.
document.getElementById('selectID').ondblclick = function(){
alert(this.selectedIndex);//remove your text here
};

Categories