Twine Tuesday: No-click Twine (without jQuery)

Like many other people who follow the work done in the Twine scene, I was excited to see Christine Love’s Even Cowgirls Bleed. It was the first working project I’d seen that got away from the “click” needed to progress in Twine. Unlike many other people though, I was also eager to find out how it all worked.

See, she beat me to figuring out how to do “no click” in Twine.

I’d been working on a way to have the same effect (without jQuery) and wasn’t having much success. I’d get it to work in one browser, and then find out it now didn’t work in another. It was a constant struggle to balance all the bizarre different ways IE, Firefox, and Webkit browsers handle and register event listeners.

Finally though, here was a working solution I could use as a basis to build my own code. And, within a few hours of pouring through it, I saw what I was missing, integrated it into my stuff, and had a working solution myself. Then, of course, I learned Safari, but not Chrome, had trouble with it.

A few days and many hours of work later, I had something that worked nearly everywhere (it still doesn’t work in IE 8 or earlier) and was relatively straightforward. Still, this is a work in progress and should be treated as such. However, I’ve tested it in IE 9+, and the latest versions of Firefox, Chrome and Safari. It seems to work correctly across them.


:: Start

:: script [script]
 mouseEvent() from
function mouseEvent(type, sx, sy, cx, cy) {
  var evt;
  var e = {
    bubbles: true, cancelable: (type != "mousemove"), view: window, detail: 0,
    screenX: sx, screenY: sy, clientX: cx, clientY: cy,
    ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
    button: 0, relatedTarget: undefined

  if (typeof( document.createEvent ) == "function") {
    evt = document.createEvent("MouseEvents");
    evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
    e.screenX, e.screenY, e.clientX, e.clientY,
    e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
    e.button, document.body.parentNode);
  } else if (document.createEventObject) {
    evt = document.createEventObject();
    for (prop in e) {
      evt[prop] = e[prop];
    evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
  return evt;

function dispatchEvent (el, evt) {
  if (el.dispatchEvent) {
  } else if (el.fireEvent) {
    el.fireEvent("on" + type, evt);
  return evt;

var oldCreateInternalLink = Wikifier.createInternalLink;
Wikifier.createInternalLink = function(place, title) {

   link = oldCreateInternalLink(place, title);

   if (link.addEventListener) 
       link.addEventListener('mouseover', function () {
            var evt = mouseEvent("click", 0,0,0,0);
            dispatchEvent(this, evt);
   = "none";
            this.removeEventListener("mouseover", function(){});
       }, false); 
   else if (link.attachEvent)  
      link.attachEvent('mouseover', function () {
           var evt = mouseEvent("click", 0,0,0,0);
           dispatchEvent(this, evt);
  = "none";
           this.detachEvent("mouseover", function(){});
      }, false);
    return link;

:: Test
[[Test 2]]

:: Test 2

2 thoughts on “Twine Tuesday: No-click Twine (without jQuery)

    • I guess.

      I actually felt rather foolish once I saw how she solved it. I had all the steps lined up but the very last one. I didn’t think of overwriting Wikifier.createInternalLink(). Everything else I had worked though.

Comments are closed.