Translate

Mostrando entradas con la etiqueta HTML5. Mostrar todas las entradas
Mostrando entradas con la etiqueta HTML5. Mostrar todas las entradas

miércoles, 3 de junio de 2015

PYMETRICK para un comercio electrónico sencillo

Seguramente este artículo será de tu interés si te dedicas a comercializar productos o a desarrollar software para comercio electrónico.

Últimamente no dejan de bombardearnos con estadísticas sobre cuanto han crecido las cifras del comercio electrónico, también nos proporcionan listas de países donde el comercio electrónico supone un 70% de transacciones con respecto al comercio tradicional, publican subvenciones a empresas que desarrollen el e-commerce,....etc. Todo esto nos lleva a preguntarnos ¿ Por qué ? ¿ Cuándo ? ¿Cuánto? ¿Dónde? ¿Cuál? ¿Quién? ¿Cómo?

¿Por qué?
Es necesario que cualquier empresa o comercio desarrolle un sistema de comercio electrónico ? Seguramente no. Para responder a esta pregunta es necesario ser muy práctico. El comercio electrónico está creciendo lentamente en el sur de Europa y existen grandes competidores como Amazón, EBay y Alibaba. Las grandes cadenas comerciales ya han apostado por el comercio electrónico pero representa una cifra muy pequeña en sus balances.

¿Cuándo?
Disponer de tiempo y recursos para ponerse manos a la obra. Qué periodo es más idóneo para acometer este proyecto?

¿Cuánto?
La buena noticia es que existen soluciones donde no deberíamos apostar una gran suma para empezar y esperar acontecimientos -no vamos a adelantarte nada, pero podrás leer la solución al final-.

Evaluar los costes iniciales y de operación siempre nos evitará sustos. Existen muchas ofertas a nivel local e internacional, pero cuál se ajustará más a lo que hemos pensado ?  Siempre es posible que nos prometan más de lo que vamos a obtener por nuestro dinero - con eso ya deberíamos contar -. 

¿Donde?
Si ya se ha decidido por alguna oferta o cualquier otra solución, debe tener cuidado sobre dónde se ubique el servidor que permita comercializar sus productos y cuente con los datos de sus cliente. Existen unas normas estrictas de la Agencia de Protección de Datos ( España ) y de la C.E.E. para ubicar datos personales de forma protegida y segura, ya que tendrá que comunicar y dar de alta su base de datos en la APD.

¿Cuál?
Qué objetivos perseguimos, B2C buscamos expandir nuestro mercado o tenemos productos innovadores que necesitan ser publicados a un publico más extenso ?  También es posible que deseemos realizar un comercio B2B y nuestros comerciales no puedan ampliar ilimitadamente su area comercial.

¿Quién?
Debemos buscar quien se encargará del desarrollo, implantación, seguimiento y operación. Si cuenta con un proveedor especializado en estas soluciones, tiene muchas posibilidades de llegar a buen puerto, aunque también es posible apostar por una STARTUP que le permita una inversión más acompasada con los objetivos.

¿Cómo?
Puedes empezar con un servidor ubicado en su instalación o bien, alquilar un servidor virtual o dedicado en un proveedor.  Adquirir un certificado electrónico (no es imprescindible pero le dará visos de seriedad), un dominio y el software necesario para que todo funcione.

Lo único cierto de todo esto es que quien no apuesta, no gana. Aunque tampoco debería apostar lo que no tiene o le hará falta para continuar.

Creo que el futuro del comercio electrónico está en disponer de recursos más seguros y asequibles (pasarelas de pago, logística, comunicaciones, identificación electrónica de usuarios,...), relacionarse con los clientes de una forma más simple -no hace falta pedir datos que no serán necesarios- y explorar métodos más flexibles para mostrar los productos o servicios - buscar un producto puede ser muy complicado o muy fácil, depende de tí -

