Mostrando entradas con la etiqueta Javascript. Mostrar todas las entradas

15 enero 2017

Subir imagenes al servidor usando un Web Services API REST

  4 comentarios
14:13

Interfaz visual del servidor de imagenes
Desde hace rato que me surgía esta duda y es que los API Rest actualmente son la manera de trabajar la web, ya que nos ofrecen infinitas herramientas y recursos para un trabajo grupal y de optimizacion, pero, en vista de que los web services son archivos textuales que nos sirve el servidor en formato JSON o XML, parece un poco complicado subir una imagen a través de un API ya que una imagen no es un texto, o si? Si no has leído mis entradas anteriores te invito a leerlas para que te empapes mas de lo que hablare en esta.


Luego de dar lectura a las dos entradas anteriores, y entender en que consiste la creación y consumo de un web services, podemos proseguir. En este caso, vamos a crear un servicio completo de subida de imágenes al servidor usando esta metodología de trabajo y entendiendo ciertas características del mismo. Primero, entendiendo que si vamos a subir una imagen al servidor haciendo uso de un REST API, es necesario que la imagen sea un texto, sino, como envías una imagen en un objeto de este estilo, y se preguntaran, en serio se puede hacer esto? codificar una imagen a texto? Y la verdad es que si, se puede, y de esta herramienta tan preciada haremos uso hoy.

 Antes de comenzar, cabe destacar que al final del post dejare un demo y un link para descargar los archivos. Tenemos 4 archivos esenciales que se basan en la siguiente estructura, cabe acotar que no son los únicos archivos incluidos dentro del directorio puesto a que tengo incluida también ciertas librerías de diseño y dinamismo, entre ellas angularJS y Materialize para CSS, pero, en el siguiente esquema, solo nos centraremos en los archivos que modificaremos, el resto de los archivos podrán encontrarlos en el enlace de descarga del proyecto completo


  • css
    • custom.css
  • js
    • custom.js
  • upload
  • index.html
  • server.php
css/custom.css

Este código no requiere mucha explicación, aunque haremos uso del framework de diseño Materialize, necesitaremos definir los siguientes estilos para ciertos elementos


body {
 background-color: #fefefe;
}

#imgCont {
 background:#eeeeee;
 width:auto;
 height:300px;
 padding: 5px 5px 5px 5px;
 border: 1px solid #cccccc;
 margin-top:10px;
 overflow: auto;
}

#imgCont img {
 width:90px;
 border:1px solid #bbbbbb;
 margin-right:5px;
 transition:all ease .2s;
 -webkit-transition:all ease .2s;
}
#imgCont img:hover {
 opacity:.8;
 transition:all ease .2s;
 -webkit-transition:all ease .2s;
}
css/custom.js

Aquí empieza la función, si bien no podemos enviar una imagen como tal a un servicio web, si lo podemos hacer si codificamos la imagen, en este caso, haremos uso de base64, la cual es una codificación que tiene la capacidad de convertir cualquier dato definido a nivel de bytes en un formato seguro de transportar por Internet como lo son los caracteres ASCII, es decir, no solo sirve para codificar imágenes, sirve para codificar cualquier archivo, música, vídeos, documentos, o simplemente, cualquier cadena de texto o carácter que se represente en bytes, es decir, puede transformar todo lo que sea recurso digital. En nuestro controlador de imagen en angular simplemente definimos la función encodeImageFileAsURL(); la cual se encarga de hacer todo el trabajo de codificación, y luego la cadena es enviada al web services a través de un objeto.


     var app = angular.module('crud',[]);


  // Controlador principal de nuestra pagina
  app.controller('mainCtrl', function($scope,$http) {
   $scope.dominio = "http://localhost/imagenes/";
         $scope.message = 'Ejemplo';
         $scope.subtitle = "Subir una imagen haciendo uso de API REST";

         $scope.imageJSON = {};

         $scope.enlaces = {};

         angular.element(document).ready(function () {
       $scope.get();  
      });

         // La funcion post() que hace la solicitud para publicar un nuevo elemento
      $scope.post = function() {
       $http.post("server.php", $scope.imageJSON)
        .then(function (response){
               console.log(response);
               Materialize.toast(response.data.statusMessage, 4000);


               if(response.data.data != null) {
                $scope.cargarImagen(response.data.data);
               } 

               $scope.get();
           }, 
           function(response) {
            // Aqui va el codigo en caso de error
           });
      }

      $scope.get = function() {
       $http.get("server.php")
        .then(function (response){
               console.log(response);
               $scope.imagenes = response.data.data;

               
           }, 
           function(response) {
            // Aqui va el codigo en caso de error
           });
      }

      $scope.cargarImagen = function(ruta) {


       var container = document.getElementById('imgTest');
       var newImage = document.getElementById('imagen');
          newImage.src = ruta;
          container.style.width = 'auto';
          container.style.height = 'auto'

          container.innerHTML = newImage.outerHTML;

         $scope.enlaces.link = $scope.dominio + ruta;
         $scope.enlaces.html = "<a href='"+ $scope.dominio + ruta +"'>"+$scope.dominio + ruta+"</a>";
         $scope.enlaces.foros = "[IMG]"+$scope.dominio + ruta+"[/IMG]"
      }


         $scope.encodeImageFileAsURL = function() {

       var filesSelected = document.getElementById("inputFileToLoad").files;

       if (filesSelected.length > 0) {
         var fileToLoad = filesSelected[0];

         var fileReader = new FileReader();

         fileReader.onload = function(fileLoadedEvent) {
          
           var srcData = fileLoadedEvent.target.result; // <--- data: base64
      $scope.imageJSON.encodedImage = srcData;


      $scope.post();
         }
         fileReader.readAsDataURL(fileToLoad);
       }
     }



     });
