Airshow 416

@Luke_4, no worries. As you probably already discovered, that pattern is totally flexible. Once you have grasped the basic idea, you can "play tunes" with it to control the content/layout to print whatever you want.

Good luck.


Airshow 416

I posted a link to a fiddle back in the original post

Luke_4 commented: Airshow!!! Thank YOU!!! It is PERFECT!!! +0

Airshow 416

diafol commented: Lovely :) +15

Airshow 416

An approach (not the only one) would be to have two main child divs within your <body></body> tags

  • <div id="screen"></div> styled to be displayed under @media screen and hidden under @media print.
  • <div id="print"></div> styled to be displayed under @media print and hidden under @media screen.

When the "Print" button is clicked, dynamically populate the "print" div with content drawn from the "screeen" div, before calling window.print().

I have never needed to do this but it may be the line-of-least-resistance here. I can see no reason why it could not be made to work.

Luke_4 commented: Would like to have you elaborate with example +0

Airshow 416


It's very odd that printing is not WYSIWYG.

Theory 1: (Physical) .autocomplete() creates the widget by replacing the original input element and/or creating one or more hidden elements. You may need to find some element other than the obvious one, which holds the final string, and establish an @media print rule that shows only that element. Use your browser's console to inpect the DOM.

Theory 2: (Temporal) It's a matter of timing. You may need to issue some command on the widget and/or wait for some widget event before printing. Have a look at autocomplete's API documentation for clues.

Airshow 416

The days of generating a special page for print purposes are long gone.

Instead of composing HTML on the fly, try mastering CSS @media rules :

If there's going to be any dynamically generated content, you will still need some javascript; but more typically @media rules alone allow you to specify a "print" version of a "screen" page.

I admit, I've never tried @media with an autocomplete element but can't immediately see any reason why it should not be successful. From what I understand, it's more about not printing the rest of the page.

Airshow 416

Neither the pictures nor the words are speaking to me.

Until such time that the question is properly expressed, I have to admit defeat.

Airshow 416

As it stands, the question is not 100% self-explanatory, in particular the relationships and juxtapositions of the various input elements.

Maybe it would be clearer if you posted an (annotated) screenshot of the original spreadsheet and/or the HTML version.

Airshow 416

You are expecting javascript arrays to behave like PHP arrays. They don't!

Elements of a JS array are indexed exclusively by integer.

Confusingly, JS arrays can also be given properties, so tmp[14]['G'] = foo is quite legal but not what you might expect from knowledge of PHP. ['G'] is a property of tmp[14] without being an array element!

This all stems from the way JS implements arrays. Array is heavily based on Object but gives special status only to integer keys.

Straightforwardly you could do as follows :

// change
tmp[i] = [];
// to
tmp[i] = {}; // a js plain object

// change
tmp[i]['"'+letters[j]+'"'] = val;
// to
tmp[i][letters[j]] = val;

However, JS plain objects are just collections of properties ... without order ..., which may suffice.

But if order is important, and you want to convey both a key (letter) and a value (val), then you need an array of objects, each containing a key|value pair.

// keep
tmp[i] = []; // arrays have order.

// change
tmp[i]['"'+letters[j]+'"'] = val;
// to
tmp[i].push({ 'key':letters[j], 'value':val });

Love it or loath it, that's javascript.

diafol commented: Masterclass :) +15

Airshow 416

The double test for hasChildNodes(), at parent and child levels, looks a bit odd.

I would have thought you want the parse out the nodes that don't have children, in which case your loop will be as follows:

