addon-sdk/source/examples/annotator/lib/main.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 var widgets = require('sdk/widget');
michael@0 6 var pageMod = require('sdk/page-mod');
michael@0 7 var data = require('sdk/self').data;
michael@0 8 var panels = require('sdk/panel');
michael@0 9 var simpleStorage = require('sdk/simple-storage');
michael@0 10 var notifications = require("sdk/notifications");
michael@0 11
michael@0 12 /*
michael@0 13 Global variables
michael@0 14 * Boolean to indicate whether the add-on is switched on or not
michael@0 15 * Array for all workers associated with the 'selector' page mod
michael@0 16 * Array for all workers associated with the 'matcher' page mod
michael@0 17 */
michael@0 18 var annotatorIsOn = false;
michael@0 19 var selectors = [];
michael@0 20 var matchers = [];
michael@0 21
michael@0 22 if (!simpleStorage.storage.annotations)
michael@0 23 simpleStorage.storage.annotations = [];
michael@0 24
michael@0 25 /*
michael@0 26 Update the matchers: call this whenever the set of annotations changes
michael@0 27 */
michael@0 28 function updateMatchers() {
michael@0 29 matchers.forEach(function (matcher) {
michael@0 30 matcher.postMessage(simpleStorage.storage.annotations);
michael@0 31 });
michael@0 32 }
michael@0 33
michael@0 34 /*
michael@0 35 Constructor for an Annotation object
michael@0 36 */
michael@0 37 function Annotation(annotationText, anchor) {
michael@0 38 this.annotationText = annotationText;
michael@0 39 this.url = anchor[0];
michael@0 40 this.ancestorId = anchor[1];
michael@0 41 this.anchorText = anchor[2];
michael@0 42 }
michael@0 43
michael@0 44 /*
michael@0 45 Function to deal with a new annotation.
michael@0 46 Create a new annotation object, store it, and
michael@0 47 notify all the annotators of the change.
michael@0 48 */
michael@0 49 function handleNewAnnotation(annotationText, anchor) {
michael@0 50 var newAnnotation = new Annotation(annotationText, anchor);
michael@0 51 simpleStorage.storage.annotations.push(newAnnotation);
michael@0 52 updateMatchers();
michael@0 53 }
michael@0 54
michael@0 55 /*
michael@0 56 Function to tell the selector page mod that the add-on has become (in)active
michael@0 57 */
michael@0 58 function activateSelectors() {
michael@0 59 selectors.forEach(
michael@0 60 function (selector) {
michael@0 61 selector.postMessage(annotatorIsOn);
michael@0 62 });
michael@0 63 }
michael@0 64
michael@0 65 /*
michael@0 66 Toggle activation: update the on/off state and notify the selectors.
michael@0 67 */
michael@0 68 function toggleActivation() {
michael@0 69 annotatorIsOn = !annotatorIsOn;
michael@0 70 activateSelectors();
michael@0 71 return annotatorIsOn;
michael@0 72 }
michael@0 73
michael@0 74 function detachWorker(worker, workerArray) {
michael@0 75 var index = workerArray.indexOf(worker);
michael@0 76 if(index != -1) {
michael@0 77 workerArray.splice(index, 1);
michael@0 78 }
michael@0 79 }
michael@0 80
michael@0 81 exports.main = function() {
michael@0 82
michael@0 83 /*
michael@0 84 The widget provides a mechanism to switch the selector on or off, and to
michael@0 85 view the list of annotations.
michael@0 86
michael@0 87 The selector is switched on/off with a left-click, and the list of annotations
michael@0 88 is displayed on a right-click.
michael@0 89 */
michael@0 90 var widget = widgets.Widget({
michael@0 91 id: 'toggle-switch',
michael@0 92 label: 'Annotator',
michael@0 93 contentURL: data.url('widget/pencil-off.png'),
michael@0 94 contentScriptWhen: 'ready',
michael@0 95 contentScriptFile: data.url('widget/widget.js')
michael@0 96 });
michael@0 97
michael@0 98 widget.port.on('left-click', function() {
michael@0 99 console.log('activate/deactivate');
michael@0 100 widget.contentURL = toggleActivation() ?
michael@0 101 data.url('widget/pencil-on.png') :
michael@0 102 data.url('widget/pencil-off.png');
michael@0 103 });
michael@0 104
michael@0 105 widget.port.on('right-click', function() {
michael@0 106 console.log('show annotation list');
michael@0 107 annotationList.show();
michael@0 108 });
michael@0 109
michael@0 110 /*
michael@0 111 The selector page-mod enables the user to select page elements to annotate.
michael@0 112
michael@0 113 It is attached to all pages but only operates if the add-on is active.
michael@0 114
michael@0 115 The content script highlights any page elements which can be annotated. If the
michael@0 116 user clicks a highlighted element it sends a message to the add-on containing
michael@0 117 information about the element clicked, which is called the anchor of the
michael@0 118 annotation.
michael@0 119
michael@0 120 When we receive this message we assign the anchor to the annotationEditor and
michael@0 121 display it.
michael@0 122 */
michael@0 123 var selector = pageMod.PageMod({
michael@0 124 include: ['*'],
michael@0 125 contentScriptWhen: 'ready',
michael@0 126 contentScriptFile: [data.url('jquery-1.4.2.min.js'),
michael@0 127 data.url('selector.js')],
michael@0 128 onAttach: function(worker) {
michael@0 129 worker.postMessage(annotatorIsOn);
michael@0 130 selectors.push(worker);
michael@0 131 worker.port.on('show', function(data) {
michael@0 132 annotationEditor.annotationAnchor = data;
michael@0 133 annotationEditor.show();
michael@0 134 });
michael@0 135 worker.on('detach', function () {
michael@0 136 detachWorker(this, selectors);
michael@0 137 });
michael@0 138 }
michael@0 139 });
michael@0 140
michael@0 141 /*
michael@0 142 The annotationEditor panel is the UI component used for creating
michael@0 143 new annotations. It contains a text area for the user to
michael@0 144 enter the annotation.
michael@0 145
michael@0 146 When we are ready to display the editor we assign its 'anchor' property
michael@0 147 and call its show() method.
michael@0 148
michael@0 149 Its content script sends the content of the text area to the add-on
michael@0 150 when the user presses the return key.
michael@0 151
michael@0 152 When we receives this message we create a new annotation using the anchor
michael@0 153 and the text the user entered, store it, and hide the panel.
michael@0 154 */
michael@0 155 var annotationEditor = panels.Panel({
michael@0 156 width: 220,
michael@0 157 height: 220,
michael@0 158 contentURL: data.url('editor/annotation-editor.html'),
michael@0 159 contentScriptFile: data.url('editor/annotation-editor.js'),
michael@0 160 onMessage: function(annotationText) {
michael@0 161 if (annotationText)
michael@0 162 handleNewAnnotation(annotationText, this.annotationAnchor);
michael@0 163 annotationEditor.hide();
michael@0 164 },
michael@0 165 onShow: function() {
michael@0 166 this.postMessage('focus');
michael@0 167 }
michael@0 168 });
michael@0 169
michael@0 170 /*
michael@0 171 The annotationList panel is the UI component that lists all the annotations
michael@0 172 the user has entered.
michael@0 173
michael@0 174 On its 'show' event we pass it the array of annotations.
michael@0 175
michael@0 176 The content script creates the HTML elements for the annotations, and
michael@0 177 intercepts clicks on the links, passing them back to the add-on to open them
michael@0 178 in the browser.
michael@0 179 */
michael@0 180 var annotationList = panels.Panel({
michael@0 181 width: 420,
michael@0 182 height: 200,
michael@0 183 contentURL: data.url('list/annotation-list.html'),
michael@0 184 contentScriptFile: [data.url('jquery-1.4.2.min.js'),
michael@0 185 data.url('list/annotation-list.js')],
michael@0 186 contentScriptWhen: 'ready',
michael@0 187 onShow: function() {
michael@0 188 this.postMessage(simpleStorage.storage.annotations);
michael@0 189 },
michael@0 190 onMessage: function(message) {
michael@0 191 require('sdk/tabs').open(message);
michael@0 192 }
michael@0 193 });
michael@0 194
michael@0 195 /*
michael@0 196 We listen for the OverQuota event from simple-storage.
michael@0 197 If it fires we just notify the user and delete the most
michael@0 198 recent annotations until we are back in quota.
michael@0 199 */
michael@0 200 simpleStorage.on("OverQuota", function () {
michael@0 201 notifications.notify({
michael@0 202 title: 'Storage space exceeded',
michael@0 203 text: 'Removing recent annotations'});
michael@0 204 while (simpleStorage.quotaUsage > 1)
michael@0 205 simpleStorage.storage.annotations.pop();
michael@0 206 });
michael@0 207
michael@0 208 /*
michael@0 209 The matcher page-mod locates anchors on web pages and prepares for the
michael@0 210 annotation to be displayed.
michael@0 211
michael@0 212 It is attached to all pages, and when it is attached we pass it the complete
michael@0 213 list of annotations. It looks for anchors in its page. If it finds one it
michael@0 214 highlights the anchor and binds mouseenter/mouseout events to 'show' and 'hide'
michael@0 215 messages to the add-on.
michael@0 216
michael@0 217 When the add-on receives the 'show' message it assigns the annotation text to
michael@0 218 the annotation panel and shows it.
michael@0 219
michael@0 220 Note that the matcher is active whether or not the add-on is active:
michael@0 221 'inactive' only means that the user can't create new add-ons, they can still
michael@0 222 see old ones.
michael@0 223 */
michael@0 224 var matcher = pageMod.PageMod({
michael@0 225 include: ['*'],
michael@0 226 contentScriptWhen: 'ready',
michael@0 227 contentScriptFile: [data.url('jquery-1.4.2.min.js'),
michael@0 228 data.url('matcher.js')],
michael@0 229 onAttach: function(worker) {
michael@0 230 if(simpleStorage.storage.annotations) {
michael@0 231 worker.postMessage(simpleStorage.storage.annotations);
michael@0 232 }
michael@0 233 worker.port.on('show', function(data) {
michael@0 234 annotation.content = data;
michael@0 235 annotation.show();
michael@0 236 });
michael@0 237 worker.port.on('hide', function() {
michael@0 238 annotation.content = null;
michael@0 239 annotation.hide();
michael@0 240 });
michael@0 241 worker.on('detach', function () {
michael@0 242 detachWorker(this, matchers);
michael@0 243 });
michael@0 244 matchers.push(worker);
michael@0 245 }
michael@0 246 });
michael@0 247
michael@0 248 /*
michael@0 249 The annotation panel is the UI component that displays an annotation.
michael@0 250
michael@0 251 When we are ready to show it we assign its 'content' attribute to contain
michael@0 252 the annotation text, and that gets sent to the content process in onShow().
michael@0 253 */
michael@0 254 var annotation = panels.Panel({
michael@0 255 width: 200,
michael@0 256 height: 180,
michael@0 257 contentURL: data.url('annotation/annotation.html'),
michael@0 258 contentScriptFile: [data.url('jquery-1.4.2.min.js'),
michael@0 259 data.url('annotation/annotation.js')],
michael@0 260 contentScriptWhen: 'ready',
michael@0 261 onShow: function() {
michael@0 262 this.postMessage(this.content);
michael@0 263 }
michael@0 264 });
michael@0 265
michael@0 266 }

mercurial