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);