El código que dejo a continuación, lo que hace es traer desde una base de datos, archivos anexados por los empleados de la empresa, para luego poder ser facturados (es para hacer órdenes de trabajo, básciamente). También se pueden agregar nuevos e items con información personalizada (detalle y valor en $).
Así es cómo se ve el Front End:
El problema que estoy teniendo es el siguiente...
Utilizo la función contextmenu() para poder hacer click sobre cada archivo y que se abra un cuadro flotante (como cuando se hace click derecho sobre un archivo en Windows).
Cuando se hace click derecho sobre un archivo o item que ya haya sido agregado anteriormente, se abre el cuadro perfectamente, pero cuando se hace click derecho sobre un item que se haya agregado en el momento, el cuadro flotante no aparece (con los archivos funciona bien, el problema es sólo con los items).
Llevo una semana y sigo sin poder resolver el problema.
Quizá alguien lo ve y se da cuenta en qué estoy fallando.
Les dejo acá todo el código del archivo.
Código Javascript :
<?php @session_start(); if(!isset($_SESSION["session"])){ header("location: ../login.php"); } include("serverconfig.php"); include("detectar_archivo.php"); include("pdf_visualizer.php"); $cliente_ot = $_POST["file"]; $sql = "SELECT * FROM `ordenes_trabajo` WHERE `id` LIKE '".$cliente_ot."'"; $cliente_id = mysql_fetch_assoc(mysql_query($sql))["id_cliente"]; $sql = "SELECT * FROM `usuarios` WHERE `id` LIKE ".$cliente_id; $query = mysql_query($sql); $nombre_cliente = mysql_fetch_assoc($query)["nombre"]; echo '<input type="hidden" id="cliente-id" value="'.$cliente_id.":".$nombre_cliente.'">'; // LISTAR ARCHIVOS DE CLIENTE function archivosCliente($cliente){ // BASE DE DATOS VIEJA $sql = "SELECT * FROM `archivos` WHERE `usuario_id` LIKE ".$cliente." AND `deleted` LIKE '0' ORDER BY `tipo`"; $query = mysql_query($sql); $last_folder = ""; while($data = mysql_fetch_assoc($query)){ $sql_ot = "SELECT * FROM `doc_ot_relation` WHERE `id_doc` LIKE '".$data["id"]."'"; if($last_folder != $data["tipo"]){ $last_folder = $data["tipo"]; echo '<div class="folder" folder-type="'.$data["tipo"].'" no-select><i class="fa fa-folder"></i> '.detectFile($data["tipo"])."</div>"; } $query_ot = mysql_query($sql_ot); if(!mysql_fetch_assoc($query_ot)){ if($data["nombre"] == ""){$data["nombre"] = "Archivo ".$data["id"];} echo '<div class="file" file-id="'.$data["id"].'" pdf="'.$data["path"].'" db-age="old" file-type="'.$data["tipo"].'" no-select><i class="fa fa-file"></i> '.$data["nombre"]."</div>"; } } // BASE DE DATOS NUEVA $sql2 = "SELECT * FROM `archivos_pdf` WHERE `cliente_id` LIKE ".$cliente." AND `papelera` LIKE '0' ORDER BY `tipo`"; $query2 = mysql_query($sql2); $last_folder = ""; while($data = mysql_fetch_assoc($query2)){ if($last_folder != $data["tipo"]){ $last_folder = $data["tipo"]; echo '<div class="folder" folder-type="'.$data["tipo"].'" no-select><i class="fa fa-folder"></i> '.detectFile($data["tipo"])."</div>"; } $query_ot = mysql_query($sql_ot); if(!mysql_fetch_assoc($query_ot)){ if($data["nro_expediente"] == ""){$data["nro_expediente"] = "Archivo ".$data["id"];} echo '<div class="file" file-id="'.$data["id"].'" pdf="'.$data["pdf"].'" db-age="new" file-type="'.$data["tipo"].'" no-select><i class="fa fa-file"></i> '.$data["nro_expediente"]."</div>"; } } } // LISTAR ARCHIVOS OT ANEXADOS function archivosOT($ot){ // BASE DE DATOS VIEJA $sql = "SELECT * FROM `doc_ot_relation` WHERE `id_ot` LIKE '".$ot."'"; $query = mysql_query($sql); while($data = mysql_fetch_assoc($query)){ if($data["db_age"] == "old"){ $sql2 = "SELECT * FROM `archivos` WHERE `id` LIKE '".$data["id_doc"]."'"; $data2 = mysql_query($sql2); $filename = mysql_fetch_assoc($data2)["nombre"]; } else { $sql2 = "SELECT * FROM `archivos_pdf` WHERE `id` LIKE '".$data["id_doc"]."'"; $data2 = mysql_query($sql2); $filename = mysql_fetch_assoc($data2)["nro_expediente"]; } if($filename == ""){$filename = "Archivo ".$data["id_doc"];} echo '<div file-ot="true" style="display: block; background: transparent none repeat scroll 0% 0%;" class="file" file-id="'.$data["id_doc"].'" pdf="'.$data["pdf"].'" db-age="'.$data["db_age"].'" file-type="'.$data["folder"].'" no-select><i class="fa fa-file"></i> '.$filename.' <span author="'.str_replace(" ", "_", $data["author"]).'">('.$data["author"].')</span></div>'; } } // LISTAR ITEMS OT ANEXADOS function itemsOT($ot){ $sql = "SELECT * FROM `items_personales` WHERE `id_ot` LIKE '".$ot."'"; $query = mysql_query($sql); while($data = mysql_fetch_assoc($query)){ $info = $data["descripcion"]; $val = $data["valor"]; echo '<div item-class style="padding: 10px; font-size: 18px; transition-duration: 0.25s; cursor: pointer; box-sizing: border-box;" no-select><i class="fa fa-file" style="color: #5a50e7; line-height: 14px; padding-right: 10px;" item-data="'.str_replace(" ", "_", $info).'" item-value="'.$val.'"></i>'.$info.'</div>'; } } ?> <style type="text/css"> [no-select] { -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -o-user-select: none; user-select: none; } .toggle-tips { cursor: pointer; margin: 0px 20px 25px; padding: 10px; box-sizing: border-box; transition-duration: 0.25s; background: #ececec; } .toggle-tips:hover { background: #e2e2e2; } .fa-exclamation-circle { color: #659be0; } .archivos-cliente .portlet-body, .archivos-ot .portlet-body { height: 300px; max-height: 300px; overflow-y: auto; } .folder i { color: #F1C40F; } .file i { margin-left: 20px; color: #659be0; } .ot-tree .file i { margin-left: 0px; color: #e7505a; } .file { cursor: pointer; display: none; } .folder, .file { cursor: pointer; padding: 10px; font-size: 18px; transition-duration: 0.25s; } .folder:hover { background: #ececec; } .context-cliente { z-index: 9994; } .context-ot { z-index: 9993; } .context-item { z-index: 9992; } .context-cliente, .context-ot, .context-item { cursor: pointer; display: none; position: absolute; padding: 0px; background: #000; box-shadow: 0px 10px 35px 0px rgba(0,0,0,.65); } .context-cliente .opt, .context-ot .opt, .context-item .opt { padding: 10px; box-sizing: border-box; width: 250px; color: #fff; background: #111; } .context-cliente .opt:hover, .context-ot .opt:hover, .context-item .opt:hover { transition-duration: 0.25s; background: #88a22a; } .context-cliente .opt:active, .context-ot .opt:active, .context-item .opt:active { transition-duration: 0s; background: #fff; color: #88a22a; } [author] { font-size: 13px; font-style: italic; color: rgba(0,0,0,.45); } .btn { margin-left: 10px; } .personal-item { display: none; z-index: 10400; left: 0px; top: 0px; position: fixed; width: 100%; height: 100vh; background: rgba(0,0,0,.85); overflow-y: auto; } .personal-box { position: relative; display: block; top: calc(50vh - 200px); color: #fff; width: 50%; text-align: left; background: #333; padding: 20px; } .personal-box .btn-control { width: 100%; text-align: right; } [item-class]:hover { background: rgb(236,236,236); } </style> <h1><?php echo $nombre_cliente; ?></h1> <div class="buffer-temp" hidden="hidden"></div> <input type="hidden" class="ot-nro" value="<?php echo $cliente_ot;?>"> <div style="background: #fff; padding-top: 20px;"> <div class="toggle-tips" no-select><i class="fa fa-exclamation-circle"></i> Ver tips informativos...</div> <div class="context-cliente" no-select><div class="opt opt-read">Ver Archivo</div><div class="opt opt-add">Agregar a Orden de Trabajo</div></div> <div class="context-ot" no-select><div class="opt opt-read">Ver Archivo</div><div class="opt opt-remove">Quitar de Orden de Trabajo</div></div> <div class="context-item" no-select><div class="opt opt-item">Eliminar Item Personalizado</div></div> <div class="row" style="padding: 0px 20px 0px 20px;"> <div class="note note-success" hidden="hidden" style="cursor: pointer; margin: 0px 15px 20px 15px;"> <p><b>•</b> Para <u>ver el archivo anexado</u>, haga <b>Click Derecho</b> sobre <i class="fa fa-file"></i> y a continuación pulse la opción <b>Ver Archivo</b>.</p> <p><b>•</b> Para <u>pasar un archivo</u> a la orden de trabajo, haga <b>Doble Click</b> sobre <i class="fa fa-file"></i> o sino <b>Click Derecho</b> sobre el mismo y a continuación pulse la opción <b>Agregar a Orden de Trabajo</b>.</p> <p><b>•</b> Para <u>quitar un archivo</u> de la orden de trabajo, haga <b>Click Derecho</b> sobre <i class="fa fa-file"></i> y a continuación pulse la opción <b>Quitar de Orden de Trabajo</b>.</p> </div> <!-- ARCHIVOS DE CLIENTE --> <div class="col-md-6 archivos-cliente" height="300px"> <div class="portlet red box"> <div class="portlet-title"> <div class="caption"> Archivos de <?php echo $nombre_cliente;?> </div> </div> <div class="portlet-body"> <?php archivosCliente($cliente_id);?> </div> </div> </div> <!-- ARCHIVOS DE OT --> <div class="col-md-6 archivos-ot"> <div class="portlet blue-madison box"> <div class="portlet-title"> <div class="caption"> Contenido de Orden de Trabajo </div> </div> <div class="portlet-body ot-tree"> <?php archivosOT($cliente_ot);?> <?php itemsOT($cliente_ot);?> </div> </div> </div> <!-- ACCIONES DE OT --> <div class="col-md-12 archivos-ot" style="margin: 0px 0px 20px; text-align: right;"> <span class="btn grey" id="item-ot">Agregar Item</span> <span class="btn blue-madison" id="abrir-ot">Guardar OT</span> </div> </div> </div> <!-- AGREGAR ITEM --> <div class="personal-item"> <center><div class="personal-box"> Item Personalizado: <input class="form-control" type="text" placeholder="Descripción Item Personalizado" name="itempersonal"><br> Valor: <input class="form-control" type="text" placeholder="$" name="itemvalor"><br> <div class="btn-control"><span class="btn blue-madison" id="agregar-item">Agregar</span><span class="btn red" id="close-item">Salir</span></div> </div></center> </div> <script type="text/javascript"> $(function(){ function unselectFiles(){ $(".file, [item-class]").removeAttr("file-active"); $(".file, [item-class]").css({"background" : "none"}); } $("html").click(function(){ unselectFiles(); $(".context-cliente, .context-ot, .context-item").hide(); }); $(".toggle-tips").on("click", function(){ $(".note-success").show(); $(this).hide(); }); $(".note-success").on("click", function(){ $(".toggle-tips").show(); $(this).hide(); }); $(".folder").on("click", function(){ var type = $(this).attr("folder-type"); $(".archivos-cliente .file[file-type="+type+"]").toggle(); }); $(".file, [item-class]").on("mouseover", function(){ if($(this).attr("file-active") != 1){ $(this).css({"background" : "#ececec"}); } }); $(".file, [item-class]").on("mouseleave", function(){ if($(this).attr("file-active") != 1){ $(this).css({"background" : "none"}); } }); $(".file").contextmenu(function(e){ unselectFiles(); $(this).attr("file-active","1"); $(this).css({"background" : "#ececec"}); if(!$(this).attr("file-ot")){ $(".context-ot").hide(); $(".context-item").hide(); $(".context-cliente").css({ "display" : "block", "left" : + e.pageX + 2 + "px", "top" : + e.pageY - 50 + "px" }); } else { $(".context-item").hide(); $(".context-cliente").hide(); $(".context-ot").css({ "display" : "block", "left" : + e.pageX + 2 + "px", "top" : + e.pageY - 50 + "px" }); } }); $("[item-class]").contextmenu(function(e){ unselectFiles(); $(this).attr("file-active","1"); $(this).css({"background" : "#ececec"}); $(".context-ot").hide(); $(".context-cliente").hide(); $(".context-item").css({ "display" : "block", "left" : + e.pageX + 2 + "px", "top" : + e.pageY - 50 + "px" }); }); $(".opt-read").on("click", function(){ var file = $(".file[file-active]").attr("pdf"); $(".pdf-viewer").show(); $(".view-pdf").attr("src", url + file); unselectFiles(); }); $(".opt-add").on("click", function(){ var user = $(".username").text().trim().replace(/ /g, "_"); $(".archivos-cliente .file[file-active]").appendTo(".buffer-temp"); $(".buffer-temp .file").attr("file-ot", true); $(".buffer-temp .file").append(' <span author="' + user + '">(' + user.replace(/_/g, " ") + ")</span>"); $(".buffer-temp .file").appendTo(".ot-tree"); $(".buffer-temp").empty(); unselectFiles(); }); $(".file").on("dblclick", function(){ unselectFiles(); $(this).attr("file-active","1"); $(this).css({"background" : "#ececec"}); var user = $(".username").text().trim().replace(/ /g, "_"); $(".archivos-cliente .file[file-active]").appendTo(".buffer-temp"); $(".buffer-temp .file").attr("file-ot", true); $(".buffer-temp .file").append(' <span author="' + user + '">(' + user.replace(/_/g, " ") + ")</span>"); $(".buffer-temp .file").appendTo(".ot-tree"); $(".buffer-temp").empty(); unselectFiles(); }); // QUITAR ARCHIVO DE OT $(".opt-remove").on("click", function(){ $(".archivos-ot .file[file-active]").appendTo(".buffer-temp"); $(".buffer-temp .file").removeAttr("file-ot"); $(".buffer-temp [author]").remove(); var folderType = $(".buffer-temp .file").attr("file-type"); $("[folder-type="+folderType+"]").after($(".buffer-temp .file").append()); $("[file-type="+folderType+"]").show(); $(".buffer-temp").empty(); unselectFiles(); }); // QUITAR ITEM PERSONALIZADO $(".opt-item").on("click", function(){ $("[item-class][file-active]").remove(); unselectFiles(); }); // AGREGAR ITEM PERSONALIZADO $("#item-ot").on("click", function(){ $(".personal-item").fadeIn(); $("[name=itempersonal]").focus(); }); function disableItemInputs(){ $(".personal-item").fadeOut(); $("[name=itempersonal]").val(""); $("[name=itemvalor]").val(""); } $("#close-item").on("click", function(){ disableItemInputs(); }); $(document).on("keyup", function(e){ if(e.which === 27){ disableItemInputs(); } }); var metadata_items = ""; function addItem(item, value){ $(".buffer-temp").append('<div item-class style="padding: 10px; font-size: 18px; transition-duration: 0.25s; cursor: pointer; box-sizing: border-box;" no-select><i class="fa fa-file" style="color: #5a50e7; line-height: 14px; padding-right: 10px;" item-data="' + item.replace(/ /g, "_") + '" item-value="' + value + '"></i>' + item + '</div>'); $(".buffer-temp [item-class]").appendTo(".ot-tree"); $(".buffer-temp").empty(); disableItemInputs(); } $("[name=itempersonal]").on("keyup", function(e){ if(e.which === 13){ $("[name=itemvalor]").focus(); } }); $("[name=itemvalor]").on("keyup", function(e){ if(e.which === 13){ var itempersonal = $("[name=itempersonal]").val(); var itemvalor = $(this).val(); addItem(itempersonal, itemvalor); } }); $("#agregar-item").on("click", function(){ var itempersonal = $("[name=itempersonal]").val(); var itemvalor = $("[name=itemvalor]").val(); addItem(itempersonal, itemvalor); }); // GUARDAR OT var metadata = ""; $("#abrir-ot").on("click", function(){ var data = $(".ot-tree").html().split(" "); var size = data.length; metadata = $("#cliente-id").val() + "|"; for(var i = 0; i < size; i += 1){ if(data[i].indexOf("file-id") >= 0){ metadata += data[i].replace('file-id=', "").replace(/"/g, "") + ":"; } if(data[i].indexOf("pdf") >= 0){ metadata += data[i].replace('pdf=', "").replace(/"/g, "") + ":"; } if(data[i].indexOf("db-age") >= 0){ metadata += data[i].replace('db-age=', "").replace(/"/g, "") + ":"; } if(data[i].indexOf("file-type") >= 0){ metadata += data[i].replace('file-type=', "").replace(/"/g, "") + ":"; } if(data[i].indexOf("author") >= 0){ metadata += data[i].replace('author=', "").replace(/"/g, "").replace(/_/g, " ").split(">")[0] + "|"; } if(data[i].indexOf("item-data") >= 0){ metadata += "item:" + data[i].replace('item-data=', "").replace(/"/g, "").replace(/_/g, " ") + ":"; } if(data[i].indexOf("item-value") >= 0){ metadata += data[i].replace('item-value=', "").replace(/"/g, "").split(">")[0] + "|"; } } var php = "generar_ot.php"; $.ajax({ url: "functions/" + php, data: "ot=" + $(".ot-nro").val() + "&metadata=" + metadata, type: "post", success: function(content){ $("html, body").animate({scrollTop: 0}, 250); $(".content-box").html(content); } }); }); }); </script>