I'm using CoverPop to display a popup to my customers. Everything seems so easy but somehow I'm to dumb to make the popup closeable. I have inserted a "close" link, as described in the setup. However when I click on it, nothing happens.
Only way to close the popup is by pressing the escape key on my keyboard.
I know this must be ridiculous for some of you. I'd really appreciate some help though.
Thanks.
HTML
<script>
CoverPop.start({});
</script>
<div id="CoverPop-cover" class="splash">
<div class="CoverPop-content splash-center">
<h2 class="splash-title">Willkommen bei Exsys <span class="bold">Schweiz</span></h2>
<p class="splash-intro">Kunden aus Deutschland und anderen EU-Ländern wechseln bitte zu unserer <span class="bold">deutschen</span> Seite.</p>
<img src="{$ShopURL}/templates/xt_grid/img/shop-ch.png" title="EXSYS Online-Shop Schweiz" height="60" style="margin: 0 20px 0 0;" alt="Schweizer Exsys-Shop"/>
<img src="{$ShopURL}/templates/xt_grid/img/shop-de.png" height="60" alt="Shop Deutschland"/>
<p class="close-splash"><a class="CoverPop-close" href="#">Close</a></p>
</div><!--end .splash-center -->
</div><!--end .splash -->
CSS
.CoverPop-open,
.CoverPop-open body {
overflow: hidden;
}
#CoverPop-cover {
display: none;
position: fixed;
overflow-y: scroll;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
-webkit-animation: fade-in .25s ease-in;
-moz-animation-name: fade-in .25s ease-in;
-ms-animation-name: fade-in .25s ease-in;
-o-animation-name: fade-in .25s ease-in;
animation-name: fade-in .25s ease-in;
}
.CoverPop-open #CoverPop-cover {
display: block;
}
.splash {
background-color:rgba(47, 99, 135, 0.9);
}
.splash-center {
background-color: white;
border-right: 8px solid #007ec8;
border-bottom: 8px solid #007ec8;
border-left: 8px solid #007ec8;
margin: 15px;
text-align: center;
top: 7px;
width: 15%;
}
.splash-center p{
margin: 20px 10px;
}
.splash-center h2{
font-size:16px;
width: 100%;
background:#007ec8;
padding: 10px 0;
color:#FFF;
}
JS
(function (CoverPop, undefined) {
'use strict';
// set default settings
var settings = {
// set default cover id
coverId: 'CoverPop-cover',
// duration (in days) before it pops up again
expires: 30,
// close if someone clicks an element with this class and prevent default action
closeClassNoDefault: 'CoverPop-close',
// close if someone clicks an element with this class and continue default action
closeClassDefault: 'CoverPop-close-go',
// change the cookie name
cookieName: '_ExsPop',
// on popup open function callback
onPopUpOpen: null,
// on popup close function callback
onPopUpClose: null,
// hash to append to url to force display of popup
forceHash: 'splash',
// hash to append to url to delay popup for 1 day
delayHash: 'go',
// close if the user clicks escape
closeOnEscape: true,
// set an optional delay (in milliseconds) before showing the popup
delay: 2000,
// automatically close the popup after a set amount of time (in milliseconds)
hideAfter: null
},
// grab the elements to be used
$el = {
html: document.getElementsByTagName('html')[0],
cover: document.getElementById(settings.coverId),
closeClassDefaultEls: document.querySelectorAll('.' + settings.closeClassDefault),
closeClassNoDefaultEls: document.querySelectorAll('.' + settings.closeClassNoDefault)
},
/**
* Helper methods
*/
util = {
hasClass: function(el, name) {
return new RegExp('(\\s|^)' + name + '(\\s|$)').test(el.className);
},
addClass: function(el, name) {
if (!util.hasClass(el, name)) {
el.className += (el.className ? ' ' : '') + name;
}
},
removeClass: function(el, name) {
if (util.hasClass(el, name)) {
el.className = el.className.replace(new RegExp('(\\s|^)' + name + '(\\s|$)'), ' ').replace(/^\s+|\s+$/g, '');
}
},
addListener: function(target, type, handler) {
if (target.addEventListener) {
target.addEventListener(type, handler, false);
} else if (target.attachEvent) {
target.attachEvent('on' + type, handler);
}
},
removeListener: function(target, type, handler) {
if (target.removeEventListener) {
target.removeEventListener(type, handler, false);
} else if (target.detachEvent) {
target.detachEvent('on' + type, handler);
}
},
isFunction: function(functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
},
setCookie: function(name, days) {
var date = new Date();
date.setTime(+ date + (days * 86400000));
document.cookie = name + '=true; expires=' + date.toGMTString() + '; path=/';
},
hasCookie: function(name) {
if (document.cookie.indexOf(name) !== -1) {
return true;
}
return false;
},
// check if there is a hash in the url
hashExists: function(hash) {
if (window.location.hash.indexOf(hash) !== -1) {
return true;
}
return false;
},
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
mergeObj: function(obj1, obj2) {
for (var attr in obj2) {
obj1[attr] = obj2[attr];
}
}
},
/**
* Private Methods
*/
// close popup when user hits escape button
onDocUp = function(e) {
if (settings.closeOnEscape) {
if (e.keyCode === 27) {
CoverPop.close();
}
}
},
openCallback = function() {
// if not the default setting
if (settings.onPopUpOpen !== null) {
// make sure the callback is a function
if (util.isFunction(settings.onPopUpOpen)) {
settings.onPopUpOpen.call();
} else {
throw new TypeError('CoverPop open callback must be a function.');
}
}
},
closeCallback = function() {
// if not the default setting
if (settings.onPopUpClose !== null) {
// make sure the callback is a function
if (util.isFunction(settings.onPopUpClose)) {
settings.onPopUpClose.call();
} else {
throw new TypeError('CoverPop close callback must be a function.');
}
}
};
/**
* Public methods
*/
CoverPop.open = function() {
var i, len;
if (util.hashExists(settings.delayHash)) {
util.setCookie(settings.cookieName, 1); // expire after 1 day
return;
}
util.addClass($el.html, 'CoverPop-open');
// bind close events and prevent default event
if ($el.closeClassNoDefaultEls.length > 0) {
for (i=0, len = $el.closeClassNoDefaultEls.length; i < len; i++) {
util.addListener($el.closeClassNoDefaultEls[i], 'click', function(e) {
if (e.target === this) {
util.preventDefault(e);
CoverPop.close();
}
});
}
}
// bind close events and continue with default event
if ($el.closeClassDefaultEls.length > 0) {
for (i=0, len = $el.closeClassDefaultEls.length; i < len; i++) {
util.addListener($el.closeClassDefaultEls[i], 'click', function(e) {
if (e.target === this) {
CoverPop.close();
}
});
}
}
// bind escape detection to document
util.addListener(document, 'keyup', onDocUp);
openCallback();
};
CoverPop.close = function(e) {
util.removeClass($el.html, 'CoverPop-open');
util.setCookie(settings.cookieName, settings.expires);
// unbind escape detection to document
util.removeListener(document, 'keyup', onDocUp);
closeCallback();
};
CoverPop.init = function(options) {
if (navigator.cookieEnabled) {
util.mergeObj(settings, options);
// check if there is a cookie or hash before proceeding
if (!util.hasCookie(settings.cookieName) || util.hashExists(settings.forceHash)) {
if (settings.delay === 0) {
CoverPop.open();
} else {
// delay showing the popup
setTimeout(CoverPop.open, settings.delay);
}
if (settings.hideAfter) {
// hide popup after the set amount of time
setTimeout(CoverPop.close, settings.hideAfter + settings.delay);
}
}
}
};
// alias
CoverPop.start = function(options) {
CoverPop.init(options);
};
}(window.CoverPop = window.CoverPop || {}));
Additional information
I quickly checked my site and these are the sections I found where the click event is present. Honestly I have no idea how they do interfere with the popup.
// tabs
$('ul.tabs').each(function(){
var $active, $content, $links = $(this).find('a');
$active = $links.first().addClass('active');
$content = $($active.attr('rel'));
$links.not(':first').each(function () {
$($(this).attr('rel')).hide();
});
$(this).on('click', 'a', function(e){
$active.removeClass('active');
$content.hide();
$active = $(this);
$content = $($(this).attr('rel'));
$active.addClass('active');
$content.show();
e.preventDefault();
});
});
// track box clicks and route them to parent radio button
$('div.box-hover').click( function(e)
{
$(this).find("input[type=radio]").click();
});
$('input[type=radio]').click(function(e){
if (this.checked != true && $(this).hasClass('autosubmit')){
this.checked = true;
this.form.submit();
}
e.stopPropagation();
});
// track box clicks to show/hide some desc (shipping/payment)
$('div.box-hover').click( function(e)
{
// ok. wir wollen clicks auf shipping abfangen
// und - laut tmpl - kann nur EIN passendes kind da sein
// also geht das mit dem length check!
if( $(this).children('p.shipping-name').length > 0)
{
$('div.box-hover').children('p.shipping-desc').css('display','none');
$(this).children('p.shipping-desc').css('display','block');
}
if( $(this).children('p.payment-name').length > 0)
{
$('div.box-hover').children('p.payment-desc').css('display','none');
$(this).children('p.payment-desc').css('display','block');
}
});
// autosize the comment textarea
$('#comments').autosize();
// slide in/out guest account form
$("#guest").click( function(e){
$("#cust_info_customers_password").val('');
$("#cust_info_customers_password_confirm").val('');
$('#guest-account').slideUp(250);
});
$("#account").click( function(e){
$('#guest-account').slideDown(250);
});
});
#santadani, found there is a rule to follow due to the implmentation of CoverPop itself. from your production environment, could you move the <script type="text/javascript" src="http://www.exsys.ch/templates/xt_grid/javascript/CoverPop.js"></script> to the end of document, before the </body> tag and try again?
It is because i saw in the CoverPop source, it grabs the element upon the script is loaded
$el = {
html: document.getElementsByTagName('html')[0],
cover: document.getElementById(settings.coverId),
closeClassDefaultEls: document.querySelectorAll('.' + settings.closeClassDefault),
closeClassNoDefaultEls: document.querySelectorAll('.' + settings.closeClassNoDefault)
},
which then the document.querySelectorAll('.' + settings.closeClassDefault) will retrieve nothing (becasue the script was loaded before the DOM are ready, therefore i suggest to try to move the script tag down)
Related
I have a circular image I want to spin with a button click and stop with a different button click.
The spin() function works, but the stop() does not because the values die outside of the spin() function (correct me if I'm wrong). How should I solve this? I'm open to using the same button to spin and stop, but my if else statement produces the same result - spinning the image works, but I can't stop it.
Another unintended bug is that if I click on the spin button more than once, the spinning gets faster.
Here's my code:
var spinImage;
function spin(){
spinImage = document.getElementById('spinImage'), degree = 0;
setInterval(function() {
spinImage.style.transform = "rotate(" + ++degree + "deg)";}, 1);
}
function stop(){
clearInterval(spinImage);
}
I need to stick to plain javascript and use the setInterval/clearInterval methods.
the value you are looking for is the return value of setInterval:
var intervalId;
function spin() {
var spinImage = document.getElementById('spinImage');
var degree = 0;
intervalId = setInterval(function() {
spinImage.style.transform = 'rotate(' + ++degree + 'deg)';
}, 1);
}
function stop() {
clearInterval(intervalId);
}
You need to get the id when initializing setInterval (here store in spin variable). That variable will have reference to setInterval so that you can clear it up using stop function.
Another unintended bug (faster spinning on consecutive clicks) is due to the fact that, previous setInterval id is not cleared and new one is created. So, the number of times you click; you will have that many setIntervals. To avoid it, you need to clear up the existing id and then re-initialize with the new set interval.
Have fixed the code. Please see:
var spinImage;
var spin;
function spin(){
spinImage = document.getElementById('spinImage');
degree = 0;
if(spin) stop();
spin = setInterval(function() {
spinImage.style.transform = "rotate(" + ++degree + "deg)";
}, 1);
}
function stop(){
clearInterval(spin);
}
Hope it helps. Revert for any doubts/clarifications
You need to remember the interval id, so that you can stop it.
let intervalId = null;
function spin() {
spinImage = document.getElementById('spinImage'), degree = 0;
intervalId = setInterval(function() {
spinImage.style.transform = "rotate(" + ++degree + "deg)";
}, 1);
}
function stop() {
clearInterval(intervalId);
}
ES6 Class
You can encapsulate this logic into a reusable class object i.e. ImageSpinner.
const main = () => {
const spinner = new ImageSpinner('#spinImage');
addEventListeners('.btn-toggle', 'click', (e) => {
spinner.toggle();
let attr = `data-text-${spinner.isRunning() ? 'off' : 'on'}`;
e.currentTarget.textContent = e.currentTarget.getAttribute(attr);
});
addEventListeners('.btn-reset', 'click', (e) => {
spinner.reset();
let btn = document.querySelector('.btn-toggle');
btn.textContent = btn.getAttribute('data-text-on');
});
}
class ImageSpinner {
constructor(selector, rate) {
/* #protected */ this.image = document.querySelector(selector);
/* #protected */ this.rate = rate;
/* #private */ this.__intervalId = null;
/* #private */ this.__degree = 0;
}
/* #public */ isRunning() {
return this.__intervalId != null;
}
/* #public */ reset() {
if (this.isRunning()) this.stop();
this.__degree = 0;
this.__rotate();
}
/* #public */ start() {
if (!this.isRunning()) {
this.__intervalId = setInterval(() => { this.update() }, this.rate);
} else {
console.log('Already running...');
}
}
/* #public */ stop() {
if (this.isRunning()) {
clearInterval(this.__intervalId);
this.__intervalId = null;
} else {
console.log('Not currently running...');
}
}
/* #public */ toggle() {
this.isRunning() ? this.stop() : this.start();
}
/* #protected */ update() {
this.__degree = (this.__degree + 1) % 360;
this.__rotate();
}
/* #private */ __rotate() {
this.image.style.transform = "rotate(" + this.__degree + "deg)";
}
}
/*
* Can either be an object of event handlers,
* or an event name followed by a function.
*/
function addEventListeners(elementsOrSelector, events) {
((els) => els.forEach(el =>
(typeof events === 'string' && arguments.length > 2)
? el.addEventListener(arguments[1], arguments[2])
: Object.keys(events)
.forEach(name => el.addEventListener(name, events[name]))))
(Array.from((typeof elementsOrSelector === 'string')
? document.querySelectorAll(elementsOrSelector)
: elementsOrSelector.entries
? elementsOrSelector
: [elementsOrSelector]));
}
main(); // Execute main function
body {
background: #222;
padding: 1.25em;
}
img {
border: 2px dotted white;
margin-left: 0.5em;
}
.btn-wrapper {
margin-top: 1.75em;
}
.btn-toggle {
display: inline-block;
width: 64px;
cursor: pointer;
}
<img id="spinImage" src="https://lh5.googleusercontent.com/-ajlbNdBMWwA/AAAAAAAAAAI/AAAAAAAAAAo/ND2LpoxaqAQ/photo.jpg?sz=96" alt="" width="96" height="96"/>
<div class="btn-wrapper">
<button class="btn btn-toggle" data-text-on="Start" data-text-off="Pause">Start</button>
<button class="btn btn-reset">Reset</button>
</div>
<!DOCTYPE html>
<head>
<title>Spin</title>
</head>
<body>
<button id='spinStart'>Start</button>
<button id='spinStop'>Stop</button>
<script>
var spinning = false;
var handle;
var counter = 0;
// Add click event listener to the start button
window.document.getElementById('spinStart').addEventListener("click", start);
// Add click event listener to the stop button
window.document.getElementById('spinStop').addEventListener("click", stop);
function start() {
if(spinning === true) {
console.log('spinning already')
// Do nothing here as it's already spinning.
spinning = !spinning;
}
if(spinning === false) {
// Not spinning here, so we have to init the setInterval
handle = setInterval(() => {
console.log(counter);
counter++;
}, 1000);
spinning = !spinning;
}
}
function stop() {
//We only want to stop the spinner if it's actually spinning
if(spinning === true){
console.log('clearing the interval now!');
clearInterval(handle);
}
}
</script>
</body>
</html>
Substitute your code as fits.
This code work perfectly. but the suggested text can't control using keyboard
when arrow key up and down. i want to control this suggested text using keyboard
how can i do this. please help..................
/*
*
* jQuery MultiComplete
* =====================
* Written by Tom Hallam
* http://tomhallam.github.com/jQuery-Multicomplete/
* Licenced with the Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) licence
* See: http://creativecommons.org/licenses/by-sa/3.0/
*
*/
(function ($) {
$.fn.multicomplete = function (options) {
// Set up the default options
var defaults = {
// Debug mode provides verbose error messages
debug: true,
// Source
source: [],
// AJAX Method (if source is a URL)
method: 'POST',
// Minimum length before a search can be triggered
minimum_length: 3,
// Delay before performing a search, ignored if source is local
search_delay: 500,
// Case sensitive search?
case_sensitive: false,
// Highlight found words?
highlight_results: true,
// Left offset for results panel
offset_left: 0,
// Top offset for results panel
offset_top: 5,
// Result template
result_template: function(row) {
// -- Please fill this in!
},
// Events -------
// On result click
result_click: null,
// On form submit
form_submit: null
},
// Extend the base object
settings = $.extend(defaults, options);
// Object to keep track of our timers
var timers = [],
// And our result groups
groups = {},
// The results themselves
results = [],
// And the query
query = '';
// Iterate over the selected elements and apply the behavior.
return this.each(function () {
multicomplete_init($(this));
});
// Bootstrapper function to attach events to the elements selected
function multicomplete_init(el) {
// Create a unique ID for this element
id = 'multicomplete-' + Math.floor(Math.random() * 1000);
$(el).data('multicomplete-id', id);
// Make a new key in our timer object
timers[id] = {};
// We need to set a timer for input to trigger based on a delay
$(el).on('keyup', function() {
// Keep a local copy of the value
query = $(this).val();
// Clear any old timers
window.clearTimeout(timers[id]);
// If there's nothing left in the input box, do nothing and hide my result panel
if(query.length == 0) {
$('.panel-multicomplete-results.' + id).hide();
return;
}
// Reset the results array
results = [];
// Make sure the query is hitting the minimum length constraint
if(query.length > settings.minimum_length) {
// Where are we sending this search?
switch(typeof(settings.source)) {
case 'string':
timers[id] = window.setTimeout(function(){
multicomplete_searchajax(function() {
multicomplete_render(el);
});
}, settings.search_delay);
break;
case 'object':
multicomplete_searchobject();
multicomplete_render(el);
break;
}
}
}).attr('autocomplete', 'off');
// Hide the DIV when someone clicks outside of the result pane.
$(document).on('mouseup', function(e) {
if($('.panel-multicomplete-results.' + id).has(e.target).length === 0) {
$('.panel-multicomplete-results.' + id).hide();
}
});
}
// Parse a result group
function multicomplete_parsegroup(group_results, group_name) {
// Loop through the group
$(group_results).each(function(index, row) {
for(var field in row) {
// No numbers (for now)
if(typeof row[field] == 'number') {
return true;
}
if(typeof row[field] == 'object') {
multicomplete_parsegroup(row);
}
else {
// If we find a result then push into our results array.
if(multicomplete_match(row[field])) {
results.push({
'field': field,
'row': row,
'group': group_name
});
return true;
}
}
}
});
}
// Does this string match the query
function multicomplete_match(field) {
if(settings.case_sensitive == true) {
return field.indexOf(query) > -1;
}
else {
return field.toLowerCase().indexOf(query.toLowerCase()) > -1;
}
}
// Search an object
function multicomplete_searchobject() {
if(settings.source.length == 0) {
if(settings.debug == true) {
alert('Source was set to an array, but the array was empty.');
}
}
// Loop through the source
for(var group_name in settings.source) {
if(settings.source[group_name].length)
groups[group_name] = multicomplete_parsegroup(settings.source[group_name], group_name);
}
}
// Search an AJAX endpoint
function multicomplete_searchajax(callback) {
// Perform the remote call.
ajax = $.ajax({
'type': settings.method,
'url': settings.source,
'dataType': 'json',
'data': {
'query': query
},
'success': function(data) {
// Loop through the source
for(var group_name in data) {
if(data[group_name].length)
groups[group_name] = multicomplete_parsegroup(data[group_name], group_name);
}
// Call the callback
callback.call(this, data);
},
'error': function(error) {
if(settings.debug == true) {
if(error.status == 412) {
alert('Your remote data source is not valid JSON! Remember to use double quotes instead of single.');
}
if(error.status == 404) {
alert('Your remote data source does not exist on this server.');
}
if(error.status == 500) {
alert('The remote server encountered an error whilst processing your source.');
}
}
}
});
}
// Render a search result
function multicomplete_render(el) {
// Where is the element
l = el.offset().left,
t = el.offset().top,
mc_html_class = 'panel-multicomplete-results ' + el.data('multicomplete-id'),
mc_class = '.panel-multicomplete-results.' + el.data('multicomplete-id');
// Is there already a results div for this element?
if($(mc_class).length == 0) {
// Build the div
$('<div class="' + mc_html_class + '"></div>').css({
'position': 'absolute',
'left': (l + settings.offset_left),
'top': (t + $(el).height() + settings.offset_top)
}).appendTo('body');
}
else {
$(mc_class).empty().show();
}
// Were there any results?
if(results.length == 0 && !$(mc_class + ' .panel-no-results').length) {
$('<div class="panel-no-results">No results found</div>').appendTo(mc_class);
}
else {
// Create a results div
$('<div class="results"></div>').appendTo(mc_class);
// Loop through the results and group them again
$(results).each(function(index, result) {
if($(mc_class + ' .results .' + result.group).length == 0) {
$('<div class="group ' + result.group + '"><div class="group-title">' + result.group + '</div><div class="group-items"></div></div>').appendTo(mc_class + ' .results');
}
// Cache the result row
r = $('<div class="result"></div>').appendTo(mc_class + ' .results .' + result.group + ' .group-items');
// Get the HTML for the result template
result_tmpl = settings.result_template.call(this, result.row, result.group, result.field);
// Apply the click action
$(result_tmpl).on('click', function() {
if(typeof settings.result_click == 'function') {
settings.result_click.call(this, result.row, result.group);
}
else {
multicomplete_defaultclick(result.row, result.group, el);
}
}).appendTo(r);
});
// Apply a clearfix to the groups
$('<div class="clearfix"></div>').appendTo(mc_class + ' .results .group');
// If we have the highlight option turned on then do that
if(settings.highlight_results == true) {
multicomplete_highlight($(mc_class + ' .results').get(0), query.toUpperCase());
}
}
}
// Default click action for a result
function multicomplete_defaultclick(result, group, el) {
// Is there even a form?
if($(el).closest('form').length == 0) {
}
else {
// Override the form submit to do some funky tings
$(el).closest('form').on('submit', function(e) {
// Check if we've already modified the form
if($(this).data('multicomplete-modified') == true) {
$(this).submit();
}
else {
// Stop the form from submitting
e.preventDefault();
// Modify the element
if(!!el.attr('name')) {
old_name = el.attr('name');
el.attr('name', el.attr('name' + '-mc-dummy'));
}
// Create a new hidden element with the ID
$('<input type="hidden" name="' + old_name + '" value="' + (!!result.id ? result.id : JSON.stringify(result)) + '" />').insertAfter(el);
// Add the checkpoint on to the form
$(this).data('multicomplete-modified', true);
// Submit the form
$(this).submit();
}
});
}
}
/*
highlight v3
Highlights arbitrary terms.
<http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html>
MIT license.
Johann Burkard
<http://johannburkard.de>
<mailto:jb#eaio.com>
*/
function multicomplete_highlight(node, pat) {
var skip = 0;
if (node.nodeType == 3) {
var pos = node.data.toUpperCase().indexOf(pat);
if (pos >= 0) {
var spannode = document.createElement('span');
spannode.className = 'highlight';
var middlebit = node.splitText(pos);
var endbit = middlebit.splitText(pat.length);
var middleclone = middlebit.cloneNode(true);
spannode.appendChild(middleclone);
middlebit.parentNode.replaceChild(spannode, middlebit);
skip = 1;
}
} else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
for (var i = 0; i < node.childNodes.length; ++i) {
i += multicomplete_highlight(node.childNodes[i], pat);
}
}
return skip;
}
}
})(jQuery);
$(document).ready(function() {
$('#input-multicomplete').multicomplete({
minimum_length: 1,
result_template: function(result, group, matched_field) {
tmpl = '<div>';
if(!!result.image) {
tmpl += '<div class="image"><img src="' + result.image + '" /></div>';
}
tmpl += '<div>' + result.name + '</div>';
if(!!result.address) {
tmpl += '<div class="meta">' + result.address + '</div>';
}
// Only display this field if something was matched in it
if(!!result.cuisine && matched_field == 'cuisine') {
tmpl += '<div class="cuisine">Cuisine offered: ' + result.cuisine + '</div>';
}
tmpl += '</div>';
return tmpl;
},
result_click: function(row, group) {
alert('You chose "' + row.name + '" in ' + group);
},
source: {
"Attractions": [
{
"name": "The Tower of London",
"address": "London, EC3N 4AB",
"image": "http://www.hrp.org.uk/Images/TOL_Main.jpg"
},
{
"name": "Camden Lock Market",
"address": "1 Kentish Town Road, London, NW1 8",
"image": "http://www.london-attractions.info/images/attractions/camden-market.jpg"
},
{
"name": "Anne Frank Museum",
"address": "Prinsengracht 267, 1000 AS, Amsterdam",
"image": "http://upload.wikimedia.org/wikipedia/commons/thumb/9/9c/AnneFrankHouseAmsterdamtheNetherlands.jpg/220px-AnneFrankHouseAmsterdamtheNetherlands.jpg"
}
],
"Hotels": [
{
"name": "The Ritz",
"address": "150 Piccadilly, London, W1J 9BR",
"image": "http://www.londonhotels.net/images/photogallery/the-ritz-london/the-ritz-london.jpg"
},
{
"name": "51 Buckingham Gate",
"address": "51 Buckingham Gate, London, SW1E 6AF",
"image": "http://static.laterooms.com/hotelphotos/laterooms/193559/gallery/51-buckingham-gate-london_060620111405093617.jpg"
},
{
"name": "Hotel de l'Europe",
"address": "2–14 Nieuwe Doelenstraat, Amsterdam, 1012 CP ",
"image": "http://www.concierge.com/images/cnt/lists/goldlist06/europe/netherlands/amsterdam/hotel_de_leurope/amsterdam_hotel_002p.jpg"
}
],
"Restaurant": [
{
"name": "Petrus",
"address": "1 Kinnerton Street, Knightsbridge, London, SW1X 8EA",
"image": "http://berkshirereview.net/images/petrus_london_dining.jpg"
},
{
"name": "Vermeer",
"address": "Prins Hendrikkade 59-72, 1012 AD Amsterdam ",
"image": "http://www.restaurantvermeer.nl/Portals/7/UltraPhotoGallery/3425/45/[7].Vermeer---desert-2.jpg"
}
]
}
});
});
/* DEMO STYLES */
.result .image {
float: left;
margin-right: 10px;
}
.result .image img {
width: 32px;
height: 32px;
border: 1px solid #ccc;
padding: 1px;
}
.result .meta {
font-size: 11px;
color: #666;
}
.result a {
text-decoration: underline;
}
.result:hover {
background-color: #f7f7f7;
}
/*
*
* jQuery MultiComplete
* =====================
* Written by Tom Hallam
* http://tomhallam.github.com/jQuery-Multicomplete/
* Licenced with the Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) licence
* See: http://creativecommons.org/licenses/by-sa/3.0/
*
*/
.panel-multicomplete-results {
border: 1px solid #ccc;
width: 420px;
font-family: Tahoma;
font-size: 12px;
background: url(mc-bg.png) repeat-y;
}
.panel-multicomplete-results .result {
padding: 5px;
border-bottom: 1px solid #e7e7e7;
cursor: pointer;
}
.panel-multicomplete-results .result:last-child {
border: none;
}
.panel-multicomplete-results .group {
border-bottom: 1px solid #ccc;
}
.panel-multicomplete-results .group:last-child {
border: none;
}
.panel-multicomplete-results .group-title {
float: left;
width: 100px;
padding: 5px;
font-weight: bold;
}
.panel-multicomplete-results .group-items {
float: left;
width: 300px;
}
.highlight {
font-weight: bold;
}
/* UTILITIES */
.clearfix {
clear: both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
Start typing a city: <input type="text" name="multiselect" id="input-multicomplete" />
</div>
https://jsfiddle.net/ynyqed1m/
When trying use the, otherwise brilliant, rslides js plugin I bump into this annoying problem. I want the images to be imported to the site via links which means I can't resize them but the slider handles this rather poorly; it expands. Now, the slider is responsive, it scales with the page width. One solution might be to set static values for the size but I would prefer not doing this as it would probably break the responsive %scaling.
Edit: forgot to link site http://208.69.30.150/build/age_past.html
Some clarification that's come up in the comments:
The images are resized within the slider. But the slider is resizing to some of the images sizes, only on the height, this is because the images do not all have the same aspect ratios. So I want to resize the images width, and if the height overflows I want to crop of that overflow.
CSS
/*SLIDER*/
.slider{
background-color: #222;
}
.rslides_container {
position: relative;
margin: 50px auto;
width: 100%;
background: #222;
}
.slider .slider_medium{
max-width: 900px;
}
.rslides {
border-radius:200px;
-moz-border-radius:20px;
-webkit-border-radius:20px;
position: relative;
list-style: none;
overflow: hidden;
width: 100%;
padding: 0;
margin: 0 auto;
}
.rslides li {
-webkit-backface-visibility: hidden;
position: absolute;
display: none;
width: 100%;
left: 0;
top: 0;
}
.rslides li:first-child {
position: relative;
display: block;
float: left;
}
.rslides img {
display: block;
height: auto;
float: left;
width: 100%;
border: 0;
}
/*SLIDER OVERLAY IMAGES*/
#banner_image_1 img{
position: absolute;
z-index: 5;
top: 10%;
left: 3%;
height:auto;
width:auto;
max-height: 100px;
background: #FFF;
}
#banner_image_2 img{
position: absolute;
z-index: 5;
bottom: 3%;
right: 1%;
height: 20%;
max-height:60px;
}
#banner_image_3 img{
position: absolute;
z-index: 5;
bottom: 3%;
right: 7%;
height: 20%;
max-height:60px;
}
HTML
<div class="block slider">
<div class="rslides_container slider_medium">
<!--<a id="banner_image_1" href="" target="">
<img src="">
</a>-->
<ul class="rslides">
<li>
<a href="http://www.agepast.com/">
<img src="http://fc00.deviantart.net/fs70/i/2010/194/2/5/Age_Past_Wallpaper_by_Tsabo6.jpg"/>
</a>
</li>
<li>
<a href="http://www.agepast.com/">
<img src="http://fc03.deviantart.net/fs71/i/2011/211/c/6/age_past_by_tsabo6-d424m3v.jpg"/>
</a>
</li>
<li>
<a href="http://www.agepast.com/">
<img src="http://fc00.deviantart.net/fs70/i/2010/257/7/e/age_past_earth_magic_by_tsabo6-d2yp0v0.jpg"/>
</a>
</li>
<li>
<a href="http://www.agepast.com/">
<img src="http://fc01.deviantart.net/fs71/i/2010/244/8/2/age_past_wall_2_by_tsabo6-d2xr9g0.jpg"/>
</a>
</li>
</ul>
</div>
<script>
$(function() {
$(".rslides").responsiveSlides({
auto: true, speed: 1500, timeout: 5000, pause: true,
});
});
</script>
</div>
& LOTS of JS (which just won't be formatted right.)
(function ($, window, i) {
$.fn.responsiveSlides = function (options) {
// Default settings
var settings = $.extend({
"auto": true, // Boolean: Animate automatically, true or false
"speed": 500, // Integer: Speed of the transition, in milliseconds
"timeout": 4000, // Integer: Time between slide transitions, in milliseconds
"pager": false, // Boolean: Show pager, true or false
"nav": false, // Boolean: Show navigation, true or false
"random": false, // Boolean: Randomize the order of the slides, true or false
"pause": false, // Boolean: Pause on hover, true or false
"pauseControls": true, // Boolean: Pause when hovering controls, true or false
"prevText": "Previous", // String: Text for the "previous" button
"nextText": "Next", // String: Text for the "next" button
"maxwidth": "", // Integer: Max-width of the slideshow, in pixels
"navContainer": "", // Selector: Where auto generated controls should be appended to, default is after the <ul>
"manualControls": "", // Selector: Declare custom pager navigation
"namespace": "rslides", // String: change the default namespace used
"before": $.noop, // Function: Before callback
"after": $.noop // Function: After callback
}, options);
return this.each(function () {
// Index for namespacing
i++;
var $this = $(this),
// Local variables
vendor,
selectTab,
startCycle,
restartCycle,
rotate,
$tabs,
// Helpers
index = 0,
$slide = $this.children(),
length = $slide.size(),
fadeTime = parseFloat(settings.speed),
waitTime = parseFloat(settings.timeout),
maxw = parseFloat(settings.maxwidth),
// Namespacing
namespace = settings.namespace,
namespaceIdx = namespace + i,
// Classes
navClass = namespace + "_nav " + namespaceIdx + "_nav",
activeClass = namespace + "_here",
visibleClass = namespaceIdx + "_on",
slideClassPrefix = namespaceIdx + "_s",
// Pager
$pager = $("<ul class='" + namespace + "_tabs " + namespaceIdx + "_tabs' />"),
// Styles for visible and hidden slides
visible = {"float": "left", "position": "relative", "opacity": 1, "zIndex": 2},
hidden = {"float": "none", "position": "absolute", "opacity": 0, "zIndex": 1},
// Detect transition support
supportsTransitions = (function () {
var docBody = document.body || document.documentElement;
var styles = docBody.style;
var prop = "transition";
if (typeof styles[prop] === "string") {
return true;
}
// Tests for vendor specific prop
vendor = ["Moz", "Webkit", "Khtml", "O", "ms"];
prop = prop.charAt(0).toUpperCase() + prop.substr(1);
var i;
for (i = 0; i < vendor.length; i++) {
if (typeof styles[vendor[i] + prop] === "string") {
return true;
}
}
return false;
})(),
// Fading animation
slideTo = function (idx) {
settings.before(idx);
// If CSS3 transitions are supported
if (supportsTransitions) {
$slide
.removeClass(visibleClass)
.css(hidden)
.eq(idx)
.addClass(visibleClass)
.css(visible);
index = idx;
setTimeout(function () {
settings.after(idx);
}, fadeTime);
// If not, use jQuery fallback
} else {
$slide
.stop()
.fadeOut(fadeTime, function () {
$(this)
.removeClass(visibleClass)
.css(hidden)
.css("opacity", 1);
})
.eq(idx)
.fadeIn(fadeTime, function () {
$(this)
.addClass(visibleClass)
.css(visible);
settings.after(idx);
index = idx;
});
}
};
// Random order
if (settings.random) {
$slide.sort(function () {
return (Math.round(Math.random()) - 0.5);
});
$this
.empty()
.append($slide);
}
// Add ID's to each slide
$slide.each(function (i) {
this.id = slideClassPrefix + i;
});
// Add max-width and classes
$this.addClass(namespace + " " + namespaceIdx);
if (options && options.maxwidth) {
$this.css("max-width", maxw);
}
// Hide all slides, then show first one
$slide
.hide()
.css(hidden)
.eq(0)
.addClass(visibleClass)
.css(visible)
.show();
// CSS transitions
if (supportsTransitions) {
$slide
.show()
.css({
// -ms prefix isn't needed as IE10 uses prefix free version
"-webkit-transition": "opacity " + fadeTime + "ms ease-in-out",
"-moz-transition": "opacity " + fadeTime + "ms ease-in-out",
"-o-transition": "opacity " + fadeTime + "ms ease-in-out",
"transition": "opacity " + fadeTime + "ms ease-in-out"
});
}
// Only run if there's more than one slide
if ($slide.size() > 1) {
// Make sure the timeout is at least 100ms longer than the fade
if (waitTime < fadeTime + 100) {
return;
}
// Pager
if (settings.pager && !settings.manualControls) {
var tabMarkup = [];
$slide.each(function (i) {
var n = i + 1;
tabMarkup +=
"<li>" +
"<a href='#' class='" + slideClassPrefix + n + "'>" + n + "</a>" +
"</li>";
});
$pager.append(tabMarkup);
// Inject pager
if (options.navContainer) {
$(settings.navContainer).append($pager);
} else {
$this.after($pager);
}
}
// Manual pager controls
if (settings.manualControls) {
$pager = $(settings.manualControls);
$pager.addClass(namespace + "_tabs " + namespaceIdx + "_tabs");
}
// Add pager slide class prefixes
if (settings.pager || settings.manualControls) {
$pager.find('li').each(function (i) {
$(this).addClass(slideClassPrefix + (i + 1));
});
}
// If we have a pager, we need to set up the selectTab function
if (settings.pager || settings.manualControls) {
$tabs = $pager.find('a');
// Select pager item
selectTab = function (idx) {
$tabs
.closest("li")
.removeClass(activeClass)
.eq(idx)
.addClass(activeClass);
};
}
// Auto cycle
if (settings.auto) {
startCycle = function () {
rotate = setInterval(function () {
// Clear the event queue
$slide.stop(true, true);
var idx = index + 1 < length ? index + 1 : 0;
// Remove active state and set new if pager is set
if (settings.pager || settings.manualControls) {
selectTab(idx);
}
slideTo(idx);
}, waitTime);
};
// Init cycle
startCycle();
}
// Restarting cycle
restartCycle = function () {
if (settings.auto) {
// Stop
clearInterval(rotate);
// Restart
startCycle();
}
};
// Pause on hover
if (settings.pause) {
$this.hover(function () {
clearInterval(rotate);
}, function () {
restartCycle();
});
}
// Pager click event handler
if (settings.pager || settings.manualControls) {
$tabs.bind("click", function (e) {
e.preventDefault();
if (!settings.pauseControls) {
restartCycle();
}
// Get index of clicked tab
var idx = $tabs.index(this);
// Break if element is already active or currently animated
if (index === idx || $("." + visibleClass).queue('fx').length) {
return;
}
// Remove active state from old tab and set new one
selectTab(idx);
// Do the animation
slideTo(idx);
})
.eq(0)
.closest("li")
.addClass(activeClass);
// Pause when hovering pager
if (settings.pauseControls) {
$tabs.hover(function () {
clearInterval(rotate);
}, function () {
restartCycle();
});
}
}
// Navigation
if (settings.nav) {
var navMarkup =
"<a href='#' class='" + navClass + " prev'>" + settings.prevText + "</a>" +
"<a href='#' class='" + navClass + " next'>" + settings.nextText + "</a>";
// Inject navigation
if (options.navContainer) {
$(settings.navContainer).append(navMarkup);
} else {
$this.after(navMarkup);
}
var $trigger = $("." + namespaceIdx + "_nav"),
$prev = $trigger.filter(".prev");
// Click event handler
$trigger.bind("click", function (e) {
e.preventDefault();
var $visibleClass = $("." + visibleClass);
// Prevent clicking if currently animated
if ($visibleClass.queue('fx').length) {
return;
}
// Adds active class during slide animation
// $(this)
// .addClass(namespace + "_active")
// .delay(fadeTime)
// .queue(function (next) {
// $(this).removeClass(namespace + "_active");
// next();
// });
// Determine where to slide
var idx = $slide.index($visibleClass),
prevIdx = idx - 1,
nextIdx = idx + 1 < length ? index + 1 : 0;
// Go to slide
slideTo($(this)[0] === $prev[0] ? prevIdx : nextIdx);
if (settings.pager || settings.manualControls) {
selectTab($(this)[0] === $prev[0] ? prevIdx : nextIdx);
}
if (!settings.pauseControls) {
restartCycle();
}
});
// Pause when hovering navigation
if (settings.pauseControls) {
$trigger.hover(function () {
clearInterval(rotate);
}, function () {
restartCycle();
});
}
}
}
// Max-width fallback
if (typeof document.body.style.maxWidth === "undefined" && options.maxwidth) {
var widthSupport = function () {
$this.css("width", "100%");
if ($this.width() > maxw) {
$this.css("width", maxw);
}
};
// Init fallback
widthSupport();
$(window).bind("resize", function () {
widthSupport();
});
}
});
};
})(jQuery, this, 0);
I think you can add width: auto; and overflow: hidden to your slider container
I could not find a proper solution. I solved my issue by switching slider. If anyone finds an answer please do share, meanwhile I suggest trying this: http://www.builtbyevolve.com/work/plugins/nerve-slider
I'm trying to do JS module for slidingup/slidingdown HTML blocks.
JS module is calculating block max-height.
The problem is, that CSS transition works only for sliding down.
I can't find the right solution.
Here is jsFiddle
var Accordion = {
'vars': {
'attrItem': 'data-accordion-item',
'attrToggle': 'data-accordion-toggle',
'classOpened': '_active',
'classPrepare': '_preparing',
'timer': null
},
'accObject': {},
'accData': function(accID, key, value) {
var module = this;
if (typeof value != 'undefined') {
if (typeof module.accObject[accID] == 'undefined') {
module.accObject[accID] = {};
}
module.accObject[accID][key] = value;
} else {
return module.accObject[accID][key];
}
},
'init': function() {
var module = this;
// Loop accToggles
$('*[' + module.vars.attrToggle + ']').each(function() {
var accToggle = $(this);
var accID = accToggle.attr(module.vars.attrToggle);
// Store data of ID
module.accData(accID, 'accID', accID);
// Store data of toggle
if (!module.accData(accID, 'accToggle')) {
module.accData(accID, 'accToggle', accToggle);
} else {
module.accData(accID, 'accToggle', module.accData(accID, 'accToggle').add(accToggle));
}
// Attach click to accToggle
accToggle.click(function(e) {
e.preventDefault();
// Toggle between open/close state
module.accData(accID, 'accOpened') ? module.toggle(accID, false) : module.toggle(accID, true);
});
});
// Loop accItems
$('*[' + module.vars.attrItem + ']').each(function() {
var accItem = $(this);
var accID = accItem.attr(module.vars.attrItem);
var accOpened = accItem.hasClass(module.vars.classOpened) ? true : false;
// Store data of ID
module.accData(accID, 'accID', accID);
// Store data of item
if (!module.accData(accID, 'accItem')) {
module.accData(accID, 'accItem', accItem);
} else {
module.accData(accID, 'accItem', module.accData(accID, 'accItem').add(accItem));
}
// Store data of state
if (!module.accData(accID, 'accOpened')) module.accData(accID, 'accOpened', accOpened);
// Check to open or close accItem
accOpened ? module.toggle(accID, true) : module.toggle(accID, false);
});
},
'getSize': function(accItem) {
var module = this;
accItem.addClass(module.vars.classPrepare);
var height = accItem.outerHeight();
accItem.removeClass(module.vars.classPrepare);
return height;
},
'toggle': function(accID, open, skipAnimation) {
var module = this;
var accItems = module.accData(accID, 'accItem');
var accToggles = module.accData(accID, 'accToggle');
var accOpened = module.accData(accID, 'accOpened');
var action;
// Check for action open/close and set vars
if (open) {
module.accData(accID, 'accOpened', true);
action = 'addClass';
} else {
module.accData(accID, 'accOpened', false);
action = 'removeClass';
}
// Loop items
if (accItems) {
accItems.each(function() {
var accItem = $(this);
accItem[action](module.vars.classOpened);
// Timer fights against no animation
if (module.timer) clearTimeout(module.timer);
module.timer = setTimeout(function() {
accItem.css('max-height', open ? module.getSize(accItem) : 0);
}, 10);
});
}
// Loop toggles
if (accToggles) {
accToggles.each(function() {
var accToggle = $(this);
accToggle[action](module.vars.classOpened);
});
}
}
}
$(document).ready(function() {
Accordion.init();
});
.f-control {
background: #ddd;
}
*[data-accordion-item] {
max-height: 0;
padding-bottom: 6px;
overflow: hidden;
opacity: 0;
-webkit-transition-property: max-height, opacity;
transition-property: max-height, opacity;
-webkit-transition-duration: 300ms;
transition-duration: 300ms;
margin-left: -20px;
margin-right: -20px;
padding-left: 20px;
padding-right: 20px;
}
*[data-accordion-item]._active {
opacity: 1;
}
*[data-accordion-item]._preparing {
max-height: initial !important;
-webkit-transition: none;
transition: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="f-row">
<a href="#" class="side-title" data-accordion-toggle="1">
<span>Show/hide</span>
</a>
<div class="f-control" data-accordion-item="1">
<h1>Test1</h1>
<h2>Test2</h2>
</div>
</div>
JQuery has a simple enough way of generating this kind of functionality using slideToggle to show/hide elements. You can even set the speed :)
$('#showHide').click(function(){
$('div').slideToggle("fast");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button id="showHide">hideshow</button>
<div>
this <br/>
and this
</div>
So I'm trying to figure out how to make a toggle button for a greasemonkey extensions that runs and navigates to various pages.
So this is what I have so far
var keepgoing = true
Beginnign of if statement and stuff here
else if keepgoing == true
{ newsearch(); }
Button click:
if keepgoing == true { keepgoing = false }
else if keepgoing == false { keepgoing = true }
So basically I need help have a button put on a webpage.
and it needs to remember the var as it navigates through pages.
Thanks, Ray
If you want a persistent button (or any data), you'll need to use some kind of storage. If multiple domains are involved, use GM_setValue(). If everything's on the same domain, use localStorage.
I add this kind of persistent button myself, here is a pared down-script that shows what I use. It doesn't just add a button, it makes the button UI a little more user-friendly, IMO.
NOTE:
The button state persists across page loads and across sites.
The button stays in the upper left (set by CSS) and fades to near opaque when not moused over.
I use an object, because I sometimes have more than 1 control that I add to page(s).
You can see a demo of how the button appears and behaves at jsFiddle. (Except that values cannot persist across page-loads in the demo. They do in the GM script.)
// ==UserScript==
// #name _Keep going button
// #include http://YOUR_SERVER_1.COM/YOUR_PATH/*
// #include http://YOUR_SERVER_2.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// ==/UserScript==
//--- Add the button.
$("body").append (
'<div class="gmPersistentButton">'
+ '<button id="gmContinueBtn">Init failed!</button></div>'
);
//--- Define and init the matching control object:
var btnControl = new PersistentButton (
"gmContinueBtn", //-- HTML id
"StopContinueBtn", //-- Storage label
["Stop", "Continue"], //-- Text that the button cycles through
[false, true] //-- Matching values for the button's states
);
//--- Activate the button click-handler.
$("#gmContinueBtn").click ( function () {
var btnValue = this.value;
keepgoing = btnValue
btnControl.SetNextValue ();
if (keepgoing == "true") {
// CALL YOUR FUNCTION HERE.
}
} );
//--- The button will fade when we aren't using it.
var zDisplayPanel = $('div.gmPersistentButton');
zDisplayPanel.hover (
function () { $(this).stop (true, false).fadeTo (50, 1 ); },
function () { $(this).stop (true, false).fadeTo (900, 0.1); }
);
zDisplayPanel.fadeTo (2900, 0.1);
//--- CSS styles to make it work and to improve appearance.
GM_addStyle ( (<><![CDATA[
.gmPersistentButton {
background: orange;
color: black;
position: fixed;
top: 1em;
right: 1em;
z-index: 6666;
padding: 1em;
border: 3px double gray;
border-radius: 1ex;
opacity: 0.8;
}
.gmPersistentButton button {
cursor: pointer;
}
.gmPersistentButton button:hover {
color: red;
}
]]></>).toString () );
//--- Button object
function PersistentButton (htmlID, setValName, textArry, valueArry) {
//--- Initialize the button to last stored value or default.
var buttonValue = valueArry[0];
fetchValue ();
storeValue (); //-- Store, in case it wasn't already.
setButtonTextAndVal ();
//--- DONE with init. Set click and keyboard listeners externally.
//***** Public functions:
this.Reset = function () {
buttonValue = valueArry[0];
storeValue ();
setButtonTextAndVal ();
};
this.SetNextValue = function () {
var numValues = valueArry.length;
var valIndex = 0;
for (var J = numValues - 1; J >= 0; --J) {
if (buttonValue == valueArry[J]) {
valIndex = J;
break;
}
}
valIndex++;
if (valIndex >= numValues)
valIndex = 0;
buttonValue = valueArry[valIndex];
storeValue ();
setButtonTextAndVal ();
};
//***** Private functions:
function fetchValue () {
buttonValue = GM_getValue (setValName, buttonValue);
}
function storeValue () {
GM_setValue (setValName, buttonValue);
}
function setButtonTextAndVal () {
var buttonText = "*ERROR!*";
for (var J = valueArry.length - 1; J >= 0; --J) {
if (buttonValue == valueArry[J]) {
buttonText = textArry[J];
break;
}
}
var theBtn = document.getElementById (htmlID);
if (theBtn) {
theBtn.textContent = buttonText;
theBtn.setAttribute ("value", buttonValue);
}
else
alert ('Missing persistent button with ID: ' + htmlID + '!');
}
}