Mercurial > defr > drupal > popups
changeset 0:76f9b43738f2
Popups 2.0-alpha5
author | Franck Deroche <franck@defr.org> |
---|---|
date | Fri, 31 Dec 2010 13:41:08 +0100 |
parents | |
children | 4215c43e74eb c076d54409cb |
files | .cvsignore .project API.txt CHANGELOG.txt LICENSE.txt README.txt ajax-loader.gif popups.api.php popups.css popups.info popups.install popups.js popups.module popups_admin.info popups_admin.module popups_test.info popups_test.module skins/basic/basic.css skins/basic/popup-icon.png skins/blue/blue.css skins/blue/images/sprites.png skins/blue/images/tile-v.png skins/facebook/facebook.css skins/facebook/facebook.js skins/facebook/loading-large.gif skins/facebook/loading.gif skins/facebook/popups-border.png translations/ja.po |
diffstat | 28 files changed, 3037 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.cvsignore Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,1 @@ +.project
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.project Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>popups62</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/API.txt Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,37 @@ +As well as attaching popup behavior to links, +Popups API provides javascript function for creating in-window popup messages. + +Popups.message(title, message) + Produces a simple modal box with the title, message and "OK", "Cancel" buttons. + +Popups.open(title, body, buttons, width) + More powerful, allows you to specify what the buttons are and what they do. + buttons is a hash of hash, with button title and function. + * Example: + Drupal.popups.open( + Drupal.t('Warning: Please Confirm'), + Drupal.t("There are unsaved changes on this page, which you will lose if you continue."), + { + 'popup_save': { + title: Drupal.t('Save Changes'), + func: function(){Drupal.popups.savePage(element, options);} + }, + 'popup_submit': { + title: Drupal.t('Continue'), + func: function(){Drupal.popups.removePopup(); Drupal.popups.openPath(element, options);} + }, + 'popup_cancel': { + title: Drupal.t('Cancel'), func: Drupal.popups.close; + } + } + ); + +// TODO - make a more useful api function for opening a path. +Popups.openPath = function(element, options, parent) + * @param element + * Element that was clicked to open the popups. + * @param options + * Hash of options controlling how the popups interacts with the underlying page. + * @param parent + * If path is being opened from inside another popup, that popup is the parent. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CHANGELOG.txt Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,91 @@ +6.x--2-0-ALPHA5 +Features + * New options and options system. + ** Added updateMethod, updateSource, onUpdate, doneTest, skipDirtyCheck, and hijackDestination. + ** Removed noUpdate, reloadOnUpdate, forceReturn, nonModal and afterSubmit. + ** Default options are declared in popups.js + ** Options in on-popups-option attribute now override default and hook options, instead of replacing them. + * Popups.addedJS => Keeping track of JIT loaded JS files, so they are not reloaded. +Bug Fixes + * Fixed tests #7 & #8. + * Fixing :input highlight in basic.css. + * http://drupal.org/node/406326 (sirkitree) - fixing facebook skin resize. +Other + * Broke out Popups.clickPopupElement from Popups.attach + * Broke out Popups.activeLayerIsEdited from Popups.attach + * Broke out Popups.Popup.prototype.fill from Popups.open + * Popups.openContent -> Popups.openContentPath + * New properties added to Popups.Popup object. + * Abstracted Popups.activeLayerIsEdited. + * Abstracted Popups.offerToSave. + * Popups.formSuccess(popup, json) - parameters changed. + * SavePage function changed to saveFormOnLayer. +Todo + * Improve Popups.activeLayerIsEdited + * Recapture the focus on popup if user tabs away. + +6.x--2-0-ALPHA4 +Features + * Broadcast "Popups Open Path Done" event. + * Huge change - Popup Stacking now works. Can have multiple Popups in the dom. + ** Skins change most ids to classes. + ** Introduced Popups.Popup object. +Other + * Clean up. + * Using Drupal.parseJson instead of eval for encoded options. + +6.x--2-0-ALPHA3 +Bug Fixes + * Removing the jit css files on popups close. +Other + * Removing additionalJavascript, additionalCSS and additionalJavascriptSettings. + +6.x--2-0-ALPHA2 +New Features + * http://drupal.org/node/336641 - Nate's big ol' just-in-time css and js loader patch +Issues + * JIT loaded css and js are not unloaded when popup is dismissed + * File order is not maintained. JIT files are loaded after page's original pages. + * Inline scripts need more testing: + ** Should inline scripts be called before or after popup content is loaded? + *** Poll wants to go after + ** Should already loaded inlines be executed again? +Todo + * Can I control order of css adds (modules vs themes)? + * What about multiple popups - can I flag the js files as already loaded? + ** Inlines will still want to be run again. + * Q: Why the heck is the poll script inlined and not a behavior? + * Drupal.popups.restorePage(); + * Not working with Popup: A&R? + +6.x--2-0-ALPHA1 +New Features + * http://drupal.org/node/364712 (sirkitree) - Customize loading graphic. + * Using a small popup signifier icon instead of unicode char (pulled from D7 patch). + * http://drupal.org/node/372378 - sirkitree & Rob Loach - popup skin interface. + * Added Facebook skin by sirkitree + * Added Blue skin by Tj Holowaychuk + * Unskinned skin checks current theme for popups-skin.js + * http://drupal.org/node/373737 (Rob Loach) - Finally caching hook_popups hash (thanks Rob). + * http://drupal.org/node/386168 (Rob Loach) - adding hook_popups_alter and popups.api.php +Bug Fixes + * http://drupal.org/node/366093 (mathiaz.sk) - Opera fix. + * Modified basic loading layer to work with #364712. + * http://drupal.org/node/361957 - breaking admin/build/block (fixed by removing popups-popup.tpl.php) + * Popups working on admin/build/block/list/* + * http://drupal.org/node/373702 (Rob Loach) - Better wording for auto close messages. + * Removing hook_theme and popup/save_dialog menu item. + * http://drupal.org/node/385732 (Rob Loach) - Bugs fixes in refocus(). +Other + * Removed popups-popup.tpl.php - theming html now done in my_theme.js or in a skin. + +6.x--1-2 +New Features + * http://drupal.org/node/336063 - Adding optional afterSubmit callback. + * Compatability with Popups: Add and Reference + ** Adding broadcasting of a couple of popup lifecycle events (popups_open_path, popups_form_success). +Other + * Added a couple new comments and cleaned up some obsolete code in popups.js + +6.x--1-1 + * Removed a couple non-working links from popups_admin.module.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE.txt Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,274 @@ +GNU GENERAL PUBLIC LICENSE + + Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, +Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute +verbatim copies of this license document, but changing it is not allowed. + + Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. This General Public License +applies to most of the Free Software Foundation's software and to any other +program whose authors commit to using it. (Some other Free Software +Foundation software is covered by the GNU Library General Public License +instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the +freedom to distribute copies of free software (and charge for this service if +you wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for +a fee, you must give the recipients all the rights that you have. You must make +sure that they, too, receive or can get the source code. And you must show +them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If the +software is modified by someone else and passed on, we want its recipients +to know that what they have is not the original, so that any problems +introduced by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will individually +obtain patent licenses, in effect making the program proprietary. To prevent +this, we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND + MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms +of this General Public License. The "Program", below, refers to any such +program or work, and a "work based on the Program" means either the +Program or any derivative work under copyright law: that is to say, a work +containing the Program or a portion of it, either verbatim or with +modifications and/or translated into another language. (Hereinafter, translation +is included without limitation in the term "modification".) Each licensee is +addressed as "you". + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running the Program is +not restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made +by running the Program). Whether that is true depends on what the Program +does. + +1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the +Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, +thus forming a work based on the Program, and copy and distribute such +modifications or work under the terms of Section 1 above, provided that you +also meet all of these conditions: + +a) You must cause the modified files to carry prominent notices stating that +you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in whole or in +part contains or is derived from the Program or any part thereof, to be +licensed as a whole at no charge to all third parties under the terms of this +License. + +c) If the modified program normally reads commands interactively when run, +you must cause it, when started running for such interactive use in the most +ordinary way, to print or display an announcement including an appropriate +copyright notice and a notice that there is no warranty (or else, saying that +you provide a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this License. +(Exception: if the Program itself is interactive but does not normally print such +an announcement, your work based on the Program is not required to print +an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be +reasonably considered independent and separate works in themselves, then +this License, and its terms, do not apply to those sections when you distribute +them as separate works. But when you distribute the same sections as part +of a whole which is a work based on the Program, the distribution of the +whole must be on the terms of this License, whose permissions for other +licensees extend to the entire whole, and thus to each and every part +regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to +work written entirely by you; rather, the intent is to exercise the right to +control the distribution of derivative or collective works based on the +Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of a +storage or distribution medium does not bring the other work under the scope +of this License. + +3. You may copy and distribute the Program (or a work based on it, under +Section 2) in object code or executable form under the terms of Sections 1 +and 2 above provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source +code, which must be distributed under the terms of Sections 1 and 2 above +on a medium customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three years, to give +any third party, for a charge no more than your cost of physically performing +source distribution, a complete machine-readable copy of the corresponding +source code, to be distributed under the terms of Sections 1 and 2 above on +a medium customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer to distribute +corresponding source code. (This alternative is allowed only for +noncommercial distribution and only if you received the program in object +code or executable form with such an offer, in accord with Subsection b +above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source code +means all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation and +installation of the executable. However, as a special exception, the source +code distributed need not include anything that is normally distributed (in +either source or binary form) with the major components (compiler, kernel, +and so on) of the operating system on which the executable runs, unless that +component itself accompanies the executable. + +If distribution of executable or object code is made by offering access to +copy from a designated place, then offering equivalent access to copy the +source code from the same place counts as distribution of the source code, +even though third parties are not compelled to copy the source along with the +object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, +modify, sublicense or distribute the Program is void, and will automatically +terminate your rights under this License. However, parties who have received +copies, or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. +However, nothing else grants you permission to modify or distribute the +Program or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the +Program (or any work based on the Program), you indicate your acceptance +of this License to do so, and all its terms and conditions for copying, +distributing or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these terms and +conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), conditions +are imposed on you (whether by court order, agreement or otherwise) that +contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution +of the Program by all those who receive copies directly or indirectly through +you, then the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or +other property right claims or to contest validity of any such claims; this +section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many +people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. In such +case, this License incorporates the limitation as if written in the body of this +License. + +9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will be +similar in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that +version or of any later version published by the Free Software Foundation. If +the Program does not specify a version number of this License, you may +choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software +Foundation, write to the Free Software Foundation; we sometimes make +exceptions for this. Our decision will be guided by the two goals of +preserving the free status of all derivatives of our free software and of +promoting the sharing and reuse of software generally. + + NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT +PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR +AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR +ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES +SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE +PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN +IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF +THE POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.txt Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,129 @@ + This module gives Drupal the ability to easily change links into popup dialog boxes. + + IMPORTANT INSTRUCTIONS + ------------------------------------------------------------------------------------ + Ajax updating only works with themes that have selectable content areas. + If you are not using garland, you will need to figure out the selector for your theme, + and enter it into the "Content Selector" field on the admin/build/themes/settings page + for your theme. Open the page.tpl.php file for your theme, and search for "print $content". + The $content should be surrounded by a div with an id. Ex: + <div id="content-content"> + <?php print $content; ?> + </div> <!-- /content-content --> + In this case, just enter '#content-content' into the Content Selector field. + Unfortunately, a lot of themes do not have well defined content areas. Just add the div yourself, + and then complain on the issue queue for the theme. It is important that there are no other + print statements inside the div. + + LIMITATIONS + ------------------------------------------------------------------------------------ + Is this still true? Does not work with tinymce. Unlikely to work with other WYSIWYG's. + + HOW TO USE THE POPUPS API + ------------------------------------------------------------------------------------ + If you just want to use the built in admin links, just enable the Popups: Admin Links + module and you are good to go. + If you want to add popups behavior to new links, or incorporate popups into your module, + there are a couple of ways to do it. + + #1) Attach popup behavior to a link with popups_add_popups() call. + ---------------------------------------------------------------- + <!-- In html or theme --> + <a href="popups/test/response" id="mylink"> + <a href="popups/test/response" id="mylink2"> + + // In your module + popups_add_popups(array('#mylink', '#mylink2=>array('width'=>'200px'))); + IMPORTANT: You can only put popups_add_popups in module, NOT in a .tpl file + or the template.php file. + This is the simplest method if you want to pass in per-link options. + The first key is a jQuery selector. It should select an 'a' element (unless you + are using the 'href' option). See http://docs.jquery.com/Selectors to learn more + about jQuery selectors. + The array is a set of Options. See below for the list of options. + No array means just use the defualts. + + #2) Add the class="popup" to an existing link. + ------------------------------------------- + And then either be sure popups_add_popups() is called sometime for the page, + or use the "Scan all pages for popup links" checkbox on the popups settings page. + + Example on the theme level ("Scan all pages for popups links" must be checked): + <a href="popups/test/response" class="popups"> + + Example in code: + popups_add_popups(); + $output .= l("Pop up entire local page.", 'popups/test/response', array('attributes'=>array('class' => 'popups'))); + + Here are the classes that you can use: + class="popups" requests an informational popup (or a form that doesn't want ajax processing). + class="popups-form" requests a popup with a form that modifies the content of the original page. + class="popups-form-reload" requests a popup with a form, and reloads the entire page when done. + class="popups-form-noupdate" requests a popup with a form, and leaves the original page as-is. + + You can use the pseudo-attribute, "on-popups-options" to send options, if you don't mind having non-validating HTML. + Note: this attribute gets removed from user content by the HTML filter. + Example: + print l("Pop with options (width=200px).", 'popups/test/response', + array('attributes'=>array(array('class' => 'popups', 'on-popups-options' => '{width: "200px"}')))) + See popups_test.module for more examples. + + #3) Add a custom module that implements hook_popups(). + --------------------------------------------------------------------- + hook_popups() returns an array of popup rules, keyed by the id of a form, + or the url of a page (which can use the wildcard '*'). + Each rule is an array of options, keyed by a jQuery selector. + Leaving off the options array is equal to a link with class="popup-form". + This is equivent to using a series of popup_add_popups() calls. + + Rule Format Example: + 'admin/content/taxonomy' => array( // Act only on the links on this page. + 'div#tabs-wrapper a:eq(1)', // No options, so use defaults. + 'table td:nth-child(2) a' => array( + 'noUpdate' => true, // Popup will not modify original page. + ), + ); + + #4) Make your module alter the default popup rules with hook_popups_alter(). + ---------------------------------------------------------------------------- + hook_popups_alter() allows you to modify how the popup rules are + registered. This is useful to modify the default behavior of some + already existing popup rules. + + See hook_popups_alter() in popups.api.php for an example. + + + LIST OF POPUP OPITIONS + ------------------------------------------------------------------------------------ + DEPRECATED OPTIONS +// noUpdate: Does the popup NOT modify the original page (Default: FALSE). +// reloadWhenDone: Force the entire page to reload after the popup form is submitted (Default: FALSE) +// nonModel: Not working. +// forceReturn: url to force a stop to work flow (Advanced. Use in conjunction with noUpdate or targetSelectors). +// afterSubmit: function to call when updating after successful form submission. + + doneTest: how do we know when the multiform flow is done? + null: flow is done when returned path = original path (default). + *path*: + *regexp*: done when returned path matches regexp. + updateMethod: + none: do not update the initial page + ajax: targeted replacement of parts of the initial page (default). + reload: full replacement of initial page with new page. + callback: use onUpdate(data, options, element). + updateSource (only used if updateMethod is not none): + initial: use the initial page (default). + final: use the path returned at the end of the multiform flow. + href: Override the href in the a element, or attach an href to a non-link element. + width: Override the width specified in the css. + targetSelectors: Hash of jQuery selectors that define the content to be swapped out. + titleSelectors: Array of jQuery selectors to place the new page title. + reloadOnError: Force the entire page to reload if the popup href is unaccessable (Default: FALSE) + noMessage: Don't show drupal_set_message messages. + onUpdate: function to call when updating after successful form submission. + skipDirtyCheck: If true, this popup will not check for edits on the originating page. + Often used with custom target selectors. Redundant is noUpdate is true. (Default: FALSE) + hijackDestination: Use the destiination param to force a form submit to return to the originating page. + Overwrites any destination already set one the link (Default: TRUE) + + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups.api.php Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,51 @@ +<?php +// $Id: popups.api.php,v 1.1.4.2 2009/03/05 19:52:48 starbow Exp $ + +/** + * @file + * Provides hook documentation for the Popups API. + */ + +/** + * Creates the rule registry for the popups. + */ +function hook_popups() { + $popups = array(); + $popups['admin/content/taxonomy'] = array( + // Act on the first primary tab. + 'div#tabs-wrapper a:eq(1)', + // Act on the 2nd column link in the table. + 'table td:nth-child(2) a' => array( + // Don't update the original page. + 'noUpdate' => TRUE, + ), + ); + return $popups; +} + +/** + * Allows altering of the popup rule registry. + * + * @param $popups + * The popup registry to be altered. + */ +function hook_popups_alter(&$popups) { + // Remove acting on the primary tabs. + unset($popups['admin/content/taxonomy']['div#tabs-wrapper a:eq(1)']); + + // Make clicking on the link update the original page. + $popups['admin/content/taxonomy']['table td:nth-child(2) a']['noUpdate'] = FALSE; +} + +/** + * Adds skins to the Popups API. + * + * Returns an associative array where the key is the skin name, along + * with CSS and JS values to tell where the skin can be found. + */ +function hook_popups_skins() { + $skin['My Skin'] = array( + 'css' => drupal_get_path('module', 'myskin') .'/myskin.css', + 'js' => drupal_get_path('module', 'myskin') .'/myskin.js', + ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups.css Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,47 @@ +/* +** Ajax popups dialog box styles +*/ + +#popups-overlay { + position: absolute; + z-index: 8; + background: black; + top: 0; +} +#popups-loading { + position: absolute; + z-index: 10; + opacity: 0.75; + width: 100px; + height: 100px; + display: none; +} +.popups-box { + position: absolute; + z-index: 9; + background: white; + border: 1px solid black; + padding: 0.5em; + width: 600px; + overflow: auto; +} +.popups-title { + font-weight: bold; + margin-bottom: 0.25em; +} +.popups-title div.title { + float: left; +} +.popups-title .popups-close { + float: right; +} +.popups-title .popups-close a { + font-weight: normal; +} +/* Allow messages to be used as the title of the popups */ +.popups-box div.messages { + background: transparent; + border: none; + padding: 0; + margin: 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups.info Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,13 @@ +; $Id: popups.info,v 1.4.8.2 2009/03/05 19:52:48 starbow Exp $ +name = Popups API +description = General dialog creation utilities +package = User interface +core = 6.x + + +; Information added by drupal.org packaging script on 2009-03-21 +version = "6.x-2.0-alpha5" +core = "6.x" +project = "popups" +datestamp = "1237597273" +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups.install Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,15 @@ +<?php +// $Id: popups.install,v 1.4.8.2 2009/03/05 19:52:48 starbow Exp $ + +/** + * @file + */ + +/** + * Implementation of hook_install(). + * + * Ensures popups runs after everything else, since it short circuits in hook_init. + */ +function popups_install() { + db_query("UPDATE {system} SET weight = %d WHERE name = 'popups'", 9999); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups.js Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,1158 @@ +// $Id: popups.js,v 1.9.8.12 2009/03/21 00:57:15 starbow Exp $ + +/** + * Popup Modal Dialog API + * + * Provide an API for building and displaying JavaScript, in-page, popups modal dialogs. + * Modality is provided by a fixed, semi-opaque div, positioned in front of the page contents. + * + */ + +/* + * TODO + * * Return key in add node form not working. + * * Tabledrag breaking after ahah reload. + */ + +// *************************************************************************** +// DRUPAL Namespace +// *************************************************************************** + +/** + * Attach the popups bevior to the all the requested links on the page. + * + * @param context + * The jQuery object to apply the behaviors to. + */ + +Drupal.behaviors.popups = function(context) { + Popups.saveSettings(); + + var $body = $('body'); + if(!$body.hasClass('popups-processed')) { + $body.addClass('popups-processed'); + $(document).bind('keydown', Popups.keyHandle); + var $popit = $('#popit'); + if ($popit.length) { + $popit.remove(); + Popups.message($popit.html()); + } + } + + // Add the popups-link-in-dialog behavior to links defined in Drupal.settings.popups.links array. + // Get these from current Drupal.settings, not Popups.originalSettings, as each page has it's own hooks. + if (Drupal.settings.popups && Drupal.settings.popups.links) { + jQuery.each(Drupal.settings.popups.links, function (link, options) { + Popups.attach(context, link, Popups.options(options)); + }); + } + + Popups.attach(context, '.popups', Popups.options({updateMethod: 'none'})); + Popups.attach(context, '.popups-form', Popups.options({updateMethod: 'ajax'})); // ajax reload. + Popups.attach(context, '.popups-form-reload', Popups.options({updateMethod: 'reload'})); // whole page reload. + Popups.attach(context, '.popups-form-noupdate', Popups.options({updateMethod: 'none'})); // no reload at all. +}; + +// *************************************************************************** +// Popups Namespace ********************************************************** +// *************************************************************************** +/** + * The Popups namespace contains: + * * An ordered stack of Popup objects, + * * The state of the original page, + * * Functions for managing both of the above. + */ +Popups = function(){}; + +/** + * Static variables in the Popups namespace. + */ +Popups.popupStack = []; +Popups.addedCSS = []; +Popups.addedJS = []; +Popups.originalSettings = null; // The initial popup options of the page. +/** + * Each popup object gets it's own set of options. + * These are the defaults. + */ +Popups.defaultOptions = { + doneTest: null, // null, *path*, *regexp*. how do we know when a multiform flow is done? + updateMethod: 'ajax', // none, ajax, reload, *callback* + updateSource: 'initial', // initial, final. Only used if updateMethod != none. + href: null, + width: null, // Override the width specified in the css. + targetSelectors: null, // Hash of jQuery selectors that define the content to be swapped out. + titleSelectors: null, // Array of jQuery selectors to place the new page title. + reloadOnError: false, // Force the entire page to reload if the popup href is unaccessable. + noMessage: false, // Don't show drupal_set_message messages. + skipDirtyCheck: false, // If true, this popup will not check for edits on the originating page. + hijackDestination: true // Use the destiination param to force a form submit to return to the originating page. +}; + +// *************************************************************************** +// Popups.Popup Object ******************************************************* +// *************************************************************************** +/** + * A Popup is a single modal dialog. + * The popup object encapslated all the info about a single popup. + */ +Popups.Popup = function() { + this.id = 'popups-' + Popups.nextCounter(); + + // These properties are needed if the popup contains a form that will be ajax submitted. + this.parent = null; // The popup that spawned this one. If parent is null, this popup was spawned by the original page. + this.path = null; // If popup is showing content from a url, this is that path. + this.element = null; // The DOM element that was clicked to launch this popup. + this.options = null; // An option array that control how the popup behaves. See Popups.defaultOptions for explainations. +}; +Popups.Popup.prototype.$popup = function() { + return $('#' + this.id); +}; +Popups.Popup.prototype.$popupBody = function() { + return $('#' + this.id + ' .popups-body'); +}; +Popups.Popup.prototype.$popupClose = function() { + return $('#' + this.id + ' .popups-close'); +}; +Popups.Popup.prototype.$popupTitle = function() { + return $('#' + this.id + ' .popups-title'); +}; +Popups.Popup.prototype.$popupButtons = function() { + return $('#' + this.id + ' .popups-buttons'); +}; +Popups.Popup.prototype.$popupFooter = function() { + return $('#' + this.id + ' .popups-footer'); +}; + +/** + * Create the jQuery wrapped html at the heart of the popup object. + * + * @param title + * String + * @param body + * String/HTML + * @param buttons + * Hash/Object + * @return + * The $popup. + */ +Popups.Popup.prototype.fill = function(title, body, buttons) { + return $(Drupal.theme('popupDialog', this.id, title, body, buttons)); +} + +/** + * Hide the popup by pushing it off to the side. + * Just making it display:none causes flash in FF2. + */ +Popups.Popup.prototype.hide = function() { + this.$popup().css('left', '-9999px'); +}; + +Popups.Popup.prototype.show = function() { + Popups.resizeAndCenter(this); +}; + +Popups.Popup.prototype.open = function(title, body, buttons, width){ + return Popups.open(this, title, body, buttons, width); +}; + +Popups.Popup.prototype.removePopup = function() { + Popups.removePopup(this); +}; + +/** + * Remove everything. + */ +Popups.Popup.prototype.close = function() { + return Popups.close(this); +}; + +/** + * Set the focus on the popups to the first visible, enabled form element, or the close link. + */ +Popups.Popup.prototype.refocus = function() { + // Select the first visible enabled input element. + var $popup = this.$popup(); + var $focus = $popup.find(':input:visible:enabled:first'); + if (!$focus.length) { + // There is no visible enabled input element, so select the close link. + $focus = $popup.find('.popups-close a'); + } + $focus.focus(); +}; + +/** + * Return a selector that will find target content on the layer that spawned this popup. + * This is needed for the popup to do ajax updates. + */ +Popups.Popup.prototype.targetLayerSelector = function() { + if (this.parent === null) { + return 'body'; // Select content in the original page. + } + else { + return '#' + this.parent.id; // Select content in the parent popup. + } +}; + +/** + * Determine if we are at an end point of a form flow, or just moving from one popups to another. + * + * @param path + * The path of the page that the form flow has moved to. + * This path is relative to the base_path. + * Ex: node/add/story, not http://localhost/drupal6/node/add/story or drupa6/node/add/story. + * @return bool + */ +Popups.Popup.prototype.isDone = function(path) { +// console.log("Doing isDone for popup: " + this.id + ", now at " + path ); + var done; + if (this.options.doneTest) { + // Test if we are at the path specified by doneTest. + done = (path === this.options.doneTest || path.match(this.options.doneTest)); + } + else { + if (this.parent) { + // Test if we are back to the parent popup's path. + done = (path === this.parent.path); +// console.log("Lookin at parent: " + this.parent.path + ". Done = " + done); + } + else { + // Test if we are back to the original page's path. + done = (path === Popups.originalSettings.popups.originalPath); +// console.log("Lookin at original page: " + Popups.originalSettings.popups.originalPath + ". Done = " + done); + } + }; + return done; +}; + + +// *************************************************************************** +// Popups Functions ********************************************************** +// *************************************************************************** + +/** + * Test if the param has been set. + * Used to distinguish between a value set to null or false and on not yet unset. + */ +Popups.isset = function(v) { + return (typeof(v) !== 'undefined'); +}; + +/** + * Get the currently active popup in the page. + * Currently it is the only one visible, but that could change. + */ +Popups.activePopup = function() { + if (Popups.popupStack.length) { + return Popups.popupStack[Popups.popupStack.length - 1]; // top of stack. + } + else { + return null; + } +}; + +/** + * Manage the page wide popupStack. + */ +Popups.push = function(popup) { + Popups.popupStack.push(popup); +}; +// Should I integrate this with popupRemove?? +Popups.pop = function(popup) { + return Popups.popupStack.pop(); +}; + +/** + * Build an options hash from defaults. + * + * @param overrides + * Hash of values to override the defaults. + */ +Popups.options = function(overrides) { + var defaults = Popups.defaultOptions; + return Popups.overrideOptions(defaults, overrides); +} + +/** + * Build an options hash. + * Also maps deprecated options to current options. + * + * @param defaults + * Hash of default values + * @param overrides + * Hash of values to override the defaults with. + */ +Popups.overrideOptions = function(defaults, overrides) { + var options = {}; + for(var option in defaults) { + var value; + if (Popups.isset(overrides[option])) { + options[option] = overrides[option]; + } + else { + options[option] = defaults[option]; + } + } + // Map deprecated options. + if (overrides['noReload'] || overrides['noUpdate']) { + options['updateMethod'] = 'none'; + } + if (overrides['reloadWhenDone']) { + options['updateMethod'] = 'reload'; + } + if (overrides['afterSubmit']) { + options['updateMethod'] = 'callback'; + options['onUpdate'] = overrides['afterSubmit']; + } + if (overrides['forceReturn']) { + options['doneTest'] = overrides['forceReturn']; + } + return options; +} + +/** + * Attach the popups behavior to all elements inside the context that match the selector. + * + * @param context + * Chunk of html to search. + * @param selector + * jQuery selector for elements to attach popups behavior to. + * @param options + * Hash of options associated with these links. + */ +Popups.attach = function(context, selector, options) { +// console.log(options); + $(selector, context).not('.popups-processed').each(function() { + var $element = $(this); + + // Mark the element as processed. + $element.addClass('popups-processed'); + + // Append note to link title. + var title = ''; + if ($element.attr('title')) { + title = $element.attr('title') + ' '; + } + title += Drupal.t('[Popup]'); + $element.attr('title', title); + + // Attach the on-click popup behavior to the element. + $element.click(function(event){ + return Popups.clickPopupElement(this, options); + }); + }); +}; + +/** + * Respond to click by opening a popup. + * + * @param element + * The element that was clicked. + * @param options + * Hash of options associated with the element. + */ +Popups.clickPopupElement = function(element, options) { + Popups.saveSettings(); + + // If the element contains a on-popups-options attribute, override default options param. + if ($(element).attr('on-popups-options')) { + var overrides = Drupal.parseJson($(element).attr('on-popups-options')); + options = Popups.overrideOptions(options, overrides); + } + + // The parent of the new popup is the currently active popup. + var parent = Popups.activePopup(); + + // If the option is distructive, check if the page is already modified, and offer to save. + var willModifyOriginal = !(options.updateMethod === 'none' || options.skipDirtyCheck); + if (willModifyOriginal && Popups.activeLayerIsEdited()) { + // The user will lose modifications, so show dialog offering to save current state. + Popups.offerToSave(element, options, parent); + } + else { + // Page is clean, or popup is safe, so just open it. + Popups.openPath(element, options, parent); + } + return false; +}; + +/** + * Test if the active layer been edited. + * Active layer is either the original page, or the active Popup. + */ +Popups.activeLayerIsEdited = function() { + var layer = Popups.activePopup(); + var $context = Popups.getLayerContext(layer); + // TODO: better test for edited page, maybe capture change event on :inputs. + var edited = $context.find('span.tabledrag-changed').length; + return edited; +} + +/** + * Show dialog offering to save form on parent layer. + * + * @param element + * The DOM element that was clicked. + * @param options + * The options associated with that element. + * @param parent + * The layer that has the unsaved edits. Null means the underlying page. + */ +Popups.offerToSave = function(element, options, parent) { + var popup = new Popups.Popup(); + var body = Drupal.t("There are unsaved changes in the form, which you will lose if you continue."); + var buttons = { + 'popup_save': {title: Drupal.t('Save Changes'), func: function(){Popups.saveFormOnLayer(element, options, parent);}}, + 'popup_submit': {title: Drupal.t('Continue'), func: function(){popup.removePopup(); Popups.openPath(element, options, parent);}}, + 'popup_cancel': {title: Drupal.t('Cancel'), func: function(){popup.close();}} + }; + popup.open(Drupal.t('Warning: Please Confirm'), body, buttons); +}; + +/** + * Generic dialog builder. + * Adds the newly built popup into the DOM. + * + * TODO: capture the focus if it tabs out of the dialog. + * + * @param popup + * Popups.Popup object to fill with content, place in the DOM, and show on the screen. + * @param String title + * String: title of new dialog. + * @param body (optional) + * String: body of new dialog. + * @param buttons (optional) + * Hash of button parameters. + * @param width (optional) + * Width of new dialog. + * + * @return popup object + */ +Popups.open = function(popup, title, body, buttons, width){ + Popups.addOverlay(); + + if (Popups.activePopup()) { + // Hiding previously active popup. + Popups.activePopup().hide(); + } + + if (!popup) { + // Popup object was not handed in, so create a new one. + popup = new Popups.Popup(); + } + Popups.push(popup); // Put this popup at the top of the stack. + + // Create the jQuery wrapped html for the new popup. + var $popup = popup.fill(title, body, buttons); + popup.hide(); // Hide the new popup until it is finished and sized. + + if (width) { + $popup.css('width', width); + } + + // Add the new popup to the DOM. + $('body').append($popup); + + // Add button function callbacks. + if (buttons) { + jQuery.each(buttons, function(id, button){ + $('#' + id).click(button.func); + }); + } + + // Add the default click-to-close behavior. + popup.$popupClose().click(function(){ + return Popups.close(popup); + }); + + Popups.resizeAndCenter(popup); + + // Focus on the first input element in the popup window. + popup.refocus(); + + // TODO - this isn't the place for this - should mirror addLoading calls. + // Remove the loading image. + Popups.removeLoading(); + + return popup; +}; + +/** + * Adjust the popup's height to fit it's content. + * Move it to be centered on the screen. + * This undoes the effects of popup.hide(). + * + * @param popup + */ +Popups.resizeAndCenter = function(popup) { + var $popup = popup.$popup(); + + // center on the screen, adding in offsets if the window has been scrolled + var popupWidth = $popup.width(); + var windowWidth = Popups.windowWidth(); + var left = (windowWidth / 2) - (popupWidth / 2) + Popups.scrollLeft(); + + // Get popups's height on the page. + $popup.css('height', 'auto'); // Reset height. + var popupHeight = $popup.height(); + $popup.height(popupHeight); + var windowHeight = Popups.windowHeight(); + + if (popupHeight > (0.9 * windowHeight) ) { // Must fit in 90% of window. + popupHeight = 0.9 * windowHeight; + $popup.height(popupHeight); + } + var top = (windowHeight / 2) - (popupHeight / 2) + Popups.scrollTop(); + + $popup.css('top', top).css('left', left); // Position the popups to be visible. +}; + + +/** + * Create and show a simple popup dialog that functions like the browser's alert box. + */ +Popups.message = function(title, message) { + message = message || ''; + var popup = new Popups.Popup(); + var buttons = { + 'popup_ok': {title: Drupal.t('OK'), func: function(){popup.close();}} + }; + popup.open(title, message, buttons); + return popup; +}; + +/** + * Handle any special keys when popups is active. + */ +Popups.keyHandle = function(e) { + if (!e) { + e = window.event; + } + switch (e.keyCode) { + case 27: // esc + Popups.close(); + break; + case 191: // '?' key, show help. + if (e.shiftKey && e.ctrlKey) { + var $help = $('a.popups.more-help'); + if ($help.size()) { + $help.click(); + } + else { + Popups.message(Drupal.t("Sorry, there is no additional help for this page")); + } + } + break; + } +}; + +/***************************************************************************** + * Appearence Functions (overlay, loading graphic, remove popups) ********* + *****************************************************************************/ + +/** + * Add full page div between the page and the dialog, to make the popup modal. + */ +Popups.addOverlay = function() { + var $overlay = $('#popups-overlay'); + if (!$overlay.length) { // Overlay does not already exist, so create it. + $overlay = $(Drupal.theme('popupOverlay')); + $overlay.css('opacity', '0.4'); // for ie6(?) + // Doing absolute positioning, so make overlay's size equal the entire body. + var $doc = $(document); + $overlay.width($doc.width()).height($doc.height()); + $overlay.click(function(){Popups.close();}); + $('body').prepend($overlay); + } +}; + +/** + * Remove overlay if popupStack is empty. + */ +Popups.removeOverlay = function() { + if (!Popups.popupStack.length) { + $('#popups-overlay').remove(); + } +}; + +/** + * Add a "Loading" message while we are waiting for the ajax response. + */ +Popups.addLoading = function() { + var $loading = $('#popups-loading'); + if (!$loading.length) { // Loading image does not already exist, so create it. + $loading = $(Drupal.theme('popupLoading')); + $('body').prepend($loading); // Loading div is initially display:none. + var width = $loading.width(); + var height = $loading.height(); + var left = (Popups.windowWidth() / 2) - (width / 2) + Popups.scrollLeft(); + var top = (Popups.windowHeight() / 2) - (height / 2) + Popups.scrollTop(); + $loading.css({'top': top, 'left': left, 'display': 'block'}); // Center it and make it visible. + } +}; + +Popups.removeLoading = function() { + $('#popups-loading').remove(); +}; + +// Should I fold this function into Popups.pop? +Popups.removePopup = function(popup) { +// console.log("Popups.removePopup: " + popup); + if (!Popups.isset(popup)) { + popup = Popups.activePopup(); + } + if (popup) { +// console.log('removing '+popup.id); + popup.$popup().remove(); + Popups.popupStack.splice(Popups.popupStack.indexOf(popup), 1); // Remove popup from stack. Probably should rework into .pop() + } +// else { +// console.log("Popups.removePopup - there is no popup to remove."); +// } +}; + +/** + * Remove everything. + */ +Popups.close = function(popup) { + if (!Popups.isset(popup)) { + popup = Popups.activePopup(); + } + Popups.removePopup(popup); // Should this be a pop?? + Popups.removeLoading(); + if (Popups.activePopup()) { + Popups.activePopup().show(); + Popups.activePopup().refocus(); + } + else { + Popups.removeOverlay(); + Popups.restorePage(); + } + return false; +}; + +/** + * Save the page's original Drupal.settings. + */ +Popups.saveSettings = function() { + if (!Popups.originalSettings) { + Popups.originalSettings = Drupal.settings; + } +}; + +/** + * Restore the page's original Drupal.settings. + */ +Popups.restoreSettings = function() { + Drupal.settings = Popups.originalSettings; +}; + +/** + * Remove as much of the effects of jit loading as possible. + */ +Popups.restorePage = function() { + Popups.restoreSettings(); + // Remove the CSS files that were jit loaded for popup. + for (var i in Popups.addedCSS) { + var link = Popups.addedCSS[i]; + $('link[href='+ $(link).attr('href') + ']').remove(); + } + Popups.addedCSS = []; +}; + + +/**************************************************************************** + * Utility Functions ****************************************************** + ****************************************************************************/ + +/** + * Get the position of the left side of the browser window. + */ +Popups.scrollLeft = function() { + return Math.max(document.documentElement.scrollLeft, document.body.scrollLeft); +}; + +/** + * Get the position of the top of the browser window. + */ +Popups.scrollTop = function() { + return Math.max(document.documentElement.scrollTop, document.body.scrollTop); +}; + +/** + * Get the height of the browser window. + * Fixes jQuery & Opera bug - http://drupal.org/node/366093 + */ +Popups.windowHeight = function() { + if ($.browser.opera && $.browser.version > "9.5" && $.fn.jquery <= "1.2.6") { + return document.documentElement.clientHeight; + } + return $(window).height(); +}; + +/** + * Get the height of the browser window. + * Fixes jQuery & Opera bug - http://drupal.org/node/366093 + */ +Popups.windowWidth = function() { + if ($.browser.opera && $.browser.version > "9.5" && $.fn.jquery <= "1.2.6") { + return document.documentElement.clientWidth; + } + return $(window).width(); +}; + +Popups.nextCounter = function() { + if (this.counter === undefined) { + this.counter = 0; + } + else { + this.counter++; + } + return this.counter; +}; + +/**************************************************************************** + * Ajax Functions ****************************************************** + ****************************************************************************/ + +/** + * Add additional CSS to the page. + */ +Popups.addCSS = function(css) { + Popups.addedCSS = []; + for (var type in css) { + for (var file in css[type]) { + var link = css[type][file]; + // Does the page already contain this stylesheet? + if (!$('link[href='+ $(link).attr('href') + ']').length) { + $('head').append(link); + Popups.addedCSS.push(link); // Keep a list, so we can remove them later. + } + } + } +}; + +/** + * Add additional Javascript to the page. + */ +Popups.addJS = function(js) { + // Parse the json info about the new context. + var scripts = []; + var inlines = []; + for (var type in js) { + if (type != 'setting') { + for (var file in js[type]) { + if (type == 'inline') { + inlines.push($(js[type][file]).text()); + } + else { + scripts.push($(js[type][file]).attr('src')); + } + } + } + } + + // Add new JS settings to the page, needed for #ahah properties to work. + Drupal.settings = js.setting; +// console.log('js.setting...'); +// console.log(js.setting); + + for (var i in scripts) { + var src = scripts[i]; + if (!$('script[src='+ src + ']').length && !Popups.addedJS[src]) { + // Get the script from the server and execute it. + $.ajax({ + type: 'GET', + url: src, + dataType: 'script', + async : false, + success: function(script) { + eval(script); + } + }); + // Mark the js as added to the underlying page. + Popups.addedJS[src] = true; + } + } + + return inlines; +}; + +/** + * Execute the jit loaded inline scripts. + * Q: Do we want to re-excute the ones already in the page? + * + * @param inlines + * Array of inline scripts. + */ +Popups.addInlineJS = function(inlines) { + // Load the inlines into the page. + for (var n in inlines) { + // If the script is not already in the page, execute it. + if (!$('script:not([src]):contains(' + inlines[n] + ')').length) { + eval(inlines[n]); + } + } +}; + +Popups.beforeSend = function(xhr) { + xhr.setRequestHeader("X-Drupal-Render-Mode", 'json/popups'); +}; + +/** + * Do before the form in the popups is submitted. + */ +Popups.beforeSubmit = function(formData, $form, options) { + Popups.removePopup(); // Remove just the dialog, but not the overlay. + Popups.addLoading(); +}; + + +/**************************************************************************** + * Page & Form in popups functions *** + ****************************************************************************/ + +/** + * Use Ajax to open a link in a popups window. + * + * @param element + * Element that was clicked to open the popups. + * @param options + * Hash of options controlling how the popups interacts with the underlying page. + * @param parent + * If path is being opened from inside another popup, that popup is the parent. + */ +Popups.openPath = function(element, options, parent) { + Popups.saveSettings(); + + // Let the user know something is happening. + $('body').css("cursor", "wait"); + + // TODO - get nonmodal working. + if (!options.nonModal) { + Popups.addOverlay(); + } + Popups.addLoading(); + + var href = options.href ? options.href : element.href; + $(document).trigger('popups_open_path', [element, href]); // Broadcast Popup Open Path event. + + var params = {}; + // Force the popups to return back to the orignal page when forms are done, unless hijackDestination option is set to FALSE. + if (options.hijackDestination) { + var returnPath; + if (parent) { + returnPath = parent.path; +// console.log('Popup parent is ...'); +// console.log(parent); + } + else { // No parent, so bring flow back to original page. + returnPath = Popups.originalSettings.popups.originalPath; + } + href = href.replace(/destination=[^;&]*[;&]?/, ''); // Strip out any existing destination param. +// console.log("Hijacking destination to " + returnPath); + params.destination = returnPath; // Set the destination to return to the parent's path. + } + + var ajaxOptions = { + url: href, + dataType: 'json', + data: params, + beforeSend: Popups.beforeSend, + success: function(json) { + // Add additional CSS to the page. + Popups.addCSS(json.css); + var inlines = Popups.addJS(json.js); + var popup = Popups.openPathContent(json.path, json.title, json.messages + json.content, element, options, parent); + Popups.addInlineJS(inlines); + // Broadcast an event that the path was opened. + $(document).trigger('popups_open_path_done', [element, href, popup]); + }, + complete: function() { + $('body').css("cursor", "auto"); // Return the cursor to normal state. + } + }; + + var ajaxOptions; + if (options.reloadOnError) { + ajaxOptions.error = function() { + location.reload(); // Reload on error. Is this working? + }; + } + else { + ajaxOptions.error = function() { + Popups.message("Unable to open: " + href); + }; + } + $.ajax(ajaxOptions); + + return false; +}; + +/** + * Open path's content in an ajax popups. + * + * @param title + * String title of the popups. + * @param content + * HTML to show in the popups. + * @param element + * A DOM object containing the element that was clicked to initiate the popup. + * @param options + * Hash of options controlling how the popups interacts with the underlying page. + * @param parent + * Spawning popup, or null if spawned from original page. + */ +Popups.openPathContent = function(path, title, content, element, options, parent) { + var popup = new Popups.Popup(); + Popups.open(popup, title, content, null, options.width); + + // Set properties on new popup. + popup.parent = parent; + popup.path = path; +// console.log("Setting popup " + popup.id + " originalPath to " + path); + popup.options = options; + popup.element = element; + + // Add behaviors to content in popups. + delete Drupal.behaviors.tableHeader; // Work-around for bug in tableheader.js (http://drupal.org/node/234377) + delete Drupal.behaviors.teaser; // Work-around for bug in teaser.js (sigh). + Drupal.attachBehaviors(popup.$popupBody()); + // Adding collapse moves focus. + popup.refocus(); + + // If the popups contains a form, capture submits. + var $form = $('form', popup.$popupBody()); + if ($form.length) { + $form.ajaxForm({ + dataType: 'json', + beforeSubmit: Popups.beforeSubmit, + beforeSend: Popups.beforeSend, + success: function(json, status) { + Popups.formSuccess(popup, json); + }, + error: function() { + Popups.message("Bad Response form submission"); + } + }); + } + return popup; +}; + +/** + * The form in the popups was successfully submitted + * Update the originating page. + * Show any messages in a popups. + * + * @param popup + * The popup object that contained the form that was just submitted. + * @param data + * JSON object from server with status of form submission. + */ +Popups.formSuccess = function(popup, data) { + // Determine if we are at an end point, or just moving from one popups to another. + var done = popup.isDone(data.path); + if (!done) { // Not done yet, so show new page in new popups. + Popups.removeLoading(); + Popups.openPathContent(data.path, data.title, data.messages + data.content, popup.element, popup.options, popup.parent); + } + else { // We are done with popup flow. + // Execute the onUpdate callback if available. + if (popup.options.updateMethod === 'callback' && popup.options.onUpdate) { + var result = eval(popup.options.onUpdate +'(data, popup.options, popup.element)'); + if (result === false) { // Give onUpdate callback a chance to skip normal processing. + return; + } + } + + if (popup.options.updateMethod === 'reload') { // Force a complete, non-ajax reload of the page. + if (popup.options.updateSource === 'final') { + location.href = Drupal.settings.basePath + data.path; // TODO: Need to test this. + } + else { // Reload originating page. + location.reload(); + } + } + else { // Normal, targeted ajax, reload behavior. + // Show messages in dialog and embed the results in the original page. + var showMessage = data.messages.length && !popup.options.noMessage; + if (showMessage) { + var messagePopup = Popups.message(data.messages); // Popup message. + if (Popups.originalSettings.popups.autoCloseFinalMessage) { + setTimeout(function(){Popups.close(messagePopup);}, 2500); // Autoclose the message box in 2.5 seconds. + } + + // Insert the message into the page above the content. + // Might not be the standard spot, but it is the easiest to find. + var $next; + if (popup.targetLayerSelector() === 'body') { + $next = $('body').find(Popups.originalSettings.popups.defaultTargetSelector); + } + else { + $next = $(popup.targetLayerSelector()).find('.popups-body'); + } + $next.parent().find('div.messages').remove(); // Remove the existing messages. + $next.before(data.messages); // Insert new messages. + } + + // Update the content area (defined by 'targetSelectors'). + if (popup.options.updateMethod !== 'none') { + Popups.testContentSelector(); // Kick up warning message if selector is bad. + + Popups.restoreSettings(); // Need to restore original Drupal.settings.popups.links before running attachBehaviors. This probably has CSS side effects! + if (popup.options.targetSelectors) { // Pick and choose what returned content goes where. + jQuery.each(popup.options.targetSelectors, function(t_new, t_old) { + if(!isNaN(t_new)) { + t_new = t_old; // handle case where targetSelectors is an array, not a hash. + } +// console.log("Updating target " + t_old + ' with ' + t_new); + var new_content = $(t_new, data.content); +// console.log("new content... "); +// console.log(new_content); + var $c = $(popup.targetLayerSelector()).find(t_old).html(new_content); // Inject the new content into the original page. + + Drupal.attachBehaviors($c); + }); + } + else { // Put the entire new content into default content area. + var $c = $(popup.targetLayerSelector()).find(Popups.originalSettings.popups.defaultTargetSelector).html(data.content); +// console.log("updating entire content area.") + Drupal.attachBehaviors($c); + } + } + + // Update the title of the page. + if (popup.options.titleSelectors) { + jQuery.each(popup.options.titleSelectors, function() { + $(''+this).html(data.title); + }); + } + + // Done with changes to the original page, remove effects. + Popups.removeLoading(); + if (!showMessage) { + // If there is not a messages popups, close current layer. + Popups.close(); + } + } + + // Broadcast an event that popup form was done and successful. + $(document).trigger('popups_form_success', [popup]); + + } // End of updating spawning layer. +}; + + +/** + * Get a jQuery object for the content of a layer. + * @param layer + * Either a popup, or null to signify the original page. + */ +Popups.getLayerContext = function(layer) { + var $context; + if (!layer) { + $context = $('body').find(Popups.originalSettings.popups.defaultTargetSelector); + } + else { + $context = layer.$popupBody(); + } + return $context; +} + +/** + * Submit the page and reload the results, before popping up the real dialog. + * + * @param element + * Element that was clicked to open a new popup. + * @param options + * Hash of options controlling how the popups interacts with the underlying page. + * @param layer + * Popup with form to save, or null if form is on original page. + */ +Popups.saveFormOnLayer = function(element, options, layer) { + var $context = Popups.getLayerContext(layer); + var $form = $context.find('form'); + var ajaxOptions = { + dataType: 'json', + beforeSubmit: Popups.beforeSubmit, + beforeSend: Popups.beforeSend, + success: function(response, status) { + // Sync up the current page contents with the submit. + var $c = $context.html(response.content); // Inject the new content into the page. + Drupal.attachBehaviors($c); + // The form has been saved, the page reloaded, now safe to show the triggering link in a popup. + Popups.openPath(element, options, layer); + } + }; + $form.ajaxSubmit(ajaxOptions); // Submit the form. +}; + +/** + * Warn the user if ajax updates will not work + * due to mismatch between the theme and the theme's popup setting. + */ +Popups.testContentSelector = function() { + var target = Popups.originalSettings.popups.defaultTargetSelector; + var hits = $(target).length; + if (hits !== 1) { // 1 is the corrent answer. + var msg = Drupal.t('The popup content area for this theme is misconfigured.') + '\n'; + if (hits === 0) { + msg += Drupal.t('There is no element that matches ') + '"' + target + '"\n'; + } + else if (hits > 1) { + msg += Drupal.t('There are multiple elements that match: ') + '"' + target + '"\n'; + } + msg += Drupal.t('Go to admin/build/themes/settings, select your theme, and edit the "Content Selector" field'); + alert(msg); + } +}; + + +// **************************************************************************** +// * Theme Functions ******************************************************** +// **************************************************************************** + +Drupal.theme.prototype.popupLoading = function() { + var loading = '<div id="popups-loading">'; + loading += '<img src="'+ Drupal.settings.basePath + Popups.originalSettings.popups.modulePath + '/ajax-loader.gif" />'; + loading += '</div>'; + return loading; +}; + +Drupal.theme.prototype.popupOverlay = function() { + return '<div id="popups-overlay"></div>'; +}; + +Drupal.theme.prototype.popupButton = function(title, id) { + return '<input type="button" value="'+ title +'" id="'+ id +'" />'; +}; + +Drupal.theme.prototype.popupDialog = function(popupId, title, body, buttons) { + var template = Drupal.theme('popupTemplate', popupId); + var popups = template.replace('%title', title).replace('%body', body); + + var themedButtons = ''; + if (buttons) { + jQuery.each(buttons, function (id, button) { + themedButtons += Drupal.theme('popupButton', button.title, id); + }); + } + popups = popups.replace('%buttons', themedButtons); + return popups; +}; + +Drupal.theme.prototype.popupTemplate = function(popupId) { + var template; + template += '<div id="'+ popupId + '" class="popups-box">'; + template += ' <div class="popups-title">'; + template += ' <div class="popups-close"><a href="#">' + Drupal.t('Close') + '</a></div>'; + template += ' <div class="title">%title</div>'; + template += ' <div class="clear-block"></div>'; + template += ' </div>'; + template += ' <div class="popups-body">%body</div>'; + template += ' <div class="popups-buttons">%buttons</div>'; + template += ' <div class="popups-footer"></div>'; + template += '</div>'; + return template; +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups.module Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,451 @@ +<?php +// $Id: popups.module,v 1.11.8.10 2009/03/21 00:57:15 starbow Exp $ + +/** + * @file + * This module provides a hook_popups for links to be openned in an Ajax Popup Modal Dialog. + */ + + +// ************************************************************************** +// CORE HOOK FUNCTIONS **************************************************** +// ************************************************************************** + +/** + * Implementation of hook_menu(). + * + * @return array of new menu items. + */ +function popups_menu() { + + // Admin Settings. + $items['admin/settings/popups'] = array( + 'page callback' => 'drupal_get_form', + 'page arguments' => array('popups_admin_settings'), + 'title' => 'Popups', + 'access arguments' => array('administer site configuration'), + 'description' => 'Configure the page-in-a-dialog behavior.', + ); + + return $items; +} + +/** + * Implementation of hook_init(). + * + * Look at the page path and see if popup behavior has been requested for any links in this page. + */ +function popups_init() { + $popups = popups_get_popups(); + + if (variable_get('popups_always_scan', 0)) { + popups_add_popups(); + } + + foreach ($popups as $path => $popup_config) { + if ($path == $_GET['q']) { + popups_add_popups($popup_config); + } + elseif (strpos($path, '*') !== FALSE && drupal_match_path($_GET['q'], $path)) { + popups_add_popups($popup_config); + } + } + + $render_mode = ''; + if (isset($_SERVER['HTTP_X_DRUPAL_RENDER_MODE'])) { + $render_mode = $_SERVER['HTTP_X_DRUPAL_RENDER_MODE']; + } + + // Check and see if the page_override param is in the URL. + // Note - the magic happens here. + // Need to cache the page_override flag in the session, so it will effect + // the results page that follows a form submission. + if ($render_mode == 'json/popups') { + $_SESSION['page_override'] = TRUE; + } + + // Move the page_override flag back out of the session. + if (isset($_SESSION['page_override'])) { + // This call will not return on form submission. + $content = menu_execute_active_handler(); + + // The call did return, so it wasn't a form request, + // so we are returning a result, so clear the session flag. + $override = $_SESSION['page_override']; + unset($_SESSION['page_override']); + + // Menu status constants are integers; page content is a string. + if (isset($content) && !is_int($content) && isset($override)) { + print popups_render_as_json($content); + exit; // Do not continue processing request in index.html. + } + } + +} + +/** + * Implementation of hook_form_alter(). + * + * Look at the form_id and see if popup behavior has been requested for any links in this form. + * + * @param form_array $form + * @param array $form_state + * @param str $form_id: + */ +function popups_form_alter(&$form, $form_state, $form_id) { + // Add popup behavior to the form if requested. +// dsm($form_id); + $popups = popups_get_popups(); + if (isset($popups[$form_id])) { + popups_add_popups($popups[$form_id]); + } + + // Alter the theme configuration pages, to add a per-theme-content selector. + $theme = arg(4); + if ($form_id == 'system_theme_settings' && $theme) { + $form['popups'] = array( + '#type' => 'fieldset', + '#title' => t('Popup Settings'), + '#weight' => -2, + ); + $form['popups']['popups_content_selector'] = array( + '#type' => 'textfield', + '#title' => t('Content Selector'), + '#default_value' => variable_get('popups_'. $theme .'_content_selector', _popups_default_content_selector()), + '#description' => t("jQuery selector to define the page's content area on this theme."), + ); + $form['popups']['popups_theme'] = array( + '#type' => 'hidden', + '#value' => $theme, + ); + $form['#submit'][] = 'popups_theme_settings_form_submit'; + } +} + +// ************************************************************************** +// UTILITY FUNCTIONS ****************************************************** +// ************************************************************************** + +/** + * Render the page contents in a custom json wrapper. + * + * @param $content: themed html. + * @return $content in a json wrapper with metadata. + */ +function popups_render_as_json($content) { + $path = $_GET['q']; // Get current path from params. + return drupal_json(array( + 'title' => drupal_get_title(), + 'messages' => theme('status_messages'), + 'path' => $path, + 'content' => $content, + 'js' => popups_get_js(), + 'css' => popups_get_css(), + )); +} + +/** + * Get the added JS in a format that is readable by popups.js. + */ +function popups_get_js() { + $js = array_merge_recursive(drupal_add_js(), drupal_add_js(NULL, NULL, 'footer')); + $query_string = '?'. substr(variable_get('css_js_query_string', '0'), 0, 1); + + $popup_js = array(); + + foreach ($js as $type => $data) { + if (!$data) continue; + switch ($type) { + case 'setting': + // Why not just array_merge_recursive($data); + $popup_js['setting'] = call_user_func_array('array_merge_recursive', $data); + break; + case 'inline': + foreach ($data as $info) { + $popup_js['inline'][] = '<script type="text/javascript"' . ($info['defer'] ? ' defer="defer"' : '') . '>' . $info['code'] . "</script>\n"; + } + break; + default: + foreach ($data as $path => $info) { + $popup_js[$type][$path] = '<script type="text/javascript"'. ($info['defer'] ? ' defer="defer"' : '') .' src="'. base_path() . $path . $query_string ."\"></script>\n"; + } + break; + } + } + + // A special exception, never include the popups settings in the JS array. + // ??? +// unset($popup_js['setting']['popups']); + + return $popup_js; +} + +/** + * Get the added CSSS in a format that is readable by popups.js. + */ +function popups_get_css() { + $css = drupal_add_css(); + $popup_css = array(); + + $query_string = '?'. substr(variable_get('css_js_query_string', '0'), 0, 1); + + // Only process styles added to "all". + $media = 'all'; + foreach ($css[$media] as $type => $files) { + if ($type == 'module') { + // Setup theme overrides for module styles. + $theme_styles = array(); + foreach (array_keys($css[$media]['theme']) as $theme_style) { + $theme_styles[] = basename($theme_style); + } + } + foreach($css[$media][$type] as $file => $preprocess) { + // If the theme supplies its own style using the name of the module style, skip its inclusion. + // This includes any RTL styles associated with its main LTR counterpart. + if ($type == 'module' && in_array(str_replace('-rtl.css', '.css', basename($file)), $theme_styles)) { + // Unset the file to prevent its inclusion when CSS aggregation is enabled. + unset($css[$media][$type][$file]); + continue; + } + // Only include the stylesheet if it exists. + if (file_exists($file)) { + // If a CSS file is not to be preprocessed and it's a module CSS file, it needs to *always* appear at the *top*, + // regardless of whether preprocessing is on or off. + if ($type == 'module') { + $popup_css['module'][$file] = '<link type="text/css" rel="stylesheet" media="'. $media .'" href="'. base_path() . $file . $query_string .'" />'."\n"; + } + // If a CSS file is not to be preprocessed and it's a theme CSS file, it needs to *always* appear at the *bottom*, + // regardless of whether preprocessing is on or off. + else if ($type == 'theme') { + $popup_css['theme'][$file] = '<link type="text/css" rel="stylesheet" media="'. $media .'" href="'. base_path() . $file . $query_string .'" />'."\n"; + } + else { + $popup_css['unknown'][$file] = '<link type="text/css" rel="stylesheet" media="'. $media .'" href="'. base_path() . $file . $query_string .'" />'."\n"; + } + } + } + } + + return $popup_css; +} + + +/** + * Define hook_popups(). + * Build the list of popup rules from all modules that implement hook_popups. + * + * Retrieves the list of popup rules from all modules that implement hook_popups. + * + * @param $reset + * (optional) If set to TRUE, forces the popup rule cache to reset. + * + */ +function popups_get_popups($reset = FALSE) { + static $popups = NULL; + if (!isset($popups) || $reset) { + // Get popups hash out of cache. + if (!$reset && ($cache = cache_get('popups:popups')) && !empty($cache->data)) { + $popups = $cache->data; + } + else { + // Call all hook_popups and cache results. + $popups = module_invoke_all('popups'); + + // Invoke hook_popups_alter() to allow altering the default popups registry. + drupal_alter('popups', $popups); + + // Save the popup registry in the cache. + cache_set('popups:popups', $popups); + } + } + return $popups; +} + +/** + * Attach the popup behavior to the page. + * + * The default behavoir of a popup is to open a form that will modify the original page. + * The popup submits the form and reloads the original page with the resulting new content. + * The popup then replaces the original page's content area with the new copy of that content area. + * + * @param array $rules: Array of rules to apply to the page or form, keyed by jQuery link selector. + * See README.txt for a listing of the options, and popups_admin.module for examples. + */ +function popups_add_popups($rules=NULL) { + static $added = FALSE; + $settings = array('popups' => array()); + + if (is_array($rules)) { + $settings['popups']['links'] = array(); + foreach ($rules as $popup_selector => $options) { + if (is_array($options)) { + $settings['popups']['links'][$popup_selector] = $options; + } + else { + $settings['popups']['links'][$options] = array(); + } + } + if($added) { + drupal_add_js( $settings, 'setting' ); + } + } + if (!$added) { + // Determing if we are showing the default theme or a custom theme. + global $custom_theme; + $theme = $custom_theme; + if (!$theme) { + $theme = variable_get('theme_default','none'); + } + + drupal_add_js('misc/jquery.form.js'); + drupal_add_css(drupal_get_path('module', 'popups') .'/popups.css'); + drupal_add_js(drupal_get_path('module', 'popups') .'/popups.js'); + + // Allow skinning of the popup. + $skin = variable_get('popups_skin', 'Basic'); + $skins = popups_skins(); + if (!$skins[$skin]['css']) { // $skin == 'Unskinned' + // Look in the current theme for popups-skin.js + drupal_add_js(drupal_get_path('theme', $theme) . '/popups-skin.js'); + } + else { // Get css and js from selected skin. + drupal_add_css($skins[$skin]['css']); + if (isset($skins[$skin]['js'])) { + drupal_add_js($skins[$skin]['js']); + } + } + + $default_target_selector = variable_get('popups_'. $theme .'_content_selector', _popups_default_content_selector()); + + $settings['popups']['originalPath'] = $_GET['q']; + $settings['popups']['defaultTargetSelector'] = $default_target_selector; + $settings['popups']['modulePath'] = drupal_get_path('module', 'popups'); +// $settings['popups']['popupFinalMessage'] = variable_get('popups_popup_final_message', 1); + $settings['popups']['autoCloseFinalMessage'] = variable_get('popups_autoclose_final_message', 1); + drupal_add_js( $settings, 'setting' ); + $added = TRUE; + } +} + + /** + * Retrieve all information from the popup skin registry. + * + * @param $reset + * (optional) If TRUE, will force the the skin registry to reset. + * @see popups_popups_skins + */ +function popups_skins($reset = FALSE) { + static $skins = array(); + if (empty($skins) || $reset) { + if (!$reset && ($cache = cache_get('popups:skins')) && !empty($cache->data)) { + $skins = $cache->data; + } + else { + // Create the popup skin registry (hook_popups_skins) and cache it. + $skins = module_invoke_all('popups_skins'); + ksort($skins); // Sort them alphabetically + cache_set('popups:skins', $skins, 'cache', CACHE_PERMANENT); + } + } + return $skins; +} + +/** + * Implementation of hook_popups_skins. + * + * This hook allows other modules to create additional custom skins for the + * popups module. + * + * @return array + * An array of key => value pairs suitable for inclusion as the #options in a + * select or radios form element. Each key must be the location of at least a + * css file for a popups skin. Optionally can have a js index as well. Each + * value should be the name of the skin. + */ +function popups_popups_skins() { + $skins = array(); + $skins_directory = drupal_get_path('module', 'popups') .'/skins'; + $files = file_scan_directory($skins_directory, '\.css$'); + + foreach ($files as $file) { + $name = drupal_ucfirst($file->name); + $skins[$name]['css'] = $file->filename; + $js = substr_replace($file->filename, '.js', -4); + if (file_exists($js)) { + $skins[$name]['js'] = $js; + } + } + return $skins; +} + + +/** + * Returns the default jQuery content selector as a string. + * Currently uses the selector for Garland. + * Sometime in the future I will change this to '#content' or '#content-content'. + */ +function _popups_default_content_selector() { + return 'div.left-corner > div.clear-block:last'; // Garland in Drupal 6. +} + +// ************************************************************************** +// ADMIN SETTINGS ********************************************************* +// ************************************************************************** + +/** + * Form for the Popups Settings page. + * + */ +function popups_admin_settings() { + popups_add_popups(); +// drupal_add_css(drupal_get_path('module', 'popups'). '/skins/blue/blue.css'); // temp + drupal_set_title("Popups Settings"); + $form = array(); + + $form['popups_always_scan'] = array( + '#type' => 'checkbox', + '#title' => t('Scan all pages for popup links.'), + '#default_value' => variable_get('popups_always_scan', 0), + ); + $form['popups_autoclose_final_message'] = array( + '#type' => 'checkbox', + '#title' => t('Automatically close final confirmation messages.'), + '#default_value' => variable_get('popups_autoclose_final_message', 1), + ); + + // Retrieve all available skins, forcing the registry to refresh. + $skins['Unskinned'] = array(); + $skins += popups_skins(TRUE); + + $skin_options = drupal_map_assoc(array_keys($skins)); + $form['popups_skins'] = array( + '#type' => 'fieldset', + '#title' => t('Skins'), + '#description' => t('Choose a skin from the list. After you save, click !here to test it out.', array('!here' => l('here', 'user', array('attributes' => array('class' => 'popups'))))), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + ); + $form['popups_skins']['popups_skin'] = array( + '#type' => 'radios', + '#title' => t('Available skins'), + '#default_value' => variable_get('popups_skin', 'Basic'), + '#options' => $skin_options, + ); + + + return system_settings_form($form); +} + +/** + * popups_form_alter adds this submit handler to the theme pages. + * Set a per-theme jQuery content selector that gets passed into the js settings. + * + * @param $form + * @param $form_state + */ +function popups_theme_settings_form_submit($form, &$form_state) { + $theme = $form_state['values']['popups_theme']; + $content_selector = $form_state['values']['popups_content_selector']; + variable_set('popups_'. $theme .'_content_selector', $content_selector); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups_admin.info Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,14 @@ +; $Id: popups_admin.info,v 1.1.6.3 2009/03/05 19:52:48 starbow Exp $ +name = Popups: Administration Links +description = Uses the Popups API to add popups to various administration pages. +package = User interface +core = 6.x +dependencies[] = popups + + +; Information added by drupal.org packaging script on 2009-03-21 +version = "6.x-2.0-alpha5" +core = "6.x" +project = "popups" +datestamp = "1237597273" +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups_admin.module Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,103 @@ +<?php +// $Id: popups_admin.module,v 1.1.6.7 2009/03/21 00:57:16 starbow Exp $ + +/** + * @file + * Uses the popups API to add some popups to admin pages. + * + * @todo + * Adding Javascript into popups doesn't always work. + * tabledrag onmouse up action. + * user.js and teaser.js bugs. + * Taxonomy > Add vocab. Adding second item to page does not trigger d-n-d transformation. + * Might be a problem with Taxonomy. Menus doesn't have problem (adds d-n-d on first item). + * Comment view: popup is too small to contain comment. + */ + +/** + * hook_popups + * + * This implements hook_popups, defined in popups_get_popups. + * It adds page-in-popup behavior to the core admin pages. + * See the comments in popups_add_popups for explination of the options. + * + */ +function popups_admin_popups() { + + return array( + 'admin/build/block' => array( // Blocks admin page. + '#tabs-wrapper a[href$=admin/build/block/add]', // Add Block + '#blocks a[href~=admin/build/block/configure]', // configure + '#blocks a[href~=admin/build/block/delete]', // delete + ), + 'admin/build/block/list/*' => array( // Blocks admin page. + '#tabs-wrapper a[href$=admin/build/block/add]', // Add Block + '#blocks a[href~=admin/build/block/configure]', // configure + '#blocks a[href~=admin/build/block/delete]', // delete + ), + 'admin/build/path' => array( // URL aliases admin page. + '#tabs-wrapper a[href$=admin/build/path/add]', // Add alias + 'td:nth-child(3) a[href~=admin/build/path/edit]', // edit alias + 'td:nth-child(4) a[href~=admin/build/path/delete]', // delete alias + ), + 'admin/content/taxonomy' => array( // Taxonomy admin page. + '#tabs-wrapper a[href$=admin/content/taxonomy/add/vocabulary]', // Add vocabulary + '#taxonomy-overview-vocabularies td a:contains('. t('edit vocabulary') .')', // edit vocabulary + '#taxonomy-overview-vocabularies td a:contains('. t('list terms') .')' => array( // list terms + 'noUpdate' => TRUE, + ), + '#taxonomy-overview-vocabularies td a:contains('. t('add terms') .')' => array( // add terms + 'noUpdate' => TRUE, + ), + ), + 'admin/content/types' => array( // Content Type admin page + '#tabs-wrapper a[href$=admin/content/types/add]', // Add content type + 'table td:nth-child(4) a, table td:nth-child(5) a, table td:nth-child(7) a' // edit, add field, delete + ), + 'admin/content/types/list' => array( // Content Type admin page + '#tabs-wrapper a[href$=admin/content/types/add]', // Add content type + 'table td:nth-child(4) a, table td:nth-child(5) a, table td:nth-child(7) a' // edit, add field, delete + ), + 'admin/content/node' => array( // Existing Content admin page + '#node-admin-content td a:contains('. t('edit') .')', // edit + ), +// 'page_node_form' => array( // Node edit form + 'node/add/*' => array( // Node edit form + 'a[href$=filter/tips]' => array( // Fixes insane "More information..." link + 'noUpdate' => TRUE, + ) + ), + 'admin/content/comment' => array( // Comments admin page. + 'table td:nth-child(2) a' => array( // view (TODO: popup too small) + 'noUpdate' => TRUE, + ), + '#comment-admin-overview td a:contains('. t('edit') .')', // edit + ), + 'admin/user/rules' => array( // Access rules admin page. + '#tabs-wrapper a[href$=admin/user/rules/add]', // Add rule + 'table td:nth-child(4) a, table td:nth-child(5) a', // edit, delete + '#tabs-wrapper a[href$=/admin/user/rules/check]' => array( // Check rule + 'noUpdate' => TRUE, + ), + ), + 'admin/user/user' => array( // Manage all users admin page. + //Add user (TODO: Can't test, keeps crashing apache!) + '#tabs-wrapper a[href$=admin/user/user/create]', + '#user-admin-account td:nth-child(2) a' => array( // View the user + 'noUpdate' => TRUE, + ), + + ), + 'menu_overview_form' => array( // Menu admin form. + // Add Item, , edit, delete + '#tabs-wrapper a:eq(1), table#menu-overview td:nth-child(5) a, table#menu-overview td:nth-child(6) a', + '#tabs-wrapper a:eq(2)' => array( // Edit menu: update just page title. + 'updateTitle' => TRUE, + 'noUpdate' => TRUE, + ), + ), + + ); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups_test.info Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,14 @@ +; $Id: popups_test.info,v 1.1.4.3 2009/03/05 19:52:49 starbow Exp $ +name = Popups: Test Page +description = Test the Popups API. +package = User interface +core = 6.x +dependencies[] = popups + + +; Information added by drupal.org packaging script on 2009-03-21 +version = "6.x-2.0-alpha5" +core = "6.x" +project = "popups" +datestamp = "1237597273" +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/popups_test.module Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,227 @@ +<?php +// $Id: popups_test.module,v 1.1.4.6 2009/03/19 15:53:44 starbow Exp $ + +/** + * @file + * Page for testing the Popups API. + */ + + +// ************************************************************************** +// CORE HOOK FUNCTIONS **************************************************** +// ************************************************************************** + +/** + * Implementation of hook_menu(). + * + * @return array of new menu items. + */ +function popups_test_menu() { + // Items for testing. + $items['popups/test'] = array( + 'title' => 'Popup Test', + 'page callback' => '_popups_test_popups', + 'type' => MENU_CALLBACK, + 'access callback' => TRUE, + ); + $items['popups/test/response'] = array( + 'page callback' => '_popups_test_response', + 'type' => MENU_CALLBACK, + 'access callback' => TRUE, + ); + $items['popups/test/namechange'] = array( + 'page callback' => 'drupal_get_form', + 'page arguments' => array('_popups_test_namechange'), + 'type' => MENU_CALLBACK, + 'access callback' => TRUE, + ); + $items['popups/test/old'] = array( + 'title' => 'Popup Test', + 'page callback' => '_popups_test_popups_old', + 'type' => MENU_CALLBACK, + 'access callback' => TRUE, + ); + return $items; +} + +/** + * Implementation of hook_popups(). + * + * This implements hook_popups, defined in popups_get_popups. + * See the comments in popups_add_popups for explination of the options. + * Adding popup behavior to the core admin pages has been moved to popups_admin. + * + * @return: Array of link selectors to apply popup behavior to. + * Keyed by path or form_id. + */ +function popups_test_popups() { + return array( + 'popups/test' => array( // test page. +// '*' => array( // test page. + '#test-popup' => array( +// 'additionalJavascript' => array('misc/collapse.js'), +// 'forceReturn' => 'node/add/story', + ), + ), + ); +} + +// ************************************************************************** +// TESTING **************************************************************** +// ************************************************************************** + +function _popups_test_popups() { + popups_add_popups(); + $output = '<ol id="test-list">'; + $output .= '<li>'. l("Pop up entire local page.", 'popups/test/response', + array('attributes' => array('class' => 'popups'))); + $output .= "<li>". l("Pop with options (href override).", 'popups/test/', + array('attributes' => array('class' => 'popups', 'on-popups-options' => '{href: "test/response"}'))); + $output .= "<li>". l("Pop with options (width=200px).", 'popups/test/response', + array('attributes' => array('class' => 'popups', 'on-popups-options' => '{width: "200px"}'))); + $output .= "<li class=\"popups\" on-popups-options=\"{href: 'test/response'}\">Non-link popup</li>"; + $output .= '<li>'. l("Add Story (hook)", 'node/add/story', + array( 'attributes' => array('id' => 'test-popup'))); + $output .= '<li>'. l("Add Story (attribute).", 'node/add/story', + array( 'attributes' => array('class' => 'popups-form'))); + + $output .= '<li>'. l("Change Settings and ajax update entire content area: ", + 'admin/settings/popups', + array( 'attributes' => array('class' => 'popups-form'), + )); + $output .= " (Auto Fade checkbox is: " . (variable_get('popups_autoclose_final_message', 1) ? 'on' : 'off') . ')'; + + $output .= '<li>'. l("Change Settings and ajax update only single target.", 'admin/settings/popups', + array( 'attributes' => array('id' => 'reload-target'), + )); + $output .= "<span id='response2'> (Auto Fade checkbox is: " . (variable_get('popups_autoclose_final_message', 1) ? 'on' : 'off') . ')</span>'; + popups_add_popups(array('#reload-target'=>array('targetSelectors'=>array('#response2')))); + + $output .= '<li>'. l("Change Settings and ajax update multiple targets with data from other page (tricky!).", 'admin/settings/popups', + array( 'attributes' => array( + 'id' => 'foo', + 'class' => 'popups-form', + 'on-popups-options' => '{targetSelectors: {"#edit-popups-always-scan-wrapper": "#foo", "#edit-popups-popup-final-message-wrapper": "#test-list li:first"}, forceReturn: "admin/settings/popups"}'))); + + $output .= '<li>'. l("Change Settings and reload entire page.", + 'admin/settings/popups', + array( 'attributes' => array('class' => 'popups-form-reload'), + )); + + $output .= '<li>'. l("Pop up defined by popups_add_popups rule.", 'popups/test/response', + array('attributes' => array('id' => 'rule-test'))); + popups_add_popups(array('#rule-test'=>array('width'=>'300px'))); + $output .= '<li>'. l('Ajax update just Page Title (only works if you theme uses id="page-title")', 'popups/test/namechange', + array('attributes' => array('id' => 'title-test'))); + popups_add_popups(array('#title-test'=>array('titleSelectors'=>array('#page-title'), 'noUpdate'=> TRUE, 'forceReturn'=>'popups/test/namechange'))); + + global $user; + $output .= "<li>You are user number $user->uid</li>"; + if ($user->uid == 0) { + $output .= '<li>'. l("Login and ajax refresh content area.", 'user', + array('attributes' => array('class' => 'popups-form'))); + $output .= '<li>'. l("Login and reload entire page.", 'user', + array('attributes' => array('class' => 'popups-form-reload'))); + $output .= '<li>'. l("Login and do not reload anything.", 'user', + array('attributes' => array('class' => 'popups-form-noupdate'))); + } + else { + $output .= '<li>'. l("Logout (need to surpress warning b/c session is dumped)", 'logout', + array('attributes' => array('id' => 'logout'))); + } + // Need to have the rule outside the else, or it won't get loaded on ajax reload. + popups_add_popups(array('#logout'=>array('noUpdate'=>TRUE, 'reloadOnError'=>TRUE))); + + $output .= '<li>'. l("Add Poll (test inline)", 'node/add/poll', + array('attributes' => array('class' => 'popups-form'))); + + $output .= "</ol>"; + return $output; +} + +function _popups_test_popups_old() { +// drupal_set_message('Popup Test Page: If you edit your page.tpl.php to wrap the print $messages in a div with id="popit", this message will popup on page load'); + popups_add_popups(); + $output = '<ul id="test-list">'; + $output .= '<li>'. l("Pop up entire local page.", 'popups/test/response', + array('attributes' => array('class' => 'popups'))); + $output .= "<li>". l("Pop with options (href override).", 'popups/test/', + array('attributes' => array('class' => 'popups', 'on-popups-options' => '{href: "test/response"}'))); + $output .= "<li>". l("Pop with options (width=200px).", 'popups/test/response', + array('attributes' => array('class' => 'popups', 'on-popups-options' => '{width: "200px"}'))); + $output .= "<li class=\"popups\" on-popups-options=\"{href: 'test/response'}\">Non-link popup</li>"; + $output .= '<li>'. l("Add Story (hook)", 'node/add/story', + array( 'attributes' => array('id' => 'test-popup'))); + $output .= '<li>'. l("Add Story (attribute).", 'node/add/story', + array( 'attributes' => array('class' => 'popups-form'))); + + $output .= '<li>'. l("Change Settings and ajax update entire content area: ", + 'admin/settings/popups', + array( 'attributes' => array('class' => 'popups-form'), + )); + $output .= " (Auto Fade checkbox is: " . (variable_get('popups_popup_final_message', 1) ? 'on' : 'off') . ')'; + + $output .= '<li>'. l("Change Settings and ajax update only single target.", 'admin/settings/popups', + array( 'attributes' => array('id' => 'reload-target'), + )); + $output .= "<span id='response2'> (Auto Fade checkbox is: " . (variable_get('popups_popup_final_message', 1) ? 'on' : 'off') . ')</span>'; + popups_add_popups(array('#reload-target'=>array('targetSelectors'=>array('#response2')))); + + $output .= '<li>'. l("Change Settings and ajax update multiple targets with data from other page (tricky!).", 'admin/settings/popups', + array( 'attributes' => array( + 'id' => 'foo', + 'class' => 'popups-form', + 'on-popups-options' => '{targetSelectors: {"#edit-popups-always-scan-wrapper": "#foo", "#edit-popups-popup-final-message-wrapper": "#test-list li:first"}, forceReturn: "admin/settings/popups"}'))); + + $output .= '<li>'. l("Change Settings and reload entire page.", + 'admin/settings/popups', + array( 'attributes' => array('class' => 'popups-form-reload'), + )); + + $output .= '<li>'. l("Pop up defined by popups_add_popups rule.", 'popups/test/response', + array('attributes' => array('id' => 'rule-test'))); + popups_add_popups(array('#rule-test'=>array('width'=>'300px'))); + $output .= '<li>'. l('Ajax update just Page Title (only works if you theme uses id="page-title")', 'popups/test/namechange', + array('attributes' => array('id' => 'title-test'))); + popups_add_popups(array('#title-test'=>array('titleSelectors'=>array('#page-title'), 'noUpdate'=> TRUE, 'forceReturn'=>'popups/test/namechange'))); + + global $user; + $output .= "<li>You are user number $user->uid</li>"; + if ($user->uid == 0) { + $output .= '<li>'. l("Login and ajax refresh content area.", 'user', + array('attributes' => array('class' => 'popups-form'))); + $output .= '<li>'. l("Login and reload entire page.", 'user', + array('attributes' => array('class' => 'popups-form-reload'))); + $output .= '<li>'. l("Login and do not reload anything.", 'user', + array('attributes' => array('class' => 'popups-form-noupdate'))); + } + else { + $output .= '<li>'. l("Logout (need to surpress warning b/c session is dumped)", 'logout', + array('attributes' => array('id' => 'logout'))); + } + // Need to have the rule outside the else, or it won't get loaded on ajax reload. + popups_add_popups(array('#logout'=>array('noUpdate'=>TRUE, 'reloadOnError'=>TRUE))); + + $output .= '<li>'. l("Add Poll (test inline)", 'node/add/poll', + array('attributes' => array('class' => 'popups-form'))); + + $output .= "</ul>"; + return $output; +} + +function _popups_test_response() { + drupal_set_title("Popup Test Two"); + return '<div>Hello World</div><a href="#" class="popups">Popup chaining test</a>'; +} + +function _popups_test_namechange() { + drupal_set_title("New Name for Test Page"); + $form = array(); + + $form['popups_popup_final_message'] = array( + '#type' => 'submit', + '#value' => t('Test Name Change'), + ); + + return $form; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/skins/basic/basic.css Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,29 @@ +.popups-box { + border: 2px solid #EDF5FA; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + opacity: 0.9; +} +.popups-title { + border-bottom: 1px solid #b4d7f0; + background-color: #d4e7f3; + color: #455067; + margin-bottom: 0.25em; + padding: 0.25em; + -moz-border-radius-topleft: 5px; + -webkit-border-radius-topleft: 5px; +} +.popups-title .popups-close a { + color: red; +} +.popups-box input { + margin: 0.1em; +} +.popups-box input[type="text"]:focus, .popups-box input[type="password"]:focus, .popups-box textarea:focus { + background-color: #FFA; + outline: thin solid grey; +} +a.popups-processed { + padding-right: 12px; + background: url(popup-icon.png) no-repeat right; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/skins/blue/blue.css Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,66 @@ +/* + Blue Popup Skin + Author: Tj Holowaychuk + Link: http://vision-media.ca +*/ +#popups-overlay { + background: #fff; + opacity:.80; +} +.popups-box { + padding: 25px; + width: 510px; + border: none; + background: transparent url(images/tile-v.png) 0 0 repeat-y; + overflow: visible; +} +.popups-title { + position: absolute; + top: -65px; + left: -11px; + margin: 0; + padding: 0; + height: 65px; + width: 570px; + line-height: 75px; + background: transparent url(images/sprites.png) 0 0 no-repeat; +} +.popups-title .title { + text-indent: 25px; + text-shadow: #fff 1px 1px 1px; + color: #437acf; +} +.popups-title .popups-close a { + position: absolute; + top: 4px; + right: -7px; + display: block; + width: 16px; + height: 16px; + text-indent: -9999999px; + outline: none; + cursor: pointer; + background: transparent url(images/sprites.png) -577px -18px no-repeat; +} +.popups-title .popups-close a:hover { + background-position: -577px -52px; +} +.popups-title .popups-close a:active { + background-position: -577px -35px; +} +.popups-body { + padding: 0 25px; + height: 250px; + overflow-y: auto; + overflow-x: hidden; +} +.popups-footer { + position: absolute; + bottom: -90px; + left: -11px; + width: 570px; + height: 90px; + background: transparent url(images/sprites.png) 0 -110px no-repeat; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/skins/facebook/facebook.css Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,102 @@ +#popups-overlay { + background-color:transparent; +} +#popups-loading { + width:248px; + position:absolute; + display:none; + opacity:1; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + z-index:99; +} +#popups-loading span.popups-loading-message { + background:#FFF url(loading-large.gif) no-repeat 8px center; + display:block; + color:#444444; + font-family:Arial; + font-size:22px; + font-weight:bold; + height:36px; + line-height:36px; + padding:0 40px; +} +#popups-loading table, +.popups-box table { + margin:0px; +} +#popups-loading tbody, +.popups-box tbody { + border:none; +} +.popups-box tr { + background-color:transparent; +} +td.popups-border { + background: url(popups-border.png); + background-color:transparent; + filter:progid:DXImageTransform.Microsoft.Alpha(opacity=85); +} +td.popups-tl, +td.popups-tr, +td.popups-bl, +td.popups-br { + background-repeat: no-repeat; + height:10px; + padding:0px; +} +td.popups-tl { background-position: 0px 0px; } +td.popups-t, +td.popups-b { + background-position: 0px -40px; + background-repeat: repeat-x; + height:10px; +} +td.popups-tr { background-position: 0px -10px; } +td.popups-cl, +td.popups-cr { + background-position: -10px 0; + background-repeat: repeat-y; + width:10px; +} +td.popups-cl, +td.popups-cr, +td.popups-c { padding:0; } +td.popups-bl { background-position: 0px -20px; } +td.popups-br { background-position: 0px -30px; } + +.popups-box, +#popups-loading { + border: 0px solid #454545; + opacity:1; + overflow:hidden; + padding:0; + background-color:transparent; +} +.popups-container { + overflow:auto; + max-height:100%; + background-color:#fff; +} +.popups-title { + -moz-border-radius-topleft: 0px; + -webkit-border-radius-topleft: 0px; + margin-bottom:0px; + background-color:#6D84B4; + border:1px solid #3B5998; + padding:4px 10px 5px; + color:white; + font-size:14px; + font-weight:bold; +} +.popups-body { + background-color:#fff; + padding:8px; +} +.popups-box .popups-buttons, +.popups-box .popups-footer { + background-color:#fff; +} +.popups-title .popups-close a { + color: #fff; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/skins/facebook/facebook.js Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,88 @@ + +/** + * Custom theming for the popupsLoading. + */ +Drupal.theme.popupLoading = function() { +console.log("Drupal.theme.popupLoading: Facebook"); + var loading; + loading += '<div id="popups-loading">'; + loading += ' <table>'; + loading += ' <tr>'; + loading += ' <td class="popups-tl popups-border"></td>'; + loading += ' <td class="popups-t popups-border"></td>'; + loading += ' <td class="popups-tr popups-border" id="popups-tr"></td>'; + loading += ' </tr>'; + loading += ' <tr>'; + loading += ' <td class="popups-cl popups-border"></td>'; + loading += ' <td class="popups-c">'; + loading += ' <span class="popups-loading-message">Loading...</span>'; + loading += ' </td>'; + loading += ' <td class="popups-cr popups-border"></td>'; + loading += ' </tr>'; + loading += ' <tr>'; + loading += ' <td class="popups-bl popups-border"></td>'; + loading += ' <td class="popups-b popups-border"></td>'; + loading += ' <td class="popups-br popups-border"></td>'; + loading += ' </tr>'; + loading += ' </table>'; + loading += '</div>'; + return loading; +}; + +Drupal.theme.popupTemplate = function (popupId) { +console.log("Drupal.theme.popupTemplate: Facebook"); + var template; + template += '<div id="' + popupId + '" class ="popups-box">'; + template += ' <table>'; + template += ' <tr>'; + template += ' <td class="popups-tl popups-border"></td>'; + template += ' <td class="popups-t popups-border"></td>'; + template += ' <td class="popups-tr popups-border"></td>'; + template += ' </tr>'; + template += ' <tr>'; + template += ' <td class="popups-cl popups-border"></td>'; + template += ' <td class="popups-c">'; + template += ' <div class="popups-container">'; + template += ' <div class="popups-title">'; + template += ' <div class="popups-close"><a href="#">' + Drupal.t('Close') + '</a></div>'; + template += ' <div class="title">%title</div>'; + template += ' <div class="clear-block"></div>'; + template += ' </div>'; + template += ' <div class="popups-body">%body</div>'; + template += ' <div class="popups-buttons">%buttons</div>'; + template += ' <div class="popups-footer"></div>'; + template += ' </div>'; + template += ' </td>'; + template += ' <td class="popups-cr popups-border"></td>'; + template += ' </tr>'; + template += ' <tr>'; + template += ' <td class="popups-bl popups-border"></td>'; + template += ' <td class="popups-b popups-border"></td>'; + template += ' <td class="popups-br popups-border"></td>'; + template += ' </tr>'; + template += ' </table>'; + template += '</div>'; + return template; +}; + +/** + * We need to resize the popups-container as well as the popups if it scrolls + */ +Drupal.behaviors.resizePopupsContainer = function() { + var popup = Popups.activePopup(); + if (popup) { + var $popupsContainer = $('#' + popup.id + ' .popups-container'); + if ($popupsContainer.length) { + var popupHeight = $popupsContainer.height(); + var windowHeight = $(window).height(); + if (popupHeight > (0.9 * windowHeight) ) { // Must fit in 90% of window. + // we make this slightly smaller than popups so that it fits inside + popupHeight = 0.85 * windowHeight; + $popupsContainer.height(popupHeight); + } + // needs an extra 20px as the bottom dropshadow looks cutoff + var $popup = popup.$popup(); + $popup.height($popup.height() + 20); + } + } +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/translations/ja.po Fri Dec 31 13:41:08 2010 +0100 @@ -0,0 +1,116 @@ +# $Id: ja.po,v 1.1.2.1 2008/09/15 10:09:10 imagine Exp $ +# ----------------------------------------------------------------------------- +# Japanese translation of Drupal (modules-popups) +# +# Copyright (c) 2008 Drupal Japan ( http://drupal.jp/ ) / +# Takafumi ( jp.drupal@imagine **reverse order**) +# +# Generated from file: +# popups-popup.tpl.php,v 1.1.2.4 2008/09/15 01:48:52 starbow +# popups.module,v 1.11.2.5 2008/09/15 01:48:53 starbow +# popups.info,v 1.4 2008/03/11 16:56:08 starbow +# popups.js,v 1.9.2.6 2008/09/15 01:48:52 starbow +# +# ----------------------------------------------------------------------------- +msgid "" +msgstr "" +"POT-Creation-Date: 2008-09-15 18:30+0900\n" +"Last-Translator: Takafumi <jp.drupal@imagine **reverse order**>\n" +"Language-Team: Drupal Japan\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" + +#: popups-popup.tpl.php:6 +msgid "Close" +msgstr "閉じる" + +#: popups.module:153 +msgid "Popup Settings" +msgstr "ポップアップの設定" + +#: popups.module:158 +msgid "Content Selector" +msgstr "コンテンツセレクタ" + +#: popups.module:160 +msgid "jQuery selector to define the page's content area on this theme." +msgstr "このテーマでページのコンテンツ領域を定義するための、jQueryセレクタを入力します。" + +#: popups.module:306 +msgid "edit vocabulary" +msgstr "ボキャブラリの編集" + +#: popups.module:307 +msgid "list terms" +msgstr "タームのリスト" + +#: popups.module:311 +msgid "add terms" +msgstr "タームの追加" + +#: popups.module:329;346 +msgid "edit" +msgstr "編集" + +#: popups.module:427 +msgid "Do NOT auto-close final message." +msgstr "最後のメッセージを自動で閉じない" + +#: popups.module:44 popups.info:0 +msgid "Popups" +msgstr "Popups" + +#: popups.module:46 +msgid "Configure the page-in-a-dialog behavior." +msgstr "ダイアログでのページの振る舞いを設定します。" + +#: popups.module:51;57 +msgid "Popup Test" +msgstr "ポップアップのテスト" + +#: popups.module:0 +msgid "popups" +msgstr "popups" + +#: popups.info:0 +msgid "General dialog creation utilities" +msgstr "全般的なダイアログ生成ユーティリティ" + +#: popups.info:0 +msgid "User interface" +msgstr "ユーザインターフェイス" + +#: popups.js:0 +msgid "[Popup]" +msgstr "[ポップアップ]" + +#: popups.js:0 +msgid "There are unsaved changes on this page, which you will lose if you continue." +msgstr "このページに保存されていない変更があります。 継続した場合、その変更は失われます。" + +#: popups.js:0 +msgid "Save Changes" +msgstr "変更を保存" + +#: popups.js:0 +msgid "Continue" +msgstr "継続" + +#: popups.js:0 +msgid "Cancel" +msgstr "キャンセル" + +#: popups.js:0 +msgid "Warning: Please Confirm" +msgstr "警告:確認してください" + +#: popups.js:0 +msgid "OK" +msgstr "OK" + +#: popups.js:0 +msgid "Sorry, there is no additional help for this page" +msgstr "このページの補足ヘルプはありません" +