Archivo de la categoría: Programación

js-icon

Olvídate de Powerpoint y comenza a usar impress.js

La primera vez que vi un slide parecido a impress.js fue en la DrupalCamp del año pasado (2011). En ese caso lo que vi era Prezi.

Tanto impress.js como Prezi son aplicaciones que nos permiten hacer slides pero de una forma mucho mas atractiva haciendo uso de zoom, rotación, perspectiva y alguna que otra cosita mas.

Es solo verlo para entender el potencial de este tipo de herramientas:
En Chrome o Safari abran este link y usen las flechas izquierda y derecha o simplemente la barra espaciadora para avanzar.

A que esta bueno!?

Para poder implementar esta libreria tenemos dos opciones. La fácil y la divertida.

La fácil es usar una app llamada “Impressionist”  que ha desarrollado Harish Sivaramakrishnan y que es la mar de simple. Solo tenes que ir agregando slides y en cada una de ellas vas colocando el texto o imagenes y finalmente podes descargar el slide terminado.

Link: http://hsivaram.com/impressionist/0.1/

La forma divertida: Hagamoslo nosotros :D

Vamos a hacer una implementación bien simple:

<div id="impress">
    <div class="step slide" data-x="1000" data-y="">
        Comenzamos con un tipico y aburrido slide
    </div>
    <div class="step slide" data-x="2000" data-y="">
        Hasta el siguiente mismo tipo de aburrido slide...
    </div>
    <div class="step" data-x="3000" data-y="" data-scale="20">
        Pero la cosa pueda cambiar a mejor cuando hacemos zoom
    </div>
    <div class="step" data-x="4000" data-y="3000" data-rotate="90" data-scale="5">
        <p>O cuando nos desplazamos haciendo giros</p>
    </div>
    <div class="step" data-x="5500" data-y="2100" data-rotate="180" data-scale="10">
        <p>Y si encima aplicamos un buen zoom, podemos obtener cosas muy locas</p>
    </div>
    <div class="step" data-x="9000" data-y="5000" data-scale="1" data-z="-500" data-rotate="190"
         data-rotate-x="" data-rotate-y="0">
        Ah y tambien se puede hacer cosas en 3D
    </div>
    <div class="step" data-x="9000" data-y="5000" data-scale="1" data-z="-3000" data-rotate="190"
         data-rotate-x="" data-rotate-y="90">
        <img src="http://ecapy.com/Archivos/impress.js/logo-capy-morado.png"/>
    </div>
</div>
<script src="impress.js"></script>
<script>impress().init();</script>

Pueden verlo en funcionamiento pinchando acá.

Del código anterior no hay que explicar mucho, pero aclaro que:

  • Los “step” deben estar dentro del id #impress y a su vez este id es obligatorio.
  • Cada step es un div que utiliza propiedades para configurar la posición en la que esta colocado, el tamaño, la rotación, etc. las propiedades disponibles al día de hoy son:
    • data-x, data-y, data-z para el posicionamiento;
    • data-rotate-x, data-rotate-y, data-rotate-z, data-rotate para manipular la rotación.
    • data-scale para el escalado/tamaño.
  • Ya por ultimo solo estamos incluyendo impress.js e inicializandolo.

Chau!

Druplicon

Como hacer formularios multistep (wizard) con Ctools

Chaos tools para muchos no es mas que una dependencia de Panels, Views, Features y muchos otros y fabulosos módulos mas. Pero (Gran pero), Ctools per se es un modulo increíblemente útil para nosotros mismos.

Bueno vamos a lo que vamos. Acá les dejo la idea de lo que vamos a hacer:

Tengo un formulario que necesita recoger tres datos de un usuario, y me parece que es mucha información para pedirla toda junta así que vamos a hacerlo en tres pasos distintos.

Para hacer este wizard vamos a usar un formulario normal pero separado en 3 funciones, y dos de las herramientas (plugins) que tiene Ctools. La primera es obviamente “Wizard” y para la persistencia de los datos entre steps usaremos “object-cache“.

Antes la estructura:

  • Necesitamos hacer un item de menú con hook_menu() que nos lleve a una función que es la que va a manejar la batuta.
  • 3 mini funciones para manejar “object-cache
  • 3 formularios/funciones para declarar el contenido de cada uno de los step.

Hagamos lo:

