Skip to content

Instantly share code, notes, and snippets.

@sjl
Created October 28, 2011 18:17
Show Gist options
  • Save sjl/1322959 to your computer and use it in GitHub Desktop.
Save sjl/1322959 to your computer and use it in GitHub Desktop.
diff --git a/README.markdown b/README.markdown
index d34e76b..42029fb 100644
--- a/README.markdown
+++ b/README.markdown
@@ -72,3 +72,12 @@ standard Django one, you just have to run (while the virtualenv is activated):
pip install werkzeug
And then use `./dev-runserver.sh plus` to run it.
+
+### bpython shell
+
+If you want to use the awesome bpython shell instead of the normal one you just
+need to run (while the virtualenv is activated):
+
+ pip install bpython
+
+Now when you run `pm shell` it will use bpython automatically.
diff --git a/apps/videos/models.py b/apps/videos/models.py
index 7baf7ad..3807dd6 100644
--- a/apps/videos/models.py
+++ b/apps/videos/models.py
@@ -670,7 +670,7 @@ class SubtitleLanguage(models.Model):
else:
return self.is_complete
- def get_widget_url(self):
+ def get_widget_url(self, mode=None):
# duplicates unisubs.widget.SubtitleDialogOpener.prototype.openDialogOrRedirect_
video = self.video
video_url = video.get_video_url()
@@ -680,7 +680,8 @@ class SubtitleLanguage(models.Model):
"effectiveVideoURL": video_url,
"languageCode": self.language,
"subLanguagePK": self.pk,
- "originalLanguageCode": video.language }
+ "originalLanguageCode": video.language,
+ "mode": mode, }
if self.is_dependent():
config['baseLanguagePK'] = self.standard_language and self.standard_language.pk
return reverse('onsite_widget')+'?config='+urlquote_plus(json.dumps(config))
diff --git a/apps/widget/views.py b/apps/widget/views.py
index 589bd30..c772991 100644
--- a/apps/widget/views.py
+++ b/apps/widget/views.py
@@ -23,11 +23,12 @@ from django.template.defaultfilters import urlize, linebreaks, force_escape
from django.shortcuts import render_to_response, redirect
from django.utils.http import cookie_date
from django.contrib.sites.models import Site
+from django.core.urlresolvers import reverse
from django.template import RequestContext
from videos import models
from widget.srt_subs import captions_and_translations_to_srt, captions_to_srt, SSASubtitles
import simplejson as json
-from simplejson.decoder import JSONDecodeError, JSONDecodeError
+from simplejson.decoder import JSONDecodeError
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
import widget
@@ -105,12 +106,19 @@ def onsite_widget(request):
if not 'effectiveVideoURL' in config:
config['effectiveVideoURL'] = video.get_video_url()
- team_videos = list(video.teamvideo_set.all()[:1])
+ team_videos = list(video.teamvideo_set.all().select_related('team')[:1])
if team_videos:
+ team = team_videos[0].team
+
config['guidelines'] = dict(
[(s.key_name.split('_', 1)[-1],
linebreaks(urlize(force_escape(s.data))))
- for s in team_videos[0].team.settings.guidelines()])
+ for s in team.settings.guidelines()
+ if s.data.strip()])
+
+ # TODO: Go to the tasks panel once the history stuff is implemented
+ config['team_url'] = reverse('teams:settings',
+ kwargs={'slug': team.slug})
else:
config['guidelines'] = {}
@@ -138,7 +146,7 @@ def onsite_widget_resume(request):
if not video_id:
raise Http404
- video = get_object_or_404(models.Video, video_id=video_id)
+ get_object_or_404(models.Video, video_id=video_id)
context['widget_params'] = json.dumps(config)
general_settings = {}
@@ -157,7 +165,6 @@ def widget_demo(request):
context['help_mode'] = True
else:
context['help_mode'] = False
- spaces = ' ' * 9
params = base_widget_params(request)
context['embed_js_url'] = \
"http://{0}/embed{1}.js".format(
diff --git a/media/js/unisubs.js b/media/js/unisubs.js
index e9e5860..c4aa4ba 100644
--- a/media/js/unisubs.js
+++ b/media/js/unisubs.js
@@ -54,6 +54,21 @@ unisubs.currentUsername = null;
unisubs.returnURL = null;
/**
+ * @type {?object}
+ */
+unisubs.guidelines = {};
+
+/**
+ * @type {?string}
+ */
+unisubs.team_url = '';
+
+/**
+ * @type {?object}
+ */
+unisubs.mode = null;
+
+/**
* Current version of embed code. Set when widget gets inital
* state from server. Corresponds to value in settings.EMBED_JS_VERSION
* in Django settings.py file.
diff --git a/media/js/widget/api/api.js b/media/js/widget/api/api.js
index 443b424..e09e23b 100644
--- a/media/js/widget/api/api.js
+++ b/media/js/widget/api/api.js
@@ -72,11 +72,18 @@ unisubs.api.openUnisubsDialogWithSettings =
unisubs.DEBUG = true;
}
unisubs.widget.WidgetController.makeGeneralSettings(generalSettings);
- if (config['returnURL'])
+ if (config['returnURL']) {
unisubs.returnURL = config['returnURL'];
+ }
if (config['guidelines']) {
unisubs.guidelines = config['guidelines'];
}
+ if (config['team_url']) {
+ unisubs.team_url = config['team_url'];
+ }
+ if (config['mode']) {
+ unisubs.mode = config['mode'];
+ }
unisubs.IS_NULL = !!config['nullWidget'];
var videoSource =
unisubs.player.MediaSource.videoSourceForURL(
diff --git a/media/js/widget/reviewsubtitles/dialog.js b/media/js/widget/reviewsubtitles/dialog.js
new file mode 100644
index 0000000..0608649
--- /dev/null
+++ b/media/js/widget/reviewsubtitles/dialog.js
@@ -0,0 +1,186 @@
+// Universal Subtitles, universalsubtitles.org
+//
+// Copyright (C) 2011 Participatory Culture Foundation
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see
+// http://www.gnu.org/licenses/agpl-3.0.html.
+
+goog.provide('unisubs.reviewsubtitles.Dialog');
+
+/**
+ * @constructor
+ *
+ */
+unisubs.reviewsubtitles.Dialog = function(videoSource, serverModel,
+ subtitleState) {
+ unisubs.Dialog.call(this, videoSource);
+ unisubs.SubTracker.getInstance().start(true);
+
+ this.opener_ = opener;
+ this.subtitleState_ = subtitleState;
+ this.serverModel_ = serverModel;
+ this.captionSet_ = this.serverModel_.getCaptionSet();
+ this.captionManager_ = new unisubs.CaptionManager(this.getVideoPlayerInternal(), this.captionSet_);
+ this.saved_ = false;
+};
+goog.inherits(unisubs.reviewsubtitles.Dialog, unisubs.Dialog);
+
+unisubs.reviewsubtitles.Dialog.prototype.createDom = function() {
+ unisubs.reviewsubtitles.Dialog.superClass_.createDom.call(this);
+ this.reviewPanel_ = new unisubs.reviewsubtitles.ReviewSubtitlesPanel(
+ this.serverModel_.getCaptionSet(), this.getVideoPlayerInternal(),
+ this.serverModel_, this.captionManager_);
+ this.getCaptioningAreaInternal().addChild(this.reviewPanel_, true);
+
+ var rightPanel = this.createRightPanel_();
+
+ this.setRightPanelInternal(rightPanel);
+ this.getHandler().
+ listen(
+ rightPanel, unisubs.RightPanel.EventType.DONE,
+ this.handleDoneKeyPress_).
+ listen(
+ rightPanel, unisubs.RightPanel.EventType.SAVEANDEXIT,
+ this.handleSaveAndExitKeyPress_);
+ goog.dom.classes.add(this.getContentElement(), 'unisubs-modal-widget-translate');
+ this.showGuidelines_();
+
+ this.timelineSubtitleSet_ = new unisubs.timeline.SubtitleSet(this.captionSet_, this.getVideoPlayerInternal());
+ this.getTimelinePanelInternal().addChild(
+ new unisubs.timeline.Timeline(
+ 1, this.timelineSubtitleSet_,
+ this.getVideoPlayerInternal()), true);
+};
+
+unisubs.reviewsubtitles.Dialog.prototype.showGuidelines_ = function() {
+ if (!unisubs.guidelines['review']) {
+ return;
+ }
+
+ var guidelinesPanel = new unisubs.GuidelinesPanel(unisubs.guidelines['review']);
+ this.showTemporaryPanel(guidelinesPanel);
+ this.displayingGuidelines_ = true;
+
+ var that = this;
+ this.getHandler().listenOnce(guidelinesPanel, unisubs.GuidelinesPanel.CONTINUE, function(e) {
+ goog.Timer.callOnce(function() {
+ that.displayingGuidelines_ = false;
+ that.hideTemporaryPanel();
+ });
+ });
+};
+
+unisubs.reviewsubtitles.Dialog.prototype.createRightPanel_ = function() {
+ var title = "Review Subtitles";
+ var helpContents = new unisubs.RightPanel.HelpContents(title, ["Help goes here"]);
+ return new unisubs.reviewsubtitles.ReviewSubtitlesRightPanel(this.serverModel_, helpContents, [], false, "Done?", "Submit final Review");
+};
+
+unisubs.reviewsubtitles.Dialog.prototype.isWorkSaved = function() {
+ // TODO
+ return this.saved_ || !this.serverModel_.anySubtitlingWorkDone();
+};
+
+
+unisubs.reviewsubtitles.Dialog.prototype.captionReached_ = function(event) {
+ var c = event.caption;
+ this.getVideoPlayerInternal().showCaptionText(c ? c.getText() : '');
+};
+unisubs.reviewsubtitles.Dialog.prototype.enterDocument = function() {
+ unisubs.reviewsubtitles.Dialog.superClass_.enterDocument.call(this);
+ unisubs.Dialog.translationDialogOpen = false;
+ var doc = this.getDomHelper().getDocument();
+ this.getHandler().listen(
+ this.captionManager_,
+ unisubs.CaptionManager.CAPTION,
+ this.captionReached_);
+};
+
+unisubs.reviewsubtitles.Dialog.prototype.handleApprove_ = function(e) {
+ e.preventDefault();
+ this.saveWork(true);
+};
+// unisubs.translate.Dialog.prototype.saveWorkInternal = function(closeAfterSave) {
+// var that = this;
+// this.getRightPanelInternal().showLoading(true);
+// this.serverModel_.finish(
+// function(serverMsg){
+// unisubs.subtitle.OnSavedDialog.show(serverMsg, function(){
+// that.onWorkSaved(closeAfterSave);
+// })
+// },
+// function(opt_status) {
+// if (that.finishFailDialog_)
+// that.finishFailDialog_.failedAgain(opt_status);
+// else
+// that.finishFailDialog_ = unisubs.finishfaildialog.Dialog.show(
+// that.serverModel_.getCaptionSet(), opt_status,
+// goog.bind(that.saveWorkInternal, that, closeAfterSave));
+// });
+// };
+// unisubs.translate.Dialog.prototype.onWorkSaved = function() {
+// if (this.finishFailDialog_) {
+// this.finishFailDialog_.setVisible(false);
+// this.finishFailDialog_ = null;
+// }
+// unisubs.widget.ResumeEditingRecord.clear();
+// this.getRightPanelInternal().showLoading(false);
+// this.saved_ = true;
+// this.setVisible(false);
+// }
+
+unisubs.reviewsubtitles.Dialog.prototype.saveWorkImpl_ = function(closeAfterSave, isComplete) {
+ this.getRightPanelInternal().showLoading(true);
+
+ var that = this;
+ this.serverModel_.finish(
+ function(serverMsg){
+ unisubs.subtitle.OnSavedDialog.show(serverMsg, function(){
+ that.onWorkSaved(closeAfterSave, isComplete);
+ });
+ },
+ function(opt_status) {
+ if (that.finishFailDialog_) {
+ that.finishFailDialog_.failedAgain(opt_status);
+ } else {
+ that.finishFailDialog_ = unisubs.finishfaildialog.Dialog.show(
+ that.captionSet_, opt_status,
+ goog.bind(that.saveWorkImpl_, that,
+ closeAfterSave, isComplete));
+ }
+ },
+ function() {
+ that.doneButtonEnabled_ = true;
+ that.getRightPanelInternal().showLoading(false);
+ });
+};
+
+unisubs.reviewsubtitles.Dialog.prototype.disposeInternal = function() {
+ unisubs.reviewsubtitles.Dialog.superClass_.disposeInternal.call(this);
+ this.serverModel_.dispose();
+ this.timelineSubtitleSet_.dispose();
+ this.timelineSubtitleSet_ = null;
+};
+
+unisubs.reviewsubtitles.Dialog.prototype.getSubtitleLanguage = function(){
+ return this.subtitleState_.LANGUAGE;
+};
+
+unisubs.reviewsubtitles.Dialog.prototype.getServerModel = function(){
+ return this.serverModel_;
+};
+
+unisubs.reviewsubtitles.Dialog.prototype.makeJsonSubs = function () {
+ return this.serverModel_.getCaptionSet().makeJsonSubs();
+};
diff --git a/media/js/widget/reviewsubtitles/reviewsubtitlespanel.js b/media/js/widget/reviewsubtitles/reviewsubtitlespanel.js
new file mode 100644
index 0000000..354ac51
--- /dev/null
+++ b/media/js/widget/reviewsubtitles/reviewsubtitlespanel.js
@@ -0,0 +1,120 @@
+// Universal Subtitles, universalsubtitles.org
+//
+// Copyright (C) 2010 Participatory Culture Foundation
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see
+// http://www.gnu.org/licenses/agpl-3.0.html.
+
+goog.provide('unisubs.reviewsubtitles.ReviewSubtitlesPanel');
+
+/**
+ * @constructor
+ * @param {unisubs.subtitle.EditableCaptionSet} subtitles The subtitles
+ * for the video, so far.
+ * @param {unisubs.player.AbstractVideoPlayer} videoPlayer
+ * @param {unisubs.CaptionManager} Caption manager, already containing subtitles
+ * with start_time set.
+ */
+unisubs.reviewsubtitles.ReviewSubtitlesPanel = function(subtitles, videoPlayer, serverModel, captionManager) {
+ goog.ui.Component.call(this);
+ /**
+ * @type {unisubs.subtitle.EditableCaptionSet}
+ */
+ this.subtitles_ = subtitles;
+
+ this.videoPlayer_ = videoPlayer;
+ /**
+ * @protected
+ */
+ this.serverModel = serverModel;
+ this.captionManager_ = captionManager;
+ this.videoStarted_ = false;
+ this.downSub_ = null;
+ this.downPlayheadTime_ = -1;
+};
+goog.inherits(unisubs.reviewsubtitles.ReviewSubtitlesPanel, goog.ui.Component);
+
+unisubs.reviewsubtitles.ReviewSubtitlesPanel.prototype.enterDocument = function() {
+ unisubs.reviewsubtitles.ReviewSubtitlesPanel.superClass_.enterDocument.call(this);
+ var handler = this.getHandler();
+ handler.listen(this.captionManager_,
+ unisubs.CaptionManager.CAPTION,
+ this.captionReached_)
+};
+unisubs.reviewsubtitles.ReviewSubtitlesPanel.prototype.createDom = function() {
+ unisubs.reviewsubtitles.ReviewSubtitlesPanel.superClass_.createDom.call(this);
+ var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
+ this.getElement().appendChild(this.contentElem_ = $d('div'));
+ this.addChild(this.subtitleList_ = new unisubs.subtitle.SubtitleList(
+ this.videoPlayer_, this.subtitles_, true, false, true), true);
+};
+unisubs.reviewsubtitles.ReviewSubtitlesPanel.prototype.getRightPanel = function() {
+ if (!this.rightPanel_) {
+ this.rightPanel_ = this.createRightPanelInternal();
+ }
+ return this.rightPanel_;
+};
+unisubs.reviewsubtitles.ReviewSubtitlesPanel.prototype.createRightPanelInternal = function() {
+ var helpContents = new unisubs.RightPanel.HelpContents(
+ "Syncing",
+ ["Congratulations, you finished the hard part (all that typing)!",
+ ["Now, to line up your subtitles to the video, tap the DOWN ARROW right ",
+ "when each subtitle should appear."].join(''),
+ "Tap DOWN to begin, tap it for the first subtitle, and so on.",
+ ["Don't worry about small mistakes. We can correct them in the ",
+ "next step. If you need to start over, click \"restart\" ",
+ "below."].join('')],
+ 3, 1);
+ var extraHelp =
+ ["Press play, then tap this button or the down arrow when the next subtitle should appear."];
+ return new unisubs.RightPanel(
+ this.serverModel, helpContents, extraHelp,
+ this.makeKeySpecsInternal(), true, "Done?",
+ "Next Step: Reviewing");
+};
+unisubs.reviewsubtitles.ReviewSubtitlesPanel.prototype.makeKeySpecsInternal = function() {
+ var KC = goog.events.KeyCodes;
+ return [
+ new unisubs.RightPanel.KeySpec(
+ 'unisubs-begin', 'unisubs-down', 'down',
+ 'Tap when next subtitle should appear', KC.DOWN, 0),
+ new unisubs.RightPanel.KeySpec(
+ 'unisubs-play', 'unisubs-tab', 'tab', 'Play/Pause', KC.TAB, 0),
+ new unisubs.RightPanel.KeySpec(
+ 'unisubs-skip', 'unisubs-control', 'shift\n+\ntab',
+ 'Skip Back 8 Seconds', KC.TAB,
+ unisubs.RightPanel.KeySpec.Modifier.SHIFT)
+ ];
+
+};
+unisubs.reviewsubtitles.ReviewSubtitlesPanel.prototype.startOverClicked_ = function() {
+ var answer =
+ confirm("Are you sure you want to start over? All timestamps " +
+ "will be deleted.");
+ if (answer) {
+ this.subtitles_.clearTimes();
+ this.videoPlayer_.setPlayheadTime(0);
+ }
+};
+unisubs.reviewsubtitles.ReviewSubtitlesPanel.prototype.captionReached_ = function(event) {
+ var editableCaption = event.caption;
+ this.subtitleList_.clearActiveWidget();
+ if (editableCaption != null)
+ this.subtitleList_.setActiveWidget(editableCaption.getCaptionID());
+};
+unisubs.reviewsubtitles.ReviewSubtitlesPanel.prototype.disposeInternal = function() {
+ unisubs.reviewsubtitles.ReviewSubtitlesPanel.superClass_.disposeInternal.call(this);
+ if (this.rightPanel_)
+ this.rightPanel_.dispose();
+};
diff --git a/media/js/widget/reviewsubtitles/reviewsubtitlesrightpanel.js b/media/js/widget/reviewsubtitles/reviewsubtitlesrightpanel.js
new file mode 100644
index 0000000..234ba47
--- /dev/null
+++ b/media/js/widget/reviewsubtitles/reviewsubtitlesrightpanel.js
@@ -0,0 +1,88 @@
+// Universal Subtitles, universalsubtitles.org
+//
+// Copyright (C) 2011 Participatory Culture Foundation
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see
+// http://www.gnu.org/licenses/agpl-3.0.html.
+
+goog.provide('unisubs.reviewsubtitles.ReviewSubtitlesRightPanel');
+
+/**
+ * @constructor
+ * @extends unisubs.RightPanel
+ */
+unisubs.reviewsubtitles.ReviewSubtitlesRightPanel = function(serverModel,
+ helpContents,
+ legendKeySpecs,
+ showRestart,
+ doneStrongText,
+ doneText) {
+ unisubs.RightPanel.call(this, serverModel, helpContents, null,
+ legendKeySpecs, showRestart, doneStrongText, doneText);
+
+ this.showSaveExit = false;
+ this.showDoneButton = false;
+};
+goog.inherits(unisubs.reviewsubtitles.ReviewSubtitlesRightPanel, unisubs.RightPanel);
+
+unisubs.reviewsubtitles.ReviewSubtitlesRightPanel.prototype.appendMiddleContentsInternal = function($d, el) {
+ el.appendChild($d('label', {'class': 'unisubs-review-notes-label', 'for': 'unisubs-review-notes'}, 'Notes'));
+ el.appendChild($d('textarea', {'class': 'unisubs-review-notes', 'id': 'unisubs-review-notes', 'name': 'notes'}));
+ el.appendChild($d('hr'));
+
+ this.reassignLink_ = $d('a', {'href': unisubs.team_url}, 'reassign this task');
+ this.editedVersionLink_ = $d('a', {'href': '#'}, 'submit an edited version');
+
+ el.appendChild($d('p', null,
+ 'You can also ',
+ this.reassignLink_,
+ ' to someone else, or ',
+ this.editedVersionLink_,
+ ' yourself.',
+ ' If you submit a new version it will also be subject to review.'
+ ));
+
+ var handler = this.getHandler();
+ handler.listen(this.reassignLink_, 'click', this.reassignLinkClicked_);
+ handler.listen(this.editedVersionLink_, 'click', this.editedVersionLinkClicked_);
+};
+unisubs.reviewsubtitles.ReviewSubtitlesRightPanel.prototype.appendCustomButtonsInternal = function($d, el) {
+ this.approveButton_ = $d('a', {'class': 'unisubs-done'}, 'Approve');
+ this.sendBackButton_ = $d('a', {'class': 'unisubs-done'}, 'Send Back');
+
+ el.appendChild(this.sendBackButton_);
+ el.appendChild(this.approveButton_);
+
+ var handler = this.getHandler();
+ handler.listen(this.approveButton_, 'click', this.approveButtonClicked_);
+ handler.listen(this.sendBackButton_, 'click', this.sendBackButtonClicked_);
+};
+
+unisubs.reviewsubtitles.ReviewSubtitlesRightPanel.prototype.approveButtonClicked_ = function(e){
+ e.preventDefault();
+
+ alert("o hai");
+};
+unisubs.reviewsubtitles.ReviewSubtitlesRightPanel.prototype.sendBackButtonClicked_ = function(e){
+ e.preventDefault();
+
+ alert("o hai");
+};
+unisubs.reviewsubtitles.ReviewSubtitlesRightPanel.prototype.reassignLinkClicked_ = function(e){
+};
+unisubs.reviewsubtitles.ReviewSubtitlesRightPanel.prototype.editedVersionLinkClicked_ = function(e){
+ e.preventDefault();
+
+ alert("o hai");
+};
diff --git a/media/js/widget/rightpanel.js b/media/js/widget/rightpanel.js
index e3dba32..8aa4899 100644
--- a/media/js/widget/rightpanel.js
+++ b/media/js/widget/rightpanel.js
@@ -59,6 +59,15 @@ unisubs.RightPanel = function(serverModel,
this.showSaveExit = true;
/**
+ * Whether to show the "Done? ... >" button. Should be overridden by sub
+ * classes as needed.
+ *
+ * @protected
+ * @type {boolean}
+ */
+ this.showDoneButton = true;
+
+ /**
* Non-null iff the mouse has just been pressed on one of the legend keys
* and not released or moved away from the legend key yet.
* @type {?string}
@@ -211,6 +220,9 @@ unisubs.RightPanel.prototype.appendLegendClearInternal = function($d, legendDiv)
unisubs.RightPanel.prototype.appendMiddleContentsInternal = function($d, el) {
// dear subclasses, override me if you want. love, rightpanel.
};
+unisubs.RightPanel.prototype.appendCustomButtonsInternal = function($d, el) {
+ // dear subclasses, override me if you want. love, rightpanel.
+};
unisubs.RightPanel.prototype.appendStepsContents_ = function($d, el) {
this.loginDiv_ = $d('div');
this.loadingGif_ = $d('img',
@@ -248,7 +260,12 @@ unisubs.RightPanel.prototype.appendStepsContents_ = function($d, el) {
this.getHandler().listen(
this.downloadLink_, 'click', this.downloadClicked_);
- goog.dom.append(stepsDiv, this.doneAnchor_);
+ this.appendCustomButtonsInternal($d, el);
+
+ if (this.showDoneButton) {
+ goog.dom.append(stepsDiv, this.doneAnchor_);
+ this.getHandler().listen(this.doneAnchor_, 'click', this.doneClicked_);
+ }
if (this.showSaveExit) {
var saveAndExitAnchor = $d(
@@ -263,7 +280,6 @@ unisubs.RightPanel.prototype.appendStepsContents_ = function($d, el) {
}
goog.dom.append(el, stepsDiv);
- this.getHandler().listen(this.doneAnchor_, 'click', this.doneClicked_);
this.updateLoginState();
};
unisubs.RightPanel.prototype.legendKeyClicked_ = function(keyCode, modifiers, event) {
diff --git a/media/js/widget/subtitle/addsubtitlewidget.js b/media/js/widget/subtitle/addsubtitlewidget.js
index d68f1cf..8c31fa8 100644
--- a/media/js/widget/subtitle/addsubtitlewidget.js
+++ b/media/js/widget/subtitle/addsubtitlewidget.js
@@ -23,7 +23,6 @@ goog.provide('unisubs.subtitle.AddSubtitleWidget');
*/
unisubs.subtitle.AddSubtitleWidget = function() {
goog.ui.Component.call(this);
-
};
goog.inherits(unisubs.subtitle.AddSubtitleWidget, goog.ui.Component);
diff --git a/media/js/widget/subtitle/editrightpanel.js b/media/js/widget/subtitle/editrightpanel.js
index 5f768a3..07976b8 100644
--- a/media/js/widget/subtitle/editrightpanel.js
+++ b/media/js/widget/subtitle/editrightpanel.js
@@ -34,6 +34,23 @@ unisubs.subtitle.EditRightPanel = function(serverModel,
doneText);
};
goog.inherits(unisubs.subtitle.EditRightPanel, unisubs.RightPanel);
+
+unisubs.subtitle.EditRightPanel.prototype.appendHelpContentsInternal = function($d, el) {
+ var backLink = $d('a', {'href': '#'}, 'click here');
+ this.getHandler().listenOnce(
+ backLink, 'click', this.backClickedInternal);
+ var helpDiv = $d('div', 'unisubs-help-heading',
+ $d('h2', null, "EDIT: Edit existing subtitles"));
+ el.appendChild(helpDiv);
+ el.appendChild($d('p', null,
+ goog.dom.createTextNode(
+ 'Double click on any subtitle to edit its text. To add more text, '),
+ backLink,
+ goog.dom.createTextNode(' for TYPING mode.')));
+ el.appendChild($d('p', null, 'Adjust subtitle timing by dragging their edges in the timeline to the left and watching the results.'));
+ el.appendChild($d('p', null, 'You can also edit timing by rolling over any timestamp, and clicking the left/right buttons that appear. After you click, your change will play back.'));
+ el.appendChild($d('p', null, 'Hitting the DOWN ARROW will set the start of the next subtitle.'));
+};
unisubs.subtitle.EditRightPanel.prototype.appendHelpContentsInternal = function($d, el) {
var backLink = $d('a', {'href': '#'}, 'click here');
this.getHandler().listenOnce(
diff --git a/media/js/widget/subtitle/reviewrightpanel.js b/media/js/widget/subtitle/reviewrightpanel.js
index 747327d..11bc462 100644
--- a/media/js/widget/subtitle/reviewrightpanel.js
+++ b/media/js/widget/subtitle/reviewrightpanel.js
@@ -22,12 +22,12 @@ goog.provide('unisubs.subtitle.ReviewRightPanel');
* @extends unisubs.RightPanel
*/
unisubs.subtitle.ReviewRightPanel = function(serverModel,
- helpContents,
- extraHelp,
- legendKeySpecs,
- showRestart,
- doneStrongText,
- doneText) {
+ helpContents,
+ extraHelp,
+ legendKeySpecs,
+ showRestart,
+ doneStrongText,
+ doneText) {
unisubs.RightPanel.call(this, serverModel, helpContents, extraHelp,
legendKeySpecs,
showRestart, doneStrongText, doneText);
diff --git a/media/js/widget/subtitle/subtitlelist.js b/media/js/widget/subtitle/subtitlelist.js
index 8336c54..5022c38 100644
--- a/media/js/widget/subtitle/subtitlelist.js
+++ b/media/js/widget/subtitle/subtitlelist.js
@@ -24,10 +24,12 @@ goog.provide('unisubs.subtitle.SubtitleList');
* @param {unisubs.subtitle.EditableCaptionSet} captionSet
*/
unisubs.subtitle.SubtitleList = function(videoPlayer, captionSet,
- displayTimes, opt_showBeginMessage) {
+ displayTimes, opt_showBeginMessage,
+ readOnly) {
goog.ui.Component.call(this);
this.videoPlayer_ = videoPlayer;
this.captionSet_ = captionSet;
+ this.readOnly_ = readOnly;
this.displayTimes_ = displayTimes;
this.currentActiveSubtitle_ = null;
/**
@@ -49,8 +51,14 @@ unisubs.subtitle.SubtitleList.prototype.createDom = function() {
var dh = this.getDomHelper();
var $d = goog.bind(dh.createDom, dh);
var $t = goog.bind(dh.createTextNode, dh);
- this.setElementInternal($d('ul', 'unisubs-titlesList'));
- if (this.captionSet_.count() == 0 && this.showBeginMessage_) {
+
+ var list_class = 'unisubs-titlesList';
+ if (this.readOnly_) {
+ list_class += ' read-only';
+ }
+ this.setElementInternal($d('ul', list_class));
+
+ if (this.captionSet_.count() === 0 && this.showBeginMessage_) {
this.showingBeginMessage_ = true;
goog.dom.classes.add(this.getElement(), 'unisubs-beginTab');
this.getElement().appendChild(
@@ -58,9 +66,8 @@ unisubs.subtitle.SubtitleList.prototype.createDom = function() {
$t('To begin, press TAB to play'),
$d('br'),
$t('and start typing!')));
- }
- else {
- this.addAddButton_();
+ } else {
+ this.readOnly_ || this.addAddButton_();
var i;
for (i = 0; i < this.captionSet_.count(); i++)
this.addSubtitle(this.captionSet_.caption(i), false, true);
@@ -107,8 +114,9 @@ unisubs.subtitle.SubtitleList.prototype.enterDocument = function() {
this.captionSet_,
et.DELETE,
this.captionDeleted_);
- if (this.addSubtitleButton_)
+ if (this.addSubtitleButton_ && !this.readOnly_) {
this.listenForAdd_();
+ }
};
unisubs.subtitle.SubtitleList.prototype.captionsCleared_ = function(event) {
this.subtitleMap_ = {};
@@ -131,7 +139,8 @@ unisubs.subtitle.SubtitleList.prototype.createNewSubWidget_ =
editableCaption,
this.captionSet_,
goog.bind(this.setCurrentlyEditing_, this),
- this.displayTimes_);
+ this.displayTimes_,
+ this.readOnly_);
};
/**
*
@@ -145,10 +154,11 @@ unisubs.subtitle.SubtitleList.prototype.addSubtitle =
goog.dom.removeChildren(this.getElement());
goog.dom.classes.remove(this.getElement(), 'unisubs-beginTab');
this.showingBeginMessage_ = false;
- this.addAddButton_();
+ this.readOnly_ || this.addAddButton_();
}
+ var dest_offset = this.getChildCount() - (this.readOnly_ ? 0 : 1);
var subtitleWidget = this.createNewSubWidget_(subtitle);
- this.addChildAt(subtitleWidget, this.getChildCount() - 1, true);
+ this.addChildAt(subtitleWidget, dest_offset, true);
this.subtitleMap_[subtitle.getCaptionID()] = subtitleWidget;
if (opt_scrollDown && typeof(opt_scrollDown) == 'boolean')
this.scrollToCaption(subtitle.getCaptionID());
@@ -177,7 +187,7 @@ unisubs.subtitle.SubtitleList.prototype.setLastSub_ = function() {
if (subWidget == this.lastSub_)
return;
this.lastSubMouseHandler_.removeAll();
- if (subWidget != null) {
+ if (subWidget != null && !this.readOnly_) {
var et = goog.events.EventType;
this.lastSubMouseHandler_.
listen(subWidget.getElement(),
diff --git a/media/js/widget/subtitle/subtitlewidget.js b/media/js/widget/subtitle/subtitlewidget.js
index 40aa9c6..5d8cc2b 100644
--- a/media/js/widget/subtitle/subtitlewidget.js
+++ b/media/js/widget/subtitle/subtitlewidget.js
@@ -30,7 +30,8 @@ goog.provide('unisubs.subtitle.SubtitleWidget');
unisubs.subtitle.SubtitleWidget = function(subtitle,
subtitleSet,
editingFn,
- displayTimes) {
+ displayTimes,
+ readOnly) {
goog.ui.Component.call(this);
this.subtitle_ = subtitle;
this.subtitleSet_ = subtitleSet;
@@ -38,6 +39,7 @@ unisubs.subtitle.SubtitleWidget = function(subtitle,
this.displayTimes_ = displayTimes;
this.keyHandler_ = null;
this.timeSpinner_ = null;
+ this.readOnly_ = readOnly;
this.insertDeleteButtonsShowing_ = false;
};
goog.inherits(unisubs.subtitle.SubtitleWidget, goog.ui.Component);
@@ -47,20 +49,31 @@ unisubs.subtitle.SubtitleWidget.prototype.getContentElement = function() {
};
unisubs.subtitle.SubtitleWidget.prototype.createDom = function() {
var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
- this.deleteButton_ = this.createDeleteButton_($d);
- this.insertButton_ = this.createInsertButton_($d);
- goog.style.showElement(this.deleteButton_, false);
- goog.style.showElement(this.insertButton_, false);
+ if (!this.readOnly_) {
+ this.deleteButton_ = this.createDeleteButton_($d);
+ this.insertButton_ = this.createInsertButton_($d);
+ goog.style.showElement(this.deleteButton_, false);
+ goog.style.showElement(this.insertButton_, false);
+
+ this.setElementInternal(
+ $d('li', null,
+ this.contentElement_,
+ this.titleElem_ =
+ $d('span', {'className':'unisubs-title'},
+ this.titleElemInner_ =
+ $d('span')),
+ this.deleteButton_,
+ this.insertButton_));
+ } else {
+ this.setElementInternal(
+ $d('li', null,
+ this.contentElement_,
+ this.titleElem_ =
+ $d('span', {'className':'unisubs-title'},
+ this.titleElemInner_ =
+ $d('span'))));
+ }
this.contentElement_ = $d('span', 'unisubs-timestamp');
- this.setElementInternal(
- $d('li', null,
- this.contentElement_,
- this.titleElem_ =
- $d('span', {'className':'unisubs-title'},
- this.titleElemInner_ =
- $d('span')),
- this.deleteButton_,
- this.insertButton_));
if (!this.displayTimes_) {
goog.dom.classes.add(this.titleElem_, 'unisubs-title-notime');
unisubs.style.showElement(this.contentElement_, false);
@@ -89,17 +102,19 @@ unisubs.subtitle.SubtitleWidget.prototype.createInsertButton_ = function($d) {
unisubs.subtitle.SubtitleWidget.prototype.enterDocument = function() {
unisubs.subtitle.SubtitleWidget.superClass_.enterDocument.call(this);
var et = goog.events.EventType;
- this.getHandler().
- listen(
- this.subtitle_,
- unisubs.subtitle.EditableCaption.CHANGE,
- this.updateValues_).
- listen(this.titleElem_, et.CLICK, this.clicked_).
- listen(this.getElement(),
- [et.MOUSEOVER, et.MOUSEOUT],
- this.mouseOverOut_).
- listen(this.deleteButton_, et.CLICK, this.deleteClicked_).
- listen(this.insertButton_, et.CLICK, this.insertClicked_);
+
+ if (!this.readOnly_) {
+ this.getHandler().listen(this.deleteButton_, et.CLICK, this.deleteClicked_)
+ .listen(this.insertButton_, et.CLICK, this.insertClicked_)
+ .listen(this.titleElem_, et.CLICK, this.clicked_)
+ .listen(this.getElement(),
+ [et.MOUSEOVER, et.MOUSEOUT],
+ this.mouseOverOut_)
+ .listen(this.subtitle_,
+ unisubs.subtitle.EditableCaption.CHANGE,
+ this.updateValues_);
+ }
+
if (this.timeSpinner_)
this.getHandler().listen(
this.timeSpinner_,
@@ -155,8 +170,10 @@ unisubs.subtitle.SubtitleWidget.prototype.showInsertDeleteButtons_ =
return;
this.insertDeleteButtonsShowing_ = show;
- goog.style.showElement(this.deleteButton_, show);
- goog.style.showElement(this.insertButton_, show);
+ if (!this.readOnly_) {
+ goog.style.showElement(this.deleteButton_, show);
+ goog.style.showElement(this.insertButton_, show);
+ }
};
unisubs.subtitle.SubtitleWidget.prototype.clicked_ = function(event) {
if (this.showingTextarea_)
diff --git a/media/js/widget/subtitle/syncpanel.js b/media/js/widget/subtitle/syncpanel.js
index 8ca2dda..1b69069 100644
--- a/media/js/widget/subtitle/syncpanel.js
+++ b/media/js/widget/subtitle/syncpanel.js
@@ -62,7 +62,7 @@ unisubs.subtitle.SyncPanel.prototype.createDom = function() {
var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
this.getElement().appendChild(this.contentElem_ = $d('div'));
this.addChild(this.subtitleList_ = new unisubs.subtitle.SubtitleList(
- this.videoPlayer_, this.subtitles_, true), true);
+ this.videoPlayer_, this.subtitles_, true, false, false), true);
};
unisubs.subtitle.SyncPanel.prototype.getRightPanel = function() {
if (!this.rightPanel_) {
@@ -115,9 +115,7 @@ unisubs.subtitle.SyncPanel.prototype.makeKeySpecsInternal = function() {
unisubs.subtitle.SyncPanel.prototype.suspendKeyEvents = function(suspended) {
this.keyEventsSuspended_ = suspended;
};
-unisubs.subtitle.SyncPanel.prototype.handleLegendKeyPress_ =
- function(event)
-{
+unisubs.subtitle.SyncPanel.prototype.handleLegendKeyPress_ = function(event) {
if (event.keyCode == goog.events.KeyCodes.DOWN) {
if (event.keyEventType == goog.events.EventType.MOUSEDOWN &&
!this.currentlyEditingSubtitle_())
diff --git a/media/js/widget/subtitle/transcribepanel.js b/media/js/widget/subtitle/transcribepanel.js
index 68f11a6..b2c7a5a 100644
--- a/media/js/widget/subtitle/transcribepanel.js
+++ b/media/js/widget/subtitle/transcribepanel.js
@@ -68,7 +68,7 @@ unisubs.subtitle.TranscribePanel.prototype.addElems_ = function(el) {
this.addChild(this.lineEntry_ = new unisubs.subtitle.TranscribeEntry(
this.videoPlayer_), true);
this.addChild(this.subtitleList_ = new unisubs.subtitle.SubtitleList(
- this.videoPlayer_, this.captionSet_, false, true), true);
+ this.videoPlayer_, this.captionSet_, false, true, false), true);
this.setPlayMode(unisubs.UserSettings.getStringValue(
unisubs.UserSettings.Settings.VIDEO_SPEED_MODE) ||
unisubs.subtitle.TranscribePanel.PlayMode.PLAY_STOP);
diff --git a/media/js/widget/subtitledialogopener.js b/media/js/widget/subtitledialogopener.js
index d62b21e..4f53542 100644
--- a/media/js/widget/subtitledialogopener.js
+++ b/media/js/widget/subtitledialogopener.js
@@ -241,9 +241,11 @@ unisubs.widget.SubtitleDialogOpener.prototype.startEditingResponseHandler_ =
}
var serverModel = new unisubs.subtitle.MSServerModel(
sessionPK, this.videoID_, this.videoURL_, captionSet);
- if (subtitles.IS_ORIGINAL || subtitles.FORKED)
+ if (unisubs.mode == 'review') {
+ this.openSubtitleReviewingDialog(serverModel, subtitles);
+ } else if (subtitles.IS_ORIGINAL || subtitles.FORKED) {
this.openSubtitlingDialog(serverModel, subtitles);
- else {
+ } else {
this.openDependentTranslationDialog_(
serverModel, subtitles, originalSubtitles);
}
@@ -258,6 +260,16 @@ unisubs.widget.SubtitleDialogOpener.prototype.startEditingResponseHandler_ =
}
};
+unisubs.widget.SubtitleDialogOpener.prototype.openSubtitleReviewingDialog =
+ function(serverModel, subtitleState)
+{
+ this.subOpenFn_ && this.subOpenFn_();
+ var subReviewDialog = new unisubs.reviewsubtitles.Dialog(this.videoSource_, serverModel, subtitleState);
+
+ subReviewDialog.setParentEventTarget(this);
+ subReviewDialog.setVisible(true);
+};
+
unisubs.widget.SubtitleDialogOpener.prototype.openSubtitlingDialog =
function(serverModel, subtitleState)
{
diff --git a/media/js/widget/subtitlestate.js b/media/js/widget/subtitlestate.js
index a6b35f7..4c7fb59 100644
--- a/media/js/widget/subtitlestate.js
+++ b/media/js/widget/subtitlestate.js
@@ -30,6 +30,8 @@ unisubs.widget.SubtitleState = function(json, opt_subs) {
this.LANGUAGE_PK = json['language_pk'];
this.IS_ORIGINAL = json['is_original'];
this.IS_COMPLETE = json['is_complete'];
+ this.MODE = json['mode'];
+
/**
* @type {number}
*/
diff --git a/settings.py b/settings.py
index 56b2755..34c53b9 100644
--- a/settings.py
+++ b/settings.py
@@ -261,6 +261,9 @@ JS_DIALOG = \
'js/finishfaildialog/errorpanel.js',
'js/finishfaildialog/reattemptuploadpanel.js',
'js/finishfaildialog/copydialog.js',
+ 'js/widget/reviewsubtitles/dialog.js',
+ 'js/widget/reviewsubtitles/reviewsubtitlespanel.js',
+ 'js/widget/reviewsubtitles/reviewsubtitlesrightpanel.js',
'js/widget/subtitle/dialog.js',
'js/widget/subtitle/msservermodel.js',
'js/widget/subtitle/subtitlewidget.js',
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment