Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Unified Diff: client/samples/swarm/SwarmViews.dart

Issue 9314024: Final CL to kill off client/samples . (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « client/samples/swarm/SwarmState.dart ('k') | client/samples/swarm/UIState.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: client/samples/swarm/SwarmViews.dart
===================================================================
--- client/samples/swarm/SwarmViews.dart (revision 3770)
+++ client/samples/swarm/SwarmViews.dart (working copy)
@@ -1,975 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// TODO(jacobr): there is a lot of dead code in this class. Checking is as is
-// and then doing a large pass to remove functionality that doesn't make sense
-// given the UI layout.
-
-/**
- * Front page of Swarm.
- */
-// TODO(jacobr): this code now needs a large refactoring.
-// Suggested refactorings:
-// Move animation specific code into helper classes.
-class FrontView extends CompositeView {
- final Swarm swarm;
-
- /** View containing all UI anchored to the top of the page. */
- CompositeView topView;
- /** View containing all UI anchored to the left side of the page. */
- CompositeView bottomView;
- HeaderView headerView;
- SliderMenu sliderMenu;
-
- /**
- * When the user is viewing a story, the data source for that story is
- * detached from the section and shown at the bottom of the screen. This keeps
- * track of that so we can restore it later.
- */
- DataSourceView detachedView;
-
- /**
- * Map from section title to the View that shows this section. This
- * is populated lazily.
- */
- StoryContentView storyView;
- bool nextPrevShown;
-
- ConveyorView sections;
-
- /**
- * The set of keys that produce a given behavior (going down one story,
- * navigating to the column to the right, etc).
- */
- //TODO(jmesserly): we need a key code enumeration
- final Set downKeyPresses;
- final Set upKeyPresses;
- final Set rightKeyPresses;
- final Set leftKeyPresses;
- final Set openKeyPresses;
- final Set backKeyPresses;
- final Set nextPageKeyPresses;
- final Set previousPageKeyPresses;
-
- FrontView(this.swarm)
- : super('front-view fullpage'),
- downKeyPresses = new Set.from([74 /*j*/, 40 /*down*/]),
- upKeyPresses = new Set.from([75 /*k*/, 38 /*up*/]),
- rightKeyPresses = new Set.from([39 /*right*/, 68 /*d*/, 76 /*l*/]),
- leftKeyPresses = new Set.from([37 /*left*/, 65 /*a*/, 72 /*h*/]),
- openKeyPresses = new Set.from([13 /*enter*/, 79 /*o*/]),
- backKeyPresses = new Set.from([8 /*delete*/, 27 /*escape*/]),
- nextPageKeyPresses = new Set.from([78 /*n*/]),
- previousPageKeyPresses = new Set.from([80 /*p*/]),
- nextPrevShown = false {
- topView = new CompositeView('top-view', false, false, false);
-
- headerView = new HeaderView(swarm);
- topView.addChild(headerView);
-
- sliderMenu = new SliderMenu(swarm.sections.sectionTitles,
- (sectionTitle) {
- swarm.state.moveToNewSection(sectionTitle);
- _onSectionSelected(sectionTitle);
- // Start with no articles selected.
- swarm.state.selectedArticle.value = null;
- });
- topView.addChild(sliderMenu);
- addChild(topView);
-
- bottomView = new CompositeView('bottom-view', false, false, false);
- addChild(bottomView);
-
- sections = new ConveyorView();
- sections.viewSelected = _onSectionTransitionEnded;
- }
-
- SectionView get currentSection() {
- var view = sections.selectedView;
- // TODO(jmesserly): this code works around a bug in the DartC --optimize
- if (view == null) {
- view = sections.childViews[0];
- sections.selectView(view);
- }
- return view;
- }
-
- void afterRender(Element node) {
- _createSectionViews();
- attachWatch(swarm.state.currentArticle, (e) { _refreshCurrentArticle(); });
- attachWatch(swarm.state.storyMaximized, (e) { _refreshMaximized(); });
- }
-
- void _refreshCurrentArticle() {
- if (!swarm.state.inMainView) {
- _animateToStory(swarm.state.currentArticle.value);
- } else {
- _animateToMainView();
- }
- }
-
- /**
- * Animates back from the story view to the main grid view.
- */
- void _animateToMainView() {
- sliderMenu.removeClass('hidden');
- storyView.addClass('hidden-story');
- currentSection.storyMode = false;
-
- headerView.startTransitionToMainView();
-
- currentSection.dataSourceView.reattachSubview(
- detachedView.source, detachedView, true);
-
- storyView.node.on.transitionEnd.add(handler(e) {
- // Only listen once.
- // TODO(rnystrom): Look into adding .once() to EventListenerList to allow
- // this for any event.
- storyView.node.on.transitionEnd.remove(handler, false);
-
- currentSection.hidden = false;
- // TODO(rnystrom): Should move this "mode" into SwarmState and have
- // header view respond to change events itself.
- removeChild(storyView);
- storyView = null;
- detachedView.removeClass('sel');
- detachedView = null;
- });
- }
-
- void _animateToStory(Article item) {
- final source = item.dataSource;
-
- if (detachedView != null && detachedView.source != source) {
- // Ignore spurious item selection clicks that occur while a data source
- // is already selected. These are likely clicks that occur while an
- // animation is in progress.
- return;
- }
-
- if (storyView != null) {
- // Remove the old story. This happens if we're already in the Story View
- // and the user has clicked to see a new story.
- removeChild(storyView);
-
- // Create the new story view and place in the frame.
- storyView = addChild(new StoryContentView(swarm, item));
- } else {
- // We are animating from the main view to the story view.
- // TODO(jmesserly): make this code better
- final view = currentSection.findView(source);
-
- final newPosition = FxUtil.computeRelativePosition(
- view.node, bottomView.node);
- currentSection.dataSourceView.detachSubview(view.source);
- detachedView = view;
-
- FxUtil.setPosition(view.node, newPosition);
- bottomView.addChild(view);
- view.addClass('sel');
- currentSection.storyMode = true;
-
- // Create the new story view.
- storyView = new StoryContentView(swarm, item);
- window.setTimeout(() {
- _animateDataSourceToMinimized();
-
- sliderMenu.addClass('hidden');
- // Make the fancy sliding into the window animation.
- window.setTimeout(() {
- storyView.addClass('hidden-story');
- addChild(storyView);
- window.setTimeout(() {
- storyView.removeClass('hidden-story');
- }, 0);
- headerView.endTransitionToStoryView();
- }, 0);
- }, 0);
- }
- }
-
- void _refreshMaximized() {
- if (swarm.state.storyMaximized.value) {
- _animateDataSourceToMaximized();
- } else {
- _animateDataSourceToMinimized();
- }
- }
-
- void _animateDataSourceToMaximized() {
- FxUtil.setWebkitTransform(topView.node, 0, -HeaderView.HEIGHT);
- if (detachedView != null) {
- FxUtil.setWebkitTransform(detachedView.node, 0,
- -DataSourceView.TAB_ONLY_HEIGHT);
- }
- }
-
- void _animateDataSourceToMinimized() {
- if (detachedView != null) {
- FxUtil.setWebkitTransform(detachedView.node, 0, 0);
- FxUtil.setWebkitTransform(topView.node, 0, 0);
- }
- }
-
- /**
- * Called when the animation to switch to a section has completed.
- */
- void _onSectionTransitionEnded(SectionView selectedView) {
- // Show the section and hide the others.
- for (SectionView view in sections.childViews) {
- if (view == selectedView) {
- // Always refresh the sources in case they've changed.
- view.showSources();
- } else {
- // Only show the current view for performance.
- view.hideSources();
- }
- }
- }
-
- /**
- * Called when the user chooses a section on the SliderMenu. Hides
- * all views except the one they want to see.
- */
- void _onSectionSelected(String sectionTitle) {
- final section = swarm.sections.findSection(sectionTitle);
- // Find the view for this section.
- for (final view in sections.childViews) {
- if (view.section == section) {
- // Have the conveyor show it.
- sections.selectView(view);
- break;
- }
- }
- }
-
- /**
- * Create SectionViews for each Section in the app and add them to the
- * conveyor. Note that the SectionViews won't actually populate or load data
- * sources until they are shown in response to [:_onSectionSelected():].
- */
- void _createSectionViews() {
- for (final section in swarm.sections) {
- final viewFactory = new DataSourceViewFactory(swarm);
- final sectionView = new SectionView(swarm, section, viewFactory);
-
- // TODO(rnystrom): Hack temp. Access node to make sure SectionView has
- // rendered and created scroller. This can go away when event registration
- // is being deferred.
- sectionView.node;
-
- sections.addChild(sectionView);
- }
- addChild(sections);
- }
-
- /**
- * Controls the logic of how to respond to keypresses and then update the
- * UI accordingly.
- */
- void processKeyEvent(KeyboardEvent e) {
- int code = e.keyCode;
- if (swarm.state.inMainView) {
- // Option 1: We're in the Main Grid mode.
- if (!swarm.state.hasArticleSelected) {
- // Then a key has been pressed. Select the first item in the
- // top left corner.
- swarm.state.goToFirstArticleInSection();
- } else if (rightKeyPresses.contains(code)) {
- // Store original state that is needed if we need to move
- // to the next section.
- swarm.state.goToNextFeed();
- } else if (leftKeyPresses.contains(code)) {
- // Store original state that is needed if we need to move
- // to the next section.
- swarm.state.goToPreviousFeed();
- } else if (downKeyPresses.contains(code)) {
- swarm.state.goToNextSelectedArticle();
- } else if (upKeyPresses.contains(code)) {
- swarm.state.goToPreviousSelectedArticle();
- } else if (openKeyPresses.contains(code)) {
- // View a story in the larger Story View.
- swarm.state.selectStoryAsCurrent();
- } else if (nextPageKeyPresses.contains(code)) {
- swarm.state.goToNextSection(sliderMenu);
- } else if (previousPageKeyPresses.contains(code)) {
- swarm.state.goToPreviousSection(sliderMenu);
- }
- } else {
- // Option 2: We're in Story Mode. In this mode, the user can move up
- // and down through stories, which automatically loads the next story.
- if (downKeyPresses.contains(code)) {
- swarm.state.goToNextArticle();
- } else if (upKeyPresses.contains(code)) {
- swarm.state.goToPreviousArticle();
- } else if (backKeyPresses.contains(code)) {
- // Move back to the main grid view.
- swarm.state.clearCurrentArticle();
- }
- }
- }
-}
-
-/** Transitions the app back to the main screen. */
-void _backToMain(SwarmState state) {
- if (state.currentArticle.value != null) {
- state.clearCurrentArticle();
- state.storyTextMode.value = true;
- state.pushToHistory();
- }
-}
-
-/** A back button that sends the user back to the front page. */
-class SwarmBackButton extends View {
- Swarm swarm;
-
- SwarmBackButton(this.swarm) : super();
-
- Element render() => new Element.html('<div class="back-arrow button"></div>');
-
- void afterRender(Element node) {
- addOnClick((e) { _backToMain(swarm.state); });
- }
-}
-
-/** Top view constaining the title and standard buttons. */
-class HeaderView extends CompositeView {
- // TODO(jacobr): make this value be coupled with the CSS file.
- static final HEIGHT = 80;
- Swarm swarm;
-
- View _title;
- View _infoButton;
- View _configButton;
- View _refreshButton;
- SwarmBackButton _backButton;
- View _infoDialog;
- View _configDialog;
-
- // For (text/web) article view controls
- View _webBackButton;
- View _webForwardButton;
- View _newWindowButton;
-
- HeaderView(this.swarm) : super('header-view') {
- _backButton = addChild(new SwarmBackButton(swarm));
- _title = addChild(View.div('app-title', 'Swarm'));
- _configButton = addChild(View.div('config button'));
- _refreshButton = addChild(View.div('refresh button'));
- _infoButton = addChild(View.div('info-button button'));
-
- // TODO(rnystrom): No more web/text mode (it's just text) so get rid of
- // these.
- _webBackButton = addChild(new WebBackButton());
- _webForwardButton = addChild(new WebForwardButton());
- _newWindowButton = addChild(View.div('new-window-button button'));
- }
-
- void afterRender(Element node) {
- // Respond to changes to whether the story is being shown as text or web.
- attachWatch(swarm.state.storyTextMode, (e) { refreshWebStoryButtons(); });
-
- _title.addOnClick((e) { _backToMain(swarm.state); });
-
- // Wire up the events.
- _configButton.addOnClick((e) {
- // Bring up the config dialog.
- if (this._configDialog == null) {
- // TODO(terry): Cleanup, HeaderView shouldn't be tangled with main view.
- this._configDialog = new ConfigHintDialog(swarm.frontView, () {
- swarm.frontView.removeChild(this._configDialog);
- this._configDialog = null;
-
- // TODO: Need to push these to the server on a per-user basis.
- // Update the storage now.
- swarm.sections.refresh();
- });
-
- swarm.frontView.addChild(this._configDialog);
- }
- // TODO(jimhug): Graceful redirection to reader.
- });
-
- // On click of the refresh button, refresh the swarm.
- _refreshButton.addOnClick(EventBatch.wrap((e) {
- swarm.refresh();
- }));
-
- // On click of the info button, show Dart info page in new window/tab.
- _infoButton.addOnClick((e) {
- // Bring up the config dialog.
- if (this._infoDialog == null) {
- // TODO(terry): Cleanup, HeaderView shouldn't be tangled with main view.
- this._infoDialog = new HelpDialog(swarm.frontView, () {
- swarm.frontView.removeChild(this._infoDialog);
- this._infoDialog = null;
-
- swarm.sections.refresh();
- });
-
- swarm.frontView.addChild(this._infoDialog);
- }
- });
-
- // On click of the new window button, show web article in new window/tab.
- _newWindowButton.addOnClick((e) {
- String currentArticleSrcUrl = swarm.state.currentArticle.value.srcUrl;
- window.open(currentArticleSrcUrl, '_blank');
- });
-
- startTransitionToMainView();
- }
-
-
- /**
- * Refreshes whether or not the buttons specific to the display of a story in
- * the web perspective are visible.
- */
- void refreshWebStoryButtons() {
- bool webButtonsHidden = true;
-
- if (swarm.state.currentArticle.value != null) {
- // Set if web buttons are hidden
- webButtonsHidden = swarm.state.storyTextMode.value;
- }
-
- _webBackButton.hidden = webButtonsHidden;
- _webForwardButton.hidden = webButtonsHidden;
- _newWindowButton.hidden = webButtonsHidden;
- }
-
- void startTransitionToMainView() {
- _title.removeClass('in-story');
- _backButton.removeClass('in-story');
-
- _configButton.removeClass('in-story');
- _refreshButton.removeClass('in-story');
- _infoButton.removeClass('in-story');
-
- refreshWebStoryButtons();
- }
-
- void endTransitionToStoryView() {
- _title.addClass('in-story');
- _backButton.addClass('in-story');
-
- _configButton.addClass('in-story');
- _refreshButton.addClass('in-story');
- _infoButton.addClass('in-story');
- }
-}
-
-
-/** A back button for the web view of a story that is equivalent to clicking
- * "back" in the browser. */
-// TODO(rnystrom): We have nearly identical versions of this littered through
-// the sample apps. Should consolidate into one.
-class WebBackButton extends View {
- WebBackButton() : super();
-
- Element render() {
- return new Element.html('<div class="web-back-button button"></div>');
- }
-
- void afterRender(Element node) {
- addOnClick((e) { back(); });
- }
-
- /** Equivalent to [window.history.back] */
- static void back() {
- window.history.back();
- }
-}
-
-/** A back button for the web view of a story that is equivalent to clicking
- * "forward" in the browser. */
-// TODO(rnystrom): We have nearly identical versions of this littered through
-// the sample apps. Should consolidate into one.
-class WebForwardButton extends View {
- WebForwardButton() : super();
-
- Element render() {
- return new Element.html('<div class="web-forward-button button"></div>');
- }
-
- void afterRender(Element node) {
- addOnClick((e) { forward(); });
- }
-
- /** Equivalent to [window.history.forward] */
- static void forward() {
- window.history.forward();
- }
-}
-
-/**
- * A factory that creates a view for data sources.
- */
-class DataSourceViewFactory implements ViewFactory<Feed> {
- Swarm swarm;
-
- DataSourceViewFactory(this.swarm) {}
-
- View newView(Feed data) => new DataSourceView(data, swarm);
-
- int get width() => ArticleViewLayout.getSingleton().width;
- int get height() => null; // Width for this view isn't known.
-}
-
-
-/**
- * A view for the items from a single data source.
- * Shows a title and a list of items.
- */
-class DataSourceView extends CompositeView {
- // TODO(jacobr): make this value be coupled with the CSS file.
- static final TAB_ONLY_HEIGHT = 34;
-
- final Feed source;
- VariableSizeListView<Article> itemsView;
-
- DataSourceView(this.source, Swarm swarm) : super('query') {
-
- // TODO(jacobr): make the title a view or decide it is sane for a subclass
- // of component view to manually add some DOM cruft.
- node.nodes.add(new Element.html(
- '<h2>${source.title}</h2>'));
-
- // TODO(jacobr): use named arguments when available.
- itemsView = addChild(new VariableSizeListView<Article>(
- source.articles,
- new ArticleViewFactory(swarm),
- true, /* scrollable */
- true, /* vertical */
- swarm.state.currentArticle, /* selectedItem */
- !Device.supportsTouch /* snapToArticles */,
- false /* paginate */,
- true /* removeClippedViews */,
- !Device.supportsTouch /* showScrollbar */));
- itemsView.addClass('story-section');
-
- node.nodes.add(new Element.html('<div class="query-name-shadow"></div>'));
-
- // Clicking the view (i.e. its title area) unmaximizes to show the entire
- // view.
- node.on.mouseDown.add((e) {
- swarm.state.storyMaximized.value = false;
- }, false);
- }
-}
-
-/** A button that toggles between states. */
-class ToggleButton extends View {
- EventListeners onChanged;
- List<String> states;
-
- ToggleButton(this.states)
- : super(),
- onChanged = new EventListeners();
-
- Element render() => new Element.tag('button');
-
- void afterRender(Element node) {
- state = states[0];
- node.on.click.add((event) { toggle(); }, false);
- }
-
- String get state() {
- final currentState = node.innerHTML;
- assert(states.indexOf(currentState, 0) >= 0);
- return currentState;
- }
-
- void set state(String state) {
- assert(states.indexOf(state, 0) >= 0);
- node.innerHTML = state;
- onChanged.fire(null);
- }
-
- void toggle() {
- final oldState = state;
- int index = states.indexOf(oldState, 0);
- index = (index + 1) % states.length;
- state = states[index];
- }
-}
-
-/**
- * A factory that creates a view for generic items.
- */
-class ArticleViewFactory implements VariableSizeViewFactory<Article> {
- Swarm swarm;
-
- ArticleViewLayout layout;
- ArticleViewFactory(this.swarm)
- : layout = ArticleViewLayout.getSingleton();
-
- View newView(Article item) => new ArticleView(item, swarm, layout);
-
- int getWidth(Article item) => layout.width;
- int getHeight(Article item) => layout.computeHeight(item);
-}
-
-class ArticleViewMetrics {
- final int height;
- final int titleLines;
- final int bodyLines;
-
- const ArticleViewMetrics(this.height, this.titleLines, this.bodyLines);
-}
-
-class ArticleViewLayout {
- // TODO(terry): clean this up once we have a framework for sharing constants
- // between JS and CSS. See bug #5405307.
- static final IPAD_WIDTH = 257;
- static final DESKTOP_WIDTH = 297;
- static final CHROME_OS_WIDTH = 317;
- static final TITLE_MARGIN_LEFT = 257 - 150;
- static final BODY_MARGIN_LEFT = 257 - 221;
- static final LINE_HEIGHT = 18;
- static final TITLE_FONT = 'bold 13px arial,sans-serif';
- static final BODY_FONT = '13px arial,sans-serif';
- static final TOTAL_MARGIN = 16 * 2 + 70;
- static final MIN_TITLE_HEIGHT = 36;
- static final MAX_TITLE_LINES = 2;
- static final MAX_BODY_LINES = 4;
-
- MeasureText measureTitleText;
- MeasureText measureBodyText;
-
- int width;
- static ArticleViewLayout _singleton;
- ArticleViewLayout() :
- measureBodyText = new MeasureText(BODY_FONT),
- measureTitleText = new MeasureText(TITLE_FONT) {
- num screenWidth = window.screen.width;
- width = DESKTOP_WIDTH;
- }
-
- static ArticleViewLayout getSingleton() {
- if (_singleton == null) {
- _singleton = new ArticleViewLayout();
- }
- return _singleton;
- }
-
- int computeHeight(Article item) {
- if (item == null) {
- // TODO(jacobr): find out why this is happening..
- print('Null item encountered.');
- return 0;
- }
-
- return computeLayout(item, null, null).height;
- }
-
- /**
- * titleContainer and snippetContainer may be null in which case the size is
- * computed but no actual layout is performed.
- */
- ArticleViewMetrics computeLayout(Article item,
- StringBuffer titleBuffer,
- StringBuffer snippetBuffer) {
- int titleWidth = width - BODY_MARGIN_LEFT;
-
- if (item.hasThumbnail) {
- titleWidth = width - TITLE_MARGIN_LEFT;
- }
-
- final titleLines = measureTitleText.addLineBrokenText(titleBuffer,
- item.title, titleWidth, MAX_TITLE_LINES);
- final bodyLines = measureBodyText.addLineBrokenText(snippetBuffer,
- item.textBody, width - BODY_MARGIN_LEFT, MAX_BODY_LINES);
-
- int height = bodyLines * LINE_HEIGHT + TOTAL_MARGIN;
-
- if (bodyLines == 0) {
- height = 92;
- }
-
- return new ArticleViewMetrics(height, titleLines, bodyLines);
- }
-}
-
-/**
- * A view for a generic item.
- */
-class ArticleView extends View {
- // Set to false to make inspecting the HTML more pleasant...
- static final SAVE_IMAGES = false;
-
- final Article item;
- final Swarm swarm;
- final ArticleViewLayout articleLayout;
-
- ArticleView(this.item, this.swarm, this.articleLayout) : super();
-
- Element render() {
- Element node;
-
- final byline = item.author.length > 0 ? item.author : item.dataSource.title;
- final date = DateUtils.toRecentTimeString(item.date);
-
- String storyClass = 'story no-thumb';
- String thumbnail = '';
-
- if (item.hasThumbnail) {
- storyClass = 'story';
- thumbnail = '<img src="${item.thumbUrl}"></img>';
- }
-
- final title = new StringBuffer();
- final snippet = new StringBuffer();
-
- // Note: also populates title and snippet elements.
- final metrics = articleLayout.computeLayout(item, title, snippet);
-
- node = new Element.html('''
-<div class="$storyClass">
- $thumbnail
- <div class="title">$title</div>
- <div class="byline">$byline</div>
- <div class="dateline">$date</div>
- <div class="snippet">$snippet</div>
-</div>''');
-
- // Remove the snippet entirely if it's empty. This keeps it from taking up
- // space and pushing the padding down.
- if ((item.textBody == null) || (item.textBody.trim() == '')) {
- node.query('.snippet').remove();
- }
-
- return node;
- }
-
- void afterRender(Element node) {
-
- // Select this view's item.
- addOnClick((e) {
- // Mark the item as read, so it shows as read in other views
- item.unread.value = false;
-
- final oldArticle = swarm.state.currentArticle.value;
- swarm.state.currentArticle.value = item;
- swarm.state.storyTextMode.value = true;
- if (oldArticle == null) {
- swarm.state.pushToHistory();
- }
- });
-
- watch(swarm.state.currentArticle, (e) {
- if (!swarm.state.inMainView) {
- swarm.state.markCurrentAsRead();
- }
- _refreshSelected(swarm.state.currentArticle);
- //TODO(efortuna): add in history stuff while reading articles?
- });
-
- watch(swarm.state.selectedArticle, (e) {
- _refreshSelected(swarm.state.selectedArticle);
- _updateViewForSelectedArticle();
- });
-
- watch(item.unread, (e) {
- // TODO(rnystrom): Would be nice to do:
- // node.classes.set('story-unread', item.unread.value)
- if (item.unread.value) {
- node.classes.add('story-unread');
- } else {
- node.classes.remove('story-unread');
- }
- });
- }
-
- /**
- * Notify the view to jump to a different area if we are selecting an
- * article that is currently outside of the visible area.
- */
- void _updateViewForSelectedArticle() {
- Article selArticle = swarm.state.selectedArticle.value;
- if (swarm.state.hasArticleSelected) {
- // Ensure that the selected article is visible in the view.
- if (!swarm.state.inMainView) {
- // Story View.
- swarm.frontView.detachedView.itemsView.showView(selArticle);
- } else {
- if(swarm.frontView.currentSection.inCurrentView(selArticle)) {
- // Scroll horizontally if needed.
- swarm.frontView.currentSection.dataSourceView.showView(
- selArticle.dataSource);
- DataSourceView dataView = swarm.frontView.currentSection
- .findView(selArticle.dataSource);
- if(dataView != null) {
- dataView.itemsView.showView(selArticle);
- }
- }
- }
- }
- }
-
- String getDataUriForImage(final img) {
- // TODO(hiltonc,jimhug) eval perf of this vs. reusing one canvas element
- final canvas = new Element.html(
- '<canvas width="${img.width}" height="${img.height}"></canvas>');
-
- final ctx = canvas.getContext("2d");
- ctx.drawImage(img, 0, 0, img.width, img.height);
-
- return canvas.toDataURL("image/png");
- }
-
- /**
- * Update this view's selected appearance based on the currently selected
- * Article.
- */
- void _refreshSelected(curItem) {
- if (curItem.value == item) {
- addClass('sel');
- } else {
- removeClass('sel');
- }
- }
-
- void _saveToStorage(String thumbUrl, ImageElement img) {
- // TODO(jimhug): Reimplement caching of images.
- }
-}
-
-/**
- * An internal view of a story as text. In other words, the article is shown
- * in-place as opposed to as an embedded web-page.
- */
-class StoryContentView extends View {
- final Swarm swarm;
- final Article item;
-
- View _pagedStory;
-
- StoryContentView(this.swarm, this.item) : super();
-
- get childViews() => [_pagedStory];
-
- Element render() {
- final storyContent = new Element.html(
- '<div class="story-content">${item.htmlBody}</div>');
- for (Element element in storyContent.queryAll(
- "iframe, script, style, object, embed, frameset, frame")) {
- element.remove();
- }
- _pagedStory = new PagedContentView(new View.fromNode(storyContent));
-
- // Modify all links to open in new windows....
- // TODO(jacobr): would it be better to add an event listener on click that
- // intercepts these instead?
- for (final anchor in storyContent.queryAll('a')) {
- anchor.target = '_blank';
- }
-
- final date = DateUtils.toRecentTimeString(item.date);
- final container = new Element.html('''
- <div class="story-view">
- <div class="story-text-view">
- <div class="story-header">
- <a class="story-title" href="${item.srcUrl}" target="_blank">
- ${item.title}</a>
- <div class="story-byline">
- ${item.author} - ${item.dataSource.title}
- </div>
- <div class="story-dateline">$date</div>
- </div>
- <div class="paged-story"></div>
- <div class="spacer"></div>
- </div>
- </div>''');
-
- container.query('.paged-story').replaceWith(_pagedStory.node);
-
- return container;
- }
-}
-
-class SectionView extends CompositeView {
- final Section section;
- final Swarm swarm;
- final DataSourceViewFactory _viewFactory;
- final View loadingText;
- ListView<Feed> dataSourceView;
- PageNumberView pageNumberView;
- final PageState pageState;
-
- SectionView(this.swarm, this.section, this._viewFactory)
- : super('section-view'),
- loadingText = new View.html('<div class="loading-section"></div>'),
- pageState = new PageState() {
- addChild(loadingText);
- }
-
- /**
- * Hides the loading text, reloads the data sources, and shows them.
- */
- void showSources() {
- loadingText.node.style.display = 'none';
-
- // Lazy initialize the data source view.
- if (dataSourceView == null) {
- // TODO(jacobr): use named arguments when available.
- dataSourceView = new ListView<Feed>(
- section.feeds, _viewFactory,
- true /* scrollable */,
- false /* vertical */,
- null /* selectedItem */,
- true /* snapToItems */,
- true /* paginate */,
- true /* removeClippedViews */,
- false, /* showScrollbar */
- pageState);
- dataSourceView.addClass("data-source-view");
- addChild(dataSourceView);
-
- pageNumberView = addChild(new PageNumberView(pageState));
-
- node.style.opacity = '1';
- } else {
- addChild(dataSourceView);
- addChild(pageNumberView);
- node.style.opacity = '1';
- }
-
- // TODO(jacobr): get rid of this call to reconfigure when it is not needed.
- dataSourceView.scroller.reconfigure(() {});
- }
-
- /**
- * Hides the data sources and shows the loading text.
- */
- void hideSources() {
- if (dataSourceView != null) {
- node.style.opacity = '0.6';
- removeChild(dataSourceView);
- removeChild(pageNumberView);
- }
-
- loadingText.node.style.display = 'block';
- }
-
- set storyMode(bool inStoryMode) {
- if (inStoryMode) {
- addClass('hide-all-queries');
- } else {
- removeClass('hide-all-queries');
- }
- }
-
- /**
- * Find the [DataSourceView] in this SectionView that's displaying the given
- * [Feed].
- */
- DataSourceView findView(Feed dataSource) {
- return dataSourceView.getSubview(dataSourceView.findIndex(dataSource));
- }
-
- bool inCurrentView(Article article) {
- return dataSourceView.findIndex(article.dataSource) != null;
- }
-}
« no previous file with comments | « client/samples/swarm/SwarmState.dart ('k') | client/samples/swarm/UIState.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698