server.php

Este archivo trabaja del lado del servidor, en este caso apache, el archivo recibe el texto de la imagen codificada, y luego la pasa a la función save_base64_image();, la cual, no hace mas que analizar la cadena enviada y mediante el uso de herramientas de decodificacion y escritura en el servidor, crea la imagen en el directorio upload del mismo, almacenando asi una imagen con una extensión, y creando la URL especifica del mismo.


<?php 
 header("Access-Control-Allow-Origin: *");
 // Permite la ejecucion de los metodos
 header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE"); 
 
 switch ($_SERVER['REQUEST_METHOD']) {

  case 'GET':
   $directorio = opendir("./upload"); //ruta actual

   $contador = 0;

   while ($archivo = readdir($directorio)) //obtenemos un archivo y luego otro sucesivamente
   {
       if (!is_dir($archivo))//verificamos si es o no un directorio
       {
           $listado[$contador] = $archivo;
       }
     $contador++;
   }


   

   $listado = array_values($listado);

   if(count($listado)!=0) {
    print_json(200, true, $listado);
   } else {
    print_json(200, "No existen elementos", null);
   }

   break;
  case 'POST':
    $content = file_get_contents("php://input");

    $array = json_decode($content, true);


    $validar = validate($array['encodedImage']);

    if($validar==1) {
     $imagen = save_base64_image($array['encodedImage'], "upload/IMG_" . strtoupper(md5($array['encodedImage'])));

     if($imagen!=null) {
      print_json(200, "Completado", $imagen);

     } else {
      print_json(200, "Este archivo ya existe", null);
     }
    } else {
     print_json(200, "Extension invalida", null);
    }

    
    
   break;
  default:
   print_json(405, 'Metodo no permitido', null);
   break;
 }

 function validate($string_base64) {
  $array = explode(",", $string_base64);
  if( ($array[0] == "data:image/jpeg;base64") || ($array[0] == "data:image/gif;base64") || ($array[0] == "data:image/png;base64") ) {
   return 1;
  } else {
   return 0;
  }
 }
 



 function save_base64_image($base64_image_string, $output_file_without_extentnion, $path_with_end_slash="" ) {
     //usage:  if( substr( $img_src, 0, 5 ) === "data:" ) {  $filename=save_base64_image($base64_image_string, $output_file_without_extentnion, getcwd() . "/application/assets/pins/$user_id/"); }      
     //
     //data is like:    data:image/png;base64,asdfasdfasdf
     $splited = explode(',', substr( $base64_image_string , 5 ) , 2);
     $mime=$splited[0];
     $data=$splited[1];

     $mime_split_without_base64=explode(';', $mime,2);
     $mime_split=explode('/', $mime_split_without_base64[0],2);
     if(count($mime_split)==2)
     {
         $extension=$mime_split[1];
         if($extension=='jpeg')$extension='jpg';
         //if($extension=='javascript')$extension='js';
         //if($extension=='text')$extension='txt';
         $output_file_with_extentnion.=$output_file_without_extentnion.'.'.$extension;
     }

     if(file_exists($output_file_with_extentnion)) {
      return null;
     } else {
      file_put_contents( $path_with_end_slash . $output_file_with_extentnion, base64_decode($data) );
      return $output_file_with_extentnion;
     }
     
     
 }

 function print_json($status, $mensaje, $data) {
  header("HTTP/1.1 $status $mensaje");
  header("Content-Type: application/json; charset=UTF-8");

  $response['statusCode'] = $status;
  $response['statusMessage'] = $mensaje;
  $response['data'] = $data;

  echo json_encode($response, JSON_PRETTY_PRINT);
 }