Una gran parte del éxito de una implantación de comercio electrónico se basa en la disponibilidad de stock y del tratamiento de garantías y devoluciones, deberíamos ponernos más en los zapatos del cliente y menos en los zapatos de la empresa si deseamos que los clientes confíen en nuestro comercio. Además de cumplir las leyes escrupulosamente existe algo que se llama sentido común, y llegaremos a solucionar conflictos generando confianza para posteriores transacciones.

te damos a conocer 10 reglas de oro que no puedes dejar pasar.

1. Cada vez que se ingrese a una sección del sitio, ésta debe decir dónde está el cliente. Es decir, Inicio> Categoría> Sub-categoría> Producto

2. Es necesario que sea posible ordenar los productos según distintas opciones. Por ejemplo, del precio, de más barato al más caro o del más nuevo al más antiguo, o por temporadas (invierno, primavera, verano, otoño).

3. Muestra todos tus productos con foto y descripción, con el fin de que los potenciales clientes se entusiasmen con lo que ofreces. Obtener las fotos es un trabajo arduo ( obtener la foto y dimensionarla adecuadamente, relacionarla con la codificación del producto, y subirla a la web. Así una tras otra hasta completar todo el catálogo), pero si sigues leyendo puede convertirse en algo hasta divertido.

4. Si tienes productos más baratos que en el mercado normal, di lo que cuesta realmente y cuánto está gastando el cliente. De esta forma es más fácil mostrar que estás entregando un buen producto, a buen precio y que conviene comprar más barato. Aunque no deberías fundamentar tus ventas solo en precios, la competencia también puede tomar este camino y puede ser un problema para tu modelo de negocio.

5. Ubica una barra de búsqueda de fácil acceso, con el fin de que los clientes puedan encontrar lo que buscan y no abandonen tu página, si además, es posible buscar con ñ, mejor.

6. Crea una búsqueda avanzada, con el fin de refinar los términos y que las personas puedan incluir más datos para encontrar lo que buscan específicamente.

7. Antes de que los clientes compren, notifica si el producto está en stock o no. De esta forma te ahorrarás malos ratos y también se lo ahorrarás a tus clientes, que sabrán que lo que compran llegará a sus manos y no tendrán que esperar tiempo de más. Cuidados con los comercios que tienen una tienda física y una tienda web, el stock debería estar compartido y bloqueado por el cliente que haya realizado la compra. También puedes indicar un stock mínimo de seguridad y una vez superado, informar al cliente de que debe ponerse en contacto con el comercio físico.

8. Muestra las opciones de entrega. A algunas personas les gusta conocer las opciones de entrega que tienen al momento de comprar, por lo que es necesario que las tengas disponibles antes de que se confirme el envío. También puede jugar a favor de las tiendas físicas, la recogida el producto en el propio comercio.

9. Si el producto se va a atrasar, notifica a tu cliente a través de un correo electrónico o teléfono. De esta forma estará tranquilo y sabrán que eres una empresa seria.

10. Una vez que la compra sea confirmada, entrega el máximo de detalles a tus clientes para que se sientan tranquilos y sepan que hicieron la compra correcta.

DropShipping. El sitio web Nuevos Emprendedores.net lo define como un modelo de negocio online, donde a través de una página en Internet puedes vender productos sin tener que contar con un lugar específico donde tengas que guardarlos. Esto, gracias a que tus proveedores son quienes almacenan y distribuyen los productos y tú quien los promociona y los comercializa a través de Internet

Y por último pero no menos importante, hoy día es absolutamente necesario que la misma web sea accesible desde cualquier dispositivo con la misma facilidad de uso que si el cliente se encontrara ante un ordenador de sobremesa.

Desde el proyecto PYMETRICK, se incorporan todas las ventajas técnicas y exigencias legales en un plazo muy corto (hablamos de días), lo que nos permite una mejora continua y adaptarnos a las necesidades del mercado y nos hemos hecho todas la preguntas posibles y lo que resulta más difícil, las hemos respondido. No desvelamos nada si decimos que PYMETRICK es un proyecto muy reciente con un desarrollo continuo desde 2012, pero que aún no ha finalizado su ciclo de desarrollo y no dispone de ningún tipo de financiación, solo tiempo y ganas.  Es un proyecto soportado en una licencia GPL y por tanto, se cederá el código de forma libre una vez finalizado - aunque no nos importaría contar con otros desarrolladores que aportaran su visión, toda ayuda es bienvenida -.

