You can stop nested elements triggering their parent element event handlers (DOM bubbling) using this handy jQuery method:

http://api.jquery.com/event.stopImmediatePropagation/

I ran into this issue whilst working on a calendar/scheduling app. Where day containing elements needed click events and their child elements needed click events too.

Love the jQuery ;]

I was experiencing this issue with some larger file uploads using the CakePHP Media plugin.

https://bugs.webkit.org/show_bug.cgi?id=5760

Add this to the virtual host declaration in your Apache config file to fix it:

1
2
3
4
5
6
<VirtualHost x.x.x.x:x>

    # Prevent Safari from hanging on uploads
    BrowserMatch  Safari  nokeepalive

</VirtualHost>

Especially if you’re trying to match attribute values!

Thankfully Kooilnc, the godsend has a solution:

http://stackoverflow.com/questions/1231770/innerhtml-removes-attribute-quotes-in-internet-explorer

I’ve wrapped that up into a jQuery function here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$.fn.ieInnerHTML = function() {
  var zz = this.html(),
       z =
     zz.match(/<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)\/?>/g);
    if (z){
      for (var i=0;i<z.length;i++){
        var y, zSaved = z[i];
        z[i] = z[i].replace(/(<?\w+)|(<\/?\w+)\s/,
                            function(a){return a.toLowerCase();});
        y = z[i].match(/\=\w+[?\s+|?>]/g);
         if (y){
          for (var j=0;j<y.length;j++){
            z[i] = z[i].replace(y[j],y[j]
                       .replace(/\=(\w+)([?\s+|?>])/g,'="$1"$2'));
          }
         }
         zz = zz.replace(zSaved,z[i]);
       }
     }
    return zz;
}

// Usage:
$('#getInnerHtmlOfThis').ieInnerHTML();

God I hate IE…. and I really don’t often hate anything….

IE tends to cache some AJAX requests, which if you ask me is very stupid for its default behaviour.

FireFox caching is disabed by default. As always much love to the Fox.

Anyway, if you’re using jQuery.ajax() remember to pass the cache: false argument otherwise you may get unexpected results.

1
2
3
4
5
6
7
8
9
10
$.ajax({
    async:true,
    cache:false,   // <-- Set this or you will feel pain!!
    type:'post',
    data: 'data[TreeRows]=' + data,
    success:function(request, xhr){
      return true;
    },
    url:'/admin/pages/save_tree_state'
  });

For my own records but may also be of interest to some…

This statement performs 4 conditional left outer joins and then uses CASE to conditionally select the returned columns as a single group of columns.

So a polymorphic one to one relationship is returned in a single query.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$sql = <<<SQL
SELECT *, ELT(Log.action,'$elt_list') AS what,
 CASE WHEN Friend.source_type = '$typeVisitor' THEN 'Anonymous Visitor' WHEN Friend.source_type = '$typeRecipient' THEN 'Referrer' WHEN Friend.source_type = '$typeDiVisitor' THEN 'DI visitor' WHEN Friend.source_type = '$typeFriend' THEN 'Friend' ELSE NULL END as 'source',
 CASE WHEN Friend.source_type = '$typeVisitor' THEN Visitor.title WHEN Friend.source_type = '$typeRecipient' THEN Recipient.title WHEN Friend.source_type = '$typeDiVisitor' THEN DiVisitor.title WHEN Friend.source_type = '$typeFriend' THEN RefFriend.title ELSE NULL END as 'Source.title',
 CASE WHEN Friend.source_type = '$typeVisitor' THEN Visitor.firstname WHEN Friend.source_type = '$typeRecipient' THEN Recipient.firstname WHEN Friend.source_type = '$typeDiVisitor' THEN DiVisitor.firstname WHEN Friend.source_type = '$typeFriend' THEN RefFriend.firstname ELSE NULL END as 'Source.firstname',
 CASE WHEN Friend.source_type = '$typeVisitor' THEN Visitor.surname WHEN Friend.source_type = '$typeRecipient' THEN Recipient.surname WHEN Friend.source_type = '$typeDiVisitor' THEN DiVisitor.surname WHEN Friend.source_type = '$typeFriend' THEN RefFriend.surname ELSE NULL END as 'Source.surname',
 CASE WHEN Friend.source_type = '$typeVisitor' THEN Visitor.email WHEN Friend.source_type = '$typeRecipient' THEN Recipient.email WHEN Friend.source_type = '$typeDiVisitor' THEN DiVisitor.email WHEN Friend.source_type = '$typeFriend' THEN RefFriend.email ELSE NULL END as 'Source.email'
 FROM friends AS Friend
 LEFT OUTER JOIN visitors AS Visitor ON (Visitor.id = Friend.source_id) AND (Friend.source_type = '$typeVisitor')
 LEFT OUTER JOIN visitors AS Recipient ON (Recipient.id = Friend.source_id) AND (Friend.source_type = '$typeRecipient')
 LEFT OUTER JOIN di_visitors AS DiVisitor ON (DiVisitor.id = Friend.source_id) AND (Friend.source_type = '$typeDiVisitor')
 LEFT OUTER JOIN friends AS RefFriend ON (RefFriend.id = Friend.source_id) AND (Friend.source_type = '$typeFriend'),
 log_table AS Log
 WHERE Log.model_id=Friend.id AND Log.type=$tf
SQL
;

If you’re trying to use the CakePHP Media plugin with 1.3 (I’m running RC3) and you get this error when deleting an attachment:

1
Call to undefined method Folder::ls() in /path_to_app/app/plugins/media/models/behaviors/media.php  on line 277

ls() has been deprecated in favour of read(), change line 277 of /path_to_app/app/plugins/media/models/behaviors/media.php to:

1
list($versions, ) = $Folder->read();

All should work fine thereafter ;]

I wasn’t having much luck with the example given in the CakePHP book for a Has and Belongs To Many relationship with a single option select menu in the view.

Anyway overriding the element type does the trick:

1
<?php echo $form->input('ResellerField', array('multiple' => false)) ?>

To create a helper which name consists of more than one word use the following naming convention:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Helper name: MyHelper

# File name
app/views/helpers/my_helper.php

# Class name (Camel Case)
class MyHelper extends AppHelper

# In Controller (Camel Case)
var $helpers = array('MyHelper');

# In View (Camel Back):
$myHelper->method();

Quick refresher for my own records. CakePHP ACL component console commands:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# View ACO tree
cake acl view aco

# Create root ACO container - in this instance site
cake acl create aco root site

# Create ACO controller node - in this instance the products controller
cake acl create aco site Products

# Create ACO controller action node - in this instance admin_index
cake acl create aco site/Products admin_index

# Create regular ACO controller action node
cake acl create aco site/Products index - in this instance index

# Delete ACO node - in this instance node id 5
cake acl delete aco 5

# Grant group (id 1) permission to the entire site - this will vary unless you called your root container site
cake acl grant group.1 site all

# Grant group (id 3) permission to Users controller home action
cake acl grant group.3 site/Users/home all

For my own records, had to look this up again today so thought best blog it:

1
2
sudo chmod -R g+s *
# Would set group permissions recursively for all directories at the current location.

If anyone is interested, files in these directories will have the group ownership as the directory, instead of the group of the user that created the file. Which is very handy if you have a user group all working in the same set of directories/directory.

top