Created
March 31, 2015 15:35
-
-
Save EliseWei/810ce13e309b827a2561 to your computer and use it in GitHub Desktop.
Magnetic Poetry js plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Triggered by an image map area with href="#magnetic" | |
(function() { | |
// Starting magnet z-index. | |
var z = 1000; | |
var d = document; | |
var b = d.getElementsByTagName('body')[0]; | |
var triggerGrandparents = []; | |
function initPanel() { | |
// In case the parsing takes a while, add a wait message. | |
var waitDiv = d.createElement('div'); | |
waitDiv.id = 'waitMsg'; | |
waitDiv.style.display = 'block'; | |
waitDiv.style.width = '50%'; | |
waitDiv.style.textAlign = 'center'; | |
waitDiv.style.color = '#000000'; | |
waitDiv.style.backgroundColor = '#ffffff'; | |
waitDiv.style.border = 'solid 2px #000000'; | |
waitDiv.style.borderRadius = '10px'; | |
waitDiv.style.padding = '50px 0'; | |
waitDiv.style.position = 'absolute'; | |
waitDiv.style.top = '250px'; | |
waitDiv.style.left = '25%'; | |
waitDiv.innerHTML = 'One moment...'; | |
b.appendChild(waitDiv); | |
// Add magnet styling. | |
var styleString = 'div.mag{display:inline-block;width:auto !important;margin:0 !important; ' + | |
'padding:0 !important; position:relative} div.mag em{display:block;visibility:hidden; ' + | |
'padding:0 .2em;border:solid 1px #000; font-family: "Times New Roman" !important;}' + | |
'div.mag span{background-color:#fff;border:solid 1px #999 !important;padding:0 .2em; ' + | |
'white-space:nowrap; color:#000 !important; display:inline-block;cursor:pointer; ' + | |
'position:absolute;left:0px;top:0px; font-family: "Times New Roman" !important;}'; | |
insertStyleSheet(styleString); | |
// Kick off parsing. | |
parseText(b); | |
}; | |
// This function steps through the DOM (with some exclusions), looking for text and images | |
// to turn into poetry elements. | |
function parseText(p) { | |
if (p.id != 'waitMsg') { | |
for (var t = 0, l = triggerGrandparents.length; t < l; t++) { | |
if (p === triggerGrandparents[t]) { | |
return; | |
} | |
} | |
// Reset some styles on the element. | |
p.style.backgroundColor = 'transparent'; | |
p.style.backgroundImage = 'none'; | |
p.style.overflow = 'visible'; | |
p.style.border = '0'; | |
var c = p.childNodes; | |
var nC = c.length; | |
for (var i = 0; i < nC; i++) { | |
if (c[i].nodeType == '3' && | |
c[i].textContent.replace(/^[\s]+|[\s]+$|\t+|\r+|\n+|\0+/, '').length > 1) { | |
// If a text node with content after stripping leading/trailing whitespace... | |
var nS = c[i].nextSibling; | |
if (nS) { | |
var sW = d.createElement('div'); | |
sW.style.display = 'inline'; | |
} | |
// Split into words on whitespace. | |
var w = c[i].textContent.split(/\s/); | |
c[i].textContent = ''; | |
for (var j = 0; j < w.length; j++) { | |
var pReg = /[\.\,\"\:\;\?\!\@]+/; | |
var nwReg = /[^A-z0-9\'\-\u2019\u2013]+/g; | |
if (w[j].search(pReg) != -1 && w[j].match(pReg).length < w[j].length) { | |
// Special characters in the word itself. Need to split further. | |
var nW = new Array; | |
var t = w[j]; | |
var tS = t.search(pReg); | |
var tML = t.match(pReg)[0].length; | |
var l = 0; | |
while (tS >= 0 && tML != t.length) { | |
if (tS == 0) {nW[l] = t.substr(0, tML);t = t.substr(tML);} | |
else {nW[l] = t.substr(0, tS).replace(nwReg, '');t = t.substr(tS);} | |
l++; | |
tS = t.search(pReg); | |
if (tS < 0) {nW[l] = t.replace(nwReg, ''); break} | |
tML = t.match(pReg)[0].length; | |
if (tML == t.length) {nW[l] = t; break} | |
} | |
for (var k = 0; k < nW.length; k++) { | |
if (nS) {sW.appendChild(magWrap(nW[k]))} | |
else {p.appendChild(magWrap(nW[k]));} | |
} | |
} else { | |
w[j] = w[j].replace(nwReg, ''); | |
if (w[j].length > 0) { | |
if (nS) {sW.appendChild(magWrap(w[j]))} | |
else {p.appendChild(magWrap(w[j]));} | |
} | |
} | |
} | |
if (nS) {p.replaceChild(sW, c[i]);} | |
} else if (c[i].nodeType == '1' && c[i].nodeName.toLowerCase() == 'img') { | |
// Wrap images. | |
var iStr = '<img '; | |
var q = 0; | |
for (q = 0; q < c[i].attributes.length; q++) { | |
iStr += c[i].attributes[q].name + '="' + c[i].attributes[q].value + '" '; | |
} | |
iStr += '/>'; | |
p.replaceChild(magWrap(iStr), c[i]); | |
} else if (c[i].nodeType == '1' && c[i].nodeName.toLowerCase() == 'map') { | |
// Clear out image maps. | |
p.removeChild(c[i]); | |
} else if (c[i].nodeType == '1' && c[i].nodeName.toLowerCase() != 'script') { | |
// If an HTML element other than a script, go deeper. | |
parseText(c[i]); | |
} | |
} | |
} | |
if (d.getElementById('waitMsg')) { | |
// Clear out wait message. | |
d.getElementById('waitMsg').style.display = 'none'; | |
} | |
}; | |
// Function to generate each magnetic element and identical placeholder element in original flow. | |
function magWrap(content, tag) { | |
// Div wrapping element. | |
var dW = d.createElement('div'); | |
dW.className = 'mag'; | |
// Hidden element to hold the space. | |
var h = d.createElement('em'); | |
h.style.visibility = 'hidden'; | |
h.innerHTML = content; | |
// The magnetic element for drag/drop. | |
var m = d.createElement('span'); | |
m.innerHTML = content; | |
m.onclick = stopEvents; | |
m.onmousedown = mClickStartHandler; | |
m.onmouseup = function(ev) { | |
if (this.onmousemove) { | |
this.onmousemove = null; | |
} | |
stopEvents(ev); | |
}; | |
dW.appendChild(h); | |
dW.appendChild(m); | |
return dW; | |
}; | |
function mClickStartHandler(ev) { | |
ev = ev || window.event; | |
var mS = this; | |
mS.style.zIndex = z; | |
// Every click, increment z, so newly-interacted-with elements stack on top. | |
z++; | |
// Center the magnetic span to original click point. | |
var parentPos = getPos(mS.parentNode); | |
var xDisp = parentPos.x + .5 * mS.offsetWidth; | |
var yDisp = parentPos.y + .5 * mS.offsetHeight; | |
// Bind dragging functionality only on click. | |
d.onmousemove = function(e) { | |
posx = eventRealXY(e).x; | |
posy = eventRealXY(e).y; | |
mS.style.left = posx - xDisp + 'px'; | |
mS.style.top = posy - yDisp + 'px'; | |
}; | |
// Unbind on mouseup, even if user somehow gets mouse off of element. | |
d.onmouseup = this.onmouseup = function(ev) { | |
if (d.onmousemove) d.onmousemove = null; | |
stopEvents(ev); | |
}; | |
stopEvents(ev); | |
}; | |
// Utility functions | |
function insertStyleSheet(cssString) { | |
var styleNode = d.createElement('style'); | |
styleNode.type = 'text/css'; | |
// browser detection (based on prototype.js) | |
if (!!(window.attachEvent && !window.opera)) { | |
styleNode.styleSheet.cssText = cssString; | |
}else { | |
var styleText = d.createTextNode(cssString); | |
styleNode.appendChild(styleText); | |
} | |
d.getElementsByTagName('head')[0].appendChild(styleNode); | |
}; | |
// Navigate up the DOM to get the element's position relative to the body for CSS purposes. | |
function getPos(el) { | |
for (var lx = 0, ly = 0; el != null;) { | |
lx += el.offsetLeft; | |
ly += el.offsetTop; | |
el = el.offsetParent; | |
} | |
return { | |
x: lx, | |
y: ly | |
}; | |
}; | |
function stopEvents(ev) { | |
ev.preventDefault(); | |
if (ev.stopPropagation) { | |
ev.stopPropagation(); | |
} | |
// For IE | |
ev.cancelBubble = true; | |
ev.returnValue = false; | |
return false; | |
}; | |
// Get coordinates of an event, relative to the body (cross-browser). | |
function eventRealXY(ev) { | |
var xCoord, yCoord; | |
if (ev.pageX || ev.pageY) { | |
xCoord = ev.pageX; | |
yCoord = ev.pageY; | |
} else { | |
xCoord = ev.clientX + d.body.scrollLeft + d.documentElement.scrollLeft; | |
yCoord = ev.clientY + d.body.scrollTop + d.documentElement.scrollTop; | |
} | |
return { | |
x: xCoord, | |
y: yCoord | |
}; | |
}; | |
// Bind initialization to the banner clickzone. | |
var clickzones = d.getElementsByTagName('area'); | |
for (var i = 0, l = clickzones.length; i < l; i++) { | |
var href = clickzones[i].getAttribute('href'); | |
if (href === '#magnetic') { | |
var banner = clickzones[i].parentNode && clickzones[i].parentNode.parentNode; | |
if (banner) { | |
triggerGrandparents.push(banner); | |
} | |
clickzones[i].onclick = initPanel; | |
} | |
} | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment