commit 233b9991f5503ee152890e60e776fcb444094ac9 parent 42673cb0a2632171d3c7337ca90ea3eddc99e17e Author: Dan Stillman <dstillman@zotero.org> Date: Wed, 24 Jun 2015 14:34:47 -0400 Merge pull request #623 from rmzelle/locale-selector Add drop-down menu for bibliographyLocale Diffstat:
23 files changed, 539 insertions(+), 209 deletions(-)
diff --git a/chrome/content/zotero/bibliography.js b/chrome/content/zotero/bibliography.js @@ -34,16 +34,13 @@ var Zotero_File_Interface_Bibliography = new function() { var _io, _saveStyle; - - this.init = init; - this.styleChanged = styleChanged; - this.acceptSelection = acceptSelection; + var lastSelectedLocale; // Only changes when explicitly selected /* * Initialize some variables and prepare event listeners for when chrome is done * loading */ - function init() { + this.init = function () { // Set font size from pref // Affects bibliography.xul and integrationDocPrefs.xul var bibContainer = document.getElementById("zotero-bibliography-container"); @@ -59,18 +56,18 @@ var Zotero_File_Interface_Bibliography = new function() { } var listbox = document.getElementById("style-listbox"); - var styles = Zotero.Styles.getVisible(); - // if no style is set, get the last style used + // if no style is requested, get the last style used if(!_io.style) { _io.style = Zotero.Prefs.get("export.lastStyle"); _saveStyle = true; } // add styles to list + var styles = Zotero.Styles.getVisible(); var index = 0; var nStyles = styles.length; - var selectIndex = -1; + var selectIndex = null; for(var i=0; i<nStyles; i++) { var itemNode = document.createElement("listitem"); itemNode.setAttribute("value", styles[i].styleID); @@ -83,14 +80,29 @@ var Zotero_File_Interface_Bibliography = new function() { index++; } - if (selectIndex < 1) { + let requestedLocale; + if (selectIndex === null) { + // Requested style not found in list, pre-select first style selectIndex = 0; + } else { + requestedLocale = _io.locale; + } + + let style = styles[selectIndex]; + lastSelectedLocale = Zotero.Prefs.get("export.lastLocale"); + if (requestedLocale && style && !style.locale) { + // pre-select supplied locale + lastSelectedLocale = requestedLocale; } + // add locales to list + Zotero.Styles.populateLocaleList(document.getElementById("locale-menu")); + // Has to be async to work properly window.setTimeout(function () { listbox.ensureIndexIsVisible(selectIndex); listbox.selectedIndex = selectIndex; + Zotero_File_Interface_Bibliography.styleChanged(); }, 0); // ONLY FOR bibliography.xul: export options @@ -149,22 +161,24 @@ var Zotero_File_Interface_Bibliography = new function() { // set style to false, in case this is cancelled _io.style = false; - } - + }; + + /* + * Called when locale is changed + */ + this.localeChanged = function (selectedValue) { + lastSelectedLocale = selectedValue; + }; + /* * Called when style is changed */ - function styleChanged(index) { - // When called from init(), selectedItem isn't yet set - if (index != undefined) { - var selectedItem = document.getElementById("style-listbox").getItemAtIndex(index); - } - else { - var selectedItem = document.getElementById("style-listbox").selectedItem; - } + this.styleChanged = function () { + var selectedItem = document.getElementById("style-listbox").selectedItem; + var selectedStyle = selectedItem.getAttribute('value'); + var selectedStyleObj = Zotero.Styles.get(selectedStyle); - var selectedStyle = selectedItem.getAttribute('value'), - selectedStyleObj = Zotero.Styles.get(selectedStyle); + updateLocaleMenu(selectedStyleObj); // // For integrationDocPrefs.xul @@ -195,20 +209,33 @@ var Zotero_File_Interface_Bibliography = new function() { // Change label to "Citation" or "Note" depending on style class if(document.getElementById("citations")) { + let label = ""; if(Zotero.Styles.get(selectedStyle).class == "note") { - var label = Zotero.getString('citation.notes'); + label = Zotero.getString('citation.notes'); } else { - var label = Zotero.getString('citation.citations'); + label = Zotero.getString('citation.citations'); } document.getElementById("citations").label = label; } window.sizeToContent(); + }; + + /* + * Update locale menulist when style is changed + */ + function updateLocaleMenu(selectedStyle) { + Zotero.Styles.updateLocaleList( + document.getElementById("locale-menu"), + selectedStyle, + lastSelectedLocale + ); } - function acceptSelection() { + this.acceptSelection = function () { // collect code - _io.style = document.getElementById("style-listbox").selectedItem.value; + _io.style = document.getElementById("style-listbox").value; + _io.locale = document.getElementById("locale-menu").value; if(document.getElementById("output-method-radio")) { // collect settings _io.mode = document.getElementById("output-mode-radio").selectedItem.id; @@ -235,5 +262,8 @@ var Zotero_File_Interface_Bibliography = new function() { if(_saveStyle) { Zotero.Prefs.set("export.lastStyle", _io.style); } - } -} -\ No newline at end of file + + // save locale + Zotero.Prefs.set("export.lastLocale", lastSelectedLocale); + }; +} diff --git a/chrome/content/zotero/bibliography.xul b/chrome/content/zotero/bibliography.xul @@ -17,6 +17,12 @@ <listbox id="style-listbox" onselect="Zotero_File_Interface_Bibliography.styleChanged()"/> </groupbox> <groupbox> + <hbox align="center"> + <caption label="&zotero.bibliography.locale.label;"/> + <menulist id="locale-menu" oncommand="Zotero_File_Interface_Bibliography.localeChanged(this.selectedItem.value)"/> + </hbox> + </groupbox> + <groupbox> <caption label="&zotero.bibliography.outputMode;"/> <radiogroup id="output-mode-radio"> <radio id="citations"/> diff --git a/chrome/content/zotero/fileInterface.js b/chrome/content/zotero/fileInterface.js @@ -420,15 +420,15 @@ var Zotero_File_Interface = new function() { * * Does not check that items are actual references (and not notes or attachments) */ - function copyItemsToClipboard(items, style, asHTML, asCitations) { + function copyItemsToClipboard(items, style, locale, asHTML, asCitations) { // copy to clipboard var transferable = Components.classes["@mozilla.org/widget/transferable;1"]. createInstance(Components.interfaces.nsITransferable); var clipboardService = Components.classes["@mozilla.org/widget/clipboard;1"]. getService(Components.interfaces.nsIClipboard); var style = Zotero.Styles.get(style); - var cslEngine = style.getCiteProc(); - + var cslEngine = style.getCiteProc(locale); + // add HTML var bibliography = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, "html", asCitations); var str = Components.classes["@mozilla.org/supports-string;1"]. @@ -458,14 +458,14 @@ var Zotero_File_Interface = new function() { * * if |asHTML| is true, copy HTML source as text */ - function copyCitationToClipboard(items, style, asHTML) { + function copyCitationToClipboard(items, style, locale, asHTML) { // copy to clipboard var transferable = Components.classes["@mozilla.org/widget/transferable;1"]. createInstance(Components.interfaces.nsITransferable); var clipboardService = Components.classes["@mozilla.org/widget/clipboard;1"]. getService(Components.interfaces.nsIClipboard); - var style = Zotero.Styles.get(style).getCiteProc(); + var style = Zotero.Styles.get(style).getCiteProc(locale); var citation = {"citationItems":[{id:item.id} for each(item in items)], properties:{}}; // add HTML @@ -518,14 +518,17 @@ var Zotero_File_Interface = new function() { format = "rtf"; } + // determine locale preference + var locale = io.locale; + // generate bibliography try { if(io.method == 'copy-to-clipboard') { - copyItemsToClipboard(items, io.style, false, io.mode === "citations"); + Zotero_File_Interface.copyItemsToClipboard(items, io.style, locale, false, io.mode === "citations"); } else { var style = Zotero.Styles.get(io.style); - var cslEngine = style.getCiteProc(); + var cslEngine = style.getCiteProc(locale); var bibliography = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, format, io.mode === "citations"); } diff --git a/chrome/content/zotero/integration/integrationDocPrefs.xul b/chrome/content/zotero/integration/integrationDocPrefs.xul @@ -48,6 +48,13 @@ <listbox id="style-listbox" onselect="Zotero_File_Interface_Bibliography.styleChanged()"/> </groupbox> + <groupbox> + <hbox align="center"> + <caption label="&zotero.bibliography.locale.label;"/> + <menulist id="locale-menu" oncommand="Zotero_File_Interface_Bibliography.localeChanged(this.selectedItem.value)"/> + </hbox> + </groupbox> + <groupbox id="displayAs-groupbox"> <caption label="&zotero.integration.prefs.displayAs.label;"/> <radiogroup id="displayAs" orient="horizontal"> diff --git a/chrome/content/zotero/preferences/preferences_export.js b/chrome/content/zotero/preferences/preferences_export.js @@ -44,10 +44,18 @@ Zotero_Preferences.Export = { populateQuickCopyList: function () { // Initialize default format drop-down var format = Zotero.Prefs.get("export.quickCopy.setting"); + format = Zotero.QuickCopy.unserializeSetting(format); var menulist = document.getElementById("zotero-quickCopy-menu"); - this.buildQuickCopyFormatDropDown(menulist, Zotero.QuickCopy.getContentType(format), format); + this.buildQuickCopyFormatDropDown(menulist, format.contentType, format); menulist.setAttribute('preference', "pref-quickCopy-setting"); - this.updateQuickCopyHTMLCheckbox(); + + // Initialize locale drop-down + var localeMenulist = document.getElementById("zotero-quickCopy-locale-menu"); + Zotero.Styles.populateLocaleList(localeMenulist); + localeMenulist.setAttribute('preference', "pref-quickCopy-locale"); + + this._lastSelectedLocale = Zotero.Prefs.get("export.quickCopy.locale"); + this.updateQuickCopyUI(); if (!Zotero.isStandalone) { this.refreshQuickCopySiteList(); @@ -58,12 +66,12 @@ Zotero_Preferences.Export = { /* * Builds a Quick Copy drop-down */ - buildQuickCopyFormatDropDown: function (menulist, contentType, currentFormat) { - if (!currentFormat) { - currentFormat = menulist.value; + buildQuickCopyFormatDropDown: function (menulist, contentType, format) { + if (!format) { + format = menulist.value; } - // Strip contentType from mode - currentFormat = Zotero.QuickCopy.stripContentType(currentFormat); + + format = Zotero.QuickCopy.unserializeSetting(format); menulist.selectedItem = null; menulist.removeAllItems(); @@ -86,15 +94,14 @@ Zotero_Preferences.Export = { // add styles to list var styles = Zotero.Styles.getVisible(); for each(var style in styles) { - var baseVal = 'bibliography=' + style.styleID; var val = 'bibliography' + (contentType == 'html' ? '/html' : '') + '=' + style.styleID; var itemNode = document.createElement("menuitem"); itemNode.setAttribute("value", val); itemNode.setAttribute("label", style.title); - itemNode.setAttribute("oncommand", 'Zotero_Preferences.Export.updateQuickCopyHTMLCheckbox()'); + itemNode.setAttribute("oncommand", 'Zotero_Preferences.Export.updateQuickCopyUI()'); popup.appendChild(itemNode); - if (baseVal == currentFormat) { + if (format.mode == 'bibliography' && format.id == style.styleID) { menulist.selectedItem = itemNode; } } @@ -115,14 +122,14 @@ Zotero_Preferences.Export = { case '14763d24-8ba0-45df-8f52-b8d1108e7ac9': continue; } - var val = 'export=' + translators[i].translatorID; + var val = 'export=' + translators[i].translatorID; var itemNode = document.createElement("menuitem"); itemNode.setAttribute("value", val); itemNode.setAttribute("label", translators[i].label); - itemNode.setAttribute("oncommand", 'Zotero_Preferences.Export.updateQuickCopyHTMLCheckbox()'); + itemNode.setAttribute("oncommand", 'Zotero_Preferences.Export.updateQuickCopyUI()'); popup.appendChild(itemNode); - if (val == currentFormat) { + if (format.mode == 'export' && format.id == translators[i].translatorID) { menulist.selectedItem = itemNode; } } @@ -133,16 +140,23 @@ Zotero_Preferences.Export = { }, - updateQuickCopyHTMLCheckbox: function () { + updateQuickCopyUI: function () { var format = document.getElementById('zotero-quickCopy-menu').value; + var mode, contentType; - var checkbox = document.getElementById('zotero-quickCopy-copyAsHTML'); [mode, format] = format.split('='); [mode, contentType] = mode.split('/'); + var checkbox = document.getElementById('zotero-quickCopy-copyAsHTML'); checkbox.checked = contentType == 'html'; checkbox.disabled = mode != 'bibliography'; + + Zotero.Styles.updateLocaleList( + document.getElementById('zotero-quickCopy-locale-menu'), + mode == 'bibliography' ? Zotero.Styles.get(format) : null, + this._lastSelectedLocale + ); }, /** @@ -164,19 +178,24 @@ Zotero_Preferences.Export = { showQuickCopySiteEditor: function (index) { var treechildren = document.getElementById('quickCopy-siteSettings-rows'); - if (index != undefined && index > -1 && index < treechildren.childNodes.length) { + var formattedName = document.getElementById('zotero-quickCopy-menu').label; + var locale = this._lastSelectedLocale; + var asHTML = document.getElementById('zotero-quickCopy-copyAsHTML').checked; + + if (index !== undefined && index > -1 && index < treechildren.childNodes.length) { var treerow = treechildren.childNodes[index].firstChild; var domain = treerow.childNodes[0].getAttribute('label'); - var format = treerow.childNodes[1].getAttribute('label'); - var asHTML = treerow.childNodes[2].getAttribute('label') != ''; + formattedName = treerow.childNodes[1].getAttribute('label'); + locale = treerow.childNodes[2].getAttribute('label'); + asHTML = treerow.childNodes[3].getAttribute('label') !== ''; } - var format = Zotero.QuickCopy.getSettingFromFormattedName(format); + var format = Zotero.QuickCopy.getSettingFromFormattedName(formattedName); if (asHTML) { format = format.replace('bibliography=', 'bibliography/html='); } - var io = {domain: domain, format: format, ok: false}; + var io = {domain: domain, format: format, locale: locale, asHTML: asHTML, ok: false}; window.openDialog('chrome://zotero/content/preferences/quickCopySiteEditor.xul', "zotero-preferences-quickCopySiteEditor", "chrome,modal,centerscreen", io); @@ -188,7 +207,10 @@ Zotero_Preferences.Export = { Zotero.DB.query("DELETE FROM settings WHERE setting='quickCopySite' AND key=?", [domain]); } - Zotero.DB.query("REPLACE INTO settings VALUES ('quickCopySite', ?, ?)", [io.domain, io.format]); + var quickCopysetting = Zotero.QuickCopy.unserializeSetting(io.format); + quickCopysetting.locale = io.locale; + + Zotero.DB.query("REPLACE INTO settings VALUES ('quickCopySite', ?, ?)", [io.domain, JSON.stringify(quickCopysetting)]); this.refreshQuickCopySiteList(); }, @@ -213,18 +235,22 @@ Zotero_Preferences.Export = { var treerow = document.createElement('treerow'); var domainCell = document.createElement('treecell'); var formatCell = document.createElement('treecell'); - var HTMLCell = document.createElement('treecell'); + var localeCell = document.createElement('treecell'); + var htmlCell = document.createElement('treecell'); domainCell.setAttribute('label', siteData[i].domainPath); - var formatted = Zotero.QuickCopy.getFormattedNameFromSetting(siteData[i].format); - formatCell.setAttribute('label', formatted); - var copyAsHTML = Zotero.QuickCopy.getContentType(siteData[i].format) == 'html'; - HTMLCell.setAttribute('label', copyAsHTML ? ' ✓ ' : ''); + var formattedName = Zotero.QuickCopy.getFormattedNameFromSetting(siteData[i].format); + formatCell.setAttribute('label', formattedName); + + var format = Zotero.QuickCopy.unserializeSetting(siteData[i].format); + localeCell.setAttribute('label', format.locale); + htmlCell.setAttribute('label', format.contentType == 'html' ? ' ✓ ' : ''); treerow.appendChild(domainCell); treerow.appendChild(formatCell); - treerow.appendChild(HTMLCell); + treerow.appendChild(localeCell); + treerow.appendChild(htmlCell); treeitem.appendChild(treerow); treechildren.appendChild(treeitem); } @@ -253,9 +279,9 @@ Zotero_Preferences.Export = { } instr.appendChild(document.createTextNode(str)); - var key = Zotero.Prefs.get('keys.copySelectedItemCitationsToClipboard'); - var str = Zotero.getString('zotero.preferences.export.quickCopy.citationInstructions', prefix + key); - var instr = document.getElementById('quickCopy-citationInstructions'); + key = Zotero.Prefs.get('keys.copySelectedItemCitationsToClipboard'); + str = Zotero.getString('zotero.preferences.export.quickCopy.citationInstructions', prefix + key); + instr = document.getElementById('quickCopy-citationInstructions'); while (instr.hasChildNodes()) { instr.removeChild(instr.firstChild); } diff --git a/chrome/content/zotero/preferences/preferences_export.xul b/chrome/content/zotero/preferences/preferences_export.xul @@ -23,7 +23,12 @@ ***** END LICENSE BLOCK ***** --> -<!DOCTYPE prefwindow SYSTEM "chrome://zotero/locale/preferences.dtd"> +<!DOCTYPE window [ + <!ENTITY % prefWindow SYSTEM "chrome://zotero/locale/preferences.dtd"> + %prefWindow; + <!ENTITY % common SYSTEM "chrome://zotero/locale/zotero.dtd"> + %common; +]> <overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <prefpane id="zotero-prefpane-export" @@ -33,6 +38,7 @@ <preferences> <preference id="pref-quickCopy-setting" name="extensions.zotero.export.quickCopy.setting" type="string"/> <preference id="pref-quickCopy-dragLimit" name="extensions.zotero.export.quickCopy.dragLimit" type="int"/> + <preference id="pref-quickCopy-locale" name="extensions.zotero.export.quickCopy.locale" type="string"/> <preference id="pref-export-displayCharsetOption" name="extensions.zotero.export.displayCharsetOption" type="bool"/> <preference id="pref-import-charset" name="extensions.zotero.import.charset" type="string"/> </preferences> @@ -49,10 +55,15 @@ <label value="&zotero.preferences.quickCopy.defaultOutputFormat;" control="quickCopy-menu"/> <menulist id="zotero-quickCopy-menu"/> - <separator class="thin"/> - - <checkbox id="zotero-quickCopy-copyAsHTML" label="&zotero.preferences.quickCopy.copyAsHTML;" - oncommand="Zotero_Preferences.Export.buildQuickCopyFormatDropDown(document.getElementById('zotero-quickCopy-menu'), this.checked ? 'html' : '');"/> + <hbox align="center"> + <label id="zotero-quickCopy-locale-menu-label" value="&zotero.bibliography.locale.label;" control="zotero-quickCopy-locale-menu"/> + <menulist id="zotero-quickCopy-locale-menu" oncommand="Zotero_Preferences.Export._lastSelectedLocale = this.value"/> + + <separator orient="vertical" width="15px"/> + + <checkbox id="zotero-quickCopy-copyAsHTML" label="&zotero.preferences.quickCopy.copyAsHTML;" + oncommand="Zotero_Preferences.Export.buildQuickCopyFormatDropDown(document.getElementById('zotero-quickCopy-menu'), this.checked ? 'html' : '');"/> + </hbox> <vbox id="zotero-prefpane-export-siteSettings"/> diff --git a/chrome/content/zotero/preferences/preferences_export_firefox.xul b/chrome/content/zotero/preferences/preferences_export_firefox.xul @@ -42,6 +42,7 @@ <treecols> <treecol id="quickCopy-urlColumn" label="&zotero.preferences.quickCopy.siteEditor.domainPath;" flex="1"/> <treecol id="quickCopy-formatColumn" label="&zotero.preferences.quickCopy.siteEditor.outputFormat;" flex="2"/> + <treecol id="quickCopy-localeColumn" label="&zotero.preferences.quickCopy.siteEditor.locale;"/> <treecol id="quickCopy-copyAsHTML" label="HTML"/> </treecols> <treechildren id="quickCopy-siteSettings-rows"/> diff --git a/chrome/content/zotero/preferences/quickCopySiteEditor.xul b/chrome/content/zotero/preferences/quickCopySiteEditor.xul @@ -27,15 +27,23 @@ <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <?xml-stylesheet href="chrome://zotero/skin/preferences.css"?> -<!DOCTYPE window SYSTEM "chrome://zotero/locale/preferences.dtd"> + +<!DOCTYPE window [ + <!ENTITY % prefWindow SYSTEM "chrome://zotero/locale/preferences.dtd"> + %prefWindow; + <!ENTITY % common SYSTEM "chrome://zotero/locale/zotero.dtd"> + %common; +]> + <dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="" buttons="cancel,accept" id="zotero-quickCopySiteEditor" - onload="sizeToContent();" + onload="Zotero_Preferences.Export.updateQuickCopyUI(); sizeToContent()" ondialogaccept="Zotero_QuickCopySiteEditor.onAccept();"> <script src="chrome://zotero/content/include.js"/> <script src="preferences.js"/> + <script src="preferences_export.js"/> <script> <![CDATA[ @@ -46,6 +54,12 @@ var io = window.arguments[0]; io.domain = document.getElementById('zotero-quickCopy-domain').value; io.format = document.getElementById('zotero-quickCopy-menu').value; + + io.locale = ''; + if (!document.getElementById('zotero-quickCopy-locale-menu').disabled) { + io.locale = document.getElementById('zotero-quickCopy-locale-menu').value; + } + io.ok = true; } } @@ -55,10 +69,21 @@ <vbox id="zotero-preferences-quickCopySiteEditor"> <label value="&zotero.preferences.quickCopy.siteEditor.domainPath; &zotero.preferences.quickCopy.siteEditor.domainPath.example;" control="zotero-quickCopy-domain"/> <textbox id="zotero-quickCopy-domain"/> + <separator class="thin"/> + <label value="&zotero.preferences.quickCopy.siteEditor.outputFormat;" control="zotero-quickCopy-menu"/> <menulist id="zotero-quickCopy-menu"/> + <separator class="thin"/> + + <label id="zotero-quickCopy-locale-menu-label" value="&zotero.preferences.quickCopy.siteEditor.locale;" control="zotero-quickCopy-locale-menu"/> + <hbox align="center"> + <menulist id="zotero-quickCopy-locale-menu" oncommand="Zotero_Preferences.Export._lastSelectedLocale = this.value"/> + </hbox> + + <separator class="thin"/> + <checkbox id="zotero-quickCopy-copyAsHTML" label="&zotero.preferences.quickCopy.copyAsHTML;" oncommand="window.opener.Zotero_Preferences.Export.buildQuickCopyFormatDropDown( document.getElementById('zotero-quickCopy-menu'), this.checked ? 'html' : '' @@ -68,13 +93,18 @@ <script> <![CDATA[ var io = window.arguments[0]; + var contentType = io.asHTML ? 'html' : ''; document.getElementById('zotero-quickCopy-domain').value = io.domain ? io.domain : ''; - window.opener.Zotero_Preferences.Export.buildQuickCopyFormatDropDown( + Zotero_Preferences.Export.buildQuickCopyFormatDropDown( document.getElementById('zotero-quickCopy-menu'), - Zotero.QuickCopy.getContentType(io.format), + contentType, io.format ); - window.opener.Zotero_Preferences.Export.updateQuickCopyHTMLCheckbox(); + Zotero.Styles.populateLocaleList( + document.getElementById('zotero-quickCopy-locale-menu') + ); + document.getElementById('zotero-quickCopy-copyAsHTML').checked = io.asHTML; + Zotero_Preferences.Export._lastSelectedLocale = io.locale; ]]> </script> </dialog> diff --git a/chrome/content/zotero/rtfScan.js b/chrome/content/zotero/rtfScan.js @@ -495,8 +495,9 @@ var Zotero_RTFScan = new function() { function _formatRTF() { // load style and create ItemSet with all items - var zStyle = Zotero.Styles.get(document.getElementById("style-listbox").selectedItem.value) - var style = zStyle.getCiteProc(); + var zStyle = Zotero.Styles.get(document.getElementById("style-listbox").value) + var locale = document.getElementById("locale-menu").value; + var style = zStyle.getCiteProc(locale); style.setOutputFormat("rtf"); var isNote = style.class == "note"; @@ -597,7 +598,12 @@ var Zotero_RTFScan = new function() { Zotero.File.putContents(outputFile, contents); + // save locale + if (!document.getElementById("locale-menu").disabled) { + Zotero.Prefs.set("export.lastLocale", locale); + } + document.documentElement.canAdvance = true; document.documentElement.advance(); } -} -\ No newline at end of file +} diff --git a/chrome/content/zotero/rtfScan.xul b/chrome/content/zotero/rtfScan.xul @@ -89,7 +89,12 @@ <caption label="&zotero.bibliography.style.label;"/> <listbox id="style-listbox" onselect="Zotero_File_Interface_Bibliography.styleChanged()" flex="1"/> </groupbox> - + <groupbox> + <hbox align="center"> + <caption label="&zotero.bibliography.locale.label;"/> + <menulist id="locale-menu" oncommand="Zotero_File_Interface_Bibliography.localeChanged(this.value)"/> + </hbox> + </groupbox> <groupbox> <caption label="&zotero.integration.prefs.displayAs.label;"/> <radiogroup id="displayAs" orient="horizontal"> diff --git a/chrome/content/zotero/tools/csledit.js b/chrome/content/zotero/tools/csledit.js @@ -27,39 +27,32 @@ var Zotero_CSL_Editor = new function() { this.init = init; this.handleKeyPress = handleKeyPress; this.loadCSL = loadCSL; - this.generateBibliography = generateBibliography; - this.refresh = refresh; function init() { + Zotero.Styles.populateLocaleList(document.getElementById("locale-menu")); + var cslList = document.getElementById('zotero-csl-list'); - if (cslList.getAttribute('initialized') == 'true') { - if (currentStyle) { - loadCSL(currentStyle); - refresh(); - } - return; - } + cslList.removeAllItems(); - var rawDefaultStyle = Zotero.Prefs.get('export.quickCopy.setting'); - var defaultStyle = Zotero.QuickCopy.stripContentType(rawDefaultStyle); + var lastStyle = Zotero.Prefs.get('export.lastStyle'); var styles = Zotero.Styles.getAll(); var currentStyle = null; - var listPos = 0; for each(var style in styles) { if (style.source) { continue; } var item = cslList.appendItem(style.title, style.styleID); - if (!currentStyle || defaultStyle == ('bibliography=' + style.styleID)) { - currentStyle = style.styleID; - cslList.selectedIndex = listPos; + if (!currentStyle && lastStyle == style.styleID) { + currentStyle = style; + cslList.selectedItem = item; } - listPos += 1; } + if (currentStyle) { - loadCSL(currentStyle); - refresh(); + // Call asynchronously, see note in Zotero.Styles + window.setTimeout(this.onStyleSelected.bind(this, currentStyle.styleID), 1); } + var pageList = document.getElementById('zotero-csl-page-type'); var locators = Zotero.Cite.labels; for each(var type in locators) { @@ -69,13 +62,25 @@ var Zotero_CSL_Editor = new function() { } pageList.selectedIndex = 0; - cslList.setAttribute('initialized', true); } - function refresh() { - var editor = document.getElementById('zotero-csl-editor'); - generateBibliography(editor.value); - + + this.onStyleSelected = function(styleID) { + Zotero.Prefs.set('export.lastStyle', styleID); + let style = Zotero.Styles.get(styleID); + Zotero.Styles.updateLocaleList( + document.getElementById("locale-menu"), + style, + Zotero.Prefs.get('export.lastLocale') + ); + + loadCSL(style.styleID); + this.refresh(); + } + + this.refresh = function() { + this.generateBibliography(this.loadStyleFromEditor()); } + this.save = function() { var editor = document.getElementById('zotero-csl-editor'); var style = editor.value; @@ -120,20 +125,52 @@ var Zotero_CSL_Editor = new function() { document.getElementById('zotero-csl-list').value = cslID; } + this.loadStyleFromEditor = function() { + var styleObject; + try { + styleObject = new Zotero.Style( + document.getElementById('zotero-csl-editor').value + ); + } catch(e) { + document.getElementById('zotero-csl-preview-box') + .contentDocument.documentElement.innerHTML = '<div>' + + Zotero.getString('styles.editor.warning.parseError') + + '</div><div>' + e + '</div>'; + throw e; + } + + return styleObject; + } + + this.onStyleModified = function(str) { + document.getElementById('zotero-csl-list').selectedIndex = -1; + + let styleObject = this.loadStyleFromEditor(); + + Zotero.Styles.updateLocaleList( + document.getElementById("locale-menu"), + styleObject, + Zotero.Prefs.get('export.lastLocale') + ); + Zotero_CSL_Editor.generateBibliography(styleObject); + } - function generateBibliography(str) { - var editor = document.getElementById('zotero-csl-editor') + this.generateBibliography = function(style) { var iframe = document.getElementById('zotero-csl-preview-box'); var items = Zotero.getActiveZoteroPane().getSelectedItems(); if (items.length == 0) { - iframe.contentDocument.documentElement.innerHTML = '<html><head><title></title></head><body><p style="color: red">' + Zotero.getString('styles.editor.warning.noItems') + '</p></body></html>'; + iframe.contentDocument.documentElement.innerHTML = + '<html><head><title></title></head><body><p style="color: red">' + + Zotero.getString('styles.editor.warning.noItems') + + '</p></body></html>'; return; } - var styleObject, styleEngine; + + var selectedLocale = document.getElementById("locale-menu").value; + var styleEngine; try { - styleObject = new Zotero.Style(str); - styleEngine = styleObject.getCiteProc(); + styleEngine = style.getCiteProc(style.locale || selectedLocale); } catch(e) { iframe.contentDocument.documentElement.innerHTML = '<div>' + Zotero.getString('styles.editor.warning.parseError') + '</div><div>'+e+'</div>'; throw e; diff --git a/chrome/content/zotero/tools/csledit.xul b/chrome/content/zotero/tools/csledit.xul @@ -58,12 +58,13 @@ <menuitem label="near-note" value="4"/> </menupopup> </menulist> - <menulist id="zotero-csl-list" style="min-height: 1.6em; min-width: 100px" initialized="false" flex="1" oncommand="Zotero_CSL_Editor.loadCSL(this.selectedItem.value)"/> + <menulist id="locale-menu" oncommand="Zotero.Prefs.set('export.lastLocale', this.value); Zotero_CSL_Editor.refresh()"/> + <menulist id="zotero-csl-list" style="min-height: 1.6em; min-width: 100px" flex="1" oncommand="Zotero_CSL_Editor.onStyleSelected(this.value)"/> </hbox> <textbox id="zotero-csl-editor" type="timed" timeout="250" multiline="true" flex="1" onkeypress="Zotero_CSL_Editor.handleKeyPress(event)" - oncommand="document.getElementById('zotero-csl-list').selectedIndex = -1; Zotero_CSL_Editor.generateBibliography(this.value)"/> + oncommand="Zotero_CSL_Editor.onStyleModified()"/> <splitter id="csledit-splitter" collapse="before" persist="state"> <grippy/> </splitter> diff --git a/chrome/content/zotero/tools/cslpreview.js b/chrome/content/zotero/tools/cslpreview.js @@ -30,7 +30,10 @@ var Zotero_CSL_Preview = new function() { this.generateBibliography = generateBibliography; function init() { - //refresh(); + var menulist = document.getElementById("locale-menu"); + + Zotero.Styles.populateLocaleList(menulist); + menulist.value = Zotero.Prefs.get('export.lastLocale');; var iframe = document.getElementById('zotero-csl-preview-box'); iframe.contentDocument.documentElement.innerHTML = '<html><head><title></title></head><body><p>' + Zotero.getString('styles.preview.instructions') + '</p></body></html>'; @@ -86,7 +89,9 @@ var Zotero_CSL_Preview = new function() { Zotero.debug("CSL IGNORE: citation format is " + style.categories); return ''; } - var styleEngine = style.getCiteProc(); + + var locale = document.getElementById("locale-menu").value; + var styleEngine = style.getCiteProc(locale); // Generate multiple citations var citations = styleEngine.previewCitationCluster( diff --git a/chrome/content/zotero/tools/cslpreview.xul b/chrome/content/zotero/tools/cslpreview.xul @@ -56,6 +56,8 @@ <menuitem value="numeric" label="&styles.preview.citationFormat.numeric;"/> </menupopup> </menulist> + + <menulist id="locale-menu" oncommand="Zotero.Prefs.set('export.lastLocale', this.value); Zotero_CSL_Preview.refresh()"/> </hbox> <iframe id="zotero-csl-preview-box" flex="1" style="padding: 0 1em; background:white;" overflow="auto" type="content"/> </vbox> diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js @@ -2039,7 +2039,7 @@ Zotero.Integration.Session.prototype.setData = function(data, resetStyle) { try { var getStyle = Zotero.Styles.get(data.style.styleID); data.style.hasBibliography = getStyle.hasBibliography; - this.style = getStyle.getCiteProc(data.prefs.automaticJournalAbbreviations); + this.style = getStyle.getCiteProc(data.locale, data.prefs.automaticJournalAbbreviations); this.style.setOutputFormat("rtf"); this.styleClass = getStyle.class; this.dateModified = new Object(); @@ -2069,6 +2069,7 @@ Zotero.Integration.Session.prototype.setDocPrefs = function(doc, primaryFieldTyp if(this.data) { io.style = this.data.style.styleID; + io.locale = this.data.locale; io.useEndnotes = this.data.prefs.noteType == 0 ? 0 : this.data.prefs.noteType-1; io.fieldType = this.data.prefs.fieldType; io.primaryFieldType = primaryFieldType; @@ -2091,13 +2092,19 @@ Zotero.Integration.Session.prototype.setDocPrefs = function(doc, primaryFieldTyp var data = new Zotero.Integration.DocumentData(); data.sessionID = oldData.sessionID; data.style.styleID = io.style; + data.locale = io.locale; data.prefs.fieldType = io.fieldType; data.prefs.storeReferences = io.storeReferences; data.prefs.automaticJournalAbbreviations = io.automaticJournalAbbreviations; + var localeChanged = false; + if (!oldData.locale || (oldData.locale != io.locale)) { + localeChanged = true; + } + me.setData(data, oldData && - oldData.prefs.automaticJournalAbbreviations != - data.prefs.automaticJournalAbbreviations); + (oldData.prefs.automaticJournalAbbreviations != + data.prefs.automaticJournalAbbreviations || localeChanged)); // need to do this after setting the data so that we know if it's a note style me.data.prefs.noteType = me.style && me.styleClass == "note" ? io.useEndnotes+1 : 0; diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js @@ -2670,12 +2670,12 @@ Zotero.ItemTreeView.prototype.onDragStart = function (event) { event.dataTransfer.setData("text/plain", text); } + format = Zotero.QuickCopy.unserializeSetting(format); try { - var [mode, ] = format.split('='); - if (mode == 'export') { + if (format.mode == 'export') { Zotero.QuickCopy.getContentFromItems(items, format, exportCallback); } - else if (mode.indexOf('bibliography') == 0) { + else if (format.mode == 'bibliography') { var content = Zotero.QuickCopy.getContentFromItems(items, format, null, event.shiftKey); if (content) { if (content.html) { @@ -2685,11 +2685,11 @@ Zotero.ItemTreeView.prototype.onDragStart = function (event) { } } else { - Components.utils.reportError("Invalid Quick Copy mode '" + mode + "'"); + Components.utils.reportError("Invalid Quick Copy mode"); } } catch (e) { - Components.utils.reportError(e + " with format '" + format + "'"); + Components.utils.reportError(e + " with '" + format.id + "'"); } } diff --git a/chrome/content/zotero/xpcom/quickCopy.js b/chrome/content/zotero/xpcom/quickCopy.js @@ -25,27 +25,61 @@ Zotero.QuickCopy = new function() { - this.getFormattedNameFromSetting = getFormattedNameFromSetting; - this.getSettingFromFormattedName = getSettingFromFormattedName; - this.getContentType = getContentType; - this.stripContentType = stripContentType; - this.getFormatFromURL = getFormatFromURL; - this.getContentFromItems = getContentFromItems; var _initialized = false; var _formattedNames = {}; + /* + * Return Quick Copy setting object from string, stringified object, or object + * + * Example string format: "bibliography/html=http://www.zotero.org/styles/apa" + * + * Quick Copy setting object has the following properties: + * - "mode": "bibliography" (for styles) or "export" (for export translators) + * - "contentType: "" (plain text output) or "html" (HTML output; for styles + * only) + * - "id": style ID or export translator ID + * - "locale": locale code (for styles only) + */ + this.unserializeSetting = function (setting) { + var settingObject = {}; + + if (typeof setting === 'string') { + try { + // First test if string input is a stringified object + settingObject = JSON.parse(setting); + } catch (e) { + // Try parsing as formatted string + var parsedSetting = setting.match(/(bibliography|export)(?:\/([^=]+))?=(.+)$/); + if (parsedSetting) { + settingObject.mode = parsedSetting[1]; + settingObject.contentType = parsedSetting[2] || ''; + settingObject.id = parsedSetting[3]; + settingObject.locale = ''; + } + } + } else { + // Return input if not a string; it might already be an object + return setting; + } + + return settingObject; + }; - function getFormattedNameFromSetting(setting) { + + this.getFormattedNameFromSetting = function (setting) { if (!_initialized) { _init(); } - var name = _formattedNames[this.stripContentType(setting)]; + var format = this.unserializeSetting(setting); + + var name = _formattedNames[format.mode + "=" + format.id]; return name ? name : ''; - } + }; + - function getSettingFromFormattedName(name) { + this.getSettingFromFormattedName = function (name) { if (!_initialized) { _init(); } @@ -57,56 +91,45 @@ Zotero.QuickCopy = new function() { } return ''; - } + }; - /* - * Returns the setting with any contentType stripped from the mode part - */ - function getContentType(setting) { - var matches = setting.match(/(?:bibliography|export)\/([^=]+)=.+$/, '$1'); - return matches ? matches[1] : ''; - } - - - /* - * Returns the setting with any contentType stripped from the mode part - */ - function stripContentType(setting) { - return setting.replace(/(bibliography|export)(?:\/[^=]+)?=(.+)$/, '$1=$2'); - } - - - function getFormatFromURL(url) { + this.getFormatFromURL = function(url) { + var quickCopyPref = Zotero.Prefs.get("export.quickCopy.setting"); + quickCopyPref = JSON.stringify(this.unserializeSetting(quickCopyPref)); + if (!url) { - return Zotero.Prefs.get("export.quickCopy.setting"); + return quickCopyPref; } var ioService = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); - var nsIURI = ioService.newURI(url, null, null); - try { + var nsIURI = ioService.newURI(url, null, null); + // Accessing some properties may throw for URIs that do not support those + // parts. E.g. hostPort throws NS_ERROR_FAILURE for about:blank var urlHostPort = nsIURI.hostPort; var urlPath = nsIURI.path; } catch (e) { - return Zotero.Prefs.get("export.quickCopy.setting"); + return quickCopyPref; } + var matches = []; var sql = "SELECT key AS domainPath, value AS format FROM settings " + "WHERE setting='quickCopySite' AND (key LIKE ? OR key LIKE ?)"; var urlDomain = urlHostPort.match(/[^\.]+\.[^\.]+$/); - var rows = Zotero.DB.query(sql, ['%' + urlDomain + '%', '/%']); - for each(var row in rows) { - var [domain, path] = row.domainPath.split(/\//); - path = '/' + (path ? path : ''); - var re = new RegExp(domain + '$'); - if (urlHostPort.match(re) && urlPath.indexOf(path) == 0) { + var rows = Zotero.DB.query(sql, ['%' + urlDomain[0] + '%', '/%']); + for (let i = 0; i < rows.length; i++) { + let row = rows[i]; + let domain = row.domainPath.split('/',1)[0]; + let path = row.domainPath.substr(domain.length) || '/'; + let re = new RegExp('(^|[./])' + Zotero.Utilities.quotemeta(domain) + '$', 'i'); + if (re.test(urlHostPort) && urlPath.indexOf(path) === 0) { matches.push({ - format: row.format, + format: JSON.stringify(this.unserializeSetting(row.format)), domainLength: domain.length, pathLength: path.length }); @@ -130,15 +153,15 @@ Zotero.QuickCopy = new function() { } return -1; - } + }; if (matches.length) { matches.sort(sort); return matches[0].format; + } else { + return quickCopyPref; } - - return Zotero.Prefs.get("export.quickCopy.setting"); - } + }; /* @@ -146,8 +169,9 @@ Zotero.QuickCopy = new function() { * * |items| is an array of Zotero.Item objects * - * |format| is a Quick Copy format string - * (e.g. "bibliography=http://purl.org/net/xbiblio/csl/styles/apa.csl") + * |format| may be a Quick Copy format string + * (e.g. "bibliography=http://www.zotero.org/styles/apa") + * or an Quick Copy format object * * |callback| is only necessary if using an export format and should be * a function suitable for Zotero.Translate.setHandler, taking parameters @@ -157,25 +181,24 @@ Zotero.QuickCopy = new function() { * If bibliography format, the process is synchronous and an object * contain properties 'text' and 'html' is returned. */ - function getContentFromItems(items, format, callback, modified) { + this.getContentFromItems = function (items, format, callback, modified) { if (items.length > Zotero.Prefs.get('export.quickCopy.dragLimit')) { Zotero.debug("Skipping quick copy for " + items.length + " items"); return false; } - var [mode, format] = format.split('='); - var [mode, contentType] = mode.split('/'); + format = this.unserializeSetting(format); - if (mode == 'export') { + if (format.mode == 'export') { var translation = new Zotero.Translate.Export; translation.noWait = true; // needed not to break drags translation.setItems(items); - translation.setTranslator(format); + translation.setTranslator(format.id); translation.setHandler("done", callback); translation.translate(); return true; } - else if (mode == 'bibliography') { + else if (format.mode == 'bibliography') { // Move notes to separate array var allNotes = true; var notes = []; @@ -320,32 +343,35 @@ Zotero.QuickCopy = new function() { } var content = { - text: contentType == "html" ? html : text, + text: format.contentType == "html" ? html : text, html: copyHTML }; return content; } + // determine locale preference + var locale = format.locale ? format.locale : Zotero.Prefs.get('export.quickCopy.locale'); + // Copy citations if shift key pressed if (modified) { - var csl = Zotero.Styles.get(format).getCiteProc(); + var csl = Zotero.Styles.get(format.id).getCiteProc(locale); csl.updateItems([item.id for each(item in items)]); var citation = {citationItems:[{id:item.id} for each(item in items)], properties:{}}; var html = csl.previewCitationCluster(citation, [], [], "html"); var text = csl.previewCitationCluster(citation, [], [], "text"); } else { - var style = Zotero.Styles.get(format); - var cslEngine = style.getCiteProc(); + var style = Zotero.Styles.get(format.id); + var cslEngine = style.getCiteProc(locale); var html = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, "html"); var text = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, "text"); } - return {text:(contentType == "html" ? html : text), html:html}; + return {text:(format.contentType == "html" ? html : text), html:html}; } - throw ("Invalid mode '" + mode + "' in Zotero.QuickCopy.getContentFromItems()"); - } + throw ("Invalid mode '" + format.mode + "' in Zotero.QuickCopy.getContentFromItems()"); + }; function _init() { diff --git a/chrome/content/zotero/xpcom/style.js b/chrome/content/zotero/xpcom/style.js @@ -44,11 +44,19 @@ Zotero.Styles = new function() { this.ns = { "csl":"http://purl.org/net/xbiblio/csl" }; - - // TEMP - // Until we get asynchronous style loading, load renamed styles at startup, since the - // synchronous call we were using breaks the first drag of the session (on OS X, at least) + this.preinit = function () { + // Upgrade style locale prefs for 4.0.27 + var bibliographyLocale = Zotero.Prefs.get("export.bibliographyLocale"); + if (bibliographyLocale) { + Zotero.Prefs.set("export.lastLocale", bibliographyLocale); + Zotero.Prefs.set("export.quickCopy.locale", bibliographyLocale); + Zotero.Prefs.clear("export.bibliographyLocale"); + } + + // TEMP + // Until we get asynchronous style loading, load renamed styles at startup, since the + // synchronous call we were using breaks the first drag of the session (on OS X, at least) _renamedStyles = {}; Zotero.HTTP.promise( "GET", "resource://zotero/schema/renamed-styles.json", { responseType: 'json' } @@ -81,9 +89,33 @@ Zotero.Styles = new function() { // hidden dir dir.append("hidden"); - if(dir.exists()) i += _readStylesFromDirectory(dir, true); + if (dir.exists()) i += _readStylesFromDirectory(dir, true); + + // Sort visible styles by title + _visibleStyles.sort(function(a, b) { + return a.title.localeCompare(b.title); + }) + // .. and freeze, so they can be returned directly + _visibleStyles = Object.freeze(_visibleStyles); Zotero.debug("Cached "+i+" styles in "+((new Date()).getTime() - start)+" ms"); + + // load available CSL locales + var localeFile = {}; + var locales = {}; + var primaryDialects = {}; + var localesLocation = "chrome://zotero/content/locale/csl/locales.json"; + localeFile = JSON.parse(Zotero.File.getContentsFromURL(localesLocation)); + + primaryDialects = localeFile["primary-dialects"]; + + // only keep localized language name + for (let locale in localeFile["language-names"]) { + locales[locale] = localeFile["language-names"][locale][0]; + } + + this.locales = locales; + this.primaryDialects = primaryDialects; } /** @@ -128,6 +160,7 @@ Zotero.Styles = new function() { } i++; } + return i; } @@ -156,11 +189,11 @@ Zotero.Styles = new function() { /** * Gets all visible styles - * @return {Zotero.Style[]} An array of Zotero.Style objects + * @return {Zotero.Style[]} An immutable array of Zotero.Style objects */ this.getVisible = function() { if(!_initialized || !_cacheTranslatorData) this.init(); - return _visibleStyles.slice(0); + return _visibleStyles; // Immutable } /** @@ -399,6 +432,97 @@ Zotero.Styles = new function() { } }); } + + /** + * Populate menulist with locales + * + * @param {xul:menulist} menulist + */ + this.populateLocaleList = function(menulist) { + if(!_initialized) this.init(); + + // Reset menulist + menulist.selectedItem = null; + menulist.removeAllItems(); + + let fallbackLocale = Zotero.Styles.primaryDialects[Zotero.locale] + || Zotero.locale; + + let menuLocales = Zotero.Utilities.deepCopy(Zotero.Styles.locales); + let menuLocalesKeys = Object.keys(menuLocales).sort(); + + // Make sure that client locale is always available as a choice + if (fallbackLocale && !(fallbackLocale in menuLocales)) { + menuLocales[fallbackLocale] = fallbackLocale; + menuLocalesKeys.unshift(fallbackLocale); + } + + for (let i=0; i<menuLocalesKeys.length; i++) { + menulist.appendItem(menuLocales[menuLocalesKeys[i]], menuLocalesKeys[i]); + } + }; + + /** + * Update locale list state based on style selection. + * For styles that do not define a locale, enable the list and select a + * preferred locale. + * For styles that define a locale, disable the list and select the + * specified locale. If the locale does not exist, it is added to the list. + * If null is passed instead of style, the list and its label are disabled, + * and set to blank value. + * + * Note: Do not call this function synchronously immediately after + * populateLocaleList. The menulist items are added, but the values are not + * yet set. + * + * @param {xul:menulist} menulist Menulist object that will be manipulated + * @param {Zotero.Style} style Currently selected style + * @param {String} prefLocale Preferred locale if not overridden by the style + * + * @return {String} The locale that was selected + */ + this.updateLocaleList = function(menulist, style, prefLocale) { + // Remove any nodes that were manually added to menulist + let availableLocales = []; + for (let i=0; i<menulist.itemCount; i++) { + let item = menulist.getItemAtIndex(i); + if (item.getAttributeNS('zotero:', 'customLocale')) { + menulist.removeItemAt(i); + i--; + continue; + } + + availableLocales.push(item.value); + } + + if (!style) { + // disable menulist and label + menulist.disabled = true; + if (menulist.labelElement) menulist.labelElement.disabled = true; + + // set node to blank node + // If we just set value to "", the internal label is collapsed and the dropdown list becomes shorter + let blankListNode = menulist.appendItem('', ''); + blankListNode.setAttributeNS('zotero:', 'customLocale', true); + + menulist.selectedItem = blankListNode; + return menulist.value; + } + + menulist.disabled = !!style.locale; + if (menulist.labelElement) menulist.labelElement.disabled = false; + + let selectLocale = style.locale || prefLocale || Zotero.locale; + selectLocale = Zotero.Styles.primaryDialects[selectLocale] || selectLocale; + + // Make sure the locale we want to select is in the menulist + if (availableLocales.indexOf(selectLocale) == -1) { + let customLocale = menulist.insertItemAt(0, selectLocale, selectLocale); + customLocale.setAttributeNS('zotero:', 'customLocale', true); + } + + return menulist.value = selectLocale; + } } /** @@ -478,10 +602,10 @@ Zotero.Style = function(arg) { /** * Get a citeproc-js CSL.Engine instance - * @param {Boolean} useAutomaticJournalAbbreviations Whether to automatically abbreviate titles + * @param {String} locale Locale code + * @param {Boolean} automaticJournalAbbreviations Whether to automatically abbreviate titles */ -Zotero.Style.prototype.getCiteProc = function(automaticJournalAbbreviations) { - var locale = Zotero.Prefs.get('export.bibliographyLocale'); +Zotero.Style.prototype.getCiteProc = function(locale, automaticJournalAbbreviations) { if(!locale) { var locale = Zotero.locale; if(!locale) { diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js @@ -413,20 +413,21 @@ Zotero.Utilities = { }, /** - * Encode special XML/HTML characters<br/> - * <br/> - * Certain entities can be inserted manually:<br/> - * <pre> <ZOTEROBREAK/> => <br/> - * <ZOTEROHELLIP/> => &#8230;</pre> - * @type String + * Encode special XML/HTML characters + * Certain entities can be inserted manually: + * <ZOTEROBREAK/> => <br/> + * <ZOTEROHELLIP/> => … + * + * @param {String} str + * @return {String} */ - "htmlSpecialChars":function(/**String*/ str) { - if (typeof str != 'string') str = str.toString(); - - if (!str) { - return ''; + "htmlSpecialChars":function(str) { + if (str && typeof str != 'string') { + str = str.toString(); } + if (!str) return ''; + return str .replace(/&/g, '&') .replace(/"/g, '"') diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js @@ -1866,24 +1866,27 @@ var ZoteroPane = new function() } var url = (window.content && window.content.location ? window.content.location.href : null); - var [mode, format] = Zotero.QuickCopy.getFormatFromURL(url).split('='); - var [mode, contentType] = mode.split('/'); + var format = Zotero.QuickCopy.getFormatFromURL(url); + format = Zotero.QuickCopy.unserializeSetting(format); - if (mode == 'bibliography') { + // determine locale preference + var locale = format.locale ? format.locale : Zotero.Prefs.get('export.quickCopy.locale'); + + if (format.mode == 'bibliography') { if (asCitations) { - Zotero_File_Interface.copyCitationToClipboard(items, format, contentType == 'html'); + Zotero_File_Interface.copyCitationToClipboard(items, format.id, locale, format.contentType == 'html'); } else { - Zotero_File_Interface.copyItemsToClipboard(items, format, contentType == 'html'); + Zotero_File_Interface.copyItemsToClipboard(items, format.id, locale, format.contentType == 'html'); } } - else if (mode == 'export') { + else if (format.mode == 'export') { // Copy citations doesn't work in export mode if (asCitations) { return; } else { - Zotero_File_Interface.exportItemsToClipboard(items, format); + Zotero_File_Interface.exportItemsToClipboard(items, format.id); } } } diff --git a/chrome/locale/en-US/zotero/preferences.dtd b/chrome/locale/en-US/zotero/preferences.dtd @@ -107,6 +107,7 @@ <!ENTITY zotero.preferences.quickCopy.siteEditor.domainPath "Domain/Path"> <!ENTITY zotero.preferences.quickCopy.siteEditor.domainPath.example "(e.g. wikipedia.org)"> <!ENTITY zotero.preferences.quickCopy.siteEditor.outputFormat "Output Format"> +<!ENTITY zotero.preferences.quickCopy.siteEditor.locale "Language"> <!ENTITY zotero.preferences.quickCopy.dragLimit "Disable Quick Copy when dragging more than"> <!ENTITY zotero.preferences.prefpane.cite "Cite"> diff --git a/chrome/locale/en-US/zotero/zotero.dtd b/chrome/locale/en-US/zotero/zotero.dtd @@ -165,6 +165,7 @@ <!ENTITY zotero.bibliography.title "Create Citation/Bibliography"> <!ENTITY zotero.bibliography.style.label "Citation Style:"> +<!ENTITY zotero.bibliography.locale.label "Language:"> <!ENTITY zotero.bibliography.outputMode "Output Mode:"> <!ENTITY zotero.bibliography.bibliography "Bibliography"> <!ENTITY zotero.bibliography.outputMethod "Output Method:"> diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js @@ -99,7 +99,6 @@ pref("extensions.zotero.export.lastTranslator", '14763d24-8ba0-45df-8f52-b8d1108 pref("extensions.zotero.export.translatorSettings", 'true,false'); pref("extensions.zotero.export.lastStyle", 'http://www.zotero.org/styles/chicago-note-bibliography'); pref("extensions.zotero.export.bibliographySettings", 'save-as-rtf'); -pref("extensions.zotero.export.bibliographyLocale", ''); pref("extensions.zotero.export.displayCharsetOption", false); pref("extensions.zotero.export.citePaperJournalArticleURL", false); pref("extensions.zotero.cite.automaticJournalAbbreviations", true);