KnockoutJS: How to color table cell (+fade away) - css

I'm discovering the awesome KnockoutJS library and I'm stuck on a feature I would like to implement:
Explanation
I have an array containing n lines of a type of object:
Html:
<tbody data-bind="foreach: indexItems">
<tr data-bind="click: $parent.UpdateInterfaceItems, css: { 'active-row' : $root.selecteditem() === $data }">
<td data-bind="text: param1"></td>
<td data-bind="text: param2"></td>
<td data-bind="text: param3"></td>
</tr>
</tbody>
Javascript:
function ViewModel() {
var self = this;
//Public Properties
self.selecteditem = ko.observable();
self.indexMats = ko.observableArray();
....
hub.client.receivedNewValue= function (param1Value, param2Value, param3Value)
{
var match = ko.utils.arrayFirst(vm.indexItems(), function (item) {
return item.param1() == param1Value;
});
if (match)
{
match.param1(param1Value);
match.param2(param2Value);
match.param3(param3Value);
}
}
}
Feature
Sometimes I want to update one row (on some values only) and I would like to highlight the modified cell with a color which would fade away. Is there any way to do that?
I've found out a quite similar question but it doesn't match my need (Knockout JS Update Color)
Thanks a lot

I have written a binding name highlight long time ago. Think that is smilar to what you need.
ko.bindingHandlers.highlight = {
update: function(element, valueAccessor) {
ko.toJS(valueAccessor());
var old = parseInt($(element).html(),10);
var current = parseInt(valueAccessor()(),10);
if ($(element).data("ko_init")) {
if(current < old) {
$(element).effect('highlight', {
color: '#AA0000'
}, 1000);
} else if (current>old ) {
$(element).effect('highlight', {
color: '#00AA00'
}, 1000);
}
}
else {
$(element).data("ko_init", true);
}
}};
function Table(rowCount, columnCount, headItems, initiliaze) {
var self = this;
var Cell = function(data, css, animate) {
var cellInstance = this;
this.data = ko.observable(data);
this.css = ko.observable(css);
this.animate = ko.observable(animate);
}
this.rowCount = ko.observable(rowCount);
this.columnCount = ko.observable(columnCount);
this.headItems = ko.observableArray(headItems);
this.rowsData = ko.observableArray();
if (initiliaze) {
for (var i = 0; i < rowCount; i++) {
var tmpArray = new Array();
for (var j = 0; j < columnCount; j++)
tmpArray.push(new Cell("0", "", ""));
self.rowsData.push(ko.observableArray(tmpArray));
}
}}
function ViewModel() {
var self = this;
this.table = new Table(5, 4, ["Name", "DT", "BID", "ASK"], true);
};
$(function() {
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
function changeData(x, y, data) {
viewModel.table.rowsData()[x]()[y].data(data);
}
setInterval(function() {
changeData(parseInt(Math.random(1000) * 5, 10), parseInt(Math.random(1000) * 4, 10), parseInt(Math.random(1000) * 10000, 10));
}, 1000);
})
Check out jsfiddle demo

Related

Lightbox2 rotate not working

