您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Collection of HTML/CSS enhancements for various bugs and/or shortcomings of the Shopping Lists page (/ShoppingList.aspx)
当前为
// ==UserScript== // @name OutOfMilk.com Shopping List Enhancements // @version 0.1.7 // @description Collection of HTML/CSS enhancements for various bugs and/or shortcomings of the Shopping Lists page (/ShoppingList.aspx) // @namespace https://gf.qytechs.cn/en/users/15562 // @author Jonathan Brochu (https://gf.qytechs.cn/en/users/15562) // @license GPLv3 or later (http://www.gnu.org/licenses/gpl-3.0.en.html) // @include http://outofmilk.com/ShoppingList.aspx* // @include http://www.outofmilk.com/ShoppingList.aspx* // @include https://outofmilk.com/ShoppingList.aspx* // @include https://www.outofmilk.com/ShoppingList.aspx* // @grant GM_addStyle // ==/UserScript== /*** * History: * * 0.1.7 Changes made: * - Updated script for use with the repository [gf.qytechs.cn]. * - No change made to the code. * (2015-09-14) * 0.1.6 Changes made: * - Kept being annoyed that everytime I added/changed a UPC from the * product history it wouldn't update, so now I re-implement method * saveProductHistory() (from "ProductManagement.js?v=...") with the * added tweaks (after all, I'm the one adding the column). Also, * updated the producthistory template with a new class for that * column. * NOTE: I'll have to watch out for any updates/changes to the site * as I replace the whole function, since obviously I cannot * just patch the existing code. Oh, wait... * NODO: I know they say "eval() is evil()", but what if I'd say the * words "toString()", "String.replace()" and "eval()" in that * particular order... OK, I'll leave that hanging in the air. * - Took the opportunity to fix the call that sets the initial width * of the "Product History Management" dialog, which was failing with * errors of the sort "Permission denied to access property". * (2015-06-30) * 0.1.5 Change made: * - Added outofmilk.com as a possible domain for include URLs. * (2015-04-02) * 0.1.4 Changes made: * - Changed how the initial width of the "Product History Management" * dialog is set. * - Implemented changes to add a "UPC" column to the product history * table (by changing its jQuery UI dialog template; this is possible * since the web service's "GetAllProductHistoryItems" method already * returns the stored UPC value for each history item). * - Removed keep-alive code since no longer necessary. * (2013-08-19) * 0.1.3 Changes made: * - Removed "!important" when setting the (initial) width property of * the "Product History Management" dialog (since the specified width * isn't meant to be permanent). * (2013-04-05) * 0.1.2 Changes made: * - Added javascript code to keep the session alive (without the * need to refresh the page). * (2013-04-04) * 0.1.1 Changes made: * - Added column names for dialog "Product History Management". * - Changed text alignment for (newly-named) column "Tax Exempt". * (2013-04-04) * 0.1.0 First implementation. (2013-04-02) * */ (function() { // constants var USERSCRIPT_NAME = 'OutOfMilk.com Shopping List Enhancements'; /* * The Payload */ // css definitions var css_fixes = '@namespace url(http://www.w3.org/1999/xhtml);\n' + // Changes & Overrides // background overlays for modal dialog with fixed postion '.ui-widget-overlay { position: fixed /* original: absolute */ !important ; }\n' + // "Product History Management" dialog - increase initial width // '-> now done through javascript // //'div[aria-describedby="manageproducthistoryform"] { width: 80% /* original: 600px */ ; }\n' + // "Product History Management" dialog - take full parent's width for table within dialog 'table.producthistory-table { width: 100% /* original: 550px */ !important ; }\n' + // "Product History Management" dialog - column headers 'table#producthistorytable.table-default > tr:nth-child(1) > th:nth-child(1) > strong:before { ' + 'content: "Item" /* original: (none specified) */ !important ; }\n' + 'table#producthistorytable.table-default > tr:nth-child(1) > th:nth-child(3) > strong:before { ' + 'content: "Tax Exempt" /* original: (none specified) */ !important ; }\n' + 'table#producthistorytable.table-default > tr:nth-child(1) > th:nth-child(4) > strong:before { ' + 'content: "Category" /* original: (none specified) */ !important ; }\n' + 'table#producthistorytable.table-default > tr:nth-child(1) > th:nth-child(5) > strong:before { ' + 'content: "UPC" /* original: (none specified) */ !important ; }\n' + 'table#producthistorytable.table-default > tr:nth-child(1) > th:nth-child(6):before { ' + 'content: "Actions" /* original: (none specified) */ !important ; ' + 'text-align: center /* original: left (through inheritance) */ !important ; ' + '}\n' + 'table#producthistorytable.table-default > tr:nth-child(1) > th:nth-child(5) { ' + 'text-align: center /* original: left (through inheritance) */ !important ; ' + '}\n' + // "Product History Management" dialog - values for column "Tax Exempt" centered horizontally 'td.producthistorytaxfree { text-align: center /* original: left (through inheritance) */ !important ; }\n' + // "Edit Product History" dialog - wider "Description" field '#ctl00_ctl00_ContentPlaceHolder1_EditProductHistoryDialog1_txtEditProductHistoryDescription { ' + 'width: 350px /* original: (none specified) */ !important ; }\n' + // <END> ''; // new "producthistory-template" template var templateProductHistory = function() { /**HEREDOC <script type="producthistory-template"> <# if(this.dataobjects.length > 0) { #> <tr> <th><strong></strong></th> <th><strong>Price</strong></th> <th><strong></strong></th> <th><strong></strong></th> <th><strong></strong></th> <th colspan="3"></th> </tr> <# $.each(this.dataobjects, function(i, object) { #> <tr> <td class="producthistoryid hidden"> <#= object.ID #> </td> <td> <span class="producthistorydescription"><#= trimDescription(object.Description,60,"<acronym title=\"" + object.Description + "\">...</acronym>") #></span> </td> <td class="producthistoryprice"> <span><#= FormatNumberCurrency(object.Price) #></span> </td> <td class="producthistorytaxfree"> <span><#= object.TaxFree #></span> </td> <td class="producthistorycategory"> <span><#= object.CategoryName #></span> </td> <td class="producthistoryupc"> <span><#= object.UPC #></span> </td> <td> <a href="javascript:void(0);" class="btn-default addproducthistory"><span>Add To List</span></a> </td> <td> <a href="javascript:void(0);" class="btn-default editproducthistory"><span>Edit</span></a> </td> <td class="last-column"> <a href="javascript:void(0);" class="btn-default deleteproducthistory"><span>Delete</span></a> </td> </tr> <# }); #> <# } else { #> <tr> <td colspan="5">There are no items to display</td> </tr> <# } #> </script> HEREDOC**/ }; // new implementation of saveProductHistory() var mySaveProductHistory = function($this) { if(validateProductHistoryForm()){ var ID = $(".editproducthistoryid").html(); var description = $(".editproducthistorydescription").val(); var price = $(".editproducthistoryprice").val(); var taxfree = $(".editproducthistorytaxfree input").is(":checked"); var upc = $(".editproducthistoryupc").val(); var Params = { "ID": ID, "description":description, "price": price, "upc":upc, "taxfree": taxfree }; var jQueryParams = JSON.stringify(Params); $.ajax({ type: "POST", url: "Services/GenericService.asmx/UpdateProductHistoryItem", data: jQueryParams, contentType: "application/json; charset=utf-8", dataType: "json", success: function (msg) { if(msg.d == false){ $(".producthistoryitemvalidation").html("An item already exists with this description and price!"); } else { var $element = $(".producthistoryid:contains("+ID+")").parents("tr"); $element.find(".producthistorydescription").html(description); $element.find(".producthistoryprice").html(FormatNumberCurrency(price)); /* added --> */ $element.find(".producthistoryupc").html(upc); if(taxfree) { $element.find(".producthistorytaxfree").html("yes"); } else { $element.find(".producthistorytaxfree").html("no"); } $this.dialog("close"); } }, failure: function (msg) { } }); } }; // of course, I could also do something like: /* eval('var mySaveProductHistory = ' + unsafeWindow.saveProductHistory.toString().replace(/(html\(FormatNumberCurrency\(price\)\);)/, '$1\n$$element.find(".producthistoryupc").html(upc);') ); */ // but, would blindly patching code be actually better than // replacing a whole function? Yeah, I thought so. /* * The Tools */ // heredoc parser var getHeredoc = function(container, identifier) { // **WARNING**: Inputs not filtered (e.g. types, illegal chars within regex, etc.) var re = new RegExp("/\\*\\*" + identifier + "[\\n\\r]+[\\s\\S]*?[\\n\\r]+" + identifier + "\\*\\*/", "m"); var str = container.toString(); str = re.exec(str).toString(); str = str.replace(new RegExp("/\\*\\*" + identifier + "[\\n\\r]+",'m'),'').toString(); return str.replace(new RegExp("[\\n\\r]+" +identifier + "\\*\\*/",'m'),'').toString(); }; // template substitution var replaceDialogTemplate = function(templateName, newContent) { var scripts = document.getElementsByTagName('script'); if (scripts.length > 0) { for (var i = 0; i < scripts.length; i++) { if (scripts[i].getAttribute('type') == templateName) { // replace template content scripts[i].innerHTML = newContent.toString().replace(/^[\r\n\s]*<script[^>]*>|<\/script>[\r\n\s]*$/g, ''); return; } } } }; // code injection, specialized var replaceUnsafeFunc = function(targetName, newFuncImpl){ // inspiration: https://gf.qytechs.cn/en/scripts/2599-gm-2-port-function-override-helper/code var tmpScript = document.createElement('script'); tmpScript.id = '__rUF_script-'+Math.random().toString().slice(2); tmpScript.type = 'text/javascript'; tmpScript.textContent = (function() { return [ ';('+(function () { window/*target*/ = /*newFunc*/window; var thisScript = document.getElementById('/*scriptId*/'); if (thisScript) { thisScript.parentNode.removeChild(thisScript); } // <-- oh no, you didn't!! }).toString()+')();', { k: 'target', v: '.'+(typeof(targetName) == 'string' && targetName.trim().length > 0 ? targetName : '_void') }, { k: 'newFunc', v: (typeof(newFuncImpl) == 'function' ? newFuncImpl : function(){}).toString()+';//' }, { k: 'scriptId', v: tmpScript.id } ].reduce(function(base, mapping){ return base.replace('/*'+mapping.k+'*/', mapping.v); }); })(); document.head.appendChild(tmpScript); }; // reference some outside objects window.console = window.console || (function() { if (typeof(unsafeWindow) == 'undefined') return { 'log': function() {} }; return unsafeWindow.console; })(); // self-explanatory document.addStyle = function(css) { if (typeof(GM_addStyle) != 'undefined') { GM_addStyle(css); } else { var heads = this.getElementsByTagName('head'); if (heads.length > 0) { var node = this.createElement('style'); node.type = 'text/css'; node.appendChild(this.createTextNode(css)); heads[0].appendChild(node); } } }; /* * The Action */ // css injection document.addStyle(css_fixes); // javascript patching try { // replace template "producthistory-template" replaceDialogTemplate('producthistory-template', getHeredoc(templateProductHistory, 'HEREDOC')); // replace saveProductHistory() replaceUnsafeFunc('saveProductHistory', mySaveProductHistory); // set initial width of "Product History Management" dialog // (and wait until dialogs are initialized) /* var $ = unsafeWindow.jQuery; $(document).ready(function () { $("#manageproducthistoryform").dialog("option", "width", "80%"); }); // $(document).ready() */ // 2015-06-30: Changed the way this is being done // (and, now we have replaceUnsafeFunc() anyway so...) replaceUnsafeFunc('onload', function(){ $("#manageproducthistoryform").dialog("option", "width", "80%"); }); } catch(err) { console.log(err); } /* * The End */ console.log('User script "' + USERSCRIPT_NAME + '" has completed.'); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址