for (i=0; i<x.length; i++) {
    if (!x[i].hasChildNodes()) {
        alert(x[i].nodeName + '=' + x[i].childNodes[0].nodeValue);

Within the loop, you could put crawl(x[i]) in an else clause but it should be OK without, as any node without cildren will simply drop straight through the next recursion of crawl().

The only thing I'm not sure about is whether or not .hasChildNodes() detects text nodes. If it does, then the if (!x[i].hasChildNodes()) test needs to be more rigorous.

Airshow 416

Gentlemedia, it's not obvious what is causing this issue. You need to devise an investigation strategy to discover what's causing it. Simplify everything one aspect at a time and see when the problem disappears.

Airshow 416

Surely cc can be permanently appended to .news-grid and cd can be permanently appended to cc with .show() and .hide() controlling visibility? There doesn't appear to be any need to detach/reappend. Even better, cc/cd could be hard coded in HTML.

I'm not sure this will fix anything but should better guarantee that the behaviour is consistent and debugging should be simpler.

Airshow 416

We have solved the problem myself.

That's cool Razamughal67, well done.

Airshow 416

Text questions will most likely attract text answers. If you want code, then provide code.

Airshow 416

I'm not too sure what the question is but here are a few observations from a client-side perspective :

  1. Don't use async:false!!! AJAX is fundamentally asynchronous and async:false should never have been provided. It is, at best, unreliable.
  2. You can't rely on an arbitrary cart-entry index to identify the correct product to update - should be a procuctID.
  3. It is safest to update the entire cart after any changes; a safe process is (i) disable UI to prevent further user interaction, (ii) make ajax request, (iii) receive response, (iv) update cart, (v) unlock interface.
  4. To attach a 'change' handler to the quantity fields, don't loop through product rows. That's horribly inefficient as the loop, at each iteration, creates a new handler. Do it as below, with a one unique hander. Judicious use of .closest(), gets you up from the changed .qty element to its cart-item wrapper (its containing <tr>), and the need for a javascript closure disappears.
  5. Adopting the suggestion at 3 above to update the entire cart after a change, you will find it simplest to delegate the change handler to a parent container (assume #cart).
  6. As you now have a mechanism to update the entire cart, you don't need to serve it as part of the orignal document; call your update function on page load.

The javascript should be something like this :

$('#cart').on('change', 'input.qty', function() {
    var me = $(this);
        url: "<?php echo site_url('cart1/update'); ?>",
        type: 'POST',
        data: {
            'productid': ...

Airshow 416


Airshow 416

But you are seeing a difference in the effect between the fiddle and the fully worked up page, yes? That's where you started out above.

Airshow 416

To give the animation every chance of being smooth, make sure there's no document reflow.

ie. make sure the div animates into a reserved space. eg. wrap #block in another div with width and height set to accommodate the div at its maximum size.

Also, chain the jQuery, so #block does not need to be discovered twice - $('#block').css(...).animate(...)

If it's still jerky, then it's because your computer's processor and/or graphics card is too busy with other tasks. This something you can't really fix, at least for js amimations. With these modern computers, we have little knowlege or control over processor usage.

It's a risk you run with any js animation. Even if your own computer runs it smoothly, there's no guarantee some other end-user's computer will be so cool.

Flash animations are diffferent. They (are far more likely to) hog the processor for the duration.

Airshow 416

If you're only seeing the code on the site and in the view source then your hosting doesn't have PHP enabled.

Or, the source file is otherwise not served via the PHP parer, eg. it does not have a .php extension, or the server is set up to recognise some other extension.

Airshow 416

Looking at the HTML again, it should probably be :

$(".bot").on('mouseenter', function() {
}).on('mouseleave', function() {

Airshow 416

You want something more like :

$(".bot").on('mouseenter', function() {
}).on('mouseleave', function() {

This should give the desired behaviour for all .bots that are in place on page load.

If .bots (and/or their contents) are dynamically added, then you need to consider delegation, which would be a mild adaptation of the above code.

Airshow 416

It's difficult to answer questions like this when the HTML is in the form of server-side source code (PHP presumably).

Please post the served HTML!

Airshow 416

So how does the mystical CHtml::activeTextField(...) render in HTML?

Airshow 416

What you show in the question would appear to be the returned JSON, decoded then re-encoded (re-stringified).

It woud be more useful to see the raw JSON, which may or may not be the same as the re-encoded JSON. To do this, temporarily use dataType:'text', and alert (data_).

Airshow 416

The problem is that count = $(".count") selects all the elements with class="count", not just the one you are interested in whenever a plus/minus button is clicked.

You need for the click handler to sniff out the particular .count element that is a sibling of the particular plus/minus button that was clicked.

Something like this should do it :

$('.minus').on('click', function() {
    var count = $(this).siblings(".count");
    var val = parseInt(count.val());
    if (val > 1)
        count.val(val - 1);
$('.plus').on('click', function() {
    var count = $(this).siblings(".count");
    var val = parseInt(count.val());
    count.val(val + 1);

Even better, you can delegate to the containing table element, AND handle both plus and minus with a single handler, as follows :

//Assuming the cart has id="cartTable"
$("#cartTable").on('click', '.minus, .plus', function() {
    var $this = $(this),
        $count = $this.siblings(".count"),
        delta = $this.hasClass('plus') ? 1 : -1; 
    $count.val(Math.max(0, parseInt($count.val()) + delta));

Not only is that more concice, but it will automatically handle :

  • any items already in the cart when this handler is put in place
  • any items added to the cart later (ie there's no need to attach individual click handlers to new items after they are added).

So, no worries if your cart is dynamically updated.

If it's not dynamically updated, then still no worries, delegation is a good idea anyway.

Airshow 416

Ah, so he means create a html comment ()

Presumably Ardav, but goodness knows why. It's not as if "View Source" will magically show the comment.

Airshow 416

Siberian, those were just three possible things you might want to do with the concatenated list.

I can see no value in creating a synthetic comment node.

Airshow 416

To concatenate the individual strings together, comma separated :

var list_ = list.join();

Then you can do what you want with list_.


Only use document.write in the document writing phase. Once the document has achieved its ready state, document.write will blitz it completely.

Airshow 416

Sorry, that's javascript!

try $i = array_push($arr, array()) - 1;.

Airshow 416

Looking at it again, you probably need to declare the main array before the outer foreach() loop, and populate it inside the loop.

If I'm right, then the switch/case structure can also disappear, as follows :

$arr = array();
foreach ($xpath->query('//table[@id="tblClubs"]/tr') as $node) {
    $rowData = array();
    foreach ($xpath->query('td', $node) as $cell) {
        $rowData[] = "\"$cell->nodeValue\"";

    $i = $arr.push(array()) - 1;

    //From cell 0
    $arr[$i]['cName'] = $rowData[0];

    //From cell 1
    //escape single quote in location information
    $arr[$i]['location'] = str_replace("'", "\'", $rowData[1]);
    //get playing days
    if(preg_match("/?!\d[0-9]{4}/", $rowData[1], $match) == 1) {
        $arr[$i]['days_times'] = "'$match[0]'";
    } else {
        $arr[$i]['days_times'] = "'0'";
    //get zip
    $pattern = '#([A-Z]{0})\s+(\d{5})#s';
    if(preg_match($pattern, $rowData[1], $match) == 1) {
        $arr[$i]['zip'] = trim($match[0]);//"'$match[0]'";
    } else {
        $arr[$i]['zip'] = 0;
    //get state
    if(preg_match("/[A-Z]{2}(?=[\s]{1,}[0-9]{5})/", $rowData[1], $match) == 1) {
        $arr[$i]['state'] = "'$match[0]'";
    } else {
        $arr[$i]['state'] = '0';

    //From cell 2
    $arr[$i]['contact_person'] = $rowData[2];
    //get contact phone number
    if(preg_match('/\(?[2-9][0-8][0-9]\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}/', $rowData[2], $match) == 1) {
        $arr[$i]['contact_phone'] = "'$match[0]'";
    } else {
        $arr[$i]['contact_phone'] = "'0'";
    //remove phone and leave contact name
    $arr[$i]['contact_person'] = preg_replace('/\(?[2-9][0-8][0-9]\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}/','',$rowData[2]);