| @@ -0,0 +1,344 @@ | ||
| /* CHANGELISTS */ | ||
|
|
||
| #changelist { | ||
| position: relative; | ||
| width: 100%; | ||
| } | ||
|
|
||
| #changelist table { | ||
| width: 100%; | ||
| } | ||
|
|
||
| .change-list .hiddenfields { display:none; } | ||
|
|
||
| .change-list .filtered table { | ||
| border-right: none; | ||
| } | ||
|
|
||
| .change-list .filtered { | ||
| min-height: 400px; | ||
| } | ||
|
|
||
| .change-list .filtered .results, .change-list .filtered .paginator, | ||
| .filtered #toolbar, .filtered div.xfull { | ||
| margin-right: 280px; | ||
| width: auto; | ||
| } | ||
|
|
||
| .change-list .filtered table tbody th { | ||
| padding-right: 1em; | ||
| } | ||
|
|
||
| #changelist-form .results { | ||
| overflow-x: auto; | ||
| } | ||
|
|
||
| #changelist .toplinks { | ||
| border-bottom: 1px solid #ddd; | ||
| } | ||
|
|
||
| #changelist .paginator { | ||
| color: #666; | ||
| border-bottom: 1px solid #eee; | ||
| background: #fff; | ||
| overflow: hidden; | ||
| } | ||
|
|
||
| /* CHANGELIST TABLES */ | ||
|
|
||
| #changelist table thead th { | ||
| padding: 0; | ||
| white-space: nowrap; | ||
| vertical-align: middle; | ||
| } | ||
|
|
||
| #changelist table thead th.action-checkbox-column { | ||
| width: 1.5em; | ||
| text-align: center; | ||
| } | ||
|
|
||
| #changelist table tbody td.action-checkbox { | ||
| text-align: center; | ||
| } | ||
|
|
||
| #changelist table tfoot { | ||
| color: #666; | ||
| } | ||
|
|
||
| /* TOOLBAR */ | ||
|
|
||
| #changelist #toolbar { | ||
| padding: 8px 10px; | ||
| margin-bottom: 15px; | ||
| border-top: 1px solid #eee; | ||
| border-bottom: 1px solid #eee; | ||
| background: #f8f8f8; | ||
| color: #666; | ||
| } | ||
|
|
||
| #changelist #toolbar form input { | ||
| border-radius: 4px; | ||
| font-size: 14px; | ||
| padding: 5px; | ||
| color: #333; | ||
| } | ||
|
|
||
| #changelist #toolbar form #searchbar { | ||
| height: 19px; | ||
| border: 1px solid #ccc; | ||
| padding: 2px 5px; | ||
| margin: 0; | ||
| vertical-align: top; | ||
| font-size: 13px; | ||
| } | ||
|
|
||
| #changelist #toolbar form #searchbar:focus { | ||
| border-color: #999; | ||
| } | ||
|
|
||
| #changelist #toolbar form input[type="submit"] { | ||
| border: 1px solid #ccc; | ||
| padding: 2px 10px; | ||
| margin: 0; | ||
| vertical-align: middle; | ||
| background: #fff; | ||
| box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; | ||
| cursor: pointer; | ||
| color: #333; | ||
| } | ||
|
|
||
| #changelist #toolbar form input[type="submit"]:focus, | ||
| #changelist #toolbar form input[type="submit"]:hover { | ||
| border-color: #999; | ||
| } | ||
|
|
||
| #changelist #changelist-search img { | ||
| vertical-align: middle; | ||
| margin-right: 4px; | ||
| } | ||
|
|
||
| /* FILTER COLUMN */ | ||
|
|
||
| #changelist-filter { | ||
| position: absolute; | ||
| top: 0; | ||
| right: 0; | ||
| z-index: 1000; | ||
| width: 240px; | ||
| background: #f8f8f8; | ||
| border-left: none; | ||
| margin: 0; | ||
| } | ||
|
|
||
| #changelist-filter h2 { | ||
| font-size: 14px; | ||
| text-transform: uppercase; | ||
| letter-spacing: 0.5px; | ||
| padding: 5px 15px; | ||
| margin-bottom: 12px; | ||
| border-bottom: none; | ||
| } | ||
|
|
||
| #changelist-filter h3 { | ||
| font-weight: 400; | ||
| font-size: 14px; | ||
| padding: 0 15px; | ||
| margin-bottom: 10px; | ||
| } | ||
|
|
||
| #changelist-filter ul { | ||
| margin: 5px 0; | ||
| padding: 0 15px 15px; | ||
| border-bottom: 1px solid #eaeaea; | ||
| } | ||
|
|
||
| #changelist-filter ul:last-child { | ||
| border-bottom: none; | ||
| padding-bottom: none; | ||
| } | ||
|
|
||
| #changelist-filter li { | ||
| list-style-type: none; | ||
| margin-left: 0; | ||
| padding-left: 0; | ||
| } | ||
|
|
||
| #changelist-filter a { | ||
| display: block; | ||
| color: #999; | ||
| text-overflow: ellipsis; | ||
| overflow-x: hidden; | ||
| } | ||
|
|
||
| #changelist-filter li.selected { | ||
| border-left: 5px solid #eaeaea; | ||
| padding-left: 10px; | ||
| margin-left: -15px; | ||
| } | ||
|
|
||
| #changelist-filter li.selected a { | ||
| color: #5b80b2; | ||
| } | ||
|
|
||
| #changelist-filter a:focus, #changelist-filter a:hover, | ||
| #changelist-filter li.selected a:focus, | ||
| #changelist-filter li.selected a:hover { | ||
| color: #036; | ||
| } | ||
|
|
||
| /* DATE DRILLDOWN */ | ||
|
|
||
| .change-list ul.toplinks { | ||
| display: block; | ||
| float: left; | ||
| padding: 0; | ||
| margin: 0; | ||
| width: 100%; | ||
| } | ||
|
|
||
| .change-list ul.toplinks li { | ||
| padding: 3px 6px; | ||
| font-weight: bold; | ||
| list-style-type: none; | ||
| display: inline-block; | ||
| } | ||
|
|
||
| .change-list ul.toplinks .date-back a { | ||
| color: #999; | ||
| } | ||
|
|
||
| .change-list ul.toplinks .date-back a:focus, | ||
| .change-list ul.toplinks .date-back a:hover { | ||
| color: #036; | ||
| } | ||
|
|
||
| /* PAGINATOR */ | ||
|
|
||
| .paginator { | ||
| font-size: 13px; | ||
| padding-top: 10px; | ||
| padding-bottom: 10px; | ||
| line-height: 22px; | ||
| margin: 0; | ||
| border-top: 1px solid #ddd; | ||
| } | ||
|
|
||
| .paginator a:link, .paginator a:visited { | ||
| padding: 2px 6px; | ||
| background: #79aec8; | ||
| text-decoration: none; | ||
| color: #fff; | ||
| } | ||
|
|
||
| .paginator a.showall { | ||
| padding: 0; | ||
| border: none; | ||
| background: none; | ||
| color: #5b80b2; | ||
| } | ||
|
|
||
| .paginator a.showall:focus, .paginator a.showall:hover { | ||
| background: none; | ||
| color: #036; | ||
| } | ||
|
|
||
| .paginator .end { | ||
| margin-right: 6px; | ||
| } | ||
|
|
||
| .paginator .this-page { | ||
| padding: 2px 6px; | ||
| font-weight: bold; | ||
| font-size: 13px; | ||
| vertical-align: top; | ||
| } | ||
|
|
||
| .paginator a:focus, .paginator a:hover { | ||
| color: white; | ||
| background: #036; | ||
| } | ||
|
|
||
| /* ACTIONS */ | ||
|
|
||
| .filtered .actions { | ||
| margin-right: 280px; | ||
| border-right: none; | ||
| } | ||
|
|
||
| #changelist table input { | ||
| margin: 0; | ||
| vertical-align: baseline; | ||
| } | ||
|
|
||
| #changelist table tbody tr.selected { | ||
| background-color: #FFFFCC; | ||
| } | ||
|
|
||
| #changelist .actions { | ||
| padding: 10px; | ||
| background: #fff; | ||
| border-top: none; | ||
| border-bottom: none; | ||
| line-height: 24px; | ||
| color: #999; | ||
| } | ||
|
|
||
| #changelist .actions.selected { | ||
| background: #fffccf; | ||
| border-top: 1px solid #fffee8; | ||
| border-bottom: 1px solid #edecd6; | ||
| } | ||
|
|
||
| #changelist .actions span.all, | ||
| #changelist .actions span.action-counter, | ||
| #changelist .actions span.clear, | ||
| #changelist .actions span.question { | ||
| font-size: 13px; | ||
| margin: 0 0.5em; | ||
| display: none; | ||
| } | ||
|
|
||
| #changelist .actions:last-child { | ||
| border-bottom: none; | ||
| } | ||
|
|
||
| #changelist .actions select { | ||
| vertical-align: top; | ||
| height: 24px; | ||
| background: none; | ||
| color: #000; | ||
| border: 1px solid #ccc; | ||
| border-radius: 4px; | ||
| font-size: 14px; | ||
| padding: 0 0 0 4px; | ||
| margin: 0; | ||
| margin-left: 10px; | ||
| } | ||
|
|
||
| #changelist .actions select:focus { | ||
| border-color: #999; | ||
| } | ||
|
|
||
| #changelist .actions label { | ||
| display: inline-block; | ||
| vertical-align: middle; | ||
| font-size: 13px; | ||
| } | ||
|
|
||
| #changelist .actions .button { | ||
| font-size: 13px; | ||
| border: 1px solid #ccc; | ||
| border-radius: 4px; | ||
| background: #fff; | ||
| box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; | ||
| cursor: pointer; | ||
| height: 24px; | ||
| line-height: 1; | ||
| padding: 4px 8px; | ||
| margin: 0; | ||
| color: #333; | ||
| } | ||
|
|
||
| #changelist .actions .button:focus, #changelist .actions .button:hover { | ||
| border-color: #999; | ||
| } |
| @@ -0,0 +1,27 @@ | ||
| /* DASHBOARD */ | ||
|
|
||
| .dashboard .module table th { | ||
| width: 100%; | ||
| } | ||
|
|
||
| .dashboard .module table td { | ||
| white-space: nowrap; | ||
| } | ||
|
|
||
| .dashboard .module table td a { | ||
| display: block; | ||
| padding-right: .6em; | ||
| } | ||
|
|
||
| /* RECENT ACTIONS MODULE */ | ||
|
|
||
| .module ul.actionlist { | ||
| margin-left: 0; | ||
| } | ||
|
|
||
| ul.actionlist li { | ||
| list-style-type: none; | ||
| overflow: hidden; | ||
| text-overflow: ellipsis; | ||
| -o-text-overflow: ellipsis; | ||
| } |
| @@ -0,0 +1,20 @@ | ||
| @font-face { | ||
| font-family: 'Roboto'; | ||
| src: url('../fonts/Roboto-Bold-webfont.woff'); | ||
| font-weight: 700; | ||
| font-style: normal; | ||
| } | ||
|
|
||
| @font-face { | ||
| font-family: 'Roboto'; | ||
| src: url('../fonts/Roboto-Regular-webfont.woff'); | ||
| font-weight: 400; | ||
| font-style: normal; | ||
| } | ||
|
|
||
| @font-face { | ||
| font-family: 'Roboto'; | ||
| src: url('../fonts/Roboto-Light-webfont.woff'); | ||
| font-weight: 300; | ||
| font-style: normal; | ||
| } |
| @@ -0,0 +1,78 @@ | ||
| /* LOGIN FORM */ | ||
|
|
||
| body.login { | ||
| background: #f8f8f8; | ||
| } | ||
|
|
||
| .login #header { | ||
| height: auto; | ||
| padding: 5px 16px; | ||
| } | ||
|
|
||
| .login #header h1 { | ||
| font-size: 18px; | ||
| } | ||
|
|
||
| .login #header h1 a { | ||
| color: #fff; | ||
| } | ||
|
|
||
| .login #content { | ||
| padding: 20px 20px 0; | ||
| } | ||
|
|
||
| .login #container { | ||
| background: #fff; | ||
| border: 1px solid #eaeaea; | ||
| border-radius: 4px; | ||
| overflow: hidden; | ||
| width: 28em; | ||
| min-width: 300px; | ||
| margin: 100px auto; | ||
| } | ||
|
|
||
| .login #content-main { | ||
| width: 100%; | ||
| } | ||
|
|
||
| .login .form-row { | ||
| padding: 4px 0; | ||
| float: left; | ||
| width: 100%; | ||
| border-bottom: none; | ||
| } | ||
|
|
||
| .login .form-row label { | ||
| padding-right: 0.5em; | ||
| line-height: 2em; | ||
| font-size: 1em; | ||
| clear: both; | ||
| color: #333; | ||
| } | ||
|
|
||
| .login .form-row #id_username, .login .form-row #id_password { | ||
| clear: both; | ||
| padding: 8px; | ||
| width: 100%; | ||
| -webkit-box-sizing: border-box; | ||
| -moz-box-sizing: border-box; | ||
| box-sizing: border-box; | ||
| } | ||
|
|
||
| .login span.help { | ||
| font-size: 10px; | ||
| display: block; | ||
| } | ||
|
|
||
| .login .submit-row { | ||
| clear: both; | ||
| padding: 1em 0 0 9.4em; | ||
| margin: 0; | ||
| border: none; | ||
| background: none; | ||
| text-align: left; | ||
| } | ||
|
|
||
| .login .password-reset-link { | ||
| text-align: center; | ||
| } |
| @@ -0,0 +1,264 @@ | ||
| body { | ||
| direction: rtl; | ||
| } | ||
|
|
||
| /* LOGIN */ | ||
|
|
||
| .login .form-row { | ||
| float: right; | ||
| } | ||
|
|
||
| .login .form-row label { | ||
| float: right; | ||
| padding-left: 0.5em; | ||
| padding-right: 0; | ||
| text-align: left; | ||
| } | ||
|
|
||
| .login .submit-row { | ||
| clear: both; | ||
| padding: 1em 9.4em 0 0; | ||
| } | ||
|
|
||
| /* GLOBAL */ | ||
|
|
||
| th { | ||
| text-align: right; | ||
| } | ||
|
|
||
| .module h2, .module caption { | ||
| text-align: right; | ||
| } | ||
|
|
||
| .module ul, .module ol { | ||
| margin-left: 0; | ||
| margin-right: 1.5em; | ||
| } | ||
|
|
||
| .addlink, .changelink { | ||
| padding-left: 0; | ||
| padding-right: 16px; | ||
| background-position: 100% 1px; | ||
| } | ||
|
|
||
| .deletelink { | ||
| padding-left: 0; | ||
| padding-right: 16px; | ||
| background-position: 100% 1px; | ||
| } | ||
|
|
||
| .object-tools { | ||
| float: left; | ||
| } | ||
|
|
||
| thead th:first-child, | ||
| tfoot td:first-child { | ||
| border-left: none; | ||
| } | ||
|
|
||
| /* LAYOUT */ | ||
|
|
||
| #user-tools { | ||
| right: auto; | ||
| left: 0; | ||
| text-align: left; | ||
| } | ||
|
|
||
| div.breadcrumbs { | ||
| text-align: right; | ||
| } | ||
|
|
||
| #content-main { | ||
| float: right; | ||
| } | ||
|
|
||
| #content-related { | ||
| float: left; | ||
| margin-left: -300px; | ||
| margin-right: auto; | ||
| } | ||
|
|
||
| .colMS { | ||
| margin-left: 300px; | ||
| margin-right: 0; | ||
| } | ||
|
|
||
| /* SORTABLE TABLES */ | ||
|
|
||
| table thead th.sorted .sortoptions { | ||
| float: left; | ||
| } | ||
|
|
||
| thead th.sorted .text { | ||
| padding-right: 0; | ||
| padding-left: 42px; | ||
| } | ||
|
|
||
| /* dashboard styles */ | ||
|
|
||
| .dashboard .module table td a { | ||
| padding-left: .6em; | ||
| padding-right: 16px; | ||
| } | ||
|
|
||
| /* changelists styles */ | ||
|
|
||
| .change-list .filtered table { | ||
| border-left: none; | ||
| border-right: 0px none; | ||
| } | ||
|
|
||
| #changelist-filter { | ||
| right: auto; | ||
| left: 0; | ||
| border-left: none; | ||
| border-right: none; | ||
| } | ||
|
|
||
| .change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { | ||
| margin-right: 0; | ||
| margin-left: 280px; | ||
| } | ||
|
|
||
| #changelist-filter li.selected { | ||
| border-left: none; | ||
| padding-left: 10px; | ||
| margin-left: 0; | ||
| border-right: 5px solid #eaeaea; | ||
| padding-right: 10px; | ||
| margin-right: -15px; | ||
| } | ||
|
|
||
| .filtered .actions { | ||
| margin-left: 280px; | ||
| margin-right: 0; | ||
| } | ||
|
|
||
| #changelist table tbody td:first-child, #changelist table tbody th:first-child { | ||
| border-right: none; | ||
| border-left: none; | ||
| } | ||
|
|
||
| /* FORMS */ | ||
|
|
||
| .aligned label { | ||
| padding: 0 0 3px 1em; | ||
| float: right; | ||
| } | ||
|
|
||
| .submit-row { | ||
| text-align: left | ||
| } | ||
|
|
||
| .submit-row p.deletelink-box { | ||
| float: right; | ||
| } | ||
|
|
||
| .submit-row input.default { | ||
| margin-left: 0; | ||
| } | ||
|
|
||
| .vDateField, .vTimeField { | ||
| margin-left: 2px; | ||
| } | ||
|
|
||
| .aligned .form-row input { | ||
| margin-left: 5px; | ||
| } | ||
|
|
||
| form .aligned p.help, form .aligned div.help { | ||
| clear: right; | ||
| } | ||
|
|
||
| form ul.inline li { | ||
| float: right; | ||
| padding-right: 0; | ||
| padding-left: 7px; | ||
| } | ||
|
|
||
| input[type=submit].default, .submit-row input.default { | ||
| float: left; | ||
| } | ||
|
|
||
| fieldset .field-box { | ||
| float: right; | ||
| margin-left: 20px; | ||
| margin-right: 0; | ||
| } | ||
|
|
||
| .errorlist li { | ||
| background-position: 100% 12px; | ||
| padding: 0; | ||
| } | ||
|
|
||
| .errornote { | ||
| background-position: 100% 12px; | ||
| padding: 10px 12px; | ||
| } | ||
|
|
||
| /* WIDGETS */ | ||
|
|
||
| .calendarnav-previous { | ||
| top: 0; | ||
| left: auto; | ||
| right: 10px; | ||
| } | ||
|
|
||
| .calendarnav-next { | ||
| top: 0; | ||
| right: auto; | ||
| left: 10px; | ||
| } | ||
|
|
||
| .calendar caption, .calendarbox h2 { | ||
| text-align: center; | ||
| } | ||
|
|
||
| .selector { | ||
| float: right; | ||
| } | ||
|
|
||
| .selector .selector-filter { | ||
| text-align: right; | ||
| } | ||
|
|
||
| .inline-deletelink { | ||
| float: left; | ||
| } | ||
|
|
||
| form .form-row p.datetime { | ||
| overflow: hidden; | ||
| } | ||
|
|
||
| .related-widget-wrapper { | ||
| float: right; | ||
| } | ||
|
|
||
| /* MISC */ | ||
|
|
||
| .inline-related h2, .inline-group h2 { | ||
| text-align: right | ||
| } | ||
|
|
||
| .inline-related h3 span.delete { | ||
| padding-right: 20px; | ||
| padding-left: inherit; | ||
| left: 10px; | ||
| right: inherit; | ||
| float:left; | ||
| } | ||
|
|
||
| .inline-related h3 span.delete label { | ||
| margin-left: inherit; | ||
| margin-right: 2px; | ||
| } | ||
|
|
||
| /* IE7 specific bug fixes */ | ||
|
|
||
| div.colM { | ||
| position: relative; | ||
| } | ||
|
|
||
| .submit-row input { | ||
| float: left; | ||
| } |
| @@ -0,0 +1,202 @@ | ||
|
|
||
| Apache License | ||
| Version 2.0, January 2004 | ||
| http://www.apache.org/licenses/ | ||
|
|
||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||
|
|
||
| 1. Definitions. | ||
|
|
||
| "License" shall mean the terms and conditions for use, reproduction, | ||
| and distribution as defined by Sections 1 through 9 of this document. | ||
|
|
||
| "Licensor" shall mean the copyright owner or entity authorized by | ||
| the copyright owner that is granting the License. | ||
|
|
||
| "Legal Entity" shall mean the union of the acting entity and all | ||
| other entities that control, are controlled by, or are under common | ||
| control with that entity. For the purposes of this definition, | ||
| "control" means (i) the power, direct or indirect, to cause the | ||
| direction or management of such entity, whether by contract or | ||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||
| outstanding shares, or (iii) beneficial ownership of such entity. | ||
|
|
||
| "You" (or "Your") shall mean an individual or Legal Entity | ||
| exercising permissions granted by this License. | ||
|
|
||
| "Source" form shall mean the preferred form for making modifications, | ||
| including but not limited to software source code, documentation | ||
| source, and configuration files. | ||
|
|
||
| "Object" form shall mean any form resulting from mechanical | ||
| transformation or translation of a Source form, including but | ||
| not limited to compiled object code, generated documentation, | ||
| and conversions to other media types. | ||
|
|
||
| "Work" shall mean the work of authorship, whether in Source or | ||
| Object form, made available under the License, as indicated by a | ||
| copyright notice that is included in or attached to the work | ||
| (an example is provided in the Appendix below). | ||
|
|
||
| "Derivative Works" shall mean any work, whether in Source or Object | ||
| form, that is based on (or derived from) the Work and for which the | ||
| editorial revisions, annotations, elaborations, or other modifications | ||
| represent, as a whole, an original work of authorship. For the purposes | ||
| of this License, Derivative Works shall not include works that remain | ||
| separable from, or merely link (or bind by name) to the interfaces of, | ||
| the Work and Derivative Works thereof. | ||
|
|
||
| "Contribution" shall mean any work of authorship, including | ||
| the original version of the Work and any modifications or additions | ||
| to that Work or Derivative Works thereof, that is intentionally | ||
| submitted to Licensor for inclusion in the Work by the copyright owner | ||
| or by an individual or Legal Entity authorized to submit on behalf of | ||
| the copyright owner. For the purposes of this definition, "submitted" | ||
| means any form of electronic, verbal, or written communication sent | ||
| to the Licensor or its representatives, including but not limited to | ||
| communication on electronic mailing lists, source code control systems, | ||
| and issue tracking systems that are managed by, or on behalf of, the | ||
| Licensor for the purpose of discussing and improving the Work, but | ||
| excluding communication that is conspicuously marked or otherwise | ||
| designated in writing by the copyright owner as "Not a Contribution." | ||
|
|
||
| "Contributor" shall mean Licensor and any individual or Legal Entity | ||
| on behalf of whom a Contribution has been received by Licensor and | ||
| subsequently incorporated within the Work. | ||
|
|
||
| 2. Grant of Copyright License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| copyright license to reproduce, prepare Derivative Works of, | ||
| publicly display, publicly perform, sublicense, and distribute the | ||
| Work and such Derivative Works in Source or Object form. | ||
|
|
||
| 3. Grant of Patent License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| (except as stated in this section) patent license to make, have made, | ||
| use, offer to sell, sell, import, and otherwise transfer the Work, | ||
| where such license applies only to those patent claims licensable | ||
| by such Contributor that are necessarily infringed by their | ||
| Contribution(s) alone or by combination of their Contribution(s) | ||
| with the Work to which such Contribution(s) was submitted. If You | ||
| institute patent litigation against any entity (including a | ||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | ||
| or a Contribution incorporated within the Work constitutes direct | ||
| or contributory patent infringement, then any patent licenses | ||
| granted to You under this License for that Work shall terminate | ||
| as of the date such litigation is filed. | ||
|
|
||
| 4. Redistribution. You may reproduce and distribute copies of the | ||
| Work or Derivative Works thereof in any medium, with or without | ||
| modifications, and in Source or Object form, provided that You | ||
| meet the following conditions: | ||
|
|
||
| (a) You must give any other recipients of the Work or | ||
| Derivative Works a copy of this License; and | ||
|
|
||
| (b) You must cause any modified files to carry prominent notices | ||
| stating that You changed the files; and | ||
|
|
||
| (c) You must retain, in the Source form of any Derivative Works | ||
| that You distribute, all copyright, patent, trademark, and | ||
| attribution notices from the Source form of the Work, | ||
| excluding those notices that do not pertain to any part of | ||
| the Derivative Works; and | ||
|
|
||
| (d) If the Work includes a "NOTICE" text file as part of its | ||
| distribution, then any Derivative Works that You distribute must | ||
| include a readable copy of the attribution notices contained | ||
| within such NOTICE file, excluding those notices that do not | ||
| pertain to any part of the Derivative Works, in at least one | ||
| of the following places: within a NOTICE text file distributed | ||
| as part of the Derivative Works; within the Source form or | ||
| documentation, if provided along with the Derivative Works; or, | ||
| within a display generated by the Derivative Works, if and | ||
| wherever such third-party notices normally appear. The contents | ||
| of the NOTICE file are for informational purposes only and | ||
| do not modify the License. You may add Your own attribution | ||
| notices within Derivative Works that You distribute, alongside | ||
| or as an addendum to the NOTICE text from the Work, provided | ||
| that such additional attribution notices cannot be construed | ||
| as modifying the License. | ||
|
|
||
| You may add Your own copyright statement to Your modifications and | ||
| may provide additional or different license terms and conditions | ||
| for use, reproduction, or distribution of Your modifications, or | ||
| for any such Derivative Works as a whole, provided Your use, | ||
| reproduction, and distribution of the Work otherwise complies with | ||
| the conditions stated in this License. | ||
|
|
||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | ||
| any Contribution intentionally submitted for inclusion in the Work | ||
| by You to the Licensor shall be under the terms and conditions of | ||
| this License, without any additional terms or conditions. | ||
| Notwithstanding the above, nothing herein shall supersede or modify | ||
| the terms of any separate license agreement you may have executed | ||
| with Licensor regarding such Contributions. | ||
|
|
||
| 6. Trademarks. This License does not grant permission to use the trade | ||
| names, trademarks, service marks, or product names of the Licensor, | ||
| except as required for reasonable and customary use in describing the | ||
| origin of the Work and reproducing the content of the NOTICE file. | ||
|
|
||
| 7. Disclaimer of Warranty. Unless required by applicable law or | ||
| agreed to in writing, Licensor provides the Work (and each | ||
| Contributor provides its Contributions) on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
| implied, including, without limitation, any warranties or conditions | ||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||
| PARTICULAR PURPOSE. You are solely responsible for determining the | ||
| appropriateness of using or redistributing the Work and assume any | ||
| risks associated with Your exercise of permissions under this License. | ||
|
|
||
| 8. Limitation of Liability. In no event and under no legal theory, | ||
| whether in tort (including negligence), contract, or otherwise, | ||
| unless required by applicable law (such as deliberate and grossly | ||
| negligent acts) or agreed to in writing, shall any Contributor be | ||
| liable to You for damages, including any direct, indirect, special, | ||
| incidental, or consequential damages of any character arising as a | ||
| result of this License or out of the use or inability to use the | ||
| Work (including but not limited to damages for loss of goodwill, | ||
| work stoppage, computer failure or malfunction, or any and all | ||
| other commercial damages or losses), even if such Contributor | ||
| has been advised of the possibility of such damages. | ||
|
|
||
| 9. Accepting Warranty or Additional Liability. While redistributing | ||
| the Work or Derivative Works thereof, You may choose to offer, | ||
| and charge a fee for, acceptance of support, warranty, indemnity, | ||
| or other liability obligations and/or rights consistent with this | ||
| License. However, in accepting such obligations, You may act only | ||
| on Your own behalf and on Your sole responsibility, not on behalf | ||
| of any other Contributor, and only if You agree to indemnify, | ||
| defend, and hold each Contributor harmless for any liability | ||
| incurred by, or claims asserted against, such Contributor by reason | ||
| of your accepting any such warranty or additional liability. | ||
|
|
||
| END OF TERMS AND CONDITIONS | ||
|
|
||
| APPENDIX: How to apply the Apache License to your work. | ||
|
|
||
| To apply the Apache License to your work, attach the following | ||
| boilerplate notice, with the fields enclosed by brackets "[]" | ||
| replaced with your own identifying information. (Don't include | ||
| the brackets!) The text should be enclosed in the appropriate | ||
| comment syntax for the file format. We also recommend that a | ||
| file or class name and description of purpose be included on the | ||
| same "printed page" as the copyright notice for easier | ||
| identification within third-party archives. | ||
|
|
||
| Copyright [yyyy] [name of copyright owner] | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. |
| @@ -0,0 +1,2 @@ | ||
| Roboto webfont source: https://www.google.com/fonts/specimen/Roboto | ||
| Weights used in this project: Light (300), Regular (400), Bold (700) |
| @@ -0,0 +1,20 @@ | ||
| The MIT License (MIT) | ||
|
|
||
| Copyright (c) 2014 Code Charm Ltd | ||
|
|
||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| this software and associated documentation files (the "Software"), to deal in | ||
| the Software without restriction, including without limitation the rights to | ||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||
| subject to the following conditions: | ||
|
|
||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| @@ -0,0 +1,7 @@ | ||
| All icons are taken from Font Awesome (http://fontawesome.io/) project. | ||
| The Font Awesome font is licensed under the SIL OFL 1.1: | ||
| - http://scripts.sil.org/OFL | ||
|
|
||
| SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG | ||
| Font-Awesome-SVG-PNG is licensed under the MIT license (see file license | ||
| in current folder). |
| @@ -0,0 +1,144 @@ | ||
| (function($) { | ||
| 'use strict'; | ||
| var SelectBox = { | ||
| cache: {}, | ||
| init: function(id) { | ||
| var box = document.getElementById(id); | ||
| var node; | ||
| SelectBox.cache[id] = []; | ||
| var cache = SelectBox.cache[id]; | ||
| var boxOptions = box.options; | ||
| var boxOptionsLength = boxOptions.length; | ||
| for (var i = 0, j = boxOptionsLength; i < j; i++) { | ||
| node = boxOptions[i]; | ||
| cache.push({value: node.value, text: node.text, displayed: 1}); | ||
| } | ||
| }, | ||
| redisplay: function(id) { | ||
| // Repopulate HTML select box from cache | ||
| var box = document.getElementById(id); | ||
| var node; | ||
| $(box).empty(); // clear all options | ||
| var new_options = box.outerHTML.slice(0, -9); // grab just the opening tag | ||
| var cache = SelectBox.cache[id]; | ||
| for (var i = 0, j = cache.length; i < j; i++) { | ||
| node = cache[i]; | ||
| if (node.displayed) { | ||
| var new_option = new Option(node.text, node.value, false, false); | ||
| // Shows a tooltip when hovering over the option | ||
| new_option.setAttribute("title", node.text); | ||
| new_options += new_option.outerHTML; | ||
| } | ||
| } | ||
| new_options += '</select>'; | ||
| box.outerHTML = new_options; | ||
| }, | ||
| filter: function(id, text) { | ||
| // Redisplay the HTML select box, displaying only the choices containing ALL | ||
| // the words in text. (It's an AND search.) | ||
| var tokens = text.toLowerCase().split(/\s+/); | ||
| var node, token; | ||
| var cache = SelectBox.cache[id]; | ||
| for (var i = 0, j = cache.length; i < j; i++) { | ||
| node = cache[i]; | ||
| node.displayed = 1; | ||
| var node_text = node.text.toLowerCase(); | ||
| var numTokens = tokens.length; | ||
| for (var k = 0; k < numTokens; k++) { | ||
| token = tokens[k]; | ||
| if (node_text.indexOf(token) === -1) { | ||
| node.displayed = 0; | ||
| break; // Once the first token isn't found we're done | ||
| } | ||
| } | ||
| } | ||
| SelectBox.redisplay(id); | ||
| }, | ||
| delete_from_cache: function(id, value) { | ||
| var node, delete_index = null; | ||
| var cache = SelectBox.cache[id]; | ||
| for (var i = 0, j = cache.length; i < j; i++) { | ||
| node = cache[i]; | ||
| if (node.value === value) { | ||
| delete_index = i; | ||
| break; | ||
| } | ||
| } | ||
| cache.splice(delete_index, 1); | ||
| }, | ||
| add_to_cache: function(id, option) { | ||
| SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); | ||
| }, | ||
| cache_contains: function(id, value) { | ||
| // Check if an item is contained in the cache | ||
| var node; | ||
| var cache = SelectBox.cache[id]; | ||
| for (var i = 0, j = cache.length; i < j; i++) { | ||
| node = cache[i]; | ||
| if (node.value === value) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| }, | ||
| move: function(from, to) { | ||
| var from_box = document.getElementById(from); | ||
| var option; | ||
| var boxOptions = from_box.options; | ||
| var boxOptionsLength = boxOptions.length; | ||
| for (var i = 0, j = boxOptionsLength; i < j; i++) { | ||
| option = boxOptions[i]; | ||
| var option_value = option.value; | ||
| if (option.selected && SelectBox.cache_contains(from, option_value)) { | ||
| SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); | ||
| SelectBox.delete_from_cache(from, option_value); | ||
| } | ||
| } | ||
| SelectBox.redisplay(from); | ||
| SelectBox.redisplay(to); | ||
| }, | ||
| move_all: function(from, to) { | ||
| var from_box = document.getElementById(from); | ||
| var option; | ||
| var boxOptions = from_box.options; | ||
| var boxOptionsLength = boxOptions.length; | ||
| for (var i = 0, j = boxOptionsLength; i < j; i++) { | ||
| option = boxOptions[i]; | ||
| var option_value = option.value; | ||
| if (SelectBox.cache_contains(from, option_value)) { | ||
| SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); | ||
| SelectBox.delete_from_cache(from, option_value); | ||
| } | ||
| } | ||
| SelectBox.redisplay(from); | ||
| SelectBox.redisplay(to); | ||
| }, | ||
| sort: function(id) { | ||
| SelectBox.cache[id].sort(function(a, b) { | ||
| a = a.text.toLowerCase(); | ||
| b = b.text.toLowerCase(); | ||
| try { | ||
| if (a > b) { | ||
| return 1; | ||
| } | ||
| if (a < b) { | ||
| return -1; | ||
| } | ||
| } | ||
| catch (e) { | ||
| // silently fail on IE 'unknown' exception | ||
| } | ||
| return 0; | ||
| } ); | ||
| }, | ||
| select_all: function(id) { | ||
| var box = document.getElementById(id); | ||
| var boxOptions = box.options; | ||
| var boxOptionsLength = boxOptions.length; | ||
| for (var i = 0; i < boxOptionsLength; i++) { | ||
| boxOptions[i].selected = 'selected'; | ||
| } | ||
| } | ||
| }; | ||
| window.SelectBox = SelectBox; | ||
| })(django.jQuery); |
| @@ -0,0 +1,236 @@ | ||
| /*global SelectBox, addEvent, gettext, interpolate, quickElement, SelectFilter*/ | ||
| /* | ||
| SelectFilter2 - Turns a multiple-select box into a filter interface. | ||
| Requires jQuery, core.js, and SelectBox.js. | ||
| */ | ||
| (function($) { | ||
| 'use strict'; | ||
| function findForm(node) { | ||
| // returns the node of the form containing the given node | ||
| if (node.tagName.toLowerCase() !== 'form') { | ||
| return findForm(node.parentNode); | ||
| } | ||
| return node; | ||
| } | ||
|
|
||
| window.SelectFilter = { | ||
| init: function(field_id, field_name, is_stacked) { | ||
| if (field_id.match(/__prefix__/)) { | ||
| // Don't initialize on empty forms. | ||
| return; | ||
| } | ||
| var from_box = document.getElementById(field_id); | ||
| from_box.id += '_from'; // change its ID | ||
| from_box.className = 'filtered'; | ||
|
|
||
| var ps = from_box.parentNode.getElementsByTagName('p'); | ||
| for (var i = 0; i < ps.length; i++) { | ||
| if (ps[i].className.indexOf("info") !== -1) { | ||
| // Remove <p class="info">, because it just gets in the way. | ||
| from_box.parentNode.removeChild(ps[i]); | ||
| } else if (ps[i].className.indexOf("help") !== -1) { | ||
| // Move help text up to the top so it isn't below the select | ||
| // boxes or wrapped off on the side to the right of the add | ||
| // button: | ||
| from_box.parentNode.insertBefore(ps[i], from_box.parentNode.firstChild); | ||
| } | ||
| } | ||
|
|
||
| // <div class="selector"> or <div class="selector stacked"> | ||
| var selector_div = quickElement('div', from_box.parentNode); | ||
| selector_div.className = is_stacked ? 'selector stacked' : 'selector'; | ||
|
|
||
| // <div class="selector-available"> | ||
| var selector_available = quickElement('div', selector_div); | ||
| selector_available.className = 'selector-available'; | ||
| var title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name])); | ||
| quickElement( | ||
| 'span', title_available, '', | ||
| 'class', 'help help-tooltip help-icon', | ||
| 'title', interpolate( | ||
| gettext( | ||
| 'This is the list of available %s. You may choose some by ' + | ||
| 'selecting them in the box below and then clicking the ' + | ||
| '"Choose" arrow between the two boxes.' | ||
| ), | ||
| [field_name] | ||
| ) | ||
| ); | ||
|
|
||
| var filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter'); | ||
| filter_p.className = 'selector-filter'; | ||
|
|
||
| var search_filter_label = quickElement('label', filter_p, '', 'for', field_id + '_input'); | ||
|
|
||
| quickElement( | ||
| 'span', search_filter_label, '', | ||
| 'class', 'help-tooltip search-label-icon', | ||
| 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name]) | ||
| ); | ||
|
|
||
| filter_p.appendChild(document.createTextNode(' ')); | ||
|
|
||
| var filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext("Filter")); | ||
| filter_input.id = field_id + '_input'; | ||
|
|
||
| selector_available.appendChild(from_box); | ||
| var choose_all = quickElement('a', selector_available, gettext('Choose all'), 'title', interpolate(gettext('Click to choose all %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_add_all_link'); | ||
| choose_all.className = 'selector-chooseall'; | ||
|
|
||
| // <ul class="selector-chooser"> | ||
| var selector_chooser = quickElement('ul', selector_div); | ||
| selector_chooser.className = 'selector-chooser'; | ||
| var add_link = quickElement('a', quickElement('li', selector_chooser), gettext('Choose'), 'title', gettext('Choose'), 'href', '#', 'id', field_id + '_add_link'); | ||
| add_link.className = 'selector-add'; | ||
| var remove_link = quickElement('a', quickElement('li', selector_chooser), gettext('Remove'), 'title', gettext('Remove'), 'href', '#', 'id', field_id + '_remove_link'); | ||
| remove_link.className = 'selector-remove'; | ||
|
|
||
| // <div class="selector-chosen"> | ||
| var selector_chosen = quickElement('div', selector_div); | ||
| selector_chosen.className = 'selector-chosen'; | ||
| var title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name])); | ||
| quickElement( | ||
| 'span', title_chosen, '', | ||
| 'class', 'help help-tooltip help-icon', | ||
| 'title', interpolate( | ||
| gettext( | ||
| 'This is the list of chosen %s. You may remove some by ' + | ||
| 'selecting them in the box below and then clicking the ' + | ||
| '"Remove" arrow between the two boxes.' | ||
| ), | ||
| [field_name] | ||
| ) | ||
| ); | ||
|
|
||
| var to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', 'multiple', 'size', from_box.size, 'name', from_box.getAttribute('name')); | ||
| to_box.className = 'filtered'; | ||
| var clear_all = quickElement('a', selector_chosen, gettext('Remove all'), 'title', interpolate(gettext('Click to remove all chosen %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_remove_all_link'); | ||
| clear_all.className = 'selector-clearall'; | ||
|
|
||
| from_box.setAttribute('name', from_box.getAttribute('name') + '_old'); | ||
|
|
||
| // Set up the JavaScript event handlers for the select box filter interface | ||
| var move_selection = function(e, elem, move_func, from, to) { | ||
| if (elem.className.indexOf('active') !== -1) { | ||
| move_func(from, to); | ||
| SelectFilter.refresh_icons(field_id); | ||
| } | ||
| e.preventDefault(); | ||
| }; | ||
| addEvent(choose_all, 'click', function(e) { move_selection(e, this, SelectBox.move_all, field_id + '_from', field_id + '_to'); }); | ||
| addEvent(add_link, 'click', function(e) { move_selection(e, this, SelectBox.move, field_id + '_from', field_id + '_to'); }); | ||
| addEvent(remove_link, 'click', function(e) { move_selection(e, this, SelectBox.move, field_id + '_to', field_id + '_from'); }); | ||
| addEvent(clear_all, 'click', function(e) { move_selection(e, this, SelectBox.move_all, field_id + '_to', field_id + '_from'); }); | ||
| addEvent(filter_input, 'keypress', function(e) { SelectFilter.filter_key_press(e, field_id); }); | ||
| addEvent(filter_input, 'keyup', function(e) { SelectFilter.filter_key_up(e, field_id); }); | ||
| addEvent(filter_input, 'keydown', function(e) { SelectFilter.filter_key_down(e, field_id); }); | ||
| addEvent(selector_div, 'change', function(e) { | ||
| if (e.target.tagName === 'SELECT') { | ||
| SelectFilter.refresh_icons(field_id); | ||
| } | ||
| }); | ||
| addEvent(selector_div, 'dblclick', function(e) { | ||
| if (e.target.tagName === 'OPTION') { | ||
| if (e.target.closest('select').id === field_id + '_to') { | ||
| SelectBox.move(field_id + '_to', field_id + '_from'); | ||
| } else { | ||
| SelectBox.move(field_id + '_from', field_id + '_to'); | ||
| } | ||
| SelectFilter.refresh_icons(field_id); | ||
| } | ||
| }); | ||
| addEvent(findForm(from_box), 'submit', function() { SelectBox.select_all(field_id + '_to'); }); | ||
| SelectBox.init(field_id + '_from'); | ||
| SelectBox.init(field_id + '_to'); | ||
| // Move selected from_box options to to_box | ||
| SelectBox.move(field_id + '_from', field_id + '_to'); | ||
|
|
||
| if (!is_stacked) { | ||
| // In horizontal mode, give the same height to the two boxes. | ||
| var j_from_box = $(from_box); | ||
| var j_to_box = $(to_box); | ||
| var resize_filters = function() { j_to_box.height($(filter_p).outerHeight() + j_from_box.outerHeight()); }; | ||
| if (j_from_box.outerHeight() > 0) { | ||
| resize_filters(); // This fieldset is already open. Resize now. | ||
| } else { | ||
| // This fieldset is probably collapsed. Wait for its 'show' event. | ||
| j_to_box.closest('fieldset').one('show.fieldset', resize_filters); | ||
| } | ||
| } | ||
|
|
||
| // Initial icon refresh | ||
| SelectFilter.refresh_icons(field_id); | ||
| }, | ||
| any_selected: function(field) { | ||
| var any_selected = false; | ||
| try { | ||
| // Temporarily add the required attribute and check validity. | ||
| // This is much faster in WebKit browsers than the fallback. | ||
| field.attr('required', 'required'); | ||
| any_selected = field.is(':valid'); | ||
| field.removeAttr('required'); | ||
| } catch (e) { | ||
| // Browsers that don't support :valid (IE < 10) | ||
| any_selected = field.find('option:selected').length > 0; | ||
| } | ||
| return any_selected; | ||
| }, | ||
| refresh_icons: function(field_id) { | ||
| var from = $('#' + field_id + '_from'); | ||
| var to = $('#' + field_id + '_to'); | ||
| // Active if at least one item is selected | ||
| $('#' + field_id + '_add_link').toggleClass('active', SelectFilter.any_selected(from)); | ||
| $('#' + field_id + '_remove_link').toggleClass('active', SelectFilter.any_selected(to)); | ||
| // Active if the corresponding box isn't empty | ||
| $('#' + field_id + '_add_all_link').toggleClass('active', from.find('option').length > 0); | ||
| $('#' + field_id + '_remove_all_link').toggleClass('active', to.find('option').length > 0); | ||
| }, | ||
| filter_key_press: function(event, field_id) { | ||
| var from = document.getElementById(field_id + '_from'); | ||
| // don't submit form if user pressed Enter | ||
| if ((event.which && event.which === 13) || (event.keyCode && event.keyCode === 13)) { | ||
| from.selectedIndex = 0; | ||
| SelectBox.move(field_id + '_from', field_id + '_to'); | ||
| from.selectedIndex = 0; | ||
| event.preventDefault(); | ||
| return false; | ||
| } | ||
| }, | ||
| filter_key_up: function(event, field_id) { | ||
| var from = document.getElementById(field_id + '_from'); | ||
| var temp = from.selectedIndex; | ||
| SelectBox.filter(field_id + '_from', document.getElementById(field_id + '_input').value); | ||
| from.selectedIndex = temp; | ||
| return true; | ||
| }, | ||
| filter_key_down: function(event, field_id) { | ||
| var from = document.getElementById(field_id + '_from'); | ||
| // right arrow -- move across | ||
| if ((event.which && event.which === 39) || (event.keyCode && event.keyCode === 39)) { | ||
| var old_index = from.selectedIndex; | ||
| SelectBox.move(field_id + '_from', field_id + '_to'); | ||
| from.selectedIndex = (old_index === from.length) ? from.length - 1 : old_index; | ||
| return false; | ||
| } | ||
| // down arrow -- wrap around | ||
| if ((event.which && event.which === 40) || (event.keyCode && event.keyCode === 40)) { | ||
| from.selectedIndex = (from.length === from.selectedIndex + 1) ? 0 : from.selectedIndex + 1; | ||
| } | ||
| // up arrow -- wrap around | ||
| if ((event.which && event.which === 38) || (event.keyCode && event.keyCode === 38)) { | ||
| from.selectedIndex = (from.selectedIndex === 0) ? from.length - 1 : from.selectedIndex - 1; | ||
| } | ||
| return true; | ||
| } | ||
| }; | ||
|
|
||
| addEvent(window, 'load', function(e) { | ||
| $('select.selectfilter, select.selectfilterstacked').each(function() { | ||
| var $el = $(this), | ||
| data = $el.data(); | ||
| SelectFilter.init($el.attr('id'), data.fieldName, parseInt(data.isStacked, 10)); | ||
| }); | ||
| }); | ||
|
|
||
| })(django.jQuery); |
| @@ -0,0 +1,153 @@ | ||
| /*global gettext, interpolate, ngettext*/ | ||
| (function($) { | ||
| 'use strict'; | ||
| var lastChecked; | ||
|
|
||
| $.fn.actions = function(opts) { | ||
| var options = $.extend({}, $.fn.actions.defaults, opts); | ||
| var actionCheckboxes = $(this); | ||
| var list_editable_changed = false; | ||
| var showQuestion = function() { | ||
| $(options.acrossClears).hide(); | ||
| $(options.acrossQuestions).show(); | ||
| $(options.allContainer).hide(); | ||
| }, | ||
| showClear = function() { | ||
| $(options.acrossClears).show(); | ||
| $(options.acrossQuestions).hide(); | ||
| $(options.actionContainer).toggleClass(options.selectedClass); | ||
| $(options.allContainer).show(); | ||
| $(options.counterContainer).hide(); | ||
| }, | ||
| reset = function() { | ||
| $(options.acrossClears).hide(); | ||
| $(options.acrossQuestions).hide(); | ||
| $(options.allContainer).hide(); | ||
| $(options.counterContainer).show(); | ||
| }, | ||
| clearAcross = function() { | ||
| reset(); | ||
| $(options.acrossInput).val(0); | ||
| $(options.actionContainer).removeClass(options.selectedClass); | ||
| }, | ||
| checker = function(checked) { | ||
| if (checked) { | ||
| showQuestion(); | ||
| } else { | ||
| reset(); | ||
| } | ||
| $(actionCheckboxes).prop("checked", checked) | ||
| .parent().parent().toggleClass(options.selectedClass, checked); | ||
| }, | ||
| updateCounter = function() { | ||
| var sel = $(actionCheckboxes).filter(":checked").length; | ||
| // data-actions-icnt is defined in the generated HTML | ||
| // and contains the total amount of objects in the queryset | ||
| var actions_icnt = $('.action-counter').data('actionsIcnt'); | ||
| $(options.counterContainer).html(interpolate( | ||
| ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), { | ||
| sel: sel, | ||
| cnt: actions_icnt | ||
| }, true)); | ||
| $(options.allToggle).prop("checked", function() { | ||
| var value; | ||
| if (sel === actionCheckboxes.length) { | ||
| value = true; | ||
| showQuestion(); | ||
| } else { | ||
| value = false; | ||
| clearAcross(); | ||
| } | ||
| return value; | ||
| }); | ||
| }; | ||
| // Show counter by default | ||
| $(options.counterContainer).show(); | ||
| // Check state of checkboxes and reinit state if needed | ||
| $(this).filter(":checked").each(function(i) { | ||
| $(this).parent().parent().toggleClass(options.selectedClass); | ||
| updateCounter(); | ||
| if ($(options.acrossInput).val() === 1) { | ||
| showClear(); | ||
| } | ||
| }); | ||
| $(options.allToggle).show().click(function() { | ||
| checker($(this).prop("checked")); | ||
| updateCounter(); | ||
| }); | ||
| $("a", options.acrossQuestions).click(function(event) { | ||
| event.preventDefault(); | ||
| $(options.acrossInput).val(1); | ||
| showClear(); | ||
| }); | ||
| $("a", options.acrossClears).click(function(event) { | ||
| event.preventDefault(); | ||
| $(options.allToggle).prop("checked", false); | ||
| clearAcross(); | ||
| checker(0); | ||
| updateCounter(); | ||
| }); | ||
| lastChecked = null; | ||
| $(actionCheckboxes).click(function(event) { | ||
| if (!event) { event = window.event; } | ||
| var target = event.target ? event.target : event.srcElement; | ||
| if (lastChecked && $.data(lastChecked) !== $.data(target) && event.shiftKey === true) { | ||
| var inrange = false; | ||
| $(lastChecked).prop("checked", target.checked) | ||
| .parent().parent().toggleClass(options.selectedClass, target.checked); | ||
| $(actionCheckboxes).each(function() { | ||
| if ($.data(this) === $.data(lastChecked) || $.data(this) === $.data(target)) { | ||
| inrange = (inrange) ? false : true; | ||
| } | ||
| if (inrange) { | ||
| $(this).prop("checked", target.checked) | ||
| .parent().parent().toggleClass(options.selectedClass, target.checked); | ||
| } | ||
| }); | ||
| } | ||
| $(target).parent().parent().toggleClass(options.selectedClass, target.checked); | ||
| lastChecked = target; | ||
| updateCounter(); | ||
| }); | ||
| $('form#changelist-form table#result_list tr').find('td:gt(0) :input').change(function() { | ||
| list_editable_changed = true; | ||
| }); | ||
| $('form#changelist-form button[name="index"]').click(function(event) { | ||
| if (list_editable_changed) { | ||
| return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost.")); | ||
| } | ||
| }); | ||
| $('form#changelist-form input[name="_save"]').click(function(event) { | ||
| var action_changed = false; | ||
| $('select option:selected', options.actionContainer).each(function() { | ||
| if ($(this).val()) { | ||
| action_changed = true; | ||
| } | ||
| }); | ||
| if (action_changed) { | ||
| if (list_editable_changed) { | ||
| return confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")); | ||
| } else { | ||
| return confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button.")); | ||
| } | ||
| } | ||
| }); | ||
| }; | ||
| /* Setup plugin defaults */ | ||
| $.fn.actions.defaults = { | ||
| actionContainer: "div.actions", | ||
| counterContainer: "span.action-counter", | ||
| allContainer: "div.actions span.all", | ||
| acrossInput: "div.actions input.select-across", | ||
| acrossQuestions: "div.actions span.question", | ||
| acrossClears: "div.actions span.clear", | ||
| allToggle: "#action-toggle", | ||
| selectedClass: "selected" | ||
| }; | ||
| $(document).ready(function() { | ||
| var $actionsEls = $('tr input.action-select'); | ||
| if ($actionsEls.length > 0) { | ||
| $actionsEls.actions(); | ||
| } | ||
| }); | ||
| })(django.jQuery); |
| @@ -0,0 +1,175 @@ | ||
| /*global SelectBox, interpolate*/ | ||
| // Handles related-objects functionality: lookup link for raw_id_fields | ||
| // and Add Another links. | ||
|
|
||
| (function($) { | ||
| 'use strict'; | ||
|
|
||
| // IE doesn't accept periods or dashes in the window name, but the element IDs | ||
| // we use to generate popup window names may contain them, therefore we map them | ||
| // to allowed characters in a reversible way so that we can locate the correct | ||
| // element when the popup window is dismissed. | ||
| function id_to_windowname(text) { | ||
| text = text.replace(/\./g, '__dot__'); | ||
| text = text.replace(/\-/g, '__dash__'); | ||
| return text; | ||
| } | ||
|
|
||
| function windowname_to_id(text) { | ||
| text = text.replace(/__dot__/g, '.'); | ||
| text = text.replace(/__dash__/g, '-'); | ||
| return text; | ||
| } | ||
|
|
||
| function showAdminPopup(triggeringLink, name_regexp, add_popup) { | ||
| var name = triggeringLink.id.replace(name_regexp, ''); | ||
| name = id_to_windowname(name); | ||
| var href = triggeringLink.href; | ||
| if (add_popup) { | ||
| if (href.indexOf('?') === -1) { | ||
| href += '?_popup=1'; | ||
| } else { | ||
| href += '&_popup=1'; | ||
| } | ||
| } | ||
| var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); | ||
| win.focus(); | ||
| return false; | ||
| } | ||
|
|
||
| function showRelatedObjectLookupPopup(triggeringLink) { | ||
| return showAdminPopup(triggeringLink, /^lookup_/, true); | ||
| } | ||
|
|
||
| function dismissRelatedLookupPopup(win, chosenId) { | ||
| var name = windowname_to_id(win.name); | ||
| var elem = document.getElementById(name); | ||
| if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) { | ||
| elem.value += ',' + chosenId; | ||
| } else { | ||
| document.getElementById(name).value = chosenId; | ||
| } | ||
| win.close(); | ||
| } | ||
|
|
||
| function showRelatedObjectPopup(triggeringLink) { | ||
| return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false); | ||
| } | ||
|
|
||
| function updateRelatedObjectLinks(triggeringLink) { | ||
| var $this = $(triggeringLink); | ||
| var siblings = $this.nextAll('.change-related, .delete-related'); | ||
| if (!siblings.length) { | ||
| return; | ||
| } | ||
| var value = $this.val(); | ||
| if (value) { | ||
| siblings.each(function() { | ||
| var elm = $(this); | ||
| elm.attr('href', elm.attr('data-href-template').replace('__fk__', value)); | ||
| }); | ||
| } else { | ||
| siblings.removeAttr('href'); | ||
| } | ||
| } | ||
|
|
||
| function dismissAddRelatedObjectPopup(win, newId, newRepr) { | ||
| var name = windowname_to_id(win.name); | ||
| var elem = document.getElementById(name); | ||
| if (elem) { | ||
| var elemName = elem.nodeName.toUpperCase(); | ||
| if (elemName === 'SELECT') { | ||
| elem.options[elem.options.length] = new Option(newRepr, newId, true, true); | ||
| } else if (elemName === 'INPUT') { | ||
| if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) { | ||
| elem.value += ',' + newId; | ||
| } else { | ||
| elem.value = newId; | ||
| } | ||
| } | ||
| // Trigger a change event to update related links if required. | ||
| $(elem).trigger('change'); | ||
| } else { | ||
| var toId = name + "_to"; | ||
| var o = new Option(newRepr, newId); | ||
| SelectBox.add_to_cache(toId, o); | ||
| SelectBox.redisplay(toId); | ||
| } | ||
| win.close(); | ||
| } | ||
|
|
||
| function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) { | ||
| var id = windowname_to_id(win.name).replace(/^edit_/, ''); | ||
| var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); | ||
| var selects = $(selectsSelector); | ||
| selects.find('option').each(function() { | ||
| if (this.value === objId) { | ||
| this.textContent = newRepr; | ||
| this.value = newId; | ||
| } | ||
| }); | ||
| win.close(); | ||
| } | ||
|
|
||
| function dismissDeleteRelatedObjectPopup(win, objId) { | ||
| var id = windowname_to_id(win.name).replace(/^delete_/, ''); | ||
| var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); | ||
| var selects = $(selectsSelector); | ||
| selects.find('option').each(function() { | ||
| if (this.value === objId) { | ||
| $(this).remove(); | ||
| } | ||
| }).trigger('change'); | ||
| win.close(); | ||
| } | ||
|
|
||
| // Global for testing purposes | ||
| window.id_to_windowname = id_to_windowname; | ||
| window.windowname_to_id = windowname_to_id; | ||
|
|
||
| window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup; | ||
| window.dismissRelatedLookupPopup = dismissRelatedLookupPopup; | ||
| window.showRelatedObjectPopup = showRelatedObjectPopup; | ||
| window.updateRelatedObjectLinks = updateRelatedObjectLinks; | ||
| window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup; | ||
| window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup; | ||
| window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup; | ||
|
|
||
| // Kept for backward compatibility | ||
| window.showAddAnotherPopup = showRelatedObjectPopup; | ||
| window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup; | ||
|
|
||
| $(document).ready(function() { | ||
| $("a[data-popup-opener]").click(function(event) { | ||
| event.preventDefault(); | ||
| opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener")); | ||
| }); | ||
| $('body').on('click', '.related-widget-wrapper-link', function(e) { | ||
| e.preventDefault(); | ||
| if (this.href) { | ||
| var event = $.Event('django:show-related', {href: this.href}); | ||
| $(this).trigger(event); | ||
| if (!event.isDefaultPrevented()) { | ||
| showRelatedObjectPopup(this); | ||
| } | ||
| } | ||
| }); | ||
| $('body').on('change', '.related-widget-wrapper select', function(e) { | ||
| var event = $.Event('django:update-related'); | ||
| $(this).trigger(event); | ||
| if (!event.isDefaultPrevented()) { | ||
| updateRelatedObjectLinks(this); | ||
| } | ||
| }); | ||
| $('.related-widget-wrapper select').trigger('change'); | ||
| $('body').on('click', '.related-lookup', function(e) { | ||
| e.preventDefault(); | ||
| var event = $.Event('django:lookup-related'); | ||
| $(this).trigger(event); | ||
| if (!event.isDefaultPrevented()) { | ||
| showRelatedObjectLookupPopup(this); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| })(django.jQuery); |
| @@ -0,0 +1,208 @@ | ||
| /*global gettext, pgettext, get_format, quickElement, removeChildren, addEvent*/ | ||
| /* | ||
| calendar.js - Calendar functions by Adrian Holovaty | ||
| depends on core.js for utility functions like removeChildren or quickElement | ||
| */ | ||
|
|
||
| (function() { | ||
| 'use strict'; | ||
| // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions | ||
| var CalendarNamespace = { | ||
| monthsOfYear: [ | ||
| gettext('January'), | ||
| gettext('February'), | ||
| gettext('March'), | ||
| gettext('April'), | ||
| gettext('May'), | ||
| gettext('June'), | ||
| gettext('July'), | ||
| gettext('August'), | ||
| gettext('September'), | ||
| gettext('October'), | ||
| gettext('November'), | ||
| gettext('December') | ||
| ], | ||
| daysOfWeek: [ | ||
| pgettext('one letter Sunday', 'S'), | ||
| pgettext('one letter Monday', 'M'), | ||
| pgettext('one letter Tuesday', 'T'), | ||
| pgettext('one letter Wednesday', 'W'), | ||
| pgettext('one letter Thursday', 'T'), | ||
| pgettext('one letter Friday', 'F'), | ||
| pgettext('one letter Saturday', 'S') | ||
| ], | ||
| firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')), | ||
| isLeapYear: function(year) { | ||
| return (((year % 4) === 0) && ((year % 100) !== 0 ) || ((year % 400) === 0)); | ||
| }, | ||
| getDaysInMonth: function(month, year) { | ||
| var days; | ||
| if (month === 1 || month === 3 || month === 5 || month === 7 || month === 8 || month === 10 || month === 12) { | ||
| days = 31; | ||
| } | ||
| else if (month === 4 || month === 6 || month === 9 || month === 11) { | ||
| days = 30; | ||
| } | ||
| else if (month === 2 && CalendarNamespace.isLeapYear(year)) { | ||
| days = 29; | ||
| } | ||
| else { | ||
| days = 28; | ||
| } | ||
| return days; | ||
| }, | ||
| draw: function(month, year, div_id, callback, selected) { // month = 1-12, year = 1-9999 | ||
| var today = new Date(); | ||
| var todayDay = today.getDate(); | ||
| var todayMonth = today.getMonth() + 1; | ||
| var todayYear = today.getFullYear(); | ||
| var todayClass = ''; | ||
|
|
||
| // Use UTC functions here because the date field does not contain time | ||
| // and using the UTC function variants prevent the local time offset | ||
| // from altering the date, specifically the day field. For example: | ||
| // | ||
| // ``` | ||
| // var x = new Date('2013-10-02'); | ||
| // var day = x.getDate(); | ||
| // ``` | ||
| // | ||
| // The day variable above will be 1 instead of 2 in, say, US Pacific time | ||
| // zone. | ||
| var isSelectedMonth = false; | ||
| if (typeof selected !== 'undefined') { | ||
| isSelectedMonth = (selected.getUTCFullYear() === year && (selected.getUTCMonth() + 1) === month); | ||
| } | ||
|
|
||
| month = parseInt(month); | ||
| year = parseInt(year); | ||
| var calDiv = document.getElementById(div_id); | ||
| removeChildren(calDiv); | ||
| var calTable = document.createElement('table'); | ||
| quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month - 1] + ' ' + year); | ||
| var tableBody = quickElement('tbody', calTable); | ||
|
|
||
| // Draw days-of-week header | ||
| var tableRow = quickElement('tr', tableBody); | ||
| for (var i = 0; i < 7; i++) { | ||
| quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]); | ||
| } | ||
|
|
||
| var startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay(); | ||
| var days = CalendarNamespace.getDaysInMonth(month, year); | ||
|
|
||
| var nonDayCell; | ||
|
|
||
| // Draw blanks before first of month | ||
| tableRow = quickElement('tr', tableBody); | ||
| for (i = 0; i < startingPos; i++) { | ||
| nonDayCell = quickElement('td', tableRow, ' '); | ||
| nonDayCell.className = "nonday"; | ||
| } | ||
|
|
||
| function calendarMonth(y, m) { | ||
| function onClick(e) { | ||
| e.preventDefault(); | ||
| callback(y, m, django.jQuery(this).text()); | ||
| } | ||
| return onClick; | ||
| } | ||
|
|
||
| // Draw days of month | ||
| var currentDay = 1; | ||
| for (i = startingPos; currentDay <= days; i++) { | ||
| if (i % 7 === 0 && currentDay !== 1) { | ||
| tableRow = quickElement('tr', tableBody); | ||
| } | ||
| if ((currentDay === todayDay) && (month === todayMonth) && (year === todayYear)) { | ||
| todayClass = 'today'; | ||
| } else { | ||
| todayClass = ''; | ||
| } | ||
|
|
||
| // use UTC function; see above for explanation. | ||
| if (isSelectedMonth && currentDay === selected.getUTCDate()) { | ||
| if (todayClass !== '') { | ||
| todayClass += " "; | ||
| } | ||
| todayClass += "selected"; | ||
| } | ||
|
|
||
| var cell = quickElement('td', tableRow, '', 'class', todayClass); | ||
| var link = quickElement('a', cell, currentDay, 'href', '#'); | ||
| addEvent(link, 'click', calendarMonth(year, month)); | ||
| currentDay++; | ||
| } | ||
|
|
||
| // Draw blanks after end of month (optional, but makes for valid code) | ||
| while (tableRow.childNodes.length < 7) { | ||
| nonDayCell = quickElement('td', tableRow, ' '); | ||
| nonDayCell.className = "nonday"; | ||
| } | ||
|
|
||
| calDiv.appendChild(calTable); | ||
| } | ||
| }; | ||
|
|
||
| // Calendar -- A calendar instance | ||
| function Calendar(div_id, callback, selected) { | ||
| // div_id (string) is the ID of the element in which the calendar will | ||
| // be displayed | ||
| // callback (string) is the name of a JavaScript function that will be | ||
| // called with the parameters (year, month, day) when a day in the | ||
| // calendar is clicked | ||
| this.div_id = div_id; | ||
| this.callback = callback; | ||
| this.today = new Date(); | ||
| this.currentMonth = this.today.getMonth() + 1; | ||
| this.currentYear = this.today.getFullYear(); | ||
| if (typeof selected !== 'undefined') { | ||
| this.selected = selected; | ||
| } | ||
| } | ||
| Calendar.prototype = { | ||
| drawCurrent: function() { | ||
| CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback, this.selected); | ||
| }, | ||
| drawDate: function(month, year, selected) { | ||
| this.currentMonth = month; | ||
| this.currentYear = year; | ||
|
|
||
| if(selected) { | ||
| this.selected = selected; | ||
| } | ||
|
|
||
| this.drawCurrent(); | ||
| }, | ||
| drawPreviousMonth: function() { | ||
| if (this.currentMonth === 1) { | ||
| this.currentMonth = 12; | ||
| this.currentYear--; | ||
| } | ||
| else { | ||
| this.currentMonth--; | ||
| } | ||
| this.drawCurrent(); | ||
| }, | ||
| drawNextMonth: function() { | ||
| if (this.currentMonth === 12) { | ||
| this.currentMonth = 1; | ||
| this.currentYear++; | ||
| } | ||
| else { | ||
| this.currentMonth++; | ||
| } | ||
| this.drawCurrent(); | ||
| }, | ||
| drawPreviousYear: function() { | ||
| this.currentYear--; | ||
| this.drawCurrent(); | ||
| }, | ||
| drawNextYear: function() { | ||
| this.currentYear++; | ||
| this.drawCurrent(); | ||
| } | ||
| }; | ||
| window.Calendar = Calendar; | ||
| window.CalendarNamespace = CalendarNamespace; | ||
| })(); |
| @@ -0,0 +1,9 @@ | ||
| (function($) { | ||
| 'use strict'; | ||
| $(function() { | ||
| $('.cancel-link').click(function(e) { | ||
| e.preventDefault(); | ||
| window.history.back(); | ||
| }); | ||
| }); | ||
| })(django.jQuery); |
| @@ -0,0 +1,20 @@ | ||
| /*global showAddAnotherPopup, showRelatedObjectLookupPopup showRelatedObjectPopup updateRelatedObjectLinks*/ | ||
|
|
||
| (function($) { | ||
| 'use strict'; | ||
| $(document).ready(function() { | ||
| var modelName = $('#django-admin-form-add-constants').data('modelName'); | ||
| $('body').on('click', '.add-another', function(e) { | ||
| e.preventDefault(); | ||
| var event = $.Event('django:add-another-related'); | ||
| $(this).trigger(event); | ||
| if (!event.isDefaultPrevented()) { | ||
| showAddAnotherPopup(this); | ||
| } | ||
| }); | ||
|
|
||
| if (modelName) { | ||
| $('form#' + modelName + '_form :input:visible:enabled:first').focus(); | ||
| } | ||
| }); | ||
| })(django.jQuery); |
| @@ -0,0 +1,26 @@ | ||
| /*global gettext*/ | ||
| (function($) { | ||
| 'use strict'; | ||
| $(document).ready(function() { | ||
| // Add anchor tag for Show/Hide link | ||
| $("fieldset.collapse").each(function(i, elem) { | ||
| // Don't hide if fields in this fieldset have errors | ||
| if ($(elem).find("div.errors").length === 0) { | ||
| $(elem).addClass("collapsed").find("h2").first().append(' (<a id="fieldsetcollapser' + | ||
| i + '" class="collapse-toggle" href="#">' + gettext("Show") + | ||
| '</a>)'); | ||
| } | ||
| }); | ||
| // Add toggle to anchor tag | ||
| $("fieldset.collapse a.collapse-toggle").click(function(ev) { | ||
| if ($(this).closest("fieldset").hasClass("collapsed")) { | ||
| // Show | ||
| $(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]); | ||
| } else { | ||
| // Hide | ||
| $(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]); | ||
| } | ||
| return false; | ||
| }); | ||
| }); | ||
| })(django.jQuery); |
| @@ -0,0 +1,250 @@ | ||
| // Core javascript helper functions | ||
|
|
||
| // basic browser identification & version | ||
| var isOpera = (navigator.userAgent.indexOf("Opera") >= 0) && parseFloat(navigator.appVersion); | ||
| var isIE = ((document.all) && (!isOpera)) && parseFloat(navigator.appVersion.split("MSIE ")[1].split(";")[0]); | ||
|
|
||
| // Cross-browser event handlers. | ||
| function addEvent(obj, evType, fn) { | ||
| 'use strict'; | ||
| if (obj.addEventListener) { | ||
| obj.addEventListener(evType, fn, false); | ||
| return true; | ||
| } else if (obj.attachEvent) { | ||
| var r = obj.attachEvent("on" + evType, fn); | ||
| return r; | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| function removeEvent(obj, evType, fn) { | ||
| 'use strict'; | ||
| if (obj.removeEventListener) { | ||
| obj.removeEventListener(evType, fn, false); | ||
| return true; | ||
| } else if (obj.detachEvent) { | ||
| obj.detachEvent("on" + evType, fn); | ||
| return true; | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| function cancelEventPropagation(e) { | ||
| 'use strict'; | ||
| if (!e) { | ||
| e = window.event; | ||
| } | ||
| e.cancelBubble = true; | ||
| if (e.stopPropagation) { | ||
| e.stopPropagation(); | ||
| } | ||
| } | ||
|
|
||
| // quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]); | ||
| function quickElement() { | ||
| 'use strict'; | ||
| var obj = document.createElement(arguments[0]); | ||
| if (arguments[2]) { | ||
| var textNode = document.createTextNode(arguments[2]); | ||
| obj.appendChild(textNode); | ||
| } | ||
| var len = arguments.length; | ||
| for (var i = 3; i < len; i += 2) { | ||
| obj.setAttribute(arguments[i], arguments[i + 1]); | ||
| } | ||
| arguments[1].appendChild(obj); | ||
| return obj; | ||
| } | ||
|
|
||
| // "a" is reference to an object | ||
| function removeChildren(a) { | ||
| 'use strict'; | ||
| while (a.hasChildNodes()) { | ||
| a.removeChild(a.lastChild); | ||
| } | ||
| } | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
| // Find-position functions by PPK | ||
| // See http://www.quirksmode.org/js/findpos.html | ||
| // ---------------------------------------------------------------------------- | ||
| function findPosX(obj) { | ||
| 'use strict'; | ||
| var curleft = 0; | ||
| if (obj.offsetParent) { | ||
| while (obj.offsetParent) { | ||
| curleft += obj.offsetLeft - ((isOpera) ? 0 : obj.scrollLeft); | ||
| obj = obj.offsetParent; | ||
| } | ||
| // IE offsetParent does not include the top-level | ||
| if (isIE && obj.parentElement) { | ||
| curleft += obj.offsetLeft - obj.scrollLeft; | ||
| } | ||
| } else if (obj.x) { | ||
| curleft += obj.x; | ||
| } | ||
| return curleft; | ||
| } | ||
|
|
||
| function findPosY(obj) { | ||
| 'use strict'; | ||
| var curtop = 0; | ||
| if (obj.offsetParent) { | ||
| while (obj.offsetParent) { | ||
| curtop += obj.offsetTop - ((isOpera) ? 0 : obj.scrollTop); | ||
| obj = obj.offsetParent; | ||
| } | ||
| // IE offsetParent does not include the top-level | ||
| if (isIE && obj.parentElement) { | ||
| curtop += obj.offsetTop - obj.scrollTop; | ||
| } | ||
| } else if (obj.y) { | ||
| curtop += obj.y; | ||
| } | ||
| return curtop; | ||
| } | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Date object extensions | ||
| // ---------------------------------------------------------------------------- | ||
| (function() { | ||
| 'use strict'; | ||
| Date.prototype.getTwelveHours = function() { | ||
| var hours = this.getHours(); | ||
| if (hours === 0) { | ||
| return 12; | ||
| } | ||
| else { | ||
| return hours <= 12 ? hours : hours - 12; | ||
| } | ||
| }; | ||
|
|
||
| Date.prototype.getTwoDigitMonth = function() { | ||
| return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1); | ||
| }; | ||
|
|
||
| Date.prototype.getTwoDigitDate = function() { | ||
| return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); | ||
| }; | ||
|
|
||
| Date.prototype.getTwoDigitTwelveHour = function() { | ||
| return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); | ||
| }; | ||
|
|
||
| Date.prototype.getTwoDigitHour = function() { | ||
| return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); | ||
| }; | ||
|
|
||
| Date.prototype.getTwoDigitMinute = function() { | ||
| return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes(); | ||
| }; | ||
|
|
||
| Date.prototype.getTwoDigitSecond = function() { | ||
| return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); | ||
| }; | ||
|
|
||
| Date.prototype.getHourMinute = function() { | ||
| return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute(); | ||
| }; | ||
|
|
||
| Date.prototype.getHourMinuteSecond = function() { | ||
| return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond(); | ||
| }; | ||
|
|
||
| Date.prototype.getFullMonthName = function() { | ||
| return typeof window.CalendarNamespace === "undefined" | ||
| ? this.getTwoDigitMonth() | ||
| : window.CalendarNamespace.monthsOfYear[this.getMonth()]; | ||
| }; | ||
|
|
||
| Date.prototype.strftime = function(format) { | ||
| var fields = { | ||
| B: this.getFullMonthName(), | ||
| c: this.toString(), | ||
| d: this.getTwoDigitDate(), | ||
| H: this.getTwoDigitHour(), | ||
| I: this.getTwoDigitTwelveHour(), | ||
| m: this.getTwoDigitMonth(), | ||
| M: this.getTwoDigitMinute(), | ||
| p: (this.getHours() >= 12) ? 'PM' : 'AM', | ||
| S: this.getTwoDigitSecond(), | ||
| w: '0' + this.getDay(), | ||
| x: this.toLocaleDateString(), | ||
| X: this.toLocaleTimeString(), | ||
| y: ('' + this.getFullYear()).substr(2, 4), | ||
| Y: '' + this.getFullYear(), | ||
| '%': '%' | ||
| }; | ||
| var result = '', i = 0; | ||
| while (i < format.length) { | ||
| if (format.charAt(i) === '%') { | ||
| result = result + fields[format.charAt(i + 1)]; | ||
| ++i; | ||
| } | ||
| else { | ||
| result = result + format.charAt(i); | ||
| } | ||
| ++i; | ||
| } | ||
| return result; | ||
| }; | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
| // String object extensions | ||
| // ---------------------------------------------------------------------------- | ||
| String.prototype.pad_left = function(pad_length, pad_string) { | ||
| var new_string = this; | ||
| for (var i = 0; new_string.length < pad_length; i++) { | ||
| new_string = pad_string + new_string; | ||
| } | ||
| return new_string; | ||
| }; | ||
|
|
||
| String.prototype.strptime = function(format) { | ||
| var split_format = format.split(/[.\-/]/); | ||
| var date = this.split(/[.\-/]/); | ||
| var i = 0; | ||
| var day, month, year; | ||
| while (i < split_format.length) { | ||
| switch (split_format[i]) { | ||
| case "%d": | ||
| day = date[i]; | ||
| break; | ||
| case "%m": | ||
| month = date[i] - 1; | ||
| break; | ||
| case "%Y": | ||
| year = date[i]; | ||
| break; | ||
| case "%y": | ||
| year = date[i]; | ||
| break; | ||
| } | ||
| ++i; | ||
| } | ||
| // Create Date object from UTC since the parsed value is supposed to be | ||
| // in UTC, not local time. Also, the calendar uses UTC functions for | ||
| // date extraction. | ||
| return new Date(Date.UTC(year, month, day)); | ||
| }; | ||
|
|
||
| })(); | ||
| // ---------------------------------------------------------------------------- | ||
| // Get the computed style for and element | ||
| // ---------------------------------------------------------------------------- | ||
| function getStyle(oElm, strCssRule) { | ||
| 'use strict'; | ||
| var strValue = ""; | ||
| if(document.defaultView && document.defaultView.getComputedStyle) { | ||
| strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule); | ||
| } | ||
| else if(oElm.currentStyle) { | ||
| strCssRule = strCssRule.replace(/\-(\w)/g, function(strMatch, p1) { | ||
| return p1.toUpperCase(); | ||
| }); | ||
| strValue = oElm.currentStyle[strCssRule]; | ||
| } | ||
| return strValue; | ||
| } |