css Audio - Active file-generic CSS - Active Generic - Active HTML - Active JS - Active SVG - Active Text - Active file-generic Video - Active header Love html icon-new-collection icon-person icon-team numbered-list123 pop-out spinner split-screen star tv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              <div class="container-fluid" ng-app="resistencias">
    <div ng-controller="controlador">
        <br>
        <div class="row">
            <div class="col-xs-12">
                <div class="alert alert-success">
                    <strong>Tip: </strong>Haz clic en una banda y selecciona el color que desees
                </div>
            </div>
        </div>
        <br>
        <div class="row">
            <div class="col-xs-12">
                <div class="resistencia  text-center">
                    <div ng-repeat="banda in bandas" context-menu-on="click" context-menu="opcionesColores"
                         class="cursor-de-manita banda {{banda.color}}"><h3>{{banda.etiqueta}}</h3></div>
                </div>
            </div>
        </div>
        <br>
        <div class="row">
            <div class="col-xs-12">
                <div class="form-group">
                    <label for="unidades">Unidad de medida:</label>
                    <select id="unidades" class="form-control"
                            ng-options="unidad as unidad.etiqueta for unidad in unidades track by unidad.id"
                            ng-model="unidadSeleccionada"></select>
                </div>
            </div>
        </div>
        <br>
        <div class="row">
            <div class="col-xs-12">
                <div class="table-responsive">
                    <table class="table table-bordered table-condensed">
                        <tbody>
                        <tr>
                            <td><strong>Resistencia</strong></td>
                            <td>{{resistencia | number:10}} {{unidadSeleccionada.etiqueta}}</td>
                        </tr>
                        <tr>
                            <td><strong>Tolerancia</strong></td>
                            <td>{{tolerancia | number:10}} {{unidadSeleccionada.etiqueta}}</td>
                        </tr>
                        <tr>
                            <td><strong>Valor mínimo</strong></td>
                            <td>{{valorMinimoResistencia | number:10}} {{unidadSeleccionada.etiqueta}}</td>
                        </tr>
                        <tr>
                            <td><strong>Valor máximo</strong></td>
                            <td>{{valorMaximoResistencia | number:10}} {{unidadSeleccionada.etiqueta}}</td>
                        </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
        <br>
        <div class="row">
            <div class="col-xs-12">
                <div class="form-group">
                    <label for="valor">Valor de la resistencia:</label>
                    <input ng-model-options="{debounce: 1000}" ng-model="valorEscrito"  placeholder="Escribe el valor de la resistencia en {{unidadSeleccionada.etiqueta}}" class="form-control" type="number"
                           id="valor"/>
                </div>
            </div>
        </div>
    </div>
</div>
            
          
!
            
              .cursor-de-manita {
    cursor: pointer;

}
span.label.blanco{
	color: #000000;
}
div.resistencia{
	width: 100%;
	height: 100px;
	display: flex;
	float: left;
	position: relative;
	vertical-align: text-bottom;
  	justify-content: center;
	background-color: #FFFDD0;
	border: 2px solid #212121;
	padding: 2px;
}
div.banda{
	border-radius: 5%;
    min-height:100%;
	display: inline-block;
	height: 100%;
	width: 20%;
  	align-self: center;
	margin-right: 3px;
}
div.invisible{
	border: none;
}
.negro{
	background-color: #000000;
}
.café{
	background-color: #795548;
}

.rojo{
	background-color: #F44336;
}
.naranja{
	background-color: #FF9800;
}

.amarillo{
	background-color: #FFEB3B;
}
.verde{
	background-color: #4CAF50;
}

.azul{
	background-color: #2196F3;
}
.violeta{
	background-color: #9C27B0;
}
.gris{
	background-color: #9E9E9E;
}
.blanco{
	background-color: #FFFFFF;
}
.dorado{
	background-color: #FFD700;
}
.plateado{
	background-color: #C0C0C0;
}
            
          
!
            
              var app = angular["module"]('resistencias', ['ui.bootstrap.contextMenu']);
