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.

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

mercurial