?>
index.html
Esta sera la pagina principal, donde se encuentra toda la interaccion con el usuario, y donde se embeden todos los archivos necesarios para el funcionamiento.


<!DOCTYPE html>
<html lang="es" ng-app="crud" >
<head>
 <meta charset="UTF-8">
 <title>Rest API Visual Client</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <!-- Incluimos el CND de Materialize CSS -->
 <link rel="stylesheet" href="css/materialize.min.css">
 <!-- Nuestro CSS personalizado -->
 <link rel="stylesheet" href="css/custom.css">
 <!-- Incluimos el CND de AngularJS -->
 <script src="js/angular.min.js"></script>
 <!-- Incluimos el CND de la libreria jQuery -->
 <script src="js/jquery-3.1.1.min.js"></script>
 
</head>
<body class="container" ng-controller="mainCtrl">

 <div class="row">
  <div class="col s12">
   <h1>{{message}}</h1>
   <p>{{subtitle}}</p> 
  </div>
 </div>

 <div class="row">
  <div class="col s12 m6 l6">
   <div class="row">
    <div class="col s12">
     <h6><small>Solo JPG, PNG, GIF</small></h6>
     <input id="inputFileToLoad" type="file"/>
     <button class="btn" ng-click="encodeImageFileAsURL()">Subir</button>
     
     
    </div>
    <div class="col s12">
     <div id="imgCont">
      <img ng-click="cargarImagen('upload/' + x)" ng-repeat="x in imagenes" src="upload/{{x}}" title="{{x}}" alt="{{x}}">
     </div>


    </div>

    <div class="input-field col s12">
        <input id="Link" type="text" placeholder="Enlace directo" class="validate" readonly ng-value="enlaces.link" ng-model="enlaces.link">
    </div>
    <div class="input-field col s12">
        <input id="HTML" type="text" class="validate" placeholder="Codigo HTML" readonly ng-value="enlaces.html" ng-model="enlaces.html">
    </div>
    <div class="input-field col s12">
        <input id="Forum" type="text" class="validate" placeholder="Codigo para foros" readonly ng-value="enlaces.foros" ng-model="enlaces.foros">
    </div>

   </div>
   
  </div>

  <div class="col s12 m6 l6">
   <div id="imgTest" class="center-align">

    <div class="preloader-wrapper small active">
        <div class="spinner-layer spinner-green-only">
          <div class="circle-clipper left">
            <div class="circle"></div>
          </div><div class="gap-patch">
            <div class="circle"></div>
          </div><div class="circle-clipper right">
            <div class="circle"></div>
          </div>
        </div>


    </div>
    <p>Esperando imagen</p>

    <img id="imagen" width="100%" alt="">

   </div>
  </div>
 </div>



 
     
 <!-- Nuestro codigo JavaScript personal -->
 <script src="js/custom.js"></script> 
 <!-- Incluimos el CND de Materialize JS -->
   <script src="js/materialize.min.js"></script>
</body>
</html>

Esto es todo, para entender mejor, les voy a dejar una demo y el link de descarga en Github para que lo tengan en su computador

  Demo Descargar

Leer completo

08 enero 2017

Consumir un Web Services API Rest con AngularJS

  6 comentarios
23:07


Actualización 12 de Julio de 2018

En vista de que algunas personas me comentaron que no funcionaba este tutorial en Windows, quiero aclarar que cuando lo realice, lo trabaje en Ubuntu, distribución GNU/Linux, por lo tanto, no me di cuenta de los errores que pudiera generar en Windows, esto ha sido corregido, y el código ha sido actualizado para funcionar en cualquier plataforma.

Como lo prometido es deuda y quiero saldar esta deuda con ustedes, ayer mas o menos a esta misma hora hice publica una entrada sobre como Crear un Web Service API Rest con PHP y MySQL en el que prometí traer pronto como consumir dicho servicio y he aquí el tutorial, por eso, si no has visto el tutorial anterior, te recomiendo leerlo antes de empezar con este, créeme, tendrás una mejor comprensión del mismo y así vamos al ritmo.

Tal cual mencione el dia de ayer, los API Rest o Web Service no son mas que archivos en formato JSON (JavaScript Object Notation) o XML (eXtended Markup Language) que nos sirven información con respecto a una entidad en una base de datos haciendo uso de los métodos HTTP (GET, POST, PUT y DELETE), justo ayer, hacíamos las pruebas básicas del API Rest creado con la aplicación de tipo extensión de Chrome Insomnia, pero, eso es solo para efectos de pruebas, valga la redundancia.

