carene_waterman: An image of the Carina Nebula (Default)
It all started with this Suggestion.

What the OP of the suggestion was doing was using the old Zapimages bookmarklet, made years ago by Jesse Ruderman, and still available at his site.

I've had that handy little bookmarklet sitting in my toolbar on Firefox for years. What the OP was experiencing was the text in the arrow icons for cuttags not updating. I started looking into why that happened and that led me on a trip through some JavaScript concepts that I hadn't had a practical exposure to. If you're not into code, this will be a boring trip, but I'm chronicling my journey mostly as an exercise in learning and reinforcement.

Original Bookmarklet


First I looked at the original bookmarklet code, which stripped of it's enclosing function and put through the beautifier looks like this:

The Code


function toArray(c) {
    var a, k;
    a = new Array;
    for (k = 0; k < c.length; ++k) a[k] = c[k];
    return a;
  }
  var images, img, altText;
  images = toArray(document.images);
  for (var i = 0; i < images.length; ++i) {
    img = images[i];
    altText = document.createTextNode(img.alt);
    img.parentNode.replaceChild(altText, img);
  }

What it does


Okay, what this does is two things. First, there's a helper function that takes one object of items and puts it into a new array. This is used on the images node list.

Second, the array of images is iterated over and the image is replaced with its alt text which has been made into text content with no enclosing html element.

This works really well as a blunt-force tool that strips the images out of the document and allows the alt text to become link text if the image is a link, or to sit there as description otherwise.

It does not respond to dynamically changing pages and it will conflict with other scripts that swap images for whatever reason, because the image is actually removed from the document, there is no image there anymore to swap.

My analysis


The first thing I wondered about was the last thing I figured out. Why is that helper function even there? It just moves the nodelist (which is an object, not an array) into an array.

The reason is because nodelists are dynamic. As the removal loop goes through, it is taking things out of the nodelist, but not the array copy. You can't just run the for loop on the nodelist, because the nodelist length keeps getting shorter and the image you just removed is lopped off the front, so the image you really want to work on is always at index 0. Oh, hey!

Revised code with no helper function


var img, altText;
var images = document.images;
var imagesLength = images.length;
  for (var i = 0; i < imagesLength; i += 1) {
    img = images[0];
    altText = document.createTextNode(img.alt);
    img.parentNode.replaceChild(altText, img);
  }


What it does


Now we just take the nodelist, note its original length, iterate over the list by that length and always work on the image at index 0.

This works fine, is shorter and (not detectable by a human) less of a performance drag. It could be made even more succinct by leaving out those temporary variables:

var images = document.images;
var imagesLength = images.length;
  for (var i = 0; i < imagesLength; i+=1){
    images[0].parentNode.replaceChild(document.createTextNode(images[0].alt), images[0]);
  }


does exactly the same thing, but is a little harder to read. There's a lot less to fuss around with taking out space and linebreaks though, and is likely a "better" coding style, since it doesn't bother with variables that aren't really used for anything. This is something you don't need to care about, I don't think, when you're making a bookmarklet. It is something you need to know to program at a bigger scale (where you can document what that complex expression does).

Zap the image a little more lightly


So, the source of the DW user's problem with the above code was that the image is gone and can't be swapped for the new one when you click on a cuttag expander. The simplest answer to this problem is to not remove the img tag itself, but to make it not display the image. When you do that the browser will just display the alt text for you making the whole process simpler.

var images = document.images;
for (var i=0; i < images.length; i+=1) 
    images.item(i).removeAttribute("src");


What it does


We just load up the nodelist and take the src attribute off each one. Easy. Peasy, even. On DW, when you click a cuttag expander, the new arrow loads as an image, and you can carry on reading. You can click the bookmarklet again to get rid of any new images that appear in the new page content.

My analysis (or why this fails)


I travelled down this path for quite a while. I added refinements to have it insert some default text when there was no alt text, resize the images so they weren't taking up huge amounts of space anymore, and I looked at ways of automatically detecting new content on the page and running the script again. Most of this works well, although the auto-remove of new content is a bit hacky, but it only works in Firefox (and likely the current Opera).

