class Calendar(FocusPanel, DateSelectedHandler): monthsOfYear = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] daysOfWeek = ['S', 'M', 'T', 'W', 'T', 'F', 'S'] today = 'Today' tomorrow = 'Tomorrow' yesterday = 'Yesterday' cancel = 'Cancel' def __init__(self, **kwargs): FocusPanel.__init__(self, **kwargs) DateSelectedHandler.__init__(self) yr, mth, day = time.strftime("%Y-%m-%d").split("-") self.todayYear = int(yr) self.todayMonth = int(mth) # change to offset 0 as per javascript self.todayDay = int(day) self.currentMonth = self.todayMonth self.currentYear = self.todayYear self.currentDay = self.todayDay self.defaultGrid = None # used later return def setDate(self, _date): """ _date - object of datetime.date class """ self.currentMonth = _date.month self.currentYear = _date.year self.currentDay = _date.day def getMonthsOfYear(self): return self.monthsOfYear def getDaysOfWeek(self): return self.daysOfWeek def isLeapYear(self, year): if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0): return True else: return False def getDaysInMonth(self, mth, year): days = 0 if mth in [1, 3, 5, 7, 8, 10, 12]: days = 31 elif mth in [4, 6, 9, 11]: days = 30 elif (mth == 2 and self.isLeapYear(year)): days = 29 else: days = 28 return days def setPosition(self, left, top): element = self.getElement() DOM.setStyleAttribute(element, "left", "%dpx" % left) DOM.setStyleAttribute(element, "top", "%dpx" % top) def show(self, left, top): if left < 0: left = 0 if top < 0: top = 0 self.setPosition(left, top) self.drawCurrent() self.setVisible(True) def drawCurrent(self): yr, mth, day = self.currentYear, self.currentMonth, self.currentDay self.draw(int(mth), int(yr)) def draw(self, month , year): tod = time.localtime() mm = tod.tm_mon yy = tod.tm_year # has today changed and thus changed month? cater to rare case # where widget in created on last day of month and # page left till next day hasChangeMonth = False if yy <> self.todayYear or mm <> self.todayMonth: hasChangeMonth = True self.todayYear = yy self.todayMonth = mm # check to see if we have drawn the full widget before if self.defaultGrid is None: self.drawFull(month, year) else: # ok means we are re-drawing, but first check if it is the same # as the defaultGrid, if yes, just use it if not hasChangeMonth and month == self.todayMonth and \ year == self.todayYear: self.middlePanel.setWidget(self.defaultGrid) self.currentMonth = self.todayMonth self.currentYear = self.todayYear else: # we have to redraw the grid -- bah g = self.drawGrid(month, year) if hasChangeMonth: # reset the default grid as we have changed months self.defaultGrid = grid # # what about the title panel? # txt = "<b>" txt += self.getMonthsOfYear()[month - 1] + " " + str(year) txt += "</b>" self.titlePanel.setWidget(HTML(txt)) self.setVisible(True) return def drawFull(self, month, year): # should be called only once when we draw the calendar for # the first time self.vp = VerticalPanel() self.vp.setSpacing(2) self.vp.addStyleName("calendarbox calendar-module calendar") self.setWidget(self.vp) self.setVisible(False) # mth = int(month) yr = int(year) tp = HorizontalPanel() tp.addStyleName("calendar-top-panel") tp.setSpacing(5) h1 = Hyperlink('<<') h1.addClickListener(getattr(self, 'onPreviousYear')) h2 = Hyperlink('<') h2.addClickListener(getattr(self, 'onPreviousMonth')) h4 = Hyperlink('>') h4.addClickListener(getattr(self, 'onNextMonth')) h5 = Hyperlink('>>') h5.addClickListener(getattr(self, 'onNextYear')) tp.add(h1) tp.add(h2) # titlePanel can be changed, whenever we draw, so keep the reference txt = "<b>" txt += self.getMonthsOfYear()[mth - 1] + " " + str(yr) txt += "</b>" self.titlePanel = SimplePanel() self.titlePanel.setWidget(HTML(txt)) self.titlePanel.setStyleName("calendar-center") tp.add(self.titlePanel) tp.add(h4) tp.add(h5) tvp = VerticalPanel() tvp.setSpacing(10) tvp.add(tp) self.vp.add(tvp) # done with top panel self.middlePanel = SimplePanel() grid = self.drawGrid(mth, yr) self.middlePanel.setWidget(grid) self.vp.add(self.middlePanel) self.defaultGrid = grid self._gridShortcutsLinks() self._gridCancelLink() # # add code to test another way of doing the layout # self.setVisible(True) return def _gridShortcutsLinks(self): # # some links & handlers # bh1 = Hyperlink(self.yesterday) bh1.addClickListener(getattr(self, 'onYesterday')) bh2 = Hyperlink(self.today) bh2.addClickListener(getattr(self, 'onToday')) bh3 = Hyperlink(self.tomorrow) bh3.addClickListener(getattr(self, 'onTomorrow')) b = HorizontalPanel() b.add(bh1) b.add(bh2) b.add(bh3) b.addStyleName("calendar-shortcuts") self.vp.add(b) def _gridCancelLink(self): bh4 = Hyperlink(self.cancel) bh4.addClickListener(getattr(self, 'onCancel')) b2 = SimplePanel() b2.add(bh4) b2.addStyleName("calendar-cancel") self.vp.add(b2) def drawGrid(self, month, year): # draw the grid in the middle of the calendar daysInMonth = self.getDaysInMonth(month, year) # first day of the month & year secs = time.mktime((year, month, 1, 0, 0, 0, 0, 0, -1)) struct = time.localtime(secs) # 0 - sunday for our needs instead 0 = monday in tm_wday startPos = (struct.tm_wday + 1) % 7 slots = startPos + daysInMonth - 1 rows = int(slots / 7) + 1 grid = Grid(rows + 1, 7) # extra row for the days in the week grid.setWidth("100%") grid.addTableListener(self) self.middlePanel.setWidget(grid) # # put some content into the grid cells # for i in range(7): grid.setText(0, i, self.getDaysOfWeek()[i]) grid.cellFormatter.addStyleName(0, i, "calendar-header") # # draw cells which are empty first # day = 0 pos = 0 while pos < startPos: grid.setText(1, pos , " ") grid.cellFormatter.setStyleAttr(1, pos, "background", "#f3f3f3") grid.cellFormatter.addStyleName(1, pos, "calendar-blank-cell") pos += 1 # now for days of the month row = 1 day = 1 col = startPos while day <= daysInMonth: if pos % 7 == 0 and day <> 1: row += 1 col = pos % 7 grid.setText(row, col, str(day)) if self.currentYear == self.todayYear and \ self.currentMonth == self.todayMonth and day == self.todayDay: grid.cellFormatter.addStyleName(row, col, "calendar-cell-today") else: grid.cellFormatter.addStyleName(row, col, "calendar-day-cell") day += 1 pos += 1 # # now blank lines on the last row # col += 1 while col < 7: grid.setText(row, col, " ") grid.cellFormatter.setStyleAttr(row, col, "background", "#f3f3f3") grid.cellFormatter.addStyleName(row, col, "calendar-blank-cell") col += 1 return grid def onCellClicked(self, grid, row, col): if row == 0: return text = grid.getText(row, col).strip() if text == "": return try: selectedDay = int(text) except ValueError, e: return self.fireDateSelectedEvent(date( self.currentYear, self.currentMonth, selectedDay, )) self.setVisible(False)
class Calendar(FocusPanel): monthsOfYear = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] daysOfWeek = ['S', 'M', 'T', 'W', 'T', 'F', 'S'] today = 'Today' tomorrow = 'Tomorrow' yesterday = 'Yesterday' cancel = 'Cancel' def __init__(self, **kwargs): FocusPanel.__init__(self, **kwargs) yr, mth, day = time.strftime("%Y-%m-%d").split("-") self.todayYear = int(yr) self.todayMonth = int(mth) # change to offset 0 as per javascript self.todayDay = int(day) self.currentMonth = self.todayMonth self.currentYear = self.todayYear self.currentDay = self.todayDay self.selectedDateListeners = [] self.defaultGrid = None # used later return def setDate(self,_date): """ _date - object of datetime.date class """ self.currentMonth = _date.month self.currentYear = _date.year self.currentDay = _date.day def getMonthsOfYear(self): return self.monthsOfYear def getDaysOfWeek(self): return self.daysOfWeek def addSelectedDateListener(self, listener): self.selectedDateListeners.append(listener) def removeSelectedDateListener(self, listener): self.selectedDateListeners.remove(listener) def isLeapYear(self, year): if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0): return True else: return False def getDaysInMonth(self, mth, year): days = 0 if mth in [1, 3, 5, 7, 8, 10, 12]: days=31 elif mth in [4, 6, 9, 11]: days = 30 elif (mth==2 and self.isLeapYear(year)): days = 29 else: days = 28 return days def setPosition(self, left, top): element = self.getElement() DOM.setStyleAttribute(element, "left", "%dpx" % left) DOM.setStyleAttribute(element, "top", "%dpx" % top) def show(self, left, top): if left < 0: left = 0 if top < 0: top = 0 self.setPosition(left, top) self.drawCurrent() self.setVisible(True) def drawCurrent(self): yr, mth, day = self.currentYear, self.currentMonth, self.currentDay self.draw(int(mth), int(yr)) def draw(self, month , year): tod = time.localtime() mm = tod.tm_mon yy = tod.tm_year # has today changed and thus changed month? cater to rare case # where widget in created on last day of month and # page left till next day hasChangeMonth = False if yy <> self.todayYear or mm <> self.todayMonth: hasChangeMonth = True self.todayYear = yy self.todayMonth = mm # check to see if we have drawn the full widget before if self.defaultGrid is None: self.drawFull(month, year) else: # ok means we are re-drawing, but first check if it is the same # as the defaultGrid, if yes, just use it if not hasChangeMonth and month == self.todayMonth and \ year == self.todayYear: self.middlePanel.setWidget(self.defaultGrid) self.currentMonth = self.todayMonth self.currentYear = self.todayYear else: # we have to redraw the grid -- bah g = self.drawGrid(month, year) if hasChangeMonth: # reset the default grid as we have changed months self.defaultGrid = grid # # what about the title panel? # txt = "<b>" txt += self.getMonthsOfYear()[month-1] + " " + str(year) txt += "</b>" self.titlePanel.setWidget(HTML(txt)) self.setVisible(True) return def drawFull(self, month, year): # should be called only once when we draw the calendar for # the first time self.vp = VerticalPanel() self.vp.setSpacing(2) self.vp.addStyleName("calendarbox calendar-module calendar") self.setWidget(self.vp) self.setVisible(False) # mth = int(month) yr = int(year) tp = HorizontalPanel() tp.addStyleName("calendar-top-panel") tp.setSpacing(5) h1 = Hyperlink('<<') h1.addClickListener(getattr(self, 'onPreviousYear')) h2 = Hyperlink('<') h2.addClickListener(getattr(self, 'onPreviousMonth')) h4 = Hyperlink('>') h4.addClickListener(getattr(self, 'onNextMonth')) h5 = Hyperlink('>>') h5.addClickListener(getattr(self, 'onNextYear')) tp.add(h1) tp.add(h2) # titlePanel can be changed, whenever we draw, so keep the reference txt = "<b>" txt += self.getMonthsOfYear()[mth-1] + " " + str(yr) txt += "</b>" self.titlePanel = SimplePanel() self.titlePanel.setWidget(HTML(txt)) self.titlePanel.setStyleName("calendar-center") tp.add(self.titlePanel) tp.add(h4) tp.add(h5) tvp = VerticalPanel() tvp.setSpacing(10) tvp.add(tp) self.vp.add(tvp) # done with top panel self.middlePanel = SimplePanel() grid = self.drawGrid(mth, yr) self.middlePanel.setWidget(grid) self.vp.add(self.middlePanel) self.defaultGrid = grid self._gridShortcutsLinks() self._gridCancelLink() # # add code to test another way of doing the layout # self.setVisible(True) return def _gridShortcutsLinks(self): # # some links & handlers # bh1 = Hyperlink(self.yesterday) bh1.addClickListener(getattr(self, 'onYesterday')) bh2 = Hyperlink(self.today) bh2.addClickListener(getattr(self, 'onToday')) bh3 = Hyperlink(self.tomorrow) bh3.addClickListener(getattr(self, 'onTomorrow')) b = HorizontalPanel() b.add(bh1) b.add(bh2) b.add(bh3) b.addStyleName("calendar-shortcuts") self.vp.add(b) def _gridCancelLink(self): bh4 = Hyperlink(self.cancel) bh4.addClickListener(getattr(self, 'onCancel')) b2 = SimplePanel() b2.add(bh4) b2.addStyleName("calendar-cancel") self.vp.add(b2) def drawGrid(self, month, year): # draw the grid in the middle of the calendar daysInMonth = self.getDaysInMonth(month, year) # first day of the month & year secs = time.mktime((year, month, 1, 0, 0, 0, 0, 0, -1)) struct = time.localtime(secs) # 0 - sunday for our needs instead 0 = monday in tm_wday startPos = (struct.tm_wday + 1) % 7 slots = startPos + daysInMonth - 1 rows = int(slots/7) + 1 grid = Grid(rows+1, 7) # extra row for the days in the week grid.setWidth("100%") grid.addTableListener(self) self.middlePanel.setWidget(grid) # # put some content into the grid cells # for i in range(7): grid.setText(0, i, self.getDaysOfWeek()[i]) grid.cellFormatter.addStyleName(0, i, "calendar-header") # # draw cells which are empty first # day =0 pos = 0 while pos < startPos: grid.setText(1, pos , " ") grid.cellFormatter.setStyleAttr(1, pos, "background", "#f3f3f3") grid.cellFormatter.addStyleName(1, pos, "calendar-blank-cell") pos += 1 # now for days of the month row = 1 day = 1 col = startPos while day <= daysInMonth: if pos % 7 == 0 and day <> 1: row += 1 col = pos % 7 grid.setText(row, col, str(day)) if self.currentYear == self.todayYear and \ self.currentMonth == self.todayMonth and day == self.todayDay: grid.cellFormatter.addStyleName(row, col, "calendar-cell-today") else: grid.cellFormatter.addStyleName(row, col, "calendar-day-cell") day += 1 pos += 1 # # now blank lines on the last row # col += 1 while col < 7: grid.setText(row, col, " ") grid.cellFormatter.setStyleAttr(row, col, "background", "#f3f3f3") grid.cellFormatter.addStyleName(row, col, "calendar-blank-cell") col += 1 return grid def onCellClicked(self, grid, row, col): if row == 0: return text = grid.getText(row, col).strip() if text == "": return try: selectedDay = int(text) except ValueError, e: return # well if anyone is listening to the listener, fire that event for listener in self.selectedDateListeners: if hasattr(listener, "onDateSelected"): listener.onDateSelected(self.currentYear, self.currentMonth, selectedDay) else: listener(self.currentYear, self.currentMonth, selectedDay) self.setVisible(False)
class MovieRatings: def onModuleLoad(self): # Setup JSON RPC self.remote = DataService() ### Initialize member variables self.mainPanel = HorizontalPanel() self.rightPanel = VerticalPanel() self.moviesPanel = VerticalPanel() self.topRatedPanel = VerticalPanel() self.categoriesPanel = VerticalPanel() self.moviesFlexTable = FlexTable() self.topRatedMoviesFlexTable = FlexTable() self.topCategoryMoviesFlexTable = FlexTable() self.lessThanFiveLabel = Label('There are less than 5 movies. Add more movies!') self.moviesListLabel = Label('Movies List') self.addPanel = VerticalPanel() self.newMovieCategoryTextBox = TextBox() self.newMovieNameTextBox = TextBox() self.newMovieRatingListBox = ListBox(False) self.addMovieButton = Button('Add', self.addMovieButton_Click) self.movies = [] self.topRatedMovies = [] self.categories = {} self.MAX_RATING = 10 ### Add Movie Panel # Add ratings to list box for i in range(self.MAX_RATING + 1): self.newMovieRatingListBox.addItem(str(i)) # Add label and textbox to horizontal panel self.labelPanel = HorizontalPanel() self.labelPanel.add(Label("Add a movie:")) self.categoryPanel = HorizontalPanel() self.categoryPanel.add(Label("Category: ")) self.categoryPanel.add(self.newMovieCategoryTextBox) self.namePanel = HorizontalPanel() self.namePanel.add(Label("Movie Name: ")) self.namePanel.add(self.newMovieNameTextBox) self.ratingPanel = HorizontalPanel() self.ratingPanel.add(Label("Movie Rating: ")) self.ratingPanel.add(self.newMovieRatingListBox) self.labelPanel.addStyleName("addLabel") self.labelPanel.setSpacing(5) self.categoryPanel.addStyleName("addPanel") self.categoryPanel.setSpacing(5) self.namePanel.addStyleName("addPanel") self.namePanel.setSpacing(5) self.ratingPanel.addStyleName("addPanel") self.ratingPanel.setSpacing(5) self.newMovieCategoryTextBox.addStyleName("addPanel-input") self.newMovieNameTextBox.addStyleName("addPanel-input") self.newMovieRatingListBox.addStyleName("addPanel-input") self.addPanel.add(self.labelPanel) self.addPanel.add(self.categoryPanel) self.addPanel.add(self.namePanel) self.addPanel.add(self.ratingPanel) self.addPanel.add(self.addMovieButton) self.addPanel.addStyleName("addPanel") self.addMovieButton.addStyleName('addButton') self.addPanel.add(self.addMovieButton) self.addPanel.addStyleName('addPanel') ### Movies table self.moviesFlexTable.setText(0, 1, "Category") self.moviesFlexTable.setText(0, 2, "Title") self.moviesFlexTable.setText(0, 3, "Rating") self.moviesFlexTable.addStyleName("movieList") self.moviesFlexTable.getRowFormatter().addStyleName(0, "listHeader") self.moviesFlexTable.setCellPadding(6) self.moviesFlexTable.getCellFormatter().setStyleName(0, 1, "listHeaderColumn") self.moviesFlexTable.getCellFormatter().setStyleName(0, 2, "listHeaderColumn") self.moviesListLabel.addStyleName("listLabel") self.moviesPanel.add(self.moviesListLabel) self.moviesPanel.add(self.moviesFlexTable) self.moviesPanel.setStyleName("moviesPanel") ### Top rated movies table self.topRatedMoviesFlexTable.setText(0, 0, "Category") self.topRatedMoviesFlexTable.setText(0, 1, "Title") self.topRatedMoviesFlexTable.setText(0, 2, "Rating") self.topRatedMoviesFlexTable.addStyleName("topMoviesList") self.topRatedMoviesFlexTable.getRowFormatter().addStyleName(0, "listHeader") self.topRatedMoviesFlexTable.setCellPadding(6) self.topRatedMoviesFlexTable.getCellFormatter().setStyleName(0, 0, "listHeaderColumn") self.topRatedMoviesFlexTable.getCellFormatter().setStyleName(0, 1, "listHeaderColumn") self.topRatedLabel = Label("Top 5 Rated Movies") self.topRatedLabel.addStyleName("listLabel") self.lessThanFiveLabel.addStyleName("noticeLabel") self.topRatedPanel.add(self.topRatedLabel) self.topRatedPanel.add(self.topRatedMoviesFlexTable) self.topRatedPanel.add(self.lessThanFiveLabel) self.topRatedPanel.setStyleName("topRatedPanel") ### Categories table self.topCategoryMoviesFlexTable.setText(0, 0, "Category") self.topCategoryMoviesFlexTable.setText(0, 1, "Top Movie") self.topCategoryMoviesFlexTable.setText(0, 2, "Average Rating") self.topCategoryMoviesFlexTable.addStyleName("topCategoryMoviesList") self.topCategoryMoviesFlexTable.getRowFormatter().addStyleName(0, "listHeader") self.topCategoryMoviesFlexTable.setCellPadding(6) self.topCategoryMoviesFlexTable.getCellFormatter().setStyleName(0, 0, "listHeaderColumn") self.topCategoryMoviesFlexTable.getCellFormatter().setStyleName(0, 1, "listHeaderColumn") self.categoriesLabel = Label("Movie Categories") self.categoriesLabel.addStyleName("listLabel") self.categoriesPanel.add(self.categoriesLabel) self.categoriesPanel.add(self.topCategoryMoviesFlexTable) self.categoriesPanel.setStyleName("categoriesPanel") ### Assemble Main panel self.rightPanel.add(self.topRatedPanel) self.rightPanel.add(self.categoriesPanel) self.mainPanel.add(self.moviesPanel) self.mainPanel.add(self.rightPanel) self.mainPanel.setStyleName("mainPanel") self.mainPanel.setSpacing(25) # Associate panels with the HTML host page RootPanel('addPanel').add(self.addPanel) RootPanel('main').add(self.mainPanel) # Move cursor focus to the input box self.newMovieNameTextBox.setFocus(True) # Load the movies self.remote.getMovies(self) def verifyInputs(self, name, category): if len(name) == 0: Window.alert("Movie name cannot be empty.") return False if len(name) > 100: Window.alert("Movie name is too long. Maximum length is 100 characters.") return False if len(category) == 0: Window.alert("Category cannot be empty.") return False p = re.compile('^[0-9A-Za-z\\.\\-\\(\\) ]{1,100}$') if p.match(category) == None: Window.alert('"%s" is not a valid category.' % category) return False return True def addMovieButton_Click(self, event): name = self.newMovieNameTextBox.getText().trim() cat = self.newMovieCategoryTextBox.getText().trim().lower() category = cat[0].upper() + cat[1:] rating = self.newMovieRatingListBox.getSelectedIndex() if not self.verifyInputs(name, category): return movie = Movie(name, category, rating) if movie in self.movies: Window.alert("'" + name + "' is already in table.") self.newMovieNameTextBox.selectAll() return self.remote.addMovie((name, category, rating), self) self.newMovieNameTextBox.setText('') def addMovie(self, sender, movie): self.movies.append(movie) row = self.moviesFlexTable.getRowCount() self.moviesFlexTable.setText(row, 1, movie.category) self.moviesFlexTable.setText(row, 2, movie.name) self.moviesFlexTable.setText(row, 3, movie.rating) # Adds buttons for remove, edit, save and cancel removeMovieButton = Button("x") editMovieButton = Button("Edit") saveButton = Button("Save") cancelButton = Button("Cancel") # Save and cancel are hidden by default saveButton.setVisible(False) cancelButton.setVisible(False) # Add buttons to row buttons = HorizontalPanel() buttons.add(removeMovieButton) buttons.add(editMovieButton) buttons.add(cancelButton) buttons.add(saveButton) self.moviesFlexTable.setWidget(row, 0, buttons) def removeMovieButton_Click(sender): self.remote.deleteMovie((movie.name, movie.category), self) removeMovieButton.addClickListener(removeMovieButton_Click) def editMovieButton_Click(sender): # Add textboxes and listbox editMovieButton.setVisible(False) cancelButton.setVisible(True) saveButton.setVisible(True) editCategory = TextBox() editName = TextBox() editRating = ListBox(False) for i in range(self.MAX_RATING + 1): editRating.addItem(str(i)) # Variable width textboxes catlen = len(movie.category) namelen = len(movie.name) if (catlen > 8): editCategory.setWidth(str(catlen*10) + "px") else: editCategory.setWidth("80px") if (namelen > 8): editName.setWidth(str(namelen*10) + "px") else: editName.setWidth("80px") self.moviesFlexTable.setWidget(row, 1, editCategory) self.moviesFlexTable.setWidget(row, 2, editName) self.moviesFlexTable.setWidget(row, 3, editRating) editCategory.setText(movie.category) editName.setText(movie.name) editRating.setSelectedIndex(movie.rating) editMovieButton.addClickListener(editMovieButton_Click) def saveButton_Click(sender): catText = self.moviesFlexTable.getWidget(row, 1) nameText = self.moviesFlexTable.getWidget(row, 2) ratingList = self.moviesFlexTable.getWidget(row, 3) newCategory = catText.getText().trim().lower() newCategory = newCategory[0].upper() + newCategory[1:] newName = nameText.getText().trim() newRating = ratingList.getSelectedIndex() if not self.verifyInputs(newName, newCategory): return # Removes temporarily to check for duplicates self.movies.remove(movie) newMovie = Movie(newName, newCategory, newRating) if newMovie in self.movies: Window.alert("'" + newName + "' is already in table.") nameText.selectAll() return self.remote.editMovie((movie.name, movie.category), (newMovie.name, newMovie.category, newMovie.rating), self) saveButton.addClickListener(saveButton_Click) def cancelButton_Click(sender): self.moviesFlexTable.remove(self.moviesFlexTable.getWidget(row, 1)) self.moviesFlexTable.remove(self.moviesFlexTable.getWidget(row, 2)) self.moviesFlexTable.remove(self.moviesFlexTable.getWidget(row, 3)) # Reverts fields to old movie info self.moviesFlexTable.setText(row, 1, movie.category) self.moviesFlexTable.setText(row, 2, movie.name) self.moviesFlexTable.setText(row, 3, movie.rating) cancelButton.setVisible(False) saveButton.setVisible(False) editMovieButton.setVisible(True) cancelButton.addClickListener(cancelButton_Click) def updateTopRatedMovies(self): numTopRated = len(self.topRatedMovies) self.clearTable(self.topRatedMoviesFlexTable) for row in range(numTopRated): self.topRatedMoviesFlexTable.setText(row+1, 0, self.topRatedMovies[row].category) self.topRatedMoviesFlexTable.setText(row+1, 1, self.topRatedMovies[row].name) self.topRatedMoviesFlexTable.setText(row+1, 2, self.topRatedMovies[row].rating) # Label should only be visible if less than 5 movies self.lessThanFiveLabel.setVisible(numTopRated < 5) def updateCategories(self): self.clearTable(self.topCategoryMoviesFlexTable) for row, cat in enumerate(self.categories): self.topCategoryMoviesFlexTable.setText(row+1, 0, cat + " (" + str(self.categories[cat][2]) + ")") self.topCategoryMoviesFlexTable.setText(row+1, 1, self.categories[cat][0]) self.topCategoryMoviesFlexTable.setText(row+1, 2, "%.1f" % float(self.categories[cat][1])) def clearTable(self, table): try: for i in range(table.getRowCount()): table.removeRow(1) except: pass # Called when a response is received from a RPC. def onRemoteResponse(self, response, request_info): if request_info.method in ['getMovies', 'addMovie', 'deleteMovie', 'editMovie']: # Clear current and add all self.movies = [] self.clearTable(self.moviesFlexTable) for m in response: movie = Movie(m[0], m[1], m[2]) self.addMovie(None, movie) self.moviesListLabel.setText("Movies List (" + str(len(self.movies)) + ")") self.remote.getTopRated(self) self.remote.getCategories(self) if request_info.method == 'getTopRated': # Update top rated self.topRatedMovies = [] for m in response: movie = Movie(m[0], m[1], m[2]) self.topRatedMovies.append(movie) self.updateTopRatedMovies() if request_info.method == 'getCategories': # Update categories self.categories = response self.updateCategories()
class PageVerify: # setup JSON RPC facebook_user = {} users = [] new_user = {} get_data = {} app_info = {} verification_key = None verification_status = False def onModuleLoad(self): self.remote = DataService() # do JSON RPC calls self.remote.get_facebook_user(self) self.remote.get_app_info(self, "verify") # labels and banners self.html_verify_banner = HTML("<h1>Verify your NetID</h1>") self.html_confirm_banner = HTML("<h1>Confirming your NetID...</h1>") self.lbl_verify_text = Label("Please verify your account.") self.lbl_confirm_text = Label("Confirming Acount...") self.lbl_confirm_result = Label() # textboxes self.tb_verify_netid = TextBox() # hook up keyboard events send_confirmation_email = self.send_confirmation_email class Add_KeyboardHandler(): def onKeyPress(self, sender, keycode, modifiers): if keycode == KEY_ENTER: send_confirmation_email() def onKeyDown(self, sender, keycode, modifiers): return def onKeyUp(self, sender, keycode, modifiers): return self.kbh = Add_KeyboardHandler() self.tb_verify_netid.addKeyboardListener(self.kbh) # buttons self.btn_verify = Button("Verify!", self.send_confirmation_email) # NetID information form self.table_verify_netid = FlexTable() self.table_verify_netid.setText(0, 0, "NetID:") self.table_verify_netid.setWidget(0, 1, self.tb_verify_netid) self.table_verify_netid.setWidget(1, 1, self.btn_verify) # panels self.main_panel = VerticalPanel() # check get information, if present, verify, if not request form self.location = Window.getLocation().getHref() self.tmp = self.location.split('?') self.tmp = self.tmp[len(self.tmp) - 1].split("&") for e in self.tmp: get_var = e.split("=") if len(get_var) == 2: PageVerify.get_data[get_var[0]] = get_var[1] if "vk" in PageVerify.get_data: # we have request from verification email self.main_panel.add(self.html_confirm_banner) self.main_panel.add(self.lbl_confirm_text) self.main_panel.add(self.lbl_confirm_result) self.verify_user() else: self.main_panel.add(self.html_verify_banner) self.main_panel.add(self.lbl_verify_text) self.main_panel.add(self.table_verify_netid) self.main_panel.addStyleName("verify_panel") # add everything to root panel RootPanel("page_verify").add(self.main_panel) def send_confirmation_email(self, sender, netid = None): """ given a valid NetID, send a confirmation email with a link (using encrypted key) to validate the user's NetID """ if netid == None: netid = self.tb_verify_netid.getText() # create a new user with netid and facebook id self.remote.create_user(self, PageVerify.facebook_user['facebook_id'], netid, PageVerify.facebook_user['full_name']) # create cryptogram based on email name self.remote.encrypt(self, netid) # subject line subject = "Hello from Textbook Connect!" class EmailTimer(Timer): def __init__(self, context): Timer.__init__(self) self.max_tries = 10 self.tries = 0 self.context = context def run(self): self.context.btn_verify.setEnabled(False) self.context.tb_verify_netid.setFocus(False) self.tries += 1 # stop timer after a certain time if self.tries >= self.max_tries: Window.alert("It looks like there's a connection problem. We're sorry about the inconvenience. Please try again later.") self.context.btn_verify.setEnabled(True) self.cancel() return False if "error" in PageVerify.new_user: Window.alert(PageVerify.new_user["error"]) return False if len(PageVerify.new_user) == 0 or PageVerify.verification_key == None: return False # message body link = "%sverify?vk=%s" % (PageVerify.app_info['url'], PageVerify.verification_key) body = "Hello, %s.<br /><br />Thank you for verifying your netid with us! " % PageVerify.new_user['name'] body += "Please click the link below or copy and paste the link into a web browser.<br /><br />" body += "<a href=\"%s\">%s</a><br /><br />" % (link, link) body += "Thanks,<br /> Textbook Connect Team" self.context.remote.send_email(self.context, netid + "@cornell.edu", subject, body) Window.alert("Thank you! An email from Textbook Connect should arrive shortly.") self.cancel() return True et = EmailTimer(self) et.scheduleRepeating(500) def verify_user(self): """ take get data input with verification key and attempt to verify a user in the database """ class VerifyTimer(Timer): def __init__(self, context): Timer.__init__(self) self.max_tries = 10 self.tries = 0 self.context = context def run(self): self.tries += 1 if self.context.facebook_user == None or "vk" not in self.context.get_data: return False # stop timer after a certain time if self.tries >= self.max_tries: Window.alert("It looks like there's a connection problem. We're sorry about the inconvenience. Please try again later.") self.context.lbl_confirm_result.setText("User verification unsuccessful...") self.cancel() return False self.context.remote.verify_email(self.context, self.context.facebook_user['facebook_id'], self.context.get_data['vk']) if self.context.verification_status: self.context.lbl_confirm_result.setText("User verification successful!") self.cancel() Window.open(self.context.app_info['url'], "_top", "") return True vt = VerifyTimer(self) vt.scheduleRepeating(500) def onRemoteResponse(self, response, request_info): """ Called when a response is received from an RPC """ if not request_info.method in DataService.methods: Window.alert('Unrecognized JSONRPC method.') return if request_info.method == "get_facebook_user": PageVerify.facebook_user = {} for k, v in response.items(): PageVerify.facebook_user[k] = v elif request_info.method == "get_app_info": for k, v in response.items(): PageVerify.app_info[k] = v elif request_info.method == "encrypt": PageVerify.verification_key = response['c'] elif request_info.method == "verify_email": PageVerify.verification_status = response['result'] elif request_info.method == "create_user": PageVerify.new_user = {} for k, v in response.items(): PageVerify.new_user[k] = v def onRemoteError(self, code, message, request_info): """ Called when a returned response is invalid or Server Error """ code = str(code) message = str(message) if len(code) > 200: code = code[0:200] + "..." if len(message) > 200: message = message[0:200] + "..." err_msg = Label("Server Error or invalid response: ERROR " + str(code) + " - " + str(message)) err_msg.addStyleName("status") Window.alert(err_msg.getText())
class Calendar(FocusPanel): monthsOfYear = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] daysOfWeek = ['M', 'T', 'W', 'T', 'F', 'S', 'S'] daysOfWeek3 = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] today = 'Today' tomorrow = 'Tomorrow' yesterday = 'Yesterday' cancel = 'Cancel' def __init__(self, **kwargs): self.backyear = kwargs.pop('BackyearSymbol', '<<') self.backmonth = kwargs.pop('BackmonthSymbol', '<') self.fwdyear = kwargs.pop('FwdyearSymbol', '>>') self.fwdmonth = kwargs.pop('FwdmonthSymbol', '>') self.addbuttons = kwargs.pop('AddButtons', True) self.mindate = kwargs.pop('MinDate', None) # (yr, mnth, day) self.maxdate = kwargs.pop('MaxDate', None) # (yr, mnth, day) self.weekdaylength = kwargs.pop('WeekdayLength', 1) self.dayoffset = kwargs.pop('DayOffset', 1) # 1 returns Mon, 0 for Sun self.daybuttons = kwargs.pop('DayButtons', False) if kwargs.pop('ArrowButtons', False): self.bkls = Button else: self.bkls = Hyperlink FocusPanel.__init__(self, **kwargs) self.setDate() self.todayYear = self.currentYear self.todayMonth = self.currentMonth self.todayDay = self.currentDay self.selectedDateListeners = [] self.defaultGrid = None # used later def setDate(self, _date=None, m=None, d=None): """ _date - object of datetime.date class """ if m is None and d is None: if _date is None: y, m, d = time.strftime("%Y-%m-%d").split("-") else: m = _date.month y = _date.year d = _date.day else: y = _date self.currentYear = int(y) self.currentMonth = int(m) self.currentDay = int(d) def getMonthsOfYear(self): return self.monthsOfYear def getDaysOfWeek(self): if self.weekdaylength == 1: dow = self.daysOfWeek else: dow = self.daysOfWeek3 return dow[-self.dayoffset:] + \ dow[:-self.dayoffset] def addSelectedDateListener(self, listener): self.selectedDateListeners.append(listener) def removeSelectedDateListener(self, listener): self.selectedDateListeners.remove(listener) def isLeapYear(self, year): if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0): return True else: return False def _indaterange(self, year, mnth, day=None): if self.mindate is not None: if year < self.mindate[0]: return False if year == self.mindate[0]: if mnth < self.mindate[1]: return False if day is not None: if mnth == self.mindate[1] and day < self.mindate[2]: return False if self.maxdate is not None: if year > self.maxdate[0]: return False if year == self.maxdate[0]: if mnth > self.maxdate[1]: return False if day is not None: if mnth == self.maxdate[1] and day > self.maxdate[2]: return False return True def getDaysInMonth(self, mth, year): days = 0 if mth in [1, 3, 5, 7, 8, 10, 12]: days=31 elif mth in [4, 6, 9, 11]: days = 30 elif (mth==2 and self.isLeapYear(year)): days = 29 else: days = 28 return days def setPosition(self, left, top): element = self.getElement() DOM.setStyleAttribute(element, "left", "%dpx" % left) DOM.setStyleAttribute(element, "top", "%dpx" % top) def show(self, left, top): if left < 0: left = 0 if top < 0: top = 0 self.setPosition(left, top) self.drawCurrent() self.setVisible(True) def drawCurrent(self): self.drawDate() def draw(self, month , year): tod = time.localtime() mm = tod.tm_mon yy = tod.tm_year # has today changed and thus changed month? cater to rare case # where widget in created on last day of month and # page left till next day hasChangeMonth = False if yy != self.todayYear or mm != self.todayMonth: hasChangeMonth = True self.todayYear = yy self.todayMonth = mm # check to see if we have drawn the full widget before if self.defaultGrid is None: self.drawFull(month, year) else: # ok means we are re-drawing, but first check if it is the same # as the defaultGrid, if yes, just use it if not hasChangeMonth and month == self.todayMonth and \ year == self.todayYear: self.middlePanel.setWidget(self.defaultGrid) self.currentMonth = self.todayMonth self.currentYear = self.todayYear else: # we have to redraw the grid -- bah g = self.drawGrid(month, year) if hasChangeMonth: # reset the default grid as we have changed months self.defaultGrid = grid # # what about the title panel? # txt = "<b>" txt += self.getMonthsOfYear()[month-1] + " " + str(year) txt += "</b>" self.titlePanel.setWidget(HTML(txt)) self.setVisible(True) def drawFull(self, month, year): # should be called only once when we draw the calendar for # the first time self.vp = VerticalPanel() self.vp.setSpacing(0) self.vp.setPadding(0) self.vp.addStyleName("calendarbox calendar-module calendar") self.setWidget(self.vp) self.setVisible(False) # mth = int(month) yr = int(year) tp = HorizontalPanel(Width="100%") tp.addStyleName("calendar-top-panel") tp.setSpacing(0) tp.setPadding(0) self.h1 = None self.h2 = None self.h4 = None self.h5 = None if self.backyear: self.h1 = self.bkls(self.backyear, StyleName="calendar-arrows") self.h1.addClickListener(getattr(self, 'onPreviousYear')) tp.add(self.h1) tp.setCellHorizontalAlignment(self.h1, "left") if self.backmonth: self.h2 = self.bkls(self.backmonth, StyleName="calendar-arrows") self.h2.addClickListener(getattr(self, 'onPreviousMonth')) tp.add(self.h2) tp.setCellHorizontalAlignment(self.h2, "left") # titlePanel can be changed, whenever we draw, so keep the reference txt = "<b>" txt += self.getMonthsOfYear()[mth-1] + " " + str(yr) txt += "</b>" self.titlePanel = SimplePanel() self.titlePanel.setWidget(HTML(txt)) self.titlePanel.setStyleName("calendar-center") tp.add(self.titlePanel) tp.setCellHorizontalAlignment(self.titlePanel, "center") tp.setCellWidth(self.titlePanel, "100%") if self.fwdmonth: self.h4 = self.bkls(self.fwdmonth, StyleName="calendar-arrows") self.h4.addClickListener(getattr(self, 'onNextMonth')) tp.add(self.h4) tp.setCellHorizontalAlignment(self.h4, "right") tp.setCellWidth(self.h4, "100%") self.h4.setWidth("100%") if self.fwdyear: self.h5 = self.bkls(self.fwdyear, StyleName="calendar-arrows") self.h5.addClickListener(getattr(self, 'onNextYear')) tp.add(self.h5) tp.setCellHorizontalAlignment(self.h5, "right") tvp = VerticalPanel(Width="100%") tvp.setSpacing(2) tvp.add(tp) self.vp.add(tvp) # done with top panel self.middlePanel = SimplePanel() grid = self.drawGrid(mth, yr) self.middlePanel.setWidget(grid) self.vp.add(self.middlePanel) self.defaultGrid = grid if self.addbuttons: # # some links & handlers # bh1 = Hyperlink(self.yesterday) bh1.addClickListener(getattr(self, 'onYesterday')) bh2 = Hyperlink(self.today) bh2.addClickListener(getattr(self, 'onToday')) bh3 = Hyperlink(self.tomorrow) bh3.addClickListener(getattr(self, 'onTomorrow')) bh4 = Hyperlink(self.cancel) bh4.addClickListener(getattr(self, 'onCancel')) # # add code to test another way of doing the layout # b = HorizontalPanel() b.add(bh1) b.add(bh2) b.add(bh3) b.addStyleName("calendar-shortcuts") self.vp.add(b) b2 = SimplePanel() b2.add(bh4) b2.addStyleName("calendar-cancel") self.vp.add(b2) self.checkLinks(mth, yr) self.setVisible(True) def checkLinks(self, month=None, year=None): if month is None: month = self.currentMonth if year is None: year = self.currentYear if self.backyear: ok = self._indaterange(year-1, month) self.h1.setEnabled(ok) if self.backmonth: py, pm = self._previousMonth(year, month) ok = self._indaterange(py, pm) print "prevmonth", month, year, py, pm, ok self.h2.setEnabled(ok) if self.fwdmonth: ny, nm = self._nextMonth(year, month) ok = self._indaterange(ny, nm) print "nextmonth", month, year, ny, nm, ok self.h4.setEnabled(ok) if self.fwdyear: ok = self._indaterange(year+1, month) self.h5.setEnabled(ok) def drawGrid(self, month, year): # draw the grid in the middle of the calendar self.checkLinks(month, year) daysInMonth = self.getDaysInMonth(month, year) # first day of the month & year secs = time.mktime((year, month, 1, 0, 0, 0, 0, 0, -1)) struct = time.localtime(secs) startPos = (struct.tm_wday + self.dayoffset) % 7 slots = startPos + daysInMonth - 1 rows = int(slots/7) + 1 grid = Grid(rows+1, 7, # extra row for the days in the week StyleName="calendar-grid") grid.setWidth("100%") grid.addTableListener(self) self.middlePanel.setWidget(grid) cf = grid.getCellFormatter() # # put some content into the grid cells # for i in range(7): grid.setText(0, i, self.getDaysOfWeek()[i]) cf.addStyleName(0, i, "calendar-header") # # draw cells which are empty first # day = 0 pos = 0 while pos < startPos: self._setCell(grid, 1, pos, BLANKCELL, "calendar-blank-cell") pos += 1 # now for days of the month row = 1 day = 1 col = startPos while day <= daysInMonth: if pos % 7 == 0 and day != 1: row += 1 col = pos % 7 if not self._indaterange(self.currentYear, self.currentMonth, day): self._setCell(grid, row, col, BLANKCELL, "calendar-blank-cell") day += 1 pos += 1 continue if self.currentYear == self.todayYear and \ self.currentMonth == self.todayMonth and day == self.todayDay: style = "calendar-cell-today" else: style = "calendar-day-cell" self._setCell(grid, row, col, str(day), style) day += 1 pos += 1 # # now blank lines on the last row # col += 1 while col < 7: self._setCell(grid, row, col, BLANKCELL, "calendar-blank-cell") col += 1 return grid def _setCell(self, grid, row, col, txt, style): cf = grid.getCellFormatter() if self.daybuttons: if txt != BLANKCELL: listener = lambda x, col=col, row=row, grid=grid\ : self.onCellClicked(grid, row, col) else: listener = None b = Button(txt, listener=listener, StyleName="%s-button" % style) grid.setWidget(row, col, b) cf.setWidth(row, col, "100%") else: grid.setHTML(row, col, txt) cf.setStyleName(row, col, style) def onCellClicked(self, grid, row, col): if row == 0: return text = grid.getText(row, col).strip() if text == BLANKCELL: return try: selectedDay = int(text) except ValueError, e: return # fire event to all listeners for listener in self.selectedDateListeners: if hasattr(listener, "onDateSelected"): listener = listener.onDateSelected listener(self.currentYear, self.currentMonth, selectedDay) self.setVisible(False)
class PageIndex: def onModuleLoad(self): # JSON RPC response containers self.facebook_user = {} self.app_info = {} self.wl_books = [] self.sl_books = [] self.events = [] # setup JSON RPC self.remote = DataService() # make JSON RPC calls self.remote.get_app_info(self, "index") self.remote.get_wish_list(self) self.remote.get_sell_list(self) self.remote.get_events(self, 10) # panels self.main_panel = HorizontalPanel() self.feed_panel = VerticalPanel() self.list_panel = VerticalPanel() self.feed_panel.addStyleName("feed_panel") self.list_panel.addStyleName("list_panel") # labels self.html_feed_title = HTML("<h1>Recent Activity</h1>") self.html_wish_title = HTML("<h1>Your Wishlist</h1>") self.html_sell_title = HTML("<h1>Your Selllist</h1>") # user lists self.wish_list = UserList("wish", self) self.sell_list = UserList("sell", self) self.wish_list.addStyleName("userlist") self.sell_list.addStyleName("userlist") self.feed_panel.add(self.html_feed_title) self.list_panel.add(self.html_wish_title) self.list_panel.add(self.wish_list) self.list_panel.add(HTML("<br />")) self.list_panel.add(self.html_sell_title) self.list_panel.add(self.sell_list) # add everything together self.main_panel.add(self.feed_panel) self.main_panel.add(self.list_panel) self.main_panel.setWidth("100%") RootPanel("page_index").add(self.main_panel) show_events = self.show_events class EventTimer(Timer): def run(self): show_events() et = EventTimer() self.show_events() et.scheduleRepeating(5000) def populate_book_lists(self): """ check the JSON RPC containers and fill the UserLists if it finds them to be non-empty """ for b in self.wl_books: Window.alert(str(b)) self.wish_list.add_book(b) for b in self.sl_books: self.sell_list.add_book(b) return True def show_events(self): """ create events on the recent activity feed """ for e in self.events: self.add_event(e) self.events = [] def add_event(self, event): """ add an event to the recent activity feed """ event_panel = HorizontalPanel() mid_panel = VerticalPanel() book_panel = HorizontalPanel() # profile picture pic_url = "https://graph.facebook.com/" + event['fbid'] + "/picture" pic_html = HTML("<img src=\"%s\" />" % pic_url) # event string event_html = HTML("<span style=\"font-weight: bold\">%s</span>" % event['string']) url = self.app_info['url'] + "book?asin=" + event['book']['asin'] cutoff = 40 # book thumbnail img_url = event['book']['thumbnail'] if event['book']["thumbnail"] == "N/A": img_url = self.app_info['url'] + "static/images/default_thumbnail.png" img_html = HTML("<a href=\"%s\" target=\"_top\"><img src=\"%s\" /></a>" % (url, img_url)) # handle book information title = event['book']['title'] author = event['book']['author'] isbn = event['book']['isbn10'] if len(title) > cutoff: title = title[0:cutoff] + "..." if len(author) > cutoff: author = author[0:cutoff] + "..." if len(isbn) > cutoff: isbn = isbn[0:cutoff] + "..." html = "<a href=\"%s\" target=\"_top\"><span style=\"font-weight: bold\">%s</span></a><br />" % (url, title) html += "<span style=\"font-weight: bold; color: #6C82AF;\">ISBN-10: %s</span><br />" % isbn html += "<span style=\"font-weight: bold; color: #7D7D7D;\">%s</span><br />" % author html_entry = HTML(html) book_panel.add(img_html) book_panel.add(html_entry) mid_panel.add(event_html) mid_panel.add(book_panel) event_panel.add(pic_html) event_panel.add(mid_panel) # html = "<span style=\"text-align: right; width: 100%; display: block;\">%s</span><hr />" % unicode(event['time']) # event_panel.add(HTML(html)) self.feed_panel.add(event_panel) def onRemoteResponse(self, response, request_info): """ Called when a response is received from an RPC """ if request_info.method == "get_facebook_user": for k, v in response.items(): self.facebook_user[k] = v elif request_info.method == "get_app_info": for k, v in response.items(): self.app_info[k] = v elif request_info.method == "get_wish_list": self.wl_books = response for b in self.wl_books: self.wish_list.add_book(b) elif request_info.method == "get_sell_list": self.sl_books = response for b in self.sl_books: self.sell_list.add_book(b) elif request_info.method == "add_event": self.events.append(response) elif request_info.method == "get_events": self.events = response def onRemoteError(self, code, message, request_info): """ Called when a returned response is invalid or Server Error """ code = str(code) message = str(message) if len(code) > 200: code = code[0:200] + "..." if len(message) > 200: message = message[0:200] + "..." err_msg = Label("Server Error or invalid response: ERROR " + str(code) + " - " + str(message)) err_msg.addStyleName("status") Window.alert(err_msg.getText())
class PageBookComments: def onModuleLoad(self): # parse get data self.location = Window.getLocation().getHref() self.get_data = {} self.tmp = self.location.split('?') self.tmp = self.tmp[len(self.tmp) - 1].split("&") for e in self.tmp: get_var = e.split("=") if len(get_var) == 2: self.get_data[get_var[0]] = get_var[1] # JSON RPC response holders self.facebook_user = {} self.app_info = {} self.sellers = [] self.book = {} self.has_book = "none" # setup JSON RPC self.remote = DataService() self.remote.get_facebook_user(self) self.remote.get_app_info(self, "book_detail") if "asin" in self.get_data: self.remote.get_book_details(self, self.get_data["asin"]) self.remote.get_sellers(self, self.get_data["asin"]) self.remote.user_has_book(self, self.get_data["asin"]) # create panels self.main_panel = HorizontalPanel() self.info_panel = VerticalPanel() self.sell_btn_panel = VerticalPanel() self.wish_btn_panel = VerticalPanel() self.seller_panel = VerticalPanel() self.add_comment_panel = VerticalPanel() # images self.img_book_cover = Image() # html labels self.html_book_title = HTML() self.html_book_author = HTML() self.html_book_isbn10 = HTML() self.html_book_publisher = HTML() self.html_book_publish_date = HTML() self.html_book_edition = HTML() self.html_book_binding = HTML() self.html_btn_sell = HTML() self.html_btn_wish = HTML() self.html_seller_title = HTML() # check for no get data! if "asin" not in self.get_data: self.html_book_title.setHTML("<h1>Book not found!</h1>\n<p>The book you are looking for does not exist.</p>") self.info_panel.setWidth("100%") self.main_panel.setWidth("100%") self.info_panel.add(self.html_book_title) self.main_panel.add(self.info_panel) RootPanel("page_book_comments").add(self.main_panel) return # add to sellers panel self.seller_panel.add(self.html_seller_title) self.seller_panel.addStyleName("comments") self.info_panel.add(self.html_book_title) self.info_panel.add(self.html_book_author) self.info_panel.add(self.html_book_isbn10) self.info_panel.add(self.html_book_publisher) self.info_panel.add(self.html_book_publish_date) self.info_panel.add(self.html_book_edition) self.info_panel.add(self.html_book_binding) self.info_panel.add(self.add_comment_panel) self.info_panel.add(self.seller_panel) self.info_panel.addStyleName("info_panel") self.main_panel.add(self.info_panel) self.main_panel.add(self.img_book_cover) RootPanel("page_book_comments").add(self.main_panel) # spin until book info get here class SpinTimer(Timer): def __init__(self, max_tries = 10, interval = 500): Timer.__init__(self) self.interval = interval self.max_tries = max_tries self.tries = 0 self.func = func self.params = params self.scheduleRepeating(self.interval) def run(self): self.tries += 1 if self.tries >= self.max_tries: Window.alert("It looks like there's a connection problem. We're sorry about the inconvenience. Please try again later.") self.cancel() return if populate_book_details(): self.cancel() populate_book_details = self.populate_book_details st = SpinTimer() def populate_book_details(self): """ fill in book information on this page """ if len(self.facebook_user) == 0: return False if len(self.app_info) == 0: return False if len(self.book) == 0: return False if self.book['num_sellers'] != 0 and len(self.sellers) == 0: return False if 'title' not in self.book or 'binding' not in self.book: return False binding = "Hardcover" if self.book['binding'] != "Hardcover" and not self.book['binding']: binding = "Paperback" self.html_book_title.setHTML("<span class=\"title\">%s [%s]</span>" % (self.book['title'], binding)) if 'author' not in self.book: return False self.html_book_author.setHTML("<span class=\"author\">%s</span>" % self.book['author']) if 'isbn10' not in self.book: return False self.html_book_isbn10.setHTML("<span class=\"isbn\">ISBN 10: %s</span>" % self.book['isbn10']) # add these in #self.html_book_publisher.setHTML("<span class=\"info\">Publisher: %s</span>" % self.book['publisher']) #self.html_book_publish_date.setHTML("<span class=\"info\">Published: %s</span>" % self.book['publish_date']) if 'edition' not in self.book: return False self.html_book_edition.setHTML("<span class=\"info\">Edition: %s</span>" % self.book['edition']) if 'thumbnail' not in self.book: return False if self.book['thumbnail'] == "N/A": self.book['thumbnail'] = self.app_info['url'] + "static/images/default_thumbnail.png" self.img_book_cover.setUrl(self.book['thumbnail']) if 'num_sellers' not in self.book: return False amount = "amount_low" if int(self.book['num_sellers']) > 3: amount = "amount_medium" elif int(self.book['num_sellers']) > 7: amount = "amount_high" self.html_btn_sell.setHTML("<span class=\"num_sellers\">Sellers: <span class=\"%s\">%d</span></span>" % (amount, self.book['num_sellers'])) if 'num_watchers' not in self.book: return False amount = "amount_low" if int(self.book['num_watchers']) > 3: amount = "amount_medium" elif int(self.book['num_watchers']) > 7: amount = "amount_high" self.html_btn_wish.setHTML("<span class=\"num_watchers\">Watchers: <span class=\"%s\">%d</span></span>" % (amount, self.book['num_watchers'])) self.html_seller_title.setHTML("<h1>%s's Seller Activity for %s</h1>" % (self.facebook_user['first_name'], self.book['title'])) comments_url = self.app_info['url'] comments_url += "fbcommentsplugin?asin=" + self.get_data['asin'] comments_url += "&fbid=" + self.get_data['fbid'] self.frame_seller_comments = HTML('<div data-height="600px" class="fb-comments" data-num-posts="3" data-width="600"></div>') self.seller_panel.add(self.html_seller_title) self.seller_panel.add(self.frame_seller_comments) return True def onRemoteResponse(self, response, request_info): """ Called when a response is received from an RPC """ if not request_info.method in DataService.methods: Window.alert('Unrecognized JSONRPC method.') return if request_info.method == "get_facebook_user": self.facebook_user = {} for k, v in response.items(): self.facebook_user[k] = v elif request_info.method == "get_book_details": self.book = {} for k, v in response.items(): self.book[k] = v elif request_info.method == "get_app_info": self.app_info = {} for k, v in response.items(): self.app_info[k] = v elif request_info.method == "get_sellers": self.sellers = response elif request_info.method == "user_has_book": self.has_book = response["result"] def onRemoteError(self, code, message, request_info): """ Called when a returned response is invalid for Server Error """ code = str(code) message = str(message) if len(code) > 200: code = code[0:200] + "..." if len(message) > 200: message = message[0:200] + "..." err_msg = Label("Server Error or invalid response: ERROR " + str(code) + " - " + str(message)) err_msg.addStyleName("status") Window.alert(err_msg.getText())