diff --git a/media/css/reader.css b/media/css/reader.css
index c3b907ef5..64f5bf63b 100644
--- a/media/css/reader.css
+++ b/media/css/reader.css
@@ -428,7 +428,6 @@ a img {
#taskbar .taskbar_leftnav .task_button .taskbar_menu li {
margin: 0;
padding: 4px;
- cursor: pointer;
}
#taskbar .taskbar_leftnav .task_button .taskbar_menu li span {
@@ -436,6 +435,7 @@ a img {
margin: 0;
display: block;
color: #203060;
+ cursor: pointer;
}
#taskbar .taskbar_leftnav .task_button .taskbar_menu li:hover span {
@@ -451,6 +451,19 @@ a img {
background: transparent url(../img/icons/silk/user.png) no-repeat center center;
}
+/* ================ */
+/* = Modal Dialog = */
+/* ================ */
+
+#simplemodal-overlay {
+ background-color: #101030;
+}
+
+#simplemodal-container {
+ width: 500px;
+ background-color: white;
+ padding: 8px;
+}
/* ==================== */
/* = OPML Import Form = */
diff --git a/media/js/jquery.dropshadow.js b/media/js/jquery.dropshadow.js
new file mode 100644
index 000000000..9eb9d7c7c
--- /dev/null
+++ b/media/js/jquery.dropshadow.js
@@ -0,0 +1,304 @@
+/*
+ VERSION: Drop Shadow jQuery Plugin 1.6 12-13-2007
+
+ REQUIRES: jquery.js (1.2.6 or later)
+
+ SYNTAX: $(selector).dropShadow(options); // Creates new drop shadows
+ $(selector).redrawShadow(); // Redraws shadows on elements
+ $(selector).removeShadow(); // Removes shadows from elements
+ $(selector).shadowId(); // Returns an existing shadow's ID
+
+ OPTIONS:
+
+ left : integer (default = 4)
+ top : integer (default = 4)
+ blur : integer (default = 2)
+ opacity : decimal (default = 0.5)
+ color : string (default = "black")
+ swap : boolean (default = false)
+
+ The left and top parameters specify the distance and direction, in pixels, to
+ offset the shadow. Zero values position the shadow directly behind the element.
+ Positive values shift the shadow to the right and down, while negative values
+ shift the shadow to the left and up.
+
+ The blur parameter specifies the spread, or dispersion, of the shadow. Zero
+ produces a sharp shadow, one or two produces a normal shadow, and three or four
+ produces a softer shadow. Higher values increase the processing load.
+
+ The opacity parameter should be a decimal value, usually less than one. You can
+ use a value higher than one in special situations, e.g. with extreme blurring.
+
+ Color is specified in the usual manner, with a color name or hex value. The
+ color parameter does not apply with transparent images.
+
+ The swap parameter reverses the stacking order of the original and the shadow.
+ This can be used for special effects, like an embossed or engraved look.
+
+ EXPLANATION:
+
+ This jQuery plug-in adds soft drop shadows behind page elements. It is only
+ intended for adding a few drop shadows to mostly stationary objects, like a
+ page heading, a photo, or content containers.
+
+ The shadows it creates are not bound to the original elements, so they won't
+ move or change size automatically if the original elements change. A window
+ resize event listener is assigned, which should re-align the shadows in many
+ cases, but if the elements otherwise move or resize you will have to handle
+ those events manually. Shadows can be redrawn with the redrawShadow() method
+ or removed with the removeShadow() method. The redrawShadow() method uses the
+ same options used to create the original shadow. If you want to change the
+ options, you should remove the shadow first and then create a new shadow.
+
+ The dropShadow method returns a jQuery collection of the new shadow(s). If
+ further manipulation is required, you can store it in a variable like this:
+
+ var myShadow = $("#myElement").dropShadow();
+
+ You can also read the ID of the shadow from the original element at a later
+ time. To get a shadow's ID, either read the shadowId attribute of the
+ original element or call the shadowId() method. For example:
+
+ var myShadowId = $("#myElement").attr("shadowId"); or
+ var myShadowId = $("#myElement").shadowId();
+
+ If the original element does not already have an ID assigned, a random ID will
+ be generated for the shadow. However, if the original does have an ID, the
+ shadow's ID will be the original ID and "_dropShadow". For example, if the
+ element's ID is "myElement", the shadow's ID would be "myElement_dropShadow".
+
+ If you have a long piece of text and the user resizes the window so that the
+ text wraps or unwraps, the shape of the text changes and the words are no
+ longer in the same positions. In that case, you can either preset the height
+ and width, so that it becomes a fixed box, or you can shadow each word
+ separately, like this:
+
+
YourPageTitle
+
+ $("h1 span").dropShadow();
+
+ The dropShadow method attempts to determine whether the selected elements have
+ transparent backgrounds. If you want to shadow the content inside an element,
+ like text or a transparent image, it must not have a background-color or
+ background-image style. If the element has a solid background it will create a
+ rectangular shadow around the outside box.
+
+ The shadow elements are positioned absolutely one layer below the original
+ element, which is positioned relatively (unless it's already absolute).
+
+ *** All shadows have the "dropShadow" class, for selecting with CSS or jQuery.
+
+ ISSUES:
+
+ 1) Limited styling of shadowed elements by ID. Because IDs must be unique,
+ and the shadows have their own ID, styles applied by ID won't transfer
+ to the shadows. Instead, style elements by class or use inline styles.
+ 2) Sometimes shadows don't align properly. Elements may need to be wrapped
+ in container elements, margins or floats changed, etc. or you may just
+ have to tweak the left and top offsets to get them to align. For example,
+ with draggable objects, you have to wrap them inside two divs. Make the
+ outer div draggable and set the inner div's position to relative. Then
+ you can create a shadow on the element inside the inner div.
+ 3) If the user changes font sizes it will throw the shadows off. Browsers
+ do not expose an event for font size changes. The only known way to
+ detect a user font size change is to embed an invisible text element and
+ then continuously poll for changes in size.
+ 4) Safari support is shaky, and may require even more tweaks/wrappers, etc.
+
+ The bottom line is that this is a gimick effect, not PFM, and if you push it
+ too hard or expect it to work in every possible situation on every browser,
+ you will be disappointed. Use it sparingly, and don't use it for anything
+ critical. Otherwise, have fun with it!
+
+ AUTHOR: Larry Stevens (McLars@eyebulb.com) This work is in the public domain,
+ and it is not supported in any way. Use it at your own risk.
+*/
+
+
+(function($){
+
+ var dropShadowZindex = 1; //z-index counter
+
+ $.fn.dropShadow = function(options)
+ {
+ // Default options
+ var opt = $.extend({
+ left: 4,
+ top: 4,
+ blur: 2,
+ opacity: .5,
+ color: "black",
+ swap: false
+ }, options);
+ var jShadows = $([]); //empty jQuery collection
+
+ // Loop through original elements
+ this.not(".dropShadow").each(function()
+ {
+ var jthis = $(this);
+ var shadows = [];
+ var blur = (opt.blur <= 0) ? 0 : opt.blur;
+ var opacity = (blur == 0) ? opt.opacity : opt.opacity / (blur * 8);
+ var zOriginal = (opt.swap) ? dropShadowZindex : dropShadowZindex + 1;
+ var zShadow = (opt.swap) ? dropShadowZindex + 1 : dropShadowZindex;
+
+ // Create ID for shadow
+ var shadowId;
+ if (this.id) {
+ shadowId = this.id + "_dropShadow";
+ }
+ else {
+ shadowId = "ds" + (1 + Math.floor(9999 * Math.random()));
+ }
+
+ // Modify original element
+ $.data(this, "shadowId", shadowId); //store id in expando
+ $.data(this, "shadowOptions", options); //store options in expando
+ jthis
+ .attr("shadowId", shadowId)
+ .css("zIndex", zOriginal);
+ if (jthis.css("position") != "absolute") {
+ jthis.css({
+ position: "relative",
+ zoom: 1 //for IE layout
+ });
+ }
+
+ // Create first shadow layer
+ bgColor = jthis.css("backgroundColor");
+ if (bgColor == "rgba(0, 0, 0, 0)") bgColor = "transparent"; //Safari
+ if (bgColor != "transparent" || jthis.css("backgroundImage") != "none"
+ || this.nodeName == "SELECT"
+ || this.nodeName == "INPUT"
+ || this.nodeName == "TEXTAREA") {
+ shadows[0] = $("")
+ .css("background", opt.color);
+ }
+ else {
+ shadows[0] = jthis
+ .clone()
+ .removeAttr("id")
+ .removeAttr("name")
+ .removeAttr("shadowId")
+ .css("color", opt.color);
+ }
+ shadows[0]
+ .addClass("dropShadow")
+ .css({
+ height: jthis.outerHeight(),
+ left: blur,
+ opacity: opacity,
+ position: "absolute",
+ top: blur,
+ width: jthis.outerWidth(),
+ zIndex: zShadow
+ });
+
+ // Create other shadow layers
+ var layers = (8 * blur) + 1;
+ for (i = 1; i < layers; i++) {
+ shadows[i] = shadows[0].clone();
+ }
+
+ // Position layers
+ var i = 1;
+ var j = blur;
+ while (j > 0) {
+ shadows[i].css({left: j * 2, top: 0}); //top
+ shadows[i + 1].css({left: j * 4, top: j * 2}); //right
+ shadows[i + 2].css({left: j * 2, top: j * 4}); //bottom
+ shadows[i + 3].css({left: 0, top: j * 2}); //left
+ shadows[i + 4].css({left: j * 3, top: j}); //top-right
+ shadows[i + 5].css({left: j * 3, top: j * 3}); //bottom-right
+ shadows[i + 6].css({left: j, top: j * 3}); //bottom-left
+ shadows[i + 7].css({left: j, top: j}); //top-left
+ i += 8;
+ j--;
+ }
+
+ // Create container
+ var divShadow = $("")
+ .attr("id", shadowId)
+ .addClass("dropShadow")
+ .css({
+ left: jthis.position().left + opt.left - blur,
+ marginTop: jthis.css("marginTop"),
+ marginRight: jthis.css("marginRight"),
+ marginBottom: jthis.css("marginBottom"),
+ marginLeft: jthis.css("marginLeft"),
+ position: "absolute",
+ top: jthis.position().top + opt.top - blur,
+ zIndex: zShadow
+ });
+
+ // Add layers to container
+ for (i = 0; i < layers; i++) {
+ divShadow.append(shadows[i]);
+ }
+
+ // Add container to DOM
+ jthis.after(divShadow);
+
+ // Add shadow to return set
+ jShadows = jShadows.add(divShadow);
+
+ // Re-align shadow on window resize
+ $(window).resize(function()
+ {
+ try {
+ divShadow.css({
+ left: jthis.position().left + opt.left - blur,
+ top: jthis.position().top + opt.top - blur
+ });
+ }
+ catch(e){}
+ });
+
+ // Increment z-index counter
+ dropShadowZindex += 2;
+
+ }); //end each
+
+ return this.pushStack(jShadows);
+ };
+
+
+ $.fn.redrawShadow = function()
+ {
+ // Remove existing shadows
+ this.removeShadow();
+
+ // Draw new shadows
+ return this.each(function()
+ {
+ var shadowOptions = $.data(this, "shadowOptions");
+ $(this).dropShadow(shadowOptions);
+ });
+ };
+
+
+ $.fn.removeShadow = function()
+ {
+ return this.each(function()
+ {
+ var shadowId = $(this).shadowId();
+ $("div#" + shadowId).remove();
+ });
+ };
+
+
+ $.fn.shadowId = function()
+ {
+ return $.data(this[0], "shadowId");
+ };
+
+
+ $(function()
+ {
+ // Suppress printing of shadows
+ var noPrint = "";
+ $("head").append(noPrint);
+ });
+
+})(jQuery);
\ No newline at end of file
diff --git a/media/js/jquery.simplemodal-1.3.js b/media/js/jquery.simplemodal-1.3.js
new file mode 100644
index 000000000..0096bb6fa
--- /dev/null
+++ b/media/js/jquery.simplemodal-1.3.js
@@ -0,0 +1,592 @@
+/*
+ * SimpleModal 1.3 - jQuery Plugin
+ * http://www.ericmmartin.com/projects/simplemodal/
+ * Copyright (c) 2009 Eric Martin
+ * Dual licensed under the MIT and GPL licenses
+ * Revision: $Id: jquery.simplemodal.js 205 2009-06-12 13:29:21Z emartin24 $
+ */
+
+/**
+ * SimpleModal is a lightweight jQuery plugin that provides a simple
+ * interface to create a modal dialog.
+ *
+ * The goal of SimpleModal is to provide developers with a cross-browser
+ * overlay and container that will be populated with data provided to
+ * SimpleModal.
+ *
+ * There are two ways to call SimpleModal:
+ * 1) As a chained function on a jQuery object, like $('#myDiv').modal();.
+ * This call would place the DOM object, #myDiv, inside a modal dialog.
+ * Chaining requires a jQuery object. An optional options object can be
+ * passed as a parameter.
+ *
+ * @example $('
my data
').modal({options});
+ * @example $('#myDiv').modal({options});
+ * @example jQueryObject.modal({options});
+ *
+ * 2) As a stand-alone function, like $.modal(data). The data parameter
+ * is required and an optional options object can be passed as a second
+ * parameter. This method provides more flexibility in the types of data
+ * that are allowed. The data could be a DOM object, a jQuery object, HTML
+ * or a string.
+ *
+ * @example $.modal('
my data
', {options});
+ * @example $.modal('my data', {options});
+ * @example $.modal($('#myDiv'), {options});
+ * @example $.modal(jQueryObject, {options});
+ * @example $.modal(document.getElementById('myDiv'), {options});
+ *
+ * A SimpleModal call can contain multiple elements, but only one modal
+ * dialog can be created at a time. Which means that all of the matched
+ * elements will be displayed within the modal container.
+ *
+ * SimpleModal internally sets the CSS needed to display the modal dialog
+ * properly in all browsers, yet provides the developer with the flexibility
+ * to easily control the look and feel. The styling for SimpleModal can be
+ * done through external stylesheets, or through SimpleModal, using the
+ * overlayCss and/or containerCss options.
+ *
+ * SimpleModal has been tested in the following browsers:
+ * - IE 6, 7, 8
+ * - Firefox 2, 3
+ * - Opera 9
+ * - Safari 3
+ * - Chrome 1, 2
+ *
+ * @name SimpleModal
+ * @type jQuery
+ * @requires jQuery v1.2.2
+ * @cat Plugins/Windows and Overlays
+ * @author Eric Martin (http://ericmmartin.com)
+ * @version 1.3
+ */
+;(function ($) {
+ var ie6 = $.browser.msie && parseInt($.browser.version) == 6 && typeof window['XMLHttpRequest'] != "object",
+ ieQuirks = null,
+ w = [];
+
+ /*
+ * Stand-alone function to create a modal dialog.
+ *
+ * @param {string, object} data A string, jQuery object or DOM object
+ * @param {object} [options] An optional object containing options overrides
+ */
+ $.modal = function (data, options) {
+ return $.modal.impl.init(data, options);
+ };
+
+ /*
+ * Stand-alone close function to close the modal dialog
+ */
+ $.modal.close = function () {
+ $.modal.impl.close();
+ };
+
+ /*
+ * Chained function to create a modal dialog.
+ *
+ * @param {object} [options] An optional object containing options overrides
+ */
+ $.fn.modal = function (options) {
+ return $.modal.impl.init(this, options);
+ };
+
+ /*
+ * SimpleModal default options
+ *
+ * appendTo: (String:'body') The jQuery selector to append the elements to. For ASP.NET, use 'form'.
+ * focus: (Boolean:true) Forces focus to remain on the modal dialog
+ * opacity: (Number:50) The opacity value for the overlay div, from 0 - 100
+ * overlayId: (String:'simplemodal-overlay') The DOM element id for the overlay div
+ * overlayCss: (Object:{}) The CSS styling for the overlay div
+ * containerId: (String:'simplemodal-container') The DOM element id for the container div
+ * containerCss: (Object:{}) The CSS styling for the container div
+ * dataId: (String:'simplemodal-data') The DOM element id for the data div
+ * dataCss: (Object:{}) The CSS styling for the data div
+ * minHeight: (Number:200) The minimum height for the container
+ * minWidth: (Number:200) The minimum width for the container
+ * maxHeight: (Number:null) The maximum height for the container. If not specified, the window height is used.
+ * maxWidth: (Number:null) The maximum width for the container. If not specified, the window width is used.
+ * autoResize: (Boolean:false) Resize container on window resize? Use with caution - this may have undesirable side-effects.
+ * zIndex: (Number: 1000) Starting z-index value
+ * close: (Boolean:true) If true, closeHTML, escClose and overClose will be used if set.
+ If false, none of them will be used.
+ * closeHTML: (String:'') The HTML for the
+ default close link. SimpleModal will automatically add the closeClass to this element.
+ * closeClass: (String:'simplemodal-close') The CSS class used to bind to the close event
+ * escClose: (Boolean:true) Allow Esc keypress to close the dialog?
+ * overlayClose: (Boolean:false) Allow click on overlay to close the dialog?
+ * position: (Array:null) Position of container [top, left]. Can be number of pixels or percentage
+ * persist: (Boolean:false) Persist the data across modal calls? Only used for existing
+ DOM elements. If true, the data will be maintained across modal calls, if false,
+ the data will be reverted to its original state.
+ * onOpen: (Function:null) The callback function used in place of SimpleModal's open
+ * onShow: (Function:null) The callback function used after the modal dialog has opened
+ * onClose: (Function:null) The callback function used in place of SimpleModal's close
+ */
+ $.modal.defaults = {
+ appendTo: 'body',
+ focus: true,
+ opacity: 50,
+ overlayId: 'simplemodal-overlay',
+ overlayCss: {},
+ containerId: 'simplemodal-container',
+ containerCss: {},
+ dataId: 'simplemodal-data',
+ dataCss: {},
+ minHeight: 200,
+ minWidth: 300,
+ maxHeight: null,
+ maxWidth: null,
+ autoResize: false,
+ zIndex: 1000,
+ close: true,
+ closeHTML: '',
+ closeClass: 'simplemodal-close',
+ escClose: true,
+ overlayClose: false,
+ position: null,
+ persist: false,
+ onOpen: null,
+ onShow: null,
+ onClose: null
+ };
+
+ /*
+ * Main modal object
+ */
+ $.modal.impl = {
+ /*
+ * Modal dialog options
+ */
+ opts: null,
+ /*
+ * Contains the modal dialog elements and is the object passed
+ * back to the callback (onOpen, onShow, onClose) functions
+ */
+ dialog: {},
+ /*
+ * Initialize the modal dialog
+ */
+ init: function (data, options) {
+ // don't allow multiple calls
+ if (this.dialog.data) {
+ return false;
+ }
+
+ // $.boxModel is undefined if checked earlier
+ ieQuirks = $.browser.msie && !$.boxModel;
+
+ // merge defaults and user options
+ this.opts = $.extend({}, $.modal.defaults, options);
+
+ // keep track of z-index
+ this.zIndex = this.opts.zIndex;
+
+ // set the onClose callback flag
+ this.occb = false;
+
+ // determine how to handle the data based on its type
+ if (typeof data == 'object') {
+ // convert DOM object to a jQuery object
+ data = data instanceof jQuery ? data : $(data);
+
+ // if the object came from the DOM, keep track of its parent
+ if (data.parent().parent().size() > 0) {
+ this.dialog.parentNode = data.parent();
+
+ // persist changes? if not, make a clone of the element
+ if (!this.opts.persist) {
+ this.dialog.orig = data.clone(true);
+ }
+ }
+ }
+ else if (typeof data == 'string' || typeof data == 'number') {
+ // just insert the data as innerHTML
+ data = $('').html(data);
+ }
+ else {
+ // unsupported data type!
+ alert('SimpleModal Error: Unsupported data type: ' + typeof data);
+ return false;
+ }
+
+ // create the modal overlay, container and, if necessary, iframe
+ this.create(data);
+ data = null;
+
+ // display the modal dialog
+ this.open();
+
+ // useful for adding events/manipulating data in the modal dialog
+ if ($.isFunction(this.opts.onShow)) {
+ this.opts.onShow.apply(this, [this.dialog]);
+ }
+
+ // don't break the chain =)
+ return this;
+ },
+ /*
+ * Create and add the modal overlay and container to the page
+ */
+ create: function (data) {
+ // get the window properties
+ w = this.getDimensions();
+
+ // add an iframe to prevent select options from bleeding through
+ if (ie6) {
+ this.dialog.iframe = $('')
+ .css($.extend(this.opts.iframeCss, {
+ display: 'none',
+ opacity: 0,
+ position: 'fixed',
+ height: w[0],
+ width: w[1],
+ zIndex: this.opts.zIndex,
+ top: 0,
+ left: 0
+ }))
+ .appendTo(this.opts.appendTo);
+ }
+
+ // create the overlay
+ this.dialog.overlay = $('')
+ .attr('id', this.opts.overlayId)
+ .addClass('simplemodal-overlay')
+ .css($.extend(this.opts.overlayCss, {
+ display: 'none',
+ opacity: this.opts.opacity / 100,
+ height: w[0],
+ width: w[1],
+ position: 'fixed',
+ left: 0,
+ top: 0,
+ zIndex: this.opts.zIndex + 1
+ }))
+ .appendTo(this.opts.appendTo);
+
+ // create the container
+ this.dialog.container = $('')
+ .attr('id', this.opts.containerId)
+ .addClass('simplemodal-container')
+ .css($.extend(this.opts.containerCss, {
+ display: 'none',
+ position: 'fixed',
+ zIndex: this.opts.zIndex + 2
+ }))
+ .append(this.opts.close && this.opts.closeHTML
+ ? $(this.opts.closeHTML).addClass(this.opts.closeClass)
+ : '')
+ .appendTo(this.opts.appendTo);
+
+ this.dialog.wrap = $('')
+ .attr('tabIndex', -1)
+ .addClass('simplemodal-wrap')
+ .css({height: '100%', outline: 0, width: '100%'})
+ .appendTo(this.dialog.container);
+
+ // add styling and attributes to the data
+ this.dialog.data = data
+ .attr('id', data.attr('id') || this.opts.dataId)
+ .addClass('simplemodal-data')
+ .css($.extend(this.opts.dataCss, {
+ display: 'none'
+ }));
+ data = null;
+
+ this.setContainerDimensions();
+ this.dialog.data.appendTo(this.dialog.wrap);
+
+ // fix issues with IE
+ if (ie6 || ieQuirks) {
+ this.fixIE();
+ }
+ },
+ /*
+ * Bind events
+ */
+ bindEvents: function () {
+ var self = this;
+
+ // bind the close event to any element with the closeClass class
+ $('.' + self.opts.closeClass).bind('click.simplemodal', function (e) {
+ e.preventDefault();
+ self.close();
+ });
+
+ // bind the overlay click to the close function, if enabled
+ if (self.opts.close && self.opts.overlayClose) {
+ self.dialog.overlay.bind('click.simplemodal', function (e) {
+ e.preventDefault();
+ self.close();
+ });
+ }
+
+ // bind keydown events
+ $(document).bind('keydown.simplemodal', function (e) {
+ if (self.opts.focus && e.keyCode == 9) { // TAB
+ self.watchTab(e);
+ }
+ else if ((self.opts.close && self.opts.escClose) && e.keyCode == 27) { // ESC
+ e.preventDefault();
+ self.close();
+ }
+ });
+
+ // update window size
+ $(window).bind('resize.simplemodal', function () {
+ // redetermine the window width/height
+ w = self.getDimensions();
+
+ // reposition the dialog
+ self.opts.autoResize ? self.setContainerDimensions() : self.setPosition();
+
+ if (ie6 || ieQuirks) {
+ self.fixIE();
+ }
+ else {
+ // update the iframe & overlay
+ self.dialog.iframe && self.dialog.iframe.css({height: w[0], width: w[1]});
+ self.dialog.overlay.css({height: w[0], width: w[1]});
+ }
+ });
+ },
+ /*
+ * Unbind events
+ */
+ unbindEvents: function () {
+ $('.' + this.opts.closeClass).unbind('click.simplemodal');
+ $(document).unbind('keydown.simplemodal');
+ $(window).unbind('resize.simplemodal');
+ this.dialog.overlay.unbind('click.simplemodal');
+ },
+ /*
+ * Fix issues in IE6 and IE7 in quirks mode
+ */
+ fixIE: function () {
+ var p = this.opts.position;
+
+ // simulate fixed position - adapted from BlockUI
+ $.each([this.dialog.iframe || null, this.dialog.overlay, this.dialog.container], function (i, el) {
+ if (el) {
+ var bch = 'document.body.clientHeight', bcw = 'document.body.clientWidth',
+ bsh = 'document.body.scrollHeight', bsl = 'document.body.scrollLeft',
+ bst = 'document.body.scrollTop', bsw = 'document.body.scrollWidth',
+ ch = 'document.documentElement.clientHeight', cw = 'document.documentElement.clientWidth',
+ sl = 'document.documentElement.scrollLeft', st = 'document.documentElement.scrollTop',
+ s = el[0].style;
+
+ s.position = 'absolute';
+ if (i < 2) {
+ s.removeExpression('height');
+ s.removeExpression('width');
+ s.setExpression('height','' + bsh + ' > ' + bch + ' ? ' + bsh + ' : ' + bch + ' + "px"');
+ s.setExpression('width','' + bsw + ' > ' + bcw + ' ? ' + bsw + ' : ' + bcw + ' + "px"');
+ }
+ else {
+ var te, le;
+ if (p && p.constructor == Array) {
+ var top = p[0]
+ ? typeof p[0] == 'number' ? p[0].toString() : p[0].replace(/px/, '')
+ : el.css('top').replace(/px/, '');
+ te = top.indexOf('%') == -1
+ ? top + ' + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"'
+ : parseInt(top.replace(/%/, '')) + ' * ((' + ch + ' || ' + bch + ') / 100) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"';
+
+ if (p[1]) {
+ var left = typeof p[1] == 'number' ? p[1].toString() : p[1].replace(/px/, '');
+ le = left.indexOf('%') == -1
+ ? left + ' + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"'
+ : parseInt(left.replace(/%/, '')) + ' * ((' + cw + ' || ' + bcw + ') / 100) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"';
+ }
+ }
+ else {
+ te = '(' + ch + ' || ' + bch + ') / 2 - (this.offsetHeight / 2) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"';
+ le = '(' + cw + ' || ' + bcw + ') / 2 - (this.offsetWidth / 2) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"';
+ }
+ s.removeExpression('top');
+ s.removeExpression('left');
+ s.setExpression('top', te);
+ s.setExpression('left', le);
+ }
+ }
+ });
+ },
+ focus: function (pos) {
+ var self = this,
+ p = pos || 'first';
+
+ // focus on dialog or the first visible/enabled input element
+ var input = $(':input:enabled:visible:' + p, self.dialog.wrap);
+ input.length > 0 ? input.focus() : self.dialog.wrap.focus();
+ },
+ getDimensions: function () {
+ var el = $(window);
+
+ // fix a jQuery/Opera bug with determining the window height
+ var h = $.browser.opera && $.browser.version > '9.5' && $.fn.jquery <= '1.2.6' ? document.documentElement['clientHeight'] :
+ $.browser.opera && $.browser.version < '9.5' && $.fn.jquery > '1.2.6' ? window.innerHeight :
+ el.height();
+
+ return [h, el.width()];
+ },
+ getVal: function (v) {
+ return v == 'auto' ? 0 : parseInt(v.replace(/px/, ''));
+ },
+ setContainerDimensions: function () {
+ // get the dimensions for the container and data
+ var ch = this.getVal(this.dialog.container.css('height')), cw = this.dialog.container.width(),
+ dh = this.dialog.data.height(), dw = this.dialog.data.width();
+
+ var mh = this.opts.maxHeight && this.opts.maxHeight < w[0] ? this.opts.maxHeight : w[0],
+ mw = this.opts.maxWidth && this.opts.maxWidth < w[1] ? this.opts.maxWidth : w[1];
+
+ // height
+ if (!ch) {
+ if (!dh) {ch = this.opts.minHeight;}
+ else {
+ if (dh > mh) {ch = mh;}
+ else if (dh < this.opts.minHeight) {ch = this.opts.minHeight;}
+ else {ch = dh;}
+ }
+ }
+ else {
+ ch = ch > mh ? mh : ch;
+ }
+
+ // width
+ if (!cw) {
+ if (!dw) {cw = this.opts.minWidth;}
+ else {
+ if (dw > mw) {cw = mw;}
+ else if (dw < this.opts.minWidth) {cw = this.opts.minWidth;}
+ else {cw = dw;}
+ }
+ }
+ else {
+ cw = cw > mw ? mw : cw;
+ }
+
+ this.dialog.container.css({height: ch, width: cw});
+ if (dh > ch || dw > cw) {
+ this.dialog.wrap.css({overflow:'auto'});
+ }
+ this.setPosition();
+ },
+ setPosition: function () {
+ var top, left,
+ hc = (w[0]/2) - ((this.dialog.container.height() || this.dialog.data.height())/2),
+ vc = (w[1]/2) - ((this.dialog.container.width() || this.dialog.data.width())/2);
+
+ if (this.opts.position && this.opts.position.constructor == Array) {
+ top = this.opts.position[0] || hc;
+ left = this.opts.position[1] || vc;
+ } else {
+ top = hc;
+ left = vc;
+ }
+ this.dialog.container.css({left: left, top: top});
+ },
+ watchTab: function (e) {
+ var self = this;
+ if ($(e.target).parents('.simplemodal-container').length > 0) {
+ // save the list of inputs
+ self.inputs = $(':input:enabled:visible:first, :input:enabled:visible:last', self.dialog.data);
+
+ // if it's the first or last tabbable element, refocus
+ if (!e.shiftKey && e.target == self.inputs[self.inputs.length -1] ||
+ e.shiftKey && e.target == self.inputs[0] ||
+ self.inputs.length == 0) {
+ e.preventDefault();
+ var pos = e.shiftKey ? 'last' : 'first';
+ setTimeout(function () {self.focus(pos);}, 10);
+ }
+ }
+ else {
+ // might be necessary when custom onShow callback is used
+ e.preventDefault();
+ setTimeout(function () {self.focus();}, 10);
+ }
+ },
+ /*
+ * Open the modal dialog elements
+ * - Note: If you use the onOpen callback, you must "show" the
+ * overlay and container elements manually
+ * (the iframe will be handled by SimpleModal)
+ */
+ open: function () {
+ // display the iframe
+ this.dialog.iframe && this.dialog.iframe.show();
+
+ if ($.isFunction(this.opts.onOpen)) {
+ // execute the onOpen callback
+ this.opts.onOpen.apply(this, [this.dialog]);
+ }
+ else {
+ // display the remaining elements
+ this.dialog.overlay.show();
+ this.dialog.container.show();
+ this.dialog.data.show();
+ }
+
+ this.focus();
+
+ // bind default events
+ this.bindEvents();
+ },
+ /*
+ * Close the modal dialog
+ * - Note: If you use an onClose callback, you must remove the
+ * overlay, container and iframe elements manually
+ *
+ * @param {boolean} external Indicates whether the call to this
+ * function was internal or external. If it was external, the
+ * onClose callback will be ignored
+ */
+ close: function () {
+ // prevent close when dialog does not exist
+ if (!this.dialog.data) {
+ return false;
+ }
+
+ // remove the default events
+ this.unbindEvents();
+
+ if ($.isFunction(this.opts.onClose) && !this.occb) {
+ // set the onClose callback flag
+ this.occb = true;
+
+ // execute the onClose callback
+ this.opts.onClose.apply(this, [this.dialog]);
+ }
+ else {
+ // if the data came from the DOM, put it back
+ if (this.dialog.parentNode) {
+ // save changes to the data?
+ if (this.opts.persist) {
+ // insert the (possibly) modified data back into the DOM
+ this.dialog.data.hide().appendTo(this.dialog.parentNode);
+ }
+ else {
+ // remove the current and insert the original,
+ // unmodified data back into the DOM
+ this.dialog.data.hide().remove();
+ this.dialog.orig.appendTo(this.dialog.parentNode);
+ }
+ }
+ else {
+ // otherwise, remove it
+ this.dialog.data.hide().remove();
+ }
+
+ // remove the remaining elements
+ this.dialog.container.hide().remove();
+ this.dialog.overlay.hide().remove();
+ this.dialog.iframe && this.dialog.iframe.hide().remove();
+
+ // reset the dialog object
+ this.dialog = {};
+ }
+ }
+ };
+})(jQuery);
diff --git a/media/js/newsblur/reader.js b/media/js/newsblur/reader.js
index c6fb1a173..50d3bf0a5 100644
--- a/media/js/newsblur/reader.js
+++ b/media/js/newsblur/reader.js
@@ -20,10 +20,6 @@
this.load_page();
this.load_feeds();
this.apply_resizable_layout();
- this.load_opml_import_facebox();
- $(document).bind('reveal.facebox', function() {
- self.handle_opml_form();
- });
this.cornerize_buttons();
this.handle_keystrokes();
this.setup_taskbar_leftnav();
@@ -467,8 +463,15 @@
// = OPML =
// ========
- load_opml_import_facebox: function() {
- $('a.open_opml_import_facebox').facebox();
+ open_opml_import_modal_form: function() {
+ var $opml = $.make('div', 'Lala');
+
+ $opml.modal({
+ 'overlayClose': true,
+ 'onShow': function() {
+ $('#simplemodal-container').corners('8px');
+ }
+ });
},
handle_opml_form: function() {
@@ -540,6 +543,11 @@
e.preventDefault();
self.open_taskbar_menu($t, e);
});
+ $.targetIs(e, { tagSelector: '.NB-task-import-upload-opml' }, function($t, $p){
+ e.preventDefault();
+ self.open_opml_import_modal_form($t);
+ });
+
},
@@ -579,6 +587,7 @@
// ===================
setup_taskbar_leftnav: function() {
+ var self = this;
var $task_buttons = $('#taskbar .taskbar_leftnav .task_button');
var $taskbar_menu = $('#taskbar .taskbar_leftnav .taskbar_menu li span').corners('2px');
@@ -588,17 +597,19 @@
$this.hover(function() {
if ($this.hasClass('active')) {
$this.stopTime('task');
+ $('.taskbar_menu', $this).dropShadow();
$('.taskbar_menu', $this)
.stop()
- .animate({ opacity: 1 }, 350);
+ .css({ opacity: 1 });
}
}, function() {
if ($this.hasClass('active')) {
+ $('.taskbar_menu', $this).removeShadow();
+
$this.stopTime('task')
- .oneTime(250, 'task', function() {
+ .oneTime(750, 'task', function() {
$('.taskbar_menu', $this).animate({ opacity: 0 }, 1500, 'easeInQuad', function() {
- $this.removeClass('active');
- $('.taskbar_menu', $this).css({ opacity: 1 });
+ self.close_taskbar_menu($this);
})
});
}
@@ -607,17 +618,37 @@
},
open_taskbar_menu: function($taskbar_button, e) {
- e.stopPropagation();
- $('.taskbar_menu', $taskbar_button).css({ opacity: 1 });
+ var self = this;
+ var $task_buttons = $('#taskbar .taskbar_leftnav .task_button');
+
if ($taskbar_button.hasClass('active')) {
- $taskbar_button.removeClass('active');
+ // Close
+ this.close_taskbar_menu($taskbar_button);
} else {
+ // Open
$taskbar_button.addClass('active');
+ $('.taskbar_menu', $taskbar_button).stop().css({ opacity: 1 }).dropShadow();
+
+ $task_buttons.each(function() {
+ if (this != $taskbar_button[0]) {
+ self.close_taskbar_menu($(this));
+ }
+ });
+
$(document).bind('click.taskbar_menu', function() {
- $taskbar_button.removeClass('active');
- $(document).unbind('click.taskbar_menu');
+ self.close_taskbar_menu($taskbar_button);
})
+ $('.taskbar_menu', $taskbar_button).bind('click.taskbar_menu', function(e) {
+ // e.stopPropagation();
+ });
}
+ },
+
+ close_taskbar_menu: function($taskbar_button) {
+ $taskbar_button.stopTime('task');
+ $taskbar_button.removeClass('active');
+ $('.taskbar_menu', $taskbar_button).removeShadow();
+ $(document).unbind('click.taskbar_menu');
}
};
diff --git a/templates/base.html b/templates/base.html
index 55dfe6bc4..a383fa34e 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -8,7 +8,6 @@
-
@@ -17,6 +16,8 @@
+
+
@@ -32,7 +33,6 @@
-
diff --git a/templates/reader/feeds.xhtml b/templates/reader/feeds.xhtml
index 89e137323..b2b5d7839 100644
--- a/templates/reader/feeds.xhtml
+++ b/templates/reader/feeds.xhtml
@@ -28,9 +28,10 @@