Bloody Chrome.

Okay, and to be fair to bloody Chrome, my code does violate web standards which say an img tag should have a valid src. The problem is that Chrome (and most other webkit browsers) and IE, reload the image if you strip its src attribute. Also if you set it to an empty string. In addition webkit browsers do a weird thing with images that don't load by displaying alt text only some of the time.

For more information of this if you're curious here's some links I collected:

Down the remove the src attribute path


For posterity, here's my works only in Firefox, souped up bookmarklet:
/*Make a .forEach that works on objects*/

var forEach = Array.prototype.forEach;

/*Get nodelists of these elements*/

var images = document.getElementsByTagName("img");
var links = document.getElementsByTagName("a");
var buttons = document.getElementsByTagName("button");

/*This function removes the src, width and height of each image and inserts default alt text when an image has none and is inside a link tag.*/

function removeImages()  {
  forEach.call(images, removal); 
  function removal(img){
    img.removeAttribute("src");
    img.removeAttribute("width");
    img.removeAttribute("height");
    var imageAlt = img.getAttribute("alt");
    if ((imageAlt === "" || imageAlt === " ")&& img.parentNode.nodeName.toLowerCase() === 'a') {
        img.setAttribute("alt", "Image");
        }    
  }
}

/*This runs the image removal function after a delay of 5 seconds*/

function delayedRemoval () {
  window.setTimeout(removeImages, 5000);
  }

/*This calls the image removal when you click on the bookmarklet*/

removeImages();
/*This puts an event listener on each button or link and then calls the delayed image removal function if any are clicked on*/

forEach.call(links, function(link){ 
  link.addEventListener("click", delayedRemoval);
});
forEach.call(buttons, function(button){ 
  button.addEventListener("click", delayedRemoval);
});

What it does


Okay, this is a big change from the short and pithy start of this concept, but it's not much more complex.

First, there's a new feature in here, the use of the .forEach method. Which is an array method that removes the need for all those for loops that look identical and repeating them violates DRY (don't repeat yourself). I already turfed the code where the nodelist gets made into an array, though and I didn't really want it back. MDN to the rescue. That page contains instructions for ways of using .forEach on objects. I picked the one where you .call the function defined in the very first line of this code.

Next up, we get nodelists of all the images, links and buttons.

The basic task of changing the attributes on each image is inside a function now. It also has a conditional statement that adds the text, "Image" if there is no alt text present and the image is inside a link. This gives you something to actually click on to use the link. (Very handy on Wikis where the use of alt text is very spotty and weirdly implemented.)

There is another function that calls the removal function with a time delay. This gets invoked when a button or link on the page is clicked. It's a (somewhat) hacky way of running the removal automatically whenever new content gets added to the page. This is usually done by a show/hide link or button. If a page designer uses that horrible technique of making a span act like a button, then this won't work, but it fails silently, and you can always just click the bookmarklet again.

My analysis


Gotta say, I like this code, not least for the way I got that for each thing to work first go, and I'll likely put it in use for myself, but the only on Firefox thing makes it of limited value.

Some improvements could also be made to the resizing of images, to allow for pages that size the image via the CSS or via a parent div. The goal there is to get the alt text to flow better and to not have text cut off. The abomination that is absolutely positioned icons is a problem however.

Also, I think it is a real hole in the Document Object Model that there's no way to trigger a script when the page dynamically changes by having hidden content un-hidden by a script (MutationObserver does not do this) since every other page has this effect on it. Obviously if I was writing a script for a specific website, I could build in the correct event listeners with class names, but a general purpose method would be nice.

So what then?


Someone else on the DW Suggestions post has an idea to use the bookmarklet to toggle images on and off. It doesn't quite work--has a couple of minor bugs, one of which I'm still trying to figure out--but I don't think it's the direction I want to go. If you click on a cuttag, you still don't see the arrow for collaps and the alt text still says expand and you have to click the bookmarklet twice to fix that.

So what do I want? Blue sky the idea first and then see if it's at all possible to do.

