Paul Irish

Making the www great

How to Quickly Find a Layer in a Big PSD

psdlayers.PNG I’ll often get PSDs from my visual designers with hundreds of layers. When I’m slicing it up, I’ll need to find a specific layer. And much of the time, I don’t instantly understand the layer architecture that was defined.

Using the “Auto Select layer” option on the move tool gets partway there, but it chokes on layer groups.

The quickest route possible: Alt-right-click That will immediately select the layer of whatever you clicked on. (The move tool (V) must be active. This doesnt work while on other tools.)

(On Mac, this has an additional click: option-click. then the revealed menu has your layer currently selected. click it.)

jQuery doOnce Plugin for Chaining Addicts

1
2
3
4
5
// jQuery doOnce plugin
jQuery.fn.doOnce = function(func){
    this.length && func.apply(this);
    return this;
}

This allows you to execute arbitrary script during a single chain. A bad example of alert() debugging follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// example usage of doOnce()
$('div.toGrow')
  .doOnce(function(){
    alert('before color swap');
  })
  .css({ backgroundColor: 'red'})
  .find('h2')
    .text('And now we\'re red')
    .end() // go back to the div.toGrow
  .animate({ height: '+=50px'},'normal','swing',function(){
    $(this)  // callback when animations complete
      .find('h2')
        .text('And now we\'re taller')
        .doOnce(function(){
          alert('animation done');
        });
  });

Note this is a little different than each(), which will execute once for every element in your current collection.


The code is pretty trivial, but sometimes you just feel like it. Nobody likes to break the chain!
Update 2009.03.04: Length checking added. thx cohitre.

How to Tweak 3rd Party Scripts “Safely”

I’m working with some code from MultiMap (basically a Google Maps clone), and unfortunately their API doesn’t support real internationalization. There are a number of strings hardcoded in English in their remotely-hosted JS, so this is my deliciously evil way of rectifying the situation.

I first started out redefining their functions in entirety, but that becomes “dangerous” when they modify a bit of code for a bug fix or something. This revised approach slips in like an evil drunken ninja and only replaces the offending parts. It’s still completely crazy, but sometimes there are no better options…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// WARNING!!  This is such a massive hack. Oh-so-hackalicious

// Problem:     Multimap doesnt allow internationalization of its buttons, etc.
// Solution:    Redefine their JS functions to use variables that are internationalized.
// Assumption:  That these internal function names stay the same. 
// Risk:        If function names change, this code will (probably) silently fail.

// The following statements change the right-click context menu items and the map/aerial/hybrid buttons.
// Instead of hard-coded strings, it will use a variable which we control.

// ON TO THE HACKS!!
// Hack 1: modify the mmjr() and mmfl() functions with funcName.toString().replace()
// Hack 2: use eval() to set the definition
// Hack 3: browser sniff because IE and FF handle toString()'d strings differently (single-quote vs double-quote)

var isIE = $.browser.msie; // jQuery browser sniff.

eval(
  "mmki.prototype.mmjr = " +
  mmki.prototype.mmjr
  .toString()
    .replace( isIE ? "'Move map to here'" : '"Move map to here"' ,      'i18n.retailLocator.moveMapToHere')
    .replace( isIE ? "'Zoom in to here'" : '"Zoom in to here"' ,        'i18n.retailLocator.zoomInToHere')
    .replace( isIE ? "'Zoom out from here'" : '"Zoom out from here"',   'i18n.retailLocator.zoomOutFromHere')
  );

eval(
  "MultimapViewer.prototype.mmfl = " +
  MultimapViewer.prototype.mmfl
  .toString()
    .replace( isIE ? "'Map'" : '"Map"',       'i18n.retailLocator.map')
    .replace( isIE ? "'Hybrid'" : '"Hybrid"', "i18n.retailLocator.hybrid")
    .replace( isIE ? "'Aerial'" : '"Aerial"', 'i18n.retailLocator.aerial')
);