En 2015 se ha iniciado el despliegue de varias web soportadas en PYMETRICK como COOP.COM. S. GARRACHON Y PEREZ BLANCO, FERROSAT, PEREZ Y RINCON S.A. , todas ellas se han desplegado con la misma filosofía, no incrementar el trabajo diario de un comercio físico en su día a día. Esto incluye actualizaciones de datos de forma autónoma ( productos, stock, precios, imágenes...) y periódica e informar al cliente en todo momento de la disponibilidad del producto y facilitarle un correo electrónico o teléfono desde el mismo botón de compra (según el dispositivo con el que accede a la web).

Llegados a este punto, y aunque PYMETRICK está desarrollado en PYTHON 2.X (y este es un BLOG sobre PYTHON), necesitábamos llegar más allá saltando de plataforma y mejorar todo lo relacionado con la captura de datos e imágenes. Creamos KEPIDE (ya en su versión 1.1.7) una APP ANDROID 4.4.X disponible en GOOGLE PLAY de forma gratuíta (y sin publicidad), que complementa todos los desarrollos que hemos implantado y que seguirán en el futuro. KEPIDE sigue en todo el rastro del desarrollo de su hermano mayor PYMETRICK, tiempo y ganas, e igual que él, GPL.  Aunque su ciclo de desarrollo no ha finalizado, ya permite muchas alegrías, sobre todo a los comerciales que la utilizan a diario realizando sus pedidos e incorporando productos e imágenes (dimensionándolas adecuadamente, relacionando la imagen y la codificación del producto y enviándola a la web para su publicación ) en pocos minutos.

Espero que este tema haya sido interesante, os espero en una próxima entrega aún por definir.




jueves, 25 de septiembre de 2014

Ancho de banda y HOTLINKS, no cojas lo que no es tuyo

Puede que te preguntes que son los HOTLINK, con toda seguridad lo habrás visto muchas veces porque es una práctica muy habitual. 

Si te gusta una foto de una web,  podrías obtener su link y hacer referencia en tu blog, esta acción aparentemente inocente no debería realizarse sin el permiso del administrador de la web origen. Seguramente no haya existido ninguna mala intención, solo has enlazado una imagen, al fin y al cabo no te has apropiado de nada. Esto sería lo que se llama un HOTLINK.

La otra cara de la moneda es cuando comprobamos el ancho de banda de la web origen. En mayor o menor medida, todos los proveedores de servicios de hosting incluyen el consumo de ancho de banda como un parámetro de los servicios que ofertan. Cuando proyectas un sitio web y su alojamiento, el ancho de banda es una de las opciones que debes contratar teniendo en cuenta a qué tipo de clientes se dirige y el tipo de actividad.

Si el contenido de la web origen es muy bueno o atractivo, seguramente otros usuarios pueden realizar un HOTLINK a imagenes que les interesen, esto provoca que las imágenes que se sirven desde nuestra página no consumen nuestro ancho de banda, sino el ancho de banda de la web origen. Y si obtenemos muchas visitas, esto provocará que agotemos el ancho de banda de la web origen sin que se haya producido ninguna visita a ésta.

Una buena solución para evitar que se enlacen imágenes desde otrás web a nuestra página y consumiendo muy pocos recursos de máquina,  es indicar estas instrucciones en el fichero de configuración del sitio web - para Apache 2 - :

# evitar hotlinking de imagenes
SetEnvIf Referer ejemplo\.es localreferer

    Order deny,allow
    Deny from all
    Allow from env=localreferer
    Header set Cache-Control max-age=3600




