diff options
Diffstat (limited to 'site/app/webroot')
23 files changed, 477 insertions, 61 deletions
diff --git a/site/app/webroot/css/editors.css b/site/app/webroot/css/editors.css index 396b600..4c11658 100644 --- a/site/app/webroot/css/editors.css +++ b/site/app/webroot/css/editors.css @@ -181,6 +181,9 @@ div.error_message { border: 0; vertical-align: middle; } +#subform div { + margin: 5px 0; +} #commentsbox { padding: 5px; } diff --git a/site/app/webroot/css/filebrowser.css b/site/app/webroot/css/filebrowser.css index 35f6d89..f94c1be 100644 --- a/site/app/webroot/css/filebrowser.css +++ b/site/app/webroot/css/filebrowser.css @@ -52,7 +52,7 @@ content: "\00BB \0020"; } .fileList li.file:before { - content: "\203A \0000"; + content: "\203A \0020"; margin-right: 2px; } diff --git a/site/app/webroot/css/localizers.css b/site/app/webroot/css/localizers.css index 6213973..ee81a39 100644 --- a/site/app/webroot/css/localizers.css +++ b/site/app/webroot/css/localizers.css @@ -46,6 +46,7 @@ table.translatedSection th { table.translatedSection td { padding: 5px; font-size: 80%; + vertical-align: top; } table.translatedSection td.field { font-weight: bold; @@ -56,3 +57,10 @@ table.translatedSection td.enus { table.translatedSection td.localized { border-left: 1px solid gray; } +table.translatedSection input { + width: 100%; +} +table.translatedSection textarea { + width: 100%; + height: 8em; +} diff --git a/site/app/webroot/css/remora.css b/site/app/webroot/css/remora.css index 57fa3e1..0c796e6 100644 --- a/site/app/webroot/css/remora.css +++ b/site/app/webroot/css/remora.css @@ -18,8 +18,8 @@ #cat-list li.selected a { background: #99CC66; } /* Add-on Summary */ -#addon-summary .stats { position: absolute; left: 20px; top: 18em; margin: 1em 0; } -#addon-summary { min-height: 225px; } +#addon-summary .stats { position: absolute; left: 20px; top: 19em; margin: 1em 0; text-align: center; } +#addon-summary { min-height: 255px; } #addon-summary .privacypolicy { clear: both; padding-top: .5em; } /* Details Page */ @@ -136,4 +136,19 @@ div.hsession { display: none; } } #tabbed-editor .ui-tabs-nav { display: block; +} + + +/* FAQ styling */ + +dl.faq dt { + margin: 1em 0 0 0; +} + +dl.faq dd { + margin-top: 0.5em; +} + +dl.faq dt:target { + color: #df731b; }
\ No newline at end of file diff --git a/site/app/webroot/css/screen.css b/site/app/webroot/css/screen.css index 62c4080..e20ff6e 100644 --- a/site/app/webroot/css/screen.css +++ b/site/app/webroot/css/screen.css @@ -4,6 +4,7 @@ Created by Craig Cook - focalcurve.com on November 20, 2007 -----------------------------------------------------------------------------*/ + /*** =Reset defaults ***/ html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, @@ -84,7 +85,7 @@ h4#moz a { display: block; height: 44px; width: 100px; padding-left: 10px;} /* =User nav */ #nav-user { max-width: 900px; min-width: 770px;} .html-ltr #nav-user { margin: -1.75em auto 0; padding: 0 50px;} -.html-rtl #nav-user { margin: -1.75em auto 0; padding: 0 0 0 50px;} +.html-rtl #nav-user { margin: 0em auto 0; padding: 0 0 0 50px;} #nav-user li { display: inline;} .html-ltr #nav-user li { padding-left: 1em; margin-right: .5em; } @@ -385,6 +386,46 @@ form.asclosed {display: none;} #addon-summary .rating { position: absolute; left: 20px; top: 180px; width: 200px; } #addon-summary .stats { position: absolute; left: 20px; top: 180px; width: 200px; margin-top: 3.5em; } +#addon-summary .link-sharing { position: absolute; left: 105px; /*padding-left: 25px; border-left: 1px solid #cecece;*/ top: 180px; font-size: 0.7em; } +#addon-summary .link-sharing .badge { } +#addon-summary .link-sharing .badge .button { display: block;color: #062445; background: #7cc11c url("../img/sprite.png?20081210") -800px -730px no-repeat; } +#addon-summary .link-sharing .badge .button a { display: block; padding: 0 8px 8px 0; background: transparent url(../img/installbtn-edges.png) no-repeat scroll right bottom; } +#addon-summary .link-sharing .badge .button a span { display: block; text-align: center; font-weight: bold; padding: 2px 0 0 2px; background: transparent url(../img/installbtn-edges-list.png) no-repeat scroll left top; } + +#addon-summary .link-sharing .share-button { padding: 0; margin: 0 } +#addon-summary .link-sharing .share-button:after, .install-container:after {content:".";clear:both;display:block;visibility:hidden;height:0;overflow:hidden;} +#addon-summary .link-sharing .share-button a { float: left; cursor: pointer; max-width: 290px; text-decoration: none; } +#addon-summary .link-sharing .share-button a * { display: block; float: left; position: relative; } +#addon-summary .link-sharing .share-button a span { padding: 0 0 0 6px; } +#addon-summary .link-sharing .share-button a span span { padding: 0 0 8px 0; } +#addon-summary .link-sharing .share-button a span span span { left: -6px; padding: 0 0 0 0; } +#addon-summary .link-sharing .share-button a span span span strong { width: 90px; text-align: center; right: -6px; padding: 0 18px 0 6px; } +#addon-summary .link-sharing .share-button a span span span strong img {padding: 0 6px 0 0;} + +#addon-summary .link-sharing .share-button a { color: #062445; background: #7cc11c url("../img/sprite.png?20081210") -800px -730px no-repeat; } +#addon-summary .link-sharing .share-button a span { background: transparent url("../img/installbtn-edges.png") left bottom no-repeat; } +#addon-summary .link-sharing .share-button a span span { background: transparent url("../img/installbtn-edges.png") right bottom no-repeat; } +#addon-summary .link-sharing .share-button a span span span { background: transparent url("../img/installbtn-edges.png") left top no-repeat; } +#addon-summary .link-sharing .share-button a span span span strong { background: transparent url("../img/installbtn-edges.png") right top no-repeat; } + +#addon-summary .link-sharing .share-button a:hover, .install-button a:focus, .install-button a:active { color: #0a3b73; background-color: #9dd34c; background-position: -800px -860px; } + +#addon-summary .link-sharing .badge .counter { display: block; position: relative; padding-right: 4px; text-align: center; top: -4px; } + +#addon-summary .link-sharing .choices { display: none; position: absolute; z-index: 999; left: -120px; top: 12px; width: 360px; background: transparent url(../img/box-pointer-top.png) center top no-repeat; padding-top: 12px; } +#addon-summary .link-sharing .choices div { margin: 0; padding: 1em; background-color: #f8f8f8; border: 1px solid #657b86; -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; } +#addon-summary .link-sharing .choices ul { list-style: none; margin: 0; } +#addon-summary .link-sharing .choices ul li { width: 50%; float: left; } +#addon-summary .link-sharing .choices ul li p { padding: 0.25em; margin: 0 0.25em 0 0 } +#addon-summary .link-sharing .choices ul li p a { font-weight: bold; display:block; height: 20px; text-decoration: none; padding-left: 22px; background: transparent url(../img/favicons/digg.gif) left top no-repeat } +#addon-summary .link-sharing .choices ul li.digg p a { background-image: url(../img/favicons/digg.gif); } +#addon-summary .link-sharing .choices ul li.facebook p a { background-image: url(../img/favicons/facebook.gif); } +#addon-summary .link-sharing .choices ul li.delicious p a { background-image: url(../img/favicons/delicious.gif); } +#addon-summary .link-sharing .choices ul li.myspace p a { background-image: url(../img/favicons/myspace.gif); } +#addon-summary .link-sharing .choices ul li.friendfeed p a { background-image: url(../img/favicons/friendfeed.gif); } +#addon-summary .link-sharing .choices ul li.reddit p a { background-image: url(../img/favicons/reddit.gif); } + + .addon-cats { margin-left: 0; } .addon-cats li { display: inline; padding-left: 1em; margin-right: .5em; } .addon-cats li:first-child { padding-left: 0; } @@ -906,6 +947,8 @@ form.asclosed {display: none;} background-color: #000; } + + /* Background iframe styling for IE6. Prevents ActiveX bleed-through (<select> form elements, etc.) */ * iframe.jqm { position: absolute; diff --git a/site/app/webroot/css/stats/dropdowns.css b/site/app/webroot/css/stats/dropdowns.css index fef396f..336ad95 100755 --- a/site/app/webroot/css/stats/dropdowns.css +++ b/site/app/webroot/css/stats/dropdowns.css @@ -214,9 +214,6 @@ .plot-dropdown.big-menu ul li.indented a { padding-left: 23px; } -.plot-dropdown.group-by .selected { - width: 98%; -} #options.plot-dropdown { width: 35px; @@ -232,6 +229,17 @@ margin-left: -120px; } +#group-by-selector { + width: 163px; + white-space: nowrap; +} +#group-by-selector .selected { + width: 98%; +} +#group-by-selector_group-by-selection-menu { + padding: 0 0.5em 0 0.5em; + width: auto; +} #plot-options #plot-selector-area { @@ -251,6 +259,15 @@ float: right; } +#weeks-legend { + display: none; + border: 2px solid #D8DCDF; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + float: left; + margin-left: 160px; +} + #summary-legend { border: 2px solid #D8DCDF; -moz-border-radius: 6px; @@ -331,3 +348,4 @@ height: 150px; border: none !important; } + diff --git a/site/app/webroot/img/box-pointer-top.png b/site/app/webroot/img/box-pointer-top.png Binary files differnew file mode 100644 index 0000000..d7f451c --- /dev/null +++ b/site/app/webroot/img/box-pointer-top.png diff --git a/site/app/webroot/img/developers/admin_review.png b/site/app/webroot/img/developers/admin_review.png Binary files differnew file mode 100644 index 0000000..cff65d7 --- /dev/null +++ b/site/app/webroot/img/developers/admin_review.png diff --git a/site/app/webroot/img/developers/info-bw.png b/site/app/webroot/img/developers/info-bw.png Binary files differnew file mode 100644 index 0000000..ade8c8f --- /dev/null +++ b/site/app/webroot/img/developers/info-bw.png diff --git a/site/app/webroot/img/developers/info-color.png b/site/app/webroot/img/developers/info-color.png Binary files differnew file mode 100644 index 0000000..1236c56 --- /dev/null +++ b/site/app/webroot/img/developers/info-color.png diff --git a/site/app/webroot/img/favicons/delicious.gif b/site/app/webroot/img/favicons/delicious.gif Binary files differnew file mode 100644 index 0000000..a136dd1 --- /dev/null +++ b/site/app/webroot/img/favicons/delicious.gif diff --git a/site/app/webroot/img/favicons/digg.gif b/site/app/webroot/img/favicons/digg.gif Binary files differnew file mode 100644 index 0000000..089f4f2 --- /dev/null +++ b/site/app/webroot/img/favicons/digg.gif diff --git a/site/app/webroot/img/favicons/facebook.gif b/site/app/webroot/img/favicons/facebook.gif Binary files differnew file mode 100644 index 0000000..90a8e02 --- /dev/null +++ b/site/app/webroot/img/favicons/facebook.gif diff --git a/site/app/webroot/img/favicons/friendfeed.gif b/site/app/webroot/img/favicons/friendfeed.gif Binary files differnew file mode 100644 index 0000000..edcc727 --- /dev/null +++ b/site/app/webroot/img/favicons/friendfeed.gif diff --git a/site/app/webroot/img/favicons/myspace.gif b/site/app/webroot/img/favicons/myspace.gif Binary files differnew file mode 100644 index 0000000..8e56437 --- /dev/null +++ b/site/app/webroot/img/favicons/myspace.gif diff --git a/site/app/webroot/img/favicons/reddit.gif b/site/app/webroot/img/favicons/reddit.gif Binary files differnew file mode 100644 index 0000000..8a4963f --- /dev/null +++ b/site/app/webroot/img/favicons/reddit.gif diff --git a/site/app/webroot/js/addons.js b/site/app/webroot/js/addons.js index 6da858b..2f23003 100644 --- a/site/app/webroot/js/addons.js +++ b/site/app/webroot/js/addons.js @@ -260,10 +260,9 @@ function removeCompatibilityHint(versionID) { * This function is used on the addon version page to create an element * at the top of the page with the most recent compatible version of an addon */ -function createLatestVersionElement(get_latest_version_text) { +function createLatestVersionElement(get_latest_version_text, app) { var container = $("#latest-version-container"); - - container.wrapInner("<p>" + get_latest_version_text + " (" + gLatestApplicationVersion + ")" + "</p>"); + container.wrapInner("<p>" + sprintf(get_latest_version_text, app, gLatestApplicationVersion) + "</p>"); container.append(gLatestAddonVersion); var installButton = $("#install-"+ gLatestVersionID); var cloned = installButton.clone(); @@ -865,3 +864,130 @@ $.fn.collection = function(options) { /*# AVOID COLLISIONS #*/ })(jQuery); /*# AVOID COLLISIONS #*/ + +/** + * jQuery rollover reveal widget + * lorchard@mozilla.com + * + * Example markup: + * <div id="foo"> + * <a href="#" class="activator">Hover me</a> + * <div class="to-reveal">This content will appear</div> + * </div> + * <script> + * $('#foo').rolloverReveal({ + * reveal_delay: 1000, dismiss_delay: 2000 + * }) + * </script> + * + * Whenever the activator element is hovered, the to-reveal content will appear + * after a short delay. If the mouse leaves the activator or revealed content, + * the content will disappear after a short delay unless the mouse returns. + * + * Clicking on a link within the revealed content will dismiss the content. + */ +;if(jQuery) (function($){ + + $.fn.rolloverReveal = function(options) { + var $cls = arguments.callee.support; + $.each(this, function() { new $cls(this, options) }); + return this; + } + + $.fn.rolloverReveal.support = function(el, options) { + this.init(el, options); + }; + + $.fn.rolloverReveal.support.prototype = function() { + + var option_defaults = { + reveal_delay: 250, + dismiss_delay: 500 + }; + + return { + // Delayed execution timers. + timers: {}, + + /** Set up the object instance and event handlers for this widget. */ + init: function(el, options) { + var that = this; + this.options = $.extend({}, option_defaults, options); + + // Assign a unique ID to the element if none found. + if (!el.id) el.id = 'el-' + + (new Date()).getTime() + '-' + + parseInt(1000 * Math.random()); + + this.root = '#'+el.id; + this.to_reveal = $(this.root_id).find('.to-reveal'); + + // Wire up the event handlers for significant elements of + // the widget. + $(this.root) + .find('.activator') + .click(function() { that.toggle(); return false; }) + .mouseover(function() { that.schedule('reveal'); that.cancel('dismiss'); }) + .mouseout(function() { that.cancel('reveal'); that.schedule('dismiss'); }) + .end() + .find('.to-reveal') + .mouseover(function() { that.cancel('dismiss'); }) + .mouseout(function() { that.schedule('dismiss'); }) + .end() + .find('.to-reveal a') + .click(function() { that.dismiss(); return true; }) + .mouseover(function() { that.cancel('dismiss'); }) + .mouseout(function() { that.schedule('dismiss'); }) + .end(); + }, + + /** Reveal the hidden content */ + reveal: function() { + this.to_reveal.show().addClass('revealed'); + }, + + /** Determine whether the hidden content is revealed */ + revealStatus: function() { + return this.to_reveal.hasClass('revealed'); + }, + + /** Dismiss the hidden content */ + dismiss: function() { + this.to_reveal.hide().removeClass('revealed'); + }, + + /** Determine whether the hidden content is hidden */ + dismissStatus: function() { + return !this.to_reveal.hasClass('revealed'); + }, + + /** Toggle the hide/show of the content */ + toggle: function() { + return (this.revealStatus()) ? + this.dismiss() : this.reveal(); + }, + + /** Schedule delayed execution of the given action. */ + schedule: function(action) { + var that = this; + // Skip if the action is already in effect. + if (this[action+'Status']()) return; + // De-bounce any existing running timer. + this.cancel(action); + // Schedule a call to the given action. + this.timers[action] = setTimeout(function() { + that[action](); + }, this.options[action + '_delay']); + }, + + /** Cancel delayed execution of the given action. */ + cancel: function(action) { + if (this.timers[action]) + clearTimeout(this.timers[action]); + }, + + EOF:null + }; + }(); + +})(jQuery); diff --git a/site/app/webroot/js/developers.js b/site/app/webroot/js/developers.js index e7ef203..0e02c86 100644 --- a/site/app/webroot/js/developers.js +++ b/site/app/webroot/js/developers.js @@ -55,7 +55,7 @@ var upload = { return true; } else { - alert('You must select a file to upload.'); + alert(devcp_js_upload_alert); return false; } } @@ -85,10 +85,13 @@ function iframeLoaded() { else if (upload.response.uploadtype == 'update') { if (upload.response.status == addon_statuses.PUBLIC) { $('#pending-message').hide(); - $('#new-file-status').text('Public'); + $('#new-file-status').text(addons_status_public); + } + else if (upload.response.status == addon_statuses.SANDBOX) { + $('#new-file-status').text(addons_status_sandbox); } else if (upload.response.status == addon_statuses.PENDING) { - $('#new-file-status').text('In Sandbox; Pending Review'); + $('#new-file-status').text(addons_status_pending); } $('#new-file-status').addClass('status-' + upload.response.status); $('#new-version-number').text(upload.response.version); @@ -99,10 +102,10 @@ function iframeLoaded() { else if (upload.response.uploadtype == 'file') { if (upload.response.status == addon_statuses.PUBLIC) { $('#pending-message').hide(); - $('#new-file-status').text('Public'); + $('#new-file-status').text(addons_status_public); } else if (upload.response.status == addon_statuses.PENDING) { - $('#new-file-status').text('In Sandbox; Pending Review'); + $('#new-file-status').text(addons_status_pending); } $('#new-file-status').addClass('status-' + upload.response.status); $('#queue-count').text(upload.response.queuecount); @@ -150,22 +153,22 @@ var addon_edit_authors = { addAuthor: function(user_id, author, role, visible, markChanges) { var row = '<tr><td>'; - row += '<a class="down-arrow" href="#" onclick="addon_edit_authors.moveDownRow(this); return false;"><img src="' + imageURL + '/developers/arrow_down.png" alt="Move Down" title="Move Down" /></a>'; - row += '<a class="up-arrow" href="#" onclick="addon_edit_authors.moveUpRow(this); return false;"><img src="' + imageURL + '/developers/arrow_up.png" alt="Move Up" title="Move Up" /></a>'; + row += '<a class="down-arrow" href="#" onclick="addon_edit_authors.moveDownRow(this); return false;"><img src="' + imageURL + '/developers/arrow_down.png" alt="' + devcp_js_img_move_down + '" title="' + devcp_js_img_move_down + '" /></a>'; + row += '<a class="up-arrow" href="#" onclick="addon_edit_authors.moveUpRow(this); return false;"><img src="' + imageURL + '/developers/arrow_up.png" alt="' + devcp_js_img_move_up + '" title="' + devcp_js_img_move_up + '" /></a>'; row += '</td><td><a href="' + profileURL + '/' + user_id + '">' + author + '</a></td><td>'; row += '<select name="data[addons_users][' + user_id + '][role]">'; - row += '<option value="' + author_roles.OWNER + '" ' + (role == author_roles.OWNER ? ' selected="selected"' : '') + '>Owner</option>'; - row += '<option value="' + author_roles.DEV + '" ' + (role == author_roles.DEV ? ' selected="selected"' : '') + '>Developer</option>'; - row += '<option value="' + author_roles.VIEWER + '" ' + (role == author_roles.VIEWER ? ' selected="selected"' : '') + '>Viewer</option>'; + row += '<option value="' + author_roles.OWNER + '" ' + (role == author_roles.OWNER ? ' selected="selected"' : '') + '>' + devcp_js_option_owner + '</option>'; + row += '<option value="' + author_roles.DEV + '" ' + (role == author_roles.DEV ? ' selected="selected"' : '') + '>' + devcp_js_option_developer + '</option>'; + row += '<option value="' + author_roles.VIEWER + '" ' + (role == author_roles.VIEWER ? ' selected="selected"' : '') + '>' + devcp_js_option_viewer + '</option>'; row += '</td><td>'; - row += '<input type="checkbox" name="data[addons_users][' + user_id + '][listed]" value="1" ' + (visible == true ? ' checked="checked"' : '') + ' title="List as author in public listings"/>'; + row += '<input type="checkbox" name="data[addons_users][' + user_id + '][listed]" value="1" ' + (visible == true ? ' checked="checked"' : '') + ' title="' + devcp_js_input_list_author + '"/>'; row += '</td><td style="width: 25px;">'; row += '<div class="inline-delete-button uses-image">'; - row += '<a href="#" onclick="addon_edit_authors.deleteAuthor(this); return false;"><img src="' + imageURL + '/developers/delete.png" alt="Remove Author" title="Remove Author" /></a>'; + row += '<a href="#" onclick="addon_edit_authors.deleteAuthor(this); return false;"><img src="' + imageURL + '/developers/delete.png" alt="' + devcp_js_remove_author + '" title="' + devcp_js_remove_author + '" /></a>'; row += '<div class="inline-delete-box">'; - row += '<p>Are you <b>sure</b> you wish to remove this author?</p><br />'; - row += '<p><a href="#" onclick="addon_edit_authors.confirmDelete(this); return false;" class="remove-button rounded">Remove Author</a> '; - row += '<a href="#" onclick="addon_edit_authors.cancelDelete(this); return false;" class="button rounded">Cancel</a></p>'; + row += '<p>' + devcp_js_sure_remove + '</p><br/>'; + row += '<p><a href="#" onclick="addon_edit_authors.confirmDelete(this); return false;" class="remove-button rounded">' + devcp_js_remove_author + '</a> '; + row += '<a href="#" onclick="addon_edit_authors.cancelDelete(this); return false;" class="button rounded">' + devcp_js_a_cancel + '</a></p>'; row += '</div></div>'; row += '</td></tr>'; @@ -239,7 +242,7 @@ var addon_edit_authors = { return true; } else { - $('#add-error').html('Please enter the account email of the author you wish to add.'); + $('#add-error').html(devcp_js_add_email); $('#add-error').slideDown(); return false; } @@ -380,7 +383,7 @@ var versions_edit = { newRow += '<input type="hidden" name="data[Application][' + application_id + '][new]" value="1"/></td>'; newRow += '<td>' + $('#app' + application_id + '-dropdowns').html() + '</td>'; newRow += '<td style="width: 25px;"><div class="inline-delete-button">'; - newRow += '<a href="#" onclick="versions_edit.confirmDelete(this); return false;"><img src="' + imageBase + '/delete.png" alt="Remove Application Compatibility" title="Remove Application Compatibility" /></a>'; + newRow += '<a href="#" onclick="versions_edit.confirmDelete(this); return false;"><img src="' + imageBase + '/delete.png" alt="' + devcp_js_img_remove_compat + '" title="' + devcp_js_img_remove_compat + '" /></a>'; newRow += '</div></td>'; newRow += '</tr>'; diff --git a/site/app/webroot/js/editors.js b/site/app/webroot/js/editors.js index d6e1bba..6a00292 100644 --- a/site/app/webroot/js/editors.js +++ b/site/app/webroot/js/editors.js @@ -26,7 +26,7 @@ function toggleFilters() { * editors/review * *************************************************/ //Array of possible actions -var actions = ['public', 'sandbox', 'superreview']; +var actions = ['public', 'sandbox', 'info', 'superreview']; //Simulate radio button group for action icons function selectAction(action) { @@ -36,34 +36,33 @@ function selectAction(action) { //Select action and deselect other actions for (var i = 0; i < actions.length; i++) { if (actions[i] == action) { - color(actions[i]); + changeIcon(actions[i], 'color'); document.getElementById('details-' + actions[i]).style.display = ''; } else { - bw(actions[i]); + changeIcon(actions[i], 'bw'); document.getElementById('details-' + actions[i]).style.display = 'none'; } } + // when rejecting, pre-select notification box + $('#subscribe input').attr('checked', (action=='sandbox')); + // no canned responses/app/os for info request + if (action=='info') + $('#canned,#testing').hide(); + else + $('#canned,#testing').show(); + $('#subform').show('medium'); } -//Turn an icon colored -function color(action) { +//Turn an icon colored/bw +function changeIcon(action, colorbw) { var icon = document.getElementById(action + 'Icon'); var span = document.getElementById(action); - icon.src = '../../../../img/developers/' + action + '-color.png'; - span.className = 'action_color'; -} - -//Turn an icon bw -function bw(action) { - var icon = document.getElementById(action + 'Icon'); - var span = document.getElementById(action); - - icon.src = '../../../../img/developers/' + action + '-bw.png'; - span.className = 'action_bw'; + icon.src = icon.src.substring(0, icon.src.lastIndexOf('/')+1) + action + '-' + colorbw + '.png'; + span.className = 'action_'+colorbw; } //Get number of selected files @@ -95,7 +94,13 @@ function selectedFile() { //Validate review form function validateReview(type) { - if (type == 'pending') { + //Make sure an action was selected + var action = document.getElementById('actionField').value; + if (action == '') { + errors += '- ' + localized['action'] + '\n'; + } + + if (type == 'pending' && action!='info') { //Make sure at least one file is selected var filesSelected = selectedFileCount(); @@ -107,15 +112,11 @@ function validateReview(type) { var errors = ''; - //Make sure an action was selected - if (document.getElementById('actionField').value == '') { - errors += '- ' + localized['action'] + '\n'; - } //Make sure comments were entered if (document.getElementById('comments').value == '') { errors += '- ' + localized['comments'] + '\n'; } - if (type == 'pending') { + if (type == 'pending' && action!='info') { //Make sure tested operating system was entered if (document.getElementById('ApprovalOs').value == '') { errors += '- ' + localized['os'] + '\n'; diff --git a/site/app/webroot/js/stats/plot-selection.js b/site/app/webroot/js/stats/plot-selection.js index 5310f32..805e3b9 100755 --- a/site/app/webroot/js/stats/plot-selection.js +++ b/site/app/webroot/js/stats/plot-selection.js @@ -65,9 +65,15 @@ var plotSelection = { menu.addItem({'value': 'date', 'name': localized['statistics_js_groupby_selector_date']}).select(); menu.addItem({'value': 'week', 'name': localized['statistics_js_groupby_selector_week']}); menu.addItem({'value': 'month', 'name': localized['statistics_js_groupby_selector_month']}); + menu.addItem({'value': 'week_over_week', 'name':localized['statistics_js_groupby_selector_week_over_week']}); $('#group-by-selector').hide(); }, + + getGroupByValue: function() { + return (!this.dropdowns['group-by-selector']) ? 'date' : + this.dropdowns['group-by-selector'].selectedItem.value; + }, addAdditionalDropdown: function() { var type = plotSelection.dropdowns['plot-selector'].selectedItem.value; @@ -371,4 +377,4 @@ var plotSelection = { } }); } -};
\ No newline at end of file +}; diff --git a/site/app/webroot/js/stats/plot-tables.js b/site/app/webroot/js/stats/plot-tables.js index 51833ad..106c3e6 100644 --- a/site/app/webroot/js/stats/plot-tables.js +++ b/site/app/webroot/js/stats/plot-tables.js @@ -61,6 +61,12 @@ var PlotsTables = (function() { $('#stats-table-instance').remove(); }, + week_over_week_count_onAddMany: function(source) { + // Clear any existing tables when week-over-week comes up + $('#stats-table').hide(); + $('#stats-table-instance').remove(); + }, + defined_count_onAddMany: function(source) { // Set the URL for the download link. diff --git a/site/app/webroot/js/stats/plots.js b/site/app/webroot/js/stats/plots.js index 464b2c3..48f792e 100755 --- a/site/app/webroot/js/stats/plots.js +++ b/site/app/webroot/js/stats/plots.js @@ -7,11 +7,7 @@ var Plots = { determinePlot: function() { var selected = plotSelection.dropdowns['plot-selector'].selectedItem.value; - - // HACK: The group-by selector doesn't exist when the plot-selector is first - // instantiated, but this method is called at that point. - var group_by = (!plotSelection.dropdowns['group-by-selector']) ? null : - plotSelection.dropdowns['group-by-selector'].selectedItem.value; + var group_by = plotSelection.getGroupByValue(); // Remove current plot selections plotSelection.removeAll(); @@ -156,11 +152,13 @@ var Plots = { var plotType = plotSelection.dropdowns['plot-selector'].selectedItem.value; if (plotType == 'summary') { + $('#weeks-legend').hide(); $('#summary-legend').show(); $('#summary-options').show(); $('#group-by-selector').hide(); } else { + $('#weeks-legend').hide(); $('#summary-legend').hide(); $('#summary-options').hide(); $('#group-by-selector').show(); @@ -231,9 +229,22 @@ var Plots = { // If there's a value for the group-by selector, add it as a // parameter to the CSV URL to invoke it server-side. - var group_by = plotSelection.dropdowns['group-by-selector'].selectedItem.value; + var group_by = plotSelection.getGroupByValue(); + + if ('week_over_week' == group_by) { + if ('updatepings' == type || 'downloads' == type) { + $('#weeks-legend').show(); + return this.plotWeekOverWeek(); + } else { + // HACK: Until I can figure out how to disable the Compare + // by: Week option for views not supported for it + group_by = 'week'; + } + } + + $('#weeks-legend').hide(); if (group_by) Plots.currentCSV += '?group_by=' + group_by; - + this.dataSources = { 'count': new Timeplot.DefaultEventSource(), 'events-firefox': new Timeplot.DefaultEventSource(), @@ -304,7 +315,7 @@ var Plots = { this.plot(); }, - + plot: function() { var timeGeometry = new Timeplot.DefaultTimeGeometry(this.timeGeometry); var valueGeometry = new Timeplot.DefaultValueGeometry(this.valueGeometry); @@ -328,6 +339,172 @@ var Plots = { Plots.timeplot.loadXML(statsURL + 'xml/events/firefox', this.dataSources['events-firefox']); Plots.timeplot.loadXML(statsURL + 'xml/events/addon/' + addonID, this.dataSources['events-addon']); }, + + /** + * Construct a plot consisting of 2 different weeks' data overlaid on + * the same graph. + */ + plotWeekOverWeek: function() { + + var type = plotSelection.dropdowns['plot-selector'].selectedItem.value; + Plots.currentCSV = statsURL + 'csv/' + addonID + '/' + type; + + this.dataSources = { + 'count': new Timeplot.DefaultEventSource(), + }; + + PlotsTables.addListeners('week_over_week', this.dataSources); + + var date_parser = Timeline.NativeDateUnit.getParser('iso8601'); + + // Collect Mondays from the set of available dates. + var available_dates = plotSelection + .summary[ (type=='downloads') ? 'downloads' : 'updatepings' ] + .availableDates; + var dates = []; + var DAY_MONDAY = 1; + for (idx in available_dates) { + // The available dates data is a little weird - it's an object + // with numerical properties, instead of an array. + if (available_dates.hasOwnProperty(idx)) { + var date = date_parser(available_dates[idx]); + if (date.getDay() == DAY_MONDAY) + dates.push(available_dates[idx]); + } + } + + // Set up empty ranges set. + var ranges = { + week1: { min: '', max: '' }, + week2: { min: '', max: '' } + }; + + var WEEK = ( 1000 * 60 * 60 * 24 * 7 ); + + if ( $('#weeks-legend .template').length ) { + + // The date selection dropdowns still contain unpopulated + // templates, so set up the defaults and populate the dropdowns + + ranges['week2']['min'] = date_parser(dates[dates.length - 1]); + ranges['week2']['max'] = new Date(ranges['week2']['min'].getTime() + WEEK); + ranges['week1']['min'] = date_parser(dates[dates.length - 2]); + ranges['week1']['max'] = new Date(ranges['week1']['min'].getTime() + WEEK); + + var weeks = ['week1', 'week2']; + for (var i=0, week; week=weeks[i]; i++) { + + // Convert the selection template into a concrete element + var tmpl = $('#'+week+'-selection select.template'); + if (!tmpl.length) continue; + tmpl.remove().removeClass('template'); + + // Convert the current min date to string for comparison. + var min_str = ranges[week]['min'].strftime('%Y-%m-%d'); + + // Now populate the selection element with options cloned + // and populated from available dates. + var t_opt = tmpl.find('option').remove(); + for (var j=0,date; date=dates[j]; j++) { + var opt = t_opt.clone(); + + var dp = date.split('-'); + opt.text([dp[1], dp[2], dp[0]].join('/')) + .attr('value', date) + .appendTo(tmpl); + + if (date == min_str) + opt.attr('selected', 'selected'); + } + + // Finally inject the populated selector into the DOM and + // wire up an onChange handler to reload the plot. + tmpl.appendTo('#'+week+'-selection') + .change(function() { Plots.determinePlot() }); + } + + } else { + + // The date selection dropdowns are populated, so set ranges + // from the selected values. + + var weeks = ['week1', 'week2']; + for (var i=0, week; week=weeks[i]; i++) { + var opt = $('#'+week+'-selection select')[0]; + var date = opt.options[opt.selectedIndex].value; + ranges[week]['min'] = date_parser(date); + ranges[week]['max'] = new Date(ranges[week]['min'].getTime() + WEEK); + } + + } + + // Assemble the time geometries from the selected time ranges. + this.timeGeometries = { + 'week1': { + 'min': ranges['week1']['min'], + 'max': ranges['week1']['max'], + 'gridColor': '#CC6666', + 'axisLabelsPlacement': 'bottom' + }, + 'week2': { + 'min': ranges['week2']['min'], + 'max': ranges['week2']['max'], + 'gridColor': '#6666CC', + 'axisLabelsPlacement': 'top' + } + }; + + // Both time ranges share the same value geometry + this.valueGeometry = { + 'gridColor': '#000000', + 'axisLabelsPlacement': 'left', + 'min': 0 + }; + + // Construct the plot info structures for each of the overlaid sets. + Plots.newTimeplot(); + Plots.timeplot = Timeplot.create(document.getElementById(Plots.timeplot_id), [ + Timeplot.createPlotInfo({ + 'id': 'week1-plot', + 'dataSource': + new Timeplot.ColumnSource(this.dataSources['count'], 1), + 'timeGeometry': + new Timeplot.DefaultTimeGeometry(this.timeGeometries['week1']), + 'valueGeometry': + new Timeplot.DefaultValueGeometry(this.valueGeometry), + 'showValues': true, + 'dotColor': '#CC6666', + 'dotRadius': 3.0, + 'lineColor': '#CC6666', + 'lineWidth': 3.0, + 'fillColor': false + }), + Timeplot.createPlotInfo({ + 'id': 'week2-plot', + 'dataSource': + new Timeplot.ColumnSource(this.dataSources['count'], 1), + 'timeGeometry': + new Timeplot.DefaultTimeGeometry(this.timeGeometries['week2']), + 'valueGeometry': + new Timeplot.DefaultValueGeometry(this.valueGeometry), + 'showValues': true, + 'dotColor': '#6666CC', + 'dotRadius': 3.0, + 'lineColor': '#6666CC', + 'lineWidth': 3.0, + 'fillColor': false + }) + ]); + + // Finally, queue up a load for the plot data. + Plots.timeplot.loadText( + Plots.currentCSV, + ",", + this.dataSources['count'], + parseFields + ); + + }, addPlot: function(plotName, column, color) { if (plotName in this.plotInfo) @@ -397,4 +574,4 @@ function parseFields(data) { } return data; -}
\ No newline at end of file +} diff --git a/site/app/webroot/services/install.php b/site/app/webroot/services/install.php index 251b790..ba70ab4 100644 --- a/site/app/webroot/services/install.php +++ b/site/app/webroot/services/install.php @@ -60,6 +60,7 @@ */ define('REGEX_MOZILLA', '/^https?:\/\/[^\/]*\.?mozilla\.(com|org)\/?.*/'); define('REGEX_LOCALHOST', '/https?:\/\/[^\/]*\.?localhost.*/'); +define('REGEX_PERSONAS', '/https?:\/\/[^\/]*\.?getpersonas\.com\/?.*/'); // If an add-on's referrers property is set, defaults will not be used unless specified $default_referrers = array('document.referrer.match('.REGEX_MOZILLA.')', @@ -140,8 +141,17 @@ $addons = array( /* Other */ 'personas' => array( 'name' => 'Personas for Firefox', - 'xpi' => 'https://labs.mozilla.com/projects/personas/xpi/personas-latest.xpi', - 'icon' => 'http://labs.mozilla.com/projects/personas/images/personas_32x32.png' + 'xpi' => 'https://addons.mozilla.org/en-US/firefox/downloads/latest/10900', + 'icon' => 'https://addons.mozilla.org/en-US/firefox/images/addon_icon/10900/1236031798', + 'referrers' => array_merge($default_referrers, array( + 'document.referrer.match('.REGEX_PERSONAS.')' + )) + ), + + 'weave' => array( + 'name' => 'Weave', + 'xpi' => 'https://addons.mozilla.org/en-US/firefox/downloads/latest/10868', + 'icon' => 'https://addons.mozilla.org/en-US/firefox/images/addon_icon/10868/1236131155' ) ); |