Does anyone have a sample project for lightbox2 rotate? I have applied all the javascript and css for this example http://jsfiddle.net/pootie/EBLc7/
and the rotate button never seems to show. What am I missing please help me
HTML CODE:
<img src="http://grgichtran.com/code/img/car-seat.jpg" class="img-polaroid" style="width: 100px;"/>
JS CODE:
(function () {
var $, Lightbox, LightboxOptions;
$ = jQuery;
LightboxOptions = (function () {
function LightboxOptions() {
this.fadeDuration = 500;
this.fitImagesInViewport = true;
this.resizeDuration = 700;
this.showImageNumberLabel = true;
this.wrapAround = false;
}
LightboxOptions.prototype.albumLabel = function (curImageNum, albumSize) {
return "Image " + curImageNum + " of " + albumSize;
};
return LightboxOptions;
})();
Lightbox = (function () {
function Lightbox(options) {
this.options = options;
this.album = [];
this.currentImageIndex = void 0;
this.init();
}
Lightbox.prototype.init = function () {
this.enable();
return this.build();
};
Lightbox.prototype.enable = function () {
var _this = this;
return $('body').on('click', 'a[rel^=lightbox], area[rel^=lightbox], a[data-lightbox], area[data-lightbox]', function (e) {
_this.start($(e.currentTarget));
return false;
});
};
Lightbox.prototype.build = function () {
var _this = this;
$("<div id='lightboxOverlay' class='lightboxOverlay'></div><div id='lightbox' class='lightbox'><div class='lb-outerContainer'><div class='lb-container'><img class='lb-image' src='' /><div class='lb-nav'><a class='lb-prev' href='' ></a><a class='lb-next' href='' ></a></div><div class='lb-loader'><a class='lb-cancel'></a></div></div></div><div class='lb-dataContainer'><div class='lb-data'><div class='lb-details'><span class='lb-caption'></span><span class='lb-number'></span></div><div class='lb-closeContainer'><a class='lb-close'></a><a class='lb-rotate'></a></div></div></div></div>").appendTo($('body'));
this.$lightbox = $('#lightbox');
this.$overlay = $('#lightboxOverlay');
this.$outerContainer = this.$lightbox.find('.lb-outerContainer');
this.$container = this.$lightbox.find('.lb-container');
this.containerTopPadding = parseInt(this.$container.css('padding-top'), 10);
this.containerRightPadding = parseInt(this.$container.css('padding-right'), 10);
this.containerBottomPadding = parseInt(this.$container.css('padding-bottom'), 10);
this.containerLeftPadding = parseInt(this.$container.css('padding-left'), 10);
this.$overlay.hide().on('click', function () {
_this.end();
return false;
});
this.$lightbox.hide().on('click', function (e) {
if ($(e.target).attr('id') === 'lightbox') {
_this.end();
}
return false;
});
this.$outerContainer.on('click', function (e) {
if ($(e.target).attr('id') === 'lightbox') {
_this.end();
}
return false;
});
this.$lightbox.find('.lb-prev').on('click', function () {
if (_this.currentImageIndex === 0) {
_this.changeImage(_this.album.length - 1);
} else {
_this.changeImage(_this.currentImageIndex - 1);
}
return false;
});
this.$lightbox.find('.lb-next').on('click', function () {
if (_this.currentImageIndex === _this.album.length - 1) {
_this.changeImage(0);
} else {
_this.changeImage(_this.currentImageIndex + 1);
}
return false;
});
this.$lightbox.find('.lb-rotate').on('click', function () {
$cont = _this.$lightbox.find('.lb-outerContainer');
$image = _this.$lightbox.find('.lb-image');
if ($($cont).attr('angle') == null) {
$($cont).attr('angle', 0);
}
var value = Number($($cont).attr('angle'));
value += 90;
$($cont).rotate({
animateTo: value
});
$($cont).attr('angle', value);
return false;
});
return this.$lightbox.find('.lb-loader, .lb-close').on('click', function () {
_this.end();
return false;
});
};
Lightbox.prototype.start = function ($link) {
var $window, a, dataLightboxValue, i, imageNumber, left, top, _i, _j, _len, _len1, _ref, _ref1;
$(window).on("resize", this.sizeOverlay);
$('select, object, embed').css({
visibility: "hidden"
});
this.$overlay.width($(document).width()).height($(document).height()).fadeIn(this.options.fadeDuration);
this.album = [];
imageNumber = 0;
dataLightboxValue = $link.attr('data-lightbox');
if (dataLightboxValue) {
_ref = $($link.prop("tagName") + '[data-lightbox="' + dataLightboxValue + '"]');
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
a = _ref[i];
this.album.push({
link: $(a).attr('href'),
title: $(a).attr('title')
});
if ($(a).attr('href') === $link.attr('href')) {
imageNumber = i;
}
}
} else {
if ($link.attr('rel') === 'lightbox') {
this.album.push({
link: $link.attr('href'),
title: $link.attr('title')
});
} else {
_ref1 = $($link.prop("tagName") + '[rel="' + $link.attr('rel') + '"]');
for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
a = _ref1[i];
this.album.push({
link: $(a).attr('href'),
title: $(a).attr('title')
});
if ($(a).attr('href') === $link.attr('href')) {
imageNumber = i;
}
}
}
}
$window = $(window);
top = $window.scrollTop() + $window.height() / 10;
left = $window.scrollLeft();
this.$lightbox.css({
top: top + 'px',
left: left + 'px'
}).fadeIn(this.options.fadeDuration);
this.changeImage(imageNumber);
};
Lightbox.prototype.changeImage = function (imageNumber) {
var $image, preloader,
_this = this;
this.disableKeyboardNav();
$image = this.$lightbox.find('.lb-image');
this.sizeOverlay();
this.$overlay.fadeIn(this.options.fadeDuration);
$('.lb-loader').fadeIn('slow');
this.$lightbox.find('.lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption').hide();
this.$outerContainer.addClass('animating');
preloader = new Image();
preloader.onload = function () {
var $preloader, imageHeight, imageWidth, maxImageHeight, maxImageWidth, windowHeight, windowWidth;
$image.attr('src', _this.album[imageNumber].link);
$preloader = $(preloader);
$image.width(preloader.width);
$image.height(preloader.height);
if (_this.options.fitImagesInViewport) {
windowWidth = $(window).width();
windowHeight = $(window).height();
maxImageWidth = windowWidth - _this.containerLeftPadding - _this.containerRightPadding - 20;
maxImageHeight = windowHeight - _this.containerTopPadding - _this.containerBottomPadding - 110;
if ((preloader.width > maxImageWidth) || (preloader.height > maxImageHeight)) {
if ((preloader.width / maxImageWidth) > (preloader.height / maxImageHeight)) {
imageWidth = maxImageWidth;
imageHeight = parseInt(preloader.height / (preloader.width / imageWidth), 10);
$image.width(imageWidth);
$image.height(imageHeight);
} else {
imageHeight = maxImageHeight;
imageWidth = parseInt(preloader.width / (preloader.height / imageHeight), 10);
$image.width(imageWidth);
$image.height(imageHeight);
}
}
}
return _this.sizeContainer($image.width(), $image.height());
};
preloader.src = this.album[imageNumber].link;
this.currentImageIndex = imageNumber;
};
Lightbox.prototype.sizeOverlay = function () {
return $('#lightboxOverlay').width($(document).width()).height($(document).height());
};
Lightbox.prototype.sizeContainer = function (imageWidth, imageHeight) {
var newHeight, newWidth, oldHeight, oldWidth,
_this = this;
oldWidth = this.$outerContainer.outerWidth();
oldHeight = this.$outerContainer.outerHeight();
newWidth = imageWidth + this.containerLeftPadding + this.containerRightPadding;
newHeight = imageHeight + this.containerTopPadding + this.containerBottomPadding;
this.$outerContainer.animate({
width: newWidth,
height: newHeight
}, this.options.resizeDuration, 'swing');
setTimeout(function () {
_this.$lightbox.find('.lb-dataContainer').width(newWidth);
_this.$lightbox.find('.lb-prevLink').height(newHeight);
_this.$lightbox.find('.lb-nextLink').height(newHeight);
_this.showImage();
}, this.options.resizeDuration);
};
Lightbox.prototype.showImage = function () {
this.$lightbox.find('.lb-loader').hide();
this.$lightbox.find('.lb-image').fadeIn('slow');
this.updateNav();
this.updateDetails();
this.preloadNeighboringImages();
this.enableKeyboardNav();
};
Lightbox.prototype.updateNav = function () {
this.$lightbox.find('.lb-nav').show();
if (this.album.length > 1) {
if (this.options.wrapAround) {
this.$lightbox.find('.lb-prev, .lb-next').show();
} else {
if (this.currentImageIndex > 0) {
this.$lightbox.find('.lb-prev').show();
}
if (this.currentImageIndex < this.album.length - 1) {
this.$lightbox.find('.lb-next').show();
}
}
}
};
Lightbox.prototype.updateDetails = function () {
var _this = this;
if (typeof this.album[this.currentImageIndex].title !== 'undefined' && this.album[this.currentImageIndex].title !== "") {
this.$lightbox.find('.lb-caption').html(this.album[this.currentImageIndex].title).fadeIn('fast');
}
if (this.album.length > 1 && this.options.showImageNumberLabel) {
this.$lightbox.find('.lb-number').text(this.options.albumLabel(this.currentImageIndex + 1, this.album.length)).fadeIn('fast');
} else {
this.$lightbox.find('.lb-number').hide();
}
this.$outerContainer.removeClass('animating');
this.$lightbox.find('.lb-dataContainer').fadeIn(this.resizeDuration, function () {
return _this.sizeOverlay();
});
};
Lightbox.prototype.preloadNeighboringImages = function () {
var preloadNext, preloadPrev;
if (this.album.length > this.currentImageIndex + 1) {
preloadNext = new Image();
preloadNext.src = this.album[this.currentImageIndex + 1].link;
}
if (this.currentImageIndex > 0) {
preloadPrev = new Image();
preloadPrev.src = this.album[this.currentImageIndex - 1].link;
}
};
Lightbox.prototype.enableKeyboardNav = function () {
$(document).on('keyup.keyboard', $.proxy(this.keyboardAction, this));
};
Lightbox.prototype.disableKeyboardNav = function () {
$(document).off('.keyboard');
};
Lightbox.prototype.keyboardAction = function (event) {
var KEYCODE_ESC, KEYCODE_LEFTARROW, KEYCODE_RIGHTARROW, key, keycode;
KEYCODE_ESC = 27;
KEYCODE_LEFTARROW = 37;
KEYCODE_RIGHTARROW = 39;
keycode = event.keyCode;
key = String.fromCharCode(keycode).toLowerCase();
if (keycode === KEYCODE_ESC || key.match(/x|o|c/)) {
this.end();
} else if (key === 'p' || keycode === KEYCODE_LEFTARROW) {
if (this.currentImageIndex !== 0) {
this.changeImage(this.currentImageIndex - 1);
}
} else if (key === 'n' || keycode === KEYCODE_RIGHTARROW) {
if (this.currentImageIndex !== this.album.length - 1) {
this.changeImage(this.currentImageIndex + 1);
}
}
};
Lightbox.prototype.end = function () {
this.disableKeyboardNav();
$(window).off("resize", this.sizeOverlay);
this.$lightbox.fadeOut(this.options.fadeDuration);
this.$overlay.fadeOut(this.options.fadeDuration);
return $('select, object, embed').css({
visibility: "visible"
});
};
return Lightbox;
})();
$(function () {
var lightbox, options;
options = new LightboxOptions();
return lightbox = new Lightbox(options);
});
}).call(this);
I'm not sure what your question is; please allow me to confirm that after applying the code in your project,
the lightbox shows up properly, but rotate button doesn't
nothing special shows up. Neither lightbox, nor rotate button show up.
If your question is the first one, please check if the rotate button image (rotate.png) is placed in proper path. From the css file, this image should be put in img/ folder.
From this sample's css, rotate.png should be here:
background: url(../img/rotate.png) top right no-repeat;
On the other hand, if your question is second one, please check all files (js/css/images) exist and are in correct path, especially css and images.