Los Web Service API Rest son usualmente consumidos desde JavaScript en el cliente, usando librerías como jQuery o el framework AngularJS, por efectos de facilidad y ademas, de visibilidad, usare AngularJS en este tutorial específicamente.

Aspecto de nuestro API Rest Visual Client


Ahora, recordemos la estructura que llevabamos anteriormente, donde teniamos completado el Web Service

Esta no es mas que la estructura básica del back-end donde podemos encontrar con los archivos de Web Services y que explique en el tutorial anterior.

Habíamos quedado pendiente con los archivos de la carpeta public_html, donde podemos encontrar el archivo index.html que sera el archivo de nuestra pagina principal y su carpeta parent sera la carpeta del Front-end específicamente.

Todo lo que este en la carpeta public_html pertenece única y exclusivamente a código estructura y maquetado del cliente, mientras que lo que este fuera de ella, pertenece al código que corre en el servidor, por lo tanto, hoy nos enfocaremos específicamente en dicha carpeta ya que haremos un cliente visual para el consumo del Web Services que realizamos previamente.

Antes de comenzar, quiero acotar que voy a dejar todos los archivos del proyecto en un enlace para descargar al final, asi que no se preocupen, presten atencion al tutorial y luego, hacen lo que deseen con el codigo.

Se ubican dentro de la carpeta public_html y crean el siguiente directorio

Donde tenemos los archivos básicos de todo proyecto web.

Es importante destacar, que ahora que tenemos mas archivos, lógicamente vamos a tener mas URL's a donde ir, entonces, antes de empezar, en el archivo .htaccess que ya tenemos creado, vamos a agregar las siguientes lineas para controlar estas direcciones

# Acortar URL
RewriteRule ^([a-zA-Z]+)/([a-zA-Z0-9-.]+)$ public_html/$1/$2
RewriteRule ^([a-zA-Z]+)/([a-zA-Z]+)/([a-zA-Z0-9-.]+)$ public_html/$1/$2/$3

Esto con el fin de que los usuarios comunes no puedan ver el ingresar directamente a la carpeta public_html desde su navegador si no que mas bien, nos genere una URL mas estilizada y amigable.

Una vez realizado esto, empezamos a crear nuestro API Rest Visual Client (Como lo he llamado).

Para empezar, en el archivo index pegaramos el siguiente codigo


core/public_html/index.html

<!DOCTYPE html>
<html lang="es" ng-app="crud" >
<head>
 <meta charset="UTF-8">
 <title>Rest API Visual Client</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <!-- Incluimos el CND de Materialize CSS -->
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.8/css/materialize.min.css">
 <!-- Nuestro CSS personalizado -->
 <link rel="stylesheet" href="css/custom.css">
 <!-- Incluimos el CND de AngularJS -->
 <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
 <!-- Incluimos el CND de Angular Route -->
 <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular-route.min.js"></script>
 <!-- Incluimos el CND de la libreria jQuery -->
 <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
 
</head>
<body ng-controller="mainCtrl">

    <nav>
      <div class="nav-wrapper blue">
        <a href="#!/" class="brand-logo">Friki Bloggeo</a>
        <ul id="nav-mobile" class="right hide-on-med-and-down">
         <li><a href="#!/">Home</a></li>
          <li><a href="#!/usuario">Usuario</a></li>
          
        </ul>
      </div>
    </nav>
          
 <div class="container">
  <!-- ng-view renderiza nuestras views y las muestra en el index -->
  <div ng-view></div>
 </div>
     
 <!-- Nuestro codigo JavaScript personal -->
 <script src="js/custom.js"></script> 
 <!-- Incluimos el CND de Materialize JS -->
   <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.8/js/materialize.min.js"></script>
</body>
</html>

Al igual que el tutorial anterior, no hare mucho enfasis en explicar los codigos ya que los mismos estan documentados. Continuamos.

Bien, hasta ahora tenemos solo nuestra pagina básica donde llamaremos las vistas o templates. Entonces, para continuar vamos a agregar los siguientes códigos a nuestros templates

core/public_html/templates/home.html


<div class="row">
 <div class="col s6">
  <h1>{{message}}</h1>
  <p>{{subtitle}}</p>
 </div>
</div>


core/public_html/templates/usuario.html


