diff --git a/build.sh b/build.sh index bb7b11e..e8fee15 100755 --- a/build.sh +++ b/build.sh @@ -3,8 +3,12 @@ # Note: The javascript is generated by the # package.json before calling this script. +mkdir dist #ensure there's a folder + #copy styles cp -v src/app/style.css dist/ +cp -v node_modules/material-design-lite/dist/material.css dist/ +cp -v node_modules/material-design-lite/dist/material.js dist/ #copy html menu cp -v src/app/menu/menu.tpl.html dist/ diff --git a/config.js b/config.js index 4dadddd..d9eff6f 100644 --- a/config.js +++ b/config.js @@ -14,7 +14,7 @@ System.config({ }, map: { - "angular": "github:angular/bower-angular@1.5.5", + "angular": "github:angular/bower-angular@1.5.8", "jquery": "npm:jquery@2.2.4", "lodash": "npm:lodash@4.12.0", "ngstorage": "npm:ngstorage@0.3.10", diff --git a/package.json b/package.json index e722887..55f9c6b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "clean": "rm -r dist", "build": "jspm bundle-sfx src/app/main.ts dist/app.js && ./build.sh", - "start": "browser-sync start -b google-chrome --startPath test/ --server --files 'src/**/*'", + "start": "browser-sync start --no-notify -b google-chrome --startPath test/ --server --files 'src/**/*'", "postinstall": "typings install && jspm install" }, "repository": { @@ -28,11 +28,12 @@ "dependencies": { "browser-sync": "^2.9.6", "jspm": "^0.16.39", + "material-design-lite": "^1.1.3", "typings": "^1.3.0" }, "jspm": { "dependencies": { - "angular": "github:angular/bower-angular@^1.5.5", + "angular": "github:angular/bower-angular@^1.5.8", "jquery": "npm:jquery@^2.2.4", "lodash": "npm:lodash@^4.12.0", "ngstorage": "npm:ngstorage@^0.3.10", diff --git a/src/app/index.appConfig.ts b/src/app/index.appConfig.ts deleted file mode 100644 index 08de000..0000000 --- a/src/app/index.appConfig.ts +++ /dev/null @@ -1,9 +0,0 @@ - -export function AppConfigInitializer ($logProvider: ng.ILogProvider) { - $logProvider.debugEnabled(true); -} - -export class AppConfigService { - serverUrl = 'https://imdb.uib.no/lexitags/lexitags/'; -} - diff --git a/src/app/main.ts b/src/app/main.ts index 754fb96..00c136c 100644 --- a/src/app/main.ts +++ b/src/app/main.ts @@ -5,9 +5,10 @@ import { BackendService, WebPageService, TagStorageService, - FileService} from './services/index'; -import {AppConfigInitializer, AppConfigService} from "./index.appConfig"; + FileService, + SettingsService} from './services/index'; import {MenuCtrl} from './menu/menu.controller'; +import {SettingsCtrl} from './menu/settings.controller'; import {preparePage} from './pageRebuilder'; import angular from 'angular'; import 'rangy'; @@ -25,20 +26,13 @@ else { function loadAngular() { angular.module('tagit', ['ngStorage']) - .config(AppConfigInitializer) - .service('AppConfigService', AppConfigService) + .service('SettingsService', SettingsService) .service('BackendService', BackendService) .service('WebPageService', WebPageService) .service('TagStorageService', TagStorageService) .service('FileService', FileService) + .controller('SettingsCtrl', SettingsCtrl) .controller('MenuCtrl', MenuCtrl) - .controller('TestCtrl', function () { - var vm = this; - vm.test = 'hello world'; - vm.alert = function () { - alert('test alert'); - } - }); angular.bootstrap( (document.getElementById("tagit-iframe")) diff --git a/src/app/menu/menu.controller.ts b/src/app/menu/menu.controller.ts index d1e3bf6..e11696a 100644 --- a/src/app/menu/menu.controller.ts +++ b/src/app/menu/menu.controller.ts @@ -13,26 +13,15 @@ export class MenuCtrl { selectedWord = ""; senses: Object[]; - backendService: BackendService; - webPageService: WebPageService; - tagStorageService: TagStorageService; - fileService: FileService; - $log: ng.ILogService; - $scope: ng.IScope; - /* @ngInject */ - constructor($scope: IVMScope, $log: angular.ILogService, - BackendService: BackendService, - WebPageService: WebPageService, - TagStorageService: TagStorageService, - FileService: FileService) { + constructor( + private $scope: IVMScope, + private $log: angular.ILogService, + private BackendService: BackendService, + private WebPageService: WebPageService, + private TagStorageService: TagStorageService, + private FileService: FileService) { $scope.vm = this; - this.$log = $log; - this.$scope = $scope; - this.backendService = BackendService; - this.webPageService = WebPageService; - this.tagStorageService = TagStorageService; - this.fileService = FileService; this.$scope.$on('wordWasSelected', (event, selectedWord) => { this.$log.debug(`Menucontroller received wordWasSelected event for: ${selectedWord}`); @@ -45,12 +34,12 @@ export class MenuCtrl { }); // Reload existing tags - var tagsToLoad = this.tagStorageService.loadTagsForCurrentPage(); + var tagsToLoad = this.TagStorageService.loadTagsForCurrentPage(); this.$log.debug('these tags were found in storage'); this.$log.debug(tagsToLoad); - this.webPageService.readdTagsToPage(tagsToLoad); + this.WebPageService.readdTagsToPage(tagsToLoad); } /** @@ -60,17 +49,17 @@ export class MenuCtrl { onSenseSelect(sense: ISense) { //remove all tags so that new tag range is serialized //based on a document without any highlights - this.webPageService.removeAllTagsFromPage(() => { + this.WebPageService.removeAllTagsFromPage(() => { //initialize and save the new tag - var senseTag = this.webPageService.initializeNewTag(sense); - this.tagStorageService.saveTag(senseTag); + var senseTag = this.WebPageService.initializeNewTag(sense); + this.TagStorageService.saveTag(senseTag); - // deactivate backendService for now. - // this.backendService.sendTaggedDataToServer(senseTag); + // deactivate BackendService for now. + this.BackendService.sendTaggedDataToServer(senseTag); //re-add tags, with new tag. Clear menu options. - this.webPageService.readdTagsToPage( - this.tagStorageService.loadTagsForCurrentPage() + this.WebPageService.readdTagsToPage( + this.TagStorageService.loadTagsForCurrentPage() ); this.clearMenuVariables(); }); @@ -84,7 +73,7 @@ export class MenuCtrl { this.$log.debug('Did not find chrome facilities. Can\'t download.') return; //do nothing } - this.fileService.saveFile(this.tagStorageService.loadTagsForCurrentPage()); + this.FileService.saveFile(this.TagStorageService.loadTagsForCurrentPage()); } downloadAllTagsForDomain() { @@ -92,7 +81,7 @@ export class MenuCtrl { this.$log.debug('Did not find chrome facilities. Can\'t download.') return; //do nothing } - this.fileService.saveFile(this.tagStorageService.loadAllTagsInLocalStorage()); + this.FileService.saveFile(this.TagStorageService.loadAllTagsInLocalStorage()); } /** @@ -100,23 +89,24 @@ export class MenuCtrl { */ removeTagsFromLocalStorage() { if (confirm('Really delete tags from the current page?')) { - this.webPageService.removeAllTagsFromPage(() => { - this.tagStorageService.deleteTagsFromCurrentPage() + this.WebPageService.removeAllTagsFromPage(() => { + this.TagStorageService.deleteTagsFromCurrentPage() }) } } onWordSelectedEvent = (newWord: string) => { if (countWords(newWord) > 2) { - this.selectedWord = "Wops! Plugin can't handle more than two words."; - this.senses = []; + this.selectedWord = "Wops! Plugin can't handle more than two words." + this.senses = [] } else if (newWord.length === 0) { this.clearMenuVariables(); } else { this.selectedWord = newWord; - this.backendService.callServer(newWord) + this.senses = [] + this.BackendService.callServer(newWord) .then((synsets: any) => { this.$log.debug(synsets); this.senses = synsets.data.senses; @@ -138,4 +128,9 @@ export class MenuCtrl { this.senses = []; } + isLoadingSenses() { + // if senses var has initialized, we check length to see if they've been loaded. + return this.senses && this.senses.length == 0 && this.selectedWord + } + } diff --git a/src/app/menu/menu.tpl.html b/src/app/menu/menu.tpl.html index c61557c..03f983b 100644 --- a/src/app/menu/menu.tpl.html +++ b/src/app/menu/menu.tpl.html @@ -3,9 +3,19 @@ - - - + -
-

