NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name CPQ Model Parts // @namespace https://github.com/okadri/bmTweaks // @version 0.63 // @description CPQ Model Parts // @author Obada Kadri // @match *://*.bigmachines.com/commerce/new_equipment/products/model_configs.jsp* // @require https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js // @require https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js // @grant GM_addStyle // ==/UserScript== function cssElement(url) { var link = document.createElement("link"); link.href = url; link.rel="stylesheet"; link.type="text/css"; return link; } function getStats () { // Grab the assetString (might have different names depending on model) // var configAssetString = document.querySelector("[name='configAssetString_ERP']"); var configAssetString = document.querySelector("[name='lolwut']"); var minimumQuantityString = document.querySelector("[name='minimumQuantityString_PF']"); var assetString = (configAssetString ? configAssetString.value : "") + (minimumQuantityString ? minimumQuantityString.value : ""); var assetStringArr = assetString.split("@@") .filter(function (p) { return p.length; }) .map(function (p) { return p.split('##'); }); // Query all parts in the config model var modelAttributes = document.querySelectorAll("[id^='attribute-'][type='hidden'], .attribute-field"); // Create an array of all the common elements in assetStringArr and modelAttributes var modelParts = assetStringArr.map( function (p) { var partInAssetString = Array.from(modelAttributes).some(function (a) { return p[1] == a.name; }); return partInAssetString ? { partNumber: p[0], attributeName: p[1] } : null; }).filter(function(p) { return p; }).sort(function(p1, p2) { return p1.partNumber>p2.partNumber?1:-1; }); return { assetStringArr: assetStringArr, modelAttributes: Array.from(modelAttributes), modelParts: modelParts }; } function setActiveStat(elementId) { var btnStat = document.getElementById(elementId); var statData = document.getElementById(elementId + "-data"); // Reset All elements Array.from(document.querySelectorAll('span.stat')).forEach(function(e){ e.classList.remove("stat-active"); }); Array.from(document.querySelectorAll('.part-data')).forEach(function(e){ e.classList.remove("part-data-active"); }); // Highlight/Show the new active one btnStat.classList.add("stat-active"); statData.classList.add("part-data-active"); } function showStats () { 'use strict'; var stats = getStats(); var totals = ` <span class="stat" id="asset-string">Total Asset String entries: ${stats.assetStringArr.length}</span> <span class="stat" id="model-attributes">Total Attributes in model: ${stats.modelAttributes.length}</span> <span class="stat stat-active" id="config-model-parts">Total config model parts: ${stats.modelParts.length}</span> `; var assetStringParts = stats.assetStringArr.map(function(p) { var partClass = stats.modelParts.some(function(mp) { return mp.partNumber == p[0]; }) ? "text-success" : "text-danger"; return "<li class='" + partClass + "'>" + p[0] + " <small>(" + p[1] + ")</small></li>"; }).join(''); var modelAttributes = stats.modelAttributes.map(function(ma) { var partClass = stats.modelParts.some(function(mp) { return mp.attributeName == ma.name; }) ? "text-success" : "text-danger"; return "<li class='" + partClass + "'>" + ma.name + "</li>"; }).join(''); var configModelParts = stats.modelParts.map(function(p) { return "<li>" + p.partNumber + " <small class='text-muted'>(" + p.attributeName + ")</small></li>"; }).join(''); var deleteButtonHtml = ` <button type="button" class="show-stats" data-toggle="modal" data-target="#myModal"> Show Model Stats </button> </div> `; var modalHtml = ` <!-- Modal --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">Config Model Stats</h4> </div> <div class="modal-body"> <h3 class="header">Totals</h3> <div class="totals">${totals}</div> <div class="part-data" id="asset-string-data"> <h3 class="header">Asset String Entries</h3> <ul>${assetStringParts}</ul> </div> <div class="part-data" id="model-attributes-data"> <h3 class="header">Model Attributes</h3> <ul>${modelAttributes}</ul> </div> <div class="part-data part-data-active" id="config-model-parts-data"> <h3 class="header">Config Model Parts</h3> <ul>${configModelParts}</ul> </div> </div> </div> </div> </div> `; //--- Add nodes to page $("body").append(deleteButtonHtml); $("body").append(modalHtml); Array.from(document.querySelectorAll('span.stat')).forEach(function(e) { e.addEventListener('click', function(event) { setActiveStat(event.target.id); }); }); } showStats(); // Styling Stuff var bm_css_src = ` button.show-stats { position: fixed; bottom: 0; right: 5em; color: #fff; background-color: #08c; border-color: #08c; display: inline-block; padding: 3px 6px; margin-bottom: 0; font-size: 11px; text-align: center; white-space: nowrap; vertical-align: middle; -ms-touch-action: manipulation; cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; background-image: none; border: 1px solid transparent; border-radius: 5px 5px 0 0; } h3.header { font-size: 1.5em; margin: .5em 0 1em 0; } .totals { font-size: 12px; } .text-muted { color: #777; } span.stat { cursor: pointer; display: inline-block; padding: 3px 10px; margin: 5px; border: 1px solid #333; border-radius: 3px; width: 25%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } span.stat-active { font-weight: bold; } .part-data { display: none; } .part-data-active { display: block; } .part-data ul { max-height: 65vh; overflow-y: auto; } .text-success { color: #3c763d; } .text-danger { color: #a94442; font-weight: bold; } /* Bootstrap Modal CSS */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } .close { float: right; font-size: 21px; font-weight: bold; line-height: 1; color: #000000; text-shadow: 0 1px 0 #ffffff; opacity: 0.2; filter: alpha(opacity=20); } .close:hover, .close:focus { color: #000000; text-decoration: none; cursor: pointer; opacity: 0.5; filter: alpha(opacity=50); } button.close { padding: 0; cursor: pointer; background: transparent; border: 0; -webkit-appearance: none; } .modal-open { overflow: hidden; } .modal { display: none; overflow: hidden; position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1050; -webkit-overflow-scrolling: touch; outline: 0; } .modal.fade .modal-dialog { -webkit-transform: translate(0, -25%); -ms-transform: translate(0, -25%); -o-transform: translate(0, -25%); transform: translate(0, -25%); -webkit-transition: -webkit-transform 0.3s ease-out; -o-transition: -o-transform 0.3s ease-out; transition: transform 0.3s ease-out; } .modal.in .modal-dialog { -webkit-transform: translate(0, 0); -ms-transform: translate(0, 0); -o-transform: translate(0, 0); transform: translate(0, 0); } .modal-open .modal { overflow-x: hidden; overflow-y: auto; } .modal-dialog { position: relative; width: auto; margin: 10px; } .modal-content { position: relative; background-color: #ffffff; border: 1px solid #999999; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 6px; -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); -webkit-background-clip: padding-box; background-clip: padding-box; outline: 0; } .modal-backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1040; background-color: #000000; } .modal-backdrop.fade { opacity: 0; filter: alpha(opacity=0); } .modal-backdrop.in { opacity: 0.5; filter: alpha(opacity=50); } .modal-header { padding: 15px; border-bottom: 1px solid #e5e5e5; min-height: 16.42857143px; } .modal-header .close { margin-top: -2px; } .modal-title { margin: 0; line-height: 1.42857143; } .modal-body { position: relative; padding: 15px; } .modal-footer { padding: 15px; text-align: right; border-top: 1px solid #e5e5e5; } .modal-footer .btn + .btn { margin-left: 5px; margin-bottom: 0; } .modal-footer .btn-group .btn + .btn { margin-left: -1px; } .modal-footer .btn-block + .btn-block { margin-left: 0; } .modal-scrollbar-measure { position: absolute; top: -9999px; width: 50px; height: 50px; overflow: scroll; } .clickable { cursor:pointer; } @media (min-width: 768px) { .modal-dialog { width: 600px; margin: 30px auto; } .modal-content { -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); } .modal-sm { width: 300px; } } @media (min-width: 992px) { .modal-lg { width: 900px; } } .clearfix:before, .clearfix:after, .modal-footer:before, .modal-footer:after { content: " "; display: table; } .clearfix:after, .modal-footer:after { clear: both; } .center-block { display: block; margin-left: auto; margin-right: auto; } .pull-right { float: right !important; } .pull-left { float: left !important; } .hide { display: none !important; } .show { display: block !important; } .invisible { visibility: hidden; } .text-hide { font: 0/0 a; color: transparent; text-shadow: none; background-color: transparent; border: 0; } .hidden { display: none !important; } .affix { position: fixed; } `; GM_addStyle(bm_css_src);