<div class="row">
  <div class="col s6">
   <h1>{{message}}</h1>
   <p>{{subtitle}}</p>
  </div>
 </div>

 <div class="row">   
      <div class="col s4">
    <form>
     <div class="row">
      <div class="input-field col s12">
              <input required id="Usuario" type="text" class="validate" ng-value="nuevo.Usuario" ng-model="nuevo.Usuario">
              <label for="Usuario">Usuario</label>
            </div>
     </div>

     <div class="row">
      <div class="input-field col s12">
              <input required id="Clave" type="password" class="validate" ng-value="nuevo.Clave" ng-model="nuevo.Clave">
              <label for="Clave">Clave</label>
            </div>
     </div>

     <div class="row">
      <div class="input-field col s12">
              <input required id="Estatus" type="text" class="validate" ng-value="nuevo.Status" ng-model="nuevo.Status">
              <label for="Estatus">Estatus</label>
            </div>
     </div>

     <div class="row">
      <div class="col-s4" ng-if="nuevo.Id == null">
       <button class="btn waves-effect blue" ng-click="post()">Submit</button>
      </div>

      <div class="col-s4" ng-if="nuevo.Id != null">
       <button class="btn waves-effect blue" ng-click="put(nuevo.Id)">Submit</button>
      </div>
     
     </div>
       </form>


      </div>
      <div class="col s8">
      <input type="text" ng-model="search" placeholder="Buscar">
    


       <table class="highlight responsive-table">
        <thead>
         <tr>
          <th>ID</th>
          <th>Usuario</th>
          <th>Clave</th>
          <th>Estatus</th>
          <th></th>
          <th></th>
         </tr>
        </thead>

        <tbody ng-if="lista.length != null">
         <tr ng-click="get(x.Id)" ng-repeat="x in lista | filter : search">
          <td>{{x.Id}}</td>
          <td>{{x.Usuario}}</td>
          <td>{{x.Clave}}</td>
          <td>{{x.Status}}</td>
          <td><button class="btn btn-small waves-effect red" ng-click="delete(x.Id)">eliminar</button></td>
         </tr>
        </tbody>

        <tbody ng-if="lista.length == null">
         <tr>
          <td colspan="4">No hay datos dispobibles</td>
         </tr>
        </tbody>


       </table>
      </div>
     </div>

Bien, nos restan tan solo dos archivos, el custom.css y custom.js los cuales contienen codigo personalizado, cada uno en su respectivo lenguaje, pero basicamente, custom.css es tu estilo personal asi que no hare ningun codigo para ello, continuamos con el siguiente archivo.
core/public_html/js/custom.js

  var app = angular.module('crud',['ngRoute']);

  // Configuracion de las rutas y sus respectivas plantillas
  app.config(function($routeProvider) {
    $routeProvider
              .when('/', {
                  templateUrl : 'templates/home.html',
                  controller  : 'mainCtrl'
              })
              .when('/usuario', {
                  templateUrl : 'templates/usuario.html',
                  controller  : 'usuario'
              })

            
      });

  // Controlador principal de nuestra pagina
  app.controller('mainCtrl', function($scope) {
         $scope.message = 'Friki Bloggeo';
         $scope.subtitle = "Ejemplo de consumo de un API Rest con AngularJS";
     });


  // Controlador de la entidad Usuario donde se incluiran cada una de sus funciones
  app.controller('usuario', function($scope,$http) {

   $scope.message = 'Friki Bloggeo';
         $scope.subtitle = "Gestion de Usuario";

   // Al cargar la pagina, ejecutamos la funcion get() para rellenar la tabla
      angular.element(document).ready(function () {
       $scope.get("");
       
      });

      // La funcion get() que hace la solicitud para obtener los datos
      $scope.get = function(id){
       // Si la Id esta en blanco, entonces la solicitud es general
       if(id=="") {
        $http.get("api/usuario").then(function (response) {
            $scope.lista = response.data.data;
            Materialize.toast(response.data.statusMessage, 4000);
            
        }, function(response) {
         // Aqui va el codigo en caso de error
        });
    // Si la Id no esta en blanco, la solicitud se hace a un elemento especifico
       } else {
        $http.get("api/usuario/" + id).then(function (response) {
            $scope.nuevo = response.data.data[0];
            Materialize.toast(response.data.statusMessage, 4000);
        }, function(response) {
         // Aqui va el codigo en caso de error
        });
       }
      }

      // La funcion post() que hace la solicitud para publicar un nuevo elemento
      $scope.post = function() {
       $http.post("api/usuario", $scope.nuevo)
        .then(function (response){
               Materialize.toast(response.data.statusMessage, 4000);
               $scope.nuevo = null;
               $scope.get("");
           }, 
           function(response) {
            // Aqui va el codigo en caso de error
           });
      }

      // La funcion put() que hace la solicitud para modificar un elemento especifico
      $scope.put = function(id) {
   
       $http.put("api/usuario/" + id, $scope.nuevo)
        .then(
         function (response){
               Materialize.toast(response.data.statusMessage, 4000);
               $scope.nuevo = null;
               $scope.get("");
           }, 
           function(response) {
            // Aqui va el codigo en caso de error
           });

      }

      // La funcion delete() que hace la solicitud para eliminar un elemeto esepecifico
      $scope.delete = function(id) {
       $http.delete("api/usuario/" + id)
       .then(
           function (response){
             console.log(response);
             Materialize.toast(response.data.statusMessage, 4000);
             $scope.nuevo = null;
             $scope.get("");
           }, 
           function (response){
             // Aqui va el codigo en caso de error
           }
        );
      }

  });