Primero: el menú y el callback del menú:

<?php
function ctools_multistep_menu() {
  $items['ctools_multistep/example_multistep_form'] = array(
    'title' => 'Ejemplo de un wizard con ctools',
    'page callback' => 'wizard_callback',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}
function wizard_callback($step = NULL) {
 $form_info = array(
    'id' => 'example_multistep_form',
    'path' => "ctools_multistep/example_multistep_form/%step",
    'return path' => "",
    'show trail' => TRUE,
    'show back' => TRUE,
    'next callback' => 'callback_paso_siguiente',
    'finish callback' => 'callback_paso_final',
    'forms' => array(
      'primer_formulario' => array(
        'form id' => 'primer_formulario',
        'title' => 'Primer paso',
        'include' => drupal_get_path("module", "ctools_multistep") . '/formularios.inc',
      ),
      'segundo_formulario' => array(
        'form id' => 'segundo_formulario',
        'title' => 'Segundo paso',
        'include' => drupal_get_path("module", "ctools_multistep") . '/formularios.inc',
      ),
      'tercer_formulario' => array(
        'form id' => 'tercer_formulario',
        'title' => 'Tercer paso',
        'include' => drupal_get_path("module", "ctools_multistep") . '/formularios.inc',
      ),
    ),
  );
  global $user;
  $object_id = "ctools_multistep_de_ejemplo_" . $user->uid;
  if (empty($step)) {
    clean_datos($object_id);
    $step = 'primer_formulario';
  }
  $object = get_datos($object_id);
  $form_state = array(
    'object_id' => $object_id,
    'object' => &$object,
  );
  ctools_include('wizard');
  $form = ctools_wizard_multistep_form($form_info, $step, $form_state);
  return drupal_render($form);
}

Como pueden ver, el item de menú no es mas que una URL normal.

Ahora bien. En la función principal podemos ver como definimos inicialmente un array normalito, y es en el en donde definimos las características del wizard:

‘id’ => ‘example_multistep_form’
id (string) es el nombre que va a tener el wizard y es obligatorio poner uno

‘path’ => “ctools_multistep/example_multistep_form/%step”,
path (url) es la URL que definimos en el hook_menu() mas “%step”. y es la URL que va a usar Ctools para ir poniendo el step actual en la arra de direcciones de nuestro navegador.

‘return path’ => “<front>”
return path (url) es la URL a la que queremos enviar al usuario cuando este haya completado el formulario. en mi caso lo quiero mandar a la home

‘show trail’ => TRUE
show trail (bool) indica a wizard que queremos que se muestre el breadcrumb de cada uno de los pasos.

‘show back’ => TRUE
show back (bool) indica si queremos dejar que un usuario vuelva a pantallas anteriores. si está en TRUE muestra el botón con dicho fin.

‘next callback’ => ‘callback_paso_siguiente’
next callback (function name) indica cual es la función que se debe ejecutar cada vez que pasemos de un formulario al siguiente. y es en esta funcion en la que vamos a ir guardando el estado actual del usuario.

‘finish callback’ => ‘callback_paso_final’
finish callback (function name) indica cual es la función que se debe ejecutar una vez que el usuario haya completado el formulario. Aquí es donde vamos a guardar de forma permanente los datos del formulario y a limpiar los datos temporales.

‘forms’ => array(
‘primer_formulario’ => array(
‘form id’ => ‘primer_formulario’,
‘title’ => ‘Primer paso’,
‘include’ => drupal_get_path(“module”, “ctools_multistep”) . ‘/formularios.inc’,
),
‘segundo_formulario’ => array(
‘form id’ => ‘segundo_formulario’,
‘title’ => ‘Segundo paso’,
‘include’ => drupal_get_path(“module”, “ctools_multistep”) . ‘/formularios.inc’,
),
)

Por ultimo en forms (array) indicaremos cuales son los formularios que se van a usar en cada paso, el titulo que van a mostrar en el breadcrumb y si tuviéramos esta función en otro archivo, la ruta en la que se aloja.

Nos quedan dos cosas en el formulario. La primera es definir el nombre del objeto que va a almacenar de forma temporal los datos del usuario, ver si ver si vamos a reiniciar el formulario (en el caso de que el usuario acceda nuevamente al formulario) e inicializar los datos del usuario (ahora lo explico).

<?php
global $user;
$object_id = "ctools_multistep_de_ejemplo_" . $user->uid;
if (empty($step)) {
  clean_datos($object_id);
  $step = 'primer_formulario';
}
  $object = get_datos($object_id);

La segunda cosa que nos queda en esta función es claramente generar el wizard:

<?php
$form_state = array( 'object_id' => $object_id, 'object' => &$object );
ctools_include('wizard');
$form = ctools_wizard_multistep_form($form_info, $step, $form_state);
return drupal_render($form);

mmmbueeeeno, tenemos declarado el formulario, un par de funciones para el avance y finalización y hacemos uso de clean_datos() y get_datos(). pues eso es lo que sigue. definir estas funciones:

set_datos(), get_datos() y clean_datos() no son mas que unos wrappers que guardan recuperan y eliminan la información que el usuario va rellenando:

<?php
function set_datos($id, $object) {
  ctools_include('object-cache');
  ctools_object_cache_set('ctools_multistep', $id, $object);
}
function get_datos($id) {
  ctools_include('object-cache');
  $object = ctools_object_cache_get('ctools_multistep', $id);
  //creamos un objeto vacío para empezar
  if (!$object) {
    $object = new stdClass;
    $object->dia = NULL;
    $object->nombre = "";
    $object->apellido = "";
  }
  return $object;
}
function clean_datos($id) {
  ctools_include('object-cache');
  ctools_object_cache_clear('ctools_multistep', $id);
}

Con las pequeñas funciones de object-cache vamos metiendo la información que el usuario complete cada vez que se le de a “Continuar” dentro del objeto:

<?php
function callback_paso_siguiente(&$form_state) {
  set_datos($form_state['object_id'], $form_state['object']);
}

Y cuando el usuario complete el formulario vamos a usar la función que definimos en “finish callback” para dejarle un mensaje en pantalla al usuario (lo mas lógico seria guardarlos de forma permanente pero esta es una demo XD) y limpiar los datos;

<?php
function callback_paso_final(&$form_state) {
  $obj = $form_state["object"];
  drupal_set_message($obj->nombre . " " . $obj->apellido . " gracias por seleccionar el día " . $obj->dia);
  clean_datos($form_state["object_id"]);
}

Y eso es básicamente todo lo que necesitamos. Faltan como es lógico, las funciones que contienen los formularios junto a su respectivo _validate() y _submit(). Les pongo uno de ejemplo para que vean que no tiene nada del otro mundo:

<?php
function segundo_formulario($form, &$form_state) {
  $form['nombre'] = array(
    '#type' => 'textfield',
    '#title' => t('Dime tu nombre'),
    '#default_value' => $form_state['object']->nombre,
    '#required' => TRUE,
  );
  return $form;
}
function segundo_formulario_validate($form, &$form_state) {
}
function segundo_formulario_submit($form, &$form_state) {
  $form_state['object']->nombre = $form_state['values']['nombre'];
}

Aunque ahora que me doy cuenta, quiero comentar que en el _submit() (que siempre se ejecuta antes que la función datos callback_paso_siguiente() que almacena los datos), es el punto en el que seteamos el valor que el usuario acaba de rellenar en la correspondiente propiedad del objeto que esta por ser almacenado.

Todo lo anterior nos va a generar un formulario como el siguiente:

y cuando el wizard nos mande a la home vamos a ver:

Les dejo un descargable con este wizard de ejemplo para que puedan verlo en detalle.

Descargar

Chau!

Druplicon

Drupal 7: Panels no me dejaba crear links dinamicos

Bueno el titulo del post no se explica muy bien, pero que le voy a hacer, no tengo tanto espacio. Me explico:

Hice un panel con una url dinámica “dashboard/!seccion“, y paralelamente cree un menú llamado “Secciones dashboard

El problema se me dio cuando quise comenzar a agregar enlaces al menú del tipo “dashboard/perfil“, “dashboard/datos-de-la-cuenta“, etc. y me daba error al crear cualquier elemento:

Después de darle un poco de vueltas al asunto (google, foros, debug) termine dándome cuenta de la boludez que era, y es que para crear elementos de menú que apunten a un panel, primero tenes que darle permisos de acceso al panel (atento a la imagen porque no estoy hablando de permisos de Drupal):

Herramientas

Copiar y pegar en Putty en Linux

Me lo tengo merecido por usar Windows.

Para los que estén usando putty sobre Linux puede que hayan notado que las siguientes funcionalidades no están disponibles:

  • Cuando seleccionas algo en putty esto automáticamente queda copiado por lo que podes ir a notepad (por decir algo) y pegarlo directamente.
  • Cuando tenes algo copiado de notepad y lo quieres pegar en putty solamente haces click derecho sobre el y se pega.

Bueno, a priori me parecía que no existía esa funcionalidad y no le di mayor importancia hasta que un dia di con esa funcionalidad por casualidad.

Resulta que cuando seleccionas algo en putty esto si que se copia a un portapapeles, pero la forma de pegar ese texto copiado es con el click central (la rueda del ratón). Esto es para ambos sentidos. Si seleccionas algo de gedit (por decir algo) y haces click central en putty, también se va a pegar el texto. 

 

Ya sabes lo que se dice. Nunca te acostaras sin haber aprendido algo nuevo.

Saludos.

Druplicon

Benchmark Drupal 7 + APC + Memcached + Varnish sobre usuarios anónimos

Vamos a hacer algunos testeos para ver lo que podemos llegar a ganar en performance al implementar una serie de tecnologías sobre Drupal 7.

Las pruebas las realizare sobre una instalación LAMP estándar de Ubuntu (Linux Mint en realidad):

  • mysql 5.1.58 (Con su configuración por defecto)
  • php 5.3.6 (Con su configuración por defecto)

El software para mejorar la performance que usé y las versiones de cada uno son:

  • APC-3.1.9
  • memcached 1.4.7
  • Varnish 3.0.4

Esta prueba es solo para que nos demos una idea de lo que podría llegar a implicar el aplicar estas tecnologías en nuestro sitio de Drupal 7, por lo que he dejado fuera cualquier explicación técnica.

Las pruebas las hice en un core2Duo @ 2.2ghz de 2 núcleos en un Linux Mint de 64bits y 8gb de ram.

La idea es ir agregando tecnologías e ir viendo el teórico beneficio que esta aporta aplicadas a la practica.

Lo primero es lo primero. vamos a hacer un bench de Drupal 7.10 en sobre nuestro LAMP sin haber tocado su configuración inicial.

Utilice Apache benchmark (ab) para todos los testeos variando la concurrencia y cantidad de request para aprovechar al máximo los recursos de los que disponía en cada testeo que hice.

Primera ronda. Estableciendo un punto de referencia.

Test 1: Drupal 7 sin cache de ningún tipo.

Resultados:
Requests per second: 5.71 [#/sec] (mean)
Transfer rate: 45.35 [Kbytes/sec] received

Test 2: Drupal 7 marcandole las opciones “Aggregate and compress CSS files.” y “Aggregate JavaScript files.” en “admin/config/development/performance”

Resultados:
Requests per second: 6.38 [#/sec] (mean)
Transfer rate: 46.27 [Kbytes/sec] received

Podemos apreciar que no hay cambios. nada que comentar.

Test 3: La configuración del testeo anterior + “Cache blocks” en “admin/config/development/performance”

Resultados:
Requests per second: 5.18 [#/sec] (mean)
Transfer rate: 37.54 [Kbytes/sec] received

Pasados los tes primeros test ya no quedan dudas que el cuello de botella de los procesadores son los limitantes. Apenas si pudimos conseguir que varíe el resultado.

——————————————————————

Hasta acá fue lo aburrido, porque en realidad lo anterior no tiene ninguna magia, pero nos da una buena idea de desde que base estamos partiendo. Nuestro objetivo es subir grotescamente la media de request por segundo partiendo de los aproximadamente 6 que hemos conseguido hasta ahora.

Test 4: La configuración del test anterior + “Cache pages for anonymous users” (El cache normal de Drupal).

Resultados:
Requests per second: 127.22 [#/sec] (mean)
Transfer rate: 921.83 [Kbytes/sec] received

Bueno bueno bueno, esto ya es otra cosa. El cache de Drupal por si solo incrementa los request de una forma brutal, pero no nos quedamos ahí ni en broma, vamos a por mas RPS (request por segundo)

——————————————————————

Segunda ronda. tecnologías y configuraciones foráneas:

Test 5: La configuración del test anterior + APC.

Este es uno de los cambios mas recomendados siempre que queramos obtener un incremento de performance (y mejor aprovechamiento de la ram disponible) sin tener que tocar ni una sola linea de código de nuestro Drupal.

Resultados:
Requests per second: 440.43 [#/sec] (mean)
Transfer rate: 3191.39 [Kbytes/sec] received

Boom! performance X4!. Vamos por buen camino. Agreguemos mas de esas cosas que recomiendan los que saben…

Test 6: La configuración del test anterior + Memcached

Para esta prueba instalé el modulo memcache (http://drupal.org/project/memcache) en su versión 7.x-1.0-rc2 y lo configuré en su forma mas básica según las instrucciones de su configuración.

Resultados:
Requests per second: 397.38 [#/sec] (mean)
Transfer rate: 2734.53 [Kbytes/sec] received

No hemos visto mejora alguna pero no porque Memcache no sirva, al contrario, en futuros bench les voy a mostrar como si que ayuda, pero bajo este entorno poco sirve ya que es una capa intermedia con la DB y estamos usando el cache de Drupal que apenas si la toca… en fin, en el próximo bench les muestro, paciencia.

Hasta ahora hemos conseguido mejorar los iniciales 6 RPS del principio por fabulosos 400 RPS de media, pero aun nos queda un paso mas para mejorar los request para usuarios anónimos, y ese es Varnish

Test 7: La configuración del test anterior + Varnish

Resultados:
Requests per second: 6166.57 [#/sec] (mean)
Transfer rate: 45075.00 [Kbytes/sec] received

Acaso hay algo que añadir?

Conclusiones:

Hemos visto como Drupal 7 sin ningún tipo de cache activo es una muy mala idea a la hora de ponerlo en producción.
El cache que trae de serie no es opcional, sino que es mandatorio. No activar como mínimo esta capa de cache en Drupal derivaría automáticamente en un uso elevadisimo de los recursos disponibles, esto acompañado de tiempos de entrega mucho mas largos y por consiguiente la insatisfacción de nuestros clientes.
APC es una excelente adición a nuestro servidor en general ya que agiliza el procesamiento de cualquier pagina escrita en PHP y particularmente en Drupal es un beneficio directo tanto para usuarios anónimos como para usuarios logueados. Recomiendo su uso sin dudarlo aunque hay que hacerlo con cabeza, documentación y alguien que sepa lo que hace si no quieren volver inestable vuestro sistema.

Memcache es una herramienta que no puede faltar en un buen servidor y es harto eficiente para usuarios no logueados en el terreno de Drupal, pero en una instalación en la que casi todos los visitantes sean anónimos, apenas van a sentir la mejora.

Por ultimo y el mas importante, Varnish, que demostró el salto ABISMAL que puede llegar a proporcionar en velocidad cuando lo ponemos a trabajar con una instalación de Drupal. Sin duda pues, esta es la herramienta mas potente de las que hemos utilizado en este bench, pero a su vez, la mas complicada de configurar.

Resumiendo la mejor combinación para usuarios anónimos:
Cache de Drupal = performance decente / Configuración… bueno no lleva configuracion XD. (ganancia de 21x con con respecto a los 6 de media iniciales)
Cache de Drupal + APC = Muy buena performance / Configuración media. (ganancia de 73x con con respecto a los 6 de media iniciales)
Cache de Drupal + APC + Varnish = Bruta performance / Configuración avanzada. (ganancia de 1027x con con respecto a los 6 de media iniciales)

Disclaimer:
No son ni de lejos las mejores versiones ni servidores los que he usado, pero procuré enfocarme en estos debido a que son los mas extendidos/populares en nuestro creciente mundo llamado Drupal.

Saludos.

Druplicon

Drupal: El “view” de un cck no está disponible cuando hago node_load() [Solución]

Cuando cargamos un nodo con node_load(), si quisiéramos hacer uso de la propiedad “view” de un campo CCK veríamos que la misma no existe:

$node = node_load(999);
var_dump($node->field_precio[0]);
 
array(2) {
  ["amount"]=> string(6) "100.00"
  ["currency"]=> string(3) "EUR"
}

Esto pasa porque CCK solo prepara esta propiedad cuando un nodo se esta por imprimir mediante node_view(). Si lo que necesitas es usar node_load() en lugar de node_view() la solución es inyectarle la propiedad “view” mediante la función que el mismo modulo de CCK utiliza:

$node = node_load(999);
$node->field_precio[0]['view'] = content_format("field_precio", $node->field_precio[0]);
 
var_dump($node->field_precio[0]);
 
array(3) {
  ["amount"]=> string(6) "100.00"
  ["currency"]=> string(3) "EUR"
  ["view"]=> string(11) "100.00 EUR"
}

bye!.

PHP

Como forzar la descarga de un archivo con PHP

Cada tanto necesitamos cosas así :)

<?php
/**
 * Downloader
 *
 * @param $archivo
 *  path al archivo
 * @param $downloadfilename
 *  (null|string) el nombre que queres usar para el archivo que se va a descargar.
 *  (si no lo especificas usa el nombre actual del archivo)
 *
 * @return file stream
 */
function download_file($archivo, $downloadfilename = null) {
    if (file_exists($archivo)) {
        $downloadfilename = $downloadfilename !== null ? $downloadfilename : basename($archivo);
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename=' . $downloadfilename);
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . filesize($archivo));
        ob_clean();
        flush();
        readfile($archivo);
        exit;
    }
}

Uso:
Si queres que el archivo se descargue con un nombre distinto al original.

<?php
download_file("archivos/archivoReal.zip", "archivoEnmascarado.zip");

Si queres que el archivo se descargue con el nombre original.

<?php
download_file("archivos/archivoReal.zip");
1263055237_start-here-ubuntuoriginal

KVM/libvirt: el guest (anfitrion) no detecta la interface virbr0 [Solución]

Si copiaste una maquina virtual KVM y al arrancar no tenes conexión a Internet, hablas visto depues de hacer ifconfig que no hay interface eth0. Esto pasa porque Linux cachea el mac de la tarjeta de red que tenia en la anterior maquina virtual en el archivo “70-persistent-net.rules“.

La solución es borrarlo y reiniciar la maquina virtual (tranquilo que si Linux no lo encuentra lo recrea).

sudo rm /etc/udev/rules.d/70-persistent-net.rules
sudo reboot
internet-explorer-logo

Solución al box-model en ie7 usando jQuery

Sé que hay soluciones hechas para este problema en particular, pero pesa 33k y solo necesitamos unas líneas como van a ver para lograr lo mismo…

Sabido es que a ie se la sudan los estándares y cuando los incorporan por lo general lo hacen taaarde.
La propiedad CSS “box-sizing” no es la excepción.

Ya sabemos que el siguiente CSS va a arreglar los desfases que se dan cuando un input que esta con un width:100%; dentro de un div que tiene un ancho fijado.

.elemento {
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}

Y como comente en el post anterior, esta propiedad no está soportada en ie7.

Soluciones hay de todo tipo, pero lo cierto es que teniendo jQuery en todos mis desarrollos, se me hiso más que obvia la decisión de usar un script que arregle este bug en lugar de usar cosas más raras (archivos .htc por ejemplo).

Para implementar la solución solo necesitas poner este script:

$(document).ready(function () {
    if ($.browser.msie && ($.browser.version.substr(0, 1) == 7 || $("meta[content='IE=EmulateIE7']").length > 0)) {
        $(".ie7Fix-Box-model").each(function (i, v) {
            var el = $(v);
            //calculamos
            var pL = el.css("paddingLeft").replace("px", "") != "" ? el.css("paddingLeft").replace("px", "") : 0;
            var pR = el.css("paddingRight").replace("px", "") != "" ? el.css("paddingRight").replace("px", "") : 0;
            var bLW = el.css("borderLeftWidth").replace("px", "") != "" ? el.css("borderLeftWidth").replace("px", "") : 0;
            var bRW = el.css("borderRightWidth").replace("px", "") != "" ? el.css("borderRightWidth").replace("px", "") : 0;
            var newSize = el.width() - (parseInt(pL, 10) + parseInt(pR, 10) + parseInt(bLW, 10) + parseInt(bRW, 10));
            //le aplicamos el nuevo tamaño
            el.width(newSize);
        });
    }
});

Y ponerle la class “ie7Fix-Box-model” a todos los input que necesites arreglar.

Ver ejemplo (vean el codigo fuente)