app["constant"]('BANDA_DE_DIGITO', 0);
app["constant"]('BANDA_MULTIPLICADORA', 1);
app["constant"]('BANDA_DE_TOLERANCIA', 2);
app["controller"]('controlador', ['$scope', 'BANDA_DE_DIGITO', 'BANDA_MULTIPLICADORA', 'BANDA_DE_TOLERANCIA', function (esto, BANDA_DE_DIGITO, BANDA_MULTIPLICADORA, BANDA_DE_TOLERANCIA) {

    /*
     Inicialmente definimos
     la resistencia como 0
     */
    esto["resistencia"] = 0;


    /*
     Un arreglo para todas las bandas de
     las resistencias, Cada banda cuenta
     con las siguientes propiedades:
     etiqueta: el texto que se muestra
     color: el color. Debe ser un color que esté dentro
     del arreglo 'colores' definido anteriormente
     tipo: ¿cómo actúa la banda? puede actuar como digito,
     como multiplicador o como tolerancia.
     Nota importante: el orden no importa, pero es recomendable
     poner en el arreglo primero las bandas que
     actúan como dígitos, luego únicamente una
     banda que actúe como multiplicador y
     finalmente úncamente una banda que actúe
     como tolerancia
     */
    esto["bandas"] = [
        {
            "etiqueta": "B1",
            "color": "verde",
            "tipo": BANDA_DE_DIGITO
        },
        {
            "etiqueta": "B2",
            "color": "azul",
            "tipo": BANDA_DE_DIGITO
        },
        {
            "etiqueta": "B3",
            "color": "rojo",
            "tipo": BANDA_MULTIPLICADORA
        },
        {
            "etiqueta": "T",
            "color": "dorado",
            "tipo": BANDA_DE_TOLERANCIA
        }
    ];

    /*
     Un arreglo para las opciones de
     medida de la resistencia
     */
    esto["unidades"] = [
        /*
         Múltiplos
         */

        {
            "id": 5,
            "etiqueta": 'KiloOhm',
            "multiplicador": 10e-4
        },
        {
            "id": 6,
            "etiqueta": 'MegaOhm',
            "multiplicador": 10e-7
        },
        {
            "id": 7,
            "etiqueta": 'GigaOhm',
            "multiplicador": 10e-10
        },
        /*
         Unidad absoluta
         */
        {
            "id": 1,
            "etiqueta": 'Ohm',
            "multiplicador": 1
        },
        /*
         Submúltiplos
         */
        {
            "id": 2,
            "etiqueta": 'MiliOhm',
            "multiplicador": 10e+2
        },
        {
            "id": 3,
            "etiqueta": 'MicroOhm',
            "multiplicador": 10e+5
        },
        {
            "id": 4,
            "etiqueta": 'NanoOhm',
            "multiplicador": 10e+8
        }
    ];

    /*
     Por defecto ponemos la medida
     que esté en el índice 4; es decir,
     el ohm

     */
    esto["unidadSeleccionada"] = esto["unidades"][3];


    /*
     Simple función ayudante para refrescar el color
     de la resistencia cuando seleccionan un color del
     menú contextual
     */
    esto["cambiarColorDeBanda"] = function ($itemScope, a, b, texto) {
        var nuevoColor = texto[0]["text"].toLowerCase();
        if ($itemScope["banda"]["tipo"] === BANDA_DE_TOLERANCIA && (nuevoColor === "blanco" || nuevoColor === "negro")) {
            alert("La banda de tolerancia no puede ser de color " + nuevoColor);
            return;
        }
        $itemScope["banda"]["color"] = nuevoColor;

        // Ya actualizamos el color, pero también
        // debemos refrescar la resistencia completa
        esto["refrescarResistencia"]();
    };

    /*
     Un arreglo para los colores. Cada
     color tiene las siguientes propiedades:
     nombre: el nombre del color en minúsculas
     valorBanda: lo que vale cuando actúa como banda
     valorMultiplicador: lo que vale cuando actúa como multiplicador
     valorTolerancia: lo que vale cuando actúa como tolerancia

     Si una propiedad está definida como nula significa
     que no es posible que la resistencia tenga ese color.
     Por ejemplo, no hay tolerancia para el color negro, por
     lo que en valorTolerancia ponemos null

     Si en el futuro se añadieran más colores, simplemente se
     agregaría otro color a la lista.

     Importante: el orden de los colores no importa
     */
    esto["colores"] = [
        {
            "nombre": "negro",
            "valorBanda": 0,
            "valorMultiplicador": 1,
            "valorTolerancia": null
        },
        {
            "nombre": "café",
            "valorBanda": 1,
            "valorMultiplicador": 1e+1,
            "valorTolerancia": 0.01
        },
        {
            "nombre": "rojo",
            "valorBanda": 2,
            "valorMultiplicador": 1e+2,
            "valorTolerancia": 0.02
        },
        {
            "nombre": "naranja",
            "valorBanda": 3,
            "valorMultiplicador": 1e+3,
            "valorTolerancia": 0.03
        },
        {
            "nombre": "amarillo",
            "valorBanda": 4,
            "valorMultiplicador": 1e+4,
            "valorTolerancia": 0.04
        },
        {
            "nombre": "verde",
            "valorBanda": 5,
            "valorMultiplicador": 1e+5,
            "valorTolerancia": 0.005
        },
        {
            "nombre": "azul",
            "valorBanda": 6,
            "valorMultiplicador": 1e+6,
            "valorTolerancia": 0.0025
        },
        {
            "nombre": "violeta",
            "valorBanda": 7,
            "valorMultiplicador": 1e+7,
            "valorTolerancia": 0.001
        },
        {
            "nombre": "gris",
            "valorBanda": 8,
            "valorMultiplicador": 1e+8,
            "valorTolerancia": 0.0005
        },
        {
            "nombre": "blanco",
            "valorBanda": 9,
            "valorMultiplicador": 1e+9,
            "valorTolerancia": null
        },
        {
            "nombre": "dorado",
            "valorBanda": null,
            "valorMultiplicador": 1e-1,
            "valorTolerancia": 0.05
        },
        {
            "nombre": "plateado",
            "valorBanda": null,
            "valorMultiplicador": 1e-2,
            "valorTolerancia": 0.1
        }
    ];
    /*
     El menú contextual que aparece
     al hacer clic en cada banda
     */
    esto["opcionesColores"] = [
        ['<span class="label negro">NEGRO</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label café">CAFÉ</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label rojo">ROJO</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label naranja">NARANJA</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label amarillo">AMARILLO</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label verde">VERDE</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label azul">AZUL</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label violeta">VIOLETA</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label gris">GRIS</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label blanco">BLANCO</span>', esto["cambiarColorDeBanda"]],
        ['<span class="label dorado">DORADO</span>', esto["cambiarColorDeBanda"], esto["comprobarColorValido"]],
        ['<span class="label plateado">PLATEADO</span>', esto["cambiarColorDeBanda"], esto["comprobarColorValido"]]

    ];

    /*
     Esta función es llamada al inicio, se
     encarga de definir todas las variables
     que usaremos durante la ejecución de la app
     */


    /*
     Vigilamos cuando la unidad de medida
     cambie, cuando eso pase refrescamos el
     valor de la resistencia
     */
    esto["$watch"]('unidadSeleccionada', function () {
        esto["refrescarResistencia"]();
    });
    /*
     Esta función se encarga de devolver
     el objeto que coincida con el color
     de búsqueda. Devuelve un objeto de
     los que están definidos en el arreglo
     "colores".
     */
    esto["valorAPartirDeColor"] = function (colorBuscado) {
        // Leemos todo el arreglo...
        for (var x = esto["colores"]["length"] - 1; x >= 0; x--)
            // Buscamos si el color de búsqueda coincide con el
            // objeto en donde estamos
            if (esto["colores"][x]["nombre"] === colorBuscado) return esto["colores"][x];
        // ¿No lo encontramos? bueno, regresamos null en caso de que
        // el color no exista
        return null;
    };


    /*
     Esta función se encarga de calcular el valor de la resistencia.
     */
    esto["refrescarResistencia"] = function () {
        var valorString = "",     // Los primeros dígitos antes del multiplicador pueden ser tratados como cadena
            multiplicador = null, // Aquí alojaremos el valor del multiplicador
            tolerancia = null;    // Aquí alojaremos el valor de la tolerancia

        // Usamos el método que angular ya ha programado
        angular["forEach"](esto["bandas"], function (banda) {
            // En cada iteración comprobamos el tipo

            // Si la banda actúa como dígito, entonces concatenamos el valor porque, como lo mencionamos
            // anteriormente: los dígitos antes del multiplicador deben unirse y ser tratados como cadena
            if (banda["tipo"] === BANDA_DE_DIGITO) valorString += esto["valorAPartirDeColor"](banda["color"])["valorBanda"];

            // En caso de que no sea dígito, pero sea multiplicador, guardamos el multiplicador
            else if (banda["tipo"] === BANDA_MULTIPLICADORA) multiplicador = esto["valorAPartirDeColor"](banda["color"])["valorMultiplicador"];

            // Si no es multiplicador ni dígito, entonces es la tolerancia
            else if (banda["tipo"] === BANDA_DE_TOLERANCIA) tolerancia = esto["valorAPartirDeColor"](banda["color"])["valorTolerancia"];
        });

        // Hora de las matemáticas. Convertimos los dígitos (que eran cadena)
        // a entero, luego ese valor lo multiplicamos por el multiplicador y
        // listo, ese es el valor de la resistencia
        esto["resistencia"] = parseInt(valorString, 0) * multiplicador * esto["unidadSeleccionada"]["multiplicador"];

        // Para calcular la tolerancia multiplicamos el valor
        // de la resistencia por la tolerancia.
        // Nota importante: no confundir esto.tolerancia con tolerancia
        // tolerancia es una variable local, mientras que esto.tolerancia
        // pertenece a todo el ámbito del controlador, así que no son las
        // mismas variables. Una es la tolerancia total, la otra es la
        // tolerancia de la banda
        esto["tolerancia"] = esto["resistencia"] * tolerancia;

        // Ahora simplemente calculamos desde dónde hasta dónde
        // puede ir la resistencia. Simples sumas y restas,
        esto["valorMinimoResistencia"] = esto["resistencia"] - esto["tolerancia"];
        esto["valorMaximoResistencia"] = esto["resistencia"] + esto["tolerancia"];
    };


    /*
     Debido a que los últimos colores
     (plateado y dorado) solamente son
     válidos en bandas de tipo multiplicador
     o de tolerancia, debemos deshabilitar
     dichos colores en bandas que sirven como
     dígitos. Simplemente comprobamos el tipo
     de banda que es.
     Si es de tolerancia o multiplicador entonces
     regresamos "verdadero" en caso de que no,
     regresamos "falso".
     Dependiendo de lo que regrese esta, el color
     puede ser deshabilitado o no.
     */
    esto["comprobarColorValido"] = function ($itemScope) {
        var tipoBanda = $itemScope["banda"]["tipo"];
        return tipoBanda === "tolerancia" || tipoBanda === "multiplicador";
    };
	esto["$watch"]('valorEscrito', function(valor){
		esto["calcularResistenciaAPartirDeValor"](valor);
	});
	esto["calcularResistenciaAPartirDeValor"] = function(valor){
		if(valor > 0){
			switch(esto["bandas"]["length"]){
				case 4:
					if(valor["toString"]()["length"] > 3){
						var primerDigito = parseInt(valor["substring"](0,1));
						var segundoDigito = parseInt(valor["substring"](1,2))
						var multiplicador = valor["toString"]()["length"] - 2;
					}
					break;
			}
		}
	}

    /*
     Luego de definir todo allá arriba, y dado
     que las resistencias ya tienen un valor por
     defecto llamamos al método refrescarResistencia
     */
    esto["refrescarResistencia"]();
}]);