Con esto, ya tenemos listo nuestro cliente visual, y ya podremos empezar a crear cuantas templates o views deseemos para consumir cada tabla especifica. Ademas, dejo el archivo del proyecto (con archivos script locales) para su uso.


Demo Descargar - 1.1 MB

Leer completo

25 diciembre 2015

Menú contextual sencillo con HTML5, CSS3 y JavaScript (jQuery)

  4 comentarios
18:36



Un menú contextual es una lista de comando alternativos que aparece al hacer clic sobre el botón secundario del mouse sobre un elemento especifico. Esta mostrará ciertas funciones que se pueden hacer con dicho elemento, es de suma importancia en los sistemas operativos pues mejorar la navegabilidad del usuario en el mismo, no es posible mencionar algún sistema operativo que no cuente con ellos.

Así como existen menúes contextuales para los sistemas operativos, es posible también que existan en la web, por supuesto, lleva cierto trabajo, a diferencia de lo que implicaría programar estos en IDE's como Visual Studio para .NET o C# o incluso NetBeans para Java, que son trabajados de forma mas visual. Programarlos requiere del uso de 3 lenguajes sumamente sencillos, y que todo programador web debe conocer, HTML, CSS y JavaScript, específicamente hablando, del framework jQuery que tanta gracia ha proporcionado a la internet.

Antes de comenzar, te dejo una demo por acá


Codigo HTML

Este código debe ser introducido entre las etiquetas <body> ... </body> de la pagina.


<div id="outer-wrapper" onclick="ocultarMenu('menu-contextual');" oncontextmenu="mostrarMenu(event, this.id, 'menu-contextual');return false;">

 </div>
 <ul id="menu-contextual" oncontextmenu="return false;">
  <li>Paginas de Busqueda<span></span>
   <ul>
    <li onclick="location.href='http://google.com'">Google</li>
    <li onclick="location.href='http://yahoo.com'">Yahoo!</li>
    <li onclick="location.href='http://bing.com'">Bing</li>
   </ul>
  </li>
  <li class="separador">Redes Sociales<span></span>
   <ul>
    <li onclick="location.href='http://facebook.com'">Facebook</li>
    <li onclick="location.href='http://twitter.com'">Twitter</li>
    <li onclick="location.href='http://googleplus.com'">Google Plus</li>
   </ul>
  </li>
  <li onclick="window.history.forward()">Adelante</li>
  <li onclick="window.history.back()">Atras</li>
  <li>Favoritos<span></span>
   <ul>
    <li onclick="location.href='http://frikiblogeeo.blogspot.com'">Friki Bloggeo</li>
    <li onclick="location.href='http://blogger.com'">Blogger</li>
    <li onclick="location.href='http://gmail.com'">Gmail</li>
   </ul>
  </li>
  
 </ul>

Si pueden observar, la sección del menú contextual tiene la misma estructura que tiene un menú desplegable, en este caso vertical, la única diferencia seria en este caso aplicarle correctamente los estilos CSS para que este se ajuste al diseño de los menúes contextuales que vemos en los sistemas operativos como Windows o cualquier otro

Codigo CSS



* {
   margin:0 auto;
   padding:0 auto;
  }

  #outer-wrapper {
   background:transparent;
   position:absolute;
   width:100%;
   height:100%;
  }

  ul#menu-contextual {
   display:none;
   background:white;
   font-family:Verdana, Arial, "Times New Roman", sans-serif;
   font-size:12px;
   color:black;
   border:1px solid #CCC;
   box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -ms-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -webkit-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -o-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -moz-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -khtml-box-shadow:5px 5px 0px rgba(0,0,0,.1);
  }

  ul#menu-contextual ul {
   display:none;
   background:white;
   font-family:Verdana, Arial, "Times New Roman", sans-serif;
   font-size:12px;
   color:black;
   border:1px solid #CCC;
   padding:2px 9px 2px 2px;
   box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -ms-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -webkit-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -o-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -moz-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -khtml-box-shadow:5px 5px 0px rgba(0,0,0,.1);
  }

  ul#menu-contextual li:hover {
   background:#CCC;
   word-wrap:break-word;
  }

  ul#menu-contextual li:hover > ul {
   display:block;
  }

  .separador {
   border-bottom:1px solid #ccc;
  }