chrome extension that count the number of times we visit a page

I'm looking around for an extension that count the number I visit a site daily, and I have edited an extension from store and it work perfectly
But the problem is when I put that site into an iframe, it's not counting anymore, somebody plz take a look and give me some advice here? many thanks
manifest.json
{
"background": {
"persistent": true,
"scripts": [ "jquery.js", "counter.js", "background.js" ]
},
"browser_action": {
"default_icon": "icon.png",
"default_popup": "counter.html"
},
"description": "Counter",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgrQn46/0KFBVFH0l9mKUXPOns5h0YMQ0isRXkB/GzK1h8JfvILDuxkIC7jbyePzMgbY0b8TO7L7FR3m4qcnPJZemz2yrGnHOkppaOWaAuyJm2cQeOul89qNPsC1GROoKfBmajag5OaOr02y4de3MEKSTubtjlO5crbg8xKnp7nHbqkeIq9MOMsEo0/uOQMqvixMnIAfPamUPOQfqmG2lUeo9UgTUoFBaxpf5VhgcuDcLHnkkSrzRrL0DoYeYFqyXwGmiCdvmwkWF+Eax/+s2xGemqMSUj0mrMxzz8KfoWuAWn9pcXYMEINSelIwS/x+wf+NWWmsCY0pV9yF54+vprQIDAQAB",
"manifest_version": 2,
"name": "counter",
"permissions": [ "tabs", "history", "background", "webNavigation", "http://*/*", "activeTab" ],
"update_url": "https://clients2.google.com/service/update2/crx",
"version": "0.4"
}
counter.js
$(document).ready(function(){
// Display day count
$('.day-count').text(countForToday());
// Display yesterday count
var yesterdayToday = new Date();
var yesterday = new Date(yesterdayToday.setDate(yesterdayToday.getDate() - 1));
var yesterdayString = dateStringForDate(yesterday);
var yesterdayCount = countForDay(yesterdayString);
$('.yesterday-count').text(yesterdayCount);
// Display last 7 days
var weeklyTotal = countForDaysFromToday(7);
$('.week-count').text(weeklyTotal);
// Display last 28 days
var monthlyTotal = countForDaysFromToday(28);
$('.month-count').text(monthlyTotal);
// Total
var total = 0;
for (var i = 0; i < localStorage.length; i++){
var key = localStorage.key(i);
if (key.indexOf("dayCount") > -1) {
var entry = JSON.parse(localStorage.getItem(key));
total += entry.length;
}
}
$('.all-count').text(total);
chrome.browserAction.setBadgeBackgroundColor({ color: '#3BAFDA' });
});
function countForToday() {
// Display day count
var today = new Date();
var todayString = dateStringForDate(today);
var todayCount = countForDay(todayString);
return todayCount;
}
function appendUrlForDay(pageUrl, dateString) {
// get
var currentUrls = urlsForDay(dateString);
// append
var found = false;
for(var i = 0; i < currentUrls.length; i++) {
if (currentUrls[i] == pageUrl) {
found = true;
break;
}
}
if (!found) {
currentUrls.push(pageUrl);
}
// set
localStorage.setItem("dayCount-" + dateString, JSON.stringify(currentUrls));
}
function dateStringForDate(dateObj) {
var month = dateObj.getUTCMonth() + 1;
var day = dateObj.getUTCDate();
var year = dateObj.getUTCFullYear();
var dateString = year + "/" + month + "/" + day;
return dateString;
}
function countForDaysFromToday(number_of_days) {
console.log(number_of_days);
var total = 0;
for (var i = 0; i < number_of_days; i++) {
var today = new Date();
var dayToLookup = new Date(today.setDate(today.getDate() - i));
var dayString = dateStringForDate(dayToLookup);
var dayCount = countForDay(dayString);
total += dayCount;
}
return total;
}
function urlsForDay(dateString) {
var item = localStorage.getItem("dayCount-" + dateString);
return JSON.parse(item);
}
function countForDay(dateString) {
var currentUrls = urlsForDay(dateString);
if (currentUrls != null) {
return currentUrls.length;
} else {
return 0;
}
}
background.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
// Get chrome history
chrome.history.search({text: '', maxResults: 1}, function(data) {
data.forEach(function(page) {
var dateObj = new Date(page.lastVisitTime);
var dateString = dateStringForDate(dateObj);
// Display last page visit
var pageUrl = page.url;
// Set value to 0 on first load
if (localStorage.getItem("dayCount-" + dateString) === null) {
localStorage.setItem("dayCount-" + dateString, JSON.stringify([]));
}
// Check if last page contains mysite.com
if (pageUrl.indexOf("mysite.com") > -1) {
appendUrlForDay(pageUrl, dateString);
}
chrome.browserAction.setBadgeText({ text: countForToday().toString() });
});
});
});
By default, your content script will only run in the top frame of a page. If you want it to run for all frames, you have to set all_frames to true in your manifest.
Google documents this here: https://developer.chrome.com/extensions/content_scripts (just search for all_frames on the page).

