cordova.define("cordova-plugin-googlemaps.HtmlInfoWindow", function(require, exports, module) {
var utils = require('cordova/utils'),
event = require('./event'),
BaseClass = require('./BaseClass');
/*****************************************************************************
* HTMLInfoWindow Class
*****************************************************************************/
var HTMLInfoWindow = function () {
var self = this;
BaseClass.apply(self);
var callbackTable = {};
var listenerMgr = {
one: function (target, eventName, callback) {
callbackTable[target.hashCode] = callbackTable[target.hashCode] || {};
callbackTable[target.hashCode][eventName] = callbackTable[target.hashCode][eventName] || [];
callbackTable[target.hashCode][eventName].push(callback);
target.one.call(target, eventName, callback);
},
on: function (target, eventName, callback) {
callbackTable[target.hashCode] = callbackTable[target.hashCode] || {};
callbackTable[target.hashCode][eventName] = callbackTable[target.hashCode][eventName] || [];
callbackTable[target.hashCode][eventName].push(callback);
target.on.call(target, eventName, callback);
},
bindTo: function (srcObj, srcField, dstObj, dstField, noNotify) {
var eventName = srcField + '_changed';
dstField = dstField || srcField;
var callback = function (oldValue, newValue) {
dstObj.set(dstField, newValue, noNotify);
};
callbackTable[dstObj.hashCode] = callbackTable[dstObj.hashCode] || {};
callbackTable[dstObj.hashCode][eventName] = callbackTable[dstObj.hashCode][eventName] || [];
callbackTable[dstObj.hashCode][eventName].push(callback);
srcObj.on.call(srcObj, eventName, callback);
},
off: function (target, eventName) {
if (!target || !eventName ||
!(target.hashCode in callbackTable) ||
!(eventName in callbackTable[target.hashCode])) {
return;
}
callbackTable[target.hashCode][eventName].forEach(function (listener) {
target.off.call(target, eventName, listener);
});
delete callbackTable[target.hashCode][eventName];
}
};
Object.defineProperty(self, '_hook', {
value: listenerMgr,
writable: false
});
var frame = document.createElement('div');
frame.style.overflow = 'visible';
frame.style.position = 'absolute';
frame.style.display = 'inline-block';
frame.classList.add('pgm-html-info-frame');
self.set('frame', frame);
var anchorDiv = document.createElement('div');
anchorDiv.setAttribute('class', 'pgm-anchor');
anchorDiv.style.overflow = 'visible';
anchorDiv.style.position = 'absolute';
anchorDiv.style['z-index'] = 0;
anchorDiv.style.width = '0 !important';
anchorDiv.style.height = '0 !important';
//anchorDiv.style.border = '1px solid green';
//anchorDiv.style.backgroundColor = 'rgba(125, 125, 255, 0.5)';
anchorDiv.style.transition = 'transform 0s ease';
anchorDiv.style['will-change'] = 'transform';
anchorDiv.style['-webkit-backface-visibility'] = 'hidden';
anchorDiv.style['-webkit-perspective'] = 1000;
anchorDiv.style['-webkit-transition'] = '-webkit-transform 0s ease';
anchorDiv.appendChild(frame);
self.set('anchor', anchorDiv);
var contentBox = document.createElement('div');
contentBox.style.display = 'inline-block';
contentBox.style.padding = '5px';
contentBox.style.boxSizing = 'content-box';
contentBox.classList.add('pgm-html-info-content-box');
var contentFrame = document.createElement('div');
contentFrame.style.display = 'block';
contentFrame.style.position = 'relative';
contentFrame.style.backgroundColor = 'white';
contentFrame.style.border = '1px solid rgb(204, 204, 204)';
contentFrame.style.left = '0px';
contentFrame.style.right = '0px';
contentFrame.style.zIndex = '1'; // In order to set higher depth than the map div certainly
contentFrame.style.overflow = 'hidden';
contentFrame.classList.add('pgm-html-info-content-frame');
frame.appendChild(contentFrame);
contentFrame.appendChild(contentBox);
var tailFrame = document.createElement('div');
tailFrame.style.position = 'relative';
tailFrame.style.top = '-1px';
tailFrame.style.zIndex = 100;
tailFrame.classList.add('pgm-html-info-tail-frame');
frame.appendChild(tailFrame);
var tailLeft = document.createElement('div');
/*
tailLeft.style.position = 'absolute';
tailLeft.style.marginLeft = '-15px';
tailLeft.style.left = '50%';
tailLeft.style.top = '0px';
tailLeft.style.height = '15px';
tailLeft.style.width = '16px';
tailLeft.style.overflow = 'hidden';
tailLeft.style.borderWidth = '0px';
*/
tailLeft.classList.add('pgm-html-info-tail-left');
tailLeft.style.position = 'absolute';
tailLeft.style.left = '50%';
tailLeft.style.height = '0px';
tailLeft.style.width = '0px';
tailLeft.style.marginLeft = '-15px';
tailLeft.style.borderWidth = '15px 15px 0px';
tailLeft.style.borderColor = 'rgb(204, 204, 204) transparent transparent';
tailLeft.style.borderStyle = 'solid';
tailFrame.appendChild(tailLeft);
/*
var tailLeftCover = document.createElement('div');
tailLeftCover.style.position = 'absolute';
tailLeftCover.style.backgroundColor = 'white';
tailLeftCover.style.transform = 'skewX(45deg)';
tailLeftCover.style.transformOrigin = '0px 0px 0px';
tailLeftCover.style.left = '0px';
tailLeftCover.style.height = '15px';
tailLeftCover.style.width = '15px';
tailLeftCover.style.top = '0px';
tailLeftCover.style.zIndex = 1;
tailLeftCover.style.borderLeft = '1px solid rgb(204, 204, 204)';
tailLeft.classList.add('pgm-html-info-tail-left-cover');
tailLeft.appendChild(tailLeftCover);
*/
var tailRight = document.createElement('div');
/*
tailRight.style.position = 'absolute';
tailRight.style.left = '50%';
tailRight.style.top = '0px';
tailRight.style.height = '15px';
tailRight.style.width = '16px';
tailRight.style.overflow = 'hidden';
tailRight.style.borderWidth = '0px';
*/
tailRight.style.position = 'absolute';
tailRight.style.left = '50%';
tailRight.style.height = '0px';
tailRight.style.width = '0px';
tailRight.style.marginLeft = '-14px';
tailRight.style.borderTopWidth = '14px';
tailRight.style.borderLeftWidth = '14px';
tailRight.style.borderRightWidth = '14px';
tailRight.style.borderColor = 'rgb(255, 255, 255) transparent transparent';
tailRight.style.borderStyle = 'solid';
tailRight.classList.add('pgm-html-info-tail-right');
tailFrame.appendChild(tailRight);
/*
var tailRightCover = document.createElement('div');
tailRightCover.style.position = 'absolute';
tailRightCover.style.backgroundColor = 'white';
tailRightCover.style.transform = 'skewX(-45deg)';
tailRightCover.style.transformOrigin = '0px 0px 0px';
tailRightCover.style.left = '0px';
tailRightCover.style.height = '15px';
tailRightCover.style.width = '15px';
tailRightCover.style.top = '0px';
tailRightCover.style.zIndex = 2;
tailRightCover.style.borderRight = '1px solid rgb(204, 204, 204)';
tailRightCover.classList.add('pgm-html-info-tail-right-cover');
tailRight.appendChild(tailRightCover);
*/
var eraseBorder = document.createElement('div');
eraseBorder.style.position = 'absolute';
eraseBorder.style.zIndex = 3;
eraseBorder.style.backgroundColor = 'white';
eraseBorder.style.width = '27px';
eraseBorder.style.height = '2px';
eraseBorder.style.top = '-1px';
eraseBorder.style.left = '50%';
eraseBorder.style.marginLeft = '-13px';
eraseBorder.classList.add('pgm-html-info-tail-erase-border');
tailFrame.appendChild(eraseBorder);
var calculate = function (marker) {
//var marker = self.get('marker');
var map = marker.getMap();
var div = map.getDiv();
var frame = self.get('frame');
var contentFrame = frame.firstChild;
var contentBox = contentFrame.firstChild;
contentBox.style.minHeight = '50px';
contentBox.style.width = 'auto';
contentBox.style.height = 'auto';
contentBox.style.padding = '5px';
var content = self.get('content');
if (typeof content === 'string') {
contentBox.style.whiteSpace = 'pre-wrap';
contentBox.innerHTML = content;
} else {
if (!content) {
contentBox.innerText = '';
} else if (content.nodeType === 1) {
contentBox.innerHTML = '';
contentBox.appendChild(content);
} else {
contentBox.innerText = content;
}
}
var cssOptions = self.get('cssOptions');
if (cssOptions && typeof cssOptions === 'object') {
var keys = Object.keys(cssOptions);
keys.forEach(function (key) {
contentBox.style.setProperty(key, cssOptions[key]);
});
}
// Insert the contents to this HTMLInfoWindow
if (!anchorDiv.parentNode) {
map._layers.info.appendChild(anchorDiv);
}
// Adjust the HTMLInfoWindow size
var contentsWidth = contentBox.offsetWidth + 10; // padding 5px x 2
var contentsHeight = contentBox.offsetHeight;
self.set('contentsHeight', contentsHeight);
contentFrame.style.width = contentsWidth + 'px';
contentFrame.style.height = contentsHeight + 'px';
frame.style.width = contentsWidth + 'px';
frame.style.height = (contentsHeight + 15) + 'px';
if (contentBox.offsetWidth > div.offsetWidth * 0.9) {
contentBox.style.width = (div.offsetWidth * 0.9) + 'px';
}
contentBox.style.width = '100%';
contentBox.style.height = '100%';
contentBox.style.padding = '5px 17px 17px 5px';
self.set('contentsWidth', contentsWidth);
var infoOffset = {
x: 31,
y: 31
};
var iconSize = {
width: 62,
height: 110
};
// If there is no specification with `anchor` property,
// the values {x: 0.5, y: 1} are specified by native APIs.
// For the case, anchor values are {x: 0} in JS.
var anchor = {
x: 15,
y: 15
};
var icon = marker.get('icon');
if (typeof icon === 'object') {
if (typeof icon.url === 'string' && icon.url.indexOf('data:image/') === 0) {
var img = document.createElement('img');
img.src = icon.url;
iconSize.width = img.width;
iconSize.height = img.height;
}
if (typeof icon.size === 'object') {
iconSize.width = icon.size.width;
iconSize.height = icon.size.height;
}
if (Array.isArray(icon.anchor)) {
anchor.x = icon.anchor[0];
anchor.y = icon.anchor[1];
}
}
var infoWindowAnchor = marker.get('infoWindowAnchor');
if (utils.isArray(infoWindowAnchor)) {
infoOffset.x = infoWindowAnchor[0];
infoOffset.y = infoWindowAnchor[1];
}
infoOffset.x = infoOffset.x / iconSize.width;
infoOffset.x = infoOffset.x > 1 ? 1 : infoOffset.x;
infoOffset.x = infoOffset.x < 0 ? 0 : infoOffset.x;
infoOffset.y = infoOffset.y / iconSize.height;
infoOffset.y = infoOffset.y > 1 ? 1 : infoOffset.y;
infoOffset.y = infoOffset.y < 0 ? 0 : infoOffset.y;
infoOffset.y *= iconSize.height;
infoOffset.x *= iconSize.width;
anchor.x = anchor.x / iconSize.width;
anchor.x = anchor.x > 1 ? 1 : anchor.x;
anchor.x = anchor.x < 0 ? 0 : anchor.x;
anchor.y = anchor.y / iconSize.height;
anchor.y = anchor.y > 1 ? 1 : anchor.y;
anchor.y = anchor.y < 0 ? 0 : anchor.y;
anchor.y *= iconSize.height;
anchor.x *= iconSize.width;
//console.log('contentsSize = ' + contentsWidth + ', ' + contentsHeight);
//console.log('iconSize = ' + iconSize.width + ', ' + iconSize.height);
//console.log('infoOffset = ' + infoOffset.x + ', ' + infoOffset.y);
//var frameBorder = parseInt(common.getStyle(contentFrame, 'border-left-width').replace(/[^\d]/g, ''), 10);
//var offsetX = (contentsWidth + frameBorder + anchor.x ) * 0.5 + (iconSize.width / 2 - infoOffset.x);
//var offsetY = contentsHeight + anchor.y - (frameBorder * 2) - infoOffset.y + 15;
var offsetX = -(iconSize.width / 2) - (cordova.platformId === 'android' ? 1 : 0);
var offsetY = -iconSize.height - (cordova.platformId === 'android' ? 1 : 0);
anchorDiv.style.width = iconSize.width + 'px';
anchorDiv.style.height = iconSize.height + 'px';
self.set('offsetX', offsetX);
self.set('offsetY', offsetY);
frame.style.bottom = (iconSize.height - infoOffset.y) + 'px';
frame.style.left = ((-contentsWidth) / 2 + infoOffset.x) + 'px';
//console.log('frameLeft = ' + frame.style.left );
var point = map.get('infoPosition');
anchorDiv.style.visibility = 'hidden';
var x = point.x + self.get('offsetX');
var y = point.y + self.get('offsetY');
anchorDiv.style['-webkit-transform'] = 'translate3d(' + x + 'px, ' + y + 'px, 0px)';
anchorDiv.style.transform = 'translate3d(' + x + 'px, ' + y + 'px, 0px)';
anchorDiv.style.visibility = 'visible';
self.trigger('infoPosition_changed', '', point);
self.trigger(event.INFO_OPEN);
};
self._hook.on(self, 'infoPosition_changed', function (ignore, point) {
if (!point) return;
var x = point.x + self.get('offsetX');
var y = point.y + self.get('offsetY');
anchorDiv.style['-webkit-transform'] = 'translate3d(' + x + 'px, ' + y + 'px, 0px)';
anchorDiv.style.transform = 'translate3d(' + x + 'px, ' + y + 'px, 0px)';
});
self._hook.on(self, 'infoWindowAnchor_changed', calculate);
self.set('isInfoWindowVisible', false);
};
utils.extend(HTMLInfoWindow, BaseClass);
HTMLInfoWindow.prototype.isInfoWindowShown = function () {
return this.get('isInfoWindowVisible') === true;
};
HTMLInfoWindow.prototype.close = function () {
var self = this;
var marker = self.get('marker');
if (marker) {
self._hook.off(marker, 'isInfoWindowVisible_changed');
}
if (!self.isInfoWindowShown() || !marker) {
return;
}
self.set('isInfoWindowVisible', false);
marker.set('isInfoWindowVisible', false);
marker.set('infoWindow', undefined);
this.set('marker', undefined);
var map = marker.getMap();
self._hook.off(marker.getMap(), 'map_clear');
self._hook.off(marker, 'infoPosition_changed');
self._hook.off(marker, 'icon_changed');
//self._hook.off(self, 'infoWindowAnchor_changed');
self._hook.off(marker, event.INFO_CLOSE); //This event listener is assigned in the open method. So detach it.
self.trigger(event.INFO_CLOSE);
map.set('active_marker', null);
//var div = map.getDiv();
var anchorDiv = self.get('anchor');
if (anchorDiv && anchorDiv.parentNode) {
anchorDiv.parentNode.removeChild(anchorDiv);
// Remove the contents from this HTMLInfoWindow
var contentFrame = anchorDiv.firstChild.firstChild;
var contentBox = contentFrame.firstChild;
contentBox.innerHTML = '';
}
};
HTMLInfoWindow.prototype.setContent = function (content, cssOptions) {
var self = this;
var prevContent = self.get('content');
self.set('content', content);
self.set('cssOptions', cssOptions);
var marker = self.get('marker');
if (content !== prevContent && marker && marker.isInfoWindowShown()) {
var anchorDiv = self.get('anchor');
if (anchorDiv) {
anchorDiv.style.width = '0 !important';
anchorDiv.style.height = '0 !important';
if (anchorDiv.parentNode) {
anchorDiv.parentNode.removeChild(anchorDiv);
// Remove the contents from this HTMLInfoWindow
var contentFrame = anchorDiv.firstChild.firstChild;
var contentBox = contentFrame.firstChild;
contentBox.innerHTML = '';
}
}
self.trigger('infoWindowAnchor_changed', marker);
}
};
HTMLInfoWindow.prototype.open = function (marker) {
if (!marker) {
return;
}
if (marker._objectInstance) {
// marker is an instance of the ionic-native wrapper plugin.
marker = marker._objectInstance;
}
var self = this,
map = marker.getMap();
marker.set('infoWindow', self);
marker.set('isInfoWindowVisible', true);
self._hook.on(marker, 'icon_changed', function () {
self.trigger.call(self, 'infoWindowAnchor_changed', marker);
});
self.set('isInfoWindowVisible', true);
self._hook.on(marker, 'isInfoWindowVisible_changed', function (prevValue, newValue) {
if (newValue === false) {
self.close.call(self);
}
});
map.fromLatLngToPoint(marker.getPosition(), function (point) {
map.set('infoPosition', {
x: point[0],
y: point[1]
});
self._hook.bindTo(map, 'infoPosition', self);
self._hook.bindTo(marker, 'infoWindowAnchor', self);
self._hook.bindTo(marker, 'icon', self);
self._hook.one(marker.getMap(), 'map_clear', self.close.bind(self));
self._hook.one(marker, event.INFO_CLOSE, self.close.bind(self));
self.set('marker', marker);
map.set('active_marker', marker);
self.trigger.call(self, 'infoWindowAnchor_changed', marker);
});
};
HTMLInfoWindow.prototype.setBackgroundColor = function (backgroundColor) {
this.get('frame').children[0].style.backgroundColor = backgroundColor;
this.get('frame').children[1].children[0].style.borderColor = backgroundColor + ' rgba(0,0,0,0) rgba(0,0,0,0)';
this.get('frame').children[1].children[1].style.borderColor = backgroundColor + ' rgba(0,0,0,0) rgba(0,0,0,0)';
this.get('frame').children[1].children[2].style.backgroundColor = backgroundColor;
};
module.exports = HTMLInfoWindow;
});