Compare commits

..
3 Commits
Author SHA1 Message Date
bachy 7884444ec6 update 2.2 + precedent custom commits
Signed-off-by: bachy <git@g-u-i.net>
2012-10-27 15:06:38 +02:00
bachy aff5ecb650 titmice theme correction
Signed-off-by: bachy <git@g-u-i.net>
2012-10-27 15:04:07 +02:00
bachy 9a18131bcf first import 2.1
Signed-off-by: bachy <git@g-u-i.net>
2012-10-27 15:02:05 +02:00
581 changed files with 8559 additions and 76752 deletions
+345
View File
@@ -0,0 +1,345 @@
Wysiwyg 7.x-2.x, xxxx-xx-xx
---------------------------
#1388224 by ksenzee, sun, TwoD: Fixed editors detaching on form submissions.
#682160 by n_vashenko, TwoD: Fixed lists plugin support for TinyMCE.
#1414354 by Merco: Fixed none.js breaks if textarea.js is not loaded.
#1064600 by TwoD: Fixed maximized editors hidden under Drupal's toolbar.
#1405786 by logaritmisk: Fixed CKEditor being wider than parent elements.
#1531896 by Chi: Fixed strict warning for WYMeditor.
#1442226 by robertom: Fixed inverted list button names for WYMeditor.
#1352426 by TwoD, sun: Added install notes (CKEditor edition clarification).
#1112212 by timdiacon, TwoD: Added language direction buttons for CKEditor.
#1398560 by markwittens: Fixed TinyMCE removing the longdesc attribute.
#970452 by smk-ka, sun, TwoD, drzraf: Fixed outdated TinyMCE plugin info.
#1155678 by james.elliott, Jody Lynn, sun: Add Drupal.detachBehaviors support.
#624018 by smk-ka, quartsize, dagmar, nedjo, rickvug, catch, sun: Added Features support.
#1238766 by Dave Reid: Fixed Missing cells in profile plugins table.
#1073106 by scottrouse: Fixed 'Input Format' should be 'Text Format'.
#1153458 by TwoD: Fixed TinyMCE 'Verify HTML' setting ignored.
#1125582 by TwoD: Fixed TinyMCE fullscreen plugin deletes content.
#1078834 by sun: Fixed coding standards errors.
#1173476 by jim0203, sun: Fixed installation instructions in README.txt.
Wysiwyg 7.x-2.1, 2011-06-19
---------------------------
#679056 by TwoD: Fixed patch for pressing enter in autocomplete, new jQuery API.
#524126 by sun: Re-added #wysiwyg property to enforce no editor via code.
#1153458 by Deciphered: Fixed TinyMCE 'Verify HTML' setting being ignored.
#1079694 by TwoD: Fixed Whizzywig not restoring textarea styles when detached.
#1132142 by tacituseu, TwoD, sun: Fixed nicEdit not removing its submit handler.
#1143104 by EugenMayer: Fixed CKEditor 3.5.4 version detection.
#1009880 by AndyF: Fixed another CKEditor selection handling issue.
#1048556 by cousin_itt, TwoD: Fixed TinyMCE insertdatetime plugin setting.
#1036900 by mattyoung: Minor code clean-up in wysiwyg_tinymce_version().
#1026088 by sun: Fixed installation instructions in README.txt.
by sun: Merged in module baseline to facilitate testing.
#1034476 by quartsize, sun: Changed Wysiwyg profiles into entities.
Wysiwyg 7.x-2.0, 2010-01-06
---------------------------
#950216 by TwoD, sun: Fixed missing editor for a single text format.
#1007630 by aspilicious: Removed files[] declarations from .info file.
#612954 by sun: Reverted 'buttons' change in profile configuration form.
#975546 by TwoD, sun: Fixed markItUp CSS loaded with wrong weight.
#659428 by TwoD, sun: Fixed editor is attached to disabled text format widgets.
#975490 by Gábor Hojtsy: Updated for 'group' API change in drupal_add_js().
#974604 by CrookedNumber, Gábor Hojtsy: Fixed theme CSS not loaded in editors.
#931374 by TwoD, ksenzee: Updated for text format schema change.
#826914 by catch, sun: Added database cache for wysiwyg_profile_load().
#941230 by sun: Fixed missing Configuration link on Modules page.
#739558 by sun, TwoD: Updated for new #type text_format.
#612954 by TwoD: Fixed broken editor settings.
#585932 by sun: Ported to Drupal 7.
Wysiwyg 6.x-2.3, 2011-01-30
---------------------------
#1025296 by TwoD: Updated CKEditor to support iFrame button.
#737318 by TwoD: Fixed CKEditor default skin array not being reindexed.
by sun: Fixed coding style in wysiwyg_schema().
#964978 by sun, TwoD: Added hook_wysiwyg_editor_settings_alter() documentation.
#775972 by TwoD, Agileware, sun: Fixed broken user default status preferences.
#1007066 by TwoD, penguin25: Fixed CKEditor ignores resizable option.
#613944 by TwoD, sun: Fixed data.node not always present in CKEditor.
#1009880 by TwoD: Fixed selection handling broken in CKEditor.
Wysiwyg 6.x-2.2, 2010-12-20
---------------------------
#613944 by TwoD, sun: Fixed data.node not available in CKEditor.
#748888 by TwoD, sun: Fixed isNode() not called in CKEditor.
#767550 by TwoD, sun, ungeek: Fixed invalid API docs and logic for
$plugin['filename'].
#988200 by sun: Changed static language list to ISO 639 defaults of Drupal core.
#973808 by David_Rothstein: Fixed CKEditor incorrectly formatting the <br> tag.
#773856 by Roi Danton: Added CSS path and file documentation.
#735186 by TwoD, torbs: Fixed missing Norwegian language code.
#678580 by TwoD, sun: Fixed Drupal.wysiwygAttachToggleLink breaks click events.
#497654 by TwoD: Fixed Drupal plugins disabled in FCKeditor/WebKit browsers.
#735624 by sun: Fixed enabling one button removes default editor toolbar.
#755610 by sun, TwoD, BrightBold: Fixed white-space in block formats setting
breaks editors.
#713942 by TwoD, sun: Fixed jQuery closure breaks OpenWYSIWYG.
#679056 by sun, TwoD: Fixed pressing enter in autocomplete detaches editors.
#80170 by sun: Changed dialog/plugin API for Inline API compatibility.
#803466 by hotspoons: Fixed TinyMCE image map support in advimage plugin.
#922436 by TwoD: Fixed Whizzywig Uncaught TypeError in Chrome.
#922520 by TwoD: Fixed Whizzywig is not detached properly.
#907186 by TwoD: Fixed Whizzywig v60+ compatibility.
#765292 by TwoD: Added TinyMCE WordCount plugin.
#768726 by TwoD: Added TinyMCE AutoResize plugin.
#781086 by TwoD: Fixed TinyMCE plugin options merged wrongly.
#767628 by TwoD: Fixed 'The version of markItUp could not be detected' error.
#651490 by TwoD: Fixed Whizzywig width.
#715228 by TwoD: Fixed TinyMCE image popups not launching for existing images.
#606952 by TwoD: Fixed inserting content in fullscreen TinyMCE.
#593008 by TwoD: Fixed third-party scripts breaking Wysiwyg.
#695398 by RichieB, Cl1mh4224rd, mcpuddin: Fixed TinyMCE 3.3.9.1 detection.
#737318 by dboune: Fixed CKEditor default skin depends on filesystem order.
#775608 by TwoD: Fixed FCKEditor crashes IE on save.
#824710 by TwoD: CKEditor not disabled upon enabling.
#752516 by nquocbao, sun: Fixed openwysiwyg version callback.
#753536 by TwoD: Fixed version detection for Whizzywig.
#752516 by nquocbao, sun: Fixed file stream warnings in version callbacks.
Wysiwyg 6.x-2.1, 2010-03-08
---------------------------
#628110 by quicksketch, sun, markus_petrux: Added editor settings alter hook.
#689218 by wwalc, TwoD, sun: Improved support for CKEditor.
#695398 by TwoD: Updated support for TinyMCE 3.3.
#613096 by Scott Reynolds: Fixed no editor appearing for user signature field.
#696040 by Dave Reid: Fixed missing Cancel link on profile form.
#594322 by TwoD: Added insert method for NicEdit.
#659200 by TwoD: Fixed YUI Editor content lost in IE.
#594928 by ericbellot, TwoD, sun: Fixed 'attribs' button missing in TinyMCE.
#557090 by TwoD: Fixed Whizzywig 56 instance not removed on detach().
#667848 by TwoD, kaakuu: Fixed FCKeditor is not properly detached in IE.
#695768 by sun: Fixed #resizable removed when no editor profiles are loaded.
#631494 by TwoD: Fixed multi-site libraries directory failure for WYMeditor.
#660080 by TwoD: Fixed Notice: Undefined offset.
#613922 by TwoD, sun: Fixed PHP warning when saving profiles.
#582298 by dereine: Added auto-paste from Word detection for FCKeditor.
#597852 by sun: Fixed missing Turkish in language list.
#620176 by sun: Fixed missing Ukrainian in language list.
#613480 by TwoD, Dave Reid: Fixed PHP 5.3 compatibility.
#462146 by TwoD: Cleaned up CKEditor implementation.
#380586 by SimonEast: Updated YUI editor: Version detection not working.
#610132 by TwoD: Updated CKEditor 3.0.1, stylesheets and version check.
#620858 by quicksketch: Fixed focus event not firing for CKeditor.
#585932 by sun: Synced various clean-ups from 7.x.
#489156 by sun: Removed orphan global 'showToggle' JS setting.
#462146 by sun, Niels Hackius: Fixed version detection for CKeditor.
#545210 by sun: Fixed default value for editor toggle link.
#372826 by Roi Danton, sun: Added Wysiwyg API developer documentation.
by sun: Fixed PHP notice.
#514912 by Likeless, sun: Added plugin/button handling for WYMeditor.
#538996 by darktygur: Fixed 404 errors for non-existing theme CSS files.
#509570 by Rob Loach, sun: Added forced detaching of editor upon form submit.
#526644 by Darren Oh: Fixed broken editor theme validation.
#490914 by sun: Fixed JS/CSS not updated after update with caching enabled.
#522440 by authentictech, sun: UX: Fixed user interface for Wysiwyg profiles.
#507608 by jfh: Added WYMeditor instance API methods.
by sun: Fixed form_build_id not removed from serialized profile settings.
#496744 by TwoD: Fixed FCKeditor: "Apply source formatting" not working.
#462146 by TwoD, et al: Added support for CKeditor.
#490270 by sun: Fixed openWYSIWYG displays no buttons by default.
#490266 by sun: Fixed JS error when wysiwyg profile contains no buttons.
#400482 by sun: Fixed editor.instance.prepareContent() breaks editor's native
markup handling. Drupal plugin authors should add the CSS class
'drupal-content' to prevent the editor selection to activate internal editor
buttons.
#394068 by kswan: Fixed missing button icons in markItUp.
Wysiwyg 6.x-2.0, 2009-06-10
---------------------------
#474908 by TwoD: Fixed Teaser break causing error in IE8.
by sun: Major code clean-up.
#331089 by wwalc: Fixed FCKeditor toolbar buttons do not wrap.
#407014 by sun: Fixed/removed migration from other editor integration modules.
#485264 by sun: Changed installation instructions to be more concise.
#479514 by sun: Fixed native plugin loading for TinyMCE (follow-up).
#434590 by sun: Fixed path admin/settings/wysiwyg not found.
#479514 by TwoD, sun: Added native plugin support for FCKeditor.
#341054 by sun: Fixed toggle link configuration setting not working.
by sun: Fixed markItUp button icons are not displayed.
by sun: Added openWYSIWYG editor support.
#362137 by jfh, sun: Fixed WYMeditor broken when JS/CSS aggregation is enabled.
#328252 by sun: Added TinyMCE plugin BBCode for 3.x.
#429926 by TwoD, sun: Fixed TinyMCE broken due to renamed Flash/Media plugin.
#342864 by davexoxide, sun: Added YUI editor support.
#332139 by sun: Fixed editor must not be changed when profile is configured.
#362137 by jfh: Added WYMeditor support.
#470928 by jfh, sun: Fixed Drupal.wysiwyg.clone turns arrays into objects.
#445826 by TwoD: Fixed FCKeditor: Drupal.wysiwyg.activeId not updated.
#478324 by jeffschuler: Fixed typo in profile configuration form.
#373542 by sun: Fixed encoding of HTML entities for certain languages.
#320562 by sun: Changed location for external editor libraries.
#449134 by sun: Fixed stylesheets of theme missing in node form previews.
Wysiwyg 6.x-2.0-ALPHA1, 2009-05-17
----------------------------------
#403728 by jfduchesneau: Fixed none.js breaks if textarea.js is not loaded.
#454992 by sun: Fixed drupal_get_js() query string 'q' breaks plugin loading.
#419696 by sun: Fixed native plugins plugins are not loaded for all profiles.
#414768 by sun: Fixed Wysiwyg API not working in Konqueror.
#293803 by sun: Fixed "Show summary in full view" checkbox not displayed.
#416742 by sun: Fixed type casting of $profile in profile configuration form.
#404532 by TwoD: Fixed Teaser break comment stripped in IE.
#380698 by TwoD: Added Drupal plugin support for FCKeditor.
#380698 by TwoD, sun: Added Drupal plugin support for FCKeditor (part I).
#398848 by sun: Added support for TinyMCE 3.1.
#394068 by StephaneC: markItUp: Fixed icons not displayed due to #385736.
#385974 by sun: Fixed form element description for CSS path (for Define CSS).
#390460 by sun: Fixed broken plugin loading due to #359626.
#385736 by sun: Fixed markItUp: Wrong editor library location.
#308912 by sun: Fixed TinyMCE: Buttons do not wrap in IE/Chrome.
#380586 by sun, hass: YUI editor: Fixed version detection.
#390224 by hass: Fixed JS error YAHOO.widget.Editor is not a constructor.
#359626 by sun: Fixed external/Drupal plugins are not loaded for all profiles.
#369115 by sun: Fixed TinyMCE's URL conversion magic breaks some input filters.
#376400 by TwoD: Fixed bad grammar in help text on profile overview page.
#367632 by sun: Fixed $this and i JavaScript variables defined in global scope.
#319363 by sun: Fixed missing spacer.gif for Teaser break plugin.
#373672 by chawl: Added (native) xhtmlextras plugin for TinyMCE 3.
#287025 by sun: Fixed native editor plugin options for TinyMCE and FCKeditor.
#373542 by sun: Fixed TinyMCE: entity_encoding 'raw' removes HTML entities.
#372806 by sun: Fixed block format configuration form element description.
#370277 by sun: Fixed "Uncaught SyntaxError: Unexpected token" in IE/Chrome.
#367632 by sun: Fixed "Unexpected identifier, string or number" error in IE.
#367632 by sun: Fixed invalid JavaScript syntax.
#319363 by sun: Follow-up: Synced 1.x with 2.x where possible.
#319363 by sun, quicksketch: Rewrote editor plugin API. The new plugin API
allows Drupal modules to expose editor plugins for ANY editor without
implementing editor-specific code. Major milestone for better content-editing
in Drupal.
#364782 by sun: Fixed theme stylesheets not properly loaded.
#352938 by sun: Fixed JS error (blank page) in IE when plugins are loaded.
#331089 by wwalc, sun: Added custom toolbar configuration support for FCKeditor.
#331089 by sun: Fixed PHP notice for 'user_choose'; FCKeditor clean-up.
#344230 by wwalc: Fixed wrong editor base path setting for FCKeditor.
#361289 by sun: Fixed CSS files do not need to use media 'screen'.
#360696 by sun: Fixed IE does not trigger onChange event when selecting an input
format.
#342376 by sun: Extended API to allow "preprocess" JavaScript option for some
editors.
#352295 by sun: Added markItUp editor support.
#352703 by sun: Fixed wrong default configuration options for TinyMCE 3.2.1+.
#348317 by sun: Fixed TinyMCE's extended_valid_elements for advlink/advimage
plugin.
#348986 by sun: Added CSS class for toggle link container.
#342864 by davexoxide, sun: Added YUI editor support.
#343217 by sun: Fixed improperly capitalized library script name for nicEdit.
#341267 by sun: Fixed improper test for internal editor plugins.
#341996 by sun: Fixed editor cannot be re-enabled with one input format only.
#341267 by sun: Added support for extensions that do not need to be loaded.
Wysiwyg 6.x-0.5, 2008-12-01
---------------------------
#340758 by sun: Changed installation instructions to be displayed permanently.
#322657 by sun: Fixed "Enabled by default" option does not work when disabled.
#328052 by sun: Fixed switching input formats leads to wrong editor/state.
#337569 by sun: Fixed different profiles for same editor are not respected.
#340195 by sun: Fixed #after_build function not invoked on all forms.
#333521 by sun: Fixed TinyMCE version detection to look at the actual script.
#329657 by svendecabooter, sun: Added Whizzywig support.
#333521 by sun: Fixed TinyMCE version detection docs.
#327100 by sun: Changed access permission for settings page to 'administer
filters' to prevent incomplete updates.
#322731 by sun: Fixed improper use of t() in module install file.
#329410 by sun: Fixed editor not loaded if there is only one input format.
#324366 by sun: Fixed "Illegal offset type" error on custom content-types.
#328948 by sun: Fixed PHP notices when editors are assigned, but not configured.
#327710 by sun: Fixed nicEdit version could not be detected.
#328116 by sun: Added Safari plugin for TinyMCE 3.
#327710 by sun: Added nicEdit support.
#323855 by sun: Increased supported version of jWYSIWYG to 0.5.
#323671 by sun: Fixed TinyMCE editor not resized when browser is resized.
#327152 by sun: Fixed breadcrumbs for profile configuration pages.
#323855 by Rob Loach, sun: Added jWYSIWYG support.
#327100 by sun: Associate editors/profiles with input formats. Major milestone.
#325980 by markus_petrux: Added Spanish/Catalan translation for Break plugin.
#323795 by sun: Removed obsolete Wysiwyg Editor module files.
#308912 by sun: Fixed alignment of editor buttons in TinyMCE 3.
#316507 by sun: Fixed TinyMCE 3 not detached properly from AJAX contents.
#320559 by markus_petrux, sun: Added confirmation form to delete profiles.
Wysiwyg 6.x-0.4, 2008-10-14
---------------------------
#321216 by sun: Replaced Wysiwyg Editor module with Wysiwyg module.
#321086 by sun: Fixed (old-style) Teaser break plugin breaks TinyMCE 3.
#316507 by sun: Code clean-up; editor settings should be cloned for init, too.
#282717 by sun: Fixed FCKeditor default settings while FCKeditor maintainers get
up and running.
#319363 by sun: Changed JS settings namespace 'wysiwygEditor' to 'wysiwyg'.
#319363 by sun: Code clean-up; fixed missing namespace change in tinymce-3.js.
#273408 by quicksketch: Added blockquote button for TinyMCE 3.
#319363 by sun: Changed JavaScript namespaces and centralized namespace
initialization.
#270780 by sun: Fixed TinyMCE 3 support for external plugins.
#309832 by sun: Fixed README.txt.
#253600 by sun: Changed editor integration so that client-side editors attach to
input formats instead of textareas and are invoked for input format enabled
textareas only.
#282717 by sun: Added (basic) FCKeditor support.
#316507 by sun: Added Drupal.wysiwyg function stacks to execute editor library
specific actions upon initializing, attaching, detaching, and toggling an
editor. Editor specific JavaScript resides in separate files now, as specified
and returned by implementations of hook_editor().
Wysiwyg is a real API finally, supporting multiple editors and editor versions.
#316507 by sun: Rewrote Wysiwyg API's internal architecture to support multiple
editors.
Wysiwyg 6.x-0.3, 2008-09-12
---------------------------
#125267 by sun: Removed Safari browser warning configuration option.
#304243 by sun: Fixed profile configuration improperly passed to JavaScript.
#304243 by sun: Code clean-up for wysiwyg_editor_profile_overview().
#289218 by gustav: Fixed E^ALL notice if node has no body field.
#304243 by sun: Code clean-up for wysiwyg_editor_user_status().
#299108 by toniw: Added setting for TinyMCE's auto-cleanup paste feature.
#293916 by sun: Clarified TinyMCE compatibility in README.txt.
#293425 by sun: Fixed foreach warning during upgrade from TinyMCE module.
#292517 by sun: Fixed SQL error during upgrade from TinyMCE module.
#286470 by chayner, sun: Fixed wrong editorBasePath in editor configuration.
#227687 by sun: Fixed improperly capitalized package name.
#288028 by Matthew Davidson: Fixed outdated check for PHP input filter.
#280727 by sun: Removed gzip compressor from installation instructions.
Wysiwyg 5.x-0.2, 2008-07-16
---------------------------
by sun: Fixed JavaScript errors when JS aggregation/compression is enabled.
#268562 by sun: Code clean-up; changed format for custom defined CSS classes
and removed error-prone auto-layout of buttons in favor of aligning them in
one row with a stylesheet; may break existing profiles.
#270730 by hass, sun: Added German translation for Teaser break plugin.
#268838 by sun: Fixed PHP warning if no buttons are enabled for a profile.
#268838 by sun: Ported to Drupal 6.x.
#152046 by sun: Added hook_wysiwyg_plugin().
#268562 by sun: Code clean-up.
#60667 by sun: Fixed wrong editor profile is loaded when user is granted access
to more than one profile.
#264739 by sun: Fixed missing t() around some profile settings options.
Wysiwyg 5.x-0.1, 2008-06-07
---------------------------
#264739 by sun: Improved output strings.
#264739 by hass, sun: Fixed potx error due to wrong t() string.
#264411 by sun: Cleaned coding-style using coder_format script.
#264411 by sun: Moved admin functions into separate include file.
#264411 by sun: Added TinyMCE data import upon installation.
#264411 by sun: Renamed module to Wysiwyg Editor.
#118747 by nedjo, sun: Upgraded code for jQuery.
Initial fork of TinyMCE module (2008-05-30).
-2
View File
@@ -1,2 +0,0 @@
Information about upgrading existing views from Drupal 6 to Drupal 7 is located
in the module's advanced help under api upgrading.
+47 -12
View File
@@ -1,19 +1,54 @@
Welcome to Views 3. Please see the advanced help for more information.
-- SUMMARY --
If you're having trouble installing this module, please ensure that your
tar program is not flattening the directory tree, truncating filenames
or losing files.
Wysiwyg API allows to users of your site to use WYSIWYG/rich-text, and other
client-side editors for editing contents. This module depends on third-party
editor libraries, most often based on JavaScript.
Installing Views:
For a full description of the module, visit the project page:
http://drupal.org/project/wysiwyg
To submit bug reports and feature suggestions, or to track changes:
http://drupal.org/project/issues/wysiwyg
Place the entirety of this directory in sites/all/modules/views
You must also install the CTools module (http://www.drupal.org/project/ctools) to use Views.
Navigate to administer >> build >> modules. Enable Views and Views UI.
-- REQUIREMENTS --
If you're new to Views, try the Simple Views module which can create some
often used Views for you, this might save you some time.
* None.
-- INSTALLATION --
* Install as usual, see
http://drupal.org/documentation/install/modules-themes/modules-7
* Go to Administration » Configuration » Content authoring » Wysiwyg,
and follow the displayed installation instructions to download and install one
of the supported editors.
-- CONFIGURATION --
* Go to Administration » Configuration » Content authoring » Text formats, and
- either configure the Full HTML format, assign it to trusted roles, and
disable "HTML filter", "Line break converter", and (optionally) "URL filter".
- or add a new text format, assign it to trusted roles, and ensure that above
mentioned input filters are disabled.
* Setup editor profiles in Administration » Configuration » Content authoring
» Wysiwyg.
-- CONTACT --
Current maintainers:
* Daniel F. Kudwien (sun) - http://drupal.org/user/54136
* Henrik Danielsson (TwoD) - http://drupal.org/user/244227
This project has been sponsored by:
* UNLEASHED MIND
Specialized in consulting and planning of Drupal powered sites, UNLEASHED
MIND offers installation, development, theming, customization, and hosting
to get you started. Visit http://www.unleashedmind.com for more information.
Here you can find many modules extending the functionality of Views:
http://drupal.org/taxonomy/term/89
-91
View File
@@ -1,91 +0,0 @@
/**
* The query details collapsible divs are not visible in IE7 because has-layout
* is not being triggered. Trigger has-layout with height: 1%;
*/
.views-edit-view .collapsible > .fieldset-wrapper {
height: 1%;
}
/**
* The column width for the bucket containers in the query details section
* is not being calculated to 32% correctly. Give IE7 a slightly smaller
* width so that the three columns line up next to each other
*/
.views-edit-view .views-display-column {
width: 31.95%;
}
/**
* IE7 has no idea how large this container should be and it doesn't
* apply has-layout. Expand it's width to 100% and trigger has-layout.
*/
.views-edit-view .views-displays {
height: 1%;
width: 100%;
}
/**
* IE7 isn't positioning the span correctly as a display-inline element
*/
.views-edit-view .views-displays .icon {
display: block;
float: left;
}
.views-edit-view .views-displays .icon-add {
top: 2px;
}
/**
* The add display query dropdown needs a lot of help
*/
.views-edit-view .views-displays .tabs.secondary {
position: relative;
z-index: 100;
}
.views-edit-view .views-displays .secondary .open > a {
border-bottom: 1px solid #f1f1f1;
}
.views-edit-view .views-displays .secondary .action-list {
border-bottom: 1px solid #cbcbcb;
top: 30px;
}
.views-edit-view .views-displays .secondary input {
text-align: left;
}
/**
* IE7 does not interpret div > * correctly
*/
.page-admin-structure-views #content .views-ui-display-tab-bucket {
padding-left: 0;
padding-right: 0;
zoom: 1;
}
.page-admin-structure-views #content .views-display-column + .views-display-column {
margin-top: 0;
}
/**
* IE7 is interpreting a top margin of 18px from somewhere. remove it
*/
.page-admin-structure-views #content .views-display-setting {
margin-top: 0;
}
/**
* IE7 can't handle the + selector that indents form wrappers after a checkbox on the add page
* zoom is necessary to trigger has layout. !imporant is necessary because IE7 is precedent
* to the theme.css stylesheet, even though it is included before this file.
*/
.page-admin-structure-views #content .form-type-checkbox + .form-wrapper {
margin-left: 27px !important;
zoom: 1;
}
-98
View File
@@ -1,98 +0,0 @@
/**
* The .css file is intended to only contain positioning and size declarations
* For example: display, position, float, clear, and overflow.
*/
/* @group Inline lists */
.horizontal > * {
float: right;
}
.horizontal.right {
float: left;
}
/* @end */
/* @group Attachment details
*
* The attachment details section, its tabs for each section and the buttons
* to add a new section
*/
.form-actions {
float: left;
}
/* @end */
/* @group Attachment details tabs
*
* The tabs that switch between sections
*/
.views-displays .secondary > li {
float: right;
}
/* @end */
/* @group Attachment details new section button */
.views-displays .secondary .action-list {
left: auto;
right: 0;
}
/* @end */
/* @group Attachment details collapsible fieldset */
.views-display-tab .fieldset-legend {
left: auto;
right: -5px;
}
/* @end */
/* @group Attachment details actions
*
* Display the "Delete" and "Duplicate" buttons to the right.
*/
.views-display-tab .fieldset-wrapper > .views-ui-display-tab-bucket .actions {
left: 0;
right: auto;
}
/* @end */
/* @group Attachment configuration columns */
.views-display-columns > * {
float: right;
margin-left: 0;
margin-right: 1%;
padding-left: 0;
padding-right: 1%;
}
.views-display-columns > *:first-child {
margin-right: 0;
padding-right: 0;
}
/* @end */
/* @group Settings forms */
.views-dependent {
margin-right: 1.5em;
}
.views-display-setting .label,
.views-display-setting .views-ajax-link {
float: right;
}
/* @end */
-24
View File
@@ -1,24 +0,0 @@
/**
* The .advanced_help.css file is intended to contain styles that override declarations
* in the Advanced Help module.
*/
/**
* Adjust the advanced help icons
*/
.views-ui-display-tab-bucket .advanced-help-link {
padding: 0;
margin: 5px 3px 0px 6px; /* LTR */
}
.views-ui-display-tab-bucket .icon-text {
padding-left: 25px; /* LTR */
}
.views-ui-display-tab-bucket .icon-linked {
background-position: 6px -151px; /* LTR */
}
.views-ui-display-tab-bucket .icon-unlinked {
background-position: 6px -193px; /* LTR */
}
-12
View File
@@ -1,12 +0,0 @@
/**
* The .bartik.css file is intended to contain styles that override declarations
* in the Bartik theme.
*/
/* @group Lists */
.views-display-top .secondary .action-list {
padding-right: 0;
}
/* @end */
-233
View File
@@ -1,233 +0,0 @@
/**
* The .bartik.css file is intended to contain styles that override declarations
* in the Bartik theme.
*/
/* @group Lists */
.views-display-top .secondary .action-list {
padding-left: 0; /* LTR */
}
/* @end */
/* @group Attachment details tabs
*
* The tabs that switch between sections
*/
.views-displays .region-content .secondary,
.views-displays .region-content .secondary {
padding-bottom: 0;
padding-left: 0;
}
.views-displays .secondary a {
font-size: smaller;
}
.views-displays .secondary > li a {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
.views-displays .secondary > li.open a {
-moz-border-radius: 5px 5px 0 0;
-webkit-border-bottom-left-radius: 0;
-webkit-border-bottom-right-radius: 0;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
border-radius: 5px 5px 0 0;
}
.views-displays .secondary .open > a:hover {
color: #0071B3;
}
.views-displays .secondary input.form-submit {
font-size: smaller;
}
/* @end */
/* @group Modal dialog box
*
* The contents of the popup dialog on the views edit form.
*/
.views-filterable-options .even .form-type-checkbox {
background-color: #F9F9F9;
}
.views-ui-dialog .ui-dialog-titlebar-close,
.views-ui-dialog #views-ajax-title,
.views-ui-dialog .views-override,
.views-ui-dialog .form-buttons {
background-color: #f6f6f6;
}
.views-ui-dialog a {
color: #0071b3;
}
.views-ui-dialog a:hover,
.views-ui-dialog a:focus {
color: #018fe2;
}
/* @end */
/* @group CTools */
/* @group Buttons */
.ctools-button-processed {
background-image:
-moz-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, rgba(255, 255, 255, 1.0)),
color-stop(1.0, rgba(249, 249, 249, 1.0))
);
background-image:
-webkit-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding-bottom: 1px;
padding-top: 1px;
}
.ctools-button-processed:hover {
background-image:
-moz-linear-gradient(
-90deg,
#ffffff 0px,
#f1f1f1 100%);
background-image:
-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, rgba(255, 255, 255, 1.0)),
color-stop(1.0, rgba(241, 241, 241, 1.0))
);
background-image:
-webkit-linear-gradient(
-90deg,
#ffffff 0px,
#f1f1f1 100%);
background-image:
linear-gradient(
-90deg,
#ffffff 0px,
#f1f1f1 100%);
}
.ctools-button-processed li a,
.views-ui-display-tab-actions .ctools-button-processed input {
padding-left: 9px;
padding-right: 9px;
}
.ctools-content ul.actions {
padding-bottom: 0;
}
.ctools-dropbutton-processed.open:hover {
background-image:
-moz-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, rgba(255, 255, 255, 1.0)),
color-stop(1.0, rgba(249, 249, 249, 1.0))
);
background-image:
-webkit-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
}
.ctools-dropbutton-processed.open {
-moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
-webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
}
.ctools-twisty {
top: 0.6667em;
}
.ctools-dropbutton-processed.open .ctools-twisty {
top: 0.3333em;
}
.ctools-dropbutton-processed li a,
.views-ui-display-tab-actions .ctools-dropbutton-processed input {
padding-right: 7px;
}
.views-ui-display-tab-actions .ctools-button-processed input.form-submit {
margin-right: 0;
margin-top: 0;
}
/* @end */
/* @group Collapsible */
.ctools-toggle {
margin-top: 0.9em;
}
.ctools-toggle.ctools-toggle-collapsed {
margin-top: 0.72em;
}
.views-display-column > .ctools-toggle {
margin-top: 14px;
}
.views-display-column > .ctools-toggle.ctools-toggle-collapsed {
margin-top: 12px;
}
.views-ui-display-tab-actions .ctools-button input {
color: #0071B3;
}
.views-ui-display-tab-actions .ctools-button input:hover,
.views-ui-display-tab-actions .ctools-button input:focus {
color: #018FE2;
}
/* @end */
/* @end */
-63
View File
@@ -1,63 +0,0 @@
/**
* The .contextual.css file is intended to contain styles that override declarations
* in the Contextual module.
*/
/* @group Wrapper */
#views-live-preview .contextual-links-region-active {
outline: medium none;
}
#views-live-preview div.contextual-links-wrapper {
right: auto;
top: auto;
}
html.js #views-live-preview div.contextual-links-wrapper {
display: inline;
}
/* @end */
/* @group Trigger */
#views-live-preview a.contextual-links-trigger {
display: block;
}
/* @end */
/* @group List */
div.contextual-links-wrapper ul.contextual-links {
-moz-border-radius: 0 4px 4px 4px;
-webkit-border-radius: 0 4px 4px 4px;
border-radius: 0 4px 4px 4px;
min-width: 10em;
padding: 6px 6px 9px 6px;
right: auto;
}
ul.contextual-links li a,
ul.contextual-links li span {
padding-bottom: 0.25em;
padding-right: 0.1667em;
padding-top: 0.25em;
}
ul.contextual-links li span {
font-weight: bold;
}
ul.contextual-links li a {
color: #666666 !important;
margin: 0.25em 0;
padding-left: 1em;
}
ul.contextual-links li a:hover {
background-color: #badbec;
}
/* @end */
-361
View File
@@ -1,361 +0,0 @@
/**
* The .css file is intended to only contain positioning and size declarations
* For example: display, position, float, clear, and overflow.
*/
/* @group Resets */
.views-admin ul,
.views-admin menu,
.views-admin dir {
padding-left: 0; /* LTR for IE */
/* padding-start is used so that RTL works out of the box */
-moz-padding-start: 0;
-webkit-padding-start: 0;
padding-start: 0;
}
.views-admin pre {
margin-bottom: 0;
margin-top: 0;
white-space: pre-wrap;
}
/* @end */
/* @group Inline lists */
.horizontal > * {
clear: none;
float: left; /* LTR */
}
.horizontal.right {
float: right;
}
.horizontal label {
position: absolute;
}
.horizontal .form-item > [class] {
margin-top: 25px;
}
.horizontal .form-item > [class] + [class] {
margin-top: 0;
}
/* @end */
/* @group Columns */
.views-left-25 {
float: left;
width: 25%;
}
.views-left-30 {
float: left;
width: 30%;
}
.views-left-40 {
float: left;
width: 40%;
}
.views-left-50 {
float: left;
width: 50%;
}
.views-left-75 {
float: left;
width: 75%;
}
.views-right-50 {
float: right;
width: 50%;
}
.views-right-60 {
float: right;
width: 60%;
}
.views-right-70 {
float: right;
width: 70%;
}
.views-group-box .form-item {
margin-left: 3px;
margin-right: 3px;
}
/* @end */
/* @group Attachment details
*
* The attachment details section, its tabs for each section and the buttons
* to add a new section
*/
.form-edit .form-actions {
float: right; /* LTR */
}
.views-displays {
clear: both;
}
/* @end */
/* @group Attachment details tabs
*
* The tabs that switch between sections
*/
.views-displays .secondary {
border-bottom: 0 none;
margin: 0;
overflow: visible;
padding: 0;
}
.views-displays .secondary > li {
border-right: 0 none;
display: inline-block;
float: left; /* LTR */
padding: 0;
}
.views-displays .secondary .open > a {
position: relative;
z-index: 51;
}
.views-displays .views-display-deleted-link {
text-decoration: line-through;
}
.views-display-deleted > fieldset > legend,
.views-display-deleted .fieldset-wrapper > .views-ui-display-tab-bucket > *,
.views-display-deleted .views-display-columns {
opacity: 0.25;
}
.views-display-disabled > fieldset > legend,
.views-display-disabled .fieldset-wrapper > .views-ui-display-tab-bucket > *,
.views-display-disabled .views-display-columns {
opacity: 0.5;
}
.views-display-tab .fieldset-wrapper > .views-ui-display-tab-bucket .actions {
opacity: 1.0;
}
/* @end */
/* @group Attachment details new section button */
.views-displays .secondary li.add {
position: relative;
}
.views-displays .secondary .action-list {
left: 0; /* LTR */
margin: 0;
position: absolute;
top: 23px;
z-index: 50;
}
.views-displays .secondary .action-list li {
display: block;
}
/* @end */
/* @group Attachment details collapsible fieldset */
.views-display-tab .fieldset-legend {
left: -5px; /* LTR */
position: relative;
}
.views-display-tab .fieldset-wrapper {
position: relative;
}
/* @end */
/* @group Attachment details actions
*
* Display the "Delete" and "Duplicate" buttons to the right.
*/
.views-display-tab .fieldset-wrapper > .views-ui-display-tab-bucket .actions {
position: absolute;
right: 0; /* LTR */
top: -5px;
}
/* @end */
/* @group Attachment configuration columns */
.views-display-columns > * {
float: left; /* LTR */
margin-left: 1%; /* LTR */
padding-left: 1%; /* LTR */
width: 32%;
}
.views-display-columns > *:first-child {
margin-left: 0; /* LTR */
padding-left: 0; /* LTR */
}
/* @end */
/* @group Modal dialog box */
.views-ui-dialog {
/* We need this so the button is visible. */
overflow: visible;
position: fixed;
}
.views-ui-dialog .ui-dialog-titlebar-close {
border: 1px solid transparent;
display: block;
margin: 0;
padding: 0;
position: absolute;
right: 0;
top: 2px;
/* Make sure this is in front of the modal backdrop. */
z-index: 1002;
}
.views-ui-dialog .ui-dialog-titlebar {
padding: 0;
margin: 0;
}
.views-ui-dialog .ui-dialog-title {
display: none;
}
.views-ui-dialog #views-ajax-popup {
padding: 0;
overflow: hidden;
}
.views-ui-dialog #views-ajax-title,
.views-ui-dialog #views-ajax-body {
margin: 0;
padding: 0;
}
.views-ui-dialog #views-ajax-popup {
overflow: hidden;
}
.views-ui-dialog .scroll {
max-height: 400px;
overflow: auto;
}
#views-filterable-options-controls {
display: none;
}
.views-ui-dialog #views-filterable-options-controls {
display: block;
}
/* Don't let the messages overwhelm the modal */
.views-ui-dialog .views-messages {
max-height: 200px;
overflow: auto;
}
/* @end */
/* @group Settings forms */
.views-display-setting .label,
.views-display-setting .views-ajax-link {
display: inline-block;
float: left; /* LTR */
}
/* @end */
/* @group Filter Settings form */
div.form-item-options-value-all {
display: none;
}
/* @end */
/* @group Drupal overrides */
/* The .progress-disabled class added to the form on submit floats the element
* left and causes the form width to shrink-wrap to the content. Setting the
* width to 100% prevents this.
*/
#views-ajax-body form {
width: 100%;
}
/* @end */
/* @group Javascript dependent styling */
.js-only {
display: none;
}
html.js .js-only {
display: inherit;
}
html.js span.js-only {
display: inline;
}
/* @end */
/* @group AJAX throbber */
/* Base Page */
#views-ui-list-page .ajax-progress-throbber,
.views-admin .ajax-progress-throbber {
/* Can't do center:50% middle: 50%, so approximate it for a typical window size. */
left: 49%;
position: fixed;
top: 48.5%;
z-index: 1000;
}
#views-ui-list-page .ajax-progress-throbber .message,
.views-admin .ajax-progress-throbber .message {
display: none;
}
/* Modal */
#views-ajax-popup .ajax-progress-throbber {
/* Can't do center:50% middle: 50%, so approximate it for a typical window size. */
left: 49%;
position: fixed;
top: 48.5%;
z-index: 1000;
}
#views-ajax-popup .ajax-progress-throbber .message {
display: none;
}
/* @end */
-82
View File
@@ -1,82 +0,0 @@
/* @group Buttons */
.ctools-dropbutton .ctools-content {
border-left: 1px solid #e8e8e8;
}
.ctools-content ul.actions {
padding-left: auto;
padding-right: 0;
}
.ctools-dropbutton .ctools-link {
border-right: 1px solid #ffffff;
}
.ctools-dropbutton li {
padding-left: 9px;
padding-left: auto;
}
.views-display-top .ctools-button {
left: 12px;
right: auto;
}
.views-ui-display-tab-bucket .ctools-button {
left: 5px;
right: auto;
}
/* @end */
/* @group Collapsible */
.ctools-toggle {
float: right;
margin-left: 2px;
margin-right: 0;
}
.ctools-toggle.ctools-toggle-collapsed {
border-left: 0;
border-right: 4px solid;
border-left-color: transparent;
border-width: 5px 5px 5px 0;
margin-left: 5px;
margin-right: 2px;
}
.ctools-export-ui-row label {
float: right;
}
.views-display-column > .ctools-toggle {
margin-left: 3px;
margin-right: 6px;
}
.views-display-column > .ctools-toggle.ctools-toggle-collapsed {
margin-left: 5px;
margin-right: 9px;
}
/* @end */
/* @group Dependent */
.dependent-options {
margin-left: 0;
margin-right: 18px;
}
/* @end */
/* @group Export */
/* Override for filter button on the views list screen */
#ctools-export-ui-list-form .form-submit {
margin-left: 0em;
margin-right: auto;
}
/* @end */
-232
View File
@@ -1,232 +0,0 @@
/* @group Buttons */
.ctools-button-processed {
background-color: #ffffff;
border-color: #cccccc;
font-size: 11px;
padding-bottom: 2px;
padding-top: 2px;
}
.ctools-button-processed:hover {
border-color: #b8b8b8;
}
.ctools-button-processed:active {
border-color: #a0a0a0;
}
.ctools-button-processed .ctools-content {
padding-bottom: 0;
padding-top: 0;
}
.ctools-dropbutton-processed {
position: absolute;
}
.ctools-dropbutton-processed .ctools-content {
border-right: 1px solid #e8e8e8;
}
.ctools-dropbutton-processed .ctools-content ul {
margin: 0;
padding: 0;
}
.ctools-content ul.actions {
margin-top: 0;
margin-bottom: 0;
padding-left: 0;
}
.ctools-button-processed .ctools-content a {
background-image: none;
border: medium none;
}
.ctools-dropbutton-processed.open:hover {
border-color: #D0D0D0;
}
.ctools-dropbutton-processed.open {
z-index: 100;
}
.ctools-dropbutton-processed .ctools-link {
border-left: 1px solid #ffffff;
}
.ctools-dropbutton-processed.open .ctools-content {
padding-bottom: 4px;
}
.ctools-dropbutton-processed li a,
.ctools-dropbutton-processed li input {
padding-right: 9px;
}
.ctools-dropbutton-processed.open li + li {
border-top: 1px solid #efefef;
margin-top: 4px;
padding-bottom: 0;
padding-top: 4px;
}
.ctools-twisty:focus {
outline: medium none;
}
.ctools-no-js .ctools-content ul {
margin-bottom: 0;
margin-top: 0;
padding-left: 0;
}
.views-display-top .ctools-button-processed {
font-size: 12px;
position: absolute;
right: 12px;
top: 7px;
}
.views-ui-display-tab-bucket .ctools-button-processed {
position: absolute;
right: 5px;
top: 4px;
}
.views-ui-display-tab-actions .ctools-button-processed li a,
.views-ui-display-tab-actions .ctools-button-processed input {
background: none;
border: medium;
font-family: inherit;
font-size: 12px;
padding-bottom: 0;
padding-left: 12px;
padding-top: 0;
margin-bottom: 0;
}
.views-ui-display-tab-actions .ctools-button-processed input:hover {
background: none;
}
/* @end */
/* @group Collapsible */
.ctools-toggle {
border-bottom-color: transparent;
border-left-color: transparent;
border-right-color: transparent;
border-style: solid;
border-width: 5px 5px 0;
display: inline-block;
float: left;
height: 0;
margin-right: 2px;
margin-top: 0.4545em;
width: 0;
}
.ctools-toggle.ctools-toggle-collapsed {
border-bottom-color: transparent;
border-left: 4px solid;
border-right-color: transparent;
border-top-color: transparent;
border-width: 5px 0 5px 5px;
margin-left: 2px;
margin-right: 5px;
margin-top: 0.3333em;
}
.ctools-toggle:hover,
.ctools-collapsible-handle:hover {
cursor: pointer;
}
.ctools-export-ui-row {
margin-bottom: 0;
padding-top: 0;
}
.ctools-export-ui-row label {
display: block;
float: left;
width: 55px;
}
.views-display-settings .ctools-toggle {
color: #000000;
}
.views-display-column > .ctools-toggle {
margin-left: 6px;
margin-right: 3px;
margin-top: 10px;
}
.views-display-column > .ctools-toggle.ctools-toggle-collapsed {
margin-left: 9px;
margin-right: 5px;
margin-top: 8px;
}
.views-display-column > .ctools-collapsible-handle {
border-color: #F3F3F3;
border-style: solid;
border-width: 1px 1px 0;
font-size: 13px;
font-weight: normal;
margin: 0;
padding: 6px 3px;
}
.views-display-column > .ctools-toggle.ctools-toggle-collapsed + .ctools-collapsible-handle {
border-width: 1px;
}
.views-display-column > .ctools-collapsible-content > .views-ui-display-tab-bucket:first-child {
border-top: medium none;
}
h2.ctools-collapsible-handle {
display: inline;
clear: both;
}
/* @end */
/* @group Dependent */
.dependent-options {
margin-left: 18px; /* LTR */
}
/* @end */
/* @group Export */
/* Override for filter button on the views list screen */
#ctools-export-ui-list-form .form-submit {
margin-top: 0em !important;
margin-right: 0em;
}
.ctools-export-ui-row + .ctools-export-ui-row {
margin-top: 1em;
}
.ctools-export-ui-fourth-row input {
margin-top: 5px !important;
}
/* @end */
/* @group Jump list */
#views-live-preview .ctools-jump-menu-select{
max-width: 450px;
}
/* @end */
-13
View File
@@ -1,13 +0,0 @@
/**
* The .garland.css file is intended to contain styles that override declarations
* in the Garland theme.
*/
/* @group Lists */
.views-displays .secondary .action-list {
left: auto;
right: 1px;
}
/* @end */
-263
View File
@@ -1,263 +0,0 @@
/**
* The .garland.css file is intended to contain styles that override declarations
* in the Garland theme.
*/
/* @group Attachment details tabs
*
* The tabs that switch between sections
*/
.views-displays .region-content .secondary,
.views-displays .region-content .secondary {
padding-bottom: 0;
padding-left: 0;
}
.views-displays .secondary .action-list {
left: 1px;
top: 20px;
}
.views-displays .secondary .action-list li,
.views-displays .secondary a {
border-color: #e9e9e9;
}
.views-displays .secondary a {
font-size: 12px;
padding: 2px 7px;
}
.views-displays ul.secondary li a:hover,
.views-displays ul.secondary li.active a {
border: 1px solid transparent;
padding: 2px 7px;
}
.views-displays .secondary > li a {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
.views-displays .secondary > li.open a {
background-image: none;
-moz-border-radius: 5px 5px 0 0;
-webkit-border-bottom-left-radius: 0;
-webkit-border-bottom-right-radius: 0;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
border-radius: 5px 5px 0 0;
}
.views-displays .secondary .open > a:hover {
border-color: #e9e9e9 #e9e9e9 #f1f1f1 #e9e9e9;
border-width: 1px 1px 1px 1px;
color: #0071B3;
}
.views-displays .secondary input.form-submit {
font-size: 11px;
}
/* @end */
/* @group Attachment buckets
*
* These are the individual "buckets," or boxes, inside the display settings area
*/
.views-ui-display-tab-bucket h3 {
font-weight: bold;
}
/* @end */
/* @group Modal dialog box
*
* The contents of the popup dialog on the views edit form.
*/
.views-filterable-options .form-type-checkbox {
margin: 0;
}
.views-filterable-options .even .form-type-checkbox {
background-color: #F9F9F9;
}
.views-ui-dialog .ui-dialog-titlebar-close,
.views-ui-dialog #views-ajax-title,
.views-ui-dialog .views-override,
.views-ui-dialog .form-buttons {
background-color: #f6f6f6;
}
/* @end */
/* @group CTools */
/* @group Buttons */
.ctools-button-processed {
background-image:
-moz-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, rgba(255, 255, 255, 1.0)),
color-stop(1.0, rgba(249, 249, 249, 1.0))
);
background-image:
-webkit-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding-bottom: 1px;
padding-top: 1px;
}
.ctools-button-processed:hover {
background-image:
-moz-linear-gradient(
-90deg,
#ffffff 0px,
#f1f1f1 100%);
background-image:
-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, rgba(255, 255, 255, 1.0)),
color-stop(1.0, rgba(241, 241, 241, 1.0))
);
background-image:
-webkit-linear-gradient(
-90deg,
#ffffff 0px,
#f1f1f1 100%);
background-image:
linear-gradient(
-90deg,
#ffffff 0px,
#f1f1f1 100%);
}
.ctools-button-processed ol li,
.ctools-button-processed ul li {
margin: 0;
padding-bottom: 0;
}
.views-ui-display-tab-actions .ctools-button-processed input {
margin-right: 0;
}
.ctools-content ul.actions {
padding-bottom: 0;
}
.ctools-dropbutton-processed.open:hover {
background-image:
-moz-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, rgba(255, 255, 255, 1.0)),
color-stop(1.0, rgba(249, 249, 249, 1.0))
);
background-image:
-webkit-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
}
.ctools-dropbutton-processed.open {
-moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
-webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
}
.ctools-twisty {
top: 0.6667em;
}
.ctools-dropbutton-processed.open .ctools-twisty {
top: 0.3333em;
}
/* @end */
/* @group Dependent */
.dependent-options,
.form-checkboxes.dependent-options,
.form-radios.dependent-options,
.form-checkboxes .form-item.dependent-options,
.form-radios .form-item.dependent-options {
margin-left: 25px;
}
/* @end */
/* @group Collapsible */
.ctools-toggle {
margin-top: 0.5em;
}
.ctools-toggle,
.views-display-settings .ctools-toggle {
color: #494949;
}
.ctools-toggle.ctools-toggle-collapsed {
margin-top: 0.25em;
}
.views-display-column > .ctools-toggle {
margin-top: 14px;
}
.views-display-column > .ctools-toggle.ctools-toggle-collapsed {
margin-top: 12px;
}
.views-ui-display-tab-actions .ctools-button input {
color: #027AC6;
font-size: 12px;
}
.views-ui-display-tab-actions .ctools-button input:hover,
.views-ui-display-tab-actions .ctools-button input:focus {
color: #0062A0;
}
/* @end */
/* @end */
-43
View File
@@ -1,43 +0,0 @@
/**
* The .seven.css file is intended to contain styles that override declarations
* in the Seven admin theme.
*/
/* @group Forms */
.views-admin .form-submit,
.views-admin a.button {
margin-left: 0;
}
/* @end */
/* @group Lists */
.views-admin .links li {
padding-left: 0;
}
/* @end */
/* @group Attachments */
.views-displays .secondary {
text-align: right;
}
/* @end */
/* @group Attachment details tabs */
.views-display-top ul.secondary {
float: right;
}
.views-displays .secondary .action-list li:first-child {
-moz-border-radius: 7px 0 0 0;
-webkit-border-radius: 7px 0 0 0;
border-radius: 7px 0 0 0;
}
/* @end */
-552
View File
@@ -1,552 +0,0 @@
/**
* The .seven.css file is intended to contain styles that override declarations
* in the Seven admin theme.
*/
/* @group Content */
.views-ui-display-tab-bucket h1,
.views-ui-display-tab-bucket h2,
.views-ui-display-tab-bucket h3,
.views-ui-display-tab-bucket h4,
.views-ui-display-tab-bucket h5 {
margin-bottom: 0;
margin-top: 0;
}
/* @end */
/* @group Forms */
.views-ui-dialog fieldset {
padding-top: 2.5em;
}
fieldset fieldset {
border: medium none;
}
/**
* Seven positions the legend absolutely, but does not have a way to ignore
* fieldsets without a legend so we make one up.
*/
fieldset.fieldset-no-legend {
padding-top: 0;
}
/**
* Being extra safe here and scoping this to the add view wizard form (where
* a layout problem occurs for the Display format fieldset if we don't fix its
* padding), but it's probably safe to just let it apply everywhere.
*/
#views-ui-add-form fieldset fieldset .fieldset-wrapper {
padding-left: 0;
padding-right: 0;
}
.views-display-tab fieldset {
padding: 0 12px;
}
.views-display-tab .fieldset-wrapper {
padding: 10px 12px 12px;
}
.views-display-tab fieldset.box-padding .fieldset-wrapper {
padding: 0;
}
.views-display-tab legend + .fieldset-wrapper {
padding-top: 2.5em;
}
.views-admin .form-item label.option,
#views-ui-preview-form .form-item label.option {
font-size: 1em;
}
#views-ui-preview-form .form-submit {
margin-top: 3px;
}
.views-admin input.form-submit,
.views-ui-dialog input.form-submit,
.views-admin a.button,
.views-ui-dialog a.button {
margin-bottom: 0;
margin-right: 0; /* LTR */
margin-top: 0;
}
/* Override for a button on the edit display screen */
#edit-displays-preview-controls .form-submit {
display: inline-block;
margin-right: 1em;
}
/* Override for filter button on the views list screen */
#ctools-export-ui-list-form .form-submit {
margin-bottom: 0;
}
#ctools-export-ui-list-form .ctools-export-ui-first-row .form-item {
margin-top: 3px;
margin-right: 5px; /* LTR */
}
.form-item,
.form-item .form-item {
margin-bottom: 0;
margin-top: 9px;
padding-bottom: 0;
padding-top: 0;
}
.form-actions {
margin-bottom: 0;
margin-top: 0;
}
.form-item .form-item {
padding-bottom: 0;
padding-top: 0;
}
.form-radios > .form-item {
margin-top: 3px;
}
/* @group Dependent options
*
* Dependent options are identified in CTools dependent.js
*/
/* The .dependent-options.form-item is necessary to supercede the Seven .form-item
* reset declaration that sets the margin to zero.
*/
.dependent-options,
.dependent-options.form-item,
.form-item-options-expose-required,
.form-item-options-expose-label,
.form-item-options-expose-description {
margin-left: 1.5em;
}
.views-admin-dependent .form-item .form-item,
.views-admin-dependent .form-type-checkboxes,
.views-admin-dependent .form-type-radios,
.views-admin-dependent .dependent-options,
.views-admin-dependent .form-item .form-item,
.views-admin-dependent .dependent-options .form-type-select,
.views-admin-dependent .dependent-options .form-type-textfield,
.form-item-options-expose-required,
.form-item-options-expose-label,
.form-item-options-expose-description {
margin-bottom: 6px;
margin-top: 6px;
}
.views-admin-dependent .form-type-radio,
.views-admin-dependent .form-radios .form-item {
margin-bottom: 2px;
margin-top: 2px;
}
/* @end */
/* @end */
/* @group Lists */
.views-admin ul.secondary,
.views-admin .item-list ul {
margin: 0;
padding: 0;
}
.views-admin ul.secondary {
clear: none;
}
.views-displays ul.secondary li a,
.views-displays ul.secondary li.active a,
.views-displays ul.secondary li.active a.active {
padding: 2px 7px 3px;
}
.views-displays ul.secondary li.active a,
.views-displays ul.secondary li.active a.active {
border: 1px solid transparent;
}
.views-admin .links li {
padding-right: 0; /* LTR */
}
.views-admin .button .links li {
padding-right: 12px; /* LTR */
}
.page-admin-structure-views #content ul.action-links {
padding-left: 0;
padding-right: 0;
}
.views-display-top ul.secondary {
background-color: transparent;
float: left
}
.views-display-top .secondary .action-list li {
float: none;
margin: 0;
}
/* @end */
/* @group Buttons */
.ctools-button-processed ul {
margin: 0;
}
/* Override for input elements that are themed like ctools-buttons */
.ctools-button-processed input.form-submit:hover {
background-image: none;
color: #0074BD;
text-shadow: none;
}
.ctools-button-processed input.form-submit:active {
background: none;
border: medium none;
color: #0074BD;
text-shadow: none;
}
/* @end */
/* @group Tables */
table td,
table th {
vertical-align: top;
}
/* @end */
/* @group Attachment details */
#edit-display-settings-title {
color: #008BCB;
}
/* @end */
/* @group Attachment details tabs
*
* The tabs that switch between sections
*/
.views-displays .secondary {
text-align: left; /* LTR */
}
.views-displays .secondary > li:first-child {
padding-left: 0;
}
.views-admin .icon.add {
background-position: center 3px;
}
.views-displays .secondary a {
background-color: #f1f1f1;
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
border-radius: 7px;
color: #008BCB;
}
.views-displays .secondary a:hover > .icon.add {
background-position: center -25px;
}
.views-displays .secondary .open > a {
-moz-border-radius: 7px 7px 0 0;
-webkit-border-radius: 7px 7px 0 0;
border-radius: 7px 7px 0 0;
}
.views-displays .secondary .open > a:hover {
background-color: #f1f1f1;
color: #008BCB;
}
.views-displays .secondary .action-list li:first-child {
-moz-border-radius: 0 7px 0 0;
-webkit-border-radius: 0 7px 0 0;
border-radius: 0 7px 0 0;
}
.views-displays .secondary .action-list li:last-child {
-moz-border-radius: 0 0 7px 7px;
-webkit-border-radius: 0 0 7px 7px;
border-radius: 0 0 7px 7px;
}
.views-displays .secondary .action-list input.form-submit {
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
color: #008BCB;
}
/* @end */
/* @group Attachment buckets
*
* These are the individual "buckets," or boxes, inside the display settings area
*/
.views-ui-display-tab-bucket h3 {
font-size: 12px;
text-transform: uppercase;
}
.views-ui-display-tab-bucket .links {
padding: 2px 6px 4px;
}
.views-ui-display-tab-bucket .links li + li {
margin-left: 3px;
}
/* @end */
/* @group Rearrange filter criteria */
#views-ui-rearrange-filter-form .action-links {
margin: 0;
padding: 0;
}
#views-ui-rearrange-filter-form table {
border: medium none;
}
#views-ui-rearrange-filter-form [id^="views-row"] {
border: medium none;
}
#views-ui-rearrange-filter-form tr td:last-child {
border-right: medium none;
}
#views-ui-rearrange-filter-form .filter-group-operator-row {
border-left: 1px solid transparent !important;
border-right: 1px solid transparent !important;
}
#views-ui-rearrange-filter-form tr.drag td {
background-color: #FFEE77 !important;
}
#views-ui-rearrange-filter-form tr.drag-previous td {
background-color: #FFFFBB !important;
}
/* @end */
/* @group Live preview elements */
.views-query-info pre {
margin-bottom: 0;
margin-top: 0;
}
/* @group Query info table */
.views-query-info table {
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
border-radius: 7px;
-webkit-border-horizontal-spacing: 1px;
-webkit-border-vertical-spacing: 1px;
}
.views-query-info table tr td:last-child {
/* Fixes a Seven style that bleeds down into this table unnecessarily */
border-right: 0 none;
}
/* @end */
/* @end */
/* @group Add view */
.form-item-page-create,
.form-item-block-create {
margin-top: 13px;
}
/* @end */
/* @group Modal dialog box
*
* The contents of the popup dialog on the views edit form.
*/
.views-ui-dialog .ui-dialog-titlebar-close {
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
border-color: #cccccc;
right: -27px;
top: -1px;
}
.views-ui-dialog fieldset.collapsible {
padding-top: 1.5em;
}
.views-ui-dialog fieldset.collapsed {
padding-top: 2.5em;
}
.filterable-option .form-item.form-type-checkbox {
/* This selector is aggressive because Seven's reset for .form-items is aggressive. */
padding-bottom: 4px;
padding-left: 4px;
padding-top: 4px;
}
/* @end */
/* @group CTools */
/* @group Buttons */
.ctools-button-processed {
background-image:
-moz-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, rgba(255, 255, 255, 1.0)),
color-stop(1.0, rgba(249, 249, 249, 1.0))
);
background-image:
-webkit-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
-moz-border-radius: 11px 11px 11px 11px;
-webkit-border-radius: 11px 11px 11px 11px;
border-radius: 11px 11px 11px 11px;
}
.ctools-button-processed:hover {
background-image:
-moz-linear-gradient(
-90deg,
#ffffff 0px,
#f1f1f1 100%);
background-image:
-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, rgba(255, 255, 255, 1.0)),
color-stop(1.0, rgba(241, 241, 241, 1.0))
);
background-image:
-webkit-linear-gradient(
-90deg,
#ffffff 0px,
#f1f1f1 100%);
background-image:
linear-gradient(
-90deg,
#ffffff 0px,
#f1f1f1 100%);
}
.ctools-dropbutton-processed.open:hover {
background-image:
-moz-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, rgba(255, 255, 255, 1.0)),
color-stop(1.0, rgba(249, 249, 249, 1.0))
);
background-image:
-webkit-linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
background-image:
linear-gradient(
-90deg,
#ffffff 0px,
#f9f9f9 100%);
}
.ctools-dropbutton-processed.open {
-moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
-webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
}
/* @end */
/* @group Collapsible */
.ctools-toggle {
margin-top: 0.6667em;
}
.ctools-toggle.ctools-toggle-collapsed {
margin-top: 0.5em;
}
.views-display-settings .ctools-toggle {
color: #008BCB;
}
.views-display-column > .ctools-toggle {
margin-top: 14px;
}
.views-display-column > .ctools-toggle.ctools-toggle-collapsed {
margin-top: 12px;
}
.views-display-column > .ctools-collapsible-handle {
color: #008BCB;
}
.views-ui-display-tab-actions .ctools-button-processed input {
color: #0074BD;
}
/* @end */
/* @end */
-208
View File
@@ -1,208 +0,0 @@
/**
* The .theme.css file is intended to contain presentation declarations including
* images, borders, colors, and fonts.
*/
/* @end */
/* @group Icons */
.actions a,
.views-admin .icon,
.views-admin .icon-text {
background-position: right top;
}
/* Targets any element with an icon -> text combo */
.views-admin .icon-text {
padding-right: 19px;
}
.views-admin .icon-linked {
background-position: right -153px;
}
.views-admin .icon-unlinked {
background-position: right -195px;
}
.actions .views-button-add {
background-position: right -39px;
}
.actions .views-button-rearrange {
background-position: right -96px;
}
.actions .views-button-add:hover {
background-position: right -58px;
}
.actions .views-button-rearrange:hover {
background-position: right -115px;
}
.actions .views-button-add:active {
background-position: right -77px;
}
.actions .views-button-rearrange:active {
background-position: right -134px;
}
.views-displays .icon-add {
background-position: right -3px;
}
.views-displays .secondary a:hover > .icon-add {
background-position: right -21px;
}
.views-displays .secondary .open a:hover > .icon-add {
background-position: right -3px;
}
/* @end */
/* @group Forms */
.form-submit + .form-submit,
.views-admin a.button + a.button {
margin-right: 1em;
}
.container-inline > * + *,
.container-inline .fieldset-wrapper > * + * {
padding-left: 0;
padding-right: 4pt;
}
.views-admin .form-type-checkbox + .form-wrapper {
margin-right: 16px;
}
/* @end */
/* @group Lists */
.horizontal > * + * {
margin-right: 9px;
padding-right: 9px;
}
/* @end */
/* @group Attachments */
.views-displays .secondary {
padding: 6px 8px 8px;
}
.views-displays .views-display-top > ul > li + li {
margin-right: 3px;
}
.views-displays .views-extra-actions {
left: 10px;
}
/* @end */
/* @group Attachment details tabs
*
* The tabs that switch between sections
*/
.views-displays .secondary .action-list li:first-child {
-moz-border-radius: 7px 0 0 0;
-webkit-border-top-left-radius: 7px;
-webkit-border-top-right-radius: 0;
border-radius: 7px 0 0 0;
}
/* @end */
/* @group Attachment details collapsible fieldset
*
* The attachment details section is a collapsible fieldset, but should not
* have a border around it.
*/
.views-display-tab .fieldset-legend {
left: auto;
right: -5px;
}
/* @end */
/* @group Auto preview
*
* The auto-preview checkbox line. This may have more stuff added to it.
*/
div.form-item-displays-live-preview {
text-align: left;
}
/* @end */
/* @group Attachment buckets
*
* These are the individual "buckets," or boxes, inside the three columns in the
* attachment details section.
*/
.views-ui-display-tab-bucket .icon-text {
padding-right: 25px;
}
/* @end */
/* @group Attachment bucket rows
*
* This is each row within one of the "boxes."
*/
.views-display-setting .label {
margin-left: 3pt;
}
/* @end */
/* @group Modal dialog box
*
* The contents of the popup dialog on the views edit form.
*/
#views-filterable-options-controls .form-item {
margin-left: 2%;
}
.views-ui-dialog #views-progress-indicator {
left: 10px;
right: auto;
}
/* @end */
/* @group Rearrange filters
*
* Styling for the form that allows views filters to be rearranged.
*/
.views-operator-label {
padding-right: 0.5em;
}
/* @end */
/* @group Live preview elements */
/* @group HTML list */
#views-live-preview .view-content > .item-list > ul {
padding-right: 21px;
}
/* @end */
/* @end */
File diff suppressed because it is too large Load Diff
-5
View File
@@ -1,5 +0,0 @@
.views-exposed-form .views-exposed-widget {
float: right; /* RTL */
padding: .5em 1em 0 0; /* RTL */
}
-42
View File
@@ -1,42 +0,0 @@
.views-exposed-form .views-exposed-widget {
float: left; /* LTR */
padding: .5em 1em 0 0; /* LTR */
}
.views-exposed-form .views-exposed-widget .form-submit {
margin-top: 1.6em;
}
.views-exposed-form .form-item,
.views-exposed-form .form-submit {
margin-top: 0;
margin-bottom: 0;
}
.views-exposed-form label {
font-weight: bold;
}
.views-exposed-widgets {
margin-bottom: .5em;
}
/* table style column align */
.views-align-left {
text-align: left;
}
.views-align-right {
text-align: right;
}
.views-align-center {
text-align: center;
}
/* Remove the border on tbody that system puts in */
.views-view-grid tbody {
border-top: none;
}
.view .progress-disabled {
float: none;
}
-5
View File
@@ -1,5 +0,0 @@
- If the interface text is *bolded*, it got strong tags.
- If it's a button they need to click, that's *bold* too.
- If the text is not bolded (ex: links to click, options to check), it
got /italicized/.
- If it's user-entered text it got 'single quotes'.
-496
View File
@@ -1,496 +0,0 @@
<?php
/**
* @file
* Drush integration of views.
*
* drush cache-clear views - Clears the views specific caches.
* views-revert - Drush command to revert views overridden in the system.
*/
/**
* Implement hook_drush_help().
*/
function views_drush_help($section) {
switch ($section) {
case 'drush:views-revert':
$help = dt('Reverts views in the drupal installation that have been overriden. ');
$help .= dt('If no view names are specified, you will be presented with a list of overridden views to choose from. ');
$help .= dt('To revert all views, do not specify any view names, and choose the option "All" from the options presented.');
return $help;
case 'drush:views-list':
return dt('Show a list of available views with information about them.');
case 'drush:views-enable':
return dt('Enable the specified views. Follow the command with a space delimited list of view names');
case 'drush:views-disable':
return dt('Disable the specified views. Follow the command with a space delimited list of view names');
}
}
/**
* Implement hook_drush_command().
*/
function views_drush_command() {
$items = array();
$items['views-revert'] = array(
'callback' => 'views_revert_views',
'drupal dependencies' => array('views'),
'description' => 'Revert overridden views to their default state. Make sure to backup first.',
'arguments' => array(
'views' => 'A space delimited list of view names.',
),
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
'aliases' => array('vr'),
'examples' => array(
'drush vr archive' => 'Reverts the "archive" view.',
'drush rln archive frontpage' => 'Reverts the "archive" and "frontpage" view.',
'drush vr' => 'Will present you with a list of overridden views to choose from, and an option to revert all overridden views.',
),
);
$items['views-dev'] = array(
'callback' => 'views_development_settings',
'drupal dependencies' => array('views'),
'description' => 'Set the Views settings to more developer-oriented values.',
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
'aliases' => array('vd'),
);
$items['views-list'] = array(
'drupal dependencies' => array('views'),
'description' => 'Get a list of all views in the system.',
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
'aliases' => array('vl'),
'options' => array(
'name' => 'String contained in view\'s name by which filter the results.',
'tags' => 'A comma-separated list of views tags by which to filter the results.',
'status' => 'Status of the views by which to filter the results. Choices: enabled, disabled.',
'type' => 'Type of the views by which to filter the results. Choices: normal, default or overridden.',
),
'examples' => array(
'drush vl' => 'Show a list of all available views.',
'drush vl --name=blog' => 'Show a list of views which names contain "blog".',
'drush vl --tags=tag1,tag2' => 'Show a list of views tagged with "tag1" or "tag2".',
'drush vl --status=enabled' => 'Show a list of enabled views.',
'drush vl --type=overridden' => 'Show a list of overridden views.',
),
);
$items['views-analyze'] = array(
'drupal dependencies' => array('views', 'views_ui'),
'description' => 'Get a list of all Views analyze warnings',
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
'aliases' => array('va'),
);
$items['views-enable'] = array(
'drupal dependencies' => array('views'),
'description' => 'Enable the specified views.',
'arguments' => array(
'views' => 'A space delimited list of view names.',
),
'aliases' => array('ven'),
'examples' => array(
'drush ven frontpage taxonomy_term' => 'Enable the frontpage and taxonomy_term views.',
),
);
$items['views-disable'] = array(
'drupal dependencies' => array('views'),
'description' => 'Disable the specified views.',
'arguments' => array(
'views' => 'A space delimited list of view names.',
),
'aliases' => array('vdis'),
'examples' => array(
'drush vdis frontpage taxonomy_term' => 'Disable the frontpage and taxonomy_term views.',
),
);
return $items;
}
/**
* Callback function for views-revert command.
*/
function views_revert_views() {
$views = views_get_all_views();
$i = 0;
// The provided views names specified in the command.
$viewnames = _convert_csv_to_array(func_get_args());
// Find all overridden views.
foreach ($views as $view) {
if ($view->disabled) {
continue;
}
if ($view->type == dt('Overridden')) {
$overridden[$view->name] = $view->name;
}
}
// Return early if there are no overridden views in the system.
if (empty($overridden)) {
return drush_set_error(dt('There are no overridden views in the system.'));
}
// If the user specified in the command the views to be overridden.
if (!empty($viewnames)) {
foreach ($viewnames as $key => $viewname) {
$is_overridden = key_exists($viewname, $overridden);
// Check if the provided view name is in the system
if ($viewname && !key_exists($viewname, $views)) {
drush_set_error(dt("'@viewname' view is not present in the system.", array('@viewname' => $viewname)));
}
// Check if the provided view is overridden.
elseif (!$is_overridden) {
drush_set_error(dt("The view specified '@viewname' is not overridden.", array('@viewname' => $viewname)));
}
// If the view is overriden, revert it.
elseif ($is_overridden){
views_revert_view($views[$viewname]);
$i++;
}
// We should never get here but well...
else {
drush_set_error(dt("The view specified '@viewname' is not provided in code, and thus cannot be reverted.", array('@viewname' => $viewname)));
}
}
}
// The user did not specify any views in the command, prompt the user
else {
// list of choices for the user
$overridden['all'] = dt('Revert all overridden views'); // add a choice at the end
$choice = drush_choice($overridden, 'Enter a number to choose which view to revert.', '!key'); // prompt the user
if ($choice !== FALSE) {
// revert all views option
if ($choice == 'all') {
$i = views_revert_allviews($views);
}
// else the user specified a single view
else {
views_revert_view($views[$choice]);
$i++;
}
}
}
// final results output
if ($i == 0) {
drush_log(dt('No views were reverted.'), 'ok');
}
else {
drush_log(dt('Reverted a total of @count views.', array('@count' => $i)), 'ok');
}
}
/**
* Reverts all views
* @param $views
* All views in the system as provided by views_get_all_views().
*/
function views_revert_allviews($views) {
$i = 0;
foreach ($views as $view) {
if ($view->disabled) {
continue;
}
if ($view->type == t('Overridden')) {
views_revert_view($view);
$i++;
}
}
return $i;
}
/**
* Revert a specified view
* @param $view
* The view object to be reverted
*
* Checks on wether or not the view is overridden is handled in views_revert_views_revert()
* We perform a check here anyway in case someone somehow calls this function on their own...
*/
function views_revert_view($view) {
// check anyway just in case
if ($view->type == t('Overridden')) {
// Revert the view.
$view->delete();
// Clear its cache.
ctools_include('object-cache');
ctools_object_cache_clear('view', $view->name);
// Give feedback.
$message = dt("Reverted the view '@viewname'", array('@viewname' => $view->name));
drush_log($message, 'success');
// Reverted one more view.
}
else {
drush_set_error(dt("The view '@viewname' is not overridden.", array('@viewname' => $view->name)));
}
}
/**
* Change the settings to a more developer oriented value.
*/
function views_development_settings() {
variable_set('views_ui_show_listing_filters', TRUE);
variable_set('views_ui_show_master_display', TRUE);
variable_set('views_ui_show_advanced_column', TRUE);
variable_set('views_ui_always_live_preview', FALSE);
variable_set('views_ui_always_live_preview_button', TRUE);
variable_set('views_ui_show_preview_information', TRUE);
variable_set('views_ui_show_sql_query', TRUE);
variable_set('views_ui_show_performance_statistics', TRUE);
variable_set('views_show_additional_queries', TRUE);
variable_set('views_devel_output', TRUE);
variable_set('views_devel_region', 'message');
variable_set('views_ui_display_embed', TRUE);
$message = dt("Setup the new views settings.");
drush_log($message, 'success');
}
/**
* Callback function for views-list command.
*/
function drush_views_list() {
// Initialize stuf
$rows = array();
$disabled_views = array();
$enabled_views = array();
$overridden = 0;
$indb = 0;
$incode = 0;
$disabled = 0;
$total = 0;
$views = views_get_all_views();
// get the --name option
// TODO : take into account the case off a comma-separated list of names
$name = drush_get_option_list('name');
$with_name = !empty($name) ? TRUE : FALSE;
// get the --tags option
$tags = drush_get_option_list('tags');
$with_tags = !empty($tags) ? TRUE : FALSE;
// get the --status option
// store user input appart to reuse it after
$status_opt = drush_get_option_list('status');
// use the same logic than $view->disabled
if (in_array('disabled', $status_opt)) {
$status = TRUE;
$with_status = TRUE;
}
elseif (in_array('enabled', $status_opt)) {
$status = FALSE;
$with_status = TRUE;
}
else {
$status = NULL;
// wrong or empty --status option
$with_status = FALSE;
}
// get the --type option
$type = drush_get_option_list('type');
// use the same logic than $view->type
$with_type = FALSE;
if (in_array('normal', $type) || in_array('default', $type)|| in_array('overridden', $type)) {
$with_type = TRUE;
}
// set the table headers
$header = array(
dt('Machine name'),
dt('Description'),
dt('Type'),
dt('Status'),
dt('Tag'),
);
// setup a row for each view
foreach($views as $id => $view){
// if options were specified, check that first
// mismatch push the loop to the next view
if ($with_tags && !in_array($view->tag, $tags)) {
continue;
}
if ($with_status && !$view->disabled == $status) {
continue;
}
if ($with_type && strtolower($view->type) !== $type[0]) {
continue;
}
if ($with_name && !stristr($view->name, $name[0])) {
continue;
}
$row = array();
// each row entry should be in the same order as the header
$row[] = $view->name;
$row[] = $view->description;
$row[] = $view->type;
$row[] = $view->disabled ? dt('Disabled') : dt('Enabled');
$row[] = $view->tag;
// place the row in the appropiate array,
// so we can have disabled views at the bottom
if($view->disabled) {
$disabled_views[] = $row;
}
else{
$enabled_views[] = $row;
}
unset($row);
// gather some statistics
switch($view->type) {
case dt('Normal'):
$indb++;
break;
case dt('Overridden'):
$overridden++;
break;
case dt('Default'):
$incode++;
break;
}
$total++;
}
$disabled = count($disabled_views);
// sort alphabeticaly
asort($disabled_views);
asort($enabled_views);
// if options were used
$summary = "";
if ($with_name || $with_tags || $with_status || $with_type) {
$summary = "Views";
if ($with_name) {
$summary .= " named $name[0]";
}
if ($with_tags) {
$tags = implode(" or ", $tags);
$summary .= " tagged $tags";
}
if ($with_status) {
$status_opt = implode("", $status_opt);
$summary .= " which status is '$status_opt'";
}
if ($with_type) {
$type = ucfirst($type[0]);
$summary .= " of type '$type'";
}
}
if (!empty($summary)) {
drush_print($summary . "\n");
}
// print all rows as a table
if ($total > 0) {
$rows = array_merge($enabled_views, $disabled_views);
// put the headers as first row
array_unshift($rows, $header);
drush_print_table($rows, TRUE);
}
// print the statistics messages
drush_print(dt("A total of @total views were found in this Drupal installation:", array('@total' => $total)));
drush_print(dt(" @indb views reside only in the database", array('@indb' => $indb )));
drush_print(dt(" @over views are overridden", array('@over' => $overridden)));
drush_print(dt(" @incode views are in their default state", array('@incode' => $incode)));
drush_print(dt(" @dis views are disabled\n", array('@dis' => $disabled)));
}
function drush_views_analyze() {
views_include('analyze');
$messages_count = 0;
$total = 0;
foreach (views_get_all_views() as $view_name => $view) {
$total++;
if ($messages = views_analyze_view($view)) {
drush_print($view_name);
foreach ($messages as $message) {
$messages_count++;
drush_print($message['type'] .': '. $message['message'], 2);
}
}
}
drush_log(dt('A total of @total views were analyzed and @messages problems were found.', array('@total' => $total, '@messages' => $messages_count)), 'ok');
}
/**
* Enables views
*/
function drush_views_enable() {
$viewnames = _convert_csv_to_array(func_get_args());
// Return early if no view names were specified.
if (empty($viewnames)) {
return drush_set_error(dt('Please specify a space delimited list of view names to enable'));
}
_views_drush_changestatus($viewnames, FALSE);
}
/**
* Disables views
*/
function drush_views_disable() {
$viewnames = _convert_csv_to_array(func_get_args());
// Return early if no view names were specified.
if (empty($viewnames)) {
return drush_set_error(dt('Please specify a space delimited list of view names to disable'));
}
_views_drush_changestatus($viewnames, TRUE);
}
/**
* Helper function to enable / disable views
* @param $viewnames: array of viewnames to process
* @param $status: TRUE to disable or FALSE to enable the view
*/
function _views_drush_changestatus($viewnames = array(), $status = NULL) {
if ($status !== NULL && !empty($viewnames)) {
$changed = FALSE;
$processed = $status ? dt('disabled') : dt('enabled');
$views_status = variable_get('views_defaults', array());
foreach ($viewnames as $key => $viewname) {
if ($views_status[$viewname] !== $status) {
$views_status[$viewname] = $status;
$changed = TRUE;
drush_log(dt("The view '!name' has been !processed", array('!name' => $viewname, '!processed' => $processed)), 'success');
}
else {
drush_set_error(dt("The view '!name' is already !processed", array('!name' => $viewname, '!processed' => $processed)));
}
}
// If we made changes to views status, save them and clear caches
if ($changed) {
variable_set('views_defaults', $views_status);
views_invalidate_cache();
drush_log(dt("Views cache was cleared"), 'ok');
drush_log(dt("Menu cache is set to be rebuilt on the next request."), 'ok');
}
}
}
/**
* Adds a cache clear option for views.
*/
function views_drush_cache_clear(&$types) {
$types['views'] = 'views_invalidate_cache';
}
+464
View File
@@ -0,0 +1,464 @@
<?php
/**
* @file
* Editor integration functions for CKEditor.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_ckeditor_editor() {
$editor['ckeditor'] = array(
'title' => 'CKEditor',
'vendor url' => 'http://ckeditor.com',
'download url' => 'http://ckeditor.com/download',
'libraries' => array(
'' => array(
'title' => 'Default',
'files' => array(
'ckeditor.js' => array('preprocess' => FALSE),
),
),
'src' => array(
'title' => 'Source',
'files' => array(
'ckeditor_source.js' => array('preprocess' => FALSE),
),
),
),
'install note callback' => 'wysiwyg_ckeditor_install_note',
'version callback' => 'wysiwyg_ckeditor_version',
'themes callback' => 'wysiwyg_ckeditor_themes',
'settings form callback' => 'wysiwyg_ckeditor_settings_form',
'init callback' => 'wysiwyg_ckeditor_init',
'settings callback' => 'wysiwyg_ckeditor_settings',
'plugin callback' => 'wysiwyg_ckeditor_plugins',
'plugin settings callback' => 'wysiwyg_ckeditor_plugin_settings',
'proxy plugin' => array(
'drupal' => array(
'load' => TRUE,
'proxy' => TRUE,
),
),
'proxy plugin settings callback' => 'wysiwyg_ckeditor_proxy_plugin_settings',
'versions' => array(
'3.0.0.3665' => array(
'js files' => array('ckeditor-3.0.js'),
),
),
);
return $editor;
}
/**
* Return an install note.
*/
function wysiwyg_ckeditor_install_note() {
return '<p class="warning">' . t('Do NOT download the "CKEditor for Drupal" edition.') . '</p>';
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_ckeditor_version($editor) {
$library = $editor['library path'] . '/ckeditor.js';
if (!file_exists($library)) {
return;
}
$library = fopen($library, 'r');
$max_lines = 8;
while ($max_lines && $line = fgets($library, 500)) {
// version:'CKEditor 3.0 SVN',revision:'3665'
// version:'3.0 RC',revision:'3753'
// version:'3.0.1',revision:'4391'
if (preg_match('@version:\'(?:CKEditor )?([\d\.]+)(?:.+revision:\'([\d]+))?@', $line, $version)) {
fclose($library);
// Version numbers need to have three parts since 3.0.1.
$version[1] = preg_replace('/^(\d+)\.(\d+)$/', '${1}.${2}.0', $version[1]);
return $version[1] . '.' . $version[2];
}
$max_lines--;
}
fclose($library);
}
/**
* Determine available editor themes or check/reset a given one.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $profile
* A wysiwyg editor profile.
*
* @return
* An array of theme names. The first returned name should be the default
* theme name.
*/
function wysiwyg_ckeditor_themes($editor, $profile) {
// @todo Skins are not themes but this will do for now.
$path = $editor['library path'] . '/skins/';
if (file_exists($path) && ($dir_handle = opendir($path))) {
$themes = array();
while ($file = readdir($dir_handle)) {
if (is_dir($path . $file) && substr($file, 0, 1) != '.' && $file != 'CVS') {
$themes[] = $file;
}
}
closedir($dir_handle);
natcasesort($themes);
$themes = array_values($themes);
return !empty($themes) ? $themes : array('default');
}
else {
return array('default');
}
}
/**
* Enhances the editor profile settings form for CKEditor.
*
* Adds support for CKEditor's advanced stylesSets, which are a more advanced
* implementation and combination of block formats and font styles that allow
* to adjust the HTML element, attributes, and CSS styles at once.
*
* @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Styles
* @see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html#.stylesSet
*/
function wysiwyg_ckeditor_settings_form(&$form, &$form_state) {
if (version_compare($form_state['wysiwyg']['editor']['installed version'], '3.2.1', '>=')) {
// Replace CSS classes element description to explain the advanced syntax.
$form['css']['css_classes']['#description'] = t('Optionally define CSS classes for the "Font style" dropdown list.<br />Enter one class on each line in the format: !format. Example: !example<br />If left blank, CSS classes are automatically imported from loaded stylesheet(s).', array(
'!format' => '<code>[label]=[element].[class]</code>',
'!example' => '<code>Title=h1.title</code>',
));
$form['css']['css_classes']['#element_validate'][] = 'wysiwyg_ckeditor_settings_form_validate_css_classes';
}
else {
// Versions below 3.2.1 do not support Font styles at all.
$form['css']['css_classes']['#access'] = FALSE;
}
}
/**
* #element_validate handler for CSS classes element altered by wysiwyg_ckeditor_settings_form().
*/
function wysiwyg_ckeditor_settings_form_validate_css_classes($element, &$form_state) {
if (wysiwyg_ckeditor_settings_parse_styles($element['#value']) === FALSE) {
form_error($element, t('The specified CSS classes are syntactically incorrect.'));
}
}
/**
* Returns an initialization JavaScript for this editor library.
*
* @param array $editor
* The editor library definition.
* @param string $library
* The library variant key from $editor['libraries'].
* @param object $profile
* The (first) wysiwyg editor profile.
*
* @return string
* A string containing inline JavaScript to execute before the editor library
* script is loaded.
*/
function wysiwyg_ckeditor_init($editor) {
// CKEditor unconditionally searches for its library filename in SCRIPT tags
// on the page upon loading the library in order to determine the base path to
// itself. When JavaScript aggregation is enabled, this search fails and all
// relative constructed paths within CKEditor are broken. The library has a
// CKEditor.basePath property, but it is not publicly documented and thus not
// reliable. The official documentation suggests to solve the issue through
// the global window variable.
// @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Specifying_the_Editor_Path
$library_path = base_path() . $editor['library path'] . '/';
return <<<EOL
window.CKEDITOR_BASEPATH = '$library_path';
EOL;
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_ckeditor_settings($editor, $config, $theme) {
$settings = array(
'width' => 'auto',
// For better compatibility with smaller textareas.
'resize_minWidth' => 450,
'height' => 420,
// @todo Do not use skins as themes and add separate skin handling.
'theme' => 'default',
'skin' => !empty($theme) ? $theme : 'kama',
// By default, CKEditor converts most characters into HTML entities. Since
// it does not support a custom definition, but Drupal supports Unicode, we
// disable at least the additional character sets. CKEditor always converts
// XML default characters '&', '<', '>'.
// @todo Check whether completely disabling ProcessHTMLEntities is an option.
'entities_latin' => FALSE,
'entities_greek' => FALSE,
);
// Add HTML block format settings; common block formats are already predefined
// by CKEditor.
if (isset($config['block_formats'])) {
$block_formats = explode(',', drupal_strtolower($config['block_formats']));
$predefined_formats = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'pre', 'address', 'div');
foreach (array_diff($block_formats, $predefined_formats) as $tag) {
$tag = trim($tag);
$settings["format_$tag"] = array('element' => $tag);
}
$settings['format_tags'] = implode(';', $block_formats);
}
if (isset($config['apply_source_formatting'])) {
$settings['apply_source_formatting'] = $config['apply_source_formatting'];
}
if (isset($config['css_setting'])) {
// Versions below 3.0.1 could only handle one stylesheet.
if (version_compare($editor['installed version'], '3.0.1.4391', '<')) {
if ($config['css_setting'] == 'theme') {
$settings['contentsCss'] = reset(wysiwyg_get_css());
}
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['contentsCss'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
}
}
else {
if ($config['css_setting'] == 'theme') {
$settings['contentsCss'] = wysiwyg_get_css();
}
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['contentsCss'] = explode(',', strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL)))));
}
}
}
// Parse and define the styles set for the Styles plugin (3.2.1+).
// @todo This should be a plugin setting, but Wysiwyg does not support
// plugin-specific settings yet.
if (!empty($config['buttons']['default']['Styles']) && version_compare($editor['installed version'], '3.2.1', '>=')) {
if ($styles = wysiwyg_ckeditor_settings_parse_styles($config['css_classes'])) {
$settings['stylesSet'] = $styles;
}
}
if (isset($config['language'])) {
$settings['language'] = $config['language'];
}
if (isset($config['resizing'])) {
// CKEditor performs a type-agnostic comparison on this particular setting.
$settings['resize_enabled'] = (bool) $config['resizing'];
}
if (isset($config['toolbar_loc'])) {
$settings['toolbarLocation'] = $config['toolbar_loc'];
}
$settings['toolbar'] = array();
if (!empty($config['buttons'])) {
$extra_plugins = array();
$plugins = wysiwyg_get_plugins($editor['name']);
foreach ($config['buttons'] as $plugin => $buttons) {
foreach ($buttons as $button => $enabled) {
// Iterate separately over buttons and extensions properties.
foreach (array('buttons', 'extensions') as $type) {
// Skip unavailable plugins.
if (!isset($plugins[$plugin][$type][$button])) {
continue;
}
// Add buttons.
if ($type == 'buttons') {
$settings['toolbar'][] = $button;
}
// Add external Drupal plugins to the list of extensions.
if ($type == 'buttons' && !empty($plugins[$plugin]['proxy'])) {
$extra_plugins[] = $button;
}
// Add external plugins to the list of extensions.
elseif ($type == 'buttons' && empty($plugins[$plugin]['internal'])) {
$extra_plugins[] = $plugin;
}
// Add internal buttons that also need to be loaded as extension.
elseif ($type == 'buttons' && !empty($plugins[$plugin]['load'])) {
$extra_plugins[] = $plugin;
}
// Add plain extensions.
elseif ($type == 'extensions' && !empty($plugins[$plugin]['load'])) {
$extra_plugins[] = $plugin;
}
// Allow plugins to add or override global configuration settings.
if (!empty($plugins[$plugin]['options'])) {
$settings = array_merge($settings, $plugins[$plugin]['options']);
}
}
}
}
if (!empty($extra_plugins)) {
$settings['extraPlugins'] = implode(',', $extra_plugins);
}
}
// For now, all buttons are placed into one row.
$settings['toolbar'] = array($settings['toolbar']);
return $settings;
}
/**
* Parses CSS classes settings string into a stylesSet JavaScript settings array.
*
* @param string $css_classes
* A string containing CSS class definitions to add to the Style dropdown
* list, separated by newlines.
*
* @return array|false
* An array containing the parsed stylesSet definition, or FALSE on parse
* error.
*
* @see wysiwyg_ckeditor_settings_form()
* @see wysiwyg_ckeditor_settings_form_validate_css_classes()
*
* @todo This should be a plugin setting, but Wysiwyg does not support
* plugin-specific settings yet.
*/
function wysiwyg_ckeditor_settings_parse_styles($css_classes) {
$set = array();
$input = trim($css_classes);
if (empty($input)) {
return $set;
}
// Handle both Unix and Windows line-endings.
foreach (explode("\n", str_replace("\r", '', $input)) as $line) {
$line = trim($line);
// [label]=[element].[class][.[class]][...] pattern expected.
if (!preg_match('@^.+= *[a-zA-Z0-9]+(\.[a-zA-Z0-9_ -]+)*$@', $line)) {
return FALSE;
}
list($label, $selector) = explode('=', $line, 2);
$classes = explode('.', $selector);
$element = array_shift($classes);
$style = array();
$style['name'] = trim($label);
$style['element'] = trim($element);
if (!empty($classes)) {
$style['attributes']['class'] = implode(' ', array_map('trim', $classes));
}
$set[] = $style;
}
return $set;
}
/**
* Build a JS settings array of native external plugins that need to be loaded separately.
*/
function wysiwyg_ckeditor_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
// Register all plugins that need to be loaded.
if (!empty($plugin['load'])) {
$settings[$name] = array();
// Add path for native external plugins.
if (empty($plugin['internal']) && isset($plugin['path'])) {
$settings[$name]['path'] = base_path() . $plugin['path'] . '/';
}
// Force native internal plugins to use the standard path.
else {
$settings[$name]['path'] = base_path() . $editor['library path'] . '/plugins/' . $name . '/';
}
// CKEditor defaults to 'plugin.js' on its own when filename is not set.
if (!empty($plugin['filename'])) {
$settings[$name]['fileName'] = $plugin['filename'];
}
}
}
return $settings;
}
/**
* Build a JS settings array for Drupal plugins loaded via the proxy plugin.
*/
function wysiwyg_ckeditor_proxy_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
// Populate required plugin settings.
$settings[$name] = $plugin['dialog settings'] + array(
'title' => $plugin['title'],
'icon' => base_path() . $plugin['icon path'] . '/' . $plugin['icon file'],
'iconTitle' => $plugin['icon title'],
// @todo These should only be set if the plugin defined them.
'css' => base_path() . $plugin['css path'] . '/' . $plugin['css file'],
);
}
return $settings;
}
/**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/
function wysiwyg_ckeditor_plugins($editor) {
$plugins = array(
'default' => array(
'buttons' => array(
'Bold' => t('Bold'), 'Italic' => t('Italic'), 'Underline' => t('Underline'),
'Strike' => t('Strike-through'),
'JustifyLeft' => t('Align left'), 'JustifyCenter' => t('Align center'), 'JustifyRight' => t('Align right'), 'JustifyBlock' => t('Justify'),
'BidiLtr' => t('Left-to-right'), 'BidiRtl' => t('Right-to-left'),
'BulletedList' => t('Bullet list'), 'NumberedList' => t('Numbered list'),
'Outdent' => t('Outdent'), 'Indent' => t('Indent'),
'Undo' => t('Undo'), 'Redo' => t('Redo'),
'Link' => t('Link'), 'Unlink' => t('Unlink'), 'Anchor' => t('Anchor'),
'Image' => t('Image'),
'TextColor' => t('Forecolor'), 'BGColor' => t('Backcolor'),
'Superscript' => t('Superscript'), 'Subscript' => t('Subscript'),
'Blockquote' => t('Blockquote'), 'Source' => t('Source code'),
'HorizontalRule' => t('Horizontal rule'),
'Cut' => t('Cut'), 'Copy' => t('Copy'), 'Paste' => t('Paste'),
'PasteText' => t('Paste Text'), 'PasteFromWord' => t('Paste from Word'),
'ShowBlocks' => t('Show blocks'),
'RemoveFormat' => t('Remove format'),
'SpecialChar' => t('Character map'),
'Format' => t('HTML block format'), 'Font' => t('Font'), 'FontSize' => t('Font size'), 'Styles' => t('Font style'),
'Table' => t('Table'),
'SelectAll' => t('Select all'), 'Find' => t('Search'), 'Replace' => t('Replace'),
'Flash' => t('Flash'), 'Smiley' => t('Smiley'),
'CreateDiv' => t('Div container'),
'Iframe' => t('iFrame'),
'Maximize' => t('Maximize'),
'SpellChecker' => t('Check spelling'), 'Scayt' => t('Check spelling as you type'),
'About' => t('About'),
),
'internal' => TRUE,
),
);
if (version_compare($editor['installed version'], '3.1.0.4885', '<')) {
unset($plugins['default']['buttons']['CreateDiv']);
}
if (version_compare($editor['installed version'], '3.4.0.5808', '<')) {
unset($plugins['default']['buttons']['BidiLtr']);
unset($plugins['default']['buttons']['BidiRtl']);
}
if (version_compare($editor['installed version'], '3.5.0.6260', '<')) {
unset($plugins['default']['buttons']['Iframe']);
}
return $plugins;
}
+11
View File
@@ -0,0 +1,11 @@
/**
* openWYSIWYG.
*/
table.tableTextareaEditor, table.tableTextareaEditor table {
margin: 0;
border-collapse: separate;
}
table.tableTextareaEditor td {
padding: 0;
}
+27
View File
@@ -0,0 +1,27 @@
/**
* TinyMCE 2.x
*/
table.mceEditor {
clear: left;
}
/**
* Align all buttons and separators in a single row, so they wrap into multiple
* rows if required.
*/
.mceToolbarTop a, .mceToolbarBottom a {
float: left;
}
.mceSeparatorLine {
float: left;
margin-top: 3px;
}
.mceSelectList {
float: left;
margin-bottom: 1px;
}
/* Place table plugin buttons into new row */
#mce_editor_0_table, #mce_editor_1_table {
clear: left;
}
+26
View File
@@ -0,0 +1,26 @@
/**
* TinyMCE 3.x
*/
table.mceLayout {
clear: left;
}
/**
* Align all buttons and separators in a single row, so they wrap into multiple
* rows if required.
*/
.mceToolbar td {
display: inline;
}
.mceToolbar a,
.mceSeparator {
float: left;
}
.mceListBox,
.mceSplitButton {
float: left;
margin-bottom: 1px;
}
.o2k7Skin .mceToolbar .mceToolbarStart span {float: left;}
.o2k7Skin .mceToolbar .mceToolbarEnd span {float: left;}
+102
View File
@@ -0,0 +1,102 @@
<?php
/**
* @file
* Editor integration functions for EpicEditor.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_epiceditor_editor() {
$editor['epiceditor'] = array(
'title' => 'EpicEditor',
'vendor url' => 'http://oscargodson.github.com/EpicEditor',
'download url' => 'http://oscargodson.github.com/EpicEditor/docs/downloads/EpicEditor-v0.1.1.zip',
'libraries' => array(
'' => array(
'title' => 'Minified',
'files' => array('js/epiceditor.min.js'),
),
'src' => array(
'title' => 'Source',
'files' => array('js/epiceditor.js'),
),
),
'version callback' => 'wysiwyg_epiceditor_version',
'themes callback' => 'wysiwyg_epiceditor_themes',
'settings callback' => 'wysiwyg_epiceditor_settings',
'versions' => array(
'0.1.1' => array(
'js files' => array('epiceditor.js'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_epiceditor_version($editor) {
$library = $editor['library path'] . '/js/epiceditor.js';
if (!file_exists($library)) {
return;
}
// @todo Do not load the entire file; use fgets() instead.
$library = file_get_contents($library, 'r');
$version = preg_match('%EpicEditor\.version = \'(.*)\'\;%', $library, $matches);
if (!isset($matches[1])) {
return;
}
return $matches[1];
}
/**
* Determine available editor themes or check/reset a given one.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $profile
* A wysiwyg editor profile.
*
* @return
* An array of theme names. The first returned name should be the default
* theme name.
*/
function wysiwyg_epiceditor_themes($editor, $profile) {
return array('epic-dark', 'epic-light');
// @todo Use the preview themes somewhere.
//return array('preview-dark', 'github');
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_epiceditor_settings($editor, $config, $theme) {
$settings = array(
'basePath' => base_path() . $editor['library path'],
'clientSideStorage' => FALSE,
'theme' => $theme,
//'preview_theme' => '',
);
return $settings;
}
+292
View File
@@ -0,0 +1,292 @@
<?php
/**
* @file
* Editor integration functions for FCKeditor.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_fckeditor_editor() {
$editor['fckeditor'] = array(
'title' => 'FCKeditor',
'vendor url' => 'http://www.fckeditor.net',
'download url' => 'http://www.fckeditor.net/download',
'libraries' => array(
'' => array(
'title' => 'Default',
'files' => array('fckeditor.js'),
),
),
'version callback' => 'wysiwyg_fckeditor_version',
'themes callback' => 'wysiwyg_fckeditor_themes',
'settings callback' => 'wysiwyg_fckeditor_settings',
'plugin callback' => 'wysiwyg_fckeditor_plugins',
'plugin settings callback' => 'wysiwyg_fckeditor_plugin_settings',
'proxy plugin' => array(
'drupal' => array(
'load' => TRUE,
'proxy' => TRUE,
),
),
'proxy plugin settings callback' => 'wysiwyg_fckeditor_proxy_plugin_settings',
'versions' => array(
'2.6' => array(
'js files' => array('fckeditor-2.6.js'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_fckeditor_version($editor) {
$library = $editor['library path'] . '/fckeditor.js';
if (!file_exists($library)) {
return;
}
$library = fopen($library, 'r');
$max_lines = 100;
while ($max_lines && $line = fgets($library, 60)) {
if (preg_match('@^FCKeditor.prototype.Version\s*= \'([\d\.]+)@', $line, $version)) {
fclose($library);
return $version[1];
}
$max_lines--;
}
fclose($library);
}
/**
* Determine available editor themes or check/reset a given one.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $profile
* A wysiwyg editor profile.
*
* @return
* An array of theme names. The first returned name should be the default
* theme name.
*/
function wysiwyg_fckeditor_themes($editor, $profile) {
return array('default', 'office2003', 'silver');
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_fckeditor_settings($editor, $config, $theme) {
$settings = array(
'EditorPath' => base_path() . $editor['library path'] . '/',
'SkinPath' => base_path() . $editor['library path'] . '/editor/skins/' . $theme . '/',
'CustomConfigurationsPath' => base_path() . drupal_get_path('module', 'wysiwyg') . '/editors/js/fckeditor.config.js',
'Width' => '100%',
'Height' => 420,
'LinkBrowser' => FALSE,
'LinkUpload' => FALSE,
'ImageBrowser' => FALSE,
'ImageUpload' => FALSE,
'FlashBrowser' => FALSE,
'FlashUpload' => FALSE,
// By default, FCKeditor converts most characters into HTML entities. Since
// it does not support a custom definition, but Drupal supports Unicode, we
// disable at least the additional character sets. FCKeditor always converts
// XML default characters '&', '<', '>'.
// @todo Check whether completely disabling ProcessHTMLEntities is an option.
'IncludeLatinEntities' => FALSE,
'IncludeGreekEntities' => FALSE,
);
if (isset($config['block_formats'])) {
$settings['FontFormats'] = strtr($config['block_formats'], array(',' => ';'));
}
if (isset($config['apply_source_formatting'])) {
$settings['FormatOutput'] = $settings['FormatSource'] = $config['apply_source_formatting'];
}
if (isset($config['paste_auto_cleanup_on_paste'])) {
$settings['AutoDetectPasteFromWord'] = $config['paste_auto_cleanup_on_paste'];
}
if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') {
$settings['EditorAreaCSS'] = implode(',', wysiwyg_get_css());
}
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['EditorAreaCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
}
}
// Use our custom toolbar set.
$settings['ToolbarSet'] = 'Wysiwyg';
// Populate our custom toolbar set for fckeditor.config.js.
$settings['buttons'] = array();
if (!empty($config['buttons'])) {
$plugins = wysiwyg_get_plugins($editor['name']);
foreach ($config['buttons'] as $plugin => $buttons) {
foreach ($buttons as $button => $enabled) {
// Iterate separately over buttons and extensions properties.
foreach (array('buttons', 'extensions') as $type) {
// Skip unavailable plugins.
if (!isset($plugins[$plugin][$type][$button])) {
continue;
}
// Add buttons.
if ($type == 'buttons') {
$settings['buttons'][] = $button;
}
// Allow plugins to add or override global configuration settings.
if (!empty($plugins[$plugin]['options'])) {
$settings = array_merge($settings, $plugins[$plugin]['options']);
}
}
}
}
}
// For now, all buttons are placed into one row.
$settings['buttons'] = array($settings['buttons']);
return $settings;
}
/**
* Build a JS settings array of native external plugins that need to be loaded separately.
*/
function wysiwyg_fckeditor_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
// Register all plugins that need to be loaded.
if (!empty($plugin['load'])) {
$settings[$name] = array();
// Add path for native external plugins; internal ones do not need a path.
if (empty($plugin['internal']) && isset($plugin['path'])) {
// All native FCKeditor plugins use the filename fckplugin.js.
$settings[$name]['path'] = base_path() . $plugin['path'] . '/';
}
if (!empty($plugin['languages'])) {
$settings[$name]['languages'] = $plugin['languages'];
}
}
}
return $settings;
}
/**
* Build a JS settings array for Drupal plugins loaded via the proxy plugin.
*/
function wysiwyg_fckeditor_proxy_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
// Populate required plugin settings.
$settings[$name] = $plugin['dialog settings'] + array(
'title' => $plugin['title'],
'icon' => base_path() . $plugin['icon path'] . '/' . $plugin['icon file'],
'iconTitle' => $plugin['icon title'],
// @todo These should only be set if the plugin defined them.
'css' => base_path() . $plugin['css path'] . '/' . $plugin['css file'],
);
}
return $settings;
}
/**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/
function wysiwyg_fckeditor_plugins($editor) {
$plugins = array(
'default' => array(
'buttons' => array(
'Bold' => t('Bold'), 'Italic' => t('Italic'), 'Underline' => t('Underline'),
'StrikeThrough' => t('Strike-through'),
'JustifyLeft' => t('Align left'), 'JustifyCenter' => t('Align center'), 'JustifyRight' => t('Align right'), 'JustifyFull' => t('Justify'),
'UnorderedList' => t('Bullet list'), 'OrderedList' => t('Numbered list'),
'Outdent' => t('Outdent'), 'Indent' => t('Indent'),
'Undo' => t('Undo'), 'Redo' => t('Redo'),
'Link' => t('Link'), 'Unlink' => t('Unlink'), 'Anchor' => t('Anchor'),
'Image' => t('Image'),
'TextColor' => t('Forecolor'), 'BGColor' => t('Backcolor'),
'Superscript' => t('Superscript'), 'Subscript' => t('Subscript'),
'Blockquote' => t('Blockquote'), 'Source' => t('Source code'),
'Rule' => t('Horizontal rule'),
'Cut' => t('Cut'), 'Copy' => t('Copy'), 'Paste' => t('Paste'),
'PasteText' => t('Paste Text'), 'PasteWord' => t('Paste from Word'),
'ShowBlocks' => t('Show blocks'),
'RemoveFormat' => t('Remove format'),
'SpecialChar' => t('Character map'),
'About' => t('About'),
'FontFormat' => t('HTML block format'), 'FontName' => t('Font'), 'FontSize' => t('Font size'), 'Style' => t('Font style'),
'Table' => t('Table'),
'Find' => t('Search'), 'Replace' => t('Replace'), 'SelectAll' => t('Select all'),
'CreateDiv' => t('Create DIV container'),
'Flash' => t('Flash'), 'Smiley' => t('Smiley'),
'FitWindow' => t('FitWindow'),
'SpellCheck' => t('Check spelling'),
),
'internal' => TRUE,
),
'autogrow' => array(
'path' => $editor['library path'] . '/editor/plugins',
'extensions' => array(
'autogrow' => t('Autogrow'),
),
'options' => array(
'AutoGrowMax' => 800,
),
'internal' => TRUE,
'load' => TRUE,
),
'bbcode' => array(
'path' => $editor['library path'] . '/editor/plugins',
'extensions' => array(
'bbcode' => t('BBCode'),
),
'internal' => TRUE,
'load' => TRUE,
),
'dragresizetable' => array(
'path' => $editor['library path'] . '/editor/plugins',
'extensions' => array(
'dragresizetable' => t('Table drag/resize'),
),
'internal' => TRUE,
'load' => TRUE,
),
'tablecommands' => array(
'path' => $editor['library path'] . '/editor/plugins',
'buttons' => array(
'TableCellProp' => t('Table: Cell properties'),
'TableInsertRowAfter' => t('Table: Insert row after'),
'TableInsertColumnAfter' => t('Table: Insert column after'),
'TableInsertCellAfter' => t('Table: Insert cell after'),
'TableDeleteRows' => t('Table: Delete rows'),
'TableDeleteColumns' => t('Table: Delete columns'),
'TableDeleteCells' => t('Table: Delete cells'),
'TableMergeCells' => t('Table: Merge cells'),
'TableHorizontalSplitCell' => t('Table: Horizontal split cell'),
),
'internal' => TRUE,
'load' => TRUE,
),
);
return $plugins;
}
+248
View File
@@ -0,0 +1,248 @@
(function($) {
Drupal.wysiwyg.editor.init.ckeditor = function(settings) {
// Plugins must only be loaded once. Only the settings from the first format
// will be used but they're identical anyway.
var registeredPlugins = {};
for (var format in settings) {
if (Drupal.settings.wysiwyg.plugins[format]) {
// Register native external plugins.
// Array syntax required; 'native' is a predefined token in JavaScript.
for (var pluginName in Drupal.settings.wysiwyg.plugins[format]['native']) {
if (!registeredPlugins[pluginName]) {
var plugin = Drupal.settings.wysiwyg.plugins[format]['native'][pluginName];
CKEDITOR.plugins.addExternal(pluginName, plugin.path, plugin.fileName);
registeredPlugins[pluginName] = true;
}
}
// Register Drupal plugins.
for (var pluginName in Drupal.settings.wysiwyg.plugins[format].drupal) {
if (!registeredPlugins[pluginName]) {
Drupal.wysiwyg.editor.instance.ckeditor.addPlugin(pluginName, Drupal.settings.wysiwyg.plugins[format].drupal[pluginName], Drupal.settings.wysiwyg.plugins.drupal[pluginName]);
registeredPlugins[pluginName] = true;
}
}
}
// Register Font styles (versions 3.2.1 and above).
if (Drupal.settings.wysiwyg.configs.ckeditor[format].stylesSet) {
CKEDITOR.stylesSet.add(format, Drupal.settings.wysiwyg.configs.ckeditor[format].stylesSet);
}
}
};
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.ckeditor = function(context, params, settings) {
// Apply editor instance settings.
CKEDITOR.config.customConfig = '';
var $drupalToolbar = $('#toolbar', Drupal.overlayChild ? window.parent.document : document);
settings.on = {
instanceReady: function(ev) {
var editor = ev.editor;
// Get a list of block, list and table tags from CKEditor's XHTML DTD.
// @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Output_Formatting.
var dtd = CKEDITOR.dtd;
var tags = CKEDITOR.tools.extend({}, dtd.$block, dtd.$listItem, dtd.$tableContent);
// Set source formatting rules for each listed tag except <pre>.
// Linebreaks can be inserted before or after opening and closing tags.
if (settings.apply_source_formatting) {
// Mimic FCKeditor output, by breaking lines between tags.
for (var tag in tags) {
if (tag == 'pre') {
continue;
}
this.dataProcessor.writer.setRules(tag, {
indent: true,
breakBeforeOpen: true,
breakAfterOpen: false,
breakBeforeClose: false,
breakAfterClose: true
});
}
}
else {
// CKEditor adds default formatting to <br>, so we want to remove that
// here too.
tags.br = 1;
// No indents or linebreaks;
for (var tag in tags) {
if (tag == 'pre') {
continue;
}
this.dataProcessor.writer.setRules(tag, {
indent: false,
breakBeforeOpen: false,
breakAfterOpen: false,
breakBeforeClose: false,
breakAfterClose: false
});
}
}
},
pluginsLoaded: function(ev) {
// Override the conversion methods to let Drupal plugins modify the data.
var editor = ev.editor;
if (editor.dataProcessor && Drupal.settings.wysiwyg.plugins[params.format]) {
editor.dataProcessor.toHtml = CKEDITOR.tools.override(editor.dataProcessor.toHtml, function(originalToHtml) {
// Convert raw data for display in WYSIWYG mode.
return function(data, fixForBody) {
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') {
data = Drupal.wysiwyg.plugins[plugin].attach(data, Drupal.settings.wysiwyg.plugins.drupal[plugin], editor.name);
data = Drupal.wysiwyg.instances[params.field].prepareContent(data);
}
}
return originalToHtml.call(this, data, fixForBody);
};
});
editor.dataProcessor.toDataFormat = CKEDITOR.tools.override(editor.dataProcessor.toDataFormat, function(originalToDataFormat) {
// Convert WYSIWYG mode content to raw data.
return function(data, fixForBody) {
data = originalToDataFormat.call(this, data, fixForBody);
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') {
data = Drupal.wysiwyg.plugins[plugin].detach(data, Drupal.settings.wysiwyg.plugins.drupal[plugin], editor.name);
}
}
return data;
};
});
}
},
selectionChange: function (event) {
var pluginSettings = Drupal.settings.wysiwyg.plugins[params.format];
if (pluginSettings && pluginSettings.drupal) {
$.each(pluginSettings.drupal, function (name) {
var plugin = Drupal.wysiwyg.plugins[name];
if ($.isFunction(plugin.isNode)) {
var node = event.data.selection.getSelectedElement();
var state = plugin.isNode(node ? node.$ : null) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
event.editor.getCommand(name).setState(state);
}
});
}
},
focus: function(ev) {
Drupal.wysiwyg.activeId = ev.editor.name;
},
afterCommandExec: function(ev) {
// Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
if (ev.data.name != 'maximize') {
return;
}
if (ev.data.command.state == CKEDITOR.TRISTATE_ON) {
$drupalToolbar.hide();
}
else {
$drupalToolbar.show();
}
}
};
// Attach editor.
CKEDITOR.replace(params.field, settings);
};
/**
* Detach a single or all editors.
*
* @todo 3.x: editor.prototype.getInstances() should always return an array
* containing all instances or the passed in params.field instance, but
* always return an array to simplify all detach functions.
*/
Drupal.wysiwyg.editor.detach.ckeditor = function (context, params, trigger) {
var method = (trigger == 'serialize') ? 'updateElement' : 'destroy';
if (typeof params != 'undefined') {
var instance = CKEDITOR.instances[params.field];
if (instance) {
instance[method]();
}
}
else {
for (var instanceName in CKEDITOR.instances) {
if (CKEDITOR.instances.hasOwnProperty(instanceName)) {
CKEDITOR.instances[instanceName][method]();
}
}
}
};
Drupal.wysiwyg.editor.instance.ckeditor = {
addPlugin: function(pluginName, settings, pluginSettings) {
CKEDITOR.plugins.add(pluginName, {
// Wrap Drupal plugin in a proxy pluygin.
init: function(editor) {
if (settings.css) {
editor.on('mode', function(ev) {
if (ev.editor.mode == 'wysiwyg') {
// Inject CSS files directly into the editing area head tag.
$('head', $('#cke_contents_' + ev.editor.name + ' iframe').eq(0).contents()).append('<link rel="stylesheet" href="' + settings.css + '" type="text/css" >');
}
});
}
if (typeof Drupal.wysiwyg.plugins[pluginName].invoke == 'function') {
var pluginCommand = {
exec: function (editor) {
var data = { format: 'html', node: null, content: '' };
var selection = editor.getSelection();
if (selection) {
data.node = selection.getSelectedElement();
if (data.node) {
data.node = data.node.$;
}
if (selection.getType() == CKEDITOR.SELECTION_TEXT) {
if (CKEDITOR.env.ie) {
data.content = selection.getNative().createRange().text;
}
else {
data.content = selection.getNative().toString();
}
}
else if (data.node) {
// content is supposed to contain the "outerHTML".
data.content = data.node.parentNode.innerHTML;
}
}
Drupal.wysiwyg.plugins[pluginName].invoke(data, pluginSettings, editor.name);
}
};
editor.addCommand(pluginName, pluginCommand);
}
editor.ui.addButton(pluginName, {
label: settings.iconTitle,
command: pluginName,
icon: settings.icon
});
// @todo Add button state handling.
}
});
},
prepareContent: function(content) {
// @todo Don't know if we need this yet.
return content;
},
insert: function(content) {
content = this.prepareContent(content);
CKEDITOR.instances[this.field].insertHtml(content);
},
setContent: function (content) {
CKEDITOR.instances[this.field].setData(content);
},
getContent: function () {
return CKEDITOR.instances[this.field].getData();
}
};
})(jQuery);
+38
View File
@@ -0,0 +1,38 @@
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.epiceditor = function (context, params, settings) {
var $target = $('#' + params.field);
var containerId = params.field + '-epiceditor';
var defaultContent = $target.val();
$target.hide().after('<div id="' + containerId + '" />');
settings.container = containerId;
settings.file = {
defaultContent: defaultContent
};
settings.theme = {
preview: '/themes/preview/preview-dark.css',
editor: '/themes/editor/' + settings.theme + '.css'
}
var editor = new EpicEditor(settings).load();
$target.data('epiceditor', editor);
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.epiceditor = function (context, params, trigger) {
var $target = $('#' + params.field);
var editor = $target.data('epiceditor');
$target.val(editor.exportFile());
editor.unload(function () {
$target.show();
});
};
})(jQuery);
+196
View File
@@ -0,0 +1,196 @@
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.fckeditor = function(context, params, settings) {
var FCKinstance = new FCKeditor(params.field, settings.Width, settings.Height, settings.ToolbarSet);
// Apply editor instance settings.
FCKinstance.BasePath = settings.EditorPath;
FCKinstance.Config.wysiwygFormat = params.format;
FCKinstance.Config.CustomConfigurationsPath = settings.CustomConfigurationsPath;
// Load Drupal plugins and apply format specific settings.
// @see fckeditor.config.js
// @see Drupal.wysiwyg.editor.instance.fckeditor.init()
// Attach editor.
FCKinstance.ReplaceTextarea();
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.fckeditor = function (context, params, trigger) {
var instances = [];
if (typeof params != 'undefined' && typeof FCKeditorAPI != 'undefined') {
var instance = FCKeditorAPI.GetInstance(params.field);
if (instance) {
instances[params.field] = instance;
}
}
else {
instances = FCKeditorAPI.__Instances;
}
for (var instanceName in instances) {
var instance = instances[instanceName];
instance.UpdateLinkedField();
if (trigger == 'serialize') {
// The editor is not being removed from the DOM, so updating the linked
// field is the only action necessary.
continue;
}
// Since we already detach the editor and update the textarea, the submit
// event handler needs to be removed to prevent data loss (in IE).
// FCKeditor uses 2 nested iFrames; instance.EditingArea.Window is the
// deepest. Its parent is the iFrame containing the editor.
var instanceScope = instance.EditingArea.Window.parent;
instanceScope.FCKTools.RemoveEventListener(instance.GetParentForm(), 'submit', instance.UpdateLinkedField);
// Run cleanups before forcing an unload of the iFrames or IE crashes.
// This also deletes the instance from the FCKeditorAPI.__Instances array.
instanceScope.FCKTools.RemoveEventListener(instanceScope, 'unload', instanceScope.FCKeditorAPI_Cleanup);
instanceScope.FCKTools.RemoveEventListener(instanceScope, 'beforeunload', instanceScope.FCKeditorAPI_ConfirmCleanup);
if (jQuery.isFunction(instanceScope.FCKIECleanup_Cleanup)) {
instanceScope.FCKIECleanup_Cleanup();
}
instanceScope.FCKeditorAPI_ConfirmCleanup();
instanceScope.FCKeditorAPI_Cleanup();
// Remove the editor elements.
$('#' + instanceName + '___Config').remove();
$('#' + instanceName + '___Frame').remove();
$('#' + instanceName).show();
}
};
Drupal.wysiwyg.editor.instance.fckeditor = {
init: function(instance) {
// Track which editor instance is active.
instance.FCK.Events.AttachEvent('OnFocus', function(editorInstance) {
Drupal.wysiwyg.activeId = editorInstance.Name;
});
// Create a custom data processor to wrap the default one and allow Drupal
// plugins modify the editor contents.
var wysiwygDataProcessor = function() {};
wysiwygDataProcessor.prototype = new instance.FCKDataProcessor();
// Attach: Convert text into HTML.
wysiwygDataProcessor.prototype.ConvertToHtml = function(data) {
// Called from SetData() with stripped comments/scripts, revert those
// manipulations and attach Drupal plugins.
var data = instance.FCKConfig.ProtectedSource.Revert(data);
if (Drupal.settings.wysiwyg.plugins[instance.wysiwygFormat] && Drupal.settings.wysiwyg.plugins[instance.wysiwygFormat].drupal) {
for (var plugin in Drupal.settings.wysiwyg.plugins[instance.wysiwygFormat].drupal) {
if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') {
data = Drupal.wysiwyg.plugins[plugin].attach(data, Drupal.settings.wysiwyg.plugins.drupal[plugin], instance.FCK.Name);
data = Drupal.wysiwyg.editor.instance.fckeditor.prepareContent(data);
}
}
}
// Re-protect the source and use the original data processor to convert it
// into XHTML.
data = instance.FCKConfig.ProtectedSource.Protect(data);
return instance.FCKDataProcessor.prototype.ConvertToHtml.call(this, data);
};
// Detach: Convert HTML into text.
wysiwygDataProcessor.prototype.ConvertToDataFormat = function(rootNode, excludeRoot, ignoreIfEmptyParagraph, format) {
// Called from GetData(), convert the content's DOM into a XHTML string
// using the original data processor and detach Drupal plugins.
var data = instance.FCKDataProcessor.prototype.ConvertToDataFormat.call(this, rootNode, excludeRoot, ignoreIfEmptyParagraph, format);
if (Drupal.settings.wysiwyg.plugins[instance.wysiwygFormat] && Drupal.settings.wysiwyg.plugins[instance.wysiwygFormat].drupal) {
for (var plugin in Drupal.settings.wysiwyg.plugins[instance.wysiwygFormat].drupal) {
if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') {
data = Drupal.wysiwyg.plugins[plugin].detach(data, Drupal.settings.wysiwyg.plugins.drupal[plugin], instance.FCK.Name);
}
}
}
return data;
};
instance.FCK.DataProcessor = new wysiwygDataProcessor();
},
addPlugin: function(plugin, settings, pluginSettings, instance) {
if (typeof Drupal.wysiwyg.plugins[plugin] != 'object') {
return;
}
if (Drupal.settings.wysiwyg.plugins[instance.wysiwygFormat].drupal[plugin].css) {
instance.FCKConfig.EditorAreaCSS += ',' + Drupal.settings.wysiwyg.plugins[instance.wysiwygFormat].drupal[plugin].css;
}
// @see fckcommands.js, fck_othercommands.js, fckpastewordcommand.js
instance.FCKCommands.RegisterCommand(plugin, {
// Invoke the plugin's button.
Execute: function () {
if (typeof Drupal.wysiwyg.plugins[plugin].invoke == 'function') {
var data = { format: 'html', node: instance.FCKSelection.GetParentElement() };
// @todo This is NOT the same as data.node.
data.content = data.node.innerHTML;
Drupal.wysiwyg.plugins[plugin].invoke(data, pluginSettings, instance.FCK.Name);
}
},
// isNode: Return whether the plugin button should be enabled for the
// current selection.
// @see FCKUnlinkCommand.prototype.GetState()
GetState: function () {
// Always disabled if not in WYSIWYG mode.
if (instance.FCK.EditMode != FCK_EDITMODE_WYSIWYG) {
return FCK_TRISTATE_DISABLED;
}
var state = instance.FCK.GetNamedCommandState(this.Name);
// FCKeditor sets the wrong state in WebKit browsers.
if (!$.support.queryCommandEnabled && state == FCK_TRISTATE_DISABLED) {
state = FCK_TRISTATE_OFF;
}
if (state == FCK_TRISTATE_OFF && instance.FCK.EditMode == FCK_EDITMODE_WYSIWYG) {
if (typeof Drupal.wysiwyg.plugins[plugin].isNode == 'function') {
var node = instance.FCKSelection.GetSelectedElement();
state = Drupal.wysiwyg.plugins[plugin].isNode(node) ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF;
}
}
return state;
},
/**
* Return information about the plugin as a name/value array.
*/
Name: plugin
});
// Register the plugin button.
// Arguments: commandName, label, tooltip, style, sourceView, contextSensitive, icon.
instance.FCKToolbarItems.RegisterItem(plugin, new instance.FCKToolbarButton(plugin, settings.iconTitle, settings.iconTitle, null, false, true, settings.icon));
},
openDialog: function(dialog, params) {
// @todo Implement open dialog.
},
closeDialog: function(dialog) {
// @todo Implement close dialog.
},
prepareContent: function(content) {
// @todo Not needed for FCKeditor?
return content;
},
insert: function(content) {
var instance = FCKeditorAPI.GetInstance(this.field);
// @see FCK.InsertHtml(), FCK.InsertElement()
instance.InsertHtml(content);
},
getContent: function () {
var instance = FCKeditorAPI.GetInstance(this.field);
return instance.GetData();
},
setContent: function (content) {
var instance = FCKeditorAPI.GetInstance(this.field);
instance.SetHTML(content);
}
};
})(jQuery);
+86
View File
@@ -0,0 +1,86 @@
Drupal = window.parent.Drupal;
/**
* Fetch and provide original editor settings as local variable.
*
* FCKeditor does not support to pass complex variable types to the editor.
* Instance settings passed to FCKinstance.Config are temporarily stored in
* FCKConfig.PageConfig.
*/
var wysiwygFormat = FCKConfig.PageConfig.wysiwygFormat;
var wysiwygSettings = Drupal.settings.wysiwyg.configs.fckeditor[wysiwygFormat];
var pluginSettings = (Drupal.settings.wysiwyg.plugins[wysiwygFormat] ? Drupal.settings.wysiwyg.plugins[wysiwygFormat] : { 'native': {}, 'drupal': {} });
/**
* Apply format-specific settings.
*/
for (var setting in wysiwygSettings) {
if (setting == 'buttons') {
// Apply custom Wysiwyg toolbar for this format.
// FCKConfig.ToolbarSets['Wysiwyg'] = wysiwygSettings.buttons;
// Temporarily stack buttons into multiple button groups and remove
// separators until #277954 is solved.
FCKConfig.ToolbarSets['Wysiwyg'] = [];
for (var i = 0; i < wysiwygSettings.buttons[0].length; i++) {
FCKConfig.ToolbarSets['Wysiwyg'].push([wysiwygSettings.buttons[0][i]]);
}
FCKTools.AppendStyleSheet(document, '#xToolbar .TB_Start { display:none; }');
// Set valid height of select element in silver and office2003 skins.
if (FCKConfig.SkinPath.match(/\/office2003\/$/)) {
FCKTools.AppendStyleSheet(document, '#xToolbar .SC_FieldCaption { height: 24px; } #xToolbar .TB_End { display: none; }');
}
else if (FCKConfig.SkinPath.match(/\/silver\/$/)) {
FCKTools.AppendStyleSheet(document, '#xToolbar .SC_FieldCaption { height: 27px; }');
}
}
else {
FCKConfig[setting] = wysiwygSettings[setting];
}
}
// Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
var oldFitWindowExecute = FCKFitWindow.prototype.Execute;
var $drupalToolbar = window.parent.jQuery('#toolbar', Drupal.overlayChild ? window.parent.window.parent.document : window.parent.document);
FCKFitWindow.prototype.Execute = function() {
oldFitWindowExecute.apply(this, arguments);
if (this.IsMaximized) {
$drupalToolbar.hide();
}
else {
$drupalToolbar.show();
}
}
/**
* Initialize this editor instance.
*/
Drupal.wysiwyg.editor.instance.fckeditor.init(window);
/**
* Register native plugins for this input format.
*
* Parameters to Plugins.Add are:
* - Plugin name.
* - Languages the plugin is available in.
* - Location of the plugin folder; <plugin_name>/fckplugin.js is appended.
*/
for (var plugin in pluginSettings['native']) {
// Languages and path may be undefined for internal plugins.
FCKConfig.Plugins.Add(plugin, pluginSettings['native'][plugin].languages, pluginSettings['native'][plugin].path);
}
/**
* Register Drupal plugins for this input format.
*
* Parameters to addPlugin() are:
* - Plugin name.
* - Format specific plugin settings.
* - General plugin settings.
* - A reference to this window so the plugin setup can access FCKConfig.
*/
for (var plugin in pluginSettings.drupal) {
Drupal.wysiwyg.editor.instance.fckeditor.addPlugin(plugin, pluginSettings.drupal[plugin], Drupal.settings.wysiwyg.plugins.drupal[plugin], window);
}
+43
View File
@@ -0,0 +1,43 @@
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.jwysiwyg = function(context, params, settings) {
// Attach editor.
$('#' + params.field).wysiwyg();
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.jwysiwyg = function (context, params, trigger) {
var $field = $('#' + params.field);
var editor = $field.data('wysiwyg');
if (typeof editor != 'undefined') {
editor.saveContent();
if (trigger != 'serialize') {
editor.element.remove();
}
}
$field.removeData('wysiwyg');
if (trigger != 'serialize') {
$field.show();
}
};
Drupal.wysiwyg.editor.instance.jwysiwyg = {
insert: function (content) {
$('#' + this.field).wysiwyg('insertHtml', content);
},
setContent: function (content) {
$('#' + this.field).wysiwyg('setContent', content);
},
getContent: function () {
return $('#' + this.field).wysiwyg('getContent');
}
};
})(jQuery);
+46
View File
@@ -0,0 +1,46 @@
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.markitup = function(context, params, settings) {
$('#' + params.field, context).markItUp(settings);
// Adjust CSS for editor buttons.
$.each(settings.markupSet, function (button) {
$('.' + settings.nameSpace + ' .' + this.className + ' a')
.css({ backgroundImage: 'url(' + settings.root + 'sets/default/images/' + button + '.png' + ')' })
.parents('li').css({ backgroundImage: 'none' });
});
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.markitup = function (context, params, trigger) {
if (trigger == 'serialize') {
return;
}
if (typeof params != 'undefined') {
$('#' + params.field, context).markItUpRemove();
}
else {
$('.markItUpEditor', context).markItUpRemove();
}
};
Drupal.wysiwyg.editor.instance.markitup = {
insert: function (content) {
$.markItUp({ replaceWith: content });
},
setContent: function (content) {
$('#' + this.field).val(content);
},
getContent: function () {
return $('#' + this.field).val();
}
};
})(jQuery);
+115
View File
@@ -0,0 +1,115 @@
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.nicedit = function(context, params, settings) {
// Intercept and ignore submit handlers or they will revert changes made
// since the instance was removed. The handlers are anonymous and hidden out
// of scope in a closure so we can't unbind them. The same operations are
// performed when the instance is detached anyway.
var oldAddEvent = bkLib.addEvent;
bkLib.addEvent = function(obj, type, fn) {
if (type != 'submit') {
oldAddEvent(obj, type, fn);
}
}
// Attach editor.
var editor = new nicEditor(settings);
editor.panelInstance(params.field);
// The old addEvent() must be restored after creating a new instance, as
// plugins with dialogs use it to bind submit handlers to their forms.
bkLib.addEvent = oldAddEvent;
editor.addEvent('focus', function () {
Drupal.wysiwyg.activeId = params.field;
});
};
/**
* Detach a single or all editors.
*
* See Drupal.wysiwyg.editor.detach.none() for a full description of this hook.
*/
Drupal.wysiwyg.editor.detach.nicedit = function (context, params, trigger) {
if (typeof params != 'undefined') {
var instance = nicEditors.findEditor(params.field);
if (instance) {
if (trigger == 'serialize') {
instance.saveContent();
}
else {
instance.ne.removeInstance(params.field);
instance.ne.removePanel();
}
}
}
else {
for (var e in nicEditors.editors) {
// Save contents of all editors back into textareas.
var instances = nicEditors.editors[e].nicInstances;
for (var i = 0; i < instances.length; i++) {
if (trigger == 'serialize') {
instances[i].saveContent();
}
else {
instances[i].remove();
}
}
// Remove all editor instances.
if (trigger != 'serialize') {
nicEditors.editors[e].nicInstances = [];
}
}
}
};
/**
* Instance methods for nicEdit.
*/
Drupal.wysiwyg.editor.instance.nicedit = {
insert: function (content) {
var instance = nicEditors.findEditor(this.field);
var editingArea = instance.getElm();
var sel = instance.getSel();
// IE.
if (document.selection) {
editingArea.focus();
sel.createRange().pasteHTML(content);
}
else {
// Convert selection to a range.
var range;
// W3C compatible.
if (sel.getRangeAt) {
range = sel.getRangeAt(0);
}
// Safari.
else {
range = editingArea.ownerDocument.createRange();
range.setStart(sel.anchorNode, sel.anchorOffset);
range.setEnd(sel.focusNode, userSeletion.focusOffset);
}
// The code below doesn't work in IE, but it never gets here.
var fragment = editingArea.ownerDocument.createDocumentFragment();
// Fragments don't support innerHTML.
var wrapper = editingArea.ownerDocument.createElement('div');
wrapper.innerHTML = content;
while (wrapper.firstChild) {
fragment.appendChild(wrapper.firstChild);
}
range.deleteContents();
// Only fragment children are inserted.
range.insertNode(fragment);
}
},
setContent: function (content) {
nicEditors.findEditor(this.field).setContent(content);
},
getContent: function () {
return nicEditors.findEditor(this.field).getContent();
}
};
})(jQuery);
+91
View File
@@ -0,0 +1,91 @@
(function($) {
/**
* Attach this editor to a target element.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param params
* An object containing input format parameters. Default parameters are:
* - editor: The internal editor name.
* - theme: The name/key of the editor theme/profile to use.
* - field: The CSS id of the target element.
* @param settings
* An object containing editor settings for all enabled editor themes.
*/
Drupal.wysiwyg.editor.attach.none = function(context, params, settings) {
if (params.resizable) {
var $wrapper = $('#' + params.field).parents('.form-textarea-wrapper:first');
$wrapper.addClass('resizable');
if (Drupal.behaviors.textarea) {
Drupal.behaviors.textarea.attach();
}
}
};
/**
* Detach a single or all editors.
*
* The editor syncs its contents back to the original field before its instance
* is removed.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param params
* (optional) An object containing input format parameters. If defined,
* only the editor instance in params.field should be detached. Otherwise,
* all editors should be detached and saved, so they can be submitted in
* AJAX/AHAH applications.
* @param trigger
* A string describing why the editor is being detached.
* Possible triggers are:
* - unload: (default) Another or no editor is about to take its place.
* - move: Currently expected to produce the same result as unload.
* - serialize: The form is about to be serialized before an AJAX request or
* a normal form submission. If possible, perform a quick detach and leave
* the editor's GUI elements in place to avoid flashes or scrolling issues.
* @see Drupal.detachBehaviors
*/
Drupal.wysiwyg.editor.detach.none = function (context, params, trigger) {
if (typeof params != 'undefined' && (trigger != 'serialize')) {
var $wrapper = $('#' + params.field).parents('.form-textarea-wrapper:first');
$wrapper.removeOnce('textarea').removeClass('.resizable-textarea')
.find('.grippie').remove();
}
};
/**
* Instance methods for plain text areas.
*/
Drupal.wysiwyg.editor.instance.none = {
insert: function(content) {
var editor = document.getElementById(this.field);
// IE support.
if (document.selection) {
editor.focus();
var sel = document.selection.createRange();
sel.text = content;
}
// Mozilla/Firefox/Netscape 7+ support.
else if (editor.selectionStart || editor.selectionStart == '0') {
var startPos = editor.selectionStart;
var endPos = editor.selectionEnd;
editor.value = editor.value.substring(0, startPos) + content + editor.value.substring(endPos, editor.value.length);
}
// Fallback, just add to the end of the content.
else {
editor.value += content;
}
},
setContent: function (content) {
$('#' + this.field).val(content);
},
getContent: function () {
return $('#' + this.field).val();
}
};
})(jQuery);
+141
View File
@@ -0,0 +1,141 @@
// Backup $ and reset it to jQuery.
Drupal.wysiwyg._openwysiwyg = $;
$ = jQuery;
// Wrap openWYSIWYG's methods to temporarily use its version of $.
jQuery.each(WYSIWYG, function (key, value) {
if (jQuery.isFunction(value)) {
WYSIWYG[key] = function () {
var old$ = $;
$ = Drupal.wysiwyg._openwysiwyg;
var result = value.apply(this, arguments);
$ = old$;
return result;
};
}
});
// Override editor functions.
WYSIWYG.getEditor = function (n) {
return Drupal.wysiwyg._openwysiwyg("wysiwyg" + n);
};
(function($) {
// Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
var oldMaximize = WYSIWYG.maximize;
WYSIWYG.maximize = function (n) {
var $drupalToolbar = $('#toolbar', Drupal.overlayChild ? window.parent.document : document);
oldMaximize.apply(this, arguments);
if (this.maximized[n]) {
$drupalToolbar.hide();
}
else {
$drupalToolbar.show();
}
}
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.openwysiwyg = function(context, params, settings) {
// Initialize settings.
settings.ImagesDir = settings.path + 'images/';
settings.PopupsDir = settings.path + 'popups/';
settings.CSSFile = settings.path + 'styles/wysiwyg.css';
//settings.DropDowns = [];
var config = new WYSIWYG.Settings();
for (var setting in settings) {
config[setting] = settings[setting];
}
// Attach editor.
WYSIWYG.setSettings(params.field, config);
WYSIWYG_Core.includeCSS(WYSIWYG.config[params.field].CSSFile);
WYSIWYG._generate(params.field, config);
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.openwysiwyg = function (context, params, trigger) {
if (typeof params != 'undefined') {
var instance = WYSIWYG.config[params.field];
if (typeof instance != 'undefined') {
WYSIWYG.updateTextArea(params.field);
if (trigger != 'serialize') {
jQuery('#wysiwyg_div_' + params.field).remove();
delete instance;
}
}
if (trigger != 'serialize') {
jQuery('#' + params.field).show();
}
}
else {
jQuery.each(WYSIWYG.config, function(field) {
WYSIWYG.updateTextArea(field);
if (trigger != 'serialize') {
jQuery('#wysiwyg_div_' + field).remove();
delete this;
jQuery('#' + field).show();
}
});
}
};
/**
* Instance methods for openWYSIWYG.
*/
Drupal.wysiwyg.editor.instance.openwysiwyg = {
insert: function (content) {
// If IE has dropped focus content will be inserted at the top of the page.
$('#wysiwyg' + this.field).contents().find('body').focus();
WYSIWYG.insertHTML(content, this.field);
},
setContent: function (content) {
// Based on openWYSIWYG's _generate() method.
var doc = WYSIWYG.getEditorWindow(this.field).document;
if (WYSIWYG.config[this.field].ReplaceLineBreaks) {
content = content.replace(/\n\r|\n/ig, '<br />');
}
if (WYSIWYG.viewTextMode[this.field]) {
var html = document.createTextNode(content);
doc.body.innerHTML = '';
doc.body.appendChild(html);
}
else {
doc.open();
doc.write(content);
doc.close();
}
},
getContent: function () {
// Based on openWYSIWYG's updateTextarea() method.
var content = '';
var doc = WYSIWYG.getEditorWindow(this.field).document;
if (WYSIWYG.viewTextMode[this.field]) {
if (WYSIWYG_Core.isMSIE) {
content = doc.body.innerText;
}
else {
var range = doc.body.ownerDocument.createRange();
range.selectNodeContents(doc.body);
content = range.toString();
}
}
else {
content = doc.body.innerHTML;
}
content = WYSIWYG.stripURLPath(this.field, content);
content = WYSIWYG_Core.replaceRGBWithHexColor(content);
if (WYSIWYG.config[this.field].ReplaceLineBreaks) {
content = content.replace(/(\r\n)|(\n)/ig, '');
}
return content;
}
};
})(jQuery);
+203
View File
@@ -0,0 +1,203 @@
(function($) {
/**
* Initialize editor instances.
*
* This function needs to be called before the page is fully loaded, as
* calling tinyMCE.init() after the page is loaded breaks IE6.
*
* @param editorSettings
* An object containing editor settings for each input format.
*/
Drupal.wysiwyg.editor.init.tinymce = function(settings) {
// Initialize editor configurations.
for (var format in settings) {
tinyMCE.init(settings[format]);
if (Drupal.settings.wysiwyg.plugins[format]) {
// Load native external plugins.
// Array syntax required; 'native' is a predefined token in JavaScript.
for (var plugin in Drupal.settings.wysiwyg.plugins[format]['native']) {
tinyMCE.loadPlugin(plugin, Drupal.settings.wysiwyg.plugins[format]['native'][plugin]);
}
// Load Drupal plugins.
for (var plugin in Drupal.settings.wysiwyg.plugins[format].drupal) {
Drupal.wysiwyg.editor.instance.tinymce.addPlugin(plugin, Drupal.settings.wysiwyg.plugins[format].drupal[plugin], Drupal.settings.wysiwyg.plugins.drupal[plugin]);
}
}
}
};
/**
* Attach this editor to a target element.
*
* See Drupal.wysiwyg.editor.attach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) {
// Configure editor settings for this input format.
for (var setting in settings) {
tinyMCE.settings[setting] = settings[setting];
}
// Remove TinyMCE's internal mceItem class, which was incorrectly added to
// submitted content by Wysiwyg <2.1. TinyMCE only temporarily adds the class
// for placeholder elements. If preemptively set, the class prevents (native)
// editor plugins from gaining an active state, so we have to manually remove
// it prior to attaching the editor. This is done on the client-side instead
// of the server-side, as Wysiwyg has no way to figure out where content is
// stored, and the class only affects editing.
$field = $('#' + params.field);
$field.val($field.val().replace(/(<.+?\s+class=['"][\w\s]*?)\bmceItem\b([\w\s]*?['"].*?>)/ig, '$1$2'));
// Attach editor.
tinyMCE.execCommand('mceAddControl', true, params.field);
};
/**
* Detach a single or all editors.
*
* See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.editor.detach.tinymce = function (context, params, trigger) {
if (typeof params != 'undefined') {
tinyMCE.removeMCEControl(tinyMCE.getEditorId(params.field));
$('#' + params.field).removeAttr('style');
}
// else if (tinyMCE.activeEditor) {
// tinyMCE.triggerSave();
// tinyMCE.activeEditor.remove();
// }
};
Drupal.wysiwyg.editor.instance.tinymce = {
addPlugin: function(plugin, settings, pluginSettings) {
if (typeof Drupal.wysiwyg.plugins[plugin] != 'object') {
return;
}
tinyMCE.addPlugin(plugin, {
// Register an editor command for this plugin, invoked by the plugin's button.
execCommand: function(editor_id, element, command, user_interface, value) {
switch (command) {
case plugin:
if (typeof Drupal.wysiwyg.plugins[plugin].invoke == 'function') {
var ed = tinyMCE.getInstanceById(editor_id);
var data = { format: 'html', node: ed.getFocusElement(), content: ed.getFocusElement() };
Drupal.wysiwyg.plugins[plugin].invoke(data, pluginSettings, ed.formTargetElementId);
return true;
}
}
// Pass to next handler in chain.
return false;
},
// Register the plugin button.
getControlHTML: function(control_name) {
switch (control_name) {
case plugin:
return tinyMCE.getButtonHTML(control_name, settings.iconTitle, settings.icon, plugin);
}
return '';
},
// Load custom CSS for editor contents on startup.
initInstance: function(ed) {
if (settings.css) {
tinyMCE.importCSS(ed.getDoc(), settings.css);
}
},
cleanup: function(type, content) {
switch (type) {
case 'insert_to_editor':
// Attach: Replace plain text with HTML representations.
if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') {
content = Drupal.wysiwyg.plugins[plugin].attach(content, pluginSettings, tinyMCE.selectedInstance.editorId);
content = Drupal.wysiwyg.editor.instance.tinymce.prepareContent(content);
}
break;
case 'get_from_editor':
// Detach: Replace HTML representations with plain text.
if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') {
content = Drupal.wysiwyg.plugins[plugin].detach(content, pluginSettings, tinyMCE.selectedInstance.editorId);
}
break;
}
// Pass through to next handler in chain
return content;
},
// isNode: Return whether the plugin button should be enabled for the
// current selection.
handleNodeChange: function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
if (node === null) {
return;
}
if (typeof Drupal.wysiwyg.plugins[plugin].isNode == 'function') {
if (Drupal.wysiwyg.plugins[plugin].isNode(node)) {
tinyMCE.switchClass(editor_id + '_' + plugin, 'mceButtonSelected');
return true;
}
}
tinyMCE.switchClass(editor_id + '_' + plugin, 'mceButtonNormal');
return true;
},
/**
* Return information about the plugin as a name/value array.
*/
getInfo: function() {
return {
longname: settings.title
};
}
});
},
openDialog: function(dialog, params) {
var editor = tinyMCE.getInstanceById(this.field);
tinyMCE.openWindow({
file: dialog.url + '/' + this.field,
width: dialog.width,
height: dialog.height,
inline: 1
}, params);
},
closeDialog: function(dialog) {
var editor = tinyMCE.getInstanceById(this.field);
tinyMCEPopup.close();
},
prepareContent: function(content) {
// Certain content elements need to have additional DOM properties applied
// to prevent this editor from highlighting an internal button in addition
// to the button of a Drupal plugin.
var specialProperties = {
img: { 'name': 'mce_drupal' }
};
var $content = $('<div>' + content + '</div>'); // No .outerHTML() in jQuery :(
jQuery.each(specialProperties, function(element, properties) {
$content.find(element).each(function() {
for (var property in properties) {
if (property == 'class') {
$(this).addClass(properties[property]);
}
else {
$(this).attr(property, properties[property]);
}
}
});
});
return $content.html();
},
insert: function(content) {
content = this.prepareContent(content);
var editor = tinyMCE.getInstanceById(this.field);
editor.execCommand('mceInsertContent', false, content);
editor.repaint();
}
};
})(jQuery);
+256
View File
@@ -0,0 +1,256 @@
(function($) {
/**
* Initialize editor instances.
*
* @todo Is the following note still valid for 3.x?
* This function needs to be called before the page is fully loaded, as
* calling tinyMCE.init() after the page is loaded breaks IE6.
*
* @param editorSettings
* An object containing editor settings for each input format.
*/
Drupal.wysiwyg.editor.init.tinymce = function(settings) {
// Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
var $drupalToolbar = $('#toolbar', Drupal.overlayChild ? window.parent.document : document);
tinyMCE.onAddEditor.add(function (mgr, ed) {
if (ed.id == 'mce_fullscreen') {
$drupalToolbar.hide();
}
});
tinyMCE.onRemoveEditor.add(function (mgr, ed) {
if (ed.id == 'mce_fullscreen') {
$drupalToolbar.show();
}
});
// Initialize editor configurations.
for (var format in settings) {
if (Drupal.settings.wysiwyg.plugins[format]) {
// Load native external plugins.
// Array syntax required; 'native' is a predefined token in JavaScript.
for (var plugin in Drupal.settings.wysiwyg.plugins[format]['native']) {
tinymce.PluginManager.load(plugin, Drupal.settings.wysiwyg.plugins[format]['native'][plugin]);
}
// Load Drupal plugins.
for (var plugin in Drupal.settings.wysiwyg.plugins[format].drupal) {
Drupal.wysiwyg.editor.instance.tinymce.addPlugin(plugin, Drupal.settings.wysiwyg.plugins[format].drupal[plugin], Drupal.settings.wysiwyg.plugins.drupal[plugin]);
}
}
}
};
/**
* Attach this editor to a target element.
*
* See Drupal.wysiwyg.editor.attach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) {
// Configure editor settings for this input format.
var ed = new tinymce.Editor(params.field, settings);
// Reset active instance id on any event.
ed.onEvent.add(function(ed, e) {
Drupal.wysiwyg.activeId = ed.id;
});
// Indicate that the DOM has been loaded (in case of Ajax).
tinymce.dom.Event.domLoaded = true;
// Make toolbar buttons wrappable (required for IE).
ed.onPostRender.add(function (ed) {
var $toolbar = $('<div class="wysiwygToolbar"></div>');
$('#' + ed.editorContainer + ' table.mceToolbar > tbody > tr > td').each(function () {
$('<div></div>').addClass(this.className).append($(this).children()).appendTo($toolbar);
});
$('#' + ed.editorContainer + ' table.mceLayout td.mceToolbar').append($toolbar);
$('#' + ed.editorContainer + ' table.mceToolbar').remove();
});
// Remove TinyMCE's internal mceItem class, which was incorrectly added to
// submitted content by Wysiwyg <2.1. TinyMCE only temporarily adds the class
// for placeholder elements. If preemptively set, the class prevents (native)
// editor plugins from gaining an active state, so we have to manually remove
// it prior to attaching the editor. This is done on the client-side instead
// of the server-side, as Wysiwyg has no way to figure out where content is
// stored, and the class only affects editing.
$field = $('#' + params.field);
$field.val($field.val().replace(/(<.+?\s+class=['"][\w\s]*?)\bmceItem\b([\w\s]*?['"].*?>)/ig, '$1$2'));
// Attach editor.
ed.render();
};
/**
* Detach a single or all editors.
*
* See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.editor.detach.tinymce = function (context, params, trigger) {
if (typeof params != 'undefined') {
var instance = tinyMCE.get(params.field);
if (instance) {
instance.save();
if (trigger != 'serialize') {
instance.remove();
}
}
}
else {
// Save contents of all editors back into textareas.
tinyMCE.triggerSave();
if (trigger != 'serialize') {
// Remove all editor instances.
for (var instance in tinyMCE.editors) {
tinyMCE.editors[instance].remove();
}
}
}
};
Drupal.wysiwyg.editor.instance.tinymce = {
addPlugin: function(plugin, settings, pluginSettings) {
if (typeof Drupal.wysiwyg.plugins[plugin] != 'object') {
return;
}
tinymce.create('tinymce.plugins.' + plugin, {
/**
* Initialize the plugin, executed after the plugin has been created.
*
* @param ed
* The tinymce.Editor instance the plugin is initialized in.
* @param url
* The absolute URL of the plugin location.
*/
init: function(ed, url) {
// Register an editor command for this plugin, invoked by the plugin's button.
ed.addCommand(plugin, function() {
if (typeof Drupal.wysiwyg.plugins[plugin].invoke == 'function') {
var data = { format: 'html', node: ed.selection.getNode(), content: ed.selection.getContent() };
// TinyMCE creates a completely new instance for fullscreen mode.
var instanceId = ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id;
Drupal.wysiwyg.plugins[plugin].invoke(data, pluginSettings, instanceId);
}
});
// Register the plugin button.
ed.addButton(plugin, {
title : settings.iconTitle,
cmd : plugin,
image : settings.icon
});
// Load custom CSS for editor contents on startup.
ed.onInit.add(function() {
if (settings.css) {
ed.dom.loadCSS(settings.css);
}
});
// Attach: Replace plain text with HTML representations.
ed.onBeforeSetContent.add(function(ed, data) {
var editorId = (ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id);
if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') {
data.content = Drupal.wysiwyg.plugins[plugin].attach(data.content, pluginSettings, editorId);
data.content = Drupal.wysiwyg.editor.instance.tinymce.prepareContent(data.content);
}
});
// Detach: Replace HTML representations with plain text.
ed.onGetContent.add(function(ed, data) {
var editorId = (ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id);
if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') {
data.content = Drupal.wysiwyg.plugins[plugin].detach(data.content, pluginSettings, editorId);
}
});
// isNode: Return whether the plugin button should be enabled for the
// current selection.
ed.onNodeChange.add(function(ed, command, node) {
if (typeof Drupal.wysiwyg.plugins[plugin].isNode == 'function') {
command.setActive(plugin, Drupal.wysiwyg.plugins[plugin].isNode(node));
}
});
},
/**
* Return information about the plugin as a name/value array.
*/
getInfo: function() {
return {
longname: settings.title
};
}
});
// Register plugin.
tinymce.PluginManager.add(plugin, tinymce.plugins[plugin]);
},
openDialog: function(dialog, params) {
var instanceId = this.getInstanceId();
var editor = tinyMCE.get(instanceId);
editor.windowManager.open({
file: dialog.url + '/' + instanceId,
width: dialog.width,
height: dialog.height,
inline: 1
}, params);
},
closeDialog: function(dialog) {
var editor = tinyMCE.get(this.getInstanceId());
editor.windowManager.close(dialog);
},
prepareContent: function(content) {
// Certain content elements need to have additional DOM properties applied
// to prevent this editor from highlighting an internal button in addition
// to the button of a Drupal plugin.
var specialProperties = {
img: { 'class': 'mceItem' }
};
var $content = $('<div>' + content + '</div>'); // No .outerHTML() in jQuery :(
// Find all placeholder/replacement content of Drupal plugins.
$content.find('.drupal-content').each(function() {
// Recursively process DOM elements below this element to apply special
// properties.
var $drupalContent = $(this);
$.each(specialProperties, function(element, properties) {
$drupalContent.find(element).andSelf().each(function() {
for (var property in properties) {
if (property == 'class') {
$(this).addClass(properties[property]);
}
else {
$(this).attr(property, properties[property]);
}
}
});
});
});
return $content.html();
},
insert: function(content) {
content = this.prepareContent(content);
tinyMCE.execInstanceCommand(this.getInstanceId(), 'mceInsertContent', false, content);
},
setContent: function (content) {
content = this.prepareContent(content);
tinyMCE.execInstanceCommand(this.getInstanceId(), 'mceSetContent', false, content);
},
getContent: function () {
return tinyMCE.get(this.getInstanceId()).getContent();
},
isFullscreen: function() {
// TinyMCE creates a completely new instance for fullscreen mode.
return tinyMCE.activeEditor.id == 'mce_fullscreen' && tinyMCE.activeEditor.getParam('fullscreen_editor_id') == this.field;
},
getInstanceId: function () {
return this.isFullscreen() ? 'mce_fullscreen' : this.field;
}
};
})(jQuery);
+155
View File
@@ -0,0 +1,155 @@
var wysiwygWhizzywig = { currentField: null, fields: {} };
var buttonPath = null;
/**
* Override Whizzywig's document.write() function.
*
* Whizzywig uses document.write() by default, which leads to a blank page when
* invoked in jQuery.ready(). Luckily, Whizzywig developers implemented a
* shorthand w() substitute function that we can override to redirect the output
* into the global wysiwygWhizzywig variable.
*
* @see o()
*/
var w = function (string) {
if (string) {
wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField] += string;
}
return wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField];
};
/**
* Override Whizzywig's document.getElementById() function.
*
* Since we redirect the output of w() into a temporary string upon attaching
* an editor, we also have to override the o() shorthand substitute function
* for document.getElementById() to search in the document or our container.
* This override function also inserts the editor instance when Whizzywig
* tries to access its IFRAME, so it has access to the full/regular window
* object.
*
* @see w()
*/
var o = function (id) {
// Upon first access to "whizzy" + id, Whizzywig tries to access its IFRAME,
// so we need to insert the editor into the DOM.
if (id == 'whizzy' + wysiwygWhizzywig.currentField && wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField]) {
jQuery('#' + wysiwygWhizzywig.currentField).after('<div id="' + wysiwygWhizzywig.currentField + '-whizzywig"></div>');
// Iframe's .contentWindow becomes null in Webkit if inserted via .after().
jQuery('#' + wysiwygWhizzywig.currentField + '-whizzywig').html(w());
// Prevent subsequent invocations from inserting the editor multiple times.
wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField] = '';
}
// If id exists in the regular window.document, return it.
if (jQuery('#' + id).size()) {
return jQuery('#' + id).get(0);
}
// Otherwise return id from our container.
return jQuery('#' + id, w()).get(0);
};
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.whizzywig = function(context, params, settings) {
// Previous versions used per-button images found in this location,
// now it is only used for custom buttons.
if (settings.buttonPath) {
window.buttonPath = settings.buttonPath;
}
// Assign the toolbar image path used for native buttons, if available.
if (settings.toolbarImagePath) {
btn._f = settings.toolbarImagePath;
}
// Fall back to text labels for all buttons.
else {
window.buttonPath = 'textbuttons';
}
// Create Whizzywig container.
wysiwygWhizzywig.currentField = params.field;
wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField] = '';
// Whizzywig needs to have the width set 'inline'.
$field = $('#' + params.field);
var originalValues = Drupal.wysiwyg.instances[params.field];
originalValues.originalStyle = $field.attr('style');
$field.css('width', $field.width() + 'px');
// Attach editor.
makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all'));
// Whizzywig fails to detect and set initial textarea contents.
$('#whizzy' + params.field).contents().find('body').html(tidyD($field.val()));
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.whizzywig = function (context, params, trigger) {
var detach = function (index) {
var id = whizzies[index], $field = $('#' + id), instance = Drupal.wysiwyg.instances[id];
// Save contents of editor back into textarea.
$field.val(instance.getContent());
// If the editor is just being serialized (not detached), our work is done.
if (trigger == 'serialize') {
return;
}
// Remove editor instance.
$('#' + id + '-whizzywig').remove();
whizzies.splice(index, 1);
// Restore original textarea styling.
$field.removeAttr('style').attr('style', instance.originalStyle);
};
if (typeof params != 'undefined') {
for (var i = 0; i < whizzies.length; i++) {
if (whizzies[i] == params.field) {
detach(i);
break;
}
}
}
else {
while (whizzies.length > 0) {
detach(0);
}
}
};
/**
* Instance methods for Whizzywig.
*/
Drupal.wysiwyg.editor.instance.whizzywig = {
insert: function (content) {
// Whizzywig executes any string beginning with 'js:'.
insHTML(content.replace(/^js:/, 'js&colon;'));
},
setContent: function (content) {
// Whizzywig shows the original textarea in source mode.
if ($field.css('display') == 'block') {
$('#' + this.field).val(content);
}
else {
var doc = $('#whizzy' + this.field).contents()[0];
doc.open();
doc.write(content);
doc.close();
}
},
getContent: function () {
// Whizzywig's tidyH() expects a document node. Clone the editing iframe's
// document so tidyH() won't mess with it if this gets called while editing.
var clone = $($('#whizzy' + this.field).contents()[0].documentElement).clone()[0].ownerDocument;
// Whizzywig shows the original textarea in source mode so update the body.
if ($field.css('display') == 'block') {
clone.body.innerHTML = $('#' + this.field).val();
}
return tidyH(clone);
}
};
})(jQuery);
+107
View File
@@ -0,0 +1,107 @@
var buttonPath = null;
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.whizzywig = function(context, params, settings) {
// Previous versions used per-button images found in this location,
// now it is only used for custom buttons.
if (settings.buttonPath) {
window.buttonPath = settings.buttonPath;
}
// Assign the toolbar image path used for native buttons, if available.
if (settings.toolbarImagePath) {
btn._f = settings.toolbarImagePath;
}
// Fall back to text labels for all buttons.
else {
window.buttonPath = 'textbuttons';
}
// Whizzywig needs to have the width set 'inline'.
$field = $('#' + params.field);
var originalValues = Drupal.wysiwyg.instances[params.field];
originalValues.originalStyle = $field.attr('style');
$field.css('width', $field.width() + 'px');
// Attach editor.
makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all'));
// Whizzywig fails to detect and set initial textarea contents.
$('#whizzy' + params.field).contents().find('body').html(tidyD($field.val()));
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.whizzywig = function (context, params, trigger) {
var detach = function (index) {
var id = whizzies[index], $field = $('#' + id), instance = Drupal.wysiwyg.instances[id];
// Save contents of editor back into textarea.
$field.val(instance.getContent());
// If the editor is just being serialized (not detached), our work is done.
if (trigger == 'serialize') {
return;
}
// Move original textarea back to its previous location.
var $container = $('#CONTAINER' + id);
$field.insertBefore($container);
// Remove editor instance.
$container.remove();
whizzies.splice(index, 1);
// Restore original textarea styling.
$field.removeAttr('style').attr('style', instance.originalStyle);
}
if (typeof params != 'undefined') {
for (var i = 0; i < whizzies.length; i++) {
if (whizzies[i] == params.field) {
detach(i);
break;
}
}
}
else {
while (whizzies.length > 0) {
detach(0);
}
}
};
/**
* Instance methods for Whizzywig.
*/
Drupal.wysiwyg.editor.instance.whizzywig = {
insert: function (content) {
// Whizzywig executes any string beginning with 'js:'.
insHTML(content.replace(/^js:/, 'js&colon;'));
},
setContent: function (content) {
// Whizzywig shows the original textarea in source mode.
if ($field.css('display') == 'block') {
$('#' + this.field).val(content);
}
else {
var doc = $('#whizzy' + this.field).contents()[0];
doc.open();
doc.write(content);
doc.close();
}
},
getContent: function () {
// Whizzywig's tidyH() expects a document node. Clone the editing iframe's
// document so tidyH() won't mess with it if this gets called while editing.
var clone = $($('#whizzy' + this.field).contents()[0].documentElement).clone()[0].ownerDocument;
// Whizzywig shows the original textarea in source mode so update the body.
if ($field.css('display') == 'block') {
clone.body.innerHTML = $('#' + this.field).val();
}
return tidyH(clone);
}
};
})(jQuery);
+154
View File
@@ -0,0 +1,154 @@
var wysiwygWhizzywig = { currentField: null, fields: {} };
var buttonPath = null;
/**
* Override Whizzywig's document.write() function.
*
* Whizzywig uses document.write() by default, which leads to a blank page when
* invoked in jQuery.ready(). Luckily, Whizzywig developers implemented a
* shorthand w() substitute function that we can override to redirect the output
* into the global wysiwygWhizzywig variable.
*
* @see o()
*/
var w = function (string) {
if (string) {
wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField] += string;
}
return wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField];
};
/**
* Override Whizzywig's document.getElementById() function.
*
* Since we redirect the output of w() into a temporary string upon attaching
* an editor, we also have to override the o() shorthand substitute function
* for document.getElementById() to search in the document or our container.
* This override function also inserts the editor instance when Whizzywig
* tries to access its IFRAME, so it has access to the full/regular window
* object.
*
* @see w()
*/
var o = function (id) {
// Upon first access to "whizzy" + id, Whizzywig tries to access its IFRAME,
// so we need to insert the editor into the DOM.
if (id == 'whizzy' + wysiwygWhizzywig.currentField && wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField]) {
jQuery('#' + wysiwygWhizzywig.currentField).after('<div id="' + wysiwygWhizzywig.currentField + '-whizzywig"></div>');
// Iframe's .contentWindow becomes null in Webkit if inserted via .after().
jQuery('#' + wysiwygWhizzywig.currentField + '-whizzywig').html(w());
// Prevent subsequent invocations from inserting the editor multiple times.
wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField] = '';
}
// If id exists in the regular window.document, return it.
if (jQuery('#' + id).size()) {
return jQuery('#' + id).get(0);
}
// Otherwise return id from our container.
return jQuery('#' + id, w()).get(0);
};
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.whizzywig = function(context, params, settings) {
// Assign button images path, if available.
if (settings.buttonPath) {
window.buttonPath = settings.buttonPath;
}
// Create Whizzywig container.
wysiwygWhizzywig.currentField = params.field;
wysiwygWhizzywig.fields[wysiwygWhizzywig.currentField] = '';
// Whizzywig needs to have the width set 'inline'.
$field = $('#' + params.field);
var originalValues = Drupal.wysiwyg.instances[params.field];
originalValues.originalStyle = $field.attr('style');
$field.css('width', $field.width() + 'px');
// Attach editor.
makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all'));
// Whizzywig fails to detect and set initial textarea contents.
$('#whizzy' + params.field).contents().find('body').html(tidyD($field.val()));
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.whizzywig = function (context, params, trigger) {
var detach = function (index) {
var id = whizzies[index], $field = $('#' + id), instance = Drupal.wysiwyg.instances[id];
// Save contents of editor back into textarea.
$field.val(instance.getContent());
// If the editor is just being serialized (not detached), our work is done.
if (trigger == 'serialize') {
return;
}
// Remove editor instance.
$('#' + id + '-whizzywig').remove();
whizzies.splice(index, 1);
// Restore original textarea styling.
$field.removeAttr('style').attr('style', instance.originalStyle);
};
if (typeof params != 'undefined') {
for (var i = 0; i < whizzies.length; i++) {
if (whizzies[i] == params.field) {
detach(i);
break;
}
}
}
else {
while (whizzies.length > 0) {
detach(0);
}
}
};
/**
* Instance methods for Whizzywig.
*/
Drupal.wysiwyg.editor.instance.whizzywig = {
insert: function (content) {
// Whizzywig executes any string beginning with 'js:'.
insHTML(content.replace(/^js:/, 'js&colon;'));
},
setContent: function (content) {
var $field = $('#' + this.field);
// Whizzywig shows the original textarea in source mode.
if ($field.css('display') == 'block') {
$field.val(content);
}
else {
var doc = $('#whizzy' + this.field).contents()[0];
doc.open();
doc.write(content);
doc.close();
}
},
getContent: function () {
var $field = $('#' + this.field),
// Whizzywig shows the original textarea in source mode.
content = ($field.css('display') == 'block' ?
$field.val() : $('#whizzy' + this.field).contents().find('body').html()
);
content = tidyH(content);
// Whizzywig's get_xhtml() addon, if defined, expects a DOM node.
if ($.isFunction(window.get_xhtml)) {
var pre = document.createElement('pre');
pre.innerHTML = content;
content = get_xhtml(pre);
}
return content.replace(location.href + '#', '#');
}
};
})(jQuery);
+74
View File
@@ -0,0 +1,74 @@
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.wymeditor = function (context, params, settings) {
// Prepend basePath to wymPath.
settings.wymPath = settings.basePath + settings.wymPath;
// Update activeId on focus.
settings.postInit = function (instance) {
$(instance._doc).focus(function () {
Drupal.wysiwyg.activeId = params.field;
});
};
// Attach editor.
$('#' + params.field).wymeditor(settings);
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.wymeditor = function (context, params, trigger) {
if (typeof params != 'undefined') {
var $field = $('#' + params.field);
var index = $field.data(WYMeditor.WYM_INDEX);
if (typeof index != 'undefined') {
var instance = WYMeditor.INSTANCES[index];
instance.update();
if (trigger != 'serialize') {
$(instance._box).remove();
$(instance._element).show();
delete instance;
}
}
if (trigger != 'serialize') {
$field.show();
}
}
else {
jQuery.each(WYMeditor.INSTANCES, function () {
this.update();
if (trigger != 'serialize') {
$(this._box).remove();
$(this._element).show();
delete this;
}
});
}
};
Drupal.wysiwyg.editor.instance.wymeditor = {
insert: function (content) {
this.getInstance().insert(content);
},
setContent: function (content) {
this.getInstance().html(content);
},
getContent: function () {
return this.getInstance().xhtml();
},
getInstance: function () {
var $field = $('#' + this.field);
var index = $field.data(WYMeditor.WYM_INDEX);
if (typeof index != 'undefined') {
return WYMeditor.INSTANCES[index];
}
return null;
}
};
})(jQuery);
+145
View File
@@ -0,0 +1,145 @@
(function($) {
/**
* Attach this editor to a target element.
*
* Since buttons must be added before the editor is rendered, we add plugins
* buttons on attach event rather than in init.
*/
Drupal.wysiwyg.editor.attach.yui = function(context, params, settings) {
// Apply theme.
$('#' + params.field).parent().addClass('yui-skin-' + settings.theme);
// Load plugins stylesheet.
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
settings.extracss += settings.extracss+' @import "'+Drupal.settings.wysiwyg.plugins[params.format].drupal[plugin].css+'"; ';
}
// Attach editor.
var editor = new YAHOO.widget.Editor(params.field, settings);
editor.on('toolbarLoaded', function() {
// Load Drupal plugins.
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
Drupal.wysiwyg.instances[params.field].addPlugin(plugin, Drupal.settings.wysiwyg.plugins[params.format].drupal[plugin], Drupal.settings.wysiwyg.plugins.drupal[plugin]);
}
});
// Allow plugins to act on setEditorHTML.
var oldSetEditorHTML = editor.setEditorHTML;
editor.setEditorHTML = function (content) {
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
var pluginSettings = Drupal.settings.wysiwyg.plugins.drupal[plugin];
if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') {
content = Drupal.wysiwyg.plugins[plugin].attach(content, pluginSettings, params.field);
content = Drupal.wysiwyg.instances[params.field].prepareContent(content);
}
}
oldSetEditorHTML.call(this, content);
};
// Allow plugins to act on getEditorHTML.
var oldGetEditorHTML = editor.getEditorHTML;
editor.getEditorHTML = function () {
var content = oldGetEditorHTML.call(this);
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
var pluginSettings = Drupal.settings.wysiwyg.plugins.drupal[plugin];
if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') {
content = Drupal.wysiwyg.plugins[plugin].detach(content, pluginSettings, params.field);
}
}
return content;
}
// Reload the editor contents to give Drupal plugins a chance to act.
editor.on('editorContentLoaded', function (e) {
e.target.setEditorHTML(oldGetEditorHTML.call(e.target));
});
editor.on('afterNodeChange', function (e) {
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
if (typeof Drupal.wysiwyg.plugins[plugin].isNode == 'function') {
if (Drupal.wysiwyg.plugins[plugin].isNode(e.target._getSelectedElement())) {
this.toolbar.selectButton(plugin);
}
}
}
});
editor.render();
};
/**
* Detach a single or all editors.
*
* See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.editor.detach.yui = function (context, params, trigger) {
var method = (trigger && trigger == 'serialize') ? 'saveHTML' : 'destroy';
if (typeof params != 'undefined') {
var instance = YAHOO.widget.EditorInfo._instances[params.field];
if (instance) {
instance[method]();
if (method == 'destroy') {
delete YAHOO.widget.EditorInfo._instances[params.field];
}
}
}
else {
for (var e in YAHOO.widget.EditorInfo._instances) {
// Save contents of all editors back into textareas.
var instance = YAHOO.widget.EditorInfo._instances[e];
instance[method]();
if (method == 'destroy') {
delete YAHOO.widget.EditorInfo._instances[e];
}
}
}
};
/**
* Instance methods for YUI Editor.
*/
Drupal.wysiwyg.editor.instance.yui = {
addPlugin: function (plugin, settings, pluginSettings) {
if (typeof Drupal.wysiwyg.plugins[plugin] != 'object') {
return;
}
var editor = YAHOO.widget.EditorInfo.getEditorById(this.field);
var button = editor.toolbar.getButtonByValue(plugin);
$(button._button).parent().css('background', 'transparent url(' + settings.icon + ') no-repeat center');
// 'this' will reference the toolbar while inside the event handler.
var instanceId = this.field;
editor.toolbar.on(plugin + 'Click', function (e) {
var selectedElement = editor._getSelectedElement();
// @todo Using .html() will cause XTHML vs HTML conflicts.
var data = {
format: 'html',
node: selectedElement,
content: $(selectedElement).html()
};
Drupal.wysiwyg.plugins[plugin].invoke(data, pluginSettings, instanceId);
});
},
prepareContent: function (content) {
var editor = YAHOO.widget.EditorInfo.getEditorById(this.field);
content = editor.cleanHTML(content);
return content;
},
insert: function (content) {
YAHOO.widget.EditorInfo.getEditorById(this.field).cmd_inserthtml(content);
},
setContent: function (content) {
YAHOO.widget.EditorInfo.getEditorById(this.field).setEditorHTML(content);
},
getContent: function () {
var instance = YAHOO.widget.EditorInfo.getEditorById(this.field);
return instance.cleanHTML(instance.getEditorHTML(content));
}
};
})(jQuery);
+62
View File
@@ -0,0 +1,62 @@
<?php
/**
* @file
* Editor integration functions for jWYSIWYG.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_jwysiwyg_editor() {
$editor['jwysiwyg'] = array(
'title' => 'jWYSIWYG',
'vendor url' => 'http://code.google.com/p/jwysiwyg/',
'download url' => 'http://code.google.com/p/jwysiwyg/downloads/list',
'libraries' => array(
'' => array(
'title' => 'Source',
'files' => array('jquery.wysiwyg.js'),
),
'pack' => array(
'title' => 'Packed',
'files' => array('jquery.wysiwyg.pack.js'),
),
),
'version callback' => 'wysiwyg_jwysiwyg_version',
// @todo Wrong property; add separate properties for editor requisites.
'css path' => wysiwyg_get_path('jwysiwyg'),
'versions' => array(
'0.5' => array(
'js files' => array('jwysiwyg.js'),
'css files' => array('jquery.wysiwyg.css'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_jwysiwyg_version($editor) {
$script = $editor['library path'] . '/jquery.wysiwyg.js';
if (!file_exists($script)) {
return;
}
$script = fopen($script, 'r');
fgets($script);
$line = fgets($script);
if (preg_match('@([0-9\.]+)$@', $line, $version)) {
fclose($script);
return $version[1];
}
fclose($script);
}
+189
View File
@@ -0,0 +1,189 @@
<?php
/**
* @file
* Editor integration functions for markItUp.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_markitup_editor() {
$editor['markitup'] = array(
'title' => 'markItUp',
'vendor url' => 'http://markitup.jaysalvat.com',
'download url' => 'http://markitup.jaysalvat.com/downloads',
'library path' => wysiwyg_get_path('markitup'),
'libraries' => array(
'' => array(
'title' => 'Source',
'files' => array('markitup/jquery.markitup.js'),
),
'pack' => array(
'title' => 'Packed',
'files' => array('markitup/jquery.markitup.pack.js'),
),
),
'version callback' => 'wysiwyg_markitup_version',
'themes callback' => 'wysiwyg_markitup_themes',
'settings callback' => 'wysiwyg_markitup_settings',
'plugin callback' => 'wysiwyg_markitup_plugins',
'versions' => array(
'1.1.5' => array(
'js files' => array('markitup.js'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_markitup_version($editor) {
// Changelog was in markitup/markitup/readme.txt <= 1.1.5.
$changelog = $editor['library path'] . '/markitup/readme.txt';
if (!file_exists($changelog)) {
// Changelog was moved up to markitup/CHANGELOG.md after 1.1.5.
$changelog = $editor['library path'] . '/CHANGELOG.md';
if (!file_exists($changelog)) {
return;
}
}
$changelog = fopen($changelog, 'r');
$line = fgets($changelog);
if (preg_match('@([0-9\.]+)@', $line, $version)) {
fclose($changelog);
return $version[1];
}
fclose($changelog);
}
/**
* Determine available editor themes or check/reset a given one.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $profile
* A wysiwyg editor profile.
*
* @return
* An array of theme names. The first returned name should be the default
* theme name.
*/
function wysiwyg_markitup_themes($editor, $profile) {
return array('simple', 'markitup');
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_markitup_settings($editor, $config, $theme) {
drupal_add_css($editor['library path'] . '/markitup/skins/' . $theme . '/style.css', array(
// Specify an alternate basename; otherwise, style.css would override a
// commonly used style.css file of the theme.
'basename' => 'markitup.' . $theme . '.style.css',
'group' => CSS_THEME,
));
$settings = array(
'root' => base_path() . $editor['library path'] . '/markitup/',
'nameSpace' => $theme,
'markupSet' => array(),
);
// Add configured buttons or all available.
$default_buttons = array(
'bold' => array(
'name' => t('Bold'),
'className' => 'markitup-bold',
'key' => 'B',
'openWith' => '(!(<strong>|!|<b>)!)',
'closeWith' => '(!(</strong>|!|</b>)!)',
),
'italic' => array(
'name' => t('Italic'),
'className' => 'markitup-italic',
'key' => 'I',
'openWith' => '(!(<em>|!|<i>)!)',
'closeWith' => '(!(</em>|!|</i>)!)',
),
'stroke' => array(
'name' => t('Strike-through'),
'className' => 'markitup-stroke',
'key' => 'S',
'openWith' => '<del>',
'closeWith' => '</del>',
),
'image' => array(
'name' => t('Image'),
'className' => 'markitup-image',
'key' => 'P',
'replaceWith' => '<img src="[![Source:!:http://]!]" alt="[![Alternative text]!]" />',
),
'link' => array(
'name' => t('Link'),
'className' => 'markitup-link',
'key' => 'K',
'openWith' => '<a href="[![Link:!:http://]!]"(!( title="[![Title]!]")!)>',
'closeWith' => '</a>',
'placeHolder' => 'Your text to link...',
),
// @todo
// 'cleanup' => array('name' => t('Clean-up'), 'className' => 'markitup-cleanup', 'replaceWith' => 'function(markitup) { return markitup.selection.replace(/<(.*?)>/g, "") }'),
'preview' => array(
'name' => t('Preview'),
'className' => 'markitup-preview',
'call' => 'preview',
),
);
$settings['markupSet'] = array();
if (!empty($config['buttons'])) {
foreach ($config['buttons'] as $plugin) {
foreach ($plugin as $button => $enabled) {
if (isset($default_buttons[$button])) {
$settings['markupSet'][$button] = $default_buttons[$button];
}
}
}
}
return $settings;
}
/**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/
function wysiwyg_markitup_plugins($editor) {
return array(
'default' => array(
'buttons' => array(
'bold' => t('Bold'), 'italic' => t('Italic'),
'stroke' => t('Strike-through'),
'link' => t('Link'),
'image' => t('Image'),
// 'cleanup' => t('Clean-up'),
'preview' => t('Preview'),
),
'internal' => TRUE,
),
);
}
+119
View File
@@ -0,0 +1,119 @@
<?php
/**
* @file
* Editor integration functions for NicEdit.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_nicedit_editor() {
$editor['nicedit'] = array(
'title' => 'NicEdit',
'vendor url' => 'http://nicedit.com',
'download url' => 'http://nicedit.com/download.php',
'libraries' => array(
'' => array(
'title' => 'Source',
'files' => array('nicEdit.js'),
),
),
'version callback' => 'wysiwyg_nicedit_version',
'settings callback' => 'wysiwyg_nicedit_settings',
'plugin callback' => 'wysiwyg_nicedit_plugins',
'versions' => array(
'0.9' => array(
'js files' => array('nicedit.js'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_nicedit_version($editor) {
// @see http://nicedit.com/forums/viewtopic.php?t=425
return '0.9';
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_nicedit_settings($editor, $config, $theme) {
$settings = array(
'iconsPath' => base_path() . $editor['library path'] . '/nicEditorIcons.gif',
);
// Add configured buttons or all available.
$settings['buttonList'] = array();
if (!empty($config['buttons'])) {
$buttons = array();
foreach ($config['buttons'] as $plugin) {
$buttons = array_merge($buttons, $plugin);
}
$settings['buttonList'] = array_keys($buttons);
}
// Add editor content stylesheet.
if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') {
$css = drupal_get_path('theme', variable_get('theme_default', NULL)) . '/style.css';
if (file_exists($css)) {
$settings['externalCSS'] = base_path() . $css;
}
}
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['externalCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
}
}
return $settings;
}
/**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/
function wysiwyg_nicedit_plugins($editor) {
return array(
'default' => array(
'buttons' => array(
'bold' => t('Bold'), 'italic' => t('Italic'), 'underline' => t('Underline'),
'strikethrough' => t('Strike-through'),
'left' => t('Align left'), 'center' => t('Align center'), 'right' => t('Align right'),
'ul' => t('Bullet list'), 'ol' => t('Numbered list'),
'outdent' => t('Outdent'), 'indent' => t('Indent'),
'image' => t('Image'),
'forecolor' => t('Forecolor'), 'bgcolor' => t('Backcolor'),
'superscript' => t('Superscript'), 'subscript' => t('Subscript'),
'hr' => t('Horizontal rule'),
// @todo New challenge: Optional internal plugins packaged into editor
// library.
'link' => t('Link'), 'unlink' => t('Unlink'),
'fontFormat' => t('HTML block format'), 'fontFamily' => t('Font'), 'fontSize' => t('Font size'),
'xhtml' => t('Source code'),
),
'internal' => TRUE,
),
);
}
+173
View File
@@ -0,0 +1,173 @@
<?php
/**
* @file
* Editor integration functions for openWYSIWYG.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_openwysiwyg_editor() {
$editor['openwysiwyg'] = array(
'title' => 'openWYSIWYG',
'vendor url' => 'http://www.openwebware.com',
'download url' => 'http://www.openwebware.com/download.shtml',
'library path' => wysiwyg_get_path('openwysiwyg') . '/scripts',
'libraries' => array(
'src' => array(
'title' => 'Source',
'files' => array('wysiwyg.js'),
),
),
'version callback' => 'wysiwyg_openwysiwyg_version',
'themes callback' => 'wysiwyg_openwysiwyg_themes',
'settings callback' => 'wysiwyg_openwysiwyg_settings',
'plugin callback' => 'wysiwyg_openwysiwyg_plugins',
'versions' => array(
'1.4.7' => array(
'js files' => array('openwysiwyg.js'),
'css files' => array('openwysiwyg.css'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_openwysiwyg_version($editor) {
// 'library path' has '/scripts' appended already.
$changelog = $editor['editor path'] . '/changelog';
if (!file_exists($changelog)) {
return;
}
$changelog = fopen($changelog, 'r');
$line = fgets($changelog, 20);
if (preg_match('@v([\d\.]+)@', $line, $version)) {
fclose($changelog);
return $version[1];
}
fclose($changelog);
}
/**
* Determine available editor themes or check/reset a given one.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $profile
* A wysiwyg editor profile.
*
* @return
* An array of theme names. The first returned name should be the default
* theme name.
*/
function wysiwyg_openwysiwyg_themes($editor, $profile) {
return array('default');
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_openwysiwyg_settings($editor, $config, $theme) {
$settings = array(
'path' => base_path() . $editor['editor path'] . '/',
'Width' => '100%',
);
if (isset($config['path_loc']) && $config['path_loc'] == 'none') {
$settings['StatusBarEnabled'] = FALSE;
}
if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') {
$settings['CSSFile'] = reset(wysiwyg_get_css());
}
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['CSSFile'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
}
}
$settings['Toolbar'] = array();
if (!empty($config['buttons'])) {
$plugins = wysiwyg_get_plugins($editor['name']);
foreach ($config['buttons'] as $plugin => $buttons) {
foreach ($buttons as $button => $enabled) {
foreach (array('buttons', 'extensions') as $type) {
// Skip unavailable plugins.
if (!isset($plugins[$plugin][$type][$button])) {
continue;
}
// Add buttons.
if ($type == 'buttons') {
$settings['Toolbar'][0][] = $button;
}
}
}
}
}
// @todo
// if (isset($config['block_formats'])) {
// $settings['DropDowns']['headings']['elements'] = explode(',', $config['block_formats']);
// }
return $settings;
}
/**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/
function wysiwyg_openwysiwyg_plugins($editor) {
$plugins = array(
'default' => array(
'buttons' => array(
'bold' => t('Bold'), 'italic' => t('Italic'), 'underline' => t('Underline'),
'strikethrough' => t('Strike-through'),
'justifyleft' => t('Align left'), 'justifycenter' => t('Align center'), 'justifyright' => t('Align right'), 'justifyfull' => t('Justify'),
'unorderedlist' => t('Bullet list'), 'orderedlist' => t('Numbered list'),
'outdent' => t('Outdent'), 'indent' => t('Indent'),
'undo' => t('Undo'), 'redo' => t('Redo'),
'createlink' => t('Link'),
'insertimage' => t('Image'),
'cleanup' => t('Clean-up'),
'forecolor' => t('Forecolor'), 'backcolor' => t('Backcolor'),
'superscript' => t('Sup'), 'subscript' => t('Sub'),
'blockquote' => t('Blockquote'), 'viewSource' => t('Source code'),
'hr' => t('Horizontal rule'),
'cut' => t('Cut'), 'copy' => t('Copy'), 'paste' => t('Paste'),
'visualaid' => t('Visual aid'),
'removeformat' => t('Remove format'),
'charmap' => t('Character map'),
'headings' => t('HTML block format'), 'font' => t('Font'), 'fontsize' => t('Font size'),
'maximize' => t('Fullscreen'),
'preview' => t('Preview'),
'print' => t('Print'),
'inserttable' => t('Table'),
'help' => t('Help'),
),
'internal' => TRUE,
),
);
return $plugins;
}
+653
View File
@@ -0,0 +1,653 @@
<?php
/**
* @file
* Editor integration functions for TinyMCE.
*/
/**
* Plugin implementation of hook_editor().
*
* @todo wysiwyg_<editor>_alter() to add/inject optional libraries like gzip.
*/
function wysiwyg_tinymce_editor() {
$editor['tinymce'] = array(
'title' => 'TinyMCE',
'vendor url' => 'http://tinymce.moxiecode.com',
'download url' => 'http://tinymce.moxiecode.com/download.php',
'library path' => wysiwyg_get_path('tinymce') . '/jscripts/tiny_mce',
'libraries' => array(
'' => array(
'title' => 'Minified',
'files' => array('tiny_mce.js'),
),
'src' => array(
'title' => 'Source',
'files' => array('tiny_mce_src.js'),
),
),
'version callback' => 'wysiwyg_tinymce_version',
'themes callback' => 'wysiwyg_tinymce_themes',
'init callback' => 'wysiwyg_tinymce_init',
'settings callback' => 'wysiwyg_tinymce_settings',
'plugin callback' => 'wysiwyg_tinymce_plugins',
'plugin settings callback' => 'wysiwyg_tinymce_plugin_settings',
'proxy plugin' => array(
'drupal' => array(
'load' => TRUE,
'proxy' => TRUE,
),
),
'proxy plugin settings callback' => 'wysiwyg_tinymce_proxy_plugin_settings',
'versions' => array(
'2.1' => array(
'js files' => array('tinymce-2.js'),
'css files' => array('tinymce-2.css'),
'download url' => 'http://sourceforge.net/project/showfiles.php?group_id=103281&package_id=111430&release_id=557383',
),
// @todo Starting from 3.3, tiny_mce.js may support JS aggregation.
'3.1' => array(
'js files' => array('tinymce-3.js'),
'css files' => array('tinymce-3.css'),
'libraries' => array(
'' => array(
'title' => 'Minified',
'files' => array(
'tiny_mce.js' => array('preprocess' => FALSE),
),
),
'jquery' => array(
'title' => 'jQuery',
'files' => array('tiny_mce_jquery.js'),
),
'src' => array(
'title' => 'Source',
'files' => array('tiny_mce_src.js'),
),
),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_tinymce_version($editor) {
$script = $editor['library path'] . '/tiny_mce.js';
if (!file_exists($script)) {
return;
}
$script = fopen($script, 'r');
// Version is contained in the first 200 chars.
$line = fgets($script, 200);
fclose($script);
// 2.x: this.majorVersion="2";this.minorVersion="1.3"
// 3.x: majorVersion:'3',minorVersion:'2.0.1'
if (preg_match('@majorVersion[=:]["\'](\d).+?minorVersion[=:]["\']([\d\.]+)@', $line, $version)) {
return $version[1] . '.' . $version[2];
}
}
/**
* Determine available editor themes or check/reset a given one.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $profile
* A wysiwyg editor profile.
*
* @return
* An array of theme names. The first returned name should be the default
* theme name.
*/
function wysiwyg_tinymce_themes($editor, $profile) {
/*
$themes = array();
$dir = $editor['library path'] . '/themes/';
if (is_dir($dir) && $dh = opendir($dir)) {
while (($file = readdir($dh)) !== FALSE) {
if (!in_array($file, array('.', '..', 'CVS', '.svn')) && is_dir($dir . $file)) {
$themes[$file] = $file;
}
}
closedir($dh);
asort($themes);
}
return $themes;
*/
return array('advanced', 'simple');
}
/**
* Returns an initialization JavaScript for this editor library.
*
* @param array $editor
* The editor library definition.
* @param string $library
* The library variant key from $editor['libraries'].
* @param object $profile
* The (first) wysiwyg editor profile.
*
* @return string
* A string containing inline JavaScript to execute before the editor library
* script is loaded.
*/
function wysiwyg_tinymce_init($editor, $library) {
// TinyMCE unconditionally searches for its library filename in SCRIPT tags on
// on the page upon loading the library in order to determine the base path to
// itself. When JavaScript aggregation is enabled, this search fails and all
// relative constructed paths within TinyMCE are broken. The library has a
// tinyMCE.baseURL property, but it is not publicly documented and thus not
// reliable. The official support forum suggests to solve the issue through
// the global window.tinyMCEPreInit variable also used by various serverside
// compressor scrips available from the official website.
// @see http://www.tinymce.com/forum/viewtopic.php?id=23286
$settings = drupal_json_encode(array(
'base' => base_path() . $editor['library path'],
'suffix' => (strpos($library, 'src') !== FALSE || strpos($library, 'dev') !== FALSE ? '_src' : ''),
'query' => '',
));
return <<<EOL
window.tinyMCEPreInit = $settings;
EOL;
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_tinymce_settings($editor, $config, $theme) {
$settings = array(
'button_tile_map' => TRUE, // @todo Add a setting for this.
'document_base_url' => base_path(),
'mode' => 'none',
'plugins' => array(),
#'theme' => $theme,
'theme' => 'advanced',
'skin' => 'o2k7',
'skin_variant' => "silver",
'width' => '100%',
// Strict loading mode must be enabled; otherwise TinyMCE would use
// document.write() in IE and Chrome.
'strict_loading_mode' => TRUE,
// TinyMCE's URL conversion magic breaks Drupal modules that use a special
// syntax for paths. This makes 'relative_urls' obsolete.
'convert_urls' => FALSE,
// The default entity_encoding ('named') converts too many characters in
// languages (like Greek). Since Drupal supports Unicode, we only convert
// HTML control characters and invisible characters. TinyMCE always converts
// XML default characters '&', '<', '>'.
'entities' => '160,nbsp,173,shy,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm',
);
if (isset($config['apply_source_formatting'])) {
$settings['apply_source_formatting'] = $config['apply_source_formatting'];
}
if (isset($config['convert_fonts_to_spans'])) {
$settings['convert_fonts_to_spans'] = $config['convert_fonts_to_spans'];
}
if (isset($config['language'])) {
$settings['language'] = $config['language'];
}
if (isset($config['paste_auto_cleanup_on_paste'])) {
$settings['paste_auto_cleanup_on_paste'] = $config['paste_auto_cleanup_on_paste'];
}
if (isset($config['preformatted'])) {
$settings['preformatted'] = $config['preformatted'];
}
if (isset($config['remove_linebreaks'])) {
$settings['remove_linebreaks'] = $config['remove_linebreaks'];
}
if (isset($config['verify_html'])) {
// TinyMCE performs a type-agnostic comparison on this particular setting.
$settings['verify_html'] = (bool) $config['verify_html'];
}
if (!empty($config['css_classes'])) {
$settings['theme_advanced_styles'] = implode(';', array_filter(explode("\n", str_replace("\r", '', $config['css_classes']))));
}
if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') {
$settings['content_css'] = implode(',', wysiwyg_get_css());
}
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['content_css'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
}
}
// Find the enabled buttons and the button row they belong on.
// Also map the plugin metadata for each button.
// @todo What follows is a pain; needs a rewrite.
// $settings['buttons'] are stacked into $settings['theme_advanced_buttons1']
// later.
$settings['buttons'] = array();
if (!empty($config['buttons']) && is_array($config['buttons'])) {
// Only array keys in $settings['extensions'] matter; added to
// $settings['plugins'] later.
$settings['extensions'] = array();
// $settings['extended_valid_elements'] are just stacked, unique'd later,
// and transformed into a comma-separated string in
// wysiwyg_add_editor_settings().
// @todo Needs a complete plugin API redesign using arrays for
// tag => attributes definitions and array_merge_recursive().
$settings['extended_valid_elements'] = array();
$plugins = wysiwyg_get_plugins($editor['name']);
foreach ($config['buttons'] as $plugin => $buttons) {
foreach ($buttons as $button => $enabled) {
// Iterate separately over buttons and extensions properties.
foreach (array('buttons', 'extensions') as $type) {
// Skip unavailable plugins.
if (!isset($plugins[$plugin][$type][$button])) {
continue;
}
// Add buttons.
if ($type == 'buttons') {
$settings['buttons'][] = $button;
}
// Add external Drupal plugins to the list of extensions.
if ($type == 'buttons' && !empty($plugins[$plugin]['proxy'])) {
$settings['extensions'][_wysiwyg_tinymce_plugin_name('add', $button)] = 1;
}
// Add external plugins to the list of extensions.
elseif ($type == 'buttons' && empty($plugins[$plugin]['internal'])) {
$settings['extensions'][_wysiwyg_tinymce_plugin_name('add', $plugin)] = 1;
}
// Add internal buttons that also need to be loaded as extension.
elseif ($type == 'buttons' && !empty($plugins[$plugin]['load'])) {
$settings['extensions'][$plugin] = 1;
}
// Add plain extensions.
elseif ($type == 'extensions' && !empty($plugins[$plugin]['load'])) {
$settings['extensions'][$plugin] = 1;
}
// Allow plugins to add valid HTML elements.
if (!empty($plugins[$plugin]['extended_valid_elements'])) {
$settings['extended_valid_elements'] = array_merge($settings['extended_valid_elements'], $plugins[$plugin]['extended_valid_elements']);
}
// Allow plugins to add or override global configuration settings.
if (!empty($plugins[$plugin]['options'])) {
$settings = array_merge($settings, $plugins[$plugin]['options']);
}
}
}
}
// Clean-up.
$settings['extended_valid_elements'] = array_unique($settings['extended_valid_elements']);
if ($settings['extensions']) {
$settings['plugins'] = array_keys($settings['extensions']);
}
unset($settings['extensions']);
}
// Add theme-specific settings.
switch ($theme) {
case 'advanced':
$settings += array(
'theme_advanced_resize_horizontal' => FALSE,
'theme_advanced_resizing_use_cookie' => FALSE,
'theme_advanced_statusbar_location' => isset($config['path_loc']) ? $config['path_loc'] : 'bottom',
'theme_advanced_resizing' => isset($config['resizing']) ? $config['resizing'] : 1,
'theme_advanced_toolbar_location' => isset($config['toolbar_loc']) ? $config['toolbar_loc'] : 'top',
'theme_advanced_toolbar_align' => isset($config['toolbar_align']) ? $config['toolbar_align'] : 'left',
);
if (isset($config['block_formats'])) {
$settings['theme_advanced_blockformats'] = $config['block_formats'];
}
if (isset($settings['buttons'])) {
// These rows explicitly need to be set to be empty, otherwise TinyMCE
// loads its default buttons of the advanced theme for each row.
$settings += array(
'theme_advanced_buttons1' => array(),
'theme_advanced_buttons2' => array(),
'theme_advanced_buttons3' => array(),
);
// @todo Allow to sort/arrange editor buttons.
for ($i = 0; $i < count($settings['buttons']); $i++) {
$settings['theme_advanced_buttons1'][] = $settings['buttons'][$i];
}
}
break;
}
unset($settings['buttons']);
// Convert the config values into the form expected by TinyMCE.
$csv_settings = array('plugins', 'extended_valid_elements', 'theme_advanced_buttons1', 'theme_advanced_buttons2', 'theme_advanced_buttons3');
foreach ($csv_settings as $key) {
if (isset($settings[$key]) && is_array($settings[$key])) {
$settings[$key] = implode(',', $settings[$key]);
}
}
return $settings;
}
/**
* Build a JS settings array of native external plugins that need to be loaded separately.
*
* TinyMCE requires that external plugins (i.e. not residing in the editor's
* directory) are loaded (once) upon initializing the editor.
*/
function wysiwyg_tinymce_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
if (!empty($plugin['load'])) {
// Add path for native external plugins; internal ones are loaded
// automatically.
if (empty($plugin['internal']) && isset($plugin['filename'])) {
$settings[$name] = base_path() . $plugin['path'] . '/' . $plugin['filename'];
}
}
}
return $settings;
}
/**
* Build a JS settings array for Drupal plugins loaded via the proxy plugin.
*/
function wysiwyg_tinymce_proxy_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
// Populate required plugin settings.
$settings[$name] = $plugin['dialog settings'] + array(
'title' => $plugin['title'],
'icon' => base_path() . $plugin['icon path'] . '/' . $plugin['icon file'],
'iconTitle' => $plugin['icon title'],
);
if (isset($plugin['css file'])) {
$settings[$name]['css'] = base_path() . $plugin['css path'] . '/' . $plugin['css file'];
}
}
return $settings;
}
/**
* Add or remove leading hiven to/of external plugin names.
*
* TinyMCE requires that external plugins, which should not be loaded from
* its own plugin repository are prefixed with a hiven in the name.
*
* @param string $op
* Operation to perform, 'add' or 'remove' (hiven).
* @param string $name
* A plugin name.
*/
function _wysiwyg_tinymce_plugin_name($op, $name) {
if ($op == 'add') {
if (strpos($name, '-') !== 0) {
return '-' . $name;
}
return $name;
}
elseif ($op == 'remove') {
if (strpos($name, '-') === 0) {
return substr($name, 1);
}
return $name;
}
}
/**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/
function wysiwyg_tinymce_plugins($editor) {
$plugins = array(
'default' => array(
'path' => $editor['library path'] . '/themes/advanced',
'buttons' => array(
'bold' => t('Bold'), 'italic' => t('Italic'), 'underline' => t('Underline'),
'strikethrough' => t('Strike-through'),
'justifyleft' => t('Align left'), 'justifycenter' => t('Align center'), 'justifyright' => t('Align right'), 'justifyfull' => t('Justify'),
'bullist' => t('Bullet list'), 'numlist' => t('Numbered list'),
'outdent' => t('Outdent'), 'indent' => t('Indent'),
'undo' => t('Undo'), 'redo' => t('Redo'),
'link' => t('Link'), 'unlink' => t('Unlink'), 'anchor' => t('Anchor'),
'image' => t('Image'),
'cleanup' => t('Clean-up'),
'formatselect' => t('Block format'), 'styleselect' => t('Styles'),
'fontselect' => t('Font'), 'fontsizeselect' => t('Font size'),
'forecolor' => t('Forecolor'), 'backcolor' => t('Backcolor'),
'sup' => t('Superscript'), 'sub' => t('Subscript'),
'blockquote' => t('Blockquote'), 'code' => t('Source code'),
'hr' => t('Horizontal rule'),
'cut' => t('Cut'), 'copy' => t('Copy'), 'paste' => t('Paste'),
'visualaid' => t('Visual aid'),
'removeformat' => t('Remove format'),
'charmap' => t('Character map'),
'help' => t('Help'),
),
'internal' => TRUE,
),
'advhr' => array(
'path' => $editor['library path'] . '/plugins/advhr',
'buttons' => array('advhr' => t('Advanced horizontal rule')),
'extended_valid_elements' => array('hr[class|width|size|noshade]'),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:advhr',
'internal' => TRUE,
'load' => TRUE,
),
'advimage' => array(
'path' => $editor['library path'] . '/plugins/advimage',
'extensions' => array('advimage' => t('Advanced image')),
'extended_valid_elements' => array('img[src|alt|title|align|width|height|usemap|hspace|vspace|border|style|class|onmouseover|onmouseout|id|name|longdesc]'),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:advimage',
'internal' => TRUE,
'load' => TRUE,
),
'advlink' => array(
'path' => $editor['library path'] . '/plugins/advlink',
'extensions' => array('advlink' => t('Advanced link')),
'extended_valid_elements' => array('a[name|href|target|title|class|onfocus|onblur|onclick|ondlbclick|onmousedown|onmouseup|onmouseover|onmouseout|onkeypress|onkeydown|onkeyup|id|style|rel]'),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:advlink',
'internal' => TRUE,
'load' => TRUE,
),
'autosave' => array(
'path' => $editor['library path'] . '/plugins/autosave',
'extensions' => array('autosave' => t('Auto save')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:autosave',
'internal' => TRUE,
'load' => TRUE,
),
'contextmenu' => array(
'path' => $editor['library path'] . '/plugins/contextmenu',
'extensions' => array('contextmenu' => t('Context menu')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:contextmenu',
'internal' => TRUE,
'load' => TRUE,
),
'directionality' => array(
'path' => $editor['library path'] . '/plugins/directionality',
'buttons' => array('ltr' => t('Left-to-right'), 'rtl' => t('Right-to-left')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:directionality',
'internal' => TRUE,
'load' => TRUE,
),
'emotions' => array(
'path' => $editor['library path'] . '/plugins/emotions',
'buttons' => array('emotions' => t('Emotions')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:emotions',
'internal' => TRUE,
'load' => TRUE,
),
'fullscreen' => array(
'path' => $editor['library path'] . '/plugins/fullscreen',
'buttons' => array('fullscreen' => t('Fullscreen')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:fullscreen',
'internal' => TRUE,
'load' => TRUE,
),
'inlinepopups' => array(
'path' => $editor['library path'] . '/plugins/inlinepopups',
'extensions' => array('inlinepopups' => t('Inline popups')),
'options' => array(
'dialog_type' => array('modal'),
),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:inlinepopups',
'internal' => TRUE,
'load' => TRUE,
),
'insertdatetime' => array(
'path' => $editor['library path'] . '/plugins/insertdatetime',
'buttons' => array('insertdate' => t('Insert date'), 'inserttime' => t('Insert time')),
'options' => array(
'plugin_insertdate_dateFormat' => '%Y-%m-%d',
'plugin_insertdate_timeFormat' => '%H:%M:%S',
),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:insertdatetime',
'internal' => TRUE,
'load' => TRUE,
),
'layer' => array(
'path' => $editor['library path'] . '/plugins/layer',
'buttons' => array('insertlayer' => t('Insert layer'), 'moveforward' => t('Move forward'), 'movebackward' => t('Move backward'), 'absolute' => t('Absolute')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:layer',
'internal' => TRUE,
'load' => TRUE,
),
'paste' => array(
'path' => $editor['library path'] . '/plugins/paste',
'buttons' => array('pastetext' => t('Paste text'), 'pasteword' => t('Paste from Word'), 'selectall' => t('Select all')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:paste',
'internal' => TRUE,
'load' => TRUE,
),
'preview' => array(
'path' => $editor['library path'] . '/plugins/preview',
'buttons' => array('preview' => t('Preview')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:preview',
'internal' => TRUE,
'load' => TRUE,
),
'print' => array(
'path' => $editor['library path'] . '/plugins/print',
'buttons' => array('print' => t('Print')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:print',
'internal' => TRUE,
'load' => TRUE,
),
'searchreplace' => array(
'path' => $editor['library path'] . '/plugins/searchreplace',
'buttons' => array('search' => t('Search'), 'replace' => t('Replace')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:searchreplace',
'internal' => TRUE,
'load' => TRUE,
),
'style' => array(
'path' => $editor['library path'] . '/plugins/style',
'buttons' => array('styleprops' => t('Advanced CSS styles')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:style',
'internal' => TRUE,
'load' => TRUE,
),
'table' => array(
'path' => $editor['library path'] . '/plugins/table',
'buttons' => array('tablecontrols' => t('Table')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:table',
'internal' => TRUE,
'load' => TRUE,
),
);
if (version_compare($editor['installed version'], '3', '<')) {
$plugins['flash'] = array(
'path' => $editor['library path'] . '/plugins/flash',
'buttons' => array('flash' => t('Flash')),
'extended_valid_elements' => array('img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name|obj|param|embed]'),
'internal' => TRUE,
'load' => TRUE,
);
}
if (version_compare($editor['installed version'], '2.0.6', '>')) {
$plugins['media'] = array(
'path' => $editor['library path'] . '/plugins/media',
'buttons' => array('media' => t('Media')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:media',
'internal' => TRUE,
'load' => TRUE,
);
$plugins['xhtmlxtras'] = array(
'path' => $editor['library path'] . '/plugins/xhtmlxtras',
'buttons' => array('cite' => t('Citation'), 'del' => t('Deleted'), 'abbr' => t('Abbreviation'), 'acronym' => t('Acronym'), 'ins' => t('Inserted'), 'attribs' => t('HTML attributes')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:xhtmlxtras',
'internal' => TRUE,
'load' => TRUE,
);
}
if (version_compare($editor['installed version'], '3', '>')) {
$plugins['bbcode'] = array(
'path' => $editor['library path'] . '/plugins/bbcode',
'extensions' => array('bbcode' => t('BBCode')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:bbcode',
'internal' => TRUE,
'load' => TRUE,
);
if (version_compare($editor['installed version'], '3.3', '<')) {
$plugins['safari'] = array(
'path' => $editor['library path'] . '/plugins/safari',
'extensions' => array('safari' => t('Safari compatibility')),
'internal' => TRUE,
'load' => TRUE,
);
}
}
if (version_compare($editor['installed version'], '3.2.5', '>=')) {
$plugins['autoresize'] = array(
'path' => $editor['library path'] . '/plugins/autoresize',
'extensions' => array('autoresize' => t('Auto resize')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:autoresize',
'internal' => TRUE,
'load' => TRUE,
);
}
if (version_compare($editor['installed version'], '3.3', '>=')) {
$plugins['advlist'] = array(
'path' => $editor['library path'] . '/plugins/advlist',
'extensions' => array('advlist' => t('Advanced list')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:advlist',
'internal' => TRUE,
'load' => TRUE,
);
}
if (version_compare($editor['installed version'], '3.2.6', '>=')) {
$plugins['wordcount'] = array(
'path' => $editor['library path'] . '/plugins/wordcount',
'extensions' => array('wordcount' => t('Word count')),
'internal' => TRUE,
'load' => TRUE,
);
}
if (version_compare($editor['installed version'], '3.4.1', '>=')) {
$plugins['lists'] = array(
'path' => $editor['library path'] . 'plugins/lists',
'extensions' => array('lists' => t('List normalizer')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:lists',
'internal' => TRUE,
'load' => TRUE,
'extended_valid_elements' => array(
'li[class|dir|id|lang|onclick|ondblclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|style|title|type|value]',
'ol[class|compact|dir|id|lang|onclick|ondblclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|start|style|title|type]',
'ul[class|compact|dir|id|lang|onclick|ondblclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|style|title|type]',
),
);
}
return $plugins;
}
+147
View File
@@ -0,0 +1,147 @@
<?php
/**
* @file
* Editor integration functions for Whizzywig.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_whizzywig_editor() {
$editor['whizzywig'] = array(
'title' => 'Whizzywig',
'vendor url' => 'http://www.unverse.net',
'download url' => 'http://www.unverse.net/whizzywig-download.html',
'libraries' => array(
'' => array(
'title' => 'Default',
'files' => array('whizzywig.js', 'xhtml.js'),
),
),
'version callback' => 'wysiwyg_whizzywig_version',
'settings callback' => 'wysiwyg_whizzywig_settings',
'plugin callback' => 'wysiwyg_whizzywig_plugins',
'versions' => array(
'55' => array(
'js files' => array('whizzywig.js'),
),
'56' => array(
'js files' => array('whizzywig-56.js'),
),
'60' => array(
'js files' => array('whizzywig-60.js'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_whizzywig_version($editor) {
$script = $editor['library path'] . '/whizzywig.js';
if (!file_exists($script)) {
return;
}
$script = fopen($script, 'r');
$line = fgets($script, 43);
// 55: Whizzywig v55i
// 60: Whizzywig 60
if (preg_match('@Whizzywig v?([0-9]+)@', $line, $version)) {
fclose($script);
return $version[1];
}
fclose($script);
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_whizzywig_settings($editor, $config, $theme) {
$settings = array();
// Add path to button images, if available.
if (is_dir($editor['library path'] . '/btn')) {
$settings['buttonPath'] = base_path() . $editor['library path'] . '/btn/';
}
if (file_exists($editor['library path'] . '/WhizzywigToolbar.png')) {
$settings['toolbarImagePath'] = base_path() . $editor['library path'] . '/WhizzywigToolbar.png';
}
// Filename changed in version 60.
elseif (file_exists($editor['library path'] . '/icons.png')) {
$settings['toolbarImagePath'] = base_path() . $editor['library path'] . '/icons.png';
}
// Add configured buttons or all available.
$settings['buttons'] = array();
if (!empty($config['buttons'])) {
$buttons = array();
foreach ($config['buttons'] as $plugin) {
$buttons = array_merge($buttons, $plugin);
}
$settings['buttons'] = implode(' ', array_keys($buttons));
}
// Add editor content stylesheet.
if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') {
$css = drupal_get_path('theme', variable_get('theme_default', NULL)) . '/style.css';
if (file_exists($css)) {
$settings['externalCSS'] = base_path() . $css;
}
}
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['externalCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
}
}
return $settings;
}
/**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/
function wysiwyg_whizzywig_plugins($editor) {
return array(
'default' => array(
'buttons' => array(
'formatblock' => t('HTML block format'), 'fontname' => t('Font'), 'fontsize' => t('Font size'),
'bold' => t('Bold'), 'italic' => t('Italic'), 'underline' => t('Underline'),
'left' => t('Align left'), 'center' => t('Align center'), 'right' => t('Align right'),
'bullet' => t('Bullet list'), 'number' => t('Numbered list'),
'outdent' => t('Outdent'), 'indent' => t('Indent'),
'undo' => t('Undo'), 'redo' => t('Redo'),
'image' => t('Image'),
'color' => t('Forecolor'), 'hilite' => t('Backcolor'),
'rule' => t('Horizontal rule'),
'link' => t('Link'),
'image' => t('Image'),
'table' => t('Table'),
'clean' => t('Clean-up'),
'html' => t('Source code'),
'spellcheck' => t('Spell check'),
),
'internal' => TRUE,
),
);
}
+234
View File
@@ -0,0 +1,234 @@
<?php
/**
* @file
* Editor integration functions for WYMeditor.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_wymeditor_editor() {
$editor['wymeditor'] = array(
'title' => 'WYMeditor',
'vendor url' => 'http://www.wymeditor.org/',
'download url' => 'http://www.wymeditor.org/download/',
'library path' => wysiwyg_get_path('wymeditor') . '/wymeditor',
'libraries' => array(
'min' => array(
'title' => 'Minified',
'files' => array('jquery.wymeditor.min.js'),
),
'pack' => array(
'title' => 'Packed',
'files' => array('jquery.wymeditor.pack.js'),
),
'src' => array(
'title' => 'Source',
'files' => array('jquery.wymeditor.js'),
),
),
'version callback' => 'wysiwyg_wymeditor_version',
'themes callback' => 'wysiwyg_wymeditor_themes',
'settings callback' => 'wysiwyg_wymeditor_settings',
'plugin callback' => 'wysiwyg_wymeditor_plugins',
'versions' => array(
'0.5-rc1' => array(
'js files' => array('wymeditor.js'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_wymeditor_version($editor) {
$script = $editor['library path'] . '/jquery.wymeditor.js';
if (!file_exists($script)) {
return;
}
$script = fopen($script, 'r');
fgets($script);
$line = fgets($script);
if (preg_match('@version\s+([0-9a-z\.-]+)@', $line, $version)) {
fclose($script);
return $version[1];
}
fclose($script);
}
/**
* Determine available editor themes or check/reset a given one.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $profile
* A wysiwyg editor profile.
*
* @return
* An array of theme names. The first returned name should be the default
* theme name.
*/
function wysiwyg_wymeditor_themes($editor, $profile) {
return array('compact', 'default', 'minimal', 'silver', 'twopanels');
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_wymeditor_settings($editor, $config, $theme) {
// @todo Setup $library in wysiwyg_load_editor() already.
$library = (isset($editor['library']) ? $editor['library'] : key($editor['libraries']));
$settings = array(
'basePath' => base_path() . $editor['library path'] . '/',
'wymPath' => $editor['libraries'][$library]['files'][0],
// @todo Does not work in Drupal; jQuery can live anywhere.
'jQueryPath' => base_path() . 'misc/jquery.js',
'updateSelector' => '.form-submit',
'skin' => $theme,
);
if (isset($config['language'])) {
$settings['lang'] = $config['language'];
}
// Add configured buttons.
$settings['toolsItems'] = array();
if (!empty($config['buttons'])) {
$buttoninfo = _wysiwyg_wymeditor_button_info();
$plugins = wysiwyg_get_plugins($editor['name']);
foreach ($config['buttons'] as $plugin => $buttons) {
foreach ($buttons as $button => $enabled) {
// Iterate separately over buttons and extensions properties.
foreach (array('buttons', 'extensions') as $type) {
// Skip unavailable plugins.
if (!isset($plugins[$plugin][$type][$button])) {
continue;
}
// Add buttons.
if ($type == 'buttons') {
// Merge meta-data for internal default buttons.
if (isset($buttoninfo[$button])) {
$buttoninfo[$button] += array('name' => $button);
$settings['toolsItems'][] = $buttoninfo[$button];
}
// For custom buttons, try to provide a valid button definition.
else {
$settings['toolsItems'][] = array(
'name' => $button,
'title' => $plugins[$plugin][$type][$button],
'css' => 'wym_tools_' . $button,
);
}
}
}
}
}
}
if (!empty($config['block_formats'])) {
$containers = array(
'p' => 'Paragraph',
'h1' => 'Heading_1',
'h2' => 'Heading_2',
'h3' => 'Heading_3',
'h4' => 'Heading_4',
'h5' => 'Heading_5',
'h6' => 'Heading_6',
'pre' => 'Preformatted',
'blockquote' => 'Blockquote',
'th' => 'Table_Header',
);
foreach (explode(',', $config['block_formats']) as $tag) {
if (isset($containers[$tag])) {
$settings['containersItems'][] = array(
'name' => strtoupper($tag),
'title' => $containers[$tag],
'css' => 'wym_containers_' . $tag,
);
}
}
}
if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') {
// WYMeditor only supports one CSS file currently.
$css = wysiwyg_get_css();
$settings['stylesheet'] = reset($css);
}
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['stylesheet'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
}
}
return $settings;
}
/**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/
function wysiwyg_wymeditor_plugins($editor) {
$plugins = array(
'default' => array(
'buttons' => array(
'Bold' => t('Bold'), 'Italic' => t('Italic'),
'InsertOrderedList' => t('Numbered list'), 'InsertUnorderedList' => t('Bullet list'),
'Outdent' => t('Outdent'), 'Indent' => t('Indent'),
'Undo' => t('Undo'), 'Redo' => t('Redo'),
'CreateLink' => t('Link'), 'Unlink' => t('Unlink'),
'InsertImage' => t('Image'),
'Superscript' => t('Superscript'), 'Subscript' => t('Subscript'),
'ToggleHtml' => t('Source code'),
'Paste' => t('Paste'),
'InsertTable' => t('Table'),
'Preview' => t('Preview'),
),
'internal' => TRUE,
),
);
return $plugins;
}
/**
* Helper function to provide additional meta-data for internal default buttons.
*/
function _wysiwyg_wymeditor_button_info() {
return array(
'Bold' => array('title' => 'Strong', 'css' => 'wym_tools_strong'),
'Italic' => array('title' => 'Emphasis', 'css' => 'wym_tools_emphasis'),
'Superscript' => array('title' => 'Superscript', 'css' => 'wym_tools_superscript'),
'Subscript' => array('title' => 'Subscript', 'css' => 'wym_tools_subscript'),
'InsertOrderedList' => array('title' => 'Ordered_List', 'css' => 'wym_tools_ordered_list'),
'InsertUnorderedList' => array('title' => 'Unordered_List', 'css' => 'wym_tools_unordered_list'),
'Indent' => array('title' => 'Indent', 'css' => 'wym_tools_indent'),
'Outdent' => array('title' => 'Outdent', 'css' => 'wym_tools_outdent'),
'Undo' => array('title' => 'Undo', 'css' => 'wym_tools_undo'),
'Redo' => array('title' => 'Redo', 'css' => 'wym_tools_redo'),
'CreateLink' => array('title' => 'Link', 'css' => 'wym_tools_link'),
'Unlink' => array('title' => 'Unlink', 'css' => 'wym_tools_unlink'),
'InsertImage' => array('title' => 'Image', 'css' => 'wym_tools_image'),
'InsertTable' => array('title' => 'Table', 'css' => 'wym_tools_table'),
'Paste' => array('title' => 'Paste_From_Word', 'css' => 'wym_tools_paste'),
'ToggleHtml' => array('title' => 'HTML', 'css' => 'wym_tools_html'),
'Preview' => array('title' => 'Preview', 'css' => 'wym_tools_preview'),
);
}
+339
View File
@@ -0,0 +1,339 @@
<?php
/**
* @file
* Editor integration functions for YUI editor.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_yui_editor() {
$editor['yui'] = array(
'title' => 'YUI editor',
'vendor url' => 'http://developer.yahoo.com/yui/editor/',
'download url' => 'http://developer.yahoo.com/yui/download/',
'library path' => wysiwyg_get_path('yui') . '/build',
'libraries' => array(
'min' => array(
'title' => 'Minified',
'files' => array(
'yahoo-dom-event/yahoo-dom-event.js',
'animation/animation-min.js',
'element/element-min.js',
'container/container-min.js',
'menu/menu-min.js',
'button/button-min.js',
'editor/editor-min.js',
),
),
'src' => array(
'title' => 'Source',
'files' => array(
'yahoo-dom-event/yahoo-dom-event.js',
'animation/animation.js',
'element/element.js',
'container/container.js',
'menu/menu.js',
'button/button.js',
'editor/editor.js',
),
),
),
'version callback' => 'wysiwyg_yui_version',
'themes callback' => 'wysiwyg_yui_themes',
'load callback' => 'wysiwyg_yui_load',
'settings callback' => 'wysiwyg_yui_settings',
'plugin callback' => 'wysiwyg_yui_plugins',
'plugin settings callback' => 'wysiwyg_yui_plugin_settings',
'proxy plugin' => array(
'drupal' => array(
'load' => TRUE,
'proxy' => TRUE,
),
),
'proxy plugin settings callback' => 'wysiwyg_yui_proxy_plugin_settings',
'versions' => array(
'2.7.0' => array(
'js files' => array('yui.js'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_yui_version($editor) {
$library = $editor['library path'] . '/editor/editor.js';
if (!file_exists($library)) {
return;
}
$library = fopen($library, 'r');
$max_lines = 10;
while ($max_lines && $line = fgets($library, 60)) {
if (preg_match('@version:\s([0-9\.]+)@', $line, $version)) {
fclose($library);
return $version[1];
}
$max_lines--;
}
fclose($library);
}
/**
* Determine available editor themes or check/reset a given one.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $profile
* A wysiwyg editor profile.
*
* @return
* An array of theme names. The first returned name should be the default
* theme name.
*/
function wysiwyg_yui_themes($editor, $profile) {
return array('sam');
}
/**
* Perform additional actions upon loading this editor.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $library
* The internal library name (array key) to use.
*/
function wysiwyg_yui_load($editor, $library) {
drupal_add_css($editor['library path'] . '/menu/assets/skins/sam/menu.css');
drupal_add_css($editor['library path'] . '/button/assets/skins/sam/button.css');
drupal_add_css($editor['library path'] . '/fonts/fonts-min.css');
drupal_add_css($editor['library path'] . '/container/assets/skins/sam/container.css');
drupal_add_css($editor['library path'] . '/editor/assets/skins/sam/editor.css');
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_yui_settings($editor, $config, $theme) {
$settings = array(
'theme' => $theme,
'animate' => TRUE,
'handleSubmit' => TRUE,
'markup' => 'xhtml',
'ptags' => TRUE,
);
if (isset($config['path_loc']) && $config['path_loc'] != 'none') {
$settings['dompath'] = $config['path_loc'];
}
// Enable auto-height feature when editor should be resizable.
if (!empty($config['resizing'])) {
$settings['autoHeight'] = TRUE;
}
$settings += array(
'toolbar' => array(
'collapse' => FALSE,
'draggable' => TRUE,
'buttonType' => 'advanced',
'buttons' => array(),
),
);
if (!empty($config['buttons'])) {
$buttons = array();
foreach ($config['buttons'] as $plugin => $enabled_buttons) {
foreach ($enabled_buttons as $button => $enabled) {
$extra = array();
if ($button == 'heading') {
$extra = array('menu' => array(
array('text' => 'Normal', 'value' => 'none', 'checked' => TRUE),
));
if (!empty($config['block_formats'])) {
$headings = array(
'p' => array('text' => 'Paragraph', 'value' => 'p'),
'h1' => array('text' => 'Heading 1', 'value' => 'h1'),
'h2' => array('text' => 'Heading 2', 'value' => 'h2'),
'h3' => array('text' => 'Heading 3', 'value' => 'h3'),
'h4' => array('text' => 'Heading 4', 'value' => 'h4'),
'h5' => array('text' => 'Heading 5', 'value' => 'h5'),
'h6' => array('text' => 'Heading 6', 'value' => 'h6'),
);
foreach (explode(',', $config['block_formats']) as $tag) {
if (isset($headings[$tag])) {
$extra['menu'][] = $headings[$tag];
}
}
}
}
elseif ($button == 'fontname') {
$extra = array('menu' => array(
array('text' => 'Arial', 'checked' => TRUE),
array('text' => 'Arial Black'),
array('text' => 'Comic Sans MS'),
array('text' => 'Courier New'),
array('text' => 'Lucida Console'),
array('text' => 'Tahoma'),
array('text' => 'Times New Roman'),
array('text' => 'Trebuchet MS'),
array('text' => 'Verdana'),
));
}
$buttons[] = wysiwyg_yui_button_setting($editor, $plugin, $button, $extra);
}
}
// Group buttons in a dummy group.
$buttons = array('group' => 'default', 'label' => '', 'buttons' => $buttons);
$settings['toolbar']['buttons'] = array($buttons);
}
if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') {
$settings['extracss'] = wysiwyg_get_css();
}
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['extracss'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
$settings['extracss'] = explode(',', $settings['extracss']);
}
// YUI only supports inline CSS, so we need to use @import directives.
// Syntax: '@import "/base/path/to/theme/style.css"; '
if (!empty($settings['extracss'])) {
$settings['extracss'] = '@import "' . implode('"; @import "', $settings['extracss']) . '";';
}
}
return $settings;
}
/**
* Create the JavaScript structure for a YUI button.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $plugin
* The internal name of a plugin.
* @param $button
* The internal name of a button, defined by $plugin.
* @param $extra
* (optional) An array containing arbitrary other elements to add to the
* resulting button.
*/
function wysiwyg_yui_button_setting($editor, $plugin, $button, $extra = array()) {
static $plugins;
if (!isset($plugins)) {
$plugins = wysiwyg_get_plugins($editor['name']);
}
// Return a simple separator.
if ($button === 'separator') {
return array('type' => 'separator');
}
// Setup defaults.
$type = 'push';
$label = $plugins[$plugin]['buttons'][$button];
// Special handling for certain buttons.
if (in_array($button, array('heading', 'fontname'))) {
$type = 'select';
$label = $extra['menu'][0]['text'];
}
elseif (in_array($button, array('fontsize'))) {
$type = 'spin';
}
elseif (in_array($button, array('forecolor', 'backcolor'))) {
$type = 'color';
}
$button = array(
'type' => $type,
'label' => $label,
'value' => $button,
);
// Add arbitrary other elements, if defined.
if (!empty($extra)) {
$button = array_merge($button, $extra);
}
return $button;
}
/**
* Build a JS settings array of native external plugins that need to be loaded separately.
*/
function wysiwyg_yui_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
if (!empty($plugin['load'])) {
// Add path for native external plugins; internal ones are loaded
// automatically.
if (empty($plugin['internal']) && isset($plugin['path'])) {
$settings[$name] = base_path() . $plugin['path'];
}
}
}
return $settings;
}
/**
* Build a JS settings array for Drupal plugins loaded via the proxy plugin.
*/
function wysiwyg_yui_proxy_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
// Populate required plugin settings.
$settings[$name] = $plugin['dialog settings'] + array(
'title' => $plugin['title'],
'icon' => base_path() . $plugin['icon path'] . '/' . $plugin['icon file'],
'iconTitle' => $plugin['icon title'],
// @todo These should only be set if the plugin defined them.
'css' => base_path() . $plugin['css path'] . '/' . $plugin['css file'],
);
}
return $settings;
}
/**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/
function wysiwyg_yui_plugins($editor) {
return array(
'default' => array(
'buttons' => array(
'bold' => t('Bold'), 'italic' => t('Italic'), 'underline' => t('Underline'),
'strikethrough' => t('Strike-through'),
'justifyleft' => t('Align left'), 'justifycenter' => t('Align center'), 'justifyright' => t('Align right'), 'justifyfull' => t('Justify'),
'insertunorderedlist' => t('Bullet list'), 'insertorderedlist' => t('Numbered list'),
'outdent' => t('Outdent'), 'indent' => t('Indent'),
'undo' => t('Undo'), 'redo' => t('Redo'),
'createlink' => t('Link'),
'insertimage' => t('Image'),
'forecolor' => t('Font Color'), 'backcolor' => t('Background Color'),
'superscript' => t('Sup'), 'subscript' => t('Sub'),
'hiddenelements' => t('Show/hide hidden elements'),
'removeformat' => t('Remove format'),
'heading' => t('HTML block format'), 'fontname' => t('Font'), 'fontsize' => t('Font size'),
),
'internal' => TRUE,
),
);
}
-133
View File
@@ -1,133 +0,0 @@
<?php
/**
* @file
* Views area handlers.
*/
/**
* @defgroup views_area_handlers Views area handlers
* @{
* Handlers to tell Views what can display in header, footer
* and empty text in a view.
*/
/**
* Base class for area handlers.
*
* @ingroup views_area_handlers
*/
class views_handler_area extends views_handler {
/**
* Overrides views_handler::init().
*
* Make sure that no result area handlers are set to be shown when the result
* is empty.
*/
function init(&$view, &$options) {
parent::init($view, $options);
if ($this->handler_type == 'empty') {
$this->options['empty'] = TRUE;
}
}
/**
* Get this field's label.
*/
function label() {
if (!isset($this->options['label'])) {
return $this->ui_name();
}
return $this->options['label'];
}
function option_definition() {
$options = parent::option_definition();
$this->definition['field'] = !empty($this->definition['field']) ? $this->definition['field'] : '';
$label = !empty($this->definition['label']) ? $this->definition['label'] : $this->definition['field'];
$options['label'] = array('default' => $label, 'translatable' => TRUE);
$options['empty'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
/**
* Provide extra data to the administration form
*/
function admin_summary() {
return $this->label();
}
/**
* Default options form that provides the label widget that all fields
* should have.
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['label'] = array(
'#type' => 'textfield',
'#title' => t('Label'),
'#default_value' => isset($this->options['label']) ? $this->options['label'] : '',
'#description' => t('The label for this area that will be displayed only administratively.'),
);
if ($form_state['type'] != 'empty') {
$form['empty'] = array(
'#type' => 'checkbox',
'#title' => t('Display even if view has no result'),
'#default_value' => isset($this->options['empty']) ? $this->options['empty'] : 0,
);
}
}
/**
* Don't run a query
*/
function query() { }
/**
* Render the area
*/
function render($empty = FALSE) {
return '';
}
/**
* Area handlers shouldn't have groupby.
*/
function use_group_by() {
return FALSE;
}
}
/**
* A special handler to take the place of missing or broken handlers.
*
* @ingroup views_area_handlers
*/
class views_handler_area_broken extends views_handler_area {
function ui_name($short = FALSE) {
return t('Broken/missing handler');
}
function ensure_my_table() { /* No table to ensure! */ }
function query($group_by = FALSE) { /* No query to run */ }
function render($empty = FALSE) { return ''; }
function options_form(&$form, &$form_state) {
$form['markup'] = array(
'#prefix' => '<div class="form-item description">',
'#value' => t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.'),
);
}
/**
* Determine if the handler is considered 'broken'
*/
function broken() { return TRUE; }
}
/**
* @}
*/
-96
View File
@@ -1,96 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_area_result.
*/
/**
* Views area handler to display some configurable result summary.
*
* @ingroup views_area_handlers
*/
class views_handler_area_result extends views_handler_area {
function option_definition() {
$options = parent::option_definition();
$options['content'] = array(
'default' => 'Displaying @start - @end of @total',
'translatable' => TRUE,
);
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$variables = array(
'items' => array(
'@start -- the initial record number in the set',
'@end -- the last record number in the set',
'@total -- the total records in the set',
'@name -- the human-readable name of the view',
'@per_page -- the number of items per page',
'@current_page -- the current page number',
'@current_record_count -- the current page record count',
'@page_count -- the total page count',
),
);
$list = theme('item_list', $variables);
$form['content'] = array(
'#title' => t('Display'),
'#type' => 'textarea',
'#rows' => 3,
'#default_value' => $this->options['content'],
'#description' => t('You may use HTML code in this field. The following tokens are supported:') . $list,
);
}
/**
* Find out the information to render.
*/
function render($empty = FALSE) {
// Must have options and does not work on summaries.
if (!isset($this->options['content']) || $this->view->plugin_name == 'default_summary') {
return;
}
$output = '';
$format = $this->options['content'];
// Calculate the page totals.
$current_page = (int) $this->view->get_current_page() + 1;
$per_page = (int) $this->view->get_items_per_page();
$count = count($this->view->result);
// @TODO: Maybe use a possible is views empty functionality.
// Not every view has total_rows set, use view->result instead.
$total = isset($this->view->total_rows) ? $this->view->total_rows : count($this->view->result);
$name = check_plain($this->view->human_name);
if ($per_page === 0) {
$page_count = 1;
$start = 1;
$end = $total;
}
else {
$page_count = (int) ceil($total / $per_page);
$total_count = $current_page * $per_page;
if ($total_count > $total) {
$total_count = $total;
}
$start = ($current_page - 1) * $per_page + 1;
$end = $total_count;
}
$current_record_count = ($end - $start) + 1;
// Get the search information.
$items = array('start', 'end', 'total', 'name', 'per_page', 'current_page', 'current_record_count', 'page_count');
$replacements = array();
foreach ($items as $item) {
$replacements["@$item"] = ${$item};
}
// Send the output.
if (!empty($total)) {
$output .= filter_xss_admin(str_replace(array_keys($replacements), array_values($replacements), $format));
}
return $output;
}
}
-110
View File
@@ -1,110 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_area_text.
*/
/**
* Views area text handler.
*
* @ingroup views_area_handlers
*/
class views_handler_area_text extends views_handler_area {
function option_definition() {
$options = parent::option_definition();
$options['content'] = array('default' => '', 'translatable' => TRUE, 'format_key' => 'format');
$options['format'] = array('default' => NULL);
$options['tokenize'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['content'] = array(
'#type' => 'text_format',
'#default_value' => $this->options['content'],
'#rows' => 6,
'#format' => isset($this->options['format']) ? $this->options['format'] : filter_default_format(),
'#wysiwyg' => FALSE,
);
// @TODO: Refactor token handling into a base class.
$form['tokenize'] = array(
'#type' => 'checkbox',
'#title' => t('Use replacement tokens from the first row'),
'#default_value' => $this->options['tokenize'],
);
// Get a list of the available fields and arguments for token replacement.
$options = array();
foreach ($this->view->display_handler->get_handlers('field') as $field => $handler) {
$options[t('Fields')]["[$field]"] = $handler->ui_name();
}
$count = 0; // This lets us prepare the key as we want it printed.
foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
$options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->ui_name()));
$options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->ui_name()));
}
if (!empty($options)) {
$output = '<p>' . t('The following tokens are available. If you would like to have the characters \'[\' and \']\' please use the html entity codes \'%5B\' or \'%5D\' or they will get replaced with empty space.' . '</p>');
foreach (array_keys($options) as $type) {
if (!empty($options[$type])) {
$items = array();
foreach ($options[$type] as $key => $value) {
$items[] = $key . ' == ' . check_plain($value);
}
$output .= theme('item_list',
array(
'items' => $items,
'type' => $type
));
}
}
$form['token_help'] = array(
'#type' => 'fieldset',
'#title' => t('Replacement patterns'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#value' => $output,
'#id' => 'edit-options-token-help',
'#dependency' => array(
'edit-options-tokenize' => array(1),
),
'#prefix' => '<div>',
'#suffix' => '</div>',
);
}
}
function options_submit(&$form, &$form_state) {
$form_state['values']['options']['format'] = $form_state['values']['options']['content']['format'];
$form_state['values']['options']['content'] = $form_state['values']['options']['content']['value'];
parent::options_submit($form, $form_state);
}
function render($empty = FALSE) {
$format = isset($this->options['format']) ? $this->options['format'] : filter_default_format();
if (!$empty || !empty($this->options['empty'])) {
return $this->render_textarea($this->options['content'], $format);
}
return '';
}
/**
* Render a text area, using the proper format.
*/
function render_textarea($value, $format) {
if ($value) {
if ($this->options['tokenize']) {
$value = $this->view->style_plugin->tokenize_value($value, 0);
}
return check_markup($value, $format, '', FALSE);
}
}
}
@@ -1,56 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_area_text_custom.
*/
/**
* Views area text custom handler.
*
* @ingroup views_area_handlers
*/
class views_handler_area_text_custom extends views_handler_area_text {
function option_definition() {
$options = parent::option_definition();
unset($options['format']);
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
// Alter the form element, to be a regular text area.
$form['content']['#type'] = 'textarea';
unset($form['content']['#format']);
unset($form['content']['#wysiwyg']);
// @TODO: Use the token refactored base class.
}
// Empty, so we don't inherit options_submit from the parent.
function options_submit(&$form, &$form_state) {
}
function render($empty = FALSE) {
if (!$empty || !empty($this->options['empty'])) {
return $this->render_textarea_custom($this->options['content']);
}
return '';
}
/**
* Render a text area with filter_xss_admin.
*/
function render_textarea_custom($value) {
if ($value) {
if ($this->options['tokenize']) {
$value = $this->view->style_plugin->tokenize_value($value, 0);
}
return $this->sanitize_value($value, 'xss_admin');
}
}
}
-83
View File
@@ -1,83 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_area_view.
*/
/**
* Views area handlers. Insert a view inside of an area.
*
* @ingroup views_area_handlers
*/
class views_handler_area_view extends views_handler_area {
function option_definition() {
$options = parent::option_definition();
$options['view_to_insert'] = array('default' => '');
$options['inherit_arguments'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
/**
* Default options form that provides the label widget that all fields
* should have.
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$view_display = $this->view->name . ':' . $this->view->current_display;
$options = array('' => t('-Select-'));
$options += views_get_views_as_options(FALSE, 'all', $view_display, FALSE, TRUE);
$form['view_to_insert'] = array(
'#type' => 'select',
'#title' => t('View to insert'),
'#default_value' => $this->options['view_to_insert'],
'#description' => t('The view to insert into this area.'),
'#options' => $options,
);
$form['inherit_arguments'] = array(
'#type' => 'checkbox',
'#title' => t('Inherit contextual filters'),
'#default_value' => $this->options['inherit_arguments'],
'#description' => t('If checked, this view will receive the same contextual filters as its parent.'),
);
}
/**
* Render the area
*/
function render($empty = FALSE) {
if (!empty($this->options['view_to_insert'])) {
list($view_name, $display_id) = explode(':', $this->options['view_to_insert']);
$view = views_get_view($view_name);
if (empty($view) || !$view->access($display_id)) {
return;
}
$view->set_display($display_id);
// Avoid recursion
$view->parent_views += $this->view->parent_views;
$view->parent_views[] = "$view_name:$display_id";
// Check if the view is part of the parent views of this view
$search = "$view_name:$display_id";
if (in_array($search, $this->view->parent_views)) {
drupal_set_message(t("Recursion detected in view @view display @display.", array('@view' => $view_name, '@display' => $display_id)), 'error');
}
else {
if (!empty($this->options['inherit_arguments']) && !empty($this->view->args)) {
return $view->preview($display_id, $this->view->args);
}
else {
return $view->preview($display_id);
}
}
}
return '';
}
}
File diff suppressed because it is too large Load Diff
-101
View File
@@ -1,101 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_argument_date.
*/
/**
* Abstract argument handler for dates.
*
* Adds an option to set a default argument based on the current date.
*
* @param $arg_format
* The format string to use on the current time when
* creating a default date argument.
*
* Definitions terms:
* - many to one: If true, the "many to one" helper will be used.
* - invalid input: A string to give to the user for obviously invalid input.
* This is deprecated in favor of argument validators.
*
* @see views_many_to_one_helper()
*
* @ingroup views_argument_handlers
*/
class views_handler_argument_date extends views_handler_argument_formula {
var $option_name = 'default_argument_date';
var $arg_format = 'Y-m-d';
/**
* Add an option to set the default value to the current date.
*/
function default_argument_form(&$form, &$form_state) {
parent::default_argument_form($form, $form_state);
$form['default_argument_type']['#options'] += array('date' => t('Current date'));
$form['default_argument_type']['#options'] += array('node_created' => t("Current node's creation time"));
$form['default_argument_type']['#options'] += array('node_changed' => t("Current node's update time")); }
/**
* Set the empty argument value to the current date,
* formatted appropriately for this argument.
*/
function get_default_argument($raw = FALSE) {
if (!$raw && $this->options['default_argument_type'] == 'date') {
return date($this->arg_format, REQUEST_TIME);
}
else if (!$raw && in_array($this->options['default_argument_type'], array('node_created', 'node_changed'))) {
foreach (range(1, 3) as $i) {
$node = menu_get_object('node', $i);
if (!empty($node)) {
continue;
}
}
if (arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1));
}
if (empty($node)) {
return parent::get_default_argument();
}
elseif ($this->options['default_argument_type'] == 'node_created') {
return date($this->arg_format, $node->created);
}
elseif ($this->options['default_argument_type'] == 'node_changed') {
return date($this->arg_format, $node->changed);
}
}
return parent::get_default_argument($raw);
}
/**
* The date handler provides some default argument types, which aren't argument default plugins,
* so addapt the export mechanism.
*/
function export_plugin($indent, $prefix, $storage, $option, $definition, $parents) {
// Only use a special behaviour for the special argument types, else just
// use the default behaviour.
if ($option == 'default_argument_type') {
$type = 'argument default';
$option_name = 'default_argument_options';
$plugin = $this->get_plugin($type);
$name = $this->options[$option];
if (in_array($name, array('date', 'node_created', 'node_changed'))) {
// Write which plugin to use.
$output = $indent . $prefix . "['$option'] = '$name';\n";
return $output;
}
}
return parent::export_plugin($indent, $prefix, $storage, $option, $definition, $parents);
}
function get_sort_name() {
return t('Date', array(), array('context' => 'Sort order'));
}
}
@@ -1,63 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_argument_formula.
*/
/**
* Abstract argument handler for simple formulae.
*
* Child classes of this object should implement summary_argument, at least.
*
* Definition terms:
* - formula: The formula to use for this handler.
*
* @ingroup views_argument_handlers
*/
class views_handler_argument_formula extends views_handler_argument {
var $formula = NULL;
/**
* Constructor
*/
function construct() {
parent::construct();
if (!empty($this->definition['formula'])) {
$this->formula = $this->definition['formula'];
}
}
function get_formula() {
return str_replace('***table***', $this->table_alias, $this->formula);
}
/**
* Build the summary query based on a formula
*/
function summary_query() {
$this->ensure_my_table();
// Now that our table is secure, get our formula.
$formula = $this->get_formula();
// Add the field.
$this->base_alias = $this->name_alias = $this->query->add_field(NULL, $formula, $this->field);
$this->query->set_count_field(NULL, $formula, $this->field);
return $this->summary_basics(FALSE);
}
/**
* Build the query based upon the formula
*/
function query($group_by = FALSE) {
$this->ensure_my_table();
// Now that our table is secure, get our formula.
$placeholder = $this->placeholder();
$formula = $this->get_formula() .' = ' . $placeholder;
$placeholders = array(
$placeholder => $this->argument,
);
$this->query->add_where(0, $formula, $placeholders, 'formula');
}
}
@@ -1,29 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_argument_group_by_numeric.
*/
/**
* Simple handler for arguments using group by.
*
* @ingroup views_argument_handlers
*/
class views_handler_argument_group_by_numeric extends views_handler_argument {
function query($group_by = FALSE) {
$this->ensure_my_table();
$field = $this->get_field();
$placeholder = $this->placeholder();
$this->query->add_having_expression(0, "$field = $placeholder", array($placeholder => $this->argument));
}
function ui_name($short = FALSE) {
return $this->get_field(parent::ui_name($short));
}
function get_sort_name() {
return t('Numerical', array(), array('context' => 'Sort order'));
}
}
@@ -1,185 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_argument_many_to_one.
*/
/**
* An argument handler for use in fields that have a many to one relationship
* with the table(s) to the left. This adds a bunch of options that are
* reasonably common with this type of relationship.
* Definition terms:
* - numeric: If true, the field will be considered numeric. Probably should
* always be set TRUE as views_handler_argument_string has many to one
* capabilities.
* - zero is null: If true, a 0 will be handled as empty, so for example
* a default argument can be provided or a summary can be shown.
*
* @ingroup views_argument_handlers
*/
class views_handler_argument_many_to_one extends views_handler_argument {
function init(&$view, &$options) {
parent::init($view, $options);
$this->helper = new views_many_to_one_helper($this);
// Ensure defaults for these, during summaries and stuff:
$this->operator = 'or';
$this->value = array();
}
function option_definition() {
$options = parent::option_definition();
if (!empty($this->definition['numeric'])) {
$options['break_phrase'] = array('default' => FALSE, 'bool' => TRUE);
}
$options['add_table'] = array('default' => FALSE, 'bool' => TRUE);
$options['require_value'] = array('default' => FALSE, 'bool' => TRUE);
if (isset($this->helper)) {
$this->helper->option_definition($options);
}
else {
$helper = new views_many_to_one_helper($this);
$helper->option_definition($options);
}
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
// allow + for or, , for and
if (!empty($this->definition['numeric'])) {
$form['break_phrase'] = array(
'#type' => 'checkbox',
'#title' => t('Allow multiple values'),
'#description' => t('If selected, users can enter multiple values in the form of 1+2+3 (for OR) or 1,2,3 (for AND).'),
'#default_value' => !empty($this->options['break_phrase']),
'#fieldset' => 'more',
);
}
$form['add_table'] = array(
'#type' => 'checkbox',
'#title' => t('Allow multiple filter values to work together'),
'#description' => t('If selected, multiple instances of this filter can work together, as though multiple values were supplied to the same filter. This setting is not compatible with the "Reduce duplicates" setting.'),
'#default_value' => !empty($this->options['add_table']),
'#fieldset' => 'more',
);
$form['require_value'] = array(
'#type' => 'checkbox',
'#title' => t('Do not display items with no value in summary'),
'#default_value' => !empty($this->options['require_value']),
'#fieldset' => 'more',
);
$this->helper->options_form($form, $form_state);
}
/**
* Override ensure_my_table so we can control how this joins in.
* The operator actually has influence over joining.
*/
function ensure_my_table() {
$this->helper->ensure_my_table();
}
function query($group_by = FALSE) {
$empty = FALSE;
if (isset($this->definition['zero is null']) && $this->definition['zero is null']) {
if (empty($this->argument)) {
$empty = TRUE;
}
}
else {
if (!isset($this->argument)) {
$empty = TRUE;
}
}
if ($empty) {
parent::ensure_my_table();
$this->query->add_where(0, "$this->table_alias.$this->real_field", NULL, 'IS NULL');
return;
}
if (!empty($this->options['break_phrase'])) {
views_break_phrase($this->argument, $this);
}
else {
$this->value = array($this->argument);
$this->operator = 'or';
}
$this->helper->add_filter();
}
function title() {
if (!$this->argument) {
return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
}
if (!empty($this->options['break_phrase'])) {
views_break_phrase($this->argument, $this);
}
else {
$this->value = array($this->argument);
$this->operator = 'or';
}
// @todo -- both of these should check definition for alternate keywords.
if (empty($this->value)) {
return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
}
if ($this->value === array(-1)) {
return !empty($this->definition['invalid input']) ? $this->definition['invalid input'] : t('Invalid input');
}
return implode($this->operator == 'or' ? ' + ' : ', ', $this->title_query());
}
function summary_query() {
$field = $this->table . '.' . $this->field;
$join = $this->get_join();
if (!empty($this->options['require_value'])) {
$join->type = 'INNER';
}
if (empty($this->options['add_table']) || empty($this->view->many_to_one_tables[$field])) {
$this->table_alias = $this->query->ensure_table($this->table, $this->relationship, $join);
}
else {
$this->table_alias = $this->helper->summary_join();
}
// Add the field.
$this->base_alias = $this->query->add_field($this->table_alias, $this->real_field);
$this->summary_name_field();
return $this->summary_basics();
}
function summary_argument($data) {
$value = $data->{$this->base_alias};
if (empty($value)) {
$value = 0;
}
return $value;
}
/**
* Override for specific title lookups.
*/
function title_query() {
return $this->value;
}
}
-67
View File
@@ -1,67 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_argument_null.
*/
/**
* Argument handler that ignores the argument.
*
* @ingroup views_argument_handlers
*/
class views_handler_argument_null extends views_handler_argument {
function option_definition() {
$options = parent::option_definition();
$options['must_not_be'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
/**
* Override options_form() so that only the relevant options
* are displayed to the user.
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['must_not_be'] = array(
'#type' => 'checkbox',
'#title' => t('Fail basic validation if any argument is given'),
'#default_value' => !empty($this->options['must_not_be']),
'#description' => t('By checking this field, you can use this to make sure views with more arguments than necessary fail validation.'),
'#fieldset' => 'more',
);
unset($form['exception']);
}
/**
* Override default_actions() to remove actions that don't
* make sense for a null argument.
*/
function default_actions($which = NULL) {
if ($which) {
if (in_array($which, array('ignore', 'not found', 'empty', 'default'))) {
return parent::default_actions($which);
}
return;
}
$actions = parent::default_actions();
unset($actions['summary asc']);
unset($actions['summary desc']);
return $actions;
}
function validate_argument_basic($arg) {
if (!empty($this->options['must_not_be'])) {
return !isset($arg);
}
return parent::validate_argument_basic($arg);
}
/**
* Override the behavior of query() to prevent the query
* from being changed in any way.
*/
function query($group_by = FALSE) {}
}
-116
View File
@@ -1,116 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_argument_numeric.
*/
/**
* Basic argument handler for arguments that are numeric. Incorporates
* break_phrase.
*
* @ingroup views_argument_handlers
*/
class views_handler_argument_numeric extends views_handler_argument {
/**
* The operator used for the query: or|and.
* @var string
*/
var $operator;
/**
* The actual value which is used for querying.
* @var array
*/
var $value;
function option_definition() {
$options = parent::option_definition();
$options['break_phrase'] = array('default' => FALSE, 'bool' => TRUE);
$options['not'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
// allow + for or, , for and
$form['break_phrase'] = array(
'#type' => 'checkbox',
'#title' => t('Allow multiple values'),
'#description' => t('If selected, users can enter multiple values in the form of 1+2+3 (for OR) or 1,2,3 (for AND).'),
'#default_value' => !empty($this->options['break_phrase']),
'#fieldset' => 'more',
);
$form['not'] = array(
'#type' => 'checkbox',
'#title' => t('Exclude'),
'#description' => t('If selected, the numbers entered for the filter will be excluded rather than limiting the view.'),
'#default_value' => !empty($this->options['not']),
'#fieldset' => 'more',
);
}
function title() {
if (!$this->argument) {
return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
}
if (!empty($this->options['break_phrase'])) {
views_break_phrase($this->argument, $this);
}
else {
$this->value = array($this->argument);
$this->operator = 'or';
}
if (empty($this->value)) {
return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
}
if ($this->value === array(-1)) {
return !empty($this->definition['invalid input']) ? $this->definition['invalid input'] : t('Invalid input');
}
return implode($this->operator == 'or' ? ' + ' : ', ', $this->title_query());
}
/**
* Override for specific title lookups.
* @return array
* Returns all titles, if it's just one title it's an array with one entry.
*/
function title_query() {
return $this->value;
}
function query($group_by = FALSE) {
$this->ensure_my_table();
if (!empty($this->options['break_phrase'])) {
views_break_phrase($this->argument, $this);
}
else {
$this->value = array($this->argument);
}
$placeholder = $this->placeholder();
$null_check = empty($this->options['not']) ? '' : "OR $this->table_alias.$this->real_field IS NULL";
if (count($this->value) > 1) {
$operator = empty($this->options['not']) ? 'IN' : 'NOT IN';
$this->query->add_where_expression(0, "$this->table_alias.$this->real_field $operator($placeholder) $null_check", array($placeholder => $this->value));
}
else {
$operator = empty($this->options['not']) ? '=' : '!=';
$this->query->add_where_expression(0, "$this->table_alias.$this->real_field $operator $placeholder $null_check", array($placeholder => $this->argument));
}
}
function get_sort_name() {
return t('Numerical', array(), array('context' => 'Sort order'));
}
}
-274
View File
@@ -1,274 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_argument_string.
*/
/**
* Basic argument handler to implement string arguments that may have length
* limits.
*
* @ingroup views_argument_handlers
*/
class views_handler_argument_string extends views_handler_argument {
function init(&$view, &$options) {
parent::init($view, $options);
if (!empty($this->definition['many to one'])) {
$this->helper = new views_many_to_one_helper($this);
// Ensure defaults for these, during summaries and stuff:
$this->operator = 'or';
$this->value = array();
}
}
function option_definition() {
$options = parent::option_definition();
$options['glossary'] = array('default' => FALSE, 'bool' => TRUE);
$options['limit'] = array('default' => 0);
$options['case'] = array('default' => 'none');
$options['path_case'] = array('default' => 'none');
$options['transform_dash'] = array('default' => FALSE, 'bool' => TRUE);
$options['break_phrase'] = array('default' => FALSE, 'bool' => TRUE);
if (!empty($this->definition['many to one'])) {
$options['add_table'] = array('default' => FALSE, 'bool' => TRUE);
$options['require_value'] = array('default' => FALSE, 'bool' => TRUE);
}
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['glossary'] = array(
'#type' => 'checkbox',
'#title' => t('Glossary mode'),
'#description' => t('Glossary mode applies a limit to the number of characters used in the filter value, which allows the summary view to act as a glossary.'),
'#default_value' => $this->options['glossary'],
'#fieldset' => 'more',
);
$form['limit'] = array(
'#type' => 'textfield',
'#title' => t('Character limit'),
'#description' => t('How many characters of the filter value to filter against. If set to 1, all fields starting with the first letter in the filter value would be matched.'),
'#default_value' => $this->options['limit'],
'#dependency' => array('edit-options-glossary' => array(TRUE)),
'#fieldset' => 'more',
);
$form['case'] = array(
'#type' => 'select',
'#title' => t('Case'),
'#description' => t('When printing the title and summary, how to transform the case of the filter value.'),
'#options' => array(
'none' => t('No transform'),
'upper' => t('Upper case'),
'lower' => t('Lower case'),
'ucfirst' => t('Capitalize first letter'),
'ucwords' => t('Capitalize each word'),
),
'#default_value' => $this->options['case'],
'#fieldset' => 'more',
);
$form['path_case'] = array(
'#type' => 'select',
'#title' => t('Case in path'),
'#description' => t('When printing url paths, how to transform the case of the filter value. Do not use this unless with Postgres as it uses case sensitive comparisons.'),
'#options' => array(
'none' => t('No transform'),
'upper' => t('Upper case'),
'lower' => t('Lower case'),
'ucfirst' => t('Capitalize first letter'),
'ucwords' => t('Capitalize each word'),
),
'#default_value' => $this->options['path_case'],
'#fieldset' => 'more',
);
$form['transform_dash'] = array(
'#type' => 'checkbox',
'#title' => t('Transform spaces to dashes in URL'),
'#default_value' => $this->options['transform_dash'],
'#fieldset' => 'more',
);
if (!empty($this->definition['many to one'])) {
$form['add_table'] = array(
'#type' => 'checkbox',
'#title' => t('Allow multiple filter values to work together'),
'#description' => t('If selected, multiple instances of this filter can work together, as though multiple values were supplied to the same filter. This setting is not compatible with the "Reduce duplicates" setting.'),
'#default_value' => !empty($this->options['add_table']),
'#fieldset' => 'more',
);
$form['require_value'] = array(
'#type' => 'checkbox',
'#title' => t('Do not display items with no value in summary'),
'#default_value' => !empty($this->options['require_value']),
'#fieldset' => 'more',
);
}
// allow + for or, , for and
$form['break_phrase'] = array(
'#type' => 'checkbox',
'#title' => t('Allow multiple values'),
'#description' => t('If selected, users can enter multiple values in the form of 1+2+3 (for OR) or 1,2,3 (for AND).'),
'#default_value' => !empty($this->options['break_phrase']),
'#fieldset' => 'more',
);
}
/**
* Build the summary query based on a string
*/
function summary_query() {
if (empty($this->definition['many to one'])) {
$this->ensure_my_table();
}
else {
$this->table_alias = $this->helper->summary_join();
}
if (empty($this->options['glossary'])) {
// Add the field.
$this->base_alias = $this->query->add_field($this->table_alias, $this->real_field);
$this->query->set_count_field($this->table_alias, $this->real_field);
}
else {
// Add the field.
$formula = $this->get_formula();
$this->base_alias = $this->query->add_field(NULL, $formula, $this->field . '_truncated');
$this->query->set_count_field(NULL, $formula, $this->field, $this->field . '_truncated');
}
$this->summary_name_field();
return $this->summary_basics(FALSE);
}
/**
* Get the formula for this argument.
*
* $this->ensure_my_table() MUST have been called prior to this.
*/
function get_formula() {
return "SUBSTRING($this->table_alias.$this->real_field, 1, " . intval($this->options['limit']) . ")";
}
/**
* Build the query based upon the formula
*/
function query($group_by = FALSE) {
$argument = $this->argument;
if (!empty($this->options['transform_dash'])) {
$argument = strtr($argument, '-', ' ');
}
if (!empty($this->options['break_phrase'])) {
views_break_phrase_string($argument, $this);
}
else {
$this->value = array($argument);
$this->operator = 'or';
}
if (!empty($this->definition['many to one'])) {
if (!empty($this->options['glossary'])) {
$this->helper->formula = TRUE;
}
$this->helper->ensure_my_table();
$this->helper->add_filter();
return;
}
$this->ensure_my_table();
$formula = FALSE;
if (empty($this->options['glossary'])) {
$field = "$this->table_alias.$this->real_field";
}
else {
$formula = TRUE;
$field = $this->get_formula();
}
if (count($this->value) > 1) {
$operator = 'IN';
$argument = $this->value;
}
else {
$operator = '=';
}
if ($formula) {
$placeholder = $this->placeholder();
if ($operator == 'IN') {
$field .= " IN($placeholder)";
}
else {
$field .= ' = ' . $placeholder;
}
$placeholders = array(
$placeholder => $argument,
);
$this->query->add_where_expression(0, $field, $placeholders);
}
else {
$this->query->add_where(0, $field, $argument, $operator);
}
}
function summary_argument($data) {
$value = $this->case_transform($data->{$this->base_alias}, $this->options['path_case']);
if (!empty($this->options['transform_dash'])) {
$value = strtr($value, ' ', '-');
}
return $value;
}
function get_sort_name() {
return t('Alphabetical', array(), array('context' => 'Sort order'));
}
function title() {
$this->argument = $this->case_transform($this->argument, $this->options['case']);
if (!empty($this->options['transform_dash'])) {
$this->argument = strtr($this->argument, '-', ' ');
}
if (!empty($this->options['break_phrase'])) {
views_break_phrase_string($this->argument, $this);
}
else {
$this->value = array($this->argument);
$this->operator = 'or';
}
if (empty($this->value)) {
return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
}
if ($this->value === array(-1)) {
return !empty($this->definition['invalid input']) ? $this->definition['invalid input'] : t('Invalid input');
}
return implode($this->operator == 'or' ? ' + ' : ', ', $this->title_query());
}
/**
* Override for specific title lookups.
*/
function title_query() {
return drupal_map_assoc($this->value, 'check_plain');
}
function summary_name($data) {
return $this->case_transform(parent::summary_name($data), $this->options['case']);
}
}
File diff suppressed because it is too large Load Diff
-110
View File
@@ -1,110 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_boolean.
*/
/**
* A handler to provide proper displays for booleans.
*
* Allows for display of true/false, yes/no, on/off, enabled/disabled.
*
* Definition terms:
* - output formats: An array where the first entry is displayed on boolean true
* and the second is displayed on boolean false. An example for sticky is:
* @code
* 'output formats' => array(
* 'sticky' => array(t('Sticky'), ''),
* ),
* @endcode
*
* @ingroup views_field_handlers
*/
class views_handler_field_boolean extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['type'] = array('default' => 'yes-no');
$options['type_custom_true'] = array('default' => '', 'translatable' => TRUE);
$options['type_custom_false'] = array('default' => '', 'translatable' => TRUE);
$options['not'] = array('definition bool' => 'reverse');
return $options;
}
function init(&$view, &$options) {
parent::init($view, $options);
$default_formats = array(
'yes-no' => array(t('Yes'), t('No')),
'true-false' => array(t('True'), t('False')),
'on-off' => array(t('On'), t('Off')),
'enabled-disabled' => array(t('Enabled'), t('Disabled')),
'boolean' => array(1, 0),
'unicode-yes-no' => array('✔', '✖'),
);
$output_formats = isset($this->definition['output formats']) ? $this->definition['output formats'] : array();
$custom_format = array('custom' => array(t('Custom')));
$this->formats = array_merge($default_formats, $output_formats, $custom_format);
}
function options_form(&$form, &$form_state) {
foreach ($this->formats as $key => $item) {
$options[$key] = implode('/', $item);
}
$form['type'] = array(
'#type' => 'select',
'#title' => t('Output format'),
'#options' => $options,
'#default_value' => $this->options['type'],
);
$form['type_custom_true'] = array(
'#type' => 'textfield',
'#title' => t('Custom output for TRUE'),
'#default_value' => $this->options['type_custom_true'],
'#states' => array(
'visible' => array(
'select[name="options[type]"]' => array('value' => 'custom'),
),
),
);
$form['type_custom_false'] = array(
'#type' => 'textfield',
'#title' => t('Custom output for FALSE'),
'#default_value' => $this->options['type_custom_false'],
'#states' => array(
'visible' => array(
'select[name="options[type]"]' => array('value' => 'custom'),
),
),
);
$form['not'] = array(
'#type' => 'checkbox',
'#title' => t('Reverse'),
'#description' => t('If checked, true will be displayed as false.'),
'#default_value' => $this->options['not'],
);
parent::options_form($form, $form_state);
}
function render($values) {
$value = $this->get_value($values);
if (!empty($this->options['not'])) {
$value = !$value;
}
if ($this->options['type'] == 'custom') {
return $value ? filter_xss_admin($this->options['type_custom_true']) : filter_xss_admin($this->options['type_custom_false']);
}
else if (isset($this->formats[$this->options['type']])) {
return $value ? $this->formats[$this->options['type']][0] : $this->formats[$this->options['type']][1];
}
else {
return $value ? $this->formats['yes-no'][0] : $this->formats['yes-no'][1];
}
}
}
@@ -1,102 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_contextual_links.
*/
/**
* Provides a handler that adds contextual links.
*
* @ingroup views_field_handlers
*/
class views_handler_field_contextual_links extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['fields'] = array('default' => array());
$options['destination'] = array('default' => TRUE, 'bool' => TRUE);
return $options;
}
function options_form(&$form, &$form_state) {
$all_fields = $this->view->display_handler->get_field_labels();
// Offer to include only those fields that follow this one.
$field_options = array_slice($all_fields, 0, array_search($this->options['id'], array_keys($all_fields)));
$form['fields'] = array(
'#type' => 'checkboxes',
'#title' => t('Fields'),
'#description' => t('Fields to be included as contextual links.'),
'#options' => $field_options,
'#default_value' => $this->options['fields'],
);
$form['destination'] = array(
'#type' => 'checkbox',
'#title' => t('Include destination'),
'#description' => t('Include a "destination" parameter in the link to return the user to the original view upon completing the contextual action.'),
'#default_value' => $this->options['destination'],
);
}
function pre_render(&$values) {
// Add a row plugin css class for the contextual link.
$class = 'contextual-links-region';
if (!empty($this->view->style_plugin->options['row_class'])) {
$this->view->style_plugin->options['row_class'] .= " $class";
}
else {
$this->view->style_plugin->options['row_class'] = $class;
}
}
/**
* Render the contextual fields.
*/
function render($values) {
$links = array();
foreach ($this->options['fields'] as $field) {
if (empty($this->view->style_plugin->rendered_fields[$this->view->row_index][$field])) {
continue;
}
$title = $this->view->field[$field]->last_render_text;
$path = '';
if (!empty($this->view->field[$field]->options['alter']['path'])) {
$path = $this->view->field[$field]->options['alter']['path'];
}
if (!empty($title) && !empty($path)) {
// Make sure that tokens are replaced for this paths as well.
$tokens = $this->get_render_tokens(array());
$path = strip_tags(decode_entities(strtr($path, $tokens)));
$links[$field] = array(
'href' => $path,
'title' => $title,
);
if (!empty($this->options['destination'])) {
$links[$field]['query'] = drupal_get_destination();
}
}
}
if (!empty($links)) {
$build = array(
'#prefix' => '<div class="contextual-links-wrapper">',
'#suffix' => '</div>',
'#theme' => 'links__contextual',
'#links' => $links,
'#attributes' => array('class' => array('contextual-links')),
'#attached' => array(
'library' => array(array('contextual', 'contextual-links')),
),
'#access' => user_access('access contextual links'),
);
return drupal_render($build);
}
else {
return '';
}
}
function query() { }
}
-50
View File
@@ -1,50 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_counter.
*/
/**
* Field handler to show a counter of the current row.
*
* @ingroup views_field_handlers
*/
class views_handler_field_counter extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['counter_start'] = array('default' => 1);
return $options;
}
function options_form(&$form, &$form_state) {
$form['counter_start'] = array(
'#type' => 'textfield',
'#title' => t('Starting value'),
'#default_value' => $this->options['counter_start'],
'#description' => t('Specify the number the counter should start at.'),
'#size' => 2,
);
parent::options_form($form, $form_state);
}
function query() {
// do nothing -- to override the parent query.
}
function render($values) {
// Note: 1 is subtracted from the counter start value below because the
// counter value is incremented by 1 at the end of this function.
$count = is_numeric($this->options['counter_start']) ? $this->options['counter_start'] - 1 : 0;
$pager = $this->view->query->pager;
// Get the base count of the pager.
if ($pager->use_pager()) {
$count += ($pager->get_items_per_page() * $pager->get_current_page() + $pager->get_offset());
}
// Add the counter for the current site.
$count += $this->view->row_index + 1;
return $count;
}
}
-55
View File
@@ -1,55 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_custom.
*/
/**
* A handler to provide a field that is completely custom by the administrator.
*
* @ingroup views_field_handlers
*/
class views_handler_field_custom extends views_handler_field {
function query() {
// do nothing -- to override the parent query.
}
function option_definition() {
$options = parent::option_definition();
// Override the alter text option to always alter the text.
$options['alter']['contains']['alter_text'] = array('default' => TRUE, 'bool' => TRUE);
$options['hide_alter_empty'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
// Remove the checkbox
unset($form['alter']['alter_text']);
unset($form['alter']['text']['#dependency']);
unset($form['alter']['text']['#process']);
unset($form['alter']['help']['#dependency']);
unset($form['alter']['help']['#process']);
$form['#pre_render'][] = 'views_handler_field_custom_pre_render_move_text';
}
function render($values) {
// Return the text, so the code never thinks the value is empty.
return $this->options['alter']['text'];
}
}
/**
* Prerender function to move the textarea to the top.
*/
function views_handler_field_custom_pre_render_move_text($form) {
$form['text'] = $form['alter']['text'];
$form['help'] = $form['alter']['help'];
unset($form['alter']['text']);
unset($form['alter']['help']);
return $form;
}
-101
View File
@@ -1,101 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_date.
*/
/**
* A handler to provide proper displays for dates.
*
* @ingroup views_field_handlers
*/
class views_handler_field_date extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['date_format'] = array('default' => 'small');
$options['custom_date_format'] = array('default' => '');
$options['timezone'] = array('default' => '');
return $options;
}
function options_form(&$form, &$form_state) {
$date_formats = array();
$date_types = system_get_date_types();
foreach ($date_types as $key => $value) {
$date_formats[$value['type']] = t('@date_format format', array('@date_format' => $value['title'])) . ': ' . format_date(REQUEST_TIME, $value['type']);
}
$form['date_format'] = array(
'#type' => 'select',
'#title' => t('Date format'),
'#options' => $date_formats + array(
'custom' => t('Custom'),
'raw time ago' => t('Time ago'),
'time ago' => t('Time ago (with "ago" appended)'),
'raw time hence' => t('Time hence'),
'time hence' => t('Time hence (with "hence" appended)'),
'raw time span' => t('Time span (future dates have "-" prepended)'),
'inverse time span' => t('Time span (past dates have "-" prepended)'),
'time span' => t('Time span (with "ago/hence" appended)'),
),
'#default_value' => isset($this->options['date_format']) ? $this->options['date_format'] : 'small',
);
$form['custom_date_format'] = array(
'#type' => 'textfield',
'#title' => t('Custom date format'),
'#description' => t('If "Custom", see the <a href="@url" target="_blank">PHP manual</a> for date formats. Otherwise, enter the number of different time units to display, which defaults to 2.', array('@url' => 'http://php.net/manual/function.date.php')),
'#default_value' => isset($this->options['custom_date_format']) ? $this->options['custom_date_format'] : '',
'#dependency' => array('edit-options-date-format' => array('custom', 'raw time ago', 'time ago', 'raw time hence', 'time hence', 'raw time span', 'time span', 'raw time span', 'inverse time span', 'time span')),
);
$form['timezone'] = array(
'#type' => 'select',
'#title' => t('Timezone'),
'#description' => t('Timezone to be used for date output.'),
'#options' => array('' => t('- Default site/user timezone -')) + system_time_zones(FALSE),
'#default_value' => $this->options['timezone'],
'#dependency' => array('edit-options-date-format' => array_merge(array('custom'), array_keys($date_formats))),
);
parent::options_form($form, $form_state);
}
function render($values) {
$value = $this->get_value($values);
$format = $this->options['date_format'];
if (in_array($format, array('custom', 'raw time ago', 'time ago', 'raw time hence', 'time hence', 'raw time span', 'time span', 'raw time span', 'inverse time span', 'time span'))) {
$custom_format = $this->options['custom_date_format'];
}
if ($value) {
$timezone = !empty($this->options['timezone']) ? $this->options['timezone'] : NULL;
$time_diff = REQUEST_TIME - $value; // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence)
switch ($format) {
case 'raw time ago':
return format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2);
case 'time ago':
return t('%time ago', array('%time' => format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2)));
case 'raw time hence':
return format_interval(-$time_diff, is_numeric($custom_format) ? $custom_format : 2);
case 'time hence':
return t('%time hence', array('%time' => format_interval(-$time_diff, is_numeric($custom_format) ? $custom_format : 2)));
case 'raw time span':
return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2);
case 'inverse time span':
return ($time_diff > 0 ? '-' : '') . format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2);
case 'time span':
return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2)));
case 'custom':
if ($custom_format == 'r') {
return format_date($value, $format, $custom_format, $timezone, 'en');
}
return format_date($value, $format, $custom_format, $timezone);
default:
return format_date($value, $format, '', $timezone);
}
}
}
}
-104
View File
@@ -1,104 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_entity.
*/
/**
* A handler to display data from entity objects.
*
* Fields based upon this handler work with all query-backends if the tables
* used by the query backend have an 'entity type' specified. In order to
* make fields based upon this handler automatically available to all compatible
* query backends, the views field can be defined in the table
* @code views_entity_{ENTITY_TYPE} @endcode.
*
* @ingroup views_field_handlers
*/
class views_handler_field_entity extends views_handler_field {
/**
* Stores the entity type which is loaded by this field.
*/
public $entity_type;
/**
* Stores all entites which are in the result.
*/
public $entities;
/**
* The base field of the entity type assosiated with this field.
*/
public $base_field;
/**
* Initialize the entity type.
*/
public function init(&$view, &$options) {
parent::init($view, $options);
// Initialize the entity-type used.
$table_data = views_fetch_data($this->table);
$this->entity_type = $table_data['table']['entity type'];
}
/**
* Overriden to add the field for the entity id.
*/
function query() {
$this->table_alias = $base_table = $this->view->base_table;
$this->base_field = $this->view->base_field;
if (!empty($this->relationship)) {
foreach ($this->view->relationship as $relationship) {
if ($relationship->alias == $this->relationship) {
$base_table = $relationship->definition['base'];
$this->table_alias = $relationship->alias;
$table_data = views_fetch_data($base_table);
$this->base_field = empty($relationship->definition['base field']) ? $table_data['table']['base']['field'] : $relationship->definition['base field'];
}
}
}
// Add the field if the query back-end implements an add_field() method,
// just like the default back-end.
if (method_exists($this->query, 'add_field')) {
$this->field_alias = $this->query->add_field($this->table_alias, $this->base_field, '');
}
$this->add_additional_fields();
}
/**
* Load the entities for all rows that are about to be displayed.
*/
function pre_render(&$values) {
if (!empty($values)) {
list($this->entity_type, $this->entities) = $this->query->get_result_entities($values, !empty($this->relationship) ? $this->relationship : NULL, $this->field_alias);
}
}
/**
* Overridden to return the entity object, or a certain property of the entity.
*/
function get_value($values, $field = NULL) {
if (isset($this->entities[$this->view->row_index])) {
$entity = $this->entities[$this->view->row_index];
// Support to get a certain part of the entity.
if (isset($field) && isset($entity->{$field})) {
return $entity->{$field};
}
// Support to get a part of the values as the normal get_value.
elseif (isset($field) && isset($values->{$this->aliases[$field]})) {
return $values->{$this->aliases[$field]};
}
else {
return $entity;
}
}
return FALSE;
}
}
@@ -1,73 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_machine_name.
*/
/**
* Field handler whichs allows to show machine name content as human name.
* @ingroup views_field_handlers
*
* Definition items:
* - options callback: The function to call in order to generate the value options. If omitted, the options 'Yes' and 'No' will be used.
* - options arguments: An array of arguments to pass to the options callback.
*/
class views_handler_field_machine_name extends views_handler_field {
/**
* @var array Stores the available options.
*/
var $value_options;
function get_value_options() {
if (isset($this->value_options)) {
return;
}
if (isset($this->definition['options callback']) && is_callable($this->definition['options callback'])) {
if (isset($this->definition['options arguments']) && is_array($this->definition['options arguments'])) {
$this->value_options = call_user_func_array($this->definition['options callback'], $this->definition['options arguments']);
}
else {
$this->value_options = call_user_func($this->definition['options callback']);
}
}
else {
$this->value_options = array();
}
}
function option_definition() {
$options = parent::option_definition();
$options['machine_name'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['machine_name'] = array(
'#title' => t('Output machine name'),
'#description' => t('Display field as machine name.'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['machine_name']),
);
}
function pre_render(&$values) {
$this->get_value_options();
}
function render($values) {
$value = $values->{$this->field_alias};
if (!empty($this->options['machine_name']) || !isset($this->value_options[$value])) {
$result = check_plain($value);
}
else {
$result = $this->value_options[$value];
}
return $result;
}
}
-59
View File
@@ -1,59 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_markup.
*/
/**
* A handler to run a field through check_markup, using a companion
* format field.
*
* - format: (REQUIRED) Either a string format id to use for this field or an
* array('field' => {$field}) where $field is the field in this table
* used to control the format such as the 'format' field in the node,
* which goes with the 'body' field.
*
* @ingroup views_field_handlers
*/
class views_handler_field_markup extends views_handler_field {
/**
* Constructor; calls to base object constructor.
*/
function construct() {
parent::construct();
$this->format = $this->definition['format'];
$this->additional_fields = array();
if (is_array($this->format)) {
$this->additional_fields['format'] = $this->format;
}
}
function render($values) {
$value = $this->get_value($values);
if (is_array($this->format)) {
$format = $this->get_value($values, 'format');
}
else {
$format = $this->format;
}
if ($value) {
$value = str_replace('<!--break-->', '', $value);
return check_markup($value, $format, '');
}
}
function element_type($none_supported = FALSE, $default_empty = FALSE, $inline = FALSE) {
if ($inline) {
return 'span';
}
if (isset($this->definition['element type'])) {
return $this->definition['element type'];
}
return 'div';
}
}
-84
View File
@@ -1,84 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_math.
*/
/**
* Render a mathematical expression as a numeric value
*
* Definition terms:
* - float: If true this field contains a decimal value. If unset this field
* will be assumed to be integer.
*
* @ingroup views_field_handlers
*/
class views_handler_field_math extends views_handler_field_numeric {
function option_definition() {
$options = parent::option_definition();
$options['expression'] = array('default' => '');
return $options;
}
function options_form(&$form, &$form_state) {
$form['expression'] = array(
'#type' => 'textarea',
'#title' => t('Expression'),
'#description' => t('Enter mathematical expressions such as 2 + 2 or sqrt(5). You may assign variables and create mathematical functions and evaluate them. Use the ; to separate these. For example: f(x) = x + 2; f(2).'),
'#default_value' => $this->options['expression'],
);
// Create a place for the help
$form['expression_help'] = array();
parent::options_form($form, $form_state);
// Then move the existing help:
$form['expression_help'] = $form['alter']['help'];
unset($form['expression_help']['#dependency']);
unset($form['alter']['help']);
}
function render($values) {
ctools_include('math-expr');
$tokens = array_map('floatval', $this->get_render_tokens(array()));
$value = strtr($this->options['expression'], $tokens);
$expressions = explode(';', $value);
$math = new ctools_math_expr;
foreach ($expressions as $expression) {
if ($expression !== '') {
$value = $math->evaluate($expression);
}
}
// The rest is directly from views_handler_field_numeric but because it
// does not allow the value to be passed in, it is copied.
if (!empty($this->options['set_precision'])) {
$value = number_format($value, $this->options['precision'], $this->options['decimal'], $this->options['separator']);
}
else {
$remainder = abs($value) - intval(abs($value));
$value = $value > 0 ? floor($value) : ceil($value);
$value = number_format($value, 0, '', $this->options['separator']);
if ($remainder) {
// The substr may not be locale safe.
$value .= $this->options['decimal'] . substr($remainder, 2);
}
}
// Check to see if hiding should happen before adding prefix and suffix.
if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
return '';
}
// Should we format as a plural.
if (!empty($this->options['format_plural']) && ($value != 0 || !$this->options['empty_zero'])) {
$value = format_plural($value, $this->options['format_plural_singular'], $this->options['format_plural_plural']);
}
return $this->sanitize_value($this->options['prefix'] . $value . $this->options['suffix']);
}
function query() { }
}
-137
View File
@@ -1,137 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_numeric.
*/
/**
* Render a field as a numeric value
*
* Definition terms:
* - float: If true this field contains a decimal value. If unset this field
* will be assumed to be integer.
*
* @ingroup views_field_handlers
*/
class views_handler_field_numeric extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['set_precision'] = array('default' => FALSE, 'bool' => TRUE);
$options['precision'] = array('default' => 0);
$options['decimal'] = array('default' => '.', 'translatable' => TRUE);
$options['separator'] = array('default' => ',', 'translatable' => TRUE);
$options['format_plural'] = array('default' => FALSE, 'bool' => TRUE);
$options['format_plural_singular'] = array('default' => '1');
$options['format_plural_plural'] = array('default' => '@count');
$options['prefix'] = array('default' => '', 'translatable' => TRUE);
$options['suffix'] = array('default' => '', 'translatable' => TRUE);
return $options;
}
function options_form(&$form, &$form_state) {
if (!empty($this->definition['float'])) {
$form['set_precision'] = array(
'#type' => 'checkbox',
'#title' => t('Round'),
'#description' => t('If checked, the number will be rounded.'),
'#default_value' => $this->options['set_precision'],
);
$form['precision'] = array(
'#type' => 'textfield',
'#title' => t('Precision'),
'#default_value' => $this->options['precision'],
'#description' => t('Specify how many digits to print after the decimal point.'),
'#dependency' => array('edit-options-set-precision' => array(TRUE)),
'#size' => 2,
);
$form['decimal'] = array(
'#type' => 'textfield',
'#title' => t('Decimal point'),
'#default_value' => $this->options['decimal'],
'#description' => t('What single character to use as a decimal point.'),
'#size' => 2,
);
}
$form['separator'] = array(
'#type' => 'select',
'#title' => t('Thousands marker'),
'#options' => array(
'' => t('- None -'),
',' => t('Comma'),
' ' => t('Space'),
'.' => t('Decimal'),
'\'' => t('Apostrophe'),
),
'#default_value' => $this->options['separator'],
'#description' => t('What single character to use as the thousands separator.'),
'#size' => 2,
);
$form['format_plural'] = array(
'#type' => 'checkbox',
'#title' => t('Format plural'),
'#description' => t('If checked, special handling will be used for plurality.'),
'#default_value' => $this->options['format_plural'],
);
$form['format_plural_singular'] = array(
'#type' => 'textfield',
'#title' => t('Singular form'),
'#default_value' => $this->options['format_plural_singular'],
'#description' => t('Text to use for the singular form.'),
'#dependency' => array('edit-options-format-plural' => array(TRUE)),
);
$form['format_plural_plural'] = array(
'#type' => 'textfield',
'#title' => t('Plural form'),
'#default_value' => $this->options['format_plural_plural'],
'#description' => t('Text to use for the plural form, @count will be replaced with the value.'),
'#dependency' => array('edit-options-format-plural' => array(TRUE)),
);
$form['prefix'] = array(
'#type' => 'textfield',
'#title' => t('Prefix'),
'#default_value' => $this->options['prefix'],
'#description' => t('Text to put before the number, such as currency symbol.'),
);
$form['suffix'] = array(
'#type' => 'textfield',
'#title' => t('Suffix'),
'#default_value' => $this->options['suffix'],
'#description' => t('Text to put after the number, such as currency symbol.'),
);
parent::options_form($form, $form_state);
}
function render($values) {
$value = $this->get_value($values);
if (!empty($this->options['set_precision'])) {
$value = number_format($value, $this->options['precision'], $this->options['decimal'], $this->options['separator']);
}
else {
$remainder = abs($value) - intval(abs($value));
$value = $value > 0 ? floor($value) : ceil($value);
$value = number_format($value, 0, '', $this->options['separator']);
if ($remainder) {
// The substr may not be locale safe.
$value .= $this->options['decimal'] . substr($remainder, 2);
}
}
// Check to see if hiding should happen before adding prefix and suffix.
if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
return '';
}
// Should we format as a plural.
if (!empty($this->options['format_plural'])) {
$value = format_plural($value, $this->options['format_plural_singular'], $this->options['format_plural_plural']);
}
return $this->sanitize_value($this->options['prefix'], 'xss')
. $this->sanitize_value($value)
. $this->sanitize_value($this->options['suffix'], 'xss');
}
}
@@ -1,158 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_prerender_list.
*/
/**
* Field handler to provide a list of items.
*
* The items are expected to be loaded by a child object during pre_render,
* and 'my field' is expected to be the pointer to the items in the list.
*
* Items to render should be in a list in $this->items
*
* @ingroup views_field_handlers
*/
class views_handler_field_prerender_list extends views_handler_field {
/**
* Stores all items which are used to render the items.
* It should be keyed first by the id of the base table, for example nid.
* The second key is the id of the thing which is displayed multiple times
* per row, for example the tid.
*
* @var array
*/
var $items = array();
function option_definition() {
$options = parent::option_definition();
$options['type'] = array('default' => 'separator');
$options['separator'] = array('default' => ', ');
return $options;
}
function options_form(&$form, &$form_state) {
$form['type'] = array(
'#type' => 'radios',
'#title' => t('Display type'),
'#options' => array(
'ul' => t('Unordered list'),
'ol' => t('Ordered list'),
'separator' => t('Simple separator'),
),
'#default_value' => $this->options['type'],
);
$form['separator'] = array(
'#type' => 'textfield',
'#title' => t('Separator'),
'#default_value' => $this->options['separator'],
'#dependency' => array('radio:options[type]' => array('separator')),
);
parent::options_form($form, $form_state);
}
/**
* Render the field.
*
* This function is deprecated, but left in for older systems that have not
* yet or won't update their prerender list fields. If a render_item method
* exists, this will not get used by advanced_render.
*/
function render($values) {
$field = $this->get_value($values);
if (!empty($this->items[$field])) {
if ($this->options['type'] == 'separator') {
return implode($this->sanitize_value($this->options['separator']), $this->items[$field]);
}
else {
return theme('item_list',
array(
'items' => $this->items[$field],
'title' => NULL,
'type' => $this->options['type']
));
}
}
}
/**
* Render all items in this field together.
*
* When using advanced render, each possible item in the list is rendered
* individually. Then the items are all pasted together.
*/
function render_items($items) {
if (!empty($items)) {
if ($this->options['type'] == 'separator') {
return implode($this->sanitize_value($this->options['separator'], 'xss_admin'), $items);
}
else {
return theme('item_list',
array(
'items' => $items,
'title' => NULL,
'type' => $this->options['type']
));
}
}
}
/**
* Return an array of items for the field.
*
* Items should be stored in the result array, if possible, as an array
* with 'value' as the actual displayable value of the item, plus
* any items that might be found in the 'alter' options array for
* creating links, such as 'path', 'fragment', 'query' etc, such a thing
* is to be made. Additionally, items that might be turned into tokens
* should also be in this array.
*/
function get_items($values) {
// Only the parent get_value returns a single field.
$field = parent::get_value($values);
if (!empty($this->items[$field])) {
return $this->items[$field];
}
return array();
}
/**
* Get the value that's supposed to be rendered.
*
* @param $values
* An object containing all retrieved values.
* @param $field
* Optional name of the field where the value is stored.
* @param $raw
* Use the raw data and not the data defined in pre_render
*/
function get_value($values, $field = NULL, $raw = FALSE) {
if ($raw) {
return parent::get_value($values, $field);
}
$item = $this->get_items($values);
$item = (array) $item;
if (isset($field) && isset($item[$field])) {
return $item[$field];
}
return $item;
}
/**
* Determine if advanced rendering is allowed.
*
* By default, advanced rendering will NOT be allowed if the class
* inheriting from this does not implement a 'render_items' method.
*/
function allow_advanced_render() {
// Note that the advanced render bits also use the presence of
// this method to determine if it needs to render items as a list.
return method_exists($this, 'render_item');
}
}
@@ -1,65 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_serialized.
*/
/**
* Field handler to show data of serialized fields.
*
* @ingroup views_field_handlers
*/
class views_handler_field_serialized extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['format'] = array('default' => 'unserialized');
$options['key'] = array('default' => '');
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['format'] = array(
'#type' => 'select',
'#title' => t('Display format'),
'#description' => t('How should the serialized data be displayed. You can choose a custom array/object key or a print_r on the full output.'),
'#options' => array(
'unserialized' => t('Full data (unserialized)'),
'serialized' => t('Full data (serialized)'),
'key' => t('A certain key'),
),
'#default_value' => $this->options['format'],
);
$form['key'] = array(
'#type' => 'textfield',
'#title' => t('Which key should be displayed'),
'#default_value' => $this->options['key'],
'#dependency' => array('edit-options-format' => array('key')),
);
}
function options_validate(&$form, &$form_state) {
// Require a key if the format is key.
if ($form_state['values']['options']['format'] == 'key' && $form_state['values']['options']['key'] == '') {
form_error($form['key'], t('You have to enter a key if you want to display a key of the data.'));
}
}
function render($values) {
$value = $values->{$this->field_alias};
if ($this->options['format'] == 'unserialized') {
return check_plain(print_r(unserialize($value), TRUE));
}
elseif ($this->options['format'] == 'key' && !empty($this->options['key'])) {
$value = (array) unserialize($value);
return check_plain($value[$this->options['key']]);
}
return $value;
}
}
@@ -1,37 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_time_interval.
*/
/**
* A handler to provide proper displays for time intervals.
*
* @ingroup views_field_handlers
*/
class views_handler_field_time_interval extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['granularity'] = array('default' => 2);
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['granularity'] = array(
'#type' => 'textfield',
'#title' => t('Granularity'),
'#description' => t('How many different units to display in the string.'),
'#default_value' => $this->options['granularity'],
);
}
function render($values) {
$value = $values->{$this->field_alias};
return format_interval($value, isset($this->options['granularity']) ? $this->options['granularity'] : 2);
}
}
-46
View File
@@ -1,46 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_field_url.
*/
/**
* Field handler to provide simple renderer that turns a URL into a clickable link.
*
* @ingroup views_field_handlers
*/
class views_handler_field_url extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['display_as_link'] = array('default' => TRUE, 'bool' => TRUE);
return $options;
}
/**
* Provide link to the page being visited.
*/
function options_form(&$form, &$form_state) {
$form['display_as_link'] = array(
'#title' => t('Display as link'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['display_as_link']),
);
parent::options_form($form, $form_state);
}
function render($values) {
$value = $this->get_value($values);
if (!empty($this->options['display_as_link'])) {
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['path'] = $value;
$text = !empty($this->options['text']) ? $this->sanitize_value($this->options['text']) : $this->sanitize_value($value, 'url');
return $text;
}
else {
return $this->sanitize_value($value, 'url');
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,179 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_boolean_operator.
*/
/**
* Simple filter to handle matching of boolean values
*
* Definition items:
* - label: (REQUIRED) The label for the checkbox.
* - type: For basic 'true false' types, an item can specify the following:
* - true-false: True/false (this is the default)
* - yes-no: Yes/No
* - on-off: On/Off
* - enabled-disabled: Enabled/Disabled
* - accept null: Treat a NULL value as false.
* - use equal: If you use this flag the query will use = 1 instead of <> 0.
* This might be helpful for performance reasons.
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_boolean_operator extends views_handler_filter {
// exposed filter options
var $always_multiple = TRUE;
// Don't display empty space where the operator would be.
var $no_operator = TRUE;
// Whether to accept NULL as a false value or not
var $accept_null = FALSE;
function construct() {
$this->value_value = t('True');
if (isset($this->definition['label'])) {
$this->value_value = $this->definition['label'];
}
if (isset($this->definition['accept null'])) {
$this->accept_null = (bool) $this->definition['accept null'];
}
else if (isset($this->definition['accept_null'])) {
$this->accept_null = (bool) $this->definition['accept_null'];
}
$this->value_options = NULL;
parent::construct();
}
/**
* Return the possible options for this filter.
*
* Child classes should override this function to set the possible values
* for the filter. Since this is a boolean filter, the array should have
* two possible keys: 1 for "True" and 0 for "False", although the labels
* can be whatever makes sense for the filter. These values are used for
* configuring the filter, when the filter is exposed, and in the admin
* summary of the filter. Normally, this should be static data, but if it's
* dynamic for some reason, child classes should use a guard to reduce
* database hits as much as possible.
*/
function get_value_options() {
if (isset($this->definition['type'])) {
if ($this->definition['type'] == 'yes-no') {
$this->value_options = array(1 => t('Yes'), 0 => t('No'));
}
if ($this->definition['type'] == 'on-off') {
$this->value_options = array(1 => t('On'), 0 => t('Off'));
}
if ($this->definition['type'] == 'enabled-disabled') {
$this->value_options = array(1 => t('Enabled'), 0 => t('Disabled'));
}
}
// Provide a fallback if the above didn't set anything.
if (!isset($this->value_options)) {
$this->value_options = array(1 => t('True'), 0 => t('False'));
}
}
function option_definition() {
$options = parent::option_definition();
$options['value']['default'] = FALSE;
return $options;
}
function operator_form(&$form, &$form_state) {
$form['operator'] = array();
}
function value_form(&$form, &$form_state) {
if (empty($this->value_options)) {
// Initialize the array of possible values for this filter.
$this->get_value_options();
}
if (!empty($form_state['exposed'])) {
// Exposed filter: use a select box to save space.
$filter_form_type = 'select';
}
else {
// Configuring a filter: use radios for clarity.
$filter_form_type = 'radios';
}
$form['value'] = array(
'#type' => $filter_form_type,
'#title' => $this->value_value,
'#options' => $this->value_options,
'#default_value' => $this->value,
);
if (!empty($this->options['exposed'])) {
$identifier = $this->options['expose']['identifier'];
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
$form_state['input'][$identifier] = $this->value;
}
// If we're configuring an exposed filter, add an <Any> option.
if (empty($form_state['exposed']) || empty($this->options['expose']['required'])) {
$any_label = variable_get('views_exposed_filter_any_label', 'new_any') == 'old_any' ? '<Any>' : t('- Any -');
if ($form['value']['#type'] != 'select') {
$any_label = check_plain($any_label);
}
$form['value']['#options'] = array('All' => $any_label) + $form['value']['#options'];
}
}
}
function value_validate($form, &$form_state) {
if ($form_state['values']['options']['value'] == 'All' && !empty($form_state['values']['options']['expose']['required'])) {
form_set_error('value', t('You must select a value unless this is an non-required exposed filter.'));
}
}
function admin_summary() {
if ($this->is_a_group()) {
return t('grouped');
}
if (!empty($this->options['exposed'])) {
return t('exposed');
}
if (empty($this->value_options)) {
$this->get_value_options();
}
// Now that we have the valid options for this filter, just return the
// human-readable label based on the current value. The value_options
// array is keyed with either 0 or 1, so if the current value is not
// empty, use the label for 1, and if it's empty, use the label for 0.
return $this->value_options[!empty($this->value)];
}
function expose_options() {
parent::expose_options();
$this->options['expose']['operator_id'] = '';
$this->options['expose']['label'] = $this->value_value;
$this->options['expose']['required'] = TRUE;
}
function query() {
$this->ensure_my_table();
$field = "$this->table_alias.$this->real_field";
if (empty($this->value)) {
if ($this->accept_null) {
$or = db_or()
->condition($field, 0, '=')
->condition($field, NULL, 'IS NULL');
$this->query->add_where($this->options['group'], $or);
}
else {
$this->query->add_where($this->options['group'], $field, 0, '=');
}
}
else {
if (!empty($this->definition['use equal'])) {
$this->query->add_where($this->options['group'], $field, 1, '=');
}
else {
$this->query->add_where($this->options['group'], $field, 0, '<>');
}
}
}
}
@@ -1,35 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_boolean_operator_string.
*/
/**
* Simple filter to handle matching of boolean values.
*
* This handler checks to see if a string field is empty (equal to '') or not.
* It is otherwise identical to the parent operator.
*
* Definition items:
* - label: (REQUIRED) The label for the checkbox.
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_boolean_operator_string extends views_handler_filter_boolean_operator {
function query() {
$this->ensure_my_table();
$where = "$this->table_alias.$this->real_field ";
if (empty($this->value)) {
$where .= "= ''";
if ($this->accept_null) {
$where = '(' . $where . " OR $this->table_alias.$this->real_field IS NULL)";
}
}
else {
$where .= "<> ''";
}
$this->query->add_where($this->options['group'], $where);
}
}
-170
View File
@@ -1,170 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_combine.
*/
/**
* Filter handler which allows to search on multiple fields.
*
* @ingroup views_field_handlers
*/
class views_handler_filter_combine extends views_handler_filter_string {
/**
* @var views_plugin_query_default
*/
public $query;
function option_definition() {
$options = parent::option_definition();
$options['fields'] = array('default' => array());
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$this->view->init_style();
// Allow to choose all fields as possible.
if ($this->view->style_plugin->uses_fields()) {
$options = array();
foreach ($this->view->display_handler->get_handlers('field') as $name => $field) {
$options[$name] = $field->ui_name(TRUE);
}
if ($options) {
$form['fields'] = array(
'#type' => 'select',
'#title' => t('Choose fields to combine for filtering'),
'#description' => t("This filter doesn't work for very special field handlers."),
'#multiple' => TRUE,
'#options' => $options,
'#default_value' => $this->options['fields'],
);
}
else {
form_set_error('', t('You have to add some fields to be able to use this filter.'));
}
}
}
function query() {
$this->view->_build('field');
$fields = array();
// Only add the fields if they have a proper field and table alias.
foreach ($this->options['fields'] as $id) {
$field = $this->view->field[$id];
// Always add the table of the selected fields to be sure a table alias
// exists.
$field->ensure_my_table();
if (!empty($field->field_alias) && !empty($field->field_alias)) {
$fields[] = "$field->table_alias.$field->real_field";
}
}
if ($fields) {
$count = count($fields);
$separated_fields = array();
foreach ($fields as $key => $field) {
$separated_fields[] = $field;
if ($key < $count - 1) {
$separated_fields[] = "' '";
}
}
$expression = implode(', ', $separated_fields);
$expression = "CONCAT_WS(' ', $expression)";
$info = $this->operators();
if (!empty($info[$this->operator]['method'])) {
$this->{$info[$this->operator]['method']}($expression);
}
}
}
// By default things like op_equal uses add_where, that doesn't support
// complex expressions, so override all operators.
function op_equal($field) {
$placeholder = $this->placeholder();
$operator = $this->operator();
$this->query->add_where_expression($this->options['group'], "$field $operator $placeholder", array($placeholder => $this->value));
}
function op_contains($field) {
$placeholder = $this->placeholder();
$this->query->add_where_expression($this->options['group'], "$field LIKE $placeholder", array($placeholder => '%' . db_like($this->value) . '%'));
}
function op_word($field) {
$where = $this->operator == 'word' ? db_or() : db_and();
// Don't filter on empty strings.
if (empty($this->value)) {
return;
}
preg_match_all('/ (-?)("[^"]+"|[^" ]+)/i', ' ' . $this->value, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$phrase = FALSE;
// Strip off phrase quotes.
if ($match[2]{0} == '"') {
$match[2] = substr($match[2], 1, -1);
$phrase = TRUE;
}
$words = trim($match[2], ',?!();:-');
$words = $phrase ? array($words) : preg_split('/ /', $words, -1, PREG_SPLIT_NO_EMPTY);
$placeholder = $this->placeholder();
foreach ($words as $word) {
$where->where($field . " LIKE $placeholder", array($placeholder => '%' . db_like(trim($word, " ,!?")) . '%'));
}
}
if (!$where) {
return;
}
// Previously this was a call_user_func_array() but that's unnecessary
// as views will unpack an array that is a single arg.
$this->query->add_where($this->options['group'], $where);
}
function op_starts($field) {
$placeholder = $this->placeholder();
$this->query->add_where_expression($this->options['group'], "$field LIKE $placeholder", array($placeholder => db_like($this->value) . '%'));
}
function op_not_starts($field) {
$placeholder = $this->placeholder();
$this->query->add_where_expression($this->options['group'], "$field NOT LIKE $placeholder", array($placeholder => db_like($this->value) . '%'));
}
function op_ends($field) {
$placeholder = $this->placeholder();
$this->query->add_where_expression($this->options['group'], "$field LIKE $placeholder", array($placeholder => '%' . db_like($this->value)));
}
function op_not_ends($field) {
$placeholder = $this->placeholder();
$this->query->add_where_expression($this->options['group'], "$field NOT LIKE $placeholder", array($placeholder => '%' . db_like($this->value)));
}
function op_not($field) {
$placeholder = $this->placeholder();
$this->query->add_where_expression($this->options['group'], "$field NOT LIKE $placeholder", array($placeholder => '%' . db_like($this->value) . '%'));
}
function op_regex($field) {
$placeholder = $this->placeholder();
$this->query->add_where_expression($this->options['group'], "$field RLIKE $placeholder", array($placeholder => $this->value));
}
function op_empty($field) {
if ($this->operator == 'empty') {
$operator = "IS NULL";
}
else {
$operator = "IS NOT NULL";
}
$this->query->add_where_expression($this->options['group'], "$field $operator");
}
}
-183
View File
@@ -1,183 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_date.
*/
/**
* Filter to handle dates stored as a timestamp.
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_date extends views_handler_filter_numeric {
function option_definition() {
$options = parent::option_definition();
// value is already set up properly, we're just adding our new field to it.
$options['value']['contains']['type']['default'] = 'date';
return $options;
}
/**
* Add a type selector to the value form
*/
function value_form(&$form, &$form_state) {
if (empty($form_state['exposed'])) {
$form['value']['type'] = array(
'#type' => 'radios',
'#title' => t('Value type'),
'#options' => array(
'date' => t('A date in any machine readable format. CCYY-MM-DD HH:MM:SS is preferred.'),
'offset' => t('An offset from the current time such as "!example1" or "!example2"', array('!example1' => '+1 day', '!example2' => '-2 hours -30 minutes')),
),
'#default_value' => !empty($this->value['type']) ? $this->value['type'] : 'date',
);
}
parent::value_form($form, $form_state);
}
function options_validate(&$form, &$form_state) {
parent::options_validate($form, $form_state);
if (!empty($this->options['exposed']) && empty($form_state['values']['options']['expose']['required'])) {
// Who cares what the value is if it's exposed and non-required.
return;
}
$this->validate_valid_time($form['value'], $form_state['values']['options']['operator'], $form_state['values']['options']['value']);
}
function exposed_validate(&$form, &$form_state) {
if (empty($this->options['exposed'])) {
return;
}
if (empty($this->options['expose']['required'])) {
// Who cares what the value is if it's exposed and non-required.
return;
}
$value = &$form_state['values'][$this->options['expose']['identifier']];
if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id'])) {
$operator = $form_state['values'][$this->options['expose']['operator_id']];
}
else {
$operator = $this->operator;
}
$this->validate_valid_time($this->options['expose']['identifier'], $operator, $value);
}
/**
* Validate that the time values convert to something usable.
*/
function validate_valid_time(&$form, $operator, $value) {
$operators = $this->operators();
if ($operators[$operator]['values'] == 1) {
$convert = strtotime($value['value']);
if (!empty($form['value']) && ($convert == -1 || $convert === FALSE)) {
form_error($form['value'], t('Invalid date format.'));
}
}
elseif ($operators[$operator]['values'] == 2) {
$min = strtotime($value['min']);
if ($min == -1 || $min === FALSE) {
form_error($form['min'], t('Invalid date format.'));
}
$max = strtotime($value['max']);
if ($max == -1 || $max === FALSE) {
form_error($form['max'], t('Invalid date format.'));
}
}
}
/**
* Validate the build group options form.
*/
function build_group_validate($form, &$form_state) {
// Special case to validate grouped date filters, this is because the
// $group['value'] array contains the type of filter (date or offset)
// and therefore the number of items the comparission has to be done
// against 'one' instead of 'zero'.
foreach ($form_state['values']['options']['group_info']['group_items'] as $id => $group) {
if (empty($group['remove'])) {
// Check if the title is defined but value wasn't defined.
if (!empty($group['title'])) {
if ((!is_array($group['value']) && empty($group['value'])) || (is_array($group['value']) && count(array_filter($group['value'])) == 1)) {
form_error($form['group_info']['group_items'][$id]['value'], t('The value is required if title for this item is defined.'));
}
}
// Check if the value is defined but title wasn't defined.
if ((!is_array($group['value']) && !empty($group['value'])) || (is_array($group['value']) && count(array_filter($group['value'])) > 1)) {
if (empty($group['title'])) {
form_error($form['group_info']['group_items'][$id]['title'], t('The title is required if value for this item is defined.'));
}
}
}
}
}
function accept_exposed_input($input) {
if (empty($this->options['exposed'])) {
return TRUE;
}
// Store this because it will get overwritten.
$type = $this->value['type'];
$rc = parent::accept_exposed_input($input);
// Don't filter if value(s) are empty.
$operators = $this->operators();
if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id'])) {
$operator = $input[$this->options['expose']['operator_id']];
}
else {
$operator = $this->operator;
}
if ($operators[$operator]['values'] == 1) {
if ($this->value['value'] == '') {
return FALSE;
}
}
else {
if ($this->value['min'] == '' || $this->value['max'] == '') {
return FALSE;
}
}
// restore what got overwritten by the parent.
$this->value['type'] = $type;
return $rc;
}
function op_between($field) {
$a = intval(strtotime($this->value['min'], 0));
$b = intval(strtotime($this->value['max'], 0));
if ($this->value['type'] == 'offset') {
$a = '***CURRENT_TIME***' . sprintf('%+d', $a); // keep sign
$b = '***CURRENT_TIME***' . sprintf('%+d', $b); // keep sign
}
// This is safe because we are manually scrubbing the values.
// It is necessary to do it this way because $a and $b are formulas when using an offset.
$operator = strtoupper($this->operator);
$this->query->add_where_expression($this->options['group'], "$field $operator $a AND $b");
}
function op_simple($field) {
$value = intval(strtotime($this->value['value'], 0));
if (!empty($this->value['type']) && $this->value['type'] == 'offset') {
$value = '***CURRENT_TIME***' . sprintf('%+d', $value); // keep sign
}
// This is safe because we are manually scrubbing the value.
// It is necessary to do it this way because $value is a formula when using an offset.
$this->query->add_where_expression($this->options['group'], "$field $this->operator $value");
}
}
@@ -1,122 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_entity_bundle
*/
/**
* Filter class which allows to filter by certain bundles of an entity.
*
* This class provides workarounds for taxonomy and comment.
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_entity_bundle extends views_handler_filter_in_operator {
/**
* Stores the entity type on which the filter filters.
*
* @var string
*/
public $entity_type;
function init(&$view, &$options) {
parent::init($view, $options);
$this->get_entity_type();
}
/**
* Set and returns the entity_type.
*
* @return string
* The entity type on the filter.
*/
function get_entity_type() {
if (!isset($this->entity_type)) {
$data = views_fetch_data($this->table);
if (isset($data['table']['entity type'])) {
$this->entity_type = $data['table']['entity type'];
}
// If the current filter is under a relationship you can't be sure that the
// entity type of the view is the entity type of the current filter
// For example a filter from a node author on a node view does have users as entity type.
if (!empty($this->options['relationship']) && $this->options['relationship'] != 'none') {
$relationships = $this->view->display_handler->get_option('relationships');
if (!empty($relationships[$this->options['relationship']])) {
$options = $relationships[$this->options['relationship']];
$data = views_fetch_data($options['table']);
$this->entity_type = $data['table']['entity type'];
}
}
}
return $this->entity_type;
}
function get_value_options() {
if (!isset($this->value_options)) {
$info = entity_get_info($this->entity_type);
$types = $info['bundles'];
$this->value_title = t('@entity types', array('@entity' => $info['label']));
$options = array();
foreach ($types as $type => $info) {
$options[$type] = t($info['label']);
}
asort($options);
$this->value_options = $options;
}
}
/**
* All entity types beside comment and taxonomy terms have a proper implement
* bundle, though these two need an additional join to node/vocab table
* to work as required.
*/
function query() {
$this->ensure_my_table();
// Adjust the join for the comment case.
if ($this->entity_type == 'comment') {
$join = new views_join();
$def = array(
'table' => 'node',
'field' => 'nid',
'left_table' => $this->table_alias,
'left_field' => 'nid',
);
$join->definition = $def;
$join->construct();
$join->adjusted = TRUE;
$this->table_alias = $this->query->add_table('node', $this->relationship, $join);
$this->real_field = 'type';
// Replace the value to match the node type column.
foreach ($this->value as &$value) {
$value = str_replace('comment_node_', '', $value);
}
}
elseif ($this->entity_type == 'taxonomy_term') {
$join = new views_join();
$def = array(
'table' => 'taxonomy_vocabulary',
'field' => 'vid',
'left_table' => $this->table_alias,
'left_field' => 'vid',
);
$join->definition = $def;
$join->construct();
$join->adjusted = TRUE;
$this->table_alias = $this->query->add_table('taxonomy_vocabulary', $this->relationship, $join);
$this->real_field = 'machine_name';
}
else {
$entity_info = entity_get_info($this->entity_type);
$this->real_field = $entity_info['bundle keys']['bundle'];
}
parent::query();
}
}
@@ -1,45 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_equality.
*/
/**
* Simple filter to handle equal to / not equal to filters
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_equality extends views_handler_filter {
// exposed filter options
var $always_multiple = TRUE;
/**
* Provide simple equality operator
*/
function operator_options() {
return array(
'=' => t('Is equal to'),
'!=' => t('Is not equal to'),
);
}
/**
* Provide a simple textfield for equality
*/
function value_form(&$form, &$form_state) {
$form['value'] = array(
'#type' => 'textfield',
'#title' => t('Value'),
'#size' => 30,
'#default_value' => $this->value,
);
if (!empty($form_state['exposed'])) {
$identifier = $this->options['expose']['identifier'];
if (!isset($form_state['input'][$identifier])) {
$form_state['input'][$identifier] = $this->value;
}
}
}
}
@@ -1,56 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_group_by_numeric.
*/
/**
* Simple filter to handle greater than/less than filters
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_group_by_numeric extends views_handler_filter_numeric {
function query() {
$this->ensure_my_table();
$field = $this->get_field();
$info = $this->operators();
if (!empty($info[$this->operator]['method'])) {
$this->{$info[$this->operator]['method']}($field);
}
}
function op_between($field) {
$placeholder_min = $this->placeholder();
$placeholder_max = $this->placeholder();
if ($this->operator == 'between') {
$this->query->add_having_expression($this->options['group'], "$field >= $placeholder_min", array($placeholder_min => $this->value['min']));
$this->query->add_having_expression($this->options['group'], "$field <= $placeholder_max", array($placeholder_max => $this->value['max']));
}
else {
$this->query->add_having_expression($this->options['group'], "$field <= $placeholder_min OR $field >= $placeholder_max", array($placeholder_min => $this->value['min'], $placeholder_max => $this->value['max']));
}
}
function op_simple($field) {
$placeholder = $this->placeholder();
$this->query->add_having_expression($this->options['group'], "$field $this->operator $placeholder", array($placeholder => $this->value['value']));
}
function op_empty($field) {
if ($this->operator == 'empty') {
$operator = "IS NULL";
}
else {
$operator = "IS NOT NULL";
}
$this->query->add_having_expression($this->options['group'], "$field $operator");
}
function ui_name($short = FALSE) {
return $this->get_field(parent::ui_name($short));
}
function can_group() { return FALSE; }
}
@@ -1,426 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_in_operator.
*/
/**
* Simple filter to handle matching of multiple options selectable via checkboxes
*
* Definition items:
* - options callback: The function to call in order to generate the value options. If omitted, the options 'Yes' and 'No' will be used.
* - options arguments: An array of arguments to pass to the options callback.
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_in_operator extends views_handler_filter {
var $value_form_type = 'checkboxes';
/**
* @var array
* Stores all operations which are available on the form.
*/
var $value_options = NULL;
function construct() {
parent::construct();
$this->value_title = t('Options');
$this->value_options = NULL;
}
/**
* Child classes should be used to override this function and set the
* 'value options', unless 'options callback' is defined as a valid function
* or static public method to generate these values.
*
* This can use a guard to be used to reduce database hits as much as
* possible.
*
* @return
* Return the stored values in $this->value_options if someone expects it.
*/
function get_value_options() {
if (isset($this->value_options)) {
return;
}
if (isset($this->definition['options callback']) && is_callable($this->definition['options callback'])) {
if (isset($this->definition['options arguments']) && is_array($this->definition['options arguments'])) {
$this->value_options = call_user_func_array($this->definition['options callback'], $this->definition['options arguments']);
}
else {
$this->value_options = call_user_func($this->definition['options callback']);
}
}
else {
$this->value_options = array(t('Yes'), t('No'));
}
return $this->value_options;
}
function expose_options() {
parent::expose_options();
$this->options['expose']['reduce'] = FALSE;
}
function expose_form(&$form, &$form_state) {
parent::expose_form($form, $form_state);
$form['expose']['reduce'] = array(
'#type' => 'checkbox',
'#title' => t('Limit list to selected items'),
'#description' => t('If checked, the only items presented to the user will be the ones selected here.'),
'#default_value' => !empty($this->options['expose']['reduce']), // safety
);
}
function option_definition() {
$options = parent::option_definition();
$options['operator']['default'] = 'in';
$options['value']['default'] = array();
$options['expose']['contains']['reduce'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
/**
* This kind of construct makes it relatively easy for a child class
* to add or remove functionality by overriding this function and
* adding/removing items from this array.
*/
function operators() {
$operators = array(
'in' => array(
'title' => t('Is one of'),
'short' => t('in'),
'short_single' => t('='),
'method' => 'op_simple',
'values' => 1,
),
'not in' => array(
'title' => t('Is not one of'),
'short' => t('not in'),
'short_single' => t('<>'),
'method' => 'op_simple',
'values' => 1,
),
);
// if the definition allows for the empty operator, add it.
if (!empty($this->definition['allow empty'])) {
$operators += array(
'empty' => array(
'title' => t('Is empty (NULL)'),
'method' => 'op_empty',
'short' => t('empty'),
'values' => 0,
),
'not empty' => array(
'title' => t('Is not empty (NOT NULL)'),
'method' => 'op_empty',
'short' => t('not empty'),
'values' => 0,
),
);
}
return $operators;
}
/**
* Build strings from the operators() for 'select' options
*/
function operator_options($which = 'title') {
$options = array();
foreach ($this->operators() as $id => $info) {
$options[$id] = $info[$which];
}
return $options;
}
function operator_values($values = 1) {
$options = array();
foreach ($this->operators() as $id => $info) {
if (isset($info['values']) && $info['values'] == $values) {
$options[] = $id;
}
}
return $options;
}
function value_form(&$form, &$form_state) {
$form['value'] = array();
$options = array();
if (empty($form_state['exposed'])) {
// Add a select all option to the value form.
$options = array('all' => t('Select all'));
}
$this->get_value_options();
$options += $this->value_options;
$default_value = (array) $this->value;
$which = 'all';
if (!empty($form['operator'])) {
$source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
}
if (!empty($form_state['exposed'])) {
$identifier = $this->options['expose']['identifier'];
if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
// exposed and locked.
$which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
}
else {
$source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
}
if (!empty($this->options['expose']['reduce'])) {
$options = $this->reduce_value_options();
if (!empty($this->options['expose']['multiple']) && empty($this->options['expose']['required'])) {
$default_value = array();
}
}
if (empty($this->options['expose']['multiple'])) {
if (empty($this->options['expose']['required']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
$default_value = 'All';
}
elseif (empty($default_value)) {
$keys = array_keys($options);
$default_value = array_shift($keys);
}
else {
$copy = $default_value;
$default_value = array_shift($copy);
}
}
}
if ($which == 'all' || $which == 'value') {
$form['value'] = array(
'#type' => $this->value_form_type,
'#title' => $this->value_title,
'#options' => $options,
'#default_value' => $default_value,
// These are only valid for 'select' type, but do no harm to checkboxes.
'#multiple' => TRUE,
'#size' => count($options) > 8 ? 8 : count($options),
);
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
$form_state['input'][$identifier] = $default_value;
}
if ($which == 'all') {
if (empty($form_state['exposed']) && (in_array($this->value_form_type, array('checkbox', 'checkboxes', 'radios', 'select')))) {
$form['value']['#prefix'] = '<div id="edit-options-value-wrapper">';
$form['value']['#suffix'] = '</div>';
}
$form['value']['#dependency'] = array($source => $this->operator_values(1));
}
}
}
/**
* When using exposed filters, we may be required to reduce the set.
*/
function reduce_value_options($input = NULL) {
if (!isset($input)) {
$input = $this->value_options;
}
// Because options may be an array of strings, or an array of mixed arrays
// and strings (optgroups) or an array of objects, we have to
// step through and handle each one individually.
$options = array();
foreach ($input as $id => $option) {
if (is_array($option)) {
$options[$id] = $this->reduce_value_options($option);
continue;
}
elseif (is_object($option)) {
$keys = array_keys($option->option);
$key = array_shift($keys);
if (isset($this->options['value'][$key])) {
$options[$id] = $option;
}
}
elseif (isset($this->options['value'][$id])) {
$options[$id] = $option;
}
}
return $options;
}
function accept_exposed_input($input) {
// A very special override because the All state for this type of
// filter could have a default:
if (empty($this->options['exposed'])) {
return TRUE;
}
// If this is non-multiple and non-required, then this filter will
// participate, but using the default settings, *if* 'limit is true.
if (empty($this->options['expose']['multiple']) && empty($this->options['expose']['required']) && !empty($this->options['expose']['limit'])) {
$identifier = $this->options['expose']['identifier'];
if ($input[$identifier] == 'All') {
return TRUE;
}
}
return parent::accept_exposed_input($input);
}
function value_submit($form, &$form_state) {
// Drupal's FAPI system automatically puts '0' in for any checkbox that
// was not set, and the key to the checkbox if it is set.
// Unfortunately, this means that if the key to that checkbox is 0,
// we are unable to tell if that checkbox was set or not.
// Luckily, the '#value' on the checkboxes form actually contains
// *only* a list of checkboxes that were set, and we can use that
// instead.
$form_state['values']['options']['value'] = $form['value']['#value'];
}
function admin_summary() {
if ($this->is_a_group()) {
return t('grouped');
}
if (!empty($this->options['exposed'])) {
return t('exposed');
}
$info = $this->operators();
$this->get_value_options();
if (!is_array($this->value)) {
return;
}
$operator = check_plain($info[$this->operator]['short']);
$values = '';
if (in_array($this->operator, $this->operator_values(1))) {
// Remove every element which is not known.
foreach ($this->value as $value) {
if (!isset($this->value_options[$value])) {
unset($this->value[$value]);
}
}
// Choose different kind of ouput for 0, a single and multiple values.
if (count($this->value) == 0) {
$values = t('Unknown');
}
else if (count($this->value) == 1) {
// If any, use the 'single' short name of the operator instead.
if (isset($info[$this->operator]['short_single'])) {
$operator = check_plain($info[$this->operator]['short_single']);
}
$keys = $this->value;
$value = array_shift($keys);
if (isset($this->value_options[$value])) {
$values = check_plain($this->value_options[$value]);
}
else {
$values = '';
}
}
else {
foreach ($this->value as $value) {
if ($values !== '') {
$values .= ', ';
}
if (drupal_strlen($values) > 8) {
$values .= '...';
break;
}
if (isset($this->value_options[$value])) {
$values .= check_plain($this->value_options[$value]);
}
}
}
}
return $operator . (($values !== '') ? ' ' . $values : '');
}
function query() {
$info = $this->operators();
if (!empty($info[$this->operator]['method'])) {
$this->{$info[$this->operator]['method']}();
}
}
function op_simple() {
if (empty($this->value)) {
return;
}
$this->ensure_my_table();
// We use array_values() because the checkboxes keep keys and that can cause
// array addition problems.
$this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", array_values($this->value), $this->operator);
}
function op_empty() {
$this->ensure_my_table();
if ($this->operator == 'empty') {
$operator = "IS NULL";
}
else {
$operator = "IS NOT NULL";
}
$this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", NULL, $operator);
}
function validate() {
$this->get_value_options();
$errors = array();
// If the operator is an operator which doesn't require a value, there is
// no need for additional validation.
if (in_array($this->operator, $this->operator_values(0))) {
return array();
}
if (!in_array($this->operator, $this->operator_values(1))) {
$errors[] = t('The operator is invalid on filter: @filter.', array('@filter' => $this->ui_name(TRUE)));
}
if (is_array($this->value)) {
if (!isset($this->value_options)) {
// Don't validate if there are none value options provided, for example for special handlers.
return $errors;
}
if ($this->options['exposed'] && !$this->options['expose']['required'] && empty($this->value)) {
// Don't validate if the field is exposed and no default value is provided.
return $errors;
}
// Some filter_in_operator usage uses optgroups forms, so flatten it.
$flat_options = form_options_flatten($this->value_options, TRUE);
// Remove every element which is not known.
foreach ($this->value as $value) {
if (!isset($flat_options[$value])) {
unset($this->value[$value]);
}
}
// Choose different kind of ouput for 0, a single and multiple values.
if (count($this->value) == 0) {
$errors[] = t('No valid values found on filter: @filter.', array('@filter' => $this->ui_name(TRUE)));
}
}
elseif (!empty($this->value) && ($this->operator == 'in' || $this->operator == 'not in')) {
$errors[] = t('The value @value is not an array for @operator on filter: @filter', array('@value' => views_var_export($this->value), '@operator' => $this->operator, '@filter' => $this->ui_name(TRUE)));
}
return $errors;
}
}
@@ -1,125 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_many_to_one.
*/
/**
* Complex filter to handle filtering for many to one relationships,
* such as terms (many terms per node) or roles (many roles per user).
*
* The construct method needs to be overridden to provide a list of options;
* alternately, the value_form and admin_summary methods need to be overriden
* to provide something that isn't just a select list.
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_many_to_one extends views_handler_filter_in_operator {
/**
* @var views_many_to_one_helper
*
* Stores the Helper object which handles the many_to_one complexity.
*/
var $helper = NULL;
function init(&$view, &$options) {
parent::init($view, $options);
$this->helper = new views_many_to_one_helper($this);
}
function option_definition() {
$options = parent::option_definition();
$options['operator']['default'] = 'or';
$options['value']['default'] = array();
if (isset($this->helper)) {
$this->helper->option_definition($options);
}
else {
$helper = new views_many_to_one_helper($this);
$helper->option_definition($options);
}
return $options;
}
function operators() {
$operators = array(
'or' => array(
'title' => t('Is one of'),
'short' => t('or'),
'short_single' => t('='),
'method' => 'op_helper',
'values' => 1,
'ensure_my_table' => 'helper',
),
'and' => array(
'title' => t('Is all of'),
'short' => t('and'),
'short_single' => t('='),
'method' => 'op_helper',
'values' => 1,
'ensure_my_table' => 'helper',
),
'not' => array(
'title' => t('Is none of'),
'short' => t('not'),
'short_single' => t('<>'),
'method' => 'op_helper',
'values' => 1,
'ensure_my_table' => 'helper',
),
);
// if the definition allows for the empty operator, add it.
if (!empty($this->definition['allow empty'])) {
$operators += array(
'empty' => array(
'title' => t('Is empty (NULL)'),
'method' => 'op_empty',
'short' => t('empty'),
'values' => 0,
),
'not empty' => array(
'title' => t('Is not empty (NOT NULL)'),
'method' => 'op_empty',
'short' => t('not empty'),
'values' => 0,
),
);
}
return $operators;
}
var $value_form_type = 'select';
function value_form(&$form, &$form_state) {
parent::value_form($form, $form_state);
if (empty($form_state['exposed'])) {
$this->helper->options_form($form, $form_state);
}
}
/**
* Override ensure_my_table so we can control how this joins in.
* The operator actually has influence over joining.
*/
function ensure_my_table() {
// Defer to helper if the operator specifies it.
$info = $this->operators();
if (isset($info[$this->operator]['ensure_my_table']) && $info[$this->operator]['ensure_my_table'] == 'helper') {
return $this->helper->ensure_my_table();
}
return parent::ensure_my_table();
}
function op_helper() {
if (empty($this->value)) {
return;
}
$this->helper->add_filter();
}
}
-325
View File
@@ -1,325 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_numeric.
*/
/**
* Simple filter to handle greater than/less than filters
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_numeric extends views_handler_filter {
var $always_multiple = TRUE;
function option_definition() {
$options = parent::option_definition();
$options['value'] = array(
'contains' => array(
'min' => array('default' => ''),
'max' => array('default' => ''),
'value' => array('default' => ''),
),
);
return $options;
}
function operators() {
$operators = array(
'<' => array(
'title' => t('Is less than'),
'method' => 'op_simple',
'short' => t('<'),
'values' => 1,
),
'<=' => array(
'title' => t('Is less than or equal to'),
'method' => 'op_simple',
'short' => t('<='),
'values' => 1,
),
'=' => array(
'title' => t('Is equal to'),
'method' => 'op_simple',
'short' => t('='),
'values' => 1,
),
'!=' => array(
'title' => t('Is not equal to'),
'method' => 'op_simple',
'short' => t('!='),
'values' => 1,
),
'>=' => array(
'title' => t('Is greater than or equal to'),
'method' => 'op_simple',
'short' => t('>='),
'values' => 1,
),
'>' => array(
'title' => t('Is greater than'),
'method' => 'op_simple',
'short' => t('>'),
'values' => 1,
),
'between' => array(
'title' => t('Is between'),
'method' => 'op_between',
'short' => t('between'),
'values' => 2,
),
'not between' => array(
'title' => t('Is not between'),
'method' => 'op_between',
'short' => t('not between'),
'values' => 2,
),
);
// if the definition allows for the empty operator, add it.
if (!empty($this->definition['allow empty'])) {
$operators += array(
'empty' => array(
'title' => t('Is empty (NULL)'),
'method' => 'op_empty',
'short' => t('empty'),
'values' => 0,
),
'not empty' => array(
'title' => t('Is not empty (NOT NULL)'),
'method' => 'op_empty',
'short' => t('not empty'),
'values' => 0,
),
);
}
// Add regexp support for MySQL.
if (Database::getConnection()->databaseType() == 'mysql') {
$operators += array(
'regular_expression' => array(
'title' => t('Regular expression'),
'short' => t('regex'),
'method' => 'op_regex',
'values' => 1,
),
);
}
return $operators;
}
/**
* Provide a list of all the numeric operators
*/
function operator_options($which = 'title') {
$options = array();
foreach ($this->operators() as $id => $info) {
$options[$id] = $info[$which];
}
return $options;
}
function operator_values($values = 1) {
$options = array();
foreach ($this->operators() as $id => $info) {
if ($info['values'] == $values) {
$options[] = $id;
}
}
return $options;
}
/**
* Provide a simple textfield for equality
*/
function value_form(&$form, &$form_state) {
$form['value']['#tree'] = TRUE;
// We have to make some choices when creating this as an exposed
// filter form. For example, if the operator is locked and thus
// not rendered, we can't render dependencies; instead we only
// render the form items we need.
$which = 'all';
if (!empty($form['operator'])) {
$source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
}
if (!empty($form_state['exposed'])) {
$identifier = $this->options['expose']['identifier'];
if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
// exposed and locked.
$which = in_array($this->operator, $this->operator_values(2)) ? 'minmax' : 'value';
}
else {
$source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
}
}
if ($which == 'all') {
$form['value']['value'] = array(
'#type' => 'textfield',
'#title' => empty($form_state['exposed']) ? t('Value') : '',
'#size' => 30,
'#default_value' => $this->value['value'],
'#dependency' => array($source => $this->operator_values(1)),
);
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['value'])) {
$form_state['input'][$identifier]['value'] = $this->value['value'];
}
}
elseif ($which == 'value') {
// When exposed we drop the value-value and just do value if
// the operator is locked.
$form['value'] = array(
'#type' => 'textfield',
'#title' => empty($form_state['exposed']) ? t('Value') : '',
'#size' => 30,
'#default_value' => $this->value['value'],
);
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
$form_state['input'][$identifier] = $this->value['value'];
}
}
if ($which == 'all' || $which == 'minmax') {
$form['value']['min'] = array(
'#type' => 'textfield',
'#title' => empty($form_state['exposed']) ? t('Min') : '',
'#size' => 30,
'#default_value' => $this->value['min'],
);
$form['value']['max'] = array(
'#type' => 'textfield',
'#title' => empty($form_state['exposed']) ? t('And max') : t('And'),
'#size' => 30,
'#default_value' => $this->value['max'],
);
if ($which == 'all') {
$dependency = array(
'#dependency' => array($source => $this->operator_values(2)),
);
$form['value']['min'] += $dependency;
$form['value']['max'] += $dependency;
}
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['min'])) {
$form_state['input'][$identifier]['min'] = $this->value['min'];
}
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['max'])) {
$form_state['input'][$identifier]['max'] = $this->value['max'];
}
if (!isset($form['value'])) {
// Ensure there is something in the 'value'.
$form['value'] = array(
'#type' => 'value',
'#value' => NULL
);
}
}
}
function query() {
$this->ensure_my_table();
$field = "$this->table_alias.$this->real_field";
$info = $this->operators();
if (!empty($info[$this->operator]['method'])) {
$this->{$info[$this->operator]['method']}($field);
}
}
function op_between($field) {
if ($this->operator == 'between') {
$this->query->add_where($this->options['group'], $field, array($this->value['min'], $this->value['max']), 'BETWEEN');
}
else {
$this->query->add_where($this->options['group'], db_or()->condition($field, $this->value['min'], '<=')->condition($field, $this->value['max'], '>='));
}
}
function op_simple($field) {
$this->query->add_where($this->options['group'], $field, $this->value['value'], $this->operator);
}
function op_empty($field) {
if ($this->operator == 'empty') {
$operator = "IS NULL";
}
else {
$operator = "IS NOT NULL";
}
$this->query->add_where($this->options['group'], $field, NULL, $operator);
}
function op_regex($field) {
$this->query->add_where($this->options['group'], $field, $this->value['value'], 'RLIKE');
}
function admin_summary() {
if ($this->is_a_group()) {
return t('grouped');
}
if (!empty($this->options['exposed'])) {
return t('exposed');
}
$options = $this->operator_options('short');
$output = check_plain($options[$this->operator]);
if (in_array($this->operator, $this->operator_values(2))) {
$output .= ' ' . t('@min and @max', array('@min' => $this->value['min'], '@max' => $this->value['max']));
}
elseif (in_array($this->operator, $this->operator_values(1))) {
$output .= ' ' . check_plain($this->value['value']);
}
return $output;
}
/**
* Do some minor translation of the exposed input
*/
function accept_exposed_input($input) {
if (empty($this->options['exposed'])) {
return TRUE;
}
// rewrite the input value so that it's in the correct format so that
// the parent gets the right data.
if (!empty($this->options['expose']['identifier'])) {
$value = &$input[$this->options['expose']['identifier']];
if (!is_array($value)) {
$value = array(
'value' => $value,
);
}
}
$rc = parent::accept_exposed_input($input);
if (empty($this->options['expose']['required'])) {
// We have to do some of our own checking for non-required filters.
$info = $this->operators();
if (!empty($info[$this->operator]['values'])) {
switch ($info[$this->operator]['values']) {
case 1:
if ($value['value'] === '') {
return FALSE;
}
break;
case 2:
if ($value['min'] === '' && $value['max'] === '') {
return FALSE;
}
break;
}
}
}
return $rc;
}
}
-338
View File
@@ -1,338 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_filter_string.
*/
/**
* Basic textfield filter to handle string filtering commands
* including equality, like, not like, etc.
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_string extends views_handler_filter {
// exposed filter options
var $always_multiple = TRUE;
function option_definition() {
$options = parent::option_definition();
$options['expose']['contains']['required'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
/**
* This kind of construct makes it relatively easy for a child class
* to add or remove functionality by overriding this function and
* adding/removing items from this array.
*/
function operators() {
$operators = array(
'=' => array(
'title' => t('Is equal to'),
'short' => t('='),
'method' => 'op_equal',
'values' => 1,
),
'!=' => array(
'title' => t('Is not equal to'),
'short' => t('!='),
'method' => 'op_equal',
'values' => 1,
),
'contains' => array(
'title' => t('Contains'),
'short' => t('contains'),
'method' => 'op_contains',
'values' => 1,
),
'word' => array(
'title' => t('Contains any word'),
'short' => t('has word'),
'method' => 'op_word',
'values' => 1,
),
'allwords' => array(
'title' => t('Contains all words'),
'short' => t('has all'),
'method' => 'op_word',
'values' => 1,
),
'starts' => array(
'title' => t('Starts with'),
'short' => t('begins'),
'method' => 'op_starts',
'values' => 1,
),
'not_starts' => array(
'title' => t('Does not start with'),
'short' => t('not_begins'),
'method' => 'op_not_starts',
'values' => 1,
),
'ends' => array(
'title' => t('Ends with'),
'short' => t('ends'),
'method' => 'op_ends',
'values' => 1,
),
'not_ends' => array(
'title' => t('Does not end with'),
'short' => t('not_ends'),
'method' => 'op_not_ends',
'values' => 1,
),
'not' => array(
'title' => t('Does not contain'),
'short' => t('!has'),
'method' => 'op_not',
'values' => 1,
),
'shorterthan' => array(
'title' => t('Length is shorter than'),
'short' => t('shorter than'),
'method' => 'op_shorter',
'values' => 1,
),
'longerthan' => array(
'title' => t('Length is longer than'),
'short' => t('longer than'),
'method' => 'op_longer',
'values' => 1,
),
);
// if the definition allows for the empty operator, add it.
if (!empty($this->definition['allow empty'])) {
$operators += array(
'empty' => array(
'title' => t('Is empty (NULL)'),
'method' => 'op_empty',
'short' => t('empty'),
'values' => 0,
),
'not empty' => array(
'title' => t('Is not empty (NOT NULL)'),
'method' => 'op_empty',
'short' => t('not empty'),
'values' => 0,
),
);
}
// Add regexp support for MySQL.
if (Database::getConnection()->databaseType() == 'mysql') {
$operators += array(
'regular_expression' => array(
'title' => t('Regular expression'),
'short' => t('regex'),
'method' => 'op_regex',
'values' => 1,
),
);
}
return $operators;
}
/**
* Build strings from the operators() for 'select' options
*/
function operator_options($which = 'title') {
$options = array();
foreach ($this->operators() as $id => $info) {
$options[$id] = $info[$which];
}
return $options;
}
function admin_summary() {
if ($this->is_a_group()) {
return t('grouped');
}
if (!empty($this->options['exposed'])) {
return t('exposed');
}
$options = $this->operator_options('short');
$output = '';
if(!empty($options[$this->operator])) {
$output = check_plain($options[$this->operator]);
}
if (in_array($this->operator, $this->operator_values(1))) {
$output .= ' ' . check_plain($this->value);
}
return $output;
}
function operator_values($values = 1) {
$options = array();
foreach ($this->operators() as $id => $info) {
if (isset($info['values']) && $info['values'] == $values) {
$options[] = $id;
}
}
return $options;
}
/**
* Provide a simple textfield for equality
*/
function value_form(&$form, &$form_state) {
// We have to make some choices when creating this as an exposed
// filter form. For example, if the operator is locked and thus
// not rendered, we can't render dependencies; instead we only
// render the form items we need.
$which = 'all';
if (!empty($form['operator'])) {
$source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
}
if (!empty($form_state['exposed'])) {
$identifier = $this->options['expose']['identifier'];
if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
// exposed and locked.
$which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
}
else {
$source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
}
}
if ($which == 'all' || $which == 'value') {
$form['value'] = array(
'#type' => 'textfield',
'#title' => t('Value'),
'#size' => 30,
'#default_value' => $this->value,
);
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
$form_state['input'][$identifier] = $this->value;
}
if ($which == 'all') {
$form['value'] += array(
'#dependency' => array($source => $this->operator_values(1)),
);
}
}
if (!isset($form['value'])) {
// Ensure there is something in the 'value'.
$form['value'] = array(
'#type' => 'value',
'#value' => NULL
);
}
}
function operator() {
return $this->operator == '=' ? 'LIKE' : 'NOT LIKE';
}
/**
* Add this filter to the query.
*
* Due to the nature of fapi, the value and the operator have an unintended
* level of indirection. You will find them in $this->operator
* and $this->value respectively.
*/
function query() {
$this->ensure_my_table();
$field = "$this->table_alias.$this->real_field";
$info = $this->operators();
if (!empty($info[$this->operator]['method'])) {
$this->{$info[$this->operator]['method']}($field);
}
}
function op_equal($field) {
$this->query->add_where($this->options['group'], $field, $this->value, $this->operator());
}
function op_contains($field) {
$this->query->add_where($this->options['group'], $field, '%' . db_like($this->value) . '%', 'LIKE');
}
function op_word($field) {
$where = $this->operator == 'word' ? db_or() : db_and();
// Don't filter on empty strings.
if (empty($this->value)) {
return;
}
preg_match_all('/ (-?)("[^"]+"|[^" ]+)/i', ' ' . $this->value, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$phrase = false;
// Strip off phrase quotes
if ($match[2]{0} == '"') {
$match[2] = substr($match[2], 1, -1);
$phrase = true;
}
$words = trim($match[2], ',?!();:-');
$words = $phrase ? array($words) : preg_split('/ /', $words, -1, PREG_SPLIT_NO_EMPTY);
foreach ($words as $word) {
$placeholder = $this->placeholder();
$where->condition($field, '%' . db_like(trim($word, " ,!?")) . '%', 'LIKE');
}
}
if (!$where) {
return;
}
// previously this was a call_user_func_array but that's unnecessary
// as views will unpack an array that is a single arg.
$this->query->add_where($this->options['group'], $where);
}
function op_starts($field) {
$this->query->add_where($this->options['group'], $field, db_like($this->value) . '%', 'LIKE');
}
function op_not_starts($field) {
$this->query->add_where($this->options['group'], $field, db_like($this->value) . '%', 'NOT LIKE');
}
function op_ends($field) {
$this->query->add_where($this->options['group'], $field, '%' . db_like($this->value), 'LIKE');
}
function op_not_ends($field) {
$this->query->add_where($this->options['group'], $field, '%' . db_like($this->value), 'NOT LIKE');
}
function op_not($field) {
$this->query->add_where($this->options['group'], $field, '%' . db_like($this->value) . '%', 'NOT LIKE');
}
function op_shorter($field) {
$placeholder = $this->placeholder();
$this->query->add_where_expression($this->options['group'], "LENGTH($field) < $placeholder", array($placeholder => $this->value));
}
function op_longer($field) {
$placeholder = $this->placeholder();
$this->query->add_where_expression($this->options['group'], "LENGTH($field) > $placeholder", array($placeholder => $this->value));
}
function op_regex($field) {
$this->query->add_where($this->options['group'], $field, $this->value, 'RLIKE');
}
function op_empty($field) {
if ($this->operator == 'empty') {
$operator = "IS NULL";
}
else {
$operator = "IS NOT NULL";
}
$this->query->add_where($this->options['group'], $field, NULL, $operator);
}
}
-186
View File
@@ -1,186 +0,0 @@
<?php
/**
* @file
* Views' relationship handlers.
*/
/**
* @defgroup views_relationship_handlers Views relationship handlers
* @{
* Handlers to tell Views how to create alternate relationships.
*/
/**
* Simple relationship handler that allows a new version of the primary table
* to be linked in.
*
* The base relationship handler can only handle a single join. Some relationships
* are more complex and might require chains of joins; for those, you must
* utilize a custom relationship handler.
*
* Definition items:
* - base: The new base table this relationship will be adding. This does not
* have to be a declared base table, but if there are no tables that
* utilize this base table, it won't be very effective.
* - base field: The field to use in the relationship; if left out this will be
* assumed to be the primary field.
* - relationship table: The actual table this relationship operates against.
* This is analogous to using a 'table' override.
* - relationship field: The actual field this relationship operates against.
* This is analogous to using a 'real field' override.
* - label: The default label to provide for this relationship, which is
* shown in parentheses next to any field/sort/filter/argument that uses
* the relationship.
*
* @ingroup views_relationship_handlers
*/
class views_handler_relationship extends views_handler {
/**
* Init handler to let relationships live on tables other than
* the table they operate on.
*/
function init(&$view, &$options) {
parent::init($view, $options);
if (isset($this->definition['relationship table'])) {
$this->table = $this->definition['relationship table'];
}
if (isset($this->definition['relationship field'])) {
// Set both real_field and field so custom handler
// can rely on the old field value.
$this->real_field = $this->field = $this->definition['relationship field'];
}
}
/**
* Get this field's label.
*/
function label() {
if (!isset($this->options['label'])) {
return $this->ui_name();
}
return $this->options['label'];
}
function option_definition() {
$options = parent::option_definition();
// Relationships definitions should define a default label, but if they aren't get another default value.
if (!empty($this->definition['label'])) {
$label = $this->definition['label'];
}
else {
$label = !empty($this->definition['field']) ? $this->definition['field'] : $this->definition['base field'];
}
$options['label'] = array('default' => $label, 'translatable' => TRUE);
$options['required'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
/**
* Default options form that provides the label widget that all fields
* should have.
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['label'] = array(
'#type' => 'textfield',
'#title' => t('Identifier'),
'#default_value' => isset($this->options['label']) ? $this->options['label'] : '',
'#description' => t('Edit the administrative label displayed when referencing this relationship from filters, etc.'),
'#required' => TRUE,
);
$form['required'] = array(
'#type' => 'checkbox',
'#title' => t('Require this relationship'),
'#description' => t('Enable to hide items that do not contain this relationship'),
'#default_value' => !empty($this->options['required']),
);
}
/**
* Called to implement a relationship in a query.
*/
function query() {
// Figure out what base table this relationship brings to the party.
$table_data = views_fetch_data($this->definition['base']);
$base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
$this->ensure_my_table();
$def = $this->definition;
$def['table'] = $this->definition['base'];
$def['field'] = $base_field;
$def['left_table'] = $this->table_alias;
$def['left_field'] = $this->real_field;
if (!empty($this->options['required'])) {
$def['type'] = 'INNER';
}
if (!empty($this->definition['extra'])) {
$def['extra'] = $this->definition['extra'];
}
if (!empty($def['join_handler']) && class_exists($def['join_handler'])) {
$join = new $def['join_handler'];
}
else {
$join = new views_join();
}
$join->definition = $def;
$join->options = $this->options;
$join->construct();
$join->adjusted = TRUE;
// use a short alias for this:
$alias = $def['table'] . '_' . $this->table;
$this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
// Add access tags if the base table provide it.
if (empty($this->query->options['disable_sql_rewrite']) && isset($table_data['table']['base']['access query tag'])) {
$access_tag = $table_data['table']['base']['access query tag'];
$this->query->add_tag($access_tag);
}
}
/**
* You can't groupby a relationship.
*/
function use_group_by() {
return FALSE;
}
}
/**
* A special handler to take the place of missing or broken handlers.
*
* @ingroup views_relationship_handlers
*/
class views_handler_relationship_broken extends views_handler_relationship {
function ui_name($short = FALSE) {
return t('Broken/missing handler');
}
function ensure_my_table() { /* No table to ensure! */ }
function query() { /* No query to run */ }
function options_form(&$form, &$form_state) {
$form['markup'] = array(
'#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
);
}
/**
* Determine if the handler is considered 'broken'
*/
function broken() { return TRUE; }
}
/**
* @}
*/
@@ -1,382 +0,0 @@
<?php
/**
* @file
* Relationship for groupwise maximum handler.
*/
/**
* Relationship handler that allows a groupwise maximum of the linked in table.
* For a definition, see:
* http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html
* In lay terms, instead of joining to get all matching records in the linked
* table, we get only one record, a 'representative record' picked according
* to a given criteria.
*
* Example:
* Suppose we have a term view that gives us the terms: Horse, Cat, Aardvark.
* We wish to show for each term the most recent node of that term.
* What we want is some kind of relationship from term to node.
* But a regular relationship will give us all the nodes for each term,
* giving the view multiple rows per term. What we want is just one
* representative node per term, the node that is the 'best' in some way:
* eg, the most recent, the most commented on, the first in alphabetical order.
*
* This handler gives us that kind of relationship from term to node.
* The method of choosing the 'best' implemented with a sort
* that the user selects in the relationship settings.
*
* So if we want our term view to show the most commented node for each term,
* add the relationship and in its options, pick the 'Comment count' sort.
*
* Relationship definition
* - 'outer field': The outer field to substitute into the correlated subquery.
* This must be the full field name, not the alias.
* Eg: 'term_data.tid'.
* - 'argument table',
* 'argument field': These options define a views argument that the subquery
* must add to itself to filter by the main view.
* Example: the main view shows terms, this handler is being used to get to
* the nodes base table. Your argument must be 'term_node', 'tid', as this
* is the argument that should be added to a node view to filter on terms.
*
* A note on performance:
* This relationship uses a correlated subquery, which is expensive.
* Subsequent versions of this handler could also implement the alternative way
* of doing this, with a join -- though this looks like it could be pretty messy
* to implement. This is also an expensive method, so providing both methods and
* allowing the user to choose which one works fastest for their data might be
* the best way.
* If your use of this relationship handler is likely to result in large
* data sets, you might want to consider storing statistics in a separate table,
* in the same way as node_comment_statistics.
*
* @ingroup views_relationship_handlers
*/
class views_handler_relationship_groupwise_max extends views_handler_relationship {
/**
* Defines default values for options.
*/
function option_definition() {
$options = parent::option_definition();
$options['subquery_sort'] = array('default' => NULL);
// Descending more useful.
$options['subquery_order'] = array('default' => 'DESC');
$options['subquery_regenerate'] = array('default' => FALSE, 'bool' => TRUE);
$options['subquery_view'] = array('default' => FALSE);
$options['subquery_namespace'] = array('default' => FALSE);
return $options;
}
/**
* Extends the relationship's basic options, allowing the user to pick
* a sort and an order for it.
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
// Get the sorts that apply to our base.
$sorts = views_fetch_fields($this->definition['base'], 'sort');
foreach ($sorts as $sort_id => $sort) {
$sort_options[$sort_id] = "$sort[group]: $sort[title]";
}
$base_table_data = views_fetch_data($this->definition['base']);
$form['subquery_sort'] = array(
'#type' => 'select',
'#title' => t('Representative sort criteria'),
// Provide the base field as sane default sort option.
'#default_value' => !empty($this->options['subquery_sort']) ? $this->options['subquery_sort'] : $this->definition['base'] . '.' . $base_table_data['table']['base']['field'],
'#options' => $sort_options,
'#description' => theme('advanced_help_topic', array('module' => 'views', 'topic' => 'relationship-representative')) .
t("The sort criteria is applied to the data brought in by the relationship to determine how a representative item is obtained for each row. For example, to show the most recent node for each user, pick 'Content: Updated date'."),
);
$form['subquery_order'] = array(
'#type' => 'radios',
'#title' => t('Representative sort order'),
'#description' => t("The ordering to use for the sort criteria selected above."),
'#options' => array('ASC' => t('Ascending'), 'DESC' => t('Descending')),
'#default_value' => $this->options['subquery_order'],
);
$form['subquery_namespace'] = array(
'#type' => 'textfield',
'#title' => t('Subquery namespace'),
'#description' => t('Advanced. Enter a namespace for the subquery used by this relationship.'),
'#default_value' => $this->options['subquery_namespace'],
);
// WIP: This stuff doens't work yet: namespacing issues.
// A list of suitable views to pick one as the subview.
$views = array('' => '<none>');
$all_views = views_get_all_views();
foreach ($all_views as $view) {
// Only get views that are suitable:
// - base must the base that our relationship joins towards
// - must have fields.
if ($view->base_table == $this->definition['base'] && !empty($view->display['default']->display_options['fields'])) {
// TODO: check the field is the correct sort?
// or let users hang themselves at this stage and check later?
if ($view->type == 'Default') {
$views[t('Default Views')][$view->name] = $view->name;
}
else {
$views[t('Existing Views')][$view->name] = $view->name;
}
}
}
$form['subquery_view'] = array(
'#type' => 'select',
'#title' => t('Representative view'),
'#default_value' => $this->options['subquery_view'],
'#options' => $views,
'#description' => t('Advanced. Use another view to generate the relationship subquery. This allows you to use filtering and more than one sort. If you pick a view here, the sort options above are ignored. Your view must have the ID of its base as its only field, and should have some kind of sorting.'),
);
$form['subquery_regenerate'] = array(
'#type' => 'checkbox',
'#title' => t('Generate subquery each time view is run.'),
'#default_value' => $this->options['subquery_regenerate'],
'#description' => t('Will re-generate the subquery for this relationship every time the view is run, instead of only when these options are saved. Use for testing if you are making changes elsewhere. WARNING: seriously impairs performance.'),
);
}
/**
* Helper function to create a pseudo view.
*
* We use this to obtain our subquery SQL.
*/
function get_temporary_view() {
views_include('view');
$view = new view();
$view->vid = 'new'; // @todo: what's this?
$view->base_table = $this->definition['base'];
$view->add_display('default');
return $view;
}
/**
* When the form is submitted, take sure to clear the subquery string cache.
*/
function options_form_submit(&$form, &$form_state) {
$cid = 'views_relationship_groupwise_max:' . $this->view->name . ':' . $this->view->current_display . ':' . $this->options['id'];
cache_clear_all($cid, 'cache_views_data');
}
/**
* Generate a subquery given the user options, as set in the options.
* These are passed in rather than picked up from the object because we
* generate the subquery when the options are saved, rather than when the view
* is run. This saves considerable time.
*
* @param $options
* An array of options:
* - subquery_sort: the id of a views sort.
* - subquery_order: either ASC or DESC.
* @return
* The subquery SQL string, ready for use in the main query.
*/
function left_query($options) {
// Either load another view, or create one on the fly.
if ($options['subquery_view']) {
$temp_view = views_get_view($options['subquery_view']);
// Remove all fields from default display
unset($temp_view->display['default']->display_options['fields']);
}
else {
// Create a new view object on the fly, which we use to generate a query
// object and then get the SQL we need for the subquery.
$temp_view = $this->get_temporary_view();
// Add the sort from the options to the default display.
// This is broken, in that the sort order field also gets added as a
// select field. See http://drupal.org/node/844910.
// We work around this further down.
$sort = $options['subquery_sort'];
list($sort_table, $sort_field) = explode('.', $sort);
$sort_options = array('order' => $options['subquery_order']);
$temp_view->add_item('default', 'sort', $sort_table, $sort_field, $sort_options);
}
// Get the namespace string.
$temp_view->namespace = (!empty($options['subquery_namespace'])) ? '_'. $options['subquery_namespace'] : '_INNER';
$this->subquery_namespace = (!empty($options['subquery_namespace'])) ? '_'. $options['subquery_namespace'] : 'INNER';
// The value we add here does nothing, but doing this adds the right tables
// and puts in a WHERE clause with a placeholder we can grab later.
$temp_view->args[] = '**CORRELATED**';
// Add the base table ID field.
$views_data = views_fetch_data($this->definition['base']);
$base_field = $views_data['table']['base']['field'];
$temp_view->add_item('default', 'field', $this->definition['base'], $this->definition['field']);
// Add the correct argument for our relationship's base
// ie the 'how to get back to base' argument.
// The relationship definition tells us which one to use.
$temp_view->add_item(
'default',
'argument',
$this->definition['argument table'], // eg 'term_node',
$this->definition['argument field'] // eg 'tid'
);
// Build the view. The creates the query object and produces the query
// string but does not run any queries.
$temp_view->build();
// Now take the SelectQuery object the View has built and massage it
// somewhat so we can get the SQL query from it.
$subquery = $temp_view->build_info['query'];
// Workaround until http://drupal.org/node/844910 is fixed:
// Remove all fields from the SELECT except the base id.
$fields =& $subquery->getFields();
foreach (array_keys($fields) as $field_name) {
// The base id for this subquery is stored in our definition.
if ($field_name != $this->definition['field']) {
unset($fields[$field_name]);
}
}
// Make every alias in the subquery safe within the outer query by
// appending a namespace to it, '_inner' by default.
$tables =& $subquery->getTables();
foreach (array_keys($tables) as $table_name) {
$tables[$table_name]['alias'] .= $this->subquery_namespace;
// Namespace the join on every table.
if (isset($tables[$table_name]['condition'])) {
$tables[$table_name]['condition'] = $this->condition_namespace($tables[$table_name]['condition']);
}
}
// Namespace fields.
foreach (array_keys($fields) as $field_name) {
$fields[$field_name]['table'] .= $this->subquery_namespace;
$fields[$field_name]['alias'] .= $this->subquery_namespace;
}
// Namespace conditions.
$where =& $subquery->conditions();
$this->alter_subquery_condition($subquery, $where);
// Not sure why, but our sort order clause doesn't have a table.
// TODO: the call to add_item() above to add the sort handler is probably
// wrong -- needs attention from someone who understands it.
// In the meantime, this works, but with a leap of faith...
$orders =& $subquery->getOrderBy();
foreach ($orders as $order_key => $order) {
// But if we're using a whole view, we don't know what we have!
if ($options['subquery_view']) {
list($sort_table, $sort_field) = explode('.', $order_key);
}
$orders[$sort_table . $this->subquery_namespace . '.' . $sort_field] = $order;
unset($orders[$order_key]);
}
// The query we get doesn't include the LIMIT, so add it here.
$subquery->range(0, 1);
// Extract the SQL the temporary view built.
$subquery_sql = $subquery->__toString();
// Replace the placeholder with the outer, correlated field.
// Eg, change the placeholder ':users_uid' into the outer field 'users.uid'.
// We have to work directly with the SQL, because putting a name of a field
// into a SelectQuery that it does not recognize (because it's outer) just
// makes it treat it as a string.
$outer_placeholder = ':' . str_replace('.', '_', $this->definition['outer field']);
$subquery_sql = str_replace($outer_placeholder, $this->definition['outer field'], $subquery_sql);
return $subquery_sql;
}
/**
* Recursive helper to add a namespace to conditions.
*
* Similar to _views_query_tag_alter_condition().
*
* (Though why is the condition we get in a simple query 3 levels deep???)
*/
function alter_subquery_condition(QueryAlterableInterface $query, &$conditions) {
foreach ($conditions as $condition_id => &$condition) {
// Skip the #conjunction element.
if (is_numeric($condition_id)) {
if (is_string($condition['field'])) {
$condition['field'] = $this->condition_namespace($condition['field']);
}
elseif (is_object($condition['field'])) {
$sub_conditions =& $condition['field']->conditions();
$this->alter_subquery_condition($query, $sub_conditions);
}
}
}
}
/**
* Helper function to namespace query pieces.
*
* Turns 'foo.bar' into 'foo_NAMESPACE.bar'.
*/
function condition_namespace($string) {
return str_replace('.', $this->subquery_namespace . '.', $string);
}
/**
* Called to implement a relationship in a query.
* This is mostly a copy of our parent's query() except for this bit with
* the join class.
*/
function query() {
// Figure out what base table this relationship brings to the party.
$table_data = views_fetch_data($this->definition['base']);
$base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
$this->ensure_my_table();
$def = $this->definition;
$def['table'] = $this->definition['base'];
$def['field'] = $base_field;
$def['left_table'] = $this->table_alias;
$def['left_field'] = $this->field;
if (!empty($this->options['required'])) {
$def['type'] = 'INNER';
}
if ($this->options['subquery_regenerate']) {
// For testing only, regenerate the subquery each time.
$def['left_query'] = $this->left_query($this->options);
}
else {
// Get the stored subquery SQL string.
$cid = 'views_relationship_groupwise_max:' . $this->view->name . ':' . $this->view->current_display . ':' . $this->options['id'];
$cache = cache_get($cid, 'cache_views_data');
if (isset($cache->data)) {
$def['left_query'] = $cache->data;
}
else {
$def['left_query'] = $this->left_query($this->options);
cache_set($cid, $def['left_query'], 'cache_views_data');
}
}
if (!empty($def['join_handler']) && class_exists($def['join_handler'])) {
$join = new $def['join_handler'];
}
else {
$join = new views_join_subquery();
}
$join->definition = $def;
$join->construct();
$join->adjusted = TRUE;
// use a short alias for this:
$alias = $def['table'] . '_' . $this->table;
$this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
}
}
-240
View File
@@ -1,240 +0,0 @@
<?php
/**
* @file
* @todo.
*/
/**
* @defgroup views_sort_handlers Views sort handlers
* @{
* Handlers to tell Views how to sort queries.
*/
/**
* Base sort handler that has no options and performs a simple sort.
*
* @ingroup views_sort_handlers
*/
class views_handler_sort extends views_handler {
/**
* Determine if a sort can be exposed.
*/
function can_expose() { return TRUE; }
/**
* Called to add the sort to a query.
*/
function query() {
$this->ensure_my_table();
// Add the field.
$this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']);
}
function option_definition() {
$options = parent::option_definition();
$options['order'] = array('default' => 'ASC');
$options['exposed'] = array('default' => FALSE, 'bool' => TRUE);
$options['expose'] = array(
'contains' => array(
'label' => array('default' => '', 'translatable' => TRUE),
),
);
return $options;
}
/**
* Display whether or not the sort order is ascending or descending
*/
function admin_summary() {
if (!empty($this->options['exposed'])) {
return t('Exposed');
}
switch ($this->options['order']) {
case 'ASC':
case 'asc':
default:
return t('asc');
break;
case 'DESC';
case 'desc';
return t('desc');
break;
}
}
/**
* Basic options for all sort criteria
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
if ($this->can_expose()) {
$this->show_expose_button($form, $form_state);
}
$form['op_val_start'] = array('#value' => '<div class="clearfix">');
$this->show_sort_form($form, $form_state);
$form['op_val_end'] = array('#value' => '</div>');
if ($this->can_expose()) {
$this->show_expose_form($form, $form_state);
}
}
/**
* Shortcut to display the expose/hide button.
*/
function show_expose_button(&$form, &$form_state) {
$form['expose_button'] = array(
'#prefix' => '<div class="views-expose clearfix">',
'#suffix' => '</div>',
// Should always come first
'#weight' => -1000,
);
// Add a checkbox for JS users, which will have behavior attached to it
// so it can replace the button.
$form['expose_button']['checkbox'] = array(
'#theme_wrappers' => array('container'),
'#attributes' => array('class' => array('js-only')),
);
$form['expose_button']['checkbox']['checkbox'] = array(
'#title' => t('Expose this sort to visitors, to allow them to change it'),
'#type' => 'checkbox',
);
// Then add the button itself.
if (empty($this->options['exposed'])) {
$form['expose_button']['markup'] = array(
'#markup' => '<div class="description exposed-description" style="float: left; margin-right:10px">' . t('This sort is not exposed. Expose it to allow the users to change it.') . '</div>',
);
$form['expose_button']['button'] = array(
'#limit_validation_errors' => array(),
'#type' => 'submit',
'#value' => t('Expose sort'),
'#submit' => array('views_ui_config_item_form_expose'),
);
$form['expose_button']['checkbox']['checkbox']['#default_value'] = 0;
}
else {
$form['expose_button']['markup'] = array(
'#markup' => '<div class="description exposed-description">' . t('This sort is exposed. If you hide it, users will not be able to change it.') . '</div>',
);
$form['expose_button']['button'] = array(
'#limit_validation_errors' => array(),
'#type' => 'submit',
'#value' => t('Hide sort'),
'#submit' => array('views_ui_config_item_form_expose'),
);
$form['expose_button']['checkbox']['checkbox']['#default_value'] = 1;
}
}
/**
* Simple validate handler
*/
function options_validate(&$form, &$form_state) {
$this->sort_validate($form, $form_state);
if (!empty($this->options['exposed'])) {
$this->expose_validate($form, $form_state);
}
}
/**
* Simple submit handler
*/
function options_submit(&$form, &$form_state) {
unset($form_state['values']['expose_button']); // don't store this.
$this->sort_submit($form, $form_state);
if (!empty($this->options['exposed'])) {
$this->expose_submit($form, $form_state);
}
}
/**
* Shortcut to display the value form.
*/
function show_sort_form(&$form, &$form_state) {
$options = $this->sort_options();
if (!empty($options)) {
$form['order'] = array(
'#type' => 'radios',
'#options' => $options,
'#default_value' => $this->options['order'],
);
}
}
function sort_validate(&$form, &$form_state) { }
function sort_submit(&$form, &$form_state) { }
/**
* Provide a list of options for the default sort form.
* Should be overridden by classes that don't override sort_form
*/
function sort_options() {
return array(
'ASC' => t('Sort ascending'),
'DESC' => t('Sort descending'),
);
}
function expose_form(&$form, &$form_state) {
// #flatten will move everything from $form['expose'][$key] to $form[$key]
// prior to rendering. That's why the pre_render for it needs to run first,
// so that when the next pre_render (the one for fieldsets) runs, it gets
// the flattened data.
array_unshift($form['#pre_render'], 'views_ui_pre_render_flatten_data');
$form['expose']['#flatten'] = TRUE;
$form['expose']['label'] = array(
'#type' => 'textfield',
'#default_value' => $this->options['expose']['label'],
'#title' => t('Label'),
'#required' => TRUE,
'#size' => 40,
'#weight' => -1,
);
}
/**
* Provide default options for exposed sorts.
*/
function expose_options() {
$this->options['expose'] = array(
'order' => $this->options['order'],
'label' => $this->definition['title'],
);
}
}
/**
* A special handler to take the place of missing or broken handlers.
*
* @ingroup views_sort_handlers
*/
class views_handler_sort_broken extends views_handler_sort {
function ui_name($short = FALSE) {
return t('Broken/missing handler');
}
function ensure_my_table() { /* No table to ensure! */ }
function query($group_by = FALSE) { /* No query to run */ }
function options_form(&$form, &$form_state) {
$form['markup'] = array(
'#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
);
}
/**
* Determine if the handler is considered 'broken'
*/
function broken() { return TRUE; }
}
/**
* @}
*/
-74
View File
@@ -1,74 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_sort_date.
*/
/**
* Basic sort handler for dates.
*
* This handler enables granularity, which is the ability to make dates
* equivalent based upon nearness.
*
* @ingroup views_sort_handlers
*/
class views_handler_sort_date extends views_handler_sort {
function option_definition() {
$options = parent::option_definition();
$options['granularity'] = array('default' => 'second');
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['granularity'] = array(
'#type' => 'radios',
'#title' => t('Granularity'),
'#options' => array(
'second' => t('Second'),
'minute' => t('Minute'),
'hour' => t('Hour'),
'day' => t('Day'),
'month' => t('Month'),
'year' => t('Year'),
),
'#description' => t('The granularity is the smallest unit to use when determining whether two dates are the same; for example, if the granularity is "Year" then all dates in 1999, regardless of when they fall in 1999, will be considered the same date.'),
'#default_value' => $this->options['granularity'],
);
}
/**
* Called to add the sort to a query.
*/
function query() {
$this->ensure_my_table();
switch ($this->options['granularity']) {
case 'second':
default:
$this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']);
return;
case 'minute':
$formula = views_date_sql_format('YmdHi', "$this->table_alias.$this->real_field");
break;
case 'hour':
$formula = views_date_sql_format('YmdH', "$this->table_alias.$this->real_field");
break;
case 'day':
$formula = views_date_sql_format('Ymd', "$this->table_alias.$this->real_field");
break;
case 'month':
$formula = views_date_sql_format('Ym', "$this->table_alias.$this->real_field");
break;
case 'year':
$formula = views_date_sql_format('Y', "$this->table_alias.$this->real_field");
break;
}
// Add the field.
$this->query->add_orderby(NULL, $formula, $this->options['order'], $this->table_alias . '_' . $this->field . '_' . $this->options['granularity']);
}
}
@@ -1,38 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_sort_group_by_numeric.
*/
/**
* Handler for GROUP BY on simple numeric fields.
*
* @ingroup views_sort_handlers
*/
class views_handler_sort_group_by_numeric extends views_handler_sort {
function init(&$view, &$options) {
parent::init($view, $options);
// Initialize the original handler.
$this->handler = views_get_handler($options['table'], $options['field'], 'sort');
$this->handler->init($view, $options);
}
/**
* Called to add the field to a query.
*/
function query() {
$this->ensure_my_table();
$params = array(
'function' => $this->options['group_type'],
);
$this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order'], NULL, $params);
}
function ui_name($short = FALSE) {
return $this->get_field(parent::ui_name($short));
}
}
@@ -1,54 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_sort_menu_hierarchy.
*/
/**
* Sort in menu hierarchy order.
*
* Given a field name of 'p' this produces an ORDER BY on p1, p2, ..., p9;
* and optionally injects multiple joins to {menu_links} to sort by weight
* and title as well.
*
* This is only really useful for the {menu_links} table.
*
* @ingroup views_sort_handlers
*/
class views_handler_sort_menu_hierarchy extends views_handler_sort {
function option_definition() {
$options = parent::option_definition();
$options['sort_within_level'] = array('default' => FALSE);
return $options;
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['sort_within_level'] = array(
'#type' => 'checkbox',
'#title' => t('Sort within each hierarchy level'),
'#description' => t('Enable this to sort the items within each level of the hierarchy by weight and title. Warning: this may produce a slow query.'),
'#default_value' => $this->options['sort_within_level'],
);
}
function query() {
$this->ensure_my_table();
$max_depth = isset($this->definition['max depth']) ? $this->definition['max depth'] : MENU_MAX_DEPTH;
for ($i = 1; $i <= $max_depth; ++$i) {
if ($this->options['sort_within_level']) {
$join = new views_join();
$join->construct('menu_links', $this->table_alias, $this->field . $i, 'mlid');
$menu_links = $this->query->add_table('menu_links', NULL, $join);
$this->query->add_orderby($menu_links, 'weight', $this->options['order']);
$this->query->add_orderby($menu_links, 'link_title', $this->options['order']);
}
// We need this even when also sorting by weight and title, to make sure
// that children of two parents with the same weight and title are
// correctly separated.
$this->query->add_orderby($this->table_alias, $this->field . $i, $this->options['order']);
}
}
}
-22
View File
@@ -1,22 +0,0 @@
<?php
/**
* @file
* Definition of views_handler_sort_random.
*/
/**
* Handle a random sort.
*
* @ingroup views_sort_handlers
*/
class views_handler_sort_random extends views_handler_sort {
function query() {
$this->query->add_orderby('rand');
}
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['order']['#access'] = FALSE;
}
}
-62
View File
@@ -1,62 +0,0 @@
The views module allows administrators and site designers to create, manage, and display lists of content. Each list managed by the views module is known as a "view", and the output of a view is known as a "display". Displays are provided in either block or page form, and a single view may have multiple displays. Optional navigation aids, including a system path and menu item, can be set for each page-based display of a view. By default, views may be created that list content (a <em>Node</em> view type), content revisions (a <em>Node revisions</em> view type) or users (a <em>User</em> view type). A view may be restricted to members of specific user roles, and may be added, edited or deleted at the <a href="base_url:admin/structure/views">views administration page</a>.
For more technical users, views can be understood as a user interface to compose SQL-queries and to pull information (Content, Users, etc.) from the database and show it on a screen as desired.
The "building block" design of the views system provides power and flexibility, allowing parameters to be specified only when needed. While an advanced view may use all of available parameters to create complex and highly interactive applications, a simple content listing may specify only a few options. All views rely on a conceptual framework that includes:
<ul>
<li><a href="topic:views/field">Fields</a>, or the individual pieces of data being displayed. Adding the fields <em>Node: Title</em>, <em>Node: Type</em>, and <em>Node: Post date</em> to a node view, for example, includes the title, content type and creation date in the displayed results </li>
<li><a href="topic:views/relationship">Relationships</a>, or information about how data elements relate to one another. If relationship data is available, like that provided by a CCK <em>nodereference</em> field, items from a related node may be included in the view </li>
<li><a href="topic:views/argument">Arguments</a>, or additional parameters that dynamically refine the view results, passed as part of the path. Adding an argument of <em>Node: Type</em> to a node view with a path of "content", for example, dynamically filters the displayed items by content type. In this example (shown with Clean URLs enabled), accessing the view through the path "<em>http://www.example.com/content/page</em>" displays all posts of the type "page", the path "<em>http://www.example.com/content/story</em>" displays all posts of the type "story", and "<em>http://www.example.com/content</em>" displays all posts regardless of type) </li>
<li><a href="topic:views/sort">Sort criteria</a>, which determine the order of items displayed in the view results. Adding the sort criteria <em>Node: Post date</em> (in descending order) to a node <em>view</em>, for example, sorts the displayed posts in descending order by creation date </li>
<li><a href="topic:views/filter">Filters</a>, which limit items displayed in the results. Adding the filter <em>Node: Published</em> (and setting it equal to "Published") to a node view, for example, prevents unpublished items from being displayed</li>
<li><a href="topic:views/display">Displays</a>, which control where the output will be seen. Every view has a default display, which doesn't actually display the view anywhere, but is used to hold the default settings for the view, and is used when the view is called programmatically if another display is not specified. Much more useful to users are the <a href="topic:views/display-page">page</a> display, which gives a view a path and allows it to be the primary content of a page, or the <a href="topic:views/display-block">block</a> display which allows it to appear as secondary content on other pages.</li>
<li><a href="topic:views/header">Header</a>, which allow you to add by default one or more text area above the views output. </li>
<li><a href="topic:views/footer">Footer</a>, which allow you to add by default one or more text area beneath the views output. </li>
<li>The <a href="topic:views/footer">Emtpy Text</a> content will be displayed, when you choose in the Arguments Section "Action to take if argument is not present" the option "Display empty text".</li>
</ul>
Parallels between the components in the Views interface and an sql query:
<table>
<thead>
<tr>
<th>Sql Query</th>
<th>Views Component</th>
<tr>
</thead>
<tr>
<td>SELECT n.title, u.name</td>
<td>fields</td>
</tr>
<tr>
<td>FROM {node} n base table</td>
<td>view type</td>
</tr>
<tr>
<td>INNER JOIN {users} u ON n.uid = u.uid</td>
<td>relationship</td>
</tr>
<tr>
<td>WHERE n.status = 1</td>
<td>filter</td>
</tr>
<tr>
<td>AND u.uid = arg(1)</td>
<td>argument</td>
</tr>
<tr>
<td>ORDER BY n.changed DESC</td>
<td>sort</td>
</tr>
</table>

Some files were not shown because too many files have changed in this diff Show More