markers places are incorrect in KML google map

I made a map on Google Maps, I downloaded the KML file and used it in a map with sidebar. But the places of the markers are incorrect. All of them are below the correct places. The code is as below. Example page is on test page .If I use the simple KML layer example of Google, same errors occur.
<style type="text/css">
html, body, #map_canvas {
width: 750px;
height: 600px;
margin: 0;
padding: 0;
}
.infowindow * {font-size: 90%; margin: 0}
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">
</script>
<script type="text/javascript" src="http://geoxml3.googlecode.com/svn/branches/polys/geoxml3.js">
</script>
<script type="text/javascript" src="http://geoxml3.googlecode.com/svn/trunk/ProjectedOverlay.js">
</script>
<script type="text/javascript">
var geoXml = null;
var geoXmlDoc = null;
var map = null;
var myLatLng = null;
var myGeoXml3Zoom = true;
var sidebarHtml = "";
var infowindow = null;
var kmlLayer = null;
var filename = "europeancapitals.xml";
function MapTypeId2UrlValue(maptype) {
var urlValue = 'm';
switch(maptype){
case google.maps.MapTypeId.HYBRID: urlValue='h';
break;
case google.maps.MapTypeId.SATELLITE: urlValue='k';
break;
case google.maps.MapTypeId.TERRAIN: urlValue='t';
break;
default:
case google.maps.MapTypeId.ROADMAP: urlValue='m';
break;
}
return urlValue;
}
// ========== This function will create the "link to this page"
function makeLink() {
// var a="http://www.geocodezip.com/v3_MW_example_linktothis.html"
var url = window.location.pathname;
var a = url.substring(url.lastIndexOf('/')+1)
+ "?lat=" + map.getCenter().lat().toFixed(6)
+ "&lng=" + map.getCenter().lng().toFixed(6)
+ "&zoom=" + map.getZoom()
+ "&type=" + MapTypeId2UrlValue(map.getMapTypeId());
if (filename != "europeancapitals.xml") a += "&filename="+filename;
document.getElementById("link").innerHTML = '<a href="' +a+ '">Link to this page<\/a>';
}
function initialize() {
myLatLng = new google.maps.LatLng(46,14);
// these set the initial center, zoom and maptype for the map
// if it is not specified in the query string
var lat = 46;
var lng = 14;
var zoom = 8;
var maptype = google.maps.MapTypeId.ROADMAP;
// If there are any parameters at eh end of the URL, they will be in location.search
// looking something like "?marker=3"
// skip the first character, we are not interested in the "?"
var query = location.search.substring(1);
// split the rest at each "&" character to give a list of "argname=value" pairs
var pairs = query.split("&");
for (var i=0; i<pairs.length; i++) {
// break each pair at the first "=" to obtain the argname and value
var pos = pairs[i].indexOf("=");
var argname = pairs[i].substring(0,pos).toLowerCase();
var value = pairs[i].substring(pos+1).toLowerCase();
// process each possible argname - use unescape() if theres any chance of spaces
if (argname == "id") {id = unescape(value);}
if (argname == "filename") {filename = unescape(value);}
if (argname == "marker") {index = parseFloat(value);}
if (argname == "lat") {lat = parseFloat(value);}
if (argname == "lng") {lng = parseFloat(value);}
if (argname == "zoom") {
zoom = parseInt(value);
myGeoXml3Zoom = false;
}
if (argname == "type") {
// from the v3 documentation 8/24/2010
// HYBRID This map type displays a transparent layer of major streets on satellite images.
// ROADMAP This map type displays a normal street map.
// SATELLITE This map type displays satellite images.
// TERRAIN This map type displays maps with physical features such as terrain and vegetation.
if (value == "m") {maptype = google.maps.MapTypeId.ROADMAP;}
if (value == "k") {maptype = google.maps.MapTypeId.SATELLITE;}
if (value == "h") {maptype = google.maps.MapTypeId.HYBRID;}
if (value == "t") {maptype = google.maps.MapTypeId.TERRAIN;}
}
}
if (!isNaN(lat) && !isNaN(lng)) {
myLatLng = new google.maps.LatLng(lat, lng);
}
var myOptions = {
zoom: zoom,
center: myLatLng,
// zoom: 5,
// center: myLatlng,
mapTypeId: maptype
};
map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
infowindow = new google.maps.InfoWindow({});
geoXml = new geoXML3.parser({
map: map,
infoWindow: infowindow,
singleInfoWindow: true,
zoom: myGeoXml3Zoom,
markerOptions: {optimized: false},
afterParse: useTheData
});
geoXml.parse(filename);
google.maps.event.addListener(map, "bounds_changed", makeSidebar);
google.maps.event.addListener(map, "center_changed", makeSidebar);
google.maps.event.addListener(map, "zoom_changed", makeSidebar);
// Make the link the first time when the page opens
makeLink();
// Make the link again whenever the map changes
google.maps.event.addListener(map, 'maptypeid_changed', makeLink);
google.maps.event.addListener(map, 'center_changed', makeLink);
google.maps.event.addListener(map, 'bounds_changed', makeLink);
google.maps.event.addListener(map, 'zoom_changed', makeLink);
};
function kmlPgClick(pm) {
if (geoXml.docs[0].placemarks[pm].polygon.getMap()) {
google.maps.event.trigger(geoXmlDoc.placemarks[pm].polygon,"click");
} else {
geoXmlDoc.placemarks[pm].polygon.setMap(map);
google.maps.event.trigger(geoXmlDoc.placemarks[pm].polygon,"click");
}
}
function kmlPlClick(pm) {
if (geoXml.docs[0].placemarks[pm].polyline.getMap()) {
google.maps.event.trigger(geoXmlDoc.placemarks[pm].polyline,"click");
} else {
geoXmlDoc.placemarks[pm].polyline.setMap(map);
google.maps.event.trigger(geoXmlDoc.placemarks[pm].polyline,"click");
}
}
function kmlClick(pm) {
if (geoXml.docs[0].placemarks[pm].marker.getMap()) {
google.maps.event.trigger(geoXml.docs[0].placemarks[pm].marker,"click");
} else {
geoXmlDoc.placemarks[pm].marker.setMap(map);
google.maps.event.trigger(geoXmlDoc.placemarks[pm].marker,"click");
}
}
function kmlShowPlacemark(pm) {
if (geoXmlDoc.placemarks[pm].polygon) {
map.fitBounds(geoXmlDoc.placemarks[pm].polygon.bounds);
} else if (geoXmlDoc.placemarks[pm].polyline) {
map.fitBounds(geoXmlDoc.placemarks[pm].polyline.bounds);
} else if (geoXmlDoc.placemarks[pm].marker) {
map.setCenter(geoXmlDoc.placemarks[pm].marker.getPosition());
}
for (var i=0;i<geoXmlDoc.placemarks.length;i++) {
var placemark = geoXmlDoc.placemarks[i];
if (i == pm) {
if (placemark.polygon) placemark.polygon.setMap(map);
if (placemark.polyline) placemark.polyline.setMap(map);
if (placemark.marker) placemark.marker.setMap(map);
} else {
if (placemark.polygon) placemark.polygon.setMap(null);
if (placemark.polyline) placemark.polyline.setMap(null);
if (placemark.marker) placemark.marker.setMap(null);
}
}
}
var highlightOptions = {fillColor: "#FFFF00", strokeColor: "#000000", fillOpacity: 0.9, strokeWidth: 10};
var highlightLineOptions = {strokeColor: "#FFFF00", strokeWidth: 10};
function kmlHighlightPoly(pm) {
for (var i=0;i<geoXmlDoc.placemarks.length;i++) {
var placemark = geoXmlDoc.placemarks[i];
if (i == pm) {
if (placemark.polygon) placemark.polygon.setOptions(highlightOptions);
if (placemark.polyline) placemark.polyline.setOptions(highlightLineOptions);
} else {
if (placemark.polygon) placemark.polygon.setOptions(placemark.polygon.normalStyle);
if (placemark.polyline) placemark.polyline.setOptions(placemark.polyline.normalStyle);
}
}
}
function kmlUnHighlightPoly(pm) {
for (var i=0;i<geoXmlDoc.placemarks.length;i++) {
if (i == pm) {
var placemark = geoXmlDoc.placemarks[i];
if (placemark.polygon) placemark.polygon.setOptions(placemark.polygon.normalStyle);
if (placemark.polyline) placemark.polyline.setOptions(placemark.polyline.normalStyle);
}
}
}
function showAll() {
map.fitBounds(geoXmlDoc.bounds);
for (var i=0;i<geoXmlDoc.placemarks.length;i++) {
var placemark = geoXmlDoc.placemarks[i];
if (placemark.polygon) placemark.polygon.setMap(map);
if (placemark.polyline) placemark.polyline.setMap(map);
if (placemark.marker) placemark.marker.setMap(map);
}
}
function highlightPoly(poly, polynum) {
// poly.setOptions({fillColor: "#0000FF", strokeColor: "#0000FF", fillOpacity: 0.3}) ;
google.maps.event.addListener(poly,"mouseover",function() {
var rowElem = document.getElementById('row'+polynum);
if (rowElem) rowElem.style.backgroundColor = "#FFFA5E";
if (geoXmlDoc.placemarks[polynum].polygon) {
poly.setOptions(highlightOptions);
} else if (geoXmlDoc.placemarks[polynum].polyline) {
poly.setOptions(highlightLineOptions);
}
});
google.maps.event.addListener(poly,"mouseout",function() {
var rowElem = document.getElementById('row'+polynum);
if (rowElem) rowElem.style.backgroundColor = "#FFFFFF";
poly.setOptions(poly.normalStyle);
});
}
// == rebuilds the sidebar to match the markers currently displayed ==
function makeSidebarPolygonEntry(i) {
var name = geoXmlDoc.placemarks[i].name;
if (!name || (name.length == 0)) name = "polygon #"+i;
// alert(name);
sidebarHtml += '<tr id="row'+i+'"><td onmouseover="kmlHighlightPoly('+i+');" onmouseout="kmlUnHighlightPoly('+i+');">'+name+' - show</td></tr>';
}
function makeSidebarPolylineEntry(i) {
var name = geoXmlDoc.placemarks[i].name;
if (!name || (name.length == 0)) name = "polyline #"+i;
// alert(name);
sidebarHtml += '<tr id="row'+i+'"><td onmouseover="kmlHighlightPoly('+i+');" onmouseout="kmlUnHighlightPoly('+i+');">'+name+' - show</td></tr>';
}
function makeSidebarEntry(i) {
var name = geoXmlDoc.placemarks[i].name;
if (!name || (name.length == 0)) name = "marker #"+i;
// alert(name);
sidebarHtml += '<tr id="row'+i+'"><td>'+name+'</td></tr>';
}
function makeSidebar() {
sidebarHtml = '<table><tr><td>Show All</td></tr>';
var currentBounds = map.getBounds();
// if bounds not yet available, just use the empty bounds object;
if (!currentBounds) currentBounds=new google.maps.LatLngBounds();
if (geoXmlDoc) {
for (var i=0; i<geoXmlDoc.placemarks.length; i++) {
if (geoXmlDoc.placemarks[i].polygon) {
if (currentBounds.intersects(geoXmlDoc.placemarks[i].polygon.bounds)) {
makeSidebarPolygonEntry(i);
}
}
if (geoXmlDoc.placemarks[i].polyline) {
if (currentBounds.intersects(geoXmlDoc.placemarks[i].polyline.bounds)) {
makeSidebarPolylineEntry(i);
}
}
if (geoXmlDoc.placemarks[i].marker) {
if (currentBounds.contains(geoXmlDoc.placemarks[i].marker.getPosition())) {
makeSidebarEntry(i);
}
}
}
}
sidebarHtml += "</table>";
document.getElementById("sidebar").innerHTML = sidebarHtml;
}
function useTheData(doc){
var currentBounds = map.getBounds();
if (!currentBounds) currentBounds=new google.maps.LatLngBounds();
// Geodata handling goes here, using JSON properties of the doc object
sidebarHtml = '<table><tr><td>Show All</td></tr>';
// var sidebarHtml = '<table>';
geoXmlDoc = doc[0];
for (var i = 0; i < geoXmlDoc.placemarks.length; i++) {
// console.log(doc[0].markers[i].title);
var placemark = geoXmlDoc.placemarks[i];
if (placemark.polygon) {
if (currentBounds.intersects(placemark.polygon.bounds)) {
makeSidebarPolygonEntry(i);
}
var normalStyle = {
strokeColor: placemark.polygon.get('strokeColor'),
strokeWeight: placemark.polygon.get('strokeWeight'),
strokeOpacity: placemark.polygon.get('strokeOpacity'),
fillColor: placemark.polygon.get('fillColor'),
fillOpacity: placemark.polygon.get('fillOpacity')
};
placemark.polygon.normalStyle = normalStyle;
highlightPoly(placemark.polygon, i);
}
if (placemark.polyline) {
if (currentBounds.intersects(placemark.polyline.bounds)) {
makeSidebarPolylineEntry(i);
}
var normalStyle = {
strokeColor: placemark.polyline.get('strokeColor'),
strokeWeight: placemark.polyline.get('strokeWeight'),
strokeOpacity: placemark.polyline.get('strokeOpacity')
};
placemark.polyline.normalStyle = normalStyle;
highlightPoly(placemark.polyline, i);
}
if (placemark.marker) {
if (currentBounds.contains(placemark.marker.getPosition())) {
makeSidebarEntry(i);
}
}
/* doc[0].markers[i].setVisible(false); */
}
sidebarHtml += "</table>";
document.getElementById("sidebar").innerHTML = sidebarHtml;
};
function hide_kml(){
geoXml.hideDocument();
}
function unhide_kml(){
geoXml.showDocument();
}
function reload_kml(){
geoXml.hideDocument();
delete geoXml;
geoXml = new geoXML3.parser({
map: map,
singleInfoWindow: true,
afterParse: useTheData
});
geoXml.parse(filename);
}
function hide_markers_kml(){
for (var i=0;i<geoXmlDoc.markers.length;i++) {
geoXmlDoc.markers[i].setVisible(false);
}
}
function unhide_markers_kml(){
for (var i=0;i<geoXmlDoc.markers.length;i++) {
geoXmlDoc.markers[i].setVisible(true);
}
}
function hide_polys_kml(){
for (var i=0;i<geoXmlDoc.gpolylines.length;i++) {
geoXmlDoc.gpolylines[i].setMap(null);
}
}
function unhide_polys_kml(){
for (var i=0;i<geoXmlDoc.gpolylines.length;i++) {
geoXmlDoc.gpolylines[i].setMap(map);
}
}
function load_kmlLayer() {
kmlLayer = new google.maps.KmlLayer(filename);
google.maps.event.addListener(kmlLayer, "status_changed", function() {
document.getElementById('kmlstatus').innerHTML = "Kml Status:"+kmlLayer.getStatus();
});
kmlLayer.setMap(map);
}
function hide_kmlLayer() {
kmlLayer.setMap(null);
}
function show_kmlLayer() {
kmlLayer.setMap(map);
}
</script>
</head>
<body onload="initialize()">
<h4>Reading a KML file with Google Maps JavaScript API Version 3 and geoxml3.</h4>
<!-- <button onclick="hide_polys_kml();">hide polylines</button>
<button onclick="unhide_polys_kml();">unhide polylines</button> -->
<button onclick="hide_kml();">hide</button>
<button onclick="unhide_kml();">unhide</button>
<button onclick="hide_markers_kml();">hide markers</button>
<button onclick="unhide_markers_kml();">show markers</button>
<button onclick="load_kmlLayer();">load kmlLayer</button>
<button onclick="hide_kmlLayer();">hide kmlLayer</button>
<button onclick="show_kmlLayer();">show kmlLayer</button>
<!-- <button onclick="reload_kml();">reload</button> -->
<table style="width:100%;"><tr><td>
<div id="map_canvas">
</div>
</td><td>
<div id="sidebar" style="width:300px;height:600px; overflow:auto"></div>
</td></tr>
<tr><td colspan="2"> <div id="link"></div></td></tr>
</table>
<div id="map_text">
</div>
<div id="kmlstatus"></div>
</body>
</html>
You need to set the "hotSpot" for your custom icons.
<hotSpot x="0.5" y="0.5" xunits="fraction" yunits="fraction">
Specifies the position within the Icon that is "anchored" to the specified in the Placemark. The x and y
values can be specified in three different ways: as pixels ("pixels"), as fractions of the icon ("fraction"), or as
inset pixels ("insetPixels"), which is an offset in pixels from the upper right corner of the icon. The x and y
positions can be specified in different ways—for example, x can be in pixels and y can be a fraction. The origin of > the coordinate system is in the lower left corner of the icon.
The hotSpot tag is (now) supported (correctly) in the kmz branch of geoxml3:
working example