/*
	El siguiente código es para que funcione el click derecho,
	yo no lo escribí.
	El respositorio en GitHub se puede ver en:
	https://github.com/Templarian/ui.bootstrap.contextMenu
*/
angular.module('ui.bootstrap.contextMenu', [])

.service('CustomService', function () {
    "use strict";

    return {
        initialize: function (item) {
            console.log("got here", item);
        }
    }

})
.directive('contextMenu', ["$parse", "$q", "CustomService", "$sce", function ($parse, $q, custom, $sce) {

    var contextMenus = [];
    var $currentContextMenu = null;
    var defaultItemText = "New Item";

    var removeContextMenus = function (level) {
        /// <summary>Remove context menu.</summary>
        while (contextMenus.length && (!level || contextMenus.length > level)) {
            contextMenus.pop().remove();
        }
        if (contextMenus.length == 0 && $currentContextMenu) {
            $currentContextMenu.remove();
        }
    };


    var processTextItem = function ($scope, item, text, event, model, $promises, nestedMenu, $) {
        "use strict";

        var $a = $('<a>');
        $a.css("padding-right", "8px");
        $a.attr({ tabindex: '-1', href: '#' });

        if (typeof item[0] === 'string') {
            text = item[0];
        }
        else if (typeof item[0] === "function") {
            text = item[0].call($scope, $scope, event, model);
        } else if (typeof item.text !== "undefined") {
            text = item.text;
        }

        var $promise = $q.when(text);
        $promises.push($promise);
        $promise.then(function (text) {
            if (nestedMenu) {
                $a.css("cursor", "default");
                $a.append($('<strong style="font-family:monospace;font-weight:bold;float:right;">&gt;</strong>'));
            }
            $a.append(text);
        });

        return $a;

    };

    var processItem = function ($scope, event, model, item, $ul, $li, $promises, $q, $, level) {
        /// <summary>Process individual item</summary>
        "use strict";
        // nestedMenu is either an Array or a Promise that will return that array.
        var nestedMenu = angular.isArray(item[1]) || (item[1] && angular.isFunction(item[1].then))
          ? item[1] : angular.isArray(item[2]) || (item[2] && angular.isFunction(item[2].then))
          ? item[2] : angular.isArray(item[3]) || (item[3] && angular.isFunction(item[3].then))
          ? item[3] : null;

        // if html property is not defined, fallback to text, otherwise use default text
        // if first item in the item array is a function then invoke .call()
        // if first item is a string, then text should be the string.

        var text = defaultItemText;
        if (typeof item[0] === 'function' || typeof item[0] === 'string' || typeof item.text !== "undefined") {
            text = processTextItem($scope, item, text, event, model, $promises, nestedMenu, $);
        }
        else if (typeof item.html === 'function') {
            // leave styling open to dev
            text = item.html($scope);
        }
        else if (typeof item.html !== "undefined") {
            // leave styling open to dev
            text = item.html;
        }

        $li.append(text);




        // if item is object, and has enabled prop invoke the prop
        // els if fallback to item[2]

        var isEnabled = function () {
            if (typeof item.enabled !== "undefined") {
                return item.enabled.call($scope, $scope, event, model, text);
            } else if (typeof item[2] === "function") {
                return item[2].call($scope, $scope, event, model, text);
            } else {
                return true;
            }
        };

        registerEnabledEvents($scope, isEnabled(), item, $ul, $li, nestedMenu, model, text, event, $, level);
    };

    var handlePromises = function ($ul, level, event, $promises) {
        /// <summary>
        /// calculate if drop down menu would go out of screen at left or bottom
        /// calculation need to be done after element has been added (and all texts are set; thus thepromises)
        /// to the DOM the get the actual height
        /// </summary>
        "use strict";
        $q.all($promises).then(function () {
            var topCoordinate = event.pageY;
            var menuHeight = angular.element($ul[0]).prop('offsetHeight');
            var winHeight = event.view.innerHeight;
            if (topCoordinate > menuHeight && winHeight - topCoordinate < menuHeight) {
                topCoordinate = event.pageY - menuHeight;
            } else if(winHeight <= menuHeight) {
                // If it really can't fit, reset the height of the menu to one that will fit
                angular.element($ul[0]).css({"height": winHeight - 5, "overflow-y": "scroll"});
                // ...then set the topCoordinate height to 0 so the menu starts from the top
                topCoordinate = 0;
            } else if(winHeight - topCoordinate < menuHeight) {
                var reduceThreshold = 5;
                if(topCoordinate < reduceThreshold) {
                    reduceThreshold = topCoordinate;
                }
                topCoordinate = winHeight - menuHeight - reduceThreshold;
            }

            var leftCoordinate = event.pageX;
            var menuWidth = angular.element($ul[0]).prop('offsetWidth');
            var winWidth = event.view.innerWidth;
            var rightPadding = 5;
            if (leftCoordinate > menuWidth && winWidth - leftCoordinate - rightPadding < menuWidth) {
                leftCoordinate = winWidth - menuWidth - rightPadding;
            } else if(winWidth - leftCoordinate < menuWidth) {
                var reduceThreshold = 5;
                if(leftCoordinate < reduceThreshold + rightPadding) {
                    reduceThreshold = leftCoordinate + rightPadding;
                }
                leftCoordinate = winWidth - menuWidth - reduceThreshold - rightPadding;
            }

            $ul.css({
                display: 'block',
                position: 'absolute',
                left: leftCoordinate + 'px',
                top: topCoordinate + 'px'
            });
        });

    };

    var registerEnabledEvents = function ($scope, enabled, item, $ul, $li, nestedMenu, model, text, event, $, level) {
        /// <summary>If item is enabled, register various mouse events.</summary>
        if (enabled) {
            var openNestedMenu = function ($event) {
                removeContextMenus(level + 1);
                /*
                 * The object here needs to be constructed and filled with data
                 * on an "as needed" basis. Copying the data from event directly
                 * or cloning the event results in unpredictable behavior.
                 */
                var ev = {
                    pageX: event.pageX + $ul[0].offsetWidth - 1,
                    pageY: $ul[0].offsetTop + $li[0].offsetTop - 3,
                    view: event.view || window
                };

                /*
                 * At this point, nestedMenu can only either be an Array or a promise.
                 * Regardless, passing them to when makes the implementation singular.
                 */
                $q.when(nestedMenu).then(function(promisedNestedMenu) {
                    renderContextMenu($scope, ev, promisedNestedMenu, model, level + 1);
                });
            };

            $li.on('click', function ($event) {
                $event.preventDefault();
                $scope.$apply(function () {
                    if (nestedMenu) {
                        openNestedMenu($event);
                    } else {
                        $(event.currentTarget).removeClass('context');
                        removeContextMenus();

                        if (angular.isFunction(item[1])) {
                            item[1].call($scope, $scope, event, model, text)
                        } else {
                            item.click.call($scope, $scope, event, model, text);
                        }
                    }
                });
            });

            $li.on('mouseover', function ($event) {
                $scope.$apply(function () {
                    if (nestedMenu) {
                        openNestedMenu($event);
                    }
                });
            });
        } else {
            $li.on('click', function ($event) {
                $event.preventDefault();
            });
            $li.addClass('disabled');
        }

    };


    var renderContextMenu = function ($scope, event, options, model, level, customClass) {
        /// <summary>Render context menu recursively.</summary>
        if (!level) { level = 0; }
        if (!$) { var $ = angular.element; }
        $(event.currentTarget).addClass('context');
        var $contextMenu = $('<div>');
        if ($currentContextMenu) {
            $contextMenu = $currentContextMenu;
        } else {
            $currentContextMenu = $contextMenu;
            $contextMenu.addClass('angular-bootstrap-contextmenu dropdown clearfix');
        }
        if (customClass) {
            $contextMenu.addClass(customClass);
        }
        var $ul = $('<ul>');
        $ul.addClass('dropdown-menu');
        $ul.attr({ 'role': 'menu' });
        $ul.css({
            display: 'block',
            position: 'absolute',
            left: event.pageX + 'px',
            top: event.pageY + 'px',
            "z-index": 10000
        });

        var $promises = [];

        angular.forEach(options, function (item) {

            var $li = $('<li>');
            if (item === null) {
                $li.addClass('divider');
            } else if (typeof item[0] === "object") {
                custom.initialize($li, item);
            } else {
                processItem($scope, event, model, item, $ul, $li, $promises, $q, $, level);
            }
            $ul.append($li);
        });
        $contextMenu.append($ul);
        var height = Math.max(
            document.body.scrollHeight, document.documentElement.scrollHeight,
            document.body.offsetHeight, document.documentElement.offsetHeight,
            document.body.clientHeight, document.documentElement.clientHeight
        );
        $contextMenu.css({
            width: '100%',
            height: height + 'px',
            position: 'absolute',
            top: 0,
            left: 0,
            zIndex: 9999,
            "max-height" : window.innerHeight - 3,
        });
        $(document).find('body').append($contextMenu);

        handlePromises($ul, level, event, $promises);

        $contextMenu.on("mousedown", function (e) {
            if ($(e.target).hasClass('dropdown')) {
                $(event.currentTarget).removeClass('context');
                removeContextMenus();
            }
        }).on('contextmenu', function (event) {
            $(event.currentTarget).removeClass('context');
            event.preventDefault();
            removeContextMenus(level);
        });

        $scope.$on("$destroy", function () {
            removeContextMenus();
        });

        contextMenus.push($ul);
    };

    function isTouchDevice() {
      return 'ontouchstart' in window        // works on most browsers
          || navigator.maxTouchPoints;       // works on IE10/11 and Surface
    };

    return function ($scope, element, attrs) {
        var openMenuEvent = "contextmenu";
        if(attrs.contextMenuOn && typeof(attrs.contextMenuOn) === "string"){
            openMenuEvent = attrs.contextMenuOn;
        }
        element.on(openMenuEvent, function (event) {
            event.stopPropagation();
            event.preventDefault();
            
            // Don't show context menu if on touch device and element is draggable
            if(isTouchDevice() && element.attr('draggable') === 'true') {
              return false;
            }

            $scope.$apply(function () {
                var options = $scope.$eval(attrs.contextMenu);
                var customClass = attrs.contextMenuClass;
                var model = $scope.$eval(attrs.model);
                if (options instanceof Array) {
                    if (options.length === 0) { return; }
                    renderContextMenu($scope, event, options, model, undefined, customClass);
                } else {
                    throw '"' + attrs.contextMenu + '" not an array';
                }
            });
        });
    };
}]);

            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console