I'm trying to solve this issue: I have an array of objects, each containing an image property, which is an absolute url to a remote image.
I have to find the first object with an image larger than 500px, extract it from the array and putting it into another object.
What I've tried to do is to cycle through the array and call a function that loads the image and returns the width, but it doesn't work…
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, loadImages) {
var articles = [
{
"image": "http://i.res.24o.it/images2010/logo.gif"
},
{
"image": "http://www.avvenire.it/Commenti/PublishingImages/ImmaginiArticolo/Originali/gispponema_47548148.jpg"
},
{
"image": "http://i.dailymail.co.uk/i/pix/2012/03/07/article-2111440-1211004C000005DC-146_1024x615_large.jpg"
},
{
"image": "http://www.brookings.edu/~/media/research/images/w/wa%20we/wealthy002/wealthy002_16x9.jpg"
},
{
"image": "http://www.avvenire.it/Mondo/PublishingImages/ImmaginiArticolo/Originali/oREUVENRIV_47517580.jpg"
}
];
$scope.articles = loadImages.getCover(articles);
})
.factory('loadImages', function(){
function getMeta(url){
var img = new Image();
img.src = url;
img.onload = function(){
return img.width;
};
}
return {
getCover: function(articles) {
var cover = null;
for (var i = 0; i < articles.length; i++) {
if(articles[i].image){
var w = getMeta(articles[i].image);
if(w > 500){
cover = articles[i];
articles.splice(i,0);
}
}
}
return {
cover: cover,
articles: articles
};
}
};
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>{{articles}}!</p>
</body>
</html>
plunkr: http://plnkr.co/edit/tCacRy0jf9WhWreWIK7I
Do you have any suggestion? What am I doing wrong?
Thanks
Thanks to #JamesP comment I tried combining an asynchronous cycle found here (Asynchronous for cycle in JavaScript) and the $q promises in this way. I don't know if it's the best way to do it, but it works.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, loadImages) {
var articles = [
{
"image": "http://placehold.it/200"
},
{
"image": "http://placehold.it/300"
},
{
"image": "http://placehold.it/600"
},
{
"image": "http://placehold.it/700"
},
{
"image": "http://placehold.it/800"
}
];
loadImages.asyncLoop(articles.length, function(loop){
var i = loop.iteration();
loadImages.getMeta(articles[i].image).then(function(r){
var cover = articles[i];
articles.splice(i,1);
$scope.articles = {
cover: cover,
articles: articles
};
}, function(){
loop.next();
})
}, function(){
$scope.articles = articles;
});
})
.factory('loadImages', function($q){
return {
getMeta: function(url){
var deferred = $q.defer();
try{
var img = new Image();
img.src = url;
img.onload = function(){
if(img.width > 500){
deferred.resolve(img.width);
}else{
deferred.reject();
}
}
}catch(e){
deferred.reject(e);
}
return deferred.promise;
},
asyncLoop: function(iterations, func, callback) {
var index = 0;
var done = false;
var loop = {
next: function() {
if (done) {
return;
}
if (index < iterations) {
index++;
func(loop);
} else {
done = true;
callback();
}
},
iteration: function() {
return index - 1;
},
break: function() {
done = true;
callback();
}
};
loop.next();
return loop;
}
};
});
Related
I think I'm doing something wrong in the variables or syntax... i don't know, help me to correct my code. (I'm using Leaflet for the map show)
Desired Behavior
The user should be able to see the BBOX entering the coordinates into the URL, for example:
.com/#013.0,052.0,013.5,052.5
I only care that the BBOX is shown, I don't care that the URL coordinates change when zooming or moving around the map.
My HTML
<!DOCTYPE html>
<html>
<header>
<link rel="stylesheet" href="style.css" />
<link
rel="stylesheet"
href="https://unpkg.com/leaflet#1.9.3/dist/leaflet.css"
integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
crossorigin=""
/>
<script
src="https://unpkg.com/leaflet#1.9.3/dist/leaflet.js"
integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
crossorigin=""
></script>
</header>
<body>
<div id="map"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="https://unpkg.com/leaflet#1.0.1/dist/leaflet.js"></script>
<script src="leaflet-hash.js"></script>
<script>
var map = L.map("map").setView([42, 12], 4);
// var hash = new L.hash(map);
var urlhash = window.location.hash.substring(1).split("/");
var boundingBox = "";
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 22,
minZoom: 1,
continuousWorld: false,
noWrap: false,
attribution:
'Data by OpenStreetMap, under ODbL.',
detectRetina: false,
}).addTo(map);
var bboxField = L.control({
position: "bottomleft",
});
bboxField.onAdd = function (map) {
//create div container for control
var div = L.DomUtil.create("div", "myButtonBar");
//prevent mouse events from propagating through to the map
L.DomEvent.disableClickPropagation(div);
//create custom radio buttons
div.innerHTML =
'BBOX (Left (LON) ,Bottom (LAT), Right (LON), Top (LAT), comma separated, with or without decimal point):<br><input type="text" id="bbox_field"/><button id="setDimensions">Display BBOX</button><button id="remove">Remove</button>';
return div;
};
bboxField.addTo(map);
$(".myButtonBar").css("font-weight", "bold");
if (urlhash[0] !== "") {
$("#bbox_field").val(urlhash[0]);
draw_bbox(urlhash[0]);
}
function draw_bbox(box) {
var myarray = box.split(",");
var bounds = [
[myarray[1], myarray[0]],
[myarray[3], myarray[2]],
];
boundingBox = L.rectangle(bounds, { color: "#ff7800", weight: 1 });
map.removeLayer(boundingBox);
boundingBox.addTo(map);
map.fitBounds(boundingBox.getBounds());
map.setZoom(map.getZoom() - 1);
}
$("#setDimensions").click(function () {
draw_bbox($("#bbox_field").val());
});
$("#bbox_field").keyup(function (event) {
if (event.keyCode === 13) {
$("#setDimensions").click();
}
});
// console.log(bbox)
$("#remove").click(function () {
map.removeLayer(boundingBox);
});
</script>
</body>
</html>
Leaflet Hash Plugin Code
(function(window) {
var HAS_HASHCHANGE = (function() {
var doc_mode = window.documentMode;
return ('onhashchange' in window) &&
(doc_mode === undefined || doc_mode > 7);
})();
L.hash = function(map) {
this.onHashChange = L.Util.bind(this.onHashChange, this);
if (map) {
this.init(map);
}
};
L.hash.parseHash = function(hash) {
if(hash.indexOf('#') === 0) {
hash = hash.substr(1);
}
var args = hash.split("/");
if (args.length == 3) {
var zoom = parseInt(args[0], 10),
lat = parseFloat(args[1]),
lon = parseFloat(args[2]);
if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
return false;
} else {
return {
center: new L.LatLng(lat, lon),
zoom: zoom
};
}
} else {
return false;
}
};
L.hash.formatHash = function(map) {
var center = map.getCenter(),
zoom = map.getZoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
return "#" + [zoom,
center.lat.toFixed(precision),
center.lng.toFixed(precision)
].join("/");
},
L.hash.prototype = {
map: null,
lastHash: null,
parseHash: L.hash.parseHash,
formatHash: L.hash.formatHash,
init: function(map) {
this.map = map;
// reset the hash
this.lastHash = null;
this.onHashChange();
if (!this.isListening) {
this.startListening();
}
},
removeFrom: function(map) {
if (this.changeTimeout) {
clearTimeout(this.changeTimeout);
}
if (this.isListening) {
this.stopListening();
}
this.map = null;
},
onMapMove: function() {
// bail if we're moving the map (updating from a hash),
// or if the map is not yet loaded
if (this.movingMap || !this.map._loaded) {
return false;
}
var hash = this.formatHash(this.map);
if (this.lastHash != hash) {
location.replace(hash);
this.lastHash = hash;
}
},
movingMap: false,
update: function() {
var hash = location.hash;
if (hash === this.lastHash) {
return;
}
var parsed = this.parseHash(hash);
if (parsed) {
this.movingMap = true;
this.map.setView(parsed.center, parsed.zoom);
this.movingMap = false;
} else {
this.onMapMove(this.map);
}
},
// defer hash change updates every 100ms
changeDefer: 100,
changeTimeout: null,
onHashChange: function() {
// throttle calls to update() so that they only happen every
// `changeDefer` ms
if (!this.changeTimeout) {
var that = this;
this.changeTimeout = setTimeout(function() {
that.update();
that.changeTimeout = null;
}, this.changeDefer);
}
},
isListening: false,
hashChangeInterval: null,
startListening: function() {
this.map.on("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.addListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
this.hashChangeInterval = setInterval(this.onHashChange, 50);
}
this.isListening = true;
},
stopListening: function() {
this.map.off("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.removeListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
}
this.isListening = false;
}
};
L.hash = function(map) {
return new L.hash(map);
};
L.map.prototype.addHash = function() {
this._hash = L.hash(this);
};
L.map.prototype.removeHash = function() {
this._hash.removeFrom();
};
})(window);
I build up an website which contains on the left side an panoramic viewer (VrView from google) and right a shopping floorplan map.
I don´t know the exact way of clicking at the json link the iframe is updated with another pano picture. Can anyone help me?
I´m also not sure if the vrviewer is the best solution or better to embed three.js with the code for panorama cube which works itself also great. I´m open for any suggestions. Thank you.
Here the code for the iframe version:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Pano Map</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="css/style.css"/>
<link rel="stylesheet" type="text/css" href="css/map.css">
</head>
<body class="stretched">
<div id="wrap">
<header>
<nav></nav>
</header>
<section id="content">
<!--VrView -->
<div class="col_two_third">
<script type='text/template'>
<iframe class="vrview" scrolling="no" frameborder="0" allowfullscreen="true" width="100%" height="800px" src="http://mypage.com/vrview/index.html?image=http://mypage.com/vrview/image/pano01.jpg"></iframe>
<script>
function DeviceMotionSender(){if(!this.isIOS_()){return}window.addEventListener("devicemotion",this.onDeviceMotion_.bind(this),false);this.iframes=document.querySelectorAll("iframe.vrview")}DeviceMotionSender.prototype.onDeviceMotion_=function(e){var message={type:"DeviceMotion",deviceMotionEvent:this.cloneDeviceMotionEvent_(e)};for(var i=0;i<this.iframes.length;i++){var iframe=this.iframes[i];var iframeWindow=iframe.contentWindow;if(this.isCrossDomainIframe_(iframe)){iframeWindow.postMessage(message,"*")}}};DeviceMotionSender.prototype.cloneDeviceMotionEvent_=function(e){return{acceleration:{x:e.acceleration.x,y:e.acceleration.y,z:e.acceleration.z},accelerationIncludingGravity:{x:e.accelerationIncludingGravity.x,y:e.accelerationIncludingGravity.y,z:e.accelerationIncludingGravity.z},rotationRate:{alpha:e.rotationRate.alpha,beta:e.rotationRate.beta,gamma:e.rotationRate.gamma},interval:e.interval}};DeviceMotionSender.prototype.isIOS_=function(){return/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream};DeviceMotionSender.prototype.isCrossDomainIframe_=function(iframe){var html=null;try{var doc=iframe.contentDocument||iframe.contentWindow.document;html=doc.body.innerHTML}catch(err){}return html===null};var dms=new DeviceMotionSender;
</script>
</script>
</div>
<!--Map -->
<div class="col_one_third col_last clearfix">
<div class="map-container">
<div id="map"></div>
</div>
</div>
</section>
<footer></footer>
</div>
<!-- Scripts -->
<!-- Map Floorplan -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/hammer.min.js"></script>
<script type="text/javascript" src="js/jquery.mousewheel.js"></script>a
<script type="text/javascript" src="js/script.js"></script>
<script type="text/javascript" src="js/magnific-popup.js"></script>
<script type="text/javascript" src="map/map.js"></script>
<script type="text/javascript">
$(document).ready(function() {
var map = $('#map').map({
source: 'maplist.json',
height: 800,
mapfill: true,
maxscale: 1
});
// EVENTS
// Map ready
map.on('mapready', function(e, self) {
console.log('Map is ready!')
// self grants direct access to the map object
// The map will be focused on the washing machine by default
//self.moveTo(0.67, 0.62, 3, 0);
});
// Location opened
map.on('locationopened', function(e, location) {
// location grants full access to the location
console.log(location.title + ' opened.');
});
// Location closed
map.on('locationclosed', function(e) {
console.log('Location closed.');
});
// Level switched
map.on('levelswitched', function(e, level) {
console.log('Switched to ' + level + ' level.');
});
// Position changed
map.on('positionchanged', function(e, self) {
// self grants direct access to the map object
//console.log('Pan or zoom performed, current scale: ' + self.scale);
});
// METHODS
// Getting mapplic object
var self = map.data('map');
map.on('locationclosed', function(e) {
//console.log(self);
});
});
</script>
<!-- VRView code from google-->
<script type='text/javascript'>
//<![CDATA[
var BreakpointHandler = function() {
this.initted = false;
this.isHomePage = false;
this.isMobile = false;
};
BreakpointHandler.prototype.finalizeSummary = function(summaryHtml, lastNode) {
// Use $.trim for IE8 compatibility
summaryHtml = $.trim(summaryHtml).replace(/(<br>|\s)+$/,'');
if (lastNode.nodeType == 3) {
var lastChar = summaryHtml.slice(-1);
if (!lastChar.match(/[.”"?]/)) {
if (!lastChar.match(/[A-Za-z]/)) {
summaryHtml = summaryHtml.slice(0, -1);
}
summaryHtml += ' ...';
}
} else if (lastNode.nodeType == 1 && (lastNode.nodeName == 'I' || lastNode.nodeName == 'A')) {
summaryHtml += ' ...';
}
return summaryHtml;
};
BreakpointHandler.prototype.generateSummaryFromContent = function(content, numWords) {
var seenWords = 0;
var summaryHtml = '';
for (var i=0; i < content.childNodes.length; i++) {
var node = content.childNodes[i];
var nodeText;
if (node.nodeType == 1) {
if (node.hasAttribute('data-about-pullquote')) {
continue;
}
nodeText = node.textContent;
if (nodeText === undefined) {
// innerText for IE8
nodeText = node.innerText;
}
if (node.nodeName == 'DIV' || node.nodeName == 'B') {
// Don't end early if we haven't seen enough words.
if (seenWords < 10) {
continue;
}
if (i > 0) {
summaryHtml = this.finalizeSummary(summaryHtml, content.childNodes[i-1]);
}
break;
}
summaryHtml += node.outerHTML;
} else if (node.nodeType == 3) {
nodeText = node.nodeValue;
summaryHtml += nodeText + ' ';
}
var words = nodeText.match(/\S+\s*/g);
if (!words) {
continue;
}
var remain = numWords - seenWords;
if (words.length >= remain) {
summaryHtml = this.finalizeSummary(summaryHtml, node);
break;
}
seenWords += words.length;
}
return summaryHtml;
};
BreakpointHandler.prototype.detect = function() {
var match,
pl = /\+/g,
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
query = window.location.search.substring(1);
var urlParams = {};
while (match = search.exec(query))
urlParams[decode(match[1])] = decode(match[2]);
this.isListPage = $('html').hasClass('list-page');
this.isMobile = urlParams['m'] === '1';
this.isHomePage = window.location.pathname == '/';
};
BreakpointHandler.prototype.initContent = function() {
var self = this;
$('.post').each(function(index) {
var body = $(this).children('.post-body')[0];
var content = $(body).children('.post-content')[0];
$(content).addClass('post-original');
var data = $(content).children('script').html();
data = self.rewriteForSSL(data);
// If exists, extract specified editor's preview.
var match = data.match(/([\s\S]+?)<div data-is-preview.+?>([\s\S]+)<\/div>/m);
if (match) {
data = match[1];
}
// Prevent big images from loading when they aren't needed.
// This must be done as a pre-injection step, since image loading can't be
// canceled once embedded into the DOM.
if (self.isListPage && self.isMobile) {
data = data.replace(/<(img|iframe) .+?>/g, '');
}
// Insert template to be rendered as nodes.
content.innerHTML = data;
if (self.isListPage) {
var summary = document.createElement('div');
$(summary).addClass('post-content');
$(summary).addClass('post-summary');
body.insertBefore(summary, content);
if (match) {
// Use provided summary.
summary.innerHTML = match[2];
} else {
// Generate a summary.
// Summary generation relies on DOM, so it must occur after content is
// inserted into the page.
summary.innerHTML = self.generateSummaryFromContent(content, 30);
}
// Add read more link to summary.
var titleAnchor = $(this).find('.title a')[0];
var link = titleAnchor.cloneNode(true);
link.innerHTML = 'Read More';
$(link).addClass('read-more');
summary.appendChild(link);
}
});
// Firefox does not allow for proper styling of BR.
if (navigator.userAgent.indexOf('Firefox') > -1) {
$('.post-content br').replaceWith('<span class="space"></span>');
}
$('.loading').removeClass('loading');
};
BreakpointHandler.prototype.process = function() {
if (!this.initted) {
var makeInsecureImageRegex = function(hosts) {
var whitelist = hosts.join('|').replace(/\./g,'\\.');
// Normal image tags, plus input images (yes, this is possible!)
return new RegExp('(<(img|input)[^>]+?src=("|\'))http:\/\/(' + whitelist +')', 'g');
};
this.sslImageRegex = makeInsecureImageRegex(BreakpointHandler.KNOWN_HTTPS_HOSTS);
this.sslImageCurrentDomainRegex = makeInsecureImageRegex([window.location.hostname]);
this.detect();
this.initContent();
this.initted = true;
}
};
BreakpointHandler.KNOWN_HTTPS_HOSTS = [
"www.google.org",
"www.google.com",
"services.google.com",
"blogger.com",
"draft.blogger.com",
"www.blogger.com",
"photos1.blogger.com",
"photos2.blogger.com",
"photos3.blogger.com",
"blogblog.com",
"img1.blogblog.com",
"img2.blogblog.com",
"www.blogblog.com",
"www1.blogblog.com",
"www2.blogblog.com",
"0.bp.blogspot.com",
"1.bp.blogspot.com",
"2.bp.blogspot.com",
"3.bp.blogspot.com",
"4.bp.blogspot.com",
"lh3.googleusercontent.com",
"lh4.googleusercontent.com",
"lh5.googleusercontent.com",
"lh6.googleusercontent.com",
"themes.googleusercontent.com",
];
BreakpointHandler.prototype.rewriteForSSL = function(html) {
// Handle HTTP -> HTTPS source replacement of images, movies, and other embedded content.
return html.replace(this.sslImageRegex, '$1https://$4')
.replace(this.sslImageCurrentDomainRegex, '$1//$4')
.replace(/(<(embed|iframe)[^>]+?src=("|'))http:\/\/([^"']*?(youtube|picasaweb\.google)\.com)/g, '$1https://$4')
// Slideshow SWF takes a image host, so we need to rewrite that parameter.
.replace(/(<embed[^>]+?feed=http(?=[^s]))/g, '$1s');
};
$(document).ready(function() {
var handler = new BreakpointHandler();
handler.process();
function DeviceMotionSender(){if(!this.isIOS_()){return}window.addEventListener("devicemotion",this.onDeviceMotion_.bind(this),false);this.iframes=document.querySelectorAll("iframe.vrview")}DeviceMotionSender.prototype.onDeviceMotion_=function(e){var message={type:"DeviceMotion",deviceMotionEvent:this.cloneDeviceMotionEvent_(e)};for(var i=0;i<this.iframes.length;i++){var iframe=this.iframes[i];var iframeWindow=iframe.contentWindow;if(this.isCrossDomainIframe_(iframe)){iframeWindow.postMessage(message,"*")}}};DeviceMotionSender.prototype.cloneDeviceMotionEvent_=function(e){return{acceleration:{x:e.acceleration.x,y:e.acceleration.y,z:e.acceleration.z},accelerationIncludingGravity:{x:e.accelerationIncludingGravity.x,y:e.accelerationIncludingGravity.y,z:e.accelerationIncludingGravity.z},rotationRate:{alpha:e.rotationRate.alpha,beta:e.rotationRate.beta,gamma:e.rotationRate.gamma},interval:e.interval}};DeviceMotionSender.prototype.isIOS_=function(){return/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream};DeviceMotionSender.prototype.isCrossDomainIframe_=function(iframe){var html=null;try{var doc=iframe.contentDocument||iframe.contentWindow.document;html=doc.body.innerHTML}catch(err){}return html===null};var dms=new DeviceMotionSender;
// Top-level navigation.
$(".BlogArchive .tab").click(function(ev) {
ev.preventDefault();
$(this).parent().toggleClass('active');
$(this).siblings().slideToggle(300);
});
$(".Label .tab").click(function(ev) {
ev.preventDefault();
$(this).parent().toggleClass('active');
$(this).siblings().slideToggle(300);
});
// Blog archive year expansion.
$('.BlogArchive .intervalToggle').click(function(ev) {
ev.preventDefault();
if ($(this).parent().hasClass('collapsed')) {
$(this).parent().removeClass('collapsed');
$(this).parent().addClass('expanded');
} else {
$(this).parent().removeClass('expanded');
$(this).parent().addClass('collapsed');
}
});
// Reverse order of months.
$('.BlogArchive .intervalToggle + div').each(function(_, items) {
var year = $(this);
year.children().each(function(_, month) {
year.prepend(month);
});
});
// Set anchors to open in new tab.
$('.post-content img').parent().each(function(_, node) {
if (node.nodeName == 'A') {
$(this).attr('target', '_blank');
}
});
// Process search requests.
$('.searchBox input').on("keypress", function(ev) {
if (ev.which == 13) {
window.location.href = 'https://www.google.com/search?q=site%3A' + window.location.hostname + '%20' + encodeURIComponent ($(this).val());
}
});
});
//]]>
</script>
<script src="vrview/index.js"></script>
</body>
</html>
maplist.json
{
"mapwidth": "2000",
"mapheight": "4000",
"categories":[
{
"id": "floor",
"title": "1st floor",
"show": "true"
},
{
"id": "roof",
"title": "2nd floor",
"show": "false"
}
],
"levels":[
{
"id":"floor",
"title":"1st floor shops",
"map":"map/images/floorplan.svg",
"minimap": "map/images/floorplan-small.jpg",
"locations":[
{
"id": "floor001",
"title": "Shop A",
"category": "floor",
"link": "<iframe src=\"http://mypage.com/vrview/images/pano01.jpg\">",
"x": "0.4547",
"y": "0.1703"
},
{
"id": "floor002",
"title": "Shop B",
"category": "floor",
"link": "<iframe src=\"http://mypage.com/vrview/images/pano02.jpg\">",
"x": "0.5814",
"y": "0.1703"
},
{
"id": "floor003",
"title": "Shop C",
"category": "floor",
"link": "<iframe src=\"http://mypage.com/vrview/images/pano03.jpg\">",
"x": "0.7176",
"y": "0.1703"
}
]
},
{
"id":"Roof",
"title":"2nd Floor",
"map":"map/images/floorplan.svg",
"minimap": "map/images/floorplan-small.jpg",
"locations":[
{"id": "roof001",
"title": "The Roof",
"description": "on top of this building",
"category": "Roof",
"link": "<iframe src=\"http://mypage.com/vrview/images/pano04.jpg\">",
"x": "0.5547",
"y": "0.3703"
}
]
}
]
}
I researched much, but I didn't get the answer.
At the moment I'm learning Angular and javascript and so I'm building a todo-app with HTML, Javascript and (of course) Angular. I want to have a drag and drop system... so if you want to delete a task you drag it and drop it into the trash.
I managed to build a drag and drop system with HTML and Javascript, but I don't get it to combine it with my angular code.
Take a look on it by yourself:
my HTML-code (and Javascript). You can drag and drop the things,but the functionality (so if you move a task to the trash it will be deleted) doesn't work (because therefor I need Angular). :
<!DOCTYPE html>
<html ng-app="todoApp">
<head>
<title>ToDo</title>
<link rel="stylesheet" href="style.css">
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("Text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
function trashdrop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body >
<div ng-controller="Tasks as tasksCtrl">
<div class="background" ng-dblclick="close()" ondrop="drop(event)" ondragover="allowDrop(event)">
...
<div id ="$index"class="ng-class: task.classe" ng-repeat="task in tasks | orderBy:sortBy:reverse" ng-click="setEditId($index)" draggable="true" ondragstart="drag(event)" >
<img ng-src="{{task.group.image}}" width="30px" height="30px" align="right" style="margin-right: 30%">
<div style="padding: 20px">{{task.title}}</br>{{task.body}} {{task.dueDate}}</div>
</div>
...
<img src="bigtrash.png" class="trash" ondrop="trashdrop(event)" ondragover="allowDrop(event)">
</div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<!-- <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular-animate.js"></script> -->
<script type="text/javascript" src="app.js"></script>
</body>
</html>
and here is my javascript:
var todoApp = angular.module('todoApp', [])
todoApp.factory('TasksService', function () {
var steps = [];
var tasks = [];
var groups = [];
return {
getTasks: function () {
return tasks;
},
deleteTask: function (id) {
tasks.splice(id-1, 1);
},
getGroups: function () {
return groups;
},
getSteps: function () {
return steps;
},
getStepsId: function (id) {
return steps[id];
},
getGroupId: function (name) {
for (var i = 0; i < groups.length; i++) {
if(groups[i].name===name) {
return i;
}
};
return undefined;
},
addTask:function (task) {
tasks.push(task);
},
addStep:function (step, id) {
steps[id].push(step);
tasks[id].steps=steps[id];
},
addStepGroup:function () {
steps.push([]);
},
setTasks:function (filterdTasks) {
tasks = filterdTasks;
console.log("tasks", tasks);
},
addGroup: function (group) {
groups.push(group);
}
}
});
todoApp.controller('Tasks', function($scope, TasksService) {
var status = "done";
var priority = "3"
$scope.groups = TasksService.getGroups();
$scope.edit = false;
$scope.specedit = false;
$scope.id = null;
$scope.newgroup = false;
$scope.tasks = TasksService.getTasks();
//the drag and drop functions
$scope.allowDrop = function(ev) {
ev.preventDefault();
}
$scope.drag = function(ev) {
console.log(ev.target);
ev.dataTransfer.setData("Text", ev.target.id);
}
$scope.drop = function(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
$scope.trashdrop = function(ev) {
ev.preventDefault();
TasksService.deleteTask(ev.target.id);
var data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
$scope.setEdit = function() {
$scope.edit = true;
}
$scope.setEditId = function(id) {
$scope.specedit = true;
$scope.id = id;
}
$scope.deleteTask = function(id) {
TasksService.deleteTask(id);
}
$scope.close = function() {
console.log("hi");
$scope.specedit = false;
$scope.edit = false;
$scope.id = null;
$scope.newgroup = false;
}
$scope.newGroup = function() {
$scope.newgroup = true;
}
this.addTask = function(title, body, group, date) {
$scope.edit = false;
TasksService.addTask({
id: $scope.tasks.length,
title: title,
body: body,
dueDate: date,
status: status,
group: {name: group, color: TasksService.getGroups()[TasksService.getGroupId(group)].color, image: TasksService.getGroups()[TasksService.getGroupId(group)].image,},
priority: priority,
classe: "note"+(($scope.tasks.length%3)+1),
steps: [],
});
TasksService.addStepGroup();
}
$scope.addGroup = function(title, description, color) {
$scope.newgroup = false;
var image = "";
if(color === "red") {
image = "pin3.png";
} else if (color === "yellow") {
image = "pin.png";
} else if (color === "green") {
image = "pin4.png";
} else if (color === "blue") {
image = "pin2.png";
}
TasksService.addGroup({
name: title,
description: description,
color: color,
image: image,
});
}
this.addStep = function(title, body) {
TasksService.addStep({
id: $scope.tasks[$scope.id].steps.length || 0,
title: title,
body: body,
status: "notyet",
}, $scope.id);
}
});
why doesn't work the second one?
the error is: Uncaught ReferenceError: drag is not defined... why?
I have the following code:
decodeFile = function(theFile, arrayBuffer) {
var song = new FileDecoder().decodeFile(theFile.type, arrayBuffer);
if (song !== null) {
fileList.push(song);
}
},
fileCreated = function(file) {
var reader = new FileReader();
reader.onload = function(e) {
decodeFile(file, e.target.result);
};
reader.readAsArrayBuffer(file);
},
readDirItems = function(items) {
var i, item,
length = items.length;
for(i = 0; i < length; i++) {
item = items[i];
if (item.isFile) {
item.file(fileCreated, errorCallback);
}
}
};
//init
uploadInput.addEventListener("click", function() {
chrome.fileSystem.chooseEntry({type: "openDirectory"}, function(chosenDir) {
var dirReader,
getFilesInDirectory = function() {
dirReader.readEntries(readDirItems, errorCallback);
};
if (chosenDir && chosenDir.isDirectory) {
dirReader = chosenDir.createReader();
getFilesInDirectory();
}
});
});
How I expected this to work is that in readDirItems I would loop though all the items and for each fileEntry call the file method and enter the fileCreated callback. However this only happens for the first file. If I breakpoint in fileCreated it is only entered once. Can anyone explain what I am doing wrong?
Works for me. Your code was quite a bit more complicated than necessary for this question, so here's a simpler version. It's possible that the bug was fixed in the process of cleaning up the code.
manifest.json
{
"name": "20184022",
"description": "Answer to Stack Overflow question 20184022.",
"manifest_version": 2,
"minimum_chrome_version": "31",
"version": "0.0.0.1",
"app": {
"background": {
"scripts": ["main.js"]
}
},
"permissions": [
{"fileSystem": ["directory"]}
]
}
main.js
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('main.html', {});
});
main.html
<!DOCTYPE html>
<html>
<head><script src="iterate.js"></script></head>
<body><button id="iterate">Iterate</button></body>
</html>
iterate.js
window.onload = function() {
var errorCallback = function(e) {
console.log(e);
}
document.querySelector("#iterate").addEventListener("click", function() {
chrome.fileSystem.chooseEntry({type: "openDirectory"}, function(dir) {
if (dir && dir.isDirectory) {
var reader = dir.createReader();
reader.readEntries(function(entries) {
for (var i = 0; i < entries.length; ++i) {
console.log("entry is " + entries[i].fullPath);
}
}, errorCallback);
}
});
});
};
... and a sample run:
entry is /20184022/manifest.json iterate.js:13
entry is /20184022/iterate.js iterate.js:13
entry is /20184022/main.js iterate.js:13
entry is /20184022/main.html iterate.js:13
I recommend that you gradually change your code to match this sample, then once your code changes from broken to fixed, determine what the problem was and update your question to point out the error.
I would like to create a method on the singleton dp.DatapodManager so that it loads the data once via $.post, then I can use that data by calling methods on the singleton.
The output of the following code is:
111
222
test data
What do I have to do to get dp.DatapodManager.loadDirectly(); to add the contents of the text file to div#content?
<html>
<head>
<title>test load</title>
<script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('div#content').append('<p>1111</p>');
$('div#content').append('<p>222</p>');
$('div#content').append(dp.DatapodManager.getTestData());
dp.DatapodManager.loadDirectly(function(html) {
$('div#content').append(html);
});
});
var dp = dp || {
VERSION : '0.00.05'
};
dp.DatapodManager = (function() {
return {
loadDirectly: function(callback) {
dp.qsys.loadDataFromExternalWebsite(function(stringBlock) {
var lines = dp.qstr.convertStringBlockToLines(stringBlock);
var html = dp.qstr.appendBrToLines(lines);
callback(html); //never executes, cannot set breakpoint here in firebug
});
callback('<p>this is returned</p>');
},
getTestData: function() {
return 'test data';
}
}
}());
dp.qsys = {
loadDataFromExternalWebsite : function(callback) {
url = 'http://localhost/webs/dpjs/data/data.txt';
var json = '';
(function() {
var json = null;
$.post(url, {}, function(jsonString) {
callback(jsonString);
});
return json;
})();
}
};
dp.qstr = {
convertStringBlockToLines: function(block, trimLines) {
var trimLines = trimLines || true;
var lines = block.split(dp.qstr.NEW_LINE());
if(trimLines && lines.length > 0) {
for(x=0; x<lines.length; x++) {
lines[x] = lines[x].trim();
}
}
return lines;
},
NEW_LINE: function() {
return '\r\n';
},
appendBrToLines: function(lines) {
var r = '';
if(lines.length > 0) {
for(x=0; x<lines.length; x++) {
r += lines[x] + '<br/>';
}
}
return r;
}
};
</script>
</head>
<body>
<div id="content"></div>
</body>
</html>