Breeze.js query does not update knockout view

I am querying data via breeze.js which works fine the first time. The second time the view isn't updated.
html
<a id="linkQDate">Order by Newest</a>
<a id="linkQScore">Order by Score</a>
<div id="questionWrapper">
<ul data-bind="foreach: results">
<li>
<strong><span data-bind="text: Score"></span></strong>
<span data-bind="text: Titel"></span>
</li>
</ul>
</DIV>
js
$(document).ready(function () {
var manager = new breeze.EntityManager('/breeze/dbentities');
var isApplied = false;
var dmodel;
$("#linkQDate").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Date");
manager.executeQuery(query).then(querySucceeded);
function querySucceeded(data) {
dmodel = data;
if (!isApplied) {
ko.applyBindings(dmodel, $("#questionWrapper")[0]);
isApplied = true;
}
}
});
$("#linkQScore").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Score");
manager.executeQuery(query).then(querySucceeded);
function querySucceeded(data) {
dmodel = data;
if (!isApplied) {
ko.applyBindings(dmodel, $("#questionWrapper")[0]);
isApplied = true;
}
}
});
});
If you just using plain JS objects it will not work. Because it does not know when underlying data changes. Use mapping plugin for this to work:
$(document).ready(function () {
var manager = new breeze.EntityManager('/breeze/dbentities');
var isApplied = false;
var dmodel;
function querySucceeded(data) {
if (!isApplied) {
dmodel = ko.mapping.fromJS(data);
ko.applyBindings(dmodel, $("#questionWrapper")[0]);
isApplied = true;
} else {
ko.mapping.fromJS(data, dmodel);
}
}
$("#linkQDate").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Date");
manager.executeQuery(query).then(querySucceeded);
});
$("#linkQScore").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Score");
});
});
Working code from Tomas without mappings. It is much faster:
$(document).ready(function () {
var manager = new breeze.EntityManager('/breeze/dbentities');
var isApplied = false;
var dmodel = { results: ko.observableArray() };
function queryFailed(data) {
console.log(data);
}
function querySucceeded(data) {
if (!isApplied) {
for (var i = 0; i < data.results.length; i++) {
dmodel.results.push(data.results[i]);
}
ko.applyBindings(dmodel, $("#questionWrapper")[0]);
isApplied = true;
} else {
dmodel.results.removeAll();
for (var i = 0; i < data.results.length; i++) {
dmodel.results.push(data.results[i]);
}
}
}
$("#linkQDate").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Date");
manager.executeQuery(query).then(querySucceeded).fail(queryFailed);;
});
$("#linkQScore").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Score");
manager.executeQuery(query).then(querySucceeded).fail(queryFailed);;
});
});