Tag you're it

- -

Menu: - Download tags (current page) | - Download all tags (domain) | - Delete tags from current page -

+
-

- Mark one or two words on the page to the right. And we'll supply you with possible definitions. Select a definition and the - word will be tagged. -

+
+ +
-

- Currently selected word: {{vm.selectedWord}} -

+
- +
-
    -
  • - {{sense.word}} {{sense.explanation}} -
  • -
+
+ +

Actions: + Download tags (current page) | + Download all tags (domain) | + Delete tags from current page +

+ +

+ Mark one or two words on the page to the right. And we'll supply you with possible definitions. Select a definition and the + word will be tagged. +

+ +

+ Currently selected word: {{vm.selectedWord}} +

+ +

+ Currently selected word: No word selected. +

+ +
+
+
+ +
    + +
  • + Available sense tags: +
  • + +
  • + {{sense.word}} {{sense.explanation}} +
  • +
+ +
+ +
+ +
+ +

Changes will be automatically saved.

+ +
+ +

+ + +
+ As you go about tagging pages the tags will be posted to this server endpoint. +

+ +

+ + +
+ The email that will be included in the tag when it's sent to the server. +

+ +
+ +

Reset to default settings

+ +
+
+ \ No newline at end of file diff --git a/src/app/menu/settings.controller.ts b/src/app/menu/settings.controller.ts new file mode 100644 index 0000000..9ea678e --- /dev/null +++ b/src/app/menu/settings.controller.ts @@ -0,0 +1,51 @@ +'use strict'; + +import { + BackendService, + WebPageService, + TagStorageService, + FileService, + SettingsService} from '../services/index' +import {IVMScope, ISense} from '../index.interfaces' + +/** + * Responsible for making settings user editable + * and communicating those settings changes to + * chrome extension background page. + */ +export class SettingsCtrl { + + serverToSendTo + senseQueryUrl + + constructor( + private $scope: IVMScope, + $log: angular.ILogService, + BackendService: BackendService, + WebPageService: WebPageService, + TagStorageService: TagStorageService, + private SettingsService: SettingsService) { + + $scope.vm = this; + this.serverToSendTo = SettingsService.senseDestinationUrl + this.senseQueryUrl = SettingsService.senseQueryUrl + + $scope.$watch('vm.serverToSendTo', (newValue: string, oldValue) => { + SettingsService.senseDestinationUrl = newValue; + }) + + } + + resetDefaults() { + + if (!confirm('Reset settings to default values?')) { + return //exit if user says 'no' + } + + this.SettingsService.resetSettings(() => { + this.serverToSendTo = this.SettingsService.senseDestinationUrl + }); + } + + +} \ No newline at end of file diff --git a/src/app/services/backend.service.ts b/src/app/services/backend.service.ts index e584046..6ba2837 100644 --- a/src/app/services/backend.service.ts +++ b/src/app/services/backend.service.ts @@ -1,6 +1,6 @@ 'use strict'; -import {AppConfigService} from '../index.appConfig'; +import {SettingsService} from '../services/index'; import {ISenseTag} from '../index.interfaces'; /** @@ -9,18 +9,13 @@ import {ISenseTag} from '../index.interfaces'; */ export class BackendService { - $http: ng.IHttpService; - $log: ng.ILogService; - $q: ng.IQService; - private serverUrl: string = null; - private previousCall: string; + private previousCall: string - /* @ngInject */ - constructor($http: ng.IHttpService, $q: ng.IQService, $log: ng.ILogService, AppConfigService: AppConfigService) { - this.$http = $http; - this.$log = $log; - this.$q = $q; - this.serverUrl = AppConfigService.serverUrl; + constructor( + private $http: ng.IHttpService, + private $q: ng.IQService, + private $log: ng.ILogService, + private SettingsService: SettingsService) { } callServer(word: string) { @@ -34,25 +29,12 @@ export class BackendService { //alright let's make this query! this.previousCall = word; - return this.$http.get(this.serverUrl + word); + return this.$http.get(`${this.SettingsService.senseQueryUrl}/${word}`); } sendTaggedDataToServer(senseTag: ISenseTag) { this.$log.debug('sendTaggedDataToServer() was called'); - - this.$log.debug('would have sent this to the server:'); - this.$log.debug(senseTag); - this.$log.debug('please uncomment code for actually sending to server'); - - // this.$http.post("example.org", senseTag) - // .then((response) => { - // this.$log.debug('successfully posted to server. Response:'); - // this.$log.debug(response); - // }) - // .catch((error) => { - // this.$log.error('something went wrong when posting to server'); - // this.$log.error(error); - // }); + return this.$http.post(this.SettingsService.senseDestinationUrl, senseTag) } } \ No newline at end of file diff --git a/src/app/services/file.service.ts b/src/app/services/file.service.ts index 4116aa1..2512afb 100644 --- a/src/app/services/file.service.ts +++ b/src/app/services/file.service.ts @@ -5,12 +5,7 @@ import {ISenseTag} from '../index.interfaces'; //Responsible for saving. export class FileService { - $log: ng.ILogService; - - /* @ngInject */ - constructor($log: ng.ILogService) { - this.$log = $log; - } + constructor(private $log: ng.ILogService) {} saveFile(content: ISenseTag[]) { var json = JSON.stringify(content, null, 2); diff --git a/src/app/services/index.ts b/src/app/services/index.ts index a08e074..6a606fc 100644 --- a/src/app/services/index.ts +++ b/src/app/services/index.ts @@ -2,3 +2,4 @@ export * from './backend.service'; export * from './file.service'; export * from './tagStorage.service'; export * from './webpage.service'; +export * from './settings.service'; diff --git a/src/app/services/settings.service.ts b/src/app/services/settings.service.ts new file mode 100644 index 0000000..2961f63 --- /dev/null +++ b/src/app/services/settings.service.ts @@ -0,0 +1,93 @@ +/** + * Responsible for handling persisting and retrieving + * *select* user settings. Some settings might not be user + * editable. + */ +export class SettingsService { + + // where to query for senses + private _senseQueryUrl = 'https://imdb.uib.no/lexitags/lexitags' + private _defaultSenseQueryUrl = 'https://imdb.uib.no/lexitags/lexitags' + + // where to send the senses + private _senseDestinationUrl = 'https://www.example.org/somewhere' + private _defaultSenseDestinationUrl = 'https://www.example.org/somewhere' + + private _emailToTagWith = '' + + constructor(private $log: ng.ILogService) { + + // fall back to default value if no user defined setting + this.loadSetting('tagitSenseQueryUrl', (loadedSetting) => { + if (loadedSetting) this._senseQueryUrl = loadedSetting + else this._senseQueryUrl = this._defaultSenseQueryUrl + }) + + this.loadSetting('tagitSenseDestinationUrl', (loadedSetting) => { + if (loadedSetting) this._senseDestinationUrl = loadedSetting + else this._senseDestinationUrl = this._defaultSenseDestinationUrl + }) + + } + + resetSettings(callback) { + + // reset to default values + this._defaultSenseQueryUrl = this._defaultSenseQueryUrl + this._senseDestinationUrl = this._defaultSenseDestinationUrl + + // delete from chrome storage + if (typeof chrome.storage !== 'undefined') { + const done = _.after(2, callback); + chrome.storage.sync.remove('tagitSenseDestinationUrl', done) + chrome.storage.sync.remove('tagitSenseQueryUrl', done) + } + // delete from localstorage (dev mode) + else { + localStorage.removeItem('tagitSenseQueryUrl') + localStorage.removeItem('tagitSenseDestinationUrl') + callback() + } + } + + private loadSetting(whatToFind: string, callback) { + // support for dev mode (when not loaded as a proper chrome plugin). + if (typeof chrome.storage === 'undefined') { + callback(localStorage.getItem(whatToFind)) + return // exit function + } + + const syncStorage = chrome.storage.sync + syncStorage.get(whatToFind, callback) + } + + private saveSetting(nameOfThingToSave: string, valueToSave) { + // support for dev mode (when not loaded as a proper chrome plugin). + if (typeof chrome.storage === 'undefined') { + localStorage.setItem(nameOfThingToSave, valueToSave) + return // exit function + } + + const syncStorage = chrome.storage.sync + syncStorage.set({ nameOfThingToSave: valueToSave }) + } + + get senseQueryUrl() { + return this._senseQueryUrl + } + + set senseQueryUrl(newUrl: string) { + this._senseQueryUrl = newUrl + } + + get senseDestinationUrl() { + return this._senseDestinationUrl + } + + set senseDestinationUrl(newUrl: string) { + this._senseDestinationUrl = newUrl + this.saveSetting('tagitSenseDestinationUrl', newUrl) + } + +} + diff --git a/src/app/services/tagStorage.service.ts b/src/app/services/tagStorage.service.ts index c6e2ecb..5357a09 100644 --- a/src/app/services/tagStorage.service.ts +++ b/src/app/services/tagStorage.service.ts @@ -6,15 +6,12 @@ import {ISenseTag} from '../index.interfaces'; // any tags related to the current page export class TagStorageService { - $http: ng.IHttpService; - $log: ng.ILogService; $localStorage: { tagStorage: ISenseTag[] }; - /* @ngInject */ - constructor($http: ng.IHttpService, $log: ng.ILogService, + constructor( + private $http: ng.IHttpService, + private $log: ng.ILogService, $localStorage: any) { - this.$http = $http; - this.$log = $log; this.$localStorage = $localStorage; if (window.location.href.indexOf("tagitreset") !== -1) { diff --git a/src/app/services/webpage.service.ts b/src/app/services/webpage.service.ts index 997c608..d4f8914 100644 --- a/src/app/services/webpage.service.ts +++ b/src/app/services/webpage.service.ts @@ -14,20 +14,17 @@ import rangy from 'rangy'; */ export class WebPageService { - $log: ng.ILogService; // when clicking the menu to select a synset // we need to remember what the currently selected word was - tagStorageService: TagStorageService; - rootScopeService: ng.IRootScopeService; savedSelection: Object; savedText: string; listOfFramesWithContent: (HTMLFrameElement | HTMLIFrameElement)[] = []; - /* @ngInject */ - constructor($log: ng.ILogService, TagStorageService: TagStorageService, $rootScope: ng.IRootScopeService) { - this.$log = $log; - this.tagStorageService = TagStorageService; - this.rootScopeService = $rootScope; + constructor( + private $log: ng.ILogService, + private TagStorageService: TagStorageService, + private $rootScope: ng.IRootScopeService) { + this.wireUpListener(); rangy.init(); } @@ -45,17 +42,17 @@ export class WebPageService { } else if (wasRemoveTagButtonClicked(evt)) { this.$log.debug('remove tag button was clicked'); - removeTagFromWebAndStorage(evt, this.tagStorageService); + removeTagFromWebAndStorage(evt, this.TagStorageService); } else if (documentThatWasClicked.getSelection().toString() !== '') { resetSavedSelection(this.savedSelection); this.savedSelection = rangy.saveSelection(documentThatWasClicked); this.savedText = joinLongWords(documentThatWasClicked.getSelection().toString()); - this.rootScopeService.$broadcast('wordWasSelected', this.savedText); + this.$rootScope.$broadcast('wordWasSelected', this.savedText); } else { resetSavedSelection(this.savedSelection); this.savedText = ''; - this.rootScopeService.$broadcast('wordWasDeSelected', null); + this.$rootScope.$broadcast('wordWasDeSelected', null); } /** diff --git a/src/plugin-specific/manifest.json b/src/plugin-specific/manifest.json index bc26b98..4d18b81 100644 --- a/src/plugin-specific/manifest.json +++ b/src/plugin-specific/manifest.json @@ -1,7 +1,7 @@ { "name": "Tag you're it", "description": "A browser tool for tagging words with exact definitions.", - "version": "0.0.9", + "version": "1.0.0", "manifest_version": 2, "icons": { "16": "icon16.png", @@ -20,8 +20,7 @@ "web_accessible_resources": [ "*.html", "*.css", - "vendor/**/*.js", - "bundle.js" + "*.js" ], "browser_action": { "default_icon": "icon48.png" diff --git a/test/index.html b/test/index.html index 25df4db..1a26639 100644 --- a/test/index.html +++ b/test/index.html @@ -8,12 +8,11 @@ -