tools
/
gw2-tooltips
Archived
1
0
Fork 0
This repository has been archived on 2022-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
gw2-tooltips/dist/js/GW2Tooltip.js

598 lines
20 KiB
JavaScript

"use strict";
/**
* Tooltip.
*
* @class
*/
var GW2Tooltip = (function()
{
/**
* Private functions for DOM interaction.
*
* @type {object}
*/
var Element =
{
/**
* Converts a string to a DOM element and returns this. If the string
* contains more than one element on the highest level, only the
* first node is returned.
*
* @method stringToNode
* @param {string} string the string.
* @return {object} a DOM element.
*/
stringToNode : function(string)
{
var parent = document.createElement("div");
parent.innerHTML = string;
return parent.firstChild;
},
/**
* Inserts an element in the DOM after another element.
*
* @method insertAfter
* @param {object} e1 the element after which is to be
* inserted.
* @param {object} e2 the element to be inserted.
*/
insertAfter : function(e1, e2)
{
e1.parentNode.insertBefore(e2, e1.nextSibling);
}
};
/**
* API access.
*
* @class
*/
var APIAccess = (function()
{
var queue = {};
/**
* Returns a cross-domain request object, or undefined if the browser
* sucks.
*
* @method getCORSRequest
* @return {(XMLHttpRequest|ActiveXObject)} a cross-domain request
* object, or undefined
* if the browser
* sucks.
*/
var getCORSRequest = (function()
{
var validFactory = -1,
factories = [
//function() { return new XDomainRequest(); },
function() { return new XMLHttpRequest(); },
function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
function() { return new ActiveXObject("Msxml3.XMLHTTP"); },
function()
{
return new ActiveXObject("Microsoft.XMLHTTP");
}
];
// Try out all factories and save index of first factory that works.
var factory,
i, length = factories.length;
for(i = 0; i < length; i++)
{
try
{
factory = factories[i]();
validFactory = i;
break;
}
catch(e)
{
continue;
}
}
// Return a function that returns the cross-domain request object.
return function()
{
if(validFactory >= 0)
return factories[validFactory]();
else
return undefined;
};
})();
/**
* Reads JSON from the given URL and passes this to the callback.
*
* @method getJSONP
* @param {string} url the URL of the JSON.
* @param {Function} callback the function to pass the JSON to.
*/
var getJSONP = function(url, callback)
{
var _baseURL = "https://api.guildwars2.com/";
var xmlhttp = getCORSRequest();
xmlhttp.onreadystatechange = function()
{
if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
if(typeof callback === "function")
callback(Polyfill.JSONParse(xmlhttp.response));
};
xmlhttp.open("GET", _baseURL + url, true);
xmlhttp.send();
};
/**
* Public functions.
*
* @type {object}
*/
var exports = {};
/**
* Requests data for a single tooltip from the API right away.
*
* @method requestData
* @param {number} id the id of the data.
* @param {class} generator the generator to use for the
* tooltip.
* @param {Function} callback the function to pass the JSON to.
*/
exports.requestData = function(id, generator, callback)
{
getJSONP("/v2/" + generator.type + "/" + id, callback);
};
/**
* Adds the id for a single tooltip to the request queue.
*
* @method queueData
* @param {object} e the element to add the tooltip to
* after completing the queue.
* @param {number} id the id of the data.
* @param {class} generator the generator to use for the
* tooltip.
*/
exports.queueData = function(e, id, generator)
{
var type = generator.type;
if(queue[type] === undefined)
queue[type] = [];
queue[type].push([e, id]);
};
/**
* Executes the queue and adds all tooltips to the right elements, and
* then empties the queue.
*
* @method executeQueue
* @param {class} generator the generator to use for the
* tooltip.
* @param {Function} callback the function to pass the JSONs to.
*/
exports.executeQueue = function(generator, options, callback)
{
var type = generator.type;
if(queue.length === 0)
return;
if(queue[type] === undefined)
return;
if(queue[type].length === 0)
return;
// Build URL
var url = [],
i, length = queue[type].length;
for(i = 0; i < length; i++)
url.push(queue[type][i][1]);
// Get JSON and add respective tooltips
getJSONP("/v2/" + type + "?ids=" + url.join(","), function(json)
{
var i, length1 = queue[type].length,
j, length2 = json.length;
for(i = 0; i < length1; i++)
for(j = 0; j < length2; j++)
if(json[j].id == queue[type][i][1])
callback(queue[type][i][0], json[j], generator,
options);
queue[type] = [];
});
};
return exports;
})();
var exports = {};
/**
* Adds a tooltip to the given element.
*
* @method addDirect
* @param {object} e the element to add the tooltip to.
* @param {object} json the data. Should have the structure as
* specified in the Guild Wars 2 API
* version 2 documentation.
* @param {class} generator the generator to use for the tooltip.
* @param {class} options additional parameters for the tooltip.
* Options starting with "link" are
* used to manipulate the contents of
* the tooltip link, which is the
* element to which the tooltip is
* added. These options can be applied
* together. Use option "linkReplace"
* to indicate whether the contents of
* the link should be replaced with the
* new information or should be
* prepended instead.
* The following options are
* recognised:
* "linkIcon" :
* true if the link info should
* contain an <img />
* element with the
* tooltip's icon; should
* be false or undefined
* otherwise.
* Use option
* "linkIconClass" to
* optionally set the class
* of these images.
* "linkIconClass":
* if "linkIcon" is true, the
* added icons will have
* the class defined in
* this option.
* "linkInfo" :
* false or undefined if no
* info should be added to
* the link; should be a
* string to add info from
* the tooltip (e.g.
* "name", "id",
* "chat_link" etc.). See
* the Guild Wars 2 API for
* all possible values.
* "linkReplace" :
* true to replace the link's
* contents with the
* content defined with
* other options starting
* with "link"; false to
* prepend this content to
* the link instead. If no
* new content is defined,
* an empty string will
* replace or prepend the
* link's contents.
*/
exports.addDirect = function(e, json, generator, options)
{
// Default parameter values
options = (options || {});
options.linkIcon = (options.linkIcon || false);
options.linkIconClass = (options.linkIconClass || "");
options.linkInfo = (options.linkInfo || false);
// If no link contents are generated, prepend with empty string
options.linkReplace = (options.linkReplace || false);
// Parse JSON if needed
if(typeof json === "string")
json = Polyfill.JSONParse(json);
Polyfill.addClass(e, "GW2TooltipLink");
var tooltip = new generator(json);
// Remove current tooltip if it is there
if(e.nextSibling !== null &&
Polyfill.hasClass(e.nextSibling, "GW2Tooltip"))
e.parentNode.removeChild(e.nextSibling);
// Change tooltip link if needed
var innerHTML = (options.linkReplace ? "" : e.innerHTML);
// Addition should be in reversed order of appearance
if(options.linkInfo !== false)
{
innerHTML = json[options.linkInfo] + innerHTML;
}
if(options.linkIcon === true)
{
innerHTML = "" +
"<img src=\"" +
json.icon +
"\" class=\"" +
options.linkIconClass +
"\" /> " +
innerHTML;
}
e.innerHTML = innerHTML;
// Insert tooltip
Element.insertAfter(e,
Element.stringToNode(tooltip.getTooltip()));
};
/**
* Adds a tooltip to the given element.
*
* @method addNow
* @param {object} e the element to add the tooltip to.
* @param {number} id the id of the data.
* @param {class} generator the generator to use for the tooltip.
*/
exports.addNow = function(e, id, generator, options)
{
APIAccess.requestData(id, generator, function(json)
{
exports.addDirect(e, json, generator, options);
});
};
/**
* Adds a tooltip to the given element as soon as the user hovers over the
* link. Decreases page load time and increases tooltip appear time.
*
* @method addLater
* @param {object} e the element to add the tooltip to.
* @param {number} id the id of the data.
* @param {class} generator the generator to use for the tooltip.
*/
exports.addLater = function(e, dataId, generator, options)
{
var curEvent = e.onmouseover;
e.onmouseover = function()
{
if(typeof curEvent === "function")
curEvent();
APIAccess.requestData(dataId, generator, function(json)
{
exports.addDirect(e, json, generator, options);
});
};
};
/**
* Adds tooltips for all elements with the data-[type]id tag. This is
* usually done directly after loading the page.
*
* @method addAllNow
* @param {class} generator the generator to use for the tooltip.
*/
exports.addAllNow = function(generator, options)
{
var eList,
i, length;
// Get all elements with proper data attribute.
if(document.querySelectorAll)
{
eList = document.querySelectorAll("[data-" + generator.attr + "]");
}
else
{
// Custom polyfill
var e, eAll = document.getElementsByTagName("*");
length = eAll.length;
for(i = 0; i < length; i++)
{
e = eAll[i];
if(e.dataset !== undefined &&
e.dataset[generator.attr] !== undefined)
{
eList.push(e);
}
}
}
// Queue tooltips
length = eList.length;
for(i = 0; i < length; i++)
{
APIAccess.queueData(
eList[i],
eList[i].dataset[generator.attr],
generator
);
}
// Add tooltips
APIAccess.executeQueue(generator, options, exports.addDirect);
};
/**
* Static tooltip data. Used by other Tooltip classes.
*
* @type {object}
*/
exports.TooltipData =
{
// List of icons.
icons :
{
base :
"https://render.guildwars2.com/file/",
ui_coin_gold :
"090A980A96D39FD36FBB004903644C6DBEFB1FFB/156904.png",
ui_coin_silver :
"E5A2197D78ECE4AE0349C8B3710D033D22DB0DA6/156907.png",
ui_coin_copper :
"6CF8F96A3299CFC75D5CC90617C3C70331A1EF0E/156902.png",
ui_infusion_slot_offensive :
"FD212A4A36BEA799E3BDCDFFDC55DEC2A50FE19D/517203.png",
ui_infusion_slot_defensive :
"3D941C5F3C0BE9FFAFE27A2C4AE70ABC94AAE724/517202.png",
ui_infusion_slot_utility :
"0B5F38D94AAA1539EC6009F4CF37DF5673C81DA0/517204.png",
ui_infusion_slot_agony :
"F54BC4283FFAB7531073FF08F470A9730E47FB4D/683590.png"
},
// List of attribute names.
attributes :
{
BoonDuration : "Concentration",
ConditionDamage : "Condition Damage",
ConditionDutation : "Expertise",
CritDamage : "Ferocity",
Healing : "Healing Power",
Power : "Power",
Precision : "Precision",
Toughness : "Toughness",
Vitality : "Vitality"
}
};
/**
* Polyfill functions for browser compatibility. Used by other Tooltip
* classes.
*
* @type {object}
*/
var Polyfill =
{
/**
* Sets the JSON parser to JSON4 if present, or falls back to JSON3,
* then to JSON2, then to default JSON and then to eval.
*
* @class
* @return {method} sets the JSON parser.
*/
JSONParse : function()
{
if(typeof JSON4 !== "undefined")
return JSON4.parse;
else if(typeof JSON3 !== "undefined")
return JSON3.parse;
else if(typeof JSON2 !== "undefined")
return JSON2.parse;
else if(typeof JSON !== "undefined")
return JSON.parse;
else
return function(sJSON)
{
// Provide a JSON library to prevent this eval from
// executing.
return eval("(" + sJSON + ")");
};
}(),
/**
* Returns the first index at which a given element can be found in the
* object, or -1 if it is not present.
*
* @method indexOf
* @param {object} object the object to traverse.
* @param {object} searchElement the element to locate in the
* object.
* @param {number} fromIndex the index to start the search
* at.
* @return {number} the first index at which a given element can be
* found in the object, or -1 if it is not
* present.
*/
indexOf : function(object, searchElement, fromIndex)
{
var k;
//if(object == null)
if(object === undefined || object === null)
throw new TypeError("\"this\" is null or not defined");
var o = Object(object),
len = o.length >>> 0;
if(len === 0)
return -1;
var n = +fromIndex || 0;
if(Math.abs(n) === Infinity)
n = 0;
if(n >= len)
return -1;
k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
while(k < len)
{
if(k in o && o[k] === searchElement)
return k;
k++;
}
return -1;
},
/**
* Returns true if the element has the given class.
*
* @method hasClass
* @param {object} element the element.
* @param {string} cls the class.
* @return {string} true if the element has the given class.
*/
hasClass : function(element, cls)
{
return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
},
/**
* Adds a class to the given element.
*
* @method addClass
* @param {object} element the element.
* @param {string} cls the class.
*/
addClass : function(element, cls)
{
if(!Polyfill.hasClass(element, cls))
element.className += (" " + cls);
},
/**
* Returns the comma-separated string of a number.
*
* @method commaSeparate
* @param {number} val the number to separate.
* @return {string} the comma-separated string of a number.
*/
commaSeparate : function(val)
{
val = val.toString();
var str = val,
dif = str.length - (3 * Math.floor(str.length / 3));
if(dif !== 0)
str = str.substr(dif, str.length);
var arr = str.match(/.{3}/g);
if(dif !== 0)
arr.unshift(val.substr(0, dif));
return arr.join(",");
}
};
exports.Polyfill = Polyfill;
return exports;
})();