Bones/node_modules/browser-sync-client/dist/index.js

2031 lines
48 KiB
JavaScript
Raw Normal View History

2017-05-17 13:45:25 -04:00
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict";
var socket = require("./socket");
var emitter = require("./emitter");
var notify = require("./notify");
var tab = require("./tab");
var utils = require("./browser.utils");
/**
* @constructor
*/
var BrowserSync = function (options) {
this.options = options;
this.socket = socket;
this.emitter = emitter;
this.utils = utils;
this.tabHidden = false;
var bs = this;
/**
* Options set
*/
socket.on("options:set", function (data) {
emitter.emit("notify", "Setting options...");
bs.options = data.options;
});
emitter.on("tab:hidden", function () {
bs.tabHidden = true;
});
emitter.on("tab:visible", function () {
bs.tabHidden = false;
});
};
/**
* Helper to check if syncing is allowed
* @param data
* @param optPath
* @returns {boolean}
*/
BrowserSync.prototype.canSync = function (data, optPath) {
data = data || {};
if (data.override) {
return true;
}
var canSync = true;
if (optPath) {
canSync = this.getOption(optPath);
}
return canSync && data.url === window.location.pathname;
};
/**
* Helper to check if syncing is allowed
* @returns {boolean}
*/
BrowserSync.prototype.getOption = function (path) {
if (path && path.match(/\./)) {
return getByPath(this.options, path);
} else {
var opt = this.options[path];
if (isUndefined(opt)) {
return false;
} else {
return opt;
}
}
};
/**
* @type {Function}
*/
module.exports = BrowserSync;
/**
* @param {String} val
* @returns {boolean}
*/
function isUndefined(val) {
return "undefined" === typeof val;
}
/**
* @param obj
* @param path
*/
function getByPath(obj, path) {
for(var i = 0, tempPath = path.split("."), len = tempPath.length; i < len; i++){
if(!obj || typeof obj !== "object") {
return false;
}
obj = obj[tempPath[i]];
}
if(typeof obj === "undefined") {
return false;
}
return obj;
}
},{"./browser.utils":2,"./emitter":5,"./notify":16,"./socket":17,"./tab":18}],2:[function(require,module,exports){
"use strict";
var utils = exports;
/**
* @returns {window}
*/
utils.getWindow = function () {
return window;
};
/**
* @returns {HTMLDocument}
*/
utils.getDocument = function () {
return document;
};
/**
* @returns {HTMLElement}
*/
utils.getBody = function () {
return document.getElementsByTagName("body")[0];
};
/**
* Get the current x/y position crossbow
* @returns {{x: *, y: *}}
*/
utils.getBrowserScrollPosition = function () {
var $window = exports.getWindow();
var $document = exports.getDocument();
var scrollX;
var scrollY;
var dElement = $document.documentElement;
var dBody = $document.body;
if ($window.pageYOffset !== undefined) {
scrollX = $window.pageXOffset;
scrollY = $window.pageYOffset;
} else {
scrollX = dElement.scrollLeft || dBody.scrollLeft || 0;
scrollY = dElement.scrollTop || dBody.scrollTop || 0;
}
return {
x: scrollX,
y: scrollY
};
};
/**
* @returns {{x: number, y: number}}
*/
utils.getScrollSpace = function () {
var $document = exports.getDocument();
var dElement = $document.documentElement;
var dBody = $document.body;
return {
x: dBody.scrollHeight - dElement.clientWidth,
y: dBody.scrollHeight - dElement.clientHeight
};
};
/**
* Saves scroll position into cookies
*/
utils.saveScrollPosition = function () {
var pos = utils.getBrowserScrollPosition();
pos = [pos.x, pos.y];
utils.getDocument.cookie = "bs_scroll_pos=" + pos.join(",");
};
/**
* Restores scroll position from cookies
*/
utils.restoreScrollPosition = function () {
var pos = utils.getDocument().cookie.replace(/(?:(?:^|.*;\s*)bs_scroll_pos\s*\=\s*([^;]*).*$)|^.*$/, "$1").split(",");
utils.getWindow().scrollTo(pos[0], pos[1]);
};
/**
* @param tagName
* @param elem
* @returns {*|number}
*/
utils.getElementIndex = function (tagName, elem) {
var allElems = utils.getDocument().getElementsByTagName(tagName);
return Array.prototype.indexOf.call(allElems, elem);
};
/**
* Force Change event on radio & checkboxes (IE)
*/
utils.forceChange = function (elem) {
elem.blur();
elem.focus();
};
/**
* @param elem
* @returns {{tagName: (elem.tagName|*), index: *}}
*/
utils.getElementData = function (elem) {
var tagName = elem.tagName;
var index = utils.getElementIndex(tagName, elem);
return {
tagName: tagName,
index: index
};
};
/**
* @param {string} tagName
* @param {number} index
*/
utils.getSingleElement = function (tagName, index) {
var elems = utils.getDocument().getElementsByTagName(tagName);
return elems[index];
};
/**
* Get the body element
*/
utils.getBody = function () {
return utils.getDocument().getElementsByTagName("body")[0];
};
/**
* @param {{x: number, y: number}} pos
*/
utils.setScroll = function (pos) {
utils.getWindow().scrollTo(pos.x, pos.y);
};
/**
* Hard reload
*/
utils.reloadBrowser = function () {
utils.getWindow().location.reload(true);
};
/**
* Foreach polyfill
* @param coll
* @param fn
*/
utils.forEach = function (coll, fn) {
for (var i = 0, n = coll.length; i < n; i += 1) {
fn(coll[i], i, coll);
}
};
/**
* Are we dealing with old IE?
* @returns {boolean}
*/
utils.isOldIe = function () {
return typeof utils.getWindow().attachEvent !== "undefined";
};
/**
* Split the URL information
* @returns {object}
*/
utils.getLocation = function (url) {
var location = utils.getDocument().createElement("a");
location.href = url;
if (location.host === "") {
location.href = location.href;
}
return location;
};
},{}],3:[function(require,module,exports){
if (!("indexOf" in Array.prototype)) {
Array.prototype.indexOf= function(find, i) {
if (i === undefined) {
i = 0;
}
if (i < 0) {
i += this.length;
}
if (i < 0) {
i= 0;
}
for (var n = this.length; i < n; i += 1) {
if (i in this && this[i]===find) {
return i;
}
}
return -1;
};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#x15.4.4.19
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(' this is null or not defined');
}
// 1. Let O be the result of calling ToObject passing the |this|
// value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal
// method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 1) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len)
// where Array is the standard built-in constructor with that name and
// len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while (k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal
// method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
kValue = O[k];
// ii. Let mappedValue be the result of calling the Call internal
// method of callback with T as the this value and argument
// list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor
// { Value: mappedValue,
// Writable: true,
// Enumerable: true,
// Configurable: true },
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, k, {
// value: mappedValue,
// writable: true,
// enumerable: true,
// configurable: true
// });
// For best browser support, use the following:
A[k] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun/*, thisArg*/) {
'use strict';
if (this === void 0 || this === null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== 'function') {
throw new TypeError();
}
var res = [];
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t) {
var val = t[i];
// NOTE: Technically this should Object.defineProperty at
// the next index, as push can be affected by
// properties on Object.prototype and Array.prototype.
// But that method's new, and collisions should be
// rare, so use the more-compatible alternative.
if (fun.call(thisArg, val, i, t)) {
res.push(val);
}
}
}
return res;
};
}
},{}],4:[function(require,module,exports){
"use strict";
var events = require("./events");
var utils = require("./browser.utils");
var emitter = require("./emitter");
var sync = exports;
var options = {
tagNames: {
"css": "link",
"jpg": "img",
"jpeg": "img",
"png": "img",
"svg": "img",
"gif": "img",
"js": "script"
},
attrs: {
"link": "href",
"img": "src",
"script": "src"
},
blacklist: [
// never allow .map files through
function(incoming) {
return incoming.ext === "map";
}
]
};
var hiddenElem;
var OPT_PATH = "codeSync";
var current = function () {
return window.location.pathname;
};
/**
* @param {BrowserSync} bs
*/
sync.init = function (bs) {
if (bs.options.tagNames) {
options.tagNames = bs.options.tagNames;
}
if (bs.options.scrollRestoreTechnique === "window.name") {
sync.saveScrollInName(emitter);
} else {
sync.saveScrollInCookie(utils.getWindow(), utils.getDocument());
}
bs.socket.on("file:reload", sync.reload(bs));
bs.socket.on("browser:reload", function () {
if (bs.canSync({url: current()}, OPT_PATH)) {
sync.reloadBrowser(true, bs);
}
});
};
/**
* Use window.name to store/restore scroll position
*/
sync.saveScrollInName = function () {
var PRE = "<<BS_START>>";
var SUF = "<<BS_END>>";
var regex = new RegExp(PRE + "(.+?)" + SUF);
var $window = utils.getWindow();
var saved = {};
/**
* Listen for the browser:hardReload event.
* When it runs, save the current scroll position
* in window.name
*/
emitter.on("browser:hardReload", function (data) {
var newname = [$window.name, PRE, JSON.stringify({
bs: {
hardReload: true,
scroll: data.scrollPosition
}
}), SUF].join("");
$window.name = newname;
});
/**
* On page load, check window.name for an existing
* BS json blob & parse it.
*/
try {
var json = $window.name.match(regex);
if (json) {
saved = JSON.parse(json[1]);
}
} catch (e) {
saved = {};
}
/**
* If the JSON was parsed correctly, try to
* find a scroll property and restore it.
*/
if (saved.bs && saved.bs.hardReload && saved.bs.scroll) {
utils.setScroll(saved.bs.scroll);
}
/**
* Remove any existing BS json from window.name
* to ensure we don't interfere with any other
* libs who may be using it.
*/
$window.name = $window.name.replace(regex, "");
};
/**
* Use a cookie-drop to save scroll position of
* @param $window
* @param $document
*/
sync.saveScrollInCookie = function ($window, $document) {
if (!utils.isOldIe()) {
return;
}
if ($document.readyState === "complete") {
utils.restoreScrollPosition();
} else {
events.manager.addEvent($document, "readystatechange", function() {
if ($document.readyState === "complete") {
utils.restoreScrollPosition();
}
});
}
emitter.on("browser:hardReload", utils.saveScrollPosition);
};
/**
* @param {string} search
* @param {string} key
* @param {string} suffix
*/
sync.updateSearch = function(search, key, suffix) {
if (search === "") {
return "?" + suffix;
}
return "?" + search
.slice(1)
.split("&")
.map(function (item) {
return item.split("=");
})
.filter(function (tuple) {
return tuple[0] !== key;
})
.map(function (item) {
return [item[0], item[1]].join("=");
})
.concat(suffix)
.join("&");
};
/**
* @param elem
* @param attr
* @param options
* @returns {{elem: HTMLElement, timeStamp: number}}
*/
sync.swapFile = function (elem, attr, options) {
var currentValue = elem[attr];
var timeStamp = new Date().getTime();
var key = "rel";
var suffix = key + "=" + timeStamp;
var anchor = utils.getLocation(currentValue);
var search = sync.updateSearch(anchor.search, key, suffix);
var newValue = anchor.href;
if (options.timestamps !== false) {
newValue = newValue.split("?")[0] + search;
}
if (elem.tagName === "LINK") {
elem = sync.swapStyle(elem, newValue);
} else {
elem[attr] = newValue;
sync.triggerReflow();
}
return {
elem: elem,
timeStamp: timeStamp
};
};
/**
* @param link
* @param newHref
* @returns HTMLElement
*/
sync.swapStyle = function (link, newHref) {
var clone = link.cloneNode(false);
clone.href = newHref;
link.parentNode.insertBefore(clone, link.nextSibling);
sync.onLinkLoad(clone, function () {
if (link.parentNode) {
link.parentNode.removeChild(link);
}
});
return clone;
};
/**
* @param link
* @param onLoad
*/
sync.onLinkLoad = function (link, onLoad) {
var loaded = false;
function cb() {
if (loaded) {
return;
}
if (link.addEventListener) {
link.removeEventListener("load", cb);
}
loaded = true;
onLoad();
}
if (link.addEventListener) {
link.addEventListener("load", cb);
}
sync.onLinkDefined(link, cb);
};
/**
* @param link
* @param onLoad
*/
sync.onLinkDefined = function (link, onLoad) {
var sheets = document.styleSheets,
i = sheets.length;
while (i--) {
if (sheets[i].href === link.href) {
onLoad();
return;
}
}
setTimeout(function () {
sync.onLinkDefined(link, onLoad);
});
};
sync.triggerReflow = function() {
var body = document.body;
setTimeout(function () {
if (!hiddenElem) {
hiddenElem = document.createElement("DIV");
body.appendChild(hiddenElem);
} else {
hiddenElem.style.display = "none";
hiddenElem.style.display = "block";
}
}, 200);
};
sync.getFilenameOnly = function (url) {
return /^[^\?]+(?=\?)/.exec(url);
};
/**
* @param {BrowserSync} bs
* @returns {*}
*/
sync.reload = function (bs) {
/**
* @param data - from socket
*/
return function (data) {
if (!bs.canSync({url: current()}, OPT_PATH)) {
return;
}
var transformedElem;
var options = bs.options;
var emitter = bs.emitter;
if (data.url || !options.injectChanges) {
sync.reloadBrowser(true);
}
if (data.basename && data.ext) {
if (sync.isBlacklisted(data)) {
return;
}
var domData = sync.getElems(data.ext);
var elems = sync.getMatches(domData.elems, data.basename, domData.attr);
if (elems.length && options.notify) {
emitter.emit("notify", {message: "Injected: " + data.basename});
}
for (var i = 0, n = elems.length; i < n; i += 1) {
transformedElem = sync.swapFile(elems[i], domData.attr, options);
}
}
return transformedElem;
};
};
/**
* @param fileExtension
* @returns {*}
*/
sync.getTagName = function (fileExtension) {
return options.tagNames[fileExtension];
};
/**
* @param tagName
* @returns {*}
*/
sync.getAttr = function (tagName) {
return options.attrs[tagName];
};
/**
* @param incoming
* @returns {boolean}
*/
sync.isBlacklisted = function (incoming) {
return options.blacklist.some(function(fn) {
return fn(incoming);
});
};
/**
* @param elems
* @param url
* @param attr
* @returns {Array}
*/
sync.getMatches = function (elems, url, attr) {
if (url[0] === "*") {
return elems;
}
var matches = [];
var urlMatcher = new RegExp("(^|/)" + url);
for (var i = 0, len = elems.length; i < len; i += 1) {
if (urlMatcher.test(elems[i][attr])) {
matches.push(elems[i]);
}
}
return matches;
};
/**
* @param fileExtension
* @returns {{elems: NodeList, attr: *}}
*/
sync.getElems = function(fileExtension) {
var tagName = sync.getTagName(fileExtension);
var attr = sync.getAttr(tagName);
return {
elems: document.getElementsByTagName(tagName),
attr: attr
};
};
/**
* @param confirm
*/
sync.reloadBrowser = function (confirm) {
emitter.emit("browser:hardReload", {
scrollPosition: utils.getBrowserScrollPosition()
});
if (confirm) {
utils.reloadBrowser();
}
};
},{"./browser.utils":2,"./emitter":5,"./events":6}],5:[function(require,module,exports){
"use strict";
exports.events = {};
/**
* @param name
* @param data
*/
exports.emit = function (name, data) {
var event = exports.events[name];
var listeners;
if (event && event.listeners) {
listeners = event.listeners;
for (var i = 0, n = listeners.length; i < n; i += 1) {
listeners[i](data);
}
}
};
/**
* @param name
* @param func
*/
exports.on = function (name, func) {
var events = exports.events;
if (!events[name]) {
events[name] = {
listeners: [func]
};
} else {
events[name].listeners.push(func);
}
};
},{}],6:[function(require,module,exports){
exports._ElementCache = function () {
var cache = {},
guidCounter = 1,
expando = "data" + (new Date).getTime();
this.getData = function (elem) {
var guid = elem[expando];
if (!guid) {
guid = elem[expando] = guidCounter++;
cache[guid] = {};
}
return cache[guid];
};
this.removeData = function (elem) {
var guid = elem[expando];
if (!guid) return;
delete cache[guid];
try {
delete elem[expando];
}
catch (e) {
if (elem.removeAttribute) {
elem.removeAttribute(expando);
}
}
};
};
/**
* Fix an event
* @param event
* @returns {*}
*/
exports._fixEvent = function (event) {
function returnTrue() {
return true;
}
function returnFalse() {
return false;
}
if (!event || !event.stopPropagation) {
var old = event || window.event;
// Clone the old object so that we can modify the values
event = {};
for (var prop in old) {
event[prop] = old[prop];
}
// The event occurred on this element
if (!event.target) {
event.target = event.srcElement || document;
}
// Handle which other element the event is related to
event.relatedTarget = event.fromElement === event.target ?
event.toElement :
event.fromElement;
// Stop the default browser action
event.preventDefault = function () {
event.returnValue = false;
event.isDefaultPrevented = returnTrue;
};
event.isDefaultPrevented = returnFalse;
// Stop the event from bubbling
event.stopPropagation = function () {
event.cancelBubble = true;
event.isPropagationStopped = returnTrue;
};
event.isPropagationStopped = returnFalse;
// Stop the event from bubbling and executing other handlers
event.stopImmediatePropagation = function () {
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
};
event.isImmediatePropagationStopped = returnFalse;
// Handle mouse position
if (event.clientX != null) {
var doc = document.documentElement, body = document.body;
event.pageX = event.clientX +
(doc && doc.scrollLeft || body && body.scrollLeft || 0) -
(doc && doc.clientLeft || body && body.clientLeft || 0);
event.pageY = event.clientY +
(doc && doc.scrollTop || body && body.scrollTop || 0) -
(doc && doc.clientTop || body && body.clientTop || 0);
}
// Handle key presses
event.which = event.charCode || event.keyCode;
// Fix button for mouse clicks:
// 0 == left; 1 == middle; 2 == right
if (event.button != null) {
event.button = (event.button & 1 ? 0 :
(event.button & 4 ? 1 :
(event.button & 2 ? 2 : 0)));
}
}
return event;
};
/**
* @constructor
*/
exports._EventManager = function (cache) {
var nextGuid = 1;
this.addEvent = function (elem, type, fn) {
var data = cache.getData(elem);
if (!data.handlers) data.handlers = {};
if (!data.handlers[type])
data.handlers[type] = [];
if (!fn.guid) fn.guid = nextGuid++;
data.handlers[type].push(fn);
if (!data.dispatcher) {
data.disabled = false;
data.dispatcher = function (event) {
if (data.disabled) return;
event = exports._fixEvent(event);
var handlers = data.handlers[event.type];
if (handlers) {
for (var n = 0; n < handlers.length; n++) {
handlers[n].call(elem, event);
}
}
};
}
if (data.handlers[type].length == 1) {
if (document.addEventListener) {
elem.addEventListener(type, data.dispatcher, false);
}
else if (document.attachEvent) {
elem.attachEvent("on" + type, data.dispatcher);
}
}
};
function tidyUp(elem, type) {
function isEmpty(object) {
for (var prop in object) {
return false;
}
return true;
}
var data = cache.getData(elem);
if (data.handlers[type].length === 0) {
delete data.handlers[type];
if (document.removeEventListener) {
elem.removeEventListener(type, data.dispatcher, false);
}
else if (document.detachEvent) {
elem.detachEvent("on" + type, data.dispatcher);
}
}
if (isEmpty(data.handlers)) {
delete data.handlers;
delete data.dispatcher;
}
if (isEmpty(data)) {
cache.removeData(elem);
}
}
this.removeEvent = function (elem, type, fn) {
var data = cache.getData(elem);
if (!data.handlers) return;
var removeType = function (t) {
data.handlers[t] = [];
tidyUp(elem, t);
};
if (!type) {
for (var t in data.handlers) removeType(t);
return;
}
var handlers = data.handlers[type];
if (!handlers) return;
if (!fn) {
removeType(type);
return;
}
if (fn.guid) {
for (var n = 0; n < handlers.length; n++) {
if (handlers[n].guid === fn.guid) {
handlers.splice(n--, 1);
}
}
}
tidyUp(elem, type);
};
this.proxy = function (context, fn) {
if (!fn.guid) {
fn.guid = nextGuid++;
}
var ret = function () {
return fn.apply(context, arguments);
};
ret.guid = fn.guid;
return ret;
};
};
/**
* Trigger a click on an element
* @param elem
*/
exports.triggerClick = function (elem) {
var evObj;
if (document.createEvent) {
window.setTimeout(function () {
evObj = document.createEvent("MouseEvents");
evObj.initEvent("click", true, true);
elem.dispatchEvent(evObj);
}, 0);
} else {
window.setTimeout(function () {
if (document.createEventObject) {
evObj = document.createEventObject();
evObj.cancelBubble = true;
elem.fireEvent("on" + "click", evObj);
}
}, 0);
}
};
var cache = new exports._ElementCache();
var eventManager = new exports._EventManager(cache);
eventManager.triggerClick = exports.triggerClick;
exports.manager = eventManager;
},{}],7:[function(require,module,exports){
"use strict";
/**
* This is the plugin for syncing clicks between browsers
* @type {string}
*/
var EVENT_NAME = "click";
var OPT_PATH = "ghostMode.clicks";
exports.canEmitEvents = true;
/**
* @param {BrowserSync} bs
* @param eventManager
*/
exports.init = function (bs, eventManager) {
eventManager.addEvent(document.body, EVENT_NAME, exports.browserEvent(bs));
bs.socket.on(EVENT_NAME, exports.socketEvent(bs, eventManager));
};
/**
* Uses event delegation to determine the clicked element
* @param {BrowserSync} bs
* @returns {Function}
*/
exports.browserEvent = function (bs) {
return function (event) {
if (exports.canEmitEvents) {
var elem = event.target || event.srcElement;
if (elem.type === "checkbox" || elem.type === "radio") {
bs.utils.forceChange(elem);
return;
}
bs.socket.emit(EVENT_NAME, bs.utils.getElementData(elem));
} else {
exports.canEmitEvents = true;
}
};
};
/**
* @param {BrowserSync} bs
* @param {manager} eventManager
* @returns {Function}
*/
exports.socketEvent = function (bs, eventManager) {
return function (data) {
if (!bs.canSync(data, OPT_PATH) || bs.tabHidden) {
return false;
}
var elem = bs.utils.getSingleElement(data.tagName, data.index);
if (elem) {
exports.canEmitEvents = false;
eventManager.triggerClick(elem);
}
};
};
},{}],8:[function(require,module,exports){
"use strict";
/**
* This is the plugin for syncing clicks between browsers
* @type {string}
*/
var EVENT_NAME = "input:text";
var OPT_PATH = "ghostMode.forms.inputs";
exports.canEmitEvents = true;
/**
* @param {BrowserSync} bs
* @param eventManager
*/
exports.init = function (bs, eventManager) {
eventManager.addEvent(document.body, "keyup", exports.browserEvent(bs));
bs.socket.on(EVENT_NAME, exports.socketEvent(bs, eventManager));
};
/**
* @param {BrowserSync} bs
* @returns {Function}
*/
exports.browserEvent = function (bs) {
return function (event) {
var elem = event.target || event.srcElement;
var data;
if (exports.canEmitEvents) {
if (elem.tagName === "INPUT" || elem.tagName === "TEXTAREA") {
data = bs.utils.getElementData(elem);
data.value = elem.value;
bs.socket.emit(EVENT_NAME, data);
}
} else {
exports.canEmitEvents = true;
}
};
};
/**
* @param {BrowserSync} bs
* @returns {Function}
*/
exports.socketEvent = function (bs) {
return function (data) {
if (!bs.canSync(data, OPT_PATH)) {
return false;
}
var elem = bs.utils.getSingleElement(data.tagName, data.index);
if (elem) {
elem.value = data.value;
return elem;
}
return false;
};
};
},{}],9:[function(require,module,exports){
"use strict";
exports.plugins = {
"inputs": require("./ghostmode.forms.input"),
"toggles": require("./ghostmode.forms.toggles"),
"submit": require("./ghostmode.forms.submit")
};
/**
* Load plugins for enabled options
* @param bs
*/
exports.init = function (bs, eventManager) {
var checkOpt = true;
var options = bs.options.ghostMode.forms;
if (options === true) {
checkOpt = false;
}
function init(name) {
exports.plugins[name].init(bs, eventManager);
}
for (var name in exports.plugins) {
if (!checkOpt) {
init(name);
} else {
if (options[name]) {
init(name);
}
}
}
};
},{"./ghostmode.forms.input":8,"./ghostmode.forms.submit":10,"./ghostmode.forms.toggles":11}],10:[function(require,module,exports){
"use strict";
/**
* This is the plugin for syncing clicks between browsers
* @type {string}
*/
var EVENT_NAME = "form:submit";
var OPT_PATH = "ghostMode.forms.submit";
exports.canEmitEvents = true;
/**
* @param {BrowserSync} bs
* @param eventManager
*/
exports.init = function (bs, eventManager) {
var browserEvent = exports.browserEvent(bs);
eventManager.addEvent(document.body, "submit", browserEvent);
eventManager.addEvent(document.body, "reset", browserEvent);
bs.socket.on(EVENT_NAME, exports.socketEvent(bs, eventManager));
};
/**
* @param {BrowserSync} bs
* @returns {Function}
*/
exports.browserEvent = function (bs) {
return function (event) {
if (exports.canEmitEvents) {
var elem = event.target || event.srcElement;
var data = bs.utils.getElementData(elem);
data.type = event.type;
bs.socket.emit(EVENT_NAME, data);
} else {
exports.canEmitEvents = true;
}
};
};
/**
* @param {BrowserSync} bs
* @returns {Function}
*/
exports.socketEvent = function (bs) {
return function (data) {
if (!bs.canSync(data, OPT_PATH)) {
return false;
}
var elem = bs.utils.getSingleElement(data.tagName, data.index);
exports.canEmitEvents = false;
if (elem && data.type === "submit") {
elem.submit();
}
if (elem && data.type === "reset") {
elem.reset();
}
return false;
};
};
},{}],11:[function(require,module,exports){
"use strict";
/**
* This is the plugin for syncing clicks between browsers
* @type {string}
*/
var EVENT_NAME = "input:toggles";
var OPT_PATH = "ghostMode.forms.toggles";
exports.canEmitEvents = true;
/**
* @param {BrowserSync} bs
* @param eventManager
*/
exports.init = function (bs, eventManager) {
var browserEvent = exports.browserEvent(bs);
exports.addEvents(eventManager, browserEvent);
bs.socket.on(EVENT_NAME, exports.socketEvent(bs, eventManager));
};
/**
* @param eventManager
* @param event
*/
exports.addEvents = function (eventManager, event) {
var elems = document.getElementsByTagName("select");
var inputs = document.getElementsByTagName("input");
addEvents(elems);
addEvents(inputs);
function addEvents(domElems) {
for (var i = 0, n = domElems.length; i < n; i += 1) {
eventManager.addEvent(domElems[i], "change", event);
}
}
};
/**
* @param {BrowserSync} bs
* @returns {Function}
*/
exports.browserEvent = function (bs) {
return function (event) {
if (exports.canEmitEvents) {
var elem = event.target || event.srcElement;
var data;
if (elem.type === "radio" || elem.type === "checkbox" || elem.tagName === "SELECT") {
data = bs.utils.getElementData(elem);
data.type = elem.type;
data.value = elem.value;
data.checked = elem.checked;
bs.socket.emit(EVENT_NAME, data);
}
} else {
exports.canEmitEvents = true;
}
};
};
/**
* @param {BrowserSync} bs
* @returns {Function}
*/
exports.socketEvent = function (bs) {
return function (data) {
if (!bs.canSync(data, OPT_PATH)) {
return false;
}
exports.canEmitEvents = false;
var elem = bs.utils.getSingleElement(data.tagName, data.index);
if (elem) {
if (data.type === "radio") {
elem.checked = true;
}
if (data.type === "checkbox") {
elem.checked = data.checked;
}
if (data.tagName === "SELECT") {
elem.value = data.value;
}
return elem;
}
return false;
};
};
},{}],12:[function(require,module,exports){
"use strict";
var eventManager = require("./events").manager;
exports.plugins = {
"scroll": require("./ghostmode.scroll"),
"clicks": require("./ghostmode.clicks"),
"forms": require("./ghostmode.forms"),
"location": require("./ghostmode.location")
};
/**
* Load plugins for enabled options
* @param bs
*/
exports.init = function (bs) {
for (var name in exports.plugins) {
if (bs.options.ghostMode[name]) {
exports.plugins[name].init(bs, eventManager);
}
}
};
},{"./events":6,"./ghostmode.clicks":7,"./ghostmode.forms":9,"./ghostmode.location":13,"./ghostmode.scroll":14}],13:[function(require,module,exports){
"use strict";
/**
* This is the plugin for syncing location
* @type {string}
*/
var EVENT_NAME = "browser:location";
var OPT_PATH = "ghostMode.location";
exports.canEmitEvents = true;
/**
* @param {BrowserSync} bs
*/
exports.init = function (bs) {
bs.socket.on(EVENT_NAME, exports.socketEvent(bs));
};
/**
* Respond to socket event
*/
exports.socketEvent = function (bs) {
return function (data) {
if (!bs.canSync(data, OPT_PATH)) {
return false;
}
if (data.path) {
exports.setPath(data.path);
} else {
exports.setUrl(data.url);
}
};
};
/**
* @param url
*/
exports.setUrl = function (url) {
window.location = url;
};
/**
* @param path
*/
exports.setPath = function (path) {
window.location = window.location.protocol + "//" + window.location.host + path;
};
},{}],14:[function(require,module,exports){
"use strict";
/**
* This is the plugin for syncing scroll between devices
* @type {string}
*/
var WINDOW_EVENT_NAME = "scroll";
var ELEMENT_EVENT_NAME = "scroll:element";
var OPT_PATH = "ghostMode.scroll";
var utils;
exports.canEmitEvents = true;
/**
* @param {BrowserSync} bs
* @param eventManager
*/
exports.init = function (bs, eventManager) {
utils = bs.utils;
var opts = bs.options;
/**
* Window Scroll events
*/
eventManager.addEvent(window, WINDOW_EVENT_NAME, exports.browserEvent(bs));
bs.socket.on(WINDOW_EVENT_NAME, exports.socketEvent(bs));
/**
* element Scroll Events
*/
var cache = {};
addElementScrollEvents("scrollElements", false);
addElementScrollEvents("scrollElementMapping", true);
bs.socket.on(ELEMENT_EVENT_NAME, exports.socketEventForElement(bs, cache));
function addElementScrollEvents (key, map) {
if (!opts[key] || !opts[key].length || !("querySelectorAll" in document)) {
return;
}
utils.forEach(opts[key], function (selector) {
var elems = document.querySelectorAll(selector) || [];
utils.forEach(elems, function (elem) {
var data = utils.getElementData(elem);
data.cacheSelector = data.tagName + ":" + data.index;
data.map = map;
cache[data.cacheSelector] = elem;
eventManager.addEvent(elem, WINDOW_EVENT_NAME, exports.browserEventForElement(bs, elem, data));
});
});
}
};
/**
* @param {BrowserSync} bs
*/
exports.socketEvent = function (bs) {
return function (data) {
if (!bs.canSync(data, OPT_PATH)) {
return false;
}
var scrollSpace = utils.getScrollSpace();
exports.canEmitEvents = false;
if (bs.options && bs.options.scrollProportionally) {
return window.scrollTo(0, scrollSpace.y * data.position.proportional); // % of y axis of scroll to px
} else {
return window.scrollTo(0, data.position.raw.y);
}
};
};
/**
* @param bs
*/
exports.socketEventForElement = function (bs, cache) {
return function (data) {
if (!bs.canSync(data, OPT_PATH)) {
return false;
}
exports.canEmitEvents = false;
function scrollOne (selector, pos) {
if (cache[selector]) {
cache[selector].scrollTop = pos;
}
}
if (data.map) {
return Object.keys(cache).forEach(function (key) {
scrollOne(key, data.position);
});
}
scrollOne(data.elem.cacheSelector, data.position);
};
};
/**
* @param bs
*/
exports.browserEventForElement = function (bs, elem, data) {
return function () {
var canSync = exports.canEmitEvents;
if (canSync) {
bs.socket.emit(ELEMENT_EVENT_NAME, {
position: elem.scrollTop,
elem: data,
map: data.map
});
}
exports.canEmitEvents = true;
};
};
exports.browserEvent = function (bs) {
return function () {
var canSync = exports.canEmitEvents;
if (canSync) {
bs.socket.emit(WINDOW_EVENT_NAME, {
position: exports.getScrollPosition()
});
}
exports.canEmitEvents = true;
};
};
/**
* @returns {{raw: number, proportional: number}}
*/
exports.getScrollPosition = function () {
var pos = utils.getBrowserScrollPosition();
return {
raw: pos, // Get px of x and y axis of scroll
proportional: exports.getScrollTopPercentage(pos) // Get % of y axis of scroll
};
};
/**
* @param {{x: number, y: number}} scrollSpace
* @param scrollPosition
* @returns {{x: number, y: number}}
*/
exports.getScrollPercentage = function (scrollSpace, scrollPosition) {
var x = scrollPosition.x / scrollSpace.x;
var y = scrollPosition.y / scrollSpace.y;
return {
x: x || 0,
y: y
};
};
/**
* Get just the percentage of Y axis of scroll
* @returns {number}
*/
exports.getScrollTopPercentage = function (pos) {
var scrollSpace = utils.getScrollSpace();
var percentage = exports.getScrollPercentage(scrollSpace, pos);
return percentage.y;
};
},{}],15:[function(require,module,exports){
"use strict";
var socket = require("./socket");
var shims = require("./client-shims");
var notify = require("./notify");
var codeSync = require("./code-sync");
var BrowserSync = require("./browser-sync");
var ghostMode = require("./ghostmode");
var emitter = require("./emitter");
var events = require("./events");
var utils = require("./browser.utils");
var shouldReload = false;
var initialised = false;
/**
* @param options
*/
exports.init = function (options) {
if (shouldReload && options.reloadOnRestart) {
utils.reloadBrowser();
}
var BS = window.___browserSync___ || {};
if (!BS.client) {
BS.client = true;
var browserSync = new BrowserSync(options);
// Always init on page load
ghostMode.init(browserSync);
codeSync.init(browserSync);
notify.init(browserSync);
if (options.notify) {
notify.flash("Connected to BrowserSync");
}
}
if (!initialised) {
socket.on("disconnect", function () {
if (options.notify) {
notify.flash("Disconnected from BrowserSync");
}
shouldReload = true;
});
initialised = true;
}
};
/**
* Handle individual socket connections
*/
socket.on("connection", exports.init);
/**debug:start**/
if (window.__karma__) {
window.__bs_scroll__ = require("./ghostmode.scroll");
window.__bs_clicks__ = require("./ghostmode.clicks");
window.__bs_location__ = require("./ghostmode.location");
window.__bs_inputs__ = require("./ghostmode.forms.input");
window.__bs_toggles__ = require("./ghostmode.forms.toggles");
window.__bs_submit__ = require("./ghostmode.forms.submit");
window.__bs_forms__ = require("./ghostmode.forms");
window.__bs_utils__ = require("./browser.utils");
window.__bs_emitter__ = emitter;
window.__bs = BrowserSync;
window.__bs_notify__ = notify;
window.__bs_code_sync__ = codeSync;
window.__bs_ghost_mode__ = ghostMode;
window.__bs_socket__ = socket;
window.__bs_index__ = exports;
}
/**debug:end**/
},{"./browser-sync":1,"./browser.utils":2,"./client-shims":3,"./code-sync":4,"./emitter":5,"./events":6,"./ghostmode":12,"./ghostmode.clicks":7,"./ghostmode.forms":9,"./ghostmode.forms.input":8,"./ghostmode.forms.submit":10,"./ghostmode.forms.toggles":11,"./ghostmode.location":13,"./ghostmode.scroll":14,"./notify":16,"./socket":17}],16:[function(require,module,exports){
"use strict";
var scroll = require("./ghostmode.scroll");
var utils = require("./browser.utils");
var styles = {
display: "none",
padding: "15px",
fontFamily: "sans-serif",
position: "fixed",
fontSize: "0.9em",
zIndex: 9999,
right: 0,
top: 0,
borderBottomLeftRadius: "5px",
backgroundColor: "#1B2032",
margin: 0,
color: "white",
textAlign: "center",
pointerEvents: "none"
};
var elem;
var options;
var timeoutInt;
/**
* @param {BrowserSync} bs
* @returns {*}
*/
exports.init = function (bs) {
options = bs.options;
var cssStyles = styles;
if (options.notify.styles) {
if (Object.prototype.toString.call(options.notify.styles) === "[object Array]") {
// handle original array behavior, replace all styles with a joined copy
cssStyles = options.notify.styles.join(";");
} else {
for (var key in options.notify.styles) {
if (options.notify.styles.hasOwnProperty(key)) {
cssStyles[key] = options.notify.styles[key];
}
}
}
}
elem = document.createElement("DIV");
elem.id = "__bs_notify__";
if (typeof cssStyles === "string") {
elem.style.cssText = cssStyles;
} else {
for (var rule in cssStyles) {
elem.style[rule] = cssStyles[rule];
}
}
var flashFn = exports.watchEvent(bs);
bs.emitter.on("notify", flashFn);
bs.socket.on("browser:notify", flashFn);
return elem;
};
/**
* @returns {Function}
*/
exports.watchEvent = function (bs) {
return function (data) {
if (bs.options.notify || data.override) {
if (typeof data === "string") {
return exports.flash(data);
}
exports.flash(data.message, data.timeout);
}
};
};
/**
*
*/
exports.getElem = function () {
return elem;
};
/**
* @param message
* @param [timeout]
* @returns {*}
*/
exports.flash = function (message, timeout) {
var elem = exports.getElem();
var $body = utils.getBody();
// return if notify was never initialised
if (!elem) {
return false;
}
elem.innerHTML = message;
elem.style.display = "block";
$body.appendChild(elem);
if (timeoutInt) {
clearTimeout(timeoutInt);
timeoutInt = undefined;
}
timeoutInt = window.setTimeout(function () {
elem.style.display = "none";
if (elem.parentNode) {
$body.removeChild(elem);
}
}, timeout || 2000);
return elem;
};
},{"./browser.utils":2,"./ghostmode.scroll":14}],17:[function(require,module,exports){
"use strict";
/**
* @type {{emit: emit, on: on}}
*/
var BS = window.___browserSync___ || {};
exports.socket = BS.socket || {
emit: function(){},
on: function(){}
};
/**
* @returns {string}
*/
exports.getPath = function () {
return window.location.pathname;
};
/**
* Alias for socket.emit
* @param name
* @param data
*/
exports.emit = function (name, data) {
var socket = exports.socket;
if (socket && socket.emit) {
// send relative path of where the event is sent
data.url = exports.getPath();
socket.emit(name, data);
}
};
/**
* Alias for socket.on
* @param name
* @param func
*/
exports.on = function (name, func) {
exports.socket.on(name, func);
};
},{}],18:[function(require,module,exports){
var utils = require("./browser.utils");
var emitter = require("./emitter");
var $document = utils.getDocument();
// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange;
if (typeof $document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof $document.mozHidden !== "undefined") {
hidden = "mozHidden";
visibilityChange = "mozvisibilitychange";
} else if (typeof $document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof $document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
// If the page is hidden, pause the video;
// if the page is shown, play the video
function handleVisibilityChange() {
if ($document[hidden]) {
emitter.emit("tab:hidden");
} else {
emitter.emit("tab:visible");
}
}
if (typeof $document.addEventListener === "undefined" ||
typeof $document[hidden] === "undefined") {
//console.log('not supported');
} else {
$document.addEventListener(visibilityChange, handleVisibilityChange, false);
}
},{"./browser.utils":2,"./emitter":5}]},{},[15]);