Las imágenes pueden descargarse igualmente, pero evitaremos que se realicen HOTLINKS, en este caso el sitio web protegido es  EJEMPLO.ES . Pero en ocasiones, hemos contratado más de un nombre de dominio para el mismo sitio web y esto hace que cuando accedemos con el nombre EJEMPLO.COM, podemos ver la web pero no veremos ninguna imagen; en ese caso deberá indicar todos los nombres de dominio la siguiente forma :

:# evitar hotlinking de imagenes
SetEnvIf Referer ejemplo\.es localreferer
SetEnvIf Referer ejemplo\.com localreferer

    Order deny,allow
    Deny from all
    Allow from env=localreferer
    Header set Cache-Control max-age=3600


En este ejemplo he indicado dos nombres de dominio, pero puede indicar todos los que desee, siempre que se redirijan al sitio web que debe servir el contenido.

Espero que esta información te haya sido util.


domingo, 26 de enero de 2014

Web en Apache con Python y WSGI (III) - Enrutador

Si has llegado hasta aquí sin pasar por el primer artículo 'Web en Apache con Python y WSGI (I)', no deberías continuar hasta leer los dos anteriores. Aunque todos los artículos son independientes en el tema a tratar, guardan una conexión con el objetivo hacia el que se dirigen PYTHON+MOD_WSGI+MYSQL+APACHE.

Introducción al concepto

Un "ENRUTADOR" de solicitudes web, tiene la importante tarea de gestionar qué respuesta se debe producir cuando se recibe una solicitud desde una página web. En la escueta definición de SOLICITUD se incluyen los clasicos FORM html, AJAX, REST,...y un largo etc. que ahora no corresponde detallar.

Esta pieza es fundamental en el desarrollo de un sitio web ( website ) que puede agrupar una gran cantidad de información y necesita responder dinámicamente según la solicitud que reciba de un cliente ( navegador, robot y otro tipo de programa o dispositivo).

Para desarrollar un 'ENRUTADOR' sencillo (para complicarse la vida, siempre hay tiempo...) estudiaremos que tipo de solicitudes podemos esperar y que tipo de respuestas vamos a producir.

Entradas y Salidas

Si te paras a pensar qué tipo de solicitudes puede hacernos un navegador cuando accede a nuestro sitio web, podríamos indicar algunas como :

http://www.prueba.com
http://www.prueba.com/cliente
http://www.prueba.com/cliente?codigo=9214&nombre=Jose%20Garcia      ( una tipica solicitud GET )
http://www.prueba.com/cliente/facturas/201400001

Además, HTTP define varias operaciones o verbos : GET, PUT, POST, DELETE que deberíamos tener en cuenta. Que pueden facilitarnos más información sobre qué tipo de operación debemos realizar con la solicitud, no olvidemos que junto a una solicitud, tambien podemos recibir datos.

GET  nos indica una solicitud de información o bien que se responda con una página web. Es el verbo por defecto.
PUT puede ser utilizado cuando nos solicitan que modifiquemos unos datos en una ficha de cliente. Por supuesto, la solicitud incluirá los datos a modificar y un código por el que deberíamos buscar al cliente.
POST puede ser utilizado cuando nos solicitan el crear un nuevo cliente.
DELETE puede ser utilizado cuando nos solicitan eliminar un cliente, siempre deberá incorporar los datos necesarios para identificar de una forma única al cliente a eliminar.

Observa que en cada información indico 'PUEDE SER UTILIZADO' porque esto es una convención, no una obligación.

También deberíamos tener en cuenta si nuestro sitio web responderá a solicitudes AJAX, creo que hoy día cualquier sitio web debe responder a solicitudes AJAX. Una solicitud AJAX transforma nuestra respuesta radicalmente.

Todo esto nos proporciona una valiosa información sobre qué se espera de 'ENRUTADOR'.

Definir un árbol de rutas posibles

 Observa el siguiente código :