Hasta ahora no tenemos mas que un menú desplegable oculto dentro de nuestra pagina, que es necesario ser mostrado al oprimir el clic secundario de nuestro mouse, y que aparezca justamente en sitio de la pantalla donde hemos hecho el clic, esta magia la hacemos con lo siguiente

Codigo JS



/*
     * Autor: Anthony Medina
     * Email: anthonyjmedinaf@gmail.com
     * Blog: http://frikibloggeo.blogspot.com
  */

  function mostrarMenu(event, id, menu_id) {
   var posX, posY, span; // Declaracion de variables

   posX = event.pageX; // Obtenemos pocision X del cursor
   posY = event.pageY; // Obtenemos pocision Y del cursor

   // Hacemos aparecer el menu contextual
   $('#' + menu_id).fadeIn('fast');

   // Flecha que indica submenues
   span = $('#' + menu_id + " span");
   span.html("»");

   // Editando el codigo CSS para ciertos elementos
   span.css({float: 'right',marginRight: '12px'});
   $('#' + menu_id).css({position: 'absolute',display: 'block',top: posY,left: posX,cursor: 'default',width: '200px',height: 'auto',padding: '2px 9px 2px 2px',listStyle: 'none',listStyleType: 'none'});
   $('#' + menu_id + " li").css({width:'100%',height:'auto',margin:'0 auto',padding:'3px 0px 3px 7px',wordWrap:'break-word'});
   $('#' + menu_id + " li ul").css({listStyle:'none',listStyleType:'none',cursor:'default',position:'absolute',left:'212px',marginTop:'-20px',width:'200px',height:'auto',padding:'2px 9px 2px 2px'});
  }

  function ocultarMenu(menu_id) {
   $('#' + menu_id).fadeOut('fast');
  }

Y no olviden, lo mas importante, colocar esta pequeña linea justo debajo del <head> de la página web.


<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

Por último, les dejo el código completo para mayor facilidad



<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Menu Contextual</title>
 <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
 <script>
    /*
     * Autor: Anthony Medina
     * Email: anthonyjmedinaf@gmail.com
     * Blog: http://frikibloggeo.blogspot.com
  */

  function mostrarMenu(event, id, menu_id) {
   var posX, posY, span; // Declaracion de variables

   posX = event.pageX; // Obtenemos pocision X del cursor
   posY = event.pageY; // Obtenemos pocision Y del cursor

   // Hacemos aparecer el menu contextual
   $('#' + menu_id).fadeIn('fast');

   // Flecha que indica submenues
   span = $('#' + menu_id + " span");
   span.html("»");

   // Editando el codigo CSS para ciertos elementos
   span.css({float: 'right',marginRight: '12px'});
   $('#' + menu_id).css({position: 'absolute',display: 'block',top: posY,left: posX,cursor: 'default',width: '200px',height: 'auto',padding: '2px 9px 2px 2px',listStyle: 'none',listStyleType: 'none'});
   $('#' + menu_id + " li").css({width:'100%',height:'auto',margin:'0 auto',padding:'3px 0px 3px 7px',wordWrap:'break-word'});
   $('#' + menu_id + " li ul").css({listStyle:'none',listStyleType:'none',cursor:'default',position:'absolute',left:'212px',marginTop:'-20px',width:'200px',height:'auto',padding:'2px 9px 2px 2px'});
  }

  function ocultarMenu(menu_id) {
   $('#' + menu_id).fadeOut('fast');
  }

 </script>
 
 <style type="text/css">
  * {
   margin:0 auto;
   padding:0 auto;
  }
  #outer-wrapper {
   background:transparent;
   position:absolute;
   width:100%;
   height:100%;
  }

  ul#menu-contextual {
   display:none;
   background:white;
   font-family:Verdana, Arial, "Times New Roman", sans-serif;
   font-size:12px;
   color:black;
   border:1px solid #CCC;
   box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -ms-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -webkit-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -o-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -moz-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -khtml-box-shadow:5px 5px 0px rgba(0,0,0,.1);
  }

  ul#menu-contextual ul {
   display:none;
   background:white;
   font-family:Verdana, Arial, "Times New Roman", sans-serif;
   font-size:12px;
   color:black;
   border:1px solid #CCC;
   padding:2px 9px 2px 2px;
   box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -ms-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -webkit-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -o-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -moz-box-shadow:5px 5px 0px rgba(0,0,0,.1);
   -khtml-box-shadow:5px 5px 0px rgba(0,0,0,.1);
  }

  ul#menu-contextual li:hover {
   background:#CCC;
   word-wrap:break-word;

  }

  ul#menu-contextual li:hover > ul {
   display:block;

  }
  .separador {
   border-bottom:1px solid #ccc;
  }


 </style>