I want...


  • Images off, but not removed from the DOM so that dynamically added images will show up on the page at least as an image.

  • Limiting the text flow issues and overlap you get where the alt text is too long for the image container.

  • Works in at least FF, Webkit (Blink!) and current Opera.

  • Allows some way to respond to unhidden new content. Either automatically or a quick re-run of the removal script.

  • Making sure an image link with no alt text is still clickable.


And I might like...

  • Some custom style for image link alt text to avoid it not looking like a link when the native styling removes the regular link styling for the page

  • Some customs style for all the alt text to make it clear it is not regular content text.

  • Some visual designation that there was an image there--to help with no alt text images and image links.



So back to the drawing board to see if I can get the image gone enough to be invisible, but still there enough to be replaced. Part II comes when I've done that.
carene_waterman: An image of the Carina Nebula (Default)
Concurrently with studying JavaScript and jQuery in the abstract, I decided to do a project to help me put the things I know into skills I've actually used.

Make things less abstract, in other words, or the exact opposite of what programming is all about.

I set up Git locally, made a set of files for a webpage--I like to use Geany to edit HTML and CSS files and display the result in Firefox so I can use the Web Developer tools to mess about without having to edit and re-edit the code file.

I'm making a basic website with a couple of pages with hand-coded HTML and CSS. I have a design idea of what the site does--display some images and text and link to an archive of previous sets.

The plan is to set it up so it works, thereby getting some practical HTML and CSS experience that isn't skinning an existing site like DW styles do.

Next up, I'll redo it with Twitter Bootstrap to learn it and LESS in a real way.

Somewhere in there I'll put in some JS or JQ effects.

At that point I really hope to be able to do it again using Rails to make the site. We'll see.

So far, it seems a bit silly to be committing small changes in a very simple set of four files, but the Git practice is really helping make Git real, and I'm learning the parts of HTML that I've never needed before.

Additionally, it is so, so ,so ,so to ifinity nice to have HTML that I've coded, that has rational and simple class names and isn't bloated with extra divs.

DW's code is very, very good, but it has a lot of built-in flexibility and therefore complexity that it's nice to dispose of.

This is a great project I would recommend to anyone who wants to improve their skills beyond tweaks and skins.

You know what you need? A browser and a text file editor--which you already have.

Make your HTML file, link your CSS file and load the HTML file from your browser's File menu. Boom, you're developing. In the browser--the way you'll learn the best.
carene_waterman: An image of the Carina Nebula (Default)
I bloodied my nose pretty hard on the Functional Programming chapter in Eloquent JavaScript. I went back a few days later and got through the first half okay and hit a wall again.

While I wait for a time stretch long enough and quiet enough to give it another go, I thought I'd go back to Codecademy and get some instant gratification (and frustration).

I tested out the HTML and CSS tracks to see if they were worth recommending and I'd give a heavily qualified meh as a rating.

I found these lessons the buggiest of all, and any exercise that uses a height or font size property requires you to have no minimum font size set in your browser and to be viewing at the un-zoomed size. Um, yeah, no.

If that's not a deal breaker for you, be aware that they were written when the submit and results display were obviously functioning differently (and submit was called run). I found you had to click things in the right order, hit submit multiple times, and occasionally save the code and refresh the page to get the lesson to validate. You get a lot of false negative results claiming your code doesn't work. They are working on their UI so this is likely to improve.

But this does dynamically teach you HTML and then integrates CSS into what you know--and then adds in JS and jQuery in some off-track projects.

That part is great and pretty much impossible to find (free) anywhere else.

I didn't like the way they showed examples of bad semantics in early lessons or the way they introduced styling with inline html styles first. (Although for DW users wanting to know how to style things in a post, this isn't useless info.) They don't put any emphasis on best practices and never utter the words web standards.

Some of the lessons link to W3Schools for reference docs, which is appalling, and they're aimed at a very young audience.

Still, it's interactive, you instantly know what things do and you get to experiment.

I skipped over to the jQuery track, which assumes you don't know JS, but doesn't tell you that on the main page. I would have done it sooner, had I known, but also I think that's the wrong order.

