[open-ils-commits] r746 - in conifer/trunk/web/opac/skin/uwin: js local/images xml xml/rdetail (gliu)
svn at svn.open-ils.org
svn at svn.open-ils.org
Sun Dec 13 21:19:34 EST 2009
Author: gliu
Date: 2009-12-13 21:19:33 -0500 (Sun, 13 Dec 2009)
New Revision: 746
Added:
conifer/trunk/web/opac/skin/uwin/js/check_sfx.js
conifer/trunk/web/opac/skin/uwin/js/rdetail_custom.js
conifer/trunk/web/opac/skin/uwin/js/xregexp.js
conifer/trunk/web/opac/skin/uwin/local/images/sfx_button.gif
Modified:
conifer/trunk/web/opac/skin/uwin/js/rdetail.js
conifer/trunk/web/opac/skin/uwin/xml/page_rdetail.xml
conifer/trunk/web/opac/skin/uwin/xml/rdetail/rdetail_summary.xml
Log:
SFX customization
Added: conifer/trunk/web/opac/skin/uwin/js/check_sfx.js
===================================================================
--- conifer/trunk/web/opac/skin/uwin/js/check_sfx.js (rev 0)
+++ conifer/trunk/web/opac/skin/uwin/js/check_sfx.js 2009-12-14 02:19:33 UTC (rev 746)
@@ -0,0 +1,102 @@
+/**
+ Functions to build SFX url and check holdings in SFX for the current record
+ 2009 Guoying Liu
+ */
+
+//For now, only valid ISSN enables SFX button
+function rdetailShowSFXButton( issnText ){
+ if (document.getElementById("rdetail_sfx_check"))
+ if( build_sfx_url(issnText) )
+ unHideMe($("rdetail_sfx_check"));
+}
+
+//Build SFX url based on ISSN, return true if the url is successfully built
+//issnText can be retrieved from marcrec_State_Change, so simply pass it
+function build_sfx_url( issnText ) {
+ issnText = cleanText(issnText, " ")
+
+ if (issnText == "")
+ return false;
+
+ var http_str = "http://sfx.scholarsportal.info/windsor-default?url_ver=Z39.88-2004"
+ + "&url_ctx_fmt=infofi/fmt:kev:mtx:ctx&ctx_enc=info:ofi/enc:UTF-8&ctx_ver=Z39.88-2004"
+ + "&rfr_id=info:sid/sfxit.com:azlist&sfx.ignore_date_threshold=1"
+ + "&rft.issn=" + escape( issnText )
+
+ var issnCheck = $("rdetail_sfx_check");
+ issnCheck.setAttribute(
+ "href",
+ http_str
+ );
+ issnCheck.setAttribute("target", "SFXWindow");
+
+ return true;
+}
+
+/* As directly retrieving ISSN text from marcrec_State_Change, following ISSN or MARC related methods are obsolete
+ but may be useful for some other MARC data field customizations
+ */
+//only return first ISSN subfield value with code "a"
+function getMarcDataISSNText(){
+ var issnItems = getMarcDataFieldItems("022");
+ if (issnItems == null)
+ return "";
+
+ //only retrieve code a subfiled for the first ISSN
+ var issnSubfildItems = getMarcSubFieldItems(issnItems[0],"a");
+ if (issnSubfildItems == null)
+ return "";
+
+ //only return first subfield value with code "a"
+ return getISSNText(issnSubfildItems[0]);
+}
+
+function getMarcDataFieldItems( dataFieldTag ) {
+ var marcItems;
+ var MARCXML;
+
+ MARCXML = MARCRequest.responseXML;
+
+ if ( MARCXML == null )
+ return null;
+
+ //Marc data tag always 3 digits long.
+ if (dataFieldTag.length != 3)
+ return null;
+
+ //for MARC21, 00X: control fields, others are data fields
+ if ((dataFieldTag.charAt(0) == "0") && (dataFieldTag.charAt(1) == "0"))
+ marcItems = getElementsByAttribute( MARCXML, "controlfield", "tag", dataFieldTag );
+ else
+ marcItems = getElementsByAttribute( MARCXML, "datafield", "tag", dataFieldTag );
+
+ return marcItems;
+}
+
+//passing the parent item and subfield code, if code not set, return all code
+function getMarcSubFieldItems( dataFieldItem, strSubFieldCode ) {
+ return getElementsByAttribute( dataFieldItem, "subfield", "code", ( strSubFieldCode != null ? strSubFieldCode : "*" ) );
+}
+
+function getISSNText( issnElement ) {
+// if (BrowserDetect.browser == "Explorer"){
+ if (navigator.appName == "Microsoft Internet Explorer"){
+ return cleanText(dojox.data.dom.textContent( issnElement ), " ");
+ }else {
+ return cleanText(issnElement.textContent, " ");
+ }
+}
+
+/* Clean text, trim beginning space, and only return a substring from beginning till the Delimiter
+ The Delimiter can be a character or a string
+ */
+function cleanText(fullText, seperator) {
+ if(fullText) {
+ fullText= fullText.toString().replace(/^\s+/,"");
+ var idx = fullText.indexOf(seperator);
+ if(idx > -1) { fullText = fullText.substring(0, idx); }
+ } else
+ fullText = "";
+
+ return fullText;
+}
\ No newline at end of file
Modified: conifer/trunk/web/opac/skin/uwin/js/rdetail.js
===================================================================
--- conifer/trunk/web/opac/skin/uwin/js/rdetail.js 2009-12-14 00:35:39 UTC (rev 745)
+++ conifer/trunk/web/opac/skin/uwin/js/rdetail.js 2009-12-14 02:19:33 UTC (rev 746)
@@ -298,7 +298,14 @@
G.ui.rdetail.title.appendChild(text(record.title()));
buildSearchLink(STYPE_AUTHOR, record.author(), G.ui.rdetail.author);
- G.ui.rdetail.isbn.appendChild(text(cleanISBN(record.isbn())));
+// G.ui.rdetail.isbn.appendChild(text(cleanISBN(record.isbn())));
+ var isbnText= text(cleanISBN(record.isbn()));
+ if (isbnText != null){
+ if (isbnText.length > 0){
+ G.ui.rdetail.isbn.appendChild(isbnText);
+ unHideMe($('rdetail_isbn_row'));
+ }
+ }
G.ui.rdetail.edition.appendChild(text(record.edition()));
G.ui.rdetail.pubdate.appendChild(text(record.pubdate()));
G.ui.rdetail.publisher.appendChild(text(record.publisher()));
@@ -411,6 +418,8 @@
// grab added content
acCollectData(cleanISBN(record.isbn()), rdetailhandleAC);
+
+ rdetailShowCustomizedMARCs ();
}
Added: conifer/trunk/web/opac/skin/uwin/js/rdetail_custom.js
===================================================================
--- conifer/trunk/web/opac/skin/uwin/js/rdetail_custom.js (rev 0)
+++ conifer/trunk/web/opac/skin/uwin/js/rdetail_custom.js 2009-12-14 02:19:33 UTC (rev 746)
@@ -0,0 +1,152 @@
+/**
+ Customizing MARC record data fields based on Alexander O'Neill's work
+ 2009 Guoying Liu
+ */
+
+function rdetailShowCustomizedMARCs( ) {
+ loadMARCRecord();
+}
+
+var MARCRequest;
+var marctags;
+var firstResultRow;
+
+function loadMARCRecord( ) {
+ MARCRequest = null;
+
+ // Code for all new browsers
+ if (window.XMLHttpRequest)
+ MARCRequest = new XMLHttpRequest();
+ // Code for IE 5 and 6
+ else if ( window.ActiveXObject )
+ MARCRequest = new ActiveXObject( "Microsoft.XMLHTTP" );
+
+ if ( MARCRequest != null ) {
+ MARCRequest.onreadystatechange = marcrec_State_Change;
+ MARCRequest.open( "GET", "/opac/extras/supercat/retrieve/marcxml/record/" + record.doc_id(), true );
+ MARCRequest.send(null);
+ }
+}
+
+function marcrec_State_Change() {
+ var hasFirstISSN = false;
+
+ // 4 means "loaded"
+ if ( MARCRequest.readyState == 4 ) {
+ // 200 means "OK"
+ if ( MARCRequest.status == 200 ) {
+ marctags = document.getElementsByTagName("MARC");
+
+ for ( i = 0; i < marctags.length; i++ ) {
+ dataField = marctags.item(i).getAttribute('dataField');
+ controlField = marctags.item(i).getAttribute('controlField');
+ marcItems = getElementsByAttribute( MARCRequest.responseXML, 'controlfield', 'tag', controlField );
+
+ if ( marcItems.length > 0 ) {
+ // This is a control field, which has no subfields, rather than a data field.
+ itemString = getText( marcItems[0] );
+ currentField = document.createElement( 'span' );
+
+ setText( currentField, itemString );
+ marctags[i].parentNode.appendChild( currentField );
+ continue;
+ }
+ marcItems = getElementsByAttribute( MARCRequest.responseXML, 'datafield', 'tag', dataField );
+
+ buildSearchString = ( marctags[i].getAttribute( 'searchfield' ) != null ? true : false );
+
+ for ( j = 0; j < marcItems.length; j++ ) {
+ nextItem = getElementsByAttribute( marcItems[j], 'subfield', 'code', ( marctags[i].getAttribute('subfield') != null ? marctags[i].getAttribute('subfield') : '*' ) );
+
+ for ( k = 0; k < nextItem.length; k++ ) {
+ itemString = nextItem[k].firstChild.nodeValue;
+ currentSubField = document.createElement( (buildSearchString ? 'a' : 'span') );
+ setText( currentSubField, itemString );
+ marctags[i].parentNode.appendChild( currentSubField );
+
+ //show SFX Button if dataField "022" has value;
+ if (dataField == "022"){
+ if(hasFirstISSN == false){
+ rdetailShowSFXButton( itemString );
+ hasFirstISSN = true;
+ }
+ }
+
+ if ( buildSearchString ) {
+ href = '../xml/rresult.xml?rt=' + marctags[i].getAttribute('searchfield') + '&tp=' + marctags[i].getAttribute('searchfield') + '&t=';
+
+ for ( l = 0; l <= k; l++ ) {
+ href += nextItem[l].firstChild.nodeValue + '%20'; // it's ok to have a space at the end.
+ }
+ href += '&l=1&d=0&f=&av=';
+ currentSubField.setAttribute('href', href);
+ currentSubField.setAttribute('title', 'Perform a search on this subject' );
+ }
+
+ separatorItem = document.createElement('span');
+
+ if ( k < nextItem.length - 1) {
+ setText( separatorItem, ( marctags[i].getAttribute('separator') != null ? ' ' + marctags[i].getAttribute('separator') + ' ' : ' ' ) );
+ marctags[i].parentNode.appendChild( separatorItem );
+ } else {
+ if ( marctags[i].getAttribute( 'newline' ) != null ) {
+ if ( marctags[i].getAttribute( 'newline' ) == 'no' ){
+ setText( separatorItem, ' ' );
+ marctags[i].parentNode.appendChild( separatorItem );
+ } else {
+ marctags[i].parentNode.appendChild( document.createElement('br') );
+ }
+ } else {
+ marctags[i].parentNode.appendChild( document.createElement('br') );
+ }
+ }
+ }//for k
+
+ } // for j
+ if ( getText(marctags[i].parentNode).replace(/^\s+|\s+$/g, '') == '' ) {
+ hideMe(marctags[i].parentNode.parentNode);
+ }
+ }
+ }
+ }
+}
+
+function getElementsByAttribute(oElm, strTagName, strAttributeName, strAttributeValue) {
+ var arrElements = oElm.getElementsByTagName(strTagName );
+ var arrReturnElements = new Array();
+ var oAttributeValue = new XRegExp( "(^|\\s)" + strAttributeValue + "(\\s|$)", "i" );
+ var oCurrent;
+ var oAttribute;
+
+ for ( var i=0; i < arrElements.length; i++ ) {
+ oCurrent = arrElements[i];
+ oAttribute = oCurrent.getAttribute( strAttributeName );
+ if( oAttribute != null && oAttribute.length > 0)
+ if( oAttributeValue && oAttributeValue.test( oAttribute ) )
+ arrReturnElements.push(oCurrent);
+ }
+ return arrReturnElements;
+}
+
+function getText( control ) {
+ if ( control == null )
+ return '';
+
+ if (document.all)
+ return control.innerText;
+ else
+ return trimStr(control.textContent);
+}
+
+function setText(control, value) {
+ if (document.all)
+ control.innerText = value;
+ else
+ control.textContent = value;
+}
+
+function trimStr( str ) {
+ if (str == null)
+ return '';
+ return str.replace(/^\s+|\s+$/g, '');
+}
Added: conifer/trunk/web/opac/skin/uwin/js/xregexp.js
===================================================================
--- conifer/trunk/web/opac/skin/uwin/js/xregexp.js (rev 0)
+++ conifer/trunk/web/opac/skin/uwin/js/xregexp.js 2009-12-14 02:19:33 UTC (rev 746)
@@ -0,0 +1,515 @@
+/*
+ XRegExp 0.6.1
+ (c) 2007-2008 Steven Levithan
+ <http://stevenlevithan.com/regex/xregexp/>
+ MIT License
+*/
+
+/** provides an augmented, cross-browser implementation of regular expressions
+ including support for additional modifiers and syntax. several convenience
+ methods and a recursive-construct parser are also included.
+*/
+
+// prevent running twice, which would break references to native globals
+if (!window.XRegExp) {
+// anonymous function to avoid global variables
+(function () {
+// copy various native globals for reference. can't use the name ``native``
+// because it's a reserved JavaScript keyword.
+var real = {
+ exec: RegExp.prototype.exec,
+ match: String.prototype.match,
+ replace: String.prototype.replace,
+ split: String.prototype.split
+ },
+ /* regex syntax parsing with support for all the necessary cross-
+ browser and context issues (escapings, character classes, etc.) */
+ lib = {
+ part: /(?:[^\\([#\s.]+|\\(?!k<[\w$]+>|[pP]{[^}]+})[\S\s]?|\((?=\?(?!#|<[\w$]+>)))+|(\()(?:\?(?:(#)[^)]*\)|<([$\w]+)>))?|\\(?:k<([\w$]+)>|[pP]{([^}]+)})|(\[\^?)|([\S\s])/g,
+ replaceVar: /(?:[^$]+|\$(?![1-9$&`']|{[$\w]+}))+|\$(?:([1-9]\d*|[$&`'])|{([$\w]+)})/g,
+ extended: /^(?:\s+|#.*)+/,
+ quantifier: /^(?:[?*+]|{\d+(?:,\d*)?})/,
+ classLeft: /&&\[\^?/g,
+ classRight: /]/g
+ },
+ indexOf = function (array, item, from) {
+ for (var i = from || 0; i < array.length; i++)
+ if (array[i] === item) return i;
+ return -1;
+ },
+ brokenExecUndef = /()??/.exec("")[1] !== undefined,
+ plugins = {};
+
+/*** XRegExp
+ accepts a pattern and flags, returns a new, extended RegExp object.
+ differs from a native regex in that additional flags and syntax are
+ supported and browser inconsistencies are ameliorated.
+*/
+XRegExp = function (pattern, flags) {
+ if (pattern instanceof RegExp) {
+ if (flags !== undefined)
+ throw TypeError("can't supply flags when constructing one RegExp from another");
+ return pattern.addFlags(); // new copy
+ }
+
+ var flags = flags || "",
+ singleline = flags.indexOf("s") > -1,
+ extended = flags.indexOf("x") > -1,
+ hasNamedCapture = false,
+ captureNames = [],
+ output = [],
+ part = lib.part,
+ match, cc, len, index, regex;
+
+ part.lastIndex = 0; // in case the last XRegExp compilation threw an error (unbalanced character class)
+
+ while (match = real.exec.call(part, pattern)) {
+ // comment pattern. this check must come before the capturing group check,
+ // because both match[1] and match[2] will be non-empty.
+ if (match[2]) {
+ // keep tokens separated unless the following token is a quantifier
+ if (!lib.quantifier.test(pattern.slice(part.lastIndex)))
+ output.push("(?:)");
+ // capturing group
+ } else if (match[1]) {
+ captureNames.push(match[3] || null);
+ if (match[3])
+ hasNamedCapture = true;
+ output.push("(");
+ // named backreference
+ } else if (match[4]) {
+ index = indexOf(captureNames, match[4]);
+ // keep backreferences separate from subsequent literal numbers
+ // preserve backreferences to named groups that are undefined at this point as literal strings
+ output.push(index > -1 ?
+ "\\" + (index + 1) + (isNaN(pattern.charAt(part.lastIndex)) ? "" : "(?:)") :
+ match[0]
+ );
+ // unicode element (requires plugin)
+ } else if (match[5]) {
+ output.push(plugins.unicode ?
+ plugins.unicode.get(match[5], match[0].charAt(1) === "P") :
+ match[0]
+ );
+ // character class opening delimiter ("[" or "[^")
+ // (non-native unicode elements are not supported within character classes)
+ } else if (match[6]) {
+ if (pattern.charAt(part.lastIndex) === "]") {
+ // for cross-browser compatibility with ECMA-262 v3 behavior,
+ // convert [] to (?!) and [^] to [\S\s].
+ output.push(match[6] === "[" ? "(?!)" : "[\\S\\s]");
+ part.lastIndex++;
+ } else {
+ // parse the character class with support for inner escapes and
+ // ES4's infinitely nesting intersection syntax ([&&[^&&[]]]).
+ cc = XRegExp.matchRecursive("&&" + pattern.slice(match.index), lib.classLeft, lib.classRight, "", {escapeChar: "\\"})[0];
+ output.push(match[6] + cc + "]");
+ part.lastIndex += cc.length + 1;
+ }
+ // dot ("."), pound sign ("#"), or whitespace character
+ } else if (match[7]) {
+ if (singleline && match[7] === ".") {
+ output.push("[\\S\\s]");
+ } else if (extended && lib.extended.test(match[7])) {
+ len = real.exec.call(lib.extended, pattern.slice(part.lastIndex - 1))[0].length;
+ // keep tokens separated unless the following token is a quantifier
+ if (!lib.quantifier.test(pattern.slice(part.lastIndex - 1 + len)))
+ output.push("(?:)");
+ part.lastIndex += len - 1;
+ } else {
+ output.push(match[7]);
+ }
+ } else {
+ output.push(match[0]);
+ }
+ }
+
+ regex = RegExp(output.join(""), real.replace.call(flags, /[sx]+/g, ""));
+ regex._x = {
+ source: pattern,
+ captureNames: hasNamedCapture ? captureNames : null
+ };
+ return regex;
+};
+
+// barebones plugin support for now (intentionally undocumented)
+XRegExp.addPlugin = function (name, o) {
+ plugins[name] = o;
+};
+
+/*** RegExp.prototype.exec
+ adds named capture support, with values returned as ``result.name``.
+ also fixes two cross-browser issues, following the ECMA-262 v3 spec:
+ - captured values for non-participating capturing groups should be returned
+ as ``undefined``, rather than the empty string.
+ - the regex's ``lastIndex`` should not be incremented after zero-length
+ matches.
+*/
+RegExp.prototype.exec = function (str) {
+ var match = real.exec.call(this, str),
+ name, i, r2;
+ if (match) {
+ // fix browsers whose exec methods don't consistently return
+ // undefined for non-participating capturing groups
+ if (brokenExecUndef && match.length > 1) {
+ // r2 doesn't need /g or /y, but they shouldn't hurt
+ r2 = new RegExp("^" + this.source + "$(?!\\s)", this.getNativeFlags());
+ real.replace.call(match[0], r2, function () {
+ for (i = 1; i < arguments.length - 2; i++) {
+ if (arguments[i] === undefined) match[i] = undefined;
+ }
+ });
+ }
+ // attach named capture properties
+ if (this._x && this._x.captureNames) {
+ for (i = 1; i < match.length; i++) {
+ name = this._x.captureNames[i - 1];
+ if (name) match[name] = match[i];
+ }
+ }
+ // fix browsers that increment lastIndex after zero-length matches
+ if (this.global && this.lastIndex > (match.index + match[0].length))
+ this.lastIndex--;
+ }
+ return match;
+};
+
+/*** String.prototype.match
+ run the altered ``exec`` when called with a non-global regex.
+*/
+String.prototype.match = function (regex) {
+ if (!(regex instanceof RegExp))
+ regex = new XRegExp(regex);
+ if (regex.global)
+ return real.match.call(this, regex);
+ return regex.exec(this); // run the altered exec
+};
+
+/*** String.prototype.replace
+ add named capture support to replacement strings using the syntax
+ ``${name}``, and to replacement functions as ``arguments[0].name``.
+*/
+String.prototype.replace = function (search, replacement) {
+ var captureNames = (search._x || {}).captureNames;
+
+ // if search is not a regex which uses named capture, use the native replace method
+ if (!(search instanceof RegExp && captureNames))
+ return real.replace.apply(this, arguments);
+
+ if (typeof replacement === "function") {
+ return real.replace.call(this, search, function () {
+ // change the arguments[0] string primitive to a String object which can store properties
+ arguments[0] = new String(arguments[0]);
+ // store named backreferences on arguments[0] before calling replacement
+ for (var i = 0; i < captureNames.length; i++) {
+ if (captureNames[i])
+ arguments[0][captureNames[i]] = arguments[i + 1];
+ }
+ return replacement.apply(window, arguments);
+ });
+ } else {
+ return real.replace.call(this, search, function () {
+ var args = arguments;
+ return real.replace.call(replacement, lib.replaceVar, function ($0, $1, $2) {
+ // numbered backreference or special variable
+ if ($1) {
+ switch ($1) {
+ case "$": return "$";
+ case "&": return args[0];
+ case "`": return args[args.length - 1].slice(0, args[args.length - 2]);
+ case "'": return args[args.length - 1].slice(args[args.length - 2] + args[0].length);
+ // numbered backreference
+ default:
+ /* what does "$10" mean?
+ - backreference 10, if 10 or more capturing groups exist
+ - backreference 1 followed by "0", if 1-9 capturing groups exist
+ - otherwise, it's the string "$10"
+ */
+ var literalNumbers = "";
+ $1 = +$1; // type-convert
+ while ($1 > captureNames.length) {
+ literalNumbers = real.split.call($1, "").pop() + literalNumbers;
+ $1 = Math.floor($1 / 10); // drop the last digit
+ }
+ return ($1 ? args[$1] : "$") + literalNumbers;
+ }
+ // named backreference
+ } else if ($2) {
+ /* what does "${name}" mean?
+ - backreference to named capture "name", if it exists
+ - otherwise, it's the string "${name}"
+ */
+ var index = indexOf(captureNames, $2);
+ return index > -1 ? args[index + 1] : $0;
+ } else {
+ return $0;
+ }
+ });
+ });
+ }
+};
+
+/*** String.prototype.split
+ a consistent cross-browser, ECMA-262 v3 compliant split method
+*/
+String.prototype.split = function (s /* separator */, limit) {
+ // if separator is not a regex, use the native split method
+ if (!(s instanceof RegExp))
+ return real.split.apply(this, arguments);
+
+ var output = [],
+ origLastIndex = s.lastIndex,
+ lastLastIndex = 0,
+ i = 0, match, lastLength;
+
+ /* behavior for limit: if it's...
+ - undefined: no limit
+ - NaN or zero: return an empty array
+ - a positive number: use limit after dropping any decimal
+ - a negative number: no limit
+ - other: type-convert, then use the above rules
+ */
+ if (limit === undefined || +limit < 0) {
+ limit = false;
+ } else {
+ limit = Math.floor(+limit);
+ if (!limit)
+ return [];
+ }
+
+ if (s.global)
+ s.lastIndex = 0;
+ else
+ s = s.addFlags("g");
+
+ while ((!limit || i++ <= limit) && (match = s.exec(this))) { // run the altered exec!
+ if (s.lastIndex > lastLastIndex) {
+ output = output.concat(this.slice(lastLastIndex, match.index));
+ if (1 < match.length && match.index < this.length)
+ output = output.concat(match.slice(1));
+ lastLength = match[0].length; // only needed if s.lastIndex === this.length
+ lastLastIndex = s.lastIndex;
+ }
+ if (!match[0].length)
+ s.lastIndex++; // avoid an infinite loop
+ }
+
+ // since this uses test(), output must be generated before restoring lastIndex
+ output = lastLastIndex === this.length ?
+ (s.test("") && !lastLength ? output : output.concat("")) :
+ (limit ? output : output.concat(this.slice(lastLastIndex)));
+ s.lastIndex = origLastIndex; // only needed if s.global, else we're working with a copy of the regex
+ return output;
+};
+})(); // end anonymous function
+} // end if(!window.XRegExp)
+
+// intentionally undocumented
+RegExp.prototype.getNativeFlags = function () {
+ return (this.global ? "g" : "") +
+ (this.ignoreCase ? "i" : "") +
+ (this.multiline ? "m" : "") +
+ (this.extended ? "x" : "") +
+ (this.sticky ? "y" : "");
+};
+
+/*** RegExp.prototype.addFlags
+ accepts flags; returns a new XRegExp object generated by recompiling
+ the regex with the additional flags (may include non-native flags).
+ the original regex object is not altered.
+*/
+RegExp.prototype.addFlags = function (flags) {
+ var regex = new XRegExp(this.source, (flags || "") + this.getNativeFlags());
+ if (this._x) {
+ regex._x = {
+ source: this._x.source,
+ captureNames: this._x.captureNames ? this._x.captureNames.slice(0) : null
+ };
+ }
+ return regex;
+};
+
+/*** RegExp.prototype.call
+ accepts a context object and string; returns the result of calling
+ ``exec`` with the provided string. the context is ignored but is
+ accepted for congruity with ``Function.prototype.call``.
+*/
+RegExp.prototype.call = function (context, str) {
+ return this.exec(str);
+};
+
+/*** RegExp.prototype.apply
+ accepts a context object and arguments array; returns the result of
+ calling ``exec`` with the first value in the arguments array. the context
+ is ignored but is accepted for congruity with ``Function.prototype.apply``.
+*/
+RegExp.prototype.apply = function (context, args) {
+ return this.exec(args[0]);
+};
+
+/*** XRegExp.cache
+ accepts a pattern and flags; returns an XRegExp object. if the pattern
+ and flag combination has previously been cached, the cached copy is
+ returned, otherwise the new object is cached.
+*/
+XRegExp.cache = function (pattern, flags) {
+ var key = "/" + pattern + "/" + (flags || "");
+ return XRegExp.cache[key] || (XRegExp.cache[key] = new XRegExp(pattern, flags));
+};
+
+/*** XRegExp.escape
+ accepts a string; returns the string with regex metacharacters escaped.
+ the returned string can safely be used within a regex to match a literal
+ string. escaped characters are [, ], {, }, (, ), -, *, +, ?, ., \, ^, $,
+ |, #, [comma], and whitespace.
+*/
+XRegExp.escape = function (str) {
+ return str.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&");
+};
+
+/*** XRegExp.matchRecursive
+ accepts a string to search, left and right delimiters as regex pattern
+ strings, optional regex flags (may include non-native s, x, and y flags),
+ and an options object which allows setting an escape character and changing
+ the return format from an array of matches to a two-dimensional array of
+ string parts with extended position data. returns an array of matches
+ (optionally with extended data), allowing nested instances of left and right
+ delimiters. use the g flag to return all matches, otherwise only the first
+ is returned. if delimiters are unbalanced within the subject data, an error
+ is thrown.
+
+ this function admittedly pushes the boundaries of what can be accomplished
+ sensibly without a "real" parser. however, by doing so it provides flexible
+ and powerful recursive parsing capabilities with minimal code weight.
+
+ warning: the ``escapeChar`` option is considered experimental and might be
+ changed or removed in future versions of XRegExp.
+
+ unsupported features:
+ - backreferences within delimiter patterns when using ``escapeChar``.
+ - although providing delimiters as regex objects adds the minor feature of
+ independent delimiter flags, it introduces other limitations and is only
+ intended to be done by the ``XRegExp`` constructor (which can't call
+ itself while building a regex).
+*/
+XRegExp.matchRecursive = function (str, left, right, flags, options) {
+ var options = options || {},
+ escapeChar = options.escapeChar,
+ vN = options.valueNames,
+ flags = flags || "",
+ global = flags.indexOf("g") > -1,
+ ignoreCase = flags.indexOf("i") > -1,
+ multiline = flags.indexOf("m") > -1,
+ sticky = flags.indexOf("y") > -1,
+ /* sticky mode has its own handling in this function, which means you
+ can use flag "y" even in browsers which don't support it natively */
+ flags = flags.replace(/y/g, ""),
+ left = left instanceof RegExp ? (left.global ? left : left.addFlags("g")) : new XRegExp(left, "g" + flags),
+ right = right instanceof RegExp ? (right.global ? right : right.addFlags("g")) : new XRegExp(right, "g" + flags),
+ output = [],
+ openTokens = 0,
+ delimStart = 0,
+ delimEnd = 0,
+ lastOuterEnd = 0,
+ outerStart, innerStart, leftMatch, rightMatch, escaped, esc;
+
+ if (escapeChar) {
+ if (escapeChar.length > 1) throw SyntaxError("can't supply more than one escape character");
+ if (multiline) throw TypeError("can't supply escape character when using the multiline flag");
+ escaped = XRegExp.escape(escapeChar);
+ /* Escape pattern modifiers:
+ /g - not needed here
+ /i - included
+ /m - **unsupported**, throws error
+ /s - handled by XRegExp when delimiters are provided as strings
+ /x - handled by XRegExp when delimiters are provided as strings
+ /y - not needed here; supported by other handling in this function
+ */
+ esc = new RegExp(
+ "^(?:" + escaped + "[\\S\\s]|(?:(?!" + left.source + "|" + right.source + ")[^" + escaped + "])+)+",
+ ignoreCase ? "i" : ""
+ );
+ }
+
+ while (true) {
+ /* advance the starting search position to the end of the last delimiter match.
+ a couple special cases are also covered:
+ - if using an escape character, advance to the next delimiter's starting position,
+ skipping any escaped characters
+ - first time through, reset lastIndex in case delimiters were provided as regexes
+ */
+ left.lastIndex = right.lastIndex = delimEnd +
+ (escapeChar ? (esc.exec(str.slice(delimEnd)) || [""])[0].length : 0);
+
+ leftMatch = left.exec(str);
+ rightMatch = right.exec(str);
+
+ // only keep the result which matched earlier in the string
+ if (leftMatch && rightMatch) {
+ if (leftMatch.index <= rightMatch.index)
+ rightMatch = null;
+ else leftMatch = null;
+ }
+
+ /* paths*:
+ leftMatch | rightMatch | openTokens | result
+ 1 | 0 | 1 | ...
+ 1 | 0 | 0 | ...
+ 0 | 1 | 1 | ...
+ 0 | 1 | 0 | throw
+ 0 | 0 | 1 | throw
+ 0 | 0 | 0 | break
+ * - does not include the sticky mode special case
+ - the loop ends after the first completed match if not in global mode
+ */
+
+ if (leftMatch || rightMatch) {
+ delimStart = (leftMatch || rightMatch).index;
+ delimEnd = (leftMatch ? left : right).lastIndex;
+ } else if (!openTokens) {
+ break;
+ }
+
+ if (sticky && !openTokens && delimStart > lastOuterEnd)
+ break;
+
+ if (leftMatch) {
+ if (!openTokens++) {
+ outerStart = delimStart;
+ innerStart = delimEnd;
+ }
+ } else if (rightMatch && openTokens) {
+ if (!--openTokens) {
+ if (vN) {
+ if (vN[0] && outerStart > lastOuterEnd)
+ output.push([vN[0], str.slice(lastOuterEnd, outerStart), lastOuterEnd, outerStart]);
+ if (vN[1]) output.push([vN[1], str.slice(outerStart, innerStart), outerStart, innerStart]);
+ if (vN[2]) output.push([vN[2], str.slice(innerStart, delimStart), innerStart, delimStart]);
+ if (vN[3]) output.push([vN[3], str.slice(delimStart, delimEnd), delimStart, delimEnd]);
+ } else {
+ output.push(str.slice(innerStart, delimStart));
+ }
+ lastOuterEnd = delimEnd;
+ if (!global)
+ break;
+ }
+ } else {
+ // reset lastIndex in case delimiters were provided as regexes
+ left.lastIndex = right.lastIndex = 0;
+ throw Error("subject data contains unbalanced delimiters");
+ }
+
+ // if the delimiter matched an empty string, advance delimEnd to avoid an infinite loop
+ if (delimStart === delimEnd)
+ delimEnd++;
+ }
+
+ if (global && !sticky && vN && vN[0] && str.length > lastOuterEnd)
+ output.push([vN[0], str.slice(lastOuterEnd), lastOuterEnd, str.length]);
+
+ // reset lastIndex in case delimiters were provided as regexes
+ left.lastIndex = right.lastIndex = 0;
+
+ return output;
+};
+
Added: conifer/trunk/web/opac/skin/uwin/local/images/sfx_button.gif
===================================================================
(Binary files differ)
Property changes on: conifer/trunk/web/opac/skin/uwin/local/images/sfx_button.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: conifer/trunk/web/opac/skin/uwin/xml/page_rdetail.xml
===================================================================
--- conifer/trunk/web/opac/skin/uwin/xml/page_rdetail.xml 2009-12-14 00:35:39 UTC (rev 745)
+++ conifer/trunk/web/opac/skin/uwin/xml/page_rdetail.xml 2009-12-14 02:19:33 UTC (rev 746)
@@ -7,6 +7,9 @@
<script language='javascript' type='text/javascript' src='<!--#echo var="OILS_OPAC_JS_HOST"-->/skin/uwin/js/holds.js'></script>
<script language='javascript' type='text/javascript' src='<!--#echo var="OILS_OPAC_JS_HOST"-->/skin/uwin/js/cn_browse.js'></script>
<script language='javascript' type='text/javascript' src='<!--#echo var="OILS_OPAC_JS_HOST"-->/skin/uwin/js/container.js'></script>
+ <script language='javascript' type='text/javascript' src='../js/rdetail_custom.js'></script>
+ <script language='javascript' type='text/javascript' src='../js/xregexp.js'></script>
+ <script language='javascript' type='text/javascript' src='../js/check_sfx.js'></script>
<script src='http://www.google.com/jsapi' type='text/javascript' language='javascript'></script>
<script type='text/javascript' src='http://books.google.com/books/api.js?key=notsupplied&v=0&callback=google.loader.callbacks.books'></script>
Modified: conifer/trunk/web/opac/skin/uwin/xml/rdetail/rdetail_summary.xml
===================================================================
--- conifer/trunk/web/opac/skin/uwin/xml/rdetail/rdetail_summary.xml 2009-12-14 00:35:39 UTC (rev 745)
+++ conifer/trunk/web/opac/skin/uwin/xml/rdetail/rdetail_summary.xml 2009-12-14 02:19:33 UTC (rev 746)
@@ -20,7 +20,9 @@
class='classic_link' id='rdetail.jacket_attrib_link'>&vendor.name;</a></div>
</div>
</td>
- <td nowrap='nowrap' class='rdetail_desc'>&common.title;</td>
+ <td nowrap='nowrap' class='rdetail_desc'>
+ <a style='float:right; white-space:nowrap;' class='hide_me' id='rdetail_sfx_check' title='Check All Holdings'>
+ <img border='0' target='_top' src='../local/images/sfx_button.gif' /></a>&common.title;</td>
<!-- *** Example of how to use the openils.BibTemplate infrastructure to augment the stock
*** summary screen with more and/or different information. In this case, the raw MARC 245. -->
<td type='opac/slot-data' query='datafield[tag=245]' class='rdetail_item' id='rdetail_title'> </td>
@@ -33,27 +35,36 @@
</td>
</tr>
- <tr>
+ <tr class='hide_me' id='rdetail_isbn_row'>
<td nowrap='nowrap' class='rdetail_desc'>&common.isbn;</td>
<td class='rdetail_item' id='rdetail_isbn'> </td>
</tr>
<tr>
+ <td nowrap='nowrap' class='rdetail_desc'>&common.issn;</td>
+ <td class='rdetail_item' id='rdetail_issn'><MARC datafield="022"></MARC></td>
+ </tr>
+
+ <tr>
<td nowrap='nowrap' class='rdetail_desc'>&common.edition;</td>
<td class='rdetail_item' id='rdetail_edition'> </td>
</tr>
<tr>
- <td nowrap='nowrap' class='rdetail_desc'>&common.pubdate;</td>
- <td class='rdetail_item' id='rdetail_pubdate'> </td>
+ <td nowrap='nowrap' class='rdetail_desc'>Place of Publication</td>
+ <td class='rdetail_item' id='rdetail_place_of_pub'><MARC datafield="260" subfield='a'></MARC></td>
</tr>
<tr>
- <td nowrap='nowrap' class='rdetail_desc'>&common.publisher;</td>
- <td type='opac/slot-data' query='datafield[tag=260]' class='rdetail_item' id='rdetail_publisher'> </td>
+ <td nowrap='nowrap' class='rdetail_desc'>&common.publisher;</td>
+ <td class='rdetail_item' id='rdetail_publisher'><MARC datafield="260" subfield='b'></MARC></td>
</tr>
+
+ <tr>
+ <td nowrap='nowrap' class='rdetail_desc'>&common.pubdate;</td>
+ <td class='rdetail_item' id='rdetail_pubdate'> </td>
+ </tr>
-
<tr>
<td nowrap='nowrap' class='rdetail_desc'>&common.physical;</td>
<td class='rdetail_item' id='rdetail_physical_desc'> </td>
More information about the open-ils-commits
mailing list