# rutas ajax
mapper = routing.Map(default_subdomain='www',redirect_defaults='/')
mapper.add(rule='/dealer_ajax',controller="dealer.rest(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/user_ajax',controller="user.rest(environ['REQUEST_METHOD'].upper(),parametros)")
        mapper.add(rule='/manufacturer_ajax',controller="manufacturer.rest(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/supplier_ajax',controller="supplier.rest(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/customer_ajax',controller="customer.rest(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/customer_list_ajax',controller="customer.getList(parametros)")
mapper.add(rule='/product_ajax',controller="customer.get()")
mapper.add(rule='/user_auth_ajax',controller="user.auth(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/customer_auth_ajax',controller="customer.auth(environ['REQUEST_METHOD'].upper(),parametros)")
 

# rutas NO ajax
mapper.add(rule='/',controller="index()")

mapper.add(rule='/index',controller="index()")
mapper.add(rule='/admin',controller="admin()")
mapper.add(rule='/dealer',controller="dealer.get(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/user',controller="user.get(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/manufacturer',controller="manufacturer.get(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/supplier',controller="supplier.get(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/customer',controller="customer.get(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/customer_list',controller="customer.getList()")
mapper.add(rule='/customers',controller="customer.getList2()")
mapper.add(rule='/product',controller="product.get(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/user_auth',controller="user.auth(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/customer_auth',controller="customer.auth(environ['REQUEST_METHOD'].upper(),parametros)")
mapper.add(rule='/upload',controller="entity.rest(environ['REQUEST_METHOD'].upper(),parametros)")

Inicialmente defino una ruta por defecto, que respondería con una página inicial del sitio web.

Posteriormente voy incorporando distintas solicitudes posibles utilizando, el parámetro REQUEST_METHOD indica el tipo de verbo http GET, PUT, POST, DELETE y parámetros puede una estructura de datos :  list, dict o json.

mapper.add(rule=' solicitud posible ', controller=" función o clase.método que responderá ")

Además, es posible que con la solicitud nos encontremos con parámetros indeseables que el usuario haya introducido a mano en la linea de navegación y para los que no hayamos preparado el 'ENRUTADOR' :

http://www.prueba.com/customer?xyzk

Antes de comenzar a tratar la solicitud recibida, deberá eliminar los parámetros indeseables que pueden hacer que el ENRUTADOR fracase. En nuestro caso, solo he tratado de eliminar cualquier parámetro que aparezca detrás de un ? o %3F, si aún así, la ruta no existe por cualquier causa, devolvemos un código 404.

if environ['REQUEST_URI'].find('%3F')>0:
        __output = mapper.match(environ['REQUEST_URI'][0:environ['REQUEST_URI'].find('%3F')])
 elif environ['REQUEST_URI'].find('?')>0:
        __output = mapper.match(environ['REQUEST_URI'][0:environ['REQUEST_URI'].find('?')])
 else:
        __output = mapper.match(environ['REQUEST_URI'])
        # Si la ruta no existe devolvera 404 y podremos decidir tratarla o no


Pero suponga que lo que el cliente necesita con su solicitud es un documento que Vd. guarda en un repositorio del sitio web, en ese caso le puede interesar dejar que acceda a él libremente :

if __output == '404':
        # Realizar directamente la peticion no parametrizada en rutas
        no_mapper = eval("noMapper(environ['REQUEST_URI'])")
        if no_mapper == '404':
               # No existe la ruta parametrizada y tampoco el recurso
               __output = mapper.match('/')
               # evita codigo malicioso en eval {'__import__': None, '__builtins__': None}, {}
               output.append(eval(__output))
        else:
               # existe ruta directa al documento
               output.append(no_mapper)

Devolver una respuesta al cliente

Una vez tenemos todo parametrizado, solo queda generar la respuesta y eso lo conseguimos con :

if __output == '404':
       ...
else:
        if __output:
            try:
                 output.append(eval(__output))
            except Exception as e:
                 tb = sys.exc_info()[2]
                 LOG.debug("Error <%s> en linea %s !!!\n" % (str(e),tb.tb_lineno))



Por tanto, los datos que devuelva la función o clase.método, se incorporan a una estructura list denominada 'output'

Y esta estructura se devolverá acompañada de unos parámetros :

try:
        if len(output)>0:
            status = '200 OK'
            try:
                  output_len = len('\n'.join(output))
            except Exception as e:
                  tb = sys.exc_info()[2]
                  LOG.debug("Error <%s> en línea %s !!!\n" % (str(e),tb.tb_lineno))
            start_response(status, [('Content-type', 'text/html; charset=UTF-8'),
                                    ('Content-Length', str(output_len)),
                                    ('Set-Cookie',_set_cookie_.encode('utf8'))])
            return ' '.join(output)

Inicialmente comprobamos si 'output' contiene información, y posteriormente valora su longitud. Crea los datos para 'start_response' y devuelve ''.join(output).

En estas fechas ya he liberado la primera versión en desarrollo de PYMETRICK donde podrá encontrar un módulo ROUTING.py, además de otros muchos de los que hablaremos.

Conclusiones

Todo este código puede insertarse en el módulo tratado en el primer artículo Web en Apache con Python y WSGI (I), en el que nos referíamos a un fichero app.wsgi 

En el caso de las solicitudes AJAX, la respuesta debería contener una estructura de datos que posteriormente pueda interpretar y tratar javascript - en otra entrega escribiré sobre este particular - pero por el momento, puedes estar preguntándote ¿Dónde puedo comprobar si se trata de una solicitud AJAX ?, deberá comprobar si existe la variable HTTP_X_REQUESTED_WITH en el diccionario 'environ',  si no existe, señal de que no es una petición AJAX.

def  isAjax(self,environ):
        """AJAX, la variable HTTP_X_REQUESTED_WITH puede estar ausente en variables de entorno"""
        try:
                if environ.get('HTTP_X_REQUESTED_WITH').upper() == 'XMLHTTPREQUEST':
                    return 1
        except Exception as e:
                return 0







jueves, 11 de abril de 2013

HTML5 y WebStorage. Almacenamiento de datos en local

Hasta el momento, los datos almacenados desde una página HTML solo podían tratarse en 4KB de una coockie o bien, debían tratarse en una base de datos del servidor web.

HTML5 rompe esta limitación y se apoya en navegadores más evolucionados que soportan esta funcionalidad; por tanto, se pueden implementar ya perfectamente en los sitios web que realizamos en la actualidad.

Esta soportado por las siguientes versiones o superiores de cada navegador:
  • IE 8.0+
  • Firefox 3.5+
  • Safari 4.0+
  • Chrome 4.0+
  • Opera 10.5+
  • iPhone 2.0+
  • Android 2.0+

El API WebStorage se divide en dos vertientes, el "SessionStorage", para guardar información que caducará al final de la sesión y el "LocalStorage", que permite almacenar datos que perduren entre distintas visitas del mismo usuario al sitio web.

Ahora un poco de teoría.

API: INTERFAZ STORAGE

Permite acceder a una serie de pares clave/valor, también llamados ítems. Está implementada por los objetos SessionStorage y LocalStorage, explicados más adelante.

Se podría pensar en el objeto como un array asociativo, es decir, un array al que se puede acceder a través de un índice de tipo string (clave) y no necesariamente una posición.

ATRIBUTOS:

length: devuelve el número de pares clave/valor que contiene el objeto. Es de sólo lectura, no es modificable.

MÉTODOS:

key(pos): devuelve la clave que se encuentra en la posición indicada en la variable "pos" que se pasa como parámetro. El parámetro puede ser un literal, es decir, un número, o bien una variable que contenga un valor numérico.

Si la posición es mayor que el número de elementos (length - 1), entonces devuelve null.

getItem(clave): obtiene el ítem del objeto que contiene como clave el valor que se le pasa como parámetro. 'clave' puede ser una cadena de caracteres o una variable de tipo string.

También se puede obtener la clave tomando el objeto como si se tratase de un array asociativo, es decir, storage['clave'] o accediendo como objeto storage.clave.

setItem(clave, valor): comprueba si la clave existe en el objeto, si no existe la inserta y en caso de existir, actualiza su valor al valor que se le pasa como segundo parámetro.

También se puede asignar una clave como si se tratase de un array asociativo, es decir, storage['clave'] = 'valor' o actualizando como objeto storage.clave = valor.

Como curiosidad, decir que los datos se guardan en orden alfabético.

removeItem(clave, valor): comprueba si la clave existe en el objeto, si no existe la inserta y en caso de existir, actualiza su valor al valor que se le pasa como segundo parámetro.

clear(): elimina todos los pares clave/valor del objeto.

SESSIONSTORAGE

Puede guardar información referente a una ventana/pestaña en la que el usuario lleva a cabo una transacción simple, pero podría llevar a cabo múltiples transacciones en diferentes ventanas/pestañas al mismo tiempo.

Para ello se utiliza el atributo sessionStorage. Cabe destacar que los datos se pierden al cerrar el navegador.


LOCALSTORAGE

Puede almacenar información útil para múltiples ventanas/pestañas, que perdura en el tiempo. No se puede compartir de navegador a navegador. Para ello se utiliza el atributo localStorage. En este caso los datos no desaparecen aun cerrando el navegador, únicamente se borrarán haciendo un borrado manual, mediante código, a través de la consola del navegador o borrándolas directamente desde la carpeta en la que se guardan en el SO.

EJEMPLO:

Creamos una página HTML5 y crearemos un ejemplo con LOCALSTORAGE :








<html lang="es">
<head>
.....
<script>
function save()
{
var vnombre = document.getElementById('nombre').value;
var vedad = document.getElementById('edad').value;
var vemail = document.getElementById('email').value;
localStorage.setItem('text_nombre', vnombre);
localStorage.setItem('text_edad', vedad);
localStorage.setItem('text_email', vemail);
}

function load()
{

if (window.localStorage) {

alert(localStorage.length);

var storedValue = localStorage.getItem('text_nombre');
if(storedValue) {
document.getElementById('nombre').value = storedValue;
}
var storedValue = localStorage.getItem('text_edad');
if(storedValue) {
document.getElementById('edad').value = storedValue;
}
var storedValue = localStorage.getItem('text_email');
if(storedValue) {
document.getElementById('email').value = storedValue;
}
} else {
alert('Actualice navegador!!!');
}
}

function remove()
{
document.getElementById('nombre').value = '';
document.getElementById('edad').value = '';
document.getElementById('email').value = '';
localStorage.removeItem('text_nombre');
localStorage.removeItem('text_edad');
localStorage.removeItem('text_email');

// tambien vale
localStorage.clear();
}
</script>

.....
</head>
<body onload="load()">
<form name="formulario">
<label for="nombre"&gtNombre&lt/label&gt&ltinput type="text" name="nombre" id="nombre" />
<label for="edad"&gtEdad&lt/label&gt&ltinput type="text" name="edad" id="edad" />
<label for="email"&gtMail&lt/label&gt&ltinput type="text" name="email" id="email" />
<input type='button' value='guardar' onclick="save()">
<input type='button' value='eliminar' onclick="remove()">
</form>
</body>
</html>

Es un ejemplo muy funcional y sencillo, cada vez que se recarga la página load() preguntará si el navegador soporta LOCALSTORAGE con if (window.localStorage) e indicará cuantos elementos están almacenados alert(localStorage.length); y a continuación carga los datos desde LOCALSTORAGE y los muestra en el formulario.

Solo tiene un botón GUARDAR y otro ELIMINAR, para guardar y eliminar los datos almacenados respectivamente. Cada dato se guardará como una clave/valor diferente, en este caso guardaremos tres claves/valores, aunque con un poco de código es posible guardar muchos valores en una sola clave si fuera necesario.

Cuando la base de datos ha llegado al límite de su máximo contenido ( 5Gb ), se puede comprobar con :

try {
localStorage.setItem('foo', 'bar');
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
alert('el almacén local excede el tamaño máximo permitido');
}
}

RECOMENDACION

Si aún no has encontrado un buen EDITOR para HTML y otros (también útil para PYTHON), te recomiendo SUBLIME TEXT