Don't learn jQuery without at least a 101 understanding of JS. Don't be one of those people who can do all kinds of cool shit with jQuery but are baffled by the simplest native JS statements and don't know anything about how JS uses the DOM API. You won't be able to debug anything that goes deeper than how you wrote the jQuery.

That said, OMG is jQuery easy to learn. It is so intuitive to anyone familiar with HTML and css, it barely needs explaining beyond the syntax.

I also found the Codecademy jQuery track the best written I've done so far. It's not too twee and it's less about testing how carefully you read the riddle instructions and how well you can copy and paste (the JS track) and more about learning through repetition and building of skills.

It is buggy--I had to make sure my cursor was at the bottom of the code in the .js tab, and then I had to hit results, do the user action on the results tab and hit submit several times for almost every exercise.

If you like text based instruction, with example code, but no exercises, nothing beats Shay Howe's HTML and CSS guide (The beginners guide is available at the same site.) He teaches the two things side-by-side, as they really should be.
carene_waterman: An image of the Carina Nebula (Default)
We bought a table saw. We bought it for a specific purpose where a hand-held power saw would just not cut it. We did the job, put the table saw away and mostly forgot about it.

We set it up again recently and searched out some learnings on its use. Jon Eakes videos are a good start, but that's epic amount of stuff on Youtube. After a while, you'll get overwhelmed by the sheer number of jigs people have built for particular tasks.

Kind of like jQuery libraries.

The thing is, even once you know how to do various things on the table saw in an abstract sort of way--practising a crosscut on a piece of scrap is pretty abstract--you still don't use the saw much.

What you need to do is change the way you think about doing a job. You need to get used to what the possibilities are, so at the planning stage you can make decisions you can carry out. If you never had a took that could cut a mortise and tenon, you might not think of that kind of solution.

This is exactly the same learning curve with programming. Until you know how to think as a programmer, all you're doing is writing code to fit an existing template you've been shown.

It's getting the mind reordered that's the long up slope of the learning curve.

(I think I just made an argument for site design including people who understand both the front end and the back end working together.)

Yay!

Mar. 14th, 2013 06:13 pm
carene_waterman: An image of the Carina Nebula (Default)
Retrying Eloquent JavaScript and I got through the Objects and Arrays chapter (all those cats!) much better than before and I'm stumbling over syntax a lot less.

I guess I'm a little more awake in March than I am in October.
carene_waterman: An image of the Carina Nebula (Default)
I'm getting back into the JavaScript. I really like the Eloquent Javascript book and online learning system.

When I worked on it before, it really brought home how Codeacademy's methods tech you to mimic code without learning it in any conceptual way. This can be okay for very beginner stuff, but it gets to a point where you're not learning, just copying forms.

I hit a wall in Eloquent, and decided to redo one of the basic projects and then ran out of any free time. I'm just going to start over. I will report back!

Bash!

Mar. 7th, 2013 12:04 pm
carene_waterman: An image of the Carina Nebula (Default)
That was fast. I bashed my way through the lessons on using the Command Line in two sessions over two days. (see my previous post for details)

It was fun, and I managed to dredge up some things from the dusty, dark recesses of my mind I knew already.

The tone of the instruction is stroppy, and I can see how that might put some people off. If you need stroking and gold stars and woots, you might not like this. I loved it.

I just wish it went on in more depth, but it makes me think his Ruby the Hard Way book might be for me.

Bash! I have conquered Terminal (on easy level anyway).
carene_waterman: An image of the Carina Nebula (Default)
I spent three months doing things in physical space, not digital.

I decided to detour from JavaScript and get myself up to speed on using Git since I'm interested in a project that takes on newbs that's on Git.

Yeah.

I just can't remember enough DOS(it's from the dark ages, don't worry if you've never heard of it) to fake it in Terminal, even thought Git seems simple enough to get the hang of.

So, I'm backing up the truck and trying out The Command Line Crash Course.

I will report back.

Profile

carene_waterman: An image of the Carina Nebula (Default)
carene_waterman

July 2014

S M T W T F S
  12345
6789101112
13141516171819
2021 22 2324 2526
2728293031  

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Sep. 25th, 2017 06:54 pm
Powered by Dreamwidth Studios