Special binding in knockout that renders one template in another

I am trying to solve a problem of rendering one template in context of another template with knockout. The outer template doesn't know and shouldn't care about the inner template and its view model. All it cares about is it's own template, a place to embed the inner template passing the name of it and its view model.
So ideally I wish I know how to implement the following binding:
<script type="text/html" id="outerTemplate">
<div class="outer-template" data-bind="here: {}"></div>
</script>
<!-- ko nested: { to: 'outerTemplate', data: { name: 'I am an inner view model' } } -->
<div class="inner-template" data-bind="text: name"></div>
<!-- /ko -->
If anyone knew the knockout well enough to easily outline such kind of binding I would greatly appreciate it.
UPDATE: The feature request was proposed: https://github.com/knockout/knockout/issues/1251
The template binding allows you to dynamically select the template name to use, so you can do something like:
<script id="outer" type="text/html">
<h2>Outer</h2>
<div data-bind="template: { name: tmplName, data: data }"></div>
</script>
<script id="inner" type="text/html">
<h3>Inner</h3>
<input data-bind="value: name" />
</script>
<div data-bind="template: 'outer'"></div>
In this case the view model would look like:
var vm = {
tmplName: 'inner',
data: {
name: ko.observable("Bob")
}
};
ko.applyBindings(vm);
The view model could be structured however you want. The key is just that you are passing the template name and data into the template binding.
Sample: http://jsfiddle.net/rniemeyer/LHhc8/
There is a working example I made myself: http://jsfiddle.net/m34wp/4/
var templateComputedDomDataKey = '__ko__templateComputedDomDataKey__';
function disposeOldComputedAndStoreNewOne(element, newComputed) {
var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
if(oldComputed && (typeof (oldComputed.dispose) == 'function')) {
oldComputed.dispose();
}
ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
}
function makeArray(arrayLikeObject) {
var result = [];
for(var i = 0, j = arrayLikeObject.length; i < j; i++) {
result.push(arrayLikeObject[i]);
}
;
return result;
}
function moveCleanedNodesToContainerElement(nodes) {
var nodesArray = makeArray(nodes);
var container = document.createElement('div');
for(var i = 0, j = nodesArray.length; i < j; i++) {
container.appendChild(ko.cleanNode(nodesArray[i]));
}
return container;
}
ko.bindingHandlers['nested'] = {
'init': function (element, valueAccessor) {
var elementType = 1;
var commentType = 8;
var bindingValue = ko.utils.unwrapObservable(valueAccessor());
if(element.nodeType == elementType || element.nodeType == commentType) {
// It's an anonymous template - store the element contents, then clear the element
var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element);
var container = moveCleanedNodesToContainerElement(templateNodes);
new ko.templateSources.anonymousTemplate(element)['nodes'](container);
}
return {
'controlsDescendantBindings': true
};
},
'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var options = ko.utils.unwrapObservable(valueAccessor());
var outerTemplateName = options['to'];
var dataValue = ko.utils.unwrapObservable(options['data']) || viewModel;
var innerContext = bindingContext['createChildContext'](dataValue);
innerContext.innerTemplateElement = element;
var templateComputed = ko.renderTemplate(outerTemplateName, innerContext, options, element);
disposeOldComputedAndStoreNewOne(element, templateComputed);
}
};
ko.bindingHandlers['here'] = {
'init': function (element, valueAccessor) {
return {
'controlsDescendantBindings': true
};
},
'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var templateElement = bindingContext.innerTemplateElement;
if(viewModel != null) {
var innerContext = bindingContext['createChildContext'](viewModel);
var templateComputed = ko.renderTemplate(templateElement, innerContext, {
}, element);
disposeOldComputedAndStoreNewOne(element, templateComputed);
} else {
}
}
};
ko.virtualElements.allowedBindings['nested'] = true;

Resources