fside
04-19-2008, 03:09 AM
Here's a simple page control for any number of pages.
You have to create the basic object on a particular webpage; in part of the template you use, for ex. The object is described as, "pgs", below. You have to provide a 'div' or whatever to which the buttons can be attached. That will be where they show up on the page, where they are located. Then just link in the script and it will automatically create the buttons, however many you want at one time.
It's also assumed that all the pages are named the same, with just different numbers, and that they all are found in the same directory.
There's also a utility section, some of which is required by the buttons script. A couple of others in the utility section were used with an earlier version that directly manipulated the styles to account for changing width given a differing number of digits. They might all prove generally useful.
Of course, it's assumed one would make the styles external, and the script external. It can run as-is. But it's assumed one would make a few changes to incorporate it into your existing library/framework. A separate .zip could have been used showing just this. But it was imagined the reader would be competent on their own to adapt this.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<STYLE type="text/css">
.npctrl {
background: #022;
color: #ccc;
font-size: 107%;
font-weight: bold;
border: none;
width: 1.5em;
padding: 0.1em;
margin-bottom: -0.05em;
}
.npctrl2 {
font-size: 112%;
padding: 0em;
margin-bottom: -0.095em;
width: 1.3em;
}
.npctrl:hover {
background: #527c50;
color: #fff;
}
.nppg, .thispg {
background: #000;
color: #fff;
font-family: verdana, sans-serif;
font-weight: bold;
border: none;
padding: 0.12em 0.16em 0.25em 0.15em;
margin: 0px;
}
.thispg {
color: #beb;
}
.nppg:hover {
color: #00f;
background: #ff3;
}
#npNext {
border-left: 0.2em solid #888;
width: 1.7em;
}
#npPrev {
border-right: 0.2em solid #888;
width: 1.7em;
}
</STYLE>
<!--[if IE]><link rel="stylesheet" type="text/css" href="iefix38a.css" /><![endif]-->
<!-- opera override: .npctrl padding: 0.05em, .nppg padding-bottom: 3em -->
</head>
<body>
<div id="mainContainer">
<div id="btns"></div>
</div>
<script language="JavaScript"><!--
/* global var, pgs, is written to each web page. If "pgs" were incl in another obj, etc, changes would be req'd below.
*
* If the #pgs < #btns, no control buttons are shown.
* If #pgs > 200, another set of buttons are shown which move the group forward or backward by 100 pages.
* The "thispg" specifies which number is this webpage. And that button will be deactivated when displayed.
* The "iddiv" is the string id of the division into which the buttons are placed. How it is located/placed on the page.
* 'fors' is used to force padding of the filenames, even if not req'd. Expected to be used only on single digit page numbers.
* e.g. one uses padding in the filenames in anticipation of more than 10 pages, but less than 10 pgs are used. Then fors:1.
*/
var pgs = {npgs:75, nbtns:12, iddiv:"btns", prefx:"pg", fors:0, thispg:23};
(function(){
var copyright = "MIT license rules (www.opensource.org/licenses/mit-license.php), copyright 2008 scenic-route.com";
/* the global reference - you could adapt to one of your own, or modify this and substitute your global in, "Glob" */
window.g93 ={
npFirst: function(){ npFirst(); },
npLast: function(){ npLast(); },
npPrev: function(){ npPrev(); },
npNext: function(){ npNext(); },
npPrev100: function(){ npPrev100(); },
npNext100: function(){ npNext100(); },
npLoc: function(arg){ npLoc(arg); }
};
var Glob = "g93.";
/*************************** Page Buttons ***************************/
/* could use your own functional test or in addition to this */
var isIE6 = (navigator.userAgent.toLowerCase().indexOf("msie 6") !==-1);
/* If "pgs" were used directly (unvectored) in code, further on, it would not allow for changes to "pgs". */
var Btns = { n: pgs.nbtns, offs: 0, prefixx: "npb", thispg: pgs.thispg, useCtrl: true, anchorDiv: pgs.iddiv };
var Pgs = { n: pgs.npgs, prefixx: pgs.prefx, forcepad: pgs.fors };
if (Pgs.n <Btns.n){
Btns.n = Pgs.n;
Btns.useCtrl = false;
}
function btn(n, strId, clas, titel, func){
/* single quotes not needed for FF or Opera, but are required for IE */
var attr = ["title='",titel,"'<>type='button'<>class='",clas,"'<>value='",n,"'<>onclick=",func].join("");
return addNode(strId, Btns.anchorDiv, "input", attr);
}
if (Btns.useCtrl){
btn("|<", "npFirst", "npctrl", "First page", Glob +"npFirst()");
if (Pgs.n >200){ btn("<", "npPrev100", "npctrl npctrl2", "Previous 100 pages", Glob +"npPrev100()"); }
btn("<", "npPrev", "npctrl", "Previous " +Btns.n +" pages", Glob +"npPrev()");
}
for (var i=1; i <Btns.n +1; i +=1){
o =btn(i, Btns.prefixx +i, "nppg", "", Glob +"npLoc('"+ i +"')");
}
if (Btns.useCtrl){
btn(">", "npNext", "npctrl", "Next " +Btns.n +" pages", Glob +"npNext()");
if (Pgs.n >200){ btn(">", "npNext100", "npctrl npctrl2", "Next 100 pages", Glob +"npNext100()"); }
btn(">|", "npLast", "npctrl", "Last page", Glob +"npLast()");
}
/**
* The underlying page is simply calculated from the button position/number added to the offset.
* But the numbers have to show on the button faces.
*/
function npMove(){
var n, styVal, theseDigits, diff;
for (var i=1; i <Btns.n +1; i +=1){
$(Btns.prefixx +i).value = i +Btns.offs;
$(Btns.prefixx +i).className = (i +Btns.offs === Btns.thispg)? "thispg" : "nppg";
}
}
/* not to move any number, just to set the thispg style if nec */
npMove();
/* Controls often tend to be simple covers/wrappers. No different here. */
function npNext(){
Btns.offs += Btns.n;
var d= Btns.offs +Btns.n >Pgs.n ? npLast() : npMove();
}
function npNext100(){
Btns.offs += 100;
var d= Btns.offs +Btns.n >Pgs.n ? npLast() : npMove();
}
function npPrev(){
Btns.offs = Btns.offs -Btns.n;
var d= Btns.offs <0 ? npFirst() : npMove();
}
function npPrev100(){
Btns.offs = Btns.offs -100;
var d= Btns.offs <0 ? npFirst() : npMove();
}
function npLast(){
Btns.offs = Pgs.n -Btns.n;
npMove();
}
function npFirst(){
Btns.offs = 0;
npMove();
}
function npLoc(btn){
if ( $("npb"+btn).className ==="thispg" ){ return; }
var pgNum = padit(Number(btn) +Btns.offs, Pgs.n, Pgs.forcepad);
location.href = "./" +Pgs.prefixx +pgNum +".htm";
}
/*************************** Utilities ***************************/
/* Since Stephenson's use in Prototype, the "$" function has become common, & usually much more elaborate than: */
function $(strID){
return document.getElementById(strID);
}
/**
* Simple left pad with zero.
* 'n' is the number to be padded, and 'max' is the maximum/largest number to be used (e.g. the last page).
* Neither n nor max are checked to see if they are numbers, but such could of course be added.
*
* forcepad is used to force left-zero padding even if not required.
* a forcepad = 10 through 90 would pad one left zero to the numbers 0-9.
* a forcepad of 100 through 990 would pad two left zeroes, 1000 - 9990 for three zeros, etc.
* One might be in the habit of padding with one zero, say, in anticipation of more than 10 pgs, even if a report doesn't run 10pgs.
*
* These are easily converted to string primitives, but a math formula, shown, could achieve the same thing.
*/
function padit(n, max, forcepad){
/* alternative: (0, int(abs(log(1/max+forcepad)))) &n */
return "0000000000000000000".substring(0, String(max+forcepad).length -String(n).length) +String(n);
}
/*
* standard new node function, adds a new HTML element with a particular id, if the id isn't already in use.
* strId must be specified.
* strObjSup is the id of the superior element to which to attach the new node/element
* strType is the type of element, 'div', 'span', etc.
* strArgs are the attributes for the element, each separated by, "<>".
* IE compatibility requires all values be single quoted, but not for events (on_, etc), so an example:
* ["class='",someClass,"'<>title='",someTitle,"'<>onclick=","func(){}","<>style='",styles,"'"].join("")
*/
function addNode(strId, strObjSup, strType, strArgs){
if (!$(strId)){
var arArgs, arAttr, namAttr, valAttr, objnode;
var objElmt = (strObjSup ==="HEAD0") ? document.documentElement : $(strObjSup);
if (isIE6){
/* Broken IE6 DOM, run everything through createElement. */
strArgs = (typeof strArgs ==="undefined") ? "" : " " +strArgs.replace(/<>/g," ");
objnode = document.createElement("<" +strType +strArgs +">");
objnode.id = strId;
return objElmt.appendChild(objnode);
} else {
objnode = document.createElement(strType);
objnode.id = strId;
objnode = objElmt.appendChild(objnode);
if (typeof strArgs !=="undefined"){
arArgs = strArgs.split("<>");
for (var i=0; i <arArgs.length; i +=1){
namAttr = arArgs[i].split("=")[0];
valAttr = arArgs[i].split("=")[1];
/* not recommended to omit single quotes, they are required for the IE branch, above */
if (valAttr.substring(0,1)==="'"){ valAttr = valAttr.substring(1,valAttr.length-1); }
switch (namAttr){
case "style":
arAttr = valAttr.split(";");
for (var j=0; j <arAttr.length; j +=1){
objnode.style[arAttr[j].split(":")[0]] =arAttr[j].split(":")[1];
}
break;
default:
objnode.setAttribute(namAttr, valAttr);
}
}
}
return objnode;
}
}
return null;
}
/**
* The next two split the scalar from its dimension label, and return both.
*
* If more than one dimension is found in the loop, it's probably a bad strValDim and garbage will be returned.
* But the only check for this, in splitWhDim, is to see if the dimension label is the last thing in strValDim.
* In that's not the case, then "unk" is returned as the dimension. And the caller will have to check that.
*/
function splitDim(strValDim){
var sd;
var dims = ["em", "px", "in", "%"];
for (var i=0; i <dims.length; i +=1){ if (strValDim.indexOf(dims[i]) !== -1){ sd =splitWhDim(strValDim, dims[i]); } }
return {valu: sd.valu, dimen: sd.dimen};
}
function splitWhDim(strValDim, strDim){
var valu, dimen;
strValDim.replace(/ /g,"");
if (strValDim.indexOf(strDim) !==-1){
valu = strValDim.split(strDim)[0];
dimen = (strValDim.split(strDim)[1].length ===0) ? strDim : "unk";
}
return {valu: valu, dimen: dimen};
}
/* The standard getRule function. Returns - array of same 'rule's. Specific styles are then found as rule[i].style.whatever . */
function classObj(clasName){
var d =document, k, m, nRules, arSty, aRule, arRtn =[ ];
var flgR = !!d.styleSheets[0].rules;
for (var j=0; j <d.styleSheets.length; j +=1) {
nRules = flgR ? d.styleSheets[j].rules : d.styleSheets[j].cssRules;
for (k=0; k <nRules.length; k +=1) {
aRule = flgR ? d.styleSheets[j].rules[k] : d.styleSheets[j].cssRules[k];
arSty = aRule.selectorText.replace(/ /g,"").split(",");
for (m=0; m <arSty.length; m +=1) {
if (arSty[m] === '.' + clasName) {
arRtn.push(aRule); }}}}
return arRtn;
}
})();
// -->
</script>
</body>
</html>
You have to create the basic object on a particular webpage; in part of the template you use, for ex. The object is described as, "pgs", below. You have to provide a 'div' or whatever to which the buttons can be attached. That will be where they show up on the page, where they are located. Then just link in the script and it will automatically create the buttons, however many you want at one time.
It's also assumed that all the pages are named the same, with just different numbers, and that they all are found in the same directory.
There's also a utility section, some of which is required by the buttons script. A couple of others in the utility section were used with an earlier version that directly manipulated the styles to account for changing width given a differing number of digits. They might all prove generally useful.
Of course, it's assumed one would make the styles external, and the script external. It can run as-is. But it's assumed one would make a few changes to incorporate it into your existing library/framework. A separate .zip could have been used showing just this. But it was imagined the reader would be competent on their own to adapt this.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<STYLE type="text/css">
.npctrl {
background: #022;
color: #ccc;
font-size: 107%;
font-weight: bold;
border: none;
width: 1.5em;
padding: 0.1em;
margin-bottom: -0.05em;
}
.npctrl2 {
font-size: 112%;
padding: 0em;
margin-bottom: -0.095em;
width: 1.3em;
}
.npctrl:hover {
background: #527c50;
color: #fff;
}
.nppg, .thispg {
background: #000;
color: #fff;
font-family: verdana, sans-serif;
font-weight: bold;
border: none;
padding: 0.12em 0.16em 0.25em 0.15em;
margin: 0px;
}
.thispg {
color: #beb;
}
.nppg:hover {
color: #00f;
background: #ff3;
}
#npNext {
border-left: 0.2em solid #888;
width: 1.7em;
}
#npPrev {
border-right: 0.2em solid #888;
width: 1.7em;
}
</STYLE>
<!--[if IE]><link rel="stylesheet" type="text/css" href="iefix38a.css" /><![endif]-->
<!-- opera override: .npctrl padding: 0.05em, .nppg padding-bottom: 3em -->
</head>
<body>
<div id="mainContainer">
<div id="btns"></div>
</div>
<script language="JavaScript"><!--
/* global var, pgs, is written to each web page. If "pgs" were incl in another obj, etc, changes would be req'd below.
*
* If the #pgs < #btns, no control buttons are shown.
* If #pgs > 200, another set of buttons are shown which move the group forward or backward by 100 pages.
* The "thispg" specifies which number is this webpage. And that button will be deactivated when displayed.
* The "iddiv" is the string id of the division into which the buttons are placed. How it is located/placed on the page.
* 'fors' is used to force padding of the filenames, even if not req'd. Expected to be used only on single digit page numbers.
* e.g. one uses padding in the filenames in anticipation of more than 10 pages, but less than 10 pgs are used. Then fors:1.
*/
var pgs = {npgs:75, nbtns:12, iddiv:"btns", prefx:"pg", fors:0, thispg:23};
(function(){
var copyright = "MIT license rules (www.opensource.org/licenses/mit-license.php), copyright 2008 scenic-route.com";
/* the global reference - you could adapt to one of your own, or modify this and substitute your global in, "Glob" */
window.g93 ={
npFirst: function(){ npFirst(); },
npLast: function(){ npLast(); },
npPrev: function(){ npPrev(); },
npNext: function(){ npNext(); },
npPrev100: function(){ npPrev100(); },
npNext100: function(){ npNext100(); },
npLoc: function(arg){ npLoc(arg); }
};
var Glob = "g93.";
/*************************** Page Buttons ***************************/
/* could use your own functional test or in addition to this */
var isIE6 = (navigator.userAgent.toLowerCase().indexOf("msie 6") !==-1);
/* If "pgs" were used directly (unvectored) in code, further on, it would not allow for changes to "pgs". */
var Btns = { n: pgs.nbtns, offs: 0, prefixx: "npb", thispg: pgs.thispg, useCtrl: true, anchorDiv: pgs.iddiv };
var Pgs = { n: pgs.npgs, prefixx: pgs.prefx, forcepad: pgs.fors };
if (Pgs.n <Btns.n){
Btns.n = Pgs.n;
Btns.useCtrl = false;
}
function btn(n, strId, clas, titel, func){
/* single quotes not needed for FF or Opera, but are required for IE */
var attr = ["title='",titel,"'<>type='button'<>class='",clas,"'<>value='",n,"'<>onclick=",func].join("");
return addNode(strId, Btns.anchorDiv, "input", attr);
}
if (Btns.useCtrl){
btn("|<", "npFirst", "npctrl", "First page", Glob +"npFirst()");
if (Pgs.n >200){ btn("<", "npPrev100", "npctrl npctrl2", "Previous 100 pages", Glob +"npPrev100()"); }
btn("<", "npPrev", "npctrl", "Previous " +Btns.n +" pages", Glob +"npPrev()");
}
for (var i=1; i <Btns.n +1; i +=1){
o =btn(i, Btns.prefixx +i, "nppg", "", Glob +"npLoc('"+ i +"')");
}
if (Btns.useCtrl){
btn(">", "npNext", "npctrl", "Next " +Btns.n +" pages", Glob +"npNext()");
if (Pgs.n >200){ btn(">", "npNext100", "npctrl npctrl2", "Next 100 pages", Glob +"npNext100()"); }
btn(">|", "npLast", "npctrl", "Last page", Glob +"npLast()");
}
/**
* The underlying page is simply calculated from the button position/number added to the offset.
* But the numbers have to show on the button faces.
*/
function npMove(){
var n, styVal, theseDigits, diff;
for (var i=1; i <Btns.n +1; i +=1){
$(Btns.prefixx +i).value = i +Btns.offs;
$(Btns.prefixx +i).className = (i +Btns.offs === Btns.thispg)? "thispg" : "nppg";
}
}
/* not to move any number, just to set the thispg style if nec */
npMove();
/* Controls often tend to be simple covers/wrappers. No different here. */
function npNext(){
Btns.offs += Btns.n;
var d= Btns.offs +Btns.n >Pgs.n ? npLast() : npMove();
}
function npNext100(){
Btns.offs += 100;
var d= Btns.offs +Btns.n >Pgs.n ? npLast() : npMove();
}
function npPrev(){
Btns.offs = Btns.offs -Btns.n;
var d= Btns.offs <0 ? npFirst() : npMove();
}
function npPrev100(){
Btns.offs = Btns.offs -100;
var d= Btns.offs <0 ? npFirst() : npMove();
}
function npLast(){
Btns.offs = Pgs.n -Btns.n;
npMove();
}
function npFirst(){
Btns.offs = 0;
npMove();
}
function npLoc(btn){
if ( $("npb"+btn).className ==="thispg" ){ return; }
var pgNum = padit(Number(btn) +Btns.offs, Pgs.n, Pgs.forcepad);
location.href = "./" +Pgs.prefixx +pgNum +".htm";
}
/*************************** Utilities ***************************/
/* Since Stephenson's use in Prototype, the "$" function has become common, & usually much more elaborate than: */
function $(strID){
return document.getElementById(strID);
}
/**
* Simple left pad with zero.
* 'n' is the number to be padded, and 'max' is the maximum/largest number to be used (e.g. the last page).
* Neither n nor max are checked to see if they are numbers, but such could of course be added.
*
* forcepad is used to force left-zero padding even if not required.
* a forcepad = 10 through 90 would pad one left zero to the numbers 0-9.
* a forcepad of 100 through 990 would pad two left zeroes, 1000 - 9990 for three zeros, etc.
* One might be in the habit of padding with one zero, say, in anticipation of more than 10 pgs, even if a report doesn't run 10pgs.
*
* These are easily converted to string primitives, but a math formula, shown, could achieve the same thing.
*/
function padit(n, max, forcepad){
/* alternative: (0, int(abs(log(1/max+forcepad)))) &n */
return "0000000000000000000".substring(0, String(max+forcepad).length -String(n).length) +String(n);
}
/*
* standard new node function, adds a new HTML element with a particular id, if the id isn't already in use.
* strId must be specified.
* strObjSup is the id of the superior element to which to attach the new node/element
* strType is the type of element, 'div', 'span', etc.
* strArgs are the attributes for the element, each separated by, "<>".
* IE compatibility requires all values be single quoted, but not for events (on_, etc), so an example:
* ["class='",someClass,"'<>title='",someTitle,"'<>onclick=","func(){}","<>style='",styles,"'"].join("")
*/
function addNode(strId, strObjSup, strType, strArgs){
if (!$(strId)){
var arArgs, arAttr, namAttr, valAttr, objnode;
var objElmt = (strObjSup ==="HEAD0") ? document.documentElement : $(strObjSup);
if (isIE6){
/* Broken IE6 DOM, run everything through createElement. */
strArgs = (typeof strArgs ==="undefined") ? "" : " " +strArgs.replace(/<>/g," ");
objnode = document.createElement("<" +strType +strArgs +">");
objnode.id = strId;
return objElmt.appendChild(objnode);
} else {
objnode = document.createElement(strType);
objnode.id = strId;
objnode = objElmt.appendChild(objnode);
if (typeof strArgs !=="undefined"){
arArgs = strArgs.split("<>");
for (var i=0; i <arArgs.length; i +=1){
namAttr = arArgs[i].split("=")[0];
valAttr = arArgs[i].split("=")[1];
/* not recommended to omit single quotes, they are required for the IE branch, above */
if (valAttr.substring(0,1)==="'"){ valAttr = valAttr.substring(1,valAttr.length-1); }
switch (namAttr){
case "style":
arAttr = valAttr.split(";");
for (var j=0; j <arAttr.length; j +=1){
objnode.style[arAttr[j].split(":")[0]] =arAttr[j].split(":")[1];
}
break;
default:
objnode.setAttribute(namAttr, valAttr);
}
}
}
return objnode;
}
}
return null;
}
/**
* The next two split the scalar from its dimension label, and return both.
*
* If more than one dimension is found in the loop, it's probably a bad strValDim and garbage will be returned.
* But the only check for this, in splitWhDim, is to see if the dimension label is the last thing in strValDim.
* In that's not the case, then "unk" is returned as the dimension. And the caller will have to check that.
*/
function splitDim(strValDim){
var sd;
var dims = ["em", "px", "in", "%"];
for (var i=0; i <dims.length; i +=1){ if (strValDim.indexOf(dims[i]) !== -1){ sd =splitWhDim(strValDim, dims[i]); } }
return {valu: sd.valu, dimen: sd.dimen};
}
function splitWhDim(strValDim, strDim){
var valu, dimen;
strValDim.replace(/ /g,"");
if (strValDim.indexOf(strDim) !==-1){
valu = strValDim.split(strDim)[0];
dimen = (strValDim.split(strDim)[1].length ===0) ? strDim : "unk";
}
return {valu: valu, dimen: dimen};
}
/* The standard getRule function. Returns - array of same 'rule's. Specific styles are then found as rule[i].style.whatever . */
function classObj(clasName){
var d =document, k, m, nRules, arSty, aRule, arRtn =[ ];
var flgR = !!d.styleSheets[0].rules;
for (var j=0; j <d.styleSheets.length; j +=1) {
nRules = flgR ? d.styleSheets[j].rules : d.styleSheets[j].cssRules;
for (k=0; k <nRules.length; k +=1) {
aRule = flgR ? d.styleSheets[j].rules[k] : d.styleSheets[j].cssRules[k];
arSty = aRule.selectorText.replace(/ /g,"").split(",");
for (m=0; m <arSty.length; m +=1) {
if (arSty[m] === '.' + clasName) {
arRtn.push(aRule); }}}}
return arRtn;
}
})();
// -->
</script>
</body>
</html>