</head>
<body>

 <div id="outer-wrapper" onclick="ocultarMenu('menu-contextual');" oncontextmenu="mostrarMenu(event, this.id, 'menu-contextual');return false;">
 </div>

 <ul id="menu-contextual" oncontextmenu="return false;">
  <li>Paginas de Busqueda<span></span>
   <ul>
    <li onclick="location.href='http://google.com'">Google</li>
    <li onclick="location.href='http://yahoo.com'">Yahoo!</li>
    <li onclick="location.href='http://bing.com'">Bing</li>
   </ul>
  </li>
  <li class="separador">Redes Sociales<span></span>
   <ul>
    <li onclick="location.href='http://facebook.com'">Facebook</li>
    <li onclick="location.href='http://twitter.com'">Twitter</li>
    <li onclick="location.href='http://googleplus.com'">Google Plus</li>
   </ul>
  </li>
  <li onclick="window.history.forward()">Adelante</li>
  <li onclick="window.history.back()">Atras</li>
  <li>Favoritos<span></span>
   <ul>
    <li onclick="location.href='http://frikiblogeeo.blogspot.com'">Friki Bloggeo</li>
    <li onclick="location.href='http://blogger.com'">Blogger</li>
    <li onclick="location.href='http://gmail.com'">Gmail</li>
   </ul>
  </li>
  

 </ul>

 
</body>
</html>


Eso es todo.

Leer completo

03 junio 2015

Validaciones esenciales en Javascript paras tus formularios de HTML

  3 comentarios
12:17

Todas las letras a mayusculas

Validacion sumamente esencial, por ejemplo, para cuando quieres llevar el control de todo lo que ingresa a la base de datos, mantener la uniformidad te ayuda en cuanto a la mejor lectura.

function aMayusculas(campo) {
    var x = document.getElementById(campo).value;
    document.getElementById(campo).value = x.toUpperCase();
}

Luego para llamarla en un campo de texto

<input type="text" name="ejemplo1" id="ejemplo1" onkeyup="aMayusculas(document.getElementById('ejemplo1').name)" />

Solo Numeros

Muy util para campos de texto donde el usuario solo se le permite introducir numeros, como campos de moneda, enteros o numeros de telefonos. Es una de las validaciones mas sencillas pero mas utiles de Javascript

function esNumero(campo) {
    var x = document.getElementById(campo).value;
    if (isNaN(x)) {
        document.getElementById(campo).value = "";
    }
}

Luego para llamarla en un campo de texto

<input type="text" name="ejemplo1" id="ejemplo1" onkeyup="esNumero(document.getElementById('ejemplo1').name)" />

Solo Letras

Asi como hay campos donde solo puede introducirse numeros, existen campos en los que estos serian incoherentes, como campos de nombres, apellidos, profesion, etc. Recordemos que es mejor prevenir que lamentar, y es mejor prevenir y controlar lo que escribe el usuario antes de lamentar una base de datos llena de basura.

function soloLetras(e){
       key = e.keyCode || e.which;
       tecla = String.fromCharCode(key).toLowerCase();
       letras = " áéíóúabcdefghijklmnñopqrstuvwxyz";
       especiales = "8-37-39-46";

       tecla_especial = false
       for(var i in especiales){
            if(key == especiales[i]){
                tecla_especial = true;
                break;
            }
        }

        if(letras.indexOf(tecla)==-1 && !tecla_especial){
            return false;
        }
    }


Luego para llamarla en un campo de texto

<input type="text" name="ejemplo1" id="ejemplo1" onkeypress="return soloLetras(event)" />

Mascaras esenciales para campos de texto

Existen ademas diferentes campos los cuales tienen una formato único y que es es sin duda, irreversible, pero que a su vez, pueden presentar diferentes formas dependiendo del gusto del usuario, pero siempre, con un mismo resultado. Para evitar la falta de uniformidad del dato, es necesario usar mascaras pues garantizan que el dato introducido presente el mismo diseño y limite al usuario al mismo.

Leer completo