Ceesiebird
Ceesiebird

Reputation: 706

How to fix button not showing up in TamperMonkey script

I am trying to adapt an existing TamperMonkey Script to create a dropdown based login button on an existing page.

I tested the working script which I found online on it's original URL (facebook.com) and the button shows up just fine.

When I adapt the @include to my URL and adjust the locator ID's in the script to match the ones in my own page, the script no longer displays the dropdown button.

And I need a little help figuring out why.

The original code looks like this and works on facebook.com:

// ==UserScript==
// @name        facebook login
// @namespace   http://123.123
// @include     https://www.facebook.com/*
// @version     1
// @require     http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.7.2.js
// @require     http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js
// @resource    bt http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css
// @resource    bt-theme http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css
// @grant       GM_addStyle
// @grant       GM_getResourceText
// ==/UserScript==
(function() {
    if ($('#login_form').length <= 0) {
        console.log('No login_form');
        return;
    }

    GM_addStyle(GM_getResourceText("bt"));
    GM_addStyle(GM_getResourceText ("bt-theme"));
    GM_addStyle("#menu1 a {text-align: left}");
    var $loginbutton = $('#loginbutton');
    var menu = '<span class="dropdown btn btn-primary" style="padding: 2px; margin: 0 0 0 5px;">' +
               '<a id="drop4" href="#" data-toggle="dropdown" role="button" style="color: #FFF">帳號 ' +
               '<b class="caret"></b>' +
               '</a>' +
               '<ul id="menu1" class="dropdown-menu" aria-labelledby="drop4" role="menu">' +
               '<li>' +
               '<a href="#" role="menuitem">kaoyenchi</a>' +
               '</li>' +
               '<li>' +
               '<a href="#" role="menuitem">tcyc</a>' +
               '</li>' +
               '<li>' +
               '<a href="#" role="menuitem">fcwu</a>' +
               '</li>' +
               '</ul>' +
               '</span>'
    $loginbutton.parent().append(menu);
    var accounts = {};
    accounts['fcwu'] = ['', ''];
    accounts['kaoyenchi'] = ['', ''];
    accounts['tcyc'] = ['', ''];
    accounts['timy'] = ['', ''];
    $('#menu1 a').click(function() {
        name = $(this).text()
        $('#email').attr('value', accounts[name][0]);
        $('#pass').attr('value', accounts[name][1]);
        $('#login_form').submit();
    });

})(); 

And the code looks like this after my changes and no longer works:

// ==UserScript==
// @name        Login-o-Tron WIP
// @namespace   http://123.123
// @include     http://myurl.com/*
// @version     1
// @require     http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.7.2.js
// @require     http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js
// @resource    bt http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css
// @resource    bt-theme http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css
// @grant       GM_addStyle
// @grant       GM_getResourceText
// ==/UserScript==
(function() {

    GM_addStyle(GM_getResourceText("bt"));
    GM_addStyle(GM_getResourceText ("bt-theme"));
    GM_addStyle("#menu1 a {text-align: left}");
    var $loginbutton = $('#loginbutton');
    var menu = '<span class="dropdown btn btn-primary" style="padding: 2px; margin: 0 0 0 5px;">' +
               '<a id="drop4" href="#" data-toggle="dropdown" role="button" style="color: #FFF">Login-o-Tron ' +
               '<b class="caret"></b>' +
               '</a>' +
               '<ul id="menu1" class="dropdown-menu" aria-labelledby="drop4" role="menu">' +
               '<li>' +
               '<a href="#" role="menuitem">kaoyenchi</a>' +
               '</li>' +
               '<li>' +
               '<a href="#" role="menuitem">tcyc</a>' +
               '</li>' +
               '<li>' +
               '<a href="#" role="menuitem">fcwu</a>' +
               '</li>' +
               '</ul>' +
               '</span>'
    $loginbutton.parent().append(menu);
    var accounts = {};
    accounts['fcwu'] = ['', ''];
    accounts['kaoyenchi'] = ['', ''];
    accounts['tcyc'] = ['', ''];
    accounts['timy'] = ['', ''];
    $('#menu1 a').click(function() {
        name = $(this).text()
        $('#username').attr('value', accounts[name][0]);
        $('#password').attr('value', accounts[name][1]);
        $('#loginButton').submit();
    });

})(); 

I made sure the locators are correct, and I tried keeping and losing the initial if statement, but it doesn't seem to affect the outcome.

I do see the font of my page changing when the script loads, so the CSS is loaded, but the dropdown button I am expecting to show, never shows up.

Thanks in advance for your help.

Upvotes: 0

Views: 1682

Answers (1)

Brock Adams
Brock Adams

Reputation: 93473

You didn't say if there where any errors in the console, but the problem is probably that the #loginbutton node is added by javascript -- which means it would appear after your script ran.

Also, menu1 and drop4 are pretty generic. There is a chance that they may already be used, causing id conflict. Use something less common and more descriptive (except that drop4 does not seem to be needed at all).

One way around the delay problem is to use something like waitForKeyElements as shown below.

Important:

  1. If you put passwords in a text file/record like that, it's only a matter of time before those accounts get hacked/pwned.
  2. The smart thing to do is to use a password manager like LastPass, KeePass, etc.
  3. Failing that, at least use an encryption framework to make it noticeably harder for bad guys to get the account credentials.


Revised script:

// ==UserScript==
// @name        Login-o-Tron WIP
// @include     http://myurl.com/*
// @require     http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.7.2.js
// @require     http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js
// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
// @resource    bt http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css
// @resource    bt-theme http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css
// @grant       GM_addStyle
// @grant       GM_getResourceText
// ==/UserScript==
/* global $, waitForKeyElements */
/* eslint-disable no-multi-spaces, dot-notation */

GM_addStyle (GM_getResourceText("bt") );
GM_addStyle (GM_getResourceText ("bt-theme") );
GM_addStyle ("#TM_accmenu a {text-align: left;}");

waitForKeyElements ("#loginbutton", addAccountsDropdown);

const accounts          = {};
accounts['fcwu']        = ['One',   'should'];
accounts['kaoyenchi']   = ['have',  'a'];
accounts['tcyc']        = ['bad',   'feeling'];
accounts['timy']        = ['about', 'this.'];

function addAccountsDropdown (jNode) {
    var jMenu = $( `
        <span class="dropdown btn btn-primary" style="padding: 2px; margin: 0 0 0 5px;">
            <a href="#" data-toggle="dropdown" role="button" style="color: #FFF">Login-o-Tron
                <b class="caret"></b>
            </a>
            <ul id="TM_accmenu" class="dropdown-menu" aria-labelledby="drop4" role="menu"></ul>
        </span>
    ` );
    var zList = jMenu.find ("#TM_accmenu");
    for (let acntName in accounts) {
        zList.append (`<li><a href="#" role="menuitem">${acntName}</a></li>`);
    }

    jNode.parent ().append (jMenu);
    $('#TM_accmenu a').click (function () {
        var acntName = $(this).text ()
        $('#username').attr ('value', accounts[acntName][0]);
        $('#password').attr ('value', accounts[acntName][1]);
        $('#loginButton').submit ();
    } );
}

Upvotes: 1

Related Questions