├── README ├── chrome.manifest ├── content ├── browser.js ├── browser.xul ├── firstrun.js ├── media │ ├── by.png │ ├── cc-plus.png │ ├── cc.png │ ├── cc.small.png │ ├── nc.png │ ├── nd.png │ ├── pd.png │ ├── remix.png │ ├── sa.png │ ├── share.png │ └── zero.png ├── pageInfo.js └── pageInfo.xul ├── defaults └── preferences │ └── preferences.js ├── doc ├── FUNCSPEC ├── WEBSITES └── proposal.pdf ├── icon.png ├── install.rdf ├── locale ├── en-US │ └── locale.properties └── ru-RU │ └── locale.properties ├── module ├── bootstrap.js ├── ccffext.js ├── hacks │ └── hacks.js ├── license.js └── rdfa.js ├── skin ├── browser.css ├── icon.svg ├── icon32.png ├── icon64.png └── pageInfo.css └── xpi.sh /README: -------------------------------------------------------------------------------- 1 | OpenAttribute for Firefox 2 | ========================= 3 | 4 | OpenAttribute for Firefox adds support for displaying license and 5 | attribution information for works as you browse. If the page or items 6 | on the page are licensed, a CC icon will appear in the URL bar, which 7 | can be clicked to display the author and license information. This 8 | metadata is used to generate HTML which can be used to attribute 9 | reuse. 10 | 11 | This add-on is the successor to MozCC 12 | (http://wiki.creativecommons.org/MozCC) and was initially developed 13 | with support from Google Summer of Code. 14 | -------------------------------------------------------------------------------- /chrome.manifest: -------------------------------------------------------------------------------- 1 | # The "ccffext" is chosen to be the internal identifier of the extension 2 | 3 | # Main data 4 | content ccffext content/ 5 | 6 | # Localizations 7 | # For now, only the "en-US" locale is supported 8 | locale ccffext en-US locale/en-US/ 9 | 10 | # Skins (style definitions) 11 | skin ccffext classic/1.0 skin/ 12 | 13 | # Code modules 14 | resource ccffext module/ 15 | 16 | # Changes to the UI: the main window is altered, as well as the "Page Info" frame 17 | overlay chrome://browser/content/browser.xul chrome://ccffext/content/browser.xul 18 | overlay chrome://browser/content/pageinfo/pageInfo.xul chrome://ccffext/content/pageInfo.xul 19 | -------------------------------------------------------------------------------- /content/browser.js: -------------------------------------------------------------------------------- 1 | var gCcHandler = { 2 | 3 | // Smart Getters 4 | get _icon () { 5 | return document.getElementById('ccffext-icon'); 6 | }, 7 | 8 | get _popup () { 9 | return document.getElementById('ccffext-popup'); 10 | }, 11 | 12 | get _popup_work_title () { 13 | return document.getElementById('ccffext-popup-work-title'); 14 | }, 15 | 16 | get _popup_attribution () { 17 | return document.getElementById('ccffext-popup-attribution-link'); 18 | }, 19 | 20 | get _popup_license () { 21 | return document.getElementById('ccffext-popup-license-link'); 22 | }, 23 | 24 | get _popup_license_band () { 25 | return document.getElementById('ccffext-popup-license-band'); 26 | }, 27 | 28 | get _popup_num_licensed_objects () { 29 | return document.getElementById('ccffext-popup-licensed-objects'); 30 | }, 31 | 32 | get _license_browser () { 33 | return document.getElementById('ccffext-license-frame'); 34 | }, 35 | 36 | resetPopup : function() { 37 | // hide popup elements which may or may not be shown for this page 38 | this._popup_license.hidden = true; 39 | this._popup_work_title.hidden = true; 40 | this._popup_num_licensed_objects.hidden = true; 41 | this._popup_attribution.hidden = true; 42 | this._popup_license_band.setAttribute( 43 | "class", "band-reset"); 44 | }, 45 | 46 | // Popup Handlers 47 | handleIconClick : function(e) { 48 | 49 | this.resetPopup(); 50 | 51 | // update the popup with the license information 52 | var doc_subject = {uri:content.document.location.href}; 53 | 54 | // -- license 55 | var license = ccffext.objects.getLicense( 56 | content.document.location.href, doc_subject); 57 | var is_doc_licensed = false; 58 | 59 | if ("undefined" != typeof license) { 60 | // document is licensed 61 | is_doc_licensed = true; 62 | 63 | this._popup_license.hidden = false; 64 | this._popup_license.value = license.uri; 65 | this._popup_license.setAttribute('href', license.uri); 66 | 67 | // ---- get the license details and update the popup when ready 68 | licenses.getLicenseInfo( 69 | ccffext.objects.getLicense(content.document.location.href, 70 | doc_subject).uri, 71 | function(license) { 72 | gCcHandler._popup_license.value = license.name; 73 | gCcHandler._popup_license_band.setAttribute( 74 | "class", "band-" + license.color); 75 | }, []); 76 | 77 | // -- title 78 | this._popup_work_title.hidden = false; 79 | this._popup_work_title.value = ccffext.objects.getDisplayTitle( 80 | content.document.location.href, doc_subject); 81 | 82 | // -- attribution link 83 | let author = ccffext.objects.getAuthor( 84 | content.document.location.href, doc_subject); 85 | let author_uri = ccffext.objects.getAuthorUri( 86 | content.document.location.href, doc_subject); 87 | 88 | if ("undefined" != typeof author || 89 | "undefined" != typeof author_uri) { 90 | 91 | // at least one has been provided 92 | this._popup_attribution.hidden = false; 93 | 94 | if ("undefined" == typeof author && 95 | "undefined" != typeof author_uri) 96 | author = author_uri; 97 | 98 | if ("undefined" != typeof author) { 99 | // attribution name was supplied 100 | this._popup_attribution.value = author; 101 | } 102 | 103 | if ("undefined" != typeof author_uri) { 104 | this._popup_attribution.setAttribute('href', 105 | author_uri.uri); 106 | this._popup_attribution.setAttribute( 107 | "class", "text-link"); 108 | } else { 109 | // no attribution URL 110 | this._popup_attribution.setAttribute( 111 | "class", ""); 112 | } 113 | } 114 | 115 | } // if license is not undefined 116 | 117 | // how many licensed objects described by this page, excluding the page 118 | var count = ccffext.objects.getLicensedSubjects( 119 | content.document.location.href).length - (is_doc_licensed?1:0); 120 | if (count > 0) { 121 | this._popup_num_licensed_objects.value = 122 | ccffext.l10n.get("icon.title.label", count); 123 | this._popup_num_licensed_objects.hidden = false; 124 | } 125 | 126 | // show the popup 127 | this._popup.hidden = false; 128 | 129 | var position = (getComputedStyle(gNavToolbox, "").direction == "rtl") ? 'after_end' : 'after_start'; 130 | 131 | this._popup.openPopup(this._icon, position); 132 | }, 133 | 134 | handleMoreInfo : function(e) { 135 | gCcHandler.hidePopup(); 136 | BrowserPageInfo(null,'ccffext-tab'); 137 | }, 138 | 139 | handleCopyHtml : function(e) { 140 | const clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"]. 141 | getService(Components.interfaces.nsIClipboardHelper); 142 | clipboard.copyString( 143 | ccffext.objects.getAttributionHtml( 144 | content.document.location.href, 145 | {'uri':content.document.location.href})); 146 | 147 | // close the popup 148 | gCcHandler.hidePopup(); 149 | }, 150 | 151 | handleCopyText : function(e) { 152 | const clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"]. 153 | getService(Components.interfaces.nsIClipboardHelper); 154 | clipboard.copyString( 155 | ccffext.objects.getAttributionText( 156 | content.document.location.href, 157 | {'uri':content.document.location.href})); 158 | 159 | // close the popup 160 | gCcHandler.hidePopup(); 161 | }, 162 | 163 | hidePopup : function() { 164 | document.getElementById('ccffext-popup').hidePopup(); 165 | }, 166 | 167 | // URL Bar manipulators 168 | hideIcon : function() { 169 | this._icon.hidden = true; 170 | }, 171 | 172 | showIcon : function(document) { 173 | const objects = ccffext.objects.getLicensedSubjects( 174 | document.location.href); 175 | 176 | this._icon.hidden = false; 177 | gCcHandler._icon.setAttribute("tooltiptext", 178 | ccffext.l10n.get("icon.title.label", 179 | objects.length)); 180 | }, 181 | 182 | showIconIfLicenseInfo : function(document) { 183 | 184 | // if no document is provided, default to the active document 185 | if ("undefined" == typeof document) { 186 | document = gBrowser.contentDocument; 187 | } 188 | 189 | // if this is the active document, hide the icon 190 | if (gBrowser.contentDocument == document) 191 | gCcHandler.hideIcon(); 192 | 193 | if (document instanceof HTMLDocument) { 194 | ccffext.objects.callbackify( 195 | document, 196 | function(document,objects) { 197 | if (gBrowser.contentDocument == document) 198 | gCcHandler.showIcon(document); 199 | }, 200 | function(document) { 201 | // license not cached 202 | ccffext.objects.parse(document.location.href, document); 203 | }); 204 | } 205 | } 206 | }; 207 | 208 | /** 209 | * Register window load listener which adds event listeners for tab, 210 | * location, and state changes. 211 | **/ 212 | window.addEventListener("load",function() { 213 | 214 | gBrowser.addEventListener( 215 | "TabSelect", 216 | function(e) { gCcHandler.showIconIfLicenseInfo();}, false); 217 | gBrowser.tabContainer.addEventListener( 218 | "TabSelect", 219 | function(e) { gCcHandler.showIconIfLicenseInfo();}, false); 220 | 221 | gBrowser.addTabsProgressListener({ 222 | onLocationChange : function(browser, progress,request,uri) { 223 | 224 | // A tab is opened, closed, or switched to 225 | // Show the location bar icon if license information is present 226 | 227 | // XXX disabling; this is called before the browser fully 228 | // -- loads the document, causing errors in the parse process 229 | // gCcHandler.showIconIfLicenseInfo(progress.DOMWindow.document); 230 | 231 | }, 232 | 233 | onStateChange : function(browser, progress,request,flag,status) { 234 | 235 | // A document in an existing tab stopped loading 236 | if (flag & Components.interfaces.nsIWebProgressListener.STATE_STOP) 237 | { 238 | const doc = progress.DOMWindow.document; 239 | 240 | gCcHandler.showIconIfLicenseInfo(progress.DOMWindow.document); 241 | } 242 | }, 243 | 244 | }); 245 | 246 | licenses.init(gCcHandler._license_browser); 247 | 248 | },false); 249 | -------------------------------------------------------------------------------- /content/browser.xul: